forked from Ports/perfect_dark
Compare commits
802
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
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 | ||
|
|
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,68 @@
|
||||
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
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Build pd.exe
|
||||
run: make -f Makefile.port -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/ntsc-final-port/pd.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@v3
|
||||
with:
|
||||
name: pd-i686-windows
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-i686-linux:
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Build pd.exe
|
||||
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/ntsc-final-port/pd.exe bin/pd
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pd-i686-linux
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
*.o
|
||||
*.pyc
|
||||
*.dll
|
||||
*.exe
|
||||
pd.*.z64
|
||||
build
|
||||
extracted
|
||||
@@ -19,3 +21,4 @@ src/assets/*/sequences/*.seq
|
||||
src/assets/*/textures/*.bin
|
||||
src/generated
|
||||
tools/mkrom/mkrom
|
||||
/.vs
|
||||
@@ -169,7 +169,8 @@ DEFINES := \
|
||||
MATCHING=$(MATCHING) \
|
||||
PAL=$(PAL) \
|
||||
PIRACYCHECKS=$(PIRACYCHECKS) \
|
||||
ROM_SIZE=$(ROM_SIZE)
|
||||
ROM_SIZE=$(ROM_SIZE) \
|
||||
PLATFORM_N64=1
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFINES := $(DEFINES) DEBUG=1
|
||||
@@ -296,6 +297,7 @@ INCLUDES = \
|
||||
-I include \
|
||||
-I include/PR \
|
||||
-I src/include \
|
||||
-I src/include/lib/libc \
|
||||
-I src/generated/$(ROMID) \
|
||||
-I src/lib/ultra/audio \
|
||||
|
||||
@@ -461,7 +463,9 @@ else ifeq ($(COMPILER), gcc)
|
||||
|
||||
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
|
||||
|
||||
CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) \
|
||||
C_DEFINES += -DAVOID_UB
|
||||
|
||||
CFLAGS := $(C_DEFINES) $(INCLUDES) \
|
||||
-EB \
|
||||
-march=vr4300 \
|
||||
-mabi=32 \
|
||||
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
# Options.
|
||||
|
||||
# HOST_PLATFORM - Which platform we're building on.
|
||||
#
|
||||
# Determined automatically if not specified on command line.
|
||||
#
|
||||
# Supported values:
|
||||
# * i686-windows
|
||||
# * i686-linux
|
||||
|
||||
HOST_PLATFORM ?=
|
||||
|
||||
# TARGET_PLATFORM - Which platform to build for.
|
||||
#
|
||||
# Determined from HOST_PLATFORM if not specified on command line.
|
||||
#
|
||||
# Supported values:
|
||||
# * i686-windows
|
||||
# * i686-linux
|
||||
|
||||
TARGET_PLATFORM ?=
|
||||
|
||||
# ROMID - The ROM version to use.
|
||||
#
|
||||
# Can be set in your environment using
|
||||
# $ export ROMID=...
|
||||
#
|
||||
# Supported values:
|
||||
# * ntsc-final
|
||||
# * pal-final
|
||||
# * jpn-final
|
||||
|
||||
ROMID ?= ntsc-final
|
||||
|
||||
# GCC_OPT_LVL - the optimisation level if building with gcc.
|
||||
#
|
||||
# Supported values: -O0, -O1, -O2, -O3, -Os, -Og
|
||||
|
||||
GCC_OPT_LVL = -Og
|
||||
|
||||
# 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
|
||||
|
||||
################################################################################
|
||||
|
||||
# Detect host platform if not specified.
|
||||
ifeq ($(HOST_PLATFORM),)
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# assume msys for now
|
||||
UNAME_OS := $(shell uname -s)
|
||||
ifneq (,$(findstring MINGW64,$(UNAME_OS)))
|
||||
HOST_PLATFORM := x86_64-windows
|
||||
else
|
||||
HOST_PLATFORM := i686-windows
|
||||
endif
|
||||
else # TODO
|
||||
UNAME_ARCH := $(shell uname -m)
|
||||
UNAME_OS := $(shell uname -s)
|
||||
UNAME_OS := $(shell echo $(UNAME_OS) | tr A-Z a-z)
|
||||
HOST_PLATFORM := $(UNAME_ARCH)-$(UNAME_OS)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Set target platform to host platform if not specified.
|
||||
ifeq ($(TARGET_PLATFORM),)
|
||||
TARGET_PLATFORM := $(HOST_PLATFORM)
|
||||
endif
|
||||
|
||||
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
|
||||
$(info Host platform: $(HOST_PLATFORM))
|
||||
$(info Target platform: $(TARGET_PLATFORM))
|
||||
endif
|
||||
|
||||
# Set whether the target arch is 64- or 32-bit.
|
||||
ifneq (,$(findstring 64,$(TARGET_PLATFORM))$(findstring armv8,$(TARGET_PLATFORM)))
|
||||
# TODO: we're not 64-bit compatible yet, error out if building the actual game
|
||||
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
|
||||
$(error 64-bit target platforms are not supported yet)
|
||||
endif
|
||||
TARGET_64BIT = 1
|
||||
else # TODO
|
||||
TARGET_64BIT = 0
|
||||
endif
|
||||
|
||||
# Set whether the target is big-endian or little-endian.
|
||||
TARGET_BIG_ENDIAN = 0 # TODO
|
||||
|
||||
# The VERSION constant is used in the source to handle version-specific code.
|
||||
ifeq ($(ROMID),ntsc-final)
|
||||
BIN_NAME = pd.exe
|
||||
VERSION = 2
|
||||
IS_PAL = 0
|
||||
else ifeq ($(ROMID),pal-final)
|
||||
BIN_NAME = pd.pal.exe
|
||||
VERSION = 4
|
||||
IS_PAL = 1
|
||||
else ifeq ($(ROMID),jpn-final)
|
||||
BIN_NAME = pd.jpn.exe
|
||||
VERSION = 5
|
||||
IS_PAL = 0
|
||||
else
|
||||
$(error ROM version $(VERSION) is not supported)
|
||||
endif
|
||||
|
||||
VERSION_HASH := $(shell git rev-parse --short HEAD)
|
||||
VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
VERSION_TARGET := $(TARGET_PLATFORM)
|
||||
VERSION_ROMID := $(ROMID)
|
||||
|
||||
ifeq ($(VERSION_BRANCH),)
|
||||
VERSION_BRANCH := port-custom
|
||||
endif
|
||||
ifeq ($(VERSION_BRANCH),HEAD)
|
||||
VERSION_BRANCH := port-custom
|
||||
endif
|
||||
|
||||
DEFINES := \
|
||||
VERSION=$(VERSION) \
|
||||
VERSION_HASH=\"$(VERSION_HASH)\" \
|
||||
VERSION_TARGET=\"$(VERSION_TARGET)\" \
|
||||
VERSION_ROMID=\"$(VERSION_ROMID)\" \
|
||||
VERSION_BRANCH=\"$(VERSION_BRANCH)\" \
|
||||
MATCHING=0 \
|
||||
PAL=$(IS_PAL) \
|
||||
PIRACYCHECKS=0 \
|
||||
ROM_SIZE=$(ROM_SIZE) \
|
||||
_LANGUAGE_C=1
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFINES := $(DEFINES) DEBUG=1
|
||||
endif
|
||||
|
||||
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
|
||||
|
||||
A_DIR := src/assets/$(ROMID)
|
||||
B_DIR := build/$(ROMID)-port
|
||||
G_DIR := src/generated/$(ROMID)
|
||||
|
||||
ifneq (,$(findstring windows,$(TARGET_PLATFORM)))
|
||||
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
|
||||
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -lws2_32 -lwinmm -ldbghelp
|
||||
# on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs
|
||||
TOOLCHAIN ?= i686-w64-mingw32-
|
||||
# on GCC link libstdc++ statically
|
||||
ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX)))
|
||||
TARGET_LDFLAGS += -static-libstdc++
|
||||
else
|
||||
TARGET_LDFLAGS += -lstdc++
|
||||
endif
|
||||
else # assume *nix
|
||||
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
|
||||
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl
|
||||
ifneq (,$(findstring arm,$(TARGET_PLATFORM))$(findstring aarch,$(TARGET_PLATFORM)))
|
||||
# linux on arm or aarch64
|
||||
# TODO: detect soft/hardfloat abi
|
||||
TOOLCHAIN ?= arm-linux-gnueabihf-
|
||||
endif
|
||||
endif
|
||||
|
||||
# On x86_64 gcc add -m32 to CFLAGS if building a 32-bit executable.
|
||||
ifneq (,$(findstring x86_64,$(HOST_PLATFORM))$(findstring x86_64,$(TOOLCHAIN)))
|
||||
ifneq (1,$(TARGET_64BIT))
|
||||
TARGET_CFLAGS += -m32
|
||||
endif
|
||||
endif
|
||||
|
||||
# These are still used in the port, but only to generate headers.
|
||||
JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
|
||||
JSON_FILES += $(shell find $(A_DIR) -path '*/pads/*.json')
|
||||
JSON_FILES += $(shell find $(A_DIR) -path '*/tiles/*.json')
|
||||
JSON_FILES += $(wildcard $(A_DIR)/*.json)
|
||||
|
||||
JSON_HEADERS := $(patsubst $(A_DIR)/%.json, $(G_DIR)/%.h, $(JSON_FILES))
|
||||
|
||||
C_FILES := $(shell find src/game port -name '*.c')
|
||||
C_FILES := $(C_FILES) \
|
||||
$(wildcard src/lib/mp3/*.c) \
|
||||
$(wildcard src/lib/naudio/*.c) \
|
||||
$(wildcard src/lib/ultra/audio/*.c) \
|
||||
$(wildcard src/lib/ultra/gu/*.c) \
|
||||
src/lib/ultra/io/vimodentsclan1.c \
|
||||
src/lib/ultra/io/vimodepallan1.c \
|
||||
src/lib/ultra/io/vimodempallan1.c \
|
||||
src/lib/ultra/io/vitbl.c \
|
||||
$(wildcard src/lib/a*.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 \
|
||||
$(wildcard src/lib/lib_*.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
|
||||
|
||||
CXX_FILES :=$(shell find port -name '*.cpp')
|
||||
|
||||
C_O_FILES := $(patsubst %.c, $(B_DIR)/%.o, $(C_FILES))
|
||||
CXX_O_FILES := $(patsubst %.cpp, $(B_DIR)/%.o, $(CXX_FILES))
|
||||
|
||||
O_FILES := $(C_O_FILES) $(CXX_O_FILES)
|
||||
|
||||
INCLUDES = \
|
||||
-I include \
|
||||
-I include/PR \
|
||||
-I src/include \
|
||||
-I src/generated/$(ROMID) \
|
||||
-I src/lib/ultra/audio \
|
||||
-I port/include
|
||||
|
||||
TOOLCHAIN ?=
|
||||
CC ?= $(TOOLCHAIN)gcc
|
||||
CXX ?= $(TOOLCHAIN)g++
|
||||
ifneq (,$(CXX_O_FILES))
|
||||
LD := $(CXX)
|
||||
else
|
||||
LD := $(CC)
|
||||
endif
|
||||
|
||||
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
|
||||
|
||||
COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \
|
||||
-fno-inline-functions \
|
||||
-fno-strict-aliasing \
|
||||
-funsigned-char \
|
||||
-fwrapv \
|
||||
-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 \
|
||||
-Wno-format-truncation
|
||||
|
||||
CFLAGS := -std=c11 $(COMMON_CFLAGS) -Wno-pointer-sign
|
||||
CXXFLAGS := -std=c++20 $(COMMON_CFLAGS) -Wno-unused-function
|
||||
LDFLAGS := $(TARGET_LDFLAGS)
|
||||
|
||||
# Make ROMID available as an environment variable to all tooling.
|
||||
# (We use this a lot)
|
||||
export ROMID
|
||||
|
||||
BIN := $(B_DIR)/$(BIN_NAME)
|
||||
|
||||
default: $(BIN)
|
||||
|
||||
################################################################################
|
||||
# Asset Manager header generation
|
||||
|
||||
# Anims
|
||||
$(G_DIR)/animations.h: $(A_DIR)/animations.json
|
||||
tools/assetmgr/mkanims --headers-only
|
||||
|
||||
# Lang
|
||||
$(G_DIR)/lang/%.h: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< en --headers-only
|
||||
|
||||
# Pads
|
||||
$(G_DIR)/pads/%.h: $(A_DIR)/pads/%.json
|
||||
tools/assetmgr/mkpads $< --headers-only
|
||||
|
||||
# Sequences
|
||||
$(G_DIR)/sequences.h: $(A_DIR)/sequences.json
|
||||
tools/assetmgr/mksequences --headers-only
|
||||
|
||||
# Textures
|
||||
$(G_DIR)/textures.h: $(A_DIR)/textures.json
|
||||
tools/assetmgr/mktextures --headers-only
|
||||
|
||||
# Tiles
|
||||
$(G_DIR)/tiles/%.h: $(A_DIR)/tiles/%.json
|
||||
tools/assetmgr/mktiles $< --headers-only
|
||||
|
||||
################################################################################
|
||||
# Generic compilation rules
|
||||
|
||||
$(BIN): $(O_FILES)
|
||||
$(LD) $(COMMON_CFLAGS) $(OPT_LVL) -o $(BIN) $^ $(LDFLAGS)
|
||||
ifneq ($(CV2PDB),)
|
||||
$(CV2PDB) $(BIN)
|
||||
endif
|
||||
|
||||
$(B_DIR)/%.o: %.c $(JSON_HEADERS)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
|
||||
$(B_DIR)/%.o: %.cpp $(JSON_HEADERS)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) -c $(CXXFLAGS) $(OPT_LVL) -o $@ $<
|
||||
|
||||
################################################################################
|
||||
# Clean rules
|
||||
|
||||
clean:
|
||||
rm -rf build/$(ROMID)-port
|
||||
|
||||
allclean:
|
||||
rm -rf build/*
|
||||
rm -rf src/generated
|
||||
|
||||
codeclean:
|
||||
find $(B_DIR)/ -name '*.o' -delete
|
||||
@@ -1,62 +1,144 @@
|
||||
# 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/fgsfdsfgs/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):
|
||||
* set `Game.TickRateDivisor` to `0` in `pd.ini` to activate;
|
||||
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
|
||||
|
||||
## Installation Requirements
|
||||
Currently only 32-bit platforms are supported, namely x86 Windows and Linux.
|
||||
Note that 32-bit binaries will still work on 64-bit versions of those platforms,
|
||||
though you might have to install some additional libraries.
|
||||
|
||||
For Arch Linux:
|
||||
## Download
|
||||
|
||||
* Install these packages: `binutils fakeroot gcc make python vim`
|
||||
* Install from AUR: `armips`
|
||||
* Install from AUR: a MIPS binutils package of your choice (eg. `mips-elf-binutils`)
|
||||
* Install from AUR: a MIPS gcc package of your choice (eg. `mips-elf-gcc`)
|
||||
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) of the netplay branch for supported platforms:
|
||||
* [i686-windows (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip)
|
||||
* [i686-linux (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip)
|
||||
|
||||
For Debian and Ubuntu:
|
||||
If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
|
||||
|
||||
* Install these packages: `binutils-mips-linux-gnu build-essential gcc-mips-linux-gnu libc6-dev-i386 libcapstone-dev make`
|
||||
* Compile and install `armips`
|
||||
## Running
|
||||
|
||||
## ROM Versions
|
||||
You must already have a Perfect Dark ROM to run the game, as specified above.
|
||||
|
||||
Perfect Dark has six known versions:
|
||||
1. Create a directory named `data` next to `pd.exe`.
|
||||
2. Put your Perfect Dark ROM named `pd.ntsc-final.z64` into it.
|
||||
3. Run `pd.exe`.
|
||||
|
||||
| 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 |
|
||||
Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).
|
||||
|
||||
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`.
|
||||
A GPU supporting OpenGL 3.0 or above is required to run the port.
|
||||
|
||||
## Extracting the base ROM
|
||||
## Controls
|
||||
|
||||
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`.
|
||||
1964GEPD-style and Xbox-style bindings are implemented.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
Support for one controller, two-stick configurations are enabled for 1.2.
|
||||
|
||||
## Compiling
|
||||
Note that the mouse only controls player 1.
|
||||
|
||||
* 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`.
|
||||
Controls can be rebound in `pd.ini`. Default control scheme is as follows:
|
||||
|
||||
## How do I know the built files are matching?
|
||||
| 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` |
|
||||
|
||||
Run `make` followed by `make test`. If `make test` produces no output then the compiled project is matching.
|
||||
## Building
|
||||
|
||||
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`.
|
||||
### Windows
|
||||
|
||||
1. Install [MSYS2](https://www.msys2.org).
|
||||
2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt)
|
||||
3. Install dependencies:
|
||||
`pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git`
|
||||
4. Get the source code:
|
||||
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Run `make -f Makefile.port`.
|
||||
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
6. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
|
||||
7. 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+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
|
||||
* On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed.
|
||||
2. Get the source code:
|
||||
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
3. Run the following command:
|
||||
* On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux```
|
||||
* On a 32-bit system: ```make -f Makefile.port```
|
||||
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
4. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
|
||||
|
||||
Currently only `i686-linux` and `i686-windows` are supported, using `gcc -m32` and `i686-w64-mingw32-gcc` as compilers, respectively.
|
||||
Alternate compilers can be specified by passing `TOOLCHAIN=i686-whatever-` as a command line argument.
|
||||
|
||||
You can build an executable with PAL or JPN ROM support by adding `ROMID=pal-final` or `ROMID=jpn-final` to the `make` command.
|
||||
You will need to provide a `jpn-final` or `pal-final` ROM to run those, named `pd.jpn-final.z64` or `pd.pal-final.z64`.
|
||||
|
||||
It might be possible to build a 32-bit ARM executable, but this has not been tested.
|
||||
|
||||
## Credits
|
||||
|
||||
* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
|
||||
* 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;
|
||||
* everyone who has submitted pull requests and issues to this repository and tested the port;
|
||||
* probably more I'm forgetting.
|
||||
@@ -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 can't throw laptop guns.
|
||||
* 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.
|
||||
@@ -60,6 +60,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 +70,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_ */
|
||||
|
||||
+97
-1
@@ -1029,16 +1029,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
|
||||
*/
|
||||
#ifdef GBI_FLOATS
|
||||
// 4x4 float matrix
|
||||
typedef float Mtx_t[4][4];
|
||||
#else
|
||||
typedef long Mtx_t[4][4];
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
Mtx_t m;
|
||||
@@ -1291,22 +1307,35 @@ typedef union {
|
||||
* Graphics DMA Packet
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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 +1350,22 @@ 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;
|
||||
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;
|
||||
#endif
|
||||
} Gtri4;
|
||||
|
||||
typedef struct {
|
||||
@@ -1356,12 +1401,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 {
|
||||
@@ -1491,6 +1545,7 @@ typedef struct {
|
||||
// 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 +1557,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;
|
||||
|
||||
/*
|
||||
@@ -1525,11 +1602,12 @@ typedef union {
|
||||
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 +1617,19 @@ typedef union {
|
||||
Gloadtile loadtile; /* use for loadblock also, th is dxt */
|
||||
Gsettilesize settilesize;
|
||||
Gloadtlut loadtlut;
|
||||
#endif
|
||||
GunkC0 unkc0;
|
||||
long long int force_structure_alignment;
|
||||
} Gfx;
|
||||
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
#define GFX_W0_BYTE(i) (i)
|
||||
#define GFX_W1_BYTE(i) (4 + (i))
|
||||
#else
|
||||
#define GFX_W0_BYTE(i) (3 - (i))
|
||||
#define GFX_W1_BYTE(i) (7 - (i))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros to assemble the graphics display list
|
||||
*/
|
||||
@@ -1847,6 +1934,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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -71,7 +71,7 @@ typedef struct {
|
||||
s32 maxAuxBusses;
|
||||
s32 outputRate;
|
||||
s32 maxOutSamples;
|
||||
s32 sv_dramout;
|
||||
uintptr_t sv_dramout;
|
||||
s32 sv_first;
|
||||
} N_ALSynth;
|
||||
|
||||
@@ -208,7 +208,7 @@ struct fx {
|
||||
s16 unk00;
|
||||
s16 unk02;
|
||||
s32 unk04;
|
||||
s16 unk08[8];
|
||||
s16 unk08[16];
|
||||
};
|
||||
|
||||
typedef struct N_ALVoiceState_s {
|
||||
|
||||
+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) */
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include "os_pfs.h"
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LANGUAGE_C_PLUS_PLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -80,13 +84,15 @@ 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);
|
||||
extern void bcopy(const void *, void *, size_t);
|
||||
extern int bcmp(const void *, const void *, size_t);
|
||||
extern void bzero(void *, size_t);
|
||||
|
||||
/* Printf */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
extern int sprintf(char *s, const char *fmt, ...);
|
||||
#endif
|
||||
extern void osSyncPrintf(const char *fmt, ...);
|
||||
|
||||
|
||||
|
||||
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,58 @@
|
||||
#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_maximum_frame_latency(int latency);
|
||||
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);
|
||||
void gfx_get_pixel_depth_prepare(float x, float y);
|
||||
uint16_t gfx_get_pixel_depth(float x, float y);
|
||||
|
||||
#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]);
|
||||
uint32_t (*new_texture)(void);
|
||||
void (*select_texture)(int tile, uint32_t texture_id);
|
||||
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_test_and_mask)(bool depth_test, bool z_upd);
|
||||
void (*set_depth_range)(float znear, float zfar);
|
||||
void (*set_zmode_decal)(bool zmode_decal);
|
||||
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)(void);
|
||||
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,342 @@
|
||||
#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 void set_fullscreen(bool on, bool call_callback) {
|
||||
if (fullscreen_state == on) {
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
if (maximized_state == on) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
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->fullscreen_is_exclusive) {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
|
||||
Uint32 flags = SDL_WINDOW_SHOWN | 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
|
||||
|
||||
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
|
||||
if (!wnd) {
|
||||
sysFatalError("Could not open SDL window:\n%s", SDL_GetError());
|
||||
}
|
||||
|
||||
// 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, 2, SDL_GL_CONTEXT_PROFILE_CORE },
|
||||
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY },
|
||||
};
|
||||
|
||||
u32 glcore = false;
|
||||
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 :
|
||||
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;
|
||||
for (u32 i = verstart; i < verend; ++i) {
|
||||
vmaj = glver[i][0];
|
||||
vmin = glver[i][1];
|
||||
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, glver[i][2]);
|
||||
ctx = SDL_GL_CreateContext(wnd);
|
||||
if (!ctx) {
|
||||
sysLogPrintf(LOG_WARNING, "GL: could not create GL%d.%d context: %s", vmaj, vmin, SDL_GetError());
|
||||
} else {
|
||||
glcore = (glver[i][2] == SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
sysFatalError("Could not create an OpenGL context of any supported version.\nSDL error: %s", SDL_GetError());
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "GL: created GL%d.%d%s context", vmaj, vmin, glcore ? "core" : "");
|
||||
}
|
||||
|
||||
SDL_GL_MakeCurrent(wnd, ctx);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
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 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);
|
||||
} 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 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 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;
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_init,
|
||||
gfx_sdl_close,
|
||||
gfx_sdl_set_fullscreen_changed_callback,
|
||||
gfx_sdl_set_fullscreen,
|
||||
gfx_sdl_set_fullscreen_exclusive,
|
||||
gfx_sdl_set_maximize_window,
|
||||
gfx_sdl_get_active_window_refresh_rate,
|
||||
gfx_sdl_set_cursor_visibility,
|
||||
gfx_sdl_get_dimensions,
|
||||
gfx_sdl_handle_events,
|
||||
gfx_sdl_start_frame,
|
||||
gfx_sdl_swap_buffers_begin,
|
||||
gfx_sdl_swap_buffers_end,
|
||||
gfx_sdl_get_time,
|
||||
gfx_sdl_set_target_fps,
|
||||
gfx_sdl_can_disable_vsync,
|
||||
gfx_sdl_get_window_handle,
|
||||
gfx_sdl_set_window_title,
|
||||
gfx_sdl_set_swap_interval,
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#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 allow_hidpi;
|
||||
};
|
||||
|
||||
struct GfxWindowManagerAPI {
|
||||
void (*init)(const struct GfxWindowInitSettings *settings);
|
||||
void (*close)(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_maximize)(bool enable);
|
||||
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
|
||||
void (*set_cursor_visibility)(bool visible);
|
||||
void (*get_dimensions)(uint32_t* width, uint32_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
|
||||
void (*set_target_fps)(int fps);
|
||||
bool (*can_disable_vsync)(void);
|
||||
void *(*get_window_handle)(void);
|
||||
void (*set_window_title)(const char *);
|
||||
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,14 @@
|
||||
#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);
|
||||
|
||||
#endif
|
||||
Vendored
+5098
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,26 @@
|
||||
#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 fsFileClose(FILE *f);
|
||||
|
||||
const char *fsGetModDir(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
#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_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_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 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_0010,
|
||||
CK_0020,
|
||||
CK_0040,
|
||||
CK_0080,
|
||||
CK_0100,
|
||||
CK_0200,
|
||||
CK_0400,
|
||||
CK_0800,
|
||||
CK_1000,
|
||||
CK_2000,
|
||||
CK_4000,
|
||||
CK_8000,
|
||||
CK_TOTAL_COUNT
|
||||
};
|
||||
|
||||
// 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 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// returns mouse position in native viewport coordinates (ie, 320x240 most of the time)
|
||||
void 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);
|
||||
|
||||
void inputStartTextInput(void);
|
||||
void inputStopTextInput(void);
|
||||
|
||||
void inputClearLastTextChar(void);
|
||||
char inputGetLastTextChar(void);
|
||||
|
||||
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol);
|
||||
|
||||
void inputClearClipboard(void);
|
||||
const char *inputGetClipboard(void);
|
||||
|
||||
// get/set Input.MouseDefaultLocked
|
||||
s32 inputGetMouseDefaultLocked(void);
|
||||
void inputSetMouseDefaultLocked(s32 defaultLocked);
|
||||
|
||||
#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,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,34 @@
|
||||
#ifndef _IN_PREPROCESS_H
|
||||
#define _IN_PREPROCESS_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
typedef void (*preprocessfunc)(u8 *data, u32 size);
|
||||
|
||||
void preprocessAnimations(u8 *data, u32 size);
|
||||
void preprocessMpConfigs(u8 *data, u32 size);
|
||||
void preprocessFont(u8 *data, u32 size);
|
||||
void preprocessJpnFont(u8 *data, u32 size);
|
||||
void preprocessALBankFile(u8 *data, u32 size);
|
||||
void preprocessALCMidiHdr(u8 *data, u32 size);
|
||||
void preprocessSequences(u8 *data, u32 size);
|
||||
void preprocessFiringRange(u8 *data, u32 size);
|
||||
void preprocessTexturesList(u8 *data, u32 size);
|
||||
|
||||
void preprocessBgSection1Header(u8 *data, u32 size);
|
||||
void preprocessBgSection1(u8 *data, u32 size);
|
||||
void preprocessBgSection2Header(u8 *data, u32 size);
|
||||
void preprocessBgSection2(u8 *data, u32 size);
|
||||
void preprocessBgSection3Header(u8 *data, u32 size);
|
||||
void preprocessBgSection3(u8 *data, u32 size);
|
||||
void preprocessBgRoom(u8 *data, u32 ofs);
|
||||
void preprocessBgLights(u8 *data, u32 ofs);
|
||||
|
||||
void preprocessLangFile(u8 *data, u32 size);
|
||||
void preprocessPadsFile(u8 *data, u32 size);
|
||||
void preprocessTilesFile(u8 *data, u32 size);
|
||||
void preprocessSetupFile(u8 *data, u32 size);
|
||||
void preprocessModelFile(u8 *data, u32 size);
|
||||
void preprocessGunFile(u8 *data, u32 size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#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);
|
||||
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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#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 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,53 @@
|
||||
#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
|
||||
|
||||
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 videoGetMaximizeWindow(void);
|
||||
void videoSetMaximizeWindow(s32 fs);
|
||||
u32 videoGetTextureFilter(void);
|
||||
s32 videoGetTextureFilter2D(void);
|
||||
s32 videoGetDetailTextures(void);
|
||||
|
||||
void videoSetWindowOffset(s32 x, s32 y);
|
||||
void videoSetFullscreen(s32 fs);
|
||||
void videoSetTextureFilter(u32 filter);
|
||||
void videoSetTextureFilter2D(s32 filter);
|
||||
void videoSetDetailTextures(s32 detail);
|
||||
void videoCapFramerate(s32 limit);
|
||||
|
||||
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);
|
||||
|
||||
#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,295 @@
|
||||
#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 256
|
||||
|
||||
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 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++];
|
||||
strncpy(cfg->key, key, CONFIG_MAX_KEYNAME);
|
||||
const char *delim = strrchr(cfg->key, '.');
|
||||
cfg->seclen = delim ? (delim - cfg->key) : 0;
|
||||
return cfg;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
fsFileClose(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);
|
||||
}
|
||||
}
|
||||
|
||||
fsFileClose(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void configInit(void)
|
||||
{
|
||||
if (fsFileSize(CONFIG_PATH) > 0) {
|
||||
configLoad(CONFIG_PATH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
#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;
|
||||
if (conOpen) {
|
||||
inputStartTextInput();
|
||||
} else {
|
||||
inputStopTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
conButton = button;
|
||||
|
||||
if (conOpen) {
|
||||
if (inputTextHandler(conInput, CON_COLS, &conInputCol)) {
|
||||
if (g_NetMode) {
|
||||
netChat(NULL, conInput);
|
||||
}
|
||||
conInput[0] = '\0';
|
||||
conInputCol = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
#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"
|
||||
|
||||
#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 {
|
||||
#ifdef PLATFORM_LINUX
|
||||
// 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 fsFileClose(FILE *f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
+1398
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,488 @@
|
||||
#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 "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);
|
||||
fsFileClose(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);
|
||||
fsFileClose(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, size_t 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 HAVE_BZERO
|
||||
void bzero(void *ptr, size_t size)
|
||||
{
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BCOPY
|
||||
void bcopy(const void *src, void *dst, size_t n)
|
||||
{
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BCMP
|
||||
s32 bcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
#endif
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
#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);
|
||||
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();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+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,386 @@
|
||||
#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 "video.h"
|
||||
#include "input.h"
|
||||
#include "config.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);
|
||||
|
||||
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) {
|
||||
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,
|
||||
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) < 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;
|
||||
}
|
||||
|
||||
struct menuitem g_NetJoinMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Address: \n",
|
||||
(uintptr_t)&menutextJoinAddress,
|
||||
menuhandlerJoinAddress,
|
||||
},
|
||||
{
|
||||
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 | MENUDIALOGFLAG_IGNOREBACK,
|
||||
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,
|
||||
NULL,
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,651 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <PR/ultrasched.h>
|
||||
#include "lib/sched.h"
|
||||
#include "lib/vars.h"
|
||||
#include "constants.h"
|
||||
#include "game/camdraw.h"
|
||||
#include "game/cheats.h"
|
||||
#include "game/debug.h"
|
||||
#include "game/file.h"
|
||||
#include "game/lang.h"
|
||||
#include "game/race.h"
|
||||
#include "game/body.h"
|
||||
#include "game/stubs/game_000840.h"
|
||||
#include "game/stubs/game_000850.h"
|
||||
#include "game/stubs/game_000860.h"
|
||||
#include "game/stubs/game_000870.h"
|
||||
#include "game/smoke.h"
|
||||
#include "game/stubs/game_0008e0.h"
|
||||
#include "game/stubs/game_0008f0.h"
|
||||
#include "game/stubs/game_000900.h"
|
||||
#include "game/stubs/game_000910.h"
|
||||
#include "game/tex.h"
|
||||
#include "game/stubs/game_00b180.h"
|
||||
#include "game/stubs/game_00b200.h"
|
||||
#include "game/challenge.h"
|
||||
#include "game/title.h"
|
||||
#include "game/pdmode.h"
|
||||
#include "game/objectives.h"
|
||||
#include "game/endscreen.h"
|
||||
#include "game/playermgr.h"
|
||||
#include "game/game_1531a0.h"
|
||||
#include "game/gfxmemory.h"
|
||||
#include "game/lang.h"
|
||||
#include "game/lv.h"
|
||||
#include "game/timing.h"
|
||||
#include "game/music.h"
|
||||
#include "game/stubs/game_175f50.h"
|
||||
#include "game/game_175f90.h"
|
||||
#include "game/zbuf.h"
|
||||
#include "game/game_1a78b0.h"
|
||||
#include "game/mplayer/mplayer.h"
|
||||
#include "game/pak.h"
|
||||
#include "game/splat.h"
|
||||
#include "game/utils.h"
|
||||
#include "bss.h"
|
||||
#include "lib/audiomgr.h"
|
||||
#include "lib/args.h"
|
||||
#include "lib/boot.h"
|
||||
#include "lib/vm.h"
|
||||
#include "lib/rzip.h"
|
||||
#include "lib/vi.h"
|
||||
#include "lib/fault.h"
|
||||
#include "lib/crash.h"
|
||||
#include "lib/dma.h"
|
||||
#include "lib/joy.h"
|
||||
#include "lib/main.h"
|
||||
#include "lib/snd.h"
|
||||
#include "lib/memp.h"
|
||||
#include "lib/mema.h"
|
||||
#include "lib/model.h"
|
||||
#include "lib/profile.h"
|
||||
#include "lib/videbug.h"
|
||||
#include "lib/debughud.h"
|
||||
#include "lib/anim.h"
|
||||
#include "lib/rdp.h"
|
||||
#include "lib/lib_34d0.h"
|
||||
#include "lib/lib_2f490.h"
|
||||
#include "lib/rmon.h"
|
||||
#include "lib/rng.h"
|
||||
#include "lib/str.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#include "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();
|
||||
|
||||
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();
|
||||
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, (s32) &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--;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,526 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "lib/rzip.h"
|
||||
#include "romdata.h"
|
||||
#include "fs.h"
|
||||
#include "system.h"
|
||||
#include "preprocess.h"
|
||||
#include "platform.h"
|
||||
|
||||
/**
|
||||
* asset files and ROM segments can be replaced by optional external files,
|
||||
* but asset filenames still have to be either pulled from the ROM or from an
|
||||
* external file, so stuff can't be completely custom
|
||||
*
|
||||
* all data is assumed to be big endian, so it has to be byteswapped
|
||||
* at load time, which is fucking terrible
|
||||
*/
|
||||
|
||||
#define ROMDATA_FILEDIR "files"
|
||||
#define ROMDATA_SEGDIR "segs"
|
||||
|
||||
#define ROMDATA_ROM_NAME "pd." VERSION_ROMID ".z64"
|
||||
#define ROMDATA_ROM_SIZE 33554432
|
||||
|
||||
#if VERSION == VERSION_NTSC_FINAL
|
||||
#define ROMDATA_ROM_TITLE "Perfect Dark"
|
||||
#define ROMDATA_ROM_ID "NPDE"
|
||||
#define ROMDATA_ROM_DESC "NTSC v1.1"
|
||||
#define ROMDATA_FILES_OFS 0x28080
|
||||
#define ROMDATA_DATA_OFS 0x39850
|
||||
#elif VERSION == VERSION_PAL_FINAL
|
||||
#define ROMDATA_ROM_TITLE "Perfect Dark"
|
||||
#define ROMDATA_ROM_ID "NPDP"
|
||||
#define ROMDATA_ROM_DESC "PAL"
|
||||
#define ROMDATA_FILES_OFS 0x28910
|
||||
#define ROMDATA_DATA_OFS 0x39850
|
||||
#elif VERSION == VERSION_JPN_FINAL
|
||||
#define ROMDATA_ROM_TITLE "PERFECT DARK"
|
||||
#define ROMDATA_ROM_ID "NPDJ"
|
||||
#define ROMDATA_ROM_DESC "JPN"
|
||||
#define ROMDATA_FILES_OFS 0x28800
|
||||
#define ROMDATA_DATA_OFS 0x39850
|
||||
#else
|
||||
#error "This ROM version is unsupported."
|
||||
#endif
|
||||
|
||||
#define ROMDATA_MAX_FILES 2048
|
||||
|
||||
u8 *g_RomFile;
|
||||
u32 g_RomFileSize;
|
||||
const char *g_RomName = ROMDATA_ROM_NAME;
|
||||
|
||||
static u8 *romDataSeg;
|
||||
static u32 romDataSegSize;
|
||||
|
||||
enum loadsource {
|
||||
SRC_UNLOADED = 0,
|
||||
SRC_ROM,
|
||||
SRC_EXTERNAL
|
||||
};
|
||||
|
||||
struct romfilepatch {
|
||||
u32 ofs;
|
||||
u32 len;
|
||||
const char *src;
|
||||
const char *dst;
|
||||
};
|
||||
|
||||
struct romfile {
|
||||
u8 **segstart;
|
||||
u8 **segend;
|
||||
const char *name;
|
||||
u8 *data;
|
||||
u32 size;
|
||||
preprocessfunc preprocess;
|
||||
s32 source; // enum loadsource
|
||||
s32 preprocessed;
|
||||
const struct romfilepatch *patches;
|
||||
u32 numpatches;
|
||||
};
|
||||
|
||||
/* patches for individual files; applied on file load, before preprocFuncs, but */
|
||||
/* after unzip; only applied when loading from a ROM file */
|
||||
static const struct romfilepatch filePatches[] = {
|
||||
/* FILE_USETUPLUE: fixes Jon's double "if what" in Infiltration outro */
|
||||
{ 0x92a2, 1, "\x6c", "\x99" },
|
||||
{ 0x92b0, 1, "\x6c", "\x99" },
|
||||
};
|
||||
|
||||
static struct romfile fileSlots[ROMDATA_MAX_FILES] = {
|
||||
[FILE_USETUPLUE] = { .patches = &filePatches[0], .numpatches = 2 },
|
||||
};
|
||||
|
||||
#define ROMSEG_START(n) _ ## n ## SegmentRomStart
|
||||
#define ROMSEG_END(n) _ ## n ## SegmentRomEnd
|
||||
|
||||
/* segment table for ntsc-final */
|
||||
/* size will get calculated automatically if it is 0 */
|
||||
/* if there are replacement files in the data dir, they will be loaded instead */
|
||||
/* offsets are specified for ntsc-final, pal-final and jpn-final in that order */
|
||||
#define ROMSEG_LIST() \
|
||||
ROMSEG_DECL_SEG(fontjpnsingle, 0x194b20, 0x180330, 0x0, 0x0, preprocessJpnFont ) \
|
||||
ROMSEG_DECL_SEG(fontjpnmulti, 0x19fb40, 0x18b340, 0x0, 0x0, preprocessJpnFont ) \
|
||||
ROMSEG_DECL_SEG(animations, 0x1a15c0, 0x18cdc0, 0x190c50, 0x0, preprocessAnimations ) \
|
||||
ROMSEG_DECL_SEG(mpconfigs, 0x7d0a40, 0x7bc240, 0x7c00d0, 0x11e0, preprocessMpConfigs ) \
|
||||
ROMSEG_DECL_SEG(mpstringsE, 0x7d1c20, 0x7bd420, 0x7c12b0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsJ, 0x7d5320, 0x7c0b20, 0x7c49b0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsP, 0x7d8a20, 0x7c4220, 0x7c80b0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsG, 0x7dc120, 0x7c7920, 0x7cb7b0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsF, 0x7df820, 0x7cb020, 0x7ceeb0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsS, 0x7e2f20, 0x7ce720, 0x7d25b0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(mpstringsI, 0x7e6620, 0x7d1e20, 0x7d5cb0, 0x3700, NULL ) \
|
||||
ROMSEG_DECL_SEG(firingrange, 0x7e9d20, 0x7d5520, 0x7d93b0, 0x1550, NULL ) \
|
||||
ROMSEG_DECL_SEG(fonttahoma, 0x7f7860, 0x7e3060, 0x7e6ef0, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(fontnumeric, 0x7f8b20, 0x7e4320, 0x7e81b0, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(fonthandelgothicsm, 0x7f9d30, 0x7e5530, 0x7e93c0, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(fonthandelgothicxs, 0x7fbfb0, 0x7e87b0, 0x7ec640, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(fonthandelgothicmd, 0x7fdd80, 0x7eae20, 0x7eecb0, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(fonthandelgothiclg, 0x8008e0, 0x7eee70, 0x7f2d00, 0x0, preprocessFont ) \
|
||||
ROMSEG_DECL_SEG(sfxctl, 0x80a250, 0x7f87e0, 0x7fc670, 0x2fb80, preprocessALBankFile ) \
|
||||
ROMSEG_DECL_SEG(sfxtbl, 0x839dd0, 0x828360, 0x82c1f0, 0x4c2160, NULL ) \
|
||||
ROMSEG_DECL_SEG(seqctl, 0xcfbf30, 0xcea4c0, 0xcee350, 0xa060, preprocessALBankFile ) \
|
||||
ROMSEG_DECL_SEG(seqtbl, 0xd05f90, 0xcf4520, 0xcf83b0, 0x17c070, NULL ) \
|
||||
ROMSEG_DECL_SEG(sequences, 0xe82000, 0xe70590, 0xe74420, 0x563a0, preprocessSequences ) \
|
||||
ROMSEG_DECL_SEG(texturesdata, 0x1d65f40, 0x1d5ca20, 0x1d61f90, 0x0, NULL ) \
|
||||
ROMSEG_DECL_SEG(textureslist, 0x1ff7ca0, 0x1fee780, 0x1ff68f0, 0x0, preprocessTexturesList ) \
|
||||
ROMSEG_DECL_SEG(copyright, 0x1ffea20, 0x1ff5500, 0x1ffd6b0, 0xb30, NULL ) \
|
||||
ROMSEG_DECL_SEG(fontjpn, 0x0, 0x0, 0x178c40, 0x17920, preprocessJpnFont )
|
||||
|
||||
// declare the vars first
|
||||
|
||||
#undef ROMSEG_DECL_SEG
|
||||
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) u8 *ROMSEG_START(name), *ROMSEG_END(name);
|
||||
ROMSEG_LIST()
|
||||
|
||||
// this is part of the animations seg and as such does not follow the naming convention
|
||||
// these are set in preprocessAnimations
|
||||
u8 *_animationsTableRomStart;
|
||||
u8 *_animationsTableRomEnd;
|
||||
|
||||
// then build the table
|
||||
|
||||
#undef ROMSEG_DECL_SEG
|
||||
|
||||
#if VERSION == VERSION_NTSC_FINAL
|
||||
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_ntsc, size, preproc },
|
||||
#elif VERSION == VERSION_PAL_FINAL
|
||||
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_pal, size, preproc },
|
||||
#elif VERSION == VERSION_JPN_FINAL
|
||||
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_jpn, size, preproc },
|
||||
#endif
|
||||
|
||||
static struct romfile romSegs[] = {
|
||||
ROMSEG_LIST()
|
||||
{ NULL, NULL, NULL, NULL, 0, NULL },
|
||||
};
|
||||
|
||||
/* the game sets g_LoadType to the type of file it expects, */
|
||||
/* so we can hijack that in fileLoad and automatically byteswap the file */
|
||||
static preprocessfunc filePreprocFuncs[] = {
|
||||
/* LOADTYPE_NONE */ NULL,
|
||||
/* LOADTYPE_BG */ NULL, // loaded in parts
|
||||
/* LOADTYPE_TILES */ preprocessTilesFile,
|
||||
/* LOADTYPE_LANG */ preprocessLangFile,
|
||||
/* LOADTYPE_SETUP */ preprocessSetupFile,
|
||||
/* LOADTYPE_PADS */ preprocessPadsFile,
|
||||
/* LOADTYPE_MODEL */ preprocessModelFile,
|
||||
/* LOADTYPE_GUN */ preprocessGunFile,
|
||||
};
|
||||
|
||||
static inline void romdataWrongRomError(const char *fmt, ...)
|
||||
{
|
||||
char reason[1024];
|
||||
reason[0] = '\0';
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(reason, sizeof(reason), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
sysFatalError("Wrong ROM file.\n%s\nEnsure that you have the correct " ROMDATA_ROM_DESC " ROM in z64 format.", reason);
|
||||
}
|
||||
|
||||
static inline void romdataLoadRom(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "ROM file: %s", g_RomName);
|
||||
|
||||
g_RomFile = fsFileLoad(g_RomName, &g_RomFileSize);
|
||||
|
||||
if (!g_RomFile) {
|
||||
sysFatalError("Could not open ROM file %s.\nEnsure that it is in the %s directory.", g_RomName, fsFullPath(""));
|
||||
}
|
||||
|
||||
// zips are not guaranteed to start with PK, but might as well at least try
|
||||
if (g_RomFileSize > 2 && (!memcmp(g_RomFile, "PK", 2) || !memcmp(g_RomFile, "Rar", 3) || !memcmp(g_RomFile, "7z", 2))) {
|
||||
romdataWrongRomError("Your ROM is in an archive file. Please extract it.");
|
||||
}
|
||||
|
||||
if (g_RomFileSize != ROMDATA_ROM_SIZE) {
|
||||
romdataWrongRomError("ROM size does not match: expected: %u, got: %u.", ROMDATA_ROM_SIZE, g_RomFileSize);
|
||||
}
|
||||
|
||||
if (memcmp(g_RomFile + 0x3b, ROMDATA_ROM_ID, 4) || memcmp(g_RomFile + 0x20, ROMDATA_ROM_TITLE, sizeof(ROMDATA_ROM_TITLE) - 1)) {
|
||||
romdataWrongRomError("ROM header does not match.");
|
||||
}
|
||||
|
||||
// inflate the compressed data segment since that's where some useful stuff is
|
||||
|
||||
u8 *zipped = g_RomFile + ROMDATA_DATA_OFS;
|
||||
if (!rzipIs1173(zipped)) {
|
||||
romdataWrongRomError("Data segment is not 1173-compressed.");
|
||||
}
|
||||
|
||||
const u32 dataSegLen = ((u32)zipped[2] << 16) | ((u32)zipped[3] << 8) | (u32)zipped[4];
|
||||
if (dataSegLen < ROMDATA_FILES_OFS) {
|
||||
romdataWrongRomError("Data segment too small (%u), need at least %u.", dataSegLen, ROMDATA_FILES_OFS);
|
||||
}
|
||||
|
||||
u8 *dataSeg = sysMemAlloc(dataSegLen);
|
||||
if (!dataSeg) {
|
||||
sysFatalError("Could not allocate %u bytes for data segment.", dataSegLen);
|
||||
}
|
||||
|
||||
u8 scratch[5 * 1024];
|
||||
if (rzipInflate(zipped, dataSeg, scratch) < 0) {
|
||||
free(dataSeg);
|
||||
sysFatalError("Could not inflate data segment.");
|
||||
}
|
||||
|
||||
romDataSeg = dataSeg;
|
||||
romDataSegSize = dataSegLen;
|
||||
}
|
||||
|
||||
static inline void romdataInitSegment(struct romfile *seg)
|
||||
{
|
||||
if (!seg->data) {
|
||||
// unused in this ROM, skip it
|
||||
sysLogPrintf(LOG_NOTE, "skipping segment %s", seg->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!seg->size) {
|
||||
// size unknown
|
||||
if (seg[1].name) {
|
||||
// use next segment's base to calculate
|
||||
seg->size = seg[1].data - seg->data;
|
||||
} else {
|
||||
// this is the last segment, calculate based on rom size
|
||||
seg->size = (u8 *)g_RomFileSize - seg->data;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have an external replacement and load it if so
|
||||
char tmp[FS_MAXPATH];
|
||||
snprintf(tmp, sizeof(tmp), ROMDATA_SEGDIR "/%s", seg->name);
|
||||
u8 *newData = NULL;
|
||||
const s32 extFileSize = fsFileSize(tmp);
|
||||
if (extFileSize > 0) {
|
||||
newData = fsFileLoad(tmp, &seg->size);
|
||||
}
|
||||
|
||||
if (!newData) {
|
||||
// no external data, just make it point to the rom
|
||||
if (g_RomFile) {
|
||||
newData = g_RomFile + (uintptr_t)seg->data;
|
||||
seg->source = SRC_ROM;
|
||||
sysLogPrintf(LOG_NOTE, "loading segment %s from ROM (offset %08x pointer %p)", seg->name, (u32)seg->data, newData);
|
||||
} else {
|
||||
sysFatalError("No ROM or external file for segment:\n%s", seg->name);
|
||||
}
|
||||
} else {
|
||||
// loaded external data
|
||||
seg->source = SRC_EXTERNAL;
|
||||
sysLogPrintf(LOG_NOTE, "loading segment %s from file (pointer %p)", seg->name, newData);
|
||||
}
|
||||
|
||||
seg->data = newData;
|
||||
|
||||
if (seg->segstart) {
|
||||
*seg->segstart = seg->data;
|
||||
}
|
||||
|
||||
if (seg->segend) {
|
||||
*seg->segend = seg->data + seg->size;
|
||||
}
|
||||
|
||||
// call the post load function if any
|
||||
if (seg->preprocess && !seg->preprocessed) {
|
||||
seg->preprocess(seg->data, seg->size);
|
||||
seg->preprocessed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline s32 romdataLoadExternalFileList(void)
|
||||
{
|
||||
romDataSeg = fsFileLoad("filenames.lst", &romDataSegSize); // this null terminates the file by itself
|
||||
if (!romDataSeg || !romDataSegSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 n = 1;
|
||||
char *p = (char *)romDataSeg;
|
||||
while (*p && n < ROMDATA_MAX_FILES) {
|
||||
// skip whitespace
|
||||
while (*p && isspace(*p)) ++p;
|
||||
if (*p) {
|
||||
const char *start = p;
|
||||
// skip to next whitespace or end of file
|
||||
while (*p && !isspace(*p)) ++p;
|
||||
// null terminate the name if needed
|
||||
if (*p) {
|
||||
*p++ = '\0';
|
||||
}
|
||||
fileSlots[n++].name = start;
|
||||
}
|
||||
}
|
||||
|
||||
return n - 1;
|
||||
}
|
||||
|
||||
static inline void romdataInitFiles(void)
|
||||
{
|
||||
if (!g_RomFile) {
|
||||
// no ROM; try to load the file name list from disk
|
||||
if (!romdataLoadExternalFileList()) {
|
||||
sysFatalError("No ROM file or external filename table found.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// the file offset table is in the data seg
|
||||
const u32 *offsets = (u32 *)(romDataSeg + ROMDATA_FILES_OFS);
|
||||
u32 i;
|
||||
for (i = 1; offsets[i]; ++i) {
|
||||
if (offsets + i + 1 < (u32 *)(romDataSeg + romDataSegSize)) {
|
||||
const u32 nextofs = PD_BE32(offsets[i + 1]);
|
||||
const u32 ofs = PD_BE32(offsets[i]);
|
||||
fileSlots[i].data = g_RomFile + ofs;
|
||||
fileSlots[i].size = nextofs - ofs;
|
||||
fileSlots[i].source = SRC_UNLOADED;
|
||||
fileSlots[i].preprocessed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// last offset is to the name table
|
||||
const u32 *nameOffsets = (u32 *)(g_RomFile + PD_BE32(offsets[i - 1]));
|
||||
for (i = 1; nameOffsets[i]; ++i) {
|
||||
const u32 ofs = PD_BE32(nameOffsets[i]);
|
||||
fileSlots[i].name = (const char *)nameOffsets + ofs; // ofs is relative to the start of the name table
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct romfile *romdataGetSeg(const char *name)
|
||||
{
|
||||
struct romfile *seg = romSegs;
|
||||
while (seg->name && strcmp(name, seg->name)) {
|
||||
++seg;
|
||||
}
|
||||
return seg;
|
||||
}
|
||||
|
||||
s32 romdataInit(void)
|
||||
{
|
||||
const char *altRomName = sysArgGetString("--rom-file");
|
||||
if (altRomName) {
|
||||
g_RomName = altRomName;
|
||||
}
|
||||
|
||||
romdataLoadRom();
|
||||
|
||||
// set segments to point to the rom or load them externally
|
||||
for (struct romfile *seg = romSegs; seg->name; ++seg) {
|
||||
romdataInitSegment(seg);
|
||||
}
|
||||
|
||||
// load file table from the files segment
|
||||
romdataInitFiles();
|
||||
|
||||
sysLogPrintf(LOG_NOTE, "romdataInit: loaded rom, size = %u", g_RomFileSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 romdataFileGetSize(s32 fileNum)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
sysLogPrintf(LOG_ERROR, "romdataFileGetSize: invalid file num %d", fileNum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ensure any external files are loaded and we use their size
|
||||
if (romdataFileLoad(fileNum, NULL)) {
|
||||
return fileSlots[fileNum].size;
|
||||
}
|
||||
|
||||
sysLogPrintf(LOG_ERROR, "romdataFileGetSize: could not load file num %d", fileNum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 *romdataFileGetData(s32 fileNum)
|
||||
{
|
||||
return romdataFileLoad(fileNum, NULL);
|
||||
}
|
||||
|
||||
u8 *romdataFileLoad(s32 fileNum, u32 *outSize)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
sysLogPrintf(LOG_ERROR, "romdataFileLoad: invalid file num %d", fileNum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *out = NULL;
|
||||
|
||||
// try to load external file
|
||||
if (fileSlots[fileNum].source == SRC_UNLOADED) {
|
||||
char tmp[FS_MAXPATH] = { 0 };
|
||||
snprintf(tmp, sizeof(tmp), ROMDATA_FILEDIR "/%s", fileSlots[fileNum].name);
|
||||
if (fsFileSize(tmp) > 0) {
|
||||
u32 size = 0;
|
||||
out = fsFileLoad(tmp, &size);
|
||||
if (out && size) {
|
||||
sysLogPrintf(LOG_NOTE, "file %d (%s) loaded externally", fileNum, fileSlots[fileNum].name);
|
||||
fileSlots[fileNum].data = out;
|
||||
fileSlots[fileNum].size = size;
|
||||
fileSlots[fileNum].source = SRC_EXTERNAL;
|
||||
// external file; do not apply patches to this
|
||||
fileSlots[fileNum].numpatches = 0;
|
||||
}
|
||||
}
|
||||
// tried and failed, fall back to ROM
|
||||
fileSlots[fileNum].source = SRC_ROM;
|
||||
}
|
||||
|
||||
if (!out) {
|
||||
out = fileSlots[fileNum].data;
|
||||
}
|
||||
|
||||
if (out && outSize) {
|
||||
*outSize = fileSlots[fileNum].size;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
sysLogPrintf(LOG_ERROR, "romdataFilePreprocess: invalid file num %d", fileNum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data && size /* && !fileSlots[fileNum].preprocessed*/) {
|
||||
if (loadType && loadType < (u32)ARRAYCOUNT(filePreprocFuncs) && filePreprocFuncs[loadType]) {
|
||||
// apply patches
|
||||
for (u32 i = 0; i < fileSlots[fileNum].numpatches; ++i) {
|
||||
const struct romfilepatch *p = &fileSlots[fileNum].patches[i];
|
||||
if (!memcmp(data + p->ofs, p->src, p->len)) {
|
||||
memcpy(data + p->ofs, p->dst, p->len);
|
||||
sysLogPrintf(LOG_NOTE, "file %d (%s) patched at offset 0x%x", fileNum, fileSlots[fileNum].name, p->ofs);
|
||||
}
|
||||
}
|
||||
// then preprocess
|
||||
filePreprocFuncs[loadType](data, size);
|
||||
// fileSlots[fileNum].preprocessed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void romdataFileFree(s32 fileNum)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
sysLogPrintf(LOG_ERROR, "fsFileFree: invalid file num %d", fileNum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileSlots[fileNum].source == SRC_EXTERNAL) {
|
||||
sysMemFree(fileSlots[fileNum].data);
|
||||
fileSlots[fileNum].data = NULL;
|
||||
}
|
||||
|
||||
fileSlots[fileNum].source = SRC_UNLOADED;
|
||||
}
|
||||
|
||||
const char *romdataFileGetName(s32 fileNum)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
return NULL;
|
||||
}
|
||||
return fileSlots[fileNum].name;
|
||||
}
|
||||
|
||||
s32 romdataFileGetNumForName(const char *name)
|
||||
{
|
||||
if (!name || !name[0]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < ROMDATA_MAX_FILES; ++i) {
|
||||
if (fileSlots[i].name && !strcmp(fileSlots[i].name, name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 *romdataSegGetData(const char *segName)
|
||||
{
|
||||
return romdataGetSeg(segName)->data;
|
||||
}
|
||||
|
||||
u8 *romdataSegGetDataEnd(const char *segName)
|
||||
{
|
||||
struct romfile *seg = romdataGetSeg(segName);
|
||||
return seg->data + seg->size;
|
||||
}
|
||||
|
||||
u32 romdataSegGetSize(const char *segName)
|
||||
{
|
||||
return romdataGetSeg(segName)->size;
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <SDL.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
#include "console.h"
|
||||
#include "system.h"
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// on win32 we use waitable timers instead of nanosleep
|
||||
typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD);
|
||||
static HANDLE timer;
|
||||
static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
|
||||
|
||||
// winapi also provides a yield macro
|
||||
#define DO_YIELD() YieldProcessor()
|
||||
|
||||
// ask system for high performance GPU, if any
|
||||
__attribute__((dllexport)) u32 NvOptimusEnablement = 1;
|
||||
__attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// figure out how to yield
|
||||
#if defined(PLATFORM_X86) || defined(PLATFORM_X86_64)
|
||||
// this should work even if the code is not built with SSE enabled, at least on gcc and clang,
|
||||
// but if it doesn't we'll have to use __builtin_ia32_pause() or something
|
||||
#include <immintrin.h>
|
||||
#define DO_YIELD() _mm_pause()
|
||||
#elif defined(PLATFORM_ARM)
|
||||
// same as YieldProcessor() on ARM Windows
|
||||
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
|
||||
#else
|
||||
// fuck it
|
||||
#define DO_YIELD() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define LOG_FNAME "pd.log"
|
||||
#define CRASHLOG_FNAME "pd.crash.log"
|
||||
#define USEC_IN_SEC 1000000ULL
|
||||
|
||||
static u64 startTick = 0;
|
||||
static char logPath[2048];
|
||||
|
||||
static s32 sysArgc;
|
||||
static const char **sysArgv;
|
||||
|
||||
static inline void sysLogSetPath(const char *fname)
|
||||
{
|
||||
// figure out where the log is and clear it
|
||||
// try working dir first
|
||||
snprintf(logPath, sizeof(logPath), "./%s", fname);
|
||||
FILE *f = fopen(logPath, "wb");
|
||||
if (!f) {
|
||||
// try home dir
|
||||
sysGetHomePath(logPath, sizeof(logPath) - 1);
|
||||
strncat(logPath, "/", sizeof(logPath) - 1);
|
||||
strncat(logPath, fname, sizeof(logPath) - 1);
|
||||
f = fopen(logPath, "wb");
|
||||
}
|
||||
if (f) {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void sysInitArgs(s32 argc, const char **argv)
|
||||
{
|
||||
sysArgc = argc;
|
||||
sysArgv = argv;
|
||||
}
|
||||
|
||||
void sysInit(void)
|
||||
{
|
||||
startTick = sysGetMicroseconds();
|
||||
|
||||
if (sysArgCheck("--log")) {
|
||||
sysLogSetPath(LOG_FNAME);
|
||||
}
|
||||
|
||||
#ifdef VERSION_HASH
|
||||
sysLogPrintf(LOG_NOTE, "version: " VERSION_BRANCH " " VERSION_HASH " (" VERSION_TARGET ")");
|
||||
#endif
|
||||
|
||||
char timestr[256];
|
||||
const time_t curtime = time(NULL);
|
||||
strftime(timestr, sizeof(timestr), "%d %b %Y %H:%M:%S", localtime(&curtime));
|
||||
sysLogPrintf(LOG_NOTE, "startup date: %s", timestr);
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
// this function is only present on Vista+, so try to import it from kernel32 by hand
|
||||
pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA");
|
||||
if (pfnCreateWaitableTimerExA) {
|
||||
// function exists, try to create a hires timer
|
||||
timer = pfnCreateWaitableTimerExA(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
||||
}
|
||||
if (!timer) {
|
||||
// no function or hires timers not supported, fallback to lower resolution timer
|
||||
sysLogPrintf(LOG_WARNING, "SYS: hires waitable timers not available");
|
||||
timer = CreateWaitableTimerA(NULL, FALSE, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 sysArgCheck(const char *arg)
|
||||
{
|
||||
for (s32 i = 1; i < sysArgc; ++i) {
|
||||
if (!strcasecmp(sysArgv[i], arg)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *sysArgGetString(const char *arg)
|
||||
{
|
||||
for (s32 i = 1; i < sysArgc; ++i) {
|
||||
if (!strcasecmp(sysArgv[i], arg)) {
|
||||
if (i < sysArgc - 1) {
|
||||
return sysArgv[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s32 sysArgGetInt(const char *arg, s32 defval)
|
||||
{
|
||||
for (s32 i = 1; i < sysArgc; ++i) {
|
||||
if (!strcasecmp(sysArgv[i], arg)) {
|
||||
if (i < sysArgc - 1) {
|
||||
return strtol(sysArgv[i + 1], NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return defval;
|
||||
}
|
||||
|
||||
u64 sysGetMicroseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return ((u64)tv.tv_sec * USEC_IN_SEC + (u64)tv.tv_usec) - startTick;
|
||||
}
|
||||
|
||||
float sysGetSeconds(void)
|
||||
{
|
||||
u64 t = sysGetMicroseconds();
|
||||
return (f32)t / 1000000.f;
|
||||
}
|
||||
|
||||
s32 sysLogIsOpen(void)
|
||||
{
|
||||
return (logPath[0] != '\0');
|
||||
}
|
||||
|
||||
void sysLogPrintf(s32 level, const char *fmt, ...)
|
||||
{
|
||||
static const char *prefix[3] = {
|
||||
"", "WARNING: ", "ERROR: "
|
||||
};
|
||||
|
||||
char logmsg[2048];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logPath[0]) {
|
||||
FILE *f = fopen(logPath, "ab");
|
||||
if (f) {
|
||||
fprintf(f, "%s%s\n", prefix[level], logmsg);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
FILE *fout = ((level & 0x0f) == LOG_NOTE) ? stdout : stderr;
|
||||
fprintf(fout, "%s%s\n", prefix[level & 0x0f], logmsg);
|
||||
fflush(fout);
|
||||
|
||||
if ((level & LOGFLAG_NOCON) == 0) {
|
||||
conPrintLn((level & LOGFLAG_SHOWMSG) != 0, logmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void sysFatalError(const char *fmt, ...)
|
||||
{
|
||||
static s32 alreadyCrashed = 0;
|
||||
|
||||
if (alreadyCrashed) {
|
||||
abort();
|
||||
}
|
||||
|
||||
char errmsg[2048] = { 0 };
|
||||
|
||||
alreadyCrashed = 1;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sysLogPrintf(LOG_ERROR, "FATAL: %s", errmsg);
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", errmsg, NULL);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void sysGetExecutablePath(char *outPath, const u32 outLen)
|
||||
{
|
||||
// try asking SDL
|
||||
char *sdlPath = SDL_GetBasePath();
|
||||
|
||||
if (sdlPath && *sdlPath) {
|
||||
// -1 to trim trailing slash
|
||||
const u32 len = strlen(sdlPath) - 1;
|
||||
if (len < outLen) {
|
||||
memcpy(outPath, sdlPath, len);
|
||||
outPath[len] = '\0';
|
||||
}
|
||||
} else if (sysArgc && sysArgv[0] && sysArgv[0][0]) {
|
||||
// get exe path from argv[0]
|
||||
strncpy(outPath, sysArgv[0], outLen - 1);
|
||||
outPath[outLen - 1] = '\0';
|
||||
} else if (outLen > 1) {
|
||||
// give up, use working directory instead
|
||||
outPath[0] = '.';
|
||||
outPath[1] = '\0';
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
// replace all backslashes with forward slashes, windows supports both
|
||||
for (u32 i = 0; i < outLen && outPath[i]; ++i) {
|
||||
if (outPath[i] == '\\') {
|
||||
outPath[i] = '/';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_free(sdlPath);
|
||||
}
|
||||
|
||||
void sysGetHomePath(char *outPath, const u32 outLen)
|
||||
{
|
||||
// try asking SDL
|
||||
char *sdlPath = SDL_GetPrefPath("", "perfectdark");
|
||||
|
||||
if (sdlPath && *sdlPath) {
|
||||
// -1 to trim trailing slash
|
||||
const u32 len = strlen(sdlPath) - 1;
|
||||
if (len < outLen) {
|
||||
memcpy(outPath, sdlPath, len);
|
||||
outPath[len] = '\0';
|
||||
}
|
||||
} else if (outLen > 1) {
|
||||
// give up, use working directory instead
|
||||
outPath[0] = '.';
|
||||
outPath[1] = '\0';
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
// replace all backslashes with forward slashes, windows supports both
|
||||
for (u32 i = 0; i < outLen && outPath[i]; ++i) {
|
||||
if (outPath[i] == '\\') {
|
||||
outPath[i] = '/';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_free(sdlPath);
|
||||
}
|
||||
|
||||
void *sysMemAlloc(const u32 size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *sysMemZeroAlloc(const u32 size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
void sysMemFree(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void sysSleep(const s64 hns)
|
||||
{
|
||||
#ifdef PLATFORM_WIN32
|
||||
static LARGE_INTEGER li;
|
||||
li.QuadPart = -hns;
|
||||
SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
#else
|
||||
const struct timespec spec = { 0, hns * 100 };
|
||||
nanosleep(&spec, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sysCpuRelax(void)
|
||||
{
|
||||
DO_YIELD();
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
|
||||
static inline bool isSingleCharToken(const s32 ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case ',':
|
||||
case '\'':
|
||||
case '=':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char *strFmt(const char *fmt, ...)
|
||||
{
|
||||
static char buf[4096];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *strRightTrim(char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const s32 len = strlen(str);
|
||||
for (s32 i = len - 1; i >= 0 && isspace(str[i]); --i) {
|
||||
str[i] = '\0';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *strTrim(char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// left trim
|
||||
while (*str && (u8)*str < ' ') {
|
||||
++str;
|
||||
}
|
||||
|
||||
// right trim
|
||||
const s32 len = strlen(str);
|
||||
for (s32 i = len - 1; i > 0 && isspace(str[i]); --i) {
|
||||
str[i] = '\0';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *strUnquote(char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*str == '"') {
|
||||
++str;
|
||||
}
|
||||
|
||||
char *end = strrchr(str, '"');
|
||||
if (end && end[1] == '\0') {
|
||||
*end = '\0';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *strParseToken(char *str, char *out, s32 *outCount)
|
||||
{
|
||||
if (outCount) {
|
||||
*outCount = 0;
|
||||
}
|
||||
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out[0] = '\0';
|
||||
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s32 cnt = 0;
|
||||
while (*str) {
|
||||
// skip whitespace and other garbage
|
||||
while (*str && (u8)*str <= ' ') {
|
||||
++str;
|
||||
}
|
||||
if (!*str) {
|
||||
// just whitespace
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// skip #, ; and // comments
|
||||
if (*str == ';' || *str == '#' || (str[0] == '/' && str[1] == '/')) {
|
||||
while (*str && *str != '\n') {
|
||||
++str;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*str == '"') {
|
||||
// quoted string; treat it as an entire token, including the quotes
|
||||
out[cnt++] = *str++;
|
||||
while (true) {
|
||||
if (*str == '\0') {
|
||||
// unterminated quoted string
|
||||
break;
|
||||
}
|
||||
|
||||
if (str[0] == '\\' && str[1] == '"') {
|
||||
// escaped quote; add to token
|
||||
if (cnt + 1 < UTIL_MAX_TOKEN) {
|
||||
out[cnt++] = str[1];
|
||||
}
|
||||
str += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// add char to token
|
||||
const s32 ch = (u8)*str++;
|
||||
if (cnt + 1 < UTIL_MAX_TOKEN) {
|
||||
out[cnt++] = ch;
|
||||
}
|
||||
|
||||
if (ch == '"') {
|
||||
// ch was the closing quote
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (isSingleCharToken(*str)) {
|
||||
// single char token
|
||||
out[cnt++] = *str++;
|
||||
break;
|
||||
}
|
||||
|
||||
// regular single word
|
||||
do {
|
||||
if (cnt + 1 < UTIL_MAX_TOKEN) {
|
||||
out[cnt++] = *str++;
|
||||
}
|
||||
if (isSingleCharToken(*str)) {
|
||||
break;
|
||||
}
|
||||
} while ((u8)*str > ' ');
|
||||
break;
|
||||
}
|
||||
|
||||
out[cnt] = '\0';
|
||||
if (outCount) {
|
||||
*outCount = cnt;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *strDuplicate(const char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
const u32 len = strlen(str);
|
||||
char *out = sysMemAlloc(len + 1);
|
||||
if (out) {
|
||||
memcpy(out, str, len + 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
#include "platform.h"
|
||||
#include "config.h"
|
||||
#include "video.h"
|
||||
|
||||
#include "../fast3d/gfx_api.h"
|
||||
#include "../fast3d/gfx_sdl.h"
|
||||
#include "../fast3d/gfx_opengl.h"
|
||||
|
||||
static struct GfxWindowManagerAPI *wmAPI;
|
||||
static struct GfxRenderingAPI *renderingAPI;
|
||||
|
||||
static bool initDone = false;
|
||||
|
||||
static s32 vidWidth = 640;
|
||||
static s32 vidHeight = 480;
|
||||
static s32 vidFramebuffers = true;
|
||||
static s32 vidFullscreen = false;
|
||||
static s32 vidFullscreenExclusive = false;
|
||||
static s32 vidMaximize = false;
|
||||
static s32 vidAllowHiDpi = false;
|
||||
static s32 vidVsync = 1;
|
||||
static s32 vidMSAA = 1;
|
||||
static s32 vidFramerateLimit = 0;
|
||||
|
||||
static s32 texFilter = FILTER_LINEAR;
|
||||
static s32 texFilter2D = true;
|
||||
static s32 texDetail = true;
|
||||
|
||||
static u32 dlcount = 0;
|
||||
static u32 frames = 0;
|
||||
static u32 framesPerSec = 0;
|
||||
static f64 startTime, endTime, fpsTime;
|
||||
|
||||
s32 videoInit(void)
|
||||
{
|
||||
wmAPI = &gfx_sdl;
|
||||
renderingAPI = &gfx_opengl_api;
|
||||
|
||||
gfx_current_native_viewport.width = 320;
|
||||
gfx_current_native_viewport.height = 220;
|
||||
gfx_current_native_aspect = 320.f / 220.f;
|
||||
gfx_framebuffers_enabled = (bool)vidFramebuffers;
|
||||
gfx_detail_textures_enabled = (bool)texDetail;
|
||||
gfx_msaa_level = vidMSAA;
|
||||
|
||||
struct GfxInitSettings set = {
|
||||
.wapi = wmAPI,
|
||||
.rapi = renderingAPI,
|
||||
.window_settings = {
|
||||
.title = "Perfect Dark",
|
||||
.width = vidWidth,
|
||||
.height = vidHeight,
|
||||
.x = 100,
|
||||
.y = 100,
|
||||
.fullscreen = vidFullscreen,
|
||||
.fullscreen_is_exclusive = vidFullscreenExclusive,
|
||||
.maximized = vidMaximize,
|
||||
.allow_hidpi = vidAllowHiDpi
|
||||
}
|
||||
};
|
||||
|
||||
gfx_init(&set);
|
||||
|
||||
if (!wmAPI->set_swap_interval(vidVsync)) {
|
||||
vidVsync = 0;
|
||||
}
|
||||
|
||||
if (vidVsync == 0 && vidFramerateLimit == 0) {
|
||||
// cap FPS if there's no vsync to prevent the game from exploding
|
||||
vidFramerateLimit = VIDEO_MAX_FPS;
|
||||
}
|
||||
|
||||
wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on
|
||||
renderingAPI->set_texture_filter((enum FilteringMode)texFilter);
|
||||
|
||||
initDone = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void videoStartFrame(void)
|
||||
{
|
||||
if (initDone) {
|
||||
startTime = wmAPI->get_time();
|
||||
gfx_start_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void videoSubmitCommands(Gfx *cmds)
|
||||
{
|
||||
if (initDone) {
|
||||
gfx_run(cmds);
|
||||
++dlcount;
|
||||
}
|
||||
}
|
||||
|
||||
void videoEndFrame(void)
|
||||
{
|
||||
if (!initDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx_end_frame();
|
||||
|
||||
endTime = wmAPI->get_time();
|
||||
|
||||
++frames;
|
||||
++framesPerSec;
|
||||
|
||||
if (endTime >= fpsTime) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames);
|
||||
wmAPI->set_window_title(tmp);
|
||||
framesPerSec = 0;
|
||||
fpsTime = endTime + 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void videoClearScreen(void)
|
||||
{
|
||||
videoStartFrame();
|
||||
// TODO: clear
|
||||
videoEndFrame();
|
||||
}
|
||||
|
||||
void *videoGetWindowHandle(void)
|
||||
{
|
||||
if (initDone) {
|
||||
return wmAPI->get_window_handle();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void videoUpdateNativeResolution(s32 w, s32 h)
|
||||
{
|
||||
gfx_current_native_viewport.width = w;
|
||||
gfx_current_native_viewport.height = h;
|
||||
gfx_current_native_aspect = (float)w / (float)h;
|
||||
}
|
||||
|
||||
s32 videoGetNativeWidth(void)
|
||||
{
|
||||
return gfx_current_native_viewport.width;
|
||||
}
|
||||
|
||||
s32 videoGetNativeHeight(void)
|
||||
{
|
||||
return gfx_current_native_viewport.height;
|
||||
}
|
||||
|
||||
s32 videoGetWidth(void)
|
||||
{
|
||||
return gfx_current_dimensions.width;
|
||||
}
|
||||
|
||||
s32 videoGetHeight(void)
|
||||
{
|
||||
return gfx_current_dimensions.height;
|
||||
}
|
||||
|
||||
s32 videoGetFullscreen(void)
|
||||
{
|
||||
return vidFullscreen;
|
||||
}
|
||||
|
||||
s32 videoGetMaximizeWindow(void)
|
||||
{
|
||||
return vidMaximize;
|
||||
}
|
||||
|
||||
f32 videoGetAspect(void)
|
||||
{
|
||||
return gfx_current_dimensions.aspect_ratio;
|
||||
}
|
||||
|
||||
s32 videoGetTextureFilter2D(void)
|
||||
{
|
||||
return texFilter2D;
|
||||
}
|
||||
|
||||
u32 videoGetTextureFilter(void)
|
||||
{
|
||||
return texFilter;
|
||||
}
|
||||
|
||||
s32 videoGetDetailTextures(void)
|
||||
{
|
||||
return texDetail;
|
||||
}
|
||||
|
||||
void videoSetWindowOffset(s32 x, s32 y)
|
||||
{
|
||||
gfx_current_game_window_viewport.x = x;
|
||||
gfx_current_game_window_viewport.y = y;
|
||||
}
|
||||
|
||||
void videoSetFullscreen(s32 fs)
|
||||
{
|
||||
if (fs != vidFullscreen) {
|
||||
vidFullscreen = !!fs;
|
||||
wmAPI->set_fullscreen(vidFullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetMaximizeWindow(s32 fs)
|
||||
{
|
||||
if (fs != vidMaximize) {
|
||||
vidMaximize = !!fs;
|
||||
wmAPI->set_maximize(vidMaximize);
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetTextureFilter(u32 filter)
|
||||
{
|
||||
if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT;
|
||||
texFilter = filter;
|
||||
renderingAPI->set_texture_filter((enum FilteringMode)filter);
|
||||
}
|
||||
|
||||
void videoSetTextureFilter2D(s32 filter)
|
||||
{
|
||||
texFilter2D = !!filter;
|
||||
}
|
||||
|
||||
void videoSetDetailTextures(s32 detail)
|
||||
{
|
||||
texDetail = !!detail;
|
||||
gfx_detail_textures_enabled = (bool)texDetail;
|
||||
}
|
||||
|
||||
void videoCapFramerate(s32 limit)
|
||||
{
|
||||
if (vidFramerateLimit > 0 && vidFramerateLimit < limit) {
|
||||
limit = vidFramerateLimit;
|
||||
}
|
||||
wmAPI->set_target_fps(limit ? limit : vidFramerateLimit);
|
||||
}
|
||||
|
||||
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
|
||||
{
|
||||
return gfx_create_framebuffer(w, h, upscale, autoresize);
|
||||
}
|
||||
|
||||
void videoSetFramebuffer(s32 target)
|
||||
{
|
||||
return gfx_set_framebuffer(target, 1.f);
|
||||
}
|
||||
|
||||
void videoResetFramebuffer(void)
|
||||
{
|
||||
return gfx_reset_framebuffer();
|
||||
}
|
||||
|
||||
s32 videoFramebuffersSupported(void)
|
||||
{
|
||||
return gfx_framebuffers_enabled;
|
||||
}
|
||||
|
||||
void videoResizeFramebuffer(s32 target, u32 w, u32 h, s32 upscale, s32 autoresize)
|
||||
{
|
||||
gfx_resize_framebuffer(target, w, h, upscale, autoresize);
|
||||
}
|
||||
|
||||
void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top)
|
||||
{
|
||||
// assume immediate copies always read the front buffer
|
||||
gfx_copy_framebuffer(dst, src, left, top, false);
|
||||
}
|
||||
|
||||
void videoResetTextureCache(void)
|
||||
{
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
void videoFreeCachedTexture(const void *texptr)
|
||||
{
|
||||
gfx_texture_cache_delete(texptr);
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1);
|
||||
configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1);
|
||||
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
|
||||
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
|
||||
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
|
||||
configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1);
|
||||
configRegisterInt("Video.VSync", &vidVsync, -1, 10);
|
||||
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
|
||||
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
|
||||
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
|
||||
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
|
||||
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
|
||||
configRegisterInt("Video.DetailTextures", &texDetail, 0, 1);
|
||||
}
|
||||
+2
-2
@@ -57,7 +57,7 @@ s32 func0f096890(s32 arg0)
|
||||
return value - (((value - nextvalue) * (arg0 & mask)) >> shiftamount);
|
||||
}
|
||||
|
||||
u16 acos(s16 arg0)
|
||||
u16 acosx(s16 arg0)
|
||||
{
|
||||
s32 value = arg0 >= 0 ? arg0 : -arg0;
|
||||
|
||||
@@ -70,7 +70,7 @@ u16 acos(s16 arg0)
|
||||
return value;
|
||||
}
|
||||
|
||||
s16 asin(s16 arg0)
|
||||
s16 asinx(s16 arg0)
|
||||
{
|
||||
s32 value = arg0 >= 0 ? arg0 : -arg0;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ f32 acosf(f32 value)
|
||||
intval = value * 32767.0f;
|
||||
}
|
||||
|
||||
return acos(intval) * M_PI / 65535.0f;
|
||||
return acosx(intval) * M_PI / 65535.0f;
|
||||
}
|
||||
|
||||
f32 asinf(f32 value)
|
||||
@@ -32,5 +32,5 @@ f32 asinf(f32 value)
|
||||
intval = value * 32767.0f;
|
||||
}
|
||||
|
||||
return asin(intval) * M_PI / 65535.0f;
|
||||
return asinx(intval) * M_PI / 65535.0f;
|
||||
}
|
||||
+50
-48
@@ -26,7 +26,7 @@
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
|
||||
struct activemenu g_AmMenus[MAX_PLAYERS];
|
||||
struct activemenu g_AmMenus[MAX_LOCAL_PLAYERS];
|
||||
struct fontchar *g_AmFont1;
|
||||
struct font *g_AmFont2;
|
||||
s32 g_AmIndex;
|
||||
@@ -90,19 +90,8 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
// All bots: num bot opponents + all human players
|
||||
s32 count = 0;
|
||||
s32 i;
|
||||
struct chrdata *playerchr = g_Vars.currentplayer->prop->chr;
|
||||
|
||||
for (i = PLAYERCOUNT(); i < g_MpNumChrs; i++) {
|
||||
if (g_MpAllChrPtrs[i]->team != playerchr->team) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
count += PLAYERCOUNT();
|
||||
data->list.value = count;
|
||||
// All bots
|
||||
data->list.value = g_MpNumChrs;
|
||||
} else {
|
||||
// Single bot: All except the bot itself
|
||||
data->list.value = g_MpNumChrs - 1;
|
||||
@@ -125,9 +114,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
chrindex++;
|
||||
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
|
||||
numremaining--;
|
||||
}
|
||||
} else {
|
||||
if (botchr != g_MpAllChrPtrs[chrindex]) {
|
||||
numremaining--;
|
||||
@@ -139,8 +126,10 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
g_AmMenus[g_AmIndex].prevallbots = false;
|
||||
|
||||
for (i = 0; i < g_Vars.currentplayer->numaibuddies; i++) {
|
||||
if (g_Vars.currentplayer->aibuddynums[i] != chrindex) {
|
||||
botApplyAttack(g_MpAllChrPtrs[g_Vars.currentplayer->aibuddynums[i]], g_MpAllChrPtrs[chrindex]->prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
botApplyAttack(botchr, g_MpAllChrPtrs[chrindex]->prop);
|
||||
}
|
||||
@@ -167,9 +156,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
chrindex++;
|
||||
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
|
||||
numremaining--;
|
||||
}
|
||||
} else {
|
||||
if (botchr != g_MpAllChrPtrs[chrindex]) {
|
||||
numremaining--;
|
||||
@@ -364,7 +351,11 @@ void amApply(s32 slot)
|
||||
bgunEquipWeapon2(HAND_RIGHT, weaponnum);
|
||||
}
|
||||
|
||||
if (bgunGetWeaponNum(HAND_LEFT) != WEAPON_NONE) {
|
||||
// don't unequip detonator
|
||||
// if we already have it equipped
|
||||
if (weaponnum == WEAPON_REMOTEMINE) {
|
||||
bgunEquipWeapon2(HAND_LEFT, weaponnum);
|
||||
} else if (bgunGetWeaponNum(HAND_LEFT) != WEAPON_NONE) {
|
||||
bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE);
|
||||
}
|
||||
}
|
||||
@@ -556,7 +547,7 @@ void amReset(void)
|
||||
g_AmFont1 = g_CharsHandelGothicSm;
|
||||
g_AmFont2 = g_FontHandelGothicSm;
|
||||
#else
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
if (LOCALPLAYERCOUNT() >= 2) {
|
||||
g_AmFont1 = g_CharsHandelGothicXs;
|
||||
g_AmFont2 = g_FontHandelGothicXs;
|
||||
} else {
|
||||
@@ -587,7 +578,7 @@ s16 amCalculateSlotWidth(void)
|
||||
}
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (PLAYERCOUNT() > 1) {
|
||||
if (LOCALPLAYERCOUNT() > 1) {
|
||||
max += 3;
|
||||
} else {
|
||||
max += 4;
|
||||
@@ -771,32 +762,32 @@ void amClose(void)
|
||||
bool amIsCramped(void)
|
||||
{
|
||||
#if VERSION == VERSION_JPN_FINAL
|
||||
if (PLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) {
|
||||
if (LOCALPLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IS4MB() && PLAYERCOUNT() == 2) {
|
||||
if (IS4MB() && LOCALPLAYERCOUNT() == 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL
|
||||
&& PLAYERCOUNT() == 2
|
||||
&& LOCALPLAYERCOUNT() == 2
|
||||
&& g_AmMenus[g_AmIndex].screenindex != 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
return (g_AmMenus[g_AmIndex].screenindex == 0 && PLAYERCOUNT() >= 3)
|
||||
|| (IS4MB() && PLAYERCOUNT() == 2)
|
||||
|| (PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL);
|
||||
return (g_AmMenus[g_AmIndex].screenindex == 0 && LOCALPLAYERCOUNT() >= 3)
|
||||
|| (IS4MB() && LOCALPLAYERCOUNT() == 2)
|
||||
|| (LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
|
||||
{
|
||||
#if VERSION == VERSION_JPN_FINAL
|
||||
s32 playercount = PLAYERCOUNT();
|
||||
s32 playercount = LOCALPLAYERCOUNT();
|
||||
|
||||
*x = g_AmMenus[g_AmIndex].xradius * (column - 1);
|
||||
*y = (row - 1) * 50;
|
||||
@@ -850,7 +841,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
|
||||
}
|
||||
}
|
||||
#elif VERSION >= VERSION_NTSC_1_0
|
||||
s32 playercount = PLAYERCOUNT();
|
||||
s32 playercount = LOCALPLAYERCOUNT();
|
||||
|
||||
*x = g_AmMenus[g_AmIndex].xradius * (column - 1);
|
||||
*y = (row - 1) * 50;
|
||||
@@ -902,7 +893,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
|
||||
}
|
||||
}
|
||||
#else
|
||||
s32 playercount = PLAYERCOUNT();
|
||||
s32 playercount = LOCALPLAYERCOUNT();
|
||||
|
||||
*x = g_AmMenus[g_AmIndex].xradius * (column - 1);
|
||||
*y = (row - 1) * 50;
|
||||
@@ -982,15 +973,15 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
|
||||
#endif
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
|
||||
if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
|
||||
wide = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3)
|
||||
if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3)
|
||||
#else
|
||||
if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3)
|
||||
if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3)
|
||||
#endif
|
||||
{
|
||||
if ((g_Vars.currentplayernum % 2) == 0) {
|
||||
@@ -1023,7 +1014,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
|
||||
- (s32)(textwidth * 0.5f)
|
||||
+ offset;
|
||||
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
if (LOCALPLAYERCOUNT() >= 2) {
|
||||
y = viGetViewTop() + 5;
|
||||
} else {
|
||||
y = viGetViewTop() + 10;
|
||||
@@ -1039,12 +1030,12 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
|
||||
gdl = func0f1574d0jf(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
|
||||
0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
|
||||
|
||||
y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
|
||||
y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
|
||||
#else
|
||||
gdl = textRender(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
|
||||
0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
|
||||
|
||||
y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
|
||||
y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
|
||||
textMeasure(&textheight, &textwidth, weaponname, g_AmFont1, g_AmFont2, 0);
|
||||
|
||||
x = viGetViewLeft() / g_ScaleX
|
||||
@@ -1073,7 +1064,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
|
||||
- (s32)(textwidth * 0.5f)
|
||||
+ offset;
|
||||
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
if (LOCALPLAYERCOUNT() >= 2) {
|
||||
y = viGetViewTop() + 5;
|
||||
} else {
|
||||
y = viGetViewTop() + 10;
|
||||
@@ -1132,7 +1123,7 @@ Gfx *amRenderSlot(Gfx *gdl, char *text, s16 x, s16 y, s32 mode, s32 flags)
|
||||
paddingtop = 6;
|
||||
paddingbottom = 6;
|
||||
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
if (LOCALPLAYERCOUNT() >= 2) {
|
||||
paddingtop = 5;
|
||||
paddingbottom = 3;
|
||||
}
|
||||
@@ -1270,6 +1261,13 @@ Gfx *amRender(Gfx *gdl)
|
||||
g_ScaleX = g_ViRes == VIRES_HI ? 2 : 1;
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
const s32 playercount = LOCALPLAYERCOUNT();
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_AmIndex = g_Vars.currentplayernum;
|
||||
g_Vars.currentplayer->commandingaibot = NULL;
|
||||
|
||||
@@ -1368,8 +1366,8 @@ Gfx *amRender(Gfx *gdl)
|
||||
vertices[6].colour = 4;
|
||||
vertices[7].colour = 4;
|
||||
|
||||
colours[0].word = 0x22222200;
|
||||
colours[1].word = 0x0000004f;
|
||||
colours[0].word = PD_BE32(0x22222200);
|
||||
colours[1].word = PD_BE32(0x0000004f);
|
||||
|
||||
gSPColor(gdl++, osVirtualToPhysical(colours), 2);
|
||||
gSPVertex(gdl++, osVirtualToPhysical(vertices), 8, 0);
|
||||
@@ -1489,7 +1487,7 @@ Gfx *amRender(Gfx *gdl)
|
||||
above = 6;
|
||||
below = 6;
|
||||
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
if (LOCALPLAYERCOUNT() >= 2) {
|
||||
above = 5;
|
||||
below = 3;
|
||||
}
|
||||
@@ -1512,7 +1510,7 @@ Gfx *amRender(Gfx *gdl)
|
||||
halfwidth = 1;
|
||||
above = 2;
|
||||
below = 0;
|
||||
} else if (PLAYERCOUNT() >= 2) {
|
||||
} else if (LOCALPLAYERCOUNT() >= 2) {
|
||||
s32 textheight;
|
||||
s32 textwidth;
|
||||
char text[32];
|
||||
@@ -1594,16 +1592,16 @@ Gfx *amRender(Gfx *gdl)
|
||||
}
|
||||
#endif
|
||||
|
||||
barwidth = PLAYERCOUNT() >= 2 ? 48 : 64;
|
||||
barheight = PLAYERCOUNT() >= 2 ? 7 : 11;
|
||||
barwidth = LOCALPLAYERCOUNT() >= 2 ? 48 : 64;
|
||||
barheight = LOCALPLAYERCOUNT() >= 2 ? 7 : 11;
|
||||
xoffset = 0;
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3) {
|
||||
if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3) {
|
||||
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
|
||||
}
|
||||
|
||||
if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
|
||||
if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
|
||||
part1left = viGetViewLeft() / g_ScaleX + 32;
|
||||
} else {
|
||||
part1left = (s32) ((viGetViewWidth() / g_ScaleX) * 0.5f)
|
||||
@@ -1612,7 +1610,7 @@ Gfx *amRender(Gfx *gdl)
|
||||
+ xoffset;
|
||||
}
|
||||
#else
|
||||
if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3) {
|
||||
if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3) {
|
||||
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
|
||||
}
|
||||
|
||||
@@ -1638,7 +1636,7 @@ Gfx *amRender(Gfx *gdl)
|
||||
gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
|
||||
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
||||
|
||||
y = viGetViewTop() + viGetViewHeight() - (PLAYERCOUNT() >= 2 ? 19 : 34);
|
||||
y = viGetViewTop() + viGetViewHeight() - (LOCALPLAYERCOUNT() >= 2 ? 19 : 34);
|
||||
|
||||
// NTSC beta doesn't scale the health bar when hi-res is on,
|
||||
// and it only matches if part2left is an inline expression
|
||||
@@ -1698,6 +1696,10 @@ Gfx *amRender(Gfx *gdl)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
#endif
|
||||
|
||||
g_ScaleX = 1;
|
||||
|
||||
return gdl;
|
||||
|
||||
+76
-55
@@ -12,18 +12,22 @@
|
||||
#include "lib/str.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "game/player.h"
|
||||
#include "input.h"
|
||||
#endif
|
||||
|
||||
void amTick(void)
|
||||
{
|
||||
s32 prevplayernum = g_Vars.currentplayernum;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < PLAYERCOUNT(); i++) {
|
||||
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
|
||||
setCurrentPlayerNum(i);
|
||||
g_AmIndex = g_Vars.currentplayernum;
|
||||
|
||||
if (g_AmMenus[g_AmIndex].togglefunc) {
|
||||
if (bgunConsiderToggleGunFunction(60, false, true) > 0) {
|
||||
if (bgunConsiderToggleGunFunction(60, false, true, 0) > 0) {
|
||||
g_AmMenus[g_AmIndex].togglefunc = false;
|
||||
}
|
||||
} else {
|
||||
@@ -40,15 +44,38 @@ void amTick(void)
|
||||
s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
|
||||
s32 numsamples = joyGetNumSamples();
|
||||
s32 j;
|
||||
u32 amask, lrtmask, umask, dmask, lmask, rmask;
|
||||
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
amask = D_JPAD;
|
||||
lrtmask = R_TRIG;
|
||||
umask = U_CBUTTONS;
|
||||
dmask = D_CBUTTONS;
|
||||
lmask = L_CBUTTONS;
|
||||
rmask = R_CBUTTONS;
|
||||
} else {
|
||||
amask = A_BUTTON;
|
||||
lrtmask = L_TRIG | R_TRIG;
|
||||
umask = U_JPAD | U_CBUTTONS;
|
||||
dmask = D_JPAD | D_CBUTTONS;
|
||||
lmask = L_JPAD | L_CBUTTONS;
|
||||
rmask = R_JPAD | R_CBUTTONS;
|
||||
}
|
||||
|
||||
for (j = 0; j < numsamples; j++) {
|
||||
s8 gotonextscreen = false;
|
||||
s8 cstickx = joyGetStickXOnSample(j, contpadnum);
|
||||
s8 csticky = joyGetStickYOnSample(j, contpadnum);
|
||||
#ifdef AVOID_UB
|
||||
// if cstickx is -128, it will get negated and stored into absstickx, negating it again if it's 8 bit
|
||||
s32 absstickx;
|
||||
s32 abssticky;
|
||||
#else
|
||||
s8 absstickx;
|
||||
s8 abssticky;
|
||||
u16 buttonsstate = joyGetButtonsOnSample(j, contpadnum, 0xffff);
|
||||
u16 buttonspressed = joyGetButtonsPressedOnSample(j, contpadnum, 0xffff);
|
||||
#endif
|
||||
u32 buttonsstate = joyGetButtonsOnSample(j, contpadnum, 0xffffffff);
|
||||
u32 buttonspressed = joyGetButtonsPressedOnSample(j, contpadnum, 0xffffffff);
|
||||
bool stickpushed = false;
|
||||
s32 slotnum;
|
||||
bool stayopen;
|
||||
@@ -63,8 +90,28 @@ void amTick(void)
|
||||
|
||||
g_AmMenus[g_AmIndex].allbots = false;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
s32 newstickx = (s32)cstickx;
|
||||
s32 newsticky = (s32)csticky;
|
||||
if (j == 0 && g_Vars.currentplayernum == 0 && inputMouseIsLocked()) {
|
||||
f32 mdx, mdy;
|
||||
struct activemenu *am = &g_AmMenus[g_AmIndex];
|
||||
inputMouseGetAbsScaledDelta(&mdx, &mdy);
|
||||
if (mdx || mdy) {
|
||||
am->mousex += mdx * PLAYER_EXTCFG().radialmenuspeed;
|
||||
am->mousey += mdy * PLAYER_EXTCFG().radialmenuspeed;
|
||||
am->mousex = (am->mousex > 127.f) ? 127.f : (am->mousex < -128.f) ? -128.f : am->mousex;
|
||||
am->mousey = (am->mousey > 127.f) ? 127.f : (am->mousey < -128.f) ? -128.f : am->mousey;
|
||||
}
|
||||
newstickx += (s32)am->mousex;
|
||||
newsticky -= (s32)am->mousey;
|
||||
}
|
||||
cstickx = (newstickx < -128) ? -128 : (newstickx > 127) ? 127 : newstickx;
|
||||
csticky = (newsticky < -128) ? -128 : (newsticky > 127) ? 127 : newsticky;
|
||||
#endif
|
||||
|
||||
if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) {
|
||||
buttonsstate = buttonsstate & A_BUTTON;
|
||||
buttonsstate = buttonsstate & amask;
|
||||
cstickx = 0;
|
||||
csticky = 0;
|
||||
buttonspressed = 0;
|
||||
@@ -72,12 +119,12 @@ void amTick(void)
|
||||
|
||||
// JPN fixes the bug that's documented in amChangeScreen
|
||||
if (controlmode == CONTROLMODE_13 || controlmode == CONTROLMODE_14) {
|
||||
if ((buttonsstate & R_TRIG) || (buttonsstate & L_TRIG)) {
|
||||
if (buttonsstate & (L_TRIG | R_TRIG)) {
|
||||
stayopen = true;
|
||||
}
|
||||
|
||||
if (buttonsstate & A_BUTTON) {
|
||||
#if VERSION >= VERSION_JPN_FINAL
|
||||
#if VERSION >= VERSION_JPN_FINAL || !defined(PLATFORM_N64)
|
||||
if (g_Vars.currentplayer->numaibuddies > 0) {
|
||||
g_AmMenus[g_AmIndex].allbots = true;
|
||||
}
|
||||
@@ -86,12 +133,12 @@ void amTick(void)
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (buttonsstate & A_BUTTON) {
|
||||
if (buttonsstate & amask) {
|
||||
stayopen = true;
|
||||
}
|
||||
|
||||
if ((buttonsstate & R_TRIG) || (buttonsstate & L_TRIG)) {
|
||||
#if VERSION >= VERSION_JPN_FINAL
|
||||
if (buttonsstate & lrtmask) {
|
||||
#if VERSION >= VERSION_JPN_FINAL || !defined(PLATFORM_N64)
|
||||
if (g_Vars.currentplayer->numaibuddies > 0) {
|
||||
g_AmMenus[g_AmIndex].allbots = true;
|
||||
}
|
||||
@@ -118,35 +165,19 @@ void amTick(void)
|
||||
amChangeScreen(0);
|
||||
}
|
||||
|
||||
if (buttonsstate & U_CBUTTONS) {
|
||||
if (buttonsstate & umask) {
|
||||
row = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate & D_CBUTTONS) {
|
||||
if (buttonsstate & dmask) {
|
||||
row = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate & L_CBUTTONS) {
|
||||
if (buttonsstate & lmask) {
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate & R_CBUTTONS) {
|
||||
column = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate & U_JPAD) {
|
||||
row = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate & D_JPAD) {
|
||||
row = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate & L_JPAD) {
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate & R_JPAD) {
|
||||
if (buttonsstate & rmask) {
|
||||
column = 2;
|
||||
}
|
||||
|
||||
@@ -157,8 +188,8 @@ void amTick(void)
|
||||
s8 contpadnum2 = optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex);
|
||||
s8 cstickx2 = joyGetStickXOnSample(j, contpadnum2);
|
||||
s8 csticky2 = joyGetStickYOnSample(j, contpadnum2);
|
||||
u16 buttonsstate2 = joyGetButtonsOnSample(j, contpadnum2, 0xffff);
|
||||
u16 buttonspressed2 = joyGetButtonsPressedOnSample(j, contpadnum2, 0xffff);
|
||||
u32 buttonsstate2 = joyGetButtonsOnSample(j, contpadnum2, 0xffffffff);
|
||||
u32 buttonspressed2 = joyGetButtonsPressedOnSample(j, contpadnum2, 0xffffffff);
|
||||
|
||||
if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) {
|
||||
buttonsstate2 = buttonsstate2 & A_BUTTON;
|
||||
@@ -175,35 +206,19 @@ void amTick(void)
|
||||
toggle = true;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & U_CBUTTONS) {
|
||||
if (buttonsstate2 & umask) {
|
||||
row = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & D_CBUTTONS) {
|
||||
if (buttonsstate2 & dmask) {
|
||||
row = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & L_CBUTTONS) {
|
||||
if (buttonsstate2 & lmask) {
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & R_CBUTTONS) {
|
||||
column = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & U_JPAD) {
|
||||
row = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & D_JPAD) {
|
||||
row = 2;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & L_JPAD) {
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (buttonsstate2 & R_JPAD) {
|
||||
if (buttonsstate2 & rmask) {
|
||||
column = 2;
|
||||
}
|
||||
|
||||
@@ -248,7 +263,7 @@ void amTick(void)
|
||||
stayopen = false;
|
||||
}
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
#if (VERSION >= VERSION_NTSC_1_0) && defined(PLATFORM_N64)
|
||||
if (g_Vars.lvupdate240 == 0) {
|
||||
stayopen = false;
|
||||
}
|
||||
@@ -369,6 +384,12 @@ void amTick(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef PLATFORM_N64
|
||||
else {
|
||||
g_AmMenus[g_AmIndex].mousex = 0.f;
|
||||
g_AmMenus[g_AmIndex].mousey = 0.f;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_Vars.currentplayer->activemenumode != AMMODE_EDIT) {
|
||||
s16 dist;
|
||||
@@ -407,7 +428,7 @@ void amTick(void)
|
||||
|
||||
// Update alpha of slots so they fade in
|
||||
if (g_AmMenus[g_AmIndex].alphafrac < 1) {
|
||||
g_AmMenus[g_AmIndex].alphafrac += LVUPDATE60FREAL() / 30.0f;
|
||||
g_AmMenus[g_AmIndex].alphafrac += (f32)g_Vars.lvupdate240 / (4.f * 30.0f);
|
||||
}
|
||||
|
||||
if (g_AmMenus[g_AmIndex].alphafrac > 1) {
|
||||
@@ -415,7 +436,7 @@ void amTick(void)
|
||||
}
|
||||
|
||||
// Make selection border pulsate
|
||||
g_AmMenus[g_AmIndex].selpulse += LVUPDATE60FREAL() / 5.0f;
|
||||
g_AmMenus[g_AmIndex].selpulse += (f32)g_Vars.lvupdate240 / (4.f * 5.0f);
|
||||
|
||||
if (g_AmMenus[g_AmIndex].selpulse > 18.849555969238f) {
|
||||
g_AmMenus[g_AmIndex].selpulse -= 18.849555969238f;
|
||||
|
||||
+222
-86
@@ -43,6 +43,11 @@
|
||||
#include "data.h"
|
||||
#include "gbiex.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "preprocess.h"
|
||||
#include "system.h"
|
||||
#include "video.h"
|
||||
#endif
|
||||
|
||||
#define BGCMD_END 0x00
|
||||
#define BGCMD_PUSH 0x01
|
||||
@@ -86,12 +91,12 @@ u32 var800a4920;
|
||||
u32 g_BgSection3;
|
||||
struct room *g_Rooms;
|
||||
u8 *g_MpRoomVisibility;
|
||||
s16 g_BgForceOnscreenRooms[350];
|
||||
RoomNum g_BgForceOnscreenRooms[350];
|
||||
s32 g_BgNumForceOnscreenRooms;
|
||||
u16 g_BgUnloadDelay240;
|
||||
u16 g_BgUnloadDelay240_2;
|
||||
u32 var800a4bf4;
|
||||
s16 g_GlareRooms[100];
|
||||
RoomNum g_GlareRooms[100];
|
||||
u32 *g_BgPrimaryData2;
|
||||
struct bgroom *g_BgRooms;
|
||||
struct bgportal *g_BgPortals;
|
||||
@@ -135,7 +140,7 @@ void bgUnpausePropsInRoom(u32 roomnum, bool tintedglassonly)
|
||||
struct prop *prop;
|
||||
struct defaultobj *obj;
|
||||
s16 *propnumptr;
|
||||
s16 rooms[2];
|
||||
RoomNum rooms[2];
|
||||
s16 propnums[256];
|
||||
|
||||
rooms[0] = roomnum;
|
||||
@@ -283,7 +288,7 @@ Gfx *bgRenderXrayData(Gfx *gdl, struct xraydata *xraydata)
|
||||
vertices[i].y = xraydata->vertices[i][1];
|
||||
vertices[i].z = xraydata->vertices[i][2];
|
||||
vertices[i].colour = i << 2;
|
||||
colours[i].word = xraydata->colours[i];
|
||||
colours[i].word = PD_BE32(xraydata->colours[i]);
|
||||
}
|
||||
|
||||
count = xraydata->numvertices;
|
||||
@@ -697,17 +702,17 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
|
||||
xraydata.numvertices = 0;
|
||||
|
||||
while (true) {
|
||||
if (readgdl[0] == G_ENDDL) {
|
||||
if (readgdl[GFX_W0_BYTE(0)] == G_ENDDL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (readgdl[0] == G_MTX) {
|
||||
if (readgdl[GFX_W0_BYTE(0)] == G_MTX) {
|
||||
// empty
|
||||
} else if (readgdl[0] == G_VTX) {
|
||||
} else if (readgdl[GFX_W0_BYTE(0)] == G_VTX) {
|
||||
Gfx *cmd = (Gfx *) readgdl;
|
||||
s32 dmemindex = cmd->bytes[1] & 0xf;
|
||||
s32 numvertices = ((u32) cmd->bytes[1] >> 4) + 1;
|
||||
u32 offset = cmd->words.w1 & 0xffffff;
|
||||
s32 dmemindex = cmd->bytes[GFX_W0_BYTE(1)] & 0xf;
|
||||
s32 numvertices = ((u32) cmd->bytes[GFX_W0_BYTE(1)] >> 4) + 1;
|
||||
u32 offset = UNSEGADDR(cmd->words.w1) & 0xffffff;
|
||||
|
||||
for (i = 0; i < numvertices; i++) {
|
||||
Vtx *vtx = (Vtx *) (verticesu8 + offset);
|
||||
@@ -720,14 +725,14 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
|
||||
|
||||
offset += sizeof(Vtx);
|
||||
}
|
||||
} else if (readgdl[0] == G_TRI1) {
|
||||
} else if (readgdl[GFX_W0_BYTE(0)] == G_TRI1) {
|
||||
Gfx *cmd = (Gfx *) readgdl;
|
||||
s16 x = cmd->tri.tri.v[0] / 10;
|
||||
s16 y = cmd->tri.tri.v[1] / 10;
|
||||
s16 z = cmd->tri.tri.v[2] / 10;
|
||||
s16 x = cmd->tri.tri.v[GFX_TRI_VTX(0)] / 10;
|
||||
s16 y = cmd->tri.tri.v[GFX_TRI_VTX(1)] / 10;
|
||||
s16 z = cmd->tri.tri.v[GFX_TRI_VTX(2)] / 10;
|
||||
|
||||
gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]);
|
||||
} else if (readgdl[0] == G_TRI4) {
|
||||
} else if (readgdl[GFX_W0_BYTE(0)] == G_TRI4) {
|
||||
Gfx *cmd = (Gfx *) readgdl;
|
||||
s16 x;
|
||||
s16 y;
|
||||
@@ -869,11 +874,11 @@ Gfx *bgRenderRoomInXray(Gfx *gdl, s32 roomnum)
|
||||
|
||||
Gfx *bgRenderSceneInXray(Gfx *gdl)
|
||||
{
|
||||
s16 *roomnumptr;
|
||||
s16 *room;
|
||||
RoomNum *roomnumptr;
|
||||
RoomNum *room;
|
||||
s16 i;
|
||||
s32 j;
|
||||
s16 roomnumsbyprop[200];
|
||||
RoomNum roomnumsbyprop[200];
|
||||
struct prop *prop;
|
||||
struct prop **ptr;
|
||||
s32 k;
|
||||
@@ -969,17 +974,19 @@ Gfx *bgRenderScene(Gfx *gdl)
|
||||
s32 firstroomnum = -1;
|
||||
s32 i;
|
||||
s32 roomnum;
|
||||
s16 roomnumsbyprop[200];
|
||||
RoomNum roomnumsbyprop[200];
|
||||
struct prop **ptr;
|
||||
struct drawslot *thing;
|
||||
s16 *roomnumptr;
|
||||
RoomNum *roomnumptr;
|
||||
struct prop *prop;
|
||||
s16 tmp;
|
||||
s16 *room;
|
||||
RoomNum *room;
|
||||
s16 roomorder[60];
|
||||
s16 roomnums[60];
|
||||
RoomNum roomnums[60];
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
g_NumRoomsWithGlares = 0;
|
||||
#endif
|
||||
|
||||
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
|
||||
gdl = bgRenderSceneInXray(gdl);
|
||||
@@ -1201,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl)
|
||||
gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop);
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage
|
||||
if (!g_Vars.mplayerisrunning) {
|
||||
artifactsCalculateGlaresForRoom(thing->roomnum);
|
||||
|
||||
@@ -1208,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl)
|
||||
g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
@@ -1492,6 +1501,9 @@ void bgReset(s32 stagenum)
|
||||
// Copy section 1 header to stack and parse into variables
|
||||
header = (u8 *)ALIGN16((uintptr_t)headerbuffer);
|
||||
bgLoadFile(header, 0, 0x40);
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection1Header(header, 0x40);
|
||||
#endif
|
||||
inflatedsize = *(u32 *)&header[0];
|
||||
section1compsize = *(u32 *)&header[4];
|
||||
primcompsize = *(u32 *)&header[8];
|
||||
@@ -1516,6 +1528,10 @@ void bgReset(s32 stagenum)
|
||||
scratch += 0xc;
|
||||
bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection1(g_BgPrimaryData, 0x0f000000);
|
||||
#endif
|
||||
|
||||
// Shrink the allocation (ie. free the scratch space)
|
||||
mempRealloc(g_BgPrimaryData, inflatedsize, MEMPOOL_STAGE);
|
||||
|
||||
@@ -1523,6 +1539,9 @@ void bgReset(s32 stagenum)
|
||||
section2start = section1compsize + 0xc;
|
||||
|
||||
bgLoadFile(header, section2start, 0x40);
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection2Header(header, 0x40);
|
||||
#endif
|
||||
|
||||
inflatedsize = (*(u16 *) &header[0] & 0x7fff) - 1;
|
||||
section2compsize = *(u16 *) &header[2];
|
||||
@@ -1552,6 +1571,10 @@ void bgReset(s32 stagenum)
|
||||
// Iterate texture IDs and ensure they're loaded
|
||||
inflatedsize = (*(u16 *) &header[0] & 0x7fff) >> 1;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection2((u8 *)section2, inflatedsize);
|
||||
#endif
|
||||
|
||||
for (i = 0; i ^ inflatedsize; i++) {
|
||||
texLoadFromTextureNum(section2[i] & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff, NULL);
|
||||
}
|
||||
@@ -1667,6 +1690,9 @@ void bgBuildTables(s32 stagenum)
|
||||
g_Rooms[i].unk4d = 0;
|
||||
g_Rooms[i].lightop = 0;
|
||||
g_Rooms[i].unk4e_04 = 0;
|
||||
#ifndef PLATFORM_N64
|
||||
g_Rooms[i].extra_flags = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bgSetStageTranslationThing(g_Stages[g_StageIndex].unk14);
|
||||
@@ -1891,6 +1917,9 @@ void bgBuildTables(s32 stagenum)
|
||||
// Load and read the header
|
||||
header = (u8 *)ALIGN16((uintptr_t)headerbuffer);
|
||||
bgLoadFile(header, g_BgSection3, 0x40);
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection3Header(header, 0x40);
|
||||
#endif
|
||||
inflatedsize = (*(u16 *)&header[0] & 0x7fff) - 1;
|
||||
section3compsize = *(u16 *)&header[2];
|
||||
inflatedsize = (inflatedsize | 0xf) + 1;
|
||||
@@ -1909,6 +1938,9 @@ void bgBuildTables(s32 stagenum)
|
||||
|
||||
bgLoadFile(scratch, g_BgSection3 + 4, ((section3compsize - 1) | 0xf) + 1);
|
||||
bgInflate(scratch, section3, section3compsize);
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection3(section3, section3compsize);
|
||||
#endif
|
||||
|
||||
// Section 3 starts with a table of room bounding boxes
|
||||
bboxptr = (s16 *) section3;
|
||||
@@ -1966,6 +1998,10 @@ void bgBuildTables(s32 stagenum)
|
||||
numlightsptr++;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgLights(g_BgLightsFileData, 0);
|
||||
#endif
|
||||
|
||||
// Free the section 3 allocation
|
||||
mempRealloc(section3, 0, MEMPOOL_STAGE);
|
||||
|
||||
@@ -2186,13 +2222,26 @@ Gfx *bgScissorToViewport(Gfx *gdl)
|
||||
|
||||
Gfx *bgScissorWithinViewportF(Gfx *gdl, f32 viewleft, f32 viewtop, f32 viewright, f32 viewbottom)
|
||||
{
|
||||
gdl = bgScissorWithinViewport(gdl, viewleft, viewtop, ceil(viewright), ceil(viewbottom));
|
||||
gdl = bgScissorWithinViewport(gdl, viewleft, viewtop, ceiltoint(viewright), ceiltoint(viewbottom));
|
||||
|
||||
return gdl;
|
||||
}
|
||||
|
||||
Gfx *bgScissorWithinViewport(Gfx *gdl, s32 viewleft, s32 viewtop, s32 viewright, s32 viewbottom)
|
||||
{
|
||||
#ifndef PLATFORM_N64
|
||||
const s32 xmargin = videoGetWidth() / SCREEN_320 - 1;
|
||||
const s32 ymargin = videoGetHeight() / SCREEN_240 - 1;
|
||||
if (xmargin > 0) {
|
||||
viewleft -= xmargin;
|
||||
viewright += xmargin;
|
||||
}
|
||||
if (ymargin > 0) {
|
||||
viewtop -= ymargin;
|
||||
viewbottom += ymargin;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (viewleft < g_Vars.currentplayer->viewleft) {
|
||||
viewleft = g_Vars.currentplayer->viewleft;
|
||||
}
|
||||
@@ -2762,12 +2811,23 @@ void bgLoadRoom(s32 roomnum)
|
||||
alloclen += 1024;
|
||||
}
|
||||
} else {
|
||||
#ifdef PLATFORM_N64
|
||||
alloclen = memaGetLongestFree();
|
||||
#else
|
||||
// probably never reaches here in practice as all rooms have gfxdatalen
|
||||
// alloc 10k and hope for the best
|
||||
alloclen = 10240;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
bgGarbageCollectRooms(alloclen, false);
|
||||
|
||||
allocation = memaAlloc(alloclen);
|
||||
#else
|
||||
// allocate room data from heap to not take up mema space
|
||||
allocation = sysMemAlloc(alloclen);
|
||||
#endif
|
||||
|
||||
if (allocation != NULL) {
|
||||
dyntexSetCurrentRoom(roomnum);
|
||||
@@ -2795,6 +2855,9 @@ void bgLoadRoom(s32 roomnum)
|
||||
|
||||
// Inflate the data to the left side of the allocation
|
||||
inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00);
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgRoom(allocation, g_BgRooms[roomnum].unk00);
|
||||
#endif
|
||||
|
||||
g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation;
|
||||
|
||||
@@ -2913,9 +2976,11 @@ void bgLoadRoom(s32 roomnum)
|
||||
|
||||
g_Rooms[roomnum].loaded240 = 1;
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
if (g_Rooms[roomnum].gfxdatalen != alloclen) {
|
||||
memaRealloc((intptr_t) allocation, alloclen, g_Rooms[roomnum].gfxdatalen);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update gdl pointers in the gfxdata so they point to the ones
|
||||
// that have been processed by textLoadFromGdl.
|
||||
@@ -3000,14 +3065,22 @@ void bgUnloadRoom(s32 roomnum)
|
||||
u32 size;
|
||||
|
||||
if (g_Rooms[roomnum].vtxbatches) {
|
||||
#ifdef PLATFORM_N64
|
||||
size = ((g_Rooms[roomnum].numvtxbatches) * sizeof(struct vtxbatch) + 0xf) & ~0xf;
|
||||
memaFree(g_Rooms[roomnum].vtxbatches, size);
|
||||
#else
|
||||
sysMemFree(g_Rooms[roomnum].vtxbatches);
|
||||
#endif
|
||||
g_Rooms[roomnum].vtxbatches = NULL;
|
||||
}
|
||||
|
||||
if (g_Rooms[roomnum].gfxdatalen > 0) {
|
||||
#ifdef PLATFORM_N64
|
||||
size = g_Rooms[roomnum].gfxdatalen;
|
||||
memaFree(g_Rooms[roomnum].gfxdata, size);
|
||||
#else
|
||||
sysMemFree(g_Rooms[roomnum].gfxdata);
|
||||
#endif
|
||||
g_Rooms[roomnum].gfxdata = NULL;
|
||||
}
|
||||
|
||||
@@ -3037,6 +3110,7 @@ void bgUnloadAllRooms(void)
|
||||
*/
|
||||
void bgGarbageCollectRooms(s32 bytesneeded, bool desparate)
|
||||
{
|
||||
#ifdef PLATFORM_N64 // don't need this on PC as rooms are allocated from heap
|
||||
s32 bytesfree = memaGetLongestFree();
|
||||
s32 oldestroom;
|
||||
s32 oldesttimer;
|
||||
@@ -3084,6 +3158,7 @@ void bgGarbageCollectRooms(s32 bytesneeded, bool desparate)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3144,8 +3219,13 @@ Gfx *bgRenderRoomPass(Gfx *gdl, s32 roomnum, struct roomblock *block, bool arg3)
|
||||
v0 = (uintptr_t)g_Rooms[roomnum].colours;
|
||||
|
||||
if (v0 != NULL) {
|
||||
#ifdef PLATFORM_N64
|
||||
s32 addr = ALIGN8((uintptr_t)&g_Rooms[roomnum].gfxdata->vertices[g_Rooms[roomnum].gfxdata->numvertices]);
|
||||
v0 += (((intptr_t)block->colours - addr) >> 2) * 4;
|
||||
#else
|
||||
uintptr_t addr = ALIGN8((uintptr_t)&g_Rooms[roomnum].gfxdata->vertices[g_Rooms[roomnum].gfxdata->numvertices]);
|
||||
v0 += (((uintptr_t)block->colours - addr) >> 2) * 4;
|
||||
#endif
|
||||
} else {
|
||||
v0 = (uintptr_t)block->colours;
|
||||
}
|
||||
@@ -3269,8 +3349,8 @@ s32 bgPopulateVtxBatchType(s32 roomnum, struct vtxbatch *batches, Gfx *gdl, s32
|
||||
batches[batchindex].bbmax.f[j] = -32768.0f;
|
||||
}
|
||||
|
||||
numvertices = (((u32)gdl[i].bytes[1] >> 4) & 0xf) + 1;
|
||||
batchvertices = (Vtx *)((uintptr_t)vertices + (gdl[i].words.w1 & 0xffffff));
|
||||
numvertices = (((u32)gdl[i].bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
|
||||
batchvertices = (Vtx *)((uintptr_t)vertices + (UNSEGADDR(gdl[i].words.w1) & 0xffffff));
|
||||
|
||||
for (j = 0; j < numvertices; j++) {
|
||||
f32 x = batchvertices[j].x;
|
||||
@@ -3369,7 +3449,11 @@ void bgFindRoomVtxBatches(s32 roomnum)
|
||||
|
||||
batchindex += xlucount;
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
batches = memaAlloc((batchindex * sizeof(struct vtxbatch) + 0xf) & ~0xf);
|
||||
#else
|
||||
batches = sysMemAlloc((batchindex * sizeof(struct vtxbatch) + 0xf) & ~0xf);
|
||||
#endif
|
||||
|
||||
if (batches != NULL) {
|
||||
gdl = bgGetNextGdlInLayer(roomnum, NULL, VTXBATCHTYPE_OPA);
|
||||
@@ -3578,9 +3662,19 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
|
||||
break;
|
||||
} else if (gdl->dma.cmd == G_VTX) {
|
||||
ptr = var800a6470;
|
||||
count = gdl->bytes[1] & 0xf;
|
||||
offset = (gdl->words.w1 & 0xffffff);
|
||||
numvertices = (((u32)gdl->bytes[1] >> 4) & 0xf) + 1;
|
||||
count = gdl->bytes[GFX_W0_BYTE(1)] & 0xf;
|
||||
#ifdef PLATFORM_N64
|
||||
offset = (UNSEGADDR(gdl->words.w1) & 0xffffff);
|
||||
#else
|
||||
if (gdl->words.w1 & 1) {
|
||||
// segmented address
|
||||
offset = (UNSEGADDR(gdl->words.w1) & 0xffffff);
|
||||
} else {
|
||||
// linear address
|
||||
offset = gdl->words.w1 - (uintptr_t)vertices;
|
||||
}
|
||||
#endif
|
||||
numvertices = (((u32) gdl->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
|
||||
vtx = (Vtx *)((uintptr_t)vertices + offset);
|
||||
vtx -= count;
|
||||
|
||||
@@ -3684,9 +3778,9 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
|
||||
if (gdl->dma.cmd == G_TRI1) {
|
||||
trisremaining = 0;
|
||||
triref = 0;
|
||||
points[0] = gdl->tri.tri.v[0] / 10;
|
||||
points[1] = gdl->tri.tri.v[1] / 10;
|
||||
points[2] = gdl->tri.tri.v[2] / 10;
|
||||
points[0] = gdl->tri.tri.v[GFX_TRI_VTX(0)] / 10;
|
||||
points[1] = gdl->tri.tri.v[GFX_TRI_VTX(1)] / 10;
|
||||
points[2] = gdl->tri.tri.v[GFX_TRI_VTX(2)] / 10;
|
||||
} else if (gdl->dma.cmd == G_TRI4) {
|
||||
tri4gdl = gdl;
|
||||
trisremaining = 3;
|
||||
@@ -3780,19 +3874,27 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
|
||||
hit = true;
|
||||
|
||||
if (imggdl == NULL
|
||||
#ifdef PLATFORM_N64
|
||||
|| (imggdl->words.w1 & 0x0f000000) == 0x0f000000
|
||||
|| (imggdl->words.w1 & 0x05000000) == 0x05000000) {
|
||||
#else // not sure if the above check even works right on N64, but we can test easily for seg addresses
|
||||
|| (imggdl->words.w1 & 1)) {
|
||||
#endif
|
||||
texturenum = -1;
|
||||
} else {
|
||||
s32 tmp = PHYS_TO_K0(imggdl->words.w1 - 8);
|
||||
#ifdef PLATFORM_N64
|
||||
s32 tmp = PHYS_TO_K0(UNSEGADDR(imggdl->words.w1) - 8);
|
||||
#else
|
||||
uintptr_t tmp = PHYS_TO_K0(UNSEGADDR(imggdl->words.w1) - 8);
|
||||
#endif
|
||||
texturenum = *(s16 *) tmp;
|
||||
}
|
||||
|
||||
lowestsqdist = sqdist;
|
||||
|
||||
hitthing->unk00.x = sp8c.x;
|
||||
hitthing->unk00.y = sp8c.y;
|
||||
hitthing->unk00.z = sp8c.z;
|
||||
hitthing->pos.x = sp8c.x;
|
||||
hitthing->pos.y = sp8c.y;
|
||||
hitthing->pos.z = sp8c.z;
|
||||
hitthing->unk0c.x = sp80.x;
|
||||
hitthing->unk0c.y = sp80.y;
|
||||
hitthing->unk0c.z = sp80.z;
|
||||
@@ -3875,13 +3977,13 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
|
||||
}
|
||||
break;
|
||||
} else if (gdl->dma.cmd == G_MTX) {
|
||||
word = gdl->words.w1 & 0xffffff;
|
||||
word = UNSEGADDR(gdl->words.w1) & 0xffffff;
|
||||
i = word / sizeof(Mtxf);
|
||||
mtx = &model->matrices[i];
|
||||
} else if (gdl->dma.cmd == G_VTX) {
|
||||
count = (gdl->bytes[1] & 0xf);
|
||||
word = gdl->words.w1 & 0xffffff;
|
||||
numvertices = ((u32)gdl->bytes[1] >> 4) + 1;
|
||||
count = (gdl->bytes[GFX_W0_BYTE(1)] & 0xf);
|
||||
word = UNSEGADDR(gdl->words.w1) & 0xffffff;
|
||||
numvertices = ((u32) gdl->bytes[GFX_W0_BYTE(1)] >> 4) + 1;
|
||||
vtx = (Vtx *)((uintptr_t)vertices + word);
|
||||
|
||||
if (count < spdc) {
|
||||
@@ -3971,9 +4073,9 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
|
||||
if (gdl->dma.cmd == G_TRI1) {
|
||||
i = 0;
|
||||
triref = 0;
|
||||
points[0] = gdl->tri.tri.v[0] / 10;
|
||||
points[1] = gdl->tri.tri.v[1] / 10;
|
||||
points[2] = gdl->tri.tri.v[2] / 10;
|
||||
points[0] = gdl->tri.tri.v[GFX_TRI_VTX(0)] / 10;
|
||||
points[1] = gdl->tri.tri.v[GFX_TRI_VTX(1)] / 10;
|
||||
points[2] = gdl->tri.tri.v[GFX_TRI_VTX(2)] / 10;
|
||||
} else if (gdl->dma.cmd == G_TRI4) {
|
||||
tri4gdl = gdl;
|
||||
i = 3;
|
||||
@@ -4068,9 +4170,9 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
|
||||
|
||||
*sqdistptr = sqdist;
|
||||
|
||||
hitthing->unk00.x = sp84.x;
|
||||
hitthing->unk00.y = sp84.y;
|
||||
hitthing->unk00.z = sp84.z;
|
||||
hitthing->pos.x = sp84.x;
|
||||
hitthing->pos.y = sp84.y;
|
||||
hitthing->pos.z = sp84.z;
|
||||
hitthing->unk0c.x = sp78.x;
|
||||
hitthing->unk0c.y = sp78.y;
|
||||
hitthing->unk0c.z = sp78.z;
|
||||
@@ -4141,8 +4243,8 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
|
||||
|
||||
vtx = bgFindVerticesForGdl(roomnum, gdl);
|
||||
iter = &gdl[batch->gbicmdindex];
|
||||
vtx = (Vtx *)((iter->words.w1 & 0xffffff) + (s32)vtx);
|
||||
numvertices = (((u32)iter->bytes[1] >> 4) & 0xf) + 1;
|
||||
vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (s32)vtx);
|
||||
numvertices = (((u32) iter->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
|
||||
ptr = var800a6470;
|
||||
|
||||
while (numvertices > 0) {
|
||||
@@ -4169,9 +4271,9 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
|
||||
if (iter->dma.cmd == G_TRI1) {
|
||||
trisremaining = 0;
|
||||
triref = 0;
|
||||
points[0] = iter->tri.tri.v[0] / 10;
|
||||
points[1] = iter->tri.tri.v[1] / 10;
|
||||
points[2] = iter->tri.tri.v[2] / 10;
|
||||
points[0] = iter->tri.tri.v[GFX_TRI_VTX(0)] / 10;
|
||||
points[1] = iter->tri.tri.v[GFX_TRI_VTX(1)] / 10;
|
||||
points[2] = iter->tri.tri.v[GFX_TRI_VTX(2)] / 10;
|
||||
} else if (iter->dma.cmd == G_TRI4) {
|
||||
tri4gdl = iter;
|
||||
trisremaining = 3;
|
||||
@@ -4272,29 +4374,41 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
|
||||
|
||||
tmpgdl = iter;
|
||||
|
||||
while (tmpgdl->bytes[0] != G_SETTIMG && tmpgdl > gdl) {
|
||||
while (tmpgdl->bytes[GFX_W0_BYTE(0)] != G_SETTIMG && tmpgdl > gdl) {
|
||||
tmpgdl--;
|
||||
}
|
||||
|
||||
if (tmpgdl == gdl
|
||||
#ifdef PLATFORM_N64
|
||||
|| (tmpgdl->words.w1 & 0x0f000000) == 0x0f000000
|
||||
|| (tmpgdl->words.w1 & 0x05000000) == 0x05000000) {
|
||||
#else // not sure if the above check even works right on N64, but we can test easily for seg addresses
|
||||
|| (tmpgdl->words.w1 & 1)) {
|
||||
#endif
|
||||
texturenum = -1;
|
||||
} else {
|
||||
s32 tmp = tmpgdl->words.w1 - 8;
|
||||
#ifdef PLATFORM_N64
|
||||
s32 tmp = UNSEGADDR(tmpgdl->words.w1) - 8;
|
||||
#else
|
||||
uintptr_t tmp = UNSEGADDR(tmpgdl->words.w1) - 8;
|
||||
#endif
|
||||
texturenum = *(s16 *) PHYS_TO_K0(tmp);
|
||||
}
|
||||
|
||||
#ifdef AVOID_UB
|
||||
if (batch->type == VTXBATCHTYPE_XLU && texturenum >= 0 && g_Textures[texturenum].surfacetype == SURFACETYPE_DEFAULT) {
|
||||
#else
|
||||
if (batch->type == VTXBATCHTYPE_XLU && g_Textures[texturenum].surfacetype == SURFACETYPE_DEFAULT) {
|
||||
#endif
|
||||
hit = false;
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
lowestsqdist = sqdist;
|
||||
|
||||
hitthing->unk00.x = spb0.x;
|
||||
hitthing->unk00.y = spb0.y;
|
||||
hitthing->unk00.z = spb0.z;
|
||||
hitthing->pos.x = spb0.x;
|
||||
hitthing->pos.y = spb0.y;
|
||||
hitthing->pos.z = spb0.z;
|
||||
hitthing->unk0c.x = spa4.x;
|
||||
hitthing->unk0c.y = spa4.y;
|
||||
hitthing->unk0c.z = spa4.z;
|
||||
@@ -4469,20 +4583,20 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
|
||||
numbatches = g_Rooms[roomnum].numvtxbatches;
|
||||
|
||||
for (i = 0; i < numbatches; batch++, i++) {
|
||||
j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->unk00);
|
||||
j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->pos);
|
||||
|
||||
if (j == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j == 1) {
|
||||
f0 = from.x - hitthing->unk00.x;
|
||||
f0 = from.x - hitthing->pos.x;
|
||||
f20 = f0 * f0;
|
||||
|
||||
f0 = from.y - hitthing->unk00.y;
|
||||
f0 = from.y - hitthing->pos.y;
|
||||
f20 += f0 * f0;
|
||||
|
||||
f0 = from.z - hitthing->unk00.z;
|
||||
f0 = from.z - hitthing->pos.z;
|
||||
f20 += f0 * f0;
|
||||
} else {
|
||||
f20 = -1.0f;
|
||||
@@ -4512,13 +4626,13 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
|
||||
|
||||
for (j = 0; j < ARRAYCOUNT(var800a6538); j++) {
|
||||
if (bgTestHitInVtxBatch(&from, &to, &dist, &g_Rooms[roomnum].vtxbatches[var800a6538[j].vtxbatchindex], roomnum, hitthing)) {
|
||||
f0 = from.x - hitthing->unk00.x;
|
||||
f0 = from.x - hitthing->pos.x;
|
||||
f2 = f0 * f0;
|
||||
|
||||
f0 = from.y - hitthing->unk00.y;
|
||||
f0 = from.y - hitthing->pos.y;
|
||||
f2 += f0 * f0;
|
||||
|
||||
f0 = from.z - hitthing->unk00.z;
|
||||
f0 = from.z - hitthing->pos.z;
|
||||
f2 += f0 * f0;
|
||||
|
||||
if (count == 0) {
|
||||
@@ -4564,31 +4678,31 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
|
||||
i++;
|
||||
|
||||
if (i < count) {
|
||||
f0 = from.x - hitthing->unk00.x;
|
||||
f0 = from.x - hitthing->pos.x;
|
||||
spc8 = f0 * f0;
|
||||
|
||||
f0 = from.y - hitthing->unk00.y;
|
||||
f0 = from.y - hitthing->pos.y;
|
||||
spc8 += f0 * f0;
|
||||
|
||||
f0 = from.z - hitthing->unk00.z;
|
||||
f0 = from.z - hitthing->pos.z;
|
||||
spc8 += f0 * f0;
|
||||
|
||||
for (; i < count; i++) {
|
||||
if (var800a6538[i].unk04 <= spc8) {
|
||||
if (bgTestHitInVtxBatch(&from, &to, &dist, &batch[var800a6538[i].vtxbatchindex], roomnum, &sp60)) {
|
||||
f0 = from.f[0] - sp60.unk00.f[0];
|
||||
f0 = from.f[0] - sp60.pos.f[0];
|
||||
f20 = f0 * f0;
|
||||
|
||||
f0 = from.f[1] - sp60.unk00.f[1];
|
||||
f0 = from.f[1] - sp60.pos.f[1];
|
||||
f20 += f0 * f0;
|
||||
|
||||
f0 = from.f[2] - sp60.unk00.f[2];
|
||||
f0 = from.f[2] - sp60.pos.f[2];
|
||||
f20 += f0 * f0;
|
||||
|
||||
if (f20 < spc8) {
|
||||
hitthing->unk00.x = sp60.unk00.x;
|
||||
hitthing->unk00.y = sp60.unk00.y;
|
||||
hitthing->unk00.z = sp60.unk00.z;
|
||||
hitthing->pos.x = sp60.pos.x;
|
||||
hitthing->pos.y = sp60.pos.y;
|
||||
hitthing->pos.z = sp60.pos.z;
|
||||
hitthing->unk0c.x = sp60.unk0c.x;
|
||||
hitthing->unk0c.y = sp60.unk0c.y;
|
||||
hitthing->unk0c.z = sp60.unk0c.z;
|
||||
@@ -4619,7 +4733,7 @@ bool bgRoomIsLoaded(s32 room)
|
||||
return g_Rooms[room].loaded240;
|
||||
}
|
||||
|
||||
bool bgRoomContainsCoord(struct coord *pos, s16 roomnum)
|
||||
bool bgRoomContainsCoord(struct coord *pos, RoomNum roomnum)
|
||||
{
|
||||
struct coord copy;
|
||||
copy.x = pos->x;
|
||||
@@ -4646,7 +4760,7 @@ bool bgRoomContainsCoord(struct coord *pos, s16 roomnum)
|
||||
* - The normal points towards the front of the portal.
|
||||
* - The room on the front side is roomnum2.
|
||||
*/
|
||||
bool bgTestPosInRoomCheap(struct coord *pos, s16 roomnum)
|
||||
bool bgTestPosInRoomCheap(struct coord *pos, RoomNum roomnum)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
@@ -4672,7 +4786,7 @@ bool bgTestPosInRoomCheap(struct coord *pos, s16 roomnum)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bgTestPosInRoomExpensive(struct coord *pos, s16 roomnum)
|
||||
bool bgTestPosInRoomExpensive(struct coord *pos, RoomNum roomnum)
|
||||
{
|
||||
s32 t5;
|
||||
struct coord *next;
|
||||
@@ -4780,7 +4894,7 @@ bool bgTestPosInRoomExpensive(struct coord *pos, s16 roomnum)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bgTestPosInRoom(struct coord *pos, s16 roomnum)
|
||||
bool bgTestPosInRoom(struct coord *pos, RoomNum roomnum)
|
||||
{
|
||||
if (g_Rooms[roomnum].flags & ROOMFLAG_COMPLICATEDPORTALS) {
|
||||
return bgTestPosInRoomExpensive(pos, roomnum);
|
||||
@@ -4809,7 +4923,7 @@ bool bgTestPosInRoom(struct coord *pos, s16 roomnum)
|
||||
* to pos and writes the room number to the bestroom pointer. The bestroom
|
||||
* pointer is a pointer to a single s16 rather than an array.
|
||||
*/
|
||||
void bgFindRoomsByPos(struct coord *posarg, s16 *inrooms, s16 *aboverooms, s32 max, s16 *bestroom)
|
||||
void bgFindRoomsByPos(struct coord *posarg, RoomNum *inrooms, RoomNum *aboverooms, s32 max, RoomNum *bestroom)
|
||||
{
|
||||
s32 inlen = 0;
|
||||
s32 abovelen = 0;
|
||||
@@ -5332,7 +5446,7 @@ void bgTickPortalsXray(void)
|
||||
bgChooseRoomsToLoad();
|
||||
}
|
||||
|
||||
void bgAddToSnake(s16 fromroomnum, s16 roomnum, s16 depth, struct screenbox *box)
|
||||
void bgAddToSnake(RoomNum fromroomnum, RoomNum roomnum, s16 depth, struct screenbox *box)
|
||||
{
|
||||
struct bgsnakeitem *item;
|
||||
s32 i;
|
||||
@@ -5419,10 +5533,10 @@ void bgConsumeSnakeItem(struct bgsnakeitem *item)
|
||||
s32 i;
|
||||
s16 portalnum;
|
||||
s16 prevvalidcount;
|
||||
s16 prevfoundroom;
|
||||
s16 newfoundroom;
|
||||
RoomNum prevfoundroom;
|
||||
RoomNum newfoundroom;
|
||||
s16 side;
|
||||
s16 tmp;
|
||||
RoomNum tmp;
|
||||
bool pass;
|
||||
struct portalmetric *metric;
|
||||
struct screenbox prevbox;
|
||||
@@ -5832,7 +5946,7 @@ Gfx *bgRenderSceneAndLoadCandidate(Gfx *gdl)
|
||||
return gdl;
|
||||
}
|
||||
|
||||
s32 bgGetForceOnscreenRooms(s16 *rooms, s32 len)
|
||||
s32 bgGetForceOnscreenRooms(RoomNum *rooms, s32 len)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
@@ -5845,7 +5959,7 @@ s32 bgGetForceOnscreenRooms(s16 *rooms, s32 len)
|
||||
return i;
|
||||
}
|
||||
|
||||
s32 bgRoomGetNeighbours(s32 roomnum, s16 *dstrooms, s32 len)
|
||||
s32 bgRoomGetNeighbours(s32 roomnum, RoomNum *dstrooms, s32 len)
|
||||
{
|
||||
s32 count = 0;
|
||||
s32 i;
|
||||
@@ -5991,7 +6105,7 @@ bool bgPortalExists(s32 portalnum)
|
||||
|
||||
void bgPortalSwapRooms(s32 portal)
|
||||
{
|
||||
s16 tmp = g_BgPortals[portal].roomnum1;
|
||||
RoomNum tmp = g_BgPortals[portal].roomnum1;
|
||||
g_BgPortals[portal].roomnum1 = g_BgPortals[portal].roomnum2;
|
||||
g_BgPortals[portal].roomnum2 = tmp;
|
||||
}
|
||||
@@ -6210,10 +6324,10 @@ void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbm
|
||||
}
|
||||
}
|
||||
|
||||
void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, s16 *rooms, s32 maxlen, bool arg4)
|
||||
void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms, s32 maxlen, bool arg4)
|
||||
{
|
||||
s16 room;
|
||||
s16 otherroom;
|
||||
RoomNum room;
|
||||
RoomNum otherroom;
|
||||
s32 portalnum;
|
||||
struct coord propbbmin;
|
||||
struct coord propbbmax;
|
||||
@@ -6287,3 +6401,25 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, s16 *rooms, s3
|
||||
end:
|
||||
rooms[len] = -1;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
|
||||
void bgCalculateGlaresForVisibleRooms(void)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
g_NumRoomsWithGlares = 0;
|
||||
|
||||
if (!g_Vars.mplayerisrunning) {
|
||||
for (i = 1; i < g_Vars.roomcount; i++) {
|
||||
if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) {
|
||||
artifactsCalculateGlaresForRoom(i);
|
||||
if (g_NumRoomsWithGlares < 100) {
|
||||
g_GlareRooms[g_NumRoomsWithGlares++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+3
-3
@@ -346,7 +346,7 @@ s32 bodyChooseHead(s32 bodynum)
|
||||
void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
|
||||
{
|
||||
struct pad pad;
|
||||
s16 rooms[2];
|
||||
RoomNum rooms[2];
|
||||
struct chrdata *chr;
|
||||
struct modeldef *headmodeldef;
|
||||
struct model *model;
|
||||
@@ -531,9 +531,9 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
|
||||
}
|
||||
}
|
||||
|
||||
struct prop *bodyAllocateEyespy(struct pad *pad, s16 room)
|
||||
struct prop *bodyAllocateEyespy(struct pad *pad, RoomNum room)
|
||||
{
|
||||
s16 rooms[2];
|
||||
RoomNum rooms[2];
|
||||
struct prop *prop;
|
||||
struct chrdata *chr;
|
||||
struct model *model;
|
||||
|
||||
+23
-13
@@ -107,7 +107,7 @@ void bbikeTryDismountAngle(f32 relativeangle, f32 distance)
|
||||
struct hoverbikeobj *bike;
|
||||
f32 angle;
|
||||
struct coord pos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
s32 result;
|
||||
f32 ymax;
|
||||
f32 ymin;
|
||||
@@ -202,14 +202,24 @@ void bbikeApplyMoveData(struct movedata *data)
|
||||
s8 contnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
|
||||
f32 value1;
|
||||
f32 tmp;
|
||||
s32 contmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
|
||||
|
||||
if ((optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_12
|
||||
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_14
|
||||
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_13
|
||||
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_11)
|
||||
if ((contmode == CONTROLMODE_12
|
||||
|| contmode == CONTROLMODE_14
|
||||
|| contmode == CONTROLMODE_13
|
||||
|| contmode == CONTROLMODE_11
|
||||
|| contmode == CONTROLMODE_PC)
|
||||
&& !lvIsPaused()) {
|
||||
data->digitalstepleft = joyCountButtonsOnSpecificSamples(0, contnum, L_JPAD | L_CBUTTONS);
|
||||
data->digitalstepright = joyCountButtonsOnSpecificSamples(0, contnum, R_JPAD | R_CBUTTONS);
|
||||
u32 lmask, rmask;
|
||||
if (contmode == CONTROLMODE_PC) {
|
||||
lmask = L_CBUTTONS;
|
||||
rmask = R_CBUTTONS;
|
||||
} else {
|
||||
lmask = L_JPAD | L_CBUTTONS;
|
||||
rmask = R_JPAD | R_CBUTTONS;
|
||||
}
|
||||
data->digitalstepleft = joyCountButtonsOnSpecificSamples(0, contnum, lmask);
|
||||
data->digitalstepright = joyCountButtonsOnSpecificSamples(0, contnum, rmask);
|
||||
}
|
||||
|
||||
// Forward/back
|
||||
@@ -281,10 +291,10 @@ void bbikeApplyMoveData(struct movedata *data)
|
||||
|
||||
sp3c = -bike->exreal;
|
||||
|
||||
if (bike->hov.unk14 < M_PI) {
|
||||
sp3c += -bike->hov.unk14 * 0.8f;
|
||||
if (bike->hov.bobpitchcur < M_PI) {
|
||||
sp3c += -bike->hov.bobpitchcur * 0.8f;
|
||||
} else {
|
||||
sp3c += (M_BADTAU - bike->hov.unk14) * 0.8f;
|
||||
sp3c += (M_BADTAU - bike->hov.bobpitchcur) * 0.8f;
|
||||
}
|
||||
|
||||
if (sp3c < 0) {
|
||||
@@ -371,11 +381,11 @@ s32 bbikeCalculateNewPosition(struct coord *vel, f32 angledelta)
|
||||
{
|
||||
s32 result = CDRESULT_NOCOLLISION;
|
||||
struct coord dstpos;
|
||||
s16 dstrooms[8];
|
||||
RoomNum dstrooms[8];
|
||||
struct hov hov;
|
||||
bool hasvel = false;
|
||||
struct hoverbikeobj *bike = (struct hoverbikeobj *) g_Vars.currentplayer->hoverbike->obj;
|
||||
s16 spa8[20];
|
||||
RoomNum spa8[20];
|
||||
f32 xdiff;
|
||||
f32 zdiff;
|
||||
f32 ymax;
|
||||
@@ -530,7 +540,7 @@ void bbikeUpdateVertical(struct coord *pos)
|
||||
{
|
||||
struct defaultobj *bike = g_Vars.currentplayer->hoverbike->obj;
|
||||
f32 angle;
|
||||
s16 newrooms[8];
|
||||
RoomNum newrooms[8];
|
||||
bool newinlift;
|
||||
struct prop *lift = NULL;
|
||||
f32 ground;
|
||||
|
||||
+104
-17
@@ -24,6 +24,9 @@
|
||||
#include "lib/collision.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "input.h"
|
||||
#endif
|
||||
|
||||
u8 g_EyespyPickup = false;
|
||||
u8 g_EyespyHit = EYESPYHIT_NONE;
|
||||
@@ -39,7 +42,7 @@ u32 g_EyespyMaxFallSpeed = 3000;
|
||||
* position 50 units above the current position, or less if the eyespy is near
|
||||
* the top of its height range.
|
||||
*/
|
||||
f32 eyespyFindGround(s16 *floorroom)
|
||||
f32 eyespyFindGround(RoomNum *floorroom)
|
||||
{
|
||||
struct prop *prop = g_Vars.currentplayer->eyespy->prop;
|
||||
s32 inlift;
|
||||
@@ -75,7 +78,7 @@ s32 eyespyTryMoveUpwards(f32 yvel)
|
||||
struct prop *prop = g_Vars.currentplayer->eyespy->prop;
|
||||
struct chrdata *chr = prop->chr;
|
||||
struct coord dstpos;
|
||||
s16 dstrooms[8];
|
||||
RoomNum dstrooms[8];
|
||||
s32 types;
|
||||
u32 stack;
|
||||
f32 f0;
|
||||
@@ -118,9 +121,9 @@ s32 eyespyCalculateNewPosition(struct coord *vel)
|
||||
struct prop *eyespyprop = g_Vars.currentplayer->eyespy->prop;
|
||||
struct chrdata *chr = eyespyprop->chr;
|
||||
struct coord dstpos;
|
||||
s16 dstrooms[8];
|
||||
s16 floorroom;
|
||||
s16 sp74[24];
|
||||
RoomNum dstrooms[8];
|
||||
RoomNum floorroom;
|
||||
RoomNum sp74[24];
|
||||
s32 types;
|
||||
s32 i;
|
||||
f32 ymin;
|
||||
@@ -698,8 +701,8 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
s8 c2stickx;
|
||||
s8 c1sticky = joyGetStickY(contpad1);
|
||||
s8 c2sticky;
|
||||
u16 c1buttons = allowbuttons ? joyGetButtons(contpad1, 0xffff) : 0;
|
||||
u16 c2buttons;
|
||||
u32 c1buttons = allowbuttons ? joyGetButtons(contpad1, 0xffffffff) : 0;
|
||||
u32 c2buttons;
|
||||
bool domovecentre = true;
|
||||
s32 controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
|
||||
|
||||
@@ -713,20 +716,42 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
f32 angle;
|
||||
f32 ascendspeed = 0.0f;
|
||||
f32 prevverta = g_Vars.currentplayer->eyespy->verta;
|
||||
s16 prevrooms[8];
|
||||
RoomNum prevrooms[8];
|
||||
s32 contpad2;
|
||||
u32 stack[5];
|
||||
f32 tmp;
|
||||
u32 umask, dmask, lmask, rmask;
|
||||
|
||||
if (controlmode >= CONTROLMODE_21) {
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
umask = U_CBUTTONS;
|
||||
dmask = D_CBUTTONS;
|
||||
lmask = L_CBUTTONS;
|
||||
rmask = R_CBUTTONS;
|
||||
} else {
|
||||
umask = U_JPAD | U_CBUTTONS;
|
||||
dmask = D_JPAD | D_CBUTTONS;
|
||||
lmask = L_JPAD | L_CBUTTONS;
|
||||
rmask = R_JPAD | R_CBUTTONS;
|
||||
}
|
||||
|
||||
if (controlmode >= CONTROLMODE_21 && controlmode < CONTROLMODE_PC) {
|
||||
contpad2 = (s8) optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex);
|
||||
c2stickx = joyGetStickX(contpad2);
|
||||
c2sticky = joyGetStickY(contpad2);
|
||||
|
||||
c2buttons = allowbuttons ? joyGetButtons(contpad2, 0xffff) : 0;
|
||||
c2buttons = allowbuttons ? joyGetButtons(contpad2, 0xffffffff) : 0;
|
||||
} else {
|
||||
#ifndef PLATFORM_N64
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
c2stickx = joyGetRStickX(contpad1);
|
||||
c2sticky = joyGetRStickY(contpad1);
|
||||
} else
|
||||
#else
|
||||
{
|
||||
c2stickx = c1stickx;
|
||||
c2sticky = c1sticky;
|
||||
}
|
||||
#endif
|
||||
c2buttons = c1buttons;
|
||||
}
|
||||
|
||||
@@ -735,11 +760,19 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
shootpressed = c1buttons & A_BUTTON;
|
||||
exitpressed = c1buttons & R_TRIG;
|
||||
activatepressed = c1buttons & B_BUTTON;
|
||||
} else if (controlmode <= CONTROLMODE_14) {
|
||||
aimpressed = c1buttons & (L_TRIG | R_TRIG);
|
||||
} else if (controlmode <= CONTROLMODE_14 || controlmode == CONTROLMODE_PC) {
|
||||
aimpressed = c1buttons & (R_TRIG);
|
||||
shootpressed = c1buttons & Z_TRIG;
|
||||
exitpressed = c1buttons & A_BUTTON;
|
||||
activatepressed = c1buttons & B_BUTTON;
|
||||
#ifndef PLATFORM_N64
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
exitpressed = c1buttons & (BUTTON_WPNBACK | BUTTON_RADIAL);
|
||||
activatepressed = c1buttons & (BUTTON_CANCEL_USE | BUTTON_ACCEPT_USE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
exitpressed = (c1buttons | c2buttons) & A_BUTTON;
|
||||
activatepressed = (c1buttons | c2buttons) & B_BUTTON;
|
||||
}
|
||||
} else {
|
||||
if (controlmode >= CONTROLMODE_23) {
|
||||
aimpressed = c1buttons & Z_TRIG;
|
||||
@@ -818,16 +851,24 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
|
||||
ascendspeed = (c1buttons & (U_CBUTTONS | U_JPAD) ? 1 : 0) - (c1buttons & (D_CBUTTONS | D_JPAD) ? 1 : 0);
|
||||
sidespeed = (c1buttons & (R_CBUTTONS | R_JPAD) ? 1 : 0) - (c1buttons & (L_CBUTTONS | L_JPAD) ? 1 : 0);
|
||||
} else if (controlmode <= CONTROLMODE_14) {
|
||||
} else if (controlmode <= CONTROLMODE_14 || controlmode == CONTROLMODE_PC) {
|
||||
if (aimpressed) {
|
||||
domovecentre = false;
|
||||
pitchspeed = c1sticky;
|
||||
} else {
|
||||
ascendspeed = c1sticky * 0.25f;
|
||||
forwardspeed = (c1buttons & (U_CBUTTONS | U_JPAD) ? 24.0f : 0) - (c1buttons & (D_CBUTTONS | D_JPAD) ? 24.0f : 0);
|
||||
forwardspeed = (c1buttons & umask ? 24.0f : 0) - (c1buttons & dmask ? 24.0f : 0);
|
||||
#ifndef PLATFORM_N64
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
forwardspeed += c2sticky;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sidespeed = (c1buttons & (R_CBUTTONS | R_JPAD) ? 1 : 0) - (c1buttons & (L_CBUTTONS | L_JPAD) ? 1 : 0);
|
||||
sidespeed = (c1buttons & rmask ? 1 : 0) - (c1buttons & lmask ? 1 : 0);
|
||||
#ifndef PLATFORM_N64
|
||||
if (!sidespeed && controlmode == CONTROLMODE_PC) sidespeed = c2stickx * 0.0125f;
|
||||
#endif
|
||||
} else if (controlmode == CONTROLMODE_21 || controlmode == CONTROLMODE_23) {
|
||||
forwardspeed = c1sticky;
|
||||
|
||||
@@ -898,6 +939,25 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_Vars.currentplayernum == 0) {
|
||||
f32 mdx, mdy;
|
||||
inputMouseGetScaledDelta(&mdx, &mdy);
|
||||
if (mdx || mdy) {
|
||||
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
|
||||
mdy = -mdy;
|
||||
}
|
||||
g_Vars.currentplayer->eyespy->theta += mdx * 1.5f;
|
||||
// hold aim to move up and down, release to look up and down
|
||||
if (aimpressed) {
|
||||
ascendspeed -= mdy;
|
||||
} else {
|
||||
g_Vars.currentplayer->eyespy->verta -= mdy * 1.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update theta
|
||||
g_Vars.currentplayer->eyespy->theta += c1stickx * 0.0625f * g_Vars.lvupdate60freal;
|
||||
|
||||
@@ -913,9 +973,28 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
g_Vars.currentplayer->eyespy->sintheta = sinf(g_Vars.currentplayer->eyespy->theta * 0.017453292384744f);
|
||||
|
||||
// Update verta
|
||||
#ifndef PLATFORM_N64
|
||||
// respect the invert pitch setting
|
||||
if (optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
|
||||
pitchspeed = -pitchspeed;
|
||||
}
|
||||
#endif
|
||||
g_Vars.currentplayer->eyespy->verta -= pitchspeed * 0.0625f * g_Vars.lvupdate60freal;
|
||||
|
||||
if (prevverta != g_Vars.currentplayer->eyespy->verta) {
|
||||
#ifndef PLATFORM_N64 // limit eyespy range to 75 degrees
|
||||
while (g_Vars.currentplayer->eyespy->verta > 90.0f) {
|
||||
g_Vars.currentplayer->eyespy->verta -= 360.0f;
|
||||
}
|
||||
|
||||
if (g_Vars.currentplayer->eyespy->verta < -75.0f) {
|
||||
g_Vars.currentplayer->eyespy->verta = -75.0f;
|
||||
}
|
||||
|
||||
if (g_Vars.currentplayer->eyespy->verta > 75.0f) {
|
||||
g_Vars.currentplayer->eyespy->verta = 75.0f;
|
||||
}
|
||||
#endif
|
||||
while (g_Vars.currentplayer->eyespy->verta < 0.0f) {
|
||||
g_Vars.currentplayer->eyespy->verta += 360.0f;
|
||||
}
|
||||
@@ -937,6 +1016,7 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
// Make eyespy look horizontally
|
||||
if (domovecentre) {
|
||||
if (g_Vars.currentplayer->eyespy->verta > 0.0f && forwardspeed != 0) {
|
||||
if (controlmode < CONTROLMODE_PC) {
|
||||
if (g_Vars.currentplayer->eyespy->verta < 180.0f) {
|
||||
tmp = g_Vars.currentplayer->eyespy->verta;
|
||||
|
||||
@@ -952,6 +1032,7 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
g_Vars.currentplayer->eyespy->verta += tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_Vars.currentplayer->eyespy->cosverta = cosf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f);
|
||||
g_Vars.currentplayer->eyespy->sinverta = sinf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f);
|
||||
@@ -1017,7 +1098,13 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
if (g_Vars.currentplayer->eyespy->bobactive || ABS(g_Vars.currentplayer->eyespy->vel.y) < 0.1f) {
|
||||
g_Vars.currentplayer->eyespy->bobactive = true;
|
||||
g_Vars.currentplayer->eyespy->bobtimer += g_Vars.lvupdate60;
|
||||
#ifdef PLATFORM_N64
|
||||
g_Vars.currentplayer->eyespy->vel.y += 0.025f * g_Vars.currentplayer->eyespy->bobdir;
|
||||
#else
|
||||
// HACK: how do I scale this properly?
|
||||
const f32 scale = (g_Vars.lvupdate60freal <= 1.1f) ? 0.0055f : 0.0125f;
|
||||
g_Vars.currentplayer->eyespy->vel.y += scale * g_Vars.lvupdate60freal * g_Vars.currentplayer->eyespy->bobdir;
|
||||
#endif
|
||||
|
||||
if (g_Vars.currentplayer->eyespy->bobtimer > TICKS(120)) {
|
||||
g_Vars.currentplayer->eyespy->bobtimer = 0;
|
||||
|
||||
+7
-7
@@ -84,7 +84,7 @@ void bgrabInit(void)
|
||||
|
||||
if (hov) {
|
||||
g_Vars.currentplayer->grabbedrotoffset =
|
||||
hov->unk10 - (M_BADTAU - (g_Vars.currentplayer->vv_theta * M_BADTAU) / 360.0f);
|
||||
hov->yrot - (M_BADTAU - (g_Vars.currentplayer->vv_theta * M_BADTAU) / 360.0f);
|
||||
|
||||
if (g_Vars.currentplayer->grabbedrotoffset >= M_BADTAU) {
|
||||
g_Vars.currentplayer->grabbedrotoffset -= M_BADTAU;
|
||||
@@ -284,7 +284,7 @@ bool bgrabTryMoveUpwards(f32 y)
|
||||
{
|
||||
bool result;
|
||||
struct coord newpos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
f32 ymax;
|
||||
f32 ymin;
|
||||
f32 radius;
|
||||
@@ -320,7 +320,7 @@ s32 bgrabCalculateNewPosition(struct coord *delta, f32 angle, bool arg2)
|
||||
s32 cdresult = CDRESULT_NOCOLLISION;
|
||||
s32 i;
|
||||
struct coord pos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
bool ismoving = false;
|
||||
f32 ymax;
|
||||
f32 ymin;
|
||||
@@ -448,7 +448,7 @@ s32 bgrabCalculateNewPosition(struct coord *delta, f32 angle, bool arg2)
|
||||
- g_Vars.currentplayer->vv_theta * M_BADTAU / 360.0f
|
||||
+ -angle
|
||||
+ g_Vars.currentplayer->grabbedrotoffset
|
||||
- hov->unk10
|
||||
- hov->yrot
|
||||
+ rotextra;
|
||||
|
||||
while (sp78 >= M_PI) {
|
||||
@@ -1038,7 +1038,7 @@ void bgrab0f0ce924(void)
|
||||
g_Vars.currentplayer->speedforwards += sp70;
|
||||
g_Vars.currentplayer->speedsideways += sp6c;
|
||||
|
||||
mult = var80075c00[1].unk0c * 0.5f * g_Vars.lvupdate60freal;
|
||||
mult = g_HeadAnims[HEADANIM_MOVING].translateperframe * 0.5f * g_Vars.lvupdate60freal;
|
||||
sp88 = mult * g_Vars.currentplayer->speedsideways;
|
||||
|
||||
speedsideways = g_Vars.currentplayer->speedsideways * 0.8f;
|
||||
@@ -1149,7 +1149,7 @@ void bgrab0f0ce924(void)
|
||||
sp3c = -1.0f;
|
||||
}
|
||||
|
||||
if (g_Vars.currentplayer->headanim == 1) {
|
||||
if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
|
||||
breathing *= 1.2f;
|
||||
}
|
||||
|
||||
@@ -1207,7 +1207,7 @@ void bgrabTick(void)
|
||||
if (g_Vars.currentplayer->grabbedprop) {
|
||||
// Determine if the grabbed prop should be force released
|
||||
f32 ydiff = g_Vars.currentplayer->grabbedprop->pos.y
|
||||
- objGetHov04(g_Vars.currentplayer->grabbedprop->obj)
|
||||
- objGetHovBobOffsetY(g_Vars.currentplayer->grabbedprop->obj)
|
||||
- g_Vars.currentplayer->vv_manground;
|
||||
|
||||
struct prop *grabbedprop = g_Vars.currentplayer->grabbedprop;
|
||||
|
||||
+276
-67
@@ -53,6 +53,12 @@
|
||||
#include "lib/lib_317f0.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "game/stagetable.h"
|
||||
#include "video.h"
|
||||
#include "net/net.h"
|
||||
#include "net/netmsg.h"
|
||||
#endif
|
||||
|
||||
#define GUNLOADSTATE_FLUX 0
|
||||
#define GUNLOADSTATE_MODEL 1
|
||||
@@ -186,6 +192,10 @@ char var800700bc[][10] = {
|
||||
{ 'x','x','x' }, // "xxx"
|
||||
};
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
s32 g_BgunGeMuzzleFlashes = false;
|
||||
#endif
|
||||
|
||||
#if !MATCHING || VERSION >= VERSION_NTSC_1_0
|
||||
void bgunRumble(s32 handnum, s32 weaponnum)
|
||||
{
|
||||
@@ -246,8 +256,9 @@ void bgunRumble(s32 handnum, s32 weaponnum)
|
||||
bool contpad2hasrumble;
|
||||
s32 contpadtouse1;
|
||||
s32 contpadtouse2;
|
||||
s32 controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
|
||||
|
||||
if (optionsGetControlMode(g_Vars.currentplayerstats->mpindex) >= CONTROLMODE_21) {
|
||||
if (controlmode >= CONTROLMODE_21 && controlmode < CONTROLMODE_PC) {
|
||||
contpad1hasrumble = pakGetType(g_Vars.currentplayernum) == PAKTYPE_RUMBLE;
|
||||
contpad2hasrumble = pakGetType(g_Vars.currentplayernum + PLAYERCOUNT()) == PAKTYPE_RUMBLE;
|
||||
|
||||
@@ -1307,6 +1318,7 @@ s32 bgunTickIncIdle(struct handweaponinfo *info, s32 handnum, struct hand *hand,
|
||||
hand->count = 0;
|
||||
|
||||
if (bgunSetState(handnum, HANDSTATE_RELOAD)) {
|
||||
hand->modenext = HANDMODE_NONE;
|
||||
return lvupdate;
|
||||
}
|
||||
}
|
||||
@@ -1905,7 +1917,17 @@ void bgun0f09a6f8(struct handweaponinfo *info, s32 handnum, struct hand *hand, s
|
||||
if (func->flags & FUNCFLAG_NOMUZZLEFLASH) {
|
||||
hand->flashon = false;
|
||||
} else {
|
||||
#ifdef PLATFORM_N64
|
||||
hand->flashon = true;
|
||||
#else
|
||||
if (g_BgunGeMuzzleFlashes) {
|
||||
if (func->type == INVENTORYFUNCTYPE_SHOOT_SINGLE || (hand->shotstotake & 1)) {
|
||||
hand->flashon = true;
|
||||
}
|
||||
} else {
|
||||
hand->flashon = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bgunStartSlide(handnum);
|
||||
@@ -3624,6 +3646,7 @@ u32 bgunCalculateGunMemCapacity(void)
|
||||
}
|
||||
|
||||
if (PLAYERCOUNT() == 1) {
|
||||
#ifdef PLATFORM_N64
|
||||
switch (g_Vars.stagenum) {
|
||||
case STAGE_CHICAGO:
|
||||
case STAGE_AIRBASE:
|
||||
@@ -3632,6 +3655,9 @@ u32 bgunCalculateGunMemCapacity(void)
|
||||
case STAGE_ATTACKSHIP:
|
||||
return g_BgunGunMemBaseSizeDefault + 25 * 1024;
|
||||
}
|
||||
#else
|
||||
return g_BgunGunMemBaseSizeDefault + stageGetCurrent()->extragunmem;
|
||||
#endif
|
||||
}
|
||||
|
||||
return g_BgunGunMemBaseSizeDefault;
|
||||
@@ -3640,6 +3666,11 @@ u32 bgunCalculateGunMemCapacity(void)
|
||||
void bgunFreeGunMem(void)
|
||||
{
|
||||
g_Vars.currentplayer->gunctrl.gunmemowner = GUNMEMOWNER_FREE;
|
||||
#ifndef PLATFORM_N64
|
||||
// gunmem is stale and so are the textures in it
|
||||
// TODO: figure out how to purge only those textures
|
||||
videoResetTextureCache();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bgunSetGunMemWeapon(s32 weaponnum)
|
||||
@@ -4149,10 +4180,10 @@ void bgunTickMasterLoad(void)
|
||||
for (i = 0; i < 2; i++) {
|
||||
hand = &player->hands[i];
|
||||
|
||||
modelInit(&hand->gunmodel, player->gunctrl.gunmodeldef, (union modelrwdata **)hand->unk0a6c, 0);
|
||||
modelInit(&hand->gunmodel, player->gunctrl.gunmodeldef, hand->unk0a6c, 0);
|
||||
|
||||
if (player->gunctrl.handmodeldef != 0) {
|
||||
modelInit(&hand->handmodel, player->gunctrl.handmodeldef, (union modelrwdata **)hand->handsavedata, false);
|
||||
modelInit(&hand->handmodel, player->gunctrl.handmodeldef, hand->handsavedata, false);
|
||||
}
|
||||
|
||||
hand->unk0dcc = (s32 *) player->gunctrl.memloadptr;
|
||||
@@ -4280,7 +4311,7 @@ struct modeldef *bgunGetCartModeldef(void)
|
||||
return g_Vars.currentplayer->gunctrl.cartmodeldef;
|
||||
}
|
||||
|
||||
void bgun0f09ebcc(struct defaultobj *obj, struct coord *coord, s16 *rooms, Mtxf *matrix1, struct coord *velocity, Mtxf *matrix2, struct prop *prop, struct coord *pos)
|
||||
void bgun0f09ebcc(struct defaultobj *obj, struct coord *coord, RoomNum *rooms, Mtxf *matrix1, struct coord *velocity, Mtxf *matrix2, struct prop *prop, struct coord *pos)
|
||||
{
|
||||
struct prop *objprop = obj->prop;
|
||||
|
||||
@@ -4325,7 +4356,7 @@ void bgun0f09ed2c(struct defaultobj *obj, struct coord *newpos, Mtxf *arg2, stru
|
||||
{
|
||||
struct prop *objprop = obj->prop;
|
||||
struct coord pos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
|
||||
if (objprop) {
|
||||
struct prop *playerprop = g_Vars.currentplayer->prop;
|
||||
@@ -4348,7 +4379,7 @@ void bgun0f09ed2c(struct defaultobj *obj, struct coord *newpos, Mtxf *arg2, stru
|
||||
}
|
||||
}
|
||||
|
||||
struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset *gset, struct coord *pos, s16 *rooms, Mtxf *arg4, struct coord *velocity)
|
||||
struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset *gset, struct coord *pos, RoomNum *rooms, Mtxf *arg4, struct coord *velocity)
|
||||
{
|
||||
struct defaultobj *obj = NULL;
|
||||
struct weaponfunc *basefunc;
|
||||
@@ -4443,12 +4474,12 @@ struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset
|
||||
* 2 = fumbling grenade from right hand (due to nbomb)
|
||||
* 3 = fumbling grenade from left hand (actually not possible)
|
||||
*/
|
||||
void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
struct defaultobj *bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
{
|
||||
struct coord velocity = {0, 0, 0};
|
||||
Mtxf sp1f4;
|
||||
struct coord sp1e8;
|
||||
struct coord sp1dc;
|
||||
struct coord gunpos;
|
||||
struct coord gundir;
|
||||
struct prop *playerprop = g_Vars.currentplayer->prop;
|
||||
struct coord *prevpos = &g_Vars.currentplayer->bondprevpos;
|
||||
struct coord *extrapos = &g_Vars.currentplayer->bondextrapos;
|
||||
@@ -4457,7 +4488,7 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
struct weaponobj *weapon;
|
||||
struct coord muzzlepos;
|
||||
struct coord spawnpos;
|
||||
s16 spawnrooms[8];
|
||||
RoomNum spawnrooms[8];
|
||||
bool droppinggrenade = false;
|
||||
struct hand *hand;
|
||||
struct coord aimpos;
|
||||
@@ -4473,6 +4504,13 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
struct trainingdata *data;
|
||||
u32 stack;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
// don't do anything if we're not the authority
|
||||
if (g_NetMode == NETMODE_CLIENT) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (handnum >= 2) {
|
||||
droppinggrenade = true;
|
||||
handnum -= 2;
|
||||
@@ -4520,17 +4558,17 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
|
||||
playerSetPerimEnabled(playerprop, true);
|
||||
|
||||
bgunCalculatePlayerShotSpread(&sp1e8, &sp1dc, handnum, true);
|
||||
mtx4RotateVecInPlace(camGetProjectionMtxF(), &sp1dc);
|
||||
bgunCalculatePlayerShotSpread(&gunpos, &gundir, handnum, true);
|
||||
mtx4RotateVecInPlace(camGetProjectionMtxF(), &gundir);
|
||||
|
||||
if (droppinggrenade) {
|
||||
// Dropping a grenade because player is in an nbomb storm
|
||||
velocity.x = sp1dc.x * 1.6666666f;
|
||||
velocity.y = sp1dc.y * 1.6666666f;
|
||||
velocity.z = sp1dc.z * 1.6666666f;
|
||||
velocity.x = gundir.x * 1.6666666f;
|
||||
velocity.y = gundir.y * 1.6666666f;
|
||||
velocity.z = gundir.z * 1.6666666f;
|
||||
} else if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) {
|
||||
// Calculate the velocity based on the trajectory to the aimpos
|
||||
func0f061d54(0, 0, 0);
|
||||
propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
|
||||
|
||||
if (hand->hasdotinfo) {
|
||||
aimpos.x = hand->dotpos.x;
|
||||
@@ -4539,11 +4577,11 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
|
||||
chrCalculateTrajectory(&spawnpos, 21.666666f, &aimpos, &sp140);
|
||||
|
||||
radians = acosf(sp1dc.f[0] * sp140.f[0] + sp1dc.f[1] * sp140.f[1] + sp1dc.f[2] * sp140.f[2]);
|
||||
radians = acosf(gundir.f[0] * sp140.f[0] + gundir.f[1] * sp140.f[1] + gundir.f[2] * sp140.f[2]);
|
||||
|
||||
// Check within 20 degrees
|
||||
if (radians > 0.34901026f || radians < -0.34901026f) {
|
||||
mtx00016b58(&spf8, 0, 0, 0, sp1dc.x, sp1dc.y, sp1dc.z, 0, 1, 0);
|
||||
mtx00016b58(&spf8, 0, 0, 0, gundir.x, gundir.y, gundir.z, 0, 1, 0);
|
||||
mtx00016b58(&spb8, 0, 0, 0, sp140.x, sp140.y, sp140.z, 0, 1, 0);
|
||||
|
||||
quaternion0f097044(&spf8, sp68);
|
||||
@@ -4559,24 +4597,24 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
quaternionSlerp(sp68, sp58, frac, sp48);
|
||||
quaternionToMtx(sp48, &sp78);
|
||||
|
||||
sp1dc.x = -sp78.m[2][0];
|
||||
sp1dc.y = -sp78.m[2][1];
|
||||
sp1dc.z = -sp78.m[2][2];
|
||||
gundir.x = -sp78.m[2][0];
|
||||
gundir.y = -sp78.m[2][1];
|
||||
gundir.z = -sp78.m[2][2];
|
||||
} else {
|
||||
sp1dc.x = sp140.x;
|
||||
sp1dc.y = sp140.y;
|
||||
sp1dc.z = sp140.z;
|
||||
gundir.x = sp140.x;
|
||||
gundir.y = sp140.y;
|
||||
gundir.z = sp140.z;
|
||||
}
|
||||
}
|
||||
|
||||
velocity.x = sp1dc.x * 21.666666f;
|
||||
velocity.y = sp1dc.y * 21.666666f;
|
||||
velocity.z = sp1dc.z * 21.666666f;
|
||||
velocity.x = gundir.x * 21.666666f;
|
||||
velocity.y = gundir.y * 21.666666f;
|
||||
velocity.z = gundir.z * 21.666666f;
|
||||
} else {
|
||||
// Simple velocity
|
||||
velocity.x = sp1dc.x * 16.666666f;
|
||||
velocity.y = sp1dc.y * 16.666666f;
|
||||
velocity.z = sp1dc.z * 16.666666f;
|
||||
velocity.x = gundir.x * 16.666666f;
|
||||
velocity.y = gundir.y * 16.666666f;
|
||||
velocity.z = gundir.z * 16.666666f;
|
||||
|
||||
if (gset->weaponnum == WEAPON_GRENADE || gset->weaponnum == WEAPON_NBOMB) {
|
||||
velocity.y += 1.6666666f;
|
||||
@@ -4638,7 +4676,16 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
|
||||
weapon->base.hidden |= OBJHFLAG_THROWNKNIFE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (obj && g_NetMode == NETMODE_SERVER) {
|
||||
netmsgSvcPropSpawnWrite(&g_NetMsgRel, obj->prop);
|
||||
netmsgSvcPropMoveWrite(&g_NetMsgRel, obj->prop, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void bgunUpdateHeldRocket(s32 handnum)
|
||||
@@ -4722,8 +4769,8 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
f32 sp25c;
|
||||
struct coord sp250;
|
||||
Mtxf sp210;
|
||||
struct coord sp204;
|
||||
struct coord sp1f8;
|
||||
struct coord gunpos;
|
||||
struct coord gundir;
|
||||
struct prop *playerprop;
|
||||
struct coord *prevpos;
|
||||
struct coord *extrapos;
|
||||
@@ -4742,6 +4789,12 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
f32 spd4[4];
|
||||
f32 spc4[4];
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_NetMode == NETMODE_CLIENT) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
hand = g_Vars.currentplayer->hands + handnum;
|
||||
|
||||
playerprop = g_Vars.currentplayer->prop;
|
||||
@@ -4757,24 +4810,24 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
funcdef = (struct weaponfunc_shootprojectile *)tmp;
|
||||
|
||||
mtx4LoadIdentity(&sp270);
|
||||
bgunCalculatePlayerShotSpread(&sp204, &sp1f8, handnum, true);
|
||||
mtx4RotateVecInPlace(camGetProjectionMtxF(), &sp1f8);
|
||||
bgunCalculatePlayerShotSpread(&gunpos, &gundir, handnum, true);
|
||||
mtx4RotateVecInPlace(camGetProjectionMtxF(), &gundir);
|
||||
|
||||
spawnpos.x = hand->muzzlepos.x;
|
||||
spawnpos.y = hand->muzzlepos.y;
|
||||
spawnpos.z = hand->muzzlepos.z;
|
||||
|
||||
if (hand->gset.weaponnum == WEAPON_SLAYER && hand->gset.weaponfunc == FUNC_SECONDARY) {
|
||||
spawnpos.x += 50.0f * sp1f8.x;
|
||||
spawnpos.y += 50.0f * sp1f8.y;
|
||||
spawnpos.z += 50.0f * sp1f8.z;
|
||||
spawnpos.x += 50.0f * gundir.x;
|
||||
spawnpos.y += 50.0f * gundir.y;
|
||||
spawnpos.z += 50.0f * gundir.z;
|
||||
}
|
||||
|
||||
sp260 = funcdef->speed * 1.6666666f / 60.0f;
|
||||
sp25c = funcdef->traveldist * 1.6666666f;
|
||||
|
||||
if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) {
|
||||
func0f061d54(0, 0, 0);
|
||||
propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
|
||||
|
||||
if (hand->hasdotinfo) {
|
||||
aimpos.x = hand->dotpos.x;
|
||||
@@ -4783,10 +4836,10 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
|
||||
chrCalculateTrajectory(&spawnpos, sp25c, &aimpos, &sp1bc);
|
||||
|
||||
radians = acosf(sp1f8.f[0] * sp1bc.f[0] + sp1f8.f[1] * sp1bc.f[1] + sp1f8.f[2] * sp1bc.f[2]);
|
||||
radians = acosf(gundir.f[0] * sp1bc.f[0] + gundir.f[1] * sp1bc.f[1] + gundir.f[2] * sp1bc.f[2]);
|
||||
|
||||
if (radians > 0.17450513f || radians < -0.17450513f) {
|
||||
mtx00016b58(&sp174, 0.0f, 0.0f, 0.0f, sp1f8.x, sp1f8.y, sp1f8.z, 0.0f, 1.0f, 0.0f);
|
||||
mtx00016b58(&sp174, 0.0f, 0.0f, 0.0f, gundir.x, gundir.y, gundir.z, 0.0f, 1.0f, 0.0f);
|
||||
mtx00016b58(&sp134, 0.0f, 0.0f, 0.0f, sp1bc.x, sp1bc.y, sp1bc.z, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
quaternion0f097044(&sp174, spe4);
|
||||
@@ -4802,24 +4855,24 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
quaternionSlerp(spe4, spd4, frac, spc4);
|
||||
quaternionToMtx(spc4, &spf4);
|
||||
|
||||
sp1f8.x = -spf4.m[2][0];
|
||||
sp1f8.y = -spf4.m[2][1];
|
||||
sp1f8.z = -spf4.m[2][2];
|
||||
gundir.x = -spf4.m[2][0];
|
||||
gundir.y = -spf4.m[2][1];
|
||||
gundir.z = -spf4.m[2][2];
|
||||
} else {
|
||||
sp1f8.x = sp1bc.x;
|
||||
sp1f8.y = sp1bc.y;
|
||||
sp1f8.z = sp1bc.z;
|
||||
gundir.x = sp1bc.x;
|
||||
gundir.y = sp1bc.y;
|
||||
gundir.z = sp1bc.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sp250.x = sp1f8.x * sp260;
|
||||
sp250.y = sp1f8.y * sp260;
|
||||
sp250.z = sp1f8.z * sp260;
|
||||
sp250.x = gundir.x * sp260;
|
||||
sp250.y = gundir.y * sp260;
|
||||
sp250.z = gundir.z * sp260;
|
||||
|
||||
sp264.x = sp250.f[0] * g_Vars.lvupdate60freal + sp1f8.f[0] * sp25c;
|
||||
sp264.y = sp250.f[1] * g_Vars.lvupdate60freal + sp1f8.f[1] * sp25c;
|
||||
sp264.z = sp250.f[2] * g_Vars.lvupdate60freal + sp1f8.f[2] * sp25c;
|
||||
sp264.x = sp250.f[0] * g_Vars.lvupdate60freal + gundir.f[0] * sp25c;
|
||||
sp264.y = sp250.f[1] * g_Vars.lvupdate60freal + gundir.f[1] * sp25c;
|
||||
sp264.z = sp250.f[2] * g_Vars.lvupdate60freal + gundir.f[2] * sp25c;
|
||||
|
||||
if ((funcdef->base.base.flags & FUNCFLAG_FLYBYWIRE) == 0 && g_Vars.lvupdate240 > 0) {
|
||||
sp264.x += (playerprop->pos.x - prevpos->x + extrapos->x) / g_Vars.lvupdate60freal;
|
||||
@@ -4954,6 +5007,12 @@ void bgunCreateFiredProjectile(s32 handnum)
|
||||
weapon->base.prop = NULL;
|
||||
weapon->base.model = NULL;
|
||||
}
|
||||
#ifndef PLATFORM_N64
|
||||
else if (g_NetMode == NETMODE_SERVER) {
|
||||
netmsgSvcPropSpawnWrite(&g_NetMsgRel, weapon->base.prop);
|
||||
netmsgSvcPropMoveWrite(&g_NetMsgRel, weapon->base.prop, NULL);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// NTSC beta doesn't have any of the failure checks
|
||||
Mtxf sp78;
|
||||
@@ -5236,7 +5295,7 @@ void bgun0f0a0c44(s32 handnum, struct coord *arg1, struct coord *arg2)
|
||||
cam0f0b4c3c(g_Vars.currentplayer->hands[handnum].crosspos, arg2, 1);
|
||||
}
|
||||
|
||||
void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 handnum, bool dorandom)
|
||||
void bgunCalculatePlayerShotSpread(struct coord *gunpos2d, struct coord *gundir2d, s32 handnum, bool dorandom)
|
||||
{
|
||||
f32 crosspos[2];
|
||||
f32 spread = 0;
|
||||
@@ -5250,7 +5309,6 @@ void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 h
|
||||
spread = shootfunc->spread;
|
||||
}
|
||||
|
||||
// Unsure what this is
|
||||
if (weaponHasAimFlag(bgunGetWeaponNum2(handnum), INVAIMFLAG_ACCURATESINGLESHOT)
|
||||
&& player->hands[handnum].burstbullets == 1) {
|
||||
spread *= 0.25f;
|
||||
@@ -5286,11 +5344,11 @@ void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 h
|
||||
crosspos[1] = player->crosspos[1] + (randfactor * scaledspread * camGetScreenHeight())
|
||||
/ viGetHeight();
|
||||
|
||||
arg0->x = 0;
|
||||
arg0->y = 0;
|
||||
arg0->z = 0;
|
||||
gunpos2d->x = 0;
|
||||
gunpos2d->y = 0;
|
||||
gunpos2d->z = 0;
|
||||
|
||||
cam0f0b4c3c(crosspos, arg1, 1);
|
||||
cam0f0b4c3c(crosspos, gundir2d, 1);
|
||||
}
|
||||
|
||||
void bgunCalculateBotShotSpread(struct coord *arg0, s32 weaponnum, s32 funcnum, bool arg3, s32 crouchpos, bool dual)
|
||||
@@ -5433,7 +5491,7 @@ void bgunTickSwitch2(void)
|
||||
ctrl->switchtoweaponnum = WEAPON_UNARMED;
|
||||
}
|
||||
|
||||
#if VERSION == VERSION_JPN_FINAL
|
||||
#if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64)
|
||||
if (ctrl->switchtoweaponnum == WEAPON_COMBATKNIFE) {
|
||||
ctrl->switchtoweaponnum = WEAPON_UNARMED;
|
||||
}
|
||||
@@ -5749,14 +5807,20 @@ bool bgunHasAmmoForWeapon(s32 weaponnum)
|
||||
|
||||
u8 g_AutoSwitchWeaponsPrimary[] = {
|
||||
WEAPON_RCP120,
|
||||
WEAPON_RCP45,
|
||||
WEAPON_SUPERDRAGON, // primary function
|
||||
WEAPON_K7AVENGER,
|
||||
WEAPON_AR34,
|
||||
WEAPON_AR53,
|
||||
WEAPON_KF7SPECIAL,
|
||||
WEAPON_CALLISTO,
|
||||
WEAPON_LAPTOPGUN,
|
||||
WEAPON_DRAGON,
|
||||
WEAPON_CMP150,
|
||||
WEAPON_CYCLONE,
|
||||
WEAPON_ZZT,
|
||||
WEAPON_DMC,
|
||||
WEAPON_KL01313,
|
||||
WEAPON_FARSIGHT,
|
||||
WEAPON_SHOTGUN,
|
||||
WEAPON_REAPER,
|
||||
@@ -5768,6 +5832,8 @@ u8 g_AutoSwitchWeaponsPrimary[] = {
|
||||
WEAPON_FALCON2_SCOPE,
|
||||
WEAPON_FALCON2,
|
||||
WEAPON_FALCON2_SILENCER,
|
||||
WEAPON_PP9I,
|
||||
WEAPON_CC13,
|
||||
WEAPON_SNIPERRIFLE,
|
||||
WEAPON_CROSSBOW,
|
||||
WEAPON_TRANQUILIZER,
|
||||
@@ -6277,6 +6343,13 @@ void bgunDisarm(struct prop *attackerprop)
|
||||
s32 modelnum;
|
||||
s32 i;
|
||||
bool drop;
|
||||
struct defaultobj *obj;
|
||||
#ifndef PLATFORM_N64
|
||||
// don't do anything if we're not the authority
|
||||
if (g_NetMode == NETMODE_CLIENT) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!weaponHasFlag(weaponnum, WEAPONFLAG_UNDROPPABLE) && weaponnum <= WEAPON_RCP45) {
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
@@ -6294,6 +6367,12 @@ void bgunDisarm(struct prop *attackerprop)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_NetMode == NETMODE_SERVER) {
|
||||
netmsgSvcChrDisarmWrite(&g_NetMsgRel, player->prop->chr, attackerprop, weaponnum, 0.f, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
chr = player->prop->chr;
|
||||
drop = true;
|
||||
|
||||
@@ -6312,11 +6391,17 @@ void bgunDisarm(struct prop *attackerprop)
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct weaponfunc *func = gsetGetWeaponFunction(&player->hands[i].gset);
|
||||
|
||||
#ifdef AVOID_UB
|
||||
if (func && (func->type & 0xff) == INVENTORYFUNCTYPE_THROW
|
||||
&& player->hands[i].state == HANDSTATE_ATTACK
|
||||
&& player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) {
|
||||
#else
|
||||
if ((func->type & 0xff) == INVENTORYFUNCTYPE_THROW
|
||||
&& player->hands[i].state == HANDSTATE_ATTACK
|
||||
&& player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) {
|
||||
#endif
|
||||
drop = false;
|
||||
bgunCreateThrownProjectile(i + 2, &player->hands[i].gset);
|
||||
obj = bgunCreateThrownProjectile(i + 2, &player->hands[i].gset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6340,6 +6425,13 @@ void bgunDisarm(struct prop *attackerprop)
|
||||
}
|
||||
|
||||
objDrop(prop2, true);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_NetMode == NETMODE_SERVER) {
|
||||
netmsgSvcPropSpawnWrite(&g_NetMsgRel, prop2);
|
||||
netmsgSvcPropMoveWrite(&g_NetMsgRel, prop2, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6748,7 +6840,7 @@ void bgunUpdateSmoke(struct hand *hand, s32 handnum, s32 weaponnum, struct weapo
|
||||
|
||||
if (hand->createsmoke && (hand->state != HANDSTATE_ATTACK || hand->forcecreatesmoke)) {
|
||||
struct coord smokepos;
|
||||
s16 smokerooms[2];
|
||||
RoomNum smokerooms[2];
|
||||
s32 smoketype = SMOKETYPE_MUZZLE_AUTOMATIC;
|
||||
|
||||
switch (weaponnum) {
|
||||
@@ -7483,6 +7575,22 @@ void bgunCreateFx(struct hand *hand, s32 handnum, struct weaponfunc *funcdef, s3
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
|
||||
// offset calculation from NeonNyan/perfect-dark
|
||||
|
||||
static inline f32 bgunGetFovOffsetZ(void)
|
||||
{
|
||||
return (PLAYER_DEFAULT_FOV - 60.f) / 3.f;
|
||||
}
|
||||
|
||||
static inline f32 bgunGetFovOffsetY(void)
|
||||
{
|
||||
return (PLAYER_DEFAULT_FOV - 60.f) / (2.75f * 4.f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void bgun0f0a5550(s32 handnum)
|
||||
{
|
||||
u8 *mtxallocation;
|
||||
@@ -7574,6 +7682,12 @@ void bgun0f0a5550(s32 handnum)
|
||||
sp274.y += player->guncloseroffset * 5.0f / -90.0f * 50.0f;
|
||||
sp274.z -= player->guncloseroffset * 15.0f / -90.0f * 50.0f;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
// adjust viewmodel position for different FOVs
|
||||
sp274.y -= bgunGetFovOffsetY();
|
||||
sp274.z += bgunGetFovOffsetZ();
|
||||
#endif
|
||||
|
||||
if (hand->firing && shootfunc && g_Vars.lvupdate240 != 0 && shootfunc->recoilsettings != NULL) {
|
||||
sp274.x += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->xrange * hand->finalmult[0];
|
||||
sp274.y += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->yrange * hand->finalmult[0];
|
||||
@@ -10869,6 +10983,7 @@ void bgunRender(Gfx **gdlptr)
|
||||
struct modelrenderdata renderdata = {NULL, true, 3}; // 10c
|
||||
struct player *player;
|
||||
s32 i;
|
||||
const u32 wnorm = mtx00016dcc(0, 300);
|
||||
|
||||
static bool renderhand = true; // var800702dc
|
||||
|
||||
@@ -10883,7 +10998,9 @@ void bgunRender(Gfx **gdlptr)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64 // TODO
|
||||
gdl = zbufDrawArtifactsOffscreen(gdl);
|
||||
#endif
|
||||
gdl = viPrepareZbuf(gdl);
|
||||
gdl = vi0000b1d0(gdl);
|
||||
|
||||
@@ -10895,11 +11012,15 @@ void bgunRender(Gfx **gdlptr)
|
||||
if (g_Vars.currentplayer->teleportstate != TELEPORTSTATE_INACTIVE) {
|
||||
f32 f2;
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
if (optionsGetScreenRatio() == SCREENRATIO_16_9) {
|
||||
f2 = player0f0bd358() * 1.3333334f;
|
||||
} else {
|
||||
f2 = player0f0bd358();
|
||||
}
|
||||
#else
|
||||
f2 = player0f0bd358();
|
||||
#endif
|
||||
|
||||
gdl = vi0000b0e8(gdl, 60, f2);
|
||||
}
|
||||
@@ -10928,7 +11049,7 @@ void bgunRender(Gfx **gdlptr)
|
||||
gSPLookAt(gdl++, camGetLookAt());
|
||||
}
|
||||
|
||||
gSPPerspNormalize(gdl++, mtx00016dcc(0, 300));
|
||||
gSPPerspNormalize(gdl++, wnorm);
|
||||
|
||||
// There is support for guns having a TV screen on them
|
||||
// but no guns have this model part so it's not used.
|
||||
@@ -11103,7 +11224,17 @@ void bgunRender(Gfx **gdlptr)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
// put the casings into the same Z range as the gun
|
||||
gSPPerspNormalize(gdl++, wnorm);
|
||||
#endif
|
||||
|
||||
casingsRender(&gdl);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPPerspNormalize(gdl++, viGetPerspScale());
|
||||
#endif
|
||||
|
||||
zbufSwap();
|
||||
|
||||
gdl = zbufConfigureRdp(gdl);
|
||||
@@ -11413,7 +11544,7 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
|
||||
#endif
|
||||
}
|
||||
|
||||
void bgunPlayGlassHitSound(struct coord *pos, s16 *rooms, s32 texturenum)
|
||||
void bgunPlayGlassHitSound(struct coord *pos, RoomNum *rooms, s32 texturenum)
|
||||
{
|
||||
if (g_Vars.lvupdate240 > 0) {
|
||||
struct sndstate **handle = bgunAllocateAudioHandle();
|
||||
@@ -11428,7 +11559,7 @@ void bgunPlayGlassHitSound(struct coord *pos, s16 *rooms, s32 texturenum)
|
||||
}
|
||||
}
|
||||
|
||||
void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum, s16 *rooms)
|
||||
void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum, RoomNum *rooms)
|
||||
{
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
struct sndstate **handle;
|
||||
@@ -11650,20 +11781,45 @@ void bgunSetTriggerOn(s32 handnum, bool on)
|
||||
* - USETIMER_STOP if the B button timer should stop (ie. the B press is consumed)
|
||||
* - USETIMER_REPEAT if this function should be called again on each frame until B is released.
|
||||
*/
|
||||
s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu)
|
||||
s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu, bool fromdedicatedbutton)
|
||||
{
|
||||
#ifndef PLATFORM_N64
|
||||
const bool extcontrols = PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote;
|
||||
bool docontinue;
|
||||
#endif
|
||||
switch (bgunGetWeaponNum(HAND_RIGHT)) {
|
||||
case WEAPON_SNIPERRIFLE:
|
||||
if (extcontrols && usedowntime < 0) {
|
||||
return USETIMER_CONTINUE;
|
||||
}
|
||||
|
||||
// At 25 ticks (or B+Z), start showing the new function
|
||||
g_Vars.currentplayer->gunctrl.invertgunfunc = true;
|
||||
|
||||
// B+Z immediately triggers crouch or stand
|
||||
if (trigpressed) {
|
||||
if (extcontrols) {
|
||||
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
|
||||
}
|
||||
return USETIMER_STOP;
|
||||
}
|
||||
|
||||
if (fromdedicatedbutton) {
|
||||
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
|
||||
return USETIMER_CONTINUE;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (extcontrols) {
|
||||
docontinue = (ABS(usedowntime) < 0);
|
||||
} else {
|
||||
// Don't do anything if B hasn't been held for 50/60ths of a second
|
||||
docontinue = (usedowntime < TICKS(50));
|
||||
}
|
||||
if (docontinue) {
|
||||
#else
|
||||
if (usedowntime < TICKS(50)) {
|
||||
#endif
|
||||
return USETIMER_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -11673,13 +11829,29 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
|
||||
|
||||
// Do crouch or stand
|
||||
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
|
||||
return USETIMER_REPEAT;
|
||||
return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT);
|
||||
case WEAPON_RCP120:
|
||||
#ifndef PLATFORM_N64
|
||||
// very special alt-button handling for RCP-120's cloaking
|
||||
if (!trigpressed && extcontrols && fromdedicatedbutton) {
|
||||
if (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) {
|
||||
g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120;
|
||||
} else {
|
||||
g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120;
|
||||
}
|
||||
g_Vars.currentplayer->gunctrl.invertgunfunc = false;
|
||||
return USETIMER_STOP;
|
||||
}
|
||||
#endif
|
||||
case WEAPON_LAPTOPGUN:
|
||||
case WEAPON_DRAGON:
|
||||
case WEAPON_REMOTEMINE:
|
||||
// These weapons use temporary alt functions
|
||||
if (extcontrols) {
|
||||
g_Vars.currentplayer->gunctrl.invertgunfunc = !g_Vars.currentplayer->gunctrl.invertgunfunc;
|
||||
} else {
|
||||
g_Vars.currentplayer->gunctrl.invertgunfunc = true;
|
||||
}
|
||||
|
||||
if (fromactivemenu && bgunIsUsingSecondaryFunction() == true) {
|
||||
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
|
||||
@@ -11725,6 +11897,18 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
|
||||
|
||||
void bgun0f0a8c50(void)
|
||||
{
|
||||
#ifndef PLATFORM_N64
|
||||
switch (bgunGetWeaponNum(HAND_RIGHT)) {
|
||||
case WEAPON_RCP120:
|
||||
case WEAPON_LAPTOPGUN:
|
||||
case WEAPON_DRAGON:
|
||||
case WEAPON_REMOTEMINE:
|
||||
if (PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary == false) {
|
||||
g_Vars.currentplayer->gunctrl.invertgunfunc = false;
|
||||
}
|
||||
@@ -12622,7 +12806,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
{
|
||||
struct player *player = g_Vars.currentplayer;
|
||||
s32 bottom = viGetViewTop() + viGetViewHeight() - 13;
|
||||
s32 playercount = PLAYERCOUNT();
|
||||
s32 playercount = LOCALPLAYERCOUNT();
|
||||
s32 playernum = g_Vars.currentplayernum;
|
||||
struct gunctrl *ctrl;
|
||||
s32 secs60;
|
||||
@@ -12674,6 +12858,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
|
||||
gdl = text0f153628(gdl);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (playercount >= 2) {
|
||||
barwidth = 5;
|
||||
reserveheight = 26;
|
||||
@@ -12894,6 +13084,9 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
}
|
||||
|
||||
if (ammoindex == -1) {
|
||||
#ifndef PLATFORM_N64
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
|
||||
#endif
|
||||
gdl = text0f153780(gdl);
|
||||
g_ScaleX = 1;
|
||||
return gdl;
|
||||
@@ -12919,6 +13112,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
xpos -= 14;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lefthand->clipsizes[ammoindex] > 0 && (weapon->ammos[ammoindex]->flags & AMMOFLAG_EQUIPPEDISRESERVE) == 0) {
|
||||
gdl = bgunDrawHudGauge(gdl,
|
||||
xpos, bottom - reserveheight - clipheight - 3, xpos + barwidth, bottom - reserveheight - 3,
|
||||
@@ -12953,6 +13152,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
xpos += 15;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Mag
|
||||
ammoheld = player->ammoheldarr[ammotype];
|
||||
|
||||
@@ -13006,6 +13211,10 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
|
||||
#endif
|
||||
|
||||
gdl = text0f153780(gdl);
|
||||
|
||||
g_ScaleX = 1;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "lib/memp.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "game/player.h"
|
||||
#endif
|
||||
|
||||
extern u32 g_BgunGunMemBaseSize4Mb2P;
|
||||
|
||||
@@ -239,9 +242,9 @@ void bgunReset(void)
|
||||
|
||||
g_Vars.currentplayer->gunammooff = 0;
|
||||
g_Vars.currentplayer->gunsightoff = GUNSIGHTREASON_NOTAIMING;
|
||||
g_Vars.currentplayer->gunzoomfovs[0] = 15;
|
||||
g_Vars.currentplayer->gunzoomfovs[1] = 60;
|
||||
g_Vars.currentplayer->gunzoomfovs[2] = 30;
|
||||
g_Vars.currentplayer->gunzoomfovs[0] = ADJUST_ZOOM_FOV(15);
|
||||
g_Vars.currentplayer->gunzoomfovs[1] = ADJUST_ZOOM_FOV(60);
|
||||
g_Vars.currentplayer->gunzoomfovs[2] = ADJUST_ZOOM_FOV(30);
|
||||
|
||||
if (stageGetIndex(g_Vars.stagenum) == STAGEINDEX_AIRBASE) {
|
||||
g_Weapons[WEAPON_EYESPY]->name = L_GUN_061; // "DrugSpy"
|
||||
|
||||
+24
-26
@@ -11,13 +11,11 @@
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
|
||||
struct var80075c00 var80075c00[] = {
|
||||
struct headanim g_HeadAnims[] = {
|
||||
{ ANIM_002B, 9.5, 27, 0, 0, 1.5 },
|
||||
{ ANIM_0029, 7.5, 17, 0, 1.5, 100 },
|
||||
};
|
||||
|
||||
struct coord var80075c30 = {0, 0, 0};
|
||||
|
||||
void bheadFlipAnimation(void)
|
||||
{
|
||||
g_Vars.currentplayer->model.anim->flip = !g_Vars.currentplayer->model.anim->flip;
|
||||
@@ -96,7 +94,7 @@ void bheadUpdateRot(struct coord *lookvel, struct coord *upvel)
|
||||
g_Vars.currentplayer->headup.z = g_Vars.currentplayer->headupsum.z * (1.0f - g_Vars.currentplayer->headdamp);
|
||||
}
|
||||
|
||||
void bheadSetdamp(f32 headdamp)
|
||||
void bheadSetDamp(f32 headdamp)
|
||||
{
|
||||
if (headdamp != g_Vars.currentplayer->headdamp) {
|
||||
f32 divisor = 1.0f - headdamp;
|
||||
@@ -112,7 +110,7 @@ void bheadSetdamp(f32 headdamp)
|
||||
|
||||
void bheadUpdate(f32 arg0, f32 arg1)
|
||||
{
|
||||
struct coord headpos = var80075c30;
|
||||
struct coord headpos = {0, 0, 0};
|
||||
struct coord lookvel = {0, 0, 1};
|
||||
struct coord upvel = {0, 1, 0};
|
||||
f32 animspeed = 0;
|
||||
@@ -120,7 +118,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
|
||||
if (animHasFrames(g_Vars.currentplayer->model.anim->animnum)) {
|
||||
animspeed = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model);
|
||||
|
||||
if (g_Vars.currentplayer->headanim == 0) {
|
||||
if (g_Vars.currentplayer->headanim == HEADANIM_RESTING) {
|
||||
if (animspeed > 0.69999998807907f) {
|
||||
g_Vars.currentplayer->headamplitude = 1;
|
||||
} else if (animspeed > 0.1f) {
|
||||
@@ -131,7 +129,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
|
||||
|
||||
g_Vars.currentplayer->sideamplitude = g_Vars.currentplayer->headamplitude;
|
||||
} else {
|
||||
if (g_Vars.currentplayer->headanim == 1) {
|
||||
if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
|
||||
g_Vars.currentplayer->headamplitude = 0.89999997615814f;
|
||||
g_Vars.currentplayer->sideamplitude = 0.5f;
|
||||
} else {
|
||||
@@ -197,9 +195,9 @@ void bheadUpdate(f32 arg0, f32 arg1)
|
||||
g_Vars.currentplayer->headwalkingtime60 += g_Vars.lvupdate60;
|
||||
|
||||
if (g_Vars.currentplayer->headwalkingtime60 > TICKS(60)) {
|
||||
bheadSetdamp(PAL ? 0.9785f : 0.982f);
|
||||
bheadSetDamp(PAL ? 0.9785f : 0.982f);
|
||||
} else {
|
||||
bheadSetdamp(PAL ? 0.99699f : 0.99748998880386f);
|
||||
bheadSetDamp(PAL ? 0.99699f : 0.99748998880386f);
|
||||
}
|
||||
} else {
|
||||
lookvel.x = g_Vars.currentplayer->bondheadmatrices[0].m[2][0];
|
||||
@@ -210,7 +208,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
|
||||
upvel.y = g_Vars.currentplayer->bondheadmatrices[0].m[1][1];
|
||||
upvel.z = g_Vars.currentplayer->bondheadmatrices[0].m[1][2];
|
||||
|
||||
bheadSetdamp(PAL ? 0.952f : 0.96f);
|
||||
bheadSetDamp(PAL ? 0.952f : 0.96f);
|
||||
}
|
||||
} else {
|
||||
g_Vars.currentplayer->headbodyoffset.x = g_Vars.currentplayer->standbodyoffset.x;
|
||||
@@ -222,7 +220,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
|
||||
headpos.z = 0;
|
||||
|
||||
g_Vars.currentplayer->headwalkingtime60 = 0;
|
||||
bheadSetdamp(PAL ? 0.99699f : 0.99748998880386f);
|
||||
bheadSetDamp(PAL ? 0.99699f : 0.99748998880386f);
|
||||
|
||||
if (bmoveGetCrouchPos() != CROUCHPOS_SQUAT) {
|
||||
g_Vars.currentplayer->standfrac +=
|
||||
@@ -261,31 +259,31 @@ void bheadAdjustAnimation(f32 speed)
|
||||
struct chrdata *chr = g_Vars.currentplayer->prop->chr;
|
||||
s32 i;
|
||||
|
||||
speed *= var80075c00[1].unk0c;
|
||||
speed *= g_HeadAnims[HEADANIM_MOVING].translateperframe;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (var80075c00[i].unk14 * var80075c00[i].unk0c >= speed) {
|
||||
s32 headanim = g_Vars.currentplayer->headanim;
|
||||
for (i = 0; i < ARRAYCOUNT(g_HeadAnims); i++) {
|
||||
if (g_HeadAnims[i].maxspeed * g_HeadAnims[i].translateperframe >= speed) {
|
||||
s32 prevheadanim = g_Vars.currentplayer->headanim;
|
||||
|
||||
if (i != headanim) {
|
||||
if (i != prevheadanim) {
|
||||
f32 startframe = 0.0f;
|
||||
|
||||
if (headanim >= 0) {
|
||||
startframe = (g_Vars.currentplayer->model.anim->frame - var80075c00[headanim].loopframe)
|
||||
/ (var80075c00[headanim].endframe - var80075c00[headanim].loopframe);
|
||||
startframe = var80075c00[i].loopframe + (var80075c00[i].endframe - var80075c00[i].loopframe) * startframe;
|
||||
if (prevheadanim >= 0) {
|
||||
startframe = (g_Vars.currentplayer->model.anim->frame - g_HeadAnims[prevheadanim].loopframe)
|
||||
/ (g_HeadAnims[prevheadanim].endframe - g_HeadAnims[prevheadanim].loopframe);
|
||||
startframe = g_HeadAnims[i].loopframe + (g_HeadAnims[i].endframe - g_HeadAnims[i].loopframe) * startframe;
|
||||
}
|
||||
|
||||
modelSetAnimation(&g_Vars.currentplayer->model, var80075c00[i].animnum,
|
||||
modelSetAnimation(&g_Vars.currentplayer->model, g_HeadAnims[i].animnum,
|
||||
g_Vars.currentplayer->model.anim->flip, startframe, 0.5f, 12);
|
||||
modelSetAnimLooping(&g_Vars.currentplayer->model, var80075c00[i].loopframe, false);
|
||||
modelSetAnimEndFrame(&g_Vars.currentplayer->model, var80075c00[i].endframe);
|
||||
modelSetAnimLooping(&g_Vars.currentplayer->model, g_HeadAnims[i].loopframe, false);
|
||||
modelSetAnimEndFrame(&g_Vars.currentplayer->model, g_HeadAnims[i].endframe);
|
||||
|
||||
modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation);
|
||||
g_Vars.currentplayer->headanim = i;
|
||||
}
|
||||
|
||||
speed = speed / var80075c00[i].unk0c;
|
||||
speed = speed / g_HeadAnims[i].translateperframe;
|
||||
|
||||
modelSetAnimSpeed(&g_Vars.currentplayer->model, speed * 0.5f, 0);
|
||||
break;
|
||||
@@ -309,11 +307,11 @@ void bheadSetSpeed(f32 speed)
|
||||
f32 bheadGetBreathingValue(void)
|
||||
{
|
||||
if (g_Vars.currentplayer->headanim >= 0) {
|
||||
f32 a = g_Vars.currentplayer->bondbreathing * 0.012500001f + 0.004166667f;
|
||||
f32 a = g_Vars.currentplayer->bondbreathing * 0.012500001f + (1.0f / 240.0f);
|
||||
f32 b = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model);
|
||||
|
||||
if (b > 0) {
|
||||
f32 c = b / (var80075c00[g_Vars.currentplayer->headanim].endframe - var80075c00[g_Vars.currentplayer->headanim].loopframe);
|
||||
f32 c = b / (g_HeadAnims[g_Vars.currentplayer->headanim].endframe - g_HeadAnims[g_Vars.currentplayer->headanim].loopframe);
|
||||
|
||||
if (c < a) {
|
||||
c = a;
|
||||
|
||||
@@ -39,7 +39,7 @@ void bheadReset(void)
|
||||
modelSetScale(&g_Vars.currentplayer->model, 0.1000000089407f);
|
||||
modelSetAnimPlaySpeed(&g_Vars.currentplayer->model, (PAL ? 1.2f : 1), 0);
|
||||
|
||||
g_Vars.currentplayer->headanim = 0;
|
||||
g_Vars.currentplayer->headanim = HEADANIM_RESTING;
|
||||
g_Vars.currentplayer->headdamp = (PAL ? 0.9166f : 0.93f);
|
||||
g_Vars.currentplayer->headwalkingtime60 = 0;
|
||||
g_Vars.currentplayer->headamplitude = 1;
|
||||
@@ -87,10 +87,10 @@ void bheadReset(void)
|
||||
g_Vars.currentplayer->standup[1].z = 0;
|
||||
g_Vars.currentplayer->standcnt = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < ARRAYCOUNT(g_HeadAnims); i++) {
|
||||
s32 translate[3];
|
||||
func0f0125a0(var80075c00[i].animnum, var80075c00[i].loopframe, var80075c00[i].endframe, translate);
|
||||
var80075c00[i].unk0c = (translate[2] * 0.1000000089407f) / (var80075c00[i].endframe - var80075c00[i].loopframe);
|
||||
func0f0125a0(g_HeadAnims[i].animnum, g_HeadAnims[i].loopframe, g_HeadAnims[i].endframe, translate);
|
||||
g_HeadAnims[i].translateperframe = (translate[2] * 0.1000000089407f) / (g_HeadAnims[i].endframe - g_HeadAnims[i].loopframe);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -112,17 +112,13 @@ void bheadReset(void)
|
||||
g_Vars.currentplayer->standbodyoffset.z = g_Vars.currentplayer->bondheadmatrices[1].m[3][2] - g_Vars.currentplayer->bondheadmatrices[0].m[3][2];
|
||||
|
||||
modelSetAnimation(&g_Vars.currentplayer->model,
|
||||
var80075c00[g_Vars.currentplayer->headanim].animnum,
|
||||
g_HeadAnims[g_Vars.currentplayer->headanim].animnum,
|
||||
0,
|
||||
var80075c00[g_Vars.currentplayer->headanim].loopframe,
|
||||
g_HeadAnims[g_Vars.currentplayer->headanim].loopframe,
|
||||
0.5f, 0);
|
||||
|
||||
modelSetAnimLooping(&g_Vars.currentplayer->model,
|
||||
var80075c00[g_Vars.currentplayer->headanim].loopframe, 0);
|
||||
|
||||
modelSetAnimEndFrame(&g_Vars.currentplayer->model,
|
||||
var80075c00[g_Vars.currentplayer->headanim].endframe);
|
||||
|
||||
modelSetAnimLooping(&g_Vars.currentplayer->model, g_HeadAnims[g_Vars.currentplayer->headanim].loopframe, 0);
|
||||
modelSetAnimEndFrame(&g_Vars.currentplayer->model, g_HeadAnims[g_Vars.currentplayer->headanim].endframe);
|
||||
modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation);
|
||||
|
||||
bheadUpdateIdleRoll();
|
||||
|
||||
+679
-75
File diff suppressed because it is too large.
Load diff
+295
-37
@@ -20,6 +20,10 @@
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#include "gbiex.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "game/player.h"
|
||||
#include "video.h"
|
||||
#endif
|
||||
|
||||
#ifdef AVOID_UB
|
||||
char var800a41c0[26];
|
||||
@@ -97,6 +101,7 @@ Gfx *bview0f141a20(Gfx *gdl, s32 top, s32 height, s32 left, s32 width)
|
||||
|
||||
Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s32 left, s32 width)
|
||||
{
|
||||
#ifdef PLATFORM_N64
|
||||
uintptr_t image;
|
||||
s32 width2;
|
||||
s32 numparts;
|
||||
@@ -161,6 +166,10 @@ Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s
|
||||
}
|
||||
|
||||
return gdl;
|
||||
#else // PLATFORM_N64
|
||||
// TODO: add an extended GBI opcode for this
|
||||
return gdl;
|
||||
#endif // PLATFORM_N64
|
||||
}
|
||||
|
||||
Gfx *bviewDrawFisheyeRect(Gfx *gdl, s32 arg1, f32 arg2, s32 arg3, s32 arg4)
|
||||
@@ -206,7 +215,7 @@ Gfx *bviewPrepareStaticRgba16(Gfx *gdl, u32 colour, u32 alpha)
|
||||
gDPSetTexturePersp(gdl++, G_TP_NONE);
|
||||
gDPSetColorDither(gdl++, G_CD_DISABLE);
|
||||
gDPSetAlphaDither(gdl++, G_AD_NOISE);
|
||||
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2);
|
||||
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -240,7 +249,7 @@ Gfx *bviewPrepareStaticI8(Gfx *gdl, u32 colour, u32 alpha)
|
||||
gDPSetTexturePersp(gdl++, G_TP_NONE);
|
||||
gDPSetColorDither(gdl++, G_CD_DISABLE);
|
||||
gDPSetAlphaDither(gdl++, G_AD_NOISE);
|
||||
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2);
|
||||
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -276,6 +285,20 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
|
||||
|
||||
var8007f844 = 0;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
// capture fb at the end of this frame
|
||||
g_BlurFbCapTimer = 0;
|
||||
|
||||
// don't render first blur frame as we haven't captured the fb yet
|
||||
if (g_BlurFbDirty) {
|
||||
return gdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
mainOverrideVariable("sfxxx", &sfxxx);
|
||||
fxxx = sfxxx / 1000.0f;
|
||||
mainOverrideVariable("sfyyy", &sfyyy);
|
||||
@@ -286,10 +309,18 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
|
||||
somefloat = (viewheight - viewheight / fyyy) * 0.5f;
|
||||
gdl = bviewPrepareStaticRgba16(gdl, colour, newalpha);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (i = viewtop; i < viewtop + viewheight; i++) {
|
||||
gdl = bviewCopyPixels(gdl, fb, viewtop + (s32)somefloat, 5, i, fxxx, viewleft, viewwidth);
|
||||
somefloat += 1.0f / fyyy;
|
||||
}
|
||||
#else
|
||||
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_BlurFb);
|
||||
gSPImageRectangleEXT(gdl++,
|
||||
viewleft << 2, viewtop << 2, viewleft, viewtop,
|
||||
(viewleft + viewwidth) << 2, (viewtop + viewheight) << 2, viewleft + viewwidth, viewtop + viewheight,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -311,9 +342,16 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
|
||||
|
||||
gdl = bviewPrepareStaticI8(gdl, arg1, arg2);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
gDPSetCombineLERP(gdl++,
|
||||
NOISE, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT,
|
||||
NOISE, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT);
|
||||
gDPFillRectangleEXT(gdl++, viewleft, viewtop, viewleft + viewwidth, viewtop + viewheight);
|
||||
#endif
|
||||
|
||||
if (fb2) {
|
||||
// empty
|
||||
@@ -351,6 +389,7 @@ Gfx *bviewDrawSlayerRocketInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
|
||||
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
s32 offsety = y - offset;
|
||||
|
||||
@@ -366,6 +405,26 @@ Gfx *bviewDrawSlayerRocketInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
|
||||
angle += increment;
|
||||
}
|
||||
#else
|
||||
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
s32 offsety = y - offset;
|
||||
|
||||
if (offsety % 8 == 0 || y == viewtop) {
|
||||
if (offsety % 16 < 8) {
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0xff, 0xff, 0x00, 0xff);
|
||||
} else {
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0xff, 0xff, 0xbf, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
gDPFillRectangle(gdl++, viewleft, y, viewleft + viewwidth, y + 1);
|
||||
}
|
||||
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -396,6 +455,7 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
|
||||
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
s32 offsety = y - offset;
|
||||
s32 tmpy = y;
|
||||
@@ -414,6 +474,31 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
|
||||
gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
s32 offsety = y - offset;
|
||||
s32 tmpy = y;
|
||||
|
||||
if (offsety % 6 == 0 || y == viewtop) {
|
||||
if (offsety % 12 < 6) {
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0x7f, 0xff, 0xff, 0xff);
|
||||
} else {
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0x00, 0xaf, 0xff, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
if (random() % 20 == 1) {
|
||||
tmpy += random() % 200;
|
||||
}
|
||||
|
||||
gDPFillRectangle(gdl++, viewleft, tmpy, viewleft + viewwidth, tmpy + 1);
|
||||
}
|
||||
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -439,6 +524,20 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
|
||||
return gdl;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
// capture fb at the end of this frame
|
||||
g_BlurFbCapTimer = 0;
|
||||
|
||||
// don't render first blur frame as we haven't captured the fb yet
|
||||
if (g_BlurFbDirty) {
|
||||
return gdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
strcpy(var800a41c0, "stretchBlurGfx");
|
||||
|
||||
gDPPipeSync(gdl++);
|
||||
@@ -447,10 +546,26 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
|
||||
|
||||
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (i = viewtop; i < viewtop + viewheight; i++) {
|
||||
gdl = bviewCopyPixels(gdl, fb, (s32)somefloat + viewtop, 5, i, arg3, viewleft, viewwidth);
|
||||
somefloat += 1.0f / arg4;
|
||||
}
|
||||
#else
|
||||
const f32 xcenter = viewleft + viewwidth * 0.5f;
|
||||
const f32 ycenter = viewtop + viewheight * 0.5f;
|
||||
const f32 halfw = viewwidth * 0.5f * arg3;
|
||||
const f32 halfh = viewheight * 0.5f * arg4;
|
||||
const s32 left = xcenter - halfw;
|
||||
const s32 top = ycenter - halfh;
|
||||
const s32 right = xcenter + halfw;
|
||||
const s32 bottom = ycenter + halfh;
|
||||
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_BlurFb);
|
||||
gSPImageRectangleEXT(gdl++,
|
||||
left << 2, top << 2, viewleft, viewtop,
|
||||
right << 2, bottom << 2, viewleft + viewwidth, viewtop + viewheight,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -475,6 +590,30 @@ f32 bview0f142d74(s32 arg0, f32 arg1, f32 arg2, f32 arg3)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
|
||||
static inline Gfx *bviewDrawFisheyeLine(Gfx *gdl, s32 viewleft, s32 viewwidth, s32 y, f32 scale)
|
||||
{
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
const f32 orighalfw = viewwidth * 0.5f;
|
||||
const f32 xcenter = viewleft + orighalfw;
|
||||
const f32 halfw = orighalfw * scale;
|
||||
const s32 left = xcenter - halfw;
|
||||
const s32 right = xcenter + halfw;
|
||||
|
||||
gSPImageRectangleEXT(gdl++,
|
||||
left << 2, y << 2, viewleft, y,
|
||||
right << 2, (y + 1) << 2, viewleft + viewwidth, y + 1,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
|
||||
return gdl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Draw the fisheye curved effect when using an eyespy.
|
||||
*
|
||||
@@ -589,6 +728,13 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
|
||||
|
||||
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
// make a copy of the current back buffer contents that we will be using as a texture
|
||||
gDPFlushEXT(gdl++);
|
||||
gDPCopyFramebufferEXT(gdl++, g_PrevFrameFb, 0, 0, 0, G_ON);
|
||||
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_PrevFrameFb);
|
||||
#endif
|
||||
|
||||
if (starting) {
|
||||
for (i = viewtop; i < viewtop + viewheight; i++) {
|
||||
if (i % 2) {
|
||||
@@ -596,7 +742,11 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
|
||||
gDPSetEnvColorViaWord(gdl++, (colour & 0xffffff00) | (spec & 0xff));
|
||||
|
||||
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * startupfrac;
|
||||
#ifdef PLATFORM_N64
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
|
||||
#else
|
||||
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,13 +772,21 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
|
||||
}
|
||||
|
||||
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * f22;
|
||||
#ifdef PLATFORM_N64
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
|
||||
#else
|
||||
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
|
||||
#endif
|
||||
|
||||
if (hit == EYESPYHIT_DAMAGE) {
|
||||
gDPSetEnvColorViaWord(gdl++, 0xddaaaa99);
|
||||
|
||||
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * 1.03f;
|
||||
#ifdef PLATFORM_N64
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
|
||||
#else
|
||||
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
s2 += s3;
|
||||
@@ -765,8 +923,8 @@ Gfx *bviewDrawEyespySideRect(Gfx *gdl, s32 *points, u8 r, u8 g, u8 b, u8 alpha)
|
||||
vertices[3].y = points[7] * 10.0f;
|
||||
vertices[3].z = -10;
|
||||
|
||||
colours[0].word = r << 0x18 | g << 0x10 | b << 8 | 0xff;
|
||||
colours[1].word = r << 0x18 | g << 0x10 | b << 8 | alpha;
|
||||
colours[0].word = PD_BE32(r << 0x18 | g << 0x10 | b << 8 | 0xff);
|
||||
colours[1].word = PD_BE32(r << 0x18 | g << 0x10 | b << 8 | alpha);
|
||||
|
||||
vertices[0].colour = 0;
|
||||
vertices[1].colour = 0;
|
||||
@@ -844,6 +1002,7 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
bool vsplit = false;
|
||||
#endif
|
||||
u32 umask, dmask, lmask, rmask;
|
||||
|
||||
#if VERSION >= VERSION_PAL_FINAL
|
||||
#if PAL
|
||||
@@ -874,6 +1033,18 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_PC) {
|
||||
umask = U_CBUTTONS;
|
||||
dmask = D_CBUTTONS;
|
||||
lmask = L_CBUTTONS;
|
||||
rmask = R_CBUTTONS;
|
||||
} else {
|
||||
umask = U_JPAD | U_CBUTTONS;
|
||||
dmask = D_JPAD | D_CBUTTONS;
|
||||
lmask = L_JPAD | L_CBUTTONS;
|
||||
rmask = R_JPAD | R_CBUTTONS;
|
||||
}
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
movex = chr->prop->pos.x - chr->prevpos.x;
|
||||
movey = chr->prop->pos.y - chr->prevpos.y;
|
||||
@@ -1225,8 +1396,8 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
|
||||
{
|
||||
s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
|
||||
u16 buttonsdown = joyGetButtons(contpadnum, 0xffff); \
|
||||
u16 buttonsthisframe = joyGetButtonsPressedThisFrame(contpadnum, 0xffff);
|
||||
u32 buttonsdown = joyGetButtons(contpadnum, 0xffffffff); \
|
||||
u32 buttonsthisframe = joyGetButtonsPressedThisFrame(contpadnum, 0xffffffff);
|
||||
s8 cstickx = joyGetStickX(contpadnum); \
|
||||
s8 csticky = joyGetStickY(contpadnum);
|
||||
s32 xpos;
|
||||
@@ -1259,32 +1430,32 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
// Up
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
brightness = 20; \
|
||||
if (buttonsdown & (U_JPAD | U_CBUTTONS)) { \
|
||||
if (buttonsdown & umask) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) { \
|
||||
if (buttonsthisframe & umask) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0, brightness, 0, 0xff); \
|
||||
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
|
||||
brightness = 127;
|
||||
|
||||
if (buttonsdown & (U_JPAD | U_CBUTTONS)) {
|
||||
if (buttonsdown & umask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) {
|
||||
if (buttonsthisframe & umask) {
|
||||
brightness += 63; \
|
||||
} \
|
||||
gDPSetPrimColor(gdl++, 0, 0, 0x10, 0x20, brightness, 0xff);
|
||||
} else {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (U_JPAD | U_CBUTTONS)) {
|
||||
if (buttonsdown & umask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) {
|
||||
if (buttonsthisframe & umask) {
|
||||
brightness += 20; \
|
||||
} \
|
||||
gDPSetPrimColor(gdl++, 0, 0, brightness, brightness >> 2, 0, 0xff);
|
||||
@@ -1297,10 +1468,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (D_JPAD | D_CBUTTONS)) { \
|
||||
if (buttonsdown & dmask) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) {
|
||||
if (buttonsthisframe & dmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1308,11 +1479,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
|
||||
brightness = 127;
|
||||
|
||||
if (buttonsdown & (D_JPAD | D_CBUTTONS)) {
|
||||
if (buttonsdown & dmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) {
|
||||
if (buttonsthisframe & dmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
@@ -1320,11 +1491,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (D_JPAD | D_CBUTTONS)) {
|
||||
if (buttonsdown & dmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) {
|
||||
if (buttonsthisframe & dmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1338,10 +1509,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (L_JPAD | L_CBUTTONS)) { \
|
||||
if (buttonsdown & lmask) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) {
|
||||
if (buttonsthisframe & lmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1349,11 +1520,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
|
||||
brightness = 127;
|
||||
|
||||
if (buttonsdown & (L_JPAD | L_CBUTTONS)) {
|
||||
if (buttonsdown & lmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) {
|
||||
if (buttonsthisframe & lmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
@@ -1361,11 +1532,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (L_JPAD | L_CBUTTONS)) {
|
||||
if (buttonsdown & lmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) {
|
||||
if (buttonsthisframe & lmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1379,10 +1550,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (R_JPAD | R_CBUTTONS)) { \
|
||||
if (buttonsdown & rmask) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) {
|
||||
if (buttonsthisframe & rmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1390,11 +1561,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
|
||||
brightness = 127;
|
||||
|
||||
if (buttonsdown & (R_JPAD | R_CBUTTONS)) {
|
||||
if (buttonsdown & rmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) {
|
||||
if (buttonsthisframe & rmask) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
@@ -1402,11 +1573,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (R_JPAD | R_CBUTTONS)) {
|
||||
if (buttonsdown & rmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) {
|
||||
if (buttonsthisframe & rmask) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1420,10 +1591,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (L_TRIG | R_TRIG)) { \
|
||||
if (buttonsdown & (R_TRIG)) { \
|
||||
brightness += 20; \
|
||||
} \
|
||||
if (buttonsthisframe & (L_TRIG | R_TRIG)) {
|
||||
if (buttonsthisframe & (R_TRIG)) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1431,11 +1602,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
|
||||
brightness = 127;
|
||||
|
||||
if (buttonsdown & (L_TRIG | R_TRIG)) {
|
||||
if (buttonsdown & (R_TRIG)) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (L_TRIG | R_TRIG)) {
|
||||
if (buttonsthisframe & (R_TRIG)) {
|
||||
brightness += 63;
|
||||
}
|
||||
|
||||
@@ -1443,11 +1614,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
} else {
|
||||
brightness = 20;
|
||||
|
||||
if (buttonsdown & (L_TRIG | R_TRIG)) {
|
||||
if (buttonsdown & (R_TRIG)) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
if (buttonsthisframe & (L_TRIG | R_TRIG)) {
|
||||
if (buttonsthisframe & (R_TRIG)) {
|
||||
brightness += 20;
|
||||
}
|
||||
|
||||
@@ -1947,6 +2118,9 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
s32 viewbottom = viewtop + viewheight;
|
||||
s32 brightness;
|
||||
s32 y;
|
||||
#ifdef AVOID_UB
|
||||
u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS;
|
||||
#endif
|
||||
|
||||
var8007f840++;
|
||||
|
||||
@@ -1968,9 +2142,15 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
skySetOverexposure(brightness, brightness, brightness);
|
||||
}
|
||||
|
||||
#ifdef AVOID_UB
|
||||
if (g_Menus[mpindex].curdialog == NULL) {
|
||||
gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60);
|
||||
}
|
||||
#else
|
||||
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
|
||||
gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60);
|
||||
}
|
||||
#endif
|
||||
|
||||
gDPPipeSync(gdl++);
|
||||
|
||||
@@ -1978,6 +2158,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
|
||||
var8007f878++;
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (y = viewtop; y < viewbottom; y++) {
|
||||
u8 green;
|
||||
|
||||
@@ -1992,6 +2173,27 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
|
||||
gdl = bviewCopyPixels(gdl, fb, y, 5, y, 1, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
|
||||
for (y = viewtop; y < viewbottom; y++) {
|
||||
u8 green;
|
||||
|
||||
if (((var8007f878 & 1) != (y & 1)) != 0) {
|
||||
u8 tmp = random() % 12;
|
||||
green = 0xff - tmp;
|
||||
} else {
|
||||
green = 0x94;
|
||||
}
|
||||
|
||||
gDPSetPrimColorViaWord(gdl++, 0, 0, (green << 16) + 0xff);
|
||||
|
||||
gDPFillRectangle(gdl++, viewleft, y, viewleft + viewwidth, y + 1);
|
||||
}
|
||||
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -2029,6 +2231,9 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
s32 viewcentrey;
|
||||
f32 viewheightf;
|
||||
s32 a0;
|
||||
#ifdef AVOID_UB
|
||||
u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS;
|
||||
#endif
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
static s32 fsscanline = 0;
|
||||
@@ -2138,6 +2343,11 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
|
||||
sqinnerradius = innerradius * innerradius;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
for (i = scantop; i < scanbottom; i++) {
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (i & 1) {
|
||||
@@ -2159,7 +2369,11 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
red = 255;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
gDPSetEnvColorViaWord(gdl++, (red << 24) + 0xff);
|
||||
#else
|
||||
gDPSetPrimColorViaWord(gdl++, 0, 0, (red << 24) + 0xff);
|
||||
#endif
|
||||
|
||||
a0 = viewcentrey - i;
|
||||
|
||||
@@ -2171,6 +2385,7 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
s32 semicircleright = viewcentrex + semicirclewidth;
|
||||
s32 rightsidewidth = viewwidth - semicircleright;
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
// Left and right of semicircle
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewcentrex);
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, semicircleright, rightsidewidth);
|
||||
@@ -2181,6 +2396,18 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
} else {
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
// Left and right of semicircle
|
||||
gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1);
|
||||
gDPFillRectangle(gdl++, semicircleright, i, semicircleright + rightsidewidth, i + 1);
|
||||
|
||||
// The semicircle itself has a static colour
|
||||
gDPSetPrimColorViaWord(gdl++, 0, 0, 0xee0000ff);
|
||||
gDPFillRectangle(gdl++, viewcentrex, i, viewcentrex + semicirclewidth, i + 1);
|
||||
} else {
|
||||
gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (g_IrScanlines[g_Vars.currentplayernum][i] > fadeincrement) {
|
||||
@@ -2193,9 +2420,19 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
#ifdef AVOID_UB
|
||||
if (g_Menus[mpindex].curdialog == NULL) {
|
||||
gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40);
|
||||
}
|
||||
#else
|
||||
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
|
||||
gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40);
|
||||
}
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -2372,7 +2609,7 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
|
||||
if (fovy == 0 || fovy == 60.0f) {
|
||||
fovy = 1;
|
||||
} else {
|
||||
fovy = 60.0f / fovy + 1;
|
||||
fovy = ADJUST_ZOOM_FOV(60.0f) / fovy;
|
||||
}
|
||||
|
||||
sprintf(zoomtext, "%s %s%s%4.2fX", arrows, "", "", fovy);
|
||||
@@ -2446,6 +2683,16 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
|
||||
vsplit = 14;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
// make a copy of what we have drawn so far and use it as a texture
|
||||
gDPFlushEXT(gdl++);
|
||||
gDPCopyFramebufferEXT(gdl++, g_PrevFrameFb, 0, 0, 0, G_ON);
|
||||
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_PrevFrameFb);
|
||||
#endif
|
||||
|
||||
// Iterate horizontal lines down the lens with a bit extra on top and bottom
|
||||
for (liney = lenstop - 9; liney < lenstop + lensheight + vsplit + 9; liney++) {
|
||||
if (liney < lenstop + lensheight && liney >= lenstop) {
|
||||
@@ -2493,7 +2740,18 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
|
||||
|
||||
gDPSetColor(gdl++, G_SETENVCOLOR, colour);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
gdl = bviewCopyPixels(gdl, fb, liney, 5, liney, RANDOMFRAC() * range + 1, viewleft, viewwidth);
|
||||
#else
|
||||
const f32 xscale = RANDOMFRAC() * range + 1;
|
||||
const f32 halfwidth = viewwidth / 2.f;
|
||||
const s32 left = viewleft + halfwidth * (1.f - xscale);
|
||||
const s32 right = viewleft + halfwidth * (1.f + xscale);
|
||||
gSPImageRectangleEXT(gdl++,
|
||||
left << 2, liney << 2, viewleft, liney,
|
||||
right << 2, (liney + 1) << 2, viewleft + viewwidth, liney + 1,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
#endif
|
||||
}
|
||||
|
||||
return gdl;
|
||||
|
||||
+110
-15
@@ -26,6 +26,71 @@
|
||||
#include "lib/collision.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#ifndef PLATFORM_N64
|
||||
#include "net/net.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
|
||||
static inline void lerpcoord(struct coord *c, const struct coord *a, const struct coord *b, const f32 t) {
|
||||
c->x = lerpf(a->x, b->x, t);
|
||||
c->y = lerpf(a->y, b->y, t);
|
||||
c->z = lerpf(a->z, b->z, t);
|
||||
}
|
||||
|
||||
static void bwalkUpdateRemote(void)
|
||||
{
|
||||
struct player *pl = g_Vars.currentplayer;
|
||||
const struct netplayermove *inmove = &pl->client->inmove[0];
|
||||
const struct netplayermove *inmoveprev = &pl->client->inmove[1];
|
||||
struct coord delta;
|
||||
u16 cdtype = CDTYPE_ALL;
|
||||
s32 moveticks = inmove->tick - inmoveprev->tick;
|
||||
if (moveticks > g_NetInterpTicks) {
|
||||
moveticks = g_NetInterpTicks;
|
||||
}
|
||||
|
||||
pl->client->inmovetick = inmove->tick;
|
||||
|
||||
pl->bondshotspeed.x = 0.f;
|
||||
pl->bondshotspeed.y = 0.f;
|
||||
pl->bondshotspeed.z = 0.f;
|
||||
pl->bondbreathing = 0.f;
|
||||
|
||||
const bool forcepos = !inmoveprev->tick ||
|
||||
(inmove->ucmd & UCMD_FL_FORCEPOS) ||
|
||||
(fabsf(pl->prop->pos.x - inmove->pos.x) > 512.f) ||
|
||||
(fabsf(pl->prop->pos.y - inmove->pos.y) > 512.f) ||
|
||||
(fabsf(pl->prop->pos.z - inmove->pos.z) > 512.f);
|
||||
|
||||
delta.x = 0.f;
|
||||
delta.y = 0.f;
|
||||
delta.z = 0.f;
|
||||
|
||||
// extrapolate
|
||||
bwalk0f0c69b8();
|
||||
|
||||
if (forcepos) {
|
||||
// no interpolation, set position and lock the lad in place
|
||||
pl->prop->pos = inmove->pos;
|
||||
pl->client->lerpticks = g_NetInterpTicks + 1;
|
||||
cdtype = CDTYPE_PLAYERS; // don't get stuck in the local client
|
||||
} else if (!moveticks) {
|
||||
// duplicate move, reposition to correct coords
|
||||
delta.x = inmove->pos.x - pl->prop->pos.x;
|
||||
delta.x = inmove->pos.y - pl->prop->pos.y;
|
||||
delta.x = inmove->pos.z - pl->prop->pos.z;
|
||||
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
|
||||
} else if (pl->client->lerpticks <= moveticks) {
|
||||
// lerp towards the correct position
|
||||
const f32 dt = (f32)1.f / (f32)moveticks;
|
||||
delta.x = g_Vars.lvupdate60freal * (inmove->pos.x - pl->prop->pos.x) * dt;
|
||||
delta.y = g_Vars.lvupdate60freal * (inmove->pos.y - pl->prop->pos.y) * dt;
|
||||
delta.z = g_Vars.lvupdate60freal * (inmove->pos.z - pl->prop->pos.z) * dt;
|
||||
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
|
||||
pl->client->lerpticks += g_Vars.lvupdate60;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void bwalkInit(void)
|
||||
{
|
||||
@@ -120,6 +185,10 @@ void bwalkInit(void)
|
||||
}
|
||||
}
|
||||
|
||||
void bwalkSetSwayTargetf(f32 value) {
|
||||
g_Vars.currentplayer->swaytarget = value * 75.f;
|
||||
}
|
||||
|
||||
void bwalkSetSwayTarget(s32 value)
|
||||
{
|
||||
g_Vars.currentplayer->swaytarget = value * 75.0f;
|
||||
@@ -187,7 +256,7 @@ s32 bwalkTryMoveUpwards(f32 amount)
|
||||
{
|
||||
bool result;
|
||||
struct coord newpos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
u32 stack;
|
||||
u32 types;
|
||||
f32 ymax;
|
||||
@@ -235,9 +304,9 @@ bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply,
|
||||
s32 result = CDRESULT_NOCOLLISION;
|
||||
f32 halfradius;
|
||||
struct coord dstpos;
|
||||
s16 dstrooms[8];
|
||||
RoomNum dstrooms[8];
|
||||
bool copyrooms = false;
|
||||
s16 sp64[22];
|
||||
RoomNum sp64[22];
|
||||
s32 types;
|
||||
f32 ymax;
|
||||
f32 ymin;
|
||||
@@ -392,7 +461,7 @@ bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bo
|
||||
} else if (obstacle->type == PROPTYPE_CHR) {
|
||||
struct chrdata *chr = obstacle->chr;
|
||||
struct coord newpos;
|
||||
s16 newrooms[8];
|
||||
RoomNum newrooms[8];
|
||||
f32 movingdist;
|
||||
f32 xdist;
|
||||
f32 zdist;
|
||||
@@ -406,7 +475,7 @@ bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bo
|
||||
}
|
||||
} else if (chr->chrflags & CHRCFLAG_PUSHABLE) {
|
||||
if (g_Vars.antiplayernum < 0
|
||||
|| g_Vars.currentplayer != g_Vars.anti
|
||||
|| PLAYER_IS_NOT_ANTI(g_Vars.currentplayer)
|
||||
|| (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) {
|
||||
canpush = true;
|
||||
}
|
||||
@@ -713,10 +782,10 @@ void bwalkUpdateVertical(void)
|
||||
f32 ground;
|
||||
bool onladder;
|
||||
bool onladder2 = false;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
struct coord testpos;
|
||||
struct coord newpos;
|
||||
s16 newrooms[8];
|
||||
RoomNum newrooms[8];
|
||||
s32 newinlift;
|
||||
struct prop *lift = NULL;
|
||||
f32 sumground;
|
||||
@@ -740,7 +809,7 @@ void bwalkUpdateVertical(void)
|
||||
// Maybe reset counter-op's radius - not sure why
|
||||
// Maybe it gets set to 0 when they die?
|
||||
if (g_Vars.antiplayernum >= 0
|
||||
&& g_Vars.currentplayer == g_Vars.anti
|
||||
&& PLAYER_IS_ANTI(g_Vars.currentplayer)
|
||||
&& g_Vars.currentplayer->bond2.radius != 30
|
||||
&& cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, CHECKVERTICAL_YES, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) {
|
||||
g_Vars.currentplayer->prop->chr->radius = 30;
|
||||
@@ -1209,8 +1278,13 @@ void bwalkUpdateTheta(void)
|
||||
f32 rotateamount;
|
||||
struct coord delta = {0, 0, 0};
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
// Turn speed is calculated from the chr's height
|
||||
mult = 159.0f / g_Vars.currentplayer->vv_eyeheight;
|
||||
#else
|
||||
// Same turn speed for all heights
|
||||
mult = 1.f;
|
||||
#endif
|
||||
rotateamount = g_Vars.currentplayer->speedtheta * mult
|
||||
* g_Vars.lvupdate60freal * 0.0174505133f * 3.5f;
|
||||
|
||||
@@ -1289,12 +1363,11 @@ void bwalkApplyMoveData(struct movedata *data)
|
||||
bwalkUpdateSpeedSideways(1, 0.2f, data->digitalstepright);
|
||||
} else if (data->unk14 == false) {
|
||||
bwalkUpdateSpeedSideways(0, 0.2f, g_Vars.lvupdate60);
|
||||
}
|
||||
|
||||
if (data->unk14) {
|
||||
} else if (data->unk14){
|
||||
bwalkUpdateSpeedSideways(data->analogstrafe * 0.014285714365542f, 0.2f, g_Vars.lvupdate60);
|
||||
}
|
||||
|
||||
|
||||
// Forward/back
|
||||
if (data->digitalstepforward) {
|
||||
bwalkUpdateSpeedForwards(1, 1);
|
||||
@@ -1303,11 +1376,12 @@ void bwalkApplyMoveData(struct movedata *data)
|
||||
bwalkUpdateSpeedForwards(-1, 1);
|
||||
} else if (data->canlookahead == false) {
|
||||
bwalkUpdateSpeedForwards(0, 1);
|
||||
} else {
|
||||
bwalkUpdateSpeedForwards(data->analogwalk * 0.014285714365542f, 1);
|
||||
}
|
||||
|
||||
if (data->canlookahead) {
|
||||
bwalkUpdateSpeedForwards(data->analogwalk * 0.014285714365542f, 1);
|
||||
|
||||
if (data->canlookahead) {
|
||||
if (data->analogwalk > 60) {
|
||||
g_Vars.currentplayer->speedmaxtime60 += g_Vars.lvupdate60;
|
||||
} else {
|
||||
@@ -1340,6 +1414,17 @@ void bwalkApplyMoveData(struct movedata *data)
|
||||
g_Vars.currentplayer->speedmaxtime60 = 0;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (data->rleanleft) {
|
||||
bwalkSetSwayTarget(-1);
|
||||
} else if (data->rleanright) {
|
||||
bwalkSetSwayTarget(1);
|
||||
} else if (fabsf(data->analoglean)) {
|
||||
bwalkSetSwayTargetf(data->analoglean);
|
||||
} else {
|
||||
bwalkSetSwayTarget(0);
|
||||
}
|
||||
#else
|
||||
if (data->rleanleft) {
|
||||
bwalkSetSwayTarget(-1);
|
||||
} else if (data->rleanright) {
|
||||
@@ -1347,6 +1432,7 @@ void bwalkApplyMoveData(struct movedata *data)
|
||||
} else {
|
||||
bwalkSetSwayTarget(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (data->crouchdown-- > 0) {
|
||||
bwalkAdjustCrouchPos(-1);
|
||||
@@ -1362,11 +1448,13 @@ void bwalkApplyMoveData(struct movedata *data)
|
||||
|
||||
void bwalkUpdateSpeedTheta(void)
|
||||
{
|
||||
#ifdef PLATFORM_N64
|
||||
if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) {
|
||||
g_Vars.currentplayer->speedtheta *= 0.5f;
|
||||
} else if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) {
|
||||
g_Vars.currentplayer->speedtheta *= 0.75f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bwalk0f0c69b8(void)
|
||||
@@ -1543,7 +1631,7 @@ void bwalk0f0c69b8(void)
|
||||
g_Vars.currentplayer->bondbreathing = 1.0f;
|
||||
}
|
||||
|
||||
mult = var80075c00[1].unk0c * 0.5f * g_Vars.lvupdate60freal;
|
||||
mult = g_HeadAnims[HEADANIM_MOVING].translateperframe * 0.5f * g_Vars.lvupdate60freal;
|
||||
spe0 = (g_Vars.currentplayer->speedsideways * spc0 + spc4) * mult;
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
@@ -1728,7 +1816,7 @@ void bwalk0f0c69b8(void)
|
||||
sp40 = -1.0f;
|
||||
}
|
||||
|
||||
if (g_Vars.currentplayer->headanim == 1) {
|
||||
if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
|
||||
breathing *= 1.2f;
|
||||
}
|
||||
|
||||
@@ -1741,7 +1829,14 @@ void bwalkTick(void)
|
||||
bwalkUpdatePrevPos();
|
||||
bwalkUpdateTheta();
|
||||
bmoveUpdateVerta();
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_Vars.currentplayer->isremote) {
|
||||
bwalkUpdateRemote();
|
||||
} else
|
||||
#endif
|
||||
bwalk0f0c69b8();
|
||||
|
||||
bwalkUpdateVertical();
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
|
||||
+21
-6
@@ -88,6 +88,10 @@ void botReset(struct chrdata *chr, u8 respawning)
|
||||
chrSetShield(chr, 0);
|
||||
chr->cmnum = 0;
|
||||
chr->cmnum2 = 0;
|
||||
#ifndef PLATFORM_N64
|
||||
chr->blurdrugamount = 0;
|
||||
chr->poisoncounter = 0;
|
||||
#endif
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
bgunFreeFireslot(chr->fireslots[0]);
|
||||
@@ -227,7 +231,7 @@ void botSpawn(struct chrdata *chr, u8 respawning)
|
||||
struct defaultobj *obj;
|
||||
struct aibot *aibot = chr->aibot;
|
||||
struct coord pos;
|
||||
s16 rooms[8];
|
||||
RoomNum rooms[8];
|
||||
|
||||
if (chr->prop) {
|
||||
prop = chr->prop->child;
|
||||
@@ -256,6 +260,17 @@ void botSpawn(struct chrdata *chr, u8 respawning)
|
||||
chr->aibot->moveratex = 0;
|
||||
chr->aibot->moveratey = 0;
|
||||
func0f02e9a0(chr, 0);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
|
||||
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
|
||||
botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
|
||||
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2);
|
||||
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,8 +675,8 @@ void botCheckPickups(struct chrdata *chr)
|
||||
s32 i;
|
||||
s16 *propnumptr;
|
||||
s16 propnums[260];
|
||||
s16 allrooms[22];
|
||||
s16 neighbours[12];
|
||||
RoomNum allrooms[22];
|
||||
RoomNum neighbours[12];
|
||||
|
||||
roomsCopy(chr->prop->rooms, allrooms);
|
||||
|
||||
@@ -1208,7 +1223,7 @@ void botApplyProtect(struct chrdata *chr, struct prop *prop)
|
||||
chr->aibot->forcemainloop = true;
|
||||
}
|
||||
|
||||
void botApplyDefend(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle)
|
||||
void botApplyDefend(struct chrdata *chr, struct coord *pos, RoomNum *room, f32 angle)
|
||||
{
|
||||
chr->aibot->command = AIBOTCMD_DEFEND;
|
||||
chr->aibot->defendholdpos.x = pos->x;
|
||||
@@ -1219,7 +1234,7 @@ void botApplyDefend(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle
|
||||
chr->aibot->forcemainloop = true;
|
||||
}
|
||||
|
||||
void botApplyHold(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle)
|
||||
void botApplyHold(struct chrdata *chr, struct coord *pos, RoomNum *room, f32 angle)
|
||||
{
|
||||
chr->aibot->command = AIBOTCMD_HOLD;
|
||||
chr->aibot->defendholdpos.x = pos->x;
|
||||
@@ -1521,7 +1536,7 @@ void botChooseGeneralTarget(struct chrdata *botchr)
|
||||
s32 i;
|
||||
s32 j;
|
||||
bool distancesdone[MAX_MPCHRS];
|
||||
s16 room = -1;
|
||||
RoomNum room = -1;
|
||||
struct chrdata *trychr;
|
||||
s32 playernum;
|
||||
|
||||
|
||||
+3
-3
@@ -259,7 +259,7 @@ bool botactShootFarsight(struct chrdata *chr, s32 arg1, struct coord *vector, st
|
||||
// chance of passing.
|
||||
if (oppchr != chr
|
||||
&& value > rand
|
||||
&& func0f06b39c(arg3, vector, &oppprop->pos, chr0f0278a4(oppchr))) {
|
||||
&& func0f06b39c(arg3, vector, &oppprop->pos, chrGetHitRadius(oppchr))) {
|
||||
bgunPlayPropHitSound(&gset, oppprop, -1);
|
||||
|
||||
if (oppchr->model && chrGetShield(oppchr) > 0) {
|
||||
@@ -440,7 +440,7 @@ s32 botactGetShootInterval60(s32 weaponnum, s32 funcnum)
|
||||
*
|
||||
* Return true if a route was found, false if not.
|
||||
*/
|
||||
bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct coord *topos, s16 *fromrooms, s16 *torooms, struct projectile *projectile)
|
||||
bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct coord *topos, RoomNum *fromrooms, RoomNum *torooms, struct projectile *projectile)
|
||||
{
|
||||
struct waypoint *from = waypointFindClosestToPos(frompos, fromrooms);
|
||||
struct waypoint *to = waypointFindClosestToPos(topos, torooms);
|
||||
@@ -479,7 +479,7 @@ bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct co
|
||||
void botactGetRocketNextStepPos(u16 padnum, struct coord *pos)
|
||||
{
|
||||
struct pad pad;
|
||||
s16 rooms[2];
|
||||
RoomNum rooms[2];
|
||||
|
||||
padUnpack(padnum, PADFIELD_ROOM | PADFIELD_POS, &pad);
|
||||
|
||||
|
||||
+12
-1
@@ -56,7 +56,7 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
|
||||
/*0x17*/ { 176, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 20, 20, 4, 4, 2, 0 }, // WEAPON_DEVASTATOR
|
||||
/*0x18*/ { 160, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 2, 0 }, // WEAPON_ROCKETLAUNCHER
|
||||
/*0x19*/ { 168, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 3, 0 }, // WEAPON_SLAYER
|
||||
#if VERSION == VERSION_JPN_FINAL
|
||||
#if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64)
|
||||
/*0x1a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATKNIFE
|
||||
#else
|
||||
/*0x1a*/ { 20, 40, 24, 40, 1, 1, BOTDISTCFG_CLOSE, BOTDISTCFG_DEFAULT, 0, 5, 0, 1, 1, 0 }, // WEAPON_COMBATKNIFE
|
||||
@@ -70,6 +70,16 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
|
||||
/*0x21*/ { 40, 176, 0, 0, 0, 0, BOTDISTCFG_THROWEXPLOSIVE, BOTDISTCFG_DEFAULT, 5, 5, 1, 1, 1, 0 }, // WEAPON_PROXIMITYMINE
|
||||
/*0x22*/ { 44, 156, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 5, 5, 2, 2, 1, 0 }, // WEAPON_REMOTEMINE
|
||||
/*0x23*/ { 8, 8, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATBOOST
|
||||
#ifndef PLATFORM_N64 // add all classic weapons to multiplayer
|
||||
/*0x24*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I
|
||||
/*0x25*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13
|
||||
/*0x26*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313
|
||||
/*0x27*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL
|
||||
/*0x28*/ { 116, 128, 136, 152, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT
|
||||
/*0x29*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC
|
||||
/*0x2a*/ { 156, 180, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 150, 0, 30, 0, 1, 0 }, // WEAPON_AR53
|
||||
/*0x2b*/ { 164, 188, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45
|
||||
#else
|
||||
/*0x24*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PP9I
|
||||
/*0x25*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_CC13
|
||||
/*0x26*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_KL01313
|
||||
@@ -78,6 +88,7 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
|
||||
/*0x29*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_DMC
|
||||
/*0x2a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_AR53
|
||||
/*0x2b*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_RCP45
|
||||
#endif
|
||||
/*0x2c*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PSYCHOSISGUN
|
||||
/*0x2d*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_NIGHTVISION
|
||||
/*0x2e*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_EYESPY
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ void botmgrRemoveAll(void)
|
||||
|
||||
void botmgrAllocateBot(s32 chrnum, s32 aibotnum)
|
||||
{
|
||||
s16 rooms[1];
|
||||
RoomNum rooms[1];
|
||||
struct prop *prop;
|
||||
struct chrdata *chr;
|
||||
struct aibot *aibot;
|
||||
|
||||
+5
-5
@@ -46,16 +46,16 @@
|
||||
* It's likely that these don't ever overflow, or they overflow minimally which
|
||||
* has no serious effect, but this should be investigated further.
|
||||
*/
|
||||
bool botroomFindPos(s16 room, struct coord *pos, f32 *angleptr, s32 *padnumptr, s32 *covernumptr)
|
||||
bool botroomFindPos(RoomNum room, struct coord *pos, f32 *angleptr, s32 *padnumptr, s32 *covernumptr)
|
||||
{
|
||||
s32 i;
|
||||
struct waypoint *waypoint;
|
||||
s32 waypointnum;
|
||||
s32 covernums[40]; /// written to stack
|
||||
s32 covernums[40];
|
||||
s32 covercount;
|
||||
struct cover cover; // written to stack
|
||||
s16 rooms[2]; // written to stack
|
||||
s32 padnums[40]; // written to stack
|
||||
struct cover cover;
|
||||
RoomNum rooms[2];
|
||||
s32 padnums[40];
|
||||
s32 padcount;
|
||||
s32 totalcount;
|
||||
struct pad pad;
|
||||
|
||||
+16
-16
@@ -948,7 +948,7 @@ void func0f14aee0(void)
|
||||
thing->unk078 = 0;
|
||||
|
||||
pak0f117150(i, thing->unk0d8);
|
||||
pak0f1171b4(SAVEDEVICE_CONTROLLERPAK1, 3, 0);
|
||||
pak0f1171b4(SAVEDEVICE_CONTROLLERPAK1, PAK00C_03, 0);
|
||||
func0f14aed0(i);
|
||||
|
||||
thing->unk094 = 0;
|
||||
@@ -1200,7 +1200,7 @@ void func0f14b8ac(s32 index)
|
||||
}
|
||||
|
||||
switch (pakGetUnk008(func0f14a5a4())) {
|
||||
case 12:
|
||||
case PAK008_12:
|
||||
func0f14a95c();
|
||||
func0f14aa48();
|
||||
func0f14e790(var800a45a0->unk470);
|
||||
@@ -1209,10 +1209,10 @@ void func0f14b8ac(s32 index)
|
||||
func0f14a16c(1);
|
||||
func0f14bc04();
|
||||
break;
|
||||
case 1:
|
||||
case PAK008_01:
|
||||
pak0f11d4dc(func0f14a5a4());
|
||||
break;
|
||||
case 11:
|
||||
case PAK008_11:
|
||||
pak0f11d9c4(func0f14a5a4(), var800a45a0->unk470, 0, 0);
|
||||
func0f14d064(index, var800a45a0->unk470);
|
||||
pak0f11d478(func0f14a5a4());
|
||||
@@ -1320,7 +1320,7 @@ void func0f14bd34(s32 index)
|
||||
struct var8007f8dc *thing = &var8007f8dc[index];
|
||||
|
||||
if (thing->unk080 != -1) {
|
||||
pak0f1171b4(func0f14a5a4(), 3, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
|
||||
pak0f11d540(func0f14a5a4(), thing->unk0b6[thing->unk080]);
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1333,7 @@ void func0f14bdbc(s32 index)
|
||||
s32 value;
|
||||
|
||||
for (i = 0; i < 30; i++) {
|
||||
thing->unk0dc[i] = NULL;
|
||||
thing->unk0dc[i] = 0;
|
||||
}
|
||||
|
||||
thing->unk094 = 0;
|
||||
@@ -1402,7 +1402,7 @@ void func0f14bec8(s32 index)
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(thing->unk0b6); i++);
|
||||
|
||||
pak0f1171b4(func0f14a5a4(), 3, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
|
||||
pak0f11d478(func0f14a5a4());
|
||||
break;
|
||||
case 3:
|
||||
@@ -1446,7 +1446,7 @@ void func0f14c1cc(s32 index)
|
||||
|
||||
switch (thing->unk0f4) {
|
||||
case 0:
|
||||
pak0f1171b4(func0f14a5a4(), 0, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_00, 0);
|
||||
pak0f11d5b0(func0f14a5a4());
|
||||
thing->unk0f4 = 1;
|
||||
break;
|
||||
@@ -1510,13 +1510,13 @@ void func0f14c3a4(s32 index)
|
||||
pak0f11d620(func0f14a5a4());
|
||||
|
||||
switch (pakGetUnk008(func0f14a5a4())) {
|
||||
case 1:
|
||||
case PAK008_01:
|
||||
func0f14c1cc(index);
|
||||
break;
|
||||
case 11:
|
||||
case PAK008_11:
|
||||
func0f14bec8(index);
|
||||
break;
|
||||
case 12:
|
||||
case PAK008_12:
|
||||
func0f14bdbc(index);
|
||||
break;
|
||||
}
|
||||
@@ -1712,7 +1712,7 @@ void func0f14cdb8(s32 index, u8 *arg1)
|
||||
void func0f14ce84(void)
|
||||
{
|
||||
if (pak0f11d3f8(func0f14a5a4())) {
|
||||
if (pakGetUnk008(func0f14a5a4()) != 12) {
|
||||
if (pakGetUnk008(func0f14a5a4()) != PAK008_12) {
|
||||
var8007f8dc[func0f14a5a4()].unk0f8 = 1;
|
||||
var8007f8dc[func0f14a5a4()].unk0d4_00 = false;
|
||||
|
||||
@@ -1739,7 +1739,7 @@ void func0f14cf6c(void)
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
pak0f1171b4(func0f14a5a4(), 3, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
|
||||
g_MpPlayerNum = 0;
|
||||
menuSetBanner(-1, false);
|
||||
break;
|
||||
@@ -1762,7 +1762,7 @@ void func0f14d064(s32 index, u8 *arg1)
|
||||
g_MpPlayerNum = index;
|
||||
menuSetBanner(MENUBANNER_CALIBRATINGCAMERA, false);
|
||||
func0f14a16c(1);
|
||||
pak0f1171b4(func0f14a5a4(), 1, 1);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_01, 1);
|
||||
thing->unk0f8 = 3;
|
||||
return;
|
||||
}
|
||||
@@ -1801,12 +1801,12 @@ void func0f14d064(s32 index, u8 *arg1)
|
||||
}
|
||||
|
||||
if (thing->unk0f8 == 6) {
|
||||
pak0f1171b4(func0f14a5a4(), 3, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
|
||||
thing->unk0f8 = 6;
|
||||
thing->unk100 = thing->unk0fc;
|
||||
g_MpPlayerNum = index;
|
||||
menuSetBanner(-1, false);
|
||||
pak0f1171b4(func0f14a5a4(), 3, 0);
|
||||
pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
|
||||
var8007f8dc[var800a45a0->unk000].unk0d4_04 = true;
|
||||
thing->unk0f8 = 0;
|
||||
}
|
||||
|
||||
+20
-14
@@ -1,4 +1,5 @@
|
||||
#include <ultra64.h>
|
||||
#include <string.h>
|
||||
#include "constants.h"
|
||||
#include "game/atan2f.h"
|
||||
#include "game/camera.h"
|
||||
@@ -105,7 +106,7 @@ void camSetScale(void)
|
||||
player->c_cameraleftnorm.z = -fVar5 * fVar4;
|
||||
}
|
||||
|
||||
void cam0f0b4c3c(f32 *crosspos, struct coord *dst, f32 arg2)
|
||||
void cam0f0b4c3c(f32 pos2d[2], struct coord *dir2d, f32 arg2)
|
||||
{
|
||||
struct player *player = g_Vars.currentplayer;
|
||||
f32 sp20;
|
||||
@@ -113,14 +114,14 @@ void cam0f0b4c3c(f32 *crosspos, struct coord *dst, f32 arg2)
|
||||
f32 sp18 = -1.0f;
|
||||
f32 f2;
|
||||
|
||||
sp1c = (player->c_halfheight - (crosspos[1] - player->c_screentop)) * player->c_scaley;
|
||||
sp20 = (crosspos[0] - player->c_screenleft - player->c_halfwidth) * player->c_scalex;
|
||||
sp1c = (player->c_halfheight - (pos2d[1] - player->c_screentop)) * player->c_scaley;
|
||||
sp20 = (pos2d[0] - player->c_screenleft - player->c_halfwidth) * player->c_scalex;
|
||||
|
||||
f2 = arg2 / sqrtf(sp20 * sp20 + sp1c * sp1c + sp18 * sp18);
|
||||
|
||||
dst->x = sp20 * f2;
|
||||
dst->y = sp1c * f2;
|
||||
dst->z = sp18 * f2;
|
||||
dir2d->x = sp20 * f2;
|
||||
dir2d->y = sp1c * f2;
|
||||
dir2d->z = sp18 * f2;
|
||||
}
|
||||
|
||||
void cam0f0b4d04(struct coord *in, f32 *out)
|
||||
@@ -128,11 +129,8 @@ void cam0f0b4d04(struct coord *in, f32 *out)
|
||||
struct player *player = g_Vars.currentplayer;
|
||||
f32 value = 1.0f / in->z;
|
||||
|
||||
out[1] = in->y * value * player->c_recipscaley
|
||||
+ (player->c_screentop + player->c_halfheight);
|
||||
|
||||
out[0] = (player->c_screenleft + player->c_halfwidth)
|
||||
- in->x * value * player->c_recipscalex;
|
||||
out[1] = in->y * value * player->c_recipscaley + (player->c_screentop + player->c_halfheight);
|
||||
out[0] = (player->c_screenleft + player->c_halfwidth) - in->x * value * player->c_recipscalex;
|
||||
}
|
||||
|
||||
void cam0f0b4d68(struct coord *in, f32 out[2])
|
||||
@@ -597,12 +595,15 @@ bool camIsPosInScreenBox(struct coord *pos, f32 arg1, struct drawslot *drawslot)
|
||||
* correct address to camIsPosInScreenBox so it can interpret the pointer as a
|
||||
* drawslot.
|
||||
*/
|
||||
bool camIsPosInFovAndVisibleRoom(s16 *rooms, struct coord *pos, f32 arg2)
|
||||
bool camIsPosInFovAndVisibleRoom(RoomNum *rooms, struct coord *pos, f32 arg2)
|
||||
{
|
||||
s32 i;
|
||||
s16 room;
|
||||
RoomNum room;
|
||||
bool hasdata = false;
|
||||
struct drawslot *thisthing;
|
||||
#ifdef AVOID_UB
|
||||
static struct drawslot dslot;
|
||||
#endif
|
||||
struct screenbox box;
|
||||
|
||||
for (i = 0, room = rooms[i]; room != -1; i++, room = rooms[i]) {
|
||||
@@ -640,5 +641,10 @@ bool camIsPosInFovAndVisibleRoom(s16 *rooms, struct coord *pos, f32 arg2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return camIsPosInScreenBox(pos, arg2, (struct drawslot *) (&box.array[-1][0]));
|
||||
#ifdef AVOID_UB
|
||||
memcpy(&dslot.box, &box, sizeof(box));
|
||||
return camIsPosInScreenBox(pos, arg2, &dslot);
|
||||
#else
|
||||
return camIsPosInScreenBox(pos, arg2, (struct drawslot *) &(((u8 *) &box)[-((uintptr_t) &(((struct drawslot *)0)->box))]));
|
||||
#endif
|
||||
}
|
||||
+1
-1
@@ -21,7 +21,7 @@ f32 ceilf(f32 value)
|
||||
return fvalue + 1;
|
||||
}
|
||||
|
||||
s32 ceil(f32 value)
|
||||
s32 ceiltoint(f32 value)
|
||||
{
|
||||
s32 ivalue;
|
||||
|
||||
|
||||
+48
-28
@@ -136,7 +136,7 @@ void challengeDetermineUnlockedFeatures(void)
|
||||
}
|
||||
|
||||
// Now same as above, but per player
|
||||
for (j = 0; j < MAX_PLAYERS; j++) {
|
||||
for (j = 0; j < MAX_LOCAL_PLAYERS; j++) {
|
||||
numgifted = 0;
|
||||
|
||||
for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) {
|
||||
@@ -197,7 +197,7 @@ void challengeDetermineUnlockedFeatures(void)
|
||||
}
|
||||
|
||||
for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) {
|
||||
for (prev = 0; prev < MAX_PLAYERS; prev++) {
|
||||
for (prev = 0; prev < MAX_LOCAL_PLAYERS; prev++) {
|
||||
if (challengeIsAvailableToPlayer(prev, challengeindex)) {
|
||||
for (i = 0; i < ARRAYCOUNT(g_MpChallenges[challengeindex].unlockfeatures); i++) {
|
||||
if (g_MpChallenges[challengeindex].unlockfeatures[i] == j) {
|
||||
@@ -249,7 +249,7 @@ void challengePerformSanityChecks(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Turn off all simulants and turn them on if enabled
|
||||
// Turn off all simulants (and players 5-8 if supported) and turn them on if enabled
|
||||
// for this number of players
|
||||
g_MpSetup.chrslots &= 0x000f;
|
||||
|
||||
@@ -265,8 +265,14 @@ void challengePerformSanityChecks(void)
|
||||
g_Vars.mphilltime = 10;
|
||||
}
|
||||
} else if (!challengeIsFeatureUnlocked(MPFEATURE_8BOTS)) {
|
||||
// Limit to 4 players and 4 simulants
|
||||
// Limit to 4 players and 4 simulants in local games
|
||||
#ifndef PLATFORM_N64
|
||||
g_MpSetup.chrslots &= (g_NetMode ? 0x0fff : 0x0f0f);
|
||||
#elif MAX_PLAYERS > 4
|
||||
g_MpSetup.chrslots &= 0x0f0f;
|
||||
#else
|
||||
g_MpSetup.chrslots &= 0x00ff;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,41 +373,55 @@ bool challengeIsCompletedByChrWithNumPlayersBySlot(s32 mpchrnum, s32 slot, s32 n
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
#define BTYPE s32
|
||||
#else
|
||||
#define BTYPE uintptr_t
|
||||
#endif
|
||||
|
||||
struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len)
|
||||
{
|
||||
struct mpconfigfull *mpconfig;
|
||||
u8 buffer2[sizeof(struct mpstrings) + 40];
|
||||
struct mpstrings *loadedstrings;
|
||||
s32 bank;
|
||||
BTYPE bank;
|
||||
u32 language_id = langGetFileNumOffset();
|
||||
#ifdef PLATFORM_N64
|
||||
extern struct mpconfig _mpconfigsSegmentRomStart[];
|
||||
extern struct mpstrings _mpstringsESegmentRomStart;
|
||||
extern struct mpstrings _mpstringsJSegmentRomStart;
|
||||
extern struct mpstrings _mpstringsPSegmentRomStart;
|
||||
extern struct mpstrings _mpstringsGSegmentRomStart;
|
||||
extern struct mpstrings _mpstringsFSegmentRomStart;
|
||||
extern struct mpstrings _mpstringsSSegmentRomStart;
|
||||
extern struct mpstrings _mpstringsISegmentRomStart;
|
||||
extern struct mpstrings _mpstringsESegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsJSegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsPSegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsGSegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsFSegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsSSegmentRomEnd;
|
||||
extern struct mpstrings _mpstringsISegmentRomEnd;
|
||||
#else
|
||||
extern u8 EXT_SEG _mpconfigsSegmentRomStart;
|
||||
#endif
|
||||
extern struct mpstrings EXT_SEG _mpstringsESegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsJSegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsPSegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsGSegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsFSegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsSSegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsISegmentRomStart;
|
||||
extern struct mpstrings EXT_SEG _mpstringsESegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsJSegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsPSegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsGSegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsFSegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd;
|
||||
extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd;
|
||||
|
||||
s32 banks[][2] = {
|
||||
{ (s32)&_mpstringsESegmentRomStart, (s32)&_mpstringsESegmentRomEnd },
|
||||
{ (s32)&_mpstringsJSegmentRomStart, (s32)&_mpstringsJSegmentRomEnd },
|
||||
{ (s32)&_mpstringsPSegmentRomStart, (s32)&_mpstringsPSegmentRomEnd },
|
||||
{ (s32)&_mpstringsGSegmentRomStart, (s32)&_mpstringsGSegmentRomEnd },
|
||||
{ (s32)&_mpstringsFSegmentRomStart, (s32)&_mpstringsFSegmentRomEnd },
|
||||
{ (s32)&_mpstringsSSegmentRomStart, (s32)&_mpstringsSSegmentRomEnd },
|
||||
{ (s32)&_mpstringsISegmentRomStart, (s32)&_mpstringsISegmentRomEnd },
|
||||
BTYPE banks[][2] = {
|
||||
{ (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsJSegmentRomStart, (BTYPE)REF_SEG _mpstringsJSegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsPSegmentRomStart, (BTYPE)REF_SEG _mpstringsPSegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsGSegmentRomStart, (BTYPE)REF_SEG _mpstringsGSegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsFSegmentRomStart, (BTYPE)REF_SEG _mpstringsFSegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsSSegmentRomStart, (BTYPE)REF_SEG _mpstringsSSegmentRomEnd },
|
||||
{ (BTYPE)REF_SEG _mpstringsISegmentRomStart, (BTYPE)REF_SEG _mpstringsISegmentRomEnd },
|
||||
};
|
||||
|
||||
// Load mpconfigs
|
||||
mpconfig = dmaExecWithAutoAlign(buffer, (s32)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig));
|
||||
#ifdef PLATFORM_N64
|
||||
mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig));
|
||||
#else
|
||||
mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)REF_SEG _mpconfigsSegmentRomStart + confignum * sizeof(struct mpconfig), sizeof(struct mpconfig));
|
||||
#endif
|
||||
|
||||
// Load mpstrings
|
||||
bank = banks[language_id][0];
|
||||
|
||||
@@ -100,6 +100,9 @@ struct cheat g_Cheats[] = {
|
||||
{ L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC
|
||||
{ L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53
|
||||
{ L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45
|
||||
#ifndef PLATFORM_N64
|
||||
{ L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // Dual wield all guns
|
||||
#endif
|
||||
};
|
||||
|
||||
u32 cheatIsUnlocked(s32 cheat_id)
|
||||
@@ -859,6 +862,79 @@ char *cheatGetName(s32 cheat_id)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
|
||||
static MenuItemHandlerResult menuhandlerUnlockEverything(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
gamefileUnlockEverything();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_CheatsConfirmUnlockMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Are you sure?\n\nThis will overwrite any progress\nsaved to the current profile.\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0x00000082,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_MARQUEE,
|
||||
0,
|
||||
MENUITEMFLAG_SMALLFONT | MENUITEMFLAG_MARQUEE_FADEBOTHSIDES | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Unlocks all cheats, weapons, missions, challenges and combat simulator items.\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0x00000082,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_191, // "No"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_190, // "Yes"
|
||||
0,
|
||||
menuhandlerUnlockEverything,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_CheatsConfirmUnlockMenuDialog = {
|
||||
MENUDIALOGTYPE_DANGER,
|
||||
L_OPTIONS_188, // "Warning"
|
||||
g_CheatsConfirmUnlockMenuItems,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct menuitem g_CheatsFunMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
@@ -1017,6 +1093,16 @@ struct menuitem g_CheatsGameplayMenuItems[] = {
|
||||
0,
|
||||
cheatCheckboxMenuHandler,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
CHEAT_DUALWIELDALLGUNS,
|
||||
0,
|
||||
(uintptr_t)&cheatGetNameIfUnlocked,
|
||||
0,
|
||||
cheatCheckboxMenuHandler,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
@@ -1538,6 +1624,16 @@ struct menuitem g_CheatsMenuItems[] = {
|
||||
0,
|
||||
cheatMenuHandleTurnOffAllCheats,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG,
|
||||
(uintptr_t)"Unlock Everything\n",
|
||||
0,
|
||||
(void *)&g_CheatsConfirmUnlockMenuDialog,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
|
||||
Loaded 100 of 309 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user