Compare commits
634
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5184064a26 | ||
|
|
6a43363539 | ||
|
|
b9195fbbad | ||
|
|
f715ad2176 | ||
|
|
ca02ee0352 | ||
|
|
fbaa54145e | ||
|
|
28754ffbf2 | ||
|
|
470c0eba7a | ||
|
|
7098dcec43 | ||
|
|
07137f57af | ||
|
|
8b7491a3d3 | ||
|
|
8cfa8ddfeb | ||
|
|
ef284a15a1 | ||
|
|
3723921573 | ||
|
|
195399635e | ||
|
|
46e2a924d3 | ||
|
|
b693ea4102 | ||
|
|
a73f55beb0 | ||
|
|
0bd2491ab7 | ||
|
|
860c797c9c | ||
|
|
38c5080f9f | ||
|
|
fae191d8fe | ||
|
|
d83a953e2d | ||
|
|
2dcf0d0f0d | ||
|
|
6dee37d8c1 | ||
|
|
3bad03afb3 | ||
|
|
6a6d8448f7 | ||
|
|
189babd2cf | ||
|
|
988a0f2294 | ||
|
|
85bf455731 | ||
|
|
589e4224f3 | ||
|
|
bd7fa154b4 | ||
|
|
a292f1992b | ||
|
|
88ddf429b7 | ||
|
|
7a1f6662df | ||
|
|
afc68bccc6 | ||
|
|
b4cdc4a64f | ||
|
|
3ad5afb81c | ||
|
|
bed3f20118 | ||
|
|
de67315178 | ||
|
|
8d5c0c7cad | ||
|
|
a8271e01bd | ||
|
|
900b3f8558 | ||
|
|
fdc4e056f9 | ||
|
|
7b98e40ccf | ||
|
|
01d89cf22c | ||
|
|
503a3c799a | ||
|
|
0b21388844 | ||
|
|
117bdf0c00 | ||
|
|
172dc5d37b | ||
|
|
874c6258ab | ||
|
|
a2d0a12c1a | ||
|
|
38b24e1c3d | ||
|
|
5ecbbe296b | ||
|
|
9d7a769d8f | ||
|
|
9b75e5ed83 | ||
|
|
a9ab8dc1d8 | ||
|
|
a34831aa02 | ||
|
|
84ebaa0751 | ||
|
|
55352805ee | ||
|
|
c0a3f2e16a | ||
|
|
28ff331a28 | ||
|
|
f9a53ec719 | ||
|
|
6a403e6caf | ||
|
|
a6f449bb93 | ||
|
|
0614bfc446 | ||
|
|
bb020c36c1 | ||
|
|
f17b0bfcfb | ||
|
|
2a85c9503f | ||
|
|
182428d6d6 | ||
|
|
8181a28557 | ||
|
|
88aed11d98 | ||
|
|
67010592b8 | ||
|
|
dd22d6424a | ||
|
|
e53775b97f | ||
|
|
d326f6c1ac | ||
|
|
556111c00a | ||
|
|
ebc7110e63 | ||
|
|
af49d1c8bb | ||
|
|
c71dbb1dfc | ||
|
|
432aa3c4fa | ||
|
|
5c93503710 | ||
|
|
0d58050def | ||
|
|
27bb78209a | ||
|
|
3201f5a25b | ||
|
|
d3df8a96d3 | ||
|
|
7ec5266b1f | ||
|
|
e74ff7c805 | ||
|
|
1d5f3c2959 | ||
|
|
469034b223 | ||
|
|
f3a394de21 | ||
|
|
cb23d4c11b | ||
|
|
bbf5b706f0 | ||
|
|
1e890f6d86 | ||
|
|
2fe543a603 | ||
|
|
24631990bd | ||
|
|
0c8c0d24ba | ||
|
|
454b8a91ba | ||
|
|
a74f1568e9 | ||
|
|
3f35d56be4 | ||
|
|
722fe2ccfb | ||
|
|
d85737cc08 | ||
|
|
ce29435831 | ||
|
|
d3715eece8 | ||
|
|
335d79f2c4 | ||
|
|
a9e33660cb | ||
|
|
8faf881399 | ||
|
|
c4969a36cc | ||
|
|
26fcaf6e75 | ||
|
|
a162002af2 | ||
|
|
9810fd51ab | ||
|
|
857c6b3d47 | ||
|
|
e1498f538d | ||
|
|
aa246eff94 | ||
|
|
5be21a21d5 | ||
|
|
8131bcd4d4 | ||
|
|
4ba11e3363 | ||
|
|
acf2be3f66 | ||
|
|
f5df0195e2 | ||
|
|
d26995b48d | ||
|
|
617f8120ae | ||
|
|
06c517c9aa | ||
|
|
593ed6408c | ||
|
|
fb7d3ed122 | ||
|
|
19b88ec858 | ||
|
|
160e65be7f | ||
|
|
079b0d2cf6 | ||
|
|
78f1310f41 | ||
|
|
eb1974c113 | ||
|
|
551409a023 | ||
|
|
a11e14daac | ||
|
|
7441e15e76 | ||
|
|
46506228a6 | ||
|
|
17c49c74cf | ||
|
|
3f8024d4db | ||
|
|
8675e44d28 | ||
|
|
1301d9a718 | ||
|
|
da3db50ca8 | ||
|
|
2ca6780305 | ||
|
|
be68fe5a35 | ||
|
|
dc41c0e302 | ||
|
|
51388c90d5 | ||
|
|
f8c9d33df2 | ||
|
|
ed0420fdce | ||
|
|
47a6f396fa | ||
|
|
9edb2aa0c1 | ||
|
|
003b647d83 | ||
|
|
2849ff8844 | ||
|
|
9f3089742a | ||
|
|
b286a9bbcd | ||
|
|
6204e745ba | ||
|
|
bbe0e48d23 | ||
|
|
79054080c0 | ||
|
|
81024c4c09 | ||
|
|
9068d96130 | ||
|
|
6f47543720 | ||
|
|
5a08384ae1 | ||
|
|
45d8fda0e4 | ||
|
|
a9e664492f | ||
|
|
3c8b6cb2cc | ||
|
|
2b3abbe13b | ||
|
|
241a52b94a | ||
|
|
82c300b077 | ||
|
|
0f8b629e20 | ||
|
|
36f6ac65f2 | ||
|
|
a25871a849 | ||
|
|
57766a9104 | ||
|
|
3770ae1645 | ||
|
|
d73edb403f | ||
|
|
b14196ff0d | ||
|
|
88903fee94 | ||
|
|
1e8311fc04 | ||
|
|
2b78370cb8 | ||
|
|
8f78bba9e9 | ||
|
|
41a4be678e | ||
|
|
8b2b4b7c3d | ||
|
|
1f3a29f89d | ||
|
|
c4c93097cd | ||
|
|
eedb7769e6 | ||
|
|
98db62a4bc | ||
|
|
df48c8e500 | ||
|
|
db9cc0f4c6 | ||
|
|
a79ee429b4 | ||
|
|
6acfca6d48 | ||
|
|
1cd6f4cb72 | ||
|
|
3271e8c7d6 | ||
|
|
0bcde064af | ||
|
|
957980b3c5 | ||
|
|
03eb328d81 | ||
|
|
e1716a741f | ||
|
|
e24707c847 | ||
|
|
7c4b8c307f | ||
|
|
109318aeaf | ||
|
|
1f2657cea0 | ||
|
|
382c435bac | ||
|
|
130fe4ca5d | ||
|
|
31ba3fe127 | ||
|
|
f68b31158f | ||
|
|
653ca9a72d | ||
|
|
ba7857f4df | ||
|
|
23e617ea21 | ||
|
|
cdf5a5229c | ||
|
|
f841a35a53 | ||
|
|
efd31237be | ||
|
|
6502822583 | ||
|
|
a9e6f2b2a5 | ||
|
|
510a94b42c | ||
|
|
d805be47ce | ||
|
|
f9ea8e380a | ||
|
|
5cb05beb30 | ||
|
|
677768e6ab | ||
|
|
ed6c951783 | ||
|
|
54254348b8 | ||
|
|
782fd07a8d | ||
|
|
a8fd55cb38 | ||
|
|
d7f515575a | ||
|
|
bafbf2ec2f | ||
|
|
7415944e0a | ||
|
|
1ff990ff44 | ||
|
|
73e73d8772 | ||
|
|
6d876bb767 | ||
|
|
2be0fe9f06 | ||
|
|
e1fb082927 | ||
|
|
65ca5ae4c4 | ||
|
|
2cea43dc70 | ||
|
|
44a0700800 | ||
|
|
1613a378f1 | ||
|
|
deed98a27d | ||
|
|
9d0cb8fb46 | ||
|
|
d8fe0f6923 | ||
|
|
581dbc2b3c | ||
|
|
7301d2ad76 | ||
|
|
3232a14d1d | ||
|
|
84c1f88d42 | ||
|
|
3695b10e4b | ||
|
|
6da02b25fa | ||
|
|
3bc544fba1 | ||
|
|
368d370f49 | ||
|
|
bb29c0edef | ||
|
|
6edcf75a0c | ||
|
|
31cc186424 | ||
|
|
0e94c1fa6d | ||
|
|
6d9e2dd3e1 | ||
|
|
4a4adeb3c8 | ||
|
|
ff77f8cfa0 | ||
|
|
36db89c36e | ||
|
|
a9948142ad | ||
|
|
8d05510584 | ||
|
|
d373de7a29 | ||
|
|
1efa9a9f7b | ||
|
|
0fb3ba2f91 | ||
|
|
3b4c5b5153 | ||
|
|
9293aeeec8 | ||
|
|
03ae83b119 | ||
|
|
abd63cc6cf | ||
|
|
2e43aa2c44 | ||
|
|
3d984e13c2 | ||
|
|
010900fe21 | ||
|
|
ffed626447 | ||
|
|
61f69af35a | ||
|
|
bd248ee91c | ||
|
|
194255bffe | ||
|
|
52ee627079 | ||
|
|
bd4200e707 | ||
|
|
73e7d6c7f3 | ||
|
|
a41b0e916b | ||
|
|
19f2a2c616 | ||
|
|
998601f722 | ||
|
|
7c3386cf3e | ||
|
|
d161182997 | ||
|
|
1646dc2dbd | ||
|
|
b640295be2 | ||
|
|
b89ae2391b | ||
|
|
a0fad441d0 | ||
|
|
340084dac3 | ||
|
|
c78135aa09 | ||
|
|
d19f8bbd30 | ||
|
|
4205899f5a | ||
|
|
7dd3940770 | ||
|
|
00d94e3015 | ||
|
|
7bacb3ee2b | ||
|
|
8e49be5ac4 | ||
|
|
3b94598d2c | ||
|
|
bddc9af3b6 | ||
|
|
2451d73a7c | ||
|
|
1dd2efa182 | ||
|
|
acea610773 | ||
|
|
8f2f1fd496 | ||
|
|
39c775872a | ||
|
|
bdb3cbd109 | ||
|
|
ff84ce2b04 | ||
|
|
225f405592 | ||
|
|
715ecffa18 | ||
|
|
e51cdc8992 | ||
|
|
133685ea37 | ||
|
|
6aff98d555 | ||
|
|
acdc524284 | ||
|
|
1ee5ec7b43 | ||
|
|
46a5403511 | ||
|
|
87bfb92576 | ||
|
|
c7a3e5601c | ||
|
|
4009130f6e | ||
|
|
c91243f6e9 | ||
|
|
0e3871ac26 | ||
|
|
55baafec8a | ||
|
|
b5a66993ca | ||
|
|
0b570b5fd6 | ||
|
|
378227c377 | ||
|
|
650645eaff | ||
|
|
62c71f3fe6 | ||
|
|
041ec3d710 | ||
|
|
5f2d871bad | ||
|
|
a30b151e4d | ||
|
|
5a651d2d1f | ||
|
|
4b3826edd9 | ||
|
|
bae1ff3759 | ||
|
|
fd82486431 | ||
|
|
c9cd91cbd8 | ||
|
|
c8abd374fe | ||
|
|
2b9ee8f721 | ||
|
|
d02673e04a | ||
|
|
f0117b8e6e | ||
|
|
bb7c41c754 | ||
|
|
efa583c154 | ||
|
|
d16ea13c14 | ||
|
|
673d8e0a18 | ||
|
|
37cfdde1ee | ||
|
|
0778ffb57a | ||
|
|
42099f7241 | ||
|
|
c52e1d22b7 | ||
|
|
0d7b0aadd1 | ||
|
|
4cd3355ef1 | ||
|
|
98d70b96d1 | ||
|
|
64735bdf43 | ||
|
|
7b87347b77 | ||
|
|
b5b29d7061 | ||
|
|
9ec21f85a0 | ||
|
|
da1a5a3f1b | ||
|
|
0885da8d44 | ||
|
|
8af961c6d3 | ||
|
|
ef5febdde3 | ||
|
|
6d7fbd3926 | ||
|
|
2680d373d8 | ||
|
|
2b2ddb3cf2 | ||
|
|
85ff95296b | ||
|
|
314a2de41a | ||
|
|
26fafab47a | ||
|
|
e56ff20e2d | ||
|
|
55d44f229d | ||
|
|
1c5e50cc4d | ||
|
|
ea898da6c2 | ||
|
|
dbb7e9f53c | ||
|
|
cbb68a399d | ||
|
|
0e794f28b1 | ||
|
|
87d2d9123e | ||
|
|
6823a4ddb5 | ||
|
|
20a7c70081 | ||
|
|
9caa33b3bb | ||
|
|
2d7e61460a | ||
|
|
a4b7fb3f44 | ||
|
|
70056cf4ca | ||
|
|
5f4ab71ade | ||
|
|
f3adb3257b | ||
|
|
438edda7fd | ||
|
|
d5b0441e6f | ||
|
|
9ba0ceb000 | ||
|
|
9474a68995 | ||
|
|
09c35f0aa6 | ||
|
|
a2113442cb | ||
|
|
d91808487f | ||
|
|
933949cc19 | ||
|
|
407620387d | ||
|
|
98947dea26 | ||
|
|
ebff7af9b5 | ||
|
|
b23c4b83ae | ||
|
|
c0cff40628 | ||
|
|
97513e354c | ||
|
|
c277ae7aff | ||
|
|
e1835e6282 | ||
|
|
5ac21db997 | ||
|
|
ca0e9fc3b2 | ||
|
|
66ebcb1608 | ||
|
|
ff92a78dda | ||
|
|
7356286fe0 | ||
|
|
54e8e68f86 | ||
|
|
d21cd7f78b | ||
|
|
1d7516982a | ||
|
|
c77a11442c | ||
|
|
5bd43a4643 | ||
|
|
9b87dfa1a9 | ||
|
|
2e3173ea40 | ||
|
|
68eac7cf83 | ||
|
|
6709505630 | ||
|
|
af6e962a5d | ||
|
|
18e6bdabaa | ||
|
|
9743942eae | ||
|
|
23062137a8 | ||
|
|
46f7fb5ccd | ||
|
|
9c90c49a6b | ||
|
|
4517b63557 | ||
|
|
58c239f4b4 | ||
|
|
cc8845ba3e | ||
|
|
6b69ce2901 | ||
|
|
55300ed21c | ||
|
|
7346dd4339 | ||
|
|
2caf3b92ce | ||
|
|
af2cd72a1f | ||
|
|
3d455ec1f8 | ||
|
|
15982d7735 | ||
|
|
5ae3542bd9 | ||
|
|
b1b02ae24b | ||
|
|
f0964e2c92 | ||
|
|
e9661d2998 | ||
|
|
ea6468f2a9 | ||
|
|
a2b38d3b83 | ||
|
|
d67ef02941 | ||
|
|
549ebe25d8 | ||
|
|
9a98348582 | ||
|
|
c5f5b025a6 | ||
|
|
23eaffa3a7 | ||
|
|
c161809248 | ||
|
|
4bf26dc818 | ||
|
|
5dd22fad6c | ||
|
|
2c3fdf7803 | ||
|
|
e984b9f5d7 | ||
|
|
a3c2e37b17 | ||
|
|
edf1b5a0a3 | ||
|
|
8efdf59ebd | ||
|
|
5c4537b2fa | ||
|
|
71e6079054 | ||
|
|
dd048d9b0d | ||
|
|
93074d653e | ||
|
|
9139c4350a | ||
|
|
38ce768168 | ||
|
|
82b3dc576c | ||
|
|
2167889f48 | ||
|
|
e9b02c2acf | ||
|
|
9ee446431b | ||
|
|
df106e3988 | ||
|
|
d0a057e0ee | ||
|
|
8b49902bf6 | ||
|
|
71c1e56564 | ||
|
|
1b12e67de2 | ||
|
|
291bb4bb81 | ||
|
|
342ddb19f8 | ||
|
|
9c9d2d548e | ||
|
|
d7a0bb4509 | ||
|
|
2b1a3323a8 | ||
|
|
99d030003c | ||
|
|
92a753560b | ||
|
|
af9904c892 | ||
|
|
e5e8c49f6c | ||
|
|
b37e5f45ca | ||
|
|
e1f08b07aa | ||
|
|
073ee8dca9 | ||
|
|
a26e51cf46 | ||
|
|
dfed732825 | ||
|
|
87aa70c6d2 | ||
|
|
aa2979ffe7 | ||
|
|
236e16aa6d | ||
|
|
184bb970e6 | ||
|
|
bd54469891 | ||
|
|
2f5dccc3ef | ||
|
|
592edb90a0 | ||
|
|
3db7e6b1b9 | ||
|
|
13c4df0d85 | ||
|
|
ef25fb09da | ||
|
|
03cf4a9efe | ||
|
|
53dd36efdd | ||
|
|
ad9e841a42 | ||
|
|
14f3f464c7 | ||
|
|
cbe51cc8d0 | ||
|
|
efaa3f6eea | ||
|
|
52cce9a3b0 | ||
|
|
b7b390311e | ||
|
|
c1eeddd14b | ||
|
|
1a7a55dfc3 | ||
|
|
fe5927ea6a | ||
|
|
119c794ad7 | ||
|
|
e2076b2c1c | ||
|
|
5208c5148e | ||
|
|
d80660b097 | ||
|
|
b916d0278b | ||
|
|
d51e13e620 | ||
|
|
40ad4326ef | ||
|
|
b8afc1684a | ||
|
|
8348b31ac8 | ||
|
|
411f2dbcce | ||
|
|
ee89c08160 | ||
|
|
357607a89f | ||
|
|
8d6dc2df44 | ||
|
|
5207582ab3 | ||
|
|
71768e6154 | ||
|
|
ecbe235523 | ||
|
|
afef079d1e | ||
|
|
df17696c69 | ||
|
|
065bf0908f | ||
|
|
5b6755e9cf | ||
|
|
b08482acf1 | ||
|
|
80c9c1d389 | ||
|
|
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 | ||
|
|
77d3c54ebb | ||
|
|
b5de39926b | ||
|
|
3a8dafbb91 | ||
|
|
6b22f547fe | ||
|
|
de78be3e25 | ||
|
|
9f507be7bc | ||
|
|
9aaf271996 | ||
|
|
b01c0d37b0 | ||
|
|
538079880d | ||
|
|
fe0529d021 | ||
|
|
d068f0f2c3 | ||
|
|
f9a64b8d54 | ||
|
|
01cbfaae95 | ||
|
|
f9006a90d5 | ||
|
|
7daeaee6b5 | ||
|
|
03218ce20f | ||
|
|
6f33522c1c | ||
|
|
3697cc3eef | ||
|
|
51a1077fda | ||
|
|
8740c2b165 | ||
|
|
6ed2bdd4c5 | ||
|
|
c32df89490 | ||
|
|
bd5a67676b | ||
|
|
903dab49e3 | ||
|
|
1668c4b0d2 | ||
|
|
2179a27bf5 | ||
|
|
6e7a0cba76 | ||
|
|
69b37b30bc | ||
|
|
ae941a0fdb | ||
|
|
1b741a81e5 | ||
|
|
edf321515b | ||
|
|
c874e6c197 | ||
|
|
9a59c22288 | ||
|
|
750e8840f0 | ||
|
|
cf59989167 | ||
|
|
7c194ab4b4 | ||
|
|
be422d0a1e | ||
|
|
68b63d3007 | ||
|
|
8525138594 | ||
|
|
7b9f8b190e | ||
|
|
67f62daa9f | ||
|
|
0ec701f30b | ||
|
|
c53439066e | ||
|
|
7278bd0c6f | ||
|
|
b842e5821a | ||
|
|
f7d4cce485 |
@@ -1,84 +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
|
|
||||||
- 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
|
|
||||||
- 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
|
|
||||||
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- build-linux
|
|
||||||
- build-psp
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Download Linux binary
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-linux
|
|
||||||
path: ./release-assets/linux
|
|
||||||
- name: Download PSP binary
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-psp
|
|
||||||
path: ./release-assets/psp
|
|
||||||
- name: Create Gitea Release
|
|
||||||
uses: akkuman/gitea-release-action@v1
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: '--experimental-fetch' # if nodejs < 18
|
|
||||||
files: |
|
|
||||||
./release-assets/linux/Dusk
|
|
||||||
./release-assets/psp/Dusk/EBOOT.PBP
|
|
||||||
@@ -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
|
||||||
+13
-1
@@ -83,7 +83,6 @@ assets/borrowed
|
|||||||
.VSCode*
|
.VSCode*
|
||||||
|
|
||||||
/vita
|
/vita
|
||||||
|
|
||||||
._*
|
._*
|
||||||
|
|
||||||
*~
|
*~
|
||||||
@@ -95,3 +94,16 @@ assets/borrowed
|
|||||||
# /archive
|
# /archive
|
||||||
|
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn-error.log
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
.editor
|
||||||
|
.venv
|
||||||
|
|
||||||
|
/build2
|
||||||
|
/build*
|
||||||
|
/assets/test
|
||||||
|
/tools_old
|
||||||
|
/assets/test.png
|
||||||
+85
-76
@@ -5,14 +5,19 @@
|
|||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
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)
|
option(DUSK_BUILD_TESTS "Enable tests" OFF)
|
||||||
set(DUSK_TARGET_SYSTEM "linux")
|
|
||||||
#set(DUSK_TARGET_SYSTEM "psp")
|
set(DUSK_GAME_NAME "Dusk" CACHE STRING "Game display name")
|
||||||
endif()
|
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
|
# Prep cache
|
||||||
set(DUSK_CACHE_TARGET "dusk-target")
|
set(DUSK_CACHE_TARGET "dusk-target")
|
||||||
@@ -21,101 +26,105 @@ set(DUSK_CACHE_TARGET "dusk-target")
|
|||||||
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
||||||
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
||||||
set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src")
|
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_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
||||||
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
||||||
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
||||||
set(DUSK_ASSETS_DIR "${DUSK_ROOT_DIR}/assets")
|
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_BUILT_ASSETS_DIR "${DUSK_BUILD_DIR}/built_assets" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated")
|
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_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_ASSETS "" 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
|
# Create directories
|
||||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
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)
|
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||||
|
|
||||||
# Toolchains
|
# Init Project.
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
project(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
find_package(pspsdk REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Init Project
|
|
||||||
project(${DUSK_TARGET_NAME}
|
|
||||||
VERSION 1.0.0
|
VERSION 1.0.0
|
||||||
LANGUAGES C
|
LANGUAGES C
|
||||||
)
|
)
|
||||||
|
|
||||||
# Executable
|
# Either, create library and binary separately (used for tests), or make them
|
||||||
add_executable(${DUSK_TARGET_NAME})
|
# 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 tools
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
|
||||||
# Assets
|
# Include generated headers from tools.
|
||||||
add_subdirectory(assets)
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
|
||||||
# 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}/assetstool/main.py
|
|
||||||
--assets ${DUSK_GAME_ASSETS_DIR}
|
|
||||||
--build-type wad
|
|
||||||
--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
|
|
||||||
${DUSK_GENERATED_HEADERS_DIR}
|
${DUSK_GENERATED_HEADERS_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Postbuild
|
# Add main code
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
add_subdirectory(${DUSK_SOURCES_DIR})
|
||||||
create_pbp_file(
|
|
||||||
TARGET "${DUSK_TARGET_NAME}"
|
# Include generated headers
|
||||||
ICON_PATH NULL
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
BACKGROUND_PATH NULL
|
${DUSK_GENERATED_HEADERS_DIR}
|
||||||
PREVIEW_PATH NULL
|
)
|
||||||
TITLE "${DUSK_TARGET_NAME}"
|
|
||||||
PSAR_PATH ${DUSK_BUILD_DIR}/dusk.dsk
|
# Handle tests
|
||||||
VERSION 01.00
|
if(DUSK_BUILD_TESTS)
|
||||||
)
|
enable_testing()
|
||||||
|
add_subdirectory(test)
|
||||||
endif()
|
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)
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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
|
||||||
|
workflow to see how the builds are done for each target. In addition, for
|
||||||
|
accessing the editor and building the game on your host system, install the
|
||||||
|
following packages, depending on your system;
|
||||||
|
|
||||||
|
Fedora;
|
||||||
|
```
|
||||||
|
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;
|
||||||
|
```
|
||||||
|
sudo apt-get install git build-essential gcc python python-polib python3-pillow python3-dotenv python3-numpy python3-pyqt5 python3-opengl
|
||||||
|
```
|
||||||
|
|
||||||
|
Arch Linux;
|
||||||
|
```
|
||||||
|
sudo pacman -S git base-devel gcc python python-polib python-pillow python-dotenv python-numpy python-pyqt5 python-opengl
|
||||||
|
```
|
||||||
@@ -1,16 +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(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
-16
@@ -1,16 +1,2 @@
|
|||||||
msgid ""
|
msgid "test.string"
|
||||||
msgstr ""
|
msgstr "This is a test string"
|
||||||
"Language: en_US\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\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."
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"tiles": [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 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,
|
|
||||||
|
|
||||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"tiles": [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 5, 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,
|
|
||||||
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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 241 B |
Binary file not shown.
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)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
cglm
|
cglm
|
||||||
|
# GIT_REPOSITORY https://git.wish.moe/YourWishes/cglm.git
|
||||||
GIT_REPOSITORY https://github.com/recp/cglm.git
|
GIT_REPOSITORY https://github.com/recp/cglm.git
|
||||||
GIT_TAG v0.9.6
|
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,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()
|
||||||
@@ -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
|
||||||
+18
-36
@@ -1,44 +1,26 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
# Copyright (c) 2026 Dominic Masters
|
||||||
#
|
#
|
||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
find_package(cglm REQUIRED)
|
add_subdirectory(dusk)
|
||||||
find_package(libzip REQUIRED)
|
|
||||||
|
|
||||||
# Libs
|
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli")
|
||||||
target_link_libraries(${DUSK_TARGET_NAME}
|
add_subdirectory(dusklinux)
|
||||||
PUBLIC
|
add_subdirectory(dusksdl2)
|
||||||
m
|
add_subdirectory(duskgl)
|
||||||
cglm
|
|
||||||
zip
|
|
||||||
pthread
|
|
||||||
)
|
|
||||||
|
|
||||||
# Includes
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||||
target_include_directories(${DUSK_TARGET_NAME}
|
add_subdirectory(duskpsp)
|
||||||
PRIVATE
|
add_subdirectory(dusksdl2)
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
add_subdirectory(duskgl)
|
||||||
)
|
|
||||||
|
|
||||||
# Sources
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "vita")
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
add_subdirectory(duskvita)
|
||||||
PRIVATE
|
add_subdirectory(dusksdl2)
|
||||||
main.c
|
add_subdirectory(duskgl)
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirs
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "wii" OR DUSK_TARGET_SYSTEM STREQUAL "gamecube")
|
||||||
add_subdirectory(assert)
|
add_subdirectory(duskdolphin)
|
||||||
add_subdirectory(asset)
|
|
||||||
add_subdirectory(debug)
|
endif()
|
||||||
add_subdirectory(display)
|
|
||||||
add_subdirectory(engine)
|
|
||||||
add_subdirectory(error)
|
|
||||||
add_subdirectory(input)
|
|
||||||
add_subdirectory(locale)
|
|
||||||
add_subdirectory(rpg)
|
|
||||||
add_subdirectory(scene)
|
|
||||||
add_subdirectory(thread)
|
|
||||||
add_subdirectory(time)
|
|
||||||
add_subdirectory(ui)
|
|
||||||
add_subdirectory(util)
|
|
||||||
@@ -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,85 +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 <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_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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
assetalphaimage.c
|
|
||||||
assetpaletteimage.c
|
|
||||||
assetlanguage.c
|
|
||||||
assetmap.c
|
|
||||||
assetchunk.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,127 +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"
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t tileCount;
|
|
||||||
uint8_t modelCount;
|
|
||||||
} 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)
|
|
||||||
|
|
||||||
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;
|
|
||||||
printf(
|
|
||||||
"Loading chunk asset at position (%d, %d, %d)...\n",
|
|
||||||
chunk->position.x,
|
|
||||||
chunk->position.y,
|
|
||||||
chunk->position.z
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
mesh_t *mesh = &chunk->meshes[i];
|
|
||||||
meshInit(
|
|
||||||
mesh,
|
|
||||||
MESH_PRIMITIVE_TRIANGLES,
|
|
||||||
modelHeader.vertexCount,
|
|
||||||
&chunk->vertices[vertexIndex]
|
|
||||||
);
|
|
||||||
|
|
||||||
vertexIndex += modelHeader.vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 <zip.h>
|
|
||||||
|
|
||||||
#define ASSET_LANG_CHUNK_CHAR_COUNT 6 * 1024 // 6 KB per chunk
|
|
||||||
#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,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
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a debug message to the debug console.
|
|
||||||
*
|
|
||||||
* @param message The message format string.
|
|
||||||
* @param ... Additional arguments for the format string.
|
|
||||||
*/
|
|
||||||
void debugPrint(const char_t *message, ...);
|
|
||||||
@@ -1,40 +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
|
|
||||||
display.c
|
|
||||||
framebuffer.c
|
|
||||||
camera.c
|
|
||||||
screen.c
|
|
||||||
texture.c
|
|
||||||
spritebatch.c
|
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirectories
|
|
||||||
add_subdirectory(mesh)
|
|
||||||
add_subdirectory(palette)
|
|
||||||
add_subdirectory(tileset)
|
|
||||||
|
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
|
||||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
DISPLAY_SDL2=1
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT=1080
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT=810
|
|
||||||
DISPLAY_SCREEN_HEIGHT_DEFAULT=270
|
|
||||||
)
|
|
||||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
|
||||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
DISPLAY_SDL2=1
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT=480
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT=272
|
|
||||||
DISPLAY_WIDTH=480
|
|
||||||
DISPLAY_HEIGHT=272
|
|
||||||
DISPLAY_SIZE_DYNAMIC=0
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "camera.h"
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
|
|
||||||
void cameraInit(camera_t *camera) {
|
|
||||||
cameraInitPerspective(camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraInitPerspective(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
camera->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
|
|
||||||
camera->perspective.fov = glm_rad(45.0f);
|
|
||||||
camera->nearClip = 0.1f;
|
|
||||||
camera->farClip = 10000.0f;
|
|
||||||
|
|
||||||
camera->viewType = CAMERA_VIEW_TYPE_LOOKAT;
|
|
||||||
glm_vec3_copy((vec3){ 5.0f, 5.0f, 5.0f }, camera->lookat.position);
|
|
||||||
glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, camera->lookat.up);
|
|
||||||
glm_vec3_copy((vec3){ 0.0f, 0.0f, 0.0f }, camera->lookat.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraInitOrthographic(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
camera->projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
|
|
||||||
camera->orthographic.left = 0.0f;
|
|
||||||
camera->orthographic.right = (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND);
|
|
||||||
camera->orthographic.bottom = 0.0f;
|
|
||||||
camera->orthographic.top = (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND);
|
|
||||||
camera->nearClip = -1.0f;
|
|
||||||
camera->farClip = 1.0f;
|
|
||||||
|
|
||||||
camera->viewType = CAMERA_VIEW_TYPE_2D;
|
|
||||||
glm_vec2_copy((vec2){ 0.0f, 0.0f }, camera->_2d.position);
|
|
||||||
camera->_2d.zoom = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraPushMatrix(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
|
|
||||||
switch(camera->projType) {
|
|
||||||
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC: {
|
|
||||||
assertTrue(
|
|
||||||
camera->orthographic.right != camera->orthographic.left &&
|
|
||||||
camera->orthographic.top != camera->orthographic.bottom,
|
|
||||||
"Invalid orthographic projection parameters"
|
|
||||||
);
|
|
||||||
glm_ortho(
|
|
||||||
camera->orthographic.left,
|
|
||||||
camera->orthographic.right,
|
|
||||||
camera->orthographic.bottom,
|
|
||||||
camera->orthographic.top,
|
|
||||||
camera->nearClip,
|
|
||||||
camera->farClip,
|
|
||||||
projection
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
|
|
||||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE: {
|
|
||||||
const float_t aspect = (
|
|
||||||
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
|
|
||||||
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
|
|
||||||
);
|
|
||||||
glm_perspective(
|
|
||||||
camera->perspective.fov,
|
|
||||||
aspect,
|
|
||||||
camera->nearClip,
|
|
||||||
camera->farClip,
|
|
||||||
projection
|
|
||||||
);
|
|
||||||
|
|
||||||
if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
|
|
||||||
// Flip Y axis
|
|
||||||
projection[1][1] *= -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(camera->viewType) {
|
|
||||||
case CAMERA_VIEW_TYPE_MATRIX:
|
|
||||||
glm_mat4_copy(camera->view, view);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_LOOKAT:
|
|
||||||
glm_lookat(
|
|
||||||
camera->lookat.position,
|
|
||||||
camera->lookat.target,
|
|
||||||
camera->lookat.up,
|
|
||||||
view
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
|
|
||||||
assertTrue(
|
|
||||||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
|
|
||||||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
|
|
||||||
"Pixel perfect camera view requires perspective projection"
|
|
||||||
);
|
|
||||||
|
|
||||||
const float_t viewportHeight = (
|
|
||||||
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
|
|
||||||
);
|
|
||||||
const float_t z = (viewportHeight / 2.0f) / (
|
|
||||||
camera->lookatPixelPerfect.pixelsPerUnit *
|
|
||||||
tanf(camera->perspective.fov / 2.0f)
|
|
||||||
);
|
|
||||||
|
|
||||||
vec3 position;
|
|
||||||
glm_vec3_copy(camera->lookatPixelPerfect.target, position);
|
|
||||||
glm_vec3_add(position, camera->lookatPixelPerfect.offset, position);
|
|
||||||
position[2] += z;
|
|
||||||
glm_lookat(
|
|
||||||
position,
|
|
||||||
camera->lookatPixelPerfect.target,
|
|
||||||
camera->lookatPixelPerfect.up,
|
|
||||||
view
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_2D:
|
|
||||||
glm_mat4_identity(view);
|
|
||||||
glm_translate(view, (vec3){
|
|
||||||
-camera->_2d.position[0],
|
|
||||||
-camera->_2d.position[1],
|
|
||||||
0.0f
|
|
||||||
});
|
|
||||||
glm_scale(view, (vec3){
|
|
||||||
camera->_2d.zoom,
|
|
||||||
camera->_2d.zoom,
|
|
||||||
1.0f
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Invalid camera view type");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
// mat4 pv;
|
|
||||||
// glm_mat4_mul(projection, camera->transform, pv);
|
|
||||||
|
|
||||||
glPushMatrix();
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glLoadMatrixf((const GLfloat*)projection);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
glLoadMatrixf((const GLfloat*)view);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraPopMatrix(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glPopMatrix();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
#define CAMERA_COUNT_MAX 4
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CAMERA_PROJECTION_TYPE_PERSPECTIVE,
|
|
||||||
CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
|
|
||||||
CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
|
|
||||||
} cameraprojectiontype_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CAMERA_VIEW_TYPE_MATRIX,
|
|
||||||
CAMERA_VIEW_TYPE_LOOKAT,
|
|
||||||
CAMERA_VIEW_TYPE_2D,
|
|
||||||
CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT
|
|
||||||
} cameraviewtype_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
cameraprojectiontype_t projType;
|
|
||||||
cameraviewtype_t viewType;
|
|
||||||
|
|
||||||
union {
|
|
||||||
mat4 view;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t position[3];
|
|
||||||
float_t target[3];
|
|
||||||
float_t up[3];
|
|
||||||
} lookat;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t offset[3];
|
|
||||||
float_t target[3];
|
|
||||||
float_t up[3];
|
|
||||||
float_t pixelsPerUnit;
|
|
||||||
} lookatPixelPerfect;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t position[2];
|
|
||||||
float_t zoom;
|
|
||||||
} _2d;
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
float_t fov;
|
|
||||||
} perspective;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t left;
|
|
||||||
float_t right;
|
|
||||||
float_t top;
|
|
||||||
float_t bottom;
|
|
||||||
} orthographic;
|
|
||||||
};
|
|
||||||
|
|
||||||
float_t nearClip;
|
|
||||||
float_t farClip;
|
|
||||||
} camera_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera to default values. This calls cameraInitPerspective.
|
|
||||||
*/
|
|
||||||
void cameraInit(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera for perspective projection.
|
|
||||||
*/
|
|
||||||
void cameraInitPerspective(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera for orthographic projection.
|
|
||||||
*/
|
|
||||||
void cameraInitOrthographic(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the camera's view matrix onto the matrix stack.
|
|
||||||
*
|
|
||||||
* @param id The ID of the camera entity to use.
|
|
||||||
*/
|
|
||||||
void cameraPushMatrix(camera_t* camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops the camera's view matrix off the matrix stack.
|
|
||||||
*/
|
|
||||||
void cameraPopMatrix(void);
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef float_t colorchannelf_t;
|
|
||||||
typedef uint8_t colorchannelb_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelf_t r;
|
|
||||||
colorchannelf_t g;
|
|
||||||
colorchannelf_t b;
|
|
||||||
} color3f_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelf_t r;
|
|
||||||
colorchannelf_t g;
|
|
||||||
colorchannelf_t b;
|
|
||||||
colorchannelf_t a;
|
|
||||||
} color4f_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelb_t r;
|
|
||||||
colorchannelb_t g;
|
|
||||||
colorchannelb_t b;
|
|
||||||
} color3b_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelb_t r;
|
|
||||||
colorchannelb_t g;
|
|
||||||
colorchannelb_t b;
|
|
||||||
colorchannelb_t a;
|
|
||||||
} color4b_t;
|
|
||||||
|
|
||||||
typedef color4b_t color_t;
|
|
||||||
|
|
||||||
#define color3f(r, g, b) ((color3f_t){r, g, b})
|
|
||||||
#define color4f(r, g, b, a) ((color4f_t){r, g, b, a})
|
|
||||||
#define color3b(r, g, b) ((color3b_t){r, g, b})
|
|
||||||
#define color4b(r, g, b, a) ((color4b_t){r, g, b, a})
|
|
||||||
#define color(r, g, b, a) ((color_t){r, g, b, a})
|
|
||||||
|
|
||||||
#define color_hex(hex) color( \
|
|
||||||
((hex >> 24) & 0xFF), \
|
|
||||||
((hex >> 16) & 0xFF), \
|
|
||||||
((hex >> 8) & 0xFF), \
|
|
||||||
(hex & 0xFF) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#define COLOR_WHITE_3F color3f(1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_WHITE_4F color4f(1.0f, 1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_WHITE_3B color3b(255, 255, 255)
|
|
||||||
#define COLOR_WHITE_4B color4b(255, 255, 255, 255)
|
|
||||||
#define COLOR_WHITE color(255, 255, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_BLACK_3F color3f(0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_BLACK_4F color4f(0.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_BLACK_3B color3b(0, 0, 0)
|
|
||||||
#define COLOR_BLACK_4B color4b(0, 0, 0, 255)
|
|
||||||
#define COLOR_BLACK color(0, 0, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_RED_3F color3f(1.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_RED_4F color4f(1.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_RED_3B color3b(255, 0, 0)
|
|
||||||
#define COLOR_RED_4B color4b(255, 0, 0, 255)
|
|
||||||
#define COLOR_RED color(255, 0, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_GREEN_3F color3f(0.0f, 1.0f, 0.0f)
|
|
||||||
#define COLOR_GREEN_4F color4f(0.0f, 1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_GREEN_3B color3b(0, 255, 0)
|
|
||||||
#define COLOR_GREEN_4B color4b(0, 255, 0, 255)
|
|
||||||
#define COLOR_GREEN color(0, 255, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_BLUE_3F color3f(0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_BLUE_4F color4f(0.0f, 0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_BLUE_3B color3b(0, 0, 255)
|
|
||||||
#define COLOR_BLUE_4B color4b(0, 0, 255, 255)
|
|
||||||
#define COLOR_BLUE color(0, 0, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_YELLOW_3F color3f(1.0f, 1.0f, 0.0f)
|
|
||||||
#define COLOR_YELLOW_4F color4f(1.0f, 1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_YELLOW_3B color3b(255, 255, 0)
|
|
||||||
#define COLOR_YELLOW_4B color4b(255, 255, 0, 255)
|
|
||||||
#define COLOR_YELLOW color(255, 255, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_CYAN_3F color3f(0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_CYAN_4F color4f(0.0f, 1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_CYAN_3B color3b(0, 255, 255)
|
|
||||||
#define COLOR_CYAN_4B color4b(0, 255, 255, 255)
|
|
||||||
#define COLOR_CYAN color(0, 255, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_MAGENTA_3F color3f(1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_MAGENTA_4F color4f(1.0f, 0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_MAGENTA_3B color3b(255, 0, 255)
|
|
||||||
#define COLOR_MAGENTA_4B color4b(255, 0, 255, 255)
|
|
||||||
#define COLOR_MAGENTA color(255, 0, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_TRANSPARENT_3F color3f(0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_TRANSPARENT_4F color4f(0.0f, 0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_TRANSPARENT_3B color3b(0, 0, 0)
|
|
||||||
#define COLOR_TRANSPARENT_4B color4b(0, 0, 0, 0)
|
|
||||||
#define COLOR_TRANSPARENT color(0, 0, 0, 0)
|
|
||||||
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_3F color3f(0.39f, 0.58f, 0.93f)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_4F color4f(0.39f, 0.58f, 0.93f, 1.0f)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_3B color3b(100, 149, 237)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_4B color4b(100, 149, 237, 255)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE color(100, 149, 237, 255)
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "engine/engine.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
#include "scene/scenemanager.h"
|
|
||||||
#include "display/spritebatch.h"
|
|
||||||
#include "display/mesh/quad.h"
|
|
||||||
#include "display/screen.h"
|
|
||||||
#include "ui/ui.h"
|
|
||||||
#include "debug/debug.h"
|
|
||||||
|
|
||||||
display_t DISPLAY;
|
|
||||||
|
|
||||||
errorret_t displayInit(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
uint32_t flags = SDL_INIT_VIDEO;
|
|
||||||
#if INPUT_GAMEPAD == 1
|
|
||||||
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
|
||||||
#endif
|
|
||||||
if(SDL_Init(flags) != 0) {
|
|
||||||
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set OpenGL attributes (Needs to be done now or later?)
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
||||||
|
|
||||||
// Create window with OpenGL flag.
|
|
||||||
DISPLAY.window = SDL_CreateWindow(
|
|
||||||
"Dusk",
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT,
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT,
|
|
||||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
|
|
||||||
SDL_WINDOW_OPENGL
|
|
||||||
);
|
|
||||||
if(!DISPLAY.window) {
|
|
||||||
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create OpenGL context
|
|
||||||
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
|
|
||||||
if(!DISPLAY.glContext) {
|
|
||||||
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
glDisable(GL_LIGHTING);// PSP defaults this on?
|
|
||||||
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
quadInit();
|
|
||||||
frameBufferInitBackbuffer();
|
|
||||||
spriteBatchInit();
|
|
||||||
screenInit();
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t displayUpdate(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_Event event;
|
|
||||||
while(SDL_PollEvent(&event)) {
|
|
||||||
switch(event.type) {
|
|
||||||
case SDL_QUIT: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT: {
|
|
||||||
switch(event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_CLOSE: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
spriteBatchClear();
|
|
||||||
frameBufferBind(NULL);
|
|
||||||
|
|
||||||
// Bind screen and render scene
|
|
||||||
screenBind();
|
|
||||||
frameBufferClear(
|
|
||||||
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
|
|
||||||
COLOR_CORNFLOWER_BLUE
|
|
||||||
);
|
|
||||||
sceneManagerRender();
|
|
||||||
uiRender();
|
|
||||||
|
|
||||||
// Finish up
|
|
||||||
spriteBatchFlush();
|
|
||||||
screenUnbind();
|
|
||||||
screenRender();
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_GL_SwapWindow(DISPLAY.window);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLenum err;
|
|
||||||
while((err = glGetError()) != GL_NO_ERROR) {
|
|
||||||
debugPrint("GL Error: %d\n", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t displayDispose(void) {
|
|
||||||
spriteBatchDispose();
|
|
||||||
screenDispose();
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(DISPLAY.glContext) {
|
|
||||||
SDL_GL_DeleteContext(DISPLAY.glContext);
|
|
||||||
DISPLAY.glContext = NULL;
|
|
||||||
}
|
|
||||||
if(DISPLAY.window) {
|
|
||||||
SDL_DestroyWindow(DISPLAY.window);
|
|
||||||
DISPLAY.window = NULL;
|
|
||||||
}
|
|
||||||
SDL_Quit();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "displaydefs.h"
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "display/camera.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_Window *window;
|
|
||||||
SDL_GLContext glContext;
|
|
||||||
#endif
|
|
||||||
} display_t;
|
|
||||||
|
|
||||||
extern display_t DISPLAY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the display system.
|
|
||||||
*/
|
|
||||||
errorret_t displayInit(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the display system to actually draw the frame.
|
|
||||||
*/
|
|
||||||
errorret_t displayUpdate(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of the display system.
|
|
||||||
*/
|
|
||||||
errorret_t displayDispose(void);
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#define GL_GLEXT_PROTOTYPES
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
#ifndef DISPLAY_SIZE_DYNAMIC
|
|
||||||
#define DISPLAY_SIZE_DYNAMIC 1
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#error "Need to specify display backend."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
#ifndef DISPLAY_WIDTH
|
|
||||||
#error "DISPLAY_WIDTH must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_HEIGHT
|
|
||||||
#error "DISPLAY_HEIGHT must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DISPLAY_WINDOW_WIDTH_DEFAULT
|
|
||||||
#error "DISPLAY_WINDOW_WIDTH_DEFAULT must be defined."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_WINDOW_HEIGHT_DEFAULT
|
|
||||||
#define DISPLAY_WINDOW_HEIGHT_DEFAULT DISPLAY_HEIGHT
|
|
||||||
#endif
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "framebuffer.h"
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
framebuffer_t FRAMEBUFFER_BACKBUFFER = {0};
|
|
||||||
const framebuffer_t *FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
|
|
||||||
void frameBufferInitBackbuffer() {
|
|
||||||
memoryZero(&FRAMEBUFFER_BACKBUFFER, sizeof(framebuffer_t));
|
|
||||||
|
|
||||||
FRAMEBUFFER_BACKBUFFER.id = -1;
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
) {
|
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(framebuffer, sizeof(framebuffer_t));
|
|
||||||
textureInit(&framebuffer->texture, width, height, GL_RGBA,(texturedata_t){
|
|
||||||
.rgba = { .colors = NULL }
|
|
||||||
});
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
|
|
||||||
glFramebufferTexture2DEXT(
|
|
||||||
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
||||||
GL_TEXTURE_2D, framebuffer->texture.id, 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if(
|
|
||||||
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
|
||||||
GL_FRAMEBUFFER_COMPLETE_EXT
|
|
||||||
) {
|
|
||||||
assertUnreachable("Framebuffer is not complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_WIDTH;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowWidth;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.width;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_HEIGHT;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowHeight;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.height;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferBind(const framebuffer_t *framebuffer) {
|
|
||||||
if(framebuffer == NULL) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the framebuffer for rendering
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if PSP
|
|
||||||
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#if PSP
|
|
||||||
assertUnreachable("Framebuffers not supported on PSP");
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
glViewport(
|
|
||||||
0, 0,
|
|
||||||
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FRAMEBUFFER_BOUND = framebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferClear(uint8_t flags, color_t color) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
GLbitfield glFlags = 0;
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_COLOR) {
|
|
||||||
glFlags |= GL_COLOR_BUFFER_BIT;
|
|
||||||
glClearColor(
|
|
||||||
color.r / 255.0f,
|
|
||||||
color.g / 255.0f,
|
|
||||||
color.b / 255.0f,
|
|
||||||
color.a / 255.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
|
|
||||||
glFlags |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
glClear(glFlags);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer) {
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
assertUnreachable("Cannot dispose of backbuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
assertUnreachable("Dynamic size framebuffers not supported");
|
|
||||||
#else
|
|
||||||
textureDispose(&framebuffer->texture);
|
|
||||||
glDeleteFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
#define FRAMEBUFFER_CLEAR_COLOR (1 << 0)
|
|
||||||
#define FRAMEBUFFER_CLEAR_DEPTH (1 << 1)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
// OpenGL Framebuffer Object ID
|
|
||||||
GLuint id;
|
|
||||||
texture_t texture;
|
|
||||||
#else
|
|
||||||
#error "Framebuffers not implemented on this platform."
|
|
||||||
#endif
|
|
||||||
} framebuffer_t;
|
|
||||||
|
|
||||||
extern framebuffer_t FRAMEBUFFER_BACKBUFFER;
|
|
||||||
extern const framebuffer_t *FRAMEBUFFER_BOUND;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the backbuffer framebuffer.
|
|
||||||
*/
|
|
||||||
void frameBufferInitBackbuffer(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to initialize.
|
|
||||||
* @param width The width of the framebuffer.
|
|
||||||
* @param height The height of the framebuffer.
|
|
||||||
*/
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the width of the framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to get the width of.
|
|
||||||
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
|
|
||||||
*/
|
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the height of the framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to get the height of.
|
|
||||||
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
|
|
||||||
*/
|
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
|
|
||||||
* provided is NULL.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to bind, or NULL to bind the backbuffer.
|
|
||||||
*/
|
|
||||||
void frameBufferBind(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the currently bound framebuffer.
|
|
||||||
*
|
|
||||||
* @param flags The clear flags.
|
|
||||||
* @param color The color to clear the color buffer to (if clearing color).
|
|
||||||
*/
|
|
||||||
void frameBufferClear(uint8_t flags, color_t color);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of the framebuffer using EXT methods.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to dispose of.
|
|
||||||
*/
|
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
// #if RENDER_USE_FRAMEBUFFER
|
|
||||||
// typedef struct {
|
|
||||||
// GLuint id;
|
|
||||||
// texture_t texture;
|
|
||||||
// } framebuffer_t;
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Initializes a framebuffer using EXT methods.
|
|
||||||
// *
|
|
||||||
// * @param framebuffer The framebuffer to initialize.
|
|
||||||
// * @param width The width of the framebuffer.
|
|
||||||
// * @param height The height of the framebuffer.
|
|
||||||
// * @return An error code indicating success or failure.
|
|
||||||
// */
|
|
||||||
// void frameBufferInit(
|
|
||||||
// framebuffer_t *framebuffer,
|
|
||||||
// const uint32_t width,
|
|
||||||
// const uint32_t height
|
|
||||||
// );
|
|
||||||
|
|
||||||
// #endif
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mesh.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
void meshInit(
|
|
||||||
mesh_t *mesh,
|
|
||||||
const meshprimitivetype_t primitiveType,
|
|
||||||
const int32_t vertexCount,
|
|
||||||
const meshvertex_t *vertices
|
|
||||||
) {
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
assertTrue(vertexCount > 0, "Vertex count must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(mesh, sizeof(mesh_t));
|
|
||||||
|
|
||||||
mesh->primitiveType = primitiveType;
|
|
||||||
mesh->vertexCount = vertexCount;
|
|
||||||
mesh->vertices = vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
void meshDraw(
|
|
||||||
const mesh_t *mesh,
|
|
||||||
const int32_t vertexOffset,
|
|
||||||
const int32_t vertexCount
|
|
||||||
) {
|
|
||||||
const int32_t offset = vertexOffset == -1 ? 0 : vertexOffset;
|
|
||||||
const int32_t count = vertexCount == -1 ? mesh->vertexCount : vertexCount;
|
|
||||||
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
assertTrue(offset >= 0, "Vertex offset must be non-negative");
|
|
||||||
assertTrue(count >= 0, "Vertex count must be non-negative");
|
|
||||||
assertTrue(offset + count <= mesh->vertexCount,
|
|
||||||
"Vertex offset + count must not exceed vertex count"
|
|
||||||
);
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
// PSP style pointer legacy OpenGL
|
|
||||||
const GLsizei stride = sizeof(meshvertex_t);
|
|
||||||
|
|
||||||
glColorPointer(
|
|
||||||
sizeof(color4b_t),
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].color
|
|
||||||
);
|
|
||||||
glTexCoordPointer(
|
|
||||||
MESH_VERTEX_UV_SIZE,
|
|
||||||
GL_FLOAT,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].uv[0]
|
|
||||||
);
|
|
||||||
glVertexPointer(
|
|
||||||
MESH_VERTEX_POS_SIZE,
|
|
||||||
GL_FLOAT,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].pos[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
glDrawArrays(
|
|
||||||
mesh->primitiveType,
|
|
||||||
0,
|
|
||||||
count
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void meshDispose(mesh_t *mesh) {
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
memoryZero(mesh, sizeof(mesh_t));
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// Copyright (c) 2025 Dominic Masters
|
|
||||||
//
|
|
||||||
// This software is released under the MIT License.
|
|
||||||
// https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
MESH_PRIMITIVE_TRIANGLES = GL_TRIANGLES,
|
|
||||||
MESH_PRIMITIVE_LINES = GL_LINES,
|
|
||||||
MESH_PRIMITIVE_POINTS = GL_POINTS,
|
|
||||||
#endif
|
|
||||||
} meshprimitivetype_t;
|
|
||||||
|
|
||||||
#define MESH_VERTEX_UV_SIZE 2
|
|
||||||
#define MESH_VERTEX_POS_SIZE 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
color4b_t color;
|
|
||||||
GLfloat uv[MESH_VERTEX_UV_SIZE];
|
|
||||||
GLfloat pos[MESH_VERTEX_POS_SIZE];
|
|
||||||
#endif
|
|
||||||
} meshvertex_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const meshvertex_t *vertices;
|
|
||||||
int32_t vertexCount;
|
|
||||||
meshprimitivetype_t primitiveType;
|
|
||||||
} mesh_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to initialize.
|
|
||||||
* @param primitiveType The OpenGL primitive type (e.g., GL_TRIANGLES).
|
|
||||||
* @param vertexCount The number of vertices in the mesh.
|
|
||||||
* @param vertices The vertex data for the mesh.
|
|
||||||
*/
|
|
||||||
void meshInit(
|
|
||||||
mesh_t *mesh,
|
|
||||||
const meshprimitivetype_t primitiveType,
|
|
||||||
const int32_t vertexCount,
|
|
||||||
const meshvertex_t *vertices
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to draw.
|
|
||||||
* @param vertexOffset The offset in the vertex array to start drawing from.
|
|
||||||
* @param vertexCount The number of vertices to draw. If -1, draws all vertices.
|
|
||||||
*/
|
|
||||||
void meshDraw(
|
|
||||||
const mesh_t *mesh,
|
|
||||||
const int32_t vertexOffset,
|
|
||||||
const int32_t vertexCount
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to dispose.
|
|
||||||
*/
|
|
||||||
void meshDispose(mesh_t *mesh);
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "quad.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
mesh_t QUAD_MESH_SIMPLE;
|
|
||||||
meshvertex_t QUAD_MESH_SIMPLE_VERTICES[QUAD_VERTEX_COUNT] = {
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
|
||||||
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f } }
|
|
||||||
};
|
|
||||||
|
|
||||||
void quadInit() {
|
|
||||||
meshInit(
|
|
||||||
&QUAD_MESH_SIMPLE,
|
|
||||||
QUAD_PRIMITIVE_TYPE,
|
|
||||||
QUAD_VERTEX_COUNT,
|
|
||||||
QUAD_MESH_SIMPLE_VERTICES
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void quadBuffer(
|
|
||||||
meshvertex_t *vertices,
|
|
||||||
const float_t minX,
|
|
||||||
const float_t minY,
|
|
||||||
const float_t maxX,
|
|
||||||
const float_t maxY,
|
|
||||||
const color_t color,
|
|
||||||
const float_t u0,
|
|
||||||
const float_t v0,
|
|
||||||
const float_t u1,
|
|
||||||
const float_t v1
|
|
||||||
) {
|
|
||||||
const float_t z = 0.0f; // Z coordinate for 2D rendering
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
|
|
||||||
// First triangle
|
|
||||||
vertices[0] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v0 }, // UV
|
|
||||||
{ minX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[1] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v0 }, // UV
|
|
||||||
{ maxX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[2] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v1 }, // UV
|
|
||||||
{ maxX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
|
|
||||||
// Second triangle
|
|
||||||
vertices[3] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v0 }, // UV
|
|
||||||
{ minX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[4] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v1 }, // UV
|
|
||||||
{ maxX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[5] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v1 }, // UV
|
|
||||||
{ minX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void quadBuffer3D(
|
|
||||||
meshvertex_t *vertices,
|
|
||||||
const vec3 min,
|
|
||||||
const vec3 max,
|
|
||||||
const color_t color,
|
|
||||||
const vec2 uvMin,
|
|
||||||
const vec2 uvMax
|
|
||||||
) {
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
assertNotNull(min, "Min vector cannot be NULL");
|
|
||||||
assertNotNull(max, "Max vector cannot be NULL");
|
|
||||||
assertNotNull(uvMin, "UV Min vector cannot be NULL");
|
|
||||||
assertNotNull(uvMax, "UV Max vector cannot be NULL");
|
|
||||||
|
|
||||||
// First triangle
|
|
||||||
vertices[0] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMin[1] }, // UV
|
|
||||||
{ min[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[1] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMin[1] }, // UV
|
|
||||||
{ max[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[2] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMax[1] }, // UV
|
|
||||||
{ max[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
|
|
||||||
// Second triangle
|
|
||||||
vertices[3] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMin[1] }, // UV
|
|
||||||
{ min[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[4] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMax[1] }, // UV
|
|
||||||
{ max[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[5] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMax[1] }, // UV
|
|
||||||
{ min[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t colorCount;
|
|
||||||
const color_t *colors;
|
|
||||||
} palette_t;
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
#include "display/camera.h"
|
|
||||||
#include "display/mesh/quad.h"
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
#ifndef DISPLAY_SCREEN_HEIGHT_DEFAULT
|
|
||||||
#error "DISPLAY_SCREEN_HEIGHT_DEFAULT must be defined when DISPLAY_SIZE_DYNAMIC is enabled."
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCREEN_MODE_BACKBUFFER,
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
SCREEN_MODE_FIXED_SIZE,
|
|
||||||
SCREEN_MODE_ASPECT_RATIO,// Maintains aspect at all cost
|
|
||||||
SCREEN_MODE_FIXED_HEIGHT, // Fixed height, width expands/contracts as needed
|
|
||||||
SCREEN_MODE_FIXED_WIDTH, // Fixed width, height expands/contracts as needed
|
|
||||||
#endif
|
|
||||||
} screenmode_t;
|
|
||||||
|
|
||||||
// typedef enum {
|
|
||||||
// SCREEN_SCALE_MODE_FILL,
|
|
||||||
// SCREEN_SCALE_MODE_INTEGER,
|
|
||||||
// SCREEN_SCALE_MODE_INEGER_OVERFLOW
|
|
||||||
// } screenscalemode_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
screenmode_t mode;
|
|
||||||
// screenscalemode_t scaleMode;
|
|
||||||
|
|
||||||
// Calculated dimensions of the viewport, to be used by the camera
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
float_t aspect;
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
framebuffer_t framebuffer;
|
|
||||||
bool_t framebufferReady;
|
|
||||||
camera_t framebufferCamera;
|
|
||||||
mesh_t frameBufferMesh;
|
|
||||||
meshvertex_t frameBufferMeshVertices[QUAD_VERTEX_COUNT];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
} fixedSize;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t ratio;
|
|
||||||
} aspectRatio;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t height;
|
|
||||||
} fixedHeight;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t width;
|
|
||||||
} fixedWidth;
|
|
||||||
};
|
|
||||||
} screen_t;
|
|
||||||
|
|
||||||
extern screen_t SCREEN;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the screen system.
|
|
||||||
*/
|
|
||||||
void screenInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the screen, this is done before rendering game content.
|
|
||||||
*/
|
|
||||||
void screenBind();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbinds the screen, does nothing for now.
|
|
||||||
*/
|
|
||||||
void screenUnbind();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the screen to the current framebuffer.
|
|
||||||
*/
|
|
||||||
void screenRender();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes the screen system.
|
|
||||||
*/
|
|
||||||
void screenDispose();
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "spritebatch.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
spritebatch_t SPRITEBATCH;
|
|
||||||
|
|
||||||
void spriteBatchInit() {
|
|
||||||
SPRITEBATCH.spriteCount = 0;
|
|
||||||
SPRITEBATCH.currentTexture = NULL;
|
|
||||||
|
|
||||||
meshInit(
|
|
||||||
&SPRITEBATCH.mesh,
|
|
||||||
MESH_PRIMITIVE_TRIANGLES,
|
|
||||||
SPRITEBATCH_VERTEX_COUNT,
|
|
||||||
&SPRITEBATCH.vertices[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchPush(
|
|
||||||
texture_t *texture,
|
|
||||||
const float_t minX,
|
|
||||||
const float_t minY,
|
|
||||||
const float_t maxX,
|
|
||||||
const float_t maxY,
|
|
||||||
const color_t color,
|
|
||||||
const float_t u0,
|
|
||||||
const float_t v0,
|
|
||||||
const float_t u1,
|
|
||||||
const float_t v1
|
|
||||||
) {
|
|
||||||
// Need to flush?
|
|
||||||
if(
|
|
||||||
SPRITEBATCH.currentTexture != texture ||
|
|
||||||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
|
|
||||||
) {
|
|
||||||
spriteBatchFlush();
|
|
||||||
SPRITEBATCH.currentTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
quadBuffer(
|
|
||||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
|
||||||
minX, minY, maxX, maxY,
|
|
||||||
color,
|
|
||||||
u0, v0, u1, v1
|
|
||||||
);
|
|
||||||
|
|
||||||
SPRITEBATCH.spriteCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchPush3D(
|
|
||||||
texture_t *texture,
|
|
||||||
const vec3 min,
|
|
||||||
const vec3 max,
|
|
||||||
const color_t color,
|
|
||||||
const vec2 uv0,
|
|
||||||
const vec2 uv1
|
|
||||||
) {
|
|
||||||
// Need to flush?
|
|
||||||
if(
|
|
||||||
SPRITEBATCH.currentTexture != texture ||
|
|
||||||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
|
|
||||||
) {
|
|
||||||
spriteBatchFlush();
|
|
||||||
SPRITEBATCH.currentTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
quadBuffer3D(
|
|
||||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
|
||||||
min, max, color, uv0, uv1
|
|
||||||
);
|
|
||||||
|
|
||||||
SPRITEBATCH.spriteCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchClear() {
|
|
||||||
SPRITEBATCH.spriteCount = 0;
|
|
||||||
SPRITEBATCH.currentTexture = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchFlush() {
|
|
||||||
if(SPRITEBATCH.spriteCount == 0) return;
|
|
||||||
textureBind(SPRITEBATCH.currentTexture);
|
|
||||||
meshDraw(&SPRITEBATCH.mesh, 0, QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount);
|
|
||||||
spriteBatchClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchDispose() {
|
|
||||||
meshDispose(&SPRITEBATCH.mesh);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user