mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-24 00:02:43 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be0293f555 | ||
|
|
54d35b47a0 | ||
|
|
04a518840f | ||
|
|
68df5343ba | ||
|
|
aead1bc4c4 | ||
|
|
b86cc88991 | ||
|
|
d946e332ae | ||
|
|
57041735cb | ||
|
|
f3ce20fb6e | ||
|
|
75d1886da1 | ||
|
|
a582068c21 | ||
|
|
4c1e9ece94 | ||
|
|
4b8e1d52b5 | ||
|
|
a9ccc61f96 | ||
|
|
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 | ||
|
|
110876b036 | ||
|
|
2ff8819265 | ||
|
|
ae7b21cf56 | ||
|
|
77d1ded519 | ||
|
|
60b8e3b49e | ||
|
|
8b0b75d4ad | ||
|
|
ea464ca6ac | ||
|
|
a9752198c3 | ||
|
|
fbd9ef002e | ||
|
|
e4972ddbe3 | ||
|
|
8dbe6f2a63 | ||
|
|
045c4c371a | ||
|
|
f4f1470e1e | ||
|
|
26251c0865 | ||
|
|
ac4f317879 | ||
|
|
e8a57d7f6f | ||
|
|
e3104b7043 | ||
|
|
176b4282fc | ||
|
|
cd8f06d03a | ||
|
|
9cff3591dd | ||
|
|
daade36e19 | ||
|
|
addc890628 | ||
|
|
2362444efd | ||
|
|
8a3dd74d5c | ||
|
|
c0aa42759c | ||
|
|
b637c6aac6 | ||
|
|
5cd436e848 | ||
|
|
d5225b7784 | ||
|
|
904faa5485 | ||
|
|
f1084b6d93 | ||
|
|
9a462d3ca8 | ||
|
|
f5251fa1b9 | ||
|
|
4f7817a0ca | ||
|
|
da4e5e4832 | ||
|
|
5ebce756ed | ||
|
|
5084b4be39 | ||
|
|
a05c4290f5 | ||
|
|
839ef7cc44 | ||
|
|
c597915466 | ||
|
|
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 | ||
|
|
5db911a58b | ||
|
|
67675d8980 | ||
|
|
9c4aded403 | ||
|
|
92e1c4aa0b | ||
|
|
f53fb8e952 | ||
|
|
0ad4492ff6 | ||
|
|
33efd36278 | ||
|
|
37e69cb83d | ||
|
|
5c5c33c116 | ||
|
|
13a3e0a0ea | ||
|
|
ccb50c6021 | ||
|
|
5425c21c83 | ||
|
|
563e8f9f64 | ||
|
|
df3e0359b9 | ||
|
|
460cc25ef5 | ||
|
|
596dd7dd40 | ||
|
|
b2338179d6 | ||
|
|
683d083fab | ||
|
|
f75a569075 | ||
|
|
b97eaa9e12 | ||
|
|
3cadaecf96 | ||
|
|
4bc1a16d36 | ||
|
|
bc1f1c26db | ||
|
|
d2d35263a4 | ||
|
|
ba1b6c3232 | ||
|
|
3c020cad84 | ||
|
|
abe04c0dda | ||
|
|
140f6f24e8 | ||
|
|
c7895d937f | ||
|
|
9f43c906db | ||
|
|
31dbb5e7c6 | ||
|
|
7d8e755fc7 | ||
|
|
103fb0e0e9 | ||
|
|
b220d73f2c | ||
|
|
efda5a5f44 | ||
|
|
41d5630eec | ||
|
|
cea20b6f31 | ||
|
|
7721297dc8 | ||
|
|
06dcbcc1b1 | ||
|
|
d7a612302e | ||
|
|
44c5a4c213 | ||
|
|
7677b40b06 | ||
|
|
d747588323 | ||
|
|
f948fc06f2 | ||
|
|
363158a93d | ||
|
|
7658a96c1c | ||
|
|
c332738f7a | ||
|
|
2542b21bfc | ||
|
|
ef8413ae58 | ||
|
|
7969d84257 | ||
|
|
26c24d62aa | ||
|
|
3d8f63dbb6 | ||
|
|
08ec8e541b | ||
|
|
9a484c1aea | ||
|
|
08afb2d90a | ||
|
|
3f45d41de6 | ||
|
|
d7e5ad5bc7 | ||
|
|
7830ccb88c | ||
|
|
8075307e09 | ||
|
|
fb18da239f | ||
|
|
bc82328353 | ||
|
|
938223db28 | ||
|
|
942c966bf2 | ||
|
|
e0d59345c7 | ||
|
|
6ddebf8aa6 | ||
|
|
f514e25208 | ||
|
|
28fceb67de | ||
|
|
130b286d0d | ||
|
|
b88c3a120b | ||
|
|
6d20ed25fb | ||
|
|
a6f5077609 | ||
|
|
e2b708d442 | ||
|
|
2cb29e91c6 | ||
|
|
55cc2d8e72 | ||
|
|
112f6da972 | ||
|
|
852349bbe0 | ||
|
|
b408d54dfb | ||
|
|
80cd44d8e2 | ||
|
|
5d9fe034ea | ||
|
|
3ff2f9e0ec | ||
|
|
1d7c381ce2 | ||
|
|
8b8eedcdfc | ||
|
|
1398f5d0f5 | ||
|
|
6c8e5ee4dc | ||
|
|
d37d9b7168 | ||
|
|
fab41b6fcb | ||
|
|
ee7ce2d988 | ||
|
|
1a1accceca | ||
|
|
0bdf79cc51 | ||
|
|
4d96fab71f | ||
|
|
91c43385dd | ||
|
|
58e64ebfc9 | ||
|
|
36f9e59304 | ||
|
|
420a1b52c1 | ||
|
|
345da23ebe | ||
|
|
3f887b2ecf | ||
|
|
d5482f3453 | ||
|
|
fdbd1667ad | ||
|
|
421ac0af79 | ||
|
|
163dbf9495 | ||
|
|
2f221b9a1e | ||
|
|
1448cd597a | ||
|
|
68e3a79e47 | ||
|
|
19ef4738b7 | ||
|
|
16f025cbbe | ||
|
|
25cdfc991b | ||
|
|
5c2082f58e | ||
|
|
23539a02a5 | ||
|
|
f37abc941e | ||
|
|
8468e69b9f | ||
|
|
8fe95d7d52 | ||
|
|
19167b8468 | ||
|
|
d5ee41fe5d | ||
|
|
796241d443 | ||
|
|
2a5c3a351e | ||
|
|
2550b5a668 | ||
|
|
24d5679f4a | ||
|
|
a3d2b56dd9 | ||
|
|
3455708e38 | ||
|
|
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 | ||
|
|
ae0ba57c24 | ||
|
|
bdbf0ab789 | ||
|
|
ca76416e1c | ||
|
|
b534a42685 | ||
|
|
6b71e622c7 | ||
|
|
48c294fc24 | ||
|
|
f0fe7f41f1 | ||
|
|
2844930a21 | ||
|
|
d36c55d048 | ||
|
|
f855dc32f1 | ||
|
|
08e2b49e88 | ||
|
|
9cd978a7a9 | ||
|
|
a60880ef80 | ||
|
|
a4b5b110ec | ||
|
|
f7435e0ead | ||
|
|
897020b3fd | ||
|
|
e85fdb3b9b | ||
|
|
e3e72617a1 | ||
|
|
bc365650ce | ||
|
|
6fa78556f4 | ||
|
|
5fdeff6a82 | ||
|
|
3573906eef | ||
|
|
e36df05a4f | ||
|
|
673ba52cbd | ||
|
|
0ea8872471 | ||
|
|
40273bdba1 | ||
|
|
e8006f3446 | ||
|
|
373f08ca3e | ||
|
|
844d6c7ec8 | ||
|
|
fceacee0e2 | ||
|
|
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 | ||
|
|
a5a2970b67 | ||
|
|
de3b8ff548 | ||
|
|
0d6a5f2d0f | ||
|
|
dce96a4a3d | ||
|
|
c5ab7d20df | ||
|
|
08b4d780b7 | ||
|
|
bc5911bfba | ||
|
|
d53dd8c48f | ||
|
|
ada20c526a | ||
|
|
4c552a42f2 | ||
|
|
edced1d0e2 | ||
|
|
e8e513fecb | ||
|
|
7cc389bc69 | ||
|
|
4601a9c318 | ||
|
|
5e03342562 | ||
|
|
5c7d4ecf52 | ||
|
|
30e987eb50 | ||
|
|
9edfd667b7 | ||
|
|
f3757e75e9 | ||
|
|
e5f142b110 | ||
|
|
a6e7d503e6 | ||
|
|
da8b9be09d | ||
|
|
95bf97a2c1 | ||
|
|
9530924c21 | ||
|
|
f52fa8f759 | ||
|
|
2ba192d411 | ||
|
|
ff4321673b | ||
|
|
7590f0bdc3 | ||
|
|
bf8192ee84 | ||
|
|
70882d8a32 | ||
|
|
45ec35172d | ||
|
|
045d5d2e46 | ||
|
|
926e4dce28 | ||
|
|
7fabc68e95 | ||
|
|
548e2c1f0b | ||
|
|
85872d7e71 | ||
|
|
948a3e0c51 | ||
|
|
a83e0aa407 | ||
|
|
7ffc1d393b | ||
|
|
aba98349ae | ||
|
|
865ca682dc | ||
|
|
dc9d0f3c9c | ||
|
|
12d06001e7 | ||
|
|
9625cd7d28 | ||
|
|
32c5d2c742 | ||
|
|
3199f99fbd | ||
|
|
0e2de3b746 | ||
|
|
51d842f516 | ||
|
|
4e7e61c207 | ||
|
|
32417c164c | ||
|
|
70b02da163 | ||
|
|
1a3f36f626 | ||
|
|
1db33f278b | ||
|
|
d8a26fa221 | ||
|
|
28d6c5b827 | ||
|
|
abc6612641 | ||
|
|
fef8985b6b | ||
|
|
fd8718f7b1 | ||
|
|
57b1e37397 | ||
|
|
197208b951 | ||
|
|
3f3c091289 | ||
|
|
4bd314f60b | ||
|
|
41ddcc7822 | ||
|
|
95b43b3f7b | ||
|
|
6708bf2aa6 | ||
|
|
62a55a3d6e | ||
|
|
12cf9df01b | ||
|
|
c16aa70a66 | ||
|
|
c5c1ef1d4e | ||
|
|
f3c1242858 | ||
|
|
60c30e9b67 | ||
|
|
ef3d53b9f7 | ||
|
|
bc01ff558f | ||
|
|
1d040b1ccc | ||
|
|
9755f3ab41 | ||
|
|
f86746364f | ||
|
|
536c766793 | ||
|
|
dca1e1752b | ||
|
|
8c844874e7 | ||
|
|
ce6424117e | ||
|
|
15c0327592 | ||
|
|
2e18ffdad9 | ||
|
|
b2ea9aa5f2 | ||
|
|
13003121ea | ||
|
|
ba56947457 | ||
|
|
b9a51e4a62 | ||
|
|
27faaecda2 | ||
|
|
798fbf7b90 | ||
|
|
a0f8550034 | ||
|
|
73dc52cfd6 | ||
|
|
5b1d03cbbb | ||
|
|
68aee1d2f2 | ||
|
|
7580ebcaf9 | ||
|
|
c9a14f090b | ||
|
|
2483d4fc35 | ||
|
|
501ab95b00 | ||
|
|
0b61ec9641 | ||
|
|
b4f7f467c0 | ||
|
|
894ccfabf3 | ||
|
|
ec8310e4a1 | ||
|
|
80faefbaf6 | ||
|
|
b72d7f54e1 | ||
|
|
c9f880e427 | ||
|
|
d8b21f78e0 | ||
|
|
92a9ac43fc | ||
|
|
0d0de5b0d4 | ||
|
|
4baae8de0b | ||
|
|
d11b5705a2 | ||
|
|
7667d37ff0 | ||
|
|
cf7c4d4239 | ||
|
|
839143550f | ||
|
|
adcf56ed34 | ||
|
|
5e65e84210 | ||
|
|
fe0d9b3cfd | ||
|
|
935cd1faa9 | ||
|
|
63a9a26908 | ||
|
|
f4530633d6 | ||
|
|
94e244a236 | ||
|
|
92d3a9f564 | ||
|
|
44a67e60e8 | ||
|
|
634eecb35d | ||
|
|
a0db91a0c9 | ||
|
|
6b105d0be0 | ||
|
|
11febd7ace | ||
|
|
dface4696c | ||
|
|
0669ce5668 | ||
|
|
6d3ea5b0fd | ||
|
|
36f8494ebf | ||
|
|
fcb1dbb298 | ||
|
|
409e955883 | ||
|
|
f006f9ba7b | ||
|
|
815c75c6a8 | ||
|
|
6a03e8d9cf | ||
|
|
a1af5b655a | ||
|
|
33cc89e8fd | ||
|
|
cc6df47eed | ||
|
|
02d7efb87f | ||
|
|
1f4d9c8cdc | ||
|
|
edeafa596d | ||
|
|
63c456a233 | ||
|
|
b954e3ce80 | ||
|
|
bfa4035642 | ||
|
|
35be4d589e | ||
|
|
474a6df3d4 | ||
|
|
884a30f970 | ||
|
|
7288947390 | ||
|
|
c444e76ecb | ||
|
|
c4b1a8d4a2 | ||
|
|
7c8b1176c7 | ||
|
|
9cde121b52 | ||
|
|
c5a088e7b8 | ||
|
|
e53f26f3eb | ||
|
|
81313f0c4e | ||
|
|
cf5588478b | ||
|
|
d9cb850848 | ||
|
|
8e443d4830 | ||
|
|
2cb52b749c | ||
|
|
de14f90daf | ||
|
|
9afc7e113e | ||
|
|
fbfe4b4564 | ||
|
|
4cb99506cb | ||
|
|
562e763fbd | ||
|
|
952de6e82b | ||
|
|
7ec54e6d0b | ||
|
|
e6df6014c7 | ||
|
|
e688a1c6e6 | ||
|
|
e44298d0c2 | ||
|
|
31cd8fc28a | ||
|
|
a46ce32ad4 | ||
|
|
31d8aae704 | ||
|
|
4b30f52b32 | ||
|
|
c8d42bbf20 | ||
|
|
511d6ca299 | ||
|
|
b9db86f89b | ||
|
|
33f6d643be | ||
|
|
c2d09135f7 | ||
|
|
9f6b21e870 | ||
|
|
4eca4a1f07 | ||
|
|
4439fdf411 | ||
|
|
6bd3597ff6 | ||
|
|
6ac8a1a0f6 | ||
|
|
8645d0a82a | ||
|
|
ba52580e0c | ||
|
|
d1d288b96a | ||
|
|
06f2283180 | ||
|
|
b1b17e21c1 | ||
|
|
f4ec781b8e | ||
|
|
5e256ea406 | ||
|
|
5abb0e484e | ||
|
|
16c247a24e | ||
|
|
0737c688d7 | ||
|
|
9de245eab6 | ||
|
|
c487e423b1 | ||
|
|
a3cc54d33a | ||
|
|
a261246e64 | ||
|
|
2e195fe21a | ||
|
|
36a692991f | ||
|
|
ca0e3c3060 | ||
|
|
39474e97a7 | ||
|
|
b74cd095a1 | ||
|
|
96e1c57f61 | ||
|
|
f6ee8bbf71 | ||
|
|
188faeecf6 | ||
|
|
2c0a0a1337 | ||
|
|
7f92551d5a | ||
|
|
f54dbb596e | ||
|
|
49f607dd79 | ||
|
|
aa3c5a85b7 | ||
|
|
f46e112c3d | ||
|
|
bcb5b3f5c1 | ||
|
|
65589e2fd2 | ||
|
|
787758c038 | ||
|
|
54fbd8ba54 | ||
|
|
49129dd3e7 | ||
|
|
7bfa2b9425 | ||
|
|
53fbbb8a10 | ||
|
|
7bee9cdcfc | ||
|
|
928544ae5f | ||
|
|
312c752205 | ||
|
|
a5d1c25fea | ||
|
|
7abebe7405 | ||
|
|
ebc126f837 | ||
|
|
67bc9c4858 | ||
|
|
c4a3c18208 | ||
|
|
cf1b87a833 | ||
|
|
fb123603ca | ||
|
|
b3ab58da3b | ||
|
|
6374fc834c | ||
|
|
6df31649f5 | ||
|
|
9de6b580ba | ||
|
|
8eb6880694 | ||
|
|
fe4d86fae1 | ||
|
|
3c62a967a2 | ||
|
|
8492670bad | ||
|
|
04f95ed1d1 | ||
|
|
ee037c10ce | ||
|
|
cbf65e53b9 | ||
|
|
8c2b15d649 | ||
|
|
2134571b9a | ||
|
|
a541c79eda | ||
|
|
454086be6b | ||
|
|
6bd5997059 | ||
|
|
99911b2290 | ||
|
|
95d8b0692f | ||
|
|
e85cc3b309 | ||
|
|
2a01d562c3 | ||
|
|
51daf45c19 | ||
|
|
c9bd2bfd54 | ||
|
|
6225f62412 | ||
|
|
d2ffd73dea | ||
|
|
02329b64a1 | ||
|
|
aae0f70dd3 | ||
|
|
41d9cb4578 | ||
|
|
2ef2427419 | ||
|
|
5fcf1083d2 | ||
|
|
f2a2458795 | ||
|
|
a7ab358b43 | ||
|
|
a82ac025da | ||
|
|
461bf8d49b | ||
|
|
370047b1b0 | ||
|
|
db1d00a9b0 | ||
|
|
6fc99e4c23 | ||
|
|
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 | ||
|
|
d1be171939 | ||
|
|
6f206345a1 | ||
|
|
13b23de6d3 | ||
|
|
d897356029 | ||
|
|
f96e7da00f | ||
|
|
1fb16b3bfd | ||
|
|
2c20a0487e | ||
|
|
aef2463361 | ||
|
|
2b8d5d4f75 | ||
|
|
ef83f23200 | ||
|
|
75133acbbd | ||
|
|
1aea68b89a | ||
|
|
af34015562 | ||
|
|
7cd3dafaa4 | ||
|
|
e0249067b9 | ||
|
|
31ad9351f5 | ||
|
|
116dc7e8b6 | ||
|
|
aced07f356 | ||
|
|
8d99ac92a0 | ||
|
|
4a3c3a29b7 | ||
|
|
523e6ba9d9 | ||
|
|
c6a36633f5 | ||
|
|
626b5937ce | ||
|
|
228851f867 | ||
|
|
1c72b3022e | ||
|
|
5d7b7adb57 | ||
|
|
2d3e3d1aaf | ||
|
|
94e8e1b5e7 | ||
|
|
d3a2ed216a | ||
|
|
600dae58e2 | ||
|
|
3a1d08509b | ||
|
|
45a44cd37e | ||
|
|
5a68daf18c | ||
|
|
e43d29f357 | ||
|
|
3328e147eb | ||
|
|
7e929c2432 | ||
|
|
b88690e8df | ||
|
|
305e64a263 | ||
|
|
b618c99abd | ||
|
|
58d815f1ec | ||
|
|
99da0586ea | ||
|
|
27e36ca24e | ||
|
|
9dfd0ec905 | ||
|
|
6f55843f30 | ||
|
|
4a16f27abd | ||
|
|
11e318b70f | ||
|
|
5bb4f1d193 | ||
|
|
f394f209b2 | ||
|
|
9c7f348652 | ||
|
|
32b2e9c28e | ||
|
|
72e9e2af95 | ||
|
|
8a348ab1b5 | ||
|
|
28b172f5c7 | ||
|
|
ef511d5889 | ||
|
|
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 | ||
|
|
0b9f99a084 | ||
|
|
4c1076080d | ||
|
|
8347900d33 | ||
|
|
f638d49693 | ||
|
|
d1817aaea6 | ||
|
|
e2b1cdce86 | ||
|
|
81a5e971ef | ||
|
|
6f0cb752aa | ||
|
|
abf5703036 | ||
|
|
b8e6e19ef5 | ||
|
|
ba51e9d5d1 | ||
|
|
8bf14c4044 | ||
|
|
b650c820e0 | ||
|
|
80d787caf9 | ||
|
|
1eb1e9686a | ||
|
|
dbebe7e626 | ||
|
|
79f8a35c33 | ||
|
|
b78a5ee064 | ||
|
|
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-net" ]
|
||||
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
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
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")
|
||||
|
||||
# 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 ws2_32 winmm 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,227 @@
|
||||
# Perfect Dark Decompilation
|
||||
# Perfect Dark port (`port-net`)
|
||||
|
||||
This repository contains a complete decompilation of Perfect Dark for the Nintendo 64.
|
||||
## Experimental netplay branch
|
||||
|
||||
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.
|
||||
This branch of the port contains an **extremely** early and experimental implementation of network play.
|
||||
**DISCLAIMER:** This is **NOT READY** for prime time. Use at your own risk if you are not a developer.
|
||||
**Do not create issues about problems in this branch until this disclaimer is gone.**
|
||||
|
||||
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.
|
||||
See [this file](https://github.com/perfect-dark-pc-port/perfect_dark/blob/port-net/docs/netplay.md) for more information on how this works.
|
||||
|
||||
## Original description
|
||||
|
||||
This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms.
|
||||
|
||||
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/perfect-dark-pc-port/perfect_dark/actions) of the netplay branch for supported platforms:
|
||||
* [x86_64-windows (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-x86_64-windows.zip)
|
||||
* [i686-windows (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip)
|
||||
* [x86_64-linux (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-x86_64-linux.zip)
|
||||
* [i686-linux (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip)
|
||||
|
||||
For Debian and Ubuntu:
|
||||
If you are looking for regular builds (the `port` branch), see [this link](https://github.com/perfect-dark-pc-port/perfect_dark/blob/port/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.
|
||||
Note that users with different ROMs can't play netgames with each other.
|
||||
|
||||
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.
|
||||
Additional information can be found in the [wiki](https://github.com/perfect-dark-pc-port/perfect_dark/wiki).
|
||||
|
||||
## Compiling
|
||||
A GPU supporting OpenGL 3.0/ES3.0 or above is required to run the port.
|
||||
|
||||
* 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`.
|
||||
### Installing the Nintendo Switch version
|
||||
|
||||
## How do I know the built files are matching?
|
||||
The Nintendo Switch build ZIP comes with all 3 regions in different folders: `perfectdark`, `perfectdark_pal` and `perfectdark_jpn`.
|
||||
|
||||
Run `make` followed by `make test`. If `make test` produces no output then the compiled project is 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.
|
||||
|
||||
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`.
|
||||
`port-net` currently does not work on the Switch.
|
||||
|
||||
## Controls
|
||||
|
||||
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 -b port-net --recursive https://github.com/perfect-dark-pc-port/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 -b port-net --recursive https://github.com/perfect-dark-pc-port/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/perfect-dark-pc-port/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/perfect-dark-pc-port/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
|
||||
@@ -0,0 +1,47 @@
|
||||
## Experimental netplay branch
|
||||
|
||||
This branch contains a **highly experimental** implementation of network play.
|
||||
|
||||
Currently only Combat Sim is partially working with experimental 8 player support and really bad netcode.
|
||||
Expect nothing to work right.
|
||||
|
||||
### Hosting
|
||||
|
||||
1. Forward the server port (`27100` by default, can be changed in `pd.ini`).
|
||||
* You can also use something like ZeroTier or Hamachi if you can't port forward.
|
||||
3. Choose `Network Game` -> `Host Game`, configure the player cap, press `Start Game`.
|
||||
4. Configure Combat Sim as desired, but do not start it yet. Keep in mind:
|
||||
* You can save and load the settings as normal.
|
||||
* Your player will have the config of Combat Sim player 1.
|
||||
5. Wait for everyone to join. You can use the console (press `~`) to chat in the meantime.
|
||||
6. Hit Enter/Start. During the game no more players will be able to join.
|
||||
7. After game is over, you will be kicked back to Combat Sim settings, at which point people can join again and the process repeats from step 3.
|
||||
|
||||
### Joining
|
||||
|
||||
1. Your player will have the config of Combat Sim player 1, so set that up beforehand in the Combat Sim menu.
|
||||
2. Choose `Network Game` -> `Join Game`, enter the address (and port if it's not 27100), press `Start Game`.
|
||||
3. If the message says `Waiting for host`, wait until the host configures the game. You can use the console (press `~`) to chat in the meantime or `ESC` to disconnect.
|
||||
4. The game will start automatically.
|
||||
5. After the game is over, press Enter/Start on the stats screen and you will be kicked back to the `Waiting for host` screen, at which point the process repeats from step 3.
|
||||
|
||||
### Misc
|
||||
|
||||
* Everyone has to have the same ROM. The game only compares the file name, but different regions in one game will definitely break everything.
|
||||
* Press `~` to bring up the console, press `F9` for network stats.
|
||||
* You can chat at any time during a net game by entering messages in the console and hitting Enter.
|
||||
* Server port and other network settings can be configured in `pd.ini`.
|
||||
* For a 4+ player game I would recommend changing `Net.Server.UpdateFrames` to `2` in `pd.ini` on the server to lower the bandwidth usage.
|
||||
* You can paste stuff into the `Enter Address` prompt by hitting `CTRL+V`.
|
||||
* Expect nothing to work right.
|
||||
|
||||
### Known issues
|
||||
|
||||
* Clients see rocket rotation incorrectly.
|
||||
* Clients can't use Slayer fly-by-wire rockets and they will not correctly sync if the server uses them.
|
||||
* Clients can't use the alt fire mode on the FarSight and probably a couple other guns.
|
||||
* Cloaking device is not synced.
|
||||
* Most likely only Combat works properly.
|
||||
* Sims don't work in netgames.
|
||||
* Bandwidth consumption on the server is pretty large on the default settings, especially with 8 players.
|
||||
|
||||
@@ -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) */
|
||||
|
||||
|
||||
+15
-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,17 @@ 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, ...);
|
||||
#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 */
|
||||
|
||||
|
||||
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
#ifndef _WIN32
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ENET_IMPLEMENTATION 1
|
||||
#define ENET_NO_PRAGMA_LINK 1
|
||||
|
||||
#include "external/enet.h"
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define MINIMP3_IMPLEMENTATION
|
||||
#include "external/minimp3.h"
|
||||
@@ -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,15 @@
|
||||
#ifndef _IN_CONSOLE_H
|
||||
#define _IN_CONSOLE_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "types.h"
|
||||
|
||||
void conInit(void);
|
||||
Gfx *conRender(Gfx *gdl);
|
||||
void conTick(void);
|
||||
void conPrint(s32 showmsg, const char *s);
|
||||
void conPrintf(s32 showmsg, const char *fmt, ...);
|
||||
void conPrintLn(s32 showmsg, const char *s);
|
||||
s32 conIsOpen(void);
|
||||
|
||||
#endif
|
||||
Vendored
+5100
File diff suppressed because it is too large.
Load diff
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,163 @@
|
||||
#ifndef _IN_NET_H
|
||||
#define _IN_NET_H
|
||||
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
#include "net/netbuf.h"
|
||||
|
||||
#define NET_PROTOCOL_VER 12
|
||||
|
||||
#define NET_QUERY_MAGIC "PDQM\x01"
|
||||
|
||||
#define NET_MAX_CLIENTS MAX_PLAYERS
|
||||
#define NET_MAX_NAME MAX_PLAYERNAME
|
||||
#define NET_MAX_ADDR 256
|
||||
|
||||
#define NET_BUFSIZE 1440
|
||||
|
||||
#define NET_DEFAULT_PORT 27100
|
||||
|
||||
#define NET_NULL_CLIENT 0xFF
|
||||
#define NET_NULL_PROP 0
|
||||
|
||||
#define NETCHAN_DEFAULT 0
|
||||
#define NETCHAN_CONTROL 1
|
||||
#define NETCHAN_COUNT 2
|
||||
|
||||
#define DISCONNECT_UNKNOWN 0
|
||||
#define DISCONNECT_SHUTDOWN 1
|
||||
#define DISCONNECT_VERSION 2
|
||||
#define DISCONNECT_KICKED 3
|
||||
#define DISCONNECT_BANNED 4
|
||||
#define DISCONNECT_TIMEOUT 5
|
||||
#define DISCONNECT_FULL 6
|
||||
#define DISCONNECT_LATE 7
|
||||
#define DISCONNECT_FILES 8
|
||||
|
||||
#define CLSTATE_DISCONNECTED 0
|
||||
#define CLSTATE_CONNECTING 1
|
||||
#define CLSTATE_AUTH 2
|
||||
#define CLSTATE_LOBBY 3
|
||||
#define CLSTATE_GAME 4
|
||||
|
||||
#define UCMD_FIRE (1 << 0)
|
||||
#define UCMD_ACTIVATE (1 << 1)
|
||||
#define UCMD_RELOAD (1 << 2)
|
||||
#define UCMD_AIMMODE (1 << 3)
|
||||
#define UCMD_DUCK (1 << 4)
|
||||
#define UCMD_SQUAT (1 << 5)
|
||||
#define UCMD_ZOOMIN (1 << 6)
|
||||
#define UCMD_SELECT (1 << 7)
|
||||
#define UCMD_SELECT_DUAL (1 << 8)
|
||||
#define UCMD_EYESSHUT (1 << 9)
|
||||
#define UCMD_SECONDARY (1 << 10)
|
||||
#define UCMD_RESPAWN (1 << 27)
|
||||
#define UCMD_CHAT (1 << 28)
|
||||
#define UCMD_IMPORTANT_MASK (UCMD_FIRE | UCMD_ACTIVATE | UCMD_RELOAD | UCMD_AIMMODE | UCMD_SELECT | UCMD_SELECT_DUAL)
|
||||
#define UCMD_FL_FORCEPOS (1 << 29)
|
||||
#define UCMD_FL_FORCEANGLE (1 << 30)
|
||||
#define UCMD_FL_FORCEGROUND (1 << 31)
|
||||
#define UCMD_FL_FORCEMASK (UCMD_FL_FORCEPOS | UCMD_FL_FORCEANGLE | UCMD_FL_FORCEGROUND)
|
||||
|
||||
struct netplayermove {
|
||||
u32 tick; // g_NetTIck value when this struct was written; if 0, this struct is invalid
|
||||
u32 ucmd; // player commands (UCMD_)
|
||||
f32 leanofs; // analog lean value (-1 .. 1; equal to player->swaytarget / 75.f)
|
||||
f32 crouchofs; // analog crouch value (-90 for SQUAT, 0 for STAND; player->crouchofs)
|
||||
f32 zoomfov; // manual zoom fov for the current gun; synced only if UCMD_AIMING is set
|
||||
f32 movespeed[2]; // move inputs, [0] is forward, [1] is sideways; used mostly for animation
|
||||
f32 angles[2]; // view angles, [0] is theta, [1] is verta
|
||||
f32 crosspos[2]; // crosshair position in aiming mode; normalized to default aspect ratio
|
||||
s8 weaponnum; // switch to this weapon if UCMD_SELECT is set
|
||||
struct coord pos; // player position at g_NetTick == tick
|
||||
};
|
||||
|
||||
struct netclient {
|
||||
struct _ENetPeer *peer;
|
||||
u32 id; // remote client number, server is always 0, even on clients
|
||||
u32 state; // CLSTATE_
|
||||
u32 flags; // CLFLAG_
|
||||
|
||||
struct {
|
||||
char name[NET_MAX_NAME];
|
||||
u16 options;
|
||||
u8 headnum;
|
||||
u8 bodynum;
|
||||
u8 team;
|
||||
f32 fovy;
|
||||
f32 fovzoommult;
|
||||
} settings;
|
||||
|
||||
struct mpplayerconfig *config;
|
||||
struct player *player;
|
||||
u8 playernum;
|
||||
|
||||
struct netplayermove outmove[2]; // last 2 outgoing player inputs, newest one first
|
||||
struct netplayermove inmove[2]; // last 2 incoming player inputs, newest one first
|
||||
u32 inmovetick; // last inmove tick which was applied to the player
|
||||
u32 outmoveack; // last acked outmove tick
|
||||
u32 forcetick; // tick on which the client's position was forced, or 0 if not forcing
|
||||
u32 lerpticks; // how many ticks we've been lerping the position
|
||||
|
||||
struct netbuf out; // outbound messages are written here, except broadcasts
|
||||
struct netbuf in; // incoming packets are fed here
|
||||
|
||||
u8 out_data[NET_BUFSIZE]; // buffer for out
|
||||
};
|
||||
|
||||
extern s32 g_NetMode;
|
||||
|
||||
extern s32 g_NetJoinLatch;
|
||||
extern s32 g_NetHostLatch;
|
||||
|
||||
// net frame, ticks at 60 fps, starts at 0 when the server is started
|
||||
extern u32 g_NetTick;
|
||||
extern u32 g_NetNextSyncId;
|
||||
|
||||
extern u64 g_NetRngSeeds[2];
|
||||
extern u32 g_NetRngLatch;
|
||||
|
||||
extern u32 g_NetInterpTicks;
|
||||
extern u32 g_NetServerPort;
|
||||
extern char g_NetLastJoinAddr[NET_MAX_ADDR + 1];
|
||||
|
||||
extern s32 g_NetDebugDraw;
|
||||
|
||||
extern s32 g_NetMaxClients;
|
||||
extern s32 g_NetNumClients;
|
||||
extern struct netclient g_NetClients[NET_MAX_CLIENTS + 1]; // last is an extra temporary client
|
||||
extern struct netclient *g_NetLocalClient;
|
||||
|
||||
extern struct netbuf g_NetMsg;
|
||||
extern struct netbuf g_NetMsgRel;
|
||||
|
||||
const char *netFormatClientAddr(const struct netclient *cl);
|
||||
|
||||
void netInit(void);
|
||||
s32 netDisconnect(void);
|
||||
void netStartFrame(void);
|
||||
void netEndFrame(void);
|
||||
|
||||
s32 netStartServer(u16 port, s32 maxclients);
|
||||
s32 netStartClient(const char *addr);
|
||||
|
||||
u32 netSend(struct netclient *dstcl, struct netbuf *buf, const s32 reliable, const s32 chan);
|
||||
|
||||
void netChat(struct netclient *dst, const char *text);
|
||||
void netChatPrintf(struct netclient *dst, const char *fmt, ...);
|
||||
|
||||
void netServerStageStart(void);
|
||||
void netServerStageEnd(void);
|
||||
void netServerKick(struct netclient *cl, const u32 reason);
|
||||
|
||||
struct netclient *netClientForPlayerNum(s32 playernum);
|
||||
|
||||
void netClientSyncRng(void);
|
||||
void netClientSettingsChanged(void);
|
||||
|
||||
void netPlayersAllocate(void);
|
||||
void netSyncIdsAllocate(void);
|
||||
|
||||
Gfx *netDebugRender(Gfx *gdl);
|
||||
|
||||
#endif // _IN_NET_H
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef _IN_NETBUF_H
|
||||
#define _IN_NETBUF_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct netbuf {
|
||||
u8 *data;
|
||||
u32 size;
|
||||
u32 rp;
|
||||
u32 wp;
|
||||
u32 error;
|
||||
};
|
||||
|
||||
void netbufStartRead(struct netbuf *buf);
|
||||
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size);
|
||||
s32 netbufReadLeft(const struct netbuf *buf);
|
||||
u32 netbufReadData(struct netbuf *buf, void *out, u32 num);
|
||||
u8 netbufReadU8(struct netbuf *buf);
|
||||
u16 netbufReadU16(struct netbuf *buf);
|
||||
u32 netbufReadU32(struct netbuf *buf);
|
||||
u64 netbufReadU64(struct netbuf *buf);
|
||||
s8 netbufReadS8(struct netbuf *buf);
|
||||
s16 netbufReadS16(struct netbuf *buf);
|
||||
s32 netbufReadS32(struct netbuf *buf);
|
||||
s64 netbufReadS64(struct netbuf *buf);
|
||||
f32 netbufReadF32(struct netbuf *buf);
|
||||
char *netbufReadStr(struct netbuf *buf);
|
||||
u32 netbufReadCoord(struct netbuf *buf, struct coord *out);
|
||||
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out);
|
||||
u32 netbufReadSkip(struct netbuf *buf, u32 count);
|
||||
|
||||
void netbufStartWrite(struct netbuf *buf);
|
||||
s32 netbufWriteLeft(const struct netbuf *buf);
|
||||
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num);
|
||||
u32 netbufWriteU8(struct netbuf *buf, const u8 v);
|
||||
u32 netbufWriteU16(struct netbuf *buf, const u16 v);
|
||||
u32 netbufWriteU32(struct netbuf *buf, const u32 v);
|
||||
u32 netbufWriteU64(struct netbuf *buf, const u64 v);
|
||||
u32 netbufWriteS8(struct netbuf *buf, const s8 v);
|
||||
u32 netbufWriteS16(struct netbuf *buf, const s16 v);
|
||||
u32 netbufWriteS32(struct netbuf *buf, const s32 v);
|
||||
u32 netbufWriteS64(struct netbuf *buf, const s64 v);
|
||||
u32 netbufWriteF32(struct netbuf *buf, const f32 v);
|
||||
u32 netbufWriteStr(struct netbuf *buf, const char *v);
|
||||
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v);
|
||||
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in);
|
||||
|
||||
void netbufReset(struct netbuf *buf);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef _IN_NETENET_H
|
||||
#define _IN_NETENET_H
|
||||
|
||||
#define ENET_NO_PRAGMA_LINK 1
|
||||
#include "external/enet.h"
|
||||
#undef bool
|
||||
#undef near
|
||||
#undef far
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef _IN_NETMSG_H
|
||||
#define _IN_NETMSG_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "net/net.h"
|
||||
#include "net/netbuf.h"
|
||||
|
||||
#define SVC_BAD 0x00 // trash
|
||||
#define SVC_NOP 0x01 // does nothing
|
||||
#define SVC_AUTH 0x02 // auth response, sent in response to CLC_AUTH
|
||||
#define SVC_CHAT 0x03 // chat message
|
||||
#define SVC_STAGE_START 0x10 // start level
|
||||
#define SVC_STAGE_END 0x11 // end level
|
||||
#define SVC_PLAYER_MOVE 0x20 // player movement and inputs
|
||||
#define SVC_PLAYER_GUNS 0x21 // player gun state
|
||||
#define SVC_PLAYER_STATS 0x22 // player stats (health etc)
|
||||
#define SVC_PROP_MOVE 0x30 // prop movement
|
||||
#define SVC_PROP_SPAWN 0x31 // new prop spawned
|
||||
#define SVC_PROP_DAMAGE 0x32 // prop was damaged
|
||||
#define SVC_PROP_PICKUP 0x33 // prop was picked up
|
||||
#define SVC_PROP_USE 0x34 // door/lift/etc was used
|
||||
#define SVC_PROP_DOOR 0x35 // door state changed
|
||||
#define SVC_PROP_LIFT 0x36 // lift state changed
|
||||
#define SVC_CHR_DAMAGE 0x42 // chr was damaged
|
||||
#define SVC_CHR_DISARM 0x43 // chr's weapons were dropped
|
||||
|
||||
#define CLC_BAD 0x00 // trash
|
||||
#define CLC_NOP 0x01 // does nothing
|
||||
#define CLC_AUTH 0x02 // auth request, sent immediately after connecting
|
||||
#define CLC_CHAT 0x03 // chat message
|
||||
#define CLC_MOVE 0x04 // player input
|
||||
#define CLC_SETTINGS 0x05 // player settings changed
|
||||
|
||||
u32 netmsgClcAuthWrite(struct netbuf *dst);
|
||||
u32 netmsgClcAuthRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgClcChatWrite(struct netbuf *dst, const char *str);
|
||||
u32 netmsgClcChatRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgClcMoveWrite(struct netbuf *dst);
|
||||
u32 netmsgClcMoveRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgClcSettingsWrite(struct netbuf *dst);
|
||||
u32 netmsgClcSettingsRead(struct netbuf *src, struct netclient *srccl);
|
||||
|
||||
u32 netmsgSvcAuthWrite(struct netbuf *dst, struct netclient *authcl);
|
||||
u32 netmsgSvcAuthRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcChatWrite(struct netbuf *dst, const char *str);
|
||||
u32 netmsgSvcChatRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcStageStartWrite(struct netbuf *dst);
|
||||
u32 netmsgSvcStageStartRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcStageEndWrite(struct netbuf *dst);
|
||||
u32 netmsgSvcStageEndRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPlayerMoveWrite(struct netbuf *dst, struct netclient *movecl);
|
||||
u32 netmsgSvcPlayerMoveRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPlayerStatsWrite(struct netbuf *dst, struct netclient *actcl);
|
||||
u32 netmsgSvcPlayerStatsRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropSpawnWrite(struct netbuf *dst, struct prop *prop);
|
||||
u32 netmsgSvcPropSpawnRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropMoveWrite(struct netbuf *dst, struct prop *prop, struct coord *initrot);
|
||||
u32 netmsgSvcPropMoveRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropDamageWrite(struct netbuf *dst, struct prop *prop, f32 damage, struct coord *pos, s32 weaponnum, s32 playernum);
|
||||
u32 netmsgSvcPropDamageRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropPickupWrite(struct netbuf *dst, struct netclient *actcl, struct prop *prop, const s32 tickop);
|
||||
u32 netmsgSvcPropPickupRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropUseWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl, const s32 tickop);
|
||||
u32 netmsgSvcPropUseRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropDoorWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl);
|
||||
u32 netmsgSvcPropDoorRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcPropLiftWrite(struct netbuf *dst, struct prop *prop);
|
||||
u32 netmsgSvcPropLiftRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcChrDamageWrite(struct netbuf *dst, struct chrdata *chr, f32 damage, struct coord *vector, struct gset *gset, struct prop *aprop, s32 hitpart, bool damageshield, struct prop *prop2, s32 side, s16 *arg11, bool explosion, struct coord *explosionpos);
|
||||
u32 netmsgSvcChrDamageRead(struct netbuf *src, struct netclient *srccl);
|
||||
u32 netmsgSvcChrDisarmWrite(struct netbuf *dst, struct chrdata *chr, struct prop *attacker, u8 weaponnum, f32 wpndamage, struct coord *wpnpos);
|
||||
u32 netmsgSvcChrDisarmRead(struct netbuf *src, struct netclient *srccl);
|
||||
|
||||
#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,29 @@
|
||||
#ifndef _IN_ROMDATA_H
|
||||
#define _IN_ROMDATA_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
extern u8 *g_RomFile;
|
||||
extern u32 g_RomFileSize;
|
||||
extern const char *g_RomName;
|
||||
|
||||
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,56 @@
|
||||
#ifndef _IN_SYSTEM_H
|
||||
#define _IN_SYSTEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
#define LOGFLAG_NOCON (1 << 6)
|
||||
#define LOGFLAG_SHOWMSG (1 << 7)
|
||||
|
||||
enum loglevel {
|
||||
LOG_NOTE = 0,
|
||||
LOG_CHAT = 0 | LOGFLAG_SHOWMSG,
|
||||
LOG_WARNING = 1 | LOGFLAG_SHOWMSG,
|
||||
LOG_ERROR = 2 | LOGFLAG_SHOWMSG,
|
||||
};
|
||||
|
||||
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);
|
||||
f32 sysGetSeconds(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,29 @@
|
||||
#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);
|
||||
|
||||
static inline f32 lerpf(const f32 a, const f32 b, const f32 t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
static inline f32 lerpanglef(const f32 a, const f32 b, const f32 t) {
|
||||
f32 d = b - a;
|
||||
if (d > 180.f) {
|
||||
d -= 360.f;
|
||||
} else if (d < -180.f) {
|
||||
d += 360.f;
|
||||
}
|
||||
return a + d * t;
|
||||
}
|
||||
|
||||
#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,80 @@
|
||||
#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 videoCapFramerate(s32 limit);
|
||||
|
||||
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,220 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "platform.h"
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
#include "config.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "console.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
#include "net/net.h"
|
||||
#include "game/hudmsg.h"
|
||||
#include "game/game_1531a0.h"
|
||||
#include "lib/vi.h"
|
||||
|
||||
#define CON_ROWS 80
|
||||
#define CON_COLS 56
|
||||
#define CON_VISROWS 10
|
||||
#define CON_MSGROWS 4
|
||||
#define CON_MSGTIMER 3.f
|
||||
|
||||
static char conBuf[CON_ROWS][CON_COLS + 1];
|
||||
static char conInput[CON_COLS + 1];
|
||||
static char *conVisRows[CON_VISROWS];
|
||||
static s32 conPrintRow = 0;
|
||||
static s32 conPrintCol = 0;
|
||||
static s32 conMsgRows = 0;
|
||||
static f32 conMsgTimer = 0.f;
|
||||
static s32 conInputCol = 0;
|
||||
static u32 conTextColour = 0x00ff00ff;
|
||||
static s32 conOpen = 0;
|
||||
static s32 conButton = 0;
|
||||
|
||||
void conInit(void)
|
||||
{
|
||||
memset(conBuf, 0, sizeof(conBuf));
|
||||
memset(conInput, 0, sizeof(conInput));
|
||||
memset(conVisRows, 0, sizeof(conVisRows));
|
||||
conPrintRow = conPrintCol = 0;
|
||||
conOpen = 0;
|
||||
conMsgRows = 0;
|
||||
conMsgTimer = 0.0f;
|
||||
conInputCol = 0;
|
||||
}
|
||||
|
||||
void conPrint(s32 showmsg, const char *str)
|
||||
{
|
||||
if (!str || !*str) {
|
||||
return;
|
||||
}
|
||||
|
||||
const s32 oldRow = conPrintRow;
|
||||
|
||||
for (const char *s = str; *s; ++s) {
|
||||
char ch = *s;
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
if (conPrintCol) {
|
||||
conPrintCol = 0;
|
||||
conPrintRow = (conPrintRow + 1) % CON_ROWS;
|
||||
}
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
case '\t':
|
||||
ch = ' ';
|
||||
/* fallthrough */
|
||||
default:
|
||||
conBuf[conPrintRow][conPrintCol++] = ch;
|
||||
if (conPrintCol == CON_COLS) {
|
||||
conPrintCol = 0;
|
||||
conPrintRow = (conPrintRow + 1) % CON_ROWS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
conBuf[conPrintRow][conPrintCol] = '\0';
|
||||
}
|
||||
|
||||
if (conPrintRow != oldRow) {
|
||||
// scroll time
|
||||
for (s32 i = 0; i < ARRAYCOUNT(conVisRows); ++i) {
|
||||
s32 row = conPrintRow - i - 1;
|
||||
if (row < 0) {
|
||||
row = CON_ROWS + row;
|
||||
}
|
||||
conVisRows[i] = &conBuf[row][0];
|
||||
}
|
||||
if (showmsg) {
|
||||
if (conMsgRows < CON_MSGROWS) {
|
||||
if (conPrintRow > oldRow) {
|
||||
conMsgRows += conPrintRow - oldRow;
|
||||
} else {
|
||||
conMsgRows += conPrintRow + (CON_ROWS - oldRow);
|
||||
}
|
||||
}
|
||||
conMsgTimer = sysGetSeconds() + CON_MSGTIMER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void conPrintLn(s32 showmsg, const char *s)
|
||||
{
|
||||
char tmp[4096];
|
||||
snprintf(tmp, sizeof(tmp), "%s\n", s);
|
||||
conPrint(showmsg, tmp);
|
||||
}
|
||||
|
||||
void conPrintf(s32 showmsg, const char *fmt, ...)
|
||||
{
|
||||
char tmp[4096];
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
tmp[0] = '\0';
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(tmp, sizeof(tmp), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
conPrint(showmsg, tmp);
|
||||
}
|
||||
|
||||
static inline Gfx *conRenderMsgs(Gfx *gdl)
|
||||
{
|
||||
if (conMsgRows) {
|
||||
s32 x, y;
|
||||
const u32 c = (conTextColour & 0xffffff00) | 0xa0;
|
||||
for (s32 i = 0; i < conMsgRows; ++i) {
|
||||
char *s = conVisRows[i];
|
||||
if (s) {
|
||||
x = 4;
|
||||
y = 4 + 8 * (conMsgRows - i - 1);
|
||||
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, c, viGetWidth(), viGetHeight(), 0, 0);
|
||||
}
|
||||
}
|
||||
const f32 t = sysGetSeconds();
|
||||
if (conMsgTimer <= t) {
|
||||
conMsgTimer = t + CON_MSGTIMER;
|
||||
--conMsgRows;
|
||||
}
|
||||
} else {
|
||||
conMsgTimer = 0;
|
||||
}
|
||||
|
||||
return gdl;
|
||||
}
|
||||
|
||||
Gfx *conRender(Gfx *gdl)
|
||||
{
|
||||
if (!g_CharsHandelGothicXs || !g_FontHandelGothicXs) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
gdl = text0f153628(gdl);
|
||||
|
||||
if (!conOpen) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT);
|
||||
gdl = conRenderMsgs(gdl);
|
||||
} else {
|
||||
s32 x, y;
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_CENTER_EXT);
|
||||
gdl = hudmsgRenderBox(gdl, 16, 0, SCREEN_WIDTH_LO - 16, 4 + 8 * (CON_VISROWS + 1), 1.f, conTextColour, 0.9f);
|
||||
for (s32 i = 0; i < CON_VISROWS; ++i) {
|
||||
char *s = conVisRows[i];
|
||||
if (s) {
|
||||
x = 18;
|
||||
y = 4 + 8 * (CON_VISROWS - i - 1);
|
||||
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
|
||||
}
|
||||
}
|
||||
char tmp[CON_COLS + 3];
|
||||
snprintf(tmp, sizeof(tmp), "> %s", conInput);
|
||||
x = 18;
|
||||
y = 4 + 8 * CON_VISROWS;
|
||||
gdl = textRenderProjected(gdl, &x, &y, tmp, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
|
||||
}
|
||||
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
|
||||
|
||||
gdl = text0f153780(gdl);
|
||||
|
||||
return gdl;
|
||||
}
|
||||
|
||||
void conTick(void)
|
||||
{
|
||||
const s32 button = inputKeyPressed(VK_GRAVE);
|
||||
if (button && !conButton) {
|
||||
conOpen = !conOpen;
|
||||
g_MenuKeyboardPlayer = -1;
|
||||
if (conOpen) {
|
||||
inputClearLastTextChar();
|
||||
inputStartTextInput();
|
||||
} else {
|
||||
inputStopTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
conButton = button;
|
||||
|
||||
if (conOpen) {
|
||||
if (inputTextHandler(conInput, CON_COLS, &conInputCol, false)) {
|
||||
if (g_NetMode) {
|
||||
netChat(NULL, conInput);
|
||||
}
|
||||
conInput[0] = '\0';
|
||||
conInputCol = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 conIsOpen(void)
|
||||
{
|
||||
return conOpen;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
+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
|
||||
}
|
||||
+1543
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
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
#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 "console.h"
|
||||
#include "utils.h"
|
||||
#include "net/net.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_LOCAL_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");
|
||||
netDisconnect();
|
||||
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();
|
||||
}
|
||||
|
||||
conInit();
|
||||
sysInit();
|
||||
fsInit();
|
||||
configInit();
|
||||
videoInit();
|
||||
inputInit();
|
||||
audioInit();
|
||||
romdataInit();
|
||||
netInit();
|
||||
|
||||
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);
|
||||
|
||||
g_FileAutoSelect = sysArgGetInt("--profile", -1);
|
||||
|
||||
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_NetJoinLatch || g_NetHostLatch) {
|
||||
if (g_FileAutoSelect < 0) {
|
||||
// default to profile 0 if going into a net game
|
||||
g_FileAutoSelect = 0;
|
||||
}
|
||||
// skip the intro if going into a net game
|
||||
g_StageNum = STAGE_CITRAINING;
|
||||
}
|
||||
|
||||
if (g_StageNum != STAGE_TITLE) {
|
||||
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
|
||||
}
|
||||
|
||||
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_LOCAL_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,721 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ultra64.h>
|
||||
|
||||
#include "mixer.h"
|
||||
#include "platform.h"
|
||||
|
||||
#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);
|
||||
}
|
||||
+1127
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,305 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "net/netbuf.h"
|
||||
|
||||
/* read */
|
||||
|
||||
void netbufStartRead(struct netbuf *buf)
|
||||
{
|
||||
buf->error = 0;
|
||||
buf->wp = buf->size;
|
||||
buf->rp = 0;
|
||||
}
|
||||
|
||||
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size)
|
||||
{
|
||||
buf->size = size;
|
||||
buf->data = (void *)data;
|
||||
netbufStartRead(buf);
|
||||
}
|
||||
|
||||
s32 netbufReadLeft(const struct netbuf *buf)
|
||||
{
|
||||
return buf->wp - buf->rp;
|
||||
}
|
||||
|
||||
static inline u32 netbufCanRead(struct netbuf *buf, const u32 num)
|
||||
{
|
||||
if (buf->error || buf->rp + num > buf->wp) {
|
||||
sysLogPrintf(LOG_ERROR, "NET: could not read %u bytes", num);
|
||||
__builtin_trap();
|
||||
buf->error = 1;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 netbufReadData(struct netbuf *buf, void *out, u32 num)
|
||||
{
|
||||
if (netbufCanRead(buf, num)) {
|
||||
memcpy(out, buf->data + buf->rp, num);
|
||||
buf->rp += num;
|
||||
return num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 netbufReadU8(struct netbuf *buf)
|
||||
{
|
||||
if (netbufCanRead(buf, 1)) {
|
||||
return buf->data[buf->rp++];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 netbufReadU16(struct netbuf *buf)
|
||||
{
|
||||
if (netbufCanRead(buf, 2)) {
|
||||
const u16 ret = *(u16 *)&buf->data[buf->rp];
|
||||
buf->rp += sizeof(ret);
|
||||
return PD_LE16(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufReadU32(struct netbuf *buf)
|
||||
{
|
||||
if (netbufCanRead(buf, 4)) {
|
||||
const u32 ret = *(u32 *)&buf->data[buf->rp];
|
||||
buf->rp += sizeof(ret);
|
||||
return PD_LE32(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 netbufReadU64(struct netbuf *buf)
|
||||
{
|
||||
if (netbufCanRead(buf, 8)) {
|
||||
const u64 ret = *(u64 *)&buf->data[buf->rp];
|
||||
buf->rp += sizeof(ret);
|
||||
return PD_LE64(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s8 netbufReadS8(struct netbuf *buf) {
|
||||
return (s8)netbufReadU8(buf);
|
||||
}
|
||||
|
||||
s16 netbufReadS16(struct netbuf *buf) {
|
||||
return (s16)netbufReadU16(buf);
|
||||
}
|
||||
|
||||
s32 netbufReadS32(struct netbuf *buf) {
|
||||
return (s32)netbufReadU32(buf);
|
||||
}
|
||||
|
||||
s64 netbufReadS64(struct netbuf *buf) {
|
||||
return (s64)netbufReadU64(buf);
|
||||
}
|
||||
|
||||
f32 netbufReadF32(struct netbuf *buf)
|
||||
{
|
||||
union {
|
||||
f32 f;
|
||||
u32 i;
|
||||
} hack;
|
||||
hack.i = netbufReadU32(buf);
|
||||
return hack.f;
|
||||
}
|
||||
|
||||
char *netbufReadStr(struct netbuf *buf)
|
||||
{
|
||||
const u16 len = netbufReadU16(buf);
|
||||
if (netbufCanRead(buf, len)) {
|
||||
char *ret = (char *)&buf->data[buf->rp];
|
||||
buf->rp += len;
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 netbufReadCoord(struct netbuf *buf, struct coord *out)
|
||||
{
|
||||
if (netbufCanRead(buf, sizeof(*out))) {
|
||||
out->x = netbufReadF32(buf);
|
||||
out->y = netbufReadF32(buf);
|
||||
out->z = netbufReadF32(buf);
|
||||
return sizeof(*out);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out)
|
||||
{
|
||||
if (netbufCanRead(buf, sizeof(*out))) {
|
||||
for (s32 i = 0; i < 4; ++i) {
|
||||
for (s32 j = 0; j < 4; ++j) {
|
||||
out->m[i][j] = netbufReadF32(buf);
|
||||
}
|
||||
}
|
||||
return sizeof(*out);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufReadSkip(struct netbuf *buf, u32 count)
|
||||
{
|
||||
if (netbufCanRead(buf, count)) {
|
||||
buf->rp += count;
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write */
|
||||
|
||||
void netbufStartWrite(struct netbuf *buf)
|
||||
{
|
||||
buf->wp = 0;
|
||||
buf->error = 0;
|
||||
}
|
||||
|
||||
static inline u32 netbufCanWrite(struct netbuf *buf, const u32 num)
|
||||
{
|
||||
if (buf->error || buf->wp + num > buf->size) {
|
||||
buf->error = 1;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 netbufWriteLeft(const struct netbuf *buf)
|
||||
{
|
||||
return buf->size - buf->wp;
|
||||
}
|
||||
|
||||
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num)
|
||||
{
|
||||
if (netbufCanWrite(buf, num)) {
|
||||
memcpy(buf->data + buf->wp, data, num);
|
||||
buf->wp += num;
|
||||
return num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteU8(struct netbuf *buf, const u8 v)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(v))) {
|
||||
buf->data[buf->wp++] = v;
|
||||
return sizeof(v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteU16(struct netbuf *buf, const u16 v)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(v))) {
|
||||
*(u16 *)&buf->data[buf->wp] = PD_LE16(v);
|
||||
buf->wp += sizeof(v);
|
||||
return sizeof(v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteU32(struct netbuf *buf, const u32 v)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(v))) {
|
||||
*(u32 *)&buf->data[buf->wp] = PD_LE32(v);
|
||||
buf->wp += sizeof(v);
|
||||
return sizeof(v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteU64(struct netbuf *buf, const u64 v)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(v))) {
|
||||
*(u64 *)&buf->data[buf->wp] = PD_LE64(v);
|
||||
buf->wp += sizeof(v);
|
||||
return sizeof(v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteS8(struct netbuf *buf, const s8 v)
|
||||
{
|
||||
return netbufWriteU8(buf, (u8)v);
|
||||
}
|
||||
|
||||
u32 netbufWriteS16(struct netbuf *buf, const s16 v)
|
||||
{
|
||||
return netbufWriteU16(buf, (u16)v);
|
||||
}
|
||||
|
||||
u32 netbufWriteS32(struct netbuf *buf, const s32 v)
|
||||
{
|
||||
return netbufWriteU32(buf, (u32)v);
|
||||
}
|
||||
|
||||
u32 netbufWriteS64(struct netbuf *buf, const s64 v)
|
||||
{
|
||||
return netbufWriteU64(buf, (u64)v);
|
||||
}
|
||||
|
||||
u32 netbufWriteF32(struct netbuf *buf, const f32 v)
|
||||
{
|
||||
const union {
|
||||
f32 f;
|
||||
u32 i;
|
||||
} hack = { .f = v };
|
||||
return netbufWriteU32(buf, hack.i);
|
||||
}
|
||||
|
||||
u32 netbufWriteStr(struct netbuf *buf, const char *v)
|
||||
{
|
||||
if (!v) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 len = strlen(v) + 1;
|
||||
if (len > 0xFFFF) {
|
||||
len = 0xFFFF;
|
||||
}
|
||||
|
||||
if (netbufCanWrite(buf, len + sizeof(u16))) {
|
||||
netbufWriteU16(buf, len);
|
||||
netbufWriteData(buf, v, len);
|
||||
buf->data[buf->wp - 1] = 0;
|
||||
return sizeof(u16) + len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(*v))) {
|
||||
netbufWriteF32(buf, v->x);
|
||||
netbufWriteF32(buf, v->y);
|
||||
netbufWriteF32(buf, v->z);
|
||||
return sizeof(*v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in)
|
||||
{
|
||||
if (netbufCanWrite(buf, sizeof(*in))) {
|
||||
for (s32 i = 0; i < 4; ++i) {
|
||||
for (s32 j = 0; j < 4; ++j) {
|
||||
netbufWriteF32(buf, in->m[i][j]);
|
||||
}
|
||||
}
|
||||
return sizeof(*in);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netbufReset(struct netbuf *buf)
|
||||
{
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#include "game/mainmenu.h"
|
||||
#include "game/menu.h"
|
||||
#include "game/gamefile.h"
|
||||
#include "game/filelist.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "config.h"
|
||||
#include "mpsetups.h"
|
||||
#include "net/net.h"
|
||||
|
||||
extern MenuItemHandlerResult menuhandlerMainMenuCombatSimulator(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
extern MenuItemHandlerResult menuhandlerMpAdvancedSetup(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
extern struct menuitem g_MpPlayerSetup234MenuItems[];
|
||||
extern struct menudialogdef g_NetJoinPlayerSetupMenuDialog;
|
||||
|
||||
static s32 g_NetMenuMaxPlayers = NET_MAX_CLIENTS;
|
||||
static s32 g_NetMenuPort = NET_DEFAULT_PORT;
|
||||
static char g_NetJoinAddr[NET_MAX_ADDR + 1];
|
||||
static s32 g_NetJoinAddrPtr = 0;
|
||||
|
||||
/* host */
|
||||
|
||||
static MenuItemHandlerResult menuhandlerHostMaxPlayers(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = g_NetMenuMaxPlayers;
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
if (data->slider.value) {
|
||||
g_NetMenuMaxPlayers = data->slider.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerHostPort(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *menuhandlerHostPortValue(struct menuitem *item)
|
||||
{
|
||||
static char tmp[16];
|
||||
snprintf(tmp, sizeof(tmp), "%u\n", g_NetMenuPort);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
MenuItemHandlerResult menuhandlerHostStart(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
if (netStartServer(g_NetMenuPort, g_NetMenuMaxPlayers) == 0) {
|
||||
// load the setup file when entering the Combat Simulator
|
||||
mpsetupCopyAllFromPak();
|
||||
mpsetupLoadCurrentFile();
|
||||
menuhandlerMainMenuCombatSimulator(MENUOP_SET, NULL, NULL);
|
||||
menuhandlerMpAdvancedSetup(MENUOP_SET, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_NetHostMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Max Players",
|
||||
NET_MAX_CLIENTS,
|
||||
menuhandlerHostMaxPlayers,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Port\n",
|
||||
(uintptr_t)&menuhandlerHostPortValue,
|
||||
menuhandlerHostPort,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
0,
|
||||
L_MPMENU_036, // "Start Game"
|
||||
0,
|
||||
menuhandlerHostStart,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetHostMenuDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Host Network Game",
|
||||
g_NetHostMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* join */
|
||||
|
||||
static const char *menutextJoinAddress(struct menuitem *item)
|
||||
{
|
||||
static char tmp[256 + 1];
|
||||
if (item && item->flags & MENUITEMFLAG_SELECTABLE_CENTRE) {
|
||||
// in centered dialog
|
||||
if (g_NetMode == NETMODE_NONE) {
|
||||
snprintf(tmp, sizeof(tmp), "%s_\n", g_NetJoinAddr);
|
||||
} else if (g_NetLocalClient->state == CLSTATE_CONNECTING) {
|
||||
snprintf(tmp, sizeof(tmp), "Connecting to %s...\n", g_NetJoinAddr);
|
||||
} else if (g_NetLocalClient->state == CLSTATE_AUTH) {
|
||||
snprintf(tmp, sizeof(tmp), "Authenticating with %s...\n", g_NetJoinAddr);
|
||||
} else if (g_NetLocalClient->state == CLSTATE_LOBBY) {
|
||||
snprintf(tmp, sizeof(tmp), "Waiting for host...\n");
|
||||
}
|
||||
} else {
|
||||
// label
|
||||
snprintf(tmp, sizeof(tmp), "%s\n", g_NetJoinAddr);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerJoining(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (inputKeyPressed(VK_ESCAPE)) {
|
||||
netDisconnect();
|
||||
menuPopDialog();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_NetJoiningMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
(uintptr_t)&menutextJoinAddress,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"ESC to abort\n",
|
||||
0,
|
||||
menuhandlerJoining,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetJoiningDialog = {
|
||||
MENUDIALOGTYPE_SUCCESS,
|
||||
(uintptr_t)"Joining Game...",
|
||||
g_NetJoiningMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
|
||||
struct menuitem g_NetJoinAddressMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
(uintptr_t)&menutextJoinAddress,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"ESC to return\n",
|
||||
0,
|
||||
menuhandlerEnterJoinAddress,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetJoinAddressDialog = {
|
||||
MENUDIALOGTYPE_SUCCESS,
|
||||
(uintptr_t)"Enter Address",
|
||||
g_NetJoinAddressMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (!menuIsDialogOpen(&g_NetJoinAddressDialog)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inputTextHandler(g_NetJoinAddr, NET_MAX_ADDR, &g_NetJoinAddrPtr, false) < 0) {
|
||||
// escape has been pressed, stop editing
|
||||
inputStopTextInput();
|
||||
menuPopDialog();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
inputClearLastKey();
|
||||
inputClearLastTextChar();
|
||||
inputStartTextInput();
|
||||
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
|
||||
menuPushDialog(&g_NetJoinAddressDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MenuItemHandlerResult menuhandlerJoinStart(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
if (netStartClient(g_NetJoinAddr) == 0) {
|
||||
menuPushDialog(&g_NetJoiningDialog);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerJoinPlayerSetup(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
// load MP player file
|
||||
filelistCreate(0, FILETYPE_MPPLAYER);
|
||||
filelistsTick();
|
||||
menuPushDialog(&g_NetJoinPlayerSetupMenuDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_NetJoinMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Address: \n",
|
||||
(uintptr_t)&menutextJoinAddress,
|
||||
menuhandlerJoinAddress,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
0,
|
||||
L_MPMENU_028, // "Player Setup"
|
||||
0,
|
||||
menuhandlerJoinPlayerSetup,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
0,
|
||||
L_MPMENU_036, // "Start Game"
|
||||
0,
|
||||
menuhandlerJoinStart,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetJoinMenuDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Join Network Game",
|
||||
g_NetJoinMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* main */
|
||||
|
||||
MenuItemHandlerResult menuhandlerHostGame(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
g_NetMenuPort = g_NetServerPort;
|
||||
g_NetMenuMaxPlayers = g_NetMaxClients;
|
||||
menuPushDialog(&g_NetHostMenuDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MenuItemHandlerResult menuhandlerJoinGame(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
if (g_NetJoinAddr[0] == '\0') {
|
||||
strncpy(g_NetJoinAddr, g_NetLastJoinAddr, NET_MAX_ADDR);
|
||||
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
|
||||
}
|
||||
menuPushDialog(&g_NetJoinMenuDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_NetMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Host Game\n",
|
||||
0,
|
||||
menuhandlerHostGame,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Join Game\n",
|
||||
0,
|
||||
menuhandlerJoinGame,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetMenuDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Network Game",
|
||||
g_NetMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_MPLOCKABLE | MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct menudialogdef g_NetJoinPlayerSetupMenuDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
L_MPMENU_028, // "Player Setup"
|
||||
g_MpPlayerSetup234MenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_DROPOUTONCLOSE | MENUDIALOGFLAG_STARTSELECTS,
|
||||
NULL,
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,653 @@
|
||||
#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 "system.h"
|
||||
#include "console.h"
|
||||
#include "net/net.h"
|
||||
#include "net/netmsg.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;
|
||||
if (g_NetMode && g_NetMaxClients > MAX_LOCAL_PLAYERS) {
|
||||
g_MainMemaHeapSize *= MAX_PLAYERS / MAX_LOCAL_PLAYERS;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
#ifdef PLATFORM_N64
|
||||
g_MpSetup.chrslots = 0x03;
|
||||
#else
|
||||
if (g_Vars.antiplayernum < 0) {
|
||||
// Counter-Operative now uses a different approach which allows more than 2 players.
|
||||
// Co-Operative, on the other hand, is currently limited to 2 players.
|
||||
g_MpSetup.chrslots = 0x03;
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
|
||||
for (s32 i = 1; i < numplayers; ++i) {
|
||||
g_MpSetup.chrslots |= 1 << i;
|
||||
}
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
gdl = conRender(gdl);
|
||||
gdl = netDebugRender(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 < LOCALPLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(i);
|
||||
endscreenPushCoop();
|
||||
}
|
||||
|
||||
setCurrentPlayerNum(prevplayernum);
|
||||
musicStartMenu();
|
||||
} else if (g_Vars.antiplayernum >= 0) {
|
||||
s32 prevplayernum = g_Vars.currentplayernum;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(i);
|
||||
endscreenPushAnti();
|
||||
}
|
||||
|
||||
setCurrentPlayerNum(prevplayernum);
|
||||
musicStartMenu();
|
||||
} else if (g_Vars.normmplayerisrunning) {
|
||||
mpEndMatch();
|
||||
} else {
|
||||
endscreenPrepare();
|
||||
musicStartMenu();
|
||||
}
|
||||
|
||||
netServerStageEnd();
|
||||
}
|
||||
|
||||
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,428 @@
|
||||
#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 "console.h"
|
||||
#include "mixer.h"
|
||||
#include "net/net.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)
|
||||
{
|
||||
videoStartFrame();
|
||||
if (g_Vars.diffframe60) {
|
||||
if (g_NetMode) {
|
||||
videoCapFramerate(120);
|
||||
netStartFrame();
|
||||
} else {
|
||||
videoCapFramerate(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
static bool netDebugKey = false;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
inputUpdate();
|
||||
conTick();
|
||||
|
||||
const bool newKey = inputKeyPressed(VK_F9);
|
||||
if (!netDebugKey && newKey) {
|
||||
g_NetDebugDraw = !g_NetDebugDraw;
|
||||
}
|
||||
netDebugKey = newKey;
|
||||
|
||||
joyStartReadData(&g_PiMesgQueue);
|
||||
joyReadData();
|
||||
joy00014238();
|
||||
|
||||
if (g_Vars.diffframe60) {
|
||||
netEndFrame();
|
||||
}
|
||||
|
||||
sndHandleRetrace();
|
||||
schedAudioFrame(sc);
|
||||
schedRenderCrashPeriodically(sc->frameCount);
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
#include "preprocess/gbi.h"
|
||||
|
||||
#if UINTPTR_MAX > 0xFFFFFFFFu
|
||||
#define HOST_DWORDS_PER_CMD 2
|
||||
#else
|
||||
#define HOST_DWORDS_PER_CMD 1
|
||||
#endif
|
||||
|
||||
struct vtx {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 z;
|
||||
u8 flags;
|
||||
u8 colour;
|
||||
s16 s;
|
||||
s16 t;
|
||||
};
|
||||
|
||||
struct texaddr {
|
||||
u32 src;
|
||||
u32 dst;
|
||||
};
|
||||
|
||||
static u32 gbiSegments[16];
|
||||
static u32 srcVtxOffset;
|
||||
static u32 dstVtxOffset;
|
||||
|
||||
static struct texaddr texAddrs[64];
|
||||
static int numTexAddrs;
|
||||
|
||||
void gbiReset(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAYCOUNT(gbiSegments); i++) {
|
||||
gbiSegments[i] = 0;
|
||||
}
|
||||
|
||||
srcVtxOffset = 0;
|
||||
dstVtxOffset = 0;
|
||||
numTexAddrs = 0;
|
||||
}
|
||||
|
||||
void gbiSetSegment(int segment, u32 offset)
|
||||
{
|
||||
gbiSegments[segment] = offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
void gbiSetVtx(u32 src_offset, u32 dst_offset)
|
||||
{
|
||||
srcVtxOffset = src_offset & 0x00ffffff;
|
||||
dstVtxOffset = dst_offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
void gbiAddTexAddr(u32 src_offset, u32 dst_offset)
|
||||
{
|
||||
texAddrs[numTexAddrs].src = src_offset & 0x00ffffff;
|
||||
texAddrs[numTexAddrs++].dst = dst_offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
u32 gbiFindTexAddr(u32 src_offset)
|
||||
{
|
||||
for (int i = 0; i < numTexAddrs; i++) {
|
||||
if (texAddrs[i].src == src_offset)
|
||||
return texAddrs[i].dst;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gbiConvertVtx(u8 *dst, u32 offset, int count)
|
||||
{
|
||||
if (!offset) return;
|
||||
struct vtx* vtxs = (struct vtx*)(dst + offset);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct vtx* vtx = &vtxs[i];
|
||||
|
||||
vtx->x = PD_BE16(vtx->x);
|
||||
vtx->y = PD_BE16(vtx->y);
|
||||
vtx->z = PD_BE16(vtx->z);
|
||||
vtx->s = PD_BE16(vtx->s);
|
||||
vtx->t = PD_BE16(vtx->t);
|
||||
}
|
||||
}
|
||||
|
||||
#define CMD_IS_VTX(cmd) ((cmd & 0xff00000000000000) == 0x0400000000000000)
|
||||
#define CMD_IS_DL(cmd) ((cmd & 0xff00000000000000) == 0x0600000000000000)
|
||||
#define CMD_IS_COL(cmd) ((cmd & 0xff00000000000000) == 0x0700000000000000)
|
||||
#define CMD_IS_ENDDL(cmd) ((cmd & 0xff00000000000000) == 0xb800000000000000)
|
||||
#define CMD_IS_MOVEWORD(cmd) ((cmd & 0xff00000000000000) == 0xbc00000000000000)
|
||||
#define CMD_IS_MOVEMEM(cmd) ((cmd & 0xff00000000000000) == 0x0300000000000000)
|
||||
#define CMD_IS_MTX(cmd) ((cmd & 0xff00000000000000) == 0x0100000000000000)
|
||||
#define CMD_IS_SETTIMG(cmd) ((cmd & 0xff00000000000000) == 0xfd00000000000000)
|
||||
#define CMD_IS_SETZIMG(cmd) ((cmd & 0xff00000000000000) == 0xfe00000000000000)
|
||||
#define CMD_IS_SETCIMG(cmd) ((cmd & 0xff00000000000000) == 0xff00000000000000)
|
||||
|
||||
#define CMD_HAS_ADDR(cmd) CMD_IS_VTX(cmd) \
|
||||
|| CMD_IS_COL(cmd) \
|
||||
|| CMD_IS_MOVEWORD(cmd) \
|
||||
|| CMD_IS_SETTIMG(cmd)
|
||||
|
||||
|
||||
#define CMD_IS_SEGMENTED(cmd) ( CMD_IS_MOVEMEM(cmd) \
|
||||
|| CMD_IS_MTX(cmd) \
|
||||
|| CMD_IS_VTX(cmd) \
|
||||
|| CMD_IS_COL(cmd) \
|
||||
|| CMD_IS_DL(cmd) \
|
||||
|| CMD_IS_SETTIMG(cmd) \
|
||||
|| CMD_IS_SETCIMG(cmd) \
|
||||
|| CMD_IS_SETZIMG(cmd))
|
||||
|
||||
/**
|
||||
* Segment 5 is the start of the model file. The data in these files shifts
|
||||
* depending on the pointer size, so this function adjusts the offset accordingly.
|
||||
*/
|
||||
static u64 gbiRewriteAddr(u64 cmd, u8 opcode)
|
||||
{
|
||||
u8 segment = (cmd & 0x0f000000) >> 24;
|
||||
u32 offset = cmd & 0x00ffffff;
|
||||
|
||||
if (segment == 5) {
|
||||
if (opcode == 0xfd) {
|
||||
offset = gbiFindTexAddr(offset);
|
||||
}
|
||||
else {
|
||||
if (offset < srcVtxOffset) {
|
||||
sysFatalError("Tried to load data from offset 0x%x but segment starts at 0x%x\n", offset, srcVtxOffset);
|
||||
}
|
||||
|
||||
offset = offset - srcVtxOffset + dstVtxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
return (cmd & 0xffffffffff000000) | offset;
|
||||
}
|
||||
|
||||
void gbiGdlRewriteAddrs(u8 *dst, u32 offset)
|
||||
{
|
||||
if (!offset) return;
|
||||
|
||||
u64 *cmds = (u64 *)(dst + (offset & 0x00ffffff));
|
||||
if (!cmds) return;
|
||||
|
||||
u64 cmd;
|
||||
|
||||
do {
|
||||
cmd = *cmds;
|
||||
Gfx* gfxcmd = (Gfx *)cmds;
|
||||
int idx = 0;
|
||||
u8 opcode = (cmd >> 24) & 0xff;
|
||||
|
||||
#if HOST_DWORDS_PER_CMD == 2
|
||||
idx = 1;
|
||||
opcode = (cmd >> 24) & 0xff;
|
||||
#endif
|
||||
cmd = (u64)opcode << 56;
|
||||
|
||||
if (CMD_HAS_ADDR(cmd)) {
|
||||
cmds[idx] = gbiRewriteAddr(cmds[idx], opcode);
|
||||
}
|
||||
|
||||
if (CMD_IS_SEGMENTED(cmd)) {
|
||||
gfxcmd->words.w1 |= 1;
|
||||
}
|
||||
|
||||
cmds += HOST_DWORDS_PER_CMD;
|
||||
} while (!CMD_IS_ENDDL(cmd));
|
||||
}
|
||||
|
||||
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds)
|
||||
{
|
||||
dstpos = ALIGN8(dstpos);
|
||||
|
||||
u64 *n64_cmd = (u64*)&src[srcpos];
|
||||
u64 *host_cmd = (u64*)&dst[dstpos];
|
||||
u64 cmd;
|
||||
|
||||
do {
|
||||
cmd = PD_BE64(*n64_cmd);
|
||||
|
||||
#if HOST_DWORDS_PER_CMD == 2
|
||||
host_cmd[0] = ((cmd & 0xffffffff00000000) >> 32);
|
||||
host_cmd[1] = (cmd & 0xffffffff);
|
||||
|
||||
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
||||
host_cmd[1] |= 1;
|
||||
}
|
||||
#else
|
||||
host_cmd[0] = (cmd >> 32) | ((cmd & 0xffffffff) << 32);
|
||||
|
||||
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
||||
Gfx* gfxcmd = (Gfx*)host_cmd;
|
||||
gfxcmd->words.w1 |= 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
dstpos += sizeof(*host_cmd) * HOST_DWORDS_PER_CMD;
|
||||
host_cmd += HOST_DWORDS_PER_CMD;
|
||||
n64_cmd++;
|
||||
} while (!CMD_IS_ENDDL(cmd));
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
#include "game/setuputils.h"
|
||||
#include "game/texdecompress.h"
|
||||
#include "mod.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
u8 *preprocessAnimations(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
// set the anim table pointers as well
|
||||
extern u8 *_animationsTableRomStart;
|
||||
extern u8 *_animationsTableRomEnd;
|
||||
|
||||
// the animation table is at the end of the segment
|
||||
u32 *animtbl = (void *)(data + size - 0x38a0);
|
||||
_animationsTableRomStart = (u8 *)animtbl;
|
||||
_animationsTableRomEnd = data + size;
|
||||
|
||||
PD_SWAP_VAL(*animtbl);
|
||||
const u32 count = *animtbl++;
|
||||
|
||||
struct animtableentry *anim = (struct animtableentry *)animtbl;
|
||||
for (u32 i = 0; i < count; ++i, ++anim) {
|
||||
PD_SWAP_VAL(anim->numframes);
|
||||
PD_SWAP_VAL(anim->bytesperframe);
|
||||
PD_SWAP_VAL(anim->headerlen);
|
||||
PD_SWAP_VAL(anim->data);
|
||||
// if an external replacement exists, replace the table entry and mark the offset
|
||||
if (modAnimationLoadDescriptor(i, anim) > 0) {
|
||||
anim->data = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessMpConfigs(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
const u32 count = size / sizeof(struct mpconfig);
|
||||
struct mpconfig *cfg = (struct mpconfig *)data;
|
||||
for (u32 i = 0; i < count; ++i, ++cfg) {
|
||||
PD_SWAP_VAL(cfg->setup.options);
|
||||
PD_SWAP_VAL(cfg->setup.teamscorelimit);
|
||||
PD_SWAP_VAL(cfg->setup.chrslots);
|
||||
#if MAX_PLAYERS > 4
|
||||
// make space for the extra players
|
||||
cfg->setup.chrslots = (cfg->setup.chrslots & 0x000f) | ((cfg->setup.chrslots & 0x0ff0) << 4);
|
||||
#endif
|
||||
// TODO: are these required or are they always 0?
|
||||
PD_SWAP_VAL(cfg->setup.fileguid.deviceserial);
|
||||
PD_SWAP_VAL(cfg->setup.fileguid.fileid);
|
||||
// convert MPWEAPON_ to take classic weapons and JPN weapons into account
|
||||
for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) {
|
||||
#if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */
|
||||
if (cfg->setup.weapons[j] >= 0x24) {
|
||||
// weapons after and including the shield need to be shifted (for classic weapons)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x22) {
|
||||
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x19) {
|
||||
// weapons after the combat knife also need to be shifted up in JPN
|
||||
cfg->setup.weapons[j]++;
|
||||
}
|
||||
#else
|
||||
if (cfg->setup.weapons[j] >= 0x25) {
|
||||
// weapons after and including the shield need to be shifted (for classic weapons)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x23) {
|
||||
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessTexturesList(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
struct texture *tex = (struct texture *)data;
|
||||
const u32 count = size / sizeof(*tex);
|
||||
for (u32 i = 0; i < count; ++i, ++tex) {
|
||||
// TODO: it sure looks like none of the fields except soundsurfacetype, surfacetype and dataoffset are set
|
||||
// just swap the last 3 bytes of the first word...
|
||||
const u32 dofs = (u32)tex->dataoffset << 8;
|
||||
tex->dataoffset = PD_BE32(dofs);
|
||||
// ...and the surface types in the first byte
|
||||
const u8 tmp = tex->soundsurfacetype;
|
||||
tex->soundsurfacetype = tex->surfacetype;
|
||||
tex->surfacetype = tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libaudio.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct n64_adpcm_waveinfo {
|
||||
u32 loop; // ptr to ALADPCMloop
|
||||
u32 book; // ptr to ALADPCMBook
|
||||
};
|
||||
|
||||
struct n64_raw_waveinfo {
|
||||
u32 loop; // ptr to ALRawLoop
|
||||
};
|
||||
|
||||
struct n64_wavetable {
|
||||
u32 base;
|
||||
s32 len;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
union {
|
||||
struct n64_adpcm_waveinfo adpcmWave;
|
||||
struct n64_raw_waveinfo rawWave;
|
||||
} waveInfo;
|
||||
};
|
||||
|
||||
struct n64_sound {
|
||||
u32 envelope; // ptr to ALEnvelope
|
||||
u32 keyMap; // ptr to ALKeyMap
|
||||
u32 wavetable; // ptr to struct n64_wavetable
|
||||
u8 samplePan;
|
||||
u8 sampleVolume;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct n64_instrument {
|
||||
u8 volume;
|
||||
u8 pan;
|
||||
u8 priority;
|
||||
u8 flags;
|
||||
u8 tremType;
|
||||
u8 tremRate;
|
||||
u8 tremDepth;
|
||||
u8 tremDelay;
|
||||
u8 vibType;
|
||||
u8 vibRate;
|
||||
u8 vibDepth;
|
||||
u8 vibDelay;
|
||||
s16 bendRange;
|
||||
s16 soundCount;
|
||||
u32 soundArray[1]; // ptr to struct n64_sound
|
||||
};
|
||||
|
||||
struct n64_bank {
|
||||
s16 instCount;
|
||||
u8 flags;
|
||||
u8 pad;
|
||||
s32 sampleRate;
|
||||
u32 percussion; // ptr to struct n64_instrument
|
||||
u32 instArray[1]; // ptr to struct n64_instrument
|
||||
};
|
||||
|
||||
struct n64_bankfile {
|
||||
s16 revision;
|
||||
s16 bankCount;
|
||||
u32 bankArray[1]; // ptr to struct n64_bank
|
||||
};
|
||||
|
||||
// only proceeds to convert the next item if it's not already converted
|
||||
#define AL_NEXT_ITEM(field, func) { \
|
||||
struct ptrmarker *marker = ptrFind(srcpos); \
|
||||
if (marker == NULL) { \
|
||||
field = (void *)(uintptr_t)(dstpos); \
|
||||
ptrAdd(srcpos, (uintptr_t)(field)); \
|
||||
dstpos = func(dst, dstpos, src, srcpos); \
|
||||
} else { \
|
||||
field = (void *)marker->ptr_host; } \
|
||||
}
|
||||
|
||||
static u32 convertAudioEnvelope(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALEnvelope *n64_envelope = (ALEnvelope *) &src[srcpos];
|
||||
ALEnvelope *host_envelope = (ALEnvelope *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALEnvelope);
|
||||
|
||||
host_envelope->attackTime = PD_BE32(n64_envelope->attackTime);
|
||||
host_envelope->decayTime = PD_BE32(n64_envelope->decayTime);
|
||||
host_envelope->releaseTime = PD_BE32(n64_envelope->releaseTime);
|
||||
host_envelope->attackVolume = n64_envelope->attackVolume;
|
||||
host_envelope->decayVolume = n64_envelope->decayVolume;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioKeyMap(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALKeyMap *n64_keymap = (ALKeyMap *) &src[srcpos];
|
||||
ALKeyMap *host_keymap = (ALKeyMap *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALKeyMap);
|
||||
|
||||
host_keymap->velocityMin = n64_keymap->velocityMin;
|
||||
host_keymap->velocityMax = n64_keymap->velocityMax;
|
||||
host_keymap->keyMin = n64_keymap->keyMin;
|
||||
host_keymap->keyMax = n64_keymap->keyMax;
|
||||
host_keymap->keyBase = n64_keymap->keyBase;
|
||||
host_keymap->detune = n64_keymap->detune;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioAdpcmLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALADPCMloop *n64_loop = (ALADPCMloop *) &src[srcpos];
|
||||
ALADPCMloop *host_loop = (ALADPCMloop *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALADPCMloop);
|
||||
|
||||
host_loop->start = PD_BE32(n64_loop->start);
|
||||
host_loop->end = PD_BE32(n64_loop->end);
|
||||
host_loop->count = PD_BE32(n64_loop->count);
|
||||
|
||||
for (int i = 0; i < ARRAYCOUNT(host_loop->state); i++) {
|
||||
host_loop->state[i] = PD_BE16(n64_loop->state[i]);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioAdpcmBook(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALADPCMBook *n64_book = (ALADPCMBook *) &src[srcpos];
|
||||
ALADPCMBook *host_book = (ALADPCMBook *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALADPCMBook);
|
||||
|
||||
host_book->order = PD_BE32(n64_book->order);
|
||||
host_book->npredictors = PD_BE32(n64_book->npredictors);
|
||||
|
||||
for (int i = 0; i < ARRAYCOUNT(host_book->book); i++) {
|
||||
host_book->book[i] = PD_BE16(n64_book->book[i]);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioRawLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALRawLoop *n64_loop = (ALRawLoop *) &src[srcpos];
|
||||
ALRawLoop *host_loop = (ALRawLoop *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALRawLoop);
|
||||
|
||||
host_loop->start = PD_BE32(n64_loop->start);
|
||||
host_loop->end = PD_BE32(n64_loop->end);
|
||||
host_loop->count = PD_BE32(n64_loop->count);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioWaveTable(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_wavetable *n64_wavetable = (struct n64_wavetable *) &src[srcpos];
|
||||
ALWaveTable *host_wavetable = (ALWaveTable *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALWaveTable);
|
||||
|
||||
host_wavetable->base = (void *)(uintptr_t)PD_BE32(n64_wavetable->base);
|
||||
host_wavetable->len = PD_BE32(n64_wavetable->len);
|
||||
host_wavetable->type = n64_wavetable->type;
|
||||
host_wavetable->flags = n64_wavetable->flags;
|
||||
|
||||
if (host_wavetable->type == AL_ADPCM_WAVE) {
|
||||
if (n64_wavetable->waveInfo.adpcmWave.loop) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.loop);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.loop, convertAudioAdpcmLoop);
|
||||
} else {
|
||||
host_wavetable->waveInfo.adpcmWave.loop = NULL;
|
||||
}
|
||||
|
||||
if (n64_wavetable->waveInfo.adpcmWave.book) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.book);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.book, convertAudioAdpcmBook);
|
||||
} else {
|
||||
host_wavetable->waveInfo.adpcmWave.book = NULL;
|
||||
}
|
||||
} else if (host_wavetable->type == AL_RAW16_WAVE) {
|
||||
if (n64_wavetable->waveInfo.rawWave.loop) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.rawWave.loop);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.rawWave.loop, convertAudioRawLoop);
|
||||
} else {
|
||||
host_wavetable->waveInfo.rawWave.loop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioSound(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_sound *n64_sound = (struct n64_sound *) &src[srcpos];
|
||||
ALSound *host_sound = (ALSound *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALSound);
|
||||
|
||||
if (n64_sound->envelope) {
|
||||
srcpos = PD_BE32(n64_sound->envelope);
|
||||
AL_NEXT_ITEM(host_sound->envelope, convertAudioEnvelope);
|
||||
} else {
|
||||
host_sound->envelope = NULL;
|
||||
}
|
||||
|
||||
if (n64_sound->keyMap) {
|
||||
srcpos = PD_BE32(n64_sound->keyMap);
|
||||
AL_NEXT_ITEM(host_sound->keyMap, convertAudioKeyMap);
|
||||
} else {
|
||||
host_sound->keyMap = NULL;
|
||||
}
|
||||
|
||||
if (n64_sound->wavetable) {
|
||||
srcpos = PD_BE32(n64_sound->wavetable);
|
||||
AL_NEXT_ITEM(host_sound->wavetable, convertAudioWaveTable);
|
||||
} else {
|
||||
host_sound->wavetable = NULL;
|
||||
}
|
||||
|
||||
host_sound->samplePan = n64_sound->samplePan;
|
||||
host_sound->sampleVolume = n64_sound->sampleVolume;
|
||||
host_sound->flags = n64_sound->flags;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioInstrument(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_instrument *n64_instrument = (struct n64_instrument *) &src[srcpos];
|
||||
ALInstrument *host_instrument = (ALInstrument *) &dst[dstpos];
|
||||
const s16 soundCount = PD_BE16(n64_instrument->soundCount);
|
||||
|
||||
host_instrument->volume = n64_instrument->volume;
|
||||
host_instrument->pan = n64_instrument->pan;
|
||||
host_instrument->priority = n64_instrument->priority;
|
||||
host_instrument->flags = n64_instrument->flags;
|
||||
host_instrument->tremType = n64_instrument->tremType;
|
||||
host_instrument->tremRate = n64_instrument->tremRate;
|
||||
host_instrument->tremDepth = n64_instrument->tremDepth;
|
||||
host_instrument->tremDelay = n64_instrument->tremDelay;
|
||||
host_instrument->vibType = n64_instrument->vibType;
|
||||
host_instrument->vibRate = n64_instrument->vibRate;
|
||||
host_instrument->vibDepth = n64_instrument->vibDepth;
|
||||
host_instrument->vibDelay = n64_instrument->vibDelay;
|
||||
host_instrument->bendRange = PD_BE16(n64_instrument->bendRange);
|
||||
host_instrument->soundCount = (soundCount);
|
||||
|
||||
dstpos = dstpos + sizeof(ALInstrument) + sizeof(uintptr_t) * (soundCount - 1);
|
||||
|
||||
for (int i = 0; i < soundCount; i++) {
|
||||
srcpos = PD_BE32(n64_instrument->soundArray[i]);
|
||||
AL_NEXT_ITEM(host_instrument->soundArray[i], convertAudioSound);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioBank(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_bank *n64_bank = (struct n64_bank *) &src[srcpos];
|
||||
ALBank *host_bank = (ALBank *) &dst[dstpos];
|
||||
const s16 instCount = PD_BE16(n64_bank->instCount);
|
||||
|
||||
host_bank->instCount = (instCount);
|
||||
host_bank->flags = n64_bank->flags;
|
||||
host_bank->pad = n64_bank->pad;
|
||||
host_bank->sampleRate = PD_BE32(n64_bank->sampleRate);
|
||||
|
||||
dstpos = dstpos + sizeof(ALBank) + sizeof(uintptr_t) * (instCount - 1);
|
||||
|
||||
if (n64_bank->percussion) {
|
||||
srcpos = PD_BE32(n64_bank->percussion);
|
||||
AL_NEXT_ITEM(host_bank->percussion, convertAudioInstrument);
|
||||
} else {
|
||||
host_bank->percussion = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < instCount; i++) {
|
||||
srcpos = PD_BE32(n64_bank->instArray[i]);
|
||||
AL_NEXT_ITEM(host_bank->instArray[i], convertAudioInstrument);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioBankFile(u8 *dst, u8 *src)
|
||||
{
|
||||
struct n64_bankfile *n64_bankfile = (struct n64_bankfile *)src;
|
||||
ALBankFile *host_bankfile = (ALBankFile *)dst;
|
||||
const s16 bankCount = PD_BE16(n64_bankfile->bankCount);
|
||||
|
||||
host_bankfile->revision = PD_BE16(n64_bankfile->revision);
|
||||
host_bankfile->bankCount = (bankCount);
|
||||
|
||||
u32 dstpos = sizeof(ALBankFile) + sizeof(uintptr_t) * (bankCount - 1);
|
||||
|
||||
for (int i = 0; i < bankCount; i++) {
|
||||
host_bankfile->bankArray[i] = (void *)(uintptr_t)(dstpos);
|
||||
u32 srcpos = PD_BE32(n64_bankfile->bankArray[i]);
|
||||
dstpos = convertAudioBank(dst, dstpos, src, srcpos);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
u8 *preprocessALBankFile(u8 *src, u32 size, u32 *outSize)
|
||||
{
|
||||
ptrReset();
|
||||
|
||||
const u32 dstlen = size * 3; // this should overshoot any possible bank size, but * 2 also works for vanilla banks
|
||||
u8 *dst = sysMemZeroAlloc(dstlen);
|
||||
|
||||
u32 reallen = convertAudioBankFile(dst, src);
|
||||
if (reallen > dstlen || ALIGN16(reallen) > dstlen) {
|
||||
sysFatalError("overflow when trying to preprocess an ALBankFile, size %u dstlen %u reallen %u", size, dstlen, reallen);
|
||||
}
|
||||
|
||||
reallen = ALIGN16(reallen);
|
||||
|
||||
if (reallen < dstlen) {
|
||||
dst = sysMemRealloc(dst, reallen);
|
||||
}
|
||||
|
||||
*outSize = reallen;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize)
|
||||
{
|
||||
ALCMidiHdr *hdr = (ALCMidiHdr *)data;
|
||||
PD_SWAP_VAL(hdr->division);
|
||||
for (s32 i = 0; i < ARRAYCOUNT(hdr->trackOffset); ++i) {
|
||||
PD_SWAP_VAL(hdr->trackOffset[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessSequences(u8* data, u32 size, u32 *outSize)
|
||||
{
|
||||
struct seqtable *seq = (struct seqtable *)data;
|
||||
PD_SWAP_VAL(seq->count);
|
||||
|
||||
for (s16 i = 0; i < seq->count; ++i) {
|
||||
PD_SWAP_VAL(seq->entries[i].binlen);
|
||||
PD_SWAP_VAL(seq->entries[i].ziplen);
|
||||
PD_SWAP_VAL(seq->entries[i].romaddr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Loaded 100 of 373 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user