Compare commits
588
Commits
77d3c54ebb
...
we-ball
| 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 | ||
|
|
bb7db57bda | ||
|
|
6a83ac767c | ||
|
|
7e47ef9d74 | ||
|
|
e7ec603526 | ||
|
|
2d8ae09bd8 | ||
|
|
b2affbc0a7 | ||
|
|
d50bc61ada | ||
|
|
ec6b032b45 | ||
|
|
bc72f48496 | ||
|
|
dcf06fbd36 | ||
|
|
96311d72c2 | ||
|
|
07938cccc7 | ||
|
|
097c8c00f9 | ||
|
|
aa5b41fe31 | ||
|
|
0d56859d94 | ||
|
|
1af5f238e4 | ||
|
|
dd697d5650 | ||
|
|
5cf299a1c7 | ||
|
|
67bf825cc9 | ||
|
|
56e1696cd4 | ||
|
|
d955fb6430 | ||
|
|
dd910a31aa | ||
|
|
708c4d0ec3 | ||
|
|
ad13d6c6a1 | ||
|
|
1c32158142 | ||
|
|
5cea284906 | ||
|
|
13dba8b604 | ||
|
|
22398ddcef | ||
|
|
94e2cc6210 | ||
|
|
da3513f63d | ||
|
|
2c83e4ba9f | ||
|
|
c862071126 | ||
|
|
fed819e9b2 | ||
|
|
c6f4518684 | ||
|
|
053778a502 | ||
|
|
78e1ae885a | ||
|
|
982d28a3e0 | ||
|
|
c2cad858a5 | ||
|
|
794e0574ad | ||
|
|
c190271565 | ||
|
|
ae8a869f64 | ||
|
|
69d64eb8e4 | ||
|
|
b2f2df650a | ||
|
|
6af570fab2 | ||
|
|
9ed902017c | ||
|
|
32b41c98e1 | ||
|
|
6bdb4ae30d | ||
|
|
25dc97e3cc | ||
|
|
cc85983736 | ||
|
|
6e78ee188d | ||
|
|
9b73f1717f | ||
|
|
c7b9a53535 | ||
|
|
2b9be6675c | ||
|
|
fb93453482 | ||
|
|
81b08b2eba | ||
|
|
d1b03c4cb3 | ||
|
|
9544d15a18 | ||
|
|
0392dd0e7f | ||
|
|
9c25fde548 | ||
|
|
2c9d0c6cff | ||
|
|
9897dbe031 | ||
|
|
e78f117cfd | ||
|
|
07afc3813a | ||
|
|
d788de8637 | ||
|
|
d749ac8a91 | ||
|
|
f71c271c97 | ||
|
|
e1d7b7308f | ||
|
|
26a71a823a | ||
|
|
5e39097faa | ||
|
|
0df7845f2c | ||
|
|
af5bf987c8 | ||
|
|
024ace1078 | ||
|
|
8d00fe9d16 | ||
|
|
ab422b14dd | ||
|
|
95c0690216 | ||
|
|
6cb80e9e23 | ||
|
|
83b799caa8 | ||
|
|
a793ac2ff7 | ||
|
|
aec937b04b | ||
|
|
8ee46fd204 | ||
|
|
726233e55f | ||
|
|
7940f4c487 | ||
|
|
b16dbaceec | ||
|
|
f39b2060a8 | ||
|
|
aed202ebf9 | ||
|
|
a495179e5f | ||
|
|
4e1b404820 | ||
|
|
8c74ee31e0 |
@@ -1,58 +0,0 @@
|
||||
name: Build Dusk
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
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
|
||||
- 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
|
||||
+6
-1
@@ -83,7 +83,6 @@ assets/borrowed
|
||||
.VSCode*
|
||||
|
||||
/vita
|
||||
|
||||
._*
|
||||
|
||||
*~
|
||||
@@ -102,3 +101,9 @@ yarn.lock
|
||||
|
||||
.editor
|
||||
.venv
|
||||
|
||||
/build2
|
||||
/build*
|
||||
/assets/test
|
||||
/tools_old
|
||||
/assets/test.png
|
||||
+84
-74
@@ -5,14 +5,19 @@
|
||||
|
||||
# Setup
|
||||
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)
|
||||
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "linux")
|
||||
#set(DUSK_TARGET_SYSTEM "psp")
|
||||
endif()
|
||||
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")
|
||||
@@ -21,100 +26,105 @@ set(DUSK_CACHE_TARGET "dusk-target")
|
||||
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
||||
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
||||
set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src")
|
||||
set(DUSK_TEST_DIR "${DUSK_ROOT_DIR}/test")
|
||||
set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
||||
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
||||
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
||||
set(DUSK_ASSETS_DIR "${DUSK_ROOT_DIR}/assets")
|
||||
set(DUSK_BUILT_ASSETS_DIR "${DUSK_BUILD_DIR}/built_assets" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
set(DUSK_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated")
|
||||
set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
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})
|
||||
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")
|
||||
endif()
|
||||
|
||||
# Create directories
|
||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||
file(MAKE_DIRECTORY ${DUSK_TEMP_DIR})
|
||||
file(MAKE_DIRECTORY ${DUSK_BUILT_ASSETS_DIR})
|
||||
|
||||
# Find packages
|
||||
# Required build packages
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
# Toolchains
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
find_package(pspsdk REQUIRED)
|
||||
endif()
|
||||
|
||||
# Init Project
|
||||
project(${DUSK_TARGET_NAME}
|
||||
# Init Project.
|
||||
project(${DUSK_LIBRARY_TARGET_NAME}
|
||||
VERSION 1.0.0
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
# Executable
|
||||
add_executable(${DUSK_TARGET_NAME})
|
||||
# Either, create library and binary separately (used for tests), or make them
|
||||
# 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)
|
||||
|
||||
# Link library to binary
|
||||
target_link_libraries(${DUSK_BINARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
else()
|
||||
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_TARGET_NAME} PRIVATE
|
||||
SDL2
|
||||
OpenGL::GL
|
||||
GL
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(${DUSK_TARGET_NAME} PUBLIC
|
||||
${SDL2_LIBRARIES}
|
||||
SDL2
|
||||
OpenGL::GL
|
||||
zip
|
||||
bz2
|
||||
z
|
||||
mbedtls
|
||||
mbedcrypto
|
||||
lzma
|
||||
)
|
||||
target_include_directories(${DUSK_TARGET_NAME} PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
# Add code
|
||||
add_subdirectory(src)
|
||||
|
||||
# Build assets
|
||||
add_custom_target(DUSK_ASSETS_BUILT ALL
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${DUSK_TOOLS_DIR}/assettool.py
|
||||
--assets ${DUSK_GAME_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_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||
|
||||
# Include generated headers
|
||||
target_include_directories(${DUSK_TARGET_NAME} PUBLIC
|
||||
# Include generated headers from tools.
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${DUSK_GENERATED_HEADERS_DIR}
|
||||
)
|
||||
|
||||
# Postbuild
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
create_pbp_file(
|
||||
TARGET "${DUSK_TARGET_NAME}"
|
||||
ICON_PATH NULL
|
||||
BACKGROUND_PATH NULL
|
||||
PREVIEW_PATH NULL
|
||||
TITLE "${DUSK_TARGET_NAME}"
|
||||
PSAR_PATH ${DUSK_BUILD_DIR}/dusk.dsk
|
||||
VERSION 01.00
|
||||
# Add main code
|
||||
add_subdirectory(${DUSK_SOURCES_DIR})
|
||||
|
||||
# Include generated headers
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${DUSK_GENERATED_HEADERS_DIR}
|
||||
)
|
||||
|
||||
# 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
|
||||
@@ -9,7 +10,7 @@ following packages, depending on your system;
|
||||
|
||||
Fedora;
|
||||
```
|
||||
sudo dnf install git make gcc python python-polib python3-pillow python3-dotenv python3-numpy python-qt5 python3-pyopengl
|
||||
sudo dnf install git make gcc cmake python python-polib python3-pillow python3-dotenv python3-numpy python-qt5 python3-pyopengl SDL2-devel zlib-devel libzip-devel bzip2-devel openssl-devel lzma-sdk-devel xz xz-devel lua-devel
|
||||
```
|
||||
|
||||
Ubuntu;
|
||||
|
||||
@@ -1,17 +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 ${DUSK_CACHE_TARGET})
|
||||
|
||||
# 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)
|
||||
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(map)
|
||||
add_subdirectory(ui)
|
||||
@@ -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();
|
||||
}
|
||||
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>
|
||||
@@ -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
|
||||
};
|
||||
+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,3 +0,0 @@
|
||||
{
|
||||
"mapName": "Test"
|
||||
}
|
||||
@@ -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]}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 241 B |
Binary file not shown.
@@ -1 +0,0 @@
|
||||
print("Test Lua script")
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 758 B |
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.11.2" name="prarie" tilewidth="16" tileheight="16" tilecount="21" columns="7">
|
||||
<image source="prarie.png" width="112" height="48"/>
|
||||
</tileset>
|
||||
@@ -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 minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
Binary file not shown.
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"automappingRulesFile": "",
|
||||
"commands": [
|
||||
],
|
||||
"compatibilityVersion": 1100,
|
||||
"extensionsPath": "extensions",
|
||||
"folders": [
|
||||
"."
|
||||
],
|
||||
"properties": [
|
||||
],
|
||||
"propertyTypes": [
|
||||
]
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
{
|
||||
"Map/SizeTest": {
|
||||
"height": 4300,
|
||||
"width": 2
|
||||
},
|
||||
"activeFile": "map/untitled.tmx",
|
||||
"expandedProjectPaths": [
|
||||
"tileset",
|
||||
".",
|
||||
"map"
|
||||
],
|
||||
"file.lastUsedOpenFilter": "All Files (*)",
|
||||
"fileStates": {
|
||||
"entity/entities.tsx": {
|
||||
"scaleInDock": 1,
|
||||
"scaleInEditor": 1
|
||||
},
|
||||
"map/prarie.tsx": {
|
||||
"scaleInDock": 1,
|
||||
"scaleInEditor": 11
|
||||
},
|
||||
"map/untitled.tmx": {
|
||||
"scale": 2,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 285.5,
|
||||
"y": 162.75
|
||||
}
|
||||
},
|
||||
"tileset/prarie.tsx": {
|
||||
"scaleInDock": 1,
|
||||
"scaleInEditor": 1
|
||||
}
|
||||
},
|
||||
"last.imagePath": "/home/yourwishes/htdocs/dusk/assets/tileset",
|
||||
"map.lastUsedFormat": "tmx",
|
||||
"map.tileHeight": 16,
|
||||
"map.tileWidth": 16,
|
||||
"openFiles": [
|
||||
"entity/entities.tsx",
|
||||
"map/untitled.tmx",
|
||||
"tileset/prarie.tsx"
|
||||
],
|
||||
"project": "untitled.tiled-project",
|
||||
"recentFiles": [
|
||||
"entity/entities.tsx",
|
||||
"tileset/prarie.tsx",
|
||||
"map/untitled.tmx",
|
||||
"map/prarie.tsx"
|
||||
],
|
||||
"tileset.lastUsedFormat": "tsx",
|
||||
"tileset.tileSize": {
|
||||
"height": 16,
|
||||
"width": 16
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
cglm
|
||||
# GIT_REPOSITORY https://git.wish.moe/YourWishes/cglm.git
|
||||
GIT_REPOSITORY https://github.com/recp/cglm.git
|
||||
GIT_TAG v0.9.6
|
||||
)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
cmocka
|
||||
GIT_REPOSITORY https://gitlab.com/cmocka/cmocka.git
|
||||
GIT_TAG cmocka-2.0.1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(cmocka)
|
||||
set(cmocka_FOUND ON)
|
||||
@@ -0,0 +1,96 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Turn things off we don't need
|
||||
set(JERRY_CMDLINE OFF CACHE BOOL "" FORCE)
|
||||
set(JERRY_EXT ON CACHE BOOL "" FORCE)
|
||||
set(JERRY_DEBUGGER OFF CACHE BOOL "" FORCE)
|
||||
set(JERRY_BUILTIN_DATE OFF CACHE BOOL "" FORCE)
|
||||
set(ENABLE_LTO OFF CACHE BOOL "" FORCE)
|
||||
|
||||
# Fetch Jerry
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
jerryscript
|
||||
GIT_REPOSITORY https://git.wish.moe/YourWishes/jerryscript
|
||||
GIT_TAG float32-fix
|
||||
)
|
||||
FetchContent_MakeAvailable(jerryscript)
|
||||
|
||||
# Mark found
|
||||
set(jerryscript_FOUND ON)
|
||||
|
||||
# Define targets
|
||||
if(TARGET jerryscript-core)
|
||||
set(JERRY_CORE_TARGET jerryscript-core)
|
||||
elseif(TARGET jerry-core)
|
||||
set(JERRY_CORE_TARGET jerry-core)
|
||||
endif()
|
||||
|
||||
if(TARGET jerryscript-ext)
|
||||
set(JERRY_EXT_TARGET jerryscript-ext)
|
||||
elseif(TARGET jerry-ext)
|
||||
set(JERRY_EXT_TARGET jerry-ext)
|
||||
endif()
|
||||
|
||||
if(TARGET jerryscript-port-default)
|
||||
set(JERRY_PORT_TARGET jerryscript-port-default)
|
||||
elseif(TARGET jerry-port-default)
|
||||
set(JERRY_PORT_TARGET jerry-port-default)
|
||||
elseif(TARGET jerryscript-port)
|
||||
set(JERRY_PORT_TARGET jerryscript-port)
|
||||
elseif(TARGET jerry-port)
|
||||
set(JERRY_PORT_TARGET jerry-port)
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_CORE_TARGET)
|
||||
message(FATAL_ERROR "JerryScript core target not found")
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_EXT_TARGET)
|
||||
message(FATAL_ERROR "JerryScript ext target not found")
|
||||
endif()
|
||||
|
||||
if(NOT JERRY_PORT_TARGET)
|
||||
message(FATAL_ERROR "JerryScript port target not found")
|
||||
endif()
|
||||
|
||||
foreach(tgt IN ITEMS
|
||||
${JERRY_CORE_TARGET}
|
||||
${JERRY_EXT_TARGET}
|
||||
${JERRY_PORT_TARGET}
|
||||
)
|
||||
if(TARGET ${tgt})
|
||||
set_property(TARGET ${tgt} PROPERTY INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
target_compile_definitions(${JERRY_CORE_TARGET} PRIVATE
|
||||
JERRY_NUMBER_TYPE_FLOAT64=0
|
||||
JERRY_BUILTIN_DATE=0
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Export include dirs through the targets
|
||||
target_include_directories(${JERRY_CORE_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-core/include
|
||||
)
|
||||
|
||||
target_include_directories(${JERRY_EXT_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-ext/include
|
||||
)
|
||||
|
||||
target_include_directories(${JERRY_PORT_TARGET} INTERFACE
|
||||
${jerryscript_SOURCE_DIR}/jerry-port/default/include
|
||||
)
|
||||
|
||||
# Suppress JerryScript-only warning
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${JERRY_CORE_TARGET} PRIVATE
|
||||
-Wno-error
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(jerryscript::core ALIAS ${JERRY_CORE_TARGET})
|
||||
add_library(jerryscript::ext ALIAS ${JERRY_EXT_TARGET})
|
||||
add_library(jerryscript::port ALIAS ${JERRY_PORT_TARGET})
|
||||
@@ -1,59 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
if(NOT TARGET lua)
|
||||
message(STATUS "Looking for Lua...")
|
||||
|
||||
set(LUA_FOUND FALSE CACHE INTERNAL "Lua found")
|
||||
set(LUA_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_lua")
|
||||
set(LUA_SEARCH_ROOTS
|
||||
"${LUA_ROOT}"
|
||||
"$ENV{LUADEV}"
|
||||
"$ENV{HOME}/luadev"
|
||||
"/usr/local/luadev"
|
||||
"/opt/luadev"
|
||||
"/usr/luadev"
|
||||
"${LUA_DOWNLOAD_DIR}/luadev"
|
||||
)
|
||||
|
||||
foreach(root IN LISTS LUA_SEARCH_ROOTS)
|
||||
list(APPEND LUA_BIN_HINTS "${root}/bin")
|
||||
list(APPEND LUA_INCLUDE_HINTS "${root}/include")
|
||||
list(APPEND LUA_LIB_HINTS "${root}/lib")
|
||||
endforeach()
|
||||
|
||||
# Find Lua interpreter
|
||||
find_program(LUA_EXECUTABLE NAMES lua HINTS ${LUA_BIN_HINTS})
|
||||
|
||||
# Find Lua headers and library
|
||||
find_path(LUA_INCLUDE_DIR lua.h HINTS ${LUA_INCLUDE_HINTS})
|
||||
find_library(LUA_LIBRARY NAMES lua HINTS ${LUA_LIB_HINTS})
|
||||
|
||||
# If not found, use FetchContent to download and build Lua
|
||||
if(NOT LUA_EXECUTABLE OR NOT LUA_INCLUDE_DIR OR NOT LUA_LIBRARY)
|
||||
message(STATUS "Lua not found in system paths. Using FetchContent to download and build Lua.")
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
lua
|
||||
GIT_REPOSITORY https://github.com/lua/lua.git
|
||||
GIT_TAG v5.4.6 # Change to desired version
|
||||
)
|
||||
FetchContent_MakeAvailable(lua)
|
||||
# Try to locate built Lua
|
||||
set(LUA_INCLUDE_DIR "${lua_SOURCE_DIR}")
|
||||
set(LUA_LIBRARY "${lua_BINARY_DIR}/liblua.a")
|
||||
set(LUA_EXECUTABLE "${lua_BINARY_DIR}/lua")
|
||||
endif()
|
||||
|
||||
if(LUA_EXECUTABLE AND LUA_INCLUDE_DIR AND LUA_LIBRARY)
|
||||
set(LUA_FOUND TRUE CACHE INTERNAL "Lua found")
|
||||
add_library(lua INTERFACE IMPORTED)
|
||||
set_target_properties(lua PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${LUA_LIBRARY}"
|
||||
)
|
||||
message(STATUS "Lua found: ${LUA_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,106 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
if(NOT TARGET pspsdk)
|
||||
message(STATUS "Looking for PSPSDK...")
|
||||
|
||||
set(PSPSDK_FOUND FALSE CACHE INTERNAL "PSPSDK found")
|
||||
set(PSPSDK_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_pspsdk")
|
||||
set(PSPSDK_SEARCH_ROOTS
|
||||
"${PSPSDK_ROOT}"
|
||||
"$ENV{PSPDEV}"
|
||||
"$ENV{HOME}/pspdev"
|
||||
"/usr/local/pspdev"
|
||||
"/opt/pspdev"
|
||||
"/usr/pspdev"
|
||||
"${PSPSDK_DOWNLOAD_DIR}/pspdev"
|
||||
)
|
||||
|
||||
foreach(root IN LISTS PSPSDK_SEARCH_ROOTS)
|
||||
list(APPEND PSPSDK_BIN_HINTS "${root}/bin")
|
||||
list(APPEND PSPSDK_INCLUDE_HINTS "${root}/include")
|
||||
list(APPEND PSPSDK_LIB_HINTS "${root}/lib")
|
||||
endforeach()
|
||||
|
||||
# Find PSP GCC
|
||||
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
|
||||
|
||||
# If we did not find it, download it.
|
||||
if(NOT PSPSDK_PSP_GCC)
|
||||
message(STATUS "psp-gcc not found in system paths. Downloading PSPSDK tarball...")
|
||||
file(DOWNLOAD
|
||||
"https://github.com/pspdev/pspdev/releases/download/v20251101/pspdev-ubuntu-latest-x86_64.tar.gz"
|
||||
"${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
|
||||
EXPECTED_HASH SHA256=8f8abc2a3008ec1e97c6ba706152a45e4f031c8d10db2102c3c68ce24fa6fcaf
|
||||
SHOW_PROGRESS
|
||||
)
|
||||
|
||||
# Make output dir
|
||||
file(MAKE_DIRECTORY "${PSPSDK_DOWNLOAD_DIR}")
|
||||
|
||||
# Extract the tarball
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E tar xzf "${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
|
||||
WORKING_DIRECTORY
|
||||
"${PSPSDK_DOWNLOAD_DIR}"
|
||||
RESULT_VARIABLE
|
||||
tar_result
|
||||
)
|
||||
if(NOT tar_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract PSPSDK tarball")
|
||||
endif()
|
||||
|
||||
# Retry discovery with extracted fallback
|
||||
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
|
||||
endif()
|
||||
|
||||
if(PSPSDK_PSP_GCC)
|
||||
get_filename_component(PSPSDK_BIN_ROOT "${PSPSDK_PSP_GCC}" DIRECTORY)
|
||||
get_filename_component(PSPSDK_ROOT "${PSPSDK_BIN_ROOT}" DIRECTORY)
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
set(ENV{PSPDEV} "${PSPSDK_ROOT}")
|
||||
set(CMAKE_TOOLCHAIN_FILE "${PSPSDK_ROOT}/psp/share/pspdev.cmake")
|
||||
set(BUILD_PRX ON CACHE BOOL "Build PRX modules")
|
||||
|
||||
include("${PSPSDK_ROOT}/psp/share/pspdev.cmake")
|
||||
set(CMAKE_C_COMPILER ${PSPSDK_BIN_ROOT}/psp-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${PSPSDK_BIN_ROOT}/psp-g++)
|
||||
|
||||
if(NOT DEFINED PSP)
|
||||
message(FATAL_ERROR "PSP environment variable is not set correctly.")
|
||||
endif()
|
||||
|
||||
add_library(pspsdk INTERFACE IMPORTED)
|
||||
set_target_properties(pspsdk PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${PSPSDK_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_DIRECTORIES "${PSPSDK_LIB_DIR}"
|
||||
)
|
||||
target_include_directories(pspsdk
|
||||
INTERFACE
|
||||
${PSPDEV}/psp/include
|
||||
${PSPDEV}/psp/sdk/include
|
||||
)
|
||||
target_link_directories(pspsdk
|
||||
INTERFACE
|
||||
${PSPDEV}/lib
|
||||
${PSPDEV}/psp/lib
|
||||
${PSPDEV}/psp/sdk/lib
|
||||
)
|
||||
target_link_libraries(pspsdk INTERFACE
|
||||
pspdebug
|
||||
pspdisplay
|
||||
pspge
|
||||
pspctrl
|
||||
pspgu
|
||||
pspaudio
|
||||
pspaudiolib
|
||||
psputility
|
||||
pspvfpu
|
||||
pspvram
|
||||
psphprm
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,31 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
stb
|
||||
GIT_REPOSITORY https://github.com/nothings/stb.git
|
||||
)
|
||||
|
||||
# Fetch stb if not already done
|
||||
FetchContent_MakeAvailable(stb)
|
||||
|
||||
# Find the stb_image.h header
|
||||
set(STB_INCLUDE_DIR "${stb_SOURCE_DIR}")
|
||||
set(STB_IMAGE_HEADER "${stb_SOURCE_DIR}/stb_image.h")
|
||||
|
||||
if(EXISTS "${STB_IMAGE_HEADER}")
|
||||
add_library(stb_image INTERFACE)
|
||||
target_include_directories(stb_image INTERFACE "${STB_INCLUDE_DIR}")
|
||||
set(STB_IMAGE_FOUND TRUE)
|
||||
else()
|
||||
set(STB_IMAGE_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# Standard CMake variables
|
||||
set(STB_IMAGE_INCLUDE_DIRS "${STB_INCLUDE_DIR}")
|
||||
set(STB_IMAGE_LIBRARIES stb_image)
|
||||
|
||||
mark_as_advanced(STB_IMAGE_INCLUDE_DIRS STB_IMAGE_LIBRARIES STB_IMAGE_FOUND)
|
||||
@@ -0,0 +1,18 @@
|
||||
include(FetchContent)
|
||||
|
||||
if(NOT TARGET yyjson)
|
||||
FetchContent_Declare(
|
||||
yyjson
|
||||
GIT_REPOSITORY https://github.com/ibireme/yyjson.git
|
||||
GIT_TAG 0.12.0
|
||||
)
|
||||
FetchContent_MakeAvailable(yyjson)
|
||||
endif()
|
||||
|
||||
# Provide an imported target if not already available
|
||||
if(NOT TARGET yyjson::yyjson)
|
||||
add_library(yyjson::yyjson ALIAS yyjson)
|
||||
endif()
|
||||
|
||||
# Mark yyjson as found for find_package compatibility
|
||||
set(yyjson_FOUND TRUE)
|
||||
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
find_package(cmocka REQUIRED)
|
||||
|
||||
# Function to create a test executable from a single .c file
|
||||
function(dusktest TEST_C_FILE)
|
||||
# Create target name from file name
|
||||
get_filename_component(TEST_NAME ${TEST_C_FILE} NAME_WE)
|
||||
|
||||
# Create the executable target
|
||||
add_executable(${TEST_NAME})
|
||||
|
||||
# Setup some compiler definitions.
|
||||
target_compile_definitions(${TEST_NAME} PRIVATE
|
||||
DUSK_TEST_ASSERT=1
|
||||
)
|
||||
|
||||
# Add the test file
|
||||
target_sources(${TEST_NAME} PRIVATE ${TEST_C_FILE})
|
||||
|
||||
# Add sources, both common and test-specific
|
||||
target_include_directories(${TEST_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${DUSK_TEST_DIR})
|
||||
|
||||
# Link against DuskCore and cmocka
|
||||
target_link_libraries(${TEST_NAME} PUBLIC ${DUSK_LIBRARY_TARGET_NAME} cmocka)
|
||||
|
||||
# Add as a CTest
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||
endfunction()
|
||||
@@ -1,64 +0,0 @@
|
||||
if(NOT DEFINED ENV_FILE)
|
||||
message(FATAL_ERROR "ENV_FILE is not set")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED OUT_HEADER)
|
||||
message(FATAL_ERROR "OUT_HEADER is not set")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${ENV_FILE}")
|
||||
message(FATAL_ERROR ".env file not found: ${ENV_FILE}")
|
||||
endif()
|
||||
|
||||
file(STRINGS "${ENV_FILE}" ENV_LINES)
|
||||
|
||||
set(HEADER_CONTENT "#pragma once\n#include \"dusk.h\"\n\n")
|
||||
|
||||
foreach(line IN LISTS ENV_LINES)
|
||||
# Skip comments and empty lines (allow whitespace before # or ;)
|
||||
if(line STREQUAL "" OR line MATCHES "^[ \t]*[#;]")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Expect KEY=VALUE (allow spaces around '=')
|
||||
if(NOT line MATCHES "^[A-Za-z_][A-Za-z0-9_]*[ \t]*=[ \t]*")
|
||||
message(WARNING "Skipping invalid line in ${ENV_FILE}: '${line}'")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Extract key
|
||||
string(REGEX MATCH "^[A-Za-z_][A-Za-z0-9_]*" KEY "${line}")
|
||||
string(LENGTH "${KEY}" key_len)
|
||||
|
||||
# Extract value (allow spaces around '=')
|
||||
string(REGEX REPLACE "^[A-Za-z_][A-Za-z0-9_]*[ \t]*=[ \t]*" "" RAW_VALUE "${line}")
|
||||
|
||||
# Lowercase copy for boolean detection
|
||||
string(TOLOWER "${RAW_VALUE}" VALUE_LC)
|
||||
set(VALUE "${RAW_VALUE}")
|
||||
|
||||
# Determine type and format accordingly
|
||||
if(VALUE_LC STREQUAL "true")
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#define ${KEY} true\n")
|
||||
|
||||
elseif(VALUE_LC STREQUAL "false")
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#define ${KEY} false\n")
|
||||
|
||||
elseif(VALUE MATCHES "^[+-]?[0-9]+$")
|
||||
# Integer
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#define ${KEY} ${VALUE}\n")
|
||||
|
||||
elseif(VALUE MATCHES "^[+-]?[0-9]*\\.[0-9]+$")
|
||||
# Float → append "f"
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#define ${KEY} ${VALUE}f\n")
|
||||
|
||||
else()
|
||||
# String → escape for C literal
|
||||
string(REPLACE "\\" "\\\\" VALUE_ESC "${VALUE}")
|
||||
string(REPLACE "\"" "\\\"" VALUE_ESC "${VALUE_ESC}")
|
||||
set(HEADER_CONTENT "${HEADER_CONTENT}#define ${KEY} \"${VALUE_ESC}\"\n")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
file(WRITE "${OUT_HEADER}" "${HEADER_CONTENT}")
|
||||
message(STATUS "Generated header: ${OUT_HEADER}")
|
||||
@@ -0,0 +1,79 @@
|
||||
# Build type: DOL (SD/USB via libfat) or ISO (DVD disc via libogc DVD driver)
|
||||
set(DUSK_DOLPHIN_BUILD_TYPE "DOL" CACHE STRING "Dolphin asset source: DOL (SD/USB) or ISO (DVD disc)")
|
||||
set_property(CACHE DUSK_DOLPHIN_BUILD_TYPE PROPERTY STRINGS "DOL" "ISO")
|
||||
|
||||
# Numeric tokens so #if DUSK_DOLPHIN_BUILD_TYPE == DOL works in C.
|
||||
# DUSK_DOLPHIN_BUILD_TYPE is passed without quotes so it expands to the identifier.
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_DOLPHIN
|
||||
DUSK_INPUT_GAMEPAD
|
||||
# DUSK_DISPLAY_WIDTH=640
|
||||
# DUSK_DISPLAY_HEIGHT=480
|
||||
DUSK_DISPLAY_WIDTH=320
|
||||
DUSK_DISPLAY_HEIGHT=240
|
||||
DUSK_DISPLAY_OVERSCAN=16
|
||||
DUSK_THREAD_PTHREAD
|
||||
DOL=1
|
||||
ISO=2
|
||||
DUSK_DOLPHIN_BUILD_TYPE=${DUSK_DOLPHIN_BUILD_TYPE}
|
||||
# GameCube/Wii PowerPC is always big-endian; declare it at compile time
|
||||
# like every other target instead of relying on endian.h's runtime probe.
|
||||
DUSK_PLATFORM_ENDIAN_BIG
|
||||
)
|
||||
|
||||
# Custom compiler flags
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
|
||||
# Disable all warnings
|
||||
target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -w)
|
||||
|
||||
# cglm: fetched at source level via Findcglm.cmake (FetchContent, headers only)
|
||||
find_package(cglm REQUIRED)
|
||||
|
||||
# Pre-create ZLIB::ZLIB so any downstream cmake module that resolves it
|
||||
# (FindZLIB, pkg-config IMPORTED_TARGET Requires processing) gets plain -lz
|
||||
# rather than an unresolvable IMPORTED target that the PPC linker rejects.
|
||||
if(NOT TARGET ZLIB::ZLIB)
|
||||
add_library(ZLIB::ZLIB INTERFACE IMPORTED GLOBAL)
|
||||
set_target_properties(ZLIB::ZLIB PROPERTIES INTERFACE_LINK_LIBRARIES "z")
|
||||
endif()
|
||||
|
||||
# Mark libzip as found so src/dusk/CMakeLists.txt skips Findlibzip.cmake.
|
||||
# Findlibzip.cmake calls find_package(ZLIB) which can recreate a broken
|
||||
# ZLIB::ZLIB IMPORTED target, bypassing the shim above.
|
||||
set(libzip_FOUND TRUE CACHE BOOL "libzip found (devkitpro portlibs)" FORCE)
|
||||
|
||||
# Locate zip.h in the devkitpro sysroot (respects CMAKE_FIND_ROOT_PATH).
|
||||
find_path(_dusk_zip_inc NAMES zip.h)
|
||||
if(_dusk_zip_inc)
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE "${_dusk_zip_inc}")
|
||||
endif()
|
||||
|
||||
# Link libraries.
|
||||
# zip/z/lzma use target_link_options (raw flags) to bypass cmake target
|
||||
# resolution - pkg-config-generated targets for these carry ZLIB::ZLIB in
|
||||
# INTERFACE_LINK_LIBRARIES which breaks the PPC link step.
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
cglm
|
||||
m
|
||||
zip
|
||||
bz2
|
||||
zstd
|
||||
z
|
||||
lzma
|
||||
)
|
||||
|
||||
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_DOLPHIN_BUILD_ISO)
|
||||
else()
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE fat)
|
||||
endif()
|
||||
|
||||
# Postbuild: ELF -> DOL
|
||||
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}"
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
include(cmake/targets/dolphin.cmake)
|
||||
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_GAMECUBE
|
||||
)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
# bba
|
||||
)
|
||||
|
||||
# ISO post-build: produce NTSC-J, NTSC-U and PAL disc images
|
||||
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||
COMMAND ${Python3_EXECUTABLE}
|
||||
"${CMAKE_SOURCE_DIR}/tools/makedolphiniso.py"
|
||||
"GCN"
|
||||
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||
"${DUSK_ASSETS_ZIP}"
|
||||
"${DUSK_GAME_NAME}"
|
||||
"${DUSK_BUILD_DIR}"
|
||||
COMMENT "Building GameCube ISO images (NTSC-J, NTSC-U, PAL)"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,47 @@
|
||||
# Find link platform-specific libraries
|
||||
set(OpenGL_GL_PREFERENCE LEGACY)
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_library(EGL_LIB EGL REQUIRED)
|
||||
find_library(GL_LIB GL REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
# Setup endianess at compile time to optimize.
|
||||
include(TestBigEndian)
|
||||
test_big_endian(IS_BIG_ENDIAN)
|
||||
if(IS_BIG_ENDIAN)
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_PLATFORM_ENDIAN_BIG
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link required libraries.
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GLES2
|
||||
${GL_LIB}
|
||||
${EGL_LIB}
|
||||
m
|
||||
)
|
||||
|
||||
# Define platform-specific macros.
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_SDL2
|
||||
DUSK_OPENGL
|
||||
DUSK_OPENGL_ES
|
||||
DUSK_LINUX
|
||||
DUSK_KNULLI
|
||||
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||
DUSK_DISPLAY_WIDTH_DEFAULT=640
|
||||
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||
DUSK_DISPLAY_SCREEN_HEIGHT=240
|
||||
DUSK_INPUT_KEYBOARD
|
||||
DUSK_INPUT_POINTER
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_TIME_DYNAMIC
|
||||
DUSK_THREAD_PTHREAD
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
# Find link platform-specific libraries
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
# find_package(CURL REQUIRED)
|
||||
|
||||
# Setup endianess at compile time to optimize.
|
||||
include(TestBigEndian)
|
||||
test_big_endian(IS_BIG_ENDIAN)
|
||||
if(IS_BIG_ENDIAN)
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_PLATFORM_ENDIAN_BIG
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link required libraries.
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
GL
|
||||
m
|
||||
# CURL::libcurl
|
||||
)
|
||||
|
||||
set(DUSK_BACKTRACE ON CACHE BOOL "Enable backtrace support for assert failures.")
|
||||
|
||||
# Define platform-specific macros.
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_SDL2
|
||||
DUSK_OPENGL
|
||||
DUSK_CONSOLE_POSIX
|
||||
# DUSK_OPENGL_LEGACY
|
||||
DUSK_LINUX
|
||||
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||
DUSK_DISPLAY_WIDTH_DEFAULT=854
|
||||
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||
DUSK_DISPLAY_SCREEN_HEIGHT=240
|
||||
DUSK_INPUT_KEYBOARD
|
||||
DUSK_INPUT_POINTER
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_TIME_DYNAMIC
|
||||
DUSK_NETWORK_IPV6
|
||||
DUSK_THREAD_PTHREAD
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
set(CMAKE_AR "$ENV{PSPDEV}/bin/psp-ar" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_RANLIB "$ENV{PSPDEV}/bin/psp-ranlib" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_C_COMPILER_AR "$ENV{PSPDEV}/bin/psp-ar" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_C_COMPILER_RANLIB "$ENV{PSPDEV}/bin/psp-ranlib" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_C_ARCHIVE_CREATE "$ENV{PSPDEV}/bin/psp-ar qc <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_C_ARCHIVE_APPEND "$ENV{PSPDEV}/bin/psp-ar q <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_C_ARCHIVE_FINISH "$ENV{PSPDEV}/bin/psp-ranlib <TARGET>")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF CACHE BOOL "" FORCE)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_C OFF CACHE BOOL "" FORCE)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||
${SDL2_LIBRARIES}
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
zip
|
||||
bz2
|
||||
z
|
||||
mbedtls
|
||||
mbedcrypto
|
||||
lzma
|
||||
m
|
||||
|
||||
pspdebug
|
||||
pspdisplay
|
||||
pspge
|
||||
pspctrl
|
||||
pspgu
|
||||
pspaudio
|
||||
pspaudiolib
|
||||
psputility
|
||||
pspvfpu
|
||||
pspvram
|
||||
psphprm
|
||||
pspnet
|
||||
pspnet_inet
|
||||
pspnet_apctl
|
||||
psphttp
|
||||
pspssl
|
||||
)
|
||||
|
||||
target_include_directories(${DUSK_BINARY_TARGET_NAME} PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_compile_definitions(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||
DUSK_SDL2
|
||||
DUSK_OPENGL
|
||||
DUSK_PSP
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||
DUSK_OPENGL_LEGACY
|
||||
DUSK_DISPLAY_WIDTH=480
|
||||
DUSK_DISPLAY_HEIGHT=272
|
||||
DUSK_THREAD_PTHREAD
|
||||
DUSK_TIME_DYNAMIC
|
||||
DUSK_DISPLAY_OVERSCAN=6
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||
DUSK_ASSERTIONS_FAKED
|
||||
)
|
||||
endif()
|
||||
|
||||
# Postbuild, create .pbp file for 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_ASSETS_ZIP}
|
||||
VERSION 01.00
|
||||
)
|
||||
@@ -0,0 +1,89 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
if(NOT DEFINED ENV{VITASDK})
|
||||
message(FATAL_ERROR "VITASDK environment variable is not set.")
|
||||
endif()
|
||||
|
||||
include("$ENV{VITASDK}/share/vita.cmake" REQUIRED)
|
||||
|
||||
set(VITA_APP_NAME "Dusk")
|
||||
set(VITA_TITLEID "DUSK00001")
|
||||
set(VITA_VERSION "01.00")
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
# 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)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${SDL2_LIBRARIES}
|
||||
cglm
|
||||
SDL2
|
||||
SDL2main
|
||||
zip
|
||||
bz2
|
||||
z
|
||||
zstd
|
||||
crypto
|
||||
lzma
|
||||
m
|
||||
pthread
|
||||
stdc++
|
||||
vitaGL
|
||||
mathneon
|
||||
vitashark
|
||||
kubridge_stub
|
||||
SceAppMgr_stub
|
||||
SceAudio_stub
|
||||
SceCtrl_stub
|
||||
SceCommonDialog_stub
|
||||
SceDisplay_stub
|
||||
SceKernelDmacMgr_stub
|
||||
SceGxm_stub
|
||||
SceShaccCg_stub
|
||||
SceSysmodule_stub
|
||||
ScePower_stub
|
||||
SceTouch_stub
|
||||
SceVshBridge_stub
|
||||
SceIofilemgr_stub
|
||||
SceShaccCgExt
|
||||
libtaihen_stub.a
|
||||
|
||||
|
||||
# SceKernel_stub
|
||||
SceAppUtil_stub
|
||||
SceHid_stub
|
||||
SceRtc_stub
|
||||
)
|
||||
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_SDL2
|
||||
DUSK_OPENGL
|
||||
DUSK_VITA
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||
DUSK_OPENGL_LEGACY
|
||||
DUSK_DISPLAY_WIDTH=960
|
||||
DUSK_DISPLAY_HEIGHT=544
|
||||
DUSK_THREAD_PTHREAD
|
||||
)
|
||||
|
||||
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
|
||||
vita_create_self(${DUSK_BINARY_TARGET_NAME}.self ${DUSK_BINARY_TARGET_NAME} UNSAFE)
|
||||
|
||||
# Post-build: package SELF + assets into a .vpk installable on the Vita
|
||||
vita_create_vpk(${DUSK_BINARY_TARGET_NAME}.vpk ${VITA_TITLEID} ${DUSK_BINARY_TARGET_NAME}.self
|
||||
VERSION ${VITA_VERSION}
|
||||
NAME ${VITA_APP_NAME}
|
||||
FILE ${DUSK_ASSETS_ZIP} dusk.dsk
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
include(cmake/targets/dolphin.cmake)
|
||||
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_WII
|
||||
)
|
||||
|
||||
# Generate Homebrew Channel meta.xml from project identity variables
|
||||
string(TIMESTAMP DUSK_BUILD_DATE "%Y%m%d000000" UTC)
|
||||
configure_file(
|
||||
"${CMAKE_SOURCE_DIR}/docker/dolphin/meta.xml.in"
|
||||
"${DUSK_BUILD_DIR}/meta.xml"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# ISO post-build: produce NTSC-J, NTSC-U and PAL disc images
|
||||
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||
COMMAND ${Python3_EXECUTABLE}
|
||||
"${CMAKE_SOURCE_DIR}/tools/makedolphiniso.py"
|
||||
"WII"
|
||||
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||
"${DUSK_ASSETS_ZIP}"
|
||||
"${DUSK_GAME_NAME}"
|
||||
"${DUSK_BUILD_DIR}"
|
||||
COMMENT "Building Wii ISO images (NTSC-J, NTSC-U, PAL)"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,29 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
||||
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
|
||||
set(CMAKE_ASM_COMPILER aarch64-linux-gnu-gcc)
|
||||
|
||||
set(CMAKE_SYSROOT /)
|
||||
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
|
||||
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH
|
||||
/usr/aarch64-linux-gnu
|
||||
/usr/lib/aarch64-linux-gnu
|
||||
/usr/include/aarch64-linux-gnu
|
||||
)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "/usr/lib/aarch64-linux-gnu/pkgconfig")
|
||||
|
||||
set(CMAKE_PREFIX_PATH "/usr/aarch64-linux-gnu;/usr/lib/aarch64-linux-gnu")
|
||||
|
||||
# Optional: helps some Find modules
|
||||
set(SDL2_DIR "/usr/lib/aarch64-linux-gnu/cmake/SDL2" CACHE PATH "")
|
||||
@@ -0,0 +1,7 @@
|
||||
FROM ghcr.io/extremscorner/libogc2
|
||||
WORKDIR /workdir
|
||||
RUN apt update && \
|
||||
dkp-pacman -Syu --noconfirm && \
|
||||
apt install -y python3 python3-pip python3-polib python3-pil python3-dotenv python3-pyqt5 python3-opengl xorriso && \
|
||||
dkp-pacman -S --needed --noconfirm gamecube-sdl2 ppc-liblzma ppc-libzip libogc2 gamecube-tools ppc-libmad ppc-zlib-ng ppc-liblzma ppc-bzip2 ppc-zstd
|
||||
VOLUME ["/workdir"]
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<app version="1">
|
||||
<name>@DUSK_GAME_NAME@</name>
|
||||
<version>@PROJECT_VERSION@</version>
|
||||
<release_date>@DUSK_BUILD_DATE@</release_date>
|
||||
<coder>@DUSK_GAME_AUTHOR@</coder>
|
||||
<short_description>@DUSK_GAME_SHORT_DESCRIPTION@</short_description>
|
||||
<long_description>@DUSK_GAME_LONG_DESCRIPTION@</long_description>
|
||||
<ahb_access/>
|
||||
</app>
|
||||
@@ -0,0 +1,35 @@
|
||||
FROM debian:trixie
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
WORKDIR /workdir
|
||||
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 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -0,0 +1,24 @@
|
||||
FROM ubuntu:latest
|
||||
WORKDIR /workdir
|
||||
RUN apt-get update
|
||||
RUN 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 \
|
||||
libzip-dev \
|
||||
libbz2-dev \
|
||||
git \
|
||||
libssl-dev
|
||||
@@ -0,0 +1,7 @@
|
||||
FROM pspdev/pspdev:latest
|
||||
WORKDIR /workdir
|
||||
RUN apk add --no-cache \
|
||||
python3 \
|
||||
py3-pip \
|
||||
py3-dotenv
|
||||
VOLUME ["/workdir"]
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM vitasdk/vitasdk:latest
|
||||
WORKDIR /workdir
|
||||
|
||||
# Install vitaGL and its dependencies (vitashark, SceShaccCg) via vdpm
|
||||
RUN which vdpm
|
||||
|
||||
# Install Python (needed for Dusk code generation tools)
|
||||
RUN apk add --no-cache \
|
||||
python3 \
|
||||
py3-pip \
|
||||
py3-dotenv
|
||||
|
||||
VOLUME ["/workdir"]
|
||||
@@ -0,0 +1,379 @@
|
||||
# Scripting
|
||||
|
||||
Dusk embeds [JerryScript](https://github.com/jerryscript-project/jerryscript) to
|
||||
drive gameplay logic from JavaScript. The engine itself (rendering, physics,
|
||||
asset loading, entity storage) is all C; scripts sit on top and manipulate that
|
||||
state through a small set of bound objects.
|
||||
|
||||
This document covers the JS-facing scripting API. **UI (buttons, sliders,
|
||||
menus, etc.) is not exposed to scripts** — it's a separate, C-only API. See
|
||||
[UI.md](UI.md) if you're building screens/menus from engine/game C code.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
On startup, `engineInit()` loads and evaluates `assets/engine.js` as the main
|
||||
script, then calls the global `init()` function if one is defined. From then
|
||||
on, every engine tick calls (in order):
|
||||
|
||||
1. `fixedUpdate()` — once per fixed timestep. Use this for gameplay logic that
|
||||
must be deterministic and independent of display refresh rate (movement,
|
||||
physics-adjacent input handling, etc). Skipped on interpolation/dynamic
|
||||
frames when the build has variable-timestep rendering enabled.
|
||||
2. `update()` — once per rendered frame, including interpolation frames. Use
|
||||
this for smooth, purely presentational animation (nothing that needs to be
|
||||
deterministic).
|
||||
|
||||
On shutdown, `deinit()` is called once.
|
||||
|
||||
All four hooks (`init`, `update`, `fixedUpdate`, `deinit`) are **optional** —
|
||||
if a script doesn't define one, the engine simply skips it, no error.
|
||||
|
||||
```js
|
||||
function update() {
|
||||
cubePosition.rotation.y += TIME.delta * 1.5;
|
||||
}
|
||||
```
|
||||
|
||||
### `async init()` and `include()`
|
||||
|
||||
`init` (or any of the other hooks) can be declared `async` and use `await`
|
||||
freely, including awaiting `include()` (see below), even though the engine
|
||||
calls these functions synchronously from C with no external JS event loop.
|
||||
When a hook returns a pending `Promise`, the engine keeps driving the asset
|
||||
system and JerryScript's job queue until that promise settles before
|
||||
continuing — so by the time e.g. `init()` "returns" from the engine's point of
|
||||
view, everything it awaited has actually finished.
|
||||
|
||||
```js
|
||||
async function init() {
|
||||
Actions = await include("input.js");
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
If the awaited work throws/rejects, it surfaces as a C-level error.
|
||||
|
||||
## Loading other scripts: `include(path)`
|
||||
|
||||
```js
|
||||
var Actions = await include("input.js");
|
||||
```
|
||||
|
||||
`include(path)` always returns a `Promise`. The named file is loaded and
|
||||
evaluated once no matter how many times (or from how many different scripts)
|
||||
you `include()` it — later calls for the same path are handed the same
|
||||
in-flight/resolved promise rather than re-running the file.
|
||||
|
||||
The included script communicates its result back by assigning to the bare
|
||||
global `module`:
|
||||
|
||||
```js
|
||||
// input.js
|
||||
Input.bind("w", INPUT_ACTION_UP);
|
||||
// ...
|
||||
|
||||
module = {
|
||||
UP: INPUT_ACTION_UP,
|
||||
DOWN: INPUT_ACTION_DOWN,
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Whatever `input.js` assigns to `module` becomes the resolved value of the
|
||||
promise `include("input.js")` returned — that's what `Actions` ends up being
|
||||
in the example above. If the included script throws, the promise rejects
|
||||
instead.
|
||||
|
||||
## Full example
|
||||
|
||||
This is the actual shipped example content (`assets/engine.js` +
|
||||
`assets/input.js`):
|
||||
|
||||
```js
|
||||
// input.js — 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
|
||||
};
|
||||
```
|
||||
|
||||
```js
|
||||
// engine.js
|
||||
var Actions;
|
||||
var camera, cameraPosition;
|
||||
var cube, cubePosition, cubeRenderable, cubeMesh;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function update() {
|
||||
cubePosition.rotation.y += TIME.delta * 1.5;
|
||||
cubePosition.rotation.x += TIME.delta * 0.7;
|
||||
}
|
||||
|
||||
function fixedUpdate() {
|
||||
var move = 3.0 * TIME.delta;
|
||||
if(Input.isDown(Actions.LEFT)) cubePosition.position.x -= move;
|
||||
if(Input.isDown(Actions.RIGHT)) cubePosition.position.x += move;
|
||||
if(Input.isDown(Actions.UP)) cubePosition.position.z += move;
|
||||
if(Input.isDown(Actions.DOWN)) cubePosition.position.z -= move;
|
||||
if(Input.pressed(Actions.ACCEPT)) cubePosition.position = new Vec3(0, 0, 0);
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
cube.dispose();
|
||||
camera.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
## API reference
|
||||
|
||||
### `TIME`
|
||||
|
||||
Plain global object, live getters (read fresh engine state every access, not
|
||||
snapshotted):
|
||||
|
||||
| Property | Type | Description |
|
||||
|---|---|---|
|
||||
| `TIME.delta` | number | Seconds since the last frame. |
|
||||
| `TIME.time` | number | Total elapsed engine time, in seconds. |
|
||||
|
||||
### `PLATFORM`
|
||||
|
||||
A single global string constant — the compile-time target name, e.g.
|
||||
`"linux"`, `"psp"`, `"vita"`, `"dolphin"`. Individual platform builds may
|
||||
inject additional platform-specific globals via their own
|
||||
`modulePlatformPlatform()` hook; those aren't documented here since they vary
|
||||
per target.
|
||||
|
||||
### `Input`
|
||||
|
||||
Static namespace (not constructible — there's no `new Input()`).
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `Input.bind(buttonName, action)` | Binds a physical button/key (string, e.g. `"w"`, `"space"`, `"gamepad_up"`) to an abstract `INPUT_ACTION_*` constant. Many buttons can bind to the same action. Throws on an empty/unrecognized button name or invalid action. |
|
||||
| `Input.isDown(action)` → boolean | Is the action currently held. |
|
||||
| `Input.pressed(action)` → boolean | Action transitioned to down this frame. |
|
||||
| `Input.released(action)` → boolean | Action transitioned to up this frame. |
|
||||
| `Input.getValue(action)` → number | Current analog value for the action. |
|
||||
| `Input.axis(negAction, posAction)` → number | Combined axis value from two opposing actions. |
|
||||
| `Input.axis2D(negX, posX, negY, posY)` → `Vec2` | Combined 2D axis from four actions. |
|
||||
|
||||
Global `INPUT_ACTION_*` constants (names are stable API; treat the numeric
|
||||
values as opaque/build-specific): `INPUT_ACTION_UP`, `INPUT_ACTION_DOWN`,
|
||||
`INPUT_ACTION_LEFT`, `INPUT_ACTION_RIGHT`, `INPUT_ACTION_ACCEPT`,
|
||||
`INPUT_ACTION_CANCEL`, `INPUT_ACTION_PAUSE`, `INPUT_ACTION_RAGEQUIT`,
|
||||
`INPUT_ACTION_CONSOLE`, `INPUT_ACTION_POINTERX`, `INPUT_ACTION_POINTERY`.
|
||||
|
||||
Conditionally-defined boolean globals reflecting build capability — only
|
||||
present at all if the corresponding input method is compiled in, so
|
||||
feature-test with `typeof`, don't assume they exist:
|
||||
`INPUT_KEYBOARD`, `INPUT_GAMEPAD`, `INPUT_POINTER`, `INPUT_TOUCH`.
|
||||
|
||||
### `Vec2` / `Vec3` / `Vec4`
|
||||
|
||||
`new Vec2(x?, y?)`, `new Vec3(x?, y?, z?)`, `new Vec4(x?, y?, z?, w?)` — all
|
||||
components optional, default `0`.
|
||||
|
||||
Common instance surface across all three: `.dot(other)`, `.length()`,
|
||||
`.lengthSq()`, `.normalize()`, `.negate()`, `.add(other)`, `.sub(other)`,
|
||||
`.scale(n)`, `.lerp(other, t)` — each of `add`/`sub`/`scale`/`negate`/
|
||||
`normalize`/`lerp` returns a **new** vector (non-mutating). `Vec3` additionally
|
||||
has `.cross(other)` and `.distance(other)`; `Vec2` has `.distance(other)` too;
|
||||
`Vec4` has neither `.cross()` nor `.distance()`.
|
||||
|
||||
`Vec4` also has UV aliases over the same four floats: `.u0` (= `.x`), `.v0`
|
||||
(= `.y`), `.u1` (= `.z`), `.v1` (= `.w`) — handy for texture-rect style code.
|
||||
|
||||
All three have `.x`/`.y`(/`.z`/`.w`) get/set properties and a `.toString()`
|
||||
like `"Vec3(1, 2, 3)"`.
|
||||
|
||||
**"Vec3Ref" — live references.** Several engine properties (entity
|
||||
`position`/`rotation`/`scale`, physics `velocity`, a mesh vertex's `position`)
|
||||
return a vector-*like* object instead of a plain `Vec3`. It has the identical
|
||||
`.x`/`.y`/`.z` surface, but reads/writes go straight into the underlying
|
||||
native buffer — writing `.x` on `entity.position.position` immediately moves
|
||||
the entity, no separate assignment needed. Anywhere the API expects a `Vec3`
|
||||
argument, a Vec3Ref works too. You never construct one directly; you only
|
||||
ever receive them from properties like the ones above.
|
||||
|
||||
### `Mat4`
|
||||
|
||||
`new Mat4()` — always constructs identity; no other constructor form.
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.mul(other)` → `Mat4` | `this * other`. |
|
||||
| `.transpose()` → `Mat4` | |
|
||||
| `.inverse()` → `Mat4` | |
|
||||
| `.determinant()` → number | |
|
||||
| `.mulVec3(vec3, w?)` → `Vec3` | `w` defaults to `1.0` (point); pass `0` for a direction. |
|
||||
| `.mulVec4(vec4)` → `Vec4` | |
|
||||
| `.translate(vec3)` → `Mat4` | Non-mutating — returns a translated copy. |
|
||||
| `.scale(vec3)` → `Mat4` | Non-mutating — returns a scaled copy. |
|
||||
| `Mat4.identity()` → `Mat4` | Static. |
|
||||
| `Mat4.perspective(fov, aspect, near, far)` → `Mat4` | Static, all 4 args required. |
|
||||
| `Mat4.lookAt(eye, center, up)` → `Mat4` | Static, all 3 args required `Vec3`s. |
|
||||
|
||||
### `Color`
|
||||
|
||||
`new Color(r?, g?, b?, a?)` — each an int `0..255`, default `255` (so
|
||||
`new Color()` is opaque white). Properties `.r`/`.g`/`.b`/`.a` get/set.
|
||||
|
||||
Named factories, each a zero-arg static returning a new opaque `Color`
|
||||
(alpha `255` unless noted): `Color.black()`, `Color.white()`, `Color.red()`,
|
||||
`Color.green()`, `Color.blue()`, `Color.yellow()`, `Color.cyan()`,
|
||||
`Color.magenta()`, `Color.transparent()` (alpha 0), `Color.transparent_white()`
|
||||
(alpha 0), `Color.transparent_black()` (alpha 0), `Color.gray()`,
|
||||
`Color.light_gray()`, `Color.dark_gray()`, `Color.orange()`, `Color.purple()`,
|
||||
`Color.brown()`, `Color.pink()`, `Color.lime()`, `Color.navy()`,
|
||||
`Color.teal()`, `Color.cornflower_blue()`.
|
||||
|
||||
`Color.rainbow(t?, speed?)` → `Color` — `t` defaults to `TIME.time * 4.0`;
|
||||
produces a shifting rainbow color, useful for debug visuals.
|
||||
|
||||
### `Mesh`
|
||||
|
||||
`new Mesh(vertexCount)` — allocates an uninitialized CPU-side vertex buffer
|
||||
(not yet uploaded to the GPU).
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.vertices` | Array of vertex wrappers, each with a `.position` (Vec3Ref, writes straight into that vertex). |
|
||||
| `.vertexCount` | Read-only. |
|
||||
| `.flush()` | Uploads to the GPU. First call initializes the GPU mesh; later calls re-upload the current vertex data — call this after editing `.vertices[i].position`. |
|
||||
| `.dispose()` | Frees GPU + CPU resources. |
|
||||
|
||||
Static engine-owned singletons (read-only, not something you dispose):
|
||||
`Mesh.DEFAULT_CUBE`, `Mesh.DEFAULT_QUAD`, `Mesh.DEFAULT_SPHERE`,
|
||||
`Mesh.DEFAULT_PLANE`, `Mesh.DEFAULT_CAPSULE`, `Mesh.DEFAULT_TRIPRISM`.
|
||||
|
||||
Static factories (each builds and uploads a brand-new `Mesh`):
|
||||
|
||||
| Factory | Notes |
|
||||
|---|---|
|
||||
| `Mesh.createCube(min?, max?)` | Both `Vec3`, default `(-0.5,-0.5,-0.5)`..`(0.5,0.5,0.5)`. |
|
||||
| `Mesh.createQuad(minX?, minY?, maxX?, maxY?)` | Default `-0.5..0.5` both axes; UV fixed `0,0`–`1,1`. |
|
||||
| `Mesh.createSphere(radius?, stacks?, sectors?)` | `radius` default `0.5`. |
|
||||
| `Mesh.createPlane(width?, height?)` | Defaults `1.0`/`1.0`; XZ-aligned, centered at origin. |
|
||||
| `Mesh.createCapsule(radius?, halfHeight?, capRings?, sectors?)` | Defaults `0.5`, `0.5`. |
|
||||
| `Mesh.createTriPrism(x0, y0, x1, y1, x2, y2, minZ, maxZ)` | All 8 args required — a triangular cross-section extruded along Z. |
|
||||
|
||||
### `Entity` and components
|
||||
|
||||
```js
|
||||
var e = new Entity();
|
||||
var pos = e.add(POSITION);
|
||||
```
|
||||
|
||||
`new Entity()` allocates an entity. `.id` is the read-only numeric engine ID.
|
||||
`.add(TYPE)` adds a component and returns its wrapper (`TYPE` is one of the
|
||||
constants below). `.dispose()` removes the entity and all its components.
|
||||
|
||||
Component-type constants: `POSITION`, `CAMERA`, `RENDERABLE`, `PHYSICS`,
|
||||
`TRIGGER`. Each entity also exposes a lowercase getter that returns the
|
||||
existing wrapper if the component is present, or `undefined` if not (it does
|
||||
**not** add the component — use `.add()` for that): `entity.position`,
|
||||
`entity.camera`, `entity.renderable`, `entity.physics`, `entity.trigger`.
|
||||
|
||||
#### `entity.add(POSITION)` → position component
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.position` | Vec3Ref. Writing rebuilds the transform automatically. |
|
||||
| `.rotation` | Vec3Ref, Euler angles. Same rebuild-on-write behavior. |
|
||||
| `.scale` | Vec3Ref. Same rebuild-on-write behavior. |
|
||||
| `.parent` | Get/set another position-component wrapper, or `null` to clear parenting. |
|
||||
| `.lookAt(target, up?)` | `target` a `Vec3`; `up` defaults to `(0,1,0)`. |
|
||||
|
||||
#### `entity.add(CAMERA)` → camera component
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.zNear` / `.zFar` | Numbers. |
|
||||
| `.fov` | Only meaningful when `projectionType` is `CAMERA_TYPE_PERSPECTIVE`; otherwise get returns `undefined` and set is a no-op. |
|
||||
| `.projectionType` | `CAMERA_TYPE_PERSPECTIVE` or `CAMERA_TYPE_ORTHOGRAPHIC`. |
|
||||
| `.orthoTop` / `.orthoBottom` / `.orthoLeft` / `.orthoRight` | Only meaningful in orthographic mode, same undefined/no-op rule otherwise. |
|
||||
|
||||
#### `entity.add(RENDERABLE)` → renderable component
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.type` | `ENTITY_RENDERABLE_TYPE_MATERIAL`, `_SPRITEBATCH`, or `_CALLBACK`. |
|
||||
| `.mesh` | Get/set a `Mesh` instance or a `Mesh.DEFAULT_*` singleton. |
|
||||
| `.color` | Get/set a `Color` instance (throws if given something else). |
|
||||
| `.addSprite({ min?, max?, uvMin?, uvMax? })` | Adds a sprite to this renderable's sprite batch; all fields optional, default zero. |
|
||||
| `.clearSprites()` | Clears the sprite batch. |
|
||||
| `.setCallback(fn?)` | Switches to `ENTITY_RENDERABLE_TYPE_CALLBACK` and calls `fn()` on every render of this entity. Omit/pass non-function to clear. Exceptions inside `fn` surface as a C error. |
|
||||
|
||||
#### `entity.add(PHYSICS)` → physics component
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.velocity` | Vec3Ref, plain (no rebuild-on-write). |
|
||||
| `.onGround` | Read-only boolean. |
|
||||
| `.bodyType` | `PHYSICS_BODY_STATIC`, `PHYSICS_BODY_DYNAMIC`, `PHYSICS_BODY_KINEMATIC`. |
|
||||
| `.applyImpulse(vec3)` | Adds to velocity. No-op on static bodies. |
|
||||
| `.setShapeCube(halfExtents)` | `halfExtents` a `Vec3`. |
|
||||
| `.setShapeSphere(radius)` | Number. |
|
||||
| `.setShapeCapsule(radius, halfHeight)` | Two numbers. |
|
||||
| `.setShapePlane(normal, distance)` | `Vec3` + number. |
|
||||
|
||||
Shape-type constants (for reading `.type` on the underlying shape, not for
|
||||
`.bodyType`): `PHYSICS_SHAPE_CUBE`, `PHYSICS_SHAPE_SPHERE`,
|
||||
`PHYSICS_SHAPE_CAPSULE`, `PHYSICS_SHAPE_PLANE`.
|
||||
|
||||
#### `entity.add(TRIGGER)` → trigger component
|
||||
|
||||
| Member | Description |
|
||||
|---|---|
|
||||
| `.min` / `.max` | Plain `Vec3` values (copies, not live refs). |
|
||||
| `.setBounds(min, max)` | Sets both at once. |
|
||||
| `.contains(point)` → boolean | `point` a `Vec3`. |
|
||||
|
||||
## Not yet available to scripts
|
||||
|
||||
The following C modules exist and are fully implemented, but aren't currently
|
||||
wired into script registration (`moduleRegister()` in
|
||||
`src/dusk/script/module/module.h`), so none of these globals exist in a
|
||||
script today: `Screen`, `SpriteBatch`, `Text`, `Scene`, `Easing`, `Console`,
|
||||
`Engine`. If you need one of these from a script, it needs to be registered
|
||||
in `moduleRegister()` first — see the existing entries there and the modules
|
||||
under `src/dusk/script/module/` for the pattern to follow.
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
# UI
|
||||
|
||||
Dusk's UI system (buttons, checkboxes, sliders, dropdowns, tabs, menus, focus
|
||||
navigation) is a **C-only API**. It is not exposed to JerryScript — see
|
||||
[SCRIPTING.md](SCRIPTING.md) for what scripts *can* touch. If you need a
|
||||
script to open/react to a menu, wire it through a C callback or a game-side
|
||||
flag scripts can poll; there's no bridge for this today.
|
||||
|
||||
## Mental model
|
||||
|
||||
There is no retained-mode UI tree, no automatic dispatch, no scissor/clip-rect
|
||||
API. Every widget is a plain struct you own (usually as a global or
|
||||
scene-owned variable). You call its `xxxInit(...)` once, then call its
|
||||
`xxxDraw(widget, x, y)` yourself, every frame you want it visible, at whatever
|
||||
screen position you choose. Nothing draws itself automatically except three
|
||||
fixed system overlays (overscan bars, debug console, FPS counter) — see
|
||||
[System overlays](#system-overlays-automatic) below.
|
||||
|
||||
### Where UI rendering happens in the frame
|
||||
|
||||
- `uiInit()` / `uiDispose()` run once, at engine startup/shutdown.
|
||||
- `uiUpdate()` runs once per tick (drives focus-navigation input handling).
|
||||
- `uiRender()` runs once per frame, called from inside `sceneRender()` — i.e.
|
||||
**after** the active scene's own 3D/game-world rendering, using an
|
||||
orthographic screen-space projection. Your own widget `xxxDraw()` calls
|
||||
should happen around the same point — typically from your scene's render
|
||||
callback, after world content, so UI draws on top.
|
||||
|
||||
## Widgets
|
||||
|
||||
Every widget follows the same shape: `xxxInit(widget, ...)` zeroes the struct
|
||||
and sets its fields; `xxxDraw(const widget*, x, y) -> errorret_t` draws it at
|
||||
that screen position.
|
||||
|
||||
> **Init before Draw.** `uislider_t`, `uidropdown_t`, and `uitab_t` cache
|
||||
> their label's measured width/height at `Init` time (an optimization —
|
||||
> label text doesn't change after that point). Calling `Draw` before `Init`,
|
||||
> or mutating `->label` directly instead of re-initializing, leaves stale
|
||||
> layout. `uibutton_t`/`uicheckbox_t` don't have this restriction.
|
||||
|
||||
### Button
|
||||
|
||||
```c
|
||||
void uiButtonInit(uibutton_t *button, const char_t *label);
|
||||
bool_t uiButtonIsHighlighted(const uibutton_t *button);
|
||||
void uiButtonSetHighlighted(uibutton_t *button, bool_t highlighted);
|
||||
errorret_t uiButtonDraw(const uibutton_t *button, float_t x, float_t y);
|
||||
```
|
||||
|
||||
Draws `label` in red when highlighted, white otherwise.
|
||||
|
||||
### Checkbox
|
||||
|
||||
```c
|
||||
void uiCheckboxInit(uicheckbox_t *checkbox, const char_t *label);
|
||||
bool_t uiCheckboxIsChecked(const uicheckbox_t *checkbox);
|
||||
void uiCheckboxSetChecked(uicheckbox_t *checkbox, bool_t checked);
|
||||
void uiCheckboxToggle(uicheckbox_t *checkbox);
|
||||
bool_t uiCheckboxIsHighlighted(const uicheckbox_t *checkbox);
|
||||
void uiCheckboxSetHighlighted(uicheckbox_t *checkbox, bool_t highlighted);
|
||||
errorret_t uiCheckboxDraw(const uicheckbox_t *checkbox, float_t x, float_t y);
|
||||
```
|
||||
|
||||
Draws `"Y "`/`"N "` then the label.
|
||||
|
||||
### Slider
|
||||
|
||||
```c
|
||||
typedef union { float_t f; int32_t i; } uislidervalue_t;
|
||||
|
||||
void uiSliderInitFloat(uislider_t*, const char_t *label,
|
||||
float_t value, float_t min, float_t max, float_t step);
|
||||
void uiSliderInitInt(uislider_t*, const char_t *label,
|
||||
int32_t value, int32_t min, int32_t max, int32_t step);
|
||||
float_t uiSliderGetFloat(const uislider_t*); // works for either type
|
||||
int32_t uiSliderGetInt(const uislider_t*); // asserts type == INT
|
||||
void uiSliderSetFloat(uislider_t*, float_t value); // asserts type == FLOAT, clamps
|
||||
void uiSliderSetInt(uislider_t*, int32_t value); // asserts type == INT, clamps
|
||||
void uiSliderStepUp(uislider_t*); // wraps to min past max
|
||||
void uiSliderStepDown(uislider_t*); // wraps to max past min
|
||||
float_t uiSliderGetRatio(const uislider_t*); // normalized 0..1
|
||||
int32_t uiSliderGetStepCount(const uislider_t*); // 0 for float sliders
|
||||
bool_t uiSliderIsHighlighted(const uislider_t*);
|
||||
void uiSliderSetHighlighted(uislider_t*, bool_t highlighted);
|
||||
errorret_t uiSliderDraw(const uislider_t*, float_t x, float_t y);
|
||||
```
|
||||
|
||||
Draws label, a track, a fill proportional to the current ratio, discrete step
|
||||
markers if it's an int slider with fewer than 10 steps, then the value as
|
||||
text.
|
||||
|
||||
### Dropdown
|
||||
|
||||
```c
|
||||
void uiDropdownInit(uidropdown_t *dropdown, const char_t *label,
|
||||
const char_t *const *options, uint8_t optionCount,
|
||||
uint8_t selectedIndex);
|
||||
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown);
|
||||
const char_t *uiDropdownGetSelectedOption(const uidropdown_t *dropdown);
|
||||
void uiDropdownSetSelectedIndex(uidropdown_t *dropdown, uint8_t index);
|
||||
void uiDropdownStepNext(uidropdown_t *dropdown); // wraps
|
||||
void uiDropdownStepPrev(uidropdown_t *dropdown); // wraps
|
||||
bool_t uiDropdownIsHighlighted(const uidropdown_t *dropdown);
|
||||
void uiDropdownSetHighlighted(uidropdown_t *dropdown, bool_t highlighted);
|
||||
errorret_t uiDropdownDraw(const uidropdown_t *dropdown, float_t x, float_t y);
|
||||
```
|
||||
|
||||
`options` is a caller-owned array of strings that must outlive the dropdown
|
||||
(it isn't copied). Draws `label` then `"< Option >"`.
|
||||
|
||||
### Tab
|
||||
|
||||
```c
|
||||
void uiTabInit(uitab_t *tab, const char_t *label);
|
||||
bool_t uiTabIsActive(const uitab_t *tab);
|
||||
void uiTabSetActive(uitab_t *tab, bool_t active);
|
||||
errorret_t uiTabDraw(const uitab_t *tab, float_t x, float_t y);
|
||||
```
|
||||
|
||||
Draws a background box sized to the label (green if active, red if inactive)
|
||||
with the label on top.
|
||||
|
||||
## Menus: assembling widgets into a navigable list
|
||||
|
||||
`uimenu_t` is the one aggregate widget — it owns an array of items (labels,
|
||||
spacers, and any of the widgets above), lays them out in a grid, and wires
|
||||
keyboard/gamepad navigation via the focus system for you.
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
UI_MENU_WIDGET_TYPE_NONE, UI_MENU_WIDGET_TYPE_LABEL,
|
||||
UI_MENU_WIDGET_TYPE_SPACER, UI_MENU_WIDGET_TYPE_CHECKBOX,
|
||||
UI_MENU_WIDGET_TYPE_BUTTON, UI_MENU_WIDGET_TYPE_TAB,
|
||||
UI_MENU_WIDGET_TYPE_SLIDER, UI_MENU_WIDGET_TYPE_DROPDOWN,
|
||||
} uimenuwidgettype_t;
|
||||
|
||||
void uiMenuInit(uimenu_t *menu, uimenuselectedcallback_t selected,
|
||||
uimenuclosedcallback_t closed, uimenuchangedcallback_t changed);
|
||||
void uiMenuSetItems(uimenu_t *menu, const uimenuitem_t *items,
|
||||
uint8_t itemCount, uint8_t columns);
|
||||
void uiMenuSetPosition(uimenu_t *menu, uint8_t x, uint8_t y); // focus cursor cell, not pixels
|
||||
void uiMenuOpen(uimenu_t *menu); // pushes onto the focus stack
|
||||
void uiMenuClose(uimenu_t *menu); // pops it
|
||||
bool_t uiMenuIsActive(const uimenu_t *menu);
|
||||
errorret_t uiMenuDraw(const uimenu_t *menu, float_t x, float_t y,
|
||||
float_t width, float_t height);
|
||||
```
|
||||
|
||||
- `selected(menu, index, item)` fires when the player presses accept on an item.
|
||||
- `changed(menu, index, item)` fires when the highlighted item changes.
|
||||
- `closed(menu)` fires when the menu is popped off the focus stack.
|
||||
- LEFT/RIGHT on a highlighted slider/checkbox/dropdown adjusts its value in
|
||||
place instead of moving focus off it (handled internally).
|
||||
|
||||
### Building a menu with the `MENU_*` macros
|
||||
|
||||
`uimenu.h` provides macros that cut the boilerplate of filling in a
|
||||
`uimenuitem_t` array. They expand into statements using local variables named
|
||||
`menu`, `menuIndex`, and `menuCapacity`, so use them together, inside one
|
||||
function, starting with `MENU_BEGIN` and ending with `MENU_END`:
|
||||
|
||||
```c
|
||||
static uimenuitem_t optionsItems[8];
|
||||
static uimenu_t optionsMenu;
|
||||
static const char_t *qualityOptions[] = { "Low", "Medium", "High" };
|
||||
|
||||
static void onOptionsSelected(
|
||||
const uimenu_t *menu, const uint8_t index, const uimenuitem_t *item
|
||||
) {
|
||||
if(index == 4) uiMenuClose(&optionsMenu); // "Back" button
|
||||
}
|
||||
|
||||
static void onOptionsClosed(const uimenu_t *menu) {
|
||||
// e.g. return to the previous screen
|
||||
}
|
||||
|
||||
void optionsMenuBuild(void) {
|
||||
MENU_BEGIN(&optionsMenu, optionsItems, onOptionsSelected, onOptionsClosed, NULL);
|
||||
MENU_LABEL("Options");
|
||||
MENU_CHECKBOX("Fullscreen");
|
||||
MENU_SLIDER_FLOAT("Volume", 0.8f, 0.0f, 1.0f, 0.05f);
|
||||
MENU_DROPDOWN("Quality", qualityOptions, 3, 1);
|
||||
MENU_BUTTON("Back");
|
||||
MENU_END(optionsItems, 1);
|
||||
}
|
||||
|
||||
// Once, when the menu screen becomes active:
|
||||
uiMenuOpen(&optionsMenu);
|
||||
|
||||
// Every frame the menu should be visible:
|
||||
uiMenuDraw(&optionsMenu, 20.0f, 20.0f, 200.0f, 100.0f);
|
||||
|
||||
// When leaving the menu screen:
|
||||
uiMenuClose(&optionsMenu);
|
||||
```
|
||||
|
||||
`MENU_LABEL`/`MENU_SPACER` force a row break and aren't focusable/selectable.
|
||||
Every other `MENU_*` macro calls the matching widget's own `Init` for you.
|
||||
|
||||
> This example is constructed directly from the widget/menu API surface (all
|
||||
> function and macro signatures above are verified against the source), but
|
||||
> there's currently no real menu-building call site anywhere else in the
|
||||
> engine to cross-check the *pattern* against — treat it as a starting point,
|
||||
> not a copy of shipped code.
|
||||
|
||||
## Focus system: navigation underneath `uimenu`
|
||||
|
||||
If you're building a custom widget that needs keyboard/gamepad navigation
|
||||
without going through `uimenu`, use `ui/focus/uifocus.h` directly. `uimenu`
|
||||
is implemented entirely in terms of this API, so it's a reasonable reference.
|
||||
|
||||
```c
|
||||
uifocusitem_t * uiFocusPush(
|
||||
uint8_t cols, uint8_t rows,
|
||||
uifocusitemcallback_t selected, // fires on accept
|
||||
uifocusitemcallback_t changed, // fires on cursor move (and once immediately)
|
||||
uifocusitemcallback_t closed, // fires on pop
|
||||
uifocusitemdirectioncallback_t direction, // optional pre-empt of a direction press; NULL for default grid movement
|
||||
void *user
|
||||
);
|
||||
void uiFocusPop(void);
|
||||
void uiFocusPopItem(uifocusitem_t *item);
|
||||
void uiFocusSetPosition(uifocusitem_t *item, uint8_t x, uint8_t y); // wraps
|
||||
void uiFocusMoveDirection(uifocusitem_t *item, uifocusdirection_t dir);
|
||||
```
|
||||
|
||||
`uiFocusUpdate()` runs automatically from `uiUpdate()` every tick — you don't
|
||||
call it yourself. It reads `INPUT_ACTION_ACCEPT` (fires `selected`),
|
||||
`INPUT_ACTION_CANCEL` (pops the stack), and the four directional actions
|
||||
(with hold-to-repeat timing) to move the cursor within the topmost pushed
|
||||
item. Only the topmost stack entry (max depth 8) receives input at a time —
|
||||
opening a submenu means pushing a new focus item on top; closing it pops back
|
||||
to the parent.
|
||||
|
||||
There's no separate "is this widget focused" query — "focused" is expressed
|
||||
as the pushed item's current `(x, y)` cursor cell matching a given slot, which
|
||||
is exactly how `uimenu`'s `changed` callback decides which item to highlight.
|
||||
|
||||
## System overlays (automatic)
|
||||
|
||||
Three small overlays are wired into a fixed internal list and draw themselves
|
||||
every frame with no call needed from game code:
|
||||
|
||||
- **Overscan bars** (`ui/overlay/uicrop.h`) — draws opaque bars over the
|
||||
screen area outside `SCREEN.scanX/scanY/scanWidth/scanHeight` (the
|
||||
overscan-safe viewport). A no-op on platforms/configs where the scan area
|
||||
already equals the full viewport. `UI_CROP.color` (default black) is the
|
||||
only thing you'd normally touch here.
|
||||
- **Debug console** (`ui/debug/uiconsole.h`) — draws console history when
|
||||
visible.
|
||||
- **FPS counter** (`ui/debug/uifps.h`) — draws a live FPS/frame-time readout.
|
||||
|
||||
None of these have a scissor/clip-rect equivalent for your own widgets —
|
||||
there is no clipping API in this UI system; everything draws unclipped at
|
||||
whatever position you give it.
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube.sh"
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube-iso.sh"
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$DEVKITPRO" ]; then
|
||||
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-gamecube-iso
|
||||
cmake -S. -Bbuild-gamecube-iso \
|
||||
-DDUSK_TARGET_SYSTEM=gamecube \
|
||||
-DDUSK_DOLPHIN_BUILD_TYPE=ISO \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake"
|
||||
cd build-gamecube-iso
|
||||
make -j$(nproc) VERBOSE=1
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$DEVKITPRO" ]; then
|
||||
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-gamecube
|
||||
cmake -S. -Bbuild-gamecube \
|
||||
-DDUSK_TARGET_SYSTEM=gamecube \
|
||||
-DDUSK_DOLPHIN_BUILD_TYPE=DOL \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake" \
|
||||
-DDKP_OGC_PLATFORM_LIBRARY=libogc2
|
||||
cd build-gamecube
|
||||
make -j$(nproc) VERBOSE=1
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-knulli -f docker/knulli/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-knulli /bin/bash -c "./scripts/build-knulli.sh"
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
cmake -S . -B build-knulli -G Ninja \
|
||||
-DDUSK_BUILD_TESTS=ON \
|
||||
-DDUSK_TARGET_SYSTEM=knulli \
|
||||
-DCMAKE_TOOLCHAIN_FILE=./cmake/toolchains/aarch64-linux-gnu.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build-knulli -- -j$(nproc)
|
||||
|
||||
# Copy necessary libs out
|
||||
mkdir -p ./build-knulli/dusk
|
||||
cp ./build-knulli/Dusk ./build-knulli/dusk/Dusk
|
||||
cp ./build-knulli/dusk.dsk ./build-knulli/dusk/dusk.dsk
|
||||
echo '#!/bin/bash' > build-knulli/dusk/Dusk.sh
|
||||
echo 'cd "$(dirname "$(readlink -f "$0")")"' >> build-knulli/dusk/Dusk.sh
|
||||
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(dirname "$(readlink -f "$0")")' >> build-knulli/dusk/Dusk.sh
|
||||
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/gl4es' >> build-knulli/dusk/Dusk.sh
|
||||
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib' >> build-knulli/dusk/Dusk.sh
|
||||
echo '$(dirname "$(readlink -f "$0")")/Dusk' >> build-knulli/dusk/Dusk.sh
|
||||
chmod +x build-knulli/dusk/Dusk.sh
|
||||
cp /usr/lib/aarch64-linux-gnu/liblua5.4.so.0 build-knulli/dusk/
|
||||
# cp /usr/lib/aarch64-linux-gnu/libSDL2-2.0.so.0 build-knulli/dusk/
|
||||
# cp /usr/lib/aarch64-linux-gnu/libGL.so.1 build-knulli/dusk/
|
||||
# cp /usr/lib/aarch64-linux-gnu/libEGL.so.1 build-knulli/dusk/
|
||||
# cp /usr/lib/aarch64-linux-gnu/libGLESv2.so.2 build-knulli/dusk/
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-linux /bin/bash -c "./scripts/build-linux.sh"
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cmake -S . -B build-linux -DDUSK_BUILD_TESTS=ON -DDUSK_TARGET_SYSTEM=linux
|
||||
cmake --build build-linux -- -j$(nproc)
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-psp -f docker/psp/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-psp /bin/bash -c "./scripts/build-psp.sh"
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$PSPDEV" ]; then
|
||||
echo "PSPDEV environment variable is not set. Please set it to the path of your PSP development environment."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-psp
|
||||
cd build-psp
|
||||
psp-cmake -DDUSK_TARGET_SYSTEM=psp -DCMAKE_TOOLCHAIN_FILE=$PSPDEV/psp/share/pspdev.cmake -DBUILD_PRX=1 .. CMAKE_BUILD_TYPE=Release
|
||||
make -j$(nproc)
|
||||
# psp-cmake -DDUSK_TARGET_SYSTEM=psp -DCMAKE_TOOLCHAIN_FILE=$PSPDEV/psp/share/pspdev.cmake -DBUILD_PRX=1 -DCMAKE_BUILD_TYPE=Debug ..
|
||||
# make
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-vita -f docker/vita/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-vita /bin/bash -c "./scripts/build-vita.sh"
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$VITASDK" ]; then
|
||||
echo "VITASDK environment variable is not set. Please set it to the path of your VitaSDK installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-vita
|
||||
cd build-vita
|
||||
cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake \
|
||||
-DDUSK_TARGET_SYSTEM=vita \
|
||||
..
|
||||
make -j$(nproc)
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii.sh"
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii-iso.sh"
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$DEVKITPRO" ]; then
|
||||
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-wii-iso
|
||||
cmake -S. -Bbuild-wii-iso \
|
||||
-DDUSK_TARGET_SYSTEM=wii \
|
||||
-DDUSK_DOLPHIN_BUILD_TYPE=ISO \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake"
|
||||
cd build-wii-iso
|
||||
make -j$(nproc) VERBOSE=1
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
if [ -z "$DEVKITPRO" ]; then
|
||||
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-wii
|
||||
cmake -S. -Bbuild-wii \
|
||||
-DDUSK_TARGET_SYSTEM=wii \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake" \
|
||||
-DDUSK_DOLPHIN_BUILD_TYPE=DOL
|
||||
cd build-wii
|
||||
make -j$(nproc) VERBOSE=1
|
||||
mv Dusk.dol boot.dol
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||
docker run \
|
||||
--rm \
|
||||
-v "${GITHUB_WORKSPACE}:/workdir" \
|
||||
dusk-linux \
|
||||
/bin/bash -c "./scripts/test-linux.sh"
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
rm -rf build-tests
|
||||
cmake -S . -B build-tests -DDUSK_BUILD_TESTS=ON -DDUSK_TARGET_SYSTEM=linux
|
||||
cmake --build build-tests -- -j$(nproc)
|
||||
ctest --output-on-failure --test-dir build-tests
|
||||
+17
-41
@@ -1,50 +1,26 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
find_package(cglm REQUIRED)
|
||||
find_package(libzip REQUIRED)
|
||||
find_package(lua REQUIRED)
|
||||
add_subdirectory(dusk)
|
||||
|
||||
# Libs
|
||||
target_link_libraries(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
m
|
||||
cglm
|
||||
zip
|
||||
lua
|
||||
pthread
|
||||
)
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli")
|
||||
add_subdirectory(dusklinux)
|
||||
add_subdirectory(dusksdl2)
|
||||
add_subdirectory(duskgl)
|
||||
|
||||
# Includes
|
||||
target_include_directories(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
add_subdirectory(duskpsp)
|
||||
add_subdirectory(dusksdl2)
|
||||
add_subdirectory(duskgl)
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
main.c
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "vita")
|
||||
add_subdirectory(duskvita)
|
||||
add_subdirectory(dusksdl2)
|
||||
add_subdirectory(duskgl)
|
||||
|
||||
# Defs
|
||||
add_defs(duskdefs.env duskdefs.h)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "wii" OR DUSK_TARGET_SYSTEM STREQUAL "gamecube")
|
||||
add_subdirectory(duskdolphin)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(asset)
|
||||
add_subdirectory(debug)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(engine)
|
||||
add_subdirectory(error)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(rpg)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(thread)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(util)
|
||||
endif()
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
#ifndef ASSERTIONS_FAKED
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool x,
|
||||
const char *message
|
||||
) {
|
||||
if(x != true) {
|
||||
debugPrint(
|
||||
"Assertion Failed in %s:%i\n\n%s\n",
|
||||
file,
|
||||
line,
|
||||
message
|
||||
);
|
||||
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
bool x,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, !x, message);
|
||||
}
|
||||
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, false, message);
|
||||
}
|
||||
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer != NULL,
|
||||
message
|
||||
);
|
||||
|
||||
// Ensure we can touch it
|
||||
volatile char temp;
|
||||
temp = *((char*)pointer);
|
||||
}
|
||||
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer == NULL,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertUnreachableImpl(file, line, message);
|
||||
}
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#ifndef ASSERTIONS_FAKED
|
||||
/**
|
||||
* Assert a given value to be true.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as true.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool_t x,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a given statement to be false.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as false.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool_t x,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts that a given line of code is unreachable. Essentially a forced
|
||||
* assertion failure, good for "edge cases"
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Assert a given pointer to not point to a null pointer.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is not a null pointer.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a given pointer to be a nullptr.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is nullptr.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a function as being deprecated.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
|
||||
void assertMemoryRangeMatchesImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *start,
|
||||
const void *end,
|
||||
const size_t size,
|
||||
const char *message
|
||||
);
|
||||
|
||||
#define assertTrue(x, message) \
|
||||
assertTrueImpl(__FILE__, __LINE__, x, message)
|
||||
|
||||
#define assertFalse(x, message) \
|
||||
assertFalseImpl(__FILE__, __LINE__, x, message)
|
||||
|
||||
#define assertUnreachable(message) \
|
||||
assertUnreachableImpl(__FILE__, __LINE__, message)
|
||||
|
||||
#define assertNotNull(pointer, message) \
|
||||
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
|
||||
#define assertNull(pointer, message) \
|
||||
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
|
||||
#define assertDeprecated(message) \
|
||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
||||
|
||||
#define assertStrLenMax(str, len, message) \
|
||||
assertTrue(strlen(str) < len, message)
|
||||
|
||||
#define assertStrLenMin(str, len, message) \
|
||||
assertTrue(strlen(str) >= len, message)
|
||||
|
||||
#else
|
||||
// If assertions are faked, we define the macros to do nothing.
|
||||
#define assertTrue(x, message) ((void)0)
|
||||
#define assertFalse(x, message) ((void)0)
|
||||
#define assertUnreachable(message) ((void)0)
|
||||
#define assertNotNull(pointer, message) ((void)0)
|
||||
#define assertNull(pointer, message) ((void)0)
|
||||
#define assertDeprecated(message) ((void)0)
|
||||
#define assertStrLenMax(str, len, message) ((void)0)
|
||||
#define assertStrLenMin(str, len, message) ((void)0)
|
||||
|
||||
#endif
|
||||
@@ -1,270 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/assettype.h"
|
||||
#include "engine/engine.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
errorret_t assetInit(void) {
|
||||
memoryZero(&ASSET, sizeof(asset_t));
|
||||
|
||||
// Engine may have been provided the launch path
|
||||
if(ENGINE.argc > 0) {
|
||||
// This first arg is the executable, so on most platforms it is say
|
||||
// "/path/file" or "C:\Path\file.exe". On PSP this would be something
|
||||
// like "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or if we are debugging it is
|
||||
// "host0:/Dusk.prx"
|
||||
|
||||
// Get the directory of the executable
|
||||
char_t buffer[FILENAME_MAX];
|
||||
stringCopy(buffer, ENGINE.argv[0], FILENAME_MAX);
|
||||
size_t len = strlen(buffer);
|
||||
|
||||
// Normalize slashes
|
||||
for(size_t i = 0; i < FILENAME_MAX; i++) {
|
||||
if(buffer[i] == '\0') break;
|
||||
if(buffer[i] == '\\') buffer[i] = '/';
|
||||
}
|
||||
|
||||
// Now find the last slash
|
||||
char_t *end = buffer + len - 1;
|
||||
do {
|
||||
end--;
|
||||
if(*end == '/') {
|
||||
*end = '\0';
|
||||
break;
|
||||
}
|
||||
} while(end != buffer);
|
||||
|
||||
|
||||
// Did we find a slash?
|
||||
if(end != buffer) {
|
||||
// We found the directory, set as system path
|
||||
stringCopy(ASSET.systemPath, buffer, FILENAME_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
// Default system path, intended to be overridden by the platform
|
||||
stringCopy(ASSET.systemPath, ".", FILENAME_MAX);
|
||||
|
||||
// PSP specific time.
|
||||
#if PSP
|
||||
assertTrue(ENGINE.argc >= 1, "PSP requires launch argument.");
|
||||
|
||||
// PSP is given either host0:/Dusk.prx (debugging) OR the PBP file.
|
||||
if(
|
||||
stringEndsWithCaseInsensitive(ENGINE.argv[0], ".pbp") ||
|
||||
ASSET_PBP_READ_PBP_FROM_HOST
|
||||
) {
|
||||
const char_t *pbpPath = (
|
||||
ASSET_PBP_READ_PBP_FROM_HOST ? "./EBOOT.PBP" : ENGINE.argv[0]
|
||||
);
|
||||
ASSET.pbpFile = fopen(pbpPath, "rb");
|
||||
if(ASSET.pbpFile == NULL) {
|
||||
errorThrow("Failed to open PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
// Get size of PBP file.
|
||||
if(fseek(ASSET.pbpFile, 0, SEEK_END) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to end of PBP file : %s", pbpPath);
|
||||
}
|
||||
size_t pbpSize = ftell(ASSET.pbpFile);
|
||||
|
||||
// Rewind to start
|
||||
if(fseek(ASSET.pbpFile, 0, SEEK_SET) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to start of PBP file : %s", pbpPath);
|
||||
}
|
||||
|
||||
// Read the PBP header
|
||||
size_t read = fread(
|
||||
&ASSET.pbpHeader,
|
||||
1,
|
||||
sizeof(assetpbp_t),
|
||||
ASSET.pbpFile
|
||||
);
|
||||
if(read != sizeof(assetpbp_t)) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to read PBP header", pbpPath);
|
||||
}
|
||||
|
||||
if(memoryCompare(
|
||||
ASSET.pbpHeader.signature,
|
||||
ASSET_PBP_SIGNATURE,
|
||||
sizeof(ASSET_PBP_SIGNATURE)
|
||||
) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Invalid PBP signature in file: %s", pbpPath);
|
||||
}
|
||||
|
||||
// If we seek to the PSAR offset, we can read the WAD file from there
|
||||
if(fseek(ASSET.pbpFile, ASSET.pbpHeader.psarOffset, SEEK_SET) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
zip_uint64_t zipPsarOffset = (zip_uint64_t)ASSET.pbpHeader.psarOffset;
|
||||
zip_int64_t zipPsarSize = (zip_int64_t)(
|
||||
pbpSize - ASSET.pbpHeader.psarOffset
|
||||
);
|
||||
|
||||
zip_source_t *psarSource = zip_source_filep_create(
|
||||
ASSET.pbpFile,
|
||||
zipPsarOffset,
|
||||
zipPsarSize,
|
||||
NULL
|
||||
);
|
||||
if(psarSource == NULL) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to create zip source in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
ASSET.zip = zip_open_from_source(
|
||||
psarSource,
|
||||
ZIP_RDONLY,
|
||||
NULL
|
||||
);
|
||||
if(ASSET.zip == NULL) {
|
||||
zip_source_free(psarSource);
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to open zip from PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Open zip file
|
||||
char_t searchPath[FILENAME_MAX];
|
||||
const char_t **path = ASSET_SEARCH_PATHS;
|
||||
do {
|
||||
sprintf(
|
||||
searchPath,
|
||||
*path,
|
||||
ASSET.systemPath,
|
||||
ASSET_FILE
|
||||
);
|
||||
|
||||
// Try open
|
||||
ASSET.zip = zip_open(searchPath, ZIP_RDONLY, NULL);
|
||||
if(ASSET.zip == NULL) continue;
|
||||
break;// Found!
|
||||
} while(*(++path) != NULL);
|
||||
|
||||
// Did we open the asset?
|
||||
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t assetFileExists(const char_t *filename) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
|
||||
zip_int64_t idx = zip_name_locate(ASSET.zip, filename, 0);
|
||||
if(idx < 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
// Try to open the file
|
||||
zip_file_t *file = zip_fopen(ASSET.zip, filename, 0);
|
||||
if(file == NULL) {
|
||||
errorThrow("Failed to open asset file: %s", filename);
|
||||
}
|
||||
|
||||
// Read the header.
|
||||
assetheader_t header;
|
||||
memoryZero(&header, sizeof(assetheader_t));
|
||||
zip_int64_t bytesRead = zip_fread(file, &header, sizeof(assetheader_t));
|
||||
if(bytesRead != sizeof(assetheader_t)) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset header for: %s", filename);
|
||||
}
|
||||
|
||||
// Find the asset type based on the header
|
||||
const assettypedef_t *def = NULL;
|
||||
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
||||
const assettypedef_t *cmp = &ASSET_TYPE_DEFINITIONS[i];
|
||||
if(cmp->header == NULL) continue;
|
||||
|
||||
// strcmp didn't work because it's a fixed char_t[3] I think, or maybe
|
||||
// because of the packed struct?
|
||||
bool_t match = true;
|
||||
for(size_t h = 0; h < ASSET_HEADER_SIZE; h++) {
|
||||
if(header.header[h] == cmp->header[h]) continue;
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if(!match) continue;
|
||||
|
||||
def = cmp;
|
||||
break;
|
||||
}
|
||||
if(def == NULL) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Unknown asset type for file: %s", filename);
|
||||
}
|
||||
|
||||
// We found the asset type, now load the asset data
|
||||
switch(def->loadStrategy) {
|
||||
case ASSET_LOAD_STRAT_ENTIRE:
|
||||
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
||||
void *data = memoryAllocate(def->dataSize);
|
||||
bytesRead = zip_fread(file, data, def->dataSize);
|
||||
if(bytesRead == 0 || bytesRead > def->dataSize) {
|
||||
memoryFree(data);
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset data for file: %s", filename);
|
||||
}
|
||||
|
||||
// Close the file now we have the data
|
||||
zip_fclose(file);
|
||||
|
||||
// Pass to the asset type loader
|
||||
errorret_t ret = def->entire(data, output);
|
||||
memoryFree(data);
|
||||
errorChain(ret);
|
||||
break;
|
||||
|
||||
case ASSET_LOAD_STRAT_CUSTOM:
|
||||
assertNotNull(def->custom, "Asset load function cannot be NULL.");
|
||||
assetcustom_t customData = {
|
||||
.zipFile = file,
|
||||
.output = output
|
||||
};
|
||||
errorChain(def->custom(customData));
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown asset load strategy.");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void assetDispose(void) {
|
||||
if(ASSET.zip != NULL) {
|
||||
zip_close(ASSET.zip);
|
||||
ASSET.zip = NULL;
|
||||
}
|
||||
|
||||
#if PSP
|
||||
if(ASSET.pbpFile != NULL) {
|
||||
fclose(ASSET.pbpFile);
|
||||
ASSET.pbpFile = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,92 +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"
|
||||
#include "assettype.h"
|
||||
|
||||
#if ASSET_TYPE == wad
|
||||
#if PSP
|
||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
||||
|
||||
typedef struct {
|
||||
char_t signature[ASSET_PBP_SIGNATURE_SIZE];
|
||||
uint32_t version;
|
||||
uint32_t sfoOffset;
|
||||
uint32_t icon0Offset;
|
||||
uint32_t icon1Offset;
|
||||
uint32_t pic0Offset;
|
||||
uint32_t pic1Offset;
|
||||
uint32_t snd0Offset;
|
||||
uint32_t pspOffset;
|
||||
uint32_t psarOffset;
|
||||
} assetpbp_t;
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported ASSET_TYPE"
|
||||
#endif
|
||||
|
||||
#define ASSET_FILE "dusk.dsk"
|
||||
#define ASSET_HEADER_SIZE 3
|
||||
|
||||
static const char_t *ASSET_SEARCH_PATHS[] = {
|
||||
"%s/%s",
|
||||
"%s",
|
||||
"../%s",
|
||||
"../../%s",
|
||||
"data/%s",
|
||||
"../data/%s",
|
||||
NULL
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
char_t header[ASSET_HEADER_SIZE];
|
||||
} assetheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
zip_t *zip;
|
||||
char_t systemPath[FILENAME_MAX];
|
||||
uint8_t assetCount;
|
||||
|
||||
#if PSP
|
||||
FILE *pbpFile;
|
||||
assetpbp_t pbpHeader;
|
||||
#endif
|
||||
} asset_t;
|
||||
|
||||
static asset_t ASSET;
|
||||
|
||||
/**
|
||||
* Initializes the asset system.
|
||||
*/
|
||||
errorret_t assetInit(void);
|
||||
|
||||
/**
|
||||
* Checks if an asset file exists.
|
||||
*
|
||||
* @param filename The filename of the asset to check.
|
||||
* @return true if the asset file exists, false otherwise.
|
||||
*/
|
||||
bool_t assetFileExists(const char_t *filename);
|
||||
|
||||
/**
|
||||
* Loads an asset by its filename, the output type depends on the asset type.
|
||||
*
|
||||
* @param filename The filename of the asset to retrieve.
|
||||
* @param output The output pointer to store the loaded asset data.
|
||||
* @return An error code if the asset could not be loaded.
|
||||
*/
|
||||
errorret_t assetLoad(const char_t *filename, void *output);
|
||||
|
||||
/**
|
||||
* Disposes/cleans up the asset system.
|
||||
*/
|
||||
void assetDispose(void);
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "type/assetpaletteimage.h"
|
||||
#include "type/assetalphaimage.h"
|
||||
#include "type/assetlanguage.h"
|
||||
#include "type/assetmap.h"
|
||||
#include "type/assetchunk.h"
|
||||
#include "type/assetscript.h"
|
||||
#include <zip.h>
|
||||
|
||||
typedef enum {
|
||||
ASSET_TYPE_NULL,
|
||||
|
||||
ASSET_TYPE_PALETTE_IMAGE,
|
||||
ASSET_TYPE_ALPHA_IMAGE,
|
||||
ASSET_TYPE_LANGUAGE,
|
||||
ASSET_TYPE_MAP,
|
||||
ASSET_TYPE_CHUNK,
|
||||
ASSET_TYPE_SCRIPT,
|
||||
|
||||
ASSET_TYPE_COUNT,
|
||||
} assettype_t;
|
||||
|
||||
typedef enum {
|
||||
ASSET_LOAD_STRAT_ENTIRE,
|
||||
ASSET_LOAD_STRAT_CUSTOM
|
||||
} assetloadstrat_t;
|
||||
|
||||
typedef struct assetcustom_s {
|
||||
zip_file_t *zipFile;
|
||||
void *output;
|
||||
} assetcustom_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *header;
|
||||
const size_t dataSize;
|
||||
const assetloadstrat_t loadStrategy;
|
||||
union {
|
||||
errorret_t (*entire)(void *data, void *output);
|
||||
errorret_t (*custom)(assetcustom_t custom);
|
||||
};
|
||||
} assettypedef_t;
|
||||
|
||||
static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
[ASSET_TYPE_NULL] = {
|
||||
0
|
||||
},
|
||||
|
||||
[ASSET_TYPE_PALETTE_IMAGE] = {
|
||||
.header = "DPI",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assetpaletteimage_t),
|
||||
.entire = assetPaletteImageLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_ALPHA_IMAGE] = {
|
||||
.header = "DAI",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assetalphaimage_t),
|
||||
.entire = assetAlphaImageLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_LANGUAGE] = {
|
||||
.header = "DLF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetLanguageHandler
|
||||
},
|
||||
|
||||
[ASSET_TYPE_MAP] = {
|
||||
.header = "DMF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(1),
|
||||
.entire = assetMapLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_CHUNK] = {
|
||||
.header = "DCF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetChunkLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_SCRIPT] = {
|
||||
.header = "DSF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetScriptHandler
|
||||
}
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
assetalphaimage.c
|
||||
assetpaletteimage.c
|
||||
assetlanguage.c
|
||||
assetmap.c
|
||||
assetchunk.c
|
||||
assetscript.c
|
||||
)
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetalphaimage.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
errorret_t assetAlphaImageLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
assetalphaimage_t *dataPtr = (assetalphaimage_t *)data;
|
||||
texture_t *outputPtr = (texture_t *)output;
|
||||
|
||||
textureInit(
|
||||
outputPtr,
|
||||
dataPtr->width,
|
||||
dataPtr->height,
|
||||
TEXTURE_FORMAT_ALPHA,
|
||||
(texturedata_t){ .alpha = { .data = dataPtr->pixels } }
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
#define ASSET_ALPHA_IMAGE_WIDTH_MAX 256
|
||||
#define ASSET_ALPHA_IMAGE_HEIGHT_MAX 256
|
||||
#define ASSET_ALPHA_IMAGE_SIZE_MAX ( \
|
||||
ASSET_ALPHA_IMAGE_WIDTH_MAX * ASSET_ALPHA_IMAGE_HEIGHT_MAX \
|
||||
)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t pixels[ASSET_ALPHA_IMAGE_SIZE_MAX];
|
||||
} assetalphaimage_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Loads an alpha image asset from the given asset structure. The asset must
|
||||
* be of type ASSET_TYPE_ALPHA_IMAGE and must be loaded.
|
||||
*
|
||||
* @param asset The asset to load the alpha image from.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetAlphaImageLoad(void *data, void *output);
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t tileCount;
|
||||
uint8_t modelCount;
|
||||
uint8_t entityCount;
|
||||
} assetchunkheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
tile_t tile;
|
||||
} assetchunktiledata_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t vertexCount;
|
||||
} assetchunkmodelheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
entitytype_t entityType;
|
||||
uint8_t localX;
|
||||
uint8_t localY;
|
||||
uint8_t localZ;
|
||||
} assetchunkentityheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
errorret_t assetChunkLoad(assetcustom_t custom) {
|
||||
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
||||
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
||||
|
||||
chunk_t *chunk = (chunk_t *)custom.output;
|
||||
assertTrue(chunk->meshCount == 0, "Chunk is not in a good state");
|
||||
|
||||
// Read header
|
||||
assetchunkheader_t header;
|
||||
size_t bytesRead = zip_fread(
|
||||
custom.zipFile, &header, sizeof(assetchunkheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunkheader_t)) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk asset header.");
|
||||
}
|
||||
|
||||
if(header.tileCount != CHUNK_TILE_COUNT) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has invalid tile count: %d (expected %d).",
|
||||
header.tileCount,
|
||||
CHUNK_TILE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
if(header.modelCount > CHUNK_MESH_COUNT_MAX) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has too many models: %d (max %d).",
|
||||
header.modelCount,
|
||||
CHUNK_MESH_COUNT_MAX
|
||||
);
|
||||
}
|
||||
|
||||
if(header.entityCount > CHUNK_ENTITY_COUNT_MAX) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has too many entities: %d (max %d).",
|
||||
header.entityCount,
|
||||
CHUNK_ENTITY_COUNT_MAX
|
||||
);
|
||||
}
|
||||
|
||||
chunk->meshCount = header.modelCount;
|
||||
|
||||
// Read tile data
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile,
|
||||
chunk->tiles,
|
||||
sizeof(assetchunktiledata_t) * header.tileCount
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunktiledata_t) * header.tileCount) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk tile data.");
|
||||
}
|
||||
|
||||
// For each model...
|
||||
uint32_t vertexIndex = 0;
|
||||
for(uint8_t i = 0; i < header.modelCount; i++) {
|
||||
assetchunkmodelheader_t modelHeader;
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile, &modelHeader, sizeof(assetchunkmodelheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunkmodelheader_t)) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk model header.");
|
||||
}
|
||||
|
||||
if(
|
||||
vertexIndex + modelHeader.vertexCount >
|
||||
CHUNK_VERTEX_COUNT_MAX
|
||||
) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Chunk model vertex count exceeds maximum.");
|
||||
}
|
||||
|
||||
// Read vertex data.
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile,
|
||||
&chunk->vertices[vertexIndex],
|
||||
sizeof(meshvertex_t) * modelHeader.vertexCount
|
||||
);
|
||||
if(bytesRead != sizeof(meshvertex_t) * modelHeader.vertexCount) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk model vertex data.");
|
||||
}
|
||||
|
||||
// Init the mesh
|
||||
if(modelHeader.vertexCount > 0) {
|
||||
mesh_t *mesh = &chunk->meshes[i];
|
||||
meshInit(
|
||||
mesh,
|
||||
MESH_PRIMITIVE_TRIANGLES,
|
||||
modelHeader.vertexCount,
|
||||
&chunk->vertices[vertexIndex]
|
||||
);
|
||||
|
||||
vertexIndex += modelHeader.vertexCount;
|
||||
} else {
|
||||
chunk->meshes[i].vertexCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read entity data
|
||||
for(uint8_t i = 0; i < header.entityCount; i++) {
|
||||
assetchunkentityheader_t entityHeader;
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile, &entityHeader, sizeof(assetchunkentityheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunkentityheader_t)) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk entity header.");
|
||||
}
|
||||
|
||||
uint8_t entityIndex = entityGetAvailable();
|
||||
if(entityIndex == 0xFF) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("No available entity slots.");
|
||||
}
|
||||
|
||||
entity_t *entity = &ENTITIES[entityIndex];
|
||||
entityInit(entity, (entitytype_t)entityHeader.entityType);
|
||||
entity->position.x = (
|
||||
(chunk->position.x * CHUNK_WIDTH) + entityHeader.localX
|
||||
);
|
||||
entity->position.y = (
|
||||
(chunk->position.y * CHUNK_HEIGHT) + entityHeader.localY
|
||||
);
|
||||
entity->position.z = (
|
||||
(chunk->position.z * CHUNK_DEPTH) + entityHeader.localZ
|
||||
);
|
||||
|
||||
chunk->entities[i] = entityIndex;
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -1,20 +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"
|
||||
#include "rpg/world/chunk.h"
|
||||
|
||||
typedef struct assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Handles loading of chunk data from a chunk asset file.
|
||||
*
|
||||
* @param custom The custom asset loading parameters.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetChunkLoad(assetcustom_t custom);
|
||||
@@ -1,111 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "locale/localemanager.h"
|
||||
|
||||
errorret_t assetLanguageHandler(assetcustom_t custom) {
|
||||
assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL");
|
||||
assertNotNull(custom.output, "Custom asset output cannot be NULL");
|
||||
|
||||
assetlanguage_t *lang = (assetlanguage_t *)custom.output;
|
||||
errorChain(assetLanguageInit(lang, custom.zipFile));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetLanguageInit(
|
||||
assetlanguage_t *lang,
|
||||
zip_file_t *zipFile
|
||||
) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
assertNotNull(zipFile, "Zip file cannot be NULL");
|
||||
assertNull(lang->zip, "Language asset zip file must be NULL.");
|
||||
// I want this but ubuntu isn't compiling with it right now.
|
||||
// assertTrue(zip_file_is_seekable(zipFile), "Language file must be seekable.");
|
||||
|
||||
// We now own the zip file handle.
|
||||
lang->zip = zipFile;
|
||||
|
||||
// Read in the header.
|
||||
zip_int64_t bytesRead = zip_fread(
|
||||
lang->zip,
|
||||
&lang->header,
|
||||
sizeof(assetlanguageheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetlanguageheader_t)) {
|
||||
zip_fclose(lang->zip);
|
||||
errorThrow("Failed to read language asset header.");
|
||||
}
|
||||
|
||||
lang->chunksOffset = zip_ftell(lang->zip);
|
||||
if(lang->chunksOffset <= 0) {
|
||||
zip_fclose(lang->zip);
|
||||
errorThrow("Failed to get language asset chunks offset.");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetLanguageRead(
|
||||
assetlanguage_t *lang,
|
||||
const uint32_t key,
|
||||
char_t *buffer,
|
||||
const uint32_t bufferSize,
|
||||
uint32_t *outLength
|
||||
) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
assertNotNull(lang->zip, "Language asset zip file cannot be NULL");
|
||||
assertTrue(key < LANG_KEY_COUNT, "Language key out of bounds.");
|
||||
|
||||
// Find the string entry
|
||||
assetlanguagestring_t *str = &lang->header.strings[LANG_MAP_TEST];
|
||||
|
||||
// If buffer is NULL, return the string length
|
||||
if(buffer == NULL) {
|
||||
assertNotNull(outLength, "Output length pointer cannot be NULL.");
|
||||
*outLength = str->length;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Ensure buffer is large enough
|
||||
assertTrue(
|
||||
bufferSize >= str->length + 1,
|
||||
"Provided buffer is too small for language string."
|
||||
);
|
||||
|
||||
// Determine the file position
|
||||
zip_int64_t seekTo = lang->chunksOffset + (
|
||||
(str->chunk * ASSET_LANG_CHUNK_CHAR_COUNT) + str->offset
|
||||
);
|
||||
|
||||
// Seek
|
||||
zip_int64_t result = zip_fseek(lang->zip, seekTo, SEEK_SET);
|
||||
if(result != 0) {
|
||||
errorThrow("Failed to seek to language string in asset.");
|
||||
}
|
||||
|
||||
// Read
|
||||
zip_int64_t readTest = zip_fread(lang->zip, buffer, str->length);
|
||||
if(readTest != str->length) {
|
||||
errorThrow("Failed to read test string from language asset.");
|
||||
}
|
||||
buffer[str->length] = '\0';
|
||||
|
||||
// Set str length if requested
|
||||
if(outLength != NULL) *outLength = str->length;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void assetLanguageDispose(assetlanguage_t *lang) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
|
||||
if(lang->zip) {
|
||||
zip_fclose(lang->zip);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "locale/language/keys.h"
|
||||
#include "error/error.h"
|
||||
#include "duskdefs.h"
|
||||
#include <zip.h>
|
||||
|
||||
#define ASSET_LANG_CHUNK_CACHE 4 // Number of chunks to cache in memory
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef char assetlanguagechunk_t[ASSET_LANG_CHUNK_CHAR_COUNT];
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t chunk;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
} assetlanguagestring_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
assetlanguagestring_t strings[LANG_KEY_COUNT];
|
||||
} assetlanguageheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
zip_file_t *zip;
|
||||
assetlanguageheader_t header;
|
||||
zip_int64_t chunksOffset;
|
||||
|
||||
// Chunk cache
|
||||
assetlanguagechunk_t chunks[ASSET_LANG_CHUNK_CACHE];
|
||||
uint32_t chunkIndices[ASSET_LANG_CHUNK_CACHE];
|
||||
} assetlanguage_t;
|
||||
|
||||
typedef struct assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Receiving function from the asset manager to handle language assets.
|
||||
*
|
||||
* @param custom Custom asset loading data.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageHandler(assetcustom_t custom);
|
||||
|
||||
/**
|
||||
* Initializes a language asset and loads the header data into memory.
|
||||
*
|
||||
* @param lang Language asset to initialize.
|
||||
* @param zipFile Zip file handle for the language asset.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageInit(assetlanguage_t *lang, zip_file_t *zipFile);
|
||||
|
||||
/**
|
||||
* Reads a string from the language asset into the provided buffer.
|
||||
*
|
||||
* @param lang Language asset to read from.
|
||||
* @param key Language key to read.
|
||||
* @param buffer Buffer to read the string into.
|
||||
* @param bufferSize Size of the provided buffer.
|
||||
* @param outLength Pointer to store the length of the string read.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageRead(
|
||||
assetlanguage_t *lang,
|
||||
const uint32_t key,
|
||||
char_t *buffer,
|
||||
const uint32_t bufferSize,
|
||||
uint32_t *outLength
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of language asset resources.
|
||||
*
|
||||
* @param custom Custom asset loading data.
|
||||
* @return Error code.
|
||||
*/
|
||||
void assetLanguageDispose(assetlanguage_t *lang);
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
errorret_t assetMapLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data cannot be NULL");
|
||||
assertNotNull(output, "Output cannot be NULL");
|
||||
|
||||
assertUnreachable("map not finished");
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -1,20 +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"
|
||||
#include "rpg/world/map.h"
|
||||
#include "display/mesh/mesh.h"
|
||||
|
||||
/**
|
||||
* Loads a map asset from the given data pointer into the output map structure.
|
||||
*
|
||||
* @param data Pointer to the raw assetmap_t data.
|
||||
* @param output Pointer to the map_t to load the map into.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetMapLoad(void *data, void *output);
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetpaletteimage.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
assetpaletteimage_t *assetData = (assetpaletteimage_t *)data;
|
||||
texture_t *texture = (texture_t *)output;
|
||||
|
||||
textureInit(
|
||||
texture,
|
||||
assetData->width,
|
||||
assetData->height,
|
||||
TEXTURE_FORMAT_PALETTE,
|
||||
(texturedata_t){
|
||||
.palette = {
|
||||
.palette = assetData->paletteIndex,
|
||||
.data = assetData->palette
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -1,34 +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"
|
||||
|
||||
#define ASSET_PALETTE_IMAGE_WIDTH_MAX 128
|
||||
#define ASSET_PALETTE_IMAGE_HEIGHT_MAX 128
|
||||
#define ASSET_PALETTE_IMAGE_SIZE_MAX ( \
|
||||
ASSET_PALETTE_IMAGE_WIDTH_MAX * ASSET_PALETTE_IMAGE_HEIGHT_MAX \
|
||||
)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t paletteIndex;
|
||||
uint8_t palette[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
||||
} assetpaletteimage_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Loads a palette image asset from the given data pointer into the output
|
||||
* texture.
|
||||
*
|
||||
* @param data Pointer to the raw assetpaletteimage_t data.
|
||||
* @param output Pointer to the texture_t to load the image into.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetPaletteImageLoad(void *data, void *output);
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
errorret_t assetScriptHandler(assetcustom_t custom) {
|
||||
assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL");
|
||||
assertNotNull(custom.output, "Custom asset output cannot be NULL");
|
||||
|
||||
assetscript_t *script = (assetscript_t *)custom.output;
|
||||
errorChain(assetScriptInit(script, custom.zipFile));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetScriptInit(
|
||||
assetscript_t *script,
|
||||
zip_file_t *zipFile
|
||||
) {
|
||||
assertNotNull(script, "Script asset cannot be NULL");
|
||||
assertNotNull(zipFile, "Zip file cannot be NULL");
|
||||
|
||||
// We now own the zip file handle.
|
||||
script->zip = zipFile;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
const char_t * assetScriptReader(lua_State* lState, void* data, size_t* size) {
|
||||
assetscript_t *script = (assetscript_t *)data;
|
||||
zip_int64_t bytesRead = zip_fread(
|
||||
script->zip, script->buffer, sizeof(script->buffer)
|
||||
);
|
||||
|
||||
if(bytesRead < 0) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = (size_t)bytesRead;
|
||||
return script->buffer;
|
||||
}
|
||||
|
||||
errorret_t assetScriptDispose(assetscript_t *script) {
|
||||
assertNotNull(script, "Script asset cannot be NULL");
|
||||
|
||||
if(script->zip != NULL) {
|
||||
zip_fclose(script->zip);
|
||||
script->zip = NULL;
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -1,57 +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"
|
||||
#include "duskdefs.h"
|
||||
#include <zip.h>
|
||||
#include <lua.h>
|
||||
|
||||
#define ASSET_SCRIPT_BUFFER_SIZE 1024
|
||||
|
||||
typedef struct assetscript_s {
|
||||
zip_file_t *zip;
|
||||
char_t buffer[ASSET_SCRIPT_BUFFER_SIZE];
|
||||
} assetscript_t;
|
||||
|
||||
typedef struct assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Receiving function from the asset manager to handle script assets.
|
||||
*
|
||||
* @param custom Custom asset loading data.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetScriptHandler(assetcustom_t custom);
|
||||
|
||||
/**
|
||||
* Initializes a script asset.
|
||||
*
|
||||
* @param script Script asset to initialize.
|
||||
* @param zipFile Zip file handle for the script asset.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetScriptInit(assetscript_t *script, zip_file_t *zipFile);
|
||||
|
||||
/**
|
||||
* Reader function for Lua to read script data from the asset.
|
||||
*
|
||||
* @param L Lua state.
|
||||
* @param data Pointer to the assetscript_t structure.
|
||||
* @param size Pointer to store the size of the read data.
|
||||
* @return Pointer to the read data buffer.
|
||||
*/
|
||||
const char_t * assetScriptReader(lua_State* L, void* data, size_t* size);
|
||||
|
||||
/**
|
||||
* Disposes of a script asset, freeing any allocated resources.
|
||||
*
|
||||
* @param script Script asset to dispose of.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetScriptDispose(assetscript_t *script);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
void debugPrint(const char_t *message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vprintf(message, args);
|
||||
va_end(args);
|
||||
|
||||
// For the time being just use standard printing functions.
|
||||
printf(message, args);
|
||||
|
||||
#if PSP
|
||||
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a");
|
||||
if(file) {
|
||||
va_start(args, message);
|
||||
vfprintf(file, message, args);
|
||||
va_end(args);
|
||||
fclose(file);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user