Compare commits
500
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5184064a26 | ||
|
|
6a43363539 | ||
|
|
b9195fbbad | ||
|
|
f715ad2176 | ||
|
|
ca02ee0352 | ||
|
|
fbaa54145e | ||
|
|
28754ffbf2 | ||
|
|
470c0eba7a | ||
|
|
7098dcec43 | ||
|
|
07137f57af | ||
|
|
8b7491a3d3 | ||
|
|
8cfa8ddfeb | ||
|
|
ef284a15a1 | ||
|
|
3723921573 | ||
|
|
195399635e | ||
|
|
46e2a924d3 | ||
|
|
b693ea4102 | ||
|
|
a73f55beb0 | ||
|
|
0bd2491ab7 | ||
|
|
860c797c9c | ||
|
|
38c5080f9f | ||
|
|
fae191d8fe | ||
|
|
d83a953e2d | ||
|
|
2dcf0d0f0d | ||
|
|
6dee37d8c1 | ||
|
|
3bad03afb3 | ||
|
|
6a6d8448f7 | ||
|
|
189babd2cf | ||
|
|
988a0f2294 | ||
|
|
85bf455731 | ||
|
|
589e4224f3 | ||
|
|
bd7fa154b4 | ||
|
|
a292f1992b | ||
|
|
88ddf429b7 | ||
|
|
7a1f6662df | ||
|
|
afc68bccc6 | ||
|
|
b4cdc4a64f | ||
|
|
3ad5afb81c | ||
|
|
bed3f20118 | ||
|
|
de67315178 | ||
|
|
8d5c0c7cad | ||
|
|
a8271e01bd | ||
|
|
900b3f8558 | ||
|
|
fdc4e056f9 | ||
|
|
7b98e40ccf | ||
|
|
01d89cf22c | ||
|
|
503a3c799a | ||
|
|
0b21388844 | ||
|
|
117bdf0c00 | ||
|
|
172dc5d37b | ||
|
|
874c6258ab | ||
|
|
a2d0a12c1a | ||
|
|
38b24e1c3d | ||
|
|
5ecbbe296b | ||
|
|
9d7a769d8f | ||
|
|
9b75e5ed83 | ||
|
|
a9ab8dc1d8 | ||
|
|
a34831aa02 | ||
|
|
84ebaa0751 | ||
|
|
55352805ee | ||
|
|
c0a3f2e16a | ||
|
|
28ff331a28 | ||
|
|
f9a53ec719 | ||
|
|
6a403e6caf | ||
|
|
a6f449bb93 | ||
|
|
0614bfc446 | ||
|
|
bb020c36c1 | ||
|
|
f17b0bfcfb | ||
|
|
2a85c9503f | ||
|
|
182428d6d6 | ||
|
|
8181a28557 | ||
|
|
88aed11d98 | ||
|
|
67010592b8 | ||
|
|
dd22d6424a | ||
|
|
e53775b97f | ||
|
|
d326f6c1ac | ||
|
|
556111c00a | ||
|
|
ebc7110e63 | ||
|
|
af49d1c8bb | ||
|
|
c71dbb1dfc | ||
|
|
432aa3c4fa | ||
|
|
5c93503710 | ||
|
|
0d58050def | ||
|
|
27bb78209a | ||
|
|
3201f5a25b | ||
|
|
d3df8a96d3 | ||
|
|
7ec5266b1f | ||
|
|
e74ff7c805 | ||
|
|
1d5f3c2959 | ||
|
|
469034b223 | ||
|
|
f3a394de21 | ||
|
|
cb23d4c11b | ||
|
|
bbf5b706f0 | ||
|
|
1e890f6d86 | ||
|
|
2fe543a603 | ||
|
|
24631990bd | ||
|
|
0c8c0d24ba | ||
|
|
454b8a91ba | ||
|
|
a74f1568e9 | ||
|
|
3f35d56be4 | ||
|
|
722fe2ccfb | ||
|
|
d85737cc08 | ||
|
|
ce29435831 | ||
|
|
d3715eece8 | ||
|
|
335d79f2c4 | ||
|
|
a9e33660cb | ||
|
|
8faf881399 | ||
|
|
c4969a36cc | ||
|
|
26fcaf6e75 | ||
|
|
a162002af2 | ||
|
|
9810fd51ab | ||
|
|
857c6b3d47 | ||
|
|
e1498f538d | ||
|
|
aa246eff94 | ||
|
|
5be21a21d5 | ||
|
|
8131bcd4d4 | ||
|
|
4ba11e3363 | ||
|
|
acf2be3f66 | ||
|
|
f5df0195e2 | ||
|
|
d26995b48d | ||
|
|
617f8120ae | ||
|
|
06c517c9aa | ||
|
|
593ed6408c | ||
|
|
fb7d3ed122 | ||
|
|
19b88ec858 | ||
|
|
160e65be7f | ||
|
|
079b0d2cf6 | ||
|
|
78f1310f41 | ||
|
|
eb1974c113 | ||
|
|
551409a023 | ||
|
|
a11e14daac | ||
|
|
7441e15e76 | ||
|
|
46506228a6 | ||
|
|
17c49c74cf | ||
|
|
3f8024d4db | ||
|
|
8675e44d28 | ||
|
|
1301d9a718 | ||
|
|
da3db50ca8 | ||
|
|
2ca6780305 | ||
|
|
be68fe5a35 | ||
|
|
dc41c0e302 | ||
|
|
51388c90d5 | ||
|
|
f8c9d33df2 | ||
|
|
ed0420fdce | ||
|
|
47a6f396fa | ||
|
|
9edb2aa0c1 | ||
|
|
003b647d83 | ||
|
|
2849ff8844 | ||
|
|
9f3089742a | ||
|
|
b286a9bbcd | ||
|
|
6204e745ba | ||
|
|
bbe0e48d23 | ||
|
|
79054080c0 | ||
|
|
81024c4c09 | ||
|
|
9068d96130 | ||
|
|
6f47543720 | ||
|
|
5a08384ae1 | ||
|
|
45d8fda0e4 | ||
|
|
a9e664492f | ||
|
|
3c8b6cb2cc | ||
|
|
2b3abbe13b | ||
|
|
241a52b94a | ||
|
|
82c300b077 | ||
|
|
0f8b629e20 | ||
|
|
36f6ac65f2 | ||
|
|
a25871a849 | ||
|
|
57766a9104 | ||
|
|
3770ae1645 | ||
|
|
d73edb403f | ||
|
|
b14196ff0d | ||
|
|
88903fee94 | ||
|
|
1e8311fc04 | ||
|
|
2b78370cb8 | ||
|
|
8f78bba9e9 | ||
|
|
41a4be678e | ||
|
|
8b2b4b7c3d | ||
|
|
1f3a29f89d | ||
|
|
c4c93097cd | ||
|
|
eedb7769e6 | ||
|
|
98db62a4bc | ||
|
|
df48c8e500 | ||
|
|
db9cc0f4c6 | ||
|
|
a79ee429b4 | ||
|
|
6acfca6d48 | ||
|
|
1cd6f4cb72 | ||
|
|
3271e8c7d6 | ||
|
|
0bcde064af | ||
|
|
957980b3c5 | ||
|
|
03eb328d81 | ||
|
|
e1716a741f | ||
|
|
e24707c847 | ||
|
|
7c4b8c307f | ||
|
|
109318aeaf | ||
|
|
1f2657cea0 | ||
|
|
382c435bac | ||
|
|
130fe4ca5d | ||
|
|
31ba3fe127 | ||
|
|
f68b31158f | ||
|
|
653ca9a72d | ||
|
|
ba7857f4df | ||
|
|
23e617ea21 | ||
|
|
cdf5a5229c | ||
|
|
f841a35a53 | ||
|
|
efd31237be | ||
|
|
6502822583 | ||
|
|
a9e6f2b2a5 | ||
|
|
510a94b42c | ||
|
|
d805be47ce | ||
|
|
f9ea8e380a | ||
|
|
5cb05beb30 | ||
|
|
677768e6ab | ||
|
|
ed6c951783 | ||
|
|
54254348b8 | ||
|
|
782fd07a8d | ||
|
|
a8fd55cb38 | ||
|
|
d7f515575a | ||
|
|
bafbf2ec2f | ||
|
|
7415944e0a | ||
|
|
1ff990ff44 | ||
|
|
73e73d8772 | ||
|
|
6d876bb767 | ||
|
|
2be0fe9f06 | ||
|
|
e1fb082927 | ||
|
|
65ca5ae4c4 | ||
|
|
2cea43dc70 | ||
|
|
44a0700800 | ||
|
|
1613a378f1 | ||
|
|
deed98a27d | ||
|
|
9d0cb8fb46 | ||
|
|
d8fe0f6923 | ||
|
|
581dbc2b3c | ||
|
|
7301d2ad76 | ||
|
|
3232a14d1d | ||
|
|
84c1f88d42 | ||
|
|
3695b10e4b | ||
|
|
6da02b25fa | ||
|
|
3bc544fba1 | ||
|
|
368d370f49 | ||
|
|
bb29c0edef | ||
|
|
6edcf75a0c | ||
|
|
31cc186424 | ||
|
|
0e94c1fa6d | ||
|
|
6d9e2dd3e1 | ||
|
|
4a4adeb3c8 | ||
|
|
ff77f8cfa0 | ||
|
|
36db89c36e | ||
|
|
a9948142ad | ||
|
|
8d05510584 | ||
|
|
d373de7a29 | ||
|
|
1efa9a9f7b | ||
|
|
0fb3ba2f91 | ||
|
|
3b4c5b5153 | ||
|
|
9293aeeec8 | ||
|
|
03ae83b119 | ||
|
|
abd63cc6cf | ||
|
|
2e43aa2c44 | ||
|
|
3d984e13c2 | ||
|
|
010900fe21 | ||
|
|
ffed626447 | ||
|
|
61f69af35a | ||
|
|
bd248ee91c | ||
|
|
194255bffe | ||
|
|
52ee627079 | ||
|
|
bd4200e707 | ||
|
|
73e7d6c7f3 | ||
|
|
a41b0e916b | ||
|
|
19f2a2c616 | ||
|
|
998601f722 | ||
|
|
7c3386cf3e | ||
|
|
d161182997 | ||
|
|
1646dc2dbd | ||
|
|
b640295be2 | ||
|
|
b89ae2391b | ||
|
|
a0fad441d0 | ||
|
|
340084dac3 | ||
|
|
c78135aa09 | ||
|
|
d19f8bbd30 | ||
|
|
4205899f5a | ||
|
|
7dd3940770 | ||
|
|
00d94e3015 | ||
|
|
7bacb3ee2b | ||
|
|
8e49be5ac4 | ||
|
|
3b94598d2c | ||
|
|
bddc9af3b6 | ||
|
|
2451d73a7c | ||
|
|
1dd2efa182 | ||
|
|
acea610773 | ||
|
|
8f2f1fd496 | ||
|
|
39c775872a | ||
|
|
bdb3cbd109 | ||
|
|
ff84ce2b04 | ||
|
|
225f405592 | ||
|
|
715ecffa18 | ||
|
|
e51cdc8992 | ||
|
|
133685ea37 | ||
|
|
6aff98d555 | ||
|
|
acdc524284 | ||
|
|
1ee5ec7b43 | ||
|
|
46a5403511 | ||
|
|
87bfb92576 | ||
|
|
c7a3e5601c | ||
|
|
4009130f6e | ||
|
|
c91243f6e9 | ||
|
|
0e3871ac26 | ||
|
|
55baafec8a | ||
|
|
b5a66993ca | ||
|
|
0b570b5fd6 | ||
|
|
378227c377 | ||
|
|
650645eaff | ||
|
|
62c71f3fe6 | ||
|
|
041ec3d710 | ||
|
|
5f2d871bad | ||
|
|
a30b151e4d | ||
|
|
5a651d2d1f | ||
|
|
4b3826edd9 | ||
|
|
bae1ff3759 | ||
|
|
fd82486431 | ||
|
|
c9cd91cbd8 | ||
|
|
c8abd374fe | ||
|
|
2b9ee8f721 | ||
|
|
d02673e04a | ||
|
|
f0117b8e6e | ||
|
|
bb7c41c754 | ||
|
|
efa583c154 | ||
|
|
d16ea13c14 | ||
|
|
673d8e0a18 | ||
|
|
37cfdde1ee | ||
|
|
0778ffb57a | ||
|
|
42099f7241 | ||
|
|
c52e1d22b7 | ||
|
|
0d7b0aadd1 | ||
|
|
4cd3355ef1 | ||
|
|
98d70b96d1 | ||
|
|
64735bdf43 | ||
|
|
7b87347b77 | ||
|
|
b5b29d7061 | ||
|
|
9ec21f85a0 | ||
|
|
da1a5a3f1b | ||
|
|
0885da8d44 | ||
|
|
8af961c6d3 | ||
|
|
ef5febdde3 | ||
|
|
6d7fbd3926 | ||
|
|
2680d373d8 | ||
|
|
2b2ddb3cf2 | ||
|
|
85ff95296b | ||
|
|
314a2de41a | ||
|
|
26fafab47a | ||
|
|
e56ff20e2d | ||
|
|
55d44f229d | ||
|
|
1c5e50cc4d | ||
|
|
ea898da6c2 | ||
|
|
dbb7e9f53c | ||
|
|
cbb68a399d | ||
|
|
0e794f28b1 | ||
|
|
87d2d9123e | ||
|
|
6823a4ddb5 | ||
|
|
20a7c70081 | ||
|
|
9caa33b3bb | ||
|
|
2d7e61460a | ||
|
|
a4b7fb3f44 | ||
|
|
70056cf4ca | ||
|
|
5f4ab71ade | ||
|
|
f3adb3257b | ||
|
|
438edda7fd | ||
|
|
d5b0441e6f | ||
|
|
9ba0ceb000 | ||
|
|
9474a68995 | ||
|
|
09c35f0aa6 | ||
|
|
a2113442cb | ||
|
|
d91808487f | ||
|
|
933949cc19 | ||
|
|
407620387d | ||
|
|
98947dea26 | ||
|
|
ebff7af9b5 | ||
|
|
b23c4b83ae | ||
|
|
c0cff40628 | ||
|
|
97513e354c | ||
|
|
c277ae7aff | ||
|
|
e1835e6282 | ||
|
|
5ac21db997 | ||
|
|
ca0e9fc3b2 | ||
|
|
66ebcb1608 | ||
|
|
ff92a78dda | ||
|
|
7356286fe0 | ||
|
|
54e8e68f86 | ||
|
|
d21cd7f78b | ||
|
|
1d7516982a | ||
|
|
c77a11442c | ||
|
|
5bd43a4643 | ||
|
|
9b87dfa1a9 | ||
|
|
2e3173ea40 | ||
|
|
68eac7cf83 | ||
|
|
6709505630 | ||
|
|
af6e962a5d | ||
|
|
18e6bdabaa | ||
|
|
9743942eae | ||
|
|
23062137a8 | ||
|
|
46f7fb5ccd | ||
|
|
9c90c49a6b | ||
|
|
4517b63557 | ||
|
|
58c239f4b4 | ||
|
|
cc8845ba3e | ||
|
|
6b69ce2901 | ||
|
|
55300ed21c | ||
|
|
7346dd4339 | ||
|
|
2caf3b92ce | ||
|
|
af2cd72a1f | ||
|
|
3d455ec1f8 | ||
|
|
15982d7735 | ||
|
|
5ae3542bd9 | ||
|
|
b1b02ae24b | ||
|
|
f0964e2c92 | ||
|
|
e9661d2998 | ||
|
|
ea6468f2a9 | ||
|
|
a2b38d3b83 | ||
|
|
d67ef02941 | ||
|
|
549ebe25d8 | ||
|
|
9a98348582 | ||
|
|
c5f5b025a6 | ||
|
|
23eaffa3a7 | ||
|
|
c161809248 | ||
|
|
4bf26dc818 | ||
|
|
5dd22fad6c | ||
|
|
2c3fdf7803 | ||
|
|
e984b9f5d7 | ||
|
|
a3c2e37b17 | ||
|
|
edf1b5a0a3 | ||
|
|
8efdf59ebd | ||
|
|
5c4537b2fa | ||
|
|
71e6079054 | ||
|
|
dd048d9b0d | ||
|
|
93074d653e | ||
|
|
9139c4350a | ||
|
|
38ce768168 | ||
|
|
82b3dc576c | ||
|
|
2167889f48 | ||
|
|
e9b02c2acf | ||
|
|
9ee446431b | ||
|
|
df106e3988 | ||
|
|
d0a057e0ee | ||
|
|
8b49902bf6 | ||
|
|
71c1e56564 | ||
|
|
1b12e67de2 | ||
|
|
291bb4bb81 | ||
|
|
342ddb19f8 | ||
|
|
9c9d2d548e | ||
|
|
d7a0bb4509 | ||
|
|
2b1a3323a8 | ||
|
|
99d030003c | ||
|
|
92a753560b | ||
|
|
af9904c892 | ||
|
|
e5e8c49f6c | ||
|
|
b37e5f45ca | ||
|
|
e1f08b07aa | ||
|
|
073ee8dca9 | ||
|
|
a26e51cf46 | ||
|
|
dfed732825 | ||
|
|
87aa70c6d2 | ||
|
|
aa2979ffe7 | ||
|
|
236e16aa6d | ||
|
|
184bb970e6 | ||
|
|
bd54469891 | ||
|
|
2f5dccc3ef | ||
|
|
592edb90a0 | ||
|
|
3db7e6b1b9 | ||
|
|
13c4df0d85 | ||
|
|
ef25fb09da | ||
|
|
03cf4a9efe | ||
|
|
53dd36efdd | ||
|
|
ad9e841a42 | ||
|
|
14f3f464c7 | ||
|
|
cbe51cc8d0 | ||
|
|
efaa3f6eea | ||
|
|
52cce9a3b0 | ||
|
|
b7b390311e | ||
|
|
c1eeddd14b | ||
|
|
1a7a55dfc3 | ||
|
|
fe5927ea6a | ||
|
|
119c794ad7 | ||
|
|
e2076b2c1c | ||
|
|
5208c5148e | ||
|
|
d80660b097 | ||
|
|
b916d0278b | ||
|
|
d51e13e620 | ||
|
|
40ad4326ef | ||
|
|
b8afc1684a | ||
|
|
8348b31ac8 | ||
|
|
411f2dbcce | ||
|
|
ee89c08160 | ||
|
|
357607a89f | ||
|
|
8d6dc2df44 | ||
|
|
5207582ab3 | ||
|
|
71768e6154 | ||
|
|
ecbe235523 | ||
|
|
afef079d1e | ||
|
|
df17696c69 | ||
|
|
065bf0908f | ||
|
|
5b6755e9cf | ||
|
|
b08482acf1 | ||
|
|
80c9c1d389 |
@@ -1,5 +0,0 @@
|
||||
FROM devkitpro/devkitppc
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y python3 python3-pip python3-polib python3-pil python3-dotenv python3-pyqt5 python3-opengl && \
|
||||
dkp-pacman -S --needed --noconfirm gamecube-sdl2 ppc-liblzma ppc-libzip
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
docker build -t myapp:latest -f ./.ci/dolphin/Dockerfile .
|
||||
docker run -v ./:/gamecube myapp:latest /bin/bash -c ' \
|
||||
export PATH="$DEVKITPPC/bin:$PATH" && \
|
||||
echo "Inside Docker container:" && \
|
||||
ls -l && \
|
||||
echo "Current directory:" && \
|
||||
realpath . && \
|
||||
echo "Listing /:" && \
|
||||
ls / && \
|
||||
echo "Changing to /gamecube" && \
|
||||
cd /gamecube && \
|
||||
echo "Contents of /gamecube:" && \
|
||||
ls -l && \
|
||||
rm -rf build-gamecube && \
|
||||
mkdir -p build-gamecube && \
|
||||
cmake -S. -Bbuild-gamecube -DDUSK_TARGET_SYSTEM=gamecube -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake" && \
|
||||
cd build-gamecube && \
|
||||
make VERBOSE=1
|
||||
'
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
docker build -t myapp:latest -f .ci/dolphin/Dockerfile .
|
||||
docker run -v ./:/workdir myapp:latest /bin/bash -c ' \
|
||||
export PATH="$DEVKITPPC/bin:$PATH" && \
|
||||
cd /workdir && \
|
||||
rm -rf build-wii && \
|
||||
mkdir -p build-wii && \
|
||||
cmake -S. -Bbuild-wii -DDUSK_TARGET_SYSTEM=wii -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake" && \
|
||||
cd build-wii && \
|
||||
make VERBOSE=1 && \
|
||||
mv ./Dusk.dol ./boot.dol
|
||||
'
|
||||
# docker run -it -v ./:/workdir myapp:latest /bin/bash
|
||||
@@ -1,147 +0,0 @@
|
||||
name: Build Dusk
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-gamecube:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)
|
||||
# Add Docker's official GPG key:
|
||||
sudo apt update
|
||||
sudo apt install ca-certificates curl
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||||
|
||||
# Add the repository to Apt sources:
|
||||
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
|
||||
Components: stable
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
EOF
|
||||
|
||||
sudo apt update --yes
|
||||
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin --yes
|
||||
- name: Build GameCube
|
||||
run: |
|
||||
echo "ls -l ."
|
||||
ls -l
|
||||
echo "Current directory:"
|
||||
realpath .
|
||||
echo "ls /"
|
||||
ls /
|
||||
echo "Run GameCube build script"
|
||||
.ci/dolphin/build-gamecube.sh
|
||||
- name: Copy gamecube
|
||||
run: |
|
||||
mkdir -p build/gitea/Gamecube/Dusk
|
||||
mv build/Dusk.dol build/gitea/Gamecube/Dusk/Dusk.dol
|
||||
mv build/dusk.dsk build/gitea/Gamecube/Dusk/dusk.dsk
|
||||
- name: Upload GameCube Binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-gamecube
|
||||
path: build/gitea/Gamecube
|
||||
if-no-files-found: error
|
||||
|
||||
# build-wii:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Checkout repository
|
||||
# uses: actions/checkout@v5
|
||||
# - name: Install dependencies
|
||||
# run: |
|
||||
# apt-get update
|
||||
# apt-get install -y docker.io
|
||||
# - name: Build Wii
|
||||
# run: |
|
||||
# ./.ci/dolphin/build-wii.sh
|
||||
# - name: Copy wii
|
||||
# run: |
|
||||
# mkdir -p build/gitea/Wii/apps/Dusk
|
||||
# mv build/Dusk.dol build/gitea/Wii/apps/Dusk/boot.dol
|
||||
# mv build/dusk.dsk build/gitea/Wii/apps/Dusk/dusk.dsk
|
||||
# - name: Upload Wii Binary
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: dusk-wii
|
||||
# path: build/gitea/Wii
|
||||
# if-no-files-found: error
|
||||
|
||||
run-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl liblua5.3-dev
|
||||
- name: Configure CMake for tests
|
||||
run: cmake -S . -B build -DDUSK_BUILD_TESTS=ON -DDUSK_TARGET_SYSTEM=linux
|
||||
- name: Build tests
|
||||
run: cmake --build build -- -j$(nproc)
|
||||
- name: Run tests
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl liblua5.3-dev
|
||||
- name: Configure CMake
|
||||
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=linux
|
||||
- name: Build
|
||||
run: cmake --build build -- -j$(nproc)
|
||||
- name: List build output
|
||||
run: ls -lh build
|
||||
- name: Upload Linux binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-linux
|
||||
path: build/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-psp:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl liblua5.3-dev
|
||||
- name: Configure CMake
|
||||
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=psp -DENABLE_TESTS=OFF
|
||||
- name: Build
|
||||
run: cmake --build build -- -j$(nproc)
|
||||
- name: Move EBOOT.PBP to Dusk subfolder
|
||||
run: |
|
||||
mkdir -p build/gitea/Dusk
|
||||
mv build/EBOOT.PBP build/gitea/Dusk/EBOOT.PBP
|
||||
- name: List build output
|
||||
run: ls -lh build/gitea/Dusk
|
||||
- name: Upload PSP binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-psp
|
||||
path: build/gitea/
|
||||
if-no-files-found: error
|
||||
@@ -0,0 +1,49 @@
|
||||
name: Setup devkitPro
|
||||
description: Install devkitPro with GameCube/Wii packages on an Ubuntu runner
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install apt dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
cmake \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-polib \
|
||||
python3-pil \
|
||||
python3-dotenv \
|
||||
python3-pyqt5 \
|
||||
python3-opengl \
|
||||
xorriso
|
||||
- name: Install devkitPro pacman
|
||||
shell: bash
|
||||
run: |
|
||||
sudo ln -sf /proc/self/mounts /etc/mtab
|
||||
wget https://apt.devkitpro.org/install-devkitpro-pacman \
|
||||
-O /tmp/install-devkitpro-pacman
|
||||
echo "=== installer script contents ==="
|
||||
cat /tmp/install-devkitpro-pacman
|
||||
echo "================================="
|
||||
chmod +x /tmp/install-devkitpro-pacman
|
||||
sudo /tmp/install-devkitpro-pacman
|
||||
echo "DEVKITPRO=/opt/devkitpro" >> $GITHUB_ENV
|
||||
echo "DEVKITPPC=/opt/devkitpro/devkitPPC" >> $GITHUB_ENV
|
||||
echo "/opt/devkitpro/tools/bin" >> $GITHUB_PATH
|
||||
echo "/opt/devkitpro/devkitPPC/bin" >> $GITHUB_PATH
|
||||
- name: Install devkitPro GameCube/Wii packages
|
||||
shell: bash
|
||||
run: |
|
||||
sudo dkp-pacman -S --needed --noconfirm \
|
||||
gamecube-dev \
|
||||
gamecube-sdl2 \
|
||||
ppc-liblzma \
|
||||
ppc-libzip \
|
||||
libogc2 \
|
||||
gamecube-tools \
|
||||
ppc-libmad \
|
||||
ppc-zlib-ng \
|
||||
ppc-bzip2 \
|
||||
ppc-zstd
|
||||
@@ -0,0 +1,20 @@
|
||||
name: Setup pspdev
|
||||
description: Install the pspdev PSP toolchain on an Ubuntu runner
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y cmake python3 python3-pip python3-dotenv
|
||||
- name: Install pspdev toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
wget -q \
|
||||
https://github.com/pspdev/pspdev/releases/latest/download/pspdev-ubuntu-latest-x86_64.tar.gz \
|
||||
-O /tmp/pspdev.tar.gz
|
||||
sudo tar -xzf /tmp/pspdev.tar.gz -C /usr/local
|
||||
echo "PSPDEV=/usr/local/pspdev" >> $GITHUB_ENV
|
||||
echo "/usr/local/pspdev/bin" >> $GITHUB_PATH
|
||||
@@ -0,0 +1,247 @@
|
||||
name: Build Dusk
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
jobs:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-polib \
|
||||
python3-pil \
|
||||
libsdl2-dev \
|
||||
libgl1-mesa-dev \
|
||||
libzip-dev \
|
||||
python3-dotenv \
|
||||
python3-pyqt5 \
|
||||
python3-opengl \
|
||||
xz-utils \
|
||||
liblzma-dev \
|
||||
libbz2-dev \
|
||||
zlib1g-dev \
|
||||
git \
|
||||
libssl-dev
|
||||
- name: Build Linux
|
||||
run: ./scripts/build-linux.sh
|
||||
- name: Upload Linux binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-linux
|
||||
path: build-linux/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-psp:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup pspdev
|
||||
uses: ./.github/actions/setup-pspdev
|
||||
- name: Build PSP
|
||||
run: ./scripts/build-psp.sh
|
||||
- name: Move EBOOT.PBP to Dusk subfolder
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk/PSP/GAME/Dusk
|
||||
cp build-psp/EBOOT.PBP ./git-artifcats/Dusk/PSP/GAME/Dusk/EBOOT.PBP
|
||||
- name: Upload PSP binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-psp
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-knulli:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: debian:trixie
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
dpkg --add-architecture arm64
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
crossbuild-essential-arm64 \
|
||||
ca-certificates \
|
||||
pkg-config \
|
||||
cmake \
|
||||
make \
|
||||
ninja-build \
|
||||
git \
|
||||
file \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-polib \
|
||||
python3-pil \
|
||||
python3-dotenv \
|
||||
python3-pyqt5 \
|
||||
python3-opengl \
|
||||
liblua5.4-dev:arm64 \
|
||||
xz-utils:arm64 \
|
||||
libbz2-dev:arm64 \
|
||||
zlib1g-dev:arm64 \
|
||||
libzip-dev:arm64 \
|
||||
libssl-dev:arm64 \
|
||||
libsdl2-dev:arm64 \
|
||||
liblzma-dev:arm64 \
|
||||
libopengl0:arm64 \
|
||||
libgl1:arm64 \
|
||||
libegl1:arm64 \
|
||||
libgles2:arm64 \
|
||||
libgl1-mesa-dev:arm64
|
||||
- name: Build Knulli
|
||||
run: ./scripts/build-knulli.sh
|
||||
- name: Move output to Dusk subfolder
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk
|
||||
cp -r build-knulli/dusk ./git-artifcats/Dusk
|
||||
- name: Upload Knulli binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-knulli
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-gamecube:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/extremscorner/libogc2:latest
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install additional dependencies
|
||||
run: |
|
||||
apt-get install -y \
|
||||
python3-pip python3-polib python3-pil \
|
||||
python3-dotenv python3-pyqt5 python3-opengl
|
||||
dkp-pacman -Syu --noconfirm
|
||||
dkp-pacman -S --needed --noconfirm \
|
||||
gamecube-sdl2 ppc-liblzma ppc-libzip \
|
||||
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
|
||||
- name: Build GameCube
|
||||
run: ./scripts/build-gamecube.sh
|
||||
- name: Copy output files
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk
|
||||
cp build-gamecube/Dusk.dol ./git-artifcats/Dusk/Dusk.dol
|
||||
cp build-gamecube/dusk.dsk ./git-artifcats/Dusk/dusk.dsk
|
||||
- name: Upload GameCube binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-gamecube
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-gamecube-iso:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/extremscorner/libogc2:latest
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install additional dependencies
|
||||
run: |
|
||||
apt-get install -y \
|
||||
python3-pip python3-polib python3-pil \
|
||||
python3-dotenv python3-pyqt5 python3-opengl xorriso
|
||||
dkp-pacman -Syu --noconfirm
|
||||
dkp-pacman -S --needed --noconfirm \
|
||||
gamecube-sdl2 ppc-liblzma ppc-libzip \
|
||||
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
|
||||
- name: Build GameCube ISO
|
||||
run: ./scripts/build-gamecube-iso.sh
|
||||
- name: Copy output files
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk
|
||||
cp build-gamecube-iso/Dusk-NTSC-J.iso ./git-artifcats/Dusk/Dusk-NTSC-J.iso
|
||||
cp build-gamecube-iso/Dusk-NTSC-U.iso ./git-artifcats/Dusk/Dusk-NTSC-U.iso
|
||||
cp build-gamecube-iso/Dusk-PAL.iso ./git-artifcats/Dusk/Dusk-PAL.iso
|
||||
- name: Upload GameCube ISO
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-gamecube-iso
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-wii:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/extremscorner/libogc2:latest
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install additional dependencies
|
||||
run: |
|
||||
apt-get install -y \
|
||||
python3-pip python3-polib python3-pil \
|
||||
python3-dotenv python3-pyqt5 python3-opengl
|
||||
dkp-pacman -Syu --noconfirm
|
||||
dkp-pacman -S --needed --noconfirm \
|
||||
gamecube-sdl2 ppc-liblzma ppc-libzip \
|
||||
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
|
||||
- name: Build Wii
|
||||
run: ./scripts/build-wii.sh
|
||||
- name: Copy output files
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk/apps/Dusk
|
||||
cp build-wii/boot.dol ./git-artifcats/Dusk/apps/Dusk/boot.dol
|
||||
cp build-wii/dusk.dsk ./git-artifcats/Dusk/apps/Dusk/dusk.dsk
|
||||
cp build-wii/meta.xml ./git-artifcats/Dusk/apps/Dusk/meta.xml
|
||||
- name: Upload Wii binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-wii
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
|
||||
build-wii-iso:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/extremscorner/libogc2:latest
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install additional dependencies
|
||||
run: |
|
||||
apt-get install -y \
|
||||
python3-pip python3-polib python3-pil \
|
||||
python3-dotenv python3-pyqt5 python3-opengl xorriso
|
||||
dkp-pacman -Syu --noconfirm
|
||||
dkp-pacman -S --needed --noconfirm \
|
||||
gamecube-sdl2 ppc-liblzma ppc-libzip \
|
||||
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
|
||||
- name: Build Wii ISO
|
||||
run: ./scripts/build-wii-iso.sh
|
||||
- name: Copy output files
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk
|
||||
cp build-wii-iso/Dusk-NTSC-J.iso ./git-artifcats/Dusk/Dusk-NTSC-J.iso
|
||||
cp build-wii-iso/Dusk-NTSC-U.iso ./git-artifcats/Dusk/Dusk-NTSC-U.iso
|
||||
cp build-wii-iso/Dusk-PAL.iso ./git-artifcats/Dusk/Dusk-PAL.iso
|
||||
- name: Upload Wii ISO
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dusk-wii-iso
|
||||
path: ./git-artifcats/Dusk
|
||||
if-no-files-found: error
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Test Dusk
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
run-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-polib \
|
||||
python3-pil \
|
||||
libsdl2-dev \
|
||||
libgl1-mesa-dev \
|
||||
libzip-dev \
|
||||
python3-dotenv \
|
||||
python3-pyqt5 \
|
||||
python3-opengl \
|
||||
xz-utils \
|
||||
liblzma-dev \
|
||||
libbz2-dev \
|
||||
zlib1g-dev \
|
||||
git \
|
||||
libssl-dev
|
||||
- name: Run tests
|
||||
run: ./scripts/test-linux.sh
|
||||
+3
-1
@@ -83,7 +83,6 @@ assets/borrowed
|
||||
.VSCode*
|
||||
|
||||
/vita
|
||||
|
||||
._*
|
||||
|
||||
*~
|
||||
@@ -105,3 +104,6 @@ yarn.lock
|
||||
|
||||
/build2
|
||||
/build*
|
||||
/assets/test
|
||||
/tools_old
|
||||
/assets/test.png
|
||||
+63
-146
@@ -4,13 +4,20 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Setup
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
# set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
|
||||
|
||||
option(ENABLE_TESTS "Enable tests" OFF)
|
||||
option(DUSK_BUILD_TESTS "Enable tests" OFF)
|
||||
|
||||
set(DUSK_GAME_NAME "Dusk" CACHE STRING "Game display name")
|
||||
set(DUSK_GAME_AUTHOR "YourWishes" CACHE STRING "Game author / coder")
|
||||
set(DUSK_GAME_SHORT_DESCRIPTION "Dusk game" CACHE STRING "One-line description")
|
||||
set(DUSK_GAME_LONG_DESCRIPTION "No description yet." CACHE STRING "Full description")
|
||||
|
||||
# Prep cache
|
||||
set(DUSK_CACHE_TARGET "dusk-target")
|
||||
@@ -30,184 +37,94 @@ set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET}
|
||||
set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
set(DUSK_LIBRARY_TARGET_NAME "DuskCore" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
set(DUSK_BINARY_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
|
||||
# Create directories
|
||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||
|
||||
# Find packages
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
# Set target system
|
||||
# message(FATAL_ERROR "DISABLED FOR NOW2 ${DUSK_TARGET_SYSTEM}")
|
||||
set(DUSK_ASSETS_ZIP "${DUSK_BUILD_DIR}/dusk.dsk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "linux")
|
||||
# set(DUSK_TARGET_SYSTEM "psp")
|
||||
endif()
|
||||
|
||||
# Toolchains
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
find_package(pspsdk REQUIRED)
|
||||
endif()
|
||||
# Create directories
|
||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||
file(MAKE_DIRECTORY ${DUSK_TEMP_DIR})
|
||||
file(MAKE_DIRECTORY ${DUSK_BUILT_ASSETS_DIR})
|
||||
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
# Override to make library and binary be the same.
|
||||
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}.elf" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
endif()
|
||||
# Required build packages
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
# Init Project.
|
||||
project(${DUSK_LIBRARY_TARGET_NAME}
|
||||
VERSION 1.0.0
|
||||
LANGUAGES C CXX
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
# Either, create library and binary separately (used for tests), or make them
|
||||
# one in the same so all code is in the binary.
|
||||
if(ENABLE_TESTS)
|
||||
# one in the same so all code is in the binary only.
|
||||
# Binary Executable
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/dusk/null.c)
|
||||
|
||||
if(DUSK_BUILD_TESTS)
|
||||
# MainLibrary
|
||||
add_library(${DUSK_LIBRARY_TARGET_NAME} STATIC)
|
||||
|
||||
# Binary Executable
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
||||
|
||||
# Link library to binary
|
||||
target_link_libraries(${DUSK_BINARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
else()
|
||||
set(DUSK_BINARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
||||
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_BINARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED DUSK_VERSION)
|
||||
string(TIMESTAMP DUSK_VERSION "debug-%y%m%d%H%M%S")
|
||||
endif()
|
||||
|
||||
# Definitions
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
DUSK_TARGET_SYSTEM="${DUSK_TARGET_SYSTEM}"
|
||||
DUSK_GAME_NAME="${DUSK_GAME_NAME}"
|
||||
DUSK_GAME_AUTHOR="${DUSK_GAME_AUTHOR}"
|
||||
DUSK_GAME_SHORT_DESCRIPTION="${DUSK_GAME_SHORT_DESCRIPTION}"
|
||||
DUSK_GAME_LONG_DESCRIPTION="${DUSK_GAME_LONG_DESCRIPTION}"
|
||||
DUSK_VERSION="${DUSK_VERSION}"
|
||||
)
|
||||
|
||||
# Toolchains
|
||||
include(cmake/targets/${DUSK_TARGET_SYSTEM}.cmake)
|
||||
|
||||
# Add tools
|
||||
add_subdirectory(tools)
|
||||
|
||||
# Assets
|
||||
add_subdirectory(assets)
|
||||
|
||||
# Add libraries
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
GL
|
||||
m
|
||||
# Include generated headers from tools.
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${DUSK_GENERATED_HEADERS_DIR}
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${SDL2_LIBRARIES}
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
zip
|
||||
bz2
|
||||
z
|
||||
mbedtls
|
||||
mbedcrypto
|
||||
lzma
|
||||
m
|
||||
)
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
configure_file(opengl.pc.in opengl.pc @ONLY)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(zip IMPORTED_TARGET libzip)
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DOLPHIN
|
||||
)
|
||||
|
||||
# Custom flags for cglm
|
||||
set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE)
|
||||
set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE)
|
||||
find_package(cglm REQUIRED)
|
||||
|
||||
# Compile lua
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
liblua
|
||||
URL https://www.lua.org/ftp/lua-5.5.0.tar.gz
|
||||
)
|
||||
FetchContent_MakeAvailable(liblua)
|
||||
set(LUA_SRC_DIR "${liblua_SOURCE_DIR}/src")
|
||||
set(LUA_C_FILES
|
||||
lapi.c lauxlib.c lbaselib.c lcode.c lcorolib.c lctype.c ldblib.c ldebug.c
|
||||
ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c
|
||||
loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c
|
||||
lstrlib.c ltable.c ltablib.c ltm.c lundump.c lutf8lib.c lvm.c lzio.c
|
||||
)
|
||||
list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/")
|
||||
add_library(liblua STATIC ${LUA_C_FILES})
|
||||
target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}")
|
||||
target_compile_definitions(liblua PRIVATE LUA_USE_C89)
|
||||
add_library(lua::lua ALIAS liblua)
|
||||
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
|
||||
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
cglm
|
||||
liblua
|
||||
m
|
||||
fat
|
||||
PkgConfig::zip
|
||||
)
|
||||
endif()
|
||||
|
||||
# Force turn tests off for now
|
||||
set(ENABLE_TESTS OFF CACHE BOOL "Enable tests" FORCE)
|
||||
|
||||
# Add code
|
||||
# Add main code
|
||||
add_subdirectory(${DUSK_SOURCES_DIR})
|
||||
|
||||
# Handle tests
|
||||
if(ENABLE_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Build assets
|
||||
dusk_run_python(
|
||||
DUSK_ASSETS_BUILT
|
||||
tools.asset.bundle
|
||||
--assets ${DUSK_ASSETS_DIR}
|
||||
--output-assets ${DUSK_BUILT_ASSETS_DIR}
|
||||
--output-file ${DUSK_BUILD_DIR}/dusk.dsk
|
||||
--headers-dir ${DUSK_GENERATED_HEADERS_DIR}
|
||||
--input ${DUSK_ASSETS}
|
||||
)
|
||||
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||
|
||||
# Include generated headers
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${DUSK_GENERATED_HEADERS_DIR}
|
||||
)
|
||||
|
||||
# Postbuild
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
create_pbp_file(
|
||||
TARGET "${DUSK_BINARY_TARGET_NAME}"
|
||||
ICON_PATH NULL
|
||||
BACKGROUND_PATH NULL
|
||||
PREVIEW_PATH NULL
|
||||
TITLE "${DUSK_BINARY_TARGET_NAME}"
|
||||
PSAR_PATH ${DUSK_BUILD_DIR}/dusk.dsk
|
||||
VERSION 01.00
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
set(DUSK_BINARY_TARGET_NAME_DOL "${DUSK_BUILD_DIR}/Dusk.dol")
|
||||
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||
COMMAND elf2dol
|
||||
"$<TARGET_FILE:${DUSK_BINARY_TARGET_NAME}>"
|
||||
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||
COMMENT "Generating ${DUSK_BINARY_TARGET_NAME_DOL} from ${DUSK_BINARY_TARGET_NAME}"
|
||||
)
|
||||
# Handle tests
|
||||
if(DUSK_BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Build assets
|
||||
file(GLOB_RECURSE DUSK_ASSET_FILES CONFIGURE_DEPENDS "${DUSK_ASSETS_DIR}/*")
|
||||
add_custom_command(
|
||||
OUTPUT "${DUSK_ASSETS_ZIP}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${DUSK_ASSETS_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f "${DUSK_ASSETS_ZIP}"
|
||||
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${DUSK_ASSETS_ZIP}" --format=zip -- .
|
||||
WORKING_DIRECTORY "${DUSK_ASSETS_DIR}"
|
||||
DEPENDS ${DUSK_ASSET_FILES}
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(DUSK_ASSETS_BUILT DEPENDS "${DUSK_ASSETS_ZIP}")
|
||||
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Dusk
|
||||
RPG Game Project, small and able to run on a PSP.
|
||||
# Documentation
|
||||
- [Scripting](docs/SCRIPTING.md) — writing gameplay logic in JavaScript.
|
||||
- [UI](docs/UI.md) — building buttons/menus/etc from engine/game C code.
|
||||
|
||||
# Building
|
||||
Each build target has different requirements. You can take a look at the git
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
#include "debug/debug.h"
|
||||
#include "assert/assert.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
|
||||
int moduleMapLoad(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
if(!lua_isstring(L, 1)) {
|
||||
luaL_error(L, "Expected string map filename");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Potentially provide up to 3 params
|
||||
chunkpos_t initial = { .x = 0, .y = 0, .z = 0 };
|
||||
if(lua_isnumber(L, 2)) {
|
||||
initial.x = (chunkunit_t)luaL_checkinteger(L, 2);
|
||||
}
|
||||
if(lua_isnumber(L, 3)) {
|
||||
initial.y = (chunkunit_t)luaL_checkinteger(L, 3);
|
||||
}
|
||||
if(lua_isnumber(L, 4)) {
|
||||
initial.z = (chunkunit_t)luaL_checkinteger(L, 4);
|
||||
}
|
||||
|
||||
// Load the map.
|
||||
errorret_t ret = mapLoad(luaL_checkstring(L, 1), initial);
|
||||
if(ret.code != ERROR_OK) {
|
||||
luaL_error(L, "Failed to load map");
|
||||
errorCatch(errorPrint(ret));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void moduleMapSystem(scriptcontext_t *context) {
|
||||
assertNotNull(context, "Script context cannot be NULL");
|
||||
|
||||
lua_register(context->luaState, "mapLoad", moduleMapLoad);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
rpg.c
|
||||
rpgcamera.c
|
||||
rpgtextbox.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(cutscene)
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(overworld)
|
||||
@@ -1,14 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
cutscenesystem.c
|
||||
cutscenemode.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(item)
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
|
||||
typedef struct cutscene_s {
|
||||
const cutsceneitem_t *items;
|
||||
uint8_t itemCount;
|
||||
} cutscene_t;
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
|
||||
bool_t cutsceneModeIsInputAllowed() {
|
||||
switch(CUTSCENE_SYSTEM.mode) {
|
||||
case CUTSCENE_MODE_FULL_FREEZE:
|
||||
case CUTSCENE_MODE_INPUT_FREEZE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef enum {
|
||||
CUTSCENE_MODE_NONE,
|
||||
CUTSCENE_MODE_FULL_FREEZE,
|
||||
CUTSCENE_MODE_INPUT_FREEZE,
|
||||
CUTSCENE_MODE_GAMEPLAY
|
||||
} cutscenemode_t;
|
||||
|
||||
// Default mode for all cutscenes.
|
||||
#define CUTSCENE_MODE_INITIAL CUTSCENE_MODE_INPUT_FREEZE
|
||||
|
||||
/**
|
||||
* Check if input is allowed in the current cutscene mode.
|
||||
*
|
||||
* @return true if input is allowed, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneModeIsInputAllowed();
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenesystem.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
cutscenesystem_t CUTSCENE_SYSTEM;
|
||||
|
||||
void cutsceneSystemInit() {
|
||||
memoryZero(&CUTSCENE_SYSTEM, sizeof(cutscenesystem_t));
|
||||
}
|
||||
|
||||
void cutsceneSystemStartCutscene(const cutscene_t *cutscene) {
|
||||
CUTSCENE_SYSTEM.scene = cutscene;
|
||||
CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_INITIAL;
|
||||
CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so start wraps.
|
||||
cutsceneSystemNext();
|
||||
}
|
||||
|
||||
void cutsceneSystemUpdate() {
|
||||
if(CUTSCENE_SYSTEM.scene == NULL) return;
|
||||
|
||||
const cutsceneitem_t *item = cutsceneSystemGetCurrentItem();
|
||||
cutsceneItemUpdate(item, &CUTSCENE_SYSTEM.data);
|
||||
}
|
||||
|
||||
void cutsceneSystemNext() {
|
||||
if(CUTSCENE_SYSTEM.scene == NULL) return;
|
||||
|
||||
CUTSCENE_SYSTEM.currentItem++;
|
||||
|
||||
// End of the cutscene?
|
||||
if(
|
||||
CUTSCENE_SYSTEM.currentItem >= CUTSCENE_SYSTEM.scene->itemCount
|
||||
) {
|
||||
CUTSCENE_SYSTEM.scene = NULL;
|
||||
CUTSCENE_SYSTEM.currentItem = 0xFF;
|
||||
CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start item.
|
||||
const cutsceneitem_t *item = cutsceneSystemGetCurrentItem();
|
||||
memset(&CUTSCENE_SYSTEM.data, 0, sizeof(CUTSCENE_SYSTEM.data));
|
||||
cutsceneItemStart(item, &CUTSCENE_SYSTEM.data);
|
||||
}
|
||||
|
||||
const cutsceneitem_t * cutsceneSystemGetCurrentItem() {
|
||||
if(CUTSCENE_SYSTEM.scene == NULL) return NULL;
|
||||
|
||||
return &CUTSCENE_SYSTEM.scene->items[CUTSCENE_SYSTEM.currentItem];
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "cutscene.h"
|
||||
#include "cutscenemode.h"
|
||||
|
||||
typedef struct {
|
||||
const cutscene_t *scene;
|
||||
uint8_t currentItem;
|
||||
|
||||
// Data (used by the current item).
|
||||
cutsceneitemdata_t data;
|
||||
cutscenemode_t mode;
|
||||
} cutscenesystem_t;
|
||||
|
||||
extern cutscenesystem_t CUTSCENE_SYSTEM;
|
||||
|
||||
/**
|
||||
* Initialize the cutscene system.
|
||||
*/
|
||||
void cutsceneSystemInit();
|
||||
|
||||
/**
|
||||
* Start a cutscene.
|
||||
*
|
||||
* @param cutscene Pointer to the cutscene to start.
|
||||
*/
|
||||
void cutsceneSystemStartCutscene(const cutscene_t *cutscene);
|
||||
|
||||
/**
|
||||
* Advance to the next item in the cutscene.
|
||||
*/
|
||||
void cutsceneSystemNext();
|
||||
|
||||
/**
|
||||
* Update the cutscene system for one frame.
|
||||
*/
|
||||
void cutsceneSystemUpdate();
|
||||
|
||||
/**
|
||||
* Get the current cutscene item.
|
||||
*
|
||||
* @return Pointer to the current cutscene item.
|
||||
*/
|
||||
const cutsceneitem_t * cutsceneSystemGetCurrentItem();
|
||||
@@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
cutsceneitem.c
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef void (*cutscenecallback_t)(void);
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "input/input.h"
|
||||
#include "time/time.h"
|
||||
|
||||
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
switch(item->type) {
|
||||
case CUTSCENE_ITEM_TYPE_TEXT: {
|
||||
rpgTextboxShow(
|
||||
item->text.position,
|
||||
item->text.text
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_WAIT:
|
||||
data->wait = item->wait;
|
||||
break;
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_CALLBACK:
|
||||
if(item->callback != NULL) item->callback();
|
||||
break;
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_CUTSCENE:
|
||||
if(item->cutscene != NULL) cutsceneSystemStartCutscene(item->cutscene);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
switch(item->type) {
|
||||
case CUTSCENE_ITEM_TYPE_TEXT:
|
||||
if(rpgTextboxIsVisible()) return;
|
||||
cutsceneSystemNext();
|
||||
break;
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_WAIT:
|
||||
data->wait -= TIME.delta;
|
||||
if(data->wait <= 0) cutsceneSystemNext();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "cutscenewait.h"
|
||||
#include "cutscenecallback.h"
|
||||
#include "cutscenetext.h"
|
||||
|
||||
typedef struct cutscene_s cutscene_t;
|
||||
|
||||
typedef enum {
|
||||
CUTSCENE_ITEM_TYPE_NULL,
|
||||
CUTSCENE_ITEM_TYPE_TEXT,
|
||||
CUTSCENE_ITEM_TYPE_CALLBACK,
|
||||
CUTSCENE_ITEM_TYPE_WAIT,
|
||||
CUTSCENE_ITEM_TYPE_CUTSCENE
|
||||
} cutsceneitemtype_t;
|
||||
|
||||
typedef struct cutsceneitem_s {
|
||||
cutsceneitemtype_t type;
|
||||
|
||||
// Arguments/Data that will be used when this item is invoked.
|
||||
union {
|
||||
cutscenetext_t text;
|
||||
cutscenecallback_t callback;
|
||||
cutscenewait_t wait;
|
||||
const cutscene_t *cutscene;
|
||||
};
|
||||
} cutsceneitem_t;
|
||||
|
||||
typedef union {
|
||||
cutscenewaitdata_t wait;
|
||||
} cutsceneitemdata_t;
|
||||
|
||||
/**
|
||||
* Start the given cutscene item.
|
||||
*
|
||||
* @param item The cutscene item to start.
|
||||
* @param data The cutscene item data storage.
|
||||
*/
|
||||
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data);
|
||||
|
||||
/**
|
||||
* Tick the given cutscene item (one frame).
|
||||
*
|
||||
* @param item The cutscene item to tick.
|
||||
* @param data The cutscene item data storage.
|
||||
*/
|
||||
void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data);
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/rpgtextbox.h"
|
||||
|
||||
typedef struct {
|
||||
char_t text[RPG_TEXTBOX_MAX_CHARS];
|
||||
rpgtextboxpos_t position;
|
||||
} cutscenetext_t;
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef float_t cutscenewait_t;
|
||||
typedef float_t cutscenewaitdata_t;
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
|
||||
static const cutsceneitem_t TEST_CUTSCENE_ONE_ITEMS[] = {
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "This is a test cutscene.", .position = RPG_TEXTBOX_POS_BOTTOM } },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 2.0f },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "It has multiple lines of text.\nAnd waits in between.", .position = RPG_TEXTBOX_POS_TOP } },
|
||||
};
|
||||
|
||||
static const cutscene_t TEST_CUTSCENE_ONE = {
|
||||
.items = TEST_CUTSCENE_ONE_ITEMS,
|
||||
.itemCount = sizeof(TEST_CUTSCENE_ONE_ITEMS) / sizeof(cutsceneitem_t)
|
||||
};
|
||||
|
||||
static const cutsceneitem_t TEST_CUTSCENE_TWO_ITEMS[] = {
|
||||
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 1.0f },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE },
|
||||
};
|
||||
|
||||
static const cutscene_t TEST_CUTSCENE = {
|
||||
.items = TEST_CUTSCENE_TWO_ITEMS,
|
||||
.itemCount = sizeof(TEST_CUTSCENE_TWO_ITEMS) / sizeof(cutsceneitem_t)
|
||||
};
|
||||
@@ -1,200 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "time/time.h"
|
||||
#include "util/math.h"
|
||||
#include "rpg/cutscene/cutscenemode.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
|
||||
entity_t ENTITIES[ENTITY_COUNT];
|
||||
|
||||
void entityInit(entity_t *entity, const entitytype_t type) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
||||
assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
|
||||
assertTrue(
|
||||
entity >= ENTITIES && entity < ENTITIES + ENTITY_COUNT,
|
||||
"Entity pointer is out of bounds"
|
||||
);
|
||||
|
||||
memoryZero(entity, sizeof(entity_t));
|
||||
entity->id = (uint8_t)(entity - ENTITIES);
|
||||
entity->type = type;
|
||||
|
||||
if(ENTITY_CALLBACKS[type].init != NULL) ENTITY_CALLBACKS[type].init(entity);
|
||||
}
|
||||
|
||||
void entityUpdate(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
||||
assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
|
||||
|
||||
// What state is the entity in?
|
||||
if(entity->animation != ENTITY_ANIM_IDLE) {
|
||||
// Entity is mid animation, tick it (down).
|
||||
entity->animTime -= TIME.delta;
|
||||
if(entity->animTime <= 0) {
|
||||
entity->animation = ENTITY_ANIM_IDLE;
|
||||
entity->animTime = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Movement code.
|
||||
if(
|
||||
cutsceneModeIsInputAllowed() &&
|
||||
ENTITY_CALLBACKS[entity->type].movement != NULL
|
||||
) {
|
||||
ENTITY_CALLBACKS[entity->type].movement(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void entityTurn(entity_t *entity, const entitydir_t direction) {
|
||||
entity->direction = direction;
|
||||
entity->animation = ENTITY_ANIM_TURN;
|
||||
entity->animTime = ENTITY_ANIM_TURN_DURATION;
|
||||
}
|
||||
|
||||
void entityWalk(entity_t *entity, const entitydir_t direction) {
|
||||
// TODO: Animation, delay, etc.
|
||||
entity->direction = direction;
|
||||
|
||||
// Where are we moving?
|
||||
worldpos_t newPos = entity->position;
|
||||
{
|
||||
worldunits_t relX, relY;
|
||||
entityDirGetRelative(direction, &relX, &relY);
|
||||
newPos.x += relX;
|
||||
newPos.y += relY;
|
||||
}
|
||||
|
||||
// Get tile under foot
|
||||
tile_t tileCurrent = mapGetTile(entity->position);
|
||||
tile_t tileNew = mapGetTile(newPos);
|
||||
bool_t fall = false;
|
||||
bool_t raise = false;
|
||||
|
||||
// Are we walking up a ramp?
|
||||
if(
|
||||
tileIsRamp(tileCurrent) &&
|
||||
(
|
||||
// Can only walk UP the direction the ramp faces.
|
||||
(direction+TILE_SHAPE_RAMP_SOUTH) == tileCurrent ||
|
||||
// If diagonal ramp, can go up one of two ways only.
|
||||
(
|
||||
(
|
||||
tileCurrent == TILE_SHAPE_RAMP_SOUTHEAST &&
|
||||
(direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_EAST)
|
||||
) ||
|
||||
(
|
||||
tileCurrent == TILE_SHAPE_RAMP_SOUTHWEST &&
|
||||
(direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_WEST)
|
||||
) ||
|
||||
(
|
||||
tileCurrent == TILE_SHAPE_RAMP_NORTHEAST &&
|
||||
(direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_EAST)
|
||||
) ||
|
||||
(
|
||||
tileCurrent == TILE_SHAPE_RAMP_NORTHWEST &&
|
||||
(direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_WEST)
|
||||
)
|
||||
)
|
||||
// Must be able to walk up.
|
||||
)
|
||||
) {
|
||||
tileNew = TILE_SHAPE_NULL;// Force check for ramp above.
|
||||
worldpos_t abovePos = newPos;
|
||||
abovePos.z += 1;
|
||||
tile_t tileAbove = mapGetTile(abovePos);
|
||||
|
||||
if(tileAbove != TILE_SHAPE_NULL && tileIsWalkable(tileAbove)) {
|
||||
// We can go up the ramp.
|
||||
raise = true;
|
||||
}
|
||||
} else if(tileNew == TILE_SHAPE_NULL && newPos.z > 0) {
|
||||
// Falling down?
|
||||
worldpos_t belowPos = newPos;
|
||||
belowPos.z -= 1;
|
||||
tile_t tileBelow = mapGetTile(belowPos);
|
||||
if(
|
||||
tileBelow != TILE_SHAPE_NULL &&
|
||||
tileIsRamp(tileBelow) &&
|
||||
(
|
||||
// This handles regular cardinal ramps
|
||||
(entityDirGetOpposite(direction)+TILE_SHAPE_RAMP_SOUTH) == tileBelow ||
|
||||
// This handles diagonal ramps
|
||||
(
|
||||
(
|
||||
tileBelow == TILE_SHAPE_RAMP_SOUTHEAST &&
|
||||
(direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_WEST)
|
||||
) ||
|
||||
(
|
||||
tileBelow == TILE_SHAPE_RAMP_SOUTHWEST &&
|
||||
(direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_EAST)
|
||||
) ||
|
||||
(
|
||||
tileBelow == TILE_SHAPE_RAMP_NORTHEAST &&
|
||||
(direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_WEST)
|
||||
) ||
|
||||
(
|
||||
tileBelow == TILE_SHAPE_RAMP_NORTHWEST &&
|
||||
(direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_EAST)
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
// We will fall to this tile.
|
||||
fall = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Can we walk here?
|
||||
if(!raise && !fall && !tileIsWalkable(tileNew)) return;// Blocked
|
||||
|
||||
// Entity in way?
|
||||
entity_t *other = ENTITIES;
|
||||
do {
|
||||
if(other == entity) continue;
|
||||
if(other->type == ENTITY_TYPE_NULL) continue;
|
||||
if(!worldPosIsEqual(other->position, newPos)) continue;
|
||||
return;// Blocked
|
||||
} while(++other, other < &ENTITIES[ENTITY_COUNT]);
|
||||
|
||||
entity->lastPosition = entity->position;
|
||||
entity->position = newPos;
|
||||
entity->animation = ENTITY_ANIM_WALK;
|
||||
entity->animTime = ENTITY_ANIM_WALK_DURATION;// TODO: Running vs walking
|
||||
|
||||
if(raise) {
|
||||
entity->position.z += 1;
|
||||
} else if(fall) {
|
||||
entity->position.z -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
entity_t * entityGetAt(const worldpos_t position) {
|
||||
entity_t *ent = ENTITIES;
|
||||
do {
|
||||
if(ent->type == ENTITY_TYPE_NULL) continue;
|
||||
if(!worldPosIsEqual(ent->position, position)) continue;
|
||||
return ent;
|
||||
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t entityGetAvailable() {
|
||||
entity_t *ent = ENTITIES;
|
||||
do {
|
||||
if(ent->type == ENTITY_TYPE_NULL) return ent - ENTITIES;
|
||||
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitydir.h"
|
||||
#include "entityanim.h"
|
||||
#include "entitytype.h"
|
||||
#include "npc.h"
|
||||
|
||||
typedef struct map_s map_t;
|
||||
|
||||
typedef struct entity_s {
|
||||
uint8_t id;
|
||||
entitytype_t type;
|
||||
entitytypedata_t data;
|
||||
|
||||
// Movement
|
||||
entitydir_t direction;
|
||||
worldpos_t position;
|
||||
worldpos_t lastPosition;
|
||||
|
||||
entityanim_t animation;
|
||||
float_t animTime;
|
||||
} entity_t;
|
||||
|
||||
extern entity_t ENTITIES[ENTITY_COUNT];
|
||||
|
||||
/**
|
||||
* Initializes an entity structure.
|
||||
*
|
||||
* @param entity Pointer to the entity structure to initialize.
|
||||
* @param type The type of the entity.
|
||||
*/
|
||||
void entityInit(entity_t *entity, const entitytype_t type);
|
||||
|
||||
/**
|
||||
* Updates an entity.
|
||||
*
|
||||
* @param entity Pointer to the entity structure to update.
|
||||
*/
|
||||
void entityUpdate(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Turn an entity to face a new direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to turn.
|
||||
* @param direction The direction to face.
|
||||
*/
|
||||
void entityTurn(entity_t *entity, const entitydir_t direction);
|
||||
|
||||
/**
|
||||
* Make an entity walk in a direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to make walk.
|
||||
* @param direction The direction to walk in.
|
||||
*/
|
||||
void entityWalk(entity_t *entity, const entitydir_t direction);
|
||||
|
||||
/**
|
||||
* Gets the entity at a specific world position.
|
||||
*
|
||||
* @param map Pointer to the map to check.
|
||||
* @param pos The world position to check.
|
||||
* @return Pointer to the entity at the position, or NULL if none.
|
||||
*/
|
||||
entity_t *entityGetAt(const worldpos_t pos);
|
||||
|
||||
/**
|
||||
* Gets an available entity index.
|
||||
*
|
||||
* @return The index of an available entity, or 0xFF if none are available.
|
||||
*/
|
||||
uint8_t entityGetAvailable();
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define ENTITY_ANIM_TURN_DURATION 0.06f
|
||||
#define ENTITY_ANIM_WALK_DURATION 0.1f
|
||||
|
||||
typedef enum {
|
||||
ENTITY_ANIM_IDLE,
|
||||
ENTITY_ANIM_TURN,
|
||||
ENTITY_ANIM_WALK,
|
||||
} entityanim_t;
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitydir.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
entitydir_t entityDirGetOpposite(const entitydir_t dir) {
|
||||
switch(dir) {
|
||||
case ENTITY_DIR_NORTH: return ENTITY_DIR_SOUTH;
|
||||
case ENTITY_DIR_SOUTH: return ENTITY_DIR_NORTH;
|
||||
case ENTITY_DIR_EAST: return ENTITY_DIR_WEST;
|
||||
case ENTITY_DIR_WEST: return ENTITY_DIR_EAST;
|
||||
default: return dir;
|
||||
}
|
||||
}
|
||||
|
||||
void entityDirGetRelative(
|
||||
const entitydir_t from,
|
||||
worldunits_t *outX,
|
||||
worldunits_t *outY
|
||||
) {
|
||||
assertValidEntityDir(from, "Invalid direction provided");
|
||||
assertNotNull(outX, "Output X pointer cannot be NULL");
|
||||
assertNotNull(outY, "Output Y pointer cannot be NULL");
|
||||
|
||||
switch(from) {
|
||||
case ENTITY_DIR_NORTH:
|
||||
*outX = 0;
|
||||
*outY = -1;
|
||||
break;
|
||||
|
||||
case ENTITY_DIR_EAST:
|
||||
*outX = 1;
|
||||
*outY = 0;
|
||||
break;
|
||||
|
||||
case ENTITY_DIR_SOUTH:
|
||||
*outX = 0;
|
||||
*outY = 1;
|
||||
break;
|
||||
|
||||
case ENTITY_DIR_WEST:
|
||||
*outX = -1;
|
||||
*outY = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
|
||||
typedef enum {
|
||||
ENTITY_DIR_UP = ENTITY_DIR_NORTH,
|
||||
ENTITY_DIR_DOWN = ENTITY_DIR_SOUTH,
|
||||
ENTITY_DIR_LEFT = ENTITY_DIR_WEST,
|
||||
ENTITY_DIR_RIGHT = ENTITY_DIR_EAST,
|
||||
} entitydir_t;
|
||||
|
||||
/**
|
||||
* Gets the opposite direction of a given direction.
|
||||
*
|
||||
* @param dir The direction to get the opposite of.
|
||||
* @return entitydir_t The opposite direction.
|
||||
*/
|
||||
entitydir_t entityDirGetOpposite(const entitydir_t dir);
|
||||
|
||||
/**
|
||||
* Asserts a given direction is valid.
|
||||
*
|
||||
* @param dir The direction to validate.
|
||||
* @param msg The message to display if the assertion fails.
|
||||
*/
|
||||
#define assertValidEntityDir(dir, msg) \
|
||||
assertTrue( \
|
||||
(dir) == ENTITY_DIR_NORTH || \
|
||||
(dir) == ENTITY_DIR_EAST || \
|
||||
(dir) == ENTITY_DIR_SOUTH || \
|
||||
(dir) == ENTITY_DIR_WEST, \
|
||||
msg \
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets the relative x and y offsets for a given direction.
|
||||
*
|
||||
* @param dir The direction to get offsets for.
|
||||
* @param relX Pointer to store the relative x offset.
|
||||
* @param relY Pointer to store the relative y offset.
|
||||
*/
|
||||
void entityDirGetRelative(
|
||||
const entitydir_t dir, worldunits_t *relX, worldunits_t *relY
|
||||
);
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskdefs.h"
|
||||
#include "rpg/entity/player.h"
|
||||
#include "npc.h"
|
||||
|
||||
typedef uint8_t entitytype_t;
|
||||
|
||||
typedef union {
|
||||
player_t player;
|
||||
npc_t npc;
|
||||
} entitytypedata_t;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* Initialization callback for the entity type.
|
||||
* @param entity Pointer to the entity to initialize.
|
||||
*/
|
||||
void (*init)(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Movement callback for the entity type.
|
||||
* @param entity Pointer to the entity to move.
|
||||
*/
|
||||
void (*movement)(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Interaction callback for the entity type.
|
||||
* @param player Pointer to the player entity.
|
||||
* @param entity Pointer to the entity to interact with.
|
||||
* @return True if the entity handled the interaction, false otherwise.
|
||||
*/
|
||||
bool_t (*interact)(entity_t *player, entity_t *entity);
|
||||
} entitycallback_t;
|
||||
|
||||
static const entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
|
||||
[ENTITY_TYPE_NULL] = { NULL },
|
||||
|
||||
[ENTITY_TYPE_PLAYER] = {
|
||||
.init = playerInit,
|
||||
.movement = playerInput
|
||||
},
|
||||
|
||||
[ENTITY_TYPE_NPC] = {
|
||||
.init = npcInit,
|
||||
.movement = npcMovement,
|
||||
.interact = npcInteract
|
||||
}
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "rpg/cutscene/scene/testcutscene.h"
|
||||
#include "rpg/rpgtextbox.h"
|
||||
|
||||
void npcInit(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
}
|
||||
|
||||
void npcMovement(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
}
|
||||
|
||||
bool_t npcInteract(entity_t *player, entity_t *npc) {
|
||||
assertNotNull(player, "Player entity pointer cannot be NULL");
|
||||
assertNotNull(npc, "NPC entity pointer cannot be NULL");
|
||||
|
||||
cutsceneSystemStartCutscene(&TEST_CUTSCENE);
|
||||
|
||||
// rpgTextboxShow(RPG_TEXTBOX_POS_BOTTOM, "Hello World!");
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct entity_s entity_t;
|
||||
|
||||
typedef struct {
|
||||
void *nothing;
|
||||
} npc_t;
|
||||
|
||||
/**
|
||||
* Initializes an NPC entity.
|
||||
*
|
||||
* @param entity Pointer to the entity structure to initialize.
|
||||
*/
|
||||
void npcInit(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Updates an NPC entity.
|
||||
*
|
||||
* @param entity Pointer to the entity structure to update.
|
||||
*/
|
||||
void npcMovement(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Handles interaction with an NPC entity.
|
||||
*
|
||||
* @param player Pointer to the player entity.
|
||||
* @param npc Pointer to the NPC entity.
|
||||
*/
|
||||
bool_t npcInteract(entity_t *player, entity_t *npc);
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
#include "assert/assert.h"
|
||||
#include "rpg/rpgcamera.h"
|
||||
#include "util/memory.h"
|
||||
#include "time/time.h"
|
||||
|
||||
void playerInit(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
}
|
||||
|
||||
void playerInput(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
|
||||
// Turn
|
||||
const playerinputdirmap_t *dirMap = PLAYER_INPUT_DIR_MAP;
|
||||
do {
|
||||
if(!inputIsDown(dirMap->action)) continue;
|
||||
if(entity->direction == dirMap->direction) continue;
|
||||
return entityTurn(entity, dirMap->direction);
|
||||
} while((++dirMap)->action != 0xFF);
|
||||
|
||||
// Walk
|
||||
dirMap = PLAYER_INPUT_DIR_MAP;
|
||||
do {
|
||||
if(!inputIsDown(dirMap->action)) continue;
|
||||
if(entity->direction != dirMap->direction) continue;
|
||||
return entityWalk(entity, dirMap->direction);
|
||||
} while((++dirMap)->action != 0xFF);
|
||||
|
||||
// Interaction
|
||||
if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
||||
worldunit_t x, y, z;
|
||||
{
|
||||
worldunits_t relX, relY;
|
||||
entityDirGetRelative(entity->direction, &relX, &relY);
|
||||
x = entity->position.x + relX;
|
||||
y = entity->position.y + relY;
|
||||
z = entity->position.z;
|
||||
}
|
||||
|
||||
entity_t *interact = entityGetAt((worldpos_t){ x, y, z });
|
||||
if(interact != NULL && ENTITY_CALLBACKS[interact->type].interact != NULL) {
|
||||
if(ENTITY_CALLBACKS[interact->type].interact(entity, interact)) return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "input/input.h"
|
||||
|
||||
typedef struct entity_s entity_t;
|
||||
|
||||
typedef struct {
|
||||
void *nothing;
|
||||
} player_t;
|
||||
|
||||
typedef struct {
|
||||
inputaction_t action;
|
||||
entitydir_t direction;
|
||||
} playerinputdirmap_t;
|
||||
|
||||
static const playerinputdirmap_t PLAYER_INPUT_DIR_MAP[] = {
|
||||
{ INPUT_ACTION_UP, ENTITY_DIR_NORTH },
|
||||
{ INPUT_ACTION_DOWN, ENTITY_DIR_SOUTH },
|
||||
{ INPUT_ACTION_LEFT, ENTITY_DIR_WEST },
|
||||
{ INPUT_ACTION_RIGHT, ENTITY_DIR_EAST },
|
||||
|
||||
{ 0xFF, 0xFF }
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a player entity.
|
||||
*
|
||||
* @param entity Pointer to the entity structure to initialize.
|
||||
*/
|
||||
void playerInit(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Handles movement logic for the player entity.
|
||||
*
|
||||
* @param entity Pointer to the player entity structure.
|
||||
*/
|
||||
void playerInput(entity_t *entity);
|
||||
@@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
chunk.c
|
||||
map.c
|
||||
worldpos.c
|
||||
tile.c
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
uint32_t chunkGetTileIndex(const chunkpos_t position) {
|
||||
return (
|
||||
(position.z * CHUNK_WIDTH * CHUNK_HEIGHT) +
|
||||
(position.y * CHUNK_WIDTH) +
|
||||
position.x
|
||||
);
|
||||
}
|
||||
|
||||
bool_t chunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b) {
|
||||
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/tile.h"
|
||||
#include "worldpos.h"
|
||||
#include "display/mesh/quad.h"
|
||||
|
||||
typedef struct chunk_s {
|
||||
chunkpos_t position;
|
||||
tile_t tiles[CHUNK_TILE_COUNT];
|
||||
|
||||
uint8_t meshCount;
|
||||
meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX];
|
||||
mesh_t meshes[CHUNK_MESH_COUNT_MAX];
|
||||
uint8_t entities[CHUNK_ENTITY_COUNT_MAX];
|
||||
} chunk_t;
|
||||
|
||||
/**
|
||||
* Gets the tile index for a tile position within a chunk.
|
||||
*
|
||||
* @param position The position within the chunk.
|
||||
* @return The tile index within the chunk.
|
||||
*/
|
||||
uint32_t chunkGetTileIndex(const chunkpos_t position);
|
||||
|
||||
/**
|
||||
* Checks if two chunk positions are equal.
|
||||
*
|
||||
* @param a The first chunk position.
|
||||
* @param b The second chunk position.
|
||||
* @return true if equal, false otherwise.
|
||||
*/
|
||||
bool_t chunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b);
|
||||
@@ -1,269 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "map.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/asset.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "util/string.h"
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
map_t MAP;
|
||||
|
||||
errorret_t mapInit() {
|
||||
memoryZero(&MAP, sizeof(map_t));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t mapIsLoaded() {
|
||||
return MAP.filePath[0] != '\0';
|
||||
}
|
||||
|
||||
errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
||||
assertStrLenMin(path, 1, "Map file path cannot be empty");
|
||||
assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long");
|
||||
|
||||
if(stringCompare(MAP.filePath, path) == 0) {
|
||||
// Same map, no need to reload
|
||||
errorOk();
|
||||
}
|
||||
|
||||
chunkindex_t i;
|
||||
|
||||
// Unload all loaded chunks
|
||||
if(mapIsLoaded()) {
|
||||
for(i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkUnload(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the map file path
|
||||
stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX);
|
||||
|
||||
// Determine directory path (it is dirname)
|
||||
stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX);
|
||||
char_t *last = stringFindLastChar(MAP.dirPath, '/');
|
||||
if(last == NULL) errorThrow("Invalid map file path");
|
||||
|
||||
// Store filename, sans extension
|
||||
stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX);
|
||||
*last = '\0'; // Terminate to get directory path
|
||||
|
||||
last = stringFindLastChar(MAP.fileName, '.');
|
||||
if(last == NULL) errorThrow("Map file name has no extension");
|
||||
*last = '\0'; // Terminate to remove extension
|
||||
|
||||
// Reset map position
|
||||
MAP.chunkPosition = position;
|
||||
|
||||
// Perform "initial load"
|
||||
i = 0;
|
||||
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
||||
for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
||||
chunk_t *chunk = &MAP.chunks[i];
|
||||
chunk->position.x = x + position.x;
|
||||
chunk->position.y = y + position.y;
|
||||
chunk->position.z = z + position.z;
|
||||
MAP.chunkOrder[i] = chunk;
|
||||
errorChain(mapChunkLoad(chunk));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute map script.
|
||||
char_t scriptPath[MAP_FILE_PATH_MAX + 16];
|
||||
stringFormat(
|
||||
scriptPath, sizeof(scriptPath), "%s/%s.dsf",
|
||||
MAP.dirPath, MAP.fileName
|
||||
);
|
||||
if(assetFileExists(scriptPath)) {
|
||||
scriptcontext_t ctx;
|
||||
errorChain(scriptContextInit(&ctx));
|
||||
errorChain(scriptContextExecFile(&ctx, scriptPath));
|
||||
scriptContextDispose(&ctx);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
const chunkpos_t curPos = MAP.chunkPosition;
|
||||
if(chunkPositionIsEqual(curPos, newPos)) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Determine which chunks remain loaded
|
||||
chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0};
|
||||
chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0};
|
||||
|
||||
uint32_t remainingCount = 0;
|
||||
uint32_t freedCount = 0;
|
||||
|
||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
// Will this chunk remain loaded?
|
||||
chunk_t *chunk = &MAP.chunks[i];
|
||||
if(
|
||||
chunk->position.x >= newPos.x &&
|
||||
chunk->position.x < newPos.x + MAP_CHUNK_WIDTH &&
|
||||
|
||||
chunk->position.y >= newPos.y &&
|
||||
chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT &&
|
||||
|
||||
chunk->position.z >= newPos.z &&
|
||||
chunk->position.z < newPos.z + MAP_CHUNK_DEPTH
|
||||
) {
|
||||
// Stays loaded
|
||||
chunksRemaining[remainingCount++] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not remaining loaded
|
||||
chunksFreed[freedCount++] = i;
|
||||
}
|
||||
|
||||
// Unload the freed chunks
|
||||
for(chunkindex_t i = 0; i < freedCount; i++) {
|
||||
chunk_t *chunk = &MAP.chunks[chunksFreed[i]];
|
||||
mapChunkUnload(chunk);
|
||||
}
|
||||
|
||||
// This can probably be optimized later, for now we check each chunk and see
|
||||
// if it needs loading or not, and update the chunk order
|
||||
chunkindex_t orderIndex = 0;
|
||||
for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) {
|
||||
for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) {
|
||||
for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) {
|
||||
const chunkpos_t newChunkPos = {
|
||||
newPos.x + xOff, newPos.y + yOff, newPos.z + zOff
|
||||
};
|
||||
|
||||
// Is this chunk already loaded (was not unloaded earlier)?
|
||||
chunkindex_t chunkIndex = -1;
|
||||
for(chunkindex_t i = 0; i < remainingCount; i++) {
|
||||
chunk_t *chunk = &MAP.chunks[chunksRemaining[i]];
|
||||
if(!chunkPositionIsEqual(chunk->position, newChunkPos)) continue;
|
||||
chunkIndex = chunksRemaining[i];
|
||||
break;
|
||||
}
|
||||
|
||||
// Need to load this chunk
|
||||
if(chunkIndex == -1) {
|
||||
// Find a freed chunk to reuse
|
||||
chunkIndex = chunksFreed[--freedCount];
|
||||
chunk_t *chunk = &MAP.chunks[chunkIndex];
|
||||
chunk->position = newChunkPos;
|
||||
errorChain(mapChunkLoad(chunk));
|
||||
}
|
||||
|
||||
MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update map position
|
||||
MAP.chunkPosition = newPos;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void mapUpdate() {
|
||||
|
||||
}
|
||||
|
||||
void mapDispose() {
|
||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkUnload(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mapChunkUnload(chunk_t* chunk) {
|
||||
for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) {
|
||||
if(chunk->entities[i] == 0xFF) break;
|
||||
entity_t *entity = &ENTITIES[chunk->entities[i]];
|
||||
entity->type = ENTITY_TYPE_NULL;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||
if(chunk->meshes[i].vertexCount == 0) continue;
|
||||
meshDispose(&chunk->meshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
errorret_t mapChunkLoad(chunk_t* chunk) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
char_t buffer[64];
|
||||
|
||||
// TODO: Can probably move this to asset load logic?
|
||||
chunk->meshCount = 0;
|
||||
memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
||||
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||
|
||||
// Get chunk filepath.
|
||||
snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dmc",
|
||||
MAP.dirPath,
|
||||
chunk->position.x,
|
||||
chunk->position.y,
|
||||
chunk->position.z
|
||||
);
|
||||
|
||||
// Chunk available?
|
||||
if(!assetFileExists(buffer)) {
|
||||
memoryZero(chunk->tiles, sizeof(chunk->tiles));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Load.
|
||||
errorChain(assetLoad(buffer, chunk));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) {
|
||||
if(!mapIsLoaded()) return -1;
|
||||
|
||||
chunkpos_t relPos = {
|
||||
position.x - MAP.chunkPosition.x,
|
||||
position.y - MAP.chunkPosition.y,
|
||||
position.z - MAP.chunkPosition.z
|
||||
};
|
||||
|
||||
if(
|
||||
relPos.x < 0 || relPos.y < 0 || relPos.z < 0 ||
|
||||
relPos.x >= MAP_CHUNK_WIDTH ||
|
||||
relPos.y >= MAP_CHUNK_HEIGHT ||
|
||||
relPos.z >= MAP_CHUNK_DEPTH
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return chunkPosToIndex(&relPos);
|
||||
}
|
||||
|
||||
chunk_t* mapGetChunk(const uint8_t index) {
|
||||
if(index >= MAP_CHUNK_COUNT) return NULL;
|
||||
if(!mapIsLoaded()) return NULL;
|
||||
return MAP.chunkOrder[index];
|
||||
}
|
||||
|
||||
tile_t mapGetTile(const worldpos_t position) {
|
||||
if(!mapIsLoaded()) return TILE_SHAPE_NULL;
|
||||
|
||||
chunkpos_t chunkPos;
|
||||
worldPosToChunkPos(&position, &chunkPos);
|
||||
chunkindex_t chunkIndex = mapGetChunkIndexAt(chunkPos);
|
||||
if(chunkIndex == -1) return TILE_SHAPE_NULL;
|
||||
|
||||
chunk_t *chunk = mapGetChunk(chunkIndex);
|
||||
assertNotNull(chunk, "Chunk pointer cannot be NULL");
|
||||
chunktileindex_t tileIndex = worldPosToChunkTileIndex(&position);
|
||||
return chunk->tiles[tileIndex];
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/chunk.h"
|
||||
|
||||
#define MAP_FILE_PATH_MAX 128
|
||||
|
||||
typedef struct map_s {
|
||||
char_t filePath[MAP_FILE_PATH_MAX];
|
||||
char_t dirPath[MAP_FILE_PATH_MAX];
|
||||
char_t fileName[MAP_FILE_PATH_MAX];
|
||||
|
||||
chunk_t chunks[MAP_CHUNK_COUNT];
|
||||
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||
chunkpos_t chunkPosition;
|
||||
} map_t;
|
||||
|
||||
extern map_t MAP;
|
||||
|
||||
/**
|
||||
* Initializes the map.
|
||||
*
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapInit();
|
||||
|
||||
/**
|
||||
* Checks if a map is loaded.
|
||||
*
|
||||
* @return true if a map is loaded, false otherwise.
|
||||
*/
|
||||
bool_t mapIsLoaded();
|
||||
|
||||
/**
|
||||
* Loads a map from the given file path.
|
||||
*
|
||||
* @param path The file path.
|
||||
* @param position The initial chunk position.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapLoad(
|
||||
const char_t *path,
|
||||
const chunkpos_t position
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the map.
|
||||
*/
|
||||
void mapUpdate();
|
||||
|
||||
/**
|
||||
* Disposes of the map.
|
||||
*/
|
||||
void mapDispose();
|
||||
|
||||
/**
|
||||
* Sets the map position and updates chunks accordingly.
|
||||
*
|
||||
* @param newPos The new chunk position.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapPositionSet(const chunkpos_t newPos);
|
||||
|
||||
/**
|
||||
* Unloads a chunk.
|
||||
*
|
||||
* @param chunk The chunk to unload.
|
||||
*/
|
||||
void mapChunkUnload(chunk_t* chunk);
|
||||
|
||||
/**
|
||||
* Loads a chunk.
|
||||
*
|
||||
* @param chunk The chunk to load.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapChunkLoad(chunk_t* chunk);
|
||||
|
||||
/**
|
||||
* Gets the index of a chunk, within the world, at the given position.
|
||||
*
|
||||
* @param position The chunk position.
|
||||
* @return The index of the chunk, or -1 if out of bounds.
|
||||
*/
|
||||
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position);
|
||||
|
||||
/**
|
||||
* Gets a chunk by its index.
|
||||
*
|
||||
* @param chunkIndex The index of the chunk.
|
||||
* @return A pointer to the chunk.
|
||||
*/
|
||||
chunk_t * mapGetChunk(const uint8_t chunkIndex);
|
||||
|
||||
/**
|
||||
* Gets the tile at the given world position.
|
||||
*
|
||||
* @param position The world position.
|
||||
* @return The tile at that position, or TILE_NULL if the chunk is unloaded.
|
||||
*/
|
||||
tile_t mapGetTile(const worldpos_t position);
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "tile.h"
|
||||
|
||||
bool_t tileIsWalkable(const tile_t tile) {
|
||||
switch(tile) {
|
||||
case TILE_SHAPE_NULL:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t tileIsRamp(const tile_t tile) {
|
||||
switch(tile) {
|
||||
case TILE_SHAPE_RAMP_NORTH:
|
||||
case TILE_SHAPE_RAMP_SOUTH:
|
||||
case TILE_SHAPE_RAMP_EAST:
|
||||
case TILE_SHAPE_RAMP_WEST:
|
||||
case TILE_SHAPE_RAMP_NORTHEAST:
|
||||
case TILE_SHAPE_RAMP_NORTHWEST:
|
||||
case TILE_SHAPE_RAMP_SOUTHEAST:
|
||||
case TILE_SHAPE_RAMP_SOUTHWEST:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/entity/entitydir.h"
|
||||
|
||||
typedef uint8_t tile_t;
|
||||
|
||||
/**
|
||||
* Returns whether or not the given tile is walkable.
|
||||
*
|
||||
* @param tile The tile to check.
|
||||
* @return bool_t True if walkable, false if not.
|
||||
*/
|
||||
bool_t tileIsWalkable(const tile_t tile);
|
||||
|
||||
/**
|
||||
* Returns whether or not the given tile is a ramp tile.
|
||||
*
|
||||
* @param tile The tile to check.
|
||||
* @return bool_t True if ramp, false if not.
|
||||
*/
|
||||
bool_t tileIsRamp(const tile_t tile);
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "worldpos.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b) {
|
||||
return a.x == b.x && a.y == b.y && a.z == b.z;
|
||||
}
|
||||
|
||||
void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out) {
|
||||
assertNotNull(chunkPos, "Chunk position pointer cannot be NULL");
|
||||
assertNotNull(out, "Output world position pointer cannot be NULL");
|
||||
|
||||
out->x = (worldunit_t)(chunkPos->x * CHUNK_WIDTH);
|
||||
out->y = (worldunit_t)(chunkPos->y * CHUNK_HEIGHT);
|
||||
out->z = (worldunit_t)(chunkPos->z * CHUNK_DEPTH);
|
||||
}
|
||||
|
||||
void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out) {
|
||||
assertNotNull(worldPos, "World position pointer cannot be NULL");
|
||||
assertNotNull(out, "Output chunk position pointer cannot be NULL");
|
||||
|
||||
if(worldPos->x < 0) {
|
||||
out->x = (chunkunit_t)((worldPos->x - (CHUNK_WIDTH - 1)) / CHUNK_WIDTH);
|
||||
} else {
|
||||
out->x = (chunkunit_t)(worldPos->x / CHUNK_WIDTH);
|
||||
}
|
||||
|
||||
if(worldPos->y < 0) {
|
||||
out->y = (chunkunit_t)((worldPos->y - (CHUNK_HEIGHT - 1)) / CHUNK_HEIGHT);
|
||||
} else {
|
||||
out->y = (chunkunit_t)(worldPos->y / CHUNK_HEIGHT);
|
||||
}
|
||||
|
||||
if(worldPos->z < 0) {
|
||||
out->z = (chunkunit_t)((worldPos->z - (CHUNK_DEPTH - 1)) / CHUNK_DEPTH);
|
||||
} else {
|
||||
out->z = (chunkunit_t)(worldPos->z / CHUNK_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos) {
|
||||
assertNotNull(worldPos, "World position pointer cannot be NULL");
|
||||
|
||||
uint8_t localX, localY, localZ;
|
||||
if(worldPos->x < 0) {
|
||||
localX = (uint8_t)(
|
||||
(CHUNK_WIDTH - 1) - ((-worldPos->x - 1) % CHUNK_WIDTH)
|
||||
);
|
||||
} else {
|
||||
localX = (uint8_t)(worldPos->x % CHUNK_WIDTH);
|
||||
}
|
||||
|
||||
if(worldPos->y < 0) {
|
||||
localY = (uint8_t)(
|
||||
(CHUNK_HEIGHT - 1) - ((-worldPos->y - 1) % CHUNK_HEIGHT)
|
||||
);
|
||||
} else {
|
||||
localY = (uint8_t)(worldPos->y % CHUNK_HEIGHT);
|
||||
}
|
||||
|
||||
if(worldPos->z < 0) {
|
||||
localZ = (uint8_t)(
|
||||
(CHUNK_DEPTH - 1) - ((-worldPos->z - 1) % CHUNK_DEPTH)
|
||||
);
|
||||
} else {
|
||||
localZ = (uint8_t)(worldPos->z % CHUNK_DEPTH);
|
||||
}
|
||||
|
||||
chunktileindex_t chunkTileIndex = (chunktileindex_t)(
|
||||
(localZ * CHUNK_WIDTH * CHUNK_HEIGHT) +
|
||||
(localY * CHUNK_WIDTH) +
|
||||
localX
|
||||
);
|
||||
assertTrue(
|
||||
chunkTileIndex < CHUNK_TILE_COUNT,
|
||||
"Calculated chunk tile index is out of bounds"
|
||||
);
|
||||
return chunkTileIndex;
|
||||
}
|
||||
|
||||
chunkindex_t chunkPosToIndex(const chunkpos_t* pos) {
|
||||
assertNotNull(pos, "Chunk position pointer cannot be NULL");
|
||||
|
||||
chunkindex_t chunkIndex = (chunkindex_t)(
|
||||
(pos->z * MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT) +
|
||||
(pos->y * MAP_CHUNK_WIDTH) +
|
||||
pos->x
|
||||
);
|
||||
|
||||
return chunkIndex;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "duskdefs.h"
|
||||
|
||||
#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH)
|
||||
|
||||
#define MAP_CHUNK_WIDTH 3
|
||||
#define MAP_CHUNK_HEIGHT 3
|
||||
#define MAP_CHUNK_DEPTH 3
|
||||
#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH)
|
||||
|
||||
typedef int16_t worldunit_t;
|
||||
typedef int16_t chunkunit_t;
|
||||
typedef int16_t chunkindex_t;
|
||||
typedef uint32_t chunktileindex_t;
|
||||
|
||||
typedef int32_t worldunits_t;
|
||||
typedef int32_t chunkunits_t;
|
||||
|
||||
typedef struct worldpos_s {
|
||||
worldunit_t x, y, z;
|
||||
} worldpos_t;
|
||||
|
||||
typedef struct chunkpos_t {
|
||||
chunkunit_t x, y, z;
|
||||
} chunkpos_t;
|
||||
|
||||
/**
|
||||
* Compares two world positions for equality.
|
||||
*
|
||||
* @param a The first world position.
|
||||
* @param b The second world position.
|
||||
* @return true if equal, false otherwise.
|
||||
*/
|
||||
bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b);
|
||||
|
||||
/**
|
||||
* Converts a world position to a chunk position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out);
|
||||
|
||||
/**
|
||||
* Converts a chunk position to a world position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out);
|
||||
|
||||
/**
|
||||
* Converts a position in world-space to an index inside a chunk that the tile
|
||||
* resides in.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @return The tile index within the chunk.
|
||||
*/
|
||||
chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos);
|
||||
|
||||
/**
|
||||
* Converts a chunk position to a world position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
chunkindex_t chunkPosToIndex(const chunkpos_t* pos);
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpg.h"
|
||||
#include "entity/entity.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "time/time.h"
|
||||
#include "rpgcamera.h"
|
||||
#include "rpgtextbox.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
errorret_t rpgInit(void) {
|
||||
memoryZero(ENTITIES, sizeof(ENTITIES));
|
||||
|
||||
// Init cutscene subsystem
|
||||
cutsceneSystemInit();
|
||||
|
||||
errorChain(mapInit());
|
||||
|
||||
rpgCameraInit();
|
||||
rpgTextboxInit();
|
||||
|
||||
// TEST: Create some entities.
|
||||
// uint8_t entIndex = entityGetAvailable();
|
||||
// assertTrue(entIndex != 0xFF, "No available entity slots!.");
|
||||
// entity_t *ent = &ENTITIES[entIndex];
|
||||
// entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||
// RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
||||
// RPG_CAMERA.followEntity.followEntityId = ent->id;
|
||||
// ent->position.x = 2, ent->position.y = 2;
|
||||
|
||||
// All Good!
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t rpgUpdate(void) {
|
||||
#if TIME_FIXED == 0
|
||||
if(TIME.dynamicUpdate) {
|
||||
errorOk();
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Do not update if the scene is not the map scene?
|
||||
mapUpdate();
|
||||
|
||||
// Update overworld ents.
|
||||
entity_t *ent = &ENTITIES[0];
|
||||
do {
|
||||
if(ent->type == ENTITY_TYPE_NULL) continue;
|
||||
entityUpdate(ent);
|
||||
} while(++ent < &ENTITIES[ENTITY_COUNT]);
|
||||
|
||||
cutsceneSystemUpdate();
|
||||
errorChain(rpgCameraUpdate());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void rpgDispose(void) {
|
||||
mapDispose();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t nothing;
|
||||
} rpg_t;
|
||||
|
||||
/**
|
||||
* Initialize the RPG subsystem.
|
||||
*
|
||||
* @return An error code and state.
|
||||
*/
|
||||
errorret_t rpgInit(void);
|
||||
|
||||
/**
|
||||
* Update the RPG subsystem.
|
||||
*
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t rpgUpdate(void);
|
||||
|
||||
/**
|
||||
* Dispose of the RPG subsystem.
|
||||
*/
|
||||
void rpgDispose(void);
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpgcamera.h"
|
||||
#include "util/memory.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
rpgcamera_t RPG_CAMERA;
|
||||
|
||||
void rpgCameraInit(void) {
|
||||
memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t));
|
||||
}
|
||||
|
||||
errorret_t rpgCameraUpdate(void) {
|
||||
if(!mapIsLoaded()) errorOk();
|
||||
|
||||
chunkpos_t chunkPos;
|
||||
|
||||
switch(RPG_CAMERA.mode) {
|
||||
case RPG_CAMERA_MODE_FREE:
|
||||
worldPosToChunkPos(&RPG_CAMERA.free, &chunkPos);
|
||||
break;
|
||||
|
||||
case RPG_CAMERA_MODE_FOLLOW_ENTITY: {
|
||||
entity_t *entity = &ENTITIES[RPG_CAMERA.followEntity.followEntityId];
|
||||
if(entity->type == ENTITY_TYPE_NULL) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Update map position to match camera. By default map wants to know the
|
||||
// top left but we want to set the center, so we need to sub half map size
|
||||
worldPosToChunkPos(&entity->position, &chunkPos);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid RPG camera mode");
|
||||
}
|
||||
|
||||
errorChain(mapPositionSet((chunkpos_t){
|
||||
.x = chunkPos.x - (MAP_CHUNK_WIDTH / 2),
|
||||
.y = chunkPos.y - (MAP_CHUNK_HEIGHT / 2),
|
||||
.z = chunkPos.z - (MAP_CHUNK_DEPTH / 2)
|
||||
}));
|
||||
errorOk();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
#include "error/error.h"
|
||||
|
||||
typedef enum {
|
||||
RPG_CAMERA_MODE_FREE,
|
||||
RPG_CAMERA_MODE_FOLLOW_ENTITY,
|
||||
} rpgcameramode_t;
|
||||
|
||||
typedef struct {
|
||||
rpgcameramode_t mode;
|
||||
|
||||
union {
|
||||
worldpos_t free;
|
||||
struct {
|
||||
uint8_t followEntityId;
|
||||
} followEntity;
|
||||
};
|
||||
} rpgcamera_t;
|
||||
|
||||
extern rpgcamera_t RPG_CAMERA;
|
||||
|
||||
/**
|
||||
* Initializes the RPG camera.
|
||||
*/
|
||||
void rpgCameraInit(void);
|
||||
|
||||
/**
|
||||
* Updates the RPG camera.
|
||||
*
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t rpgCameraUpdate(void);
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpgtextbox.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
rpgtextbox_t RPG_TEXTBOX;
|
||||
|
||||
void rpgTextboxInit() {
|
||||
memoryZero(&RPG_TEXTBOX, sizeof(rpgtextbox_t));
|
||||
}
|
||||
|
||||
void rpgTextboxShow(
|
||||
const rpgtextboxpos_t position,
|
||||
const char_t *text
|
||||
) {
|
||||
RPG_TEXTBOX.position = position;
|
||||
RPG_TEXTBOX.visible = true;
|
||||
|
||||
stringCopy(
|
||||
RPG_TEXTBOX.text,
|
||||
text,
|
||||
RPG_TEXTBOX_MAX_CHARS
|
||||
);
|
||||
}
|
||||
|
||||
void rpgTextboxHide() {
|
||||
RPG_TEXTBOX.visible = false;
|
||||
}
|
||||
|
||||
bool_t rpgTextboxIsVisible() {
|
||||
return RPG_TEXTBOX.visible;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define RPG_TEXTBOX_MAX_CHARS 256
|
||||
|
||||
typedef enum {
|
||||
RPG_TEXTBOX_POS_TOP,
|
||||
RPG_TEXTBOX_POS_BOTTOM,
|
||||
} rpgtextboxpos_t;
|
||||
|
||||
typedef struct {
|
||||
rpgtextboxpos_t position;
|
||||
bool_t visible;
|
||||
char_t text[RPG_TEXTBOX_MAX_CHARS];
|
||||
} rpgtextbox_t;
|
||||
|
||||
extern rpgtextbox_t RPG_TEXTBOX;
|
||||
|
||||
/**
|
||||
* Initializes the RPG textbox.
|
||||
*/
|
||||
void rpgTextboxInit();
|
||||
|
||||
/**
|
||||
* Shows the RPG textbox at a specified position.
|
||||
*
|
||||
* @param position The position to show the textbox at.
|
||||
* @param text The text to display in the textbox (copied).
|
||||
*/
|
||||
void rpgTextboxShow(
|
||||
const rpgtextboxpos_t position,
|
||||
const char_t *text
|
||||
);
|
||||
|
||||
/**
|
||||
* Hides the RPG textbox.
|
||||
*/
|
||||
void rpgTextboxHide();
|
||||
|
||||
/**
|
||||
* Checks if the RPG textbox is currently visible.
|
||||
*
|
||||
* @return true if the textbox is visible, false otherwise.
|
||||
*/
|
||||
bool_t rpgTextboxIsVisible();
|
||||
@@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
scenemanager.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(scene)
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "error/error.h"
|
||||
#include "display/color.h"
|
||||
|
||||
#define SCENE_FLAG_INITIALIZED (1 << 0)
|
||||
|
||||
typedef struct scenedata_s scenedata_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *name;
|
||||
errorret_t (*init)(scenedata_t *data);
|
||||
void (*update)(scenedata_t *data);
|
||||
void (*render)(scenedata_t *data);
|
||||
void (*dispose)(scenedata_t *data);
|
||||
uint8_t flags;
|
||||
} scene_t;
|
||||
@@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
scenetest.c
|
||||
scenemap.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
@@ -1,212 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scenemap.h"
|
||||
#include "scene/scenedata.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/asset.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "display/screen.h"
|
||||
#include "rpg/rpgcamera.h"
|
||||
#include "util/memory.h"
|
||||
#include "duskdefs.h"
|
||||
|
||||
errorret_t sceneMapInit(scenedata_t *data) {
|
||||
// Init the camera.
|
||||
cameraInitPerspective(&data->sceneMap.camera);
|
||||
data->sceneMap.camera.projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED;
|
||||
data->sceneMap.camera.viewType = CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT;
|
||||
glm_vec3_zero(data->sceneMap.camera.lookatPixelPerfect.offset);
|
||||
data->sceneMap.camera.lookatPixelPerfect.offset[1] = RPG_CAMERA_Z_OFFSET;
|
||||
glm_vec3_copy(
|
||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||
data->sceneMap.camera.lookatPixelPerfect.target
|
||||
);
|
||||
glm_vec3_copy(
|
||||
(vec3){ 0.0f, 1.0f, 0.0f },
|
||||
data->sceneMap.camera.lookatPixelPerfect.up
|
||||
);
|
||||
data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = (
|
||||
RPG_CAMERA_PIXELS_PER_UNIT
|
||||
);
|
||||
data->sceneMap.camera.perspective.fov = glm_rad(RPG_CAMERA_FOV);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void sceneMapUpdate(scenedata_t *data) {
|
||||
|
||||
}
|
||||
|
||||
void sceneMapGetWorldPosition(const worldpos_t pos, vec3 outPosition) {
|
||||
assertNotNull(outPosition, "Output position cannot be NULL");
|
||||
|
||||
outPosition[0] = pos.x * TILE_WIDTH;
|
||||
outPosition[1] = pos.y * TILE_HEIGHT;
|
||||
outPosition[2] = pos.z * TILE_DEPTH;
|
||||
|
||||
// Handle stair tiles.
|
||||
tile_t tile = mapGetTile(pos);
|
||||
if(tileIsRamp(tile)) {
|
||||
outPosition[2] += TILE_DEPTH / 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void sceneMapEntityGetPosition(const entity_t *entity, vec3 outPosition) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertNotNull(outPosition, "Output position cannot be NULL");
|
||||
|
||||
// Get position
|
||||
sceneMapGetWorldPosition(entity->position, outPosition);
|
||||
|
||||
// Add a small offset so we render above the tile
|
||||
outPosition[2] += 0.1f;
|
||||
|
||||
// Add animation offset(s)
|
||||
switch(entity->animation) {
|
||||
case ENTITY_ANIM_WALK: {
|
||||
float_t animPercentage = entity->animTime / ENTITY_ANIM_WALK_DURATION;
|
||||
|
||||
vec3 lastPosition;
|
||||
sceneMapGetWorldPosition(entity->lastPosition, lastPosition);
|
||||
|
||||
vec3 offset;
|
||||
glm_vec3_sub(outPosition, lastPosition, offset);
|
||||
glm_vec3_scale(offset, -animPercentage, offset);
|
||||
glm_vec3_add(outPosition, offset, outPosition);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sceneMapRender(scenedata_t *data) {
|
||||
if(!mapIsLoaded()) return;
|
||||
|
||||
// Look at target.
|
||||
vec3 cameraTarget;
|
||||
switch(RPG_CAMERA.mode) {
|
||||
case RPG_CAMERA_MODE_FREE:
|
||||
sceneMapGetWorldPosition(RPG_CAMERA.free, cameraTarget);
|
||||
break;
|
||||
|
||||
case RPG_CAMERA_MODE_FOLLOW_ENTITY: {
|
||||
const entity_t *ent = &ENTITIES[RPG_CAMERA.followEntity.followEntityId];
|
||||
sceneMapEntityGetPosition(ent, cameraTarget);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
glm_vec3_zero(cameraTarget);
|
||||
break;
|
||||
}
|
||||
|
||||
glm_vec3_copy(
|
||||
cameraTarget,
|
||||
data->sceneMap.camera.lookatPixelPerfect.target
|
||||
);
|
||||
|
||||
// Push camera
|
||||
cameraPushMatrix(&data->sceneMap.camera);
|
||||
|
||||
// Render map probably.
|
||||
sceneMapRenderMap();
|
||||
|
||||
// Render ents
|
||||
entity_t *ent = ENTITIES;
|
||||
do {
|
||||
sceneMapRenderEntity(ent);
|
||||
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
||||
spriteBatchFlush();
|
||||
|
||||
// Finished, pop back camera.
|
||||
cameraPopMatrix();
|
||||
}
|
||||
|
||||
void sceneMapRenderEntity(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
|
||||
if(entity->type == ENTITY_TYPE_NULL) return;
|
||||
|
||||
vec3 posMin, posMax;
|
||||
vec3 size = { TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH };
|
||||
sceneMapEntityGetPosition(entity, posMin);
|
||||
glm_vec3_add(posMin, size, posMax);
|
||||
|
||||
// TEST: Change color depending on dir.
|
||||
color_t testColor;
|
||||
switch(entity->direction) {
|
||||
case ENTITY_DIR_NORTH:
|
||||
testColor = COLOR_BLUE;
|
||||
break;
|
||||
case ENTITY_DIR_EAST:
|
||||
testColor = COLOR_GREEN;
|
||||
break;
|
||||
case ENTITY_DIR_SOUTH:
|
||||
testColor = COLOR_CYAN;
|
||||
break;
|
||||
case ENTITY_DIR_WEST:
|
||||
testColor = COLOR_YELLOW;
|
||||
break;
|
||||
default:
|
||||
testColor = COLOR_WHITE;
|
||||
break;
|
||||
}
|
||||
|
||||
vec2 uv0 = { 0.0f, 0.0f };
|
||||
vec2 uv1 = { 1.0f, 1.0f };
|
||||
|
||||
spriteBatchPush3D(NULL, posMin, posMax, testColor, uv0, uv1);
|
||||
}
|
||||
|
||||
void sceneMapRenderMap() {
|
||||
assertTrue(mapIsLoaded(), "No map loaded to render");
|
||||
|
||||
// For each chunk.
|
||||
for(uint32_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
chunk_t *chunk = MAP.chunkOrder[i];
|
||||
|
||||
for(uint8_t j = 0; j < chunk->meshCount; j++) {
|
||||
mesh_t *mesh = &chunk->meshes[j];
|
||||
if(mesh->vertexCount == 0) continue;
|
||||
textureBind(NULL);
|
||||
meshDraw(mesh, -1, -1);
|
||||
}
|
||||
|
||||
// vec3 min, max;
|
||||
// min[0] = chunk->position.x * CHUNK_WIDTH * TILE_WIDTH;
|
||||
// min[1] = chunk->position.y * CHUNK_HEIGHT * TILE_HEIGHT;
|
||||
// min[2] = chunk->position.z * CHUNK_DEPTH * TILE_DEPTH;
|
||||
|
||||
// max[0] = min[0] + (CHUNK_WIDTH * TILE_WIDTH);
|
||||
// max[1] = min[1] + (CHUNK_HEIGHT * TILE_HEIGHT);
|
||||
// max[2] = min[2];
|
||||
|
||||
// color_t color = COLOR_WHITE;
|
||||
// if(chunk->position.x % 2 == 0) {
|
||||
// color = (chunk->position.y % 2 == 0) ? COLOR_BLACK : COLOR_WHITE;
|
||||
// } else {
|
||||
// color = (chunk->position.y % 2 == 0) ? COLOR_WHITE : COLOR_BLACK;
|
||||
// }
|
||||
|
||||
// spriteBatchPush3D(
|
||||
// NULL,
|
||||
// min,
|
||||
// max,
|
||||
// color,
|
||||
// (vec2){ 0.0f, 0.0f },
|
||||
// (vec2){ 1.0f, 1.0f }
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
void sceneMapDispose(scenedata_t *data) {
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scene/scene.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "display/camera/camera.h"
|
||||
#include "asset/asset.h"
|
||||
|
||||
typedef struct {
|
||||
camera_t camera;
|
||||
} scenemap_t;
|
||||
|
||||
errorret_t sceneMapInit(scenedata_t *data);
|
||||
void sceneMapUpdate(scenedata_t *data);
|
||||
void sceneMapRender(scenedata_t *data);
|
||||
void sceneMapRenderEntity(entity_t *entity);
|
||||
void sceneMapRenderMap();
|
||||
void sceneMapDispose(scenedata_t *data);
|
||||
|
||||
static scene_t SCENE_MAP = {
|
||||
.name = "map",
|
||||
.init = sceneMapInit,
|
||||
.update = sceneMapUpdate,
|
||||
.render = sceneMapRender,
|
||||
.dispose = sceneMapDispose,
|
||||
.flags = 0
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scenetest.h"
|
||||
#include "scene/scenedata.h"
|
||||
|
||||
errorret_t sceneTestInit(scenedata_t *data) {
|
||||
data->sceneTest.nothing = 0;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void sceneTestUpdate(scenedata_t *data) {
|
||||
|
||||
}
|
||||
|
||||
void sceneTestRender(scenedata_t *data) {
|
||||
|
||||
}
|
||||
|
||||
void sceneTestDispose(scenedata_t *data) {
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scene/scene.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t nothing;
|
||||
} scenetest_t;
|
||||
|
||||
errorret_t sceneTestInit(scenedata_t *data);
|
||||
void sceneTestUpdate(scenedata_t *data);
|
||||
void sceneTestRender(scenedata_t *data);
|
||||
void sceneTestDispose(scenedata_t *data);
|
||||
|
||||
static scene_t SCENE_TEST = {
|
||||
.name = "test",
|
||||
.init = sceneTestInit,
|
||||
.update = sceneTestUpdate,
|
||||
.render = sceneTestRender,
|
||||
.dispose = sceneTestDispose,
|
||||
.flags = 0
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scene/scene.h"
|
||||
|
||||
#include "scene/scene/scenetest.h"
|
||||
#include "scene/scene/scenemap.h"
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scenemanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/framebuffer.h"
|
||||
#include "util/string.h"
|
||||
#include "asset/asset.h"
|
||||
#include "script/scriptmanager.h"
|
||||
|
||||
scenemanager_t SCENE_MANAGER;
|
||||
|
||||
errorret_t sceneManagerInit(void) {
|
||||
memoryZero(&SCENE_MANAGER, sizeof(scenemanager_t));
|
||||
|
||||
sceneManagerRegisterScene(&SCENE_TEST);
|
||||
sceneManagerRegisterScene(&SCENE_MAP);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
scene_t * sceneManagerGetSceneByName(const char_t *name) {
|
||||
assertNotNull(name, "Name is null");
|
||||
|
||||
for(uint8_t i = 0; i < SCENE_MANAGER.sceneCount; i++) {
|
||||
if(strcmp(SCENE_MANAGER.scenes[i]->name, name) != 0) continue;
|
||||
return SCENE_MANAGER.scenes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sceneManagerRegisterScene(scene_t *scene) {
|
||||
assertNotNull(scene, "Scene is null");
|
||||
assertTrue(
|
||||
SCENE_MANAGER.sceneCount < SCENE_MANAGER_SCENE_COUNT_MAX,
|
||||
"Scene count exceeded max"
|
||||
);
|
||||
assertNotNull(scene->name, "Scene name is null");
|
||||
assertNull(
|
||||
sceneManagerGetSceneByName(scene->name), "Scene name already registered"
|
||||
);
|
||||
|
||||
SCENE_MANAGER.scenes[SCENE_MANAGER.sceneCount++] = scene;
|
||||
}
|
||||
|
||||
errorret_t sceneManagerSetScene(scene_t *scene) {
|
||||
if(
|
||||
SCENE_MANAGER.current &&
|
||||
(SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED) != 0
|
||||
) {
|
||||
SCENE_MANAGER.current->flags &= ~SCENE_FLAG_INITIALIZED;
|
||||
if(SCENE_MANAGER.current->dispose) {
|
||||
SCENE_MANAGER.current->dispose(&SCENE_MANAGER.sceneData);
|
||||
}
|
||||
}
|
||||
|
||||
SCENE_MANAGER.current = scene;
|
||||
|
||||
if(scene && (scene->flags & SCENE_FLAG_INITIALIZED) == 0) {
|
||||
scene->flags |= SCENE_FLAG_INITIALIZED;
|
||||
|
||||
if(scene->init) errorChain(scene->init(&SCENE_MANAGER.sceneData));
|
||||
|
||||
// Execute scene script if it exists
|
||||
char_t buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "scene/%s.dsf", scene->name);
|
||||
if(assetFileExists(buffer)) {
|
||||
scriptcontext_t ctx;
|
||||
scriptContextInit(&ctx);
|
||||
errorChain(scriptContextExecFile(&ctx, buffer));
|
||||
scriptContextDispose(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void sceneManagerUpdate(void) {
|
||||
if(!SCENE_MANAGER.current) return;
|
||||
|
||||
assertTrue(
|
||||
SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED,
|
||||
"Current scene not initialized"
|
||||
);
|
||||
|
||||
if(SCENE_MANAGER.current->update) {
|
||||
SCENE_MANAGER.current->update(&SCENE_MANAGER.sceneData);
|
||||
}
|
||||
}
|
||||
|
||||
void sceneManagerRender(void) {
|
||||
if(!SCENE_MANAGER.current) return;
|
||||
|
||||
assertTrue(
|
||||
SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED,
|
||||
"Current scene not initialized"
|
||||
);
|
||||
|
||||
if(SCENE_MANAGER.current->render) {
|
||||
SCENE_MANAGER.current->render(&SCENE_MANAGER.sceneData);
|
||||
}
|
||||
}
|
||||
|
||||
void sceneManagerDispose(void) {
|
||||
for(uint8_t i = 0; i < SCENE_MANAGER.sceneCount; i++) {
|
||||
scene_t *scene = SCENE_MANAGER.scenes[i];
|
||||
if(scene->flags & SCENE_FLAG_INITIALIZED) {
|
||||
scene->dispose(&SCENE_MANAGER.sceneData);
|
||||
}
|
||||
}
|
||||
|
||||
SCENE_MANAGER.sceneCount = 0;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scene.h"
|
||||
#include "scenedata.h"
|
||||
|
||||
#define SCENE_MANAGER_SCENE_COUNT_MAX 16
|
||||
|
||||
typedef struct {
|
||||
scene_t *current;
|
||||
scene_t *scenes[SCENE_MANAGER_SCENE_COUNT_MAX];
|
||||
uint8_t sceneCount;
|
||||
} scenemanager_t;
|
||||
|
||||
extern scenemanager_t SCENE_MANAGER;
|
||||
|
||||
/**
|
||||
* Initializes the scene manager and the initial scene.
|
||||
*/
|
||||
errorret_t sceneManagerInit(void);
|
||||
|
||||
/**
|
||||
* Retrieves a registered scene by its name.
|
||||
*
|
||||
* @param name The name of the scene to retrieve.
|
||||
* @return The scene with the specified name, or NULL if not found.
|
||||
*/
|
||||
scene_t * sceneManagerGetSceneByName(const char_t *name);
|
||||
|
||||
/**
|
||||
* Registers a scene with the scene manager.
|
||||
*
|
||||
* @param scene The scene to register.
|
||||
*/
|
||||
void sceneManagerRegisterScene(scene_t *scene);
|
||||
|
||||
/**
|
||||
* Sets the current active scene.
|
||||
*
|
||||
* @param scene The scene to set as current.
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
errorret_t sceneManagerSetScene(scene_t *scene);
|
||||
|
||||
/**
|
||||
* Updates all active scenes.
|
||||
*/
|
||||
void sceneManagerUpdate(void);
|
||||
|
||||
/**
|
||||
* Renders all visible scenes.
|
||||
*/
|
||||
void sceneManagerRender(void);
|
||||
|
||||
/**
|
||||
* Disposes of all scenes.
|
||||
*/
|
||||
void sceneManagerDispose(void);
|
||||
@@ -1,135 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
int scriptFuncEntityAdd(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
assertTrue(lua_isinteger(L, 1), "Expected integer entity type");
|
||||
|
||||
lua_Integer entityType = luaL_checkinteger(L, 1);
|
||||
assertTrue(
|
||||
entityType >= ENTITY_TYPE_NULL && entityType < ENTITY_TYPE_COUNT,
|
||||
"Invalid entity type passed to scriptFuncEntityAdd"
|
||||
);
|
||||
|
||||
// Pop entity
|
||||
uint8_t available = entityGetAvailable();
|
||||
if(available == 0xFF) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
entity_t *ent = &ENTITIES[available];
|
||||
entityInit(ent, (entitytype_t)entityType);
|
||||
|
||||
// May include X, Y and/or Z
|
||||
if(lua_isinteger(L, 2)) {
|
||||
lua_Integer xPos = luaL_checkinteger(L, 2);
|
||||
ent->position.x = (int32_t)xPos;
|
||||
}
|
||||
if(lua_isinteger(L, 3)) {
|
||||
lua_Integer yPos = luaL_checkinteger(L, 3);
|
||||
ent->position.y = (int32_t)yPos;
|
||||
}
|
||||
if(lua_isinteger(L, 4)) {
|
||||
lua_Integer zPos = luaL_checkinteger(L, 4);
|
||||
ent->position.z = (int32_t)zPos;
|
||||
}
|
||||
|
||||
// Send entity id.
|
||||
lua_pushinteger(L, ent->id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int scriptFuncEntitySetX(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
|
||||
assertTrue(lua_isinteger(L, 2), "Expected integer x position");
|
||||
|
||||
lua_Integer entityId = luaL_checkinteger(L, 1);
|
||||
lua_Integer xPos = luaL_checkinteger(L, 2);
|
||||
|
||||
assertTrue(
|
||||
entityId >= 0 && entityId < ENTITY_COUNT,
|
||||
"Invalid entity id passed to scriptFuncEntitySetX"
|
||||
);
|
||||
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
assertTrue(
|
||||
ent->type != ENTITY_TYPE_NULL,
|
||||
"Cannot set position of NULL entity in scriptFuncEntitySetX"
|
||||
);
|
||||
|
||||
ent->position.x = (int32_t)xPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scriptFuncEntitySetY(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
|
||||
assertTrue(lua_isinteger(L, 2), "Expected integer y position");
|
||||
|
||||
lua_Integer entityId = luaL_checkinteger(L, 1);
|
||||
lua_Integer yPos = luaL_checkinteger(L, 2);
|
||||
|
||||
assertTrue(
|
||||
entityId >= 0 && entityId < ENTITY_COUNT,
|
||||
"Invalid entity id passed to scriptFuncEntitySetY"
|
||||
);
|
||||
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
assertTrue(
|
||||
ent->type != ENTITY_TYPE_NULL,
|
||||
"Cannot set position of NULL entity in scriptFuncEntitySetY"
|
||||
);
|
||||
|
||||
ent->position.y = (int32_t)yPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scriptFuncEntitySetZ(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
|
||||
assertTrue(lua_isinteger(L, 2), "Expected integer z position");
|
||||
|
||||
lua_Integer entityId = luaL_checkinteger(L, 1);
|
||||
lua_Integer zPos = luaL_checkinteger(L, 2);
|
||||
|
||||
assertTrue(
|
||||
entityId >= 0 && entityId < ENTITY_COUNT,
|
||||
"Invalid entity id passed to scriptFuncEntitySetZ"
|
||||
);
|
||||
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
assertTrue(
|
||||
ent->type != ENTITY_TYPE_NULL,
|
||||
"Cannot set position of NULL entity in scriptFuncEntitySetZ"
|
||||
);
|
||||
|
||||
ent->position.z = (int32_t)zPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scriptFuncEntity(scriptcontext_t *context) {
|
||||
assertNotNull(context, "Script context cannot be NULL");
|
||||
|
||||
lua_register(context->luaState, "entityAdd", scriptFuncEntityAdd);
|
||||
lua_register(context->luaState, "entitySetX", scriptFuncEntitySetX);
|
||||
lua_register(context->luaState, "entitySetY", scriptFuncEntitySetY);
|
||||
lua_register(context->luaState, "entitySetZ", scriptFuncEntitySetZ);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
ui.c
|
||||
uitext.c
|
||||
uidebug.c
|
||||
uiframe.c
|
||||
uitextbox.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(element)
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
UI_ELEMENT_TYPE_NULL,
|
||||
|
||||
UI_ELEMENT_TYPE_TEXT,
|
||||
|
||||
UI_ELEMENT_TYPE_COUNT,
|
||||
} uielementtype_t;
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "ui.h"
|
||||
#include "assert/assert.h"
|
||||
#include "ui/uidebug.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
#include "display/screen.h"
|
||||
// #include "ui/uitextbox.h"
|
||||
|
||||
ui_t UI;
|
||||
|
||||
errorret_t uiInit(void) {
|
||||
memoryZero(&UI, sizeof(ui_t));
|
||||
|
||||
cameraInitOrthographic(&UI.camera);
|
||||
|
||||
// Initialize UI components here
|
||||
uiSetFont(&TILESET_MINOGRAM);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiUpdate(void) {
|
||||
// Update UI state here
|
||||
UI.camera.orthographic.left = 0;
|
||||
UI.camera.orthographic.right = SCREEN.width;
|
||||
UI.camera.orthographic.top = 0;
|
||||
UI.camera.orthographic.bottom = SCREEN.height;
|
||||
|
||||
// uiTextboxUpdate();
|
||||
}
|
||||
|
||||
void uiRender(void) {
|
||||
cameraPushMatrix(&UI.camera);
|
||||
|
||||
// Render UI elements here
|
||||
if(UI.fontTexture.width > 0) {
|
||||
uiDebugRender(UI.fontTileset, &UI.fontTexture);
|
||||
}
|
||||
cameraPopMatrix();
|
||||
}
|
||||
|
||||
errorret_t uiSetFont(const tileset_t *fontTileset) {
|
||||
if(UI.fontTexture.width > 0) {
|
||||
textureDispose(&UI.fontTexture);
|
||||
UI.fontTexture.width = -1;
|
||||
}
|
||||
|
||||
assertNotNull(fontTileset, "Font tileset cannot be NULL.");
|
||||
|
||||
UI.fontTileset = fontTileset;
|
||||
errorChain(assetLoad(UI.fontTileset->image, &UI.fontTexture));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiDispose(void) {
|
||||
if(UI.fontTexture.width > 0) {
|
||||
textureDispose(&UI.fontTexture);
|
||||
UI.fontTexture.width = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture.h"
|
||||
#include "display/tileset/tileset.h"
|
||||
#include "display/camera/camera.h"
|
||||
|
||||
typedef struct {
|
||||
camera_t camera;
|
||||
texture_t fontTexture;
|
||||
const tileset_t *fontTileset;
|
||||
} ui_t;
|
||||
|
||||
extern ui_t UI;
|
||||
|
||||
/**
|
||||
* Initializes the UI system, loading necessary resources.
|
||||
*
|
||||
* @return An errorret_t indicating success or failure.
|
||||
*/
|
||||
errorret_t uiInit(void);
|
||||
|
||||
/**
|
||||
* Updates the UI state, handling user interactions and animations.
|
||||
*/
|
||||
void uiUpdate(void);
|
||||
|
||||
/**
|
||||
* Renders the UI elements to the screen.
|
||||
*/
|
||||
void uiRender(void);
|
||||
|
||||
/**
|
||||
* Sets the font tileset for UI text rendering.
|
||||
*
|
||||
* @param fontTileset Pointer to the tileset to use for UI fonts.
|
||||
*
|
||||
* @return An errorret_t indicating success or failure.
|
||||
*/
|
||||
errorret_t uiSetFont(const tileset_t *fontTileset);
|
||||
|
||||
/**
|
||||
* Cleans up and frees all UI resources.
|
||||
*/
|
||||
void uiDispose(void);
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uidebug.h"
|
||||
#include "time/time.h"
|
||||
#include "util/string.h"
|
||||
#include "ui/uitext.h"
|
||||
#include "display/screen.h"
|
||||
#include "display/spritebatch.h"
|
||||
// #include "rpg/entity/entity.h"
|
||||
|
||||
bool_t UI_DEBUG_DRAW = true;
|
||||
|
||||
void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
||||
if(!UI_DEBUG_DRAW) return;
|
||||
|
||||
char_t buffer[128];
|
||||
color_t color;
|
||||
int32_t w, h, hOffset = 0;
|
||||
|
||||
// FPS Meter
|
||||
#if TIME_FIXED == 0
|
||||
float_t fpsDynamic = TIME.dynamicDelta > 0.0f ? (1.0f / TIME.dynamicDelta) : 0.0f;
|
||||
float_t fpsFixed = TIME.delta > 0.0f ? (1.0f / TIME.delta) : 0.0f;
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%.2f/%.2f/%d/%d",
|
||||
TIME.dynamicDelta * 1000.0f,
|
||||
TIME.delta * 1000.0f,
|
||||
TIME.dynamicUpdate,
|
||||
(int32_t)fpsDynamic
|
||||
);
|
||||
|
||||
color = (
|
||||
fpsDynamic >= 50.0f ? COLOR_GREEN :
|
||||
fpsDynamic >= 30.0f ? COLOR_YELLOW :
|
||||
COLOR_RED
|
||||
);
|
||||
#else
|
||||
float_t fps = TIME.delta > 0.0f ? (1.0f / TIME.delta) : 0.0f;
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%.2f/%d/FXD",
|
||||
TIME.delta * 1000.0f,
|
||||
(int32_t)fps
|
||||
);
|
||||
|
||||
color = (
|
||||
fps >= 50.0f ? COLOR_GREEN :
|
||||
fps >= 30.0f ? COLOR_YELLOW :
|
||||
COLOR_RED
|
||||
);
|
||||
#endif
|
||||
|
||||
uiTextMeasure(buffer, tileset, &w, &h);
|
||||
uiTextDraw(
|
||||
SCREEN.width - w, hOffset,
|
||||
buffer, color, tileset, texture
|
||||
);
|
||||
hOffset += h;
|
||||
|
||||
|
||||
// Player position
|
||||
// entity_t *player = NULL;
|
||||
// for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
||||
// if(ENTITIES[i].type != ENTITY_TYPE_PLAYER) continue;
|
||||
// player = &ENTITIES[i];
|
||||
// break;
|
||||
// }
|
||||
// if(player == NULL) {
|
||||
// snprintf(buffer, sizeof(buffer), "Player: N/A");
|
||||
// } else {
|
||||
// snprintf(
|
||||
// buffer,
|
||||
// sizeof(buffer),
|
||||
// "%d,%d,%d/%d/%d",
|
||||
// player->position.x,
|
||||
// player->position.y,
|
||||
// player->position.z,
|
||||
// (int32_t)player->direction,
|
||||
// (int32_t)player->animation
|
||||
// );
|
||||
// }
|
||||
// uiTextMeasure(buffer, tileset, &w, &h);
|
||||
// uiTextDraw(
|
||||
// SCREEN.width - w, hOffset,
|
||||
// buffer, COLOR_GREEN, tileset, texture
|
||||
// );
|
||||
// hOffset += h;
|
||||
|
||||
spriteBatchFlush();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/tileset/tileset.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
/**
|
||||
* Renders the debug information UI element.
|
||||
*
|
||||
* @param tileset The tileset to use for rendering text.
|
||||
* @param texture The texture associated with the tileset.
|
||||
*/
|
||||
void uiDebugRender(const tileset_t *tileset, texture_t *texture);
|
||||
@@ -1,390 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uiframe.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/math.h"
|
||||
|
||||
void uiFrameDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const float_t width,
|
||||
const float_t height,
|
||||
const tileset_t *tileset,
|
||||
const uint16_t column,
|
||||
const uint16_t row,
|
||||
const bool_t drawInner,
|
||||
texture_t *texture
|
||||
) {
|
||||
assertNotNull(tileset, "Tileset cannot be NULL");
|
||||
assertNotNull(texture, "Texture cannot be NULL");
|
||||
|
||||
if(height <= 0 || width <= 0) return;
|
||||
|
||||
// Top-Left
|
||||
vec4 uv;
|
||||
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column,
|
||||
row,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y,
|
||||
x + tileset->tileWidth,
|
||||
y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Top-Center
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 1,
|
||||
row,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + tileset->tileWidth, y,
|
||||
x + width - tileset->tileWidth, y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Top-Right
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 2,
|
||||
row,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, y,
|
||||
x + width, y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Middle-Left
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column,
|
||||
row + 1,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y + tileset->tileHeight,
|
||||
x + tileset->tileWidth, y + height - tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Middle-Center
|
||||
if(drawInner) {
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 1,
|
||||
row + 1,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + tileset->tileWidth, y + tileset->tileHeight,
|
||||
x + width - tileset->tileWidth, y + height - tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
// Middle-Right
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 2,
|
||||
row + 1,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, y + tileset->tileHeight,
|
||||
x + width, y + height - tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Bottom-Left
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column,
|
||||
row + 2,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y + height - tileset->tileHeight,
|
||||
x + tileset->tileWidth, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Bottom-Center
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 1,
|
||||
row + 2,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + tileset->tileWidth, y + height - tileset->tileHeight,
|
||||
x + width - tileset->tileWidth, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Bottom-Right
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 2,
|
||||
row + 2,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, y + height - tileset->tileHeight,
|
||||
x + width, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
void uiFrameDrawTiled(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const float_t width,
|
||||
const float_t height,
|
||||
const tileset_t *tileset,
|
||||
const uint16_t column,
|
||||
const uint16_t row,
|
||||
const bool_t drawInner,
|
||||
texture_t *texture
|
||||
) {
|
||||
assertNotNull(tileset, "Tileset cannot be NULL");
|
||||
assertNotNull(texture, "Texture cannot be NULL");
|
||||
|
||||
if(height <= 0 || width <= 0) return;
|
||||
|
||||
uint32_t segmentsX, segmentsY;
|
||||
float_t remainderX, remainderY;
|
||||
segmentsX = (width - (tileset->tileWidth * 2)) / tileset->tileWidth;
|
||||
segmentsY = (height - (tileset->tileHeight * 2)) / tileset->tileHeight;
|
||||
remainderX = fmodf(width - (tileset->tileWidth * 2), tileset->tileWidth);
|
||||
remainderY = fmodf(height - (tileset->tileHeight * 2), tileset->tileHeight);
|
||||
|
||||
// Corners
|
||||
vec4 uv;
|
||||
|
||||
// Top-Left
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column,
|
||||
row,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y,
|
||||
x + tileset->tileWidth,
|
||||
y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Top-Right
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 2,
|
||||
row,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, y,
|
||||
x + width, y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Bottom-Left
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column,
|
||||
row + 2,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y + height - tileset->tileHeight,
|
||||
x + tileset->tileWidth, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Bottom-Right
|
||||
tilesetPositionGetUV(
|
||||
tileset,
|
||||
column + 2,
|
||||
row + 2,
|
||||
uv
|
||||
);
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, y + height - tileset->tileHeight,
|
||||
x + width, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
|
||||
// Top and Bottom Edges (Tiled)
|
||||
tilesetPositionGetUV(tileset, column + 1, row, uv); // Top edge
|
||||
float_t edgeX = x + tileset->tileWidth;
|
||||
for(uint32_t i = 0; i < segmentsX; ++i, edgeX += tileset->tileWidth) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
edgeX, y,
|
||||
edgeX + tileset->tileWidth, y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderX) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
edgeX, y,
|
||||
edgeX + remainderX, y + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
tilesetPositionGetUV(tileset, column + 1, row + 2, uv); // Bottom edge
|
||||
edgeX = x + tileset->tileWidth;
|
||||
for(uint32_t i = 0; i < segmentsX; ++i, edgeX += tileset->tileWidth) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
edgeX, y + height - tileset->tileHeight,
|
||||
edgeX + tileset->tileWidth, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderX) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
edgeX, y + height - tileset->tileHeight,
|
||||
edgeX + remainderX, y + height,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
// Left and Right Edges (Tiled)
|
||||
tilesetPositionGetUV(tileset, column, row + 1, uv); // Left edge
|
||||
float_t edgeY = y + tileset->tileHeight;
|
||||
for(uint32_t i = 0; i < segmentsY; ++i, edgeY += tileset->tileHeight) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, edgeY,
|
||||
x + tileset->tileWidth, edgeY + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderY) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, edgeY,
|
||||
x + tileset->tileWidth, edgeY + remainderY,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
tilesetPositionGetUV(tileset, column + 2, row + 1, uv); // Right edge
|
||||
edgeY = y + tileset->tileHeight;
|
||||
for(uint32_t i = 0; i < segmentsY; ++i, edgeY += tileset->tileHeight) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, edgeY,
|
||||
x + width, edgeY + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderY) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x + width - tileset->tileWidth, edgeY,
|
||||
x + width, edgeY + remainderY,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
// Center (Tiled)
|
||||
if(!drawInner) return;
|
||||
|
||||
tilesetPositionGetUV(tileset, column + 1, row + 1, uv); // Center tile
|
||||
float_t centerY = y + tileset->tileHeight;
|
||||
for(uint32_t j = 0; j < segmentsY; ++j, centerY += tileset->tileHeight) {
|
||||
float_t centerX = x + tileset->tileWidth;
|
||||
for(uint32_t i = 0; i < segmentsX; ++i, centerX += tileset->tileWidth) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
centerX, centerY,
|
||||
centerX + tileset->tileWidth, centerY + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderX) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
centerX, centerY,
|
||||
centerX + remainderX, centerY + tileset->tileHeight,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
}
|
||||
if(remainderY) {
|
||||
float_t centerX = x + tileset->tileWidth;
|
||||
for(uint32_t i = 0; i < segmentsX; ++i, centerX += tileset->tileWidth) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
centerX, centerY,
|
||||
centerX + tileset->tileWidth, centerY + remainderY,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
if(remainderX) {
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
centerX, centerY,
|
||||
centerX + remainderX, centerY + remainderY,
|
||||
COLOR_WHITE,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/tileset/tileset.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
/**
|
||||
* Draw a UI Frame (using the 9-slice technique).
|
||||
*
|
||||
* @param x The x position to draw the frame at.
|
||||
* @param y The y position to draw the frame at.
|
||||
* @param width The width of the frame.
|
||||
* @param height The height of the frame.
|
||||
* @param tileset The tileset to use for rendering the frame.
|
||||
* @param column The column in the tileset to use for the frame.
|
||||
* @param row The row in the tileset to use for the frame.
|
||||
* @param drawInner Whether to draw the inner area.
|
||||
* @param texture The texture associated with the tileset.
|
||||
*/
|
||||
void uiFrameDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const float_t width,
|
||||
const float_t height,
|
||||
const tileset_t *tileset,
|
||||
const uint16_t column,
|
||||
const uint16_t row,
|
||||
const bool_t drawInner,
|
||||
texture_t *texture
|
||||
);
|
||||
|
||||
/**
|
||||
* Draw a tiled UI Frame (using the 9-slice technique). This will tile the
|
||||
* center components to allow them to repeat without distortion.
|
||||
*
|
||||
* @param x The x position to draw the frame at.
|
||||
* @param y The y position to draw the frame at.
|
||||
* @param width The width of the frame.
|
||||
* @param height The height of the frame.
|
||||
* @param tileset The tileset to use for rendering the frame.
|
||||
* @param column The column in the tileset to use for the frame.
|
||||
* @param row The row in the tileset to use for the frame.
|
||||
* @param drawInner Whether to draw the inner tiled area.
|
||||
* @param texture The texture associated with the tileset.
|
||||
*/
|
||||
void uiFrameDrawTiled(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const float_t width,
|
||||
const float_t height,
|
||||
const tileset_t *tileset,
|
||||
const uint16_t column,
|
||||
const uint16_t row,
|
||||
const bool_t drawInner,
|
||||
texture_t *texture
|
||||
);
|
||||
@@ -1,111 +0,0 @@
|
||||
// /**
|
||||
// * Copyright (c) 2025 Dominic Masters
|
||||
// *
|
||||
// * This software is released under the MIT License.
|
||||
// * https://opensource.org/licenses/MIT
|
||||
// */
|
||||
|
||||
#include "uitext.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/spritebatch.h"
|
||||
|
||||
void uiTextDrawChar(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t c,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
) {
|
||||
int32_t tileIndex = (int32_t)(c) - UI_TEXT_CHAR_START;
|
||||
if(tileIndex < 0 || tileIndex >= tileset->tileCount) {
|
||||
tileIndex = ((int32_t)'@') - UI_TEXT_CHAR_START;
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
tileIndex >= 0 && tileIndex <= tileset->tileCount,
|
||||
"Character is out of bounds for font tiles"
|
||||
);
|
||||
|
||||
vec4 uv;
|
||||
tilesetTileGetUV(tileset, tileIndex, uv);
|
||||
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y,
|
||||
x + tileset->tileWidth,
|
||||
y + tileset->tileHeight,
|
||||
color,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
void uiTextDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
) {
|
||||
assertNotNull(text, "Text cannot be NULL");
|
||||
|
||||
float_t posX = x;
|
||||
float_t posY = y;
|
||||
|
||||
char_t c;
|
||||
int32_t i = 0;
|
||||
while((c = text[i++]) != '\0') {
|
||||
if(c == '\n') {
|
||||
posX = x;
|
||||
posY += tileset->tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == ' ') {
|
||||
posX += tileset->tileWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
uiTextDrawChar(posX, posY, c, color, tileset, texture);
|
||||
posX += tileset->tileWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void uiTextMeasure(
|
||||
const char_t *text,
|
||||
const tileset_t *tileset,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight
|
||||
) {
|
||||
assertNotNull(text, "Text cannot be NULL");
|
||||
assertNotNull(outWidth, "Output width pointer cannot be NULL");
|
||||
assertNotNull(outHeight, "Output height pointer cannot be NULL");
|
||||
|
||||
int32_t width = 0;
|
||||
int32_t height = tileset->tileHeight;
|
||||
int32_t lineWidth = 0;
|
||||
|
||||
char_t c;
|
||||
int32_t i = 0;
|
||||
while((c = text[i++]) != '\0') {
|
||||
if(c == '\n') {
|
||||
if(lineWidth > width) {
|
||||
width = lineWidth;
|
||||
}
|
||||
lineWidth = 0;
|
||||
height += tileset->tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
lineWidth += tileset->tileWidth;
|
||||
}
|
||||
|
||||
if(lineWidth > width) {
|
||||
width = lineWidth;
|
||||
}
|
||||
|
||||
*outWidth = width;
|
||||
*outHeight = height;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
|
||||
#define UI_TEXT_CHAR_START '!'
|
||||
|
||||
/**
|
||||
* Draws a single character at the specified position.
|
||||
*
|
||||
* @param x The x-coordinate to draw the character at.
|
||||
* @param y The y-coordinate to draw the character at.
|
||||
* @param c The character to draw.
|
||||
* @param color The color to draw the character in.
|
||||
* @param tileset Font tileset to use for rendering.
|
||||
* @param texture Texture containing the font tileset image.
|
||||
*/
|
||||
void uiTextDrawChar(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t c,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
);
|
||||
|
||||
/**
|
||||
* Draws a string of text at the specified position.
|
||||
*
|
||||
* @param x The x-coordinate to draw the text at.
|
||||
* @param y The y-coordinate to draw the text at.
|
||||
* @param text The null-terminated string of text to draw.
|
||||
* @param color The color to draw the text in.
|
||||
* @param tileset Font tileset to use for rendering.
|
||||
* @param texture Texture containing the font tileset image.
|
||||
*/
|
||||
void uiTextDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
);
|
||||
|
||||
/**
|
||||
* Measures the width and height of the given text string when rendered.
|
||||
*
|
||||
* @param text The null-terminated string of text to measure.
|
||||
* @param tileset Font tileset to use for measurement.
|
||||
* @param outWidth Pointer to store the measured width in pixels.
|
||||
* @param outHeight Pointer to store the measured height in pixels.
|
||||
*/
|
||||
void uiTextMeasure(
|
||||
const char_t *text,
|
||||
const tileset_t *tileset,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight
|
||||
);
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uitextbox.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/uitext.h"
|
||||
// #include "rpg/rpgtextbox.h"
|
||||
#include "display/screen.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "input/input.h"
|
||||
|
||||
// void uiTextboxUpdate() {
|
||||
// if(!rpgTextboxIsVisible()) return;
|
||||
|
||||
// if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
||||
// rpgTextboxHide();
|
||||
// }
|
||||
// }
|
||||
|
||||
// void uiTextboxRender() {
|
||||
// if(!rpgTextboxIsVisible()) return;
|
||||
|
||||
// const char_t *text = RPG_TEXTBOX.text;
|
||||
// int32_t textWidth, textHeight;
|
||||
|
||||
// uiTextMeasure(text, UI.fontTileset, &textWidth, &textHeight);
|
||||
|
||||
// float_t y = 0;
|
||||
// if(RPG_TEXTBOX.position == RPG_TEXTBOX_POS_BOTTOM) {
|
||||
// y = SCREEN.height - (float_t)textHeight;
|
||||
// }
|
||||
|
||||
// spriteBatchPush(
|
||||
// NULL,
|
||||
// 0.0f, y,
|
||||
// (float_t)SCREEN.width, (float_t)(y + textHeight),
|
||||
// COLOR_BLACK,
|
||||
// 0.0f, 0.0f, 1.0f, 1.0f
|
||||
// );
|
||||
// uiTextDraw(0, y, text, COLOR_RED, UI.fontTileset, &UI.fontTexture);
|
||||
// }
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
/**
|
||||
* Updates the RPG textbox state.
|
||||
*/
|
||||
void uiTextboxUpdate();
|
||||
|
||||
/**
|
||||
* Draws the RPG textbox if it is visible.
|
||||
*/
|
||||
void uiTextboxRender();
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) 2026 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
// Two kinds of UI elements, those that are scripted (with a state, logic, etc)
|
||||
// and those that are draw only (rectangle, text, etc).
|
||||
@@ -1,21 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DUSK_GAME_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "Game assets directory")
|
||||
|
||||
# Palette asset needs to be added before any images.
|
||||
add_subdirectory(palette)
|
||||
|
||||
# Languages need to be added before anything that uses text.
|
||||
add_subdirectory(locale)
|
||||
|
||||
# Rest, order doesn't matter
|
||||
add_asset(SCRIPT init.lua)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(map)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(scene)
|
||||
@@ -0,0 +1,47 @@
|
||||
var Actions;
|
||||
var camera, cameraPosition;
|
||||
var cube, cubePosition, cubeRenderable, cubeMesh;
|
||||
var ground, groundPosition, groundRenderable;
|
||||
|
||||
// init() is called via scriptManagerCallGlobal(), which pumps the asset
|
||||
// system + job queue until any promise it returns settles - so it's safe
|
||||
// to await include() here even though this runs before the main loop.
|
||||
async function init() {
|
||||
Actions = await include("input.js");
|
||||
|
||||
camera = new Entity();
|
||||
cameraPosition = camera.add(POSITION);
|
||||
camera.add(CAMERA);
|
||||
cameraPosition.position = new Vec3(3, 3, -6);
|
||||
cameraPosition.lookAt(new Vec3(0, 0, 0));
|
||||
|
||||
cube = new Entity();
|
||||
cubePosition = cube.add(POSITION);
|
||||
cubeRenderable = cube.add(RENDERABLE);
|
||||
cubeMesh = Mesh.createCube();
|
||||
cubeRenderable.mesh = cubeMesh;
|
||||
cubeRenderable.color = Color.red();
|
||||
|
||||
ground = new Entity();
|
||||
groundPosition = ground.add(POSITION);
|
||||
groundRenderable = ground.add(RENDERABLE);
|
||||
groundRenderable.mesh = Mesh.createCube();
|
||||
groundRenderable.color = Color.dark_gray();
|
||||
}
|
||||
|
||||
// Runs every frame (including dynamic/interpolation frames) - use for
|
||||
// smooth, purely presentational animation.
|
||||
function update() {
|
||||
cubePosition.rotation.y += TIME.delta * 1.5;
|
||||
cubePosition.rotation.x += TIME.delta * 0.7;
|
||||
}
|
||||
|
||||
// Runs once per fixed timestep only - use for gameplay logic that should
|
||||
// be deterministic and independent of display refresh rate.
|
||||
function fixedUpdate() {
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
cube.dispose();
|
||||
camera.dispose();
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(TILESET entities.tsx)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 336 B |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.11.2" name="entities" tilewidth="16" tileheight="16" tilecount="64" columns="8">
|
||||
<image source="entities.png" width="128" height="128"/>
|
||||
</tileset>
|
||||
@@ -1,56 +0,0 @@
|
||||
module('platform')
|
||||
module('input')
|
||||
module('scene')
|
||||
module('locale')
|
||||
|
||||
-- Default Input bindings.
|
||||
if PLATFORM == "psp" then
|
||||
inputBind("up", INPUT_ACTION_UP)
|
||||
inputBind("down", INPUT_ACTION_DOWN)
|
||||
inputBind("left", INPUT_ACTION_LEFT)
|
||||
inputBind("right", INPUT_ACTION_RIGHT)
|
||||
inputBind("circle", INPUT_ACTION_CANCEL)
|
||||
inputBind("cross", INPUT_ACTION_ACCEPT)
|
||||
inputBind("select", INPUT_ACTION_RAGEQUIT)
|
||||
inputBind("lstick_up", INPUT_ACTION_UP)
|
||||
inputBind("lstick_down", INPUT_ACTION_DOWN)
|
||||
inputBind("lstick_left", INPUT_ACTION_LEFT)
|
||||
inputBind("lstick_right", INPUT_ACTION_RIGHT)
|
||||
|
||||
elseif PLATFORM == "gamecube" then
|
||||
-- inputBind("start", INPUT_ACTION_RAGEQUIT)
|
||||
-- inputBind("dpad_up", INPUT_ACTION_UP)
|
||||
-- inputBind("dpad_down", INPUT_ACTION_DOWN)
|
||||
-- inputBind("dpad_left", INPUT_ACTION_LEFT)
|
||||
-- inputBind("dpad_right", INPUT_ACTION_RIGHT)
|
||||
-- inputBind("button_b", INPUT_ACTION_CANCEL)
|
||||
-- inputBind("button_a", INPUT_ACTION_ACCEPT)
|
||||
-- inputBind("button_start", INPUT_ACTION_RAGEQUIT)
|
||||
-- inputBind("lstick_up", INPUT_ACTION_UP)
|
||||
-- inputBind("lstick_down", INPUT_ACTION_DOWN)
|
||||
-- inputBind("lstick_left", INPUT_ACTION_LEFT)
|
||||
-- inputBind("lstick_right", INPUT_ACTION_RIGHT)
|
||||
|
||||
else
|
||||
if INPUT_KEYBOARD then
|
||||
inputBind("w", INPUT_ACTION_UP)
|
||||
inputBind("s", INPUT_ACTION_DOWN)
|
||||
inputBind("a", INPUT_ACTION_LEFT)
|
||||
inputBind("d", INPUT_ACTION_RIGHT)
|
||||
|
||||
inputBind("left", INPUT_ACTION_LEFT)
|
||||
inputBind("right", INPUT_ACTION_RIGHT)
|
||||
inputBind("up", INPUT_ACTION_UP)
|
||||
inputBind("down", INPUT_ACTION_DOWN)
|
||||
|
||||
inputBind("enter", INPUT_ACTION_ACCEPT)
|
||||
inputBind("e", INPUT_ACTION_ACCEPT)
|
||||
|
||||
inputBind("q", INPUT_ACTION_CANCEL)
|
||||
|
||||
inputBind("escape", INPUT_ACTION_RAGEQUIT)
|
||||
end
|
||||
end
|
||||
|
||||
-- localeSet(DUSK_LOCALE_EN_US)
|
||||
sceneSet('scene/initial.dsf')
|
||||
@@ -0,0 +1,27 @@
|
||||
// Binds physical buttons to abstract actions, then exports the action
|
||||
// constants so other scripts don't need to know raw INPUT_ACTION_* names.
|
||||
Input.bind("w", INPUT_ACTION_UP);
|
||||
Input.bind("s", INPUT_ACTION_DOWN);
|
||||
Input.bind("a", INPUT_ACTION_LEFT);
|
||||
Input.bind("d", INPUT_ACTION_RIGHT);
|
||||
Input.bind("space", INPUT_ACTION_ACCEPT);
|
||||
Input.bind("escape", INPUT_ACTION_RAGEQUIT);
|
||||
|
||||
if(typeof INPUT_GAMEPAD !== "undefined") {
|
||||
Input.bind("gamepad_up", INPUT_ACTION_UP);
|
||||
Input.bind("gamepad_down", INPUT_ACTION_DOWN);
|
||||
Input.bind("gamepad_left", INPUT_ACTION_LEFT);
|
||||
Input.bind("gamepad_right", INPUT_ACTION_RIGHT);
|
||||
Input.bind("gamepad_a", INPUT_ACTION_ACCEPT);
|
||||
Input.bind("gamepad_start", INPUT_ACTION_RAGEQUIT);
|
||||
}
|
||||
|
||||
module = {
|
||||
UP: INPUT_ACTION_UP,
|
||||
DOWN: INPUT_ACTION_DOWN,
|
||||
LEFT: INPUT_ACTION_LEFT,
|
||||
RIGHT: INPUT_ACTION_RIGHT,
|
||||
ACCEPT: INPUT_ACTION_ACCEPT,
|
||||
CANCEL: INPUT_ACTION_CANCEL,
|
||||
RAGEQUIT: INPUT_ACTION_RAGEQUIT
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(LANGUAGE en_US.po)
|
||||
+2
-15
@@ -1,15 +1,2 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: en_US\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "ui.test"
|
||||
msgstr "Hello this is a test."
|
||||
|
||||
msgid "map.test"
|
||||
msgstr "This is a map test."
|
||||
|
||||
msgid "test.test2"
|
||||
msgstr "This is another test."
|
||||
msgid "test.string"
|
||||
msgstr "This is a test string"
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(testmap)
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(MAP testmap.json)
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []}
|
||||
@@ -1 +0,0 @@
|
||||
{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Test"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(PALETTE palette0.png)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user