mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-24 16:22:41 +02:00
Compare commits
1095
Commits
master
...
port-debugger
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc9b4d1a39 | ||
|
|
f96a03e60f | ||
|
|
9d2db1a346 | ||
|
|
fc7141d0f2 | ||
|
|
f414e8a792 | ||
|
|
ab73fdcc30 | ||
|
|
30071e8f64 | ||
|
|
9695856be6 | ||
|
|
053f7dc8a5 | ||
|
|
1555a4be84 | ||
|
|
d4856a193b | ||
|
|
cb6dc1feab | ||
|
|
b93015c51c | ||
|
|
6198fbc479 | ||
|
|
0316317aa3 | ||
|
|
f9cfa0fa43 | ||
|
|
7a98095a0b | ||
|
|
8f477a36b6 | ||
|
|
4d4fa8f681 | ||
|
|
0ac5fdd5c3 | ||
|
|
33c5194a1b | ||
|
|
edd58c8925 | ||
|
|
e32d719c16 | ||
|
|
be4d8330bd | ||
|
|
91c207a51b | ||
|
|
0d76ad102f | ||
|
|
135c293656 | ||
|
|
a1d6916871 | ||
|
|
9a853077a0 | ||
|
|
dace9fd634 | ||
|
|
9e19055348 | ||
|
|
dcef8deed8 | ||
|
|
c44704e2af | ||
|
|
1a5e42e55f | ||
|
|
a26260e932 | ||
|
|
3d75365f2b | ||
|
|
ad9ed9ff3b | ||
|
|
4f55a41d99 | ||
|
|
355f0ed0ee | ||
|
|
f5d851f7c2 | ||
|
|
4019bd59cf | ||
|
|
6c29e7ecc8 | ||
|
|
e65f46d081 | ||
|
|
9633e7eac6 | ||
|
|
2ff8819265 | ||
|
|
77d1ded519 | ||
|
|
60b8e3b49e | ||
|
|
8b0b75d4ad | ||
|
|
ea464ca6ac | ||
|
|
a9752198c3 | ||
|
|
fbd9ef002e | ||
|
|
e4972ddbe3 | ||
|
|
8dbe6f2a63 | ||
|
|
045c4c371a | ||
|
|
f4f1470e1e | ||
|
|
26251c0865 | ||
|
|
ac4f317879 | ||
|
|
e3104b7043 | ||
|
|
176b4282fc | ||
|
|
cd8f06d03a | ||
|
|
9cff3591dd | ||
|
|
daade36e19 | ||
|
|
addc890628 | ||
|
|
8a3dd74d5c | ||
|
|
c0aa42759c | ||
|
|
b637c6aac6 | ||
|
|
5cd436e848 | ||
|
|
d5225b7784 | ||
|
|
904faa5485 | ||
|
|
42a151a84d | ||
|
|
f1084b6d93 | ||
|
|
9a462d3ca8 | ||
|
|
7cfead440b | ||
|
|
4f7817a0ca | ||
|
|
5084b4be39 | ||
|
|
a05c4290f5 | ||
|
|
85af83859e | ||
|
|
49cd478622 | ||
|
|
0443c708dd | ||
|
|
7f105f1dcb | ||
|
|
721b9b004e | ||
|
|
23d5a5771a | ||
|
|
0701f43d6b | ||
|
|
d5ae464f6d | ||
|
|
701c854ced | ||
|
|
afd432444b | ||
|
|
26b3b91433 | ||
|
|
8945809c1f | ||
|
|
da07772b1c | ||
|
|
1e76f6af69 | ||
|
|
a14e9ed97e | ||
|
|
615e9267d8 | ||
|
|
4f2b911802 | ||
|
|
c43f550a7e | ||
|
|
2439eb6e8d | ||
|
|
903dd82ebf | ||
|
|
cb449bf7ce | ||
|
|
e2e5bc352d | ||
|
|
687b966c5e | ||
|
|
0b8a333e2b | ||
|
|
b34bb01240 | ||
|
|
1e2f6dcb91 | ||
|
|
210b299bd4 | ||
|
|
6de98cfcd4 | ||
|
|
d43c4c0cba | ||
|
|
1d14877bec | ||
|
|
5aa1cc6117 | ||
|
|
1be0e3680b | ||
|
|
09b0a12b0a | ||
|
|
05e462b680 | ||
|
|
a2e362caea | ||
|
|
49ee5b7efb | ||
|
|
a1ca69d9ee | ||
|
|
424d4de9ac | ||
|
|
0e1a7e136a | ||
|
|
2386494030 | ||
|
|
1b803d792f | ||
|
|
67675d8980 | ||
|
|
9c4aded403 | ||
|
|
92e1c4aa0b | ||
|
|
f53fb8e952 | ||
|
|
0ad4492ff6 | ||
|
|
33efd36278 | ||
|
|
37e69cb83d | ||
|
|
5c5c33c116 | ||
|
|
13a3e0a0ea | ||
|
|
ccb50c6021 | ||
|
|
cee61eeb75 | ||
|
|
563e8f9f64 | ||
|
|
df3e0359b9 | ||
|
|
460cc25ef5 | ||
|
|
596dd7dd40 | ||
|
|
4883fde642 | ||
|
|
b2338179d6 | ||
|
|
683d083fab | ||
|
|
f75a569075 | ||
|
|
b97eaa9e12 | ||
|
|
3cadaecf96 | ||
|
|
4bc1a16d36 | ||
|
|
bc1f1c26db | ||
|
|
d2d35263a4 | ||
|
|
ba1b6c3232 | ||
|
|
3c020cad84 | ||
|
|
fc865fe8cd | ||
|
|
140f6f24e8 | ||
|
|
c7895d937f | ||
|
|
9f43c906db | ||
|
|
31dbb5e7c6 | ||
|
|
7d8e755fc7 | ||
|
|
103fb0e0e9 | ||
|
|
b220d73f2c | ||
|
|
efda5a5f44 | ||
|
|
41d5630eec | ||
|
|
cea20b6f31 | ||
|
|
c45763d47c | ||
|
|
06dcbcc1b1 | ||
|
|
d7a612302e | ||
|
|
9812d86a24 | ||
|
|
d747588323 | ||
|
|
ed5865b350 | ||
|
|
363158a93d | ||
|
|
7658a96c1c | ||
|
|
c332738f7a | ||
|
|
2542b21bfc | ||
|
|
ef8413ae58 | ||
|
|
7969d84257 | ||
|
|
2e9de9455b | ||
|
|
3d8f63dbb6 | ||
|
|
08ec8e541b | ||
|
|
08afb2d90a | ||
|
|
d7e5ad5bc7 | ||
|
|
7830ccb88c | ||
|
|
8075307e09 | ||
|
|
fb18da239f | ||
|
|
bc82328353 | ||
|
|
938223db28 | ||
|
|
942c966bf2 | ||
|
|
e0d59345c7 | ||
|
|
f514e25208 | ||
|
|
28fceb67de | ||
|
|
130b286d0d | ||
|
|
b88c3a120b | ||
|
|
a6f5077609 | ||
|
|
e2b708d442 | ||
|
|
2cb29e91c6 | ||
|
|
55cc2d8e72 | ||
|
|
3852b28194 | ||
|
|
852349bbe0 | ||
|
|
b408d54dfb | ||
|
|
0e7fb4f6b2 | ||
|
|
5d9fe034ea | ||
|
|
4a7df4de4b | ||
|
|
1d7c381ce2 | ||
|
|
8d6a19f55b | ||
|
|
6c8e5ee4dc | ||
|
|
d37d9b7168 | ||
|
|
fab41b6fcb | ||
|
|
ee7ce2d988 | ||
|
|
1a1accceca | ||
|
|
0bdf79cc51 | ||
|
|
507cc5a13b | ||
|
|
91c43385dd | ||
|
|
58e64ebfc9 | ||
|
|
36f9e59304 | ||
|
|
420a1b52c1 | ||
|
|
345da23ebe | ||
|
|
3f887b2ecf | ||
|
|
d5482f3453 | ||
|
|
fdbd1667ad | ||
|
|
421ac0af79 | ||
|
|
163dbf9495 | ||
|
|
2f221b9a1e | ||
|
|
1448cd597a | ||
|
|
68e3a79e47 | ||
|
|
19ef4738b7 | ||
|
|
16f025cbbe | ||
|
|
25cdfc991b | ||
|
|
5c2082f58e | ||
|
|
23539a02a5 | ||
|
|
f37abc941e | ||
|
|
8468e69b9f | ||
|
|
8fe95d7d52 | ||
|
|
19167b8468 | ||
|
|
d5ee41fe5d | ||
|
|
87e8a3f1af | ||
|
|
2a5c3a351e | ||
|
|
2550b5a668 | ||
|
|
24d5679f4a | ||
|
|
a3d2b56dd9 | ||
|
|
18ad06e3d7 | ||
|
|
34d3e082ec | ||
|
|
a277ca7ee4 | ||
|
|
af8e808e39 | ||
|
|
8f445d344f | ||
|
|
e9b946feb4 | ||
|
|
2d51c0a60a | ||
|
|
cf13976db3 | ||
|
|
6344cc8914 | ||
|
|
b2657eb0c2 | ||
|
|
35d263e15b | ||
|
|
c224055ff7 | ||
|
|
096a833838 | ||
|
|
ee8d7a6e89 | ||
|
|
538385a991 | ||
|
|
b8348a45bc | ||
|
|
a6b516be15 | ||
|
|
9ac8af6639 | ||
|
|
28bdccd322 | ||
|
|
8865130c35 | ||
|
|
153ca3341e | ||
|
|
8533189561 | ||
|
|
eabbdc612c | ||
|
|
5841fb9afa | ||
|
|
077cc67b79 | ||
|
|
589bdf1cd9 | ||
|
|
3524ec73b7 | ||
|
|
ab514f39af | ||
|
|
8be982fdb6 | ||
|
|
ae2543de90 | ||
|
|
6a5d249e67 | ||
|
|
4b44b5b4e3 | ||
|
|
2fd1c49ef5 | ||
|
|
22ad5a44db | ||
|
|
e77b3172ed | ||
|
|
a721349cff | ||
|
|
40cc42a941 | ||
|
|
cec92dbcb6 | ||
|
|
2c4d3e7768 | ||
|
|
e09aebebe7 | ||
|
|
a5d9f02184 | ||
|
|
d2dd109a05 | ||
|
|
01cbcd99cb | ||
|
|
a9e82658fd | ||
|
|
5bee1b0cce | ||
|
|
a11abc0511 | ||
|
|
c36b6b286d | ||
|
|
18fe7fd797 | ||
|
|
d6d4bc2c14 | ||
|
|
c519997b33 | ||
|
|
4d60c93beb | ||
|
|
b44dbb16b5 | ||
|
|
8b1e81f32a | ||
|
|
9e34f80a2c | ||
|
|
c1c71ea21d | ||
|
|
c8383babcc | ||
|
|
bdbf0ab789 | ||
|
|
ca76416e1c | ||
|
|
b534a42685 | ||
|
|
6b71e622c7 | ||
|
|
48c294fc24 | ||
|
|
f0fe7f41f1 | ||
|
|
2844930a21 | ||
|
|
d36c55d048 | ||
|
|
f855dc32f1 | ||
|
|
08e2b49e88 | ||
|
|
9cd978a7a9 | ||
|
|
a60880ef80 | ||
|
|
a4b5b110ec | ||
|
|
b9eb0f2747 | ||
|
|
897020b3fd | ||
|
|
e85fdb3b9b | ||
|
|
e3e72617a1 | ||
|
|
bc365650ce | ||
|
|
6fa78556f4 | ||
|
|
5fdeff6a82 | ||
|
|
3573906eef | ||
|
|
e36df05a4f | ||
|
|
673ba52cbd | ||
|
|
0ea8872471 | ||
|
|
40273bdba1 | ||
|
|
e8006f3446 | ||
|
|
373f08ca3e | ||
|
|
844d6c7ec8 | ||
|
|
8d5e94e121 | ||
|
|
b43c2ec617 | ||
|
|
a8c68aed97 | ||
|
|
4c09de6de0 | ||
|
|
29d6392514 | ||
|
|
b9f6961931 | ||
|
|
949faf09d9 | ||
|
|
5beef0916b | ||
|
|
89397bd566 | ||
|
|
288a007202 | ||
|
|
50b912db98 | ||
|
|
71dc521baa | ||
|
|
06a45738cc | ||
|
|
5795634b9c | ||
|
|
cec197e841 | ||
|
|
58c31075b0 | ||
|
|
167a4a5d81 | ||
|
|
06c01208d3 | ||
|
|
86649345cd | ||
|
|
2e2dbfb578 | ||
|
|
10a3992a62 | ||
|
|
ef4b60d384 | ||
|
|
32faea2b95 | ||
|
|
8a94af6a1c | ||
|
|
315a5642da | ||
|
|
00c990eded | ||
|
|
b6b7133e76 | ||
|
|
b0e6e8f24f | ||
|
|
4dbbcbeb58 | ||
|
|
8c8109e8cd | ||
|
|
b523b1e076 | ||
|
|
07e6fdc1e0 | ||
|
|
3242105ef8 | ||
|
|
7c6508af28 | ||
|
|
55ab679a81 | ||
|
|
946a3166b3 | ||
|
|
de3b8ff548 | ||
|
|
e6eaca9e3d | ||
|
|
dce96a4a3d | ||
|
|
fbb6669e23 | ||
|
|
08b4d780b7 | ||
|
|
bc5911bfba | ||
|
|
cf19cebc27 | ||
|
|
ada20c526a | ||
|
|
4c552a42f2 | ||
|
|
4c0cbbf554 | ||
|
|
e8e513fecb | ||
|
|
9d44606a4c | ||
|
|
4601a9c318 | ||
|
|
e326c14760 | ||
|
|
5c7d4ecf52 | ||
|
|
e13e03fd7f | ||
|
|
9edfd667b7 | ||
|
|
f3757e75e9 | ||
|
|
04a6f64a95 | ||
|
|
a6e7d503e6 | ||
|
|
da8b9be09d | ||
|
|
39e2f7730d | ||
|
|
9530924c21 | ||
|
|
083cae49c6 | ||
|
|
2ba192d411 | ||
|
|
6e8190062c | ||
|
|
bf8192ee84 | ||
|
|
9ee2391a69 | ||
|
|
45ec35172d | ||
|
|
926e4dce28 | ||
|
|
7f886a817c | ||
|
|
548e2c1f0b | ||
|
|
85872d7e71 | ||
|
|
d9037ba1da | ||
|
|
a83e0aa407 | ||
|
|
8d8650ebd0 | ||
|
|
865ca682dc | ||
|
|
dc9d0f3c9c | ||
|
|
12d06001e7 | ||
|
|
75331721f7 | ||
|
|
32c5d2c742 | ||
|
|
3199f99fbd | ||
|
|
2623918359 | ||
|
|
51d842f516 | ||
|
|
4e7e61c207 | ||
|
|
265d21c35d | ||
|
|
70b02da163 | ||
|
|
1a3f36f626 | ||
|
|
5fea484089 | ||
|
|
d8a26fa221 | ||
|
|
28d6c5b827 | ||
|
|
322892e254 | ||
|
|
fef8985b6b | ||
|
|
fd8718f7b1 | ||
|
|
4e0025a847 | ||
|
|
197208b951 | ||
|
|
38ff8ca5df | ||
|
|
4bd314f60b | ||
|
|
9270b6647a | ||
|
|
95b43b3f7b | ||
|
|
e5effc4522 | ||
|
|
62a55a3d6e | ||
|
|
12cf9df01b | ||
|
|
22e49d75e1 | ||
|
|
c5c1ef1d4e | ||
|
|
f3c1242858 | ||
|
|
f8617ebbd6 | ||
|
|
ef3d53b9f7 | ||
|
|
bf1b8da629 | ||
|
|
1d040b1ccc | ||
|
|
9755f3ab41 | ||
|
|
f86746364f | ||
|
|
536c766793 | ||
|
|
dca1e1752b | ||
|
|
86eaa624a3 | ||
|
|
ce6424117e | ||
|
|
c2fcb992ca | ||
|
|
54ba0d41c1 | ||
|
|
15c0327592 | ||
|
|
13003121ea | ||
|
|
ba56947457 | ||
|
|
2c0abcb0e2 | ||
|
|
5554fb7219 | ||
|
|
27faaecda2 | ||
|
|
798fbf7b90 | ||
|
|
a0f8550034 | ||
|
|
73dc52cfd6 | ||
|
|
5b1d03cbbb | ||
|
|
68aee1d2f2 | ||
|
|
7580ebcaf9 | ||
|
|
c9a14f090b | ||
|
|
2483d4fc35 | ||
|
|
501ab95b00 | ||
|
|
0b61ec9641 | ||
|
|
b4f7f467c0 | ||
|
|
894ccfabf3 | ||
|
|
ec8310e4a1 | ||
|
|
80faefbaf6 | ||
|
|
804674e2b1 | ||
|
|
c9f880e427 | ||
|
|
20534a731b | ||
|
|
92a9ac43fc | ||
|
|
242a89a622 | ||
|
|
4baae8de0b | ||
|
|
d11b5705a2 | ||
|
|
04e2ed51a6 | ||
|
|
839143550f | ||
|
|
11fd86002b | ||
|
|
fe0d9b3cfd | ||
|
|
935cd1faa9 | ||
|
|
36f8494ebf | ||
|
|
fcb1dbb298 | ||
|
|
815c75c6a8 | ||
|
|
33cc89e8fd | ||
|
|
cc6df47eed | ||
|
|
02d7efb87f | ||
|
|
1f4d9c8cdc | ||
|
|
63c456a233 | ||
|
|
474a6df3d4 | ||
|
|
9cde121b52 | ||
|
|
e53f26f3eb | ||
|
|
81313f0c4e | ||
|
|
cf5588478b | ||
|
|
d9cb850848 | ||
|
|
b9db86f89b | ||
|
|
6bd3597ff6 | ||
|
|
8645d0a82a | ||
|
|
ba52580e0c | ||
|
|
d1d288b96a | ||
|
|
06f2283180 | ||
|
|
b1b17e21c1 | ||
|
|
c487e423b1 | ||
|
|
49f607dd79 | ||
|
|
787758c038 | ||
|
|
3c62a967a2 | ||
|
|
2ef2427419 | ||
|
|
5fcf1083d2 | ||
|
|
f2a2458795 | ||
|
|
a7ab358b43 | ||
|
|
a82ac025da | ||
|
|
461bf8d49b | ||
|
|
db1d00a9b0 | ||
|
|
92c66c93dc | ||
|
|
94df3fc58c | ||
|
|
f2545b4e53 | ||
|
|
0221839699 | ||
|
|
1698f53728 | ||
|
|
7ac734fc81 | ||
|
|
28218b26c2 | ||
|
|
4233e5e066 | ||
|
|
cdd7d6edac | ||
|
|
581c63fc27 | ||
|
|
dee7ab7b54 | ||
|
|
8c509db888 | ||
|
|
5aa799718a | ||
|
|
880a7a0971 | ||
|
|
e84d83e404 | ||
|
|
79fb976bcf | ||
|
|
519bd95a75 | ||
|
|
8421140e3f | ||
|
|
894ea53b29 | ||
|
|
fb05725c34 | ||
|
|
2a6625278a | ||
|
|
342e186f79 | ||
|
|
cabd40f898 | ||
|
|
0a7faf2409 | ||
|
|
03324c0823 | ||
|
|
aeb6851606 | ||
|
|
26da2aa5e6 | ||
|
|
7647062619 | ||
|
|
3a313287bb | ||
|
|
42af4d4604 | ||
|
|
3118d01921 | ||
|
|
f46359b307 | ||
|
|
00297f6d0d | ||
|
|
39d5b57ccb | ||
|
|
75c4905e9b | ||
|
|
d1be171939 | ||
|
|
6f206345a1 | ||
|
|
13b23de6d3 | ||
|
|
d897356029 | ||
|
|
f96e7da00f | ||
|
|
1fb16b3bfd | ||
|
|
336b7825c7 | ||
|
|
2c20a0487e | ||
|
|
aef2463361 | ||
|
|
2b8d5d4f75 | ||
|
|
ef83f23200 | ||
|
|
75133acbbd | ||
|
|
1aea68b89a | ||
|
|
af34015562 | ||
|
|
7cd3dafaa4 | ||
|
|
63046b4a00 | ||
|
|
e0249067b9 | ||
|
|
31ad9351f5 | ||
|
|
116dc7e8b6 | ||
|
|
aced07f356 | ||
|
|
8d99ac92a0 | ||
|
|
4a3c3a29b7 | ||
|
|
523e6ba9d9 | ||
|
|
c6a36633f5 | ||
|
|
626b5937ce | ||
|
|
228851f867 | ||
|
|
1c72b3022e | ||
|
|
5affafacbd | ||
|
|
8ca7f79c1e | ||
|
|
5d7b7adb57 | ||
|
|
2d3e3d1aaf | ||
|
|
94e8e1b5e7 | ||
|
|
d3a2ed216a | ||
|
|
600dae58e2 | ||
|
|
3a1d08509b | ||
|
|
f72b2968f2 | ||
|
|
5c152c1842 | ||
|
|
0cf6021727 | ||
|
|
45a44cd37e | ||
|
|
5a68daf18c | ||
|
|
e43d29f357 | ||
|
|
3328e147eb | ||
|
|
7e929c2432 | ||
|
|
b88690e8df | ||
|
|
305e64a263 | ||
|
|
b618c99abd | ||
|
|
58d815f1ec | ||
|
|
99da0586ea | ||
|
|
27e36ca24e | ||
|
|
9dfd0ec905 | ||
|
|
aa6ac4b5cc | ||
|
|
6f55843f30 | ||
|
|
4a16f27abd | ||
|
|
11e318b70f | ||
|
|
5bb4f1d193 | ||
|
|
f394f209b2 | ||
|
|
9c7f348652 | ||
|
|
32b2e9c28e | ||
|
|
72e9e2af95 | ||
|
|
8a348ab1b5 | ||
|
|
28b172f5c7 | ||
|
|
ef511d5889 | ||
|
|
df2ba8ec7d | ||
|
|
83a155fa49 | ||
|
|
eecee9d940 | ||
|
|
cd19c07810 | ||
|
|
f1edc91fd8 | ||
|
|
5df6d2fdfb | ||
|
|
83c5b4980b | ||
|
|
0e043f24b5 | ||
|
|
828776e272 | ||
|
|
407d4724a7 | ||
|
|
d75adeb0c8 | ||
|
|
dc6e6a507c | ||
|
|
fbae610a3b | ||
|
|
479c0335f3 | ||
|
|
d021e95d70 | ||
|
|
3ac194f9ee | ||
|
|
fea0a1e4ca | ||
|
|
a802d2db06 | ||
|
|
4a0296d1a4 | ||
|
|
c040c17b49 | ||
|
|
4eaaae91a6 | ||
|
|
83d22c3b70 | ||
|
|
4914aa335b | ||
|
|
afb91ab9e9 | ||
|
|
ed65f7971a | ||
|
|
3feddd8c64 | ||
|
|
9b65199d3d | ||
|
|
50b74e4280 | ||
|
|
c8db5fa106 | ||
|
|
cea9527936 | ||
|
|
2813ecedeb | ||
|
|
015817f204 | ||
|
|
da7e1493a5 | ||
|
|
368021201b | ||
|
|
30b8400d86 | ||
|
|
77fcac4912 | ||
|
|
790d44afb0 | ||
|
|
0ea3bea096 | ||
|
|
05c108a950 | ||
|
|
6957c1540d | ||
|
|
be689a0495 | ||
|
|
10baed1ee1 | ||
|
|
0b9f99a084 | ||
|
|
4c1076080d | ||
|
|
8347900d33 | ||
|
|
f638d49693 | ||
|
|
d1817aaea6 | ||
|
|
e2b1cdce86 | ||
|
|
81a5e971ef | ||
|
|
6f0cb752aa | ||
|
|
abf5703036 | ||
|
|
b8e6e19ef5 | ||
|
|
ba51e9d5d1 | ||
|
|
8bf14c4044 | ||
|
|
b650c820e0 | ||
|
|
80d787caf9 | ||
|
|
ac46cf80aa | ||
|
|
1eb1e9686a | ||
|
|
dbebe7e626 | ||
|
|
79f8a35c33 | ||
|
|
b78a5ee064 | ||
|
|
704153d7e1 | ||
|
|
e6919bc247 | ||
|
|
b74bc59164 | ||
|
|
d7a6c29552 | ||
|
|
9e1189747d | ||
|
|
4085ae5806 | ||
|
|
ed3bd97dd7 | ||
|
|
d3d313c9e8 | ||
|
|
8bb847508f | ||
|
|
63b38e48ba | ||
|
|
e8cb7e4136 | ||
|
|
8a71ff651a | ||
|
|
4c201ef3ff | ||
|
|
0278458a28 | ||
|
|
3b4600d0af | ||
|
|
50e3393951 | ||
|
|
72fa10634f | ||
|
|
e6a852ea8b | ||
|
|
603a879bdf | ||
|
|
94221e2c62 | ||
|
|
28837dd034 | ||
|
|
9a7e9c9ee3 | ||
|
|
608b02d363 | ||
|
|
940ba8c4c0 | ||
|
|
b0c6e79329 | ||
|
|
86ed199054 | ||
|
|
466c77362e | ||
|
|
8a342a0698 | ||
|
|
75b0d2dd29 | ||
|
|
704015deac | ||
|
|
d98575d77b | ||
|
|
9b17aaf258 | ||
|
|
4638af52e2 | ||
|
|
8aa1e6b9c9 | ||
|
|
c4e0e4f868 | ||
|
|
85b2ba5f77 | ||
|
|
ef090a2b8f | ||
|
|
d1d11b9362 | ||
|
|
ee4434eb6c | ||
|
|
9d2957c419 | ||
|
|
e606a58515 | ||
|
|
d303971c2d | ||
|
|
bd113a5b44 | ||
|
|
99337e8157 | ||
|
|
dad5b3c074 | ||
|
|
7d5f33d033 | ||
|
|
54842f50db | ||
|
|
5ae29afdeb | ||
|
|
8a62b884cc | ||
|
|
ca8851789a | ||
|
|
205032c626 | ||
|
|
f0842337e1 | ||
|
|
b2cb5c1737 | ||
|
|
eef42a1e3e | ||
|
|
53ff42836c | ||
|
|
e92f556cf9 | ||
|
|
13a6cc1c28 | ||
|
|
89a3377456 | ||
|
|
053d6172e5 | ||
|
|
31bb7c62ad | ||
|
|
c3f572f016 | ||
|
|
309aff78fe | ||
|
|
8553c788ab | ||
|
|
d567f707cb | ||
|
|
6686221029 | ||
|
|
3ee473d909 | ||
|
|
2010d31f6b | ||
|
|
ae2d463d7e | ||
|
|
233f4b7514 | ||
|
|
6a1b0a474c | ||
|
|
78ff5683ce | ||
|
|
53e881b75e | ||
|
|
fff2fcae21 | ||
|
|
a68a23d1cb | ||
|
|
cb1e1e5dca | ||
|
|
3b09cb3fae | ||
|
|
c10050a14c | ||
|
|
f8ef6939b0 | ||
|
|
52854b6502 | ||
|
|
fe5d1dd152 | ||
|
|
180e62d597 | ||
|
|
4870641d38 | ||
|
|
33e2f15f49 | ||
|
|
cf51f09826 | ||
|
|
8a75774506 | ||
|
|
7e8c57ee4d | ||
|
|
84331c4d08 | ||
|
|
ceac1be026 | ||
|
|
892d50ba7c | ||
|
|
c08d8b6bcb | ||
|
|
dde656c4c3 | ||
|
|
2d628e2b5a | ||
|
|
d7652a6db6 | ||
|
|
491d3521f7 | ||
|
|
d6854c412c | ||
|
|
110386a3dd | ||
|
|
7d96cd8fbd | ||
|
|
840a2e73a5 | ||
|
|
d033a7fa02 | ||
|
|
07c3a513ef | ||
|
|
18b467a4d8 | ||
|
|
ff8505c013 | ||
|
|
7207bb6293 | ||
|
|
0d6a62ada0 | ||
|
|
721c27c329 | ||
|
|
488198b7da | ||
|
|
702db43590 | ||
|
|
d8c5960c80 | ||
|
|
0942f61aff | ||
|
|
b83604a677 | ||
|
|
56df5b4054 | ||
|
|
cc079e842b | ||
|
|
37907dccfc | ||
|
|
701193e71a | ||
|
|
eff475c498 | ||
|
|
5235581e33 | ||
|
|
ec6b6b25a4 | ||
|
|
e5e685902c | ||
|
|
b0d97bde89 | ||
|
|
810db26bf4 | ||
|
|
5033c096a2 | ||
|
|
83cfaa5e77 | ||
|
|
29dae044cc | ||
|
|
7e83207444 | ||
|
|
9744b2266f | ||
|
|
9eb3ffcc30 | ||
|
|
917209cb65 | ||
|
|
0bf57ddd48 | ||
|
|
fb009ae52f | ||
|
|
2a5160c519 | ||
|
|
349b502149 | ||
|
|
1c1164d9e8 | ||
|
|
35386bbd2c | ||
|
|
96bd8e05aa | ||
|
|
85c1adb258 | ||
|
|
e540a42c9c | ||
|
|
93ff313237 | ||
|
|
60e2118001 | ||
|
|
49963c2e47 | ||
|
|
e883144a76 | ||
|
|
b6a3aef345 | ||
|
|
b49cc250e0 | ||
|
|
2e49ba10dd | ||
|
|
4042fb3a62 | ||
|
|
24ced381de | ||
|
|
e265482cb4 | ||
|
|
ba8346edb7 | ||
|
|
600f261dcb | ||
|
|
14efaee388 | ||
|
|
687682cab0 | ||
|
|
c3b4d59168 | ||
|
|
970e13773d | ||
|
|
af1422a1de | ||
|
|
4947350230 | ||
|
|
e29e20e779 | ||
|
|
3490f1d7ae | ||
|
|
d39d7fb1f5 | ||
|
|
8b3b684675 | ||
|
|
630b236ac0 | ||
|
|
5bb7cb47aa | ||
|
|
7d152b37ad | ||
|
|
0235a971d6 | ||
|
|
bb9bb83202 | ||
|
|
1a7458a290 | ||
|
|
00decf3347 | ||
|
|
6e1df743d0 | ||
|
|
c54a768b19 | ||
|
|
250e9b1805 | ||
|
|
43a91b2b4b | ||
|
|
e4742bcafb | ||
|
|
21f3dee554 | ||
|
|
889ae950fe | ||
|
|
272b28b6a9 | ||
|
|
9a259acefa | ||
|
|
92392da6fe | ||
|
|
0f6920a3f1 | ||
|
|
d2574c4b49 | ||
|
|
0e5b4bde62 | ||
|
|
916d147619 | ||
|
|
4f56cd4c09 | ||
|
|
ab17a995a4 | ||
|
|
3f562c3009 | ||
|
|
66443dd2c2 | ||
|
|
89849bc805 | ||
|
|
4fef14f9fc | ||
|
|
dce1f5492f | ||
|
|
0b1aabf345 | ||
|
|
57b6247a65 | ||
|
|
9529a991ef | ||
|
|
1f49665c05 | ||
|
|
0f73ab889f | ||
|
|
aa8e08e4d0 | ||
|
|
2a78f6902d | ||
|
|
558875c91c | ||
|
|
8ec0feb49b | ||
|
|
5b0874daef | ||
|
|
df8c1139a1 | ||
|
|
0d7bd746ac | ||
|
|
e95c7f144e | ||
|
|
10844e7a52 | ||
|
|
077a091f7d | ||
|
|
f88493870a | ||
|
|
3f6f0b3f9c | ||
|
|
5a0580005f | ||
|
|
1439f8bbeb | ||
|
|
bf8277fb2c | ||
|
|
d9c974fc00 | ||
|
|
23dfc05511 | ||
|
|
4d9a41bc76 | ||
|
|
db0059e0f0 | ||
|
|
2b27c2dc6a | ||
|
|
85e914c129 | ||
|
|
5710b2a7dd | ||
|
|
844139b339 | ||
|
|
79a94b29ce | ||
|
|
d03617d682 | ||
|
|
8494e29075 | ||
|
|
d229ba2405 | ||
|
|
4ab1e08129 | ||
|
|
4255867f29 | ||
|
|
87529f37c8 | ||
|
|
caaf82385b | ||
|
|
ffdcdeee9f | ||
|
|
0db9e84b58 | ||
|
|
82f647299c | ||
|
|
a85a18774f | ||
|
|
143d2a107a | ||
|
|
47258ebd7f | ||
|
|
095b7540d5 | ||
|
|
e871156301 | ||
|
|
35da8e2e67 | ||
|
|
5d4606d0f6 | ||
|
|
2533a844a7 | ||
|
|
62ea74f332 | ||
|
|
38345c1672 | ||
|
|
3a10d47903 | ||
|
|
12eeb97e71 | ||
|
|
4b1dc93792 | ||
|
|
5aa8474d2b | ||
|
|
58e13db613 | ||
|
|
9e3dd9b6d4 | ||
|
|
81902e1b96 | ||
|
|
2670db7ca1 | ||
|
|
bf43f32946 | ||
|
|
4455cfcde1 | ||
|
|
682c0c83a1 | ||
|
|
b9944e8669 | ||
|
|
b4207b3fd9 | ||
|
|
2b6b205a78 | ||
|
|
8c6d6df5fc | ||
|
|
18ae54f656 | ||
|
|
f6fb534035 | ||
|
|
4b0f2ea439 | ||
|
|
45a81e92f4 | ||
|
|
e0ced73d8a | ||
|
|
f1186a35d8 | ||
|
|
933ba8a708 | ||
|
|
bd5d613a24 | ||
|
|
3da1fd4372 | ||
|
|
d007550adb | ||
|
|
170f2646e1 | ||
|
|
207f97a0eb | ||
|
|
577de9683b | ||
|
|
ec09d4a6ca | ||
|
|
1b04dd8032 | ||
|
|
24bfac89ae | ||
|
|
2a5594d7d5 | ||
|
|
44c8b024b0 | ||
|
|
9acd05f16c | ||
|
|
7e71450a76 | ||
|
|
6fbb7e39ec | ||
|
|
920c0eada5 | ||
|
|
97c1b13370 | ||
|
|
47d4e4f659 | ||
|
|
97258542be | ||
|
|
908aa3556e | ||
|
|
93679e62e8 | ||
|
|
09edfb8545 | ||
|
|
d7926f12ad | ||
|
|
e18167d8ae | ||
|
|
c3dc838acb | ||
|
|
7e26e6eac0 | ||
|
|
0c80abf5b9 | ||
|
|
a7692fe4ef | ||
|
|
05233ef853 | ||
|
|
8232d4a3f2 | ||
|
|
e6a4b9f2fe | ||
|
|
67c4531771 | ||
|
|
6f3f48d1e9 | ||
|
|
b7f77498b3 | ||
|
|
8d26944642 | ||
|
|
2f54ceb96e | ||
|
|
63a5701906 | ||
|
|
41cdef055e | ||
|
|
420053178e | ||
|
|
412dcd7736 | ||
|
|
d7c94b4d04 | ||
|
|
032c5166f4 | ||
|
|
4e42e3ef82 | ||
|
|
a71c7cbba2 | ||
|
|
781fbcddd4 | ||
|
|
1d151f2864 | ||
|
|
ffae4540f9 | ||
|
|
25b5f66e6b | ||
|
|
68c00af44e | ||
|
|
12571746d7 | ||
|
|
d90504675f | ||
|
|
249041764b | ||
|
|
554fde7a9d | ||
|
|
a49bfd00a4 | ||
|
|
bc4c08fe2f | ||
|
|
b906f77b37 | ||
|
|
e1f6e167fb | ||
|
|
034ff984cc | ||
|
|
fedcbb8917 | ||
|
|
fb5b505bab | ||
|
|
f020543599 | ||
|
|
7a4edd6ef7 | ||
|
|
2b5e136cc0 | ||
|
|
ab4d595904 | ||
|
|
b1247b5eac | ||
|
|
bed505fd91 | ||
|
|
ffea7cd65a | ||
|
|
8600aead20 | ||
|
|
f48879653a | ||
|
|
0c01ab76cf | ||
|
|
1eb30b28e1 | ||
|
|
6a749bdae5 | ||
|
|
9aa15c6fbb | ||
|
|
8aa8d61bb8 | ||
|
|
24657743ff | ||
|
|
6f35e00c16 | ||
|
|
20fd3a8f67 | ||
|
|
7666ccf2c7 | ||
|
|
0cc29d2c99 | ||
|
|
1b1222494e | ||
|
|
94c3dfe51e | ||
|
|
58d93cb083 | ||
|
|
f5bcc25e10 | ||
|
|
a31e2209c5 | ||
|
|
4d52a8e476 | ||
|
|
c3fb50c358 | ||
|
|
65115089af | ||
|
|
48bac90a7b | ||
|
|
93a38649f3 | ||
|
|
89c5cfb46b | ||
|
|
51808cd1f8 | ||
|
|
758eb77578 | ||
|
|
358f788b61 | ||
|
|
e0d4bf44b8 | ||
|
|
7ec10febae | ||
|
|
8acd495e91 | ||
|
|
5f11dd48a2 | ||
|
|
38343bfbf1 | ||
|
|
76ed7f180e | ||
|
|
6750bd9422 | ||
|
|
d51a7bc9d6 | ||
|
|
6cb545aaf0 | ||
|
|
4b8c4a5bcd | ||
|
|
0a9a191f27 | ||
|
|
83c1bd3ffd | ||
|
|
23c57ad033 | ||
|
|
cf1594bcbb | ||
|
|
10caa91099 | ||
|
|
6f209d26d8 | ||
|
|
6d777fb18f | ||
|
|
c007bee536 | ||
|
|
0f0e674f71 | ||
|
|
56ab86cddc | ||
|
|
8c9c0abee6 | ||
|
|
ae01850ce1 | ||
|
|
319aaaa81d | ||
|
|
4f4280de58 | ||
|
|
dbd2da4923 | ||
|
|
16fcca7a2f | ||
|
|
a803d5a4ec | ||
|
|
d888e82de6 | ||
|
|
07adda3fa6 | ||
|
|
3416e0632d | ||
|
|
6396b38a6f | ||
|
|
25d9e4a195 | ||
|
|
b109d866dd | ||
|
|
075b7f9bd7 | ||
|
|
fc16dc1330 | ||
|
|
28282f1c35 | ||
|
|
67492e744d | ||
|
|
288b37a1b3 | ||
|
|
60e64e1a1d | ||
|
|
18bab30c59 | ||
|
|
a37441b221 | ||
|
|
245d5095b5 | ||
|
|
62f3007d2a | ||
|
|
f9b27d7d01 | ||
|
|
885bfeaf38 | ||
|
|
2d6e6c887e | ||
|
|
afae1a3aae | ||
|
|
9081421eba | ||
|
|
eb8c4e9ee9 | ||
|
|
81c1c206d4 | ||
|
|
063df3243d | ||
|
|
af3e235348 | ||
|
|
ffb5ca4b5b | ||
|
|
866be01860 | ||
|
|
32c05e6a3d | ||
|
|
f1e1e6b204 | ||
|
|
e1b892e8b4 | ||
|
|
da9046f745 | ||
|
|
51a27cba75 | ||
|
|
0e931b0be0 | ||
|
|
ea8e49c870 | ||
|
|
172f943891 | ||
|
|
e6965580a0 | ||
|
|
a9b772ef99 | ||
|
|
c2d1d9b4bf | ||
|
|
d6ee4f49d2 | ||
|
|
05889b54cb | ||
|
|
952d23de08 | ||
|
|
c8e3641bbc | ||
|
|
a12d756d79 | ||
|
|
406900e253 | ||
|
|
ff9030f5fb | ||
|
|
316516422b | ||
|
|
58120e299e | ||
|
|
46a9888647 | ||
|
|
a542e93fe7 | ||
|
|
03ea57dab8 | ||
|
|
9d1e40c5f7 | ||
|
|
a3c3f8df72 | ||
|
|
4fa7deed5a | ||
|
|
c0e73091f5 | ||
|
|
c449a687cf | ||
|
|
23f5b72943 | ||
|
|
9ec6fa06f8 | ||
|
|
9433dc7769 | ||
|
|
9508b136ff | ||
|
|
157d46b73a | ||
|
|
a37bb4c3be | ||
|
|
5c9a502657 | ||
|
|
2331b0911d | ||
|
|
f91401cb95 | ||
|
|
da94644c38 | ||
|
|
aeca25d984 | ||
|
|
cef885db72 | ||
|
|
a780b5f179 | ||
|
|
3b4451a2d1 | ||
|
|
83e8265d5b |
No files matched your search
@@ -0,0 +1,32 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# Top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches all C source files
|
||||
[*.c]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Matches all header files
|
||||
[*.h]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Matches Makefiles
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Matches Markdown files
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,330 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "port", "port-debugger" ]
|
||||
pull_request:
|
||||
branches: [ "port" ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-i686-windows:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW32
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
mingw-w64-i686-toolchain
|
||||
mingw-w64-i686-SDL2
|
||||
mingw-w64-i686-zlib
|
||||
mingw-w64-i686-cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.i686.exe bin/
|
||||
cp build_pal/pd.pal.i686.exe bin/
|
||||
cp build_jpn/pd.jpn.i686.exe bin/
|
||||
cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-i686-windows
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-i686-linux:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386 cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 . && cmake --build build -j
|
||||
- name: Build pd.pal.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.i686 bin/
|
||||
cp build_pal/pd.pal.i686 bin/
|
||||
cp build_jpn/pd.jpn.i686 bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-i686-linux
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-x86_64-windows:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
mingw-w64-x86_64-toolchain
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-zlib
|
||||
mingw-w64-x86_64-cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64.exe bin/
|
||||
cp build_pal/pd.pal.x86_64.exe bin/
|
||||
cp build_jpn/pd.jpn.x86_64.exe bin/
|
||||
cp /mingw64/bin/{SDL2.dll,zlib1.dll,libwinpthread-1.dll,libgcc_s_seh-1.dll} bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-windows
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-x86_64-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture amd64
|
||||
sudo apt-get update
|
||||
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-2.0-0 cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64 bin/
|
||||
cp build_pal/pd.pal.x86_64 bin/
|
||||
cp build_jpn/pd.jpn.x86_64 bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-linux
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-x86_64-osx:
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install zlib
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .
|
||||
cmake --build build --target pd -j4 --clean-first
|
||||
- name: Build pd.pal.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=pal-final .
|
||||
cmake --build build_pal --target pd -j4 --clean-first
|
||||
- name: Build pd.jpn.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=jpn-final .
|
||||
cmake --build build_jpn --target pd -j4 --clean-first
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64 bin/
|
||||
cp build_pal/pd.pal.x86_64 bin/
|
||||
cp build_jpn/pd.jpn.x86_64 bin/
|
||||
cp -vr /Library/Frameworks/SDL2.framework bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-osx
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-arm64-osx:
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install zlib
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=arm64 .
|
||||
cmake --build build --target pd -j4 --clean-first
|
||||
- name: Build pd.pal.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=pal-final .
|
||||
cmake --build build_pal --target pd -j4 --clean-first
|
||||
- name: Build pd.jpn.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=jpn-final .
|
||||
cmake --build build_jpn --target pd -j4 --clean-first
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.arm64 bin/
|
||||
cp build_pal/pd.pal.arm64 bin/
|
||||
cp build_jpn/pd.jpn.arm64 bin/
|
||||
cp -vr /Library/Frameworks/SDL2.framework bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-arm64-osx
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-arm64-nswitch:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/port'
|
||||
steps:
|
||||
- name: Install host dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install git make cmake curl
|
||||
- name: Install devkitA64 docker image
|
||||
run: sudo docker pull devkitpro/devkita64:latest
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build
|
||||
- name: Build pd.pal.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_pal -DROMID=pal-final
|
||||
- name: Build pd.jpn.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_jpn -DROMID=jpn-final
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/perfectdark/data
|
||||
mkdir -p bin/perfectdark_pal/data
|
||||
mkdir -p bin/perfectdark_jpn/data
|
||||
cp build/pd.arm64.nro bin/perfectdark/
|
||||
cp build_pal/pd.pal.arm64.nro bin/perfectdark_pal/
|
||||
cp build_jpn/pd.jpn.arm64.nro bin/perfectdark_jpn/
|
||||
touch bin/perfectdark/data/put_your_rom_here.txt
|
||||
touch bin/perfectdark_pal/data/put_your_rom_here.txt
|
||||
touch bin/perfectdark_jpn/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-arm64-nswitch
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-flatpak-bundle:
|
||||
name: "Build flatpak bundle"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-x86_64-linux]
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
|
||||
options: --privileged
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-linux
|
||||
path: dist/linux/bin/
|
||||
|
||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
with:
|
||||
bundle: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
manifest-path: dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml
|
||||
cache-key: flatpak-builder-${{ github.sha }}
|
||||
upload-artifact: false
|
||||
|
||||
# - name: Build Flatpak bundle
|
||||
# run: |
|
||||
# cd dist/linux/
|
||||
# flatpak-builder build --force-clean io.github.fgsfdsfgs.perfect_dark.yaml
|
||||
# flatpak build-export export build
|
||||
# flatpak build-bundle export io.github.fgsfdsfgs.perfect_dark.flatpak io.github.fgsfdsfgs.perfect_dark
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
path: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
retention-days: 0
|
||||
|
||||
|
||||
publish-latest-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/port'
|
||||
needs: [build-i686-windows, build-i686-linux, build-x86_64-windows, build-x86_64-linux, build-arm64-nswitch, build-x86_64-osx, build-arm64-osx, build-flatpak-bundle]
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ci-artifacts
|
||||
- name: Publish latest dev-build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
mkdir ci-release
|
||||
pushd ci-artifacts
|
||||
tar czf ../ci-release/pd-i686-linux.tar.gz pd-i686-linux
|
||||
tar czf ../ci-release/pd-x86_64-linux.tar.gz pd-x86_64-linux
|
||||
tar cJf ../ci-release/pd-x86_64-osx.tar.xz pd-x86_64-osx
|
||||
tar cJf ../ci-release/pd-arm64-osx.tar.xz pd-arm64-osx
|
||||
zip -r ../ci-release/pd-i686-windows.zip pd-i686-windows
|
||||
zip -r ../ci-release/pd-x86_64-windows.zip pd-x86_64-windows
|
||||
zip -r ../ci-release/pd-arm64-nswitch.zip pd-arm64-nswitch
|
||||
mv io.github.fgsfdsfgs.perfect_dark.flatpak/io.github.fgsfdsfgs.perfect_dark.flatpak ../ci-release/
|
||||
popd
|
||||
git tag --force ci-dev-build port
|
||||
git push --force origin ci-dev-build
|
||||
gh release upload --clobber ci-dev-build ci-release/*
|
||||
@@ -1,7 +1,10 @@
|
||||
*.o
|
||||
*.pyc
|
||||
*.dll
|
||||
*.exe
|
||||
pd.*.z64
|
||||
build
|
||||
.flatpak-builder
|
||||
extracted
|
||||
src/assets/*/*.bin
|
||||
src/assets/*/*.ctl
|
||||
@@ -19,3 +22,7 @@ src/assets/*/sequences/*.seq
|
||||
src/assets/*/textures/*.bin
|
||||
src/generated
|
||||
tools/mkrom/mkrom
|
||||
/.vs
|
||||
CppProperties.json
|
||||
.idea
|
||||
cmake-build-debug
|
||||
+359
@@ -0,0 +1,359 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
if(APPLE)
|
||||
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
# ARM Macs start at OS 11.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
|
||||
else()
|
||||
# SDL2 requires at least this version for everything to work properly.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(pd C CXX)
|
||||
|
||||
include(TargetArch)
|
||||
include(FindPkgConfig)
|
||||
include(AssetUtils)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# On first build set the build type to RelWithDebInfo if it's not already set
|
||||
if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt)
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Options
|
||||
|
||||
set(ROMID "ntsc-final" CACHE STRING "Which ROM to build an executable for: ntsc-final, pal-final or jpn-final")
|
||||
option(FORCE_CROSSCOMPILE "Force cross compiling" NO)
|
||||
|
||||
# Determine target arch
|
||||
|
||||
target_architecture(TARGET_ARCH)
|
||||
if(TARGET_ARCH STREQUAL "i386")
|
||||
# for historical reasons
|
||||
set(TARGET_ARCH "i686")
|
||||
endif()
|
||||
|
||||
# TODO
|
||||
set(TARGET_IS_BIG_ENDIAN FALSE)
|
||||
|
||||
if((TARGET_ARCH MATCHES "unknown") OR (TARGET_ARCH STREQUAL ""))
|
||||
message(FATAL_ERROR "Unknown target arch")
|
||||
elseif(TARGET_ARCH MATCHES "64")
|
||||
set(TARGET_IS_64BIT TRUE)
|
||||
else()
|
||||
set(TARGET_IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
message(STATUS "Target arch: ${TARGET_ARCH}")
|
||||
|
||||
# Determine target OS and platform identifier ($arch-$os)
|
||||
|
||||
if(WIN32)
|
||||
# Windows
|
||||
set(TARGET_OS "windows")
|
||||
elseif(APPLE)
|
||||
# OSX
|
||||
set(TARGET_OS "osx")
|
||||
elseif(NINTENDO_SWITCH)
|
||||
# Switch
|
||||
set(TARGET_OS "nswitch")
|
||||
elseif(UNIX)
|
||||
# Generic *nix; assume Linux
|
||||
set(TARGET_OS "linux")
|
||||
else()
|
||||
# ???
|
||||
message(FATAL_ERROR "Unknown target OS or compiler")
|
||||
endif()
|
||||
|
||||
set(TARGET_PLATFORM "${TARGET_ARCH}-${TARGET_OS}")
|
||||
|
||||
message(STATUS "Target platform: ${TARGET_PLATFORM}")
|
||||
|
||||
# Calculate version info and binary name
|
||||
|
||||
set(VERSION_IS_PAL 0)
|
||||
|
||||
if(ROMID STREQUAL "ntsc-final")
|
||||
set(VERSION 2)
|
||||
set(BIN_REGION "")
|
||||
elseif(ROMID STREQUAL "pal-final")
|
||||
set(VERSION 4)
|
||||
set(BIN_REGION ".pal")
|
||||
set(VERSION_IS_PAL 1)
|
||||
elseif(ROMID STREQUAL "jpn-final")
|
||||
set(VERSION 5)
|
||||
set(BIN_REGION ".jpn")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown ROM ID: ${ROMID}")
|
||||
endif()
|
||||
|
||||
# git commit hash
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VERSION_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# git branch name
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VERSION_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
set(VERSION_TARGET "${TARGET_PLATFORM}")
|
||||
set(VERSION_ARCH "${TARGET_ARCH}")
|
||||
set(VERSION_ROMID "${ROMID}")
|
||||
set(VERSION_BUILD "${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if((VERSION_BRANCH STREQUAL "") OR (VERSION_BRANCH STREQUAL "HEAD"))
|
||||
set(VERSION_BRANCH "port-custom")
|
||||
endif()
|
||||
|
||||
message(STATUS "Version: ${VERSION_ROMID}, hash ${VERSION_HASH}, branch ${VERSION_BRANCH}")
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/port/include/versioninfo.h.in" "${CMAKE_BINARY_DIR}/port/include/versioninfo.h" @ONLY)
|
||||
|
||||
set(ASSET_DIR "src/assets/${ROMID}")
|
||||
set(GENERATED_DIR "src/generated/${ROMID}")
|
||||
|
||||
set(ENV{ROMID} ${ROMID})
|
||||
|
||||
# Build folder postfix
|
||||
|
||||
set(BUILD_ID "${VERSION_ROMID}-${VERSION_TARGET}")
|
||||
|
||||
# Compiler defs
|
||||
|
||||
add_definitions(
|
||||
-DMATCHING=0
|
||||
-DPIRACYCHECKS=0
|
||||
-DROM_SIZE=32
|
||||
-DAVOID_UB=1
|
||||
-D_LANGUAGE_C=1
|
||||
-DPAL=${VERSION_IS_PAL}
|
||||
-DVERSION=${VERSION}
|
||||
)
|
||||
|
||||
if(TARGET_IS_64BIT)
|
||||
add_definitions(-DPLATFORM_64BIT=1)
|
||||
endif()
|
||||
|
||||
# Compiler flags
|
||||
|
||||
# Include directories
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include/PR")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src/include")
|
||||
include_directories("${CMAKE_BINARY_DIR}/src/generated/${ROMID}")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src/lib/ultra/audio")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/port/include")
|
||||
include_directories("${CMAKE_BINARY_DIR}/port/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/port/src/imgui")
|
||||
|
||||
# Set Release optimization to -Og until I fix the -O2 issues
|
||||
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
add_compile_options(-Og)
|
||||
endif()
|
||||
|
||||
# Common CFLAGS
|
||||
add_compile_options(
|
||||
-fno-inline-functions
|
||||
-fno-strict-aliasing
|
||||
-funsigned-char
|
||||
-fwrapv
|
||||
-include "versioninfo.h"
|
||||
)
|
||||
|
||||
# Common warning flags
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-address
|
||||
-Wno-int-in-bool-context
|
||||
-Wno-misleading-indentation
|
||||
-Wno-missing-braces
|
||||
-Wno-multichar
|
||||
-Wno-tautological-compare
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-unused-value
|
||||
-Wno-unused-variable
|
||||
)
|
||||
|
||||
# C specific flags
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-pointer-sign>)
|
||||
|
||||
# C++ specific flags
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-unused-function>)
|
||||
|
||||
# Platform-specific flags
|
||||
if (APPLE)
|
||||
# Make it look for libs in the executable folder manually since CMake's rpath system is wack
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rpath @executable_path")
|
||||
else()
|
||||
# This warning is not recognized by XCode/Clang for some reason.
|
||||
add_compile_options(-Wno-format-truncation)
|
||||
endif()
|
||||
|
||||
# Dependencies
|
||||
|
||||
set(LIBS )
|
||||
|
||||
# SDL2
|
||||
find_package(SDL2 REQUIRED)
|
||||
if(NINTENDO_SWITCH)
|
||||
if(NOT SDL2_LIBRARY OR NOT SDL2_INCLUDE_DIR)
|
||||
# sometimes FindSDL2 just wants us to suffer and does not set these
|
||||
set(SDL2_LIBRARY "SDL2")
|
||||
set(SDL2_INCLUDE_DIR "${DEVKITPRO}/portlibs/switch/include/SDL2")
|
||||
endif()
|
||||
endif()
|
||||
include_directories(SYSTEM "${SDL2_INCLUDE_DIR}")
|
||||
list(APPEND LIBS "${SDL2_LIBRARY}")
|
||||
|
||||
# ZLib
|
||||
find_package(ZLIB REQUIRED)
|
||||
if(ZLIB_INCLUDE_DIR)
|
||||
include_directories(SYSTEM "${ZLIB_INCLUDE_DIR}")
|
||||
endif()
|
||||
list(APPEND LIBS "${ZLIB_LIBRARY}")
|
||||
|
||||
# GL
|
||||
if(NOT GL_LIBRARY)
|
||||
if(WIN32)
|
||||
set(GL_LIBRARY opengl32)
|
||||
elseif(NINTENDO_SWITCH)
|
||||
set(GL_LIBRARY EGL glapi drm_nouveau)
|
||||
elseif(APPLE)
|
||||
set(GL_LIBRARY "-framework OpenGL")
|
||||
else()
|
||||
set(GL_LIBRARY GL)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND LIBS "${GL_LIBRARY}")
|
||||
|
||||
# Platform-specific extra libs
|
||||
if(NOT EXTRA_LIBRARIES)
|
||||
if(WIN32)
|
||||
set(EXTRA_LIBRARIES dbghelp -static-libstdc++)
|
||||
elseif(NINTENDO_SWITCH)
|
||||
set(EXTRA_LIBRARIES stdc++ pthread)
|
||||
else()
|
||||
set(EXTRA_LIBRARIES stdc++ m dl)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND LIBS "${EXTRA_LIBRARIES}")
|
||||
|
||||
# Sources
|
||||
|
||||
file(GLOB_RECURSE SRC_PORT "${CMAKE_SOURCE_DIR}/port/*.c")
|
||||
file(GLOB_RECURSE SRC_PORT_CXX "${CMAKE_SOURCE_DIR}/port/*.cpp")
|
||||
|
||||
file(GLOB_RECURSE SRC_GAME "${CMAKE_SOURCE_DIR}/src/game/*.c")
|
||||
|
||||
file(GLOB SRC_LIB_MP3 "${CMAKE_SOURCE_DIR}/src/lib/mp3/*.c")
|
||||
file(GLOB SRC_LIB_NAUDIO "${CMAKE_SOURCE_DIR}/src/lib/naudio/*.c")
|
||||
file(GLOB SRC_LIB_ULTRA_AUDIO "${CMAKE_SOURCE_DIR}/src/lib/ultra/audio/*.c")
|
||||
file(GLOB SRC_LIB_GU "${CMAKE_SOURCE_DIR}/src/lib/ultra/gu/*.c")
|
||||
set(SRC_LIB
|
||||
src/lib/ultra/io/vimodentsclan1.c
|
||||
src/lib/ultra/io/vimodepallan1.c
|
||||
src/lib/ultra/io/vimodempallan1.c
|
||||
src/lib/ultra/io/vitbl.c
|
||||
src/lib/ailist.c
|
||||
src/lib/anim.c
|
||||
src/lib/args.c
|
||||
src/lib/audiodma.c
|
||||
src/lib/audiomgr.c
|
||||
src/lib/base.c
|
||||
src/lib/collision.c
|
||||
src/lib/debughud.c
|
||||
src/lib/dma.c
|
||||
src/lib/fault.c
|
||||
src/lib/joy.c
|
||||
src/lib/lib_2f490_c.c
|
||||
src/lib/lib_2fc60.c
|
||||
src/lib/lib_3e3e0.c
|
||||
src/lib/lib_04f60nb.c
|
||||
src/lib/lib_17ce0.c
|
||||
src/lib/lib_034d0.c
|
||||
src/lib/lib_39c80.c
|
||||
src/lib/lib_15850.c
|
||||
src/lib/mema.c
|
||||
src/lib/memp.c
|
||||
src/lib/model.c
|
||||
src/lib/modelasm_c.c
|
||||
src/lib/mp3.c
|
||||
src/lib/mtx_c.c
|
||||
src/lib/mtx.c
|
||||
src/lib/music.c
|
||||
src/lib/path.c
|
||||
src/lib/profile.c
|
||||
src/lib/rdp.c
|
||||
src/lib/rmon.c
|
||||
src/lib/rng_c.c
|
||||
src/lib/rzip_c.c
|
||||
src/lib/snd.c
|
||||
src/lib/speaker.c
|
||||
src/lib/varsinit.c
|
||||
src/lib/vi.c
|
||||
src/textureconfig.c
|
||||
)
|
||||
list(PREPEND SRC_LIB "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
set(SRC
|
||||
${SRC_GAME}
|
||||
${SRC_PORT}
|
||||
${SRC_PORT_CXX}
|
||||
${SRC_LIB_MP3}
|
||||
${SRC_LIB_NAUDIO}
|
||||
${SRC_LIB_ULTRA_AUDIO}
|
||||
${SRC_LIB_GU}
|
||||
${SRC_LIB}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SRC "${CMAKE_SOURCE_DIR}/dist/windows/icon.rc")
|
||||
endif()
|
||||
|
||||
# Asset files
|
||||
|
||||
generate_asset_headers("lang/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mklang" "en" JSON_HEADERS)
|
||||
generate_asset_headers("pads/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkpads" "" JSON_HEADERS)
|
||||
generate_asset_headers("tiles/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktiles" "" JSON_HEADERS)
|
||||
generate_asset_headers("animations.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkanims" "" JSON_HEADERS)
|
||||
generate_asset_headers("sequences.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mksequences" "" JSON_HEADERS)
|
||||
generate_asset_headers("textures.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktextures" "" JSON_HEADERS)
|
||||
|
||||
add_custom_target(pd_headers ALL DEPENDS ${JSON_HEADERS})
|
||||
|
||||
# Game target
|
||||
|
||||
set(BIN_NAME "pd${BIN_REGION}.${TARGET_ARCH}")
|
||||
add_executable(pd ${SRC})
|
||||
add_dependencies(pd pd_headers)
|
||||
target_link_libraries(pd ${LIBS})
|
||||
set_target_properties(pd PROPERTIES OUTPUT_NAME "${BIN_NAME}")
|
||||
if(WIN32)
|
||||
set_target_properties(pd PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||
endif()
|
||||
|
||||
# Additional commands for specific platforms.
|
||||
|
||||
if(NINTENDO_SWITCH)
|
||||
add_custom_command(TARGET pd POST_BUILD
|
||||
COMMAND nacptool --create "Perfect Dark" "fgsfds and contributors" "${VERSION_ROMID}/${VERSION_BRANCH}/${VERSION_HASH}" "${BIN_NAME}.nacp"
|
||||
COMMAND aarch64-none-elf-strip -o ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.elf
|
||||
COMMAND elf2nro ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/dist/nswitch/icon.jpg --nacp=${BIN_NAME}.nacp
|
||||
)
|
||||
endif()
|
||||
@@ -1,808 +0,0 @@
|
||||
################################################################################
|
||||
# Options
|
||||
|
||||
# ROMID - The ROM version to build.
|
||||
#
|
||||
# Can be set in your environment using
|
||||
# $ export ROMID=...
|
||||
#
|
||||
# Supported values:
|
||||
# * ntsc-beta
|
||||
# * ntsc-1.0
|
||||
# * ntsc-final
|
||||
# * pal-beta
|
||||
# * pal-final
|
||||
# * jpn-final
|
||||
|
||||
ROMID ?= ntsc-final
|
||||
|
||||
# MATCHING - Whether to build a matching ROM (1) or a custom one (0).
|
||||
#
|
||||
# Build a matching ROM to prove that the decompilation is accurate.
|
||||
#
|
||||
# If enabled, all further options are ignored and are set automatically.
|
||||
|
||||
MATCHING = 1
|
||||
|
||||
# COMPILER - Choose which compiler to use.
|
||||
#
|
||||
# A matching build uses ido. For non-matching builds, use gcc for performance.
|
||||
#
|
||||
# gcc is currently only supported when ROMID is ntsc-1.0 or ntsc-final.
|
||||
#
|
||||
# Supported values: ido, gcc
|
||||
|
||||
COMPILER = gcc
|
||||
|
||||
# GCC_OPT_LVL - the optimisation level if building with gcc.
|
||||
#
|
||||
# Supported values: -O0, -O1, -O2, -Os
|
||||
|
||||
GCC_OPT_LVL = -Os
|
||||
|
||||
# PAL - Whether to use the PAL television standard (1) or NTSC (0).
|
||||
#
|
||||
# PAL runs at 50Hz while NTSC is 60Hz, and PAL uses different screen dimensions.
|
||||
|
||||
PAL = 0
|
||||
|
||||
# ROMALLOCATION
|
||||
#
|
||||
# The lib, data and game segments are compressed in the final ROM.
|
||||
#
|
||||
# These options define how much space is allocated for the compressed segments.
|
||||
#
|
||||
# If any value is not big enough, the build system will tell you which one needs
|
||||
# to be changed and what to change it to.
|
||||
|
||||
ROMALLOCATION_DATA = 0x015000
|
||||
ROMALLOCATION_LIB = 0x038800
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
|
||||
# ROM_SIZE - The desired ROM size in megabytes.
|
||||
#
|
||||
# All versions of the retail ROM are 32MB.
|
||||
#
|
||||
# If this is too low you might get this error from ld:
|
||||
# "final link failed: memory exhausted"
|
||||
|
||||
ROM_SIZE := 32
|
||||
|
||||
# DEBUG - Enable (1) or disable (0) the debug menu and crash screen.
|
||||
#
|
||||
# When enabled, press C-up and C-down simultaneously to toggle the debug menu.
|
||||
# Note that some emulators have problems displaying the crash screen text.
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
################################################################################
|
||||
|
||||
# The VERSION constant is used in the source to handle version-specific code.
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
VERSION = 0
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-1.0)
|
||||
VERSION = 1
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-final)
|
||||
VERSION = 2
|
||||
endif
|
||||
ifeq ($(ROMID), pal-beta)
|
||||
VERSION = 3
|
||||
endif
|
||||
ifeq ($(ROMID), pal-final)
|
||||
VERSION = 4
|
||||
endif
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
VERSION = 5
|
||||
endif
|
||||
|
||||
# Set runtime piracy checks off. We turn this on for matching builds if needed.
|
||||
PIRACYCHECKS = 0
|
||||
|
||||
# A magic value that's only used to produce a matching ROM.
|
||||
# It's required because old-school zlib was influenced by uninitialised data.
|
||||
# ZIPMAGIC is the value of the uninitialised data. We set it per version for
|
||||
# matching builds, otherwise 0 is fine.
|
||||
ZIPMAGIC = 0x0000
|
||||
|
||||
# This is also a value that's only used to produce a matching ROM.
|
||||
# The final ROM has some duplicate bytes, and there doesn't seem to be any logic
|
||||
# for determining how many bytes are duplicated.
|
||||
COPYLEN = 2
|
||||
|
||||
# If a matching build has been requested, override directives as needed.
|
||||
ifeq ($(MATCHING), 1)
|
||||
COMPILER = ido
|
||||
|
||||
ROMALLOCATION_DATA = 0x015000
|
||||
ROMALLOCATION_LIB = 0x038800
|
||||
|
||||
ROM_SIZE = 32
|
||||
DEBUG = 0
|
||||
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 0
|
||||
ROMALLOCATION_DATA = 0x012000
|
||||
ROMALLOCATION_LIB = 0x02f800
|
||||
ROMALLOCATION_GAME = 0x105000
|
||||
DEBUG = 1
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-1.0)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
ZIPMAGIC = 0xffff
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-final)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
ZIPMAGIC = 0xffff
|
||||
endif
|
||||
ifeq ($(ROMID), pal-beta)
|
||||
PAL = 1
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1306f0
|
||||
ZIPMAGIC = 0x0c00
|
||||
COPYLEN = 6
|
||||
DEBUG = 1
|
||||
endif
|
||||
ifeq ($(ROMID), pal-final)
|
||||
PAL = 1
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1306f0
|
||||
ZIPMAGIC = 0xaf00
|
||||
endif
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1296f0
|
||||
ZIPMAGIC = 0x0002
|
||||
COPYLEN = 4
|
||||
endif
|
||||
endif
|
||||
|
||||
DEFINES := \
|
||||
VERSION=$(VERSION) \
|
||||
MATCHING=$(MATCHING) \
|
||||
PAL=$(PAL) \
|
||||
PIRACYCHECKS=$(PIRACYCHECKS) \
|
||||
ROM_SIZE=$(ROM_SIZE)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFINES := $(DEFINES) DEBUG=1
|
||||
endif
|
||||
|
||||
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
|
||||
AS_DEFINES := $(foreach d,$(DEFINES),--defsym $(d)) --defsym _LANGUAGE_ASSEMBLY=1
|
||||
|
||||
A_DIR := src/assets/$(ROMID)
|
||||
B_DIR := build/$(ROMID)
|
||||
E_DIR := extracted/$(ROMID)
|
||||
|
||||
ifneq ($(strip $(MIPS_BINUTILS_PREFIX)),)
|
||||
TOOLCHAIN := $(MIPS_BINUTILS_PREFIX)
|
||||
else ifeq ($(shell type mips-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips-elf
|
||||
else ifeq ($(shell type mips-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips-linux-gnu
|
||||
else ifeq ($(shell type mips64-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips64-elf
|
||||
else ifeq ($(shell type mips64-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips64-linux-gnu
|
||||
else
|
||||
$(error You need to install a suitable MIPS binutils toolchain (eg. mips-elf-ld))
|
||||
endif
|
||||
|
||||
# Asset files are files which are included in the "files" segment of the ROM.
|
||||
# This excludes animations, fonts, SFX, MIDI and textures.
|
||||
# And because setup files are part of the files segment they are included here,
|
||||
# despite them being written in C.
|
||||
#
|
||||
# Create names such as $(B_DIR)/assets/files/PfooZ.
|
||||
# These names (with .o added) will be dependenices for ld.
|
||||
ASSET_FILES := \
|
||||
$(patsubst $(A_DIR)/files/audio/%.mp3, $(B_DIR)/assets/files/A%M, $(shell find $(A_DIR) -path '*/files/audio/*.mp3')) \
|
||||
$(patsubst $(A_DIR)/files/chrs/%.bin, $(B_DIR)/assets/files/C%Z, $(shell find $(A_DIR) -path '*/files/chrs/*.bin')) \
|
||||
$(patsubst $(A_DIR)/files/guns/%.bin, $(B_DIR)/assets/files/G%Z, $(shell find $(A_DIR) -path '*/files/guns/*.bin')) \
|
||||
$(patsubst $(A_DIR)/files/props/%.bin, $(B_DIR)/assets/files/P%Z, $(shell find $(A_DIR) -path '*/files/props/*.bin')) \
|
||||
$(patsubst src/setups/%.c, $(B_DIR)/assets/files/U%Z, $(shell find src/setups -name '*.c')) \
|
||||
$(patsubst $(A_DIR)/files/bgdata/%.seg, $(B_DIR)/assets/files/bgdata/%.seg, $(shell find $(A_DIR) -path '*/files/bgdata/*.seg')) \
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg.o
|
||||
|
||||
LANG_JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
|
||||
PADS_JSON_FILES := $(shell find $(A_DIR) -path '*/pads/*.json')
|
||||
TILES_JSON_FILES := $(shell find $(A_DIR) -path '*/tiles/*.json')
|
||||
|
||||
LANG_O_FILES := \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%E.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%J.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%P.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_f.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_g.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_i.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_s.o, $(LANG_JSON_FILES))
|
||||
|
||||
PADS_O_FILES := $(patsubst $(A_DIR)/pads/%.json, $(B_DIR)/assets/files/bgdata/bg_%_padsZ.o, $(PADS_JSON_FILES))
|
||||
TILES_O_FILES := $(patsubst $(A_DIR)/tiles/%.json, $(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o, $(TILES_JSON_FILES))
|
||||
|
||||
C_FILES := $(shell find src/lib src/game src/inflate -name '*.c')
|
||||
S_FILES := $(shell find src/lib src/game src/preamble -name '*.s')
|
||||
|
||||
C_O_FILES := $(patsubst src/%.c, $(B_DIR)/%.o, $(C_FILES))
|
||||
S_O_FILES := $(patsubst src/%.s, $(B_DIR)/%.o, $(S_FILES))
|
||||
|
||||
O_FILES := \
|
||||
$(C_O_FILES) \
|
||||
$(S_O_FILES) \
|
||||
$(patsubst %, %.o, $(ASSET_FILES)) \
|
||||
$(LANG_O_FILES) \
|
||||
$(PADS_O_FILES) \
|
||||
$(TILES_O_FILES) \
|
||||
$(B_DIR)/assets/animations.o \
|
||||
$(B_DIR)/assets/copyrightZ.o \
|
||||
$(B_DIR)/assets/files/list.o \
|
||||
$(B_DIR)/assets/fonts/bankgothic.o \
|
||||
$(B_DIR)/assets/fonts/handelgothiclg.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicmd.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicsm.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicxs.o \
|
||||
$(B_DIR)/assets/fonts/numeric.o \
|
||||
$(B_DIR)/assets/fonts/ocralg.o \
|
||||
$(B_DIR)/assets/fonts/ocramd.o \
|
||||
$(B_DIR)/assets/fonts/tahoma.o \
|
||||
$(B_DIR)/assets/fonts/zurich.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsE.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsF.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsG.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsI.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsJ.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsP.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsS.o \
|
||||
$(B_DIR)/assets/seq.ctl.o \
|
||||
$(B_DIR)/assets/seq.tbl.o \
|
||||
$(B_DIR)/assets/sequences.o \
|
||||
$(B_DIR)/assets/sfx.ctl.o \
|
||||
$(B_DIR)/assets/sfx.tbl.o \
|
||||
$(B_DIR)/assets/textureslist.o \
|
||||
$(B_DIR)/bootloader.o \
|
||||
$(B_DIR)/firingrange.o \
|
||||
$(B_DIR)/getitle.o \
|
||||
$(B_DIR)/mpconfigs.o \
|
||||
$(B_DIR)/romheader.o \
|
||||
$(B_DIR)/rsp/asp.data.o \
|
||||
$(B_DIR)/rsp/asp.text.o \
|
||||
$(B_DIR)/rsp/gsp.data.o \
|
||||
$(B_DIR)/rsp/gsp.text.o \
|
||||
$(B_DIR)/rsp/rspboot.text.o \
|
||||
$(B_DIR)/textureconfig.o
|
||||
|
||||
# ntsc-beta doesn't have this segment
|
||||
ifneq ($(ROMID), ntsc-beta)
|
||||
O_FILES := $(O_FILES) $(B_DIR)/assets/accessingpakZ.o
|
||||
endif
|
||||
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
O_FILES := $(O_FILES) $(B_DIR)/assets/fonts/jpn.o
|
||||
else
|
||||
O_FILES := $(O_FILES) \
|
||||
$(B_DIR)/assets/fonts/jpnsingle.o \
|
||||
$(B_DIR)/assets/fonts/jpnmulti.o
|
||||
endif
|
||||
|
||||
INCLUDES = \
|
||||
-I include \
|
||||
-I include/PR \
|
||||
-I src/include \
|
||||
-I src/generated/$(ROMID) \
|
||||
-I src/lib/ultra/audio \
|
||||
|
||||
AS := $(TOOLCHAIN)-as
|
||||
ASFLAGS = -march=vr4300 -mabi=32 $(INCLUDES) $(AS_DEFINES)
|
||||
|
||||
ifeq ($(COMPILER), ido)
|
||||
RECOMP_FILES := \
|
||||
build/recomp/5.3/as1 \
|
||||
build/recomp/5.3/cc \
|
||||
build/recomp/5.3/cfe \
|
||||
build/recomp/5.3/err.english.cc \
|
||||
build/recomp/5.3/ugen \
|
||||
build/recomp/5.3/ujoin \
|
||||
build/recomp/5.3/uld \
|
||||
build/recomp/5.3/umerge \
|
||||
build/recomp/5.3/uopt \
|
||||
build/recomp/5.3/usplit \
|
||||
build/recomp/7.1/as1 \
|
||||
build/recomp/7.1/cc \
|
||||
build/recomp/7.1/cfe \
|
||||
build/recomp/7.1/err.english.cc \
|
||||
build/recomp/7.1/ugen \
|
||||
build/recomp/7.1/uopt
|
||||
|
||||
LOOPUNROLL_C_FILES := \
|
||||
src/lib/ultra/gu/frustum.c \
|
||||
src/lib/ultra/gu/mtxutil.c \
|
||||
src/lib/ultra/gu/ortho.c \
|
||||
src/lib/ultra/io/conteepread.c \
|
||||
src/lib/ultra/io/conteepwrite.c \
|
||||
src/lib/ultra/io/contpfs.c \
|
||||
src/lib/ultra/io/contramread.c \
|
||||
src/lib/ultra/io/contramwrite.c \
|
||||
src/lib/ultra/io/gbpakgetstatus.c \
|
||||
src/lib/ultra/io/gbpakreadid.c \
|
||||
src/lib/ultra/io/motor.c \
|
||||
src/lib/ultra/io/pfschecker.c \
|
||||
src/lib/ultra/io/pfsfreeblocks.c \
|
||||
src/lib/ultra/io/pfsgetstatus.c \
|
||||
src/lib/ultra/io/pfsinitpak2.c
|
||||
|
||||
MIPS3_C_FILES := \
|
||||
src/lib/rng_c.c \
|
||||
src/lib/ultra/libc/ll.c \
|
||||
src/lib/ultra/libc/llcvt.c
|
||||
|
||||
G_C_FILES := \
|
||||
$(shell find src/lib/ultra/audio -name '*.c') \
|
||||
$(shell find src/lib/naudio -name '*.c') \
|
||||
$(shell find src/lib/mp3 -name '*.c') \
|
||||
src/lib/lib_2fc60.c \
|
||||
src/lib/lib_317f0.c \
|
||||
src/lib/lib_39c80.c \
|
||||
src/lib/lib_3e3e0.c \
|
||||
src/lib/mp3.c \
|
||||
src/lib/speaker.c
|
||||
|
||||
O1_C_FILES := \
|
||||
src/lib/lib_04f60nb.c \
|
||||
src/lib/ultra/io/ai.c \
|
||||
src/lib/ultra/io/aisetnextbuf.c \
|
||||
src/lib/ultra/io/conteeplongread.c \
|
||||
src/lib/ultra/io/contquery.c \
|
||||
src/lib/ultra/io/controller.c \
|
||||
src/lib/ultra/io/dpctr.c \
|
||||
src/lib/ultra/io/pigetcmdq.c \
|
||||
src/lib/ultra/io/pidma.c \
|
||||
src/lib/ultra/io/si.c \
|
||||
src/lib/ultra/io/sp.c \
|
||||
src/lib/ultra/io/spsetpc.c \
|
||||
src/lib/ultra/io/sptaskyielded.c \
|
||||
src/lib/ultra/io/vi.c \
|
||||
src/lib/ultra/io/viblack.c \
|
||||
src/lib/ultra/io/vigetcurrframebuf.c \
|
||||
src/lib/ultra/io/vigetnextframebuf.c \
|
||||
src/lib/ultra/io/visetevent.c \
|
||||
src/lib/ultra/io/visetmode.c \
|
||||
src/lib/ultra/io/visetxscale.c \
|
||||
src/lib/ultra/io/visetyscale.c \
|
||||
src/lib/ultra/io/viswapbuf.c \
|
||||
src/lib/ultra/libc/ll.c \
|
||||
src/lib/ultra/libc/llcvt.c \
|
||||
src/lib/ultra/os/atomic.c \
|
||||
src/lib/ultra/os/createmesgqueue.c \
|
||||
src/lib/ultra/os/destroythread.c \
|
||||
src/lib/ultra/os/getmemsize.c \
|
||||
src/lib/ultra/os/gettime.c \
|
||||
src/lib/ultra/os/initialize2.c \
|
||||
src/lib/ultra/os/jammesg.c \
|
||||
src/lib/ultra/os/recvmesg.c \
|
||||
src/lib/ultra/os/resetglobalintmask.c \
|
||||
src/lib/ultra/os/sendmesg.c \
|
||||
src/lib/ultra/os/seteventmesg.c \
|
||||
src/lib/ultra/os/setglobalintmask.c \
|
||||
src/lib/ultra/os/setthreadpri.c \
|
||||
src/lib/ultra/os/settimer.c \
|
||||
src/lib/ultra/os/startthread.c \
|
||||
src/lib/ultra/os/stopthread.c \
|
||||
src/lib/ultra/os/stoptimer.c \
|
||||
src/lib/ultra/os/thread.c \
|
||||
src/lib/ultra/os/timerintr.c \
|
||||
src/lib/ultra/os/virtualtophysical.c \
|
||||
src/lib/ultra/os/yieldthread.c
|
||||
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
O1_C_FILES := $(O1_C_FILES) src/lib/ultra/io/pfsisplug.c
|
||||
endif
|
||||
|
||||
O3_C_FILES := \
|
||||
src/lib/ultra/gu/align.c \
|
||||
src/lib/ultra/gu/frustum.c \
|
||||
src/lib/ultra/gu/ortho.c \
|
||||
src/lib/ultra/gu/scale.c \
|
||||
src/lib/ultra/libc/xprintf.c
|
||||
|
||||
IDO71_C_FILES := \
|
||||
$(shell find src/lib/ultra/audio -name '*.c') \
|
||||
$(shell find src/lib/naudio -name '*.c') \
|
||||
$(shell find src/lib/mp3 -name '*.c') \
|
||||
src/lib/lib_2fc60.c \
|
||||
src/lib/lib_39c80.c
|
||||
|
||||
LOOPUNROLL_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(LOOPUNROLL_C_FILES))
|
||||
MIPS3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(MIPS3_C_FILES))
|
||||
G_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(G_C_FILES))
|
||||
O1_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O1_C_FILES))
|
||||
O3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O3_C_FILES))
|
||||
IDO71_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(IDO71_C_FILES))
|
||||
|
||||
LOOPUNROLL := -Wo,-loopunroll,0
|
||||
MIPSISET := -mips2
|
||||
OPT_LVL := -O2
|
||||
CC := build/recomp/5.3/cc
|
||||
|
||||
$(LOOPUNROLL_O_FILES): LOOPUNROLL :=
|
||||
$(MIPS3_O_FILES): MIPSISET := -mips3
|
||||
$(G_O_FILES): OPT_LVL := -g
|
||||
$(O1_O_FILES): OPT_LVL := -O1
|
||||
$(O3_O_FILES): OPT_LVL := -O3
|
||||
$(IDO71_O_FILES): CC := build/recomp/7.1/cc
|
||||
|
||||
CFLAGS = $(C_DEFINES) $(INCLUDES) \
|
||||
$(LOOPUNROLL) \
|
||||
-Wab,-r4300_mul \
|
||||
-non_shared \
|
||||
-Olimit 2000 \
|
||||
-G 0 \
|
||||
-Xcpluscomm \
|
||||
-w2 \
|
||||
-Wab,-w \
|
||||
-woff 581,649,819,820,821,838,852 \
|
||||
$(MIPSISET) -32
|
||||
|
||||
# Files containing GLOBAL_ASM must be built with the asm_processor
|
||||
ifeq ($(MATCHING), 1)
|
||||
GLOBALASM_C_FILES != grep -rl 'GLOBAL_ASM(' $(C_FILES)
|
||||
GLOBALASM_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(GLOBALASM_C_FILES))
|
||||
$(GLOBALASM_O_FILES): CC := /usr/bin/env python3 tools/asm_processor/build.py $(CC) -- $(TOOLCHAIN)-as $(ASFLAGS) --
|
||||
endif
|
||||
else ifeq ($(COMPILER), gcc)
|
||||
CC := $(TOOLCHAIN)-gcc
|
||||
|
||||
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
|
||||
|
||||
CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) \
|
||||
-EB \
|
||||
-march=vr4300 \
|
||||
-mabi=32 \
|
||||
-mfix4300 \
|
||||
-mdivide-breaks \
|
||||
-mno-abicalls \
|
||||
-ffreestanding \
|
||||
-fno-builtin \
|
||||
-fno-common \
|
||||
-fno-inline-functions \
|
||||
-fno-merge-constants \
|
||||
-fno-strict-aliasing \
|
||||
-fno-zero-initialized-in-bss \
|
||||
-funsigned-char \
|
||||
-fwrapv \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-address \
|
||||
-Wno-aggressive-loop-optimizations \
|
||||
-Wno-array-bounds \
|
||||
-Wno-int-in-bool-context \
|
||||
-Wno-int-to-pointer-cast \
|
||||
-Wno-maybe-uninitialized \
|
||||
-Wno-misleading-indentation \
|
||||
-Wno-missing-braces \
|
||||
-Wno-multichar \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-pointer-to-int-cast \
|
||||
-Wno-tautological-compare \
|
||||
-Wno-uninitialized \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-unused-value \
|
||||
-Wno-unused-variable \
|
||||
-G 0
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/xldtob.o: CFLAGS += -ffast-math -fno-unsafe-math-optimizations
|
||||
else
|
||||
$(error The COMPILER option must be "ido" or "gcc")
|
||||
endif
|
||||
|
||||
# Make ROMID available as an environment variable to all tooling.
|
||||
# (We use this a lot)
|
||||
export ROMID
|
||||
|
||||
default: rom
|
||||
|
||||
################################################################################
|
||||
# Recomp
|
||||
# ------------------------------------------------------------------------------
|
||||
# The ido-static-recomp project is installed as a git submodule at tools/recomp.
|
||||
# The IRIX binaries are taken from that project and they are recompiled to
|
||||
# build/recomp/<version>/
|
||||
|
||||
tools/recomp/recomp.cpp:
|
||||
@echo "Please install ido-static-recomp by running:"
|
||||
@echo
|
||||
@echo " git submodule update --init --recursive"
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
build/recomp/recomp: tools/recomp/recomp.cpp
|
||||
@mkdir -p build/recomp/5.3
|
||||
@mkdir -p build/recomp/7.1
|
||||
g++ tools/recomp/recomp.cpp -o build/recomp/recomp -g -lcapstone
|
||||
|
||||
build/recomp/5.3/ugen:
|
||||
@mkdir -p build/recomp/5.3
|
||||
g++ tools/recomp/recomp.cpp -o build/recomp/recomp-ugen53 -g -lcapstone -Dugen53
|
||||
./build/recomp/recomp-ugen53 tools/recomp/ido/5.3/usr/lib/ugen > build/recomp/5.3/ugen.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/ugen.c -Itools/recomp -o build/recomp/5.3/ugen -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/5.3/cc: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/5.3/usr/bin/cc > build/recomp/5.3/cc.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/cc.c -Itools/recomp -o build/recomp/5.3/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/5.3/%: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/5.3/usr/lib/$* > build/recomp/5.3/$*.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/$*.c -Itools/recomp -o build/recomp/5.3/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/7.1/cc: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/7.1/usr/bin/cc > build/recomp/7.1/cc.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/7.1/cc.c -Itools/recomp -o build/recomp/7.1/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
|
||||
|
||||
build/recomp/7.1/%: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/7.1/usr/lib/$* > build/recomp/7.1/$*.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/7.1/$*.c -Itools/recomp -o build/recomp/7.1/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
|
||||
|
||||
build/recomp/%/err.english.cc:
|
||||
@mkdir -p build/recomp/$?
|
||||
cp tools/err.english.cc build/recomp/$*
|
||||
|
||||
################################################################################
|
||||
# ROM Finalisation Stages
|
||||
|
||||
# Link all objects together with ld to make stage1.elf. In this stage, the game,
|
||||
# lib and data segments are uncompressed and placed past the end of the ROM.
|
||||
$(B_DIR)/stage1.elf: $(O_FILES) ld/pd.ld
|
||||
cpp -DROMID=$(ROMID) -DVERSION=$(VERSION) -DROMALLOCATION_DATA=$(ROMALLOCATION_DATA) -DROMALLOCATION_LIB=$(ROMALLOCATION_LIB) -DROMALLOCATION_GAME=$(ROMALLOCATION_GAME) -DROM_SIZE=$(ROM_SIZE) -P ld/pd.ld -o $(B_DIR)/pd.ld
|
||||
$(TOOLCHAIN)-ld --no-check-sections -z muldefs -T $(B_DIR)/pd.ld --print-map -o $@ > $(B_DIR)/pd.map
|
||||
|
||||
$(B_DIR)/stage1.bin: $(B_DIR)/stage1.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
# Build the final ROM from stage1.bin using mkrom
|
||||
# mkrom handles calculating the piracy checksums, zipping segments and
|
||||
# calculating the ROM checksum.
|
||||
$(B_DIR)/pd.z64: $(B_DIR)/stage1.bin tools/mkrom/mkrom
|
||||
tools/mkrom/mkrom $(B_DIR)/stage1.bin $(B_DIR)/pd.map $(PIRACYCHECKS) $(ZIPMAGIC) $(COPYLEN) $@
|
||||
@echo -e "\033[0;32mROM written to $@\033[0m"
|
||||
|
||||
tools/mkrom/mkrom:
|
||||
$(MAKE) -C tools/mkrom
|
||||
|
||||
################################################################################
|
||||
# Testing Related
|
||||
# ---------------------
|
||||
# This works a little backwards, in that the ROM has to be built to at least
|
||||
# stage 2, then extract-segment is used to slice out the segments.
|
||||
|
||||
CHECK_FILES := $(shell awk '{print $$2}' checksums.$(ROMID).md5)
|
||||
|
||||
test: $(CHECK_FILES)
|
||||
@md5sum --quiet -c checksums.$(ROMID).md5
|
||||
|
||||
$(B_DIR)/segments/%.bin: $(B_DIR)/pd.z64
|
||||
@B_DIR=$(B_DIR) tools/extract-segment $*
|
||||
|
||||
################################################################################
|
||||
# Raw data segments
|
||||
|
||||
$(B_DIR)/assets/fonts/%.o: $(A_DIR)/fonts/%.bin
|
||||
mkdir -p $(B_DIR)/assets/fonts
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/getitle.o: $(E_DIR)/getitle.bin
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/seq.ctl.o: $(A_DIR)/seq.ctl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/seq.tbl.o: $(A_DIR)/seq.tbl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/sfx.ctl.o: $(A_DIR)/sfx.ctl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/sfx.tbl.o: $(A_DIR)/sfx.tbl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
################################################################################
|
||||
# Asset Manager
|
||||
|
||||
ASSETMGR_O_FILES := \
|
||||
$(B_DIR)/assets/animations.o \
|
||||
$(LANG_O_FILES) \
|
||||
$(PADS_O_FILES) \
|
||||
$(TILES_O_FILES) \
|
||||
$(B_DIR)/assets/sequences.o \
|
||||
$(B_DIR)/assets/textureslist.o \
|
||||
|
||||
# Anims
|
||||
$(B_DIR)/assets/animations.o: $(A_DIR)/animations.json
|
||||
tools/assetmgr/mkanims
|
||||
|
||||
# Lang
|
||||
$(B_DIR)/assets/files/L%E.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< en
|
||||
|
||||
$(B_DIR)/assets/files/L%J.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< jp
|
||||
|
||||
$(B_DIR)/assets/files/L%P.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< gb
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_f.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< fr
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_g.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< de
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_i.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< it
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_s.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< es
|
||||
|
||||
# Pads
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_padsZ.o: $(A_DIR)/pads/%.json
|
||||
tools/assetmgr/mkpads $<
|
||||
|
||||
# Pads - but this is the zipped non-obj, for make test
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_padsZ: $(A_DIR)/pads/%.json
|
||||
tools/assetmgr/mkpads $<
|
||||
|
||||
# Sequences
|
||||
$(B_DIR)/assets/sequences.o: $(A_DIR)/sequences.json
|
||||
tools/assetmgr/mksequences
|
||||
|
||||
# Textures
|
||||
$(B_DIR)/assets/textureslist.o: $(A_DIR)/textures.json
|
||||
tools/assetmgr/mktextures
|
||||
|
||||
# Tiles
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o: $(A_DIR)/tiles/%.json
|
||||
tools/assetmgr/mktiles $<
|
||||
|
||||
# Tiles - but this is the zipped non-obj, for make test
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ: $(A_DIR)/tiles/%.json
|
||||
tools/assetmgr/mktiles $<
|
||||
|
||||
################################################################################
|
||||
# Files
|
||||
|
||||
# Audio
|
||||
$(B_DIR)/assets/files/A%M: $(A_DIR)/files/audio/%.mp3
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
cp $< $@
|
||||
|
||||
# BG segs
|
||||
$(B_DIR)/assets/files/bgdata/bg_%.seg: $(A_DIR)/files/bgdata/bg_%.seg
|
||||
@mkdir -p $(B_DIR)/assets/files/bgdata
|
||||
cp $< $@
|
||||
|
||||
# Chrs
|
||||
$(B_DIR)/assets/files/C%Z: $(A_DIR)/files/chrs/%.bin
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# Guns
|
||||
$(B_DIR)/assets/files/G%Z: $(A_DIR)/files/guns/%.bin
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# OB seg
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg.o: $(B_DIR)/assets/files/ob/ob_mid.seg
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg:
|
||||
@mkdir -p $(B_DIR)/assets/files/ob
|
||||
> $@
|
||||
|
||||
# Props
|
||||
$(B_DIR)/assets/files/P%Z: $(A_DIR)/files/props/%.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# Stage setups
|
||||
# $(A_DIR)/files/setup/foo.c
|
||||
# -> B_DIR/assets/files/setup/foo.o (done here)
|
||||
# -> B_DIR/assets/files/setup/foo.elf (done here)
|
||||
# -> B_DIR/assets/files/setup/foo.bin (done here)
|
||||
# -> B_DIR/assets/files/UsetupfooZ (done here)
|
||||
# -> B_DIR/assets/files/UsetupfooZ.o (done elsewhere)
|
||||
$(B_DIR)/assets/files/setup/%.o: src/setups/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(B_DIR)/assets/files/setup/%.elf: $(B_DIR)/assets/files/setup/%.o
|
||||
TOOLCHAIN=$(TOOLCHAIN) tools/mksimpleelf $< $@
|
||||
|
||||
$(B_DIR)/files/setup/%.bin: $(B_DIR)/assets/files/setup/%.elf
|
||||
@mkdir -p $(dir $@)
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
$(B_DIR)/assets/files/U%Z: $(B_DIR)/files/setup/%.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# General target to convert any finalised file into a raw object for ld
|
||||
$(B_DIR)/assets/files/%.o: $(B_DIR)/assets/files/%
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/files/%.bin: $(B_DIR)/assets/files/%.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
################################################################################
|
||||
# Miscellaneous
|
||||
|
||||
$(B_DIR)/bootloader.o: $(E_DIR)/bootloader.bin
|
||||
@mkdir -p $(dir $@)
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/romheader.o: src/romheader/romheader.s
|
||||
$(TOOLCHAIN)-as --defsym VERSION=$(VERSION) -march=vr4300 -mabi=32 -I src/include -EB -o $@ $<
|
||||
|
||||
$(B_DIR)/assets/accessingpakZ: $(A_DIR)/accessingpak.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
$(B_DIR)/assets/copyrightZ: $(A_DIR)/copyright.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
$(B_DIR)/assets/accessingpakZ.o: $(B_DIR)/assets/accessingpakZ
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/copyrightZ.o: $(B_DIR)/assets/copyrightZ
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/rsp/%.text.bin $(B_DIR)/rsp/%.data.bin: src/rsp/%.s
|
||||
@mkdir -p $(dir $@)
|
||||
armips -strequ CODE_FILE $(B_DIR)/rsp/$*.text.bin -strequ DATA_FILE $(B_DIR)/rsp/$*.data.bin $<
|
||||
|
||||
$(B_DIR)/rsp/%.o: $(B_DIR)/rsp/%.bin
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
ifeq ($(COMPILER), ido)
|
||||
$(B_DIR)/lib/rng_c.o: src/lib/rng_c.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
tools/patchmips3 $@ || rm $@
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/llcvt.o: src/lib/ultra/libc/llcvt.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
tools/patchmips3 $@ || rm $@
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/ll.o: src/lib/ultra/libc/ll.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) $< -o $@
|
||||
tools/patchmips3 $@ || rm $@
|
||||
endif
|
||||
|
||||
$(B_DIR)/%.o: src/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
|
||||
$(B_DIR)/%.o: src/%.s
|
||||
@mkdir -p $(dir $@)
|
||||
cpp -P -Wno-trigraphs -I include -I include/PR -I src/include $(C_DEFINES) -D_LANGUAGE_ASSEMBLY -D_MIPSEB $< | $(AS) $(ASFLAGS) -o $@
|
||||
|
||||
$(B_DIR)/assets/%.o: $(A_DIR)/%.c $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
extract:
|
||||
ROMID=$(ROMID) tools/extract
|
||||
|
||||
rom: $(B_DIR)/pd.z64
|
||||
|
||||
clean:
|
||||
rm -rf build/$(ROMID) src/generated/$(ROMID)
|
||||
|
||||
allclean:
|
||||
rm -rf build/* src/generated
|
||||
|
||||
codeclean:
|
||||
find $(B_DIR)/game $(B_DIR)/inflate $(B_DIR)/lib -name '*.o' -delete
|
||||
@@ -1,62 +1,214 @@
|
||||
# Perfect Dark Decompilation
|
||||
# Perfect Dark port
|
||||
|
||||
This repository contains a complete decompilation of Perfect Dark for the Nintendo 64.
|
||||
This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms.
|
||||
|
||||
The project aims to be a matching decompilation. When a matching decompilation is compiled with the same compiler that the original developers used, the output will be exactly the same as the retail game, byte for byte.
|
||||
|
||||
To build the project, you must already have a Perfect Dark ROM. The project can build the exact same ROM from decomp's source code combined with assets that it extracts from your base ROM.
|
||||
To run the port, you must already have a Perfect Dark ROM, specifically one of the following:
|
||||
* `ntsc-final`/`US V1.1`/`US Rev 1` (md5 `e03b088b6ac9e0080440efed07c1e40f`).
|
||||
**This is the recommended version to use**.
|
||||
Called `NTSC version 8.7 final` on the boot screen.
|
||||
* `ntsc-1.0`/`US V1.0` (md5 `7f4171b0c8d17815be37913f535e4e93`).
|
||||
Technically supported, but not recommended.
|
||||
Called `NTSC version 8.7 final` on the boot screen as well.
|
||||
* `jpn-final` (md5 `538d2b75945eae069b29c46193e74790`).
|
||||
Technically supported, but requires a separate custom-built executable.
|
||||
Called `JPN version 8.9 final` on the boot screen.
|
||||
* `pal-final` (md5 `d9b5cd305d228424891ce38e71bc9213`).
|
||||
Technically supported, but requires a separate custom-built executable.
|
||||
Called `PAL 8.7 final` on the boot screen.
|
||||
|
||||
## Status
|
||||
|
||||
See the [Perfect Dark Decompilation Status Page](https://ryandwyer.gitlab.io/pdstatus/).
|
||||
The game is in a mostly functional state, with both singleplayer and split-screen multiplayer modes fully working.
|
||||
There are minor graphics- and gameplay-related issues, and possibly occasional crashes.
|
||||
|
||||
All versions of the game are fully decompiled but a small handful of functions are not yet byte-matching even though they are functionally the same. The status page doesn't show these as 100% because it counts matching functions only.
|
||||
**The following extra features are implemented:**
|
||||
* mouselook;
|
||||
* dual analog controller support;
|
||||
* widescreen resolution support;
|
||||
* configurable field of view;
|
||||
* 60 FPS support, including fixes for some framerate-related issues;
|
||||
* fixes for a couple original bugs and crashes;
|
||||
* basic mod support, currently enough to load a few custom levels;
|
||||
* slightly expanded memory heap size;
|
||||
* experimental high framerate support (up to 240 FPS):
|
||||
* enable `Uncap Tickrate` in `Extended Video Options` to activate;
|
||||
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
|
||||
* emulate the Transfer Pak functionality the game has on the Nintendo 64 to unlock some cheats automatically.
|
||||
|
||||
## Installation Requirements
|
||||
**The following platforms are officially supported and tested:**
|
||||
* Windows 7+: i686, x86_64
|
||||
* Linux: i686, x86_64
|
||||
* MacOS: x86_64 (OS 10.9+), arm64 (OS 11.0+)
|
||||
* Nintendo Switch: arm64
|
||||
|
||||
For Arch Linux:
|
||||
## Download
|
||||
|
||||
* Install these packages: `binutils fakeroot gcc make python vim`
|
||||
* Install from AUR: `armips`
|
||||
* Install from AUR: a MIPS binutils package of your choice (eg. `mips-elf-binutils`)
|
||||
* Install from AUR: a MIPS gcc package of your choice (eg. `mips-elf-gcc`)
|
||||
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/releases/tag/ci-dev-build) for supported platforms:
|
||||
* [x86_64-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-windows.zip)
|
||||
* [i686-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-windows.zip)
|
||||
* [x86_64-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-linux.tar.gz)
|
||||
* [i686-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-linux.tar.gz)
|
||||
* [arm64-nswitch](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-arm64-nswitch.zip)
|
||||
|
||||
For Debian and Ubuntu:
|
||||
If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
|
||||
|
||||
* Install these packages: `binutils-mips-linux-gnu build-essential gcc-mips-linux-gnu libc6-dev-i386 libcapstone-dev make`
|
||||
* Compile and install `armips`
|
||||
## Running
|
||||
|
||||
## ROM Versions
|
||||
You must already have a Perfect Dark ROM to run the game, as specified above.
|
||||
|
||||
Perfect Dark has six known versions:
|
||||
This assumes that you're using an x86_64 build. If you aren't, replace `x86_64` below with your arch (e.g. `i686`).
|
||||
|
||||
| ROM ID | Description | MD5 Checksum |
|
||||
|------------|---------------------------------------------|----------------------------------|
|
||||
| ntsc-beta | NTSC 6.4 beta | aa93f4df16fceada399a749f5ad2f273 |
|
||||
| ntsc-1.0 | NTSC 8.7 final (the initial, buggy release) | 7f4171b0c8d17815be37913f535e4e93 |
|
||||
| ntsc-final | NTSC 8.7 final | e03b088b6ac9e0080440efed07c1e40f |
|
||||
| pal-beta | PAL 28.7 beta | ad2de210a3455ba5ec541f0c78d91444 |
|
||||
| pal-final | PAL 8.7 final | d9b5cd305d228424891ce38e71bc9213 |
|
||||
| jpn-final | JPN 8.9 final | 538d2b75945eae069b29c46193e74790 |
|
||||
1. Create a directory named `data` next to `pd.x86_64` if it's not there.
|
||||
2. Put your Perfect Dark NTSC ROM named `pd.ntsc-final.z64` into it.
|
||||
3. Run the `pd.x86_64` executable.
|
||||
|
||||
The project uses the `$ROMID` environment variable to know which version to work with. If not set, it defaults to `ntsc-final`. You can change it by running something like `export ROMID=ntsc-1.0`.
|
||||
If you want to use a PAL or JPN ROM instead, put them into the `data` directory and run the appropriate executable:
|
||||
* PAL: ROM name `pd.pal-final.z64`, executable name `pd.pal.x86_64`.
|
||||
* JPN: ROM name `pd.jpn-final.z64`, executable name `pd.jpn.x86_64`.
|
||||
|
||||
## Extracting the base ROM
|
||||
Optionally, you can also put your Perfect Dark for GameBoy Color ROM named `pd.gbc` in the `data` directory if you want to emulate having the Nintendo 64's Transfer Pak and unlock some cheats automatically.
|
||||
|
||||
1. Save your existing ROM file into the root of the repository with the name `pd.ntsc-final.z64`. It should not be byteswapped (the first four bytes should be `0x80371240`).
|
||||
2. Run `make extract`.
|
||||
Optionally, you can move the data folder to `~/.local/share/perfectdark` on Linux or `~/Library/Application Support/perfectdark` on MacOS.
|
||||
|
||||
This will extract assets to `src/assets`. If any asset already exists then it will not be overwritten. This means you can modify assets as desired, and your changes will not be overwritten if you run the extract command again.
|
||||
Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).
|
||||
|
||||
The extract command will also create an `extracted/ntsc-final` directory. This directory contains some compiled code segments from the ROM and is only used for comparison purposes.
|
||||
A GPU supporting OpenGL 3.0/ES3.0 or above is required to run the port.
|
||||
|
||||
## Compiling
|
||||
### Installing the Nintendo Switch version
|
||||
|
||||
* Run `git submodule update --init --recursive`. You only have to do this once.
|
||||
* Run `make -j` to build the ROM. The ROM will be written to `build/ntsc-final/pd.z64`.
|
||||
The Nintendo Switch build ZIP comes with all 3 regions in different folders: `perfectdark`, `perfectdark_pal` and `perfectdark_jpn`.
|
||||
|
||||
## How do I know the built files are matching?
|
||||
Take the folder for the region you want and put it into the `/switch` folder on your SD card, then put your ROM into the `data` folder inside of the folder you extracted as described above.
|
||||
|
||||
Run `make` followed by `make test`. If `make test` produces no output then the compiled project is matching.
|
||||
## Controls
|
||||
|
||||
You can also md5sum your base ROM with the built ROM and check they have the same hash: `md5sum pd.ntsc-final.z64 build/ntsc-final/pd.z64`.
|
||||
1964GEPD-style and Xbox-style bindings are implemented.
|
||||
|
||||
N64 pad buttons X and Y (or `X_BUTTON`, `Y_BUTTON` in the code) refer to the reserved buttons `0x40` and `0x80`, which are also leveraged by 1964GEPD.
|
||||
|
||||
Support for one controller, two-stick configurations are enabled for 1.2.
|
||||
|
||||
Note that the mouse only controls player 1.
|
||||
|
||||
Controls can be rebound in `pd.ini`. Default control scheme is as follows:
|
||||
|
||||
| Action | Keyboard and mouse | Xbox pad | N64 pad |
|
||||
| - | - | - | - |
|
||||
| Fire / Accept | LMB/Space | RT | Z Trigger |
|
||||
| Aim mode | RMB/Z | LT | R Trigger |
|
||||
| Use / Cancel | E | N/A | B |
|
||||
| Use / Accept | N/A | A | A |
|
||||
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) |
|
||||
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
|
||||
| Full-Crouch | Control | N/A | `0x20000000` (Extra) |
|
||||
| Reload | R | X | X `(0x40)` |
|
||||
| Previous weapon | Mousewheel forward | B | D-Left |
|
||||
| Next weapon | Mousewheel back | Y | Y `(0x80)` |
|
||||
| Radial menu | Q | LB | D-Down |
|
||||
| Alt fire mode | F | RB | L Trigger |
|
||||
| Alt-fire oneshot | `F + LMB` or `E + LMB` | `A + RT` or `RB + RT` | `A + Z` or `L + Z` |
|
||||
| Quick-detonate | `E + Q` or `E + R` | `A + B` or `A + X` | `A + D-Left`or `A + X` |
|
||||
|
||||
## Building
|
||||
|
||||
### Windows
|
||||
|
||||
1. Install [MSYS2](https://www.msys2.org).
|
||||
2. Open the `MINGW64` prompt if building for x86_64, or the `MINGW32` prompt if building for i686. (**NOTE:** _do not_ use the `MSYS` prompt)
|
||||
3. Install dependencies:
|
||||
`pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-SDL2 mingw-w64-x86_64-zlib mingw-w64-x86_64-cmake mingw-w64-x86_64-python3 mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-cmake mingw-w64-i686-python3 make git`
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Run `cmake -G"Unix Makefiles" -Bbuild .`.
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.\
|
||||
6. Run `cmake --build build -j4 -- -O`.
|
||||
7. The resulting executable will be at `build/pd.x86_64.exe` (or at `build/pd.i686.exe` if building for i686).
|
||||
8. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory.
|
||||
|
||||
### Linux
|
||||
|
||||
1. Ensure you have gcc, g++ (version 10.0+), make, cmake, git, python3 and SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
|
||||
* If you wish to crosscompile, you will also need to have libraries and compilers for the target platform installed, e.g. `gcc-multilib` and `g++-multilib` for x86_64 -> i686 crosscompilation.
|
||||
2. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
3. Run the following command:
|
||||
* ```cmake -G"Unix Makefiles" -Bbuild .```
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
* Add ` -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32` at the end of the command if you want to crosscompile from x86_64 to x86.
|
||||
4. Run `cmake --build build -j4`.
|
||||
5. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
|
||||
|
||||
### MacOS
|
||||
|
||||
1. Set up Homebrew.
|
||||
2. Install dependencies:
|
||||
* Execute command: `brew install cmake gcc python3 zlib git`
|
||||
3. Install SDL2:
|
||||
* Execute commands:
|
||||
```
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
hdiutil detach /Volumes/SDL2
|
||||
```
|
||||
* This installs SDL2 system-wide and this is how the automatic builds are done. The game will also look for it in the executable path, so you could
|
||||
download it locally instead.
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Configure:
|
||||
* Execute command: `cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .`
|
||||
* Replace `x86_64` with `arm64` if building for an ARM64 Mac.
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
6. Build:
|
||||
* Execute command: `cmake --build build --target pd -j4 --clean-first`
|
||||
7. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
|
||||
* You might need to execute `chmod +x build/pd.x86-64` before you can run it.
|
||||
|
||||
### Nintendo Switch
|
||||
|
||||
1. Set up the [devkitA64 environment](https://devkitpro.org/wiki/Getting_Started).
|
||||
* On Windows you can do it under MSYS2 or WSL, usually MSYS2 is recommended.
|
||||
* If using MSYS2, make sure to use the **MSYS2** shell, **not** MINGW32 or MINGW64.
|
||||
2. Install host dependencies:
|
||||
* On MSYS2: execute command `pacman -Syuu && pacman -S git make cmake python3`
|
||||
* On Linux: use your package manager as normal to install the above dependencies.
|
||||
3. Install Switch toolchain and dependencies:
|
||||
* Execute commands:
|
||||
```
|
||||
dkp-pacman -Syuu
|
||||
dkp-pacman -S devkitA64 libnx switch-zlib switch-sdl2 switch-cmake dkp-toolchain-vars
|
||||
```
|
||||
* If in MSYS2 or `dkp-pacman` doesn't work, replace it with just `pacman`.
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Ensure devkitA64 environment variables are set:
|
||||
* Execute command: `source /opt/devkitpro/switchvars.sh`
|
||||
* If your `$DEVKITPRO` path is different, substitute that instead or set the variables manually.
|
||||
6. Configure:
|
||||
* Execute command: `aarch64-none-elf-cmake -G"Unix Makefiles" -Bbuild .`
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
7. Build:
|
||||
* Execute command: `make -C build -j4`
|
||||
8. The resulting executable will be at `build/pd.arm64.nro`.
|
||||
|
||||
### Notes
|
||||
|
||||
Alternate compilers or toolchains can be specified by passing `-DCMAKE_TOOLCHAIN_FILE=whatever` as normal. The port does not build with Visual Studio.
|
||||
|
||||
You will need to provide a `jpn-final` or `pal-final` ROM to run executables built for those regions, named `pd.jpn-final.z64` or `pd.pal-final.z64`.
|
||||
|
||||
It might be possible to build and run the game on platforms that are not specified in the supported platforms list (e.g. Linux on armv7), but this has not been tested.
|
||||
|
||||
## Credits
|
||||
|
||||
* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
|
||||
* Ryan Dwyer for the above, additional help, and `pd-extract`;
|
||||
* doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find;
|
||||
* [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes;
|
||||
* [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D), Emill and MaikelChan for the libultraship version of fast3d that this port uses;
|
||||
* lieff for [minimp3](https://github.com/lieff/minimp3);
|
||||
* Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes;
|
||||
* Raf for the 64-bit port;
|
||||
* NicNamSam for the icon;
|
||||
* everyone who has submitted pull requests and issues to this repository and tested the port;
|
||||
* probably more I'm forgetting.
|
||||
@@ -0,0 +1,27 @@
|
||||
# execute a header generator (execcmd) for every json file in jsonpath, collect headers in headerlist
|
||||
# note that this reads ROMID
|
||||
macro(generate_asset_headers jsonpath execcmd extraarg headerlist)
|
||||
set(TMP_JSON "")
|
||||
|
||||
if (${jsonpath} MATCHES "\.json")
|
||||
# is a json file
|
||||
list(APPEND TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}")
|
||||
else()
|
||||
# is a directory
|
||||
file(GLOB TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}*.json")
|
||||
endif()
|
||||
|
||||
foreach(JSON ${TMP_JSON})
|
||||
unset(HEADERNAME)
|
||||
string(REPLACE ".json" ".h" HEADERNAME ${JSON})
|
||||
string(REPLACE "${CMAKE_SOURCE_DIR}/${ASSET_DIR}" "${CMAKE_BINARY_DIR}/${GENERATED_DIR}" HEADERNAME ${HEADERNAME})
|
||||
add_custom_command(
|
||||
OUTPUT ${HEADERNAME}
|
||||
DEPENDS ${JSON}
|
||||
COMMAND ${execcmd} ${JSON} ${extraarg} --headers-only --romid=${ROMID}
|
||||
)
|
||||
list(APPEND ${headerlist} "${HEADERNAME}")
|
||||
endforeach()
|
||||
|
||||
unset(TMP_JSON)
|
||||
endmacro()
|
||||
@@ -0,0 +1,172 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
# Locate SDL2 library
|
||||
# This module defines
|
||||
# SDL2_LIBRARY, the name of the library to link against
|
||||
# SDL2_FOUND, if false, do not try to link to SDL2
|
||||
# SDL2_INCLUDE_DIR, where to find SDL.h
|
||||
#
|
||||
# This module responds to the the flag:
|
||||
# SDL2_BUILDING_LIBRARY
|
||||
# If this is defined, then no SDL2_main will be linked in because
|
||||
# only applications need main().
|
||||
# Otherwise, it is assumed you are building an application and this
|
||||
# module will attempt to locate and set the the proper link flags
|
||||
# as part of the returned SDL2_LIBRARY variable.
|
||||
#
|
||||
# Don't forget to include SDL2main.h and SDL2main.m your project for the
|
||||
# OS X framework based version. (Other versions link to -lSDL2main which
|
||||
# this module will try to find on your behalf.) Also for OS X, this
|
||||
# module will automatically add the -framework Cocoa on your behalf.
|
||||
#
|
||||
#
|
||||
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
|
||||
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
|
||||
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
|
||||
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
|
||||
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
|
||||
# as appropriate. These values are used to generate the final SDL2_LIBRARY
|
||||
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
|
||||
#
|
||||
#
|
||||
# $SDL2DIR is an environment variable that would
|
||||
# correspond to the ./configure --prefix=$SDL2DIR
|
||||
# used in building SDL2.
|
||||
# l.e.galup 9-20-02
|
||||
#
|
||||
# Modified by Eric Wing.
|
||||
# Added code to assist with automated building by using environmental variables
|
||||
# and providing a more controlled/consistent search behavior.
|
||||
# Added new modifications to recognize OS X frameworks and
|
||||
# additional Unix paths (FreeBSD, etc).
|
||||
# Also corrected the header search path to follow "proper" SDL2 guidelines.
|
||||
# Added a search for SDL2main which is needed by some platforms.
|
||||
# Added a search for threads which is needed by some platforms.
|
||||
# Added needed compile switches for MinGW.
|
||||
#
|
||||
# On OSX, this will prefer the Framework version (if found) over others.
|
||||
# People will have to manually change the cache values of
|
||||
# SDL2_LIBRARY to override this selection or set the CMake environment
|
||||
# CMAKE_INCLUDE_PATH to modify the search paths.
|
||||
#
|
||||
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
|
||||
# This needed to change because "proper" SDL2 convention
|
||||
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
|
||||
# reasons because not all systems place things in SDL2/ (see FreeBSD).
|
||||
#
|
||||
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
|
||||
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
|
||||
# was not created for redistribution, and exists temporarily pending official
|
||||
# SDL2 CMake modules.
|
||||
|
||||
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES include/SDL2 include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/include/SDL2
|
||||
/usr/include/SDL2
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
/boot/system/develop/headers/SDL2 #Hiaku OS
|
||||
)
|
||||
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
|
||||
|
||||
FIND_LIBRARY(SDL2_LIBRARY_TEMP
|
||||
NAMES SDL2
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
/system/lib #Hiaku OS
|
||||
)
|
||||
|
||||
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
|
||||
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
# Non-OS X framework versions expect you to also dynamically link to
|
||||
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||
# seem to provide SDL2main for compatibility even though they don't
|
||||
# necessarily need it.
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# SDL2 may require threads on your system.
|
||||
# The Apple build may not need an explicit flag because one of the
|
||||
# frameworks may already provide it.
|
||||
# But for non-OSX systems, I will use the CMake Threads package.
|
||||
IF(NOT APPLE)
|
||||
FIND_PACKAGE(Threads)
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# MinGW needs an additional library, mwindows
|
||||
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
|
||||
# (Actually on second look, I think it only needs one of the m* libraries.)
|
||||
IF(MINGW)
|
||||
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
|
||||
ENDIF(MINGW)
|
||||
|
||||
SET(SDL2_FOUND "NO")
|
||||
IF(SDL2_LIBRARY_TEMP)
|
||||
# For SDL2main
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(SDL2MAIN_LIBRARY)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(SDL2MAIN_LIBRARY)
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||
# though it actually is there if I modify a pre-used variable.
|
||||
# I think it has something to do with the CACHE STRING.
|
||||
# So I use a temporary variable until the end so I can set the
|
||||
# "real" variable in one-shot.
|
||||
IF(APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
|
||||
ENDIF(APPLE)
|
||||
|
||||
# For threads, as mentioned Apple doesn't need this.
|
||||
# In fact, there seems to be a problem if I used the Threads package
|
||||
# and try using this line, so I'm just skipping it entirely for OS X.
|
||||
IF(NOT APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# For MinGW library
|
||||
IF(MINGW)
|
||||
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(MINGW)
|
||||
|
||||
# Set the final string here so the GUI reflects the final state.
|
||||
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
|
||||
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
|
||||
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
|
||||
|
||||
SET(SDL2_FOUND "YES")
|
||||
ENDIF(SDL2_LIBRARY_TEMP)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
|
||||
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
|
||||
# Based on the Qt 5 processor detection code, so should be very accurate
|
||||
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
|
||||
|
||||
# Regarding POWER/PowerPC, just as is noted in the Qt source,
|
||||
# "There are many more known variants/revisions that we do not handle/detect."
|
||||
|
||||
set(archdetect_c_code "
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM64) || defined (__aarch64__)
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
|
||||
#error cmake_ARCH armv7
|
||||
#elif defined(__ARM_ARCH_6__) \\
|
||||
|| defined(__ARM_ARCH_6J__) \\
|
||||
|| defined(__ARM_ARCH_6T2__) \\
|
||||
|| defined(__ARM_ARCH_6Z__) \\
|
||||
|| defined(__ARM_ARCH_6K__) \\
|
||||
|| defined(__ARM_ARCH_6ZK__) \\
|
||||
|| defined(__ARM_ARCH_6M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
|
||||
#error cmake_ARCH armv6
|
||||
#elif defined(__ARM_ARCH_5TEJ__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
|
||||
#error cmake_ARCH armv5
|
||||
#elif defined(_M_ARM64) || defined (__aarch64__)
|
||||
#error cmake_ARCH arm64
|
||||
#else
|
||||
#error cmake_ARCH arm
|
||||
#endif
|
||||
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#error cmake_ARCH i386
|
||||
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||
#error cmake_ARCH x86_64
|
||||
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||
#error cmake_ARCH ia64
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||
#error cmake_ARCH ppc64
|
||||
#else
|
||||
#error cmake_ARCH ppc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#error cmake_ARCH unknown
|
||||
")
|
||||
|
||||
# Set ppc_support to TRUE before including this file or ppc and ppc64
|
||||
# will be treated as invalid architectures since they are no longer supported by Apple
|
||||
|
||||
function(target_architecture output_var)
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
|
||||
# First let's normalize the order of the values
|
||||
|
||||
# Note that it's not possible to compile PowerPC applications if you are using
|
||||
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
|
||||
# disable it by default
|
||||
# See this page for more information:
|
||||
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
|
||||
|
||||
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
|
||||
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
set(osx_arch_ppc TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "i386")
|
||||
set(osx_arch_i386 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "x86_64")
|
||||
set(osx_arch_x86_64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "arm64")
|
||||
set(osx_arch_arm64 TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Now add all the architectures in our normalized order
|
||||
if(osx_arch_ppc)
|
||||
list(APPEND ARCH ppc)
|
||||
endif()
|
||||
|
||||
if(osx_arch_i386)
|
||||
list(APPEND ARCH i386)
|
||||
endif()
|
||||
|
||||
if(osx_arch_x86_64)
|
||||
list(APPEND ARCH x86_64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_arm64)
|
||||
list(APPEND ARCH arm64)
|
||||
endif()
|
||||
else()
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
|
||||
|
||||
enable_language(C)
|
||||
|
||||
# Detect the architecture in a rather creative way...
|
||||
# This compiles a small C program which is a series of ifdefs that selects a
|
||||
# particular #error preprocessor directive whose message string contains the
|
||||
# target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of the
|
||||
# #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# way, we can detect the correct target architecture even when cross-compiling,
|
||||
# since the program itself never needs to be run (only the compiler/preprocessor)
|
||||
try_run(
|
||||
run_result_unused
|
||||
compile_result_unused
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}/arch.c"
|
||||
COMPILE_OUTPUT_VARIABLE ARCH
|
||||
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
|
||||
)
|
||||
|
||||
# Parse the architecture name from the compiler output
|
||||
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
|
||||
|
||||
# Get rid of the value marker leaving just the architecture name
|
||||
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
|
||||
|
||||
# If we are compiling with an unknown architecture this variable should
|
||||
# already be set to "unknown" but in the case that it's empty (i.e. due
|
||||
# to a typo in the code), then set it to unknown
|
||||
if (NOT ARCH)
|
||||
set(ARCH unknown)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${output_var} "${ARCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Name=Perfect Dark
|
||||
Comment=Modern source port of Perfect Dark
|
||||
Exec=io.github.fgsfdsfgs.perfect_dark.sh
|
||||
Icon=io.github.fgsfdsfgs.perfect_dark
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Game;ActionGame;
|
||||
StartupNotify=false
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>io.github.fgsfdsfgs.perfect_dark</id>
|
||||
<name>Perfect Dark</name>
|
||||
<developer id="io.github.fgsfdsfgs.perfect_dark">
|
||||
<name>Perfect Dark Contributors</name>
|
||||
<url>https://github.com/fgsfdsfgs/perfect_dark/graphs/contributors</url>
|
||||
</developer>
|
||||
<launchable type="desktop-id">io.github.fgsfdsfgs.perfect_dark.desktop</launchable>
|
||||
<summary>Modern cross-platform port of Perfect Dark</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
<url type="homepage">https://github.com/fgsfdsfgs/perfect_dark/</url>
|
||||
<description>
|
||||
<p>This is a port of Ryan Dywer's decompilation of classic N64 shooter Perfect Dark to modern systems.</p>
|
||||
</description>
|
||||
<!--
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source">https://gitlab.com/fpiesche/dxx-rebirth-assets/-/raw/c6e7e79eebe92905f84f07a635ffab5122a94bd1/d1x/screenshots/retromode.png</image>
|
||||
<caption>"Retro mode": the default graphics setup, like the original game but in high resolution</caption>
|
||||
<screenshots>
|
||||
-->
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
<category>ActionGame</category>
|
||||
<category>Shooter</category>
|
||||
</categories>
|
||||
<keywords>
|
||||
<keyword>n64</keyword>
|
||||
<keyword>scifi</keyword>
|
||||
<keyword>cyberpunk</keyword>
|
||||
<keyword>retro</keyword>
|
||||
<keyword>sourceport</keyword>
|
||||
<keyword>port</keyword>
|
||||
</keywords>
|
||||
<releases>
|
||||
<release version="latest" date="2024-05-14"/>
|
||||
</releases>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="violence-realistic">moderate</content_attribute>
|
||||
<content_attribute id="violence-bloodshed">mild</content_attribute>
|
||||
</content_rating>
|
||||
<update_contact>https://github.com/fgsfdsfgs/perfect_dark/</update_contact>
|
||||
</component>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Create user data directories if necessary
|
||||
userdirs=( roms saves mods )
|
||||
for path in "${userdirs[@]}"; do
|
||||
if [ ! -d "${XDG_DATA_HOME}/${path}" ]; then
|
||||
mkdir -p "${XDG_DATA_HOME}/${path}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Default to pd as executable but switch to jpn/pal if the NTSC rom
|
||||
# is missing but JPN/PAL are present.
|
||||
# TODO: Other arch
|
||||
executable="pd.x86_64"
|
||||
if [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-final.z64 ] | \
|
||||
[ -f ${XDG_DATA_HOME}/roms/pd.ntsc-1.0.z64 ]; then
|
||||
executable="pd.x86_64"
|
||||
elif [ -f ${XDG_DATA_HOME}/roms/pd.jpn-final.z64 ]; then
|
||||
executable="pd.jpn.x86_64"
|
||||
elif [ -f ${XDG_DATA_HOME}/roms/pd.pal-final.z64 ]; then
|
||||
executable="pd.pal.x86_64"
|
||||
fi
|
||||
|
||||
# If first parameter passed to this script is one of the pd executables,
|
||||
# run that regardless of ROM auto-detection above and pass the remaining
|
||||
# parameters to it; otherwise pass all arguments to the executable selected
|
||||
# above
|
||||
case $1 in
|
||||
"pd."*)
|
||||
executable=$1
|
||||
params="${@:2}"
|
||||
;;
|
||||
*)
|
||||
params="$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Run game
|
||||
$executable --basedir ${XDG_DATA_HOME}/roms --savedir ${XDG_DATA_HOME}/saves $params
|
||||
@@ -0,0 +1,41 @@
|
||||
app-id: io.github.fgsfdsfgs.perfect_dark
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: "23.08"
|
||||
sdk: org.freedesktop.Sdk
|
||||
command: io.github.fgsfdsfgs.perfect_dark.sh
|
||||
|
||||
finish-args:
|
||||
- --device=all
|
||||
- --share=ipc
|
||||
- --socket=x11
|
||||
# Audio
|
||||
- --socket=pulseaudio
|
||||
# Enable network for multiplayer
|
||||
- --share=network
|
||||
|
||||
modules:
|
||||
- name: perfect_dark
|
||||
buildsystem: simple
|
||||
sources:
|
||||
- type: file
|
||||
path: bin/pd.x86_64
|
||||
- type: file
|
||||
path: bin/pd.jpn.x86_64
|
||||
- type: file
|
||||
path: bin/pd.pal.x86_64
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.sh
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.png
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.metainfo.xml
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.desktop
|
||||
build-commands: []
|
||||
post-install:
|
||||
# Install the binaries
|
||||
- install -Dm 755 -t /app/bin/ pd.*
|
||||
- install -Dm 755 ${FLATPAK_ID}.sh /app/bin/${FLATPAK_ID}.sh
|
||||
- install -Dm 644 ${FLATPAK_ID}.desktop /app/share/applications/${FLATPAK_ID}.desktop
|
||||
- install -Dm 644 ${FLATPAK_ID}.metainfo.xml /app/share/metainfo/${FLATPAK_ID}.metainfo.xml
|
||||
- install -Dm 644 ${FLATPAK_ID}.png /app/share/icons/hicolor/256x256/apps/${FLATPAK_ID}.png
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
# Switch (SDL_GetPlatform is not changed in switch-sdl2)
|
||||
000038f853776974636820436f6e7400,Switch Controller,a:b0,b:b1,back:b11,dpdown:b15,dpleft:b12,dpright:b14,dpup:b13,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Unknown (see SDL_platform.h),
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
Vendored
+1
@@ -0,0 +1 @@
|
||||
id ICON icon.ico
|
||||
@@ -22,6 +22,7 @@
|
||||
#define __R4300_H__
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
|
||||
/*
|
||||
* Segment base addresses and sizes
|
||||
@@ -60,6 +61,8 @@
|
||||
|
||||
#else /* _LANGUAGE_C */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
|
||||
#define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */
|
||||
#define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */
|
||||
#define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */
|
||||
@@ -68,6 +71,24 @@
|
||||
#define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */
|
||||
#define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */
|
||||
|
||||
#else /* PLATFORM_N64 */
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
typedef u64 k_ptr_t;
|
||||
#else
|
||||
typedef u32 k_ptr_t;
|
||||
#endif
|
||||
|
||||
#define K0_TO_K1(x) ((k_ptr_t)(x)) /* kseg0 to kseg1 */
|
||||
#define K1_TO_K0(x) ((k_ptr_t)(x)) /* kseg1 to kseg0 */
|
||||
#define K0_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg0 to physical */
|
||||
#define K1_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg1 to physical */
|
||||
#define KDM_TO_PHYS(x) ((k_ptr_t)(x)) /* direct mapped to physical */
|
||||
#define PHYS_TO_K0(x) ((k_ptr_t)(x)) /* physical to kseg0 */
|
||||
#define PHYS_TO_K1(x) ((k_ptr_t)(x)) /* physical to kseg1 */
|
||||
|
||||
#endif /* PLATFORM_N64 */
|
||||
|
||||
#endif /* _LANGUAGE_ASSEMBLY */
|
||||
|
||||
/*
|
||||
|
||||
@@ -265,6 +265,8 @@ typedef short RESAMPLE_STATE[16];
|
||||
*/
|
||||
typedef short ENVMIX_STATE[40];
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
|
||||
/*
|
||||
* Macros to assemble the audio command list
|
||||
*/
|
||||
@@ -402,6 +404,12 @@ typedef short ENVMIX_STATE[40];
|
||||
_a->words.w1 = (unsigned int) d; \
|
||||
}
|
||||
|
||||
#else // PLATFORM_N64
|
||||
|
||||
#include "mixer.h"
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LANGUAGE_C */
|
||||
|
||||
#endif /* !_ABI_H_ */
|
||||
|
||||
+159
-31
@@ -22,6 +22,12 @@
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "gbiex.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* To use the F3DEX ucodes, define F3DEX_GBI before include this file.
|
||||
@@ -594,10 +600,10 @@
|
||||
#define G_BL_0 3
|
||||
|
||||
#define GBL_c1(m1a, m1b, m2a, m2b) \
|
||||
(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18
|
||||
(u32)(m1a) << 30 | (u32)(m1b) << 26 | (u32)(m2a) << 22 | (u32)(m2b) << 18
|
||||
|
||||
#define GBL_c2(m1a, m1b, m2a, m2b) \
|
||||
(m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16
|
||||
(u32)(m1a) << 28 | (u32)(m1b) << 24 | (u32)(m2a) << 20 | (u32)(m2b) << 16
|
||||
|
||||
#define RM_AA_ZB_OPA_SURF(clk) \
|
||||
AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
|
||||
@@ -1029,16 +1035,32 @@ typedef union {
|
||||
* Triangle face
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
unsigned char flag;
|
||||
unsigned char v[3];
|
||||
#else
|
||||
unsigned char v[3]; // reverse order
|
||||
unsigned char flag;
|
||||
#endif
|
||||
} Tri;
|
||||
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
#define GFX_TRI_VTX(i) (i)
|
||||
#else
|
||||
#define GFX_TRI_VTX(i) (2 - i)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4x4 matrix, fixed point s15.16 format.
|
||||
* First 8 words are integer portion of the 4x4 matrix
|
||||
* Last 8 words are the fraction portion of the 4x4 matrix
|
||||
*/
|
||||
typedef long Mtx_t[4][4];
|
||||
#ifdef GBI_FLOATS
|
||||
// 4x4 float matrix
|
||||
typedef float Mtx_t[4][4];
|
||||
#else
|
||||
typedef int32_t Mtx_t[4][4];
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
Mtx_t m;
|
||||
@@ -1290,23 +1312,45 @@ typedef union {
|
||||
/*
|
||||
* Graphics DMA Packet
|
||||
*/
|
||||
#ifdef PLATFORM_64BIT
|
||||
typedef struct {
|
||||
intptr_t par : 24;
|
||||
intptr_t cmd : 8;
|
||||
intptr_t len : 32;
|
||||
uintptr_t addr;
|
||||
} Gdma;
|
||||
#else
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
int cmd:8;
|
||||
unsigned int par:8;
|
||||
unsigned int len:16;
|
||||
unsigned int addr;
|
||||
#else // NOTE: changing signedness mid int will break up the bitfield on normal platforms, even BE
|
||||
int len:16;
|
||||
int par:8;
|
||||
int cmd:8;
|
||||
unsigned int addr;
|
||||
#endif
|
||||
} Gdma;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Graphics Immediate Mode Packet types
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
int cmd:8;
|
||||
int pad:24;
|
||||
#else
|
||||
int pad:24;
|
||||
int cmd:8;
|
||||
#endif
|
||||
Tri tri;
|
||||
} Gtri;
|
||||
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
unsigned char cmd:8;
|
||||
unsigned char pad:8;
|
||||
unsigned char z4:4;
|
||||
@@ -1321,6 +1365,28 @@ typedef struct {
|
||||
unsigned char x2:4;
|
||||
unsigned char y1:4;
|
||||
unsigned char x1:4;
|
||||
#else
|
||||
unsigned char z1:4;
|
||||
unsigned char z2:4;
|
||||
unsigned char z3:4;
|
||||
unsigned char z4:4;
|
||||
unsigned char pad:8;
|
||||
unsigned char cmd:8;
|
||||
#ifdef PLATFORM_64BIT
|
||||
unsigned char pad2[4];
|
||||
#endif
|
||||
unsigned char x1:4;
|
||||
unsigned char y1:4;
|
||||
unsigned char x2:4;
|
||||
unsigned char y2:4;
|
||||
unsigned char x3:4;
|
||||
unsigned char y3:4;
|
||||
unsigned char x4:4;
|
||||
unsigned char y4:4;
|
||||
#ifdef PLATFORM_64BIT
|
||||
unsigned char pad3[4];
|
||||
#endif
|
||||
#endif
|
||||
} Gtri4;
|
||||
|
||||
typedef struct {
|
||||
@@ -1356,12 +1422,21 @@ typedef struct {
|
||||
} GsetothermodeH;
|
||||
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
unsigned char cmd;
|
||||
unsigned char lodscale;
|
||||
unsigned char tile;
|
||||
unsigned char on;
|
||||
unsigned short s;
|
||||
unsigned short t;
|
||||
#else
|
||||
unsigned char on;
|
||||
unsigned char tile;
|
||||
unsigned char lodscale;
|
||||
unsigned char cmd;
|
||||
unsigned short t;
|
||||
unsigned short s;
|
||||
#endif
|
||||
} Gtexture;
|
||||
|
||||
typedef struct {
|
||||
@@ -1484,13 +1559,14 @@ typedef struct {
|
||||
* Generic Gfx Packet
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int w0;
|
||||
unsigned int w1;
|
||||
uintptr_t w0;
|
||||
uintptr_t w1;
|
||||
} Gwords;
|
||||
|
||||
// xxxxxxxx 11223344 44555566 66666777
|
||||
// 88888888 99999999 9999aaaa aaaaaaaa
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
unsigned int cmd:8;
|
||||
unsigned int unk08:2;
|
||||
unsigned int unk0a:2;
|
||||
@@ -1502,15 +1578,37 @@ typedef struct {
|
||||
unsigned int unk20:8;
|
||||
unsigned int tile1:12;
|
||||
unsigned int tile2:12;
|
||||
#else
|
||||
unsigned int subcmd:3;
|
||||
unsigned int flags:7;
|
||||
unsigned int unk12:4;
|
||||
unsigned int unk0e:4;
|
||||
unsigned int unk0c:2;
|
||||
unsigned int unk0a:2;
|
||||
unsigned int unk08:2;
|
||||
unsigned int cmd:8;
|
||||
unsigned int tile2:12;
|
||||
unsigned int tile1:12;
|
||||
unsigned int unk20:8;
|
||||
#endif
|
||||
} GunkC0;
|
||||
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
unsigned int cmd:8;
|
||||
unsigned int unk08:4;
|
||||
unsigned int unk0c:4;
|
||||
unsigned int unk10:16;
|
||||
unsigned int seg:8;
|
||||
unsigned int offset:24;
|
||||
#else
|
||||
unsigned int unk10:16;
|
||||
unsigned int unk0c:4;
|
||||
unsigned int unk08:4;
|
||||
unsigned int cmd:8;
|
||||
unsigned int offset:24;
|
||||
unsigned int seg:8;
|
||||
#endif
|
||||
} Gvtx;
|
||||
|
||||
/*
|
||||
@@ -1519,17 +1617,22 @@ typedef struct {
|
||||
*/
|
||||
typedef union {
|
||||
Gwords words;
|
||||
#ifdef PLATFORM_64BIT
|
||||
u8 bytes[16];
|
||||
#else
|
||||
u8 bytes[8];
|
||||
#endif
|
||||
Gdma dma;
|
||||
Gvtx vtx;
|
||||
Gtri tri;
|
||||
Gtri4 tri4;
|
||||
Gline3D line;
|
||||
Gtexture texture;
|
||||
#ifdef PLATFORM_N64 /* the rest is not needed on other platforms and some of em screw up the size */
|
||||
Gpopmtx popmtx;
|
||||
Gsegment segment;
|
||||
GsetothermodeH setothermodeH;
|
||||
GsetothermodeL setothermodeL;
|
||||
Gtexture texture;
|
||||
Gperspnorm perspnorm;
|
||||
Gsetimg setimg;
|
||||
Gsetcombine setcombine;
|
||||
@@ -1539,10 +1642,26 @@ typedef union {
|
||||
Gloadtile loadtile; /* use for loadblock also, th is dxt */
|
||||
Gsettilesize settilesize;
|
||||
Gloadtlut loadtlut;
|
||||
#endif
|
||||
GunkC0 unkc0;
|
||||
#ifdef PLATFORM_64BIT
|
||||
long long int force_structure_alignment[2];
|
||||
#else
|
||||
long long int force_structure_alignment;
|
||||
#endif
|
||||
} Gfx;
|
||||
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
#define GFX_W0_BYTE(i) (i)
|
||||
#define GFX_W1_BYTE(i) (4 + (i))
|
||||
#elif PLATFORM_64BIT
|
||||
#define GFX_W0_BYTE(i) (3 - (i))
|
||||
#define GFX_W1_BYTE(i) (11 - (i))
|
||||
#else
|
||||
#define GFX_W0_BYTE(i) (3 - (i))
|
||||
#define GFX_W1_BYTE(i) (7 - (i))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros to assemble the graphics display list
|
||||
*/
|
||||
@@ -1555,12 +1674,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \
|
||||
_g->words.w1 = (unsigned int)(s); \
|
||||
_g->words.w1 = (uintptr_t)(s); \
|
||||
}
|
||||
|
||||
#define gsDma0p(c, s, l) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (unsigned int)(s) \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s) \
|
||||
}
|
||||
|
||||
#define gDma1p(pkt, c, s, l, p) \
|
||||
@@ -1569,14 +1688,14 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
|
||||
_SHIFTL((l), 0, 16)); \
|
||||
_g->words.w1 = (unsigned int)(s); \
|
||||
_g->words.w1 = (uintptr_t)(s); \
|
||||
}
|
||||
|
||||
#define gsDma1p(c, s, l, p) \
|
||||
{ \
|
||||
(_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
|
||||
_SHIFTL((l), 0, 16)), \
|
||||
(unsigned int)(s) \
|
||||
(uintptr_t)(s) \
|
||||
}
|
||||
|
||||
#define gDma2p(pkt, c, adrs, len, idx, ofs) \
|
||||
@@ -1584,14 +1703,14 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
_g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
|
||||
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \
|
||||
_g->words.w1 = (unsigned int)(adrs); \
|
||||
_g->words.w1 = (uintptr_t)(adrs); \
|
||||
}
|
||||
|
||||
#define gsDma2p(c, adrs, len, idx, ofs) \
|
||||
{ \
|
||||
(_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
|
||||
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \
|
||||
(unsigned int)(adrs) \
|
||||
(uintptr_t)(adrs) \
|
||||
}
|
||||
|
||||
#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
|
||||
@@ -1640,12 +1759,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL((c), 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(p0); \
|
||||
_g->words.w1 = (uintptr_t)(p0); \
|
||||
}
|
||||
|
||||
#define gsImmp1(c, p0) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8), (unsigned int)(p0) \
|
||||
_SHIFTL((c), 24, 8), (uintptr_t)(p0) \
|
||||
}
|
||||
|
||||
#define gImmp2(pkt, c, p0, p1) \
|
||||
@@ -1682,13 +1801,13 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \
|
||||
_SHIFTL((p1), 0, 8)); \
|
||||
_g->words.w1 = (unsigned int) (dat); \
|
||||
_g->words.w1 = (uintptr_t) (dat); \
|
||||
}
|
||||
|
||||
#define gsImmp21(c, p0, p1, dat) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \
|
||||
(unsigned int) (dat) \
|
||||
(uintptr_t) (dat) \
|
||||
}
|
||||
|
||||
#define gMoveWd(pkt, index, offset, data) \
|
||||
@@ -1831,7 +1950,7 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
|
||||
((0x0f & (vstart))*40); \
|
||||
_g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \
|
||||
_g->words.w1 = (uintptr_t)((0x0f & ((vend)+1))*40); \
|
||||
}
|
||||
|
||||
// Removed in PD
|
||||
@@ -1847,6 +1966,15 @@ typedef union {
|
||||
#define gsSPSegment(segment, base) \
|
||||
gsMoveWd(G_MW_SEGMENT, (segment)*4, base)
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
#define SEGADDR(x) x
|
||||
#define UNSEGADDR(x) x
|
||||
#else
|
||||
// we mark all segmented addresses so that it'll be easier to recognize them later
|
||||
#define SEGADDR(x) ((void *)((uintptr_t)(x) | 1))
|
||||
#define UNSEGADDR(x) ((uintptr_t)(x) & ~1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clipping Macros
|
||||
*/
|
||||
@@ -2143,12 +2271,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(word); \
|
||||
_g->words.w1 = (uintptr_t)(word); \
|
||||
}
|
||||
|
||||
#define gsSPSetGeometryMode(word) \
|
||||
{ \
|
||||
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \
|
||||
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
|
||||
}
|
||||
|
||||
#define gSPClearGeometryMode(pkt, word) \
|
||||
@@ -2156,12 +2284,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(word); \
|
||||
_g->words.w1 = (uintptr_t)(word); \
|
||||
}
|
||||
|
||||
#define gsSPClearGeometryMode(word) \
|
||||
{ \
|
||||
_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) \
|
||||
_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
|
||||
}
|
||||
|
||||
#define gSPSetOtherMode(pkt, cmd, sft, len, data) \
|
||||
@@ -2170,13 +2298,13 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
|
||||
_SHIFTL(len, 0, 8)); \
|
||||
_g->words.w1 = (unsigned int)(data); \
|
||||
_g->words.w1 = (uintptr_t)(data); \
|
||||
}
|
||||
|
||||
#define gsSPSetOtherMode(cmd, sft, len, data) \
|
||||
{ \
|
||||
_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
|
||||
(unsigned int)(data) \
|
||||
(uintptr_t)(data) \
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2227,14 +2355,14 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
|
||||
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \
|
||||
_g->words.w1 = (unsigned int)(i); \
|
||||
_g->words.w1 = (uintptr_t)(i); \
|
||||
}
|
||||
|
||||
#define gsSetImage(cmd, fmt, siz, width, i) \
|
||||
{ \
|
||||
_SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
|
||||
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \
|
||||
(unsigned int)(i) \
|
||||
(uintptr_t)(i) \
|
||||
}
|
||||
|
||||
#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i)
|
||||
@@ -2260,13 +2388,13 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \
|
||||
_g->words.w1 = (unsigned int)(muxs1); \
|
||||
_g->words.w1 = (uintptr_t)(muxs1); \
|
||||
}
|
||||
|
||||
#define gsDPSetCombine(muxs0, muxs1) \
|
||||
{ \
|
||||
_SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
|
||||
(unsigned int)(muxs1) \
|
||||
(uintptr_t)(muxs1) \
|
||||
}
|
||||
|
||||
#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \
|
||||
@@ -2339,12 +2467,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(c, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(d); \
|
||||
_g->words.w1 = (uintptr_t)(d); \
|
||||
}
|
||||
|
||||
#define gsDPSetColor(c, d) \
|
||||
{ \
|
||||
_SHIFTL(c, 24, 8), (unsigned int)(d) \
|
||||
_SHIFTL(c, 24, 8), (uintptr_t)(d) \
|
||||
}
|
||||
|
||||
#define DPRGBColor(pkt, cmd, r, g, b, a) \
|
||||
@@ -2425,13 +2553,13 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24); \
|
||||
_g->words.w1 = (unsigned int)(mode1); \
|
||||
_g->words.w1 = (uintptr_t)(mode1); \
|
||||
}
|
||||
|
||||
#define gsDPSetOtherMode(mode0, mode1) \
|
||||
{ \
|
||||
_SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \
|
||||
(unsigned int)(mode1) \
|
||||
(uintptr_t)(mode1) \
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
#define OS_M_PI 3.14159265358979323846
|
||||
#define M_DTOR (3.14159265358979323846/180.0)
|
||||
|
||||
#define FTOFIX32(x) (long)((x) * (float)0x00010000)
|
||||
#define FTOFIX32(x) (int)((x) * (float)0x00010000)
|
||||
#define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000))
|
||||
#define FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff)
|
||||
|
||||
|
||||
@@ -120,7 +120,11 @@ typedef struct ALLink_s {
|
||||
void alUnlink(ALLink *element);
|
||||
void alLink(ALLink *element, ALLink *after);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
typedef s32 (*ALDMAproc)(s32 addr, s32 len, void *state);
|
||||
#else
|
||||
typedef uintptr_t (*ALDMAproc)(uintptr_t addr, s32 len, void *state);
|
||||
#endif
|
||||
typedef ALDMAproc (*ALDMANew)(void *state);
|
||||
|
||||
void alCopy(void *src, void *dest, s32 len);
|
||||
|
||||
+14
-3
@@ -28,6 +28,7 @@ extern "C" {
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/mbi.h>
|
||||
#include "platform.h"
|
||||
|
||||
struct var8009c340 {
|
||||
u8 surround;
|
||||
@@ -71,7 +72,7 @@ typedef struct {
|
||||
s32 maxAuxBusses;
|
||||
s32 outputRate;
|
||||
s32 maxOutSamples;
|
||||
s32 sv_dramout;
|
||||
uintptr_t sv_dramout;
|
||||
s32 sv_first;
|
||||
} N_ALSynth;
|
||||
|
||||
@@ -208,7 +209,7 @@ struct fx {
|
||||
s16 unk00;
|
||||
s16 unk02;
|
||||
s32 unk04;
|
||||
s16 unk08[8];
|
||||
s16 unk08[16];
|
||||
};
|
||||
|
||||
typedef struct N_ALVoiceState_s {
|
||||
@@ -256,7 +257,7 @@ typedef struct {
|
||||
ALOscStop stopOsc;
|
||||
ALSeqMarker *loopStart;
|
||||
ALSeqMarker *loopEnd;
|
||||
s32 loopCount; /* -1 = loop forever, 0 = no loop */
|
||||
intptr_t loopCount; /* -1 = loop forever, 0 = no loop */
|
||||
u8 unk88;
|
||||
u8 unk89;
|
||||
} N_ALSeqPlayer;
|
||||
@@ -284,9 +285,19 @@ typedef struct {
|
||||
ALOscInit initOsc;
|
||||
ALOscUpdate updateOsc;
|
||||
ALOscStop stopOsc;
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
s32 _pad1_;
|
||||
f32 unk7c;
|
||||
s32 _pad2_;
|
||||
f32 unk80;
|
||||
#else
|
||||
f32 unk7c;
|
||||
f32 unk80;
|
||||
#endif
|
||||
|
||||
void *queue;
|
||||
|
||||
u8 unk88;
|
||||
u8 unk89;
|
||||
} N_ALCSPlayer;
|
||||
|
||||
+42
-18
@@ -53,14 +53,18 @@ extern "C" {
|
||||
typedef struct {
|
||||
u16 type; /* Controller Type */
|
||||
u8 status; /* Controller status */
|
||||
u8 errno;
|
||||
u8 errnum;
|
||||
}OSContStatus;
|
||||
|
||||
typedef struct {
|
||||
u16 button;
|
||||
u32 button;
|
||||
s8 stick_x; /* -80 <= stick_x <= 80 */
|
||||
s8 stick_y; /* -80 <= stick_y <= 80 */
|
||||
u8 errno;
|
||||
u8 errnum;
|
||||
#ifndef PLATFORM_N64
|
||||
s8 rstick_x;
|
||||
s8 rstick_y;
|
||||
#endif
|
||||
} OSContPad;
|
||||
|
||||
typedef struct {
|
||||
@@ -68,7 +72,7 @@ typedef struct {
|
||||
u8 databuffer[32]; /* address of the data buffer */
|
||||
u8 addressCrc; /* CRC code for address */
|
||||
u8 dataCrc; /* CRC code for data */
|
||||
u8 errno;
|
||||
u8 errnum;
|
||||
} OSContRamIo;
|
||||
|
||||
|
||||
@@ -118,21 +122,39 @@ typedef struct {
|
||||
#define CONT_EEPROM_BUSY 0x80
|
||||
|
||||
/* Buttons */
|
||||
#define CONT_8000 0x80000000
|
||||
#define CONT_4000 0x40000000
|
||||
#define CONT_2000 0x20000000
|
||||
#define CONT_1000 0x10000000
|
||||
#define CONT_0800 0x08000000
|
||||
#define CONT_0400 0x04000000
|
||||
#define CONT_0200 0x02000000
|
||||
#define CONT_0100 0x01000000
|
||||
#define CONT_0080 0x00800000
|
||||
#define CONT_0040 0x00400000
|
||||
#define CONT_0020 0x00200000
|
||||
#define CONT_0010 0x00100000
|
||||
#define CONT_0008 0x00080000
|
||||
#define CONT_0004 0x00040000
|
||||
#define CONT_0002 0x00020000
|
||||
#define CONT_0001 0x00010000
|
||||
|
||||
#define CONT_A 0x8000
|
||||
#define CONT_B 0x4000
|
||||
#define CONT_G 0x2000
|
||||
#define CONT_START 0x1000
|
||||
#define CONT_UP 0x0800
|
||||
#define CONT_DOWN 0x0400
|
||||
#define CONT_LEFT 0x0200
|
||||
#define CONT_RIGHT 0x0100
|
||||
#define CONT_L 0x0020
|
||||
#define CONT_R 0x0010
|
||||
#define CONT_E 0x0008
|
||||
#define CONT_D 0x0004
|
||||
#define CONT_C 0x0002
|
||||
#define CONT_F 0x0001
|
||||
#define CONT_A 0x00008000
|
||||
#define CONT_B 0x00004000
|
||||
#define CONT_G 0x00002000
|
||||
#define CONT_START 0x00001000
|
||||
#define CONT_UP 0x00000800
|
||||
#define CONT_DOWN 0x00000400
|
||||
#define CONT_LEFT 0x00000200
|
||||
#define CONT_RIGHT 0x00000100
|
||||
#define CONT_EXTRA1 0x00000080
|
||||
#define CONT_EXTRA0 0x00000040
|
||||
#define CONT_L 0x00000020
|
||||
#define CONT_R 0x00000010
|
||||
#define CONT_E 0x00000008
|
||||
#define CONT_D 0x00000004
|
||||
#define CONT_C 0x00000002
|
||||
#define CONT_F 0x00000001
|
||||
|
||||
/* Nintendo's official button names */
|
||||
|
||||
@@ -150,6 +172,8 @@ typedef struct {
|
||||
#define L_CBUTTONS CONT_C
|
||||
#define R_CBUTTONS CONT_F
|
||||
#define D_CBUTTONS CONT_D
|
||||
#define X_BUTTON CONT_EXTRA0
|
||||
#define Y_BUTTON CONT_EXTRA1
|
||||
|
||||
/* Controller error number */
|
||||
|
||||
|
||||
+15
-3
@@ -35,6 +35,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#ifndef PLATFORM_N64
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
|
||||
|
||||
@@ -70,12 +73,17 @@ extern "C" {
|
||||
#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL))
|
||||
#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL))
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
#define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000))
|
||||
#define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000))
|
||||
|
||||
#define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000))
|
||||
#define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000))
|
||||
|
||||
#else
|
||||
#define OS_K0_TO_PHYSICAL(x) (uintptr_t)(x)
|
||||
#define OS_K1_TO_PHYSICAL(x) (uintptr_t)(x)
|
||||
#define OS_PHYSICAL_TO_K0(x) (void *)(x)
|
||||
#define OS_PHYSICAL_TO_K1(x) (void *)(x)
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
@@ -92,9 +100,13 @@ extern "C" {
|
||||
|
||||
/* Address translation routines and macros */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
extern u32 osVirtualToPhysical(void *);
|
||||
extern void * osPhysicalToVirtual(u32);
|
||||
|
||||
#else
|
||||
extern uintptr_t osVirtualToPhysical(void *);
|
||||
extern void * osPhysicalToVirtual(uintptr_t);
|
||||
#endif
|
||||
|
||||
#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */
|
||||
|
||||
|
||||
+18
-3
@@ -31,6 +31,14 @@
|
||||
#define _OS_LIBC_H_
|
||||
|
||||
#include "os_pfs.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_OSX
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LANGUAGE_C_PLUS_PLUS
|
||||
extern "C" {
|
||||
@@ -80,13 +88,20 @@ extern "C" {
|
||||
|
||||
/* byte string operations */
|
||||
|
||||
extern void bcopy(const void *, void *, int);
|
||||
extern int bcmp(const void *, const void *, int);
|
||||
extern void bzero(void *, int);
|
||||
#ifndef PLATFORM_OSX
|
||||
extern void bcopy(const void *, void *, size_t);
|
||||
extern int bcmp(const void *, const void *, size_t);
|
||||
extern void bzero(void *, size_t);
|
||||
#endif
|
||||
|
||||
/* Printf */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
extern int sprintf(char *s, const char *fmt, ...);
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
extern void osSyncPrintf(const char *fmt, ...);
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ extern "C" {
|
||||
#include <PR/ultratypes.h>
|
||||
#include "os_thread.h"
|
||||
#include "os_message.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
|
||||
|
||||
@@ -198,7 +198,7 @@ extern u32 osPiGetStatus(void);
|
||||
extern s32 osPiGetDeviceType(void);
|
||||
extern s32 osPiWriteIo(u32, u32);
|
||||
extern s32 osPiReadIo(u32, u32 *);
|
||||
extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32,
|
||||
extern s32 osPiStartDma(OSIoMesg *, s32, s32, uintptr_t, void *, u32,
|
||||
OSMesgQueue *);
|
||||
extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32);
|
||||
|
||||
|
||||
File renamed without changes.
@@ -57,6 +57,8 @@ typedef volatile long long vs64; /* signed 64-bit */
|
||||
typedef float f32; /* single prec floating point */
|
||||
typedef double f64; /* double prec floating point */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
|
||||
#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEF)
|
||||
#define _SIZE_T
|
||||
#define _SIZE_T_DEF /* exeGCC size_t define label */
|
||||
@@ -68,6 +70,12 @@ typedef unsigned long size_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LANGUAGE_C */
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Emill, MaikelChan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef GFX_API_H
|
||||
#define GFX_API_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include "gfx_rendering_api.h"
|
||||
#include "gfx_window_manager_api.h"
|
||||
|
||||
struct XYWidthHeight {
|
||||
int16_t x, y;
|
||||
uint32_t width, height;
|
||||
};
|
||||
|
||||
struct GfxDimensions {
|
||||
float internal_mul;
|
||||
uint32_t width, height;
|
||||
float aspect_ratio;
|
||||
};
|
||||
|
||||
struct GfxInitSettings {
|
||||
struct GfxWindowManagerAPI *wapi;
|
||||
struct GfxRenderingAPI *rapi;
|
||||
struct GfxWindowInitSettings window_settings;
|
||||
};
|
||||
|
||||
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
|
||||
extern struct GfxDimensions
|
||||
gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
|
||||
extern struct XYWidthHeight
|
||||
gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
|
||||
extern uint32_t gfx_msaa_level;
|
||||
extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game
|
||||
extern float gfx_current_native_aspect; // The aspect ratio of the above mode
|
||||
extern bool gfx_framebuffers_enabled;
|
||||
extern bool gfx_detail_textures_enabled;
|
||||
|
||||
void gfx_init(const struct GfxInitSettings *settings);
|
||||
void gfx_destroy(void);
|
||||
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
|
||||
void gfx_start_frame(void);
|
||||
void gfx_run(Gfx* commands);
|
||||
void gfx_end_frame(void);
|
||||
void gfx_set_target_fps(int);
|
||||
void gfx_set_texture_filter(enum FilteringMode mode);
|
||||
void gfx_texture_cache_clear(void);
|
||||
void gfx_texture_cache_delete(const uint8_t *orig_addr);
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize);
|
||||
void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize);
|
||||
void gfx_set_framebuffer(int fb, float noise_scale) ;
|
||||
void gfx_reset_framebuffer(void);
|
||||
void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "gfx_cc.h"
|
||||
|
||||
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
cc_features->c[i][j][k] = (shader_id0 >> (i * 32 + j * 16 + k * 4)) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cc_features->opt_alpha = (shader_id1 & SHADER_OPT_ALPHA) != 0;
|
||||
cc_features->opt_fog = (shader_id1 & SHADER_OPT_FOG) != 0;
|
||||
cc_features->opt_texture_edge = (shader_id1 & SHADER_OPT_TEXTURE_EDGE) != 0;
|
||||
cc_features->opt_noise = (shader_id1 & SHADER_OPT_NOISE) != 0;
|
||||
cc_features->opt_2cyc = (shader_id1 & SHADER_OPT_2CYC) != 0;
|
||||
cc_features->opt_alpha_threshold = (shader_id1 & SHADER_OPT_ALPHA_THRESHOLD) != 0;
|
||||
cc_features->opt_invisible = (shader_id1 & SHADER_OPT_INVISIBLE) != 0;
|
||||
cc_features->opt_grayscale = (shader_id1 & SHADER_OPT_GRAYSCALE) != 0;
|
||||
cc_features->opt_blur = (shader_id1 & SHADER_OPT_BLUR) != 0;
|
||||
|
||||
cc_features->clamp[0][0] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_S);
|
||||
cc_features->clamp[0][1] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_T);
|
||||
cc_features->clamp[1][0] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_S);
|
||||
cc_features->clamp[1][1] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_T);
|
||||
|
||||
cc_features->used_textures[0] = false;
|
||||
cc_features->used_textures[1] = false;
|
||||
cc_features->num_inputs = 0;
|
||||
|
||||
for (int c = 0; c < 2; c++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (cc_features->c[c][i][j] >= SHADER_INPUT_1 && cc_features->c[c][i][j] <= SHADER_INPUT_7) {
|
||||
if (cc_features->c[c][i][j] > cc_features->num_inputs) {
|
||||
cc_features->num_inputs = cc_features->c[c][i][j];
|
||||
}
|
||||
}
|
||||
if (cc_features->c[c][i][j] == SHADER_TEXEL0 || cc_features->c[c][i][j] == SHADER_TEXEL0A) {
|
||||
cc_features->used_textures[0] = true;
|
||||
}
|
||||
if (cc_features->c[c][i][j] == SHADER_TEXEL1 || cc_features->c[c][i][j] == SHADER_TEXEL1A) {
|
||||
cc_features->used_textures[1] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int c = 0; c < 2; c++) {
|
||||
cc_features->do_single[c][0] = cc_features->c[c][0][2] == SHADER_0;
|
||||
cc_features->do_single[c][1] = cc_features->c[c][1][2] == SHADER_0;
|
||||
cc_features->do_multiply[c][0] = cc_features->c[c][0][1] == SHADER_0 && cc_features->c[c][0][3] == SHADER_0;
|
||||
cc_features->do_multiply[c][1] = cc_features->c[c][1][1] == SHADER_0 && cc_features->c[c][1][3] == SHADER_0;
|
||||
cc_features->do_mix[c][0] = cc_features->c[c][0][1] == cc_features->c[c][0][3];
|
||||
cc_features->do_mix[c][1] = cc_features->c[c][1][1] == cc_features->c[c][1][3];
|
||||
cc_features->color_alpha_same[c] =
|
||||
((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef GFX_CC_H
|
||||
#define GFX_CC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <compare>
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SHADER_0,
|
||||
SHADER_INPUT_1,
|
||||
SHADER_INPUT_2,
|
||||
SHADER_INPUT_3,
|
||||
SHADER_INPUT_4,
|
||||
SHADER_INPUT_5,
|
||||
SHADER_INPUT_6,
|
||||
SHADER_INPUT_7,
|
||||
SHADER_TEXEL0,
|
||||
SHADER_TEXEL0A,
|
||||
SHADER_TEXEL1,
|
||||
SHADER_TEXEL1A,
|
||||
SHADER_1,
|
||||
SHADER_COMBINED,
|
||||
SHADER_NOISE,
|
||||
SHADER_LOD_FRAC,
|
||||
};
|
||||
|
||||
#define SHADER_OPT_ALPHA (1 << 0)
|
||||
#define SHADER_OPT_FOG (1 << 1)
|
||||
#define SHADER_OPT_TEXTURE_EDGE (1 << 2)
|
||||
#define SHADER_OPT_NOISE (1 << 3)
|
||||
#define SHADER_OPT_2CYC (1 << 4)
|
||||
#define SHADER_OPT_ALPHA_THRESHOLD (1 << 5)
|
||||
#define SHADER_OPT_INVISIBLE (1 << 6)
|
||||
#define SHADER_OPT_GRAYSCALE (1 << 7)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 8)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
|
||||
#define SHADER_OPT_BLUR (1 << 12)
|
||||
|
||||
struct ColorCombinerKey {
|
||||
uint64_t combine_mode;
|
||||
uint64_t options;
|
||||
auto operator<=>(const ColorCombinerKey&) const = default;
|
||||
};
|
||||
|
||||
#define SHADER_MAX_TEXTURES 2
|
||||
#define SHADER_FIRST_TEXTURE 0
|
||||
|
||||
struct CCFeatures {
|
||||
uint8_t c[2][2][4];
|
||||
bool opt_alpha;
|
||||
bool opt_fog;
|
||||
bool opt_texture_edge;
|
||||
bool opt_noise;
|
||||
bool opt_2cyc;
|
||||
bool opt_alpha_threshold;
|
||||
bool opt_invisible;
|
||||
bool opt_grayscale;
|
||||
bool opt_blur;
|
||||
bool used_textures[2];
|
||||
bool clamp[2][2];
|
||||
int num_inputs;
|
||||
bool do_single[2][2];
|
||||
bool do_multiply[2][2];
|
||||
bool do_mix[2][2];
|
||||
bool color_alpha_same[2];
|
||||
};
|
||||
|
||||
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,8 @@
|
||||
#ifndef GFX_OPENGL_H
|
||||
#define GFX_OPENGL_H
|
||||
|
||||
#include "gfx_rendering_api.h"
|
||||
|
||||
extern struct GfxRenderingAPI gfx_opengl_api;
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,60 @@
|
||||
#ifndef GFX_PC_H
|
||||
#define GFX_PC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
|
||||
#include <PR/gbi.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#define SCREEN_WIDTH ((int32_t)gfx_current_native_viewport.width)
|
||||
#define SCREEN_HEIGHT ((int32_t)gfx_current_native_viewport.height)
|
||||
|
||||
extern uintptr_t gfxFramebuffer;
|
||||
|
||||
struct GfxRenderingAPI;
|
||||
struct GfxWindowManagerAPI;
|
||||
|
||||
struct TextureCacheKey {
|
||||
const uint8_t* texture_addr;
|
||||
const uint8_t* palette_addrs[2];
|
||||
uint8_t fmt, siz;
|
||||
uint8_t palette_index;
|
||||
|
||||
bool operator==(const TextureCacheKey&) const noexcept = default;
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const TextureCacheKey& key) const noexcept {
|
||||
uintptr_t addr = (uintptr_t)key.texture_addr;
|
||||
return (size_t)(addr ^ (addr >> 5));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
typedef std::unordered_map<TextureCacheKey, struct TextureCacheValue, TextureCacheKey::Hasher> TextureCacheMap;
|
||||
typedef std::pair<const TextureCacheKey, struct TextureCacheValue> TextureCacheNode;
|
||||
|
||||
struct TextureCacheValue {
|
||||
uint32_t texture_id;
|
||||
uint8_t cms, cmt;
|
||||
bool linear_filter;
|
||||
|
||||
std::list<struct TextureCacheMapIter>::iterator lru_location;
|
||||
};
|
||||
|
||||
struct TextureCacheMapIter {
|
||||
TextureCacheMap::iterator it;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "gfx_api.h"
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef GFX_RENDERING_API_H
|
||||
#define GFX_RENDERING_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct ShaderProgram;
|
||||
|
||||
struct GfxClipParameters {
|
||||
bool z_is_from_0_to_1;
|
||||
bool invert_y;
|
||||
};
|
||||
|
||||
enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT };
|
||||
|
||||
struct GfxRenderingAPI {
|
||||
const char* (*get_name)(void);
|
||||
int (*get_max_texture_size)(void);
|
||||
struct GfxClipParameters (*get_clip_parameters)(void);
|
||||
void (*unload_shader)(struct ShaderProgram* old_prg);
|
||||
void (*load_shader)(struct ShaderProgram* new_prg);
|
||||
struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
|
||||
struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1);
|
||||
void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]);
|
||||
void (*clear_shaders)(void);
|
||||
uint32_t (*new_texture)(void);
|
||||
void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter);
|
||||
void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height);
|
||||
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
|
||||
void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode);
|
||||
void (*set_depth_range)(float znear, float zfar);
|
||||
void (*set_viewport)(int x, int y, int width, int height);
|
||||
void (*set_scissor)(int x, int y, int width, int height);
|
||||
void (*set_use_alpha)(bool use_alpha, bool modulate);
|
||||
void (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris);
|
||||
void (*init)(void);
|
||||
void (*on_resize)(void);
|
||||
void (*start_frame)(void);
|
||||
void (*end_frame)(void);
|
||||
void (*finish_render)(void);
|
||||
int (*create_framebuffer)();
|
||||
void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level,
|
||||
bool opengl_invert_y, bool render_target, bool has_depth_buffer,
|
||||
bool can_extract_depth);
|
||||
bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
|
||||
void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back);
|
||||
void (*clear_framebuffer)(bool clear_color, bool clear_depth);
|
||||
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
|
||||
void* (*get_framebuffer_texture_id)(int fb_id);
|
||||
void (*select_texture_fb)(int fb_id);
|
||||
void (*delete_texture)(uint32_t texID);
|
||||
void (*set_texture_filter)(enum FilteringMode mode);
|
||||
enum FilteringMode (*get_texture_filter)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef GFX_SCREEN_CONFIG_H
|
||||
#define GFX_SCREEN_CONFIG_H
|
||||
|
||||
#define DESIRED_SCREEN_WIDTH 640
|
||||
#define DESIRED_SCREEN_HEIGHT 480
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef GFX_SDL_H
|
||||
#define GFX_SDL_H
|
||||
|
||||
#include "gfx_window_manager_api.h"
|
||||
|
||||
extern struct GfxWindowManagerAPI gfx_sdl;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,463 @@
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "gfx_window_manager_api.h"
|
||||
#include "gfx_screen_config.h"
|
||||
|
||||
static SDL_Window* wnd;
|
||||
static SDL_GLContext ctx;
|
||||
static SDL_Renderer* renderer;
|
||||
static int sdl_to_lus_table[512];
|
||||
static bool vsync_enabled = true;
|
||||
// OTRTODO: These are redundant. Info can be queried from SDL.
|
||||
static int window_width = DESIRED_SCREEN_WIDTH;
|
||||
static int window_height = DESIRED_SCREEN_HEIGHT;
|
||||
static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
static bool fullscreen_state;
|
||||
static bool maximized_state;
|
||||
static bool is_running = true;
|
||||
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
|
||||
|
||||
static int target_fps = 120; // above 60 since vsync is enabled by default
|
||||
static uint64_t previous_time;
|
||||
static uint64_t qpc_freq;
|
||||
|
||||
#define FRAME_INTERVAL_US_NUMERATOR 1000000
|
||||
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
|
||||
|
||||
static int32_t gfx_sdl_get_maximized_state(void) {
|
||||
return (int32_t)maximized_state;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_fullscreen_state(void) {
|
||||
return (int32_t)fullscreen_state;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_fullscreen_flag_mode(void) {
|
||||
return fullscreen_flag == SDL_WINDOW_FULLSCREEN_DESKTOP ? 0 : 1;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen_flag(int32_t mode) {
|
||||
switch (mode) {
|
||||
case 0: {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
} break;
|
||||
case 1: {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_fullscreen(bool on, bool call_callback) {
|
||||
fullscreen_state = on;
|
||||
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
|
||||
if (call_callback && on_fullscreen_changed_callback) {
|
||||
on_fullscreen_changed_callback(on);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_maximize_window(bool on) {
|
||||
maximized_state = on;
|
||||
if (on) {
|
||||
SDL_MaximizeWindow(wnd);
|
||||
} else {
|
||||
SDL_RestoreWindow (wnd);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
|
||||
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
|
||||
SDL_DisplayMode mode;
|
||||
SDL_GetCurrentDisplayMode(display_in_use, &mode);
|
||||
*refresh_rate = mode.refresh_rate;
|
||||
}
|
||||
|
||||
static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
|
||||
window_width = set->width;
|
||||
window_height = set->height;
|
||||
|
||||
#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED
|
||||
if (!set->allow_hidpi) {
|
||||
// HiDPI control, if available
|
||||
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
||||
#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS)
|
||||
// if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows
|
||||
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
sysFatalError("Could not init SDL:\n%s", SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
if (sysArgCheck("--debug-gl")) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
}
|
||||
|
||||
int posX = set->x;
|
||||
int posY = set->y;
|
||||
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
if (display_in_use < 0) { // Fallback to default if out of bounds
|
||||
posX = 100;
|
||||
posY = 100;
|
||||
}
|
||||
|
||||
if (set->centered) {
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetCurrentDisplayMode(0, &mode);
|
||||
posX = mode.w / 2 - window_width / 2;
|
||||
posY = mode.h / 2 - window_height / 2;
|
||||
}
|
||||
|
||||
if (set->fullscreen_is_exclusive) {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
|
||||
// we will unhide the window once the GL context is successfully created
|
||||
Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
|
||||
|
||||
// if fullscreen was requested, start the window in fullscreen right away
|
||||
if (set->fullscreen) {
|
||||
flags |= fullscreen_flag;
|
||||
fullscreen_state = true;
|
||||
}
|
||||
|
||||
if (set->maximized) {
|
||||
flags |= SDL_WINDOW_MAXIMIZED;
|
||||
maximized_state = true;
|
||||
}
|
||||
|
||||
#ifdef SDL_WINDOW_ALLOW_HIGHDPI
|
||||
if (set->allow_hidpi) {
|
||||
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ideally we need 3.0 compat
|
||||
// if that doesn't work, try 3.2 core in case we're on mac, 2.1 compat as a last resort
|
||||
static u32 glver[][3] = {
|
||||
{ 0, 0, 0 }, // for command line override
|
||||
{ 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 3.0: default, has all the features required
|
||||
{ 4, 1, SDL_GL_CONTEXT_PROFILE_CORE }, // 4.1core: macs only have core profile and this is the latest
|
||||
{ 3, 2, SDL_GL_CONTEXT_PROFILE_CORE }, // 3.2core: older macs will only have this at best
|
||||
{ 3, 0, SDL_GL_CONTEXT_PROFILE_ES }, // es3: don't really support ES properly, but we can try
|
||||
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 2.1: absolute last resort, will still require GLSL130 as an extension
|
||||
};
|
||||
|
||||
u32 verstart = 1;
|
||||
const u32 verend = sizeof(glver) / sizeof(*glver);
|
||||
const char *verstr = sysArgGetString("--gl-version");
|
||||
if (verstr && *verstr) {
|
||||
// user override
|
||||
glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE :
|
||||
(strstr(verstr, "es") ? SDL_GL_CONTEXT_PROFILE_ES :
|
||||
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]);
|
||||
if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) {
|
||||
verstart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx = NULL;
|
||||
u32 vmin = 0, vmaj = 0, vprof = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
|
||||
const char *vprofstr = "";
|
||||
for (u32 i = verstart; i < verend && !ctx; ++i) {
|
||||
vmaj = glver[i][0];
|
||||
vmin = glver[i][1];
|
||||
vprof = glver[i][2];
|
||||
vprofstr = (vprof == SDL_GL_CONTEXT_PROFILE_CORE ? "core" :
|
||||
(vprof == SDL_GL_CONTEXT_PROFILE_ES ? "es" : ""));
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, vprof);
|
||||
|
||||
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
|
||||
if (!wnd) {
|
||||
sysLogPrintf(LOG_WARNING, "SDL: could not open SDL window for GL%d.%d%s:\n%s", vmaj, vmin, vprofstr, SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx = SDL_GL_CreateContext(wnd);
|
||||
if (!ctx) {
|
||||
sysLogPrintf(LOG_WARNING, "SDL: could not create GL%d.%d%s context: %s", vmaj, vmin, vprofstr, SDL_GetError());
|
||||
SDL_DestroyWindow(wnd);
|
||||
wnd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wnd || !ctx) {
|
||||
sysFatalError("Could not open SDL window with an OpenGL context of any supported version:\n%s", SDL_GetError());
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "SDL: created GL%d.%d%s context", vmaj, vmin, vprofstr);
|
||||
}
|
||||
|
||||
SDL_GL_MakeCurrent(wnd, ctx);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
SDL_ShowWindow(wnd);
|
||||
|
||||
qpc_freq = SDL_GetPerformanceFrequency();
|
||||
}
|
||||
|
||||
static void gfx_sdl_close(void) {
|
||||
is_running = false;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) {
|
||||
on_fullscreen_changed_callback = on_fullscreen_changed;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen(bool enable) {
|
||||
set_fullscreen(enable, true);
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen_exclusive(bool enable) {
|
||||
const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
if (fullscreen_flag != newflag) {
|
||||
fullscreen_flag = newflag;
|
||||
// reset fullscreen to take new value into account if it already is in fullscreen
|
||||
if (fullscreen_state) {
|
||||
fullscreen_state = false;
|
||||
set_fullscreen(enable, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_maximize_window(bool enable) {
|
||||
set_maximize_window(enable);
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_cursor_visibility(bool visible) {
|
||||
if (visible) {
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
} else {
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_centered_positions_native(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetDesktopDisplayMode(disp_idx, &mode);
|
||||
*posX = mode.w / 2 - width / 2;
|
||||
*posY = mode.h / 2 - height / 2;
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_centered_positions(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetCurrentDisplayMode(disp_idx, &mode);
|
||||
*posX = mode.w / 2 - width / 2;
|
||||
*posY = mode.h / 2 - height / 2;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_closest_resolution(int32_t width, int32_t height, bool should_center) {
|
||||
const SDL_DisplayMode mode = {.w = width, .h = height};
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode closest = {};
|
||||
if (SDL_GetClosestDisplayMode(disp_idx, &mode, &closest)) {
|
||||
SDL_SetWindowDisplayMode(wnd, &closest);
|
||||
SDL_SetWindowSize(wnd, closest.w, closest.h);
|
||||
if (should_center) {
|
||||
int32_t posX = 0;
|
||||
int32_t posY = 0;
|
||||
get_centered_positions_native(closest.w, closest.h, &posX, &posY);
|
||||
SDL_SetWindowPosition(wnd, posX, posY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_dimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) {
|
||||
SDL_SetWindowSize(wnd, width, height);
|
||||
SDL_SetWindowPosition(wnd, posX, posY);
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) {
|
||||
SDL_GL_GetDrawableSize(wnd, static_cast<int*>((void*)width), static_cast<int*>((void*)height));
|
||||
SDL_GetWindowPosition(wnd, static_cast<int*>(posX), static_cast<int*>(posY));
|
||||
}
|
||||
|
||||
static void gfx_sdl_handle_events(void) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)) {
|
||||
// alt-enter received, switch fullscreen state
|
||||
set_fullscreen(!fullscreen_state, true);
|
||||
}
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);
|
||||
if (!fullscreen_state) {
|
||||
maximized_state = SDL_GetWindowFlags(wnd) & SDL_WINDOW_MAXIMIZED ? true : false;
|
||||
}
|
||||
} else if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
|
||||
event.window.windowID == SDL_GetWindowID(wnd)) {
|
||||
// We listen specifically for main window close because closing main window
|
||||
// on macOS does not trigger SDL_Quit.
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool gfx_sdl_start_frame(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t qpc_to_100ns(uint64_t qpc) {
|
||||
return qpc / qpc_freq * 10000000 + qpc % qpc_freq * 10000000 / qpc_freq;
|
||||
}
|
||||
|
||||
static inline void sync_framerate_with_timer(void) {
|
||||
uint64_t t;
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
|
||||
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
int64_t left = next - t;
|
||||
// We want to exit a bit early, so we can busy-wait the rest to never miss the deadline
|
||||
left -= 15000UL;
|
||||
if (left > 0) {
|
||||
sysSleep(left);
|
||||
}
|
||||
|
||||
do {
|
||||
sysCpuRelax();
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
} while ((int64_t)t < next);
|
||||
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
if (left > 0 && t - next < 10000) {
|
||||
// In case it takes some time for the application to wake up after sleep,
|
||||
// or inaccurate timer,
|
||||
// don't let that slow down the framerate.
|
||||
t = next;
|
||||
}
|
||||
previous_time = t;
|
||||
}
|
||||
|
||||
static void gfx_sdl_swap_buffers_begin(void) {
|
||||
if (target_fps) {
|
||||
sync_framerate_with_timer();
|
||||
}
|
||||
SDL_GL_SwapWindow(wnd);
|
||||
}
|
||||
|
||||
static void gfx_sdl_swap_buffers_end(void) {
|
||||
|
||||
}
|
||||
|
||||
static double gfx_sdl_get_time(void) {
|
||||
return SDL_GetPerformanceCounter() / (double)qpc_freq;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_target_fps(void) {
|
||||
return target_fps;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_target_fps(int fps) {
|
||||
target_fps = fps;
|
||||
}
|
||||
|
||||
static bool gfx_sdl_can_disable_vsync(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *gfx_sdl_get_window_handle(void) {
|
||||
return (void *)wnd;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_window_title(const char *title) {
|
||||
SDL_SetWindowTitle(wnd, title);
|
||||
}
|
||||
|
||||
static int gfx_sdl_get_swap_interval(void) {
|
||||
return SDL_GL_GetSwapInterval();
|
||||
}
|
||||
|
||||
static bool gfx_sdl_set_swap_interval(int interval) {
|
||||
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
|
||||
vsync_enabled = success && (interval != 0);
|
||||
if (!success) {
|
||||
sysLogPrintf(LOG_WARNING, "SDL: failed to set vsync %d: %s", interval, SDL_GetError());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int gfx_sdl_get_display_mode(int modenum, int *out_w, int *out_h) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode sdlmode;
|
||||
if (SDL_GetDisplayMode(display_in_use, modenum, &sdlmode) == 0) {
|
||||
*out_w = sdlmode.w;
|
||||
*out_h = sdlmode.h;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfx_sdl_get_current_display_mode(int *out_w, int *out_h) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode sdlmode;
|
||||
if (SDL_GetCurrentDisplayMode(display_in_use, &sdlmode) == 0) {
|
||||
*out_w = sdlmode.w;
|
||||
*out_h = sdlmode.h;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfx_sdl_get_num_display_modes(void) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
return SDL_GetNumDisplayModes(display_in_use);
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_init,
|
||||
gfx_sdl_close,
|
||||
gfx_sdl_get_display_mode,
|
||||
gfx_sdl_get_current_display_mode,
|
||||
gfx_sdl_get_num_display_modes,
|
||||
gfx_sdl_get_fullscreen_state,
|
||||
gfx_sdl_set_fullscreen_changed_callback,
|
||||
gfx_sdl_set_fullscreen,
|
||||
gfx_sdl_set_fullscreen_exclusive,
|
||||
gfx_sdl_set_fullscreen_flag,
|
||||
gfx_sdl_get_fullscreen_flag_mode,
|
||||
gfx_sdl_get_maximized_state,
|
||||
gfx_sdl_set_maximize_window,
|
||||
gfx_sdl_get_active_window_refresh_rate,
|
||||
gfx_sdl_set_cursor_visibility,
|
||||
gfx_sdl_set_closest_resolution,
|
||||
gfx_sdl_set_dimensions,
|
||||
gfx_sdl_get_dimensions,
|
||||
gfx_sdl_get_centered_positions,
|
||||
gfx_sdl_handle_events,
|
||||
gfx_sdl_start_frame,
|
||||
gfx_sdl_swap_buffers_begin,
|
||||
gfx_sdl_swap_buffers_end,
|
||||
gfx_sdl_get_time,
|
||||
gfx_sdl_get_target_fps,
|
||||
gfx_sdl_set_target_fps,
|
||||
gfx_sdl_can_disable_vsync,
|
||||
gfx_sdl_get_window_handle,
|
||||
gfx_sdl_set_window_title,
|
||||
gfx_sdl_get_swap_interval,
|
||||
gfx_sdl_set_swap_interval,
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef GFX_WINDOW_MANAGER_API_H
|
||||
#define GFX_WINDOW_MANAGER_API_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct GfxWindowInitSettings {
|
||||
const char *title;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
bool fullscreen;
|
||||
bool fullscreen_is_exclusive;
|
||||
bool maximized;
|
||||
bool centered;
|
||||
bool allow_hidpi;
|
||||
};
|
||||
|
||||
struct GfxWindowManagerAPI {
|
||||
void (*init)(const struct GfxWindowInitSettings *settings);
|
||||
void (*close)(void);
|
||||
int (*get_display_mode)(int modenum, int *out_w, int *out_h);
|
||||
int (*get_current_display_mode)(int *out_w, int *out_h);
|
||||
int (*get_num_display_modes)(void);
|
||||
int32_t (*get_fullscreen_state)(void);
|
||||
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
|
||||
void (*set_fullscreen)(bool enable);
|
||||
void (*set_fullscreen_exclusive)(bool exc);
|
||||
void (*set_fullscreen_flag)(int32_t mode);
|
||||
int32_t (*get_fullscreen_flag_mode)(void);
|
||||
int32_t (*get_maximized_state)(void);
|
||||
void (*set_maximize)(bool enable);
|
||||
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
|
||||
void (*set_cursor_visibility)(bool visible);
|
||||
void (*set_closest_resolution)(int32_t width, int32_t height, bool should_center);
|
||||
void (*set_dimensions)(uint32_t width, uint32_t height, int32_t posX, int32_t posY);
|
||||
void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
|
||||
void (*get_centered_positions)(int32_t width, int32_t height, int32_t *posX, int32_t *posY);
|
||||
void (*handle_events)(void);
|
||||
bool (*start_frame)(void);
|
||||
void (*swap_buffers_begin)(void);
|
||||
void (*swap_buffers_end)(void);
|
||||
double (*get_time)(void); // For debug
|
||||
int32_t (*get_target_fps)(void);
|
||||
void (*set_target_fps)(int fps);
|
||||
bool (*can_disable_vsync)(void);
|
||||
void *(*get_window_handle)(void);
|
||||
void (*set_window_title)(const char *);
|
||||
int (*get_swap_interval)(void);
|
||||
bool (*set_swap_interval)(int);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,311 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _IN_AUDIO_H
|
||||
#define _IN_AUDIO_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
s32 audioInit(void);
|
||||
s32 audioGetBytesBuffered(void);
|
||||
s32 audioGetSamplesBuffered(void);
|
||||
void audioSetNextBuffer(const s16 *buf, u32 len);
|
||||
void audioEndFrame(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
#define CONFIG_FNAME "pd.ini"
|
||||
#define CONFIG_PATH "$S/" CONFIG_FNAME
|
||||
|
||||
void configInit(void);
|
||||
|
||||
// loads config from file (path extensions such as ! apply)
|
||||
s32 configLoad(const char *fname);
|
||||
|
||||
// saves config to file (path extensions such as ! apply)
|
||||
s32 configSave(const char *fname);
|
||||
|
||||
// registers a variable in the config file
|
||||
// this should be done before configInit() is called, preferably in a module constructor
|
||||
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max);
|
||||
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max);
|
||||
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max);
|
||||
void configRegisterString(const char *key, char *var, u32 maxstr);
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _IN_DEBUGGER_H
|
||||
#define _IN_DEBUGGER_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
extern s32 g_DebuggerActive;
|
||||
extern s32 g_DebuggerTimePasses;
|
||||
extern s32 g_DebuggerFrameAdvance;
|
||||
|
||||
void debuggerInit(void);
|
||||
void debuggerProcessEvent(void *event);
|
||||
|
||||
void debuggerStartFrame(void);
|
||||
void debuggerFrame(void);
|
||||
void debuggerEndFrame(void);
|
||||
|
||||
void debuggerUpdatePropInfo(s32 clear);
|
||||
Gfx *debuggerDrawPropInfo(Gfx *gdl);
|
||||
|
||||
#endif
|
||||
Vendored
+1865
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,27 @@
|
||||
#ifndef _IN_FS_H
|
||||
#define _IN_FS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
#define FS_MAXPATH 1024
|
||||
|
||||
s32 fsInit(void);
|
||||
|
||||
const char *fsFullPath(const char *relPath);
|
||||
|
||||
s32 fsPathIsAbsolute(const char *path);
|
||||
s32 fsPathIsCwdRelative(const char *path);
|
||||
|
||||
void *fsFileLoad(const char *name, u32 *outSize);
|
||||
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize);
|
||||
s32 fsFileSize(const char *name);
|
||||
|
||||
FILE *fsFileOpenWrite(const char *name);
|
||||
FILE *fsFileOpenRead(const char *name);
|
||||
void fsFileFree(FILE *f);
|
||||
|
||||
const char *fsGetModDir(void);
|
||||
s32 fsCreateDir(const char *path);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
#ifndef _IN_INPUT_H
|
||||
#define _IN_INPUT_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/os_cont.h>
|
||||
|
||||
#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS
|
||||
#define INPUT_MAX_CONNECTED_CONTROLLERS 8
|
||||
#define INPUT_MAX_CONTROLLER_BUTTONS 32
|
||||
#define INPUT_MAX_BINDS 4
|
||||
|
||||
#define CONT_STICK_XNEG 0x10000
|
||||
#define CONT_STICK_XPOS 0x20000
|
||||
#define CONT_STICK_YNEG 0x40000
|
||||
#define CONT_STICK_YPOS 0x80000
|
||||
|
||||
#define CONT_NUM_BUTTONS 32 // not including the stick axes
|
||||
|
||||
enum virtkey {
|
||||
/* same order as SDL scancodes */
|
||||
VK_KEYBOARD_BEGIN = 0,
|
||||
VK_A = 4,
|
||||
VK_Z = 29,
|
||||
VK_1 = 30,
|
||||
VK_9 = 38,
|
||||
VK_0 = 39,
|
||||
VK_RETURN = 40,
|
||||
VK_ESCAPE = 41,
|
||||
VK_BACKSPACE = 42,
|
||||
VK_SPACE = 44,
|
||||
VK_MINUS = 45,
|
||||
VK_LEFTBRACKET = 47,
|
||||
VK_RIGHTBRACKET = 48,
|
||||
VK_SEMICOLON = 51,
|
||||
VK_GRAVE = 53,
|
||||
VK_COMMA = 54,
|
||||
VK_PERIOD = 55,
|
||||
VK_F1 = 58,
|
||||
VK_F9 = 66,
|
||||
VK_DELETE = 76,
|
||||
VK_LCTRL = 224,
|
||||
VK_LSHIFT = 225,
|
||||
VK_LALT = 226,
|
||||
VK_RCTRL = 228,
|
||||
VK_RSHIFT = 229,
|
||||
|
||||
/* same order as SDL mouse buttons */
|
||||
VK_MOUSE_BEGIN = 512,
|
||||
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
|
||||
VK_MOUSE_MIDDLE,
|
||||
VK_MOUSE_RIGHT,
|
||||
VK_MOUSE_X1,
|
||||
VK_MOUSE_X2,
|
||||
VK_MOUSE_WHEEL_UP,
|
||||
VK_MOUSE_WHEEL_DN,
|
||||
|
||||
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
|
||||
VK_JOY_BEGIN,
|
||||
VK_JOY1_BEGIN = VK_JOY_BEGIN,
|
||||
VK_JOY1_LSHOULDER = VK_JOY1_BEGIN + 9,
|
||||
VK_JOY1_RSHOULDER = VK_JOY1_BEGIN + 10,
|
||||
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
|
||||
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
|
||||
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
|
||||
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
};
|
||||
|
||||
enum keymod {
|
||||
/* same order as SDL keymods */
|
||||
KM_LSHIFT = 0x0001,
|
||||
KM_RSHIFT = 0x0002,
|
||||
KM_LCTRL = 0x0040,
|
||||
KM_RCTRL = 0x0080,
|
||||
KM_CAPS = 0x2000,
|
||||
KM_CTRL = KM_LCTRL | KM_RCTRL,
|
||||
KM_SHIFT = KM_LSHIFT | KM_RSHIFT
|
||||
};
|
||||
|
||||
enum contkey {
|
||||
CK_C_R,
|
||||
CK_C_L,
|
||||
CK_C_D,
|
||||
CK_C_U,
|
||||
CK_RTRIG,
|
||||
CK_LTRIG,
|
||||
CK_X, // gap in CONT_
|
||||
CK_Y, // gap in CONT_
|
||||
CK_DPAD_R,
|
||||
CK_DPAD_L,
|
||||
CK_DPAD_D,
|
||||
CK_DPAD_U,
|
||||
CK_START,
|
||||
CK_ZTRIG,
|
||||
CK_B,
|
||||
CK_A,
|
||||
CK_STICK_XNEG,
|
||||
CK_STICK_XPOS,
|
||||
CK_STICK_YNEG,
|
||||
CK_STICK_YPOS,
|
||||
CK_ACCEPT,
|
||||
CK_CANCEL,
|
||||
CK_0040,
|
||||
CK_0080,
|
||||
CK_0100,
|
||||
CK_0200,
|
||||
CK_0400,
|
||||
CK_0800,
|
||||
CK_1000,
|
||||
CK_2000,
|
||||
CK_4000,
|
||||
CK_8000,
|
||||
CK_TOTAL_COUNT
|
||||
};
|
||||
|
||||
enum mouselockmode {
|
||||
MLOCK_OFF = 0,
|
||||
MLOCK_ON = 1,
|
||||
MLOCK_AUTO = 2
|
||||
};
|
||||
|
||||
// returns bitmask of connected controllers or -1 if failed
|
||||
s32 inputInit(void);
|
||||
|
||||
// read the specified player's inputs into the N64 pad struct
|
||||
// returns 0 if read, non-0 if failed
|
||||
s32 inputReadController(s32 idx, OSContPad *npad);
|
||||
|
||||
// returns 1 if rumble is supported for specified player's controller
|
||||
s32 inputRumbleSupported(s32 idx);
|
||||
|
||||
// returns 1 if specified player has a live controller assigned
|
||||
s32 inputControllerConnected(s32 idx);
|
||||
|
||||
// returns bitmask of players with assigned controllers
|
||||
s32 inputControllerMask(void);
|
||||
|
||||
// get/set Input.Player%d.SwapSticks
|
||||
s32 inputControllerGetSticksSwapped(s32 cidx);
|
||||
void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);
|
||||
|
||||
// get/set Input.Player%d.StickCButtons (DualAnalog is 1 if StickCButtons is 0)
|
||||
s32 inputControllerGetDualAnalog(s32 cidx);
|
||||
void inputControllerSetDualAnalog(s32 cidx, s32 enable);
|
||||
|
||||
// get/set Input.Player%d.CancelCButtons
|
||||
s32 inputControllerGetCancelCButtons(s32 cidx);
|
||||
void inputControllerSetCancelCButtons(s32 cidx, s32 cancel);
|
||||
|
||||
// get/set sensitivity for a given player
|
||||
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
|
||||
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);
|
||||
|
||||
// get/set deadzone for a given player
|
||||
f32 inputControllerGetAxisDeadzone(s32 cidx, s32 stick, s32 axis);
|
||||
void inputControllerSetAxisDeadzone(s32 cidx, s32 stick, s32 axis, f32 value);
|
||||
|
||||
// writes array of up to INPUT_MAX_CONNECTED_CONTROLLERS controller IDs
|
||||
// for all the controllers available on this machine into out if it's not NULL
|
||||
// returns number of IDs that would've been written (or were written if out is not NULL)
|
||||
s32 inputGetConnectedControllers(s32 *out);
|
||||
|
||||
// get name of connected controller id
|
||||
// returns "Invalid" on failure
|
||||
const char *inputGetConnectedControllerName(s32 id);
|
||||
|
||||
// get id of the controller currently assigned to player cidx or -1 if none
|
||||
s32 inputGetAssignedControllerId(s32 cidx);
|
||||
|
||||
// assign connected controller id to player cidx
|
||||
// if id is -1, unassigns controller from player, if any
|
||||
// returns true on success, false on failure
|
||||
s32 inputAssignController(s32 cidx, s32 id);
|
||||
|
||||
// vk is a value from the virtkey enum above
|
||||
s32 inputKeyPressed(u32 vk);
|
||||
s32 inputKeyJustPressed(u32 vk);
|
||||
|
||||
// idx is controller index, contbtn is one of the CONT_ constants
|
||||
s32 inputButtonPressed(s32 idx, u32 contbtn);
|
||||
|
||||
// bind virtkey vk to n64 pad #idx's button/axis ck as represented by its contkey value
|
||||
// if bind is -1, picks a bind slot automatically
|
||||
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);
|
||||
|
||||
const u32 *inputKeyGetBinds(s32 idx, u32 ck);
|
||||
|
||||
// get VK_ value from human-readable name
|
||||
s32 inputGetKeyByName(const char *name);
|
||||
|
||||
// get human-readable name from VK_ value
|
||||
const char *inputGetKeyName(s32 vk);
|
||||
|
||||
// get CK_ value from human-readable name
|
||||
s32 inputGetContKeyByName(const char *name);
|
||||
|
||||
// get human-readable name from CK_ value
|
||||
const char *inputGetContKeyName(u32 ck);
|
||||
|
||||
// strength is 0 .. 1; 0 strength turns it off
|
||||
void inputRumble(s32 idx, f32 strength, f32 time);
|
||||
|
||||
f32 inputRumbleGetStrength(s32 cidx);
|
||||
void inputRumbleSetStrength(s32 cidx, f32 val);
|
||||
|
||||
// locks the mouse cursor in the window and makes it invisible if argument is true
|
||||
void inputLockMouse(s32 lock);
|
||||
|
||||
// returns the current state of the above
|
||||
s32 inputMouseIsLocked(void);
|
||||
|
||||
// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time)
|
||||
// returns true if mouse has moved this input frame
|
||||
s32 inputMouseGetPosition(s32 *x, s32 *y);
|
||||
|
||||
// returns changes in mouse position since last frame, in window coordinates
|
||||
void inputMouseGetRawDelta(s32 *dx, s32 *dy);
|
||||
|
||||
// returns changes in mouse position since last frame, scaled by sensitivity
|
||||
// returns 0, 0 when the mouse is not locked into the window
|
||||
void inputMouseGetScaledDelta(f32 *dx, f32 *dy);
|
||||
|
||||
// returns changes in mouse position since last frame, scaled by absolute sensitivity
|
||||
// returns 0, 0 when the mouse is not locked into the window
|
||||
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy);
|
||||
|
||||
void inputMouseGetSpeed(f32 *x, f32 *y);
|
||||
void inputMouseSetSpeed(f32 x, f32 y);
|
||||
|
||||
s32 inputMouseIsEnabled(void);
|
||||
void inputMouseEnable(s32 enabled);
|
||||
|
||||
// call this every frame
|
||||
void inputUpdate(void);
|
||||
|
||||
// call this before configSave()
|
||||
void inputSaveBinds(void);
|
||||
|
||||
// reset given player's binds to either PC or N64 defaults
|
||||
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode);
|
||||
|
||||
// clear or get the last pressed button
|
||||
void inputClearLastKey(void);
|
||||
s32 inputGetLastKey(void);
|
||||
|
||||
// get/set Input.MouseLockMode
|
||||
s32 inputGetMouseLockMode(void);
|
||||
void inputSetMouseLockMode(s32 lockmode);
|
||||
|
||||
// same as inputLockMouse but works only if mouse is enabled and lockmode == MLOCK_AUTO
|
||||
s32 inputAutoLockMouse(s32 wantlock);
|
||||
|
||||
// show/hide mouse cursor; if mouse lock is on the cursor is always hidden
|
||||
void inputMouseShowCursor(s32 show);
|
||||
|
||||
void inputStartTextInput(void);
|
||||
void inputStopTextInput(void);
|
||||
s32 inputIsTextInputActive(void);
|
||||
|
||||
void inputClearLastTextChar(void);
|
||||
char inputGetLastTextChar(void);
|
||||
|
||||
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly);
|
||||
|
||||
void inputClearClipboard(void);
|
||||
const char *inputGetClipboard(void);
|
||||
|
||||
// returns keymod values
|
||||
u32 inputGetKeyModState(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef MIXER_H
|
||||
#define MIXER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ultra64.h>
|
||||
|
||||
#undef aSegment
|
||||
#undef aClearBuffer
|
||||
#undef aSetBuffer
|
||||
#undef aLoadBuffer
|
||||
#undef aSaveBuffer
|
||||
#undef aDMEMMove
|
||||
#undef aMix
|
||||
#undef aEnvMixer
|
||||
#undef aResample
|
||||
#undef aInterleave
|
||||
#undef aSetVolume
|
||||
#undef aSetVolume32
|
||||
#undef aSetLoop
|
||||
#undef aLoadADPCM
|
||||
#undef aADPCMdec
|
||||
|
||||
void aClearBufferImpl(uint16_t addr, int nbytes);
|
||||
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr);
|
||||
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes);
|
||||
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state);
|
||||
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs);
|
||||
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag);
|
||||
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes);
|
||||
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes);
|
||||
void aInterleaveImpl(void);
|
||||
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr);
|
||||
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t some_vol);
|
||||
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r);
|
||||
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr);
|
||||
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c);
|
||||
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset);
|
||||
|
||||
#define aDisable(pkt, o, b, c) aDisableImpl(o, b, c)
|
||||
#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c)
|
||||
#define aLoadBuffer(pkt, c, d, s) aLoadBufferImpl((void *)(s), d, c)
|
||||
#define aSaveBuffer(pkt, c, s, d) aSaveBufferImpl(s, (int16_t *)(d), c)
|
||||
#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, (int16_t *)(d))
|
||||
#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c)
|
||||
#define aSetLoop(pkt, a) aSetLoopImpl((void *)(a))
|
||||
#define aADPCMdec(pkt, s, f, c, i, o) aADPCMdecImpl(f, (void *)(s), c, i, o)
|
||||
#define aResample(pkt, s, f, p, i, o) aResampleImpl(f, p, (void *)(s), i, o)
|
||||
#define aInterleave(pkt) aInterleaveImpl()
|
||||
#define aMix(pkt, f, g, i, o) aMixImpl(f, g, i, o)
|
||||
#define aEnvMixer(pkt, f, t, s) aEnvMixerImpl(f, (void *)(s), t)
|
||||
#define aSetVolume(pkt, f, v, t, r) aSetVolumeImpl(f, v, t, r)
|
||||
#define aPoleFilter(pkt, f, g, t, s) aPoleFilterImpl(f, g, t, s)
|
||||
#define aPlayMP3(pkt, a, b, c, r) aPlayMP3Impl((void *)(a), b, (void *)(c), r)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef _IN_MOD_H
|
||||
#define _IN_MOD_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
#define MOD_CONFIG_FNAME "modconfig.txt"
|
||||
|
||||
struct animtableentry;
|
||||
|
||||
s32 modConfigLoad(const char *path);
|
||||
|
||||
s32 modTextureLoad(u16 num, void *dst, u32 dstSize);
|
||||
|
||||
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim);
|
||||
void *modAnimationLoadData(u16 num);
|
||||
|
||||
void *modSequenceLoad(u16 num, u32 *outSize);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _IN_MPSETUPS_H
|
||||
#define _IN_MPSETUPS_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
s32 mpsetupLoadCurrentFile(void);
|
||||
s32 mpsetupSaveCurrentFile(void);
|
||||
void mpsetupLoadSetup(s32 slotindex);
|
||||
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile);
|
||||
void mpsetupCopyAllFromPak(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef _IN_PREPROCESS_H
|
||||
#define _IN_PREPROCESS_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
typedef u8 *(*preprocessfunc)(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
u8* preprocessAnimations(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessMpConfigs(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessFont(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessJpnFont(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessALBankFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessSequences(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessTexturesList(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
void preprocessBgSection1(u8* data, u32 size, u32 ofs);
|
||||
void preprocessBgSection2(u8 *data, u32 size);
|
||||
void preprocessBgSection3(u8* data, u32 size);
|
||||
void preprocessBgSection1Header(u8 *data, u32 size);
|
||||
void preprocessBgSection2Header(u8 *data, u32 size);
|
||||
void preprocessBgSection3Header(u8 *data, u32 size);
|
||||
u32 preprocessBgRoom(u8* data, u32 size, u32 room_ofs);
|
||||
|
||||
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessPadsFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessSetupFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessModelFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessGunFile(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _IN_PREPROCESS_COMMON_H
|
||||
#define _IN_PREPROCESS_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "romdata.h"
|
||||
#include "preprocess.h"
|
||||
|
||||
#define MAX_PTR_MARKERS (1024 * 8)
|
||||
|
||||
#define PD_ALIGN(val, size) (((val) + ((size) - 1)) & ~((size) - 1))
|
||||
|
||||
#define PD_PTR_BASE(x, b) (void *)((u8 *)b + (uintptr_t)x)
|
||||
#define PD_PTR_BASEOFS(x, b, d) (void *)((u8 *)b - d + (uintptr_t)x)
|
||||
|
||||
static inline f32 swapF32(f32 x) { *(u32*)&x = PD_BE32(*(u32*)&x); return x; }
|
||||
static inline u32 swapU32(u32 x) { return PD_BE32(x); }
|
||||
static inline s32 swapS32(s32 x) { return PD_BE32(x); }
|
||||
static inline u16 swapU16(u16 x) { return PD_BE16(x); }
|
||||
static inline s16 swapS16(s16 x) { return PD_BE16(x); }
|
||||
static inline void* swapPtr(void** x) { return (void*)PD_BEPTR((uintptr_t)x); }
|
||||
static inline struct coord swapCrd(struct coord crd) { crd.x = swapF32(crd.x); crd.y = swapF32(crd.y); crd.z = swapF32(crd.z); return crd; }
|
||||
static inline u32 swapUnk(u32 x) { assert(0 && "unknown type"); return x; }
|
||||
|
||||
#define PD_SWAPPED_VAL(x) _Generic((x), \
|
||||
f32: swapF32, \
|
||||
u32: swapU32, \
|
||||
s32: swapS32, \
|
||||
u16: swapU16, \
|
||||
s16: swapS16, \
|
||||
struct coord: swapCrd, \
|
||||
default: swapUnk \
|
||||
)(x)
|
||||
|
||||
#define PD_SWAP_VAL(x) x = PD_SWAPPED_VAL(x)
|
||||
|
||||
#define PD_SWAP_PTR(x) x = swapPtr((void *)(x))
|
||||
|
||||
// ptr marker functions
|
||||
|
||||
struct ptrmarker {
|
||||
u32 ptr_src;
|
||||
uintptr_t ptr_host;
|
||||
};
|
||||
|
||||
void ptrAdd(u32 ptr_src, uintptr_t ptr_host);
|
||||
struct ptrmarker* ptrFind(uintptr_t ptr_src);
|
||||
void ptrReset(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _IN_PREPROCESS_GBI_H
|
||||
#define _IN_PREPROCESS_GBI_H
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
// gbi related functions
|
||||
void gbiReset(void);
|
||||
void gbiSetSegment(int segment, u32 offset);
|
||||
void gbiSetVtx(u32 src_offset, u32 dst_offset);
|
||||
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds);
|
||||
void gbiConvertVtx(u8* dst, u32 dstpos, int count);
|
||||
void gbiGdlRewriteAddrs(u8* dst, u32 offset);
|
||||
void gbiAddTexAddr(u32 src_offset, u32 dst_offset);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,640 @@
|
||||
#ifndef _IN_SETUP_DECL
|
||||
#define _IN_SETUP_DECL
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct n64_stagesetup {
|
||||
u32 ptr_waypoints;
|
||||
u32 ptr_waygroups;
|
||||
u32 ptr_cover;
|
||||
u32 ptr_intro;
|
||||
u32 ptr_props;
|
||||
u32 ptr_paths;
|
||||
u32 ptr_ailists;
|
||||
u32 ptr_padfiledata;
|
||||
};
|
||||
|
||||
struct n64_coord {
|
||||
f32 x;
|
||||
f32 y;
|
||||
f32 z;
|
||||
};
|
||||
|
||||
struct n64_defaultobj {
|
||||
u16 extrascale;
|
||||
u8 hidden2;
|
||||
u8 type;
|
||||
s16 modelnum;
|
||||
s16 pad;
|
||||
u32 flags;
|
||||
u32 flags2;
|
||||
u32 flags3;
|
||||
u32 ptr_prop;
|
||||
u32 ptr_model;
|
||||
f32 realrot[3][3];
|
||||
u32 hidden;
|
||||
union {
|
||||
u32 ptr_geotilef;
|
||||
u32 ptr_geoblock;
|
||||
u32 ptr_geocyl;
|
||||
u32 ptr_unkgeo;
|
||||
};
|
||||
union {
|
||||
u32 ptr_projectile;
|
||||
u32 ptr_embedment;
|
||||
};
|
||||
s16 damage;
|
||||
s16 maxdamage;
|
||||
u8 shadecol[4];
|
||||
u8 nextcol[4];
|
||||
u16 floorcol;
|
||||
s8 geocount;
|
||||
s8 _pad_;
|
||||
};
|
||||
|
||||
struct n64_doorobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 maxfrac;
|
||||
f32 perimfrac;
|
||||
f32 accel;
|
||||
f32 decel;
|
||||
f32 maxspeed;
|
||||
u16 doorflags;
|
||||
u16 doortype;
|
||||
u32 keyflags;
|
||||
s32 autoclosetime;
|
||||
f32 frac;
|
||||
f32 fracspeed;
|
||||
s8 mode;
|
||||
s8 glasshits;
|
||||
s16 fadealpha;
|
||||
s16 xludist;
|
||||
s16 opadist;
|
||||
struct n64_coord startpos;
|
||||
f32 mtx98[3][3];
|
||||
u32 ptr_sibling;
|
||||
s32 lastopen60;
|
||||
s16 portalnum;
|
||||
s8 soundtype;
|
||||
s8 fadetime60;
|
||||
s32 lastcalc60;
|
||||
u8 laserfade;
|
||||
u8 unusedmaybe[3];
|
||||
u8 shadeinfo1[4];
|
||||
u8 shadeinfo2[4];
|
||||
u8 actual1;
|
||||
u8 actual2;
|
||||
u8 extra1;
|
||||
u8 extra2;
|
||||
};
|
||||
|
||||
struct n64_doorscaleobj {
|
||||
u32 unk00;
|
||||
s32 scale;
|
||||
};
|
||||
|
||||
struct n64_keyobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 keyflags;
|
||||
};
|
||||
|
||||
struct n64_alarmobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_cctvobj {
|
||||
struct n64_defaultobj base;
|
||||
|
||||
s16 lookatpadnum;
|
||||
s16 toleft;
|
||||
//Mtxf camrotm;
|
||||
f32 m[4][4];
|
||||
f32 yzero;
|
||||
f32 yrot;
|
||||
f32 yleft;
|
||||
f32 yright;
|
||||
f32 yspeed;
|
||||
f32 ymaxspeed;
|
||||
s32 seebondtime60;
|
||||
f32 maxdist;
|
||||
f32 xzero;
|
||||
};
|
||||
|
||||
struct n64_ammocrateobj {
|
||||
struct n64_defaultobj base;
|
||||
s32 ammotype;
|
||||
};
|
||||
|
||||
struct n64_gset {
|
||||
u8 weaponnum;
|
||||
u8 unk0639;
|
||||
u8 unk063a;
|
||||
u8 weaponfunc;
|
||||
};
|
||||
|
||||
struct n64_weaponobj {
|
||||
struct n64_defaultobj base;
|
||||
|
||||
union {
|
||||
struct n64_gset gset;
|
||||
struct {
|
||||
u8 weaponnum;
|
||||
s8 unk5d;
|
||||
s8 unk5e;
|
||||
u8 gunfunc;
|
||||
};
|
||||
};
|
||||
|
||||
s8 fadeouttimer60;
|
||||
s8 dualweaponnum;
|
||||
|
||||
union {
|
||||
s16 timer240;
|
||||
s16 team;
|
||||
};
|
||||
|
||||
u32 ptr_dualweapon;
|
||||
};
|
||||
|
||||
struct n64_packedchr {
|
||||
s16 chrindex;
|
||||
s8 unk02;
|
||||
s8 typenum;
|
||||
u32 spawnflags;
|
||||
s16 chrnum;
|
||||
u16 padnum;
|
||||
u8 bodynum;
|
||||
s8 headnum;
|
||||
u16 ailistnum;
|
||||
u16 padpreset;
|
||||
u16 chrpreset;
|
||||
u16 hearscale;
|
||||
u16 viewdist;
|
||||
u32 flags;
|
||||
u32 flags2;
|
||||
u8 team;
|
||||
u8 squadron;
|
||||
s16 chair;
|
||||
u32 convtalk;
|
||||
u8 tude;
|
||||
u8 naturalanim;
|
||||
u8 yvisang;
|
||||
u8 teamscandist;
|
||||
};
|
||||
|
||||
struct n64_tvscreen {
|
||||
u32 ptr_cmdlist;
|
||||
u16 offset;
|
||||
s16 pause60;
|
||||
u32 ptr_tconfig;
|
||||
f32 rot;
|
||||
f32 xscale;
|
||||
f32 xscalefrac;
|
||||
f32 xscaleinc;
|
||||
f32 xscaleold;
|
||||
f32 xscalenew;
|
||||
f32 yscale;
|
||||
f32 yscalefrac;
|
||||
f32 yscaleinc;
|
||||
f32 yscaleold;
|
||||
f32 yscalenew;
|
||||
f32 xmid;
|
||||
f32 xmidfrac;
|
||||
f32 xmidinc;
|
||||
f32 xmidold;
|
||||
f32 xmidnew;
|
||||
f32 ymid;
|
||||
f32 ymidfrac;
|
||||
f32 ymidinc;
|
||||
f32 ymidold;
|
||||
f32 ymidnew;
|
||||
u8 red;
|
||||
u8 redold;
|
||||
u8 rednew;
|
||||
u8 green;
|
||||
u8 greenold;
|
||||
u8 greennew;
|
||||
u8 blue;
|
||||
u8 blueold;
|
||||
u8 bluenew;
|
||||
u8 alpha;
|
||||
u8 alphaold;
|
||||
u8 alphanew;
|
||||
f32 colfrac;
|
||||
f32 colinc;
|
||||
};
|
||||
|
||||
struct n64_singlemonitorobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_tvscreen screen;
|
||||
s16 owneroffset;
|
||||
s8 ownerpart;
|
||||
u8 imagenum;
|
||||
};
|
||||
|
||||
struct n64_multimonitorobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_tvscreen screens[4];
|
||||
u8 imagenums[4];
|
||||
};
|
||||
|
||||
struct n64_hangingmonitorsobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_autogunobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 targetpad;
|
||||
s8 firing;
|
||||
u8 firecount;
|
||||
f32 yzero;
|
||||
f32 ymaxleft;
|
||||
f32 ymaxright;
|
||||
f32 yrot;
|
||||
f32 yspeed;
|
||||
f32 xzero;
|
||||
f32 xrot;
|
||||
f32 xspeed;
|
||||
f32 maxspeed;
|
||||
f32 aimdist;
|
||||
f32 barrelspeed;
|
||||
f32 barrelrot;
|
||||
s32 lastseebond60;
|
||||
s32 lastaimbond60;
|
||||
s32 allowsoundframe;
|
||||
u32 ptr_beam;
|
||||
f32 shotbondsum;
|
||||
u32 ptr_target;
|
||||
u8 targetteam;
|
||||
u8 ammoquantity;
|
||||
s16 nextchrtest;
|
||||
};
|
||||
|
||||
struct n64_linkgunsobj {
|
||||
u32 unk00;
|
||||
s16 offset1;
|
||||
s16 offset2;
|
||||
};
|
||||
|
||||
struct n64_debrisobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_hatobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_grenadeprobobj { // objtype 0x12
|
||||
u32 unk00;
|
||||
s16 chrnum;
|
||||
u16 probability;
|
||||
};
|
||||
|
||||
struct n64_linkliftdoorobj {
|
||||
u32 unk00;
|
||||
u32 ptr_door;
|
||||
u32 ptr_lift;
|
||||
u32 ptr_next;
|
||||
s32 stopnum;
|
||||
};
|
||||
|
||||
struct n64_multiammocrateslot {
|
||||
u16 modelnum;
|
||||
u16 quantity;
|
||||
};
|
||||
|
||||
struct n64_multiammocrateobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_multiammocrateslot slots[19];
|
||||
};
|
||||
|
||||
struct n64_shieldobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 initialamount;
|
||||
f32 amount;
|
||||
u32 unk64;
|
||||
};
|
||||
|
||||
struct n64_tag {
|
||||
u32 identifier;
|
||||
u16 tagnum;
|
||||
s16 cmdoffset;
|
||||
u32 ptr_next;
|
||||
u32 ptr_obj;
|
||||
};
|
||||
|
||||
struct n64_objective {
|
||||
u32 unk00;
|
||||
s32 index;
|
||||
u32 text;
|
||||
u16 unk0c;
|
||||
u8 flags;
|
||||
s8 difficulties;
|
||||
};
|
||||
|
||||
struct n64_stdobjective {
|
||||
u32 cmd;
|
||||
};
|
||||
|
||||
struct n64_objectivecmd {
|
||||
u8 cmd0[4];
|
||||
u32 cmd1;
|
||||
};
|
||||
|
||||
struct n64_briefingobj {
|
||||
u32 unk00;
|
||||
u32 type;
|
||||
u32 text;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_padlockeddoorobj {
|
||||
u32 unk00;
|
||||
u32 ptr_door;
|
||||
u32 ptr_lock;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_truckobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 speed;
|
||||
f32 wheelxrot;
|
||||
f32 wheelyrot;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
};
|
||||
|
||||
struct n64_tankobj {
|
||||
u8 _pad_[128];
|
||||
};
|
||||
|
||||
struct n64_heliobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 rotoryrot;
|
||||
f32 rotoryspeed;
|
||||
f32 rotoryspeedaim;
|
||||
f32 rotoryspeedtime;
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 yrot;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
};
|
||||
|
||||
struct n64_glassobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 portalnum;
|
||||
s16 _pad_;
|
||||
};
|
||||
|
||||
struct n64_safeobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_safeitemobj {
|
||||
u32 unk00;
|
||||
u32 ptr_item;
|
||||
u32 ptr_safe;
|
||||
u32 ptr_door;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_cameraposobj {
|
||||
s32 type;
|
||||
f32 x;
|
||||
f32 y;
|
||||
f32 z;
|
||||
f32 theta;
|
||||
f32 verta;
|
||||
s32 pad;
|
||||
};
|
||||
|
||||
struct n64_tintedglassobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 xludist;
|
||||
s16 opadist;
|
||||
s16 opacity;
|
||||
s16 portalnum;
|
||||
f32 unk64;
|
||||
};
|
||||
|
||||
struct n64_liftobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 pads[4];
|
||||
u32 ptr_doors[4];
|
||||
f32 dist;
|
||||
f32 speed;
|
||||
f32 accel;
|
||||
f32 maxspeed;
|
||||
s8 soundtype;
|
||||
s8 levelcur;
|
||||
s8 levelaim;
|
||||
s8 _pad_;
|
||||
struct n64_coord prevpos;
|
||||
};
|
||||
|
||||
struct n64_linksceneryobj {
|
||||
u32 unk00;
|
||||
u32 ptr_trigger;
|
||||
u32 ptr_unexp;
|
||||
u32 ptr_exp;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_blockedpathobj {
|
||||
u32 unk00;
|
||||
u32 ptr_blocker;
|
||||
s16 waypoint1;
|
||||
s16 waypoint2;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_hov {
|
||||
u8 type;
|
||||
u8 flags;
|
||||
s16 _pad_;
|
||||
f32 bobycur;
|
||||
f32 bobytarget;
|
||||
f32 bobyspeed;
|
||||
f32 yrot;
|
||||
f32 bobpitchcur;
|
||||
f32 bobpitchtarget;
|
||||
f32 bobpitchspeed;
|
||||
f32 bobrollcur;
|
||||
f32 bobrolltarget;
|
||||
f32 bobrollspeed;
|
||||
f32 groundpitch;
|
||||
f32 y;
|
||||
f32 ground;
|
||||
s32 prevframe60;
|
||||
s32 prevgroundframe60;
|
||||
};
|
||||
|
||||
struct n64_hoverbikeobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_hov hov;
|
||||
f32 speed[2];
|
||||
f32 prevpos[2];
|
||||
f32 w;
|
||||
f32 rels[2];
|
||||
f32 exreal;
|
||||
f32 ezreal;
|
||||
f32 ezreal2;
|
||||
f32 leanspeed;
|
||||
f32 leandiff;
|
||||
s32 maxspeedtime240;
|
||||
f32 speedabs[2];
|
||||
f32 speedrel[2];
|
||||
};
|
||||
|
||||
struct n64_hoverpropobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_hov hov;
|
||||
};
|
||||
|
||||
struct n64_fanobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 yrot;
|
||||
f32 yrotprev;
|
||||
f32 ymaxspeed;
|
||||
f32 yspeed;
|
||||
f32 yaccel;
|
||||
s8 on;
|
||||
u8 _pad_[3];
|
||||
};
|
||||
|
||||
struct n64_hovercarobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 turnyspeed60;
|
||||
f32 turnxspeed60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
f32 rotx;
|
||||
f32 rotz;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
s16 status;
|
||||
s16 dead;
|
||||
s16 deadtimer60;
|
||||
s16 sparkstimer60;
|
||||
};
|
||||
|
||||
struct n64_chopperobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
union {
|
||||
struct {
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
};
|
||||
struct n64_coord fall;
|
||||
};
|
||||
f32 turnyspeed60;
|
||||
f32 turnxspeed60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
f32 rotx;
|
||||
f32 rotz;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;//
|
||||
s16 weaponsarmed;
|
||||
s16 ontarget;
|
||||
s16 target;
|
||||
u8 attackmode;
|
||||
u8 cw;
|
||||
f32 vx;
|
||||
f32 vy;
|
||||
f32 vz;
|
||||
f32 power;
|
||||
f32 otx;
|
||||
f32 oty;
|
||||
f32 otz;
|
||||
f32 bob;
|
||||
f32 bobstrength;
|
||||
s32 targetvisible;
|
||||
s32 timer60;
|
||||
s32 patroltimer60;
|
||||
f32 gunturnyspeed60;
|
||||
f32 gunturnxspeed60;
|
||||
f32 gunroty;
|
||||
f32 gunrotx;
|
||||
f32 barrelrotspeed;
|
||||
f32 barrelrot;
|
||||
u32 ptr_fireslotthing;
|
||||
s32 dead;
|
||||
};
|
||||
|
||||
struct n64_escalatorobj {
|
||||
struct n64_defaultobj base;
|
||||
s32 frame;
|
||||
struct n64_coord prevpos;
|
||||
};
|
||||
|
||||
struct n64_textoverride {
|
||||
u32 unk00;
|
||||
s32 objoffset;
|
||||
s32 weapon;
|
||||
u32 obtaintext;
|
||||
u32 ownertext;
|
||||
u32 inventorytext;
|
||||
u32 inventory2text;
|
||||
u32 pickuptext;
|
||||
u32 ptr_next;
|
||||
u32 ptr_obj;
|
||||
};
|
||||
|
||||
struct n64_criteria_roomentered {
|
||||
u32 unk00;
|
||||
u32 pad;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_criteria_throwinroom {
|
||||
u32 unk00;
|
||||
u32 unk04;
|
||||
u32 pad;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_criteria_holograph {
|
||||
u32 unk00;
|
||||
u32 obj;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_ailist {
|
||||
u32 ptr_list;
|
||||
s32 id;
|
||||
};
|
||||
|
||||
struct n64_path {
|
||||
u32 ptr_pads;
|
||||
u8 id;
|
||||
u8 flags;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef _IN_ROMDATA_H
|
||||
#define _IN_ROMDATA_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
extern u8 *g_RomFile;
|
||||
extern u32 g_RomFileSize;
|
||||
|
||||
s32 romdataInit(void);
|
||||
|
||||
u8 *romdataFileLoad(s32 fileNum, u32 *outSize);
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize);
|
||||
void romdataFileFree(s32 fileNum);
|
||||
const char *romdataFileGetName(s32 fileNum);
|
||||
|
||||
u8 *romdataFileGetData(s32 fileNum);
|
||||
s32 romdataFileGetSize(s32 fileNum);
|
||||
|
||||
s32 romdataFileGetNumForName(const char *name);
|
||||
|
||||
u8 *romdataSegGetData(const char *segName);
|
||||
u8 *romdataSegGetDataEnd(const char *segName);
|
||||
u32 romdataSegGetSize(const char *segName);
|
||||
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype);
|
||||
|
||||
s32 romdataCheckGbcRom(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef _IN_SYSTEM_H
|
||||
#define _IN_SYSTEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
enum LogLevel {
|
||||
LOG_NOTE,
|
||||
LOG_WARNING,
|
||||
LOG_ERROR,
|
||||
};
|
||||
|
||||
void sysInitArgs(s32 argc, const char **argv);
|
||||
void sysInit(void);
|
||||
|
||||
s32 sysArgCheck(const char *arg);
|
||||
const char *sysArgGetString(const char *arg);
|
||||
s32 sysArgGetInt(const char *arg, s32 defval);
|
||||
|
||||
u64 sysGetMicroseconds(void);
|
||||
|
||||
void sysFatalError(const char *fmt, ...) __attribute__((noreturn));
|
||||
|
||||
s32 sysLogIsOpen(void);
|
||||
void sysLogPrintf(s32 level, const char *fmt, ...);
|
||||
|
||||
void sysGetExecutablePath(char *outPath, const u32 outLen);
|
||||
void sysGetHomePath(char *outPath, const u32 outLen);
|
||||
|
||||
void *sysMemAlloc(const u32 size);
|
||||
void *sysMemZeroAlloc(const u32 size);
|
||||
void *sysMemRealloc(void *ptr, const u32 newSize);
|
||||
void sysMemFree(void *ptr);
|
||||
|
||||
// hns is specified in 100ns units
|
||||
void sysSleep(const s64 hns);
|
||||
|
||||
// yield CPU if supported (e.g. during a busy loop)
|
||||
void sysCpuRelax(void);
|
||||
|
||||
void crashInit(void);
|
||||
void crashShutdown(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _IN_UTILS_H
|
||||
#define _IN_UTILS_H
|
||||
|
||||
#define UTIL_MAX_TOKEN 1024
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
char *strRightTrim(char *str);
|
||||
char *strTrim(char *str);
|
||||
char *strUnquote(char *str);
|
||||
char *strParseToken(char *str, char *out, s32 *outCount);
|
||||
char *strFmt(const char *fmt, ...);
|
||||
char *strDuplicate(const char *str);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef _IN_VERSIONINFO_H
|
||||
#define _IN_VERSIONINFO_H
|
||||
|
||||
#define VERSION_TARGET "@VERSION_TARGET@"
|
||||
#define VERSION_ARCH "@VERSION_ARCH@"
|
||||
#define VERSION_ROMID "@VERSION_ROMID@"
|
||||
#define VERSION_BUILD "@VERSION_BUILD@"
|
||||
#define VERSION_HASH "@VERSION_HASH@"
|
||||
#define VERSION_BRANCH "@VERSION_BRANCH@"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef _IN_VIDEO_H
|
||||
#define _IN_VIDEO_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
// maximum framerate; if the game runs faster than this, things will break
|
||||
#if PAL
|
||||
#define VIDEO_MAX_FPS 200
|
||||
#else
|
||||
#define VIDEO_MAX_FPS 240
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
s32 width;
|
||||
s32 height;
|
||||
} displaymode;
|
||||
|
||||
s32 videoInit(void);
|
||||
void videoStartFrame(void);
|
||||
void videoSubmitCommands(Gfx *cmds);
|
||||
void videoClearScreen(void);
|
||||
void videoEndFrame(void);
|
||||
|
||||
void *videoGetWindowHandle(void);
|
||||
|
||||
void videoUpdateNativeResolution(s32 w, s32 h);
|
||||
s32 videoGetNativeWidth(void);
|
||||
s32 videoGetNativeHeight(void);
|
||||
|
||||
s32 videoGetWidth(void);
|
||||
s32 videoGetHeight(void);
|
||||
f32 videoGetAspect(void);
|
||||
s32 videoGetFullscreen(void);
|
||||
s32 videoGetFullscreenMode(void);
|
||||
s32 videoGetMaximizeWindow(void);
|
||||
void videoSetMaximizeWindow(s32 fs);
|
||||
s32 videoGetCenterWindow(void);
|
||||
void videoSetCenterWindow(s32 center);
|
||||
u32 videoGetTextureFilter(void);
|
||||
s32 videoGetTextureFilter2D(void);
|
||||
s32 videoGetDetailTextures(void);
|
||||
s32 videoGetDisplayModeIndex(void);
|
||||
s32 videoGetDisplayMode(displaymode *out, const s32 index);
|
||||
s32 videoGetNumDisplayModes(void);
|
||||
s32 videoGetVsync(void);
|
||||
s32 videoGetFramerateLimit(void);
|
||||
s32 videoGetDisplayFPS(void);
|
||||
s32 videoGetMSAA(void);
|
||||
|
||||
f32 videoGetAverageFPS(void);
|
||||
f64 videoGetLastRenderTime(void);
|
||||
|
||||
void videoSetWindowOffset(s32 x, s32 y);
|
||||
void videoSetFullscreen(s32 fs);
|
||||
void videoSetFullscreenMode(s32 mode);
|
||||
void videoSetTextureFilter(u32 filter);
|
||||
void videoSetTextureFilter2D(s32 filter);
|
||||
void videoSetDetailTextures(s32 detail);
|
||||
void videoSetDisplayMode(const s32 index);
|
||||
void videoSetVsync(const s32 vsync);
|
||||
void videoSetFramerateLimit(const s32 limit);
|
||||
void videoSetDisplayFPS(const s32 displayfps);
|
||||
void videoSetMSAA(const s32 msaa);
|
||||
|
||||
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
|
||||
void videoSetFramebuffer(s32 target);
|
||||
void videoResetFramebuffer(void);
|
||||
void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top);
|
||||
void videoResizeFramebuffer(s32 target, u32 w, u32 h, s32 upscale, s32 autoresize);
|
||||
s32 videoFramebuffersSupported(void);
|
||||
|
||||
void videoResetTextureCache(void);
|
||||
void videoFreeCachedTexture(const void *texptr);
|
||||
|
||||
void videoShutdown(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
#include <PR/ultratypes.h>
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include "platform.h"
|
||||
#include "config.h"
|
||||
#include "audio.h"
|
||||
#include "system.h"
|
||||
|
||||
static SDL_AudioDeviceID dev;
|
||||
static const s16 *nextBuf;
|
||||
static u32 nextSize = 0;
|
||||
|
||||
static s32 bufferSize = 512;
|
||||
static s32 queueLimit = 8192;
|
||||
|
||||
s32 audioInit(void)
|
||||
{
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
sysLogPrintf(LOG_ERROR, "SDL audio init error: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_AudioSpec want, have;
|
||||
SDL_zero(want);
|
||||
want.freq = 22020; // TODO: this might cause trouble for some platforms
|
||||
want.format = AUDIO_S16SYS;
|
||||
want.channels = 2;
|
||||
want.samples = bufferSize;
|
||||
want.callback = NULL;
|
||||
|
||||
nextBuf = NULL;
|
||||
|
||||
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
|
||||
if (dev == 0) {
|
||||
sysLogPrintf(LOG_ERROR, "SDL_OpenAudio error: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_PauseAudioDevice(dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 audioGetBytesBuffered(void)
|
||||
{
|
||||
return SDL_GetQueuedAudioSize(dev);
|
||||
}
|
||||
|
||||
s32 audioGetSamplesBuffered(void)
|
||||
{
|
||||
return audioGetBytesBuffered() / 4;
|
||||
}
|
||||
|
||||
void audioSetNextBuffer(const s16 *buf, u32 len)
|
||||
{
|
||||
nextBuf = buf;
|
||||
nextSize = len;
|
||||
}
|
||||
|
||||
void audioEndFrame(void)
|
||||
{
|
||||
if (nextBuf && nextSize) {
|
||||
if (audioGetSamplesBuffered() < queueLimit) {
|
||||
SDL_QueueAudio(dev, nextBuf, nextSize);
|
||||
}
|
||||
nextBuf = NULL;
|
||||
nextSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void audioConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024);
|
||||
configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "fs.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define CONFIG_MAX_SECNAME 128
|
||||
#define CONFIG_MAX_KEYNAME 256
|
||||
#define CONFIG_MAX_SETTINGS 300
|
||||
|
||||
typedef enum {
|
||||
CFG_NONE,
|
||||
CFG_S32,
|
||||
CFG_F32,
|
||||
CFG_U32,
|
||||
CFG_STR
|
||||
} configtype;
|
||||
|
||||
struct configentry {
|
||||
char key[CONFIG_MAX_KEYNAME + 1];
|
||||
s32 seclen;
|
||||
configtype type;
|
||||
void *ptr;
|
||||
union {
|
||||
struct { f32 min_f32, max_f32; };
|
||||
struct { s32 min_s32, max_s32; };
|
||||
struct { u32 min_u32, max_u32; };
|
||||
u32 max_str;
|
||||
};
|
||||
} settings[CONFIG_MAX_SETTINGS];
|
||||
|
||||
static s32 numSettings = 0;
|
||||
static u8 configMaxWarningLogged = 0;
|
||||
|
||||
static inline s32 configClampInt(s32 val, s32 min, s32 max)
|
||||
{
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline u32 configClampUInt(u32 val, u32 min, u32 max)
|
||||
{
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline f32 configClampFloat(f32 val, f32 min, f32 max)
|
||||
{
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline struct configentry *configFindEntry(const char *key)
|
||||
{
|
||||
for (s32 i = 0; i < numSettings; ++i) {
|
||||
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
|
||||
return &settings[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct configentry *configAddEntry(const char *key)
|
||||
{
|
||||
if (numSettings < CONFIG_MAX_SETTINGS) {
|
||||
struct configentry *cfg = &settings[numSettings++];
|
||||
snprintf(cfg->key, CONFIG_MAX_KEYNAME, "%s", key);
|
||||
const char *delim = strrchr(cfg->key, '.');
|
||||
cfg->seclen = delim ? (delim - cfg->key) : 0;
|
||||
return cfg;
|
||||
}
|
||||
if (!configMaxWarningLogged) {
|
||||
sysLogPrintf(LOG_WARNING, "Maximum number of configuration entries exceeded: %d", CONFIG_MAX_SETTINGS);
|
||||
configMaxWarningLogged = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct configentry *configFindOrAddEntry(const char *key)
|
||||
{
|
||||
for (s32 i = 0; i < numSettings; ++i) {
|
||||
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
|
||||
return &settings[i];
|
||||
}
|
||||
}
|
||||
return configAddEntry(key);
|
||||
}
|
||||
|
||||
static inline const char *configGetSection(char *sec, const struct configentry *cfg)
|
||||
{
|
||||
if (!cfg->seclen || cfg->seclen > CONFIG_MAX_SECNAME) {
|
||||
strncpy(sec, cfg->key, CONFIG_MAX_SECNAME);
|
||||
sec[CONFIG_MAX_SECNAME] = '\0';
|
||||
return sec;
|
||||
}
|
||||
|
||||
memcpy(sec, cfg->key, cfg->seclen);
|
||||
sec[cfg->seclen] = '\0';
|
||||
|
||||
return sec;
|
||||
}
|
||||
|
||||
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max)
|
||||
{
|
||||
struct configentry *cfg = configFindOrAddEntry(key);
|
||||
if (cfg) {
|
||||
cfg->type = CFG_S32;
|
||||
cfg->ptr = var;
|
||||
cfg->min_s32 = min;
|
||||
cfg->max_s32 = max;
|
||||
}
|
||||
}
|
||||
|
||||
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max)
|
||||
{
|
||||
struct configentry* cfg = configFindOrAddEntry(key);
|
||||
if (cfg) {
|
||||
cfg->type = CFG_U32;
|
||||
cfg->ptr = var;
|
||||
cfg->min_u32 = min;
|
||||
cfg->max_u32 = max;
|
||||
}
|
||||
}
|
||||
|
||||
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max)
|
||||
{
|
||||
struct configentry *cfg = configFindOrAddEntry(key);
|
||||
if (cfg) {
|
||||
cfg->type = CFG_F32;
|
||||
cfg->ptr = var;
|
||||
cfg->min_f32 = min;
|
||||
cfg->max_f32 = max;
|
||||
}
|
||||
}
|
||||
|
||||
void configRegisterString(const char *key, char *var, u32 maxstr)
|
||||
{
|
||||
struct configentry *cfg = configFindOrAddEntry(key);
|
||||
if (cfg) {
|
||||
cfg->type = CFG_STR;
|
||||
cfg->ptr = var;
|
||||
cfg->max_str = maxstr;
|
||||
}
|
||||
}
|
||||
|
||||
static void configSetFromString(const char *key, const char *val)
|
||||
{
|
||||
struct configentry *cfg = configFindEntry(key);
|
||||
if (!cfg) return;
|
||||
|
||||
s32 tmp_s32;
|
||||
f32 tmp_f32;
|
||||
u32 tmp_u32;
|
||||
switch (cfg->type) {
|
||||
case CFG_S32:
|
||||
tmp_s32 = strtol(val, NULL, 0);
|
||||
if (cfg->min_s32 < cfg->max_s32) {
|
||||
tmp_s32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32);
|
||||
}
|
||||
*(s32 *)cfg->ptr = tmp_s32;
|
||||
break;
|
||||
case CFG_F32:
|
||||
tmp_f32 = strtof(val, NULL);
|
||||
if (cfg->min_f32 < cfg->max_f32) {
|
||||
tmp_f32 = configClampFloat(tmp_f32, cfg->min_f32, cfg->max_f32);
|
||||
}
|
||||
*(f32 *)cfg->ptr = tmp_f32;
|
||||
break;
|
||||
case CFG_U32:
|
||||
tmp_u32 = strtoul(val, NULL, 0);
|
||||
if (cfg->min_u32 < cfg->max_u32) {
|
||||
tmp_u32 = configClampUInt(tmp_u32, cfg->min_u32, cfg->max_u32);
|
||||
}
|
||||
*(u32*)cfg->ptr = tmp_u32;
|
||||
break;
|
||||
case CFG_STR:
|
||||
strncpy(cfg->ptr, val, cfg->max_str ? cfg->max_str - 1 : 4096);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void configSaveEntry(struct configentry *cfg, FILE *f)
|
||||
{
|
||||
switch (cfg->type) {
|
||||
case CFG_S32:
|
||||
if (cfg->min_s32 < cfg->max_s32) {
|
||||
*(s32 *)cfg->ptr = configClampInt(*(s32 *)cfg->ptr, cfg->min_s32, cfg->max_s32);
|
||||
}
|
||||
fprintf(f, "%s=%d\n", cfg->key + cfg->seclen + 1, *(s32 *)cfg->ptr);
|
||||
break;
|
||||
case CFG_F32:
|
||||
if (cfg->min_f32 < cfg->max_f32) {
|
||||
*(f32 *)cfg->ptr = configClampFloat(*(f32 *)cfg->ptr, cfg->min_f32, cfg->max_f32);
|
||||
}
|
||||
fprintf(f, "%s=%f\n", cfg->key + cfg->seclen + 1, *(f32 *)cfg->ptr);
|
||||
break;
|
||||
case CFG_U32:
|
||||
if (cfg->min_u32 < cfg->max_u32) {
|
||||
*(u32*)cfg->ptr = configClampUInt(*(u32*)cfg->ptr, cfg->min_u32, cfg->max_u32);
|
||||
}
|
||||
fprintf(f, "%s=%u\n", cfg->key + cfg->seclen + 1, *(u32 *)cfg->ptr);
|
||||
break;
|
||||
case CFG_STR:
|
||||
fprintf(f, "%s=%s\n", cfg->key + cfg->seclen + 1, (char *)cfg->ptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s32 configSave(const char *fname)
|
||||
{
|
||||
FILE *f = fsFileOpenWrite(fname);
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char tmpSec[CONFIG_MAX_SECNAME + 1] = { 0 };
|
||||
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
|
||||
configGetSection(curSec, &settings[0]);
|
||||
fprintf(f, "[%s]\n", curSec);
|
||||
|
||||
for (s32 i = 0; i < numSettings; ++i) {
|
||||
struct configentry *cfg = &settings[i];
|
||||
configGetSection(tmpSec, cfg);
|
||||
if (strncmp(curSec, tmpSec, CONFIG_MAX_SECNAME) != 0) {
|
||||
fprintf(f, "\n[%s]\n", tmpSec);
|
||||
strncpy(curSec, tmpSec, CONFIG_MAX_SECNAME);
|
||||
}
|
||||
configSaveEntry(cfg, f);
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 configLoad(const char *fname)
|
||||
{
|
||||
FILE *f = fsFileOpenRead(fname);
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
|
||||
char keyBuf[CONFIG_MAX_SECNAME * 2 + 2] = { 0 }; // SECTION + . + KEY + \0
|
||||
char token[UTIL_MAX_TOKEN + 1] = { 0 };
|
||||
char lineBuf[2048] = { 0 };
|
||||
char *line = lineBuf;
|
||||
s32 lineLen = 0;
|
||||
|
||||
while (fgets(lineBuf, sizeof(lineBuf), f)) {
|
||||
line = lineBuf;
|
||||
|
||||
line = strParseToken(line, token, NULL);
|
||||
|
||||
if (token[0] == '[' && token[1] == '\0') {
|
||||
// section; get name
|
||||
line = strParseToken(line, token, NULL);
|
||||
if (!token[0]) {
|
||||
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
|
||||
continue;
|
||||
}
|
||||
strncpy(curSec, token, CONFIG_MAX_SECNAME);
|
||||
// eat ]
|
||||
line = strParseToken(line, token, NULL);
|
||||
if (token[0] != ']' || token[1] != '\0') {
|
||||
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
|
||||
}
|
||||
} else if (token[0]) {
|
||||
// probably a key=value pair; append key name to section name
|
||||
snprintf(keyBuf, sizeof(keyBuf) - 1, "%s.%s", curSec, token);
|
||||
// eat =
|
||||
line = strParseToken(line, token, NULL);
|
||||
if (token[0] != '=' || token[1] != '\0') {
|
||||
sysLogPrintf(LOG_ERROR, "configLoad: malformed keyvalue line: %s", lineBuf);
|
||||
continue;
|
||||
}
|
||||
// the rest of the line is the value
|
||||
line = strTrim(line);
|
||||
if (line[0] == '"') {
|
||||
line = strUnquote(line);
|
||||
}
|
||||
configSetFromString(keyBuf, line);
|
||||
}
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void configInit(void)
|
||||
{
|
||||
if (fsFileSize(CONFIG_PATH) > 0) {
|
||||
configLoad(CONFIG_PATH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <SDL.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "system.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define CRASH_LOG_FNAME "pd.crash.log"
|
||||
#define CRASH_MAX_MSG 8192
|
||||
#define CRASH_MAX_SYM 256
|
||||
#define CRASH_MAX_FRAMES 32
|
||||
#define CRASH_MSG(...) \
|
||||
if (msglen < CRASH_MAX_MSG) msglen += snprintf(msg + msglen, CRASH_MAX_MSG - msglen, __VA_ARGS__)
|
||||
|
||||
#if defined(PLATFORM_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <inttypes.h>
|
||||
#include <excpt.h>
|
||||
|
||||
// NOTE: game builds with gcc, which means we have no PDBs for the windows version
|
||||
// this means that you generally won't get any symbol names in the main executable
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER prevExFilter;
|
||||
|
||||
static void *crashGetModuleBase(const void *addr)
|
||||
{
|
||||
HMODULE h = NULL;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &h);
|
||||
return (void *)h;
|
||||
}
|
||||
|
||||
static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo)
|
||||
{
|
||||
CONTEXT context = *exinfo->ContextRecord;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
|
||||
SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
STACKFRAME64 stackframe;
|
||||
memset(&stackframe, 0, sizeof(stackframe));
|
||||
|
||||
DWORD image;
|
||||
#ifdef PLATFORM_X86
|
||||
image = IMAGE_FILE_MACHINE_I386;
|
||||
stackframe.AddrPC.Offset = context.Eip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Ebp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Esp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif defined(PLATFORM_X86_64)
|
||||
image = IMAGE_FILE_MACHINE_AMD64;
|
||||
stackframe.AddrPC.Offset = context.Rip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Rsp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Rsp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
snprintf(msg, CRASH_MAX_MSG, "no stack trace available on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
|
||||
DWORD disp = 0;
|
||||
DWORD64 disp64 = 0;
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD msglen = 0;
|
||||
|
||||
CRASH_MSG("EXCEPTION: 0x%08lx\n", exinfo->ExceptionRecord->ExceptionCode);
|
||||
CRASH_MSG("PC: %p", exinfo->ExceptionRecord->ExceptionAddress);
|
||||
if (SymGetLineFromAddr64(process, (uintptr_t)exinfo->ExceptionRecord->ExceptionAddress, &disp, &line)) {
|
||||
CRASH_MSG(": %s:%lu+%lu", line.FileName, line.LineNumber, disp);
|
||||
}
|
||||
CRASH_MSG("\nMODULE: [%p]\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress));
|
||||
CRASH_MSG("MAIN MODULE: [%p]\n", crashGetModuleBase(crashInit));
|
||||
CRASH_MSG("\nBACKTRACE:\n");
|
||||
|
||||
char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO sym = (PSYMBOL_INFO)symbuf;
|
||||
sym->SizeOfStruct = sizeof(*sym);
|
||||
sym->MaxNameLen = CRASH_MAX_SYM;
|
||||
|
||||
s32 i;
|
||||
for (i = 0; i < CRASH_MAX_FRAMES; ++i) {
|
||||
const BOOL res = StackWalk64(image, process, thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
|
||||
if (!res) {
|
||||
break;
|
||||
}
|
||||
|
||||
CRASH_MSG("#%02d: %p", i, (void *)(uintptr_t)stackframe.AddrPC.Offset);
|
||||
|
||||
if (SymFromAddr(process, stackframe.AddrPC.Offset, &disp64, sym)) {
|
||||
CRASH_MSG(": %s+%llu", sym->Name, disp64);
|
||||
} else if (process, stackframe.AddrPC.Offset) {
|
||||
const uintptr_t modbase = (uintptr_t)crashGetModuleBase((void *)(uintptr_t)stackframe.AddrPC.Offset);
|
||||
const uintptr_t modofs = (uintptr_t)stackframe.AddrPC.Offset - modbase;
|
||||
CRASH_MSG(": [%p]+%p", (void *)modbase, (void *)modofs);
|
||||
}
|
||||
|
||||
if(SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &disp, &line)) {
|
||||
CRASH_MSG(" (%s:%lu+%lu)", line.FileName, line.LineNumber, disp);
|
||||
}
|
||||
|
||||
CRASH_MSG("\n");
|
||||
}
|
||||
|
||||
if (i <= 1) {
|
||||
CRASH_MSG("no information\n");
|
||||
} else if (i == CRASH_MAX_FRAMES) {
|
||||
CRASH_MSG("...\n");
|
||||
}
|
||||
|
||||
SymCleanup(process);
|
||||
}
|
||||
|
||||
static long __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
|
||||
{
|
||||
char msg[CRASH_MAX_MSG + 1] = { 0 };
|
||||
|
||||
if (IsDebuggerPresent()) {
|
||||
if (prevExFilter) {
|
||||
return prevExFilter(exinfo);
|
||||
}
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p CODE=0x%08lx", exinfo->ExceptionRecord->ExceptionAddress, exinfo->ExceptionRecord->ExceptionCode);
|
||||
|
||||
fflush(stderr);
|
||||
fflush(stdout);
|
||||
|
||||
crashStackTrace(msg, exinfo);
|
||||
|
||||
// open log file for the crash dump if one hasn't been opened yet
|
||||
if (!sysLogIsOpen()) {
|
||||
FILE *f = fopen(CRASH_LOG_FNAME, "wb");
|
||||
if (f) {
|
||||
fprintf(f, "Crash!\n\n%s", msg);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
sysFatalError("Crash!\n\n%s", msg);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
|
||||
#include <ucontext.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
static struct sigaction prevSigAction;
|
||||
|
||||
static s32 crashIsDebuggerPresent(void)
|
||||
{
|
||||
static s32 result = -1;
|
||||
|
||||
if (result >= 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char buf[4096] = { 0 };
|
||||
|
||||
int fd = open("/proc/self/status", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
result = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rx = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (rx <= 0) {
|
||||
result = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf[rx] = 0;
|
||||
|
||||
char *str = strstr(buf, "TracerPid:");
|
||||
if (!str) {
|
||||
result = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
str += 10;
|
||||
|
||||
while (*str && !isdigit(*str)) {
|
||||
if (*str == '\n') {
|
||||
result = 0;
|
||||
return 0;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
|
||||
result = (atoi(str) != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void *crashGetModuleBase(const void *addr)
|
||||
{
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info)) {
|
||||
return info.dli_fbase;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void crashStackTrace(char *msg, s32 sig, void *pc)
|
||||
{
|
||||
u32 msglen = 0;
|
||||
void *frames[CRASH_MAX_FRAMES] = { NULL };
|
||||
|
||||
const s32 nframes = backtrace(frames, CRASH_MAX_FRAMES);
|
||||
if (nframes <= 0) {
|
||||
CRASH_MSG("no information\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char **strings = backtrace_symbols(frames, nframes);
|
||||
|
||||
CRASH_MSG("SIGNAL: %d\n", sig);
|
||||
CRASH_MSG("PC: ");
|
||||
if (pc) {
|
||||
CRASH_MSG("%p\n", pc);
|
||||
} else if (strings) {
|
||||
CRASH_MSG("%s\n", strings[0]);
|
||||
} else {
|
||||
CRASH_MSG("%p\n", frames[0]);
|
||||
}
|
||||
|
||||
CRASH_MSG("MODULE: %p\n", crashGetModuleBase(frames[0]));
|
||||
CRASH_MSG("MAIN MODULE: %p\n", crashGetModuleBase(crashInit));
|
||||
CRASH_MSG("\nBACKTRACE:\n");
|
||||
|
||||
s32 i;
|
||||
for (i = 0; i < nframes; ++i) {
|
||||
CRASH_MSG("#%02d: ", i);
|
||||
if (strings && strings[i]) {
|
||||
CRASH_MSG("%s\n", strings[i]);
|
||||
} else {
|
||||
CRASH_MSG("%p\n", frames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == CRASH_MAX_FRAMES) {
|
||||
CRASH_MSG("...\n");
|
||||
} else if (i <= 1) {
|
||||
CRASH_MSG("no information\n");
|
||||
}
|
||||
|
||||
free(strings);
|
||||
}
|
||||
|
||||
static void crashHandler(s32 sig, siginfo_t *siginfo, void *ctx)
|
||||
{
|
||||
char msg[CRASH_MAX_MSG + 1] = { 0 };
|
||||
|
||||
if (crashIsDebuggerPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
void *pc = NULL;
|
||||
if (ctx) {
|
||||
ucontext_t *ucontext = (ucontext_t *)ctx;
|
||||
#ifdef PLATFORM_X86
|
||||
pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
#elif defined(PLATFORM_X86_64)
|
||||
pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
#elif defined(PLATFORM_ARM) && defined(PLATFORM_64BIT)
|
||||
pc = (void *)ucontext->uc_mcontext.pc;
|
||||
#elif defined(PLATFORM_ARM)
|
||||
pc = (void *)ucontext->uc_mcontext.arm_pc;
|
||||
#endif
|
||||
}
|
||||
|
||||
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p SIGNAL=%d", pc, sig);
|
||||
|
||||
fflush(stderr);
|
||||
fflush(stdout);
|
||||
|
||||
crashStackTrace(msg, sig, pc);
|
||||
|
||||
sysFatalError("Crash!\n\n%s", msg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
s32 g_CrashEnabled = 0;
|
||||
|
||||
static char crashMsg[1024];
|
||||
|
||||
void crashInit(void)
|
||||
{
|
||||
#ifdef PLATFORM_WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
prevExFilter = SetUnhandledExceptionFilter(crashHandler);
|
||||
g_CrashEnabled = 1;
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
struct sigaction sigact = { 0 };
|
||||
sigact.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigact.sa_sigaction = crashHandler;
|
||||
sigaction(SIGSEGV, &sigact, &prevSigAction);
|
||||
sigaction(SIGABRT, &sigact, &prevSigAction);
|
||||
sigaction(SIGBUS, &sigact, &prevSigAction);
|
||||
sigaction(SIGILL, &sigact, &prevSigAction);
|
||||
g_CrashEnabled = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void crashShutdown(void)
|
||||
{
|
||||
if (!g_CrashEnabled) {
|
||||
return;
|
||||
}
|
||||
#ifdef PLATFORM_WIN32
|
||||
if (prevExFilter) {
|
||||
SetUnhandledExceptionFilter(prevExFilter);
|
||||
}
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
sigaction(SIGSEGV, &prevSigAction, NULL);
|
||||
sigaction(SIGABRT, &prevSigAction, NULL);
|
||||
sigaction(SIGBUS, &prevSigAction, NULL);
|
||||
sigaction(SIGILL, &prevSigAction, NULL);
|
||||
#endif
|
||||
g_CrashEnabled = 0;
|
||||
}
|
||||
|
||||
void crashCreateThread(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void crashSetMessage(char *string)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void crashReset(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void crashAppendChar(char c)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,905 @@
|
||||
#include <string>
|
||||
#include <SDL.h>
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/backends/imgui_impl_sdlrenderer2.h"
|
||||
#include "imgui/backends/imgui_impl_sdl2.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
#include <gbiex.h>
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
#include "constants.h"
|
||||
#include "game/stagetable.h"
|
||||
#include "game/chr.h"
|
||||
#include "game/chraction.h"
|
||||
#include "game/bg.h"
|
||||
#include "game/player.h"
|
||||
#include "game/propobj.h"
|
||||
#include "game/prop.h"
|
||||
#include "game/sight.h"
|
||||
#include "game/game_1531a0.h"
|
||||
#include "lib/memp.h"
|
||||
#include "lib/mema.h"
|
||||
#include "lib/vi.h"
|
||||
#include "lib/lib_17ce0.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
#include "romdata.h"
|
||||
|
||||
#undef bool
|
||||
#undef true
|
||||
#undef false
|
||||
|
||||
s32 g_DebuggerActive = FALSE;
|
||||
s32 g_DebuggerTimePasses = TRUE;
|
||||
s32 g_DebuggerFrameAdvance = 0;
|
||||
|
||||
u32 memaGetSize(void);
|
||||
|
||||
}
|
||||
|
||||
static SDL_Window *dbgwin = nullptr;
|
||||
static SDL_Renderer *dbgren = nullptr;
|
||||
|
||||
static char xstr[64] = "0";
|
||||
static char ystr[64] = "0";
|
||||
static char zstr[64] = "0";
|
||||
static char gotostr[64] = "";
|
||||
|
||||
static bool advanceHeld = false;
|
||||
|
||||
static s32 propFilter = 0;
|
||||
static s32 objFilter = 0;
|
||||
|
||||
static const char *propTypes[9];
|
||||
static const char *objTypes[0x3c];
|
||||
|
||||
static bool expandLatch = false;
|
||||
static bool expandValue = false;
|
||||
|
||||
static bool showPropInfo = false;
|
||||
static bool showActiveProps = true;
|
||||
|
||||
static void *focusPtr = nullptr;
|
||||
|
||||
static struct prop *lookatprop = nullptr;
|
||||
static struct hitthing lookathit;
|
||||
static bool lookathitset;
|
||||
|
||||
static inline const char *fmtCoord(const coord& crd)
|
||||
{
|
||||
static char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "(%.2f, %.2f, %.2f)", crd.x, crd.y, crd.z);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#define DEF_ACT_NAME(x) case x: return #x;
|
||||
|
||||
static inline const char *fmtActionType(s8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(ACT_INIT )
|
||||
DEF_ACT_NAME(ACT_STAND )
|
||||
DEF_ACT_NAME(ACT_KNEEL )
|
||||
DEF_ACT_NAME(ACT_ANIM )
|
||||
DEF_ACT_NAME(ACT_DIE )
|
||||
DEF_ACT_NAME(ACT_DEAD )
|
||||
DEF_ACT_NAME(ACT_ARGH )
|
||||
DEF_ACT_NAME(ACT_PREARGH )
|
||||
DEF_ACT_NAME(ACT_ATTACK )
|
||||
DEF_ACT_NAME(ACT_ATTACKWALK )
|
||||
DEF_ACT_NAME(ACT_ATTACKROLL )
|
||||
DEF_ACT_NAME(ACT_SIDESTEP )
|
||||
DEF_ACT_NAME(ACT_JUMPOUT )
|
||||
DEF_ACT_NAME(ACT_RUNPOS )
|
||||
DEF_ACT_NAME(ACT_PATROL )
|
||||
DEF_ACT_NAME(ACT_GOPOS )
|
||||
DEF_ACT_NAME(ACT_SURRENDER )
|
||||
DEF_ACT_NAME(ACT_LOOKATTARGET )
|
||||
DEF_ACT_NAME(ACT_SURPRISED )
|
||||
DEF_ACT_NAME(ACT_STARTALARM )
|
||||
DEF_ACT_NAME(ACT_THROWGRENADE )
|
||||
DEF_ACT_NAME(ACT_TURNDIR )
|
||||
DEF_ACT_NAME(ACT_TEST )
|
||||
DEF_ACT_NAME(ACT_BONDINTRO )
|
||||
DEF_ACT_NAME(ACT_BONDDIE )
|
||||
DEF_ACT_NAME(ACT_BONDMULTI )
|
||||
DEF_ACT_NAME(ACT_NULL )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKSTAND )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKKNEEL )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKSTRAFE)
|
||||
DEF_ACT_NAME(ACT_DRUGGEDDROP )
|
||||
DEF_ACT_NAME(ACT_DRUGGEDKO )
|
||||
DEF_ACT_NAME(ACT_DRUGGEDCOMINGUP )
|
||||
DEF_ACT_NAME(ACT_ATTACKAMOUNT )
|
||||
DEF_ACT_NAME(ACT_ROBOTATTACK )
|
||||
DEF_ACT_NAME(ACT_SKJUMP )
|
||||
DEF_ACT_NAME(ACT_PUNCH )
|
||||
DEF_ACT_NAME(ACT_CUTFIRE )
|
||||
default: return "ACT";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *fmtPropType(u8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(PROPTYPE_OBJ)
|
||||
DEF_ACT_NAME(PROPTYPE_DOOR)
|
||||
DEF_ACT_NAME(PROPTYPE_CHR)
|
||||
DEF_ACT_NAME(PROPTYPE_WEAPON)
|
||||
DEF_ACT_NAME(PROPTYPE_EYESPY)
|
||||
DEF_ACT_NAME(PROPTYPE_PLAYER)
|
||||
DEF_ACT_NAME(PROPTYPE_EXPLOSION)
|
||||
DEF_ACT_NAME(PROPTYPE_SMOKE)
|
||||
default: return "Prop";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *fmtObjType(u8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(OBJTYPE_DOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_DOORSCALE )
|
||||
DEF_ACT_NAME(OBJTYPE_BASIC )
|
||||
DEF_ACT_NAME(OBJTYPE_KEY )
|
||||
DEF_ACT_NAME(OBJTYPE_ALARM )
|
||||
DEF_ACT_NAME(OBJTYPE_CCTV )
|
||||
DEF_ACT_NAME(OBJTYPE_AMMOCRATE )
|
||||
DEF_ACT_NAME(OBJTYPE_WEAPON )
|
||||
DEF_ACT_NAME(OBJTYPE_CHR )
|
||||
DEF_ACT_NAME(OBJTYPE_SINGLEMONITOR )
|
||||
DEF_ACT_NAME(OBJTYPE_MULTIMONITOR )
|
||||
DEF_ACT_NAME(OBJTYPE_HANGINGMONITORS )
|
||||
DEF_ACT_NAME(OBJTYPE_AUTOGUN )
|
||||
DEF_ACT_NAME(OBJTYPE_LINKGUNS )
|
||||
DEF_ACT_NAME(OBJTYPE_DEBRIS )
|
||||
DEF_ACT_NAME(OBJTYPE_10 )
|
||||
DEF_ACT_NAME(OBJTYPE_HAT )
|
||||
DEF_ACT_NAME(OBJTYPE_GRENADEPROB )
|
||||
DEF_ACT_NAME(OBJTYPE_LINKLIFTDOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_MULTIAMMOCRATE )
|
||||
DEF_ACT_NAME(OBJTYPE_SHIELD )
|
||||
DEF_ACT_NAME(OBJTYPE_TAG )
|
||||
DEF_ACT_NAME(OBJTYPE_BEGINOBJECTIVE )
|
||||
DEF_ACT_NAME(OBJTYPE_ENDOBJECTIVE )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_DESTROYOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_COMPFLAGS )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_FAILFLAGS )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_COLLECTOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_THROWOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_HOLOGRAPH )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_1F )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_ENTERROOM )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_THROWINROOM )
|
||||
DEF_ACT_NAME(OBJTYPE_22 )
|
||||
DEF_ACT_NAME(OBJTYPE_BRIEFING )
|
||||
DEF_ACT_NAME(OBJTYPE_GASBOTTLE )
|
||||
DEF_ACT_NAME(OBJTYPE_RENAMEOBJ )
|
||||
DEF_ACT_NAME(OBJTYPE_PADLOCKEDDOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_TRUCK )
|
||||
DEF_ACT_NAME(OBJTYPE_HELI )
|
||||
DEF_ACT_NAME(OBJTYPE_29 )
|
||||
DEF_ACT_NAME(OBJTYPE_GLASS )
|
||||
DEF_ACT_NAME(OBJTYPE_SAFE )
|
||||
DEF_ACT_NAME(OBJTYPE_SAFEITEM )
|
||||
DEF_ACT_NAME(OBJTYPE_TANK )
|
||||
DEF_ACT_NAME(OBJTYPE_CAMERAPOS )
|
||||
DEF_ACT_NAME(OBJTYPE_TINTEDGLASS )
|
||||
DEF_ACT_NAME(OBJTYPE_LIFT )
|
||||
DEF_ACT_NAME(OBJTYPE_CONDITIONALSCENERY)
|
||||
DEF_ACT_NAME(OBJTYPE_BLOCKEDPATH )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERBIKE )
|
||||
DEF_ACT_NAME(OBJTYPE_END )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERPROP )
|
||||
DEF_ACT_NAME(OBJTYPE_FAN )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERCAR )
|
||||
DEF_ACT_NAME(OBJTYPE_PADEFFECT )
|
||||
DEF_ACT_NAME(OBJTYPE_CHOPPER )
|
||||
DEF_ACT_NAME(OBJTYPE_MINE )
|
||||
DEF_ACT_NAME(OBJTYPE_ESCASTEP )
|
||||
default: return "Obj";
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEF_ACT_NAME
|
||||
|
||||
extern "C" void debuggerInit(void)
|
||||
{
|
||||
SDL_Window *parent = (SDL_Window *)videoGetWindowHandle();
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
int pw = 0;
|
||||
int ph = 0;
|
||||
// in windowed mode put the debugger to the right of the window
|
||||
if ((SDL_GetWindowFlags(parent) & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
|
||||
SDL_GetWindowPosition(parent, &px, &py);
|
||||
SDL_GetWindowSize(parent, &pw, &ph);
|
||||
}
|
||||
|
||||
const Uint32 winflags = SDL_WINDOW_RESIZABLE;
|
||||
dbgwin = SDL_CreateWindow("Debugger", px + pw + 4, py, 320, ph, winflags);
|
||||
if (!dbgwin) {
|
||||
sysLogPrintf(LOG_ERROR, "DBG: could not create SDL window: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// can't trust any hardware accelerated windows to live in harmony with our main window, so force SW
|
||||
dbgren = SDL_CreateRenderer(dbgwin, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (!dbgren) {
|
||||
sysLogPrintf(LOG_ERROR, "DBG: could not create SDL renderer: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
io.IniFilename = nullptr;
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(dbgwin, dbgren);
|
||||
ImGui_ImplSDLRenderer2_Init(dbgren);
|
||||
|
||||
propTypes[0] = "NONE";
|
||||
for (s32 i = 1; i < ARRAYCOUNT(propTypes); ++i) {
|
||||
propTypes[i] = fmtPropType(i);
|
||||
}
|
||||
|
||||
objTypes[0] = "NONE";
|
||||
for (s32 i = 1; i < ARRAYCOUNT(objTypes); ++i) {
|
||||
objTypes[i] = fmtObjType(i);
|
||||
}
|
||||
|
||||
g_DebuggerActive = TRUE;
|
||||
}
|
||||
|
||||
static inline void debuggerHotKey(const s32 key, const bool pressed)
|
||||
{
|
||||
switch (key) {
|
||||
case SDLK_F1:
|
||||
if (pressed)
|
||||
g_DebuggerTimePasses ^= 1;
|
||||
break;
|
||||
case SDLK_F2:
|
||||
if (pressed)
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
break;
|
||||
case SDLK_F3:
|
||||
if (pressed)
|
||||
g_DebuggerFrameAdvance = 5;
|
||||
break;
|
||||
case SDLK_F4:
|
||||
advanceHeld = pressed;
|
||||
break;
|
||||
case SDLK_F5:
|
||||
if (pressed) {
|
||||
if (g_TickRateDiv <= 1) {
|
||||
g_TickRateDiv = 2;
|
||||
} else {
|
||||
g_TickRateDiv = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_F6:
|
||||
if (pressed) {
|
||||
g_TickRateDiv++;
|
||||
if (g_TickRateDiv > 5) {
|
||||
g_TickRateDiv = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerProcessEvent(void *data)
|
||||
{
|
||||
if (g_DebuggerActive) {
|
||||
SDL_Event *e = (SDL_Event *)data;
|
||||
if (e->type == SDL_KEYDOWN || e->type == SDL_KEYUP) {
|
||||
debuggerHotKey(e->key.keysym.sym, e->type == SDL_KEYDOWN);
|
||||
} else if (e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEBUTTONUP) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->button.windowID) {
|
||||
return;
|
||||
}
|
||||
} else if (e->type == SDL_MOUSEMOTION) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->motion.windowID) {
|
||||
return;
|
||||
}
|
||||
} else if (e->type == SDL_MOUSEWHEEL) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->wheel.windowID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ImGui_ImplSDL2_ProcessEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerStartFrame(void)
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
static inline bool debuggerGetSurfaceInfo(struct hitthing *hit)
|
||||
{
|
||||
struct coord endpos;
|
||||
endpos.x = g_Vars.currentplayer->cam_pos.x + g_Vars.currentplayer->cam_look.x * 10000.f;
|
||||
endpos.y = g_Vars.currentplayer->cam_pos.y + g_Vars.currentplayer->cam_look.y * 10000.f;
|
||||
endpos.z = g_Vars.currentplayer->cam_pos.z + g_Vars.currentplayer->cam_look.z * 10000.f;
|
||||
|
||||
// get what rooms the LOS goes through
|
||||
RoomNum outrooms[17], tmprooms[8], srcrooms[2];
|
||||
srcrooms[0] = g_Vars.currentplayer->cam_room;
|
||||
srcrooms[1] = -1;
|
||||
outrooms[16] = -1;
|
||||
portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16);
|
||||
|
||||
// no prop was hit; check for bg hits
|
||||
for (s32 i = 0; outrooms[i] != -1; ++i) {
|
||||
if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], hit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void debuggerUpdatePropInfo(s32 clear)
|
||||
{
|
||||
if (showPropInfo) {
|
||||
if (clear) {
|
||||
lookatprop = nullptr;
|
||||
lookathitset = false;
|
||||
} else {
|
||||
lookatprop = propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
|
||||
if (!lookatprop) {
|
||||
// if we aren't looking at a prop, try to get the surface we're looking at
|
||||
lookathitset = debuggerGetSurfaceInfo(&lookathit);
|
||||
} else {
|
||||
lookathitset = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lookatprop = nullptr;
|
||||
lookathitset = false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void debuggerTeleportPlayer(struct coord& crd)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: teleporting player 1 to (%.2f, %.2f, %.2f)", crd.x, crd.y, crd.z);
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
struct chrdata *playerchr = g_Vars.players[0]->prop->chr;
|
||||
if (!playerchr) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: player 1 has no chr");
|
||||
return;
|
||||
}
|
||||
|
||||
RoomNum inrooms[9] = { -1 };
|
||||
RoomNum aboverooms[9] = { -1 };
|
||||
|
||||
bgFindRoomsByPos(&crd, inrooms, aboverooms, 8, NULL);
|
||||
|
||||
RoomNum *rooms = NULL;
|
||||
if (inrooms[0] != -1) {
|
||||
rooms = inrooms;
|
||||
} else if (aboverooms[0] != -1) {
|
||||
rooms = aboverooms;
|
||||
}
|
||||
|
||||
if (rooms) {
|
||||
const u32 old = playerchr->hidden;
|
||||
playerchr->hidden |= CHRHFLAG_WARPONSCREEN;
|
||||
chrMoveToPos(playerchr, &crd, rooms, g_Vars.players[0]->vv_theta, true);
|
||||
if ((old & CHRHFLAG_WARPONSCREEN) == 0) {
|
||||
playerchr->hidden &= ~CHRHFLAG_WARPONSCREEN;
|
||||
}
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: could not find any rooms at teleport destination");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void debuggerKillChr(struct chrdata *chr)
|
||||
{
|
||||
struct coord dmgdir = { 0.f, 0.f, 0.f };
|
||||
chrDamageByImpact(chr, 10000.f, &dmgdir, nullptr, nullptr, HITPART_GENERAL);
|
||||
}
|
||||
|
||||
static inline void debuggerKillPlayer(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: killing player 1");
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
struct chrdata *playerchr = g_Vars.players[0]->prop->chr;
|
||||
if (!playerchr) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: player 1 has no chr");
|
||||
return;
|
||||
}
|
||||
|
||||
debuggerKillChr(playerchr);
|
||||
}
|
||||
|
||||
static inline void debuggerHealPlayer(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: healing player 1");
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
player *prev = g_Vars.currentplayer;
|
||||
g_Vars.currentplayer = g_Vars.players[0];
|
||||
playerDisplayHealth();
|
||||
g_Vars.currentplayer->bondhealth = 1.f;
|
||||
g_Vars.currentplayer = prev;
|
||||
}
|
||||
|
||||
static inline void describeHand(hand *hand)
|
||||
{
|
||||
ImGui::Text("Gun num: %02x", hand->gset.weaponnum);
|
||||
ImGui::Text("Gun func: %02x", hand->gset.weaponfunc);
|
||||
ImGui::Text("Aim pos: %s", fmtCoord(hand->aimpos));
|
||||
ImGui::Text("Hit pos: %s", fmtCoord(hand->hitpos));
|
||||
}
|
||||
|
||||
static inline std::string& describeRoomList(RoomNum *rooms, s32 maxRooms, std::string& out)
|
||||
{
|
||||
for (s32 i = 0; i < maxRooms && rooms[i] >= 0; ++i) {
|
||||
out += strFmt("%03x ", rooms[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline void describeProjectile(projectile *prj)
|
||||
{
|
||||
ImGui::Text("Drop type: %04x", (u16)prj->droptype);
|
||||
ImGui::Text("Flags: %08x", prj->flags);
|
||||
ImGui::Text("Vel: %s", fmtCoord(prj->speed));
|
||||
}
|
||||
|
||||
static inline void describeObj(defaultobj *obj)
|
||||
{
|
||||
ImGui::Text("Type: %s (%02x)", fmtObjType(obj->type), obj->type);
|
||||
ImGui::Text("Model: %04x", (u16)obj->modelnum);
|
||||
ImGui::Text("Pad: %04x", (u16)obj->pad);
|
||||
ImGui::Text("Flags 1: %08x", obj->flags);
|
||||
ImGui::Text("Flags 2: %08x", obj->flags2);
|
||||
ImGui::Text("Flags 3: %08x", obj->flags3);
|
||||
ImGui::Text("Hidden 1: %08x", obj->hidden);
|
||||
ImGui::Text("Hidden 2: %02x", obj->hidden2);
|
||||
|
||||
if ((obj->hidden & OBJHFLAG_PROJECTILE) && obj->projectile) {
|
||||
if (ImGui::TreeNode(strFmt("Projectile (%p)", obj->projectile))) {
|
||||
describeProjectile(obj->projectile);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describeWeapon(weaponobj *wpn)
|
||||
{
|
||||
ImGui::Text("Gun num: %02x", wpn->weaponnum);
|
||||
ImGui::Text("Gun func: %02x", wpn->gunfunc);
|
||||
ImGui::Text("Fade out timer (60hz): %d", wpn->fadeouttimer60);
|
||||
ImGui::Text("Timer (240hz): %d", wpn->timer240);
|
||||
}
|
||||
|
||||
static inline void describeProp(prop *prop);
|
||||
|
||||
static inline void describeChr(chrdata *chr)
|
||||
{
|
||||
ImGui::Text("Number: %04x", (u16)chr->chrnum);
|
||||
ImGui::Text("Flags 1: %08x", chr->flags);
|
||||
ImGui::Text("Flags 2: %08x", chr->flags2);
|
||||
ImGui::Text("Hidden 1: %08x", chr->hidden);
|
||||
ImGui::Text("Hidden 2: %04x", chr->hidden2);
|
||||
ImGui::Text("Chr flags: %08x", chr->chrflags);
|
||||
ImGui::Text("Damage: %.3f", chr->damage);
|
||||
ImGui::Text("Shield: %.3f", chr->cshield);
|
||||
ImGui::Text("Body: %04x", (u16)chr->bodynum);
|
||||
ImGui::Text("Head: %02x", (u8)chr->headnum);
|
||||
ImGui::Text("Team: %02x", chr->team);
|
||||
ImGui::Text("Tude: %02x", chr->tude);
|
||||
ImGui::Text("Action: %s (%02x)", fmtActionType(chr->actiontype), (u8)chr->actiontype);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (chr->weapons_held[HAND_RIGHT]) {
|
||||
if (ImGui::TreeNode(strFmt("Right hand prop (%p)", chr->weapons_held[HAND_RIGHT]))) {
|
||||
describeProp(chr->weapons_held[HAND_RIGHT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
if (chr->weapons_held[HAND_LEFT]) {
|
||||
if (ImGui::TreeNode(strFmt("Left hand prop (%p)", chr->weapons_held[HAND_LEFT]))) {
|
||||
describeProp(chr->weapons_held[HAND_LEFT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
if (chr->weapons_held[2]) {
|
||||
if (ImGui::TreeNode(strFmt("Hat prop (%p)", chr->weapons_held[2]))) {
|
||||
describeProp(chr->weapons_held[2]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Controls");
|
||||
|
||||
if (ImGui::Button("Kill")) {
|
||||
debuggerKillChr(chr);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Heal")) {
|
||||
chr->damage = 0.f;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Sleep")) {
|
||||
chr->sleep = 127;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Wake")) {
|
||||
chr->sleep = 0;
|
||||
}
|
||||
|
||||
// line break
|
||||
|
||||
if (ImGui::Button("Drop guns")) {
|
||||
chrDropItemsForOwnerReap(chr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describeProp(prop *prop)
|
||||
{
|
||||
ImGui::Text(prop->active ? "Active" : "Inactive");
|
||||
ImGui::Text("Type: %s (%02x)", fmtPropType(prop->type), prop->type);
|
||||
ImGui::Text("Flags: %02x", prop->flags);
|
||||
ImGui::Text("Pos: %s", fmtCoord(prop->pos));
|
||||
|
||||
std::string roomstr = "";
|
||||
ImGui::Text("Rooms: %s", describeRoomList(prop->rooms, ARRAYCOUNT(prop->rooms), roomstr).c_str());
|
||||
|
||||
if (prop->obj) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("%s (%p)", fmtObjType(prop->obj->type), prop->obj))) {
|
||||
describeObj(prop->obj);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if ((prop->type == PROPTYPE_CHR || prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_EYESPY) && prop->chr) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("Chr (%p)", prop->chr))) {
|
||||
describeChr(prop->chr);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
} else if (prop->type == PROPTYPE_WEAPON && prop->weapon) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("Weapon (%p)", prop->weapon))) {
|
||||
describeWeapon(prop->weapon);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describePlayer(player *plr)
|
||||
{
|
||||
ImGui::Text("Cam pos: %s", fmtCoord(plr->cam_pos));
|
||||
ImGui::Text("Cam look: %s", fmtCoord(plr->cam_look));
|
||||
ImGui::Text("Cam room: %03x", (u32)plr->cam_room);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Health: %.3f", plr->bondhealth);
|
||||
ImGui::Text("Shield: %.3f", plr->apparentarmour);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (plr->prop) {
|
||||
if (ImGui::TreeNode(strFmt("Prop (%p)", plr->prop))) {
|
||||
describeProp(plr->prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode("Right hand")) {
|
||||
describeHand(&plr->hands[HAND_RIGHT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Left hand")) {
|
||||
describeHand(&plr->hands[HAND_LEFT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerFrame(void)
|
||||
{
|
||||
if (!g_DebuggerActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (advanceHeld) {
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
}
|
||||
|
||||
expandLatch = false;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0.f, 0.f));
|
||||
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||
ImGui::Begin("Debugger", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
if (ImGui::CollapsingHeader("Debug")) {
|
||||
ImGui::SeparatorText("Player");
|
||||
|
||||
ImGui::PushItemWidth(56.f);
|
||||
ImGui::InputText("X", xstr, IM_ARRAYSIZE(xstr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("Y", ystr, IM_ARRAYSIZE(ystr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("Z", zstr, IM_ARRAYSIZE(zstr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::PopItemWidth();
|
||||
if (ImGui::Button("Warp")) {
|
||||
struct coord crd;
|
||||
crd.x = std::atof(xstr);
|
||||
crd.y = std::atof(ystr);
|
||||
crd.z = std::atof(zstr);
|
||||
debuggerTeleportPlayer(crd);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Kill")) {
|
||||
debuggerKillPlayer();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Heal")) {
|
||||
debuggerHealPlayer();
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Time");
|
||||
|
||||
bool timePasses = (g_DebuggerTimePasses != 0);
|
||||
if (ImGui::Checkbox("Time passes", &timePasses)) {
|
||||
g_DebuggerTimePasses = (s32)timePasses;
|
||||
}
|
||||
|
||||
s32 framediv = g_TickRateDiv;
|
||||
if (ImGui::InputInt("Tickrate", &framediv, 1, 2)) {
|
||||
if (framediv >= 0 && framediv < 60) {
|
||||
g_TickRateDiv = framediv;
|
||||
g_Vars.mininc60 = framediv;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("+1 frame")) {
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+5 frames")) {
|
||||
g_DebuggerFrameAdvance = 5;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+10 frames")) {
|
||||
g_DebuggerFrameAdvance = 10;
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Other");
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Time")) {
|
||||
ImGui::Text("Level Frame#: %d", g_Vars.lvframenum);
|
||||
ImGui::Text("Level Tick (60hz): %d", g_Vars.lvframe60);
|
||||
ImGui::Text("Level Tick (240hz): %d", g_Vars.lvframe240);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Frame Time (60hz): %.2f", g_Vars.diffframe60f);
|
||||
ImGui::Text("Frame Time (240hz): %.2f", g_Vars.diffframe240f);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Lost Time (60hz): %d", g_Vars.lostframetime60t);
|
||||
ImGui::Text("Lost Time (240hz): %d", g_Vars.lostframetime240t);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Players")) {
|
||||
for (s32 i = 0; i < ARRAYCOUNT(g_Vars.players); ++i) {
|
||||
auto plr = g_Vars.players[i];
|
||||
if (plr) {
|
||||
if (ImGui::TreeNode(strFmt("Player %d (%p)###Player%p", i + 1, plr, plr))) {
|
||||
describePlayer(plr);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_Vars.activeprops && g_Vars.activeprops != g_Vars.activepropstail) {
|
||||
if (ImGui::CollapsingHeader("Props")) {
|
||||
ImGui::Text("Visible: %d", g_Vars.numonscreenprops);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox("Active props only", &showActiveProps);
|
||||
|
||||
ImGui::Combo("Filter prop", &propFilter, propTypes, ARRAYCOUNT(propTypes));
|
||||
ImGui::Combo("Filter obj", &objFilter, objTypes, ARRAYCOUNT(objTypes));
|
||||
|
||||
if (ImGui::Button("Expand all")) {
|
||||
expandLatch = true;
|
||||
expandValue = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Close all")) {
|
||||
expandLatch = true;
|
||||
expandValue = false;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto showProp = [&](struct prop *prop) {
|
||||
if (prop && (!propFilter || propFilter == prop->type)) {
|
||||
if (!objFilter || (prop->obj && prop->obj->type == objFilter)) {
|
||||
const bool focus = (focusPtr && ((void *)prop == focusPtr || (void *)prop->obj == focusPtr));
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
} else if (focus) {
|
||||
ImGui::SetNextItemOpen(true);
|
||||
focusPtr = nullptr;
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("%s (%p)###Prop%p", fmtPropType(prop->type), prop, prop))) {
|
||||
if (focus) {
|
||||
ImGui::SetScrollHereY();
|
||||
}
|
||||
describeProp(prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (showActiveProps) {
|
||||
// show the active props list
|
||||
struct prop *prop;
|
||||
struct prop *next;
|
||||
bool done;
|
||||
prop = g_Vars.activeprops;
|
||||
do {
|
||||
next = prop->next;
|
||||
done = next == g_Vars.pausedprops;
|
||||
showProp(prop);
|
||||
prop = next;
|
||||
} while (!done);
|
||||
} else {
|
||||
// show all props
|
||||
for (s32 i = 0; i < g_Vars.maxprops; ++i) {
|
||||
struct prop *prop = &g_Vars.props[i];
|
||||
showProp(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_ChrSlots && g_NumChrSlots) {
|
||||
if (ImGui::CollapsingHeader("Characters")) {
|
||||
ImGui::Text("Count: %d/%d", g_NumChrs, g_NumChrSlots);
|
||||
ImGui::Separator();
|
||||
for (s32 i = 0; i < g_NumChrSlots; ++i) {
|
||||
if (g_ChrSlots[i].chrnum >= 0) {
|
||||
if (ImGui::TreeNode(strFmt("Slot %3d: %04x (%p)", i, g_ChrSlots[i].chrnum, &g_ChrSlots[i]))) {
|
||||
describeChr(&g_ChrSlots[i]);
|
||||
if (g_ChrSlots[i].prop && ImGui::TreeNode(strFmt("Prop (%p)##chr", g_ChrSlots[i].prop))) {
|
||||
describeProp(g_ChrSlots[i].prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Stage")) {
|
||||
ImGui::Text("Number: %02x", g_Vars.stagenum);
|
||||
ImGui::Text("Index: %02x", g_StageIndex);
|
||||
ImGui::Text("Setup: %s", romdataFileGetName(g_Stages[g_StageIndex].setupfileid));
|
||||
ImGui::Text("Room count: %d", g_Vars.roomcount);
|
||||
if (g_Rooms && ImGui::TreeNode("Rooms")) {
|
||||
ImGui::Separator();
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
if (ImGui::TreeNode(strFmt("Room %03x", i))) {
|
||||
ImGui::Text("Loaded: %d", g_Rooms[i].loaded240);
|
||||
ImGui::Text("Flags: %04x", g_Rooms[i].flags);
|
||||
ImGui::Text("Portals: %d", g_Rooms[i].numportals);
|
||||
ImGui::Text("Centre: %s", fmtCoord(g_Rooms[i].centre));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Memory")) {
|
||||
ImGui::Text("Mema size: %uk", memaGetSize() / 1024);
|
||||
ImGui::Spacing();
|
||||
if (ImGui::TreeNode("Memp state")) {
|
||||
if (ImGui::BeginTable("MemaTab", 3)) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Pool");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Onboard");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Expansion");
|
||||
for (u8 i = MEMPOOL_STAGE; i <= MEMPOOL_PERMANENT; i += 2) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text((i == MEMPOOL_STAGE) ? "Stage" : "Permanent");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%uk/%uk", mempGetPoolFree(i, MEMBANK_ONBOARD) / 1024, mempGetPoolSize(i, MEMBANK_ONBOARD) / 1024);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%uk/%uk", mempGetPoolFree(i, MEMBANK_EXPANSION) / 1024, mempGetPoolSize(i, MEMBANK_EXPANSION) / 1024);
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if ((showPropInfo = ImGui::CollapsingHeader("Looking at"))) {
|
||||
if (lookatprop) {
|
||||
ImGui::Text("Looking at prop");
|
||||
describeProp(lookatprop);
|
||||
} else if (lookathitset) {
|
||||
ImGui::Text("Looking at surface");
|
||||
ImGui::Text("Hit pos: %s", fmtCoord(lookathit.pos));
|
||||
ImGui::Text("Texture: %04x", lookathit.texturenum);
|
||||
} else {
|
||||
ImGui::Text("Looking at nothing");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
extern "C" void debuggerEndFrame(void)
|
||||
{
|
||||
ImGui::Render();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
SDL_RenderSetScale(dbgren, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
|
||||
SDL_SetRenderDrawColor(dbgren, 0, 0, 0, 255);
|
||||
SDL_RenderClear(dbgren);
|
||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_RenderPresent(dbgren);
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
#include "fs.h"
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_BASEDIR_NAME "data"
|
||||
|
||||
static char baseDir[FS_MAXPATH + 1]; // replaces $B
|
||||
static char modDir[FS_MAXPATH + 1]; // replaces $M
|
||||
static char saveDir[FS_MAXPATH + 1]; // replaces $S
|
||||
static char homeDir[FS_MAXPATH + 1]; // replaces $H
|
||||
static char exeDir[FS_MAXPATH + 1]; // replaces $E
|
||||
|
||||
static s32 fsPathIsWritable(const char *path)
|
||||
{
|
||||
#ifdef PLATFORM_WIN32
|
||||
// on windows access() on directories will only check if the directory exists, so
|
||||
char tmp[FS_MAXPATH + 1] = { 0 };
|
||||
snprintf(tmp, sizeof(tmp), "%s/.tmp", path);
|
||||
FILE *f = fopen(tmp, "wb");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
remove(tmp);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return (access(path, W_OK) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 fsPathIsAbsolute(const char *path)
|
||||
{
|
||||
return (path[0] == '/' || (isalpha(path[0]) && path[1] == ':'));
|
||||
}
|
||||
|
||||
s32 fsPathIsCwdRelative(const char *path)
|
||||
{
|
||||
// ., .., ./, ../
|
||||
return (path[0] == '.' && (path[1] == '.' || path[1] == '/' || path[1] == '\\' || path[1] == '\0'));
|
||||
}
|
||||
|
||||
const char *fsFullPath(const char *relPath)
|
||||
{
|
||||
static char pathBuf[FS_MAXPATH + 1];
|
||||
|
||||
if (relPath[0] == '$') {
|
||||
// expandable placeholder $X; will be replaced with the corresponding path, if any
|
||||
const char *expStr = NULL;
|
||||
switch (relPath[1]) {
|
||||
case 'E': expStr = exeDir; break;
|
||||
case 'H': expStr = homeDir; break;
|
||||
case 'M': expStr = modDir; break;
|
||||
case 'B': expStr = baseDir; break;
|
||||
case 'S': expStr = saveDir; break;
|
||||
default: break;
|
||||
}
|
||||
if (expStr) {
|
||||
const u32 len = strlen(expStr);
|
||||
if (len > 0) {
|
||||
memcpy(pathBuf, expStr, len);
|
||||
strncpy(pathBuf + len, relPath + 2, FS_MAXPATH - len);
|
||||
return pathBuf;
|
||||
}
|
||||
}
|
||||
// couldn't expand anything, return as is
|
||||
return relPath;
|
||||
} else if (!baseDir[0] || fsPathIsAbsolute(relPath) || fsPathIsCwdRelative(relPath)) {
|
||||
// user explicitly wants working directory or this is an absolute path or we have no baseDir set up yet
|
||||
return relPath;
|
||||
}
|
||||
|
||||
// path relative to mod or base dir; this will be a read request, so check where the file actually is
|
||||
if (modDir[0]) {
|
||||
snprintf(pathBuf, FS_MAXPATH, "%s/%s", modDir, relPath);
|
||||
if (fsFileSize(pathBuf) >= 0) {
|
||||
return pathBuf;
|
||||
}
|
||||
}
|
||||
// fall back to basedir
|
||||
snprintf(pathBuf, FS_MAXPATH, "%s/%s", baseDir, relPath);
|
||||
return pathBuf;
|
||||
}
|
||||
|
||||
s32 fsInit(void)
|
||||
{
|
||||
sysGetExecutablePath(exeDir, FS_MAXPATH);
|
||||
|
||||
// if this is set, default to exe path for everything
|
||||
const s32 portable = sysArgCheck("--portable");
|
||||
if (portable) {
|
||||
strcpy(homeDir, exeDir);
|
||||
} else {
|
||||
sysGetHomePath(homeDir, FS_MAXPATH);
|
||||
}
|
||||
|
||||
// get path to base dir and expand it if needed
|
||||
const char *path = sysArgGetString("--basedir");
|
||||
if (!path) {
|
||||
// check if there's a `data` directory in working directory or homeDir, otherwise default to exe directory
|
||||
path = "$E/" DEFAULT_BASEDIR_NAME;
|
||||
if (!portable) {
|
||||
if (fsFileSize("./" DEFAULT_BASEDIR_NAME) >= 0) {
|
||||
path = "./" DEFAULT_BASEDIR_NAME;
|
||||
} else if (fsFileSize("$H/" DEFAULT_BASEDIR_NAME)) {
|
||||
path = "$H/" DEFAULT_BASEDIR_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(baseDir, fsFullPath(path), FS_MAXPATH);
|
||||
|
||||
// get path to mod dir and expand it if needed
|
||||
// mod directory is overlaid on top of base directory
|
||||
path = sysArgGetString("--moddir");
|
||||
if (path) {
|
||||
if (fsPathIsAbsolute(path) || fsPathIsCwdRelative(path) || path[0] == '$') {
|
||||
// path is explicit; check as-is
|
||||
if (fsFileSize(path) >= 0) {
|
||||
strncpy(modDir, fsFullPath(path), FS_MAXPATH);
|
||||
}
|
||||
} else {
|
||||
// path is relative to workdir; try to find it
|
||||
const char *priority[] = { ".", "$E", "$H" };
|
||||
for (s32 i = 0; i < 2 + (portable != 0); ++i) {
|
||||
char *tmp = strFmt("%s/%s", priority[i], path);
|
||||
if (fsFileSize(tmp) >= 0) {
|
||||
strncpy(modDir, fsFullPath(tmp), FS_MAXPATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!modDir[0]) {
|
||||
sysLogPrintf(LOG_WARNING, "could not find specified moddir `%s`", path);
|
||||
}
|
||||
}
|
||||
|
||||
// get path to save dir and expand it if needed
|
||||
path = sysArgGetString("--savedir");
|
||||
if (!path) {
|
||||
if (portable) {
|
||||
path = "$E";
|
||||
} else {
|
||||
#if defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
|
||||
// check if there's a config in the working directory, otherwise default to homeDir
|
||||
if (fsFileSize("./" CONFIG_FNAME) >= 0) {
|
||||
path = ".";
|
||||
} else {
|
||||
path = "$H";
|
||||
}
|
||||
#else
|
||||
// check if working directory is writable, otherwise default to homeDir
|
||||
if (fsPathIsWritable("./")) {
|
||||
path = ".";
|
||||
} else {
|
||||
sysLogPrintf(LOG_WARNING, "cannot write to working directory, will use %s for saves instead", homeDir);
|
||||
path = "$H";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(saveDir, fsFullPath(path), FS_MAXPATH);
|
||||
|
||||
if (modDir[0]) {
|
||||
sysLogPrintf(LOG_NOTE, " mod dir: %s", modDir);
|
||||
}
|
||||
sysLogPrintf(LOG_NOTE, "base dir: %s", baseDir);
|
||||
sysLogPrintf(LOG_NOTE, "save dir: %s", saveDir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *fsGetModDir(void)
|
||||
{
|
||||
return modDir[0] ? modDir : NULL;
|
||||
}
|
||||
|
||||
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize)
|
||||
{
|
||||
const char *fullName = fsFullPath(name);
|
||||
|
||||
FILE *f = fopen(fullName, "rb");
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
const s32 size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (size < 0) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: empty file or invalid size (%d): %s", size, fullName);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((u32)size > dstSize) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: file too big for buffer (%u > %u): %s", size, dstSize, fullName);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fread(dst, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void *fsFileLoad(const char *name, u32 *outSize)
|
||||
{
|
||||
const char *fullName = fsFullPath(name);
|
||||
|
||||
FILE *f = fopen(fullName, "rb");
|
||||
if (!f) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not find file: %s", fullName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
const s32 size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (size < 0) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileLoad: empty file or invalid size (%d): %s", size, fullName);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *buf = NULL;
|
||||
if (size) {
|
||||
buf = sysMemZeroAlloc(size + 1); // sick hack for a free null terminator
|
||||
if (!buf) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not alloc %d bytes for file: %s", size, fullName);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
fread(buf, 1, size, f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (outSize) {
|
||||
*outSize = size;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
s32 fsFileSize(const char *name)
|
||||
{
|
||||
const char *fullName = fsFullPath(name);
|
||||
struct stat st;
|
||||
if (stat(fullName, &st) < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return st.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *fsFileOpenWrite(const char *name)
|
||||
{
|
||||
return fopen(fsFullPath(name), "wb");
|
||||
}
|
||||
|
||||
FILE *fsFileOpenRead(const char *name)
|
||||
{
|
||||
return fopen(fsFullPath(name), "rb");
|
||||
}
|
||||
|
||||
void fsFileFree(FILE *f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
s32 fsCreateDir(const char *path)
|
||||
{
|
||||
#ifdef PLATFORM_WIN32
|
||||
return _mkdir(fsFullPath(path));
|
||||
#else
|
||||
return mkdir(fsFullPath(path), 0777);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2023 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,46 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features:
|
||||
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,268 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Note how SDL_Renderer is an _optional_ component of SDL2.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
|
||||
// it might be difficult to step out of those boundaries.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// CHANGELOG
|
||||
// 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3.
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
|
||||
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||
// 2021-09-21: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_sdlrenderer2.h"
|
||||
#include <stdint.h> // intptr_t
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||
#endif
|
||||
|
||||
// SDL_Renderer data
|
||||
struct ImGui_ImplSDLRenderer2_Data
|
||||
{
|
||||
SDL_Renderer* SDLRenderer;
|
||||
SDL_Texture* FontTexture;
|
||||
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_sdlrenderer2";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
bd->SDLRenderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLRenderer2_SetupRenderState()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// Clear out any viewports and cliprect set by the user
|
||||
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, nullptr);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, nullptr);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplSDLRenderer2_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// If there's a scale factor set by the user, use that instead
|
||||
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||
float rsx = 1.0f;
|
||||
float rsy = 1.0f;
|
||||
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
|
||||
ImVec2 render_scale;
|
||||
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||
struct BackupSDLRendererState
|
||||
{
|
||||
SDL_Rect Viewport;
|
||||
bool ClipEnabled;
|
||||
SDL_Rect ClipRect;
|
||||
};
|
||||
BackupSDLRendererState old = {};
|
||||
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
|
||||
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = render_scale;
|
||||
|
||||
// Render command lists
|
||||
ImGui_ImplSDLRenderer2_SetupRenderState();
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplSDLRenderer2_SetupRenderState();
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
|
||||
|
||||
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos));
|
||||
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv));
|
||||
#if SDL_VERSION_ATLEAST(2,0,19)
|
||||
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+
|
||||
#else
|
||||
const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
|
||||
#endif
|
||||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||
xy, (int)sizeof(ImDrawVert),
|
||||
color, (int)sizeof(ImDrawVert),
|
||||
uv, (int)sizeof(ImDrawVert),
|
||||
cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
|
||||
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified SDL_Renderer state
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
||||
}
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
bool ImGui_ImplSDLRenderer2_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
|
||||
if (bd->FontTexture == nullptr)
|
||||
{
|
||||
SDL_Log("error creating texture");
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
|
||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
io.Fonts->SetTexID(0);
|
||||
SDL_DestroyTexture(bd->FontTexture);
|
||||
bd->FontTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDLRenderer2_CreateDeviceObjects()
|
||||
{
|
||||
return ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,41 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Note how SDL_Renderer is an _optional_ component of SDL2.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
|
||||
// it might be difficult to step out of those boundaries.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Renderer;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,129 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1557
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,487 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <PR/os_internal.h>
|
||||
#include <PR/rcp.h>
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "input.h"
|
||||
#include "video.h"
|
||||
#include "audio.h"
|
||||
#include "fs.h"
|
||||
|
||||
#define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8)
|
||||
#define EEPROM_FNAME "eeprom.bin"
|
||||
#define EEPROM_PATH "$S/" EEPROM_FNAME
|
||||
|
||||
#define OS_COUNTER_RATE 46875000ULL
|
||||
#define OS_COUNTER_NUM (OS_COUNTER_RATE / 1000ULL)
|
||||
#define OS_COUNTER_DEN (1000000ULL / 1000ULL)
|
||||
|
||||
u64 osClockRate = OS_CLOCK_RATE;
|
||||
u32 osMemSize = 16 * 1024 * 1024; /* expansion pak installed plus some extra */
|
||||
s32 osTvType = OS_TV_NTSC; /* 0 = PAL, 1 = NTSC, 2 = MPAL */
|
||||
s32 osResetType = 0; /* 0 = cold reset */
|
||||
s32 osViClock = VI_NTSC_CLOCK;
|
||||
|
||||
static u8 eeprom[EEPROM_SIZE];
|
||||
static char eepromPath[FS_MAXPATH + 1];
|
||||
static s32 eepromLoaded = 0;
|
||||
|
||||
/* Time */
|
||||
|
||||
OSTime osGetTime(void)
|
||||
{
|
||||
// u64 should be enough to last a while
|
||||
return (sysGetMicroseconds() * OS_COUNTER_NUM) / OS_COUNTER_DEN;
|
||||
}
|
||||
|
||||
u32 osGetCount(void)
|
||||
{
|
||||
return (u32)osGetTime();
|
||||
}
|
||||
|
||||
/* Thread */
|
||||
|
||||
void osCreateThread(OSThread *thrd, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p)
|
||||
{
|
||||
thrd->id = id;
|
||||
thrd->state = OS_STATE_STOPPED;
|
||||
}
|
||||
|
||||
void osDestroyThread(OSThread *thrd)
|
||||
{
|
||||
thrd->id = 0;
|
||||
thrd->state = 0;
|
||||
}
|
||||
|
||||
void osYieldThread(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osStartThread(OSThread *thrd)
|
||||
{
|
||||
thrd->state = OS_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void osStopThread(OSThread *thrd)
|
||||
{
|
||||
thrd->state = OS_STATE_STOPPED;
|
||||
}
|
||||
|
||||
OSPri osGetThreadPri(OSThread *thrd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osSetThreadPri(OSThread *thrd, OSPri pri)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Mesg */
|
||||
|
||||
void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msgBuf, s32 count)
|
||||
{
|
||||
mq->validCount = 0;
|
||||
mq->first = 0;
|
||||
mq->msgCount = count;
|
||||
mq->msg = msgBuf;
|
||||
}
|
||||
|
||||
void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Vi */
|
||||
|
||||
void osCreateViManager(OSPri pri)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViSetMode(OSViMode *mode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViBlack(u8 active)
|
||||
{
|
||||
if (active) {
|
||||
videoClearScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void osViSetSpecialFeatures(u32 func)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViSwapBuffer(void *vaddr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViSetXScale(f32 value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osViSetYScale(f32 value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Ai */
|
||||
|
||||
s32 osAiSetFrequency(u32 frequency)
|
||||
{
|
||||
// we can allow for any freq
|
||||
return (s32)frequency;
|
||||
}
|
||||
|
||||
u32 osAiGetLength(void)
|
||||
{
|
||||
return audioGetBytesBuffered();
|
||||
}
|
||||
|
||||
s32 osAiSetNextBuffer(void *bufPtr, u32 size)
|
||||
{
|
||||
audioSetNextBuffer(bufPtr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cont */
|
||||
|
||||
s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data)
|
||||
{
|
||||
if (bitpattern) {
|
||||
*bitpattern = inputControllerMask();
|
||||
}
|
||||
if (data) {
|
||||
osContGetQuery(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osContStartReadData(OSMesgQueue *mesgq)
|
||||
{
|
||||
osSendMesg(mesgq, (OSMesg)0, OS_MESG_NOBLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osContGetReadData(OSContPad *pad)
|
||||
{
|
||||
// game always passes in an array of 4 OSContPads
|
||||
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++pad) {
|
||||
pad->button = 0;
|
||||
pad->stick_x = 0;
|
||||
pad->stick_y = 0;
|
||||
pad->rstick_x = 0;
|
||||
pad->rstick_y = 0;
|
||||
if (inputReadController(i, pad) < 0) {
|
||||
pad->errnum = CONT_NO_RESPONSE_ERROR;
|
||||
} else {
|
||||
pad->errnum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 osContStartQuery(OSMesgQueue *mq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osContGetQuery(OSContStatus *status)
|
||||
{
|
||||
// also always 4 status structs here
|
||||
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++status) {
|
||||
if (inputControllerConnected(i)) {
|
||||
status->errnum = 0;
|
||||
status->type = CONT_ABSOLUTE;
|
||||
status->status = CONT_CARD_ON;
|
||||
} else {
|
||||
status->errnum = CONT_NO_RESPONSE_ERROR;
|
||||
status->type = 0;
|
||||
status->status = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Motor */
|
||||
|
||||
s32 osMotorProbe(OSMesgQueue *ctrlrqueue, OSPfs* pfs, s32 channel)
|
||||
{
|
||||
if (pfs && inputRumbleSupported(channel)) {
|
||||
pfs->queue = ctrlrqueue;
|
||||
pfs->channel = channel;
|
||||
pfs->activebank = 0xff;
|
||||
pfs->status = PFS_MOTOR_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 __osMotorAccess(OSPfs *pfs, s32 cmd)
|
||||
{
|
||||
if (!pfs || pfs->channel < 0 || pfs->channel >= INPUT_MAX_CONTROLLERS) {
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
const f32 strength = (f32)(cmd == MOTOR_START);
|
||||
inputRumble(pfs->channel, strength, 5.f); // hope someone turns it off in those 5 seconds
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Eeprom */
|
||||
|
||||
static inline void osEepromSetPath(void)
|
||||
{
|
||||
const char *extPath = sysArgGetString("--eeprom-file");
|
||||
if (extPath && extPath[0]) {
|
||||
if (extPath[0] == '$' || fsPathIsAbsolute(extPath) || fsPathIsCwdRelative(extPath)) {
|
||||
strncpy(eepromPath, extPath, FS_MAXPATH);
|
||||
} else {
|
||||
// just a filename, look for it in the save dir
|
||||
snprintf(eepromPath, FS_MAXPATH, "$S/%s", extPath);
|
||||
}
|
||||
} else {
|
||||
strncpy(eepromPath, EEPROM_PATH, FS_MAXPATH);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void osEeepromLoad(const char *fname)
|
||||
{
|
||||
if (!eepromLoaded) {
|
||||
eepromLoaded = 1;
|
||||
FILE *fp = fsFileOpenRead(fname);
|
||||
if (fp) {
|
||||
fread(eeprom, 1, EEPROM_SIZE, fp);
|
||||
fsFileFree(fp);
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void osEeepromSave(const char *fname)
|
||||
{
|
||||
FILE* fp = fsFileOpenWrite(fname);
|
||||
if (fp) {
|
||||
fwrite(eeprom, 1, EEPROM_SIZE, fp);
|
||||
fsFileFree(fp);
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
s32 osEepromProbe(OSMesgQueue *mq)
|
||||
{
|
||||
return EEPROM_TYPE_16K;
|
||||
}
|
||||
|
||||
s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
|
||||
{
|
||||
if (!eepromPath[0]) {
|
||||
osEepromSetPath();
|
||||
}
|
||||
|
||||
osEeepromLoad(eepromPath);
|
||||
|
||||
memcpy(buffer, eeprom + address * 8, nbytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
|
||||
{
|
||||
if (!eepromPath[0]) {
|
||||
osEepromSetPath();
|
||||
}
|
||||
|
||||
osEeepromLoad(eepromPath);
|
||||
|
||||
memcpy(eeprom + address * 8, buffer, nbytes);
|
||||
|
||||
osEeepromSave(eepromPath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pfs */
|
||||
|
||||
s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern)
|
||||
{
|
||||
if (pattern) {
|
||||
*pattern = 0;
|
||||
for (s32 i = 0; i < MAXCONTROLLERS; ++i) {
|
||||
if (inputRumbleSupported(i)) {
|
||||
*pattern |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osPfsInitPak(OSMesgQueue *queue, OSPfs *pfs, s32 channel, s32 *arg3)
|
||||
{
|
||||
// if rumble is supported, indicate that we have a rumble pak instead
|
||||
return inputRumbleSupported(channel) ? PFS_ERR_DEVICE : PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsChecker(OSPfs *pfs)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsFreeBlocks(OSPfs *pfs, s32 *remaining)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int num_bytes, s32 *file_no)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsReSizeFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int length)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsFileState(OSPfs *pfs, s32 fileNo, OSPfsState *state)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osPfsReadWriteFile(OSPfs* pfs, s32 fileNo, u8 flag, int offset, int size, u8* data)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
/* Gbpak */
|
||||
|
||||
s32 osGbpakInit(OSMesgQueue *queue, OSPfs *pfs, s32 ch)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osGbpakPower(OSPfs *pfs, s32 flag)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osGbpakReadWrite(OSPfs *pfs, u16 flag, u16 addr, u8 *buf, u16 size)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
s32 osGbpakReadId(OSPfs *pfs, OSGbpakId *id, u8 *status)
|
||||
{
|
||||
return PFS_ERR_NOPACK;
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
|
||||
void osWritebackDCacheAll(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osWritebackDCache(void *a, s32 b)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void osInvalDCache(void *a, s32 b)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq)
|
||||
{
|
||||
memcpy(vAddr, (const void *)devAddr, nbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osPiReadIo(u32 devaddr, u32 *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t osVirtualToPhysical(void *addr)
|
||||
{
|
||||
return (uintptr_t)addr;
|
||||
}
|
||||
|
||||
u32 osGetMemSize(void)
|
||||
{
|
||||
return osMemSize;
|
||||
}
|
||||
|
||||
OSIntMask osGetIntMask(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSIntMask osSetIntMask(OSIntMask mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* libc compatibility wrappers */
|
||||
|
||||
#ifndef PLATFORM_OSX
|
||||
|
||||
void bzero(void *ptr, size_t size)
|
||||
{
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
void bcopy(const void *src, void *dst, size_t n)
|
||||
{
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
s32 bcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
#endif
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/ultrasched.h>
|
||||
#include <PR/os_message.h>
|
||||
|
||||
#include "lib/main.h"
|
||||
#include "bss.h"
|
||||
#include "data.h"
|
||||
|
||||
#include "video.h"
|
||||
#include "audio.h"
|
||||
#include "input.h"
|
||||
#include "fs.h"
|
||||
#include "romdata.h"
|
||||
#include "config.h"
|
||||
#include "mod.h"
|
||||
#include "system.h"
|
||||
#include "debugger.h"
|
||||
#include "utils.h"
|
||||
|
||||
u32 g_OsMemSize = 0;
|
||||
s32 g_OsMemSizeMb = 16;
|
||||
u8 g_Is4Mb = 0;
|
||||
s8 g_Resetting = false;
|
||||
OSSched g_Sched;
|
||||
|
||||
OSMesgQueue g_MainMesgQueue;
|
||||
OSMesg g_MainMesgBuf[32];
|
||||
|
||||
u8 *g_MempHeap = NULL;
|
||||
u32 g_MempHeapSize = 0;
|
||||
|
||||
u32 g_VmNumTlbMisses = 0;
|
||||
u32 g_VmNumPageMisses = 0;
|
||||
u32 g_VmNumPageReplaces = 0;
|
||||
u8 g_VmShowStats = 0;
|
||||
|
||||
s32 g_TickRateDiv = 1;
|
||||
s32 g_TickExtraSleep = true;
|
||||
|
||||
s32 g_SkipIntro = false;
|
||||
|
||||
s32 g_FileAutoSelect = -1;
|
||||
|
||||
extern s32 g_StageNum;
|
||||
|
||||
s32 bootGetMemSize(void)
|
||||
{
|
||||
return (s32)g_OsMemSize;
|
||||
}
|
||||
|
||||
void *bootAllocateStack(s32 threadid, s32 size)
|
||||
{
|
||||
static u8 bruh[0x1000];
|
||||
return bruh;
|
||||
}
|
||||
|
||||
void bootCreateSched(void)
|
||||
{
|
||||
osCreateMesgQueue(&g_MainMesgQueue, g_MainMesgBuf, ARRAYCOUNT(g_MainMesgBuf));
|
||||
if (osTvType == OS_TV_MPAL) {
|
||||
osCreateScheduler(&g_Sched, NULL, OS_VI_MPAL_LAN1, 1);
|
||||
} else {
|
||||
osCreateScheduler(&g_Sched, NULL, OS_VI_NTSC_LAN1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gameInit(void)
|
||||
{
|
||||
osMemSize = g_OsMemSizeMb * 1024 * 1024;
|
||||
|
||||
for (s32 i = 0; i < MAX_PLAYERS; ++i) {
|
||||
struct extplayerconfig *cfg = g_PlayerExtCfg + i;
|
||||
cfg->fovzoommult = cfg->fovzoom ? cfg->fovy / 60.0f : 1.0f;
|
||||
}
|
||||
|
||||
if (g_HudCenter == HUDCENTER_NORMAL) {
|
||||
g_HudAlignModeL = G_ASPECT_CENTER_EXT;
|
||||
g_HudAlignModeR = G_ASPECT_CENTER_EXT;
|
||||
} else if (g_HudCenter == HUDCENTER_WIDE) {
|
||||
g_HudAlignModeL = G_ASPECT_LEFT_EXT | G_ASPECT_WIDE_EXT;
|
||||
g_HudAlignModeR = G_ASPECT_RIGHT_EXT | G_ASPECT_WIDE_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "shutdown");
|
||||
inputSaveBinds();
|
||||
configSave(CONFIG_PATH);
|
||||
videoShutdown();
|
||||
crashShutdown();
|
||||
// TODO: actually shut down all subsystems
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
sysInitArgs(argc, argv);
|
||||
|
||||
if (!sysArgCheck("--no-crash-handler")) {
|
||||
crashInit();
|
||||
}
|
||||
|
||||
sysInit();
|
||||
fsInit();
|
||||
configInit();
|
||||
videoInit();
|
||||
inputInit();
|
||||
audioInit();
|
||||
romdataInit();
|
||||
debuggerInit();
|
||||
|
||||
g_ValidGbcRomFound = romdataCheckGbcRom();
|
||||
|
||||
gameInit();
|
||||
|
||||
if (fsGetModDir()) {
|
||||
modConfigLoad(MOD_CONFIG_FNAME);
|
||||
}
|
||||
|
||||
atexit(cleanup);
|
||||
|
||||
bootCreateSched();
|
||||
|
||||
g_OsMemSize = osGetMemSize();
|
||||
|
||||
g_MempHeapSize = g_OsMemSize;
|
||||
g_MempHeap = sysMemZeroAlloc(g_MempHeapSize);
|
||||
if (!g_MempHeap) {
|
||||
sysFatalError("Could not alloc %u bytes for memp heap.", g_MempHeapSize);
|
||||
}
|
||||
|
||||
sysLogPrintf(LOG_NOTE, "memp heap at %p - %p", g_MempHeap, g_MempHeap + g_MempHeapSize);
|
||||
sysLogPrintf(LOG_NOTE, "rom file at %p - %p", g_RomFile, g_RomFile + g_RomFileSize);
|
||||
|
||||
g_SndDisabled = sysArgCheck("--no-sound");
|
||||
|
||||
g_StageNum = sysArgGetInt("--boot-stage", STAGE_TITLE);
|
||||
|
||||
if (g_StageNum == STAGE_TITLE && (sysArgCheck("--skip-intro") || g_SkipIntro)) {
|
||||
// shorthand for --boot-stage 0x26
|
||||
g_StageNum = STAGE_CITRAINING;
|
||||
} else if (g_StageNum < 0x01 || g_StageNum > 0x5d) {
|
||||
// stage num out of range
|
||||
g_StageNum = STAGE_TITLE;
|
||||
}
|
||||
|
||||
if (g_StageNum != STAGE_TITLE) {
|
||||
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
|
||||
}
|
||||
|
||||
g_FileAutoSelect = sysArgGetInt("--profile", -1);
|
||||
if (g_FileAutoSelect >= 0) {
|
||||
sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect);
|
||||
}
|
||||
|
||||
mainProc();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
|
||||
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
|
||||
configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1);
|
||||
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
|
||||
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
|
||||
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
|
||||
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
|
||||
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
|
||||
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
|
||||
for (s32 j = 0; j < MAX_PLAYERS; ++j) {
|
||||
const s32 i = j + 1;
|
||||
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
|
||||
configRegisterInt(strFmt("Game.Player%d.FovAffectsZoom", i), &g_PlayerExtCfg[j].fovzoom, 0, 1);
|
||||
configRegisterInt(strFmt("Game.Player%d.MouseAimMode", i), &g_PlayerExtCfg[j].mouseaimmode, 0, 1);
|
||||
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedX", i), &g_PlayerExtCfg[j].mouseaimspeedx, 0.f, 10.f);
|
||||
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedY", i), &g_PlayerExtCfg[j].mouseaimspeedy, 0.f, 10.f);
|
||||
configRegisterFloat(strFmt("Game.Player%d.RadialMenuSpeed", i), &g_PlayerExtCfg[j].radialmenuspeed, 0.f, 10.f);
|
||||
configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f);
|
||||
configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG);
|
||||
configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1);
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
|
||||
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
|
||||
configRegisterInt(strFmt("Game.Player%d.UseKeyReloads", i), &g_PlayerExtCfg[j].usereloads, 0, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ultra64.h>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define MINIMP3_IMPLEMENTATION
|
||||
#include "external/minimp3.h"
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
#include <immintrin.h>
|
||||
#define HAS_SSE41 1
|
||||
#define HAS_NEON 0
|
||||
#elif __ARM_NEON
|
||||
#include <arm_neon.h>
|
||||
#define HAS_SSE41 0
|
||||
#define HAS_NEON 1
|
||||
#else
|
||||
#define HAS_SSE41 0
|
||||
#define HAS_NEON 0
|
||||
#endif
|
||||
|
||||
#pragma GCC optimize ("unroll-loops")
|
||||
|
||||
#if HAS_SSE41
|
||||
#define LOADLH(l, h) _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd((const double *)(l)), (const double *)(h)))
|
||||
#endif
|
||||
|
||||
#define ROUND_UP_64(v) (((v) + 63) & ~63)
|
||||
#define ROUND_UP_32(v) (((v) + 31) & ~31)
|
||||
#define ROUND_UP_16(v) (((v) + 15) & ~15)
|
||||
#define ROUND_UP_8(v) (((v) + 7) & ~7)
|
||||
#define ROUND_DOWN_16(v) ((v) & ~0xf)
|
||||
|
||||
#define BUF_SIZE 3072 // 2720 + slack
|
||||
#define BUF_U8(a) (rspa.buf.as_u8 + (a))
|
||||
#define BUF_S16(a) (rspa.buf.as_s16 + (a) / sizeof(int16_t))
|
||||
|
||||
#define NUM_SAMPLES 0xB8
|
||||
#define NUM_BYTES 0x170
|
||||
|
||||
#define OFS_BASE 0
|
||||
#define OFS_TEMP1 0x170
|
||||
#define OFS_MAIN_L 0x4E0
|
||||
#define OFS_MAIN_R 0x650
|
||||
#define OFS_AUX_L 0x7C0
|
||||
#define OFS_AUX_R 0x930
|
||||
|
||||
static struct {
|
||||
int16_t vol[2];
|
||||
|
||||
int16_t target[2];
|
||||
int32_t rate[2];
|
||||
|
||||
int16_t vol_dry;
|
||||
int16_t vol_wet;
|
||||
|
||||
ADPCM_STATE *adpcm_loop_state;
|
||||
|
||||
int16_t adpcm_table[8][2][8];
|
||||
|
||||
union {
|
||||
int16_t as_s16[BUF_SIZE / sizeof(int16_t)];
|
||||
uint8_t as_u8[BUF_SIZE];
|
||||
} buf;
|
||||
} rspa;
|
||||
|
||||
static int16_t resample_table[64][4] = {
|
||||
{0x0c39, 0x66ad, 0x0d46, 0xffdf}, {0x0b39, 0x6696, 0x0e5f, 0xffd8},
|
||||
{0x0a44, 0x6669, 0x0f83, 0xffd0}, {0x095a, 0x6626, 0x10b4, 0xffc8},
|
||||
{0x087d, 0x65cd, 0x11f0, 0xffbf}, {0x07ab, 0x655e, 0x1338, 0xffb6},
|
||||
{0x06e4, 0x64d9, 0x148c, 0xffac}, {0x0628, 0x643f, 0x15eb, 0xffa1},
|
||||
{0x0577, 0x638f, 0x1756, 0xff96}, {0x04d1, 0x62cb, 0x18cb, 0xff8a},
|
||||
{0x0435, 0x61f3, 0x1a4c, 0xff7e}, {0x03a4, 0x6106, 0x1bd7, 0xff71},
|
||||
{0x031c, 0x6007, 0x1d6c, 0xff64}, {0x029f, 0x5ef5, 0x1f0b, 0xff56},
|
||||
{0x022a, 0x5dd0, 0x20b3, 0xff48}, {0x01be, 0x5c9a, 0x2264, 0xff3a},
|
||||
{0x015b, 0x5b53, 0x241e, 0xff2c}, {0x0101, 0x59fc, 0x25e0, 0xff1e},
|
||||
{0x00ae, 0x5896, 0x27a9, 0xff10}, {0x0063, 0x5720, 0x297a, 0xff02},
|
||||
{0x001f, 0x559d, 0x2b50, 0xfef4}, {0xffe2, 0x540d, 0x2d2c, 0xfee8},
|
||||
{0xffac, 0x5270, 0x2f0d, 0xfedb}, {0xff7c, 0x50c7, 0x30f3, 0xfed0},
|
||||
{0xff53, 0x4f14, 0x32dc, 0xfec6}, {0xff2e, 0x4d57, 0x34c8, 0xfebd},
|
||||
{0xff0f, 0x4b91, 0x36b6, 0xfeb6}, {0xfef5, 0x49c2, 0x38a5, 0xfeb0},
|
||||
{0xfedf, 0x47ed, 0x3a95, 0xfeac}, {0xfece, 0x4611, 0x3c85, 0xfeab},
|
||||
{0xfec0, 0x4430, 0x3e74, 0xfeac}, {0xfeb6, 0x424a, 0x4060, 0xfeaf},
|
||||
{0xfeaf, 0x4060, 0x424a, 0xfeb6}, {0xfeac, 0x3e74, 0x4430, 0xfec0},
|
||||
{0xfeab, 0x3c85, 0x4611, 0xfece}, {0xfeac, 0x3a95, 0x47ed, 0xfedf},
|
||||
{0xfeb0, 0x38a5, 0x49c2, 0xfef5}, {0xfeb6, 0x36b6, 0x4b91, 0xff0f},
|
||||
{0xfebd, 0x34c8, 0x4d57, 0xff2e}, {0xfec6, 0x32dc, 0x4f14, 0xff53},
|
||||
{0xfed0, 0x30f3, 0x50c7, 0xff7c}, {0xfedb, 0x2f0d, 0x5270, 0xffac},
|
||||
{0xfee8, 0x2d2c, 0x540d, 0xffe2}, {0xfef4, 0x2b50, 0x559d, 0x001f},
|
||||
{0xff02, 0x297a, 0x5720, 0x0063}, {0xff10, 0x27a9, 0x5896, 0x00ae},
|
||||
{0xff1e, 0x25e0, 0x59fc, 0x0101}, {0xff2c, 0x241e, 0x5b53, 0x015b},
|
||||
{0xff3a, 0x2264, 0x5c9a, 0x01be}, {0xff48, 0x20b3, 0x5dd0, 0x022a},
|
||||
{0xff56, 0x1f0b, 0x5ef5, 0x029f}, {0xff64, 0x1d6c, 0x6007, 0x031c},
|
||||
{0xff71, 0x1bd7, 0x6106, 0x03a4}, {0xff7e, 0x1a4c, 0x61f3, 0x0435},
|
||||
{0xff8a, 0x18cb, 0x62cb, 0x04d1}, {0xff96, 0x1756, 0x638f, 0x0577},
|
||||
{0xffa1, 0x15eb, 0x643f, 0x0628}, {0xffac, 0x148c, 0x64d9, 0x06e4},
|
||||
{0xffb6, 0x1338, 0x655e, 0x07ab}, {0xffbf, 0x11f0, 0x65cd, 0x087d},
|
||||
{0xffc8, 0x10b4, 0x6626, 0x095a}, {0xffd0, 0x0f83, 0x6669, 0x0a44},
|
||||
{0xffd8, 0x0e5f, 0x6696, 0x0b39}, {0xffdf, 0x0d46, 0x66ad, 0x0c39}
|
||||
};
|
||||
|
||||
static inline int16_t clamp16(int32_t v) {
|
||||
if (v < -0x8000) {
|
||||
return -0x8000;
|
||||
} else if (v > 0x7fff) {
|
||||
return 0x7fff;
|
||||
}
|
||||
return (int16_t)v;
|
||||
}
|
||||
|
||||
static inline int32_t clamp32(int64_t v) {
|
||||
if (v < -0x7fffffff - 1) {
|
||||
return -0x7fffffff - 1;
|
||||
} else if (v > 0x7fffffff) {
|
||||
return 0x7fffffff;
|
||||
}
|
||||
return (int32_t)v;
|
||||
}
|
||||
|
||||
void aClearBufferImpl(uint16_t addr, int nbytes) {
|
||||
nbytes = ROUND_UP_16(nbytes);
|
||||
memset(BUF_U8(addr), 0, nbytes);
|
||||
}
|
||||
|
||||
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) {
|
||||
memcpy(BUF_U8(dest_addr), source_addr, ROUND_UP_8(nbytes));
|
||||
}
|
||||
|
||||
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
|
||||
memcpy(dest_addr, BUF_S16(source_addr), ROUND_UP_8(nbytes));
|
||||
}
|
||||
|
||||
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr) {
|
||||
memcpy(rspa.adpcm_table, book_source_addr, num_entries_times_16);
|
||||
}
|
||||
|
||||
void aInterleaveImpl(void) {
|
||||
const int16_t *l = BUF_S16(OFS_MAIN_L);
|
||||
const int16_t *r = BUF_S16(OFS_MAIN_R);
|
||||
int count = ROUND_UP_16(NUM_SAMPLES) / 8;
|
||||
int16_t *d = BUF_S16(OFS_BASE);
|
||||
while (count > 0) {
|
||||
int16_t l0 = *l++;
|
||||
int16_t l1 = *l++;
|
||||
int16_t l2 = *l++;
|
||||
int16_t l3 = *l++;
|
||||
int16_t l4 = *l++;
|
||||
int16_t l5 = *l++;
|
||||
int16_t l6 = *l++;
|
||||
int16_t l7 = *l++;
|
||||
int16_t r0 = *r++;
|
||||
int16_t r1 = *r++;
|
||||
int16_t r2 = *r++;
|
||||
int16_t r3 = *r++;
|
||||
int16_t r4 = *r++;
|
||||
int16_t r5 = *r++;
|
||||
int16_t r6 = *r++;
|
||||
int16_t r7 = *r++;
|
||||
*d++ = l0;
|
||||
*d++ = r0;
|
||||
*d++ = l1;
|
||||
*d++ = r1;
|
||||
*d++ = l2;
|
||||
*d++ = r2;
|
||||
*d++ = l3;
|
||||
*d++ = r3;
|
||||
*d++ = l4;
|
||||
*d++ = r4;
|
||||
*d++ = l5;
|
||||
*d++ = r5;
|
||||
*d++ = l6;
|
||||
*d++ = r6;
|
||||
*d++ = l7;
|
||||
*d++ = r7;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) {
|
||||
memmove(BUF_U8(out_addr), BUF_U8(in_addr), ROUND_UP_16(nbytes));
|
||||
}
|
||||
|
||||
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state) {
|
||||
rspa.adpcm_loop_state = adpcm_loop_state;
|
||||
}
|
||||
|
||||
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs) {
|
||||
#if HAS_SSE41
|
||||
const __m128i tblrev = _mm_setr_epi8(12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, -1, -1);
|
||||
const __m128i pos0 = _mm_set_epi8(3, -1, 3, -1, 2, -1, 2, -1, 1, -1, 1, -1, 0, -1, 0, -1);
|
||||
const __m128i pos1 = _mm_set_epi8(7, -1, 7, -1, 6, -1, 6, -1, 5, -1, 5, -1, 4, -1, 4, -1);
|
||||
const __m128i mult = _mm_set_epi16(0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01);
|
||||
const __m128i mask = _mm_set1_epi16((int16_t)0xf000);
|
||||
#elif HAS_NEON
|
||||
static const int8_t pos0_data[] = {-1, 0, -1, 0, -1, 1, -1, 1, -1, 2, -1, 2, -1, 3, -1, 3};
|
||||
static const int8_t pos1_data[] = {-1, 4, -1, 4, -1, 5, -1, 5, -1, 6, -1, 6, -1, 7, -1, 7};
|
||||
static const int16_t mult_data[] = {0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10};
|
||||
static const int16_t table_prefix_data[] = {0, 0, 0, 0, 0, 0, 0, 1 << 11};
|
||||
const int8x16_t pos0 = vld1q_s8(pos0_data);
|
||||
const int8x16_t pos1 = vld1q_s8(pos1_data);
|
||||
const int16x8_t mult = vld1q_s16(mult_data);
|
||||
const int16x8_t mask = vdupq_n_s16((int16_t)0xf000);
|
||||
const int16x8_t table_prefix = vld1q_s16(table_prefix_data);
|
||||
#endif
|
||||
uint8_t *in = BUF_U8(inofs);
|
||||
int16_t *out = BUF_S16(outofs);
|
||||
nbytes = ROUND_UP_32(nbytes);
|
||||
if (flags & A_INIT) {
|
||||
memset(out, 0, 16 * sizeof(int16_t));
|
||||
} else if (flags & A_LOOP) {
|
||||
memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t));
|
||||
} else {
|
||||
memcpy(out, state, 16 * sizeof(int16_t));
|
||||
}
|
||||
out += 16;
|
||||
#if HAS_SSE41
|
||||
__m128i prev_interleaved = _mm_set1_epi32((uint16_t)out[-2] | ((uint16_t)out[-1] << 16));
|
||||
//__m128i prev_interleaved = _mm_shuffle_epi32(_mm_loadu_si32(out - 2), 0); // GCC misses this?
|
||||
#elif HAS_NEON
|
||||
int16x8_t result = vld1q_s16(out - 8);
|
||||
#endif
|
||||
while (nbytes > 0) {
|
||||
int shift = *in >> 4; // should be in 0..12
|
||||
int table_index = *in++ & 0xf; // should be in 0..7
|
||||
int16_t (*tbl)[8] = rspa.adpcm_table[table_index];
|
||||
int i;
|
||||
#if HAS_SSE41
|
||||
// The _mm_loadu_si64 instruction was added in GCC 9, and results in the same
|
||||
// asm as the following instructions, so better be compatible with old GCC.
|
||||
//__m128i inv = _mm_loadu_si64(in);
|
||||
uint64_t v; memcpy(&v, in, 8);
|
||||
__m128i inv = _mm_set_epi64x(0, v);
|
||||
__m128i invec[2] = {_mm_shuffle_epi8(inv, pos0), _mm_shuffle_epi8(inv, pos1)};
|
||||
__m128i tblvec0 = _mm_loadu_si128((const __m128i *)tbl[0]);
|
||||
__m128i tblvec1 = _mm_loadu_si128((const __m128i *)(tbl[1]));
|
||||
__m128i tbllo = _mm_unpacklo_epi16(tblvec0, tblvec1);
|
||||
__m128i tblhi = _mm_unpackhi_epi16(tblvec0, tblvec1);
|
||||
__m128i shiftcount = _mm_set_epi64x(0, 12 - shift); // _mm_cvtsi64_si128 does not exist on 32-bit x86
|
||||
__m128i tblvec1_rev[8];
|
||||
|
||||
tblvec1_rev[0] = _mm_insert_epi16(_mm_shuffle_epi8(tblvec1, tblrev), 1 << 11, 7);
|
||||
tblvec1_rev[1] = _mm_bsrli_si128(tblvec1_rev[0], 2);
|
||||
tblvec1_rev[2] = _mm_bsrli_si128(tblvec1_rev[0], 4);
|
||||
tblvec1_rev[3] = _mm_bsrli_si128(tblvec1_rev[0], 6);
|
||||
tblvec1_rev[4] = _mm_bsrli_si128(tblvec1_rev[0], 8);
|
||||
tblvec1_rev[5] = _mm_bsrli_si128(tblvec1_rev[0], 10);
|
||||
tblvec1_rev[6] = _mm_bsrli_si128(tblvec1_rev[0], 12);
|
||||
tblvec1_rev[7] = _mm_bsrli_si128(tblvec1_rev[0], 14);
|
||||
in += 8;
|
||||
for (i = 0; i < 2; i++) {
|
||||
__m128i acc0 = _mm_madd_epi16(prev_interleaved, tbllo);
|
||||
__m128i acc1 = _mm_madd_epi16(prev_interleaved, tblhi);
|
||||
__m128i muls[8];
|
||||
__m128i result;
|
||||
invec[i] = _mm_sra_epi16(_mm_and_si128(_mm_mullo_epi16(invec[i], mult), mask), shiftcount);
|
||||
|
||||
muls[7] = _mm_madd_epi16(tblvec1_rev[0], invec[i]);
|
||||
muls[6] = _mm_madd_epi16(tblvec1_rev[1], invec[i]);
|
||||
muls[5] = _mm_madd_epi16(tblvec1_rev[2], invec[i]);
|
||||
muls[4] = _mm_madd_epi16(tblvec1_rev[3], invec[i]);
|
||||
muls[3] = _mm_madd_epi16(tblvec1_rev[4], invec[i]);
|
||||
muls[2] = _mm_madd_epi16(tblvec1_rev[5], invec[i]);
|
||||
muls[1] = _mm_madd_epi16(tblvec1_rev[6], invec[i]);
|
||||
muls[0] = _mm_madd_epi16(tblvec1_rev[7], invec[i]);
|
||||
|
||||
acc0 = _mm_add_epi32(acc0, _mm_hadd_epi32(_mm_hadd_epi32(muls[0], muls[1]), _mm_hadd_epi32(muls[2], muls[3])));
|
||||
acc1 = _mm_add_epi32(acc1, _mm_hadd_epi32(_mm_hadd_epi32(muls[4], muls[5]), _mm_hadd_epi32(muls[6], muls[7])));
|
||||
|
||||
acc0 = _mm_srai_epi32(acc0, 11);
|
||||
acc1 = _mm_srai_epi32(acc1, 11);
|
||||
|
||||
result = _mm_packs_epi32(acc0, acc1);
|
||||
_mm_storeu_si128((__m128i *)out, result);
|
||||
out += 8;
|
||||
|
||||
prev_interleaved = _mm_shuffle_epi32(result, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
}
|
||||
#elif HAS_NEON
|
||||
int8x8_t inv = vld1_s8((int8_t *)in);
|
||||
int16x8_t tblvec[2] = {vld1q_s16(tbl[0]), vld1q_s16(tbl[1])};
|
||||
int16x8_t invec[2] = {vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos0)),
|
||||
vtbl1_s8(inv, vget_high_s8(pos0)))),
|
||||
vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos1)),
|
||||
vtbl1_s8(inv, vget_high_s8(pos1))))};
|
||||
int16x8_t shiftcount = vdupq_n_s16(shift - 12); // negative means right shift
|
||||
int16x8_t tblvec1[8];
|
||||
|
||||
in += 8;
|
||||
tblvec1[0] = vextq_s16(table_prefix, tblvec[1], 7);
|
||||
invec[0] = vmulq_s16(invec[0], mult);
|
||||
tblvec1[1] = vextq_s16(table_prefix, tblvec[1], 6);
|
||||
invec[1] = vmulq_s16(invec[1], mult);
|
||||
tblvec1[2] = vextq_s16(table_prefix, tblvec[1], 5);
|
||||
tblvec1[3] = vextq_s16(table_prefix, tblvec[1], 4);
|
||||
invec[0] = vandq_s16(invec[0], mask);
|
||||
tblvec1[4] = vextq_s16(table_prefix, tblvec[1], 3);
|
||||
invec[1] = vandq_s16(invec[1], mask);
|
||||
tblvec1[5] = vextq_s16(table_prefix, tblvec[1], 2);
|
||||
tblvec1[6] = vextq_s16(table_prefix, tblvec[1], 1);
|
||||
invec[0] = vqshlq_s16(invec[0], shiftcount);
|
||||
invec[1] = vqshlq_s16(invec[1], shiftcount);
|
||||
tblvec1[7] = table_prefix;
|
||||
for (i = 0; i < 2; i++) {
|
||||
int32x4_t acc0;
|
||||
int32x4_t acc1;
|
||||
|
||||
acc1 = vmull_lane_s16(vget_high_s16(tblvec[0]), vget_high_s16(result), 2);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec[1]), vget_high_s16(result), 3);
|
||||
acc0 = vmull_lane_s16(vget_low_s16(tblvec[0]), vget_high_s16(result), 2);
|
||||
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec[1]), vget_high_s16(result), 3);
|
||||
|
||||
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
|
||||
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
|
||||
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
|
||||
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
|
||||
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[4]), vget_high_s16(invec[i]), 0);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[5]), vget_high_s16(invec[i]), 1);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[6]), vget_high_s16(invec[i]), 2);
|
||||
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[7]), vget_high_s16(invec[i]), 3);
|
||||
|
||||
result = vcombine_s16(vqshrn_n_s32(acc0, 11), vqshrn_n_s32(acc1, 11));
|
||||
vst1q_s16(out, result);
|
||||
out += 8;
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < 2; i++) {
|
||||
int16_t ins[8];
|
||||
int16_t prev1 = out[-1];
|
||||
int16_t prev2 = out[-2];
|
||||
int j, k;
|
||||
for (j = 0; j < 4; j++) {
|
||||
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
|
||||
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
|
||||
for (k = 0; k < j; k++) {
|
||||
acc += tbl[1][((j - k) - 1)] * ins[k];
|
||||
}
|
||||
acc >>= 11;
|
||||
*out++ = clamp16(acc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nbytes -= 16 * sizeof(int16_t);
|
||||
}
|
||||
memcpy(state, out - 16, 16 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag) {
|
||||
int16_t tmp[16];
|
||||
int16_t *in_initial = BUF_S16(inofs);
|
||||
int16_t *in = in_initial;
|
||||
int16_t *out = BUF_S16(OFS_BASE + ((outflag & 3) != 0) * NUM_BYTES);
|
||||
int nbytes = ROUND_UP_16(NUM_BYTES);
|
||||
uint32_t pitch_accumulator;
|
||||
int i;
|
||||
#if !HAS_SSE41 && !HAS_NEON
|
||||
int16_t *tbl;
|
||||
int32_t sample;
|
||||
#endif
|
||||
if (flags & A_INIT) {
|
||||
memset(tmp, 0, 5 * sizeof(int16_t));
|
||||
} else {
|
||||
memcpy(tmp, state, 16 * sizeof(int16_t));
|
||||
}
|
||||
if (flags & 2) {
|
||||
memcpy(in - 8, tmp + 8, 8 * sizeof(int16_t));
|
||||
in -= tmp[5] / sizeof(int16_t);
|
||||
}
|
||||
in -= 4;
|
||||
pitch_accumulator = (uint16_t)tmp[4];
|
||||
memcpy(in, tmp, 4 * sizeof(int16_t));
|
||||
|
||||
#if HAS_SSE41
|
||||
__m128i multiples = _mm_setr_epi16(0, 2, 4, 6, 8, 10, 12, 14);
|
||||
__m128i pitchvec = _mm_set1_epi16((int16_t)pitch);
|
||||
__m128i pitchvec_8_steps = _mm_set1_epi32((pitch << 1) * 8);
|
||||
__m128i pitchacclo_vec = _mm_set1_epi32((uint16_t)pitch_accumulator);
|
||||
__m128i pl = _mm_mullo_epi16(multiples, pitchvec);
|
||||
__m128i ph = _mm_mulhi_epu16(multiples, pitchvec);
|
||||
__m128i acc_a = _mm_add_epi32(_mm_unpacklo_epi16(pl, ph), pitchacclo_vec);
|
||||
__m128i acc_b = _mm_add_epi32(_mm_unpackhi_epi16(pl, ph), pitchacclo_vec);
|
||||
|
||||
do {
|
||||
__m128i tbl_positions = _mm_srli_epi16(_mm_packus_epi32(
|
||||
_mm_and_si128(acc_a, _mm_set1_epi32(0xffff)),
|
||||
_mm_and_si128(acc_b, _mm_set1_epi32(0xffff))), 10);
|
||||
|
||||
__m128i in_positions = _mm_packus_epi32(_mm_srli_epi32(acc_a, 16), _mm_srli_epi32(acc_b, 16));
|
||||
__m128i tbl_entries[4];
|
||||
__m128i samples[4];
|
||||
|
||||
/*for (i = 0; i < 4; i++) {
|
||||
tbl_entries[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
|
||||
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i)]),
|
||||
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i + 1)]));
|
||||
samples[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
|
||||
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i)]),
|
||||
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i + 1)]));
|
||||
samples[i] = _mm_mulhrs_epi16(samples[i], tbl_entries[i]);
|
||||
}*/
|
||||
tbl_entries[0] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 0)], resample_table[_mm_extract_epi16(tbl_positions, 1)]);
|
||||
tbl_entries[1] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 2)], resample_table[_mm_extract_epi16(tbl_positions, 3)]);
|
||||
tbl_entries[2] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 4)], resample_table[_mm_extract_epi16(tbl_positions, 5)]);
|
||||
tbl_entries[3] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 6)], resample_table[_mm_extract_epi16(tbl_positions, 7)]);
|
||||
samples[0] = LOADLH(&in[_mm_extract_epi16(in_positions, 0)], &in[_mm_extract_epi16(in_positions, 1)]);
|
||||
samples[1] = LOADLH(&in[_mm_extract_epi16(in_positions, 2)], &in[_mm_extract_epi16(in_positions, 3)]);
|
||||
samples[2] = LOADLH(&in[_mm_extract_epi16(in_positions, 4)], &in[_mm_extract_epi16(in_positions, 5)]);
|
||||
samples[3] = LOADLH(&in[_mm_extract_epi16(in_positions, 6)], &in[_mm_extract_epi16(in_positions, 7)]);
|
||||
samples[0] = _mm_mulhrs_epi16(samples[0], tbl_entries[0]);
|
||||
samples[1] = _mm_mulhrs_epi16(samples[1], tbl_entries[1]);
|
||||
samples[2] = _mm_mulhrs_epi16(samples[2], tbl_entries[2]);
|
||||
samples[3] = _mm_mulhrs_epi16(samples[3], tbl_entries[3]);
|
||||
|
||||
_mm_storeu_si128((__m128i *)out, _mm_hadds_epi16(_mm_hadds_epi16(samples[0], samples[1]), _mm_hadds_epi16(samples[2], samples[3])));
|
||||
|
||||
acc_a = _mm_add_epi32(acc_a, pitchvec_8_steps);
|
||||
acc_b = _mm_add_epi32(acc_b, pitchvec_8_steps);
|
||||
out += 8;
|
||||
nbytes -= 8 * sizeof(int16_t);
|
||||
} while (nbytes > 0);
|
||||
in += (uint16_t)_mm_extract_epi16(acc_a, 1);
|
||||
pitch_accumulator = (uint16_t)_mm_extract_epi16(acc_a, 0);
|
||||
#elif HAS_NEON
|
||||
static const uint16_t multiples_data[8] = {0, 2, 4, 6, 8, 10, 12, 14};
|
||||
uint16x8_t multiples = vld1q_u16(multiples_data);
|
||||
uint32x4_t pitchvec_8_steps = vdupq_n_u32((pitch << 1) * 8);
|
||||
uint32x4_t pitchacclo_vec = vdupq_n_u32((uint16_t)pitch_accumulator);
|
||||
uint32x4_t acc_a = vmlal_n_u16(pitchacclo_vec, vget_low_u16(multiples), pitch);
|
||||
uint32x4_t acc_b = vmlal_n_u16(pitchacclo_vec, vget_high_u16(multiples), pitch);
|
||||
|
||||
do {
|
||||
uint16x8x2_t unzipped = vuzpq_u16(vreinterpretq_u16_u32(acc_a), vreinterpretq_u16_u32(acc_b));
|
||||
uint16x8_t tbl_positions = vshrq_n_u16(unzipped.val[0], 10);
|
||||
uint16x8_t in_positions = unzipped.val[1];
|
||||
int16x8_t tbl_entries[4];
|
||||
int16x8_t samples[4];
|
||||
int16x8x2_t unzipped1;
|
||||
int16x8x2_t unzipped2;
|
||||
|
||||
tbl_entries[0] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 0)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 1)]));
|
||||
tbl_entries[1] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 2)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 3)]));
|
||||
tbl_entries[2] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 4)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 5)]));
|
||||
tbl_entries[3] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 6)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 7)]));
|
||||
samples[0] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 0)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 1)]));
|
||||
samples[1] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 2)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 3)]));
|
||||
samples[2] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 4)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 5)]));
|
||||
samples[3] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 6)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 7)]));
|
||||
samples[0] = vqrdmulhq_s16(samples[0], tbl_entries[0]);
|
||||
samples[1] = vqrdmulhq_s16(samples[1], tbl_entries[1]);
|
||||
samples[2] = vqrdmulhq_s16(samples[2], tbl_entries[2]);
|
||||
samples[3] = vqrdmulhq_s16(samples[3], tbl_entries[3]);
|
||||
|
||||
unzipped1 = vuzpq_s16(samples[0], samples[1]);
|
||||
unzipped2 = vuzpq_s16(samples[2], samples[3]);
|
||||
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
|
||||
samples[1] = vqaddq_s16(unzipped2.val[0], unzipped2.val[1]);
|
||||
unzipped1 = vuzpq_s16(samples[0], samples[1]);
|
||||
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
|
||||
|
||||
vst1q_s16(out, samples[0]);
|
||||
|
||||
acc_a = vaddq_u32(acc_a, pitchvec_8_steps);
|
||||
acc_b = vaddq_u32(acc_b, pitchvec_8_steps);
|
||||
out += 8;
|
||||
nbytes -= 8 * sizeof(int16_t);
|
||||
} while (nbytes > 0);
|
||||
in += vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 1);
|
||||
pitch_accumulator = vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 0);
|
||||
#else
|
||||
do {
|
||||
for (i = 0; i < 8; i++) {
|
||||
tbl = resample_table[pitch_accumulator * 64 >> 16];
|
||||
sample = ((in[0] * tbl[0] + 0x4000) >> 15) +
|
||||
((in[1] * tbl[1] + 0x4000) >> 15) +
|
||||
((in[2] * tbl[2] + 0x4000) >> 15) +
|
||||
((in[3] * tbl[3] + 0x4000) >> 15);
|
||||
*out++ = clamp16(sample);
|
||||
|
||||
pitch_accumulator += (pitch << 1);
|
||||
in += pitch_accumulator >> 16;
|
||||
pitch_accumulator %= 0x10000;
|
||||
}
|
||||
nbytes -= 8 * sizeof(int16_t);
|
||||
} while (nbytes > 0);
|
||||
#endif
|
||||
|
||||
state[4] = (int16_t)pitch_accumulator;
|
||||
memcpy(state, in, 4 * sizeof(int16_t));
|
||||
i = (in - in_initial + 4) & 7;
|
||||
in -= i;
|
||||
if (i != 0) {
|
||||
i = -8 - i;
|
||||
}
|
||||
state[5] = i;
|
||||
memcpy(state + 8, in, 8 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t rvol) {
|
||||
int16_t *in = BUF_S16(OFS_BASE);
|
||||
int16_t *dry[2] = {BUF_S16(OFS_MAIN_L), BUF_S16(OFS_MAIN_R)};
|
||||
int16_t *wet[2] = {BUF_S16(OFS_AUX_L), BUF_S16(OFS_AUX_R)};
|
||||
int nsamples = NUM_SAMPLES;
|
||||
|
||||
struct {
|
||||
int32_t t[2];
|
||||
int32_t rate[2];
|
||||
int16_t tgt[2];
|
||||
int16_t voldry;
|
||||
int16_t volwet;
|
||||
} *savedstate = (void *)state;
|
||||
|
||||
rspa.vol[1] = rvol; // why the fuck is this here?
|
||||
|
||||
// naudio uses a linear envelope
|
||||
// TODO: sse/neon
|
||||
|
||||
int32_t t[2], tgt[2], rate[2];
|
||||
int16_t voldry, volwet;
|
||||
|
||||
if (flags & A_INIT) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
t[i] = rspa.vol[i] << 16;
|
||||
rate[i] = rspa.rate[i] >> 3;
|
||||
tgt[i] = rspa.target[i] << 16;
|
||||
}
|
||||
voldry = rspa.vol_dry;
|
||||
volwet = rspa.vol_wet;
|
||||
} else {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
t[i] = savedstate->t[i];
|
||||
rate[i] = savedstate->rate[i];
|
||||
tgt[i] = savedstate->tgt[i] << 16;
|
||||
}
|
||||
voldry = savedstate->voldry;
|
||||
volwet = savedstate->volwet;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
#define XOR 0
|
||||
#else
|
||||
#define XOR 1
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < nsamples; ++i) {
|
||||
int16_t gain[4];
|
||||
int16_t vol[2];
|
||||
int16_t *outptr[4];
|
||||
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
t[j] += rate[j];
|
||||
if ((rate[j] <= 0 && t[j] <= tgt[j]) || (rate[j] > 0 && t[j] >= tgt[j])) {
|
||||
t[j] = tgt[j];
|
||||
rate[j] = 0;
|
||||
}
|
||||
vol[j] = t[j] >> 16;
|
||||
}
|
||||
|
||||
outptr[0] = dry[0] + (i^XOR);
|
||||
outptr[1] = dry[1] + (i^XOR);
|
||||
outptr[2] = wet[0] + (i^XOR);
|
||||
outptr[3] = wet[1] + (i^XOR);
|
||||
|
||||
gain[0] = clamp16((vol[0] * voldry + 0x4000) >> 15);
|
||||
gain[1] = clamp16((vol[1] * voldry + 0x4000) >> 15);
|
||||
gain[2] = clamp16((vol[0] * volwet + 0x4000) >> 15);
|
||||
gain[3] = clamp16((vol[1] * volwet + 0x4000) >> 15);
|
||||
|
||||
const int16_t insamp = in[i^XOR];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
*outptr[j] = clamp16(*outptr[j] + ((insamp * gain[j]) >> 15));
|
||||
}
|
||||
}
|
||||
|
||||
#undef XOR
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
savedstate->t[i] = t[i];
|
||||
savedstate->rate[i] = rate[i];
|
||||
savedstate->tgt[i] = tgt[i] >> 16;
|
||||
}
|
||||
savedstate->voldry = voldry;
|
||||
savedstate->volwet = volwet;
|
||||
}
|
||||
|
||||
// flags is always 0 in PD
|
||||
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||
int nbytes = ROUND_UP_16(NUM_BYTES); // can't round up to 32 here because 0x170 ain't gonna do that
|
||||
int16_t *in = BUF_S16(in_addr);
|
||||
int16_t *out = BUF_S16(out_addr);
|
||||
#if HAS_SSE41
|
||||
__m128i gain_vec = _mm_set1_epi16(gain);
|
||||
#elif !HAS_NEON
|
||||
int i;
|
||||
int32_t sample;
|
||||
#endif
|
||||
|
||||
#if !HAS_NEON
|
||||
if (gain == -0x8000) {
|
||||
while (nbytes > 0) {
|
||||
#if HAS_SSE41
|
||||
__m128i out1, in1;
|
||||
out1 = _mm_loadu_si128((const __m128i *)out);
|
||||
in1 = _mm_loadu_si128((const __m128i *)in);
|
||||
|
||||
out1 = _mm_subs_epi16(out1, in1);
|
||||
|
||||
_mm_storeu_si128((__m128i *)out, out1);
|
||||
|
||||
out += 8;
|
||||
in += 8;
|
||||
#else
|
||||
for (i = 0; i < 8; i++) {
|
||||
sample = *out - *in++;
|
||||
*out++ = clamp16(sample);
|
||||
}
|
||||
#endif
|
||||
|
||||
nbytes -= 8 * sizeof(int16_t);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while (nbytes > 0) {
|
||||
#if HAS_SSE41
|
||||
__m128i out1, in1;
|
||||
out1 = _mm_loadu_si128((const __m128i *)out);
|
||||
in1 = _mm_loadu_si128((const __m128i *)in);
|
||||
|
||||
out1 = _mm_adds_epi16(out1, _mm_mulhrs_epi16(in1, gain_vec));
|
||||
|
||||
_mm_storeu_si128((__m128i *)out, out1);
|
||||
|
||||
out += 8;
|
||||
in += 8;
|
||||
#elif HAS_NEON
|
||||
int16x8_t out1, in1;
|
||||
out1 = vld1q_s16(out);
|
||||
in1 = vld1q_s16(in);
|
||||
|
||||
out1 = vqaddq_s16(out1, vqrdmulhq_n_s16(in1, gain));
|
||||
|
||||
vst1q_s16(out, out1);
|
||||
|
||||
out += 8;
|
||||
in += 8;
|
||||
#else
|
||||
for (i = 0; i < 8; i++) {
|
||||
sample = ((*out * 0x7fff + *in++ * gain) + 0x4000) >> 15;
|
||||
*out++ = clamp16(sample);
|
||||
}
|
||||
#endif
|
||||
|
||||
nbytes -= 8 * sizeof(int16_t);
|
||||
}
|
||||
}
|
||||
|
||||
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r) {
|
||||
// the flags are not really very intuitive here
|
||||
if (flags & A_VOL) {
|
||||
if (flags & A_LEFT) {
|
||||
rspa.vol[0] = v;
|
||||
rspa.vol_dry = t;
|
||||
rspa.vol_wet = r;
|
||||
} else {
|
||||
rspa.target[1] = v;
|
||||
rspa.rate[1] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
|
||||
}
|
||||
} else /* A_RATE */ {
|
||||
rspa.target[0] = v;
|
||||
rspa.rate[0] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
|
||||
}
|
||||
}
|
||||
|
||||
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset) {
|
||||
static mp3dec_t mp3d;
|
||||
static const u8 *curdata = NULL; // pointer to the mp3 we're currently processing
|
||||
static s32 dataptr = 0; // byte index into curdata
|
||||
|
||||
if (mp3file != curdata || reset) {
|
||||
// new mp3, reinit decoder
|
||||
mp3dec_init(&mp3d);
|
||||
curdata = mp3file;
|
||||
dataptr = 0;
|
||||
}
|
||||
|
||||
// this command is supposed to write one full frame to out
|
||||
// but which frame? we'll just decode sequentially, it'll probably work
|
||||
if (dataptr < mp3size) {
|
||||
// FIXME: decoding straight to out might bite us in the ass because it's only 1160 bytes
|
||||
mp3dec_frame_info_t info;
|
||||
const s32 samples = mp3dec_decode_frame(&mp3d, curdata + dataptr, mp3size - dataptr, out, &info);
|
||||
// fill in the rest of the buffer if frame is smaller
|
||||
const s32 diff = 580 - samples;
|
||||
if (diff > 0) {
|
||||
memset((s16 *)out + samples, 0, diff * 2);
|
||||
} else {
|
||||
assert(diff == 0);
|
||||
}
|
||||
dataptr += info.frame_bytes;
|
||||
} else {
|
||||
// empty frame
|
||||
memset(out, 0, 580 * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr) {
|
||||
// this never gets called?
|
||||
}
|
||||
|
||||
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c) {
|
||||
// this never gets called?
|
||||
}
|
||||
+533
@@ -0,0 +1,533 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "fs.h"
|
||||
#include "utils.h"
|
||||
#include "romdata.h"
|
||||
#include "mod.h"
|
||||
#include "data.h"
|
||||
#include "game/stagetable.h"
|
||||
|
||||
#define MOD_TEXTURES_DIR "textures"
|
||||
#define MOD_ANIMATIONS_DIR "animations"
|
||||
#define MOD_SEQUENCES_DIR "sequences"
|
||||
|
||||
extern struct stagemusic g_StageTracks[];
|
||||
extern struct stageallocation g_StageAllocations8Mb[];
|
||||
|
||||
#define PARSE_STAGE_FLOAT(sec, name, v, min, max) \
|
||||
p = modConfigParseFloatValue(p, token, &v); \
|
||||
if (!p || v < (min) || v > (max)) { \
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define PARSE_STAGE_INT(sec, name, v, min, max) \
|
||||
p = modConfigParseIntValue(p, token, &v); \
|
||||
if (!p || v < (min) || v > (max)) { \
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define PARSE_STAGE_FILENAME(sec, name, v) \
|
||||
p = modConfigParseFileValue(p, token, &v); \
|
||||
if (!p) { \
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define PARSE_STAGE_STRING(sec, name, v) \
|
||||
p = strParseToken(p, token, NULL); \
|
||||
if (!p) { \
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
|
||||
return NULL; \
|
||||
} \
|
||||
v = strUnquote(token);
|
||||
|
||||
#define PARSE_INT(sec, name, v, min, max, ret) \
|
||||
p = modConfigParseIntValue(p, token, &v); \
|
||||
if (!p || v < (min) || v > (max)) { \
|
||||
sysLogPrintf(LOG_ERROR, "mod: %s: invalid " name " value: %s", sec, token); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
static inline char *modConfigParseFileValue(char *p, char *token, s32 *filenum)
|
||||
{
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (!token[0]) {
|
||||
return NULL; // empty
|
||||
}
|
||||
// check if it is a number already
|
||||
s32 num = strtol(token, NULL, 0);
|
||||
if (num > 0 && romdataFileGetName(num)) {
|
||||
*filenum = num;
|
||||
return p;
|
||||
}
|
||||
// it's a filename
|
||||
num = romdataFileGetNumForName(strUnquote(token));
|
||||
if (num >= 0) {
|
||||
*filenum = num;
|
||||
return p;
|
||||
}
|
||||
// the filename was invalid
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline char *modConfigParseIntValue(char *p, char *token, s32 *out)
|
||||
{
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (!token[0]) {
|
||||
return NULL; // empty
|
||||
}
|
||||
char *endp = token;
|
||||
const s32 num = strtol(token, &endp, 0);
|
||||
if (num == 0 && (endp == token || *endp != '\0')) {
|
||||
return NULL;
|
||||
}
|
||||
*out = num;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline char *modConfigParseFloatValue(char *p, char *token, f32 *out)
|
||||
{
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (!token[0]) {
|
||||
return NULL; // empty
|
||||
}
|
||||
char *endp = token;
|
||||
const f32 num = strtof(token, &endp);
|
||||
if (num == 0.f && (endp == token || *endp != '\0')) {
|
||||
return NULL;
|
||||
}
|
||||
*out = num;
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *modConfigParseStageMusic(char *p, char *token, s32 stagenum)
|
||||
{
|
||||
struct stagemusic *smus = NULL;
|
||||
for (struct stagemusic *p = g_StageTracks; p->stagenum; ++p) {
|
||||
if (p->stagenum == stagenum) {
|
||||
smus = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!smus) {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music can't be changed for this stage", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// eat opening bracket
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (token[0] != '{' || token[1] != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// parse keyvalues until } is reached
|
||||
s32 tmp = 0;
|
||||
p = strParseToken(p, token, NULL);
|
||||
while (p && token[0] && strcmp(token, "}") != 0) {
|
||||
if (!strcmp(token, "primarytrack")) {
|
||||
PARSE_STAGE_INT("music:", "primarytrack", tmp, 0, 128);
|
||||
smus->primarytrack = tmp;
|
||||
} else if (!strcmp(token, "ambienttrack")) {
|
||||
PARSE_STAGE_INT("music:", "ambienttrack", tmp, 0, 128);
|
||||
smus->ambienttrack = tmp;
|
||||
} else if (!strcmp(token, "xtrack")) {
|
||||
PARSE_STAGE_INT("music:", "xtrack", tmp, 0, 128);
|
||||
smus->xtrack = tmp;
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music: invalid key: %s", stagenum, token);
|
||||
return NULL;
|
||||
}
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
if (token[0] != '}') {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated music block", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *modConfigParseStageWeatherRooms(char *p, char *token, s32 stagenum, struct weathercfg *wcfg)
|
||||
{
|
||||
// determine where we can start adding rooms
|
||||
s32 idx;
|
||||
for (idx = 0; idx < WEATHERCFG_MAX_SKIPROOMS && wcfg->skiprooms[idx]; ++idx);
|
||||
|
||||
// eat opening bracket
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (token[0] != '{' || token[1] != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check if user wants to clear the whole list
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (!strcmp(token, "clear")) {
|
||||
memset(wcfg->skiprooms, 0, sizeof(wcfg->skiprooms));
|
||||
idx = 0;
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
s32 tmp = 0;
|
||||
while (p && token[0] && strcmp(token, "}") != 0) {
|
||||
if (token[0] == ',' && !token[1]) {
|
||||
p = strParseToken(p, token, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = strtol(token, NULL, 0);
|
||||
if (tmp <= 0 || tmp > 32767) {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: rooms: invalid room %s", stagenum, token);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (idx < WEATHERCFG_MAX_SKIPROOMS) {
|
||||
wcfg->skiprooms[idx++] = tmp;
|
||||
}
|
||||
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
if (token[0] != '}') {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: unterminated rooms block", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *modConfigParseStageWeather(char *p, char *token, s32 stagenum)
|
||||
{
|
||||
s32 wi;
|
||||
struct weathercfg *wcfg = NULL;
|
||||
for (wi = 0; wi < ARRAYCOUNT(g_WeatherConfig) && g_WeatherConfig[wi].stagenum; ++wi) {
|
||||
if (g_WeatherConfig[wi].stagenum == stagenum) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wi >= WEATHERCFG_MAX_STAGES) {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: no more space for weather config", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wcfg = &g_WeatherConfig[wi];
|
||||
|
||||
if (!wcfg->stagenum) {
|
||||
// new weather config; initialize with defaults
|
||||
*wcfg = g_DefaultWeatherConfig;
|
||||
wcfg->stagenum = stagenum;
|
||||
} else {
|
||||
// flags have to be re-specified
|
||||
wcfg->flags = 0;
|
||||
}
|
||||
|
||||
// eat opening bracket
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (token[0] != '{' || token[1] != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// parse keyvalues until } is reached
|
||||
s32 tmpi = 0;
|
||||
f32 tmpf = 0.f;
|
||||
p = strParseToken(p, token, NULL);
|
||||
while (p && token[0] && strcmp(token, "}") != 0) {
|
||||
if (!strcmp(token, "include_rooms") || !strcmp(token, "exclude_rooms")) {
|
||||
// include_rooms | exclude_rooms { ROOM_NUMBERS... }
|
||||
const s32 include = (token[0] == 'i');
|
||||
p = modConfigParseStageWeatherRooms(p, token, stagenum, wcfg);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
if (wcfg->skiprooms[0] && include) {
|
||||
wcfg->flags |= WEATHERFLAG_INCLUDE;
|
||||
}
|
||||
} else if (!strcmp(token, "cutscene_only")) {
|
||||
wcfg->flags |= WEATHERFLAG_CUTSCENE_ONLY;
|
||||
} else if (!strcmp(token, "constant_wind")) {
|
||||
PARSE_STAGE_FLOAT("weather:", "constant_wind (0)", wcfg->windanglerad, -M_TAU, M_TAU);
|
||||
PARSE_STAGE_FLOAT("weather:", "constant_wind (1)", wcfg->windspeedx, -1024.f, 1024.f);
|
||||
PARSE_STAGE_FLOAT("weather:", "constant_wind (2)", wcfg->windspeedz, -1024.f, 1024.f);
|
||||
wcfg->flags |= WEATHERFLAG_FORCE_WINDDIR;
|
||||
} else if (!strcmp(token, "windspeed")) {
|
||||
PARSE_STAGE_FLOAT("weather:", "windspeed", tmpf, -1024.f, 1024.f);
|
||||
wcfg->windspeed = tmpf;
|
||||
} else if (!strcmp(token, "ymin")) {
|
||||
PARSE_STAGE_FLOAT("weather:", "ymin", tmpf, -65536.f, 65536.f);
|
||||
wcfg->ymin = tmpf;
|
||||
} else if (!strcmp(token, "ymax")) {
|
||||
PARSE_STAGE_FLOAT("weather:", "ymax", tmpf, -65536.f, 65536.f);
|
||||
wcfg->ymax = tmpf;
|
||||
} else if (!strcmp(token, "zmax")) {
|
||||
PARSE_STAGE_FLOAT("weather:", "zmax", tmpf, -65536.f, 65536.f);
|
||||
wcfg->zmax = tmpf;
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: invalid key: %s", stagenum, token);
|
||||
return NULL;
|
||||
}
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
if (token[0] != '}') {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated weather block", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *modConfigParseStage(char *p, char *token)
|
||||
{
|
||||
// stage number
|
||||
p = strParseToken(p, token, NULL);
|
||||
const s32 stagenum = strtol(token, NULL, 0);
|
||||
if (stagenum <= 0x01 || stagenum > 0x50) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// eat opening bracket
|
||||
p = strParseToken(p, token, NULL);
|
||||
if (token[0] != '{' || token[1] != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find the stage table pointers this corresponds to
|
||||
struct stagetableentry *stab = NULL;
|
||||
struct stageallocation *salloc = NULL;
|
||||
const s32 sidx = stageGetIndex(stagenum);
|
||||
if (sidx >= 0) {
|
||||
stab = &g_Stages[sidx];
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unknown stage number", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
for (struct stageallocation *p = g_StageAllocations8Mb; p->stagenum; ++p) {
|
||||
if (p->stagenum == stagenum) {
|
||||
salloc = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// parse keyvalues until } is reached
|
||||
s32 tmp = 0;
|
||||
char *tmps = NULL;
|
||||
p = strParseToken(p, token, NULL);
|
||||
while (p && token[0] && strcmp(token, "}") != 0) {
|
||||
if (!strcmp(token, "bgfile")) {
|
||||
// bg FILE_NAME_OR_NUM
|
||||
PARSE_STAGE_FILENAME("", "bgfile", tmp);
|
||||
stab->bgfileid = tmp;
|
||||
} else if (!strcmp(token, "tilesfile")) {
|
||||
// tilesfile FILE_NAME_OR_NUM
|
||||
PARSE_STAGE_FILENAME("", "tilesfile", tmp);
|
||||
stab->tilefileid = tmp;
|
||||
} else if (!strcmp(token, "padsfile")) {
|
||||
// padsfile FILE_NAME_OR_NUM
|
||||
PARSE_STAGE_FILENAME("", "padsfile", tmp);
|
||||
stab->padsfileid = tmp;
|
||||
} else if (!strcmp(token, "setupfile")) {
|
||||
// setupfile FILE_NAME_OR_NUM
|
||||
PARSE_STAGE_FILENAME("", "setupfile", tmp);
|
||||
stab->setupfileid = tmp;
|
||||
} else if (!strcmp(token, "mpsetupfile")) {
|
||||
// mpsetupfile FILE_NAME_OR_NUM
|
||||
PARSE_STAGE_FILENAME("", "mpsetupfile", tmp);
|
||||
stab->mpsetupfileid = tmp;
|
||||
} else if (!strcmp(token, "alarm")) {
|
||||
PARSE_STAGE_INT("", "alarm", tmp, 1, 0xFFFF);
|
||||
stab->alarm = tmp;
|
||||
} else if (!strcmp(token, "extragunmem")) {
|
||||
PARSE_STAGE_INT("", "extragunmem", tmp, 0, 0xFFFF);
|
||||
stab->extragunmem = tmp;
|
||||
} else if (!strcmp(token, "allocation")) {
|
||||
// allocation "ALLOCSTRING"
|
||||
PARSE_STAGE_STRING("", "allocation", tmps);
|
||||
// FIXME: this leaks
|
||||
tmps = strDuplicate(tmps);
|
||||
if (tmps) {
|
||||
salloc->string = tmps;
|
||||
}
|
||||
} else if (!strcmp(token, "music")) {
|
||||
// music { KEYVALUES... }
|
||||
p = modConfigParseStageMusic(p, token, stagenum);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
} else if (!strcmp(token, "weather")) {
|
||||
// weather { KEYVALUES... }
|
||||
p = modConfigParseStageWeather(p, token, stagenum);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: invalid key: %s", stagenum, token);
|
||||
return NULL;
|
||||
}
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
if (token[0] != '}') {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: unterminated stage 0x%02x block", stagenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
s32 modConfigLoad(const char *fname)
|
||||
{
|
||||
u32 dataLen = 0;
|
||||
char *data = fsFileLoad(fname, &dataLen);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 success = true;
|
||||
char token[UTIL_MAX_TOKEN + 1] = { 0 };
|
||||
char *end = data + dataLen;
|
||||
char *p = strParseToken(data, token, NULL);
|
||||
while (p && token[0]) {
|
||||
if (!strcmp(token, "stage")) {
|
||||
// stage NUMBER { KEYVALUES... }
|
||||
char *prev = p;
|
||||
p = modConfigParseStage(p, token);
|
||||
if (!p) {
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: malformed stage block at offset %d", prev - data);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// garbage
|
||||
sysLogPrintf(LOG_ERROR, "modconfig: unexpected %s at offset %d", token[0] ? token : "end of file", p - data);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
sysMemFree(data);
|
||||
return success;
|
||||
}
|
||||
|
||||
s32 modTextureLoad(u16 num, void *dst, u32 dstSize)
|
||||
{
|
||||
static s32 dirExists = -1;
|
||||
if (dirExists < 0) {
|
||||
dirExists = (fsFileSize(MOD_TEXTURES_DIR "/") >= 0);
|
||||
}
|
||||
|
||||
if (!dirExists) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[FS_MAXPATH + 1];
|
||||
snprintf(path, sizeof(path), MOD_TEXTURES_DIR "/%04x.bin", num);
|
||||
|
||||
const s32 ret = fsFileLoadTo(path, dst, dstSize);
|
||||
if (ret > 0) {
|
||||
sysLogPrintf(LOG_NOTE, "mod: loaded external texture %04x", num);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *modSequenceLoad(u16 num, u32 *outSize)
|
||||
{
|
||||
static s32 dirExists = -1;
|
||||
if (dirExists < 0) {
|
||||
dirExists = (fsFileSize(MOD_SEQUENCES_DIR "/") >= 0);
|
||||
}
|
||||
|
||||
if (!dirExists) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char path[FS_MAXPATH + 1];
|
||||
snprintf(path, sizeof(path), MOD_SEQUENCES_DIR "/%04x.bin", num);
|
||||
if (fsFileSize(path) > 0) {
|
||||
void *ret = fsFileLoad(path, outSize);
|
||||
if (ret) {
|
||||
sysLogPrintf(LOG_NOTE, "mod: loaded external sequence %04x", num);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *modAnimationLoadData(u16 num)
|
||||
{
|
||||
char path[FS_MAXPATH + 1];
|
||||
// load the animation data
|
||||
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.bin", num);
|
||||
void *data = fsFileLoad(path, NULL);
|
||||
if (!data) {
|
||||
sysFatalError("External animation %04x has no data file.\nEnsure that it is placed at %s or delete the descriptor.", num, path);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim)
|
||||
{
|
||||
static s32 dirExists = -1;
|
||||
if (dirExists < 0) {
|
||||
dirExists = (fsFileSize(MOD_ANIMATIONS_DIR "/") >= 0);
|
||||
}
|
||||
|
||||
if (!dirExists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[FS_MAXPATH + 1];
|
||||
|
||||
// load the descriptor, if any
|
||||
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.txt", num);
|
||||
if (fsFileSize(path) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *desc = fsFileLoad(path, NULL);
|
||||
if (!desc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse the descriptor
|
||||
char token[UTIL_MAX_TOKEN + 1] = { 0 };
|
||||
char *p = strParseToken(desc, token, NULL);
|
||||
s32 tmp = 0;
|
||||
while (p && token[0]) {
|
||||
if (!strcmp(token, "numframes")) {
|
||||
PARSE_INT(path, "numframes", tmp, 0, 0xFFFF, false);
|
||||
anim->numframes = tmp;
|
||||
} else if (!strcmp(token, "bytesperframe")) {
|
||||
PARSE_INT(path, "bytesperframe", tmp, 0, 0xFFFF, false);
|
||||
anim->bytesperframe = tmp;
|
||||
} else if (!strcmp(token, "headerlen")) {
|
||||
PARSE_INT(path, "headerlen", tmp, 0, 0xFFFF, false);
|
||||
anim->headerlen = tmp;
|
||||
} else if (!strcmp(token, "framelen")) {
|
||||
PARSE_INT(path, "framelen", tmp, 0, 0xFF, false);
|
||||
anim->framelen = tmp;
|
||||
} else if (!strcmp(token, "flags")) {
|
||||
PARSE_INT(path, "flags", tmp, 0, 0xFF, false);
|
||||
anim->flags = tmp;
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "mod: %s: invalid key: %s", path, token);
|
||||
return false;
|
||||
}
|
||||
p = strParseToken(p, token, NULL);
|
||||
}
|
||||
|
||||
sysMemFree(desc);
|
||||
|
||||
sysLogPrintf(LOG_NOTE, "mod: loaded external animation %04x", num);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
#include "bss.h"
|
||||
#include "game/pak.h"
|
||||
#include "game/filelist.h"
|
||||
#include "game/menu.h"
|
||||
#include "game/savebuffer.h"
|
||||
#include "game/mplayer/mplayer.h"
|
||||
#include <string.h>
|
||||
#include "fs.h"
|
||||
#include "system.h"
|
||||
#include "mpsetups.h"
|
||||
|
||||
/*
|
||||
MP Setup File Format
|
||||
# header
|
||||
[version{1}]
|
||||
[defaultsetup{1}]
|
||||
[numsetups{1}]
|
||||
# setups
|
||||
[setup_1{80}]
|
||||
...
|
||||
[setup_n{80}]
|
||||
*/
|
||||
|
||||
#define MPSETUP_VERSION 1
|
||||
|
||||
#define MPSETUP_EXPORTDIR "$S/exported/"
|
||||
#define MPSETUP_FILENAME "mpsetups"
|
||||
#define MPSETUP_FILENAME_EXP "mpsetups-ext"
|
||||
|
||||
#define MPSETUP_OP_DEFAULT 0
|
||||
#define MPSETUP_OP_IMPORT 1
|
||||
#define MPSETUP_OP_EXPORT 2
|
||||
|
||||
#define MPSETUP_IMPORT_OVERWRITE 0
|
||||
#define MPSETUP_IMPORT_ADD 1
|
||||
|
||||
#define MPSETUP_IMPORT_CONFLICT 0x1313
|
||||
|
||||
extern struct menudialogdef g_MpSaveSetupNameMenuDialog;
|
||||
|
||||
s16 g_MpCurrentSetup = -1;
|
||||
struct mpsetupfile g_MpSetupFile;
|
||||
|
||||
static struct mpsetupfile g_ImportMpSetupFile;
|
||||
static u64 g_MpImportExportFilter[2];
|
||||
|
||||
static char g_StatusText[128];
|
||||
static char g_TitleImportExportDialog[20];
|
||||
static char g_LabelSetDefault[20] = "Set Default\n";
|
||||
|
||||
/* extended mpsetup menu definitions */
|
||||
|
||||
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
|
||||
static struct menuitem g_StatusOkMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)g_StatusText,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_347, // "OK"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_StatusOkDialog = {
|
||||
MENUDIALOGTYPE_SUCCESS,
|
||||
L_OPTIONS_345, // "Cool!"
|
||||
g_StatusOkMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_DISABLEBANNER,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_StatusErrorMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)g_StatusText,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_347, // "OK"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
/* public */
|
||||
struct menudialogdef g_StatusErrorDialog = {
|
||||
MENUDIALOGTYPE_DANGER,
|
||||
L_OPTIONS_277, // "Failed"
|
||||
g_StatusErrorMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_DISABLEBANNER,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_RenameSetupItems[] = {
|
||||
#if VERSION != VERSION_JPN_FINAL
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)"Enter the setup name:\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_KEYBOARD,
|
||||
18,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
menuhandlerRenameSetup,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_RenameSetupDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Setup Name:\n",
|
||||
g_RenameSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_DeleteSetupItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)"Delete Setup?\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_385, // "No"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_386, // "Yes"
|
||||
0,
|
||||
menuhandlerDeleteSetup,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_DeleteSetupDialog = {
|
||||
MENUDIALOGTYPE_DANGER,
|
||||
(uintptr_t)"Delete Setup\n",
|
||||
g_DeleteSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ImportExportItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LIST,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
|
||||
140,
|
||||
0x0000004d,
|
||||
menuhandlerImportOrExportSettings,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ImportExportDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) g_TitleImportExportDialog,
|
||||
g_ImportExportItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ManageImportExportItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_OP_IMPORT,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Import Settings\n",
|
||||
0,
|
||||
menuhandlerOpenImportExportDialog,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_OP_EXPORT,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Export Settings\n",
|
||||
0,
|
||||
menuhandlerOpenImportExportDialog,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ManageImportExportDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) "Import/Export\n",
|
||||
g_ManageImportExportItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_MpManageSettingsListItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LIST,
|
||||
0,
|
||||
MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
|
||||
160,
|
||||
0x00000042,
|
||||
menuhandlerSelectSetupHandler,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
|
||||
};
|
||||
|
||||
/* public */
|
||||
struct menudialogdef g_ManageSettingsDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) "Manage Settings\n",
|
||||
g_MpManageSettingsListItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
&g_ManageImportExportDialog,
|
||||
};
|
||||
|
||||
static struct menuitem g_ManageSetupItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Rename\n",
|
||||
0,
|
||||
menuhandlerSetupRename,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Delete\n",
|
||||
0,
|
||||
menuhandlerSetupDelete,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)g_LabelSetDefault,
|
||||
0,
|
||||
menuhandlerSetupSetDefault,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ManageSetupDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Manage Setup",
|
||||
g_ManageSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ImportOverrideItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t) "How to resolve setups\nwith the same name?\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_IMPORT_ADD,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
(uintptr_t) "Add\n",
|
||||
0,
|
||||
menuhandlerImportAction,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_IMPORT_OVERWRITE,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
(uintptr_t) "Overwrite\n",
|
||||
0,
|
||||
menuhandlerImportAction,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ImportOverrideDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Name Conflicts\n",
|
||||
g_ImportOverrideItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* common utils */
|
||||
|
||||
static s32 mpsetupDeserialize(FILE *f, struct mpsetupfile *setupfile)
|
||||
{
|
||||
s32 rx = 0;
|
||||
|
||||
rx += fread(&setupfile->version, sizeof(setupfile->version), 1, f);
|
||||
rx += fread(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
|
||||
rx += fread(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
|
||||
|
||||
for (int i = 0; i < setupfile->numsetups; ++i) {
|
||||
rx += fread(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
|
||||
}
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
static s32 mpsetupSerialize(FILE *f, struct mpsetupfile *setupfile)
|
||||
{
|
||||
s32 wx = 0;
|
||||
|
||||
wx += fwrite(&setupfile->version, sizeof(setupfile->version), 1, f);
|
||||
wx += fwrite(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
|
||||
wx += fwrite(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
|
||||
|
||||
for (int i = 0; i < setupfile->numsetups; ++i) {
|
||||
wx += fwrite(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
|
||||
}
|
||||
|
||||
return wx;
|
||||
}
|
||||
|
||||
static FILE *mpsetupOpenFile(bool write, u8 op) {
|
||||
const char *filename = fsFullPath("$S/" MPSETUP_FILENAME ".bin");
|
||||
|
||||
if (op == MPSETUP_OP_EXPORT) {
|
||||
// create export directory if it doesn't exist
|
||||
if (fsFileSize(MPSETUP_EXPORTDIR) < 0) {
|
||||
if (fsCreateDir(MPSETUP_EXPORTDIR) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
filename = fsFullPath(MPSETUP_EXPORTDIR MPSETUP_FILENAME_EXP ".bin");
|
||||
} else if (op == MPSETUP_OP_IMPORT) {
|
||||
// same name as export but different folder
|
||||
filename = fsFullPath("$S/" MPSETUP_FILENAME_EXP ".bin");
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
if (fsFileSize(filename) < 0) {
|
||||
// setup file doesn't exist: create one
|
||||
f = fsFileOpenWrite(filename);
|
||||
fsFileFree(f);
|
||||
}
|
||||
|
||||
if (write) {
|
||||
f = fsFileOpenWrite(filename);
|
||||
} else {
|
||||
f = fsFileOpenRead(filename);
|
||||
}
|
||||
|
||||
if (f == NULL) {
|
||||
sysLogPrintf(LOG_ERROR, "Unable to open mp setup file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile)
|
||||
{
|
||||
FILE *f = mpsetupOpenFile(true, op);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 nwritten = mpsetupSerialize(f, setupfile);
|
||||
if (nwritten < 1) {
|
||||
fsFileFree(f);
|
||||
sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file");
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write the setup file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op)
|
||||
{
|
||||
FILE *f = mpsetupOpenFile(false, op);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mpsetupDeserialize(f, setupfile);
|
||||
|
||||
if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) {
|
||||
mpsetupLoadSetup(setupfile->defaultsetup - 1);
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 mpsetupImportFile(u8 op, u8 skipOverlap)
|
||||
{
|
||||
if (!skipOverlap) {
|
||||
// check for names overlap
|
||||
u8 overlap = false;
|
||||
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
|
||||
for (int j = 0; j < g_MpSetupFile.numsetups; ++j) {
|
||||
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
|
||||
overlap = true;
|
||||
return MPSETUP_IMPORT_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
|
||||
s16 overlapIdx = -1;
|
||||
for (int j = g_MpSetupFile.numsetups-1; j >= 0; --j) {
|
||||
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
|
||||
overlapIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s16 importIdx = overlapIdx;
|
||||
if (overlapIdx < 0 || op == MPSETUP_IMPORT_ADD) {
|
||||
if (g_MpSetupFile.numsetups == MPSETUP_MAXSETUPS) {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS);
|
||||
return -1;
|
||||
}
|
||||
importIdx = g_MpSetupFile.numsetups++;
|
||||
}
|
||||
|
||||
memcpy(g_MpSetupFile.setups[importIdx].bytes, g_ImportMpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
|
||||
}
|
||||
|
||||
return mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
static s32 mpsetupExportFile(void)
|
||||
{
|
||||
struct mpsetupfile expMpSetupFile;
|
||||
expMpSetupFile.numsetups = 0;
|
||||
expMpSetupFile.defaultsetup = 0;
|
||||
expMpSetupFile.version = MPSETUP_VERSION;
|
||||
|
||||
u8 maxsetups = MPSETUP_MAXSETUPS;
|
||||
maxsetups = MIN(maxsetups, g_MpSetupFile.numsetups);
|
||||
for (int i = 0; i < maxsetups; ++i) {
|
||||
u8 bank = i < 64 ? 0 : 1;
|
||||
u8 bit = i - bank * 64;
|
||||
if (g_MpImportExportFilter[bank] & (1 << bit)) {
|
||||
u8 n = expMpSetupFile.numsetups;
|
||||
expMpSetupFile.numsetups++;
|
||||
char *name = g_MpSetupFile.setups[i].bytes;
|
||||
memcpy(expMpSetupFile.setups[n].bytes, g_MpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
|
||||
expMpSetupFile.numsetups = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
s32 err = mpsetupSaveFile(MPSETUP_OP_EXPORT, &expMpSetupFile);
|
||||
if (err) {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write\nsetup file\n");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static s32 mpsetupDelete(void)
|
||||
{
|
||||
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) {
|
||||
u8* dst = g_MpSetupFile.setups[i].bytes;
|
||||
u8* src = g_MpSetupFile.setups[i+1].bytes;
|
||||
memcpy(dst, src, MPSETUP_BLOCKSIZE);
|
||||
}
|
||||
|
||||
if (g_MpCurrentSetup > slotindex) {
|
||||
g_MpCurrentSetup--;
|
||||
}
|
||||
else if (g_MpCurrentSetup == slotindex) {
|
||||
g_MpCurrentSetup = -1;
|
||||
}
|
||||
|
||||
if (g_MpSetupFile.defaultsetup > slotindex + 1) {
|
||||
g_MpSetupFile.defaultsetup--;
|
||||
}
|
||||
else if (g_MpSetupFile.defaultsetup == slotindex + 1) {
|
||||
g_MpSetupFile.defaultsetup = 0;
|
||||
}
|
||||
|
||||
g_MpSetupFile.numsetups--;
|
||||
return mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
/* menu handlers */
|
||||
|
||||
// Rename setup dialog
|
||||
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
char *name = data->keyboard.string;
|
||||
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
struct setupblock *setup = &g_MpSetupFile.setups[slotindex];
|
||||
s32 err;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETTEXT:
|
||||
strcpy(name, setup->bytes);
|
||||
break;
|
||||
case MENUOP_SETTEXT:
|
||||
strcpy(g_MpSetup.name, name);
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
strcpy(setup->bytes, name);
|
||||
err = mpsetupSaveSetup(slotindex, true);
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
} else {
|
||||
// TODO
|
||||
// menuPushDialog(&g_FilemgrFileSavedMenuDialog);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Delete setup dialog
|
||||
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 err = mpsetupDelete();
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
menuPopDialog();
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Import (or Export) settings dialog
|
||||
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *labels[] = {
|
||||
"Select All",
|
||||
"Select None",
|
||||
"Import",
|
||||
"Export",
|
||||
};
|
||||
|
||||
s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24;
|
||||
|
||||
struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile;
|
||||
|
||||
u8 numsetups = setupfile->numsetups;
|
||||
u8 numitems = numsetups + 3;
|
||||
u8 bank = data->list.value < 64 ? 0 : 1;
|
||||
u8 bit = data->list.value - bank * 64;
|
||||
u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0;
|
||||
u8 ofs;
|
||||
s32 err;
|
||||
u32 colour;
|
||||
s32 index;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETCOLOUR:
|
||||
colour = data->list.unk04;
|
||||
if (data->list.value == numitems - 1) {
|
||||
data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66;
|
||||
}
|
||||
break;
|
||||
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->list.value = numitems;
|
||||
break;
|
||||
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
if (data->list.value < numsetups) {
|
||||
return (uintptr_t) setupfile->setups[data->list.value].bytes;
|
||||
} else {
|
||||
// creates an offset to select the "Export" or "Import" label for the last item
|
||||
ofs = (data->list.value == numitems - 1) ? op - 1 : 0;
|
||||
return (intptr_t)labels[data->list.value - numsetups + ofs];
|
||||
}
|
||||
|
||||
case MENUOP_SET:
|
||||
if (data->list.value < setupfile->numsetups) {
|
||||
g_MpImportExportFilter[bank] ^= (1 << bit);
|
||||
} else {
|
||||
index = data->list.value - setupfile->numsetups;
|
||||
|
||||
switch (index) {
|
||||
// Select All
|
||||
case 0:
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
|
||||
break;
|
||||
// Select None
|
||||
case 1:
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0;
|
||||
break;
|
||||
// Export (or Import)
|
||||
case 2:
|
||||
if (hasselection) {
|
||||
err = op == MPSETUP_OP_IMPORT ? mpsetupImportFile(0, false) : mpsetupExportFile();
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
if (op == MPSETUP_OP_IMPORT) {
|
||||
// back to the 'Manage Settings' screen
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ManageSettingsDialog);
|
||||
} else {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP);
|
||||
menuPushDialog(&g_StatusOkDialog);
|
||||
}
|
||||
} else {
|
||||
if (err == MPSETUP_IMPORT_CONFLICT) {
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ImportOverrideDialog);
|
||||
} else {
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->list.value = 0x000fffff;
|
||||
break;
|
||||
|
||||
case MENUOP_GETLISTITEMCHECKBOX:
|
||||
if (data->list.value < numsetups) {
|
||||
data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Import: overwrite dialog
|
||||
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 err = mpsetupImportFile(item->param, true);
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ManageSettingsDialog);
|
||||
} else {
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Manage Import/Export settings dialog
|
||||
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_SET:
|
||||
if (item->param == MPSETUP_OP_IMPORT) {
|
||||
strcpy(g_TitleImportExportDialog, "Import Settings\n");
|
||||
if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) {
|
||||
snprintf(
|
||||
g_StatusText, sizeof(g_StatusText),
|
||||
"No import file found.\n"
|
||||
"Place the file %s.bin\n"
|
||||
"Next to your %s.bin file\n",
|
||||
MPSETUP_FILENAME_EXP, MPSETUP_FILENAME
|
||||
);
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT);
|
||||
} else {
|
||||
strcpy(g_TitleImportExportDialog, "Export Settings\n");
|
||||
}
|
||||
g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param;
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
|
||||
menuPushDialog(&g_ImportExportDialog);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Manage settings dialog
|
||||
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
u32 colour;
|
||||
switch (operation) {
|
||||
case MENUOP_GETCOLOUR:
|
||||
colour = data->list.unk04;
|
||||
if (data->list.value + 1 == g_MpSetupFile.defaultsetup) {
|
||||
data->list.unk04 = (colour & 0xffff0000) | 0xff;
|
||||
}
|
||||
break;
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->list.value = g_MpSetupFile.numsetups;
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes;
|
||||
case MENUOP_SET:
|
||||
g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value;
|
||||
if (data->list.value == g_MpSetupFile.defaultsetup - 1) {
|
||||
strcpy(g_LabelSetDefault, "Clear Default\n");
|
||||
} else {
|
||||
strcpy(g_LabelSetDefault, "Set Default\n");
|
||||
}
|
||||
menuPushDialog(&g_ManageSetupDialog);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->list.value = 0xfffff;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
menuPushDialog(&g_RenameSetupDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
menuPushDialog(&g_DeleteSetupDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
// clicked on "clear default"
|
||||
if (selected == g_MpSetupFile.defaultsetup - 1) {
|
||||
g_MpSetupFile.defaultsetup = -1;
|
||||
strcpy(g_LabelSetDefault, "Set Default\n");
|
||||
} else {
|
||||
g_MpSetupFile.defaultsetup = selected + 1;
|
||||
strcpy(g_LabelSetDefault, "Clear Default\n");
|
||||
}
|
||||
|
||||
mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
|
||||
s32 mpsetupLoadCurrentFile(void)
|
||||
{
|
||||
return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT);
|
||||
}
|
||||
|
||||
s32 mpsetupSaveCurrentFile(void)
|
||||
{
|
||||
g_MpSetupFile.version = MPSETUP_VERSION;
|
||||
return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile);
|
||||
}
|
||||
|
||||
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile)
|
||||
{
|
||||
struct savebuffer setup;
|
||||
|
||||
// request to add a new setup
|
||||
if (slotindex == g_MpSetupFile.numsetups) {
|
||||
g_MpCurrentSetup = g_MpSetupFile.numsetups++;
|
||||
}
|
||||
|
||||
savebufferClear(&setup);
|
||||
mpsetupfileSaveWad(&setup);
|
||||
|
||||
memcpy(g_MpSetupFile.setups[slotindex].bytes, setup.bytes, MPSETUP_BLOCKSIZE);
|
||||
|
||||
return savefile ? mpsetupSaveCurrentFile() : 0;
|
||||
}
|
||||
|
||||
void mpsetupLoadSetup(s32 index)
|
||||
{
|
||||
struct savebuffer buffer;
|
||||
savebufferClear(&buffer);
|
||||
struct setupblock *block = &g_MpSetupFile.setups[index];
|
||||
memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE);
|
||||
mpsetupfileLoadWad(&buffer, g_MpSetupFile.version);
|
||||
g_MpCurrentSetup = index;
|
||||
}
|
||||
|
||||
void mpsetupCopyAllFromPak(void)
|
||||
{
|
||||
if (fsFileSize("$S/" MPSETUP_FILENAME ".bin") > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
filelistCreate(1, FILETYPE_MPSETUP);
|
||||
filelistsTick();
|
||||
|
||||
for (int i = 0; i < g_FileLists[1]->numfiles; ++i) {
|
||||
struct savebuffer buffer;
|
||||
savebufferClear(&buffer);
|
||||
struct filelistfile *file = &g_FileLists[1]->files[i];
|
||||
s32 device = pakFindBySerial(file->deviceserial);
|
||||
s32 err = pakReadBodyAtGuid(device, file->fileid, buffer.bytes, 0);
|
||||
|
||||
if (err != 0) {
|
||||
sysLogPrintf(LOG_ERROR, "Unable to read pak. device %d fileid %d deviceserial %d err %d",
|
||||
device, file->fileid, file->deviceserial, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
mpsetupfileLoadWad(&buffer, 0);
|
||||
|
||||
// save the file when writing the last setup
|
||||
u8 savefile = i == g_FileLists[1]->numfiles - 1;
|
||||
mpsetupSaveSetup(g_MpSetupFile.numsetups, savefile);
|
||||
}
|
||||
|
||||
// to reset the mp setup
|
||||
mpInit(false);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,651 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <PR/ultrasched.h>
|
||||
#include "lib/sched.h"
|
||||
#include "lib/vars.h"
|
||||
#include "constants.h"
|
||||
#include "game/camdraw.h"
|
||||
#include "game/cheats.h"
|
||||
#include "game/debug.h"
|
||||
#include "game/file.h"
|
||||
#include "game/lang.h"
|
||||
#include "game/race.h"
|
||||
#include "game/body.h"
|
||||
#include "game/stubs/game_000840.h"
|
||||
#include "game/stubs/game_000850.h"
|
||||
#include "game/stubs/game_000860.h"
|
||||
#include "game/stubs/game_000870.h"
|
||||
#include "game/smoke.h"
|
||||
#include "game/stubs/game_0008e0.h"
|
||||
#include "game/stubs/game_0008f0.h"
|
||||
#include "game/stubs/game_000900.h"
|
||||
#include "game/stubs/game_000910.h"
|
||||
#include "game/tex.h"
|
||||
#include "game/stubs/game_00b180.h"
|
||||
#include "game/stubs/game_00b200.h"
|
||||
#include "game/challenge.h"
|
||||
#include "game/title.h"
|
||||
#include "game/pdmode.h"
|
||||
#include "game/objectives.h"
|
||||
#include "game/endscreen.h"
|
||||
#include "game/playermgr.h"
|
||||
#include "game/game_1531a0.h"
|
||||
#include "game/gfxmemory.h"
|
||||
#include "game/lang.h"
|
||||
#include "game/lv.h"
|
||||
#include "game/timing.h"
|
||||
#include "game/music.h"
|
||||
#include "game/stubs/game_175f50.h"
|
||||
#include "game/game_175f90.h"
|
||||
#include "game/zbuf.h"
|
||||
#include "game/game_1a78b0.h"
|
||||
#include "game/mplayer/mplayer.h"
|
||||
#include "game/pak.h"
|
||||
#include "game/splat.h"
|
||||
#include "game/utils.h"
|
||||
#include "bss.h"
|
||||
#include "lib/audiomgr.h"
|
||||
#include "lib/args.h"
|
||||
#include "lib/boot.h"
|
||||
#include "lib/vm.h"
|
||||
#include "lib/rzip.h"
|
||||
#include "lib/vi.h"
|
||||
#include "lib/fault.h"
|
||||
#include "lib/crash.h"
|
||||
#include "lib/dma.h"
|
||||
#include "lib/joy.h"
|
||||
#include "lib/main.h"
|
||||
#include "lib/snd.h"
|
||||
#include "lib/memp.h"
|
||||
#include "lib/mema.h"
|
||||
#include "lib/model.h"
|
||||
#include "lib/profile.h"
|
||||
#include "lib/videbug.h"
|
||||
#include "lib/debughud.h"
|
||||
#include "lib/anim.h"
|
||||
#include "lib/rdp.h"
|
||||
#include "lib/lib_34d0.h"
|
||||
#include "lib/lib_2f490.h"
|
||||
#include "lib/rmon.h"
|
||||
#include "lib/rng.h"
|
||||
#include "lib/str.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#include "debugger.h"
|
||||
#include "system.h"
|
||||
|
||||
extern u8 *g_MempHeap;
|
||||
extern u32 g_MempHeapSize;
|
||||
|
||||
void rngSetSeed(u32 seed);
|
||||
|
||||
bool var8005d9b0 = false;
|
||||
s32 g_StageNum = STAGE_TITLE;
|
||||
u32 g_MainMemaHeapSize = 1024 * 300;
|
||||
bool var8005d9bc = false;
|
||||
s32 var8005d9c0 = 0;
|
||||
s32 var8005d9c4 = 0;
|
||||
bool g_MainGameLogicEnabled = true;
|
||||
u32 g_MainNumGfxTasks = 0;
|
||||
bool g_MainIsEndscreen = false;
|
||||
s32 g_DoBootPakMenu = 0;
|
||||
|
||||
u32 var8005dd3c = 0x00000000;
|
||||
u32 var8005dd40 = 0x00000000;
|
||||
u32 var8005dd44 = 0x00000000;
|
||||
u32 var8005dd48 = 0x00000000;
|
||||
u32 var8005dd4c = 0x00000000;
|
||||
u32 var8005dd50 = 0x00000000;
|
||||
s32 g_MainChangeToStageNum = -1;
|
||||
bool g_MainIsDebugMenuOpen = false;
|
||||
|
||||
struct stageallocation g_StageAllocations8Mb[] = {
|
||||
{ STAGE_CITRAINING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_DEFECTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_INVESTIGATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_EXTRACTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_CHICAGO, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_G5BUILDING, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_VILLA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma600" },
|
||||
{ STAGE_INFILTRATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
|
||||
{ STAGE_RESCUE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
|
||||
{ STAGE_ESCAPE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
|
||||
{ STAGE_AIRBASE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_AIRFORCEONE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_CRASHSITE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_PELAGIC, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_DEEPSEA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_DEFENSE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_ATTACKSHIP, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_SKEDARRUINS, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
|
||||
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_ASH, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_28, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_MBR, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
|
||||
{ STAGE_TEST_SILO, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_24, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_MAIANSOS, "-ml0 -me0 -mgfx120 -mvtx100 -ma500" },
|
||||
{ STAGE_RETAKING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_TEST_DEST, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_2B, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_WAR, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_TEST_UFF, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_TEST_OLD, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_DUEL, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
|
||||
{ STAGE_TEST_LAM, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
|
||||
{ STAGE_TEST_ARCH, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
|
||||
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
|
||||
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
|
||||
{ 0, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
|
||||
};
|
||||
|
||||
struct stageallocation g_StageAllocations4Mb[] = {
|
||||
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx96 -mvtx96 -ma130" },
|
||||
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
|
||||
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
|
||||
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx100 -mvtx96 -ma120" },
|
||||
{ STAGE_4MBMENU, "-mgfx100 -mvtx50 -ma50" },
|
||||
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
|
||||
{ 0, "-ml0 -me0 -mgfx100 -mvtx96 -ma300" },
|
||||
};
|
||||
|
||||
Gfx var8005dcc8[] = {
|
||||
gsSPSegment(0x00, 0x00000000),
|
||||
gsSPDisplayList(&var800613a0),
|
||||
gsSPDisplayList(&var80061380),
|
||||
gsDPFullSync(),
|
||||
gsSPEndDisplayList(),
|
||||
};
|
||||
|
||||
s32 g_MainIsBooting = 1;
|
||||
|
||||
void mainInit(void)
|
||||
{
|
||||
s32 x;
|
||||
s32 i;
|
||||
s32 j;
|
||||
u32 addr;
|
||||
|
||||
faultInit();
|
||||
dmaInit();
|
||||
amgrInit();
|
||||
varsInit();
|
||||
mempInit();
|
||||
memaInit();
|
||||
joyInit();
|
||||
joyReset();
|
||||
|
||||
var8005d9b0 = rmonIsDisabled();
|
||||
|
||||
g_Is4Mb = (osGetMemSize() <= 0x400000);
|
||||
g_VmShowStats = 0;
|
||||
|
||||
// no copyright screen
|
||||
viSetMode(VIMODE_HI);
|
||||
viConfigureForLegal();
|
||||
viBlack(true);
|
||||
viUpdateMode();
|
||||
|
||||
filesInit();
|
||||
|
||||
if (var8005d9b0) {
|
||||
argSetString(" -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma400");
|
||||
}
|
||||
|
||||
mempSetHeap(g_MempHeap, g_MempHeapSize);
|
||||
|
||||
mempResetPool(MEMPOOL_8);
|
||||
mempResetPool(MEMPOOL_PERMANENT);
|
||||
crashReset();
|
||||
challengesInit();
|
||||
utilsInit();
|
||||
texInit();
|
||||
langInit();
|
||||
lvInit();
|
||||
cheatsInit();
|
||||
textInit();
|
||||
dhudInit();
|
||||
playermgrInit();
|
||||
frametimeInit();
|
||||
profileInit();
|
||||
smokesInit();
|
||||
mpInit(true);
|
||||
pheadInit();
|
||||
paksInit();
|
||||
pheadInit2();
|
||||
animsInit();
|
||||
racesInit();
|
||||
bodiesInit();
|
||||
titleInit();
|
||||
|
||||
modelSetDistanceChecksDisabled(true); // don't use LODs
|
||||
|
||||
g_MainIsBooting = 0;
|
||||
}
|
||||
|
||||
void mainProc(void)
|
||||
{
|
||||
mainInit();
|
||||
rdpInit();
|
||||
sndInit();
|
||||
|
||||
while (true) {
|
||||
mainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It's suspected that this function would have allowed developers to override
|
||||
* the value of variables while the game is running in order to view their
|
||||
* effects immediately rather than having to recompile the game each time.
|
||||
*
|
||||
* The developers would have used rmon to create a table of name/value pairs,
|
||||
* then this function would have looked up the given variable name in the table
|
||||
* and written the new value to the variable's address.
|
||||
*/
|
||||
void mainOverrideVariable(char *name, void *value)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* This function enters an infinite loop which iterates once per stage load.
|
||||
* Within this loop is an inner loop which runs very frequently and decides
|
||||
* whether to run mainTick on each iteration.
|
||||
*
|
||||
* NTSC beta checks two shorts at an offset 64MB into the development board
|
||||
* and refuses to continue if they are not any of the allowed values.
|
||||
* Decomp patches these reads in its build system so it can be played
|
||||
* without the development board.
|
||||
*/
|
||||
void mainLoop(void)
|
||||
{
|
||||
s32 ending = false;
|
||||
s32 index;
|
||||
s32 numplayers;
|
||||
u32 stack;
|
||||
|
||||
func0f175f98();
|
||||
|
||||
var8005d9c4 = 0;
|
||||
argGetLevel(&g_StageNum);
|
||||
|
||||
if (g_DoBootPakMenu) {
|
||||
g_Vars.pakstocheck = 0xfd;
|
||||
g_StageNum = STAGE_BOOTPAKMENU;
|
||||
}
|
||||
|
||||
if (g_StageNum != STAGE_TITLE) {
|
||||
titleSetNextStage(g_StageNum);
|
||||
|
||||
if (g_StageNum < STAGE_TITLE) {
|
||||
func0f01b148(0);
|
||||
|
||||
if (argFindByPrefix(1, "-hard")) {
|
||||
lvSetDifficulty(argFindByPrefix(1, "-hard")[0] - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_StageNum == STAGE_CITRAINING && IS4MB()) {
|
||||
g_StageNum = STAGE_4MBMENU;
|
||||
}
|
||||
|
||||
rngSetSeed(osGetCount());
|
||||
|
||||
// Outer loop - this is infinite because ending is never changed
|
||||
while (!ending) {
|
||||
g_MainNumGfxTasks = 0;
|
||||
g_MainGameLogicEnabled = true;
|
||||
g_MainIsEndscreen = false;
|
||||
|
||||
if (var8005d9b0 && var8005d9c4 == 0) {
|
||||
index = -1;
|
||||
|
||||
if (IS4MB()) {
|
||||
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
|
||||
index = 0; \
|
||||
while (g_StageAllocations4Mb[index].stagenum) { \
|
||||
if (g_StageAllocations4Mb[index].stagenum == g_StageNum + 400) { \
|
||||
break; \
|
||||
} \
|
||||
index++;
|
||||
}
|
||||
|
||||
if (g_StageAllocations4Mb[index].stagenum == 0) {
|
||||
index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (index);
|
||||
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
while (g_StageAllocations4Mb[index].stagenum) {
|
||||
if (g_StageNum == g_StageAllocations4Mb[index].stagenum) {
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
argSetString(g_StageAllocations4Mb[index].string);
|
||||
} else {
|
||||
// 8MB
|
||||
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
|
||||
index = 0; \
|
||||
while (g_StageAllocations8Mb[index].stagenum) { \
|
||||
if (g_StageNum + 400 == g_StageAllocations8Mb[index].stagenum) { \
|
||||
break; \
|
||||
} \
|
||||
index++;
|
||||
}
|
||||
|
||||
if (g_StageAllocations8Mb[index].stagenum == 0) {
|
||||
index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
|
||||
while (g_StageAllocations8Mb[index].stagenum) {
|
||||
if (g_StageNum == g_StageAllocations8Mb[index].stagenum) {
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
argSetString(g_StageAllocations8Mb[index].string);
|
||||
}
|
||||
}
|
||||
|
||||
var8005d9c4 = 0;
|
||||
|
||||
mempResetPool(MEMPOOL_7);
|
||||
mempResetPool(MEMPOOL_STAGE);
|
||||
filesStop(4);
|
||||
|
||||
if (argFindByPrefix(1, "-ma")) {
|
||||
g_MainMemaHeapSize = strtol(argFindByPrefix(1, "-ma"), NULL, 0) * 1024;
|
||||
}
|
||||
|
||||
memaReset(mempAlloc(g_MainMemaHeapSize, MEMPOOL_STAGE), g_MainMemaHeapSize);
|
||||
langReset(g_StageNum);
|
||||
playermgrReset();
|
||||
|
||||
if (g_StageNum >= STAGE_TITLE) {
|
||||
numplayers = 0;
|
||||
} else {
|
||||
if (argFindByPrefix(1, "-play")) {
|
||||
numplayers = strtol(argFindByPrefix(1, "-play"), NULL, 0);
|
||||
} else {
|
||||
numplayers = 1;
|
||||
}
|
||||
|
||||
if (getNumPlayers() >= 2) {
|
||||
numplayers = getNumPlayers();
|
||||
}
|
||||
}
|
||||
|
||||
if (numplayers < 2) {
|
||||
g_Vars.bondplayernum = 0;
|
||||
g_Vars.coopplayernum = -1;
|
||||
g_Vars.antiplayernum = -1;
|
||||
} else if (argFindByPrefix(1, "-coop")) {
|
||||
g_Vars.bondplayernum = 0;
|
||||
g_Vars.coopplayernum = 1;
|
||||
g_Vars.antiplayernum = -1;
|
||||
} else if (argFindByPrefix(1, "-anti")) {
|
||||
g_Vars.bondplayernum = 0;
|
||||
g_Vars.coopplayernum = -1;
|
||||
g_Vars.antiplayernum = 1;
|
||||
}
|
||||
|
||||
playermgrAllocatePlayers(numplayers);
|
||||
|
||||
if (argFindByPrefix(1, "-mpbots")) {
|
||||
g_Vars.lvmpbotlevel = 1;
|
||||
}
|
||||
|
||||
if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
|
||||
g_MpSetup.chrslots = 0x03;
|
||||
mpReset();
|
||||
} else if (g_Vars.perfectbuddynum) {
|
||||
mpReset();
|
||||
} else if (g_Vars.mplayerisrunning == false
|
||||
&& (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) {
|
||||
g_MpSetup.chrslots = 1;
|
||||
|
||||
if (numplayers >= 2) {
|
||||
g_MpSetup.chrslots |= 1 << 1;
|
||||
}
|
||||
|
||||
if (numplayers >= 3) {
|
||||
g_MpSetup.chrslots |= 1 << 2;
|
||||
}
|
||||
|
||||
if (numplayers >= 4) {
|
||||
g_MpSetup.chrslots |= 1 << 3;
|
||||
}
|
||||
|
||||
g_MpSetup.stagenum = g_StageNum;
|
||||
mpReset();
|
||||
}
|
||||
|
||||
gfxReset();
|
||||
joyReset();
|
||||
dhudReset();
|
||||
zbufReset(g_StageNum);
|
||||
lvReset(g_StageNum);
|
||||
viReset(g_StageNum);
|
||||
frametimeCalculate();
|
||||
profileReset();
|
||||
|
||||
while (g_MainChangeToStageNum < 0) {
|
||||
const s32 cycles = osGetCount() - g_Vars.thisframestartt;
|
||||
if (!g_Vars.mininc60 || (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2)) {
|
||||
schedStartFrame(&g_Sched);
|
||||
mainTick();
|
||||
schedEndFrame(&g_Sched);
|
||||
}
|
||||
if (g_TickExtraSleep) {
|
||||
sysSleep(EXTRA_SLEEP_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
lvStop();
|
||||
mempDisablePool(MEMPOOL_STAGE);
|
||||
mempDisablePool(MEMPOOL_7);
|
||||
filesStop(4);
|
||||
viBlack(true);
|
||||
pak0f116994();
|
||||
|
||||
g_StageNum = g_MainChangeToStageNum;
|
||||
g_MainChangeToStageNum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void mainTick(void)
|
||||
{
|
||||
Gfx *gdl = NULL;
|
||||
Gfx *gdlstart = NULL;
|
||||
OSScMsg msg = {OS_SC_DONE_MSG};
|
||||
s32 i;
|
||||
|
||||
if (g_MainChangeToStageNum < 0) {
|
||||
frametimeCalculate();
|
||||
profileReset();
|
||||
profileSetMarker(PROFILE_MAINTICK_START);
|
||||
joyDebugJoy();
|
||||
schedSetCrashEnable2(false);
|
||||
|
||||
if (g_DebuggerTimePasses) {
|
||||
g_MainGameLogicEnabled = true;
|
||||
} else {
|
||||
g_MainGameLogicEnabled = (g_DebuggerFrameAdvance > 0);
|
||||
if (g_MainGameLogicEnabled) {
|
||||
--g_DebuggerFrameAdvance;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_MainGameLogicEnabled) {
|
||||
gdl = gdlstart = gfxGetMasterDisplayList();
|
||||
|
||||
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
|
||||
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 0, 0x0100, 6, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
|
||||
|
||||
lvTick();
|
||||
playermgrShuffle();
|
||||
|
||||
if (g_StageNum < STAGE_TITLE) {
|
||||
for (i = 0; i < PLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(playermgrGetPlayerAtOrder(i));
|
||||
|
||||
if (g_StageNum != STAGE_TEST_OLD || !titleIsKeepingMode()) {
|
||||
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
|
||||
viSetFovAspectAndSize(
|
||||
g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
|
||||
g_Vars.currentplayer->viewwidth, g_Vars.currentplayer->viewheight);
|
||||
}
|
||||
|
||||
lvTickPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
gdl = lvRender(gdl);
|
||||
|
||||
if (debugGetProfileMode() >= 2) {
|
||||
gdl = profileRender(gdl);
|
||||
}
|
||||
|
||||
gDPFullSync(gdl++);
|
||||
gSPEndDisplayList(gdl++);
|
||||
}
|
||||
|
||||
if (g_MainGameLogicEnabled) {
|
||||
gfxSwapBuffers();
|
||||
viUpdateMode();
|
||||
rdpCreateTask(gdlstart, gdl, 0, (uintptr_t) &msg);
|
||||
memaPrint();
|
||||
profileSetMarker(PROFILE_MAINTICK_END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mainEndStage(void)
|
||||
{
|
||||
sndStopNosedive();
|
||||
|
||||
if (!g_MainIsEndscreen) {
|
||||
pak0f11c6d0();
|
||||
joyDisableTemporarily();
|
||||
|
||||
if (g_Vars.coopplayernum >= 0) {
|
||||
s32 prevplayernum = g_Vars.currentplayernum;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < PLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(i);
|
||||
endscreenPushCoop();
|
||||
}
|
||||
|
||||
setCurrentPlayerNum(prevplayernum);
|
||||
musicStartMenu();
|
||||
} else if (g_Vars.antiplayernum >= 0) {
|
||||
s32 prevplayernum = g_Vars.currentplayernum;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < PLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(i);
|
||||
endscreenPushAnti();
|
||||
}
|
||||
|
||||
setCurrentPlayerNum(prevplayernum);
|
||||
musicStartMenu();
|
||||
} else if (g_Vars.normmplayerisrunning) {
|
||||
mpEndMatch();
|
||||
} else {
|
||||
endscreenPrepare();
|
||||
musicStartMenu();
|
||||
}
|
||||
}
|
||||
|
||||
g_MainIsEndscreen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change to the given stage at the end of the current frame.
|
||||
*/
|
||||
void mainChangeToStage(s32 stagenum)
|
||||
{
|
||||
pak0f11c6d0();
|
||||
|
||||
g_MainChangeToStageNum = stagenum;
|
||||
}
|
||||
|
||||
s32 mainGetStageNum(void)
|
||||
{
|
||||
return g_StageNum;
|
||||
}
|
||||
|
||||
void func0000e990(void)
|
||||
{
|
||||
objectivesCheckAll();
|
||||
objectivesDisableChecking();
|
||||
mainEndStage();
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/ultrasched.h>
|
||||
#include "lib/boot.h"
|
||||
#include "lib/sched.h"
|
||||
#include "constants.h"
|
||||
#include "game/menugfx.h"
|
||||
#include "bss.h"
|
||||
#include "lib/args.h"
|
||||
#include "lib/audiomgr.h"
|
||||
#include "lib/reset.h"
|
||||
#include "lib/rzip.h"
|
||||
#include "lib/crash.h"
|
||||
#include "lib/main.h"
|
||||
#include "lib/snd.h"
|
||||
#include "lib/pimgr.h"
|
||||
#include "lib/profile.h"
|
||||
#include "lib/rmon.h"
|
||||
#include "lib/lib_48150.h"
|
||||
#include "lib/vi.h"
|
||||
#include "lib/joy.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
|
||||
#include "video.h"
|
||||
#include "audio.h"
|
||||
#include "input.h"
|
||||
#include "mixer.h"
|
||||
#include "debugger.h"
|
||||
|
||||
/*
|
||||
* private typedefs and defines
|
||||
*/
|
||||
#define VIDEO_MSG 666
|
||||
#define RSP_DONE_MSG 667
|
||||
#define RDP_DONE_MSG 668
|
||||
#define PRE_NMI_MSG 669
|
||||
|
||||
/*
|
||||
* OSScTask state
|
||||
*/
|
||||
#define OS_SC_DP 0x0001 /* set if still needs dp */
|
||||
#define OS_SC_SP 0x0002 /* set if still needs sp */
|
||||
#define OS_SC_YIELD 0x0010 /* set if yield requested */
|
||||
#define OS_SC_YIELDED 0x0020 /* set if yield completed */
|
||||
|
||||
/*
|
||||
* OSScTask->flags type identifier
|
||||
*/
|
||||
#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP)
|
||||
#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST)
|
||||
#define OS_SC_DP_XBUS (OS_SC_SP)
|
||||
#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST)
|
||||
#define OS_SC_SP_XBUS (OS_SC_DP)
|
||||
#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST)
|
||||
|
||||
/*
|
||||
* private functions
|
||||
*/
|
||||
void __scMain(void *arg);
|
||||
void __scHandleTasks(OSSched *s);
|
||||
void __scHandleRSP(OSSched *s);
|
||||
void __scHandleRDP(OSSched *s);
|
||||
void __scAppendList(OSSched *s, OSScTask *t);
|
||||
OSScTask *__scTaskReady(OSScTask *t);
|
||||
s32 __scTaskComplete(OSSched *s,OSScTask *t);
|
||||
void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp);
|
||||
void __scYield(OSSched *s);
|
||||
s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP);
|
||||
|
||||
OSViMode var8008dcc0[NUM_GFXTASKS];
|
||||
OSViMode *var8008dd60[NUM_GFXTASKS];
|
||||
OSViMode var8008dd68[NUM_GFXTASKS];
|
||||
s32 var8008de08;
|
||||
s32 g_ViCurVStart0;
|
||||
s32 g_ViCurVStart1;
|
||||
u32 var8008de14;
|
||||
OSTimer g_SchedRspTimer;
|
||||
u32 g_SchedDpCounters[4];
|
||||
struct artifact g_ArtifactLists[3][120];
|
||||
u8 g_SchedSpecialArtifactIndexes[3];
|
||||
s32 g_SchedWriteArtifactsIndex;
|
||||
s32 g_SchedFrontArtifactsIndex;
|
||||
s32 g_SchedPendingArtifactsIndex;
|
||||
|
||||
bool g_SchedCrashedUnexpectedly = false;
|
||||
bool g_SchedCrashEnable1 = false;
|
||||
bool g_SchedCrashEnable2 = false;
|
||||
u32 g_SchedCrashRenderInterval = 45000000;
|
||||
u32 g_SchedCrashLastRendered = 0;
|
||||
|
||||
s32 var8005ce74 = 0;
|
||||
f32 g_ViXScalesBySlot[NUM_GFXTASKS] = {1, 1};
|
||||
f32 g_ViYScalesBySlot[NUM_GFXTASKS] = {1, 1};
|
||||
bool g_SchedViModesPending[NUM_GFXTASKS] = {false, false};
|
||||
s32 g_ViUnblackTimer = NUM_FRAMEBUFFERS + 1;
|
||||
s32 g_ViShakeDirection = 1;
|
||||
s32 g_ViShakeIntensity = 0;
|
||||
f32 g_ViShakeIntensityMult = 1.f;
|
||||
s32 g_ViShakeTimer = 0;
|
||||
u32 var8005cea0 = 0;
|
||||
u32 var8005cea4 = 0;
|
||||
OSScMsg g_SchedRspMsg = {OS_SC_RSP_MSG};
|
||||
bool g_SchedIsFirstTask = true;
|
||||
|
||||
s32 g_PrevFrameFb = -1;
|
||||
s32 g_BlurFb = -1;
|
||||
s32 g_BlurFbCapTimer = -1;
|
||||
bool g_BlurFbDirty = true;
|
||||
|
||||
void schedSetCrashEnable1(bool enable)
|
||||
{
|
||||
g_SchedCrashEnable1 = enable;
|
||||
}
|
||||
|
||||
void schedSetCrashedUnexpectedly(bool enable)
|
||||
{
|
||||
g_SchedCrashedUnexpectedly = enable;
|
||||
}
|
||||
|
||||
void schedSetCrashEnable2(bool enable)
|
||||
{
|
||||
g_SchedCrashEnable2 = enable;
|
||||
}
|
||||
|
||||
void schedSetCrashRenderInterval(u32 cycles)
|
||||
{
|
||||
g_SchedCrashRenderInterval = cycles;
|
||||
}
|
||||
|
||||
void schedRenderCrashOnBuffer(void *framebuffer)
|
||||
{
|
||||
if ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly) {
|
||||
// crashRenderFrame(framebuffer);
|
||||
g_SchedCrashLastRendered = osGetCount();
|
||||
}
|
||||
}
|
||||
|
||||
void schedRenderCrashPeriodically(u32 framecount)
|
||||
{
|
||||
if ((framecount & 0xf) == 0 && ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly)) {
|
||||
if (osGetCount() - g_SchedCrashLastRendered > g_SchedCrashRenderInterval) {
|
||||
// crashRenderFrame(g_FrameBuffers[0]);
|
||||
// crashRenderFrame(g_FrameBuffers[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void schedInitCrashLastRendered(void)
|
||||
{
|
||||
g_SchedCrashLastRendered = osGetCount();
|
||||
}
|
||||
|
||||
void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields)
|
||||
{
|
||||
sc->curRSPTask = 0;
|
||||
sc->curRDPTask = 0;
|
||||
sc->clientList = 0;
|
||||
sc->frameCount = 0;
|
||||
sc->audioListHead = 0;
|
||||
sc->gfxListHead = 0;
|
||||
sc->audioListTail = 0;
|
||||
sc->gfxListTail = 0;
|
||||
sc->retraceMsg.type = OS_SC_RETRACE_MSG;
|
||||
sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
|
||||
sc->thread = thread;
|
||||
|
||||
osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS);
|
||||
osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS);
|
||||
|
||||
osCreateViManager(OS_PRIORITY_VIMGR);
|
||||
|
||||
var8008de08 = osViModeTable[mode].comRegs.hStart;
|
||||
g_ViCurVStart0 = osViModeTable[mode].fldRegs[0].vStart;
|
||||
g_ViCurVStart1 = osViModeTable[mode].fldRegs[1].vStart;
|
||||
|
||||
var8008dd60[0] = &var8008dd68[0];
|
||||
var8008dd60[1] = &var8008dd68[1];
|
||||
|
||||
var8008dd68[0] = osViModeTable[mode];
|
||||
var8008dd68[1] = osViModeTable[mode];
|
||||
|
||||
osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields);
|
||||
schedInitCrashLastRendered();
|
||||
|
||||
g_PrevFrameFb = videoCreateFramebuffer(0, 0, false, true);
|
||||
g_BlurFb = videoCreateFramebuffer(0, 0, false, true);
|
||||
}
|
||||
|
||||
void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, bool is30fps)
|
||||
{
|
||||
c->msgQ = msgQ;
|
||||
c->is30fps = is30fps;
|
||||
c->next = sc->clientList;
|
||||
sc->clientList = c;
|
||||
}
|
||||
|
||||
OSMesgQueue *osScGetCmdQ(OSSched *sc)
|
||||
{
|
||||
return &sc->cmdQ;
|
||||
}
|
||||
|
||||
void __scUpdateViMode(void)
|
||||
{
|
||||
if (g_SchedIsFirstTask) {
|
||||
osViBlack(false);
|
||||
g_SchedIsFirstTask = false;
|
||||
}
|
||||
|
||||
var8005ce74 = (var8005ce74 + 1) % 2;
|
||||
|
||||
if (g_SchedViModesPending[1 - var8005ce74]) {
|
||||
// TODO: make this a little less awkward
|
||||
extern struct rend_vidat *g_ViBackData;
|
||||
videoUpdateNativeResolution(g_ViBackData->bufx, g_ViBackData->bufy);
|
||||
g_SchedViModesPending[1 - var8005ce74] = false;
|
||||
}
|
||||
|
||||
if (g_ViUnblackTimer != 0 && g_ViUnblackTimer <= NUM_FRAMEBUFFERS) {
|
||||
g_ViUnblackTimer--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nintendo's sheduler accepts tasks on a "command" message queue.
|
||||
* This isn't used here.
|
||||
*
|
||||
* In PD, the main and audio threads submit tasks by calling this function
|
||||
* instead. It temporarily increases the calling thread's priority above the
|
||||
* scheduler, adds the task to the linked list directly and attempts to execute
|
||||
* it. This is faster than the queue method because it avoids switching threads.
|
||||
*/
|
||||
void schedSubmitTask(OSSched *sc, OSScTask *t)
|
||||
{
|
||||
if (sc->doAudio && t->list.t.type == M_AUDTASK) {
|
||||
// send this into the mixer
|
||||
} else if (t->list.t.type == M_GFXTASK) {
|
||||
videoSubmitCommands((Gfx *)t->list.t.data_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void schedStartFrame(OSSched *sc)
|
||||
{
|
||||
debuggerStartFrame();
|
||||
videoStartFrame();
|
||||
}
|
||||
|
||||
void schedAudioFrame(OSSched *sc)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
if (!g_SndDisabled) {
|
||||
for (i = 0; i < g_Vars.diffframe60; i++) {
|
||||
amgrFrame();
|
||||
audioEndFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a retrace (vsync) event.
|
||||
*
|
||||
* Audio tasks are scheduled based on retrace + a timer (approximately 6ms).
|
||||
* On NTSC, this is done on every second frame if 8MB, or every second frame
|
||||
* if 4MB. I guess less memory means the audio queue has to be kept smaller
|
||||
* and processed more frequently. On PAL, it's every second frame regardless.
|
||||
*
|
||||
* Controller input is polled here.
|
||||
*
|
||||
* Lastly, if there's crash information available then it will be checked and
|
||||
* rendered periodically (once every 16 retraces). I guess this makes it render
|
||||
* if the RDP has hung.
|
||||
*/
|
||||
void schedEndFrame(OSSched *sc)
|
||||
{
|
||||
sc->frameCount++;
|
||||
|
||||
#if PAL
|
||||
if (!g_Resetting && (sc->frameCount & 1)) {
|
||||
// osStopTimer(&g_SchedRspTimer);
|
||||
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
|
||||
}
|
||||
#else
|
||||
if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) {
|
||||
// osStopTimer(&g_SchedRspTimer);
|
||||
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!g_Resetting) {
|
||||
viHandleRetrace();
|
||||
}
|
||||
|
||||
debuggerFrame();
|
||||
|
||||
inputUpdate();
|
||||
|
||||
joyStartReadData(&g_PiMesgQueue);
|
||||
joyReadData();
|
||||
joy00014238();
|
||||
|
||||
sndHandleRetrace();
|
||||
schedAudioFrame(sc);
|
||||
schedRenderCrashPeriodically(sc->frameCount);
|
||||
|
||||
debuggerEndFrame();
|
||||
videoEndFrame();
|
||||
|
||||
if (g_MainIsBooting == 0) {
|
||||
schedConsiderScreenshot();
|
||||
}
|
||||
|
||||
// check for vid mode changes
|
||||
__scUpdateViMode();
|
||||
}
|
||||
|
||||
void schedInitArtifacts(void)
|
||||
{
|
||||
s32 i;
|
||||
s32 j;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (j = 0; j < MAX_ARTIFACTS; j++) {
|
||||
g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE;
|
||||
}
|
||||
|
||||
g_SchedSpecialArtifactIndexes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The write list is an artifact list that is not currently being displayed on
|
||||
* the screen. Update logic can write here to put artifacts on the next frame.
|
||||
*/
|
||||
struct artifact *schedGetWriteArtifacts(void)
|
||||
{
|
||||
return g_ArtifactLists[g_SchedWriteArtifactsIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* The front list is the artifact list that is currently being displayed on the
|
||||
* screen. Rendering logic reads this list. The list may be re-used for multiple
|
||||
* frames in a row during lag.
|
||||
*/
|
||||
struct artifact *schedGetFrontArtifacts(void)
|
||||
{
|
||||
return g_ArtifactLists[g_SchedFrontArtifactsIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* The pending list is possibly misnamed. I'm not sure how this list works.
|
||||
*
|
||||
* @TODO: Investigate.
|
||||
*/
|
||||
struct artifact *schedGetPendingArtifacts(void)
|
||||
{
|
||||
return g_ArtifactLists[g_SchedPendingArtifactsIndex];
|
||||
}
|
||||
|
||||
void schedIncrementWriteArtifacts(void)
|
||||
{
|
||||
g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3;
|
||||
}
|
||||
|
||||
void schedIncrementFrontArtifacts(void)
|
||||
{
|
||||
g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3;
|
||||
}
|
||||
|
||||
void schedIncrementPendingArtifacts(void)
|
||||
{
|
||||
g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3;
|
||||
}
|
||||
|
||||
void schedResetArtifacts(void)
|
||||
{
|
||||
g_SchedWriteArtifactsIndex = 0;
|
||||
g_SchedFrontArtifactsIndex = 1;
|
||||
g_SchedPendingArtifactsIndex = 0;
|
||||
}
|
||||
|
||||
void schedUpdatePendingArtifacts(void)
|
||||
{
|
||||
g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0;
|
||||
schedIncrementPendingArtifacts();
|
||||
}
|
||||
|
||||
void schedConsiderScreenshot(void)
|
||||
{
|
||||
if (g_MenuData.screenshottimer == 1) {
|
||||
if (IS8MB()) {
|
||||
menugfxCreateBlur();
|
||||
}
|
||||
|
||||
g_MenuData.screenshottimer = 0;
|
||||
}
|
||||
|
||||
if (g_BlurFbCapTimer == 0) {
|
||||
videoCopyFramebuffer(g_BlurFb, 0, -1, -1);
|
||||
g_BlurFbCapTimer = -1;
|
||||
g_BlurFbDirty = false;
|
||||
} else if (g_BlurFbCapTimer > 0) {
|
||||
--g_BlurFbCapTimer;
|
||||
} else if (g_BlurFbCapTimer < 0) {
|
||||
// no blur requested this frame, mark blur fb dirty
|
||||
g_BlurFbDirty = true;
|
||||
}
|
||||
|
||||
if (g_MenuData.screenshottimer >= 2) {
|
||||
g_MenuData.screenshottimer--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "preprocess/common.h"
|
||||
|
||||
static struct ptrmarker ptrMarkers[MAX_PTR_MARKERS];
|
||||
static int numPtrMarkers;
|
||||
|
||||
void ptrAdd(u32 ptr_src, uintptr_t ptr_host)
|
||||
{
|
||||
if (numPtrMarkers >= ARRAYCOUNT(ptrMarkers)) {
|
||||
sysFatalError("ptrAdd(%p, %p): ptrmarker limit exceeded", (void *)(uintptr_t)ptr_src, (void *)ptr_host);
|
||||
}
|
||||
|
||||
ptrMarkers[numPtrMarkers].ptr_src = ptr_src;
|
||||
ptrMarkers[numPtrMarkers].ptr_host = ptr_host;
|
||||
numPtrMarkers++;
|
||||
}
|
||||
|
||||
struct ptrmarker *ptrFind(uintptr_t ptr_src)
|
||||
{
|
||||
for (int i = 0; i < numPtrMarkers; i++) {
|
||||
if (ptrMarkers[i].ptr_src == ptr_src) {
|
||||
return &ptrMarkers[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ptrReset(void)
|
||||
{
|
||||
numPtrMarkers = 0;
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
#include "preprocess/gbi.h"
|
||||
|
||||
/**
|
||||
* 4 bytes decompressed size of primary data
|
||||
* 4 bytes compressed size of section 1 in its entirety
|
||||
* 4 bytes compressed size of primary data
|
||||
* Section 1:
|
||||
* Primary: (zipped)
|
||||
* 4 bytes null
|
||||
* 4 bytes pointer to room table
|
||||
* 4 bytes pointer to portal table
|
||||
* 4 bytes pointer to bgcmds
|
||||
* 4 bytes pointer to lights table
|
||||
* 4 bytes null
|
||||
* (room table)
|
||||
* (portal table)
|
||||
* (bgcmds)
|
||||
* (lights table)
|
||||
* room 1 (zipped)
|
||||
* room 2 (zipped)
|
||||
* ...
|
||||
* Section 2:
|
||||
* 2 bytes decompressed size of section (mask with 0x7fff)
|
||||
* 2 bytes compressed size of section
|
||||
* Texture ID list (zipped)
|
||||
* Section 3:
|
||||
* 2 bytes decompressed size of section (mask with 0x7fff)
|
||||
* 2 bytes compressed size of section
|
||||
* Zipped:
|
||||
* (room bbox table)
|
||||
* (list of roomgfxdata sizes)
|
||||
* (list of light counts per room)
|
||||
*/
|
||||
|
||||
struct fileheader {
|
||||
u32 primary_infsize;
|
||||
u32 section1_cmpsize;
|
||||
u32 primary_cmpsize;
|
||||
};
|
||||
|
||||
struct sectionheader {
|
||||
u16 infsize;
|
||||
u16 cmpsize;
|
||||
};
|
||||
|
||||
struct n64_primaryheader {
|
||||
u32 unused1;
|
||||
u32 ptr_rooms;
|
||||
u32 ptr_portals;
|
||||
u32 ptr_bgcmds;
|
||||
u32 ptr_lights;
|
||||
u32 unused2;
|
||||
};
|
||||
|
||||
struct host_primaryheader {
|
||||
uintptr_t unused1;
|
||||
uintptr_t ptr_rooms;
|
||||
uintptr_t ptr_portals;
|
||||
uintptr_t ptr_bgcmds;
|
||||
uintptr_t ptr_lights;
|
||||
uintptr_t unused2;
|
||||
};
|
||||
|
||||
struct n64_bgroom {
|
||||
u32 ptr_gfxdata;
|
||||
struct coord pos;
|
||||
u8 br_light_min;
|
||||
u8 br_light_max;
|
||||
};
|
||||
|
||||
struct n64_roomblock {
|
||||
u8 type;
|
||||
u32 ptr_next;
|
||||
u32 ptr_gdl;
|
||||
u32 ptr_vertices;
|
||||
u32 ptr_colours;
|
||||
};
|
||||
|
||||
struct n64_roomgfxdata {
|
||||
u32 ptr_vertices;
|
||||
u32 ptr_colours;
|
||||
u32 ptr_opablocks;
|
||||
u32 ptr_xlublocks;
|
||||
s16 lightsindex;
|
||||
s16 numlights;
|
||||
s16 numvertices;
|
||||
s16 numcolours;
|
||||
// roomblocks[]
|
||||
};
|
||||
|
||||
struct vtx {
|
||||
s16 coord[3];
|
||||
u8 flag;
|
||||
u8 color;
|
||||
u16 s;
|
||||
u16 t;
|
||||
};
|
||||
|
||||
static void convertPrimaryRooms(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos)
|
||||
{
|
||||
struct n64_bgroom *n64_rooms = (struct n64_bgroom *) &src[*srcpos];
|
||||
struct bgroom *host_rooms = (struct bgroom *) &dst[*dstpos];
|
||||
|
||||
s32 numRooms = 0;
|
||||
|
||||
for (int i = 1; n64_rooms[i].ptr_gfxdata != 0; i++) {
|
||||
numRooms++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numRooms + 1; i++) {
|
||||
host_rooms[i].unk00 = PD_BE32(n64_rooms[i].ptr_gfxdata);
|
||||
host_rooms[i].pos = PD_SWAPPED_VAL(n64_rooms[i].pos);
|
||||
host_rooms[i].br_light_min = n64_rooms[i].br_light_min;
|
||||
host_rooms[i].br_light_max = n64_rooms[i].br_light_max;
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_rooms) * (numRooms + 2);
|
||||
*dstpos += sizeof(*host_rooms) * (numRooms +2);
|
||||
}
|
||||
|
||||
static void convertPrimaryPortals(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 *src_portalvtxs, u32 *dst_portalvtxs)
|
||||
{
|
||||
struct bgportal *n64_portals = (struct bgportal *) &src[*srcpos];
|
||||
struct bgportal *host_portals = (struct bgportal *) &dst[*dstpos];
|
||||
|
||||
// Count portals
|
||||
int numportals = 0;
|
||||
|
||||
for (int i = 0; n64_portals[i].verticesoffset != 0; i++) {
|
||||
numportals++;
|
||||
}
|
||||
|
||||
// Convert portals
|
||||
for (int i = 0; i < numportals; i++) {
|
||||
host_portals[i].verticesoffset = PD_BE16(n64_portals[i].verticesoffset);
|
||||
host_portals[i].roomnum1 = PD_BE16(n64_portals[i].roomnum1);
|
||||
host_portals[i].roomnum2 = PD_BE16(n64_portals[i].roomnum2);
|
||||
host_portals[i].flags = n64_portals[i].flags;
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_portals) * (numportals + 1);
|
||||
*dstpos += sizeof(*host_portals) * (numportals + 1);
|
||||
|
||||
*src_portalvtxs = *srcpos;
|
||||
*dst_portalvtxs = *dstpos;
|
||||
|
||||
while (1) {
|
||||
struct portalvertices *n64_pvertices = (struct portalvertices *)&src[*srcpos];
|
||||
struct portalvertices *host_pvertices = (struct portalvertices *)&dst[*dstpos];
|
||||
|
||||
host_pvertices->count = n64_pvertices->count;
|
||||
|
||||
for (int j = 0; j < host_pvertices->count; j++) {
|
||||
host_pvertices->vertices[j] = PD_SWAPPED_VAL(n64_pvertices->vertices[j]);
|
||||
}
|
||||
|
||||
*srcpos += 4 + host_pvertices->count * 12;
|
||||
*dstpos += 4 + host_pvertices->count * 12;
|
||||
|
||||
if (host_pvertices->count == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void convertPrimaryBgCmds(u8 *dst, u32 *dstpos, u8 *src, u32 dst_portalvtxs, u32 src_portalvtxs)
|
||||
{
|
||||
struct bgcmd *n64_cmds = (struct bgcmd *) src;
|
||||
struct bgcmd *host_cmds = (struct bgcmd *) &dst[*dstpos];
|
||||
int num_cmds = 0;
|
||||
|
||||
for (int i = 0; n64_cmds[i].type != 0; i++) {
|
||||
num_cmds++;
|
||||
}
|
||||
|
||||
num_cmds++;
|
||||
|
||||
for (int i = 0; i < num_cmds; i++) {
|
||||
host_cmds[i].type = n64_cmds[i].type;
|
||||
host_cmds[i].len = n64_cmds[i].len;
|
||||
host_cmds[i].param = PD_BE32(n64_cmds[i].param);
|
||||
|
||||
if (host_cmds[i].type == 0x64) {
|
||||
u32 offset = host_cmds[i].param - src_portalvtxs;
|
||||
host_cmds[i].param = dst_portalvtxs + offset;
|
||||
}
|
||||
}
|
||||
|
||||
*dstpos += sizeof(*host_cmds) * num_cmds;
|
||||
}
|
||||
|
||||
static void convertPrimaryLights(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 end)
|
||||
{
|
||||
struct light *n64_lights = (struct light *) &src[*srcpos];
|
||||
struct light *host_lights = (struct light *) &dst[*dstpos];
|
||||
int num_lights = (end - *srcpos) / sizeof(struct light);
|
||||
|
||||
for (int i = 0; i < num_lights; i++) {
|
||||
host_lights[i].roomnum = PD_BE16(n64_lights[i].roomnum);
|
||||
host_lights[i].colour = PD_BE16(n64_lights[i].colour);
|
||||
host_lights[i].brightness = n64_lights[i].brightness;
|
||||
host_lights[i].sparkable = n64_lights[i].sparkable;
|
||||
host_lights[i].healthy = n64_lights[i].healthy;
|
||||
host_lights[i].on = n64_lights[i].on;
|
||||
host_lights[i].sparking = n64_lights[i].sparking;
|
||||
host_lights[i].vulnerable = n64_lights[i].vulnerable;
|
||||
host_lights[i].brightnessmult = n64_lights[i].brightnessmult;
|
||||
host_lights[i].dirx = n64_lights[i].dirx;
|
||||
host_lights[i].diry = n64_lights[i].diry;
|
||||
host_lights[i].dirz = n64_lights[i].dirz;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
host_lights[i].bbox[j].x = PD_BE16(n64_lights[i].bbox[j].x);
|
||||
host_lights[i].bbox[j].y = PD_BE16(n64_lights[i].bbox[j].y);
|
||||
host_lights[i].bbox[j].z = PD_BE16(n64_lights[i].bbox[j].z);
|
||||
}
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_lights) * num_lights;
|
||||
*dstpos += ALIGN(sizeof(*host_lights) * num_lights, 4);
|
||||
}
|
||||
|
||||
#define BLOCK_LEAF 0
|
||||
#define BLOCK_PARENT 1
|
||||
|
||||
void relinkPtr(uintptr_t* ptr)
|
||||
{
|
||||
if (!*ptr) return;
|
||||
|
||||
struct ptrmarker* marker = ptrFind(*ptr);
|
||||
if (!marker) {
|
||||
sysFatalError("[BG] WARNING: Unable to relink pointer: %p\n", ptr);
|
||||
}
|
||||
|
||||
*ptr = marker->ptr_host;
|
||||
}
|
||||
|
||||
static u32 convertRoomGfxData(u8 *dst, u8 *src, u32 infsize, u32 src_ofs)
|
||||
{
|
||||
ptrReset();
|
||||
gbiReset();
|
||||
|
||||
u32 dst_roomoffset = src_ofs;
|
||||
|
||||
uintptr_t gdls_addr[64];
|
||||
int numgdls = 0;
|
||||
|
||||
struct n64_roomgfxdata *src_header = (struct n64_roomgfxdata*)src;
|
||||
struct roomgfxdata *dst_header = (struct roomgfxdata*)dst;
|
||||
|
||||
dst_header->vertices = (void *)(uintptr_t)PD_BE32(src_header->ptr_vertices);
|
||||
dst_header->colours = (void *)(uintptr_t)PD_BE32(src_header->ptr_colours);
|
||||
dst_header->opablocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_opablocks);
|
||||
dst_header->xlublocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_xlublocks);
|
||||
dst_header->lightsindex = PD_BE16(src_header->lightsindex);
|
||||
dst_header->numlights = PD_BE16(src_header->numlights);
|
||||
dst_header->numvertices = PD_BE16(src_header->numvertices);
|
||||
dst_header->numcolours = PD_BE16(src_header->numcolours);
|
||||
|
||||
intptr_t endpos = (uintptr_t)dst_header->vertices - src_ofs;
|
||||
uintptr_t curpos_src = sizeof(struct n64_roomgfxdata);
|
||||
uintptr_t curpos_dst = sizeof(struct roomgfxdata) - sizeof(struct roomblock); // compensate for the [1]
|
||||
|
||||
// roomblocks
|
||||
int ncoords = 0;
|
||||
|
||||
// save the ptr to roomblocks here to iterate later to fix the pointers
|
||||
struct roomblock *ptr_dst_roomblocks = (struct roomblock*)&dst[curpos_dst];
|
||||
|
||||
int numblocks = 0;
|
||||
while ((intptr_t)(curpos_src + sizeof(struct n64_roomblock)) <= endpos) {
|
||||
struct n64_roomblock *src_roomblock = (struct n64_roomblock*)&src[curpos_src];
|
||||
struct roomblock *dest_roomblock = (struct roomblock*)&dst[curpos_dst];
|
||||
|
||||
dest_roomblock->type = src_roomblock->type;
|
||||
dest_roomblock->next = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_next);
|
||||
dest_roomblock->gdl = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_gdl);
|
||||
dest_roomblock->vertices = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_vertices);
|
||||
dest_roomblock->colours = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_colours);
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
if (src_roomblock->type == BLOCK_PARENT) {
|
||||
ncoords++;
|
||||
uintptr_t vtx_ptr = (uintptr_t)dest_roomblock->vertices - src_ofs;
|
||||
if (vtx_ptr < endpos) endpos = vtx_ptr;
|
||||
}
|
||||
else if (src_roomblock->ptr_gdl) {
|
||||
gdls_addr[numgdls++] = PD_BE32(src_roomblock->ptr_gdl) - src_ofs;
|
||||
}
|
||||
|
||||
curpos_src += sizeof(struct n64_roomblock);
|
||||
curpos_dst += sizeof(struct roomblock);
|
||||
numblocks++;
|
||||
}
|
||||
|
||||
// block coords
|
||||
for (size_t i = 0; i < ncoords; i++) {
|
||||
u32 *src_coord = (u32*)(src + curpos_src);
|
||||
u32 *dst_coord = (u32*)(dst + curpos_dst);
|
||||
|
||||
dst_coord[0] = PD_BE32(src_coord[0]);
|
||||
dst_coord[1] = PD_BE32(src_coord[1]);
|
||||
dst_coord[2] = PD_BE32(src_coord[2]);
|
||||
|
||||
dst_coord[3] = PD_BE32(src_coord[3]);
|
||||
dst_coord[4] = PD_BE32(src_coord[4]);
|
||||
dst_coord[5] = PD_BE32(src_coord[5]);
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
curpos_src += 6 * sizeof(u32);
|
||||
curpos_dst += 6 * sizeof(u32);
|
||||
}
|
||||
|
||||
curpos_dst = ALIGN8(curpos_dst);
|
||||
|
||||
// vertices
|
||||
uintptr_t ptr_src_vertices = curpos_src = ALIGN8((uintptr_t)dst_header->vertices - src_ofs);
|
||||
uintptr_t ptr_dst_vertices = curpos_dst + dst_roomoffset;
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
uintptr_t vtx_end = (uintptr_t)dst_header->colours - src_ofs;
|
||||
|
||||
while (dst_header->colours && curpos_src < vtx_end) {
|
||||
struct vtx *src_vtx = (struct vtx*)(src + curpos_src);
|
||||
struct vtx *dst_vtx = (struct vtx*)(dst + curpos_dst);
|
||||
|
||||
dst_vtx->coord[0] = PD_BE16(src_vtx->coord[0]);
|
||||
dst_vtx->coord[1] = PD_BE16(src_vtx->coord[1]);
|
||||
dst_vtx->coord[2] = PD_BE16(src_vtx->coord[2]);
|
||||
|
||||
dst_vtx->flag = src_vtx->flag;
|
||||
dst_vtx->color = src_vtx->color;
|
||||
|
||||
dst_vtx->s = PD_BE16(src_vtx->s);
|
||||
dst_vtx->t = PD_BE16(src_vtx->t);
|
||||
|
||||
curpos_src += sizeof(struct vtx);
|
||||
curpos_dst += sizeof(struct vtx);
|
||||
}
|
||||
|
||||
curpos_dst = ALIGN8(curpos_dst);
|
||||
|
||||
// colors
|
||||
uintptr_t ptr_src_colors = 0;
|
||||
uintptr_t ptr_dst_colors = 0;
|
||||
|
||||
if (dst_header->colours) {
|
||||
ptr_src_colors = curpos_src = ALIGN8((uintptr_t)dst_header->colours - src_ofs);
|
||||
ptr_dst_colors = curpos_dst + dst_roomoffset;
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
uintptr_t col_end = (numgdls > 0) ? gdls_addr[0] : infsize;
|
||||
size_t col_len = col_end - curpos_src;
|
||||
|
||||
memcpy(dst + curpos_dst, src + curpos_src, col_len);
|
||||
curpos_src += col_len;
|
||||
curpos_dst += col_len;
|
||||
}
|
||||
|
||||
// gdls
|
||||
gbiSetVtx(src_header->ptr_vertices, ptr_src_vertices);
|
||||
gbiSetSegment(0x0e, (uintptr_t)dst_header->vertices);
|
||||
|
||||
uintptr_t gdlstart = curpos_dst;
|
||||
for (size_t i = 0; i < numgdls; i++) {
|
||||
ptrAdd(gdls_addr[i] + src_ofs, curpos_dst + dst_roomoffset);
|
||||
curpos_dst = gbiConvertGdl(dst, curpos_dst, src, gdls_addr[i], 1);
|
||||
}
|
||||
|
||||
// relink ptrs: roomblocks
|
||||
for (size_t i = 0; i < numblocks; i++) {
|
||||
struct roomblock *block = (struct roomblock*)&ptr_dst_roomblocks[i];
|
||||
|
||||
relinkPtr((uintptr_t*)&block->next);
|
||||
|
||||
if (block->type == BLOCK_LEAF) {
|
||||
relinkPtr((uintptr_t*)&block->gdl);
|
||||
u32 offset_vtx = (uintptr_t)block->vertices - ptr_src_vertices - src_ofs;
|
||||
u32 offset_col = (uintptr_t)block->colours - ptr_src_colors - src_ofs;
|
||||
|
||||
block->vertices = (void *)(ptr_dst_vertices + offset_vtx);
|
||||
block->colours = (void *)(ptr_dst_colors + offset_col);
|
||||
}
|
||||
else {
|
||||
relinkPtr((uintptr_t*)&block->gdl); // child
|
||||
relinkPtr((uintptr_t*)&block->vertices); // coord
|
||||
}
|
||||
}
|
||||
|
||||
// relink ptrs: header
|
||||
relinkPtr((uintptr_t*)&dst_header->vertices);
|
||||
relinkPtr((uintptr_t*)&dst_header->colours);
|
||||
relinkPtr((uintptr_t*)&dst_header->opablocks);
|
||||
relinkPtr((uintptr_t*)&dst_header->xlublocks);
|
||||
|
||||
return curpos_dst;
|
||||
}
|
||||
|
||||
static u32 convertSection1(u8 *dst, u8 *src, u32 ofs)
|
||||
{
|
||||
// Convert primary
|
||||
u32 srcpos = 0;
|
||||
u32 dstpos = 0;
|
||||
struct host_primaryheader *host_primary_header = (struct host_primaryheader *) dst;
|
||||
struct n64_primaryheader *n64_primary_header = (struct n64_primaryheader *) src;
|
||||
srcpos += sizeof(struct n64_primaryheader);
|
||||
dstpos += sizeof(*host_primary_header);
|
||||
|
||||
u32 src_bgcmds = PD_BE32(n64_primary_header->ptr_bgcmds) - ofs;
|
||||
|
||||
host_primary_header->unused1 = 0;
|
||||
host_primary_header->unused2 = 0;
|
||||
|
||||
host_primary_header->ptr_rooms = dstpos + ofs;
|
||||
convertPrimaryRooms(dst, &dstpos, src, &srcpos);
|
||||
|
||||
if (n64_primary_header->ptr_lights) {
|
||||
host_primary_header->ptr_lights = dstpos + ofs;
|
||||
srcpos = PD_BE32(n64_primary_header->ptr_lights) - ofs;
|
||||
convertPrimaryLights(dst, &dstpos, src, &srcpos, src_bgcmds);
|
||||
}
|
||||
|
||||
host_primary_header->ptr_portals = dstpos + ofs;
|
||||
srcpos = PD_BE32(n64_primary_header->ptr_portals) - ofs;
|
||||
u32 src_portalvtxs, dst_portalvtxs;
|
||||
convertPrimaryPortals(dst, &dstpos, src, &srcpos, &src_portalvtxs, &dst_portalvtxs);
|
||||
|
||||
host_primary_header->ptr_bgcmds = dstpos + ofs;
|
||||
convertPrimaryBgCmds(dst, &dstpos, &src[src_bgcmds], dst_portalvtxs, src_portalvtxs);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
void preprocessBgSection1(u8 *data, u32 size, u32 ofs)
|
||||
{
|
||||
u8 *dst = sysMemZeroAlloc(size);
|
||||
|
||||
u32 newSize = convertSection1(dst, data, ofs);
|
||||
|
||||
if (newSize > size) {
|
||||
sysFatalError("overflow when trying to preprocess a bg file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
}
|
||||
|
||||
u32 preprocessBgRoom(u8 *data, u32 size, u32 room_ofs)
|
||||
{
|
||||
size *= 2;
|
||||
u8 *dst = sysMemZeroAlloc(size);
|
||||
u32 newSize = convertRoomGfxData(dst, data, size, room_ofs);
|
||||
|
||||
if (newSize > size) {
|
||||
sysFatalError("overflow when trying to preprocess a bg room, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
void preprocessBgSection1Header(u8* data, u32 size)
|
||||
{
|
||||
u32* header = (u32*)data;
|
||||
PD_SWAP_VAL(header[0]); // inflatedsize
|
||||
PD_SWAP_VAL(header[1]); // section1size
|
||||
PD_SWAP_VAL(header[2]); // primcompsize
|
||||
}
|
||||
|
||||
void preprocessBgSection2Header(u8* data, u32 size)
|
||||
{
|
||||
u16* header = (u16*)data;
|
||||
PD_SWAP_VAL(header[0]); // inflatedsize
|
||||
PD_SWAP_VAL(header[1]); // section2compsize
|
||||
}
|
||||
|
||||
void preprocessBgSection2(u8* data, u32 size)
|
||||
{
|
||||
// section2 is a texture id list
|
||||
u16* section2 = (u16*)data;
|
||||
for (s32 i = 0; i < size; ++i) {
|
||||
PD_SWAP_VAL(section2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void preprocessBgSection3Header(u8* data, u32 size)
|
||||
{
|
||||
u16* header = (u16*)data;
|
||||
PD_SWAP_VAL(header[0]);
|
||||
PD_SWAP_VAL(header[1]);
|
||||
}
|
||||
|
||||
void preprocessBgSection3(u8* data, u32 size)
|
||||
{
|
||||
// room bounding boxes, 6x s16 per room
|
||||
s16* bbox = (s16*)data;
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
}
|
||||
|
||||
// gfxdatalen list
|
||||
u16* gfxdatalen = (u16*)bbox;
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
PD_SWAP_VAL(*gfxdatalen); ++gfxdatalen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
static int getNextNonZero(u8 *src, u32 offset, size_t len)
|
||||
{
|
||||
u32 *ptr = (u32 *) &src[offset];
|
||||
u32 *end = (u32 *) &src[len];
|
||||
|
||||
while (ptr < end) {
|
||||
if (*ptr != 0) {
|
||||
return PD_BE32(*ptr);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getNumStrings(u8 *src, size_t len)
|
||||
{
|
||||
u32 ptr_table_len = getNextNonZero(src, 0, len);
|
||||
|
||||
if (ptr_table_len) {
|
||||
return ptr_table_len / sizeof(u32);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 convertLangFile(u8 *dst, u8 *src, size_t srclen)
|
||||
{
|
||||
// Convert it
|
||||
u32 *src_offsets = (u32 *) src;
|
||||
size_t src_ptr_table_len = PD_BE32(src_offsets[0]);
|
||||
size_t src_str_table_len = srclen - src_ptr_table_len;
|
||||
int num_strings = getNumStrings(src, srclen);
|
||||
size_t dst_ptr_table_len = num_strings * sizeof(uintptr_t);
|
||||
size_t dst_str_table_len = src_str_table_len;
|
||||
|
||||
int cur_dst_offset = dst_ptr_table_len;
|
||||
|
||||
uintptr_t *dst_offsets = (uintptr_t *) dst;
|
||||
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
u32 src_offset = PD_BE32(src_offsets[i]);
|
||||
|
||||
if (src_offset) {
|
||||
// Write pointer
|
||||
dst_offsets[i] = (cur_dst_offset);
|
||||
|
||||
// Write string
|
||||
u32 end = getNextNonZero(src, (i + 1) * 4, num_strings * 4);
|
||||
|
||||
if (!end) {
|
||||
end = srclen;
|
||||
}
|
||||
|
||||
size_t len = end - src_offset;
|
||||
len = ALIGN4(len);
|
||||
memcpy(&dst[cur_dst_offset], &src[src_offset], len);
|
||||
|
||||
cur_dst_offset += len;
|
||||
} else {
|
||||
// Write pointer
|
||||
dst_offsets[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ALIGN16(cur_dst_offset);
|
||||
}
|
||||
|
||||
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize) {
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_LANG);
|
||||
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertLangFile(dst, data, size);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a lang file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,292 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
struct n64_header {
|
||||
s32 num_pads;
|
||||
s32 num_covers;
|
||||
u32 ptr_waypoints;
|
||||
u32 ptr_waygroups;
|
||||
u32 ptr_cover;
|
||||
};
|
||||
|
||||
struct host_header {
|
||||
s32 num_pads;
|
||||
s32 num_covers;
|
||||
uintptr_t ptr_waypoints;
|
||||
uintptr_t ptr_waygroups;
|
||||
uintptr_t ptr_cover;
|
||||
};
|
||||
|
||||
struct padheader {
|
||||
u32 flags : 18;
|
||||
u32 room : 10;
|
||||
u32 liftnum : 4;
|
||||
};
|
||||
|
||||
struct n64_waypoint {
|
||||
s32 padnum;
|
||||
u32 ptr_neighbours;
|
||||
s32 groupnum;
|
||||
s32 step;
|
||||
};
|
||||
|
||||
struct n64_waygroup {
|
||||
u32 ptr_neighbours;
|
||||
u32 ptr_waypoints;
|
||||
s32 step;
|
||||
};
|
||||
|
||||
static u32 convertPads(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_pads)
|
||||
{
|
||||
u16 *src_offsets = (u16 *) &src[srcpos];
|
||||
u16 *dst_offsets = (u16 *) &dst[dstpos];
|
||||
|
||||
dstpos += num_pads * sizeof(u16);
|
||||
|
||||
for (int i = 0; i < num_pads; i++) {
|
||||
srcpos = PD_BE16(src_offsets[i]);
|
||||
|
||||
dst_offsets[i] = (dstpos);
|
||||
|
||||
// Header
|
||||
u32 n64_padheader = PD_BE32(*(u32 *) &src[srcpos]);
|
||||
struct padheader *host_padheader = (struct padheader *) &dst[dstpos];
|
||||
u32 flags = (n64_padheader >> 14) & 0x3ffff;
|
||||
|
||||
*(u32*)host_padheader = (n64_padheader);
|
||||
|
||||
srcpos += sizeof(struct padheader);
|
||||
dstpos += sizeof(struct padheader);
|
||||
|
||||
// Position
|
||||
if (flags & PADFLAG_INTPOS) {
|
||||
s16 *srcptr = (s16 *) &src[srcpos];
|
||||
s16 *dstptr = (s16 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE16(srcptr[0]);
|
||||
dstptr[1] = PD_BE16(srcptr[1]);
|
||||
dstptr[2] = PD_BE16(srcptr[2]);
|
||||
|
||||
srcpos += 8;
|
||||
dstpos += 8;
|
||||
} else {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Up
|
||||
if ((flags & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ)) == 0) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Look
|
||||
if ((flags & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ)) == 0) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Bbox
|
||||
if (flags & PADFLAG_HASBBOXDATA) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
dstptr[3] = PD_BE32(srcptr[3]);
|
||||
dstptr[4] = PD_BE32(srcptr[4]);
|
||||
dstptr[5] = PD_BE32(srcptr[5]);
|
||||
|
||||
srcpos += 4 * 6;
|
||||
dstpos += 4 * 6;
|
||||
}
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertWayPoints(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_waypoint *n64_waypoints = (struct n64_waypoint *) &src[srcpos];
|
||||
struct waypoint *host_waypoints = (struct waypoint *) &dst[dstpos];
|
||||
int num_waypoints;
|
||||
|
||||
for (num_waypoints = 0; n64_waypoints[num_waypoints].padnum != -1; num_waypoints++);
|
||||
|
||||
dstpos += (num_waypoints + 1) * sizeof(struct waypoint);
|
||||
|
||||
u32 *host_neighbours = (u32 *) &dst[dstpos];
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < num_waypoints; i++) {
|
||||
host_waypoints[i].padnum = PD_BE32(n64_waypoints[i].padnum);
|
||||
host_waypoints[i].neighbours = (void *)(uintptr_t)dstpos;
|
||||
host_waypoints[i].groupnum = PD_BE32(n64_waypoints[i].groupnum);
|
||||
host_waypoints[i].step = 0;
|
||||
|
||||
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waypoints[i].ptr_neighbours)];
|
||||
|
||||
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
|
||||
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_neighbours[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
// Terminator
|
||||
host_waypoints[num_waypoints].padnum = 0xffffffff;
|
||||
host_waypoints[num_waypoints].neighbours = NULL;
|
||||
host_waypoints[num_waypoints].groupnum = 0;
|
||||
host_waypoints[num_waypoints].step = 0;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertWayGroups(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_waygroup *n64_waygroups = (struct n64_waygroup *) &src[srcpos];
|
||||
struct waygroup *host_waygroups = (struct waygroup *) &dst[dstpos];
|
||||
int num_waygroups;
|
||||
|
||||
for (num_waygroups = 0; n64_waygroups[num_waygroups].ptr_neighbours != 0; num_waygroups++);
|
||||
|
||||
dstpos += (num_waygroups + 1) * sizeof(struct waygroup);
|
||||
|
||||
// Waygroups and child waypoints
|
||||
u32 *host_waypoints = (u32 *) &dst[dstpos];
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < num_waygroups; i++) {
|
||||
host_waygroups[i].waypoints = (void *)(uintptr_t)dstpos;
|
||||
host_waygroups[i].step = 0;
|
||||
|
||||
u32 *n64_waypoints = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_waypoints)];
|
||||
|
||||
for (int j = 0; n64_waypoints[j] != 0xffffffff; j++) {
|
||||
host_waypoints[n++] = PD_BE32(n64_waypoints[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_waypoints[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
// Terminator
|
||||
host_waygroups[num_waygroups].neighbours = NULL;
|
||||
host_waygroups[num_waygroups].waypoints = NULL;
|
||||
host_waygroups[num_waygroups].step = 0;
|
||||
|
||||
// Waygroup neighbours
|
||||
u32 *host_neighbours = (u32 *) &dst[dstpos];
|
||||
n = 0;
|
||||
|
||||
for (int i = 0; i < num_waygroups; i++) {
|
||||
host_waygroups[i].neighbours = (void *)(uintptr_t)dstpos;
|
||||
|
||||
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_neighbours)];
|
||||
|
||||
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
|
||||
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_neighbours[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertCover(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_covers)
|
||||
{
|
||||
struct coverdefinition *n64_covers = (struct coverdefinition *) &src[srcpos];
|
||||
struct coverdefinition *host_covers = (struct coverdefinition *) &dst[dstpos];
|
||||
|
||||
for (int i = 0; i < num_covers; i++) {
|
||||
host_covers[i].pos = PD_SWAPPED_VAL(n64_covers[i].pos);
|
||||
host_covers[i].look = PD_SWAPPED_VAL(n64_covers[i].look);
|
||||
host_covers[i].flags = PD_BE16(n64_covers[i].flags);
|
||||
}
|
||||
|
||||
dstpos += num_covers * sizeof(struct coverdefinition);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertPadsFile(u8 *dst, u8 *src)
|
||||
{
|
||||
u32 dstpos = 0;
|
||||
struct n64_header *n64_header = (struct n64_header *) src;
|
||||
struct host_header *host_header = (struct host_header *) dst;
|
||||
|
||||
int num_pads = PD_BE32(n64_header->num_pads);
|
||||
int num_covers = PD_BE32(n64_header->num_covers);
|
||||
host_header->num_pads = (num_pads);
|
||||
host_header->num_covers = (num_covers);
|
||||
|
||||
dstpos += sizeof(struct host_header);
|
||||
|
||||
// Pads
|
||||
dstpos = convertPads(dst, dstpos, src, sizeof(struct n64_header), num_pads);
|
||||
|
||||
// Waypoints
|
||||
host_header->ptr_waypoints = (dstpos);
|
||||
dstpos = convertWayPoints(dst, dstpos, src, PD_BE32(n64_header->ptr_waypoints));
|
||||
|
||||
// Waygroups
|
||||
host_header->ptr_waygroups = (dstpos);
|
||||
dstpos = convertWayGroups(dst, dstpos, src, PD_BE32(n64_header->ptr_waygroups));
|
||||
|
||||
// Cover
|
||||
host_header->ptr_cover = (dstpos);
|
||||
dstpos = convertCover(dst, dstpos, src, PD_BE32(n64_header->ptr_cover), num_covers);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
u8* preprocessPadsFile(u8 *data, u32 size, u32 *outSize) {
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_PADS);
|
||||
u8* dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertPadsFile(dst, data);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a pads file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct tile {
|
||||
u8 type;
|
||||
u8 numvertices;
|
||||
u16 flags;
|
||||
u16 floortype;
|
||||
u8 xmin;
|
||||
u8 ymin;
|
||||
u8 zmin;
|
||||
u8 xmax;
|
||||
u8 ymax;
|
||||
u8 zmax;
|
||||
u16 floorcol;
|
||||
};
|
||||
|
||||
static u32 convertTiles(u8 *dst, u8 *src, size_t srclen)
|
||||
{
|
||||
int num_rooms = PD_BE32(*(u32 *) src);
|
||||
|
||||
size_t src_ptr_table_len = (num_rooms + 1) * 4;
|
||||
size_t dst_ptr_table_len = (num_rooms + 1) * sizeof(u32);
|
||||
|
||||
u32 *src_offsets = (u32 *) &src[4];
|
||||
|
||||
size_t data_len = srclen - src_ptr_table_len - 4;
|
||||
|
||||
*(u32 *) dst = (num_rooms);
|
||||
|
||||
u32 *dst_offsets = (u32 *) (dst + sizeof(u32));
|
||||
u32 cur_dst_offset = dst_ptr_table_len + sizeof(u32);
|
||||
|
||||
u32 cur_src_offset = PD_BE32(src_offsets[0]);
|
||||
u32 end_src_offset = PD_BE32(src_offsets[num_rooms]);
|
||||
int room = 0;
|
||||
|
||||
while (1) {
|
||||
// Check if this is a new room and write the pointer offset if so
|
||||
while (room < (num_rooms + 1) && PD_BE32(src_offsets[room]) == cur_src_offset) {
|
||||
dst_offsets[room] = (cur_dst_offset);
|
||||
room++;
|
||||
}
|
||||
|
||||
if (cur_src_offset >= end_src_offset) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write tile data
|
||||
struct tile *n64tile = (struct tile *) &src[cur_src_offset];
|
||||
struct tile hosttile;
|
||||
|
||||
hosttile.type = n64tile->type;
|
||||
hosttile.numvertices = n64tile->numvertices;
|
||||
hosttile.flags = PD_BE16(n64tile->flags);
|
||||
hosttile.floortype = PD_BE16(n64tile->floortype);
|
||||
hosttile.xmin = n64tile->xmin;
|
||||
hosttile.ymin = n64tile->ymin;
|
||||
hosttile.zmin = n64tile->zmin;
|
||||
hosttile.xmax = n64tile->xmax;
|
||||
hosttile.ymax = n64tile->ymax;
|
||||
hosttile.zmax = n64tile->zmax;
|
||||
hosttile.floorcol = PD_BE16(n64tile->floorcol);
|
||||
|
||||
memcpy(&dst[cur_dst_offset], &hosttile, sizeof(struct tile));
|
||||
|
||||
cur_dst_offset += sizeof(struct tile);
|
||||
cur_src_offset += sizeof(struct tile);
|
||||
|
||||
// Write tile vertices
|
||||
for (int i = 0; i < hosttile.numvertices; i++) {
|
||||
*(s16 *) &dst[cur_dst_offset + 0] = PD_BE16(*(s16 *) &src[cur_src_offset + 0]);
|
||||
*(s16 *) &dst[cur_dst_offset + 2] = PD_BE16(*(s16 *) &src[cur_src_offset + 2]);
|
||||
*(s16 *) &dst[cur_dst_offset + 4] = PD_BE16(*(s16 *) &src[cur_src_offset + 4]);
|
||||
cur_dst_offset += 6;
|
||||
cur_src_offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
return ALIGN16(cur_dst_offset);
|
||||
}
|
||||
|
||||
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize)
|
||||
{
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_TILES);
|
||||
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertTiles(dst, data, size);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a tiles file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loaded 100 of 375 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user