forked from Ports/perfect_dark
Compare commits
431
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc9b4d1a39 | ||
|
|
f96a03e60f | ||
|
|
9d2db1a346 | ||
|
|
fc7141d0f2 | ||
|
|
f414e8a792 | ||
|
|
ab73fdcc30 | ||
|
|
30071e8f64 | ||
|
|
9695856be6 | ||
|
|
053f7dc8a5 | ||
|
|
1555a4be84 | ||
|
|
d4856a193b | ||
|
|
cb6dc1feab | ||
|
|
b93015c51c | ||
|
|
6198fbc479 | ||
|
|
0316317aa3 | ||
|
|
f9cfa0fa43 | ||
|
|
7a98095a0b | ||
|
|
8f477a36b6 | ||
|
|
4d4fa8f681 | ||
|
|
0ac5fdd5c3 | ||
|
|
33c5194a1b | ||
|
|
edd58c8925 | ||
|
|
e32d719c16 | ||
|
|
be4d8330bd | ||
|
|
91c207a51b | ||
|
|
0d76ad102f | ||
|
|
135c293656 | ||
|
|
a1d6916871 | ||
|
|
9a853077a0 | ||
|
|
dace9fd634 | ||
|
|
9e19055348 | ||
|
|
dcef8deed8 | ||
|
|
c44704e2af | ||
|
|
1a5e42e55f | ||
|
|
a26260e932 | ||
|
|
3d75365f2b | ||
|
|
ad9ed9ff3b | ||
|
|
4f55a41d99 | ||
|
|
355f0ed0ee | ||
|
|
f5d851f7c2 | ||
|
|
4019bd59cf | ||
|
|
6c29e7ecc8 | ||
|
|
e65f46d081 | ||
|
|
9633e7eac6 | ||
|
|
2ff8819265 | ||
|
|
77d1ded519 | ||
|
|
60b8e3b49e | ||
|
|
8b0b75d4ad | ||
|
|
ea464ca6ac | ||
|
|
a9752198c3 | ||
|
|
fbd9ef002e | ||
|
|
e4972ddbe3 | ||
|
|
8dbe6f2a63 | ||
|
|
045c4c371a | ||
|
|
f4f1470e1e | ||
|
|
26251c0865 | ||
|
|
ac4f317879 | ||
|
|
e3104b7043 | ||
|
|
176b4282fc | ||
|
|
cd8f06d03a | ||
|
|
9cff3591dd | ||
|
|
daade36e19 | ||
|
|
addc890628 | ||
|
|
8a3dd74d5c | ||
|
|
c0aa42759c | ||
|
|
b637c6aac6 | ||
|
|
5cd436e848 | ||
|
|
d5225b7784 | ||
|
|
904faa5485 | ||
|
|
42a151a84d | ||
|
|
f1084b6d93 | ||
|
|
9a462d3ca8 | ||
|
|
7cfead440b | ||
|
|
4f7817a0ca | ||
|
|
5084b4be39 | ||
|
|
a05c4290f5 | ||
|
|
85af83859e | ||
|
|
49cd478622 | ||
|
|
0443c708dd | ||
|
|
7f105f1dcb | ||
|
|
721b9b004e | ||
|
|
23d5a5771a | ||
|
|
0701f43d6b | ||
|
|
d5ae464f6d | ||
|
|
701c854ced | ||
|
|
afd432444b | ||
|
|
26b3b91433 | ||
|
|
8945809c1f | ||
|
|
da07772b1c | ||
|
|
1e76f6af69 | ||
|
|
a14e9ed97e | ||
|
|
615e9267d8 | ||
|
|
4f2b911802 | ||
|
|
c43f550a7e | ||
|
|
2439eb6e8d | ||
|
|
903dd82ebf | ||
|
|
cb449bf7ce | ||
|
|
e2e5bc352d | ||
|
|
687b966c5e | ||
|
|
0b8a333e2b | ||
|
|
b34bb01240 | ||
|
|
1e2f6dcb91 | ||
|
|
210b299bd4 | ||
|
|
6de98cfcd4 | ||
|
|
d43c4c0cba | ||
|
|
1d14877bec | ||
|
|
5aa1cc6117 | ||
|
|
1be0e3680b | ||
|
|
09b0a12b0a | ||
|
|
05e462b680 | ||
|
|
a2e362caea | ||
|
|
49ee5b7efb | ||
|
|
a1ca69d9ee | ||
|
|
424d4de9ac | ||
|
|
0e1a7e136a | ||
|
|
2386494030 | ||
|
|
1b803d792f | ||
|
|
67675d8980 | ||
|
|
9c4aded403 | ||
|
|
92e1c4aa0b | ||
|
|
f53fb8e952 | ||
|
|
0ad4492ff6 | ||
|
|
33efd36278 | ||
|
|
37e69cb83d | ||
|
|
5c5c33c116 | ||
|
|
13a3e0a0ea | ||
|
|
ccb50c6021 | ||
|
|
cee61eeb75 | ||
|
|
563e8f9f64 | ||
|
|
df3e0359b9 | ||
|
|
460cc25ef5 | ||
|
|
596dd7dd40 | ||
|
|
4883fde642 | ||
|
|
b2338179d6 | ||
|
|
683d083fab | ||
|
|
f75a569075 | ||
|
|
b97eaa9e12 | ||
|
|
3cadaecf96 | ||
|
|
4bc1a16d36 | ||
|
|
bc1f1c26db | ||
|
|
d2d35263a4 | ||
|
|
ba1b6c3232 | ||
|
|
3c020cad84 | ||
|
|
fc865fe8cd | ||
|
|
140f6f24e8 | ||
|
|
c7895d937f | ||
|
|
9f43c906db | ||
|
|
31dbb5e7c6 | ||
|
|
7d8e755fc7 | ||
|
|
103fb0e0e9 | ||
|
|
b220d73f2c | ||
|
|
efda5a5f44 | ||
|
|
41d5630eec | ||
|
|
cea20b6f31 | ||
|
|
c45763d47c | ||
|
|
06dcbcc1b1 | ||
|
|
d7a612302e | ||
|
|
9812d86a24 | ||
|
|
d747588323 | ||
|
|
ed5865b350 | ||
|
|
363158a93d | ||
|
|
7658a96c1c | ||
|
|
c332738f7a | ||
|
|
2542b21bfc | ||
|
|
ef8413ae58 | ||
|
|
7969d84257 | ||
|
|
2e9de9455b | ||
|
|
3d8f63dbb6 | ||
|
|
08ec8e541b | ||
|
|
08afb2d90a | ||
|
|
d7e5ad5bc7 | ||
|
|
7830ccb88c | ||
|
|
8075307e09 | ||
|
|
fb18da239f | ||
|
|
bc82328353 | ||
|
|
938223db28 | ||
|
|
942c966bf2 | ||
|
|
e0d59345c7 | ||
|
|
f514e25208 | ||
|
|
28fceb67de | ||
|
|
130b286d0d | ||
|
|
b88c3a120b | ||
|
|
a6f5077609 | ||
|
|
e2b708d442 | ||
|
|
2cb29e91c6 | ||
|
|
55cc2d8e72 | ||
|
|
3852b28194 | ||
|
|
852349bbe0 | ||
|
|
b408d54dfb | ||
|
|
0e7fb4f6b2 | ||
|
|
5d9fe034ea | ||
|
|
4a7df4de4b | ||
|
|
1d7c381ce2 | ||
|
|
8d6a19f55b | ||
|
|
6c8e5ee4dc | ||
|
|
d37d9b7168 | ||
|
|
fab41b6fcb | ||
|
|
ee7ce2d988 | ||
|
|
1a1accceca | ||
|
|
0bdf79cc51 | ||
|
|
507cc5a13b | ||
|
|
91c43385dd | ||
|
|
58e64ebfc9 | ||
|
|
36f9e59304 | ||
|
|
420a1b52c1 | ||
|
|
345da23ebe | ||
|
|
3f887b2ecf | ||
|
|
d5482f3453 | ||
|
|
fdbd1667ad | ||
|
|
421ac0af79 | ||
|
|
163dbf9495 | ||
|
|
2f221b9a1e | ||
|
|
1448cd597a | ||
|
|
68e3a79e47 | ||
|
|
19ef4738b7 | ||
|
|
16f025cbbe | ||
|
|
25cdfc991b | ||
|
|
5c2082f58e | ||
|
|
23539a02a5 | ||
|
|
f37abc941e | ||
|
|
8468e69b9f | ||
|
|
8fe95d7d52 | ||
|
|
19167b8468 | ||
|
|
d5ee41fe5d | ||
|
|
87e8a3f1af | ||
|
|
2a5c3a351e | ||
|
|
2550b5a668 | ||
|
|
24d5679f4a | ||
|
|
a3d2b56dd9 | ||
|
|
18ad06e3d7 | ||
|
|
34d3e082ec | ||
|
|
a277ca7ee4 | ||
|
|
af8e808e39 | ||
|
|
8f445d344f | ||
|
|
e9b946feb4 | ||
|
|
2d51c0a60a | ||
|
|
cf13976db3 | ||
|
|
6344cc8914 | ||
|
|
b2657eb0c2 | ||
|
|
35d263e15b | ||
|
|
c224055ff7 | ||
|
|
096a833838 | ||
|
|
ee8d7a6e89 | ||
|
|
538385a991 | ||
|
|
b8348a45bc | ||
|
|
a6b516be15 | ||
|
|
9ac8af6639 | ||
|
|
28bdccd322 | ||
|
|
8865130c35 | ||
|
|
153ca3341e | ||
|
|
8533189561 | ||
|
|
eabbdc612c | ||
|
|
5841fb9afa | ||
|
|
077cc67b79 | ||
|
|
589bdf1cd9 | ||
|
|
3524ec73b7 | ||
|
|
ab514f39af | ||
|
|
8be982fdb6 | ||
|
|
ae2543de90 | ||
|
|
6a5d249e67 | ||
|
|
4b44b5b4e3 | ||
|
|
2fd1c49ef5 | ||
|
|
22ad5a44db | ||
|
|
e77b3172ed | ||
|
|
a721349cff | ||
|
|
40cc42a941 | ||
|
|
cec92dbcb6 | ||
|
|
2c4d3e7768 | ||
|
|
e09aebebe7 | ||
|
|
a5d9f02184 | ||
|
|
d2dd109a05 | ||
|
|
01cbcd99cb | ||
|
|
a9e82658fd | ||
|
|
5bee1b0cce | ||
|
|
a11abc0511 | ||
|
|
c36b6b286d | ||
|
|
18fe7fd797 | ||
|
|
d6d4bc2c14 | ||
|
|
c519997b33 | ||
|
|
4d60c93beb | ||
|
|
b44dbb16b5 | ||
|
|
8b1e81f32a | ||
|
|
9e34f80a2c | ||
|
|
c1c71ea21d | ||
|
|
c8383babcc | ||
|
|
bdbf0ab789 | ||
|
|
ca76416e1c | ||
|
|
b534a42685 | ||
|
|
6b71e622c7 | ||
|
|
48c294fc24 | ||
|
|
f0fe7f41f1 | ||
|
|
2844930a21 | ||
|
|
d36c55d048 | ||
|
|
f855dc32f1 | ||
|
|
08e2b49e88 | ||
|
|
9cd978a7a9 | ||
|
|
a60880ef80 | ||
|
|
a4b5b110ec | ||
|
|
b9eb0f2747 | ||
|
|
897020b3fd | ||
|
|
e85fdb3b9b | ||
|
|
e3e72617a1 | ||
|
|
bc365650ce | ||
|
|
6fa78556f4 | ||
|
|
5fdeff6a82 | ||
|
|
3573906eef | ||
|
|
e36df05a4f | ||
|
|
673ba52cbd | ||
|
|
0ea8872471 | ||
|
|
40273bdba1 | ||
|
|
e8006f3446 | ||
|
|
373f08ca3e | ||
|
|
844d6c7ec8 | ||
|
|
8d5e94e121 | ||
|
|
b43c2ec617 | ||
|
|
a8c68aed97 | ||
|
|
4c09de6de0 | ||
|
|
29d6392514 | ||
|
|
b9f6961931 | ||
|
|
949faf09d9 | ||
|
|
5beef0916b | ||
|
|
89397bd566 | ||
|
|
288a007202 | ||
|
|
50b912db98 | ||
|
|
71dc521baa | ||
|
|
06a45738cc | ||
|
|
5795634b9c | ||
|
|
cec197e841 | ||
|
|
58c31075b0 | ||
|
|
167a4a5d81 | ||
|
|
06c01208d3 | ||
|
|
86649345cd | ||
|
|
2e2dbfb578 | ||
|
|
10a3992a62 | ||
|
|
ef4b60d384 | ||
|
|
32faea2b95 | ||
|
|
8a94af6a1c | ||
|
|
315a5642da | ||
|
|
00c990eded | ||
|
|
b6b7133e76 | ||
|
|
b0e6e8f24f | ||
|
|
4dbbcbeb58 | ||
|
|
8c8109e8cd | ||
|
|
b523b1e076 | ||
|
|
07e6fdc1e0 | ||
|
|
3242105ef8 | ||
|
|
7c6508af28 | ||
|
|
55ab679a81 | ||
|
|
946a3166b3 | ||
|
|
de3b8ff548 | ||
|
|
e6eaca9e3d | ||
|
|
dce96a4a3d | ||
|
|
fbb6669e23 | ||
|
|
08b4d780b7 | ||
|
|
bc5911bfba | ||
|
|
cf19cebc27 | ||
|
|
ada20c526a | ||
|
|
4c552a42f2 | ||
|
|
4c0cbbf554 | ||
|
|
e8e513fecb | ||
|
|
9d44606a4c | ||
|
|
4601a9c318 | ||
|
|
e326c14760 | ||
|
|
5c7d4ecf52 | ||
|
|
e13e03fd7f | ||
|
|
9edfd667b7 | ||
|
|
f3757e75e9 | ||
|
|
04a6f64a95 | ||
|
|
a6e7d503e6 | ||
|
|
da8b9be09d | ||
|
|
39e2f7730d | ||
|
|
9530924c21 | ||
|
|
083cae49c6 | ||
|
|
2ba192d411 | ||
|
|
6e8190062c | ||
|
|
bf8192ee84 | ||
|
|
9ee2391a69 | ||
|
|
45ec35172d | ||
|
|
926e4dce28 | ||
|
|
7f886a817c | ||
|
|
548e2c1f0b | ||
|
|
85872d7e71 | ||
|
|
d9037ba1da | ||
|
|
a83e0aa407 | ||
|
|
8d8650ebd0 | ||
|
|
865ca682dc | ||
|
|
dc9d0f3c9c | ||
|
|
12d06001e7 | ||
|
|
75331721f7 | ||
|
|
2623918359 | ||
|
|
265d21c35d | ||
|
|
5fea484089 | ||
|
|
322892e254 | ||
|
|
4e0025a847 | ||
|
|
38ff8ca5df | ||
|
|
9270b6647a | ||
|
|
e5effc4522 | ||
|
|
22e49d75e1 | ||
|
|
f8617ebbd6 | ||
|
|
bf1b8da629 | ||
|
|
86eaa624a3 | ||
|
|
c2fcb992ca | ||
|
|
54ba0d41c1 | ||
|
|
2c0abcb0e2 | ||
|
|
5554fb7219 | ||
|
|
804674e2b1 | ||
|
|
20534a731b | ||
|
|
242a89a622 | ||
|
|
04e2ed51a6 | ||
|
|
11fd86002b | ||
|
|
63c456a233 | ||
|
|
2ef2427419 | ||
|
|
5fcf1083d2 | ||
|
|
75c4905e9b | ||
|
|
336b7825c7 | ||
|
|
63046b4a00 | ||
|
|
5affafacbd | ||
|
|
8ca7f79c1e | ||
|
|
f72b2968f2 | ||
|
|
5c152c1842 | ||
|
|
0cf6021727 | ||
|
|
aa6ac4b5cc | ||
|
|
df2ba8ec7d | ||
|
|
10baed1ee1 | ||
|
|
ac46cf80aa | ||
|
|
704153d7e1 | ||
|
|
e6919bc247 | ||
|
|
b74bc59164 | ||
|
|
d7a6c29552 | ||
|
|
9e1189747d | ||
|
|
4085ae5806 |
No files matched your search
@@ -0,0 +1,32 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# Top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches all C source files
|
||||
[*.c]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Matches all header files
|
||||
[*.h]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Matches Makefiles
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Matches Markdown files
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
+276
-14
@@ -2,7 +2,7 @@ name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "port" ]
|
||||
branches: [ "port", "port-debugger" ]
|
||||
pull_request:
|
||||
branches: [ "port" ]
|
||||
workflow_dispatch:
|
||||
@@ -25,44 +25,306 @@ jobs:
|
||||
mingw-w64-i686-toolchain
|
||||
mingw-w64-i686-SDL2
|
||||
mingw-w64-i686-zlib
|
||||
mingw-w64-i686-cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Build pd.exe
|
||||
run: make -f Makefile.port -j
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.i686.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/ntsc-final-port/pd.exe bin/
|
||||
cp build/pd.i686.exe bin/
|
||||
cp build_pal/pd.pal.i686.exe bin/
|
||||
cp build_jpn/pd.jpn.i686.exe bin/
|
||||
cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-i686-windows
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-i686-linux:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386
|
||||
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386 cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Build pd.exe
|
||||
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 . && cmake --build build -j
|
||||
- name: Build pd.pal.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.i686
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/ntsc-final-port/pd.exe bin/pd
|
||||
cp build/pd.i686 bin/
|
||||
cp build_pal/pd.pal.i686 bin/
|
||||
cp build_jpn/pd.jpn.i686 bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-i686-linux
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
|
||||
build-x86_64-windows:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
mingw-w64-x86_64-toolchain
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-zlib
|
||||
mingw-w64-x86_64-cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.x86_64.exe
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64.exe bin/
|
||||
cp build_pal/pd.pal.x86_64.exe bin/
|
||||
cp build_jpn/pd.jpn.x86_64.exe bin/
|
||||
cp /mingw64/bin/{SDL2.dll,zlib1.dll,libwinpthread-1.dll,libgcc_s_seh-1.dll} bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-windows
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-x86_64-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture amd64
|
||||
sudo apt-get update
|
||||
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-2.0-0 cmake
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
|
||||
- name: Build pd.pal.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
|
||||
- name: Build pd.jpn.x86_64
|
||||
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64 bin/
|
||||
cp build_pal/pd.pal.x86_64 bin/
|
||||
cp build_jpn/pd.jpn.x86_64 bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-linux
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-x86_64-osx:
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install zlib
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .
|
||||
cmake --build build --target pd -j4 --clean-first
|
||||
- name: Build pd.pal.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=pal-final .
|
||||
cmake --build build_pal --target pd -j4 --clean-first
|
||||
- name: Build pd.jpn.x86_64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=jpn-final .
|
||||
cmake --build build_jpn --target pd -j4 --clean-first
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.x86_64 bin/
|
||||
cp build_pal/pd.pal.x86_64 bin/
|
||||
cp build_jpn/pd.jpn.x86_64 bin/
|
||||
cp -vr /Library/Frameworks/SDL2.framework bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-osx
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-arm64-osx:
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install zlib
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=arm64 .
|
||||
cmake --build build --target pd -j4 --clean-first
|
||||
- name: Build pd.pal.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=pal-final .
|
||||
cmake --build build_pal --target pd -j4 --clean-first
|
||||
- name: Build pd.jpn.arm64
|
||||
run: |
|
||||
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=jpn-final .
|
||||
cmake --build build_jpn --target pd -j4 --clean-first
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/data
|
||||
cp build/pd.arm64 bin/
|
||||
cp build_pal/pd.pal.arm64 bin/
|
||||
cp build_jpn/pd.jpn.arm64 bin/
|
||||
cp -vr /Library/Frameworks/SDL2.framework bin/
|
||||
touch bin/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-arm64-osx
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-arm64-nswitch:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/port'
|
||||
steps:
|
||||
- name: Install host dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install git make cmake curl
|
||||
- name: Install devkitA64 docker image
|
||||
run: sudo docker pull devkitpro/devkita64:latest
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build pd.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build
|
||||
- name: Build pd.pal.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_pal -DROMID=pal-final
|
||||
- name: Build pd.jpn.arm64.nro
|
||||
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_jpn -DROMID=jpn-final
|
||||
- name: Prepare artifact for packaging
|
||||
run: |
|
||||
mkdir -p bin/perfectdark/data
|
||||
mkdir -p bin/perfectdark_pal/data
|
||||
mkdir -p bin/perfectdark_jpn/data
|
||||
cp build/pd.arm64.nro bin/perfectdark/
|
||||
cp build_pal/pd.pal.arm64.nro bin/perfectdark_pal/
|
||||
cp build_jpn/pd.jpn.arm64.nro bin/perfectdark_jpn/
|
||||
touch bin/perfectdark/data/put_your_rom_here.txt
|
||||
touch bin/perfectdark_pal/data/put_your_rom_here.txt
|
||||
touch bin/perfectdark_jpn/data/put_your_rom_here.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pd-arm64-nswitch
|
||||
path: bin/
|
||||
retention-days: 0
|
||||
|
||||
build-flatpak-bundle:
|
||||
name: "Build flatpak bundle"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-x86_64-linux]
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
|
||||
options: --privileged
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pd-x86_64-linux
|
||||
path: dist/linux/bin/
|
||||
|
||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
with:
|
||||
bundle: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
manifest-path: dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml
|
||||
cache-key: flatpak-builder-${{ github.sha }}
|
||||
upload-artifact: false
|
||||
|
||||
# - name: Build Flatpak bundle
|
||||
# run: |
|
||||
# cd dist/linux/
|
||||
# flatpak-builder build --force-clean io.github.fgsfdsfgs.perfect_dark.yaml
|
||||
# flatpak build-export export build
|
||||
# flatpak build-bundle export io.github.fgsfdsfgs.perfect_dark.flatpak io.github.fgsfdsfgs.perfect_dark
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
path: io.github.fgsfdsfgs.perfect_dark.flatpak
|
||||
retention-days: 0
|
||||
|
||||
|
||||
publish-latest-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/port'
|
||||
needs: [build-i686-windows, build-i686-linux, build-x86_64-windows, build-x86_64-linux, build-arm64-nswitch, build-x86_64-osx, build-arm64-osx, build-flatpak-bundle]
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ci-artifacts
|
||||
- name: Publish latest dev-build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
mkdir ci-release
|
||||
pushd ci-artifacts
|
||||
tar czf ../ci-release/pd-i686-linux.tar.gz pd-i686-linux
|
||||
tar czf ../ci-release/pd-x86_64-linux.tar.gz pd-x86_64-linux
|
||||
tar cJf ../ci-release/pd-x86_64-osx.tar.xz pd-x86_64-osx
|
||||
tar cJf ../ci-release/pd-arm64-osx.tar.xz pd-arm64-osx
|
||||
zip -r ../ci-release/pd-i686-windows.zip pd-i686-windows
|
||||
zip -r ../ci-release/pd-x86_64-windows.zip pd-x86_64-windows
|
||||
zip -r ../ci-release/pd-arm64-nswitch.zip pd-arm64-nswitch
|
||||
mv io.github.fgsfdsfgs.perfect_dark.flatpak/io.github.fgsfdsfgs.perfect_dark.flatpak ../ci-release/
|
||||
popd
|
||||
git tag --force ci-dev-build port
|
||||
git push --force origin ci-dev-build
|
||||
gh release upload --clobber ci-dev-build ci-release/*
|
||||
@@ -4,6 +4,7 @@
|
||||
*.exe
|
||||
pd.*.z64
|
||||
build
|
||||
.flatpak-builder
|
||||
extracted
|
||||
src/assets/*/*.bin
|
||||
src/assets/*/*.ctl
|
||||
@@ -22,3 +23,6 @@ src/assets/*/textures/*.bin
|
||||
src/generated
|
||||
tools/mkrom/mkrom
|
||||
/.vs
|
||||
CppProperties.json
|
||||
.idea
|
||||
cmake-build-debug
|
||||
+359
@@ -0,0 +1,359 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
if(APPLE)
|
||||
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
# ARM Macs start at OS 11.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
|
||||
else()
|
||||
# SDL2 requires at least this version for everything to work properly.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(pd C CXX)
|
||||
|
||||
include(TargetArch)
|
||||
include(FindPkgConfig)
|
||||
include(AssetUtils)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# On first build set the build type to RelWithDebInfo if it's not already set
|
||||
if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt)
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Options
|
||||
|
||||
set(ROMID "ntsc-final" CACHE STRING "Which ROM to build an executable for: ntsc-final, pal-final or jpn-final")
|
||||
option(FORCE_CROSSCOMPILE "Force cross compiling" NO)
|
||||
|
||||
# Determine target arch
|
||||
|
||||
target_architecture(TARGET_ARCH)
|
||||
if(TARGET_ARCH STREQUAL "i386")
|
||||
# for historical reasons
|
||||
set(TARGET_ARCH "i686")
|
||||
endif()
|
||||
|
||||
# TODO
|
||||
set(TARGET_IS_BIG_ENDIAN FALSE)
|
||||
|
||||
if((TARGET_ARCH MATCHES "unknown") OR (TARGET_ARCH STREQUAL ""))
|
||||
message(FATAL_ERROR "Unknown target arch")
|
||||
elseif(TARGET_ARCH MATCHES "64")
|
||||
set(TARGET_IS_64BIT TRUE)
|
||||
else()
|
||||
set(TARGET_IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
message(STATUS "Target arch: ${TARGET_ARCH}")
|
||||
|
||||
# Determine target OS and platform identifier ($arch-$os)
|
||||
|
||||
if(WIN32)
|
||||
# Windows
|
||||
set(TARGET_OS "windows")
|
||||
elseif(APPLE)
|
||||
# OSX
|
||||
set(TARGET_OS "osx")
|
||||
elseif(NINTENDO_SWITCH)
|
||||
# Switch
|
||||
set(TARGET_OS "nswitch")
|
||||
elseif(UNIX)
|
||||
# Generic *nix; assume Linux
|
||||
set(TARGET_OS "linux")
|
||||
else()
|
||||
# ???
|
||||
message(FATAL_ERROR "Unknown target OS or compiler")
|
||||
endif()
|
||||
|
||||
set(TARGET_PLATFORM "${TARGET_ARCH}-${TARGET_OS}")
|
||||
|
||||
message(STATUS "Target platform: ${TARGET_PLATFORM}")
|
||||
|
||||
# Calculate version info and binary name
|
||||
|
||||
set(VERSION_IS_PAL 0)
|
||||
|
||||
if(ROMID STREQUAL "ntsc-final")
|
||||
set(VERSION 2)
|
||||
set(BIN_REGION "")
|
||||
elseif(ROMID STREQUAL "pal-final")
|
||||
set(VERSION 4)
|
||||
set(BIN_REGION ".pal")
|
||||
set(VERSION_IS_PAL 1)
|
||||
elseif(ROMID STREQUAL "jpn-final")
|
||||
set(VERSION 5)
|
||||
set(BIN_REGION ".jpn")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown ROM ID: ${ROMID}")
|
||||
endif()
|
||||
|
||||
# git commit hash
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VERSION_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# git branch name
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VERSION_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
set(VERSION_TARGET "${TARGET_PLATFORM}")
|
||||
set(VERSION_ARCH "${TARGET_ARCH}")
|
||||
set(VERSION_ROMID "${ROMID}")
|
||||
set(VERSION_BUILD "${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if((VERSION_BRANCH STREQUAL "") OR (VERSION_BRANCH STREQUAL "HEAD"))
|
||||
set(VERSION_BRANCH "port-custom")
|
||||
endif()
|
||||
|
||||
message(STATUS "Version: ${VERSION_ROMID}, hash ${VERSION_HASH}, branch ${VERSION_BRANCH}")
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/port/include/versioninfo.h.in" "${CMAKE_BINARY_DIR}/port/include/versioninfo.h" @ONLY)
|
||||
|
||||
set(ASSET_DIR "src/assets/${ROMID}")
|
||||
set(GENERATED_DIR "src/generated/${ROMID}")
|
||||
|
||||
set(ENV{ROMID} ${ROMID})
|
||||
|
||||
# Build folder postfix
|
||||
|
||||
set(BUILD_ID "${VERSION_ROMID}-${VERSION_TARGET}")
|
||||
|
||||
# Compiler defs
|
||||
|
||||
add_definitions(
|
||||
-DMATCHING=0
|
||||
-DPIRACYCHECKS=0
|
||||
-DROM_SIZE=32
|
||||
-DAVOID_UB=1
|
||||
-D_LANGUAGE_C=1
|
||||
-DPAL=${VERSION_IS_PAL}
|
||||
-DVERSION=${VERSION}
|
||||
)
|
||||
|
||||
if(TARGET_IS_64BIT)
|
||||
add_definitions(-DPLATFORM_64BIT=1)
|
||||
endif()
|
||||
|
||||
# Compiler flags
|
||||
|
||||
# Include directories
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include/PR")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src/include")
|
||||
include_directories("${CMAKE_BINARY_DIR}/src/generated/${ROMID}")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src/lib/ultra/audio")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/port/include")
|
||||
include_directories("${CMAKE_BINARY_DIR}/port/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/port/src/imgui")
|
||||
|
||||
# Set Release optimization to -Og until I fix the -O2 issues
|
||||
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
add_compile_options(-Og)
|
||||
endif()
|
||||
|
||||
# Common CFLAGS
|
||||
add_compile_options(
|
||||
-fno-inline-functions
|
||||
-fno-strict-aliasing
|
||||
-funsigned-char
|
||||
-fwrapv
|
||||
-include "versioninfo.h"
|
||||
)
|
||||
|
||||
# Common warning flags
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-address
|
||||
-Wno-int-in-bool-context
|
||||
-Wno-misleading-indentation
|
||||
-Wno-missing-braces
|
||||
-Wno-multichar
|
||||
-Wno-tautological-compare
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-unused-value
|
||||
-Wno-unused-variable
|
||||
)
|
||||
|
||||
# C specific flags
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-pointer-sign>)
|
||||
|
||||
# C++ specific flags
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-unused-function>)
|
||||
|
||||
# Platform-specific flags
|
||||
if (APPLE)
|
||||
# Make it look for libs in the executable folder manually since CMake's rpath system is wack
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rpath @executable_path")
|
||||
else()
|
||||
# This warning is not recognized by XCode/Clang for some reason.
|
||||
add_compile_options(-Wno-format-truncation)
|
||||
endif()
|
||||
|
||||
# Dependencies
|
||||
|
||||
set(LIBS )
|
||||
|
||||
# SDL2
|
||||
find_package(SDL2 REQUIRED)
|
||||
if(NINTENDO_SWITCH)
|
||||
if(NOT SDL2_LIBRARY OR NOT SDL2_INCLUDE_DIR)
|
||||
# sometimes FindSDL2 just wants us to suffer and does not set these
|
||||
set(SDL2_LIBRARY "SDL2")
|
||||
set(SDL2_INCLUDE_DIR "${DEVKITPRO}/portlibs/switch/include/SDL2")
|
||||
endif()
|
||||
endif()
|
||||
include_directories(SYSTEM "${SDL2_INCLUDE_DIR}")
|
||||
list(APPEND LIBS "${SDL2_LIBRARY}")
|
||||
|
||||
# ZLib
|
||||
find_package(ZLIB REQUIRED)
|
||||
if(ZLIB_INCLUDE_DIR)
|
||||
include_directories(SYSTEM "${ZLIB_INCLUDE_DIR}")
|
||||
endif()
|
||||
list(APPEND LIBS "${ZLIB_LIBRARY}")
|
||||
|
||||
# GL
|
||||
if(NOT GL_LIBRARY)
|
||||
if(WIN32)
|
||||
set(GL_LIBRARY opengl32)
|
||||
elseif(NINTENDO_SWITCH)
|
||||
set(GL_LIBRARY EGL glapi drm_nouveau)
|
||||
elseif(APPLE)
|
||||
set(GL_LIBRARY "-framework OpenGL")
|
||||
else()
|
||||
set(GL_LIBRARY GL)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND LIBS "${GL_LIBRARY}")
|
||||
|
||||
# Platform-specific extra libs
|
||||
if(NOT EXTRA_LIBRARIES)
|
||||
if(WIN32)
|
||||
set(EXTRA_LIBRARIES dbghelp -static-libstdc++)
|
||||
elseif(NINTENDO_SWITCH)
|
||||
set(EXTRA_LIBRARIES stdc++ pthread)
|
||||
else()
|
||||
set(EXTRA_LIBRARIES stdc++ m dl)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND LIBS "${EXTRA_LIBRARIES}")
|
||||
|
||||
# Sources
|
||||
|
||||
file(GLOB_RECURSE SRC_PORT "${CMAKE_SOURCE_DIR}/port/*.c")
|
||||
file(GLOB_RECURSE SRC_PORT_CXX "${CMAKE_SOURCE_DIR}/port/*.cpp")
|
||||
|
||||
file(GLOB_RECURSE SRC_GAME "${CMAKE_SOURCE_DIR}/src/game/*.c")
|
||||
|
||||
file(GLOB SRC_LIB_MP3 "${CMAKE_SOURCE_DIR}/src/lib/mp3/*.c")
|
||||
file(GLOB SRC_LIB_NAUDIO "${CMAKE_SOURCE_DIR}/src/lib/naudio/*.c")
|
||||
file(GLOB SRC_LIB_ULTRA_AUDIO "${CMAKE_SOURCE_DIR}/src/lib/ultra/audio/*.c")
|
||||
file(GLOB SRC_LIB_GU "${CMAKE_SOURCE_DIR}/src/lib/ultra/gu/*.c")
|
||||
set(SRC_LIB
|
||||
src/lib/ultra/io/vimodentsclan1.c
|
||||
src/lib/ultra/io/vimodepallan1.c
|
||||
src/lib/ultra/io/vimodempallan1.c
|
||||
src/lib/ultra/io/vitbl.c
|
||||
src/lib/ailist.c
|
||||
src/lib/anim.c
|
||||
src/lib/args.c
|
||||
src/lib/audiodma.c
|
||||
src/lib/audiomgr.c
|
||||
src/lib/base.c
|
||||
src/lib/collision.c
|
||||
src/lib/debughud.c
|
||||
src/lib/dma.c
|
||||
src/lib/fault.c
|
||||
src/lib/joy.c
|
||||
src/lib/lib_2f490_c.c
|
||||
src/lib/lib_2fc60.c
|
||||
src/lib/lib_3e3e0.c
|
||||
src/lib/lib_04f60nb.c
|
||||
src/lib/lib_17ce0.c
|
||||
src/lib/lib_034d0.c
|
||||
src/lib/lib_39c80.c
|
||||
src/lib/lib_15850.c
|
||||
src/lib/mema.c
|
||||
src/lib/memp.c
|
||||
src/lib/model.c
|
||||
src/lib/modelasm_c.c
|
||||
src/lib/mp3.c
|
||||
src/lib/mtx_c.c
|
||||
src/lib/mtx.c
|
||||
src/lib/music.c
|
||||
src/lib/path.c
|
||||
src/lib/profile.c
|
||||
src/lib/rdp.c
|
||||
src/lib/rmon.c
|
||||
src/lib/rng_c.c
|
||||
src/lib/rzip_c.c
|
||||
src/lib/snd.c
|
||||
src/lib/speaker.c
|
||||
src/lib/varsinit.c
|
||||
src/lib/vi.c
|
||||
src/textureconfig.c
|
||||
)
|
||||
list(PREPEND SRC_LIB "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
set(SRC
|
||||
${SRC_GAME}
|
||||
${SRC_PORT}
|
||||
${SRC_PORT_CXX}
|
||||
${SRC_LIB_MP3}
|
||||
${SRC_LIB_NAUDIO}
|
||||
${SRC_LIB_ULTRA_AUDIO}
|
||||
${SRC_LIB_GU}
|
||||
${SRC_LIB}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SRC "${CMAKE_SOURCE_DIR}/dist/windows/icon.rc")
|
||||
endif()
|
||||
|
||||
# Asset files
|
||||
|
||||
generate_asset_headers("lang/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mklang" "en" JSON_HEADERS)
|
||||
generate_asset_headers("pads/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkpads" "" JSON_HEADERS)
|
||||
generate_asset_headers("tiles/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktiles" "" JSON_HEADERS)
|
||||
generate_asset_headers("animations.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkanims" "" JSON_HEADERS)
|
||||
generate_asset_headers("sequences.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mksequences" "" JSON_HEADERS)
|
||||
generate_asset_headers("textures.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktextures" "" JSON_HEADERS)
|
||||
|
||||
add_custom_target(pd_headers ALL DEPENDS ${JSON_HEADERS})
|
||||
|
||||
# Game target
|
||||
|
||||
set(BIN_NAME "pd${BIN_REGION}.${TARGET_ARCH}")
|
||||
add_executable(pd ${SRC})
|
||||
add_dependencies(pd pd_headers)
|
||||
target_link_libraries(pd ${LIBS})
|
||||
set_target_properties(pd PROPERTIES OUTPUT_NAME "${BIN_NAME}")
|
||||
if(WIN32)
|
||||
set_target_properties(pd PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||
endif()
|
||||
|
||||
# Additional commands for specific platforms.
|
||||
|
||||
if(NINTENDO_SWITCH)
|
||||
add_custom_command(TARGET pd POST_BUILD
|
||||
COMMAND nacptool --create "Perfect Dark" "fgsfds and contributors" "${VERSION_ROMID}/${VERSION_BRANCH}/${VERSION_HASH}" "${BIN_NAME}.nacp"
|
||||
COMMAND aarch64-none-elf-strip -o ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.elf
|
||||
COMMAND elf2nro ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/dist/nswitch/icon.jpg --nacp=${BIN_NAME}.nacp
|
||||
)
|
||||
endif()
|
||||
@@ -1,812 +0,0 @@
|
||||
################################################################################
|
||||
# Options
|
||||
|
||||
# ROMID - The ROM version to build.
|
||||
#
|
||||
# Can be set in your environment using
|
||||
# $ export ROMID=...
|
||||
#
|
||||
# Supported values:
|
||||
# * ntsc-beta
|
||||
# * ntsc-1.0
|
||||
# * ntsc-final
|
||||
# * pal-beta
|
||||
# * pal-final
|
||||
# * jpn-final
|
||||
|
||||
ROMID ?= ntsc-final
|
||||
|
||||
# MATCHING - Whether to build a matching ROM (1) or a custom one (0).
|
||||
#
|
||||
# Build a matching ROM to prove that the decompilation is accurate.
|
||||
#
|
||||
# If enabled, all further options are ignored and are set automatically.
|
||||
|
||||
MATCHING = 1
|
||||
|
||||
# COMPILER - Choose which compiler to use.
|
||||
#
|
||||
# A matching build uses ido. For non-matching builds, use gcc for performance.
|
||||
#
|
||||
# gcc is currently only supported when ROMID is ntsc-1.0 or ntsc-final.
|
||||
#
|
||||
# Supported values: ido, gcc
|
||||
|
||||
COMPILER = gcc
|
||||
|
||||
# GCC_OPT_LVL - the optimisation level if building with gcc.
|
||||
#
|
||||
# Supported values: -O0, -O1, -O2, -Os
|
||||
|
||||
GCC_OPT_LVL = -Os
|
||||
|
||||
# PAL - Whether to use the PAL television standard (1) or NTSC (0).
|
||||
#
|
||||
# PAL runs at 50Hz while NTSC is 60Hz, and PAL uses different screen dimensions.
|
||||
|
||||
PAL = 0
|
||||
|
||||
# ROMALLOCATION
|
||||
#
|
||||
# The lib, data and game segments are compressed in the final ROM.
|
||||
#
|
||||
# These options define how much space is allocated for the compressed segments.
|
||||
#
|
||||
# If any value is not big enough, the build system will tell you which one needs
|
||||
# to be changed and what to change it to.
|
||||
|
||||
ROMALLOCATION_DATA = 0x015000
|
||||
ROMALLOCATION_LIB = 0x038800
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
|
||||
# ROM_SIZE - The desired ROM size in megabytes.
|
||||
#
|
||||
# All versions of the retail ROM are 32MB.
|
||||
#
|
||||
# If this is too low you might get this error from ld:
|
||||
# "final link failed: memory exhausted"
|
||||
|
||||
ROM_SIZE := 32
|
||||
|
||||
# DEBUG - Enable (1) or disable (0) the debug menu and crash screen.
|
||||
#
|
||||
# When enabled, press C-up and C-down simultaneously to toggle the debug menu.
|
||||
# Note that some emulators have problems displaying the crash screen text.
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
################################################################################
|
||||
|
||||
# The VERSION constant is used in the source to handle version-specific code.
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
VERSION = 0
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-1.0)
|
||||
VERSION = 1
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-final)
|
||||
VERSION = 2
|
||||
endif
|
||||
ifeq ($(ROMID), pal-beta)
|
||||
VERSION = 3
|
||||
endif
|
||||
ifeq ($(ROMID), pal-final)
|
||||
VERSION = 4
|
||||
endif
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
VERSION = 5
|
||||
endif
|
||||
|
||||
# Set runtime piracy checks off. We turn this on for matching builds if needed.
|
||||
PIRACYCHECKS = 0
|
||||
|
||||
# A magic value that's only used to produce a matching ROM.
|
||||
# It's required because old-school zlib was influenced by uninitialised data.
|
||||
# ZIPMAGIC is the value of the uninitialised data. We set it per version for
|
||||
# matching builds, otherwise 0 is fine.
|
||||
ZIPMAGIC = 0x0000
|
||||
|
||||
# This is also a value that's only used to produce a matching ROM.
|
||||
# The final ROM has some duplicate bytes, and there doesn't seem to be any logic
|
||||
# for determining how many bytes are duplicated.
|
||||
COPYLEN = 2
|
||||
|
||||
# If a matching build has been requested, override directives as needed.
|
||||
ifeq ($(MATCHING), 1)
|
||||
COMPILER = ido
|
||||
|
||||
ROMALLOCATION_DATA = 0x015000
|
||||
ROMALLOCATION_LIB = 0x038800
|
||||
|
||||
ROM_SIZE = 32
|
||||
DEBUG = 0
|
||||
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 0
|
||||
ROMALLOCATION_DATA = 0x012000
|
||||
ROMALLOCATION_LIB = 0x02f800
|
||||
ROMALLOCATION_GAME = 0x105000
|
||||
DEBUG = 1
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-1.0)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
ZIPMAGIC = 0xffff
|
||||
endif
|
||||
ifeq ($(ROMID), ntsc-final)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x144ee0
|
||||
ZIPMAGIC = 0xffff
|
||||
endif
|
||||
ifeq ($(ROMID), pal-beta)
|
||||
PAL = 1
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1306f0
|
||||
ZIPMAGIC = 0x0c00
|
||||
COPYLEN = 6
|
||||
DEBUG = 1
|
||||
endif
|
||||
ifeq ($(ROMID), pal-final)
|
||||
PAL = 1
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1306f0
|
||||
ZIPMAGIC = 0xaf00
|
||||
endif
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
PAL = 0
|
||||
PIRACYCHECKS = 1
|
||||
ROMALLOCATION_GAME = 0x1296f0
|
||||
ZIPMAGIC = 0x0002
|
||||
COPYLEN = 4
|
||||
endif
|
||||
endif
|
||||
|
||||
DEFINES := \
|
||||
VERSION=$(VERSION) \
|
||||
MATCHING=$(MATCHING) \
|
||||
PAL=$(PAL) \
|
||||
PIRACYCHECKS=$(PIRACYCHECKS) \
|
||||
ROM_SIZE=$(ROM_SIZE) \
|
||||
PLATFORM_N64=1
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFINES := $(DEFINES) DEBUG=1
|
||||
endif
|
||||
|
||||
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
|
||||
AS_DEFINES := $(foreach d,$(DEFINES),--defsym $(d)) --defsym _LANGUAGE_ASSEMBLY=1
|
||||
|
||||
A_DIR := src/assets/$(ROMID)
|
||||
B_DIR := build/$(ROMID)
|
||||
E_DIR := extracted/$(ROMID)
|
||||
|
||||
ifneq ($(strip $(MIPS_BINUTILS_PREFIX)),)
|
||||
TOOLCHAIN := $(MIPS_BINUTILS_PREFIX)
|
||||
else ifeq ($(shell type mips-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips-elf
|
||||
else ifeq ($(shell type mips-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips-linux-gnu
|
||||
else ifeq ($(shell type mips64-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips64-elf
|
||||
else ifeq ($(shell type mips64-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
|
||||
TOOLCHAIN := mips64-linux-gnu
|
||||
else
|
||||
$(error You need to install a suitable MIPS binutils toolchain (eg. mips-elf-ld))
|
||||
endif
|
||||
|
||||
# Asset files are files which are included in the "files" segment of the ROM.
|
||||
# This excludes animations, fonts, SFX, MIDI and textures.
|
||||
# And because setup files are part of the files segment they are included here,
|
||||
# despite them being written in C.
|
||||
#
|
||||
# Create names such as $(B_DIR)/assets/files/PfooZ.
|
||||
# These names (with .o added) will be dependenices for ld.
|
||||
ASSET_FILES := \
|
||||
$(patsubst $(A_DIR)/files/audio/%.mp3, $(B_DIR)/assets/files/A%M, $(shell find $(A_DIR) -path '*/files/audio/*.mp3')) \
|
||||
$(patsubst $(A_DIR)/files/chrs/%.bin, $(B_DIR)/assets/files/C%Z, $(shell find $(A_DIR) -path '*/files/chrs/*.bin')) \
|
||||
$(patsubst $(A_DIR)/files/guns/%.bin, $(B_DIR)/assets/files/G%Z, $(shell find $(A_DIR) -path '*/files/guns/*.bin')) \
|
||||
$(patsubst $(A_DIR)/files/props/%.bin, $(B_DIR)/assets/files/P%Z, $(shell find $(A_DIR) -path '*/files/props/*.bin')) \
|
||||
$(patsubst src/setups/%.c, $(B_DIR)/assets/files/U%Z, $(shell find src/setups -name '*.c')) \
|
||||
$(patsubst $(A_DIR)/files/bgdata/%.seg, $(B_DIR)/assets/files/bgdata/%.seg, $(shell find $(A_DIR) -path '*/files/bgdata/*.seg')) \
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg.o
|
||||
|
||||
LANG_JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
|
||||
PADS_JSON_FILES := $(shell find $(A_DIR) -path '*/pads/*.json')
|
||||
TILES_JSON_FILES := $(shell find $(A_DIR) -path '*/tiles/*.json')
|
||||
|
||||
LANG_O_FILES := \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%E.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%J.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%P.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_f.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_g.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_i.o, $(LANG_JSON_FILES)) \
|
||||
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_s.o, $(LANG_JSON_FILES))
|
||||
|
||||
PADS_O_FILES := $(patsubst $(A_DIR)/pads/%.json, $(B_DIR)/assets/files/bgdata/bg_%_padsZ.o, $(PADS_JSON_FILES))
|
||||
TILES_O_FILES := $(patsubst $(A_DIR)/tiles/%.json, $(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o, $(TILES_JSON_FILES))
|
||||
|
||||
C_FILES := $(shell find src/lib src/game src/inflate -name '*.c')
|
||||
S_FILES := $(shell find src/lib src/game src/preamble -name '*.s')
|
||||
|
||||
C_O_FILES := $(patsubst src/%.c, $(B_DIR)/%.o, $(C_FILES))
|
||||
S_O_FILES := $(patsubst src/%.s, $(B_DIR)/%.o, $(S_FILES))
|
||||
|
||||
O_FILES := \
|
||||
$(C_O_FILES) \
|
||||
$(S_O_FILES) \
|
||||
$(patsubst %, %.o, $(ASSET_FILES)) \
|
||||
$(LANG_O_FILES) \
|
||||
$(PADS_O_FILES) \
|
||||
$(TILES_O_FILES) \
|
||||
$(B_DIR)/assets/animations.o \
|
||||
$(B_DIR)/assets/copyrightZ.o \
|
||||
$(B_DIR)/assets/files/list.o \
|
||||
$(B_DIR)/assets/fonts/bankgothic.o \
|
||||
$(B_DIR)/assets/fonts/handelgothiclg.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicmd.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicsm.o \
|
||||
$(B_DIR)/assets/fonts/handelgothicxs.o \
|
||||
$(B_DIR)/assets/fonts/numeric.o \
|
||||
$(B_DIR)/assets/fonts/ocralg.o \
|
||||
$(B_DIR)/assets/fonts/ocramd.o \
|
||||
$(B_DIR)/assets/fonts/tahoma.o \
|
||||
$(B_DIR)/assets/fonts/zurich.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsE.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsF.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsG.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsI.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsJ.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsP.o \
|
||||
$(B_DIR)/assets/mpstrings/mpstringsS.o \
|
||||
$(B_DIR)/assets/seq.ctl.o \
|
||||
$(B_DIR)/assets/seq.tbl.o \
|
||||
$(B_DIR)/assets/sequences.o \
|
||||
$(B_DIR)/assets/sfx.ctl.o \
|
||||
$(B_DIR)/assets/sfx.tbl.o \
|
||||
$(B_DIR)/assets/textureslist.o \
|
||||
$(B_DIR)/bootloader.o \
|
||||
$(B_DIR)/firingrange.o \
|
||||
$(B_DIR)/getitle.o \
|
||||
$(B_DIR)/mpconfigs.o \
|
||||
$(B_DIR)/romheader.o \
|
||||
$(B_DIR)/rsp/asp.data.o \
|
||||
$(B_DIR)/rsp/asp.text.o \
|
||||
$(B_DIR)/rsp/gsp.data.o \
|
||||
$(B_DIR)/rsp/gsp.text.o \
|
||||
$(B_DIR)/rsp/rspboot.text.o \
|
||||
$(B_DIR)/textureconfig.o
|
||||
|
||||
# ntsc-beta doesn't have this segment
|
||||
ifneq ($(ROMID), ntsc-beta)
|
||||
O_FILES := $(O_FILES) $(B_DIR)/assets/accessingpakZ.o
|
||||
endif
|
||||
|
||||
ifeq ($(ROMID), jpn-final)
|
||||
O_FILES := $(O_FILES) $(B_DIR)/assets/fonts/jpn.o
|
||||
else
|
||||
O_FILES := $(O_FILES) \
|
||||
$(B_DIR)/assets/fonts/jpnsingle.o \
|
||||
$(B_DIR)/assets/fonts/jpnmulti.o
|
||||
endif
|
||||
|
||||
INCLUDES = \
|
||||
-I include \
|
||||
-I include/PR \
|
||||
-I src/include \
|
||||
-I src/include/lib/libc \
|
||||
-I src/generated/$(ROMID) \
|
||||
-I src/lib/ultra/audio \
|
||||
|
||||
AS := $(TOOLCHAIN)-as
|
||||
ASFLAGS = -march=vr4300 -mabi=32 $(INCLUDES) $(AS_DEFINES)
|
||||
|
||||
ifeq ($(COMPILER), ido)
|
||||
RECOMP_FILES := \
|
||||
build/recomp/5.3/as1 \
|
||||
build/recomp/5.3/cc \
|
||||
build/recomp/5.3/cfe \
|
||||
build/recomp/5.3/err.english.cc \
|
||||
build/recomp/5.3/ugen \
|
||||
build/recomp/5.3/ujoin \
|
||||
build/recomp/5.3/uld \
|
||||
build/recomp/5.3/umerge \
|
||||
build/recomp/5.3/uopt \
|
||||
build/recomp/5.3/usplit \
|
||||
build/recomp/7.1/as1 \
|
||||
build/recomp/7.1/cc \
|
||||
build/recomp/7.1/cfe \
|
||||
build/recomp/7.1/err.english.cc \
|
||||
build/recomp/7.1/ugen \
|
||||
build/recomp/7.1/uopt
|
||||
|
||||
LOOPUNROLL_C_FILES := \
|
||||
src/lib/ultra/gu/frustum.c \
|
||||
src/lib/ultra/gu/mtxutil.c \
|
||||
src/lib/ultra/gu/ortho.c \
|
||||
src/lib/ultra/io/conteepread.c \
|
||||
src/lib/ultra/io/conteepwrite.c \
|
||||
src/lib/ultra/io/contpfs.c \
|
||||
src/lib/ultra/io/contramread.c \
|
||||
src/lib/ultra/io/contramwrite.c \
|
||||
src/lib/ultra/io/gbpakgetstatus.c \
|
||||
src/lib/ultra/io/gbpakreadid.c \
|
||||
src/lib/ultra/io/motor.c \
|
||||
src/lib/ultra/io/pfschecker.c \
|
||||
src/lib/ultra/io/pfsfreeblocks.c \
|
||||
src/lib/ultra/io/pfsgetstatus.c \
|
||||
src/lib/ultra/io/pfsinitpak2.c
|
||||
|
||||
MIPS3_C_FILES := \
|
||||
src/lib/rng_c.c \
|
||||
src/lib/ultra/libc/ll.c \
|
||||
src/lib/ultra/libc/llcvt.c
|
||||
|
||||
G_C_FILES := \
|
||||
$(shell find src/lib/ultra/audio -name '*.c') \
|
||||
$(shell find src/lib/naudio -name '*.c') \
|
||||
$(shell find src/lib/mp3 -name '*.c') \
|
||||
src/lib/lib_2fc60.c \
|
||||
src/lib/lib_317f0.c \
|
||||
src/lib/lib_39c80.c \
|
||||
src/lib/lib_3e3e0.c \
|
||||
src/lib/mp3.c \
|
||||
src/lib/speaker.c
|
||||
|
||||
O1_C_FILES := \
|
||||
src/lib/lib_04f60nb.c \
|
||||
src/lib/ultra/io/ai.c \
|
||||
src/lib/ultra/io/aisetnextbuf.c \
|
||||
src/lib/ultra/io/conteeplongread.c \
|
||||
src/lib/ultra/io/contquery.c \
|
||||
src/lib/ultra/io/controller.c \
|
||||
src/lib/ultra/io/dpctr.c \
|
||||
src/lib/ultra/io/pigetcmdq.c \
|
||||
src/lib/ultra/io/pidma.c \
|
||||
src/lib/ultra/io/si.c \
|
||||
src/lib/ultra/io/sp.c \
|
||||
src/lib/ultra/io/spsetpc.c \
|
||||
src/lib/ultra/io/sptaskyielded.c \
|
||||
src/lib/ultra/io/vi.c \
|
||||
src/lib/ultra/io/viblack.c \
|
||||
src/lib/ultra/io/vigetcurrframebuf.c \
|
||||
src/lib/ultra/io/vigetnextframebuf.c \
|
||||
src/lib/ultra/io/visetevent.c \
|
||||
src/lib/ultra/io/visetmode.c \
|
||||
src/lib/ultra/io/visetxscale.c \
|
||||
src/lib/ultra/io/visetyscale.c \
|
||||
src/lib/ultra/io/viswapbuf.c \
|
||||
src/lib/ultra/libc/ll.c \
|
||||
src/lib/ultra/libc/llcvt.c \
|
||||
src/lib/ultra/os/atomic.c \
|
||||
src/lib/ultra/os/createmesgqueue.c \
|
||||
src/lib/ultra/os/destroythread.c \
|
||||
src/lib/ultra/os/getmemsize.c \
|
||||
src/lib/ultra/os/gettime.c \
|
||||
src/lib/ultra/os/initialize2.c \
|
||||
src/lib/ultra/os/jammesg.c \
|
||||
src/lib/ultra/os/recvmesg.c \
|
||||
src/lib/ultra/os/resetglobalintmask.c \
|
||||
src/lib/ultra/os/sendmesg.c \
|
||||
src/lib/ultra/os/seteventmesg.c \
|
||||
src/lib/ultra/os/setglobalintmask.c \
|
||||
src/lib/ultra/os/setthreadpri.c \
|
||||
src/lib/ultra/os/settimer.c \
|
||||
src/lib/ultra/os/startthread.c \
|
||||
src/lib/ultra/os/stopthread.c \
|
||||
src/lib/ultra/os/stoptimer.c \
|
||||
src/lib/ultra/os/thread.c \
|
||||
src/lib/ultra/os/timerintr.c \
|
||||
src/lib/ultra/os/virtualtophysical.c \
|
||||
src/lib/ultra/os/yieldthread.c
|
||||
|
||||
ifeq ($(ROMID), ntsc-beta)
|
||||
O1_C_FILES := $(O1_C_FILES) src/lib/ultra/io/pfsisplug.c
|
||||
endif
|
||||
|
||||
O3_C_FILES := \
|
||||
src/lib/ultra/gu/align.c \
|
||||
src/lib/ultra/gu/frustum.c \
|
||||
src/lib/ultra/gu/ortho.c \
|
||||
src/lib/ultra/gu/scale.c \
|
||||
src/lib/ultra/libc/xprintf.c
|
||||
|
||||
IDO71_C_FILES := \
|
||||
$(shell find src/lib/ultra/audio -name '*.c') \
|
||||
$(shell find src/lib/naudio -name '*.c') \
|
||||
$(shell find src/lib/mp3 -name '*.c') \
|
||||
src/lib/lib_2fc60.c \
|
||||
src/lib/lib_39c80.c
|
||||
|
||||
LOOPUNROLL_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(LOOPUNROLL_C_FILES))
|
||||
MIPS3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(MIPS3_C_FILES))
|
||||
G_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(G_C_FILES))
|
||||
O1_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O1_C_FILES))
|
||||
O3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O3_C_FILES))
|
||||
IDO71_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(IDO71_C_FILES))
|
||||
|
||||
LOOPUNROLL := -Wo,-loopunroll,0
|
||||
MIPSISET := -mips2
|
||||
OPT_LVL := -O2
|
||||
CC := build/recomp/5.3/cc
|
||||
|
||||
$(LOOPUNROLL_O_FILES): LOOPUNROLL :=
|
||||
$(MIPS3_O_FILES): MIPSISET := -mips3
|
||||
$(G_O_FILES): OPT_LVL := -g
|
||||
$(O1_O_FILES): OPT_LVL := -O1
|
||||
$(O3_O_FILES): OPT_LVL := -O3
|
||||
$(IDO71_O_FILES): CC := build/recomp/7.1/cc
|
||||
|
||||
CFLAGS = $(C_DEFINES) $(INCLUDES) \
|
||||
$(LOOPUNROLL) \
|
||||
-Wab,-r4300_mul \
|
||||
-non_shared \
|
||||
-Olimit 2000 \
|
||||
-G 0 \
|
||||
-Xcpluscomm \
|
||||
-w2 \
|
||||
-Wab,-w \
|
||||
-woff 581,649,819,820,821,838,852 \
|
||||
$(MIPSISET) -32
|
||||
|
||||
# Files containing GLOBAL_ASM must be built with the asm_processor
|
||||
ifeq ($(MATCHING), 1)
|
||||
GLOBALASM_C_FILES != grep -rl 'GLOBAL_ASM(' $(C_FILES)
|
||||
GLOBALASM_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(GLOBALASM_C_FILES))
|
||||
$(GLOBALASM_O_FILES): CC := /usr/bin/env python3 tools/asm_processor/build.py $(CC) -- $(TOOLCHAIN)-as $(ASFLAGS) --
|
||||
endif
|
||||
else ifeq ($(COMPILER), gcc)
|
||||
CC := $(TOOLCHAIN)-gcc
|
||||
|
||||
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
|
||||
|
||||
C_DEFINES += -DAVOID_UB
|
||||
|
||||
CFLAGS := $(C_DEFINES) $(INCLUDES) \
|
||||
-EB \
|
||||
-march=vr4300 \
|
||||
-mabi=32 \
|
||||
-mfix4300 \
|
||||
-mdivide-breaks \
|
||||
-mno-abicalls \
|
||||
-ffreestanding \
|
||||
-fno-builtin \
|
||||
-fno-common \
|
||||
-fno-inline-functions \
|
||||
-fno-merge-constants \
|
||||
-fno-strict-aliasing \
|
||||
-fno-zero-initialized-in-bss \
|
||||
-funsigned-char \
|
||||
-fwrapv \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-address \
|
||||
-Wno-aggressive-loop-optimizations \
|
||||
-Wno-array-bounds \
|
||||
-Wno-int-in-bool-context \
|
||||
-Wno-int-to-pointer-cast \
|
||||
-Wno-maybe-uninitialized \
|
||||
-Wno-misleading-indentation \
|
||||
-Wno-missing-braces \
|
||||
-Wno-multichar \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-pointer-to-int-cast \
|
||||
-Wno-tautological-compare \
|
||||
-Wno-uninitialized \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-unused-value \
|
||||
-Wno-unused-variable \
|
||||
-G 0
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/xldtob.o: CFLAGS += -ffast-math -fno-unsafe-math-optimizations
|
||||
else
|
||||
$(error The COMPILER option must be "ido" or "gcc")
|
||||
endif
|
||||
|
||||
# Make ROMID available as an environment variable to all tooling.
|
||||
# (We use this a lot)
|
||||
export ROMID
|
||||
|
||||
default: rom
|
||||
|
||||
################################################################################
|
||||
# Recomp
|
||||
# ------------------------------------------------------------------------------
|
||||
# The ido-static-recomp project is installed as a git submodule at tools/recomp.
|
||||
# The IRIX binaries are taken from that project and they are recompiled to
|
||||
# build/recomp/<version>/
|
||||
|
||||
tools/recomp/recomp.cpp:
|
||||
@echo "Please install ido-static-recomp by running:"
|
||||
@echo
|
||||
@echo " git submodule update --init --recursive"
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
build/recomp/recomp: tools/recomp/recomp.cpp
|
||||
@mkdir -p build/recomp/5.3
|
||||
@mkdir -p build/recomp/7.1
|
||||
g++ tools/recomp/recomp.cpp -o build/recomp/recomp -g -lcapstone
|
||||
|
||||
build/recomp/5.3/ugen:
|
||||
@mkdir -p build/recomp/5.3
|
||||
g++ tools/recomp/recomp.cpp -o build/recomp/recomp-ugen53 -g -lcapstone -Dugen53
|
||||
./build/recomp/recomp-ugen53 tools/recomp/ido/5.3/usr/lib/ugen > build/recomp/5.3/ugen.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/ugen.c -Itools/recomp -o build/recomp/5.3/ugen -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/5.3/cc: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/5.3/usr/bin/cc > build/recomp/5.3/cc.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/cc.c -Itools/recomp -o build/recomp/5.3/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/5.3/%: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/5.3/usr/lib/$* > build/recomp/5.3/$*.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/5.3/$*.c -Itools/recomp -o build/recomp/5.3/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
|
||||
|
||||
build/recomp/7.1/cc: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/7.1/usr/bin/cc > build/recomp/7.1/cc.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/7.1/cc.c -Itools/recomp -o build/recomp/7.1/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
|
||||
|
||||
build/recomp/7.1/%: build/recomp/recomp
|
||||
./build/recomp/recomp tools/recomp/ido/7.1/usr/lib/$* > build/recomp/7.1/$*.c
|
||||
gcc tools/recomp/libc_impl.c build/recomp/7.1/$*.c -Itools/recomp -o build/recomp/7.1/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
|
||||
|
||||
build/recomp/%/err.english.cc:
|
||||
@mkdir -p build/recomp/$?
|
||||
cp tools/err.english.cc build/recomp/$*
|
||||
|
||||
################################################################################
|
||||
# ROM Finalisation Stages
|
||||
|
||||
# Link all objects together with ld to make stage1.elf. In this stage, the game,
|
||||
# lib and data segments are uncompressed and placed past the end of the ROM.
|
||||
$(B_DIR)/stage1.elf: $(O_FILES) ld/pd.ld
|
||||
cpp -DROMID=$(ROMID) -DVERSION=$(VERSION) -DROMALLOCATION_DATA=$(ROMALLOCATION_DATA) -DROMALLOCATION_LIB=$(ROMALLOCATION_LIB) -DROMALLOCATION_GAME=$(ROMALLOCATION_GAME) -DROM_SIZE=$(ROM_SIZE) -P ld/pd.ld -o $(B_DIR)/pd.ld
|
||||
$(TOOLCHAIN)-ld --no-check-sections -z muldefs -T $(B_DIR)/pd.ld --print-map -o $@ > $(B_DIR)/pd.map
|
||||
|
||||
$(B_DIR)/stage1.bin: $(B_DIR)/stage1.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
# Build the final ROM from stage1.bin using mkrom
|
||||
# mkrom handles calculating the piracy checksums, zipping segments and
|
||||
# calculating the ROM checksum.
|
||||
$(B_DIR)/pd.z64: $(B_DIR)/stage1.bin tools/mkrom/mkrom
|
||||
tools/mkrom/mkrom $(B_DIR)/stage1.bin $(B_DIR)/pd.map $(PIRACYCHECKS) $(ZIPMAGIC) $(COPYLEN) $@
|
||||
@echo -e "\033[0;32mROM written to $@\033[0m"
|
||||
|
||||
tools/mkrom/mkrom:
|
||||
$(MAKE) -C tools/mkrom
|
||||
|
||||
################################################################################
|
||||
# Testing Related
|
||||
# ---------------------
|
||||
# This works a little backwards, in that the ROM has to be built to at least
|
||||
# stage 2, then extract-segment is used to slice out the segments.
|
||||
|
||||
CHECK_FILES := $(shell awk '{print $$2}' checksums.$(ROMID).md5)
|
||||
|
||||
test: $(CHECK_FILES)
|
||||
@md5sum --quiet -c checksums.$(ROMID).md5
|
||||
|
||||
$(B_DIR)/segments/%.bin: $(B_DIR)/pd.z64
|
||||
@B_DIR=$(B_DIR) tools/extract-segment $*
|
||||
|
||||
################################################################################
|
||||
# Raw data segments
|
||||
|
||||
$(B_DIR)/assets/fonts/%.o: $(A_DIR)/fonts/%.bin
|
||||
mkdir -p $(B_DIR)/assets/fonts
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/getitle.o: $(E_DIR)/getitle.bin
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/seq.ctl.o: $(A_DIR)/seq.ctl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/seq.tbl.o: $(A_DIR)/seq.tbl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/sfx.ctl.o: $(A_DIR)/sfx.ctl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/sfx.tbl.o: $(A_DIR)/sfx.tbl
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
################################################################################
|
||||
# Asset Manager
|
||||
|
||||
ASSETMGR_O_FILES := \
|
||||
$(B_DIR)/assets/animations.o \
|
||||
$(LANG_O_FILES) \
|
||||
$(PADS_O_FILES) \
|
||||
$(TILES_O_FILES) \
|
||||
$(B_DIR)/assets/sequences.o \
|
||||
$(B_DIR)/assets/textureslist.o \
|
||||
|
||||
# Anims
|
||||
$(B_DIR)/assets/animations.o: $(A_DIR)/animations.json
|
||||
tools/assetmgr/mkanims
|
||||
|
||||
# Lang
|
||||
$(B_DIR)/assets/files/L%E.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< en
|
||||
|
||||
$(B_DIR)/assets/files/L%J.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< jp
|
||||
|
||||
$(B_DIR)/assets/files/L%P.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< gb
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_f.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< fr
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_g.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< de
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_i.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< it
|
||||
|
||||
$(B_DIR)/assets/files/L%_str_s.o: $(A_DIR)/lang/%.json
|
||||
tools/assetmgr/mklang $< es
|
||||
|
||||
# Pads
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_padsZ.o: $(A_DIR)/pads/%.json
|
||||
tools/assetmgr/mkpads $<
|
||||
|
||||
# Pads - but this is the zipped non-obj, for make test
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_padsZ: $(A_DIR)/pads/%.json
|
||||
tools/assetmgr/mkpads $<
|
||||
|
||||
# Sequences
|
||||
$(B_DIR)/assets/sequences.o: $(A_DIR)/sequences.json
|
||||
tools/assetmgr/mksequences
|
||||
|
||||
# Textures
|
||||
$(B_DIR)/assets/textureslist.o: $(A_DIR)/textures.json
|
||||
tools/assetmgr/mktextures
|
||||
|
||||
# Tiles
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o: $(A_DIR)/tiles/%.json
|
||||
tools/assetmgr/mktiles $<
|
||||
|
||||
# Tiles - but this is the zipped non-obj, for make test
|
||||
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ: $(A_DIR)/tiles/%.json
|
||||
tools/assetmgr/mktiles $<
|
||||
|
||||
################################################################################
|
||||
# Files
|
||||
|
||||
# Audio
|
||||
$(B_DIR)/assets/files/A%M: $(A_DIR)/files/audio/%.mp3
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
cp $< $@
|
||||
|
||||
# BG segs
|
||||
$(B_DIR)/assets/files/bgdata/bg_%.seg: $(A_DIR)/files/bgdata/bg_%.seg
|
||||
@mkdir -p $(B_DIR)/assets/files/bgdata
|
||||
cp $< $@
|
||||
|
||||
# Chrs
|
||||
$(B_DIR)/assets/files/C%Z: $(A_DIR)/files/chrs/%.bin
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# Guns
|
||||
$(B_DIR)/assets/files/G%Z: $(A_DIR)/files/guns/%.bin
|
||||
@mkdir -p $(B_DIR)/assets/files
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# OB seg
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg.o: $(B_DIR)/assets/files/ob/ob_mid.seg
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/files/ob/ob_mid.seg:
|
||||
@mkdir -p $(B_DIR)/assets/files/ob
|
||||
> $@
|
||||
|
||||
# Props
|
||||
$(B_DIR)/assets/files/P%Z: $(A_DIR)/files/props/%.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# Stage setups
|
||||
# $(A_DIR)/files/setup/foo.c
|
||||
# -> B_DIR/assets/files/setup/foo.o (done here)
|
||||
# -> B_DIR/assets/files/setup/foo.elf (done here)
|
||||
# -> B_DIR/assets/files/setup/foo.bin (done here)
|
||||
# -> B_DIR/assets/files/UsetupfooZ (done here)
|
||||
# -> B_DIR/assets/files/UsetupfooZ.o (done elsewhere)
|
||||
$(B_DIR)/assets/files/setup/%.o: src/setups/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(B_DIR)/assets/files/setup/%.elf: $(B_DIR)/assets/files/setup/%.o
|
||||
TOOLCHAIN=$(TOOLCHAIN) tools/mksimpleelf $< $@
|
||||
|
||||
$(B_DIR)/files/setup/%.bin: $(B_DIR)/assets/files/setup/%.elf
|
||||
@mkdir -p $(dir $@)
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
$(B_DIR)/assets/files/U%Z: $(B_DIR)/files/setup/%.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
# General target to convert any finalised file into a raw object for ld
|
||||
$(B_DIR)/assets/files/%.o: $(B_DIR)/assets/files/%
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/files/%.bin: $(B_DIR)/assets/files/%.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
################################################################################
|
||||
# Miscellaneous
|
||||
|
||||
$(B_DIR)/bootloader.o: $(E_DIR)/bootloader.bin
|
||||
@mkdir -p $(dir $@)
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/romheader.o: src/romheader/romheader.s
|
||||
$(TOOLCHAIN)-as --defsym VERSION=$(VERSION) -march=vr4300 -mabi=32 -I src/include -EB -o $@ $<
|
||||
|
||||
$(B_DIR)/assets/accessingpakZ: $(A_DIR)/accessingpak.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
$(B_DIR)/assets/copyrightZ: $(A_DIR)/copyright.bin
|
||||
tools/rarezip $< > $@
|
||||
|
||||
$(B_DIR)/assets/accessingpakZ.o: $(B_DIR)/assets/accessingpakZ
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/assets/copyrightZ.o: $(B_DIR)/assets/copyrightZ
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
$(B_DIR)/rsp/%.text.bin $(B_DIR)/rsp/%.data.bin: src/rsp/%.s
|
||||
@mkdir -p $(dir $@)
|
||||
armips -strequ CODE_FILE $(B_DIR)/rsp/$*.text.bin -strequ DATA_FILE $(B_DIR)/rsp/$*.data.bin $<
|
||||
|
||||
$(B_DIR)/rsp/%.o: $(B_DIR)/rsp/%.bin
|
||||
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
|
||||
|
||||
ifeq ($(COMPILER), ido)
|
||||
$(B_DIR)/lib/rng_c.o: src/lib/rng_c.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
tools/patchmips3 $@ || rm $@
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/llcvt.o: src/lib/ultra/libc/llcvt.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
tools/patchmips3 $@ || rm $@
|
||||
|
||||
$(B_DIR)/lib/ultra/libc/ll.o: src/lib/ultra/libc/ll.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) $< -o $@
|
||||
tools/patchmips3 $@ || rm $@
|
||||
endif
|
||||
|
||||
$(B_DIR)/%.o: src/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
|
||||
|
||||
$(B_DIR)/%.o: src/%.s
|
||||
@mkdir -p $(dir $@)
|
||||
cpp -P -Wno-trigraphs -I include -I include/PR -I src/include $(C_DEFINES) -D_LANGUAGE_ASSEMBLY -D_MIPSEB $< | $(AS) $(ASFLAGS) -o $@
|
||||
|
||||
$(B_DIR)/assets/%.o: $(A_DIR)/%.c $(RECOMP_FILES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
extract:
|
||||
ROMID=$(ROMID) tools/extract
|
||||
|
||||
rom: $(B_DIR)/pd.z64
|
||||
|
||||
clean:
|
||||
rm -rf build/$(ROMID) src/generated/$(ROMID)
|
||||
|
||||
allclean:
|
||||
rm -rf build/* src/generated
|
||||
|
||||
codeclean:
|
||||
find $(B_DIR)/game $(B_DIR)/inflate $(B_DIR)/lib -name '*.o' -delete
|
||||
-336
@@ -1,336 +0,0 @@
|
||||
# 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 -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
|
||||
@@ -31,18 +31,24 @@ There are minor graphics- and gameplay-related issues, and possibly occasional c
|
||||
* 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;
|
||||
* enable `Uncap Tickrate` in `Extended Video Options` to activate;
|
||||
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
|
||||
* emulate the Transfer Pak functionality the game has on the Nintendo 64 to unlock some cheats automatically.
|
||||
|
||||
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.
|
||||
**The following platforms are officially supported and tested:**
|
||||
* Windows 7+: i686, x86_64
|
||||
* Linux: i686, x86_64
|
||||
* MacOS: x86_64 (OS 10.9+), arm64 (OS 11.0+)
|
||||
* Nintendo Switch: arm64
|
||||
|
||||
## Download
|
||||
|
||||
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for supported platforms:
|
||||
* [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip)
|
||||
* [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip)
|
||||
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/releases/tag/ci-dev-build) for supported platforms:
|
||||
* [x86_64-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-windows.zip)
|
||||
* [i686-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-windows.zip)
|
||||
* [x86_64-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-linux.tar.gz)
|
||||
* [i686-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-linux.tar.gz)
|
||||
* [arm64-nswitch](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-arm64-nswitch.zip)
|
||||
|
||||
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).
|
||||
|
||||
@@ -50,13 +56,29 @@ If you are looking for netplay builds (the `port-net` branch), see [this link](h
|
||||
|
||||
You must already have a Perfect Dark ROM to run the game, as specified above.
|
||||
|
||||
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`.
|
||||
This assumes that you're using an x86_64 build. If you aren't, replace `x86_64` below with your arch (e.g. `i686`).
|
||||
|
||||
1. Create a directory named `data` next to `pd.x86_64` if it's not there.
|
||||
2. Put your Perfect Dark NTSC ROM named `pd.ntsc-final.z64` into it.
|
||||
3. Run the `pd.x86_64` executable.
|
||||
|
||||
If you want to use a PAL or JPN ROM instead, put them into the `data` directory and run the appropriate executable:
|
||||
* PAL: ROM name `pd.pal-final.z64`, executable name `pd.pal.x86_64`.
|
||||
* JPN: ROM name `pd.jpn-final.z64`, executable name `pd.jpn.x86_64`.
|
||||
|
||||
Optionally, you can also put your Perfect Dark for GameBoy Color ROM named `pd.gbc` in the `data` directory if you want to emulate having the Nintendo 64's Transfer Pak and unlock some cheats automatically.
|
||||
|
||||
Optionally, you can move the data folder to `~/.local/share/perfectdark` on Linux or `~/Library/Application Support/perfectdark` on MacOS.
|
||||
|
||||
Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).
|
||||
|
||||
A GPU supporting OpenGL 3.0 or above is required to run the port.
|
||||
A GPU supporting OpenGL 3.0/ES3.0 or above is required to run the port.
|
||||
|
||||
### Installing the Nintendo Switch version
|
||||
|
||||
The Nintendo Switch build ZIP comes with all 3 regions in different folders: `perfectdark`, `perfectdark_pal` and `perfectdark_jpn`.
|
||||
|
||||
Take the folder for the region you want and put it into the `/switch` folder on your SD card, then put your ROM into the `data` folder inside of the folder you extracted as described above.
|
||||
|
||||
## Controls
|
||||
|
||||
@@ -92,43 +114,101 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows:
|
||||
### Windows
|
||||
|
||||
1. Install [MSYS2](https://www.msys2.org).
|
||||
2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt)
|
||||
2. Open the `MINGW64` prompt if building for x86_64, or the `MINGW32` prompt if building for i686. (**NOTE:** _do not_ use the `MSYS` prompt)
|
||||
3. Install dependencies:
|
||||
`pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git`
|
||||
`pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-SDL2 mingw-w64-x86_64-zlib mingw-w64-x86_64-cmake mingw-w64-x86_64-python3 mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-cmake mingw-w64-i686-python3 make git`
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Run `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.
|
||||
5. Run `cmake -G"Unix Makefiles" -Bbuild .`.
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.\
|
||||
6. Run `cmake --build build -j4 -- -O`.
|
||||
7. The resulting executable will be at `build/pd.x86_64.exe` (or at `build/pd.i686.exe` if building for i686).
|
||||
8. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory.
|
||||
|
||||
### Linux
|
||||
|
||||
1. Ensure you have gcc, g++ (version 10.0+) 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.
|
||||
1. Ensure you have gcc, g++ (version 10.0+), make, cmake, git, python3 and SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
|
||||
* If you wish to crosscompile, you will also need to have libraries and compilers for the target platform installed, e.g. `gcc-multilib` and `g++-multilib` for x86_64 -> i686 crosscompilation.
|
||||
2. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
3. Run the following command:
|
||||
* 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`.
|
||||
* ```cmake -G"Unix Makefiles" -Bbuild .```
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
* Add ` -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32` at the end of the command if you want to crosscompile from x86_64 to x86.
|
||||
4. Run `cmake --build build -j4`.
|
||||
5. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
|
||||
|
||||
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.
|
||||
### MacOS
|
||||
|
||||
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`.
|
||||
1. Set up Homebrew.
|
||||
2. Install dependencies:
|
||||
* Execute command: `brew install cmake gcc python3 zlib git`
|
||||
3. Install SDL2:
|
||||
* Execute commands:
|
||||
```
|
||||
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
|
||||
hdiutil mount SDL2.dmg
|
||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||
hdiutil detach /Volumes/SDL2
|
||||
```
|
||||
* This installs SDL2 system-wide and this is how the automatic builds are done. The game will also look for it in the executable path, so you could
|
||||
download it locally instead.
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Configure:
|
||||
* Execute command: `cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .`
|
||||
* Replace `x86_64` with `arm64` if building for an ARM64 Mac.
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
6. Build:
|
||||
* Execute command: `cmake --build build --target pd -j4 --clean-first`
|
||||
7. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
|
||||
* You might need to execute `chmod +x build/pd.x86-64` before you can run it.
|
||||
|
||||
It might be possible to build a 32-bit ARM executable, but this has not been tested.
|
||||
### Nintendo Switch
|
||||
|
||||
1. Set up the [devkitA64 environment](https://devkitpro.org/wiki/Getting_Started).
|
||||
* On Windows you can do it under MSYS2 or WSL, usually MSYS2 is recommended.
|
||||
* If using MSYS2, make sure to use the **MSYS2** shell, **not** MINGW32 or MINGW64.
|
||||
2. Install host dependencies:
|
||||
* On MSYS2: execute command `pacman -Syuu && pacman -S git make cmake python3`
|
||||
* On Linux: use your package manager as normal to install the above dependencies.
|
||||
3. Install Switch toolchain and dependencies:
|
||||
* Execute commands:
|
||||
```
|
||||
dkp-pacman -Syuu
|
||||
dkp-pacman -S devkitA64 libnx switch-zlib switch-sdl2 switch-cmake dkp-toolchain-vars
|
||||
```
|
||||
* If in MSYS2 or `dkp-pacman` doesn't work, replace it with just `pacman`.
|
||||
4. Get the source code:
|
||||
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
|
||||
5. Ensure devkitA64 environment variables are set:
|
||||
* Execute command: `source /opt/devkitpro/switchvars.sh`
|
||||
* If your `$DEVKITPRO` path is different, substitute that instead or set the variables manually.
|
||||
6. Configure:
|
||||
* Execute command: `aarch64-none-elf-cmake -G"Unix Makefiles" -Bbuild .`
|
||||
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
|
||||
7. Build:
|
||||
* Execute command: `make -C build -j4`
|
||||
8. The resulting executable will be at `build/pd.arm64.nro`.
|
||||
|
||||
### Notes
|
||||
|
||||
Alternate compilers or toolchains can be specified by passing `-DCMAKE_TOOLCHAIN_FILE=whatever` as normal. The port does not build with Visual Studio.
|
||||
|
||||
You will need to provide a `jpn-final` or `pal-final` ROM to run executables built for those regions, named `pd.jpn-final.z64` or `pd.pal-final.z64`.
|
||||
|
||||
It might be possible to build and run the game on platforms that are not specified in the supported platforms list (e.g. Linux on armv7), but this has not been tested.
|
||||
|
||||
## Credits
|
||||
|
||||
* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
|
||||
* Ryan Dwyer for the above, additional help, and `pd-extract`;
|
||||
* doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find;
|
||||
* [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes;
|
||||
* [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D), Emill and MaikelChan for the libultraship version of fast3d that this port uses;
|
||||
* lieff for [minimp3](https://github.com/lieff/minimp3);
|
||||
* Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes;
|
||||
* Raf for the 64-bit port;
|
||||
* NicNamSam for the icon;
|
||||
* everyone who has submitted pull requests and issues to this repository and tested the port;
|
||||
* probably more I'm forgetting.
|
||||
@@ -0,0 +1,27 @@
|
||||
# execute a header generator (execcmd) for every json file in jsonpath, collect headers in headerlist
|
||||
# note that this reads ROMID
|
||||
macro(generate_asset_headers jsonpath execcmd extraarg headerlist)
|
||||
set(TMP_JSON "")
|
||||
|
||||
if (${jsonpath} MATCHES "\.json")
|
||||
# is a json file
|
||||
list(APPEND TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}")
|
||||
else()
|
||||
# is a directory
|
||||
file(GLOB TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}*.json")
|
||||
endif()
|
||||
|
||||
foreach(JSON ${TMP_JSON})
|
||||
unset(HEADERNAME)
|
||||
string(REPLACE ".json" ".h" HEADERNAME ${JSON})
|
||||
string(REPLACE "${CMAKE_SOURCE_DIR}/${ASSET_DIR}" "${CMAKE_BINARY_DIR}/${GENERATED_DIR}" HEADERNAME ${HEADERNAME})
|
||||
add_custom_command(
|
||||
OUTPUT ${HEADERNAME}
|
||||
DEPENDS ${JSON}
|
||||
COMMAND ${execcmd} ${JSON} ${extraarg} --headers-only --romid=${ROMID}
|
||||
)
|
||||
list(APPEND ${headerlist} "${HEADERNAME}")
|
||||
endforeach()
|
||||
|
||||
unset(TMP_JSON)
|
||||
endmacro()
|
||||
@@ -0,0 +1,172 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
# Locate SDL2 library
|
||||
# This module defines
|
||||
# SDL2_LIBRARY, the name of the library to link against
|
||||
# SDL2_FOUND, if false, do not try to link to SDL2
|
||||
# SDL2_INCLUDE_DIR, where to find SDL.h
|
||||
#
|
||||
# This module responds to the the flag:
|
||||
# SDL2_BUILDING_LIBRARY
|
||||
# If this is defined, then no SDL2_main will be linked in because
|
||||
# only applications need main().
|
||||
# Otherwise, it is assumed you are building an application and this
|
||||
# module will attempt to locate and set the the proper link flags
|
||||
# as part of the returned SDL2_LIBRARY variable.
|
||||
#
|
||||
# Don't forget to include SDL2main.h and SDL2main.m your project for the
|
||||
# OS X framework based version. (Other versions link to -lSDL2main which
|
||||
# this module will try to find on your behalf.) Also for OS X, this
|
||||
# module will automatically add the -framework Cocoa on your behalf.
|
||||
#
|
||||
#
|
||||
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
|
||||
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
|
||||
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
|
||||
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
|
||||
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
|
||||
# as appropriate. These values are used to generate the final SDL2_LIBRARY
|
||||
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
|
||||
#
|
||||
#
|
||||
# $SDL2DIR is an environment variable that would
|
||||
# correspond to the ./configure --prefix=$SDL2DIR
|
||||
# used in building SDL2.
|
||||
# l.e.galup 9-20-02
|
||||
#
|
||||
# Modified by Eric Wing.
|
||||
# Added code to assist with automated building by using environmental variables
|
||||
# and providing a more controlled/consistent search behavior.
|
||||
# Added new modifications to recognize OS X frameworks and
|
||||
# additional Unix paths (FreeBSD, etc).
|
||||
# Also corrected the header search path to follow "proper" SDL2 guidelines.
|
||||
# Added a search for SDL2main which is needed by some platforms.
|
||||
# Added a search for threads which is needed by some platforms.
|
||||
# Added needed compile switches for MinGW.
|
||||
#
|
||||
# On OSX, this will prefer the Framework version (if found) over others.
|
||||
# People will have to manually change the cache values of
|
||||
# SDL2_LIBRARY to override this selection or set the CMake environment
|
||||
# CMAKE_INCLUDE_PATH to modify the search paths.
|
||||
#
|
||||
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
|
||||
# This needed to change because "proper" SDL2 convention
|
||||
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
|
||||
# reasons because not all systems place things in SDL2/ (see FreeBSD).
|
||||
#
|
||||
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
|
||||
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
|
||||
# was not created for redistribution, and exists temporarily pending official
|
||||
# SDL2 CMake modules.
|
||||
|
||||
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES include/SDL2 include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/include/SDL2
|
||||
/usr/include/SDL2
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
/boot/system/develop/headers/SDL2 #Hiaku OS
|
||||
)
|
||||
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
|
||||
|
||||
FIND_LIBRARY(SDL2_LIBRARY_TEMP
|
||||
NAMES SDL2
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
/system/lib #Hiaku OS
|
||||
)
|
||||
|
||||
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
|
||||
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
# Non-OS X framework versions expect you to also dynamically link to
|
||||
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||
# seem to provide SDL2main for compatibility even though they don't
|
||||
# necessarily need it.
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# SDL2 may require threads on your system.
|
||||
# The Apple build may not need an explicit flag because one of the
|
||||
# frameworks may already provide it.
|
||||
# But for non-OSX systems, I will use the CMake Threads package.
|
||||
IF(NOT APPLE)
|
||||
FIND_PACKAGE(Threads)
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# MinGW needs an additional library, mwindows
|
||||
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
|
||||
# (Actually on second look, I think it only needs one of the m* libraries.)
|
||||
IF(MINGW)
|
||||
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
|
||||
ENDIF(MINGW)
|
||||
|
||||
SET(SDL2_FOUND "NO")
|
||||
IF(SDL2_LIBRARY_TEMP)
|
||||
# For SDL2main
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(SDL2MAIN_LIBRARY)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(SDL2MAIN_LIBRARY)
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||
# though it actually is there if I modify a pre-used variable.
|
||||
# I think it has something to do with the CACHE STRING.
|
||||
# So I use a temporary variable until the end so I can set the
|
||||
# "real" variable in one-shot.
|
||||
IF(APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
|
||||
ENDIF(APPLE)
|
||||
|
||||
# For threads, as mentioned Apple doesn't need this.
|
||||
# In fact, there seems to be a problem if I used the Threads package
|
||||
# and try using this line, so I'm just skipping it entirely for OS X.
|
||||
IF(NOT APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# For MinGW library
|
||||
IF(MINGW)
|
||||
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(MINGW)
|
||||
|
||||
# Set the final string here so the GUI reflects the final state.
|
||||
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
|
||||
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
|
||||
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
|
||||
|
||||
SET(SDL2_FOUND "YES")
|
||||
ENDIF(SDL2_LIBRARY_TEMP)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
|
||||
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
|
||||
# Based on the Qt 5 processor detection code, so should be very accurate
|
||||
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
|
||||
|
||||
# Regarding POWER/PowerPC, just as is noted in the Qt source,
|
||||
# "There are many more known variants/revisions that we do not handle/detect."
|
||||
|
||||
set(archdetect_c_code "
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM64) || defined (__aarch64__)
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
|
||||
#error cmake_ARCH armv7
|
||||
#elif defined(__ARM_ARCH_6__) \\
|
||||
|| defined(__ARM_ARCH_6J__) \\
|
||||
|| defined(__ARM_ARCH_6T2__) \\
|
||||
|| defined(__ARM_ARCH_6Z__) \\
|
||||
|| defined(__ARM_ARCH_6K__) \\
|
||||
|| defined(__ARM_ARCH_6ZK__) \\
|
||||
|| defined(__ARM_ARCH_6M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
|
||||
#error cmake_ARCH armv6
|
||||
#elif defined(__ARM_ARCH_5TEJ__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
|
||||
#error cmake_ARCH armv5
|
||||
#elif defined(_M_ARM64) || defined (__aarch64__)
|
||||
#error cmake_ARCH arm64
|
||||
#else
|
||||
#error cmake_ARCH arm
|
||||
#endif
|
||||
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#error cmake_ARCH i386
|
||||
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||
#error cmake_ARCH x86_64
|
||||
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||
#error cmake_ARCH ia64
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||
#error cmake_ARCH ppc64
|
||||
#else
|
||||
#error cmake_ARCH ppc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#error cmake_ARCH unknown
|
||||
")
|
||||
|
||||
# Set ppc_support to TRUE before including this file or ppc and ppc64
|
||||
# will be treated as invalid architectures since they are no longer supported by Apple
|
||||
|
||||
function(target_architecture output_var)
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
|
||||
# First let's normalize the order of the values
|
||||
|
||||
# Note that it's not possible to compile PowerPC applications if you are using
|
||||
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
|
||||
# disable it by default
|
||||
# See this page for more information:
|
||||
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
|
||||
|
||||
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
|
||||
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
set(osx_arch_ppc TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "i386")
|
||||
set(osx_arch_i386 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "x86_64")
|
||||
set(osx_arch_x86_64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "arm64")
|
||||
set(osx_arch_arm64 TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Now add all the architectures in our normalized order
|
||||
if(osx_arch_ppc)
|
||||
list(APPEND ARCH ppc)
|
||||
endif()
|
||||
|
||||
if(osx_arch_i386)
|
||||
list(APPEND ARCH i386)
|
||||
endif()
|
||||
|
||||
if(osx_arch_x86_64)
|
||||
list(APPEND ARCH x86_64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_arm64)
|
||||
list(APPEND ARCH arm64)
|
||||
endif()
|
||||
else()
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
|
||||
|
||||
enable_language(C)
|
||||
|
||||
# Detect the architecture in a rather creative way...
|
||||
# This compiles a small C program which is a series of ifdefs that selects a
|
||||
# particular #error preprocessor directive whose message string contains the
|
||||
# target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of the
|
||||
# #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# way, we can detect the correct target architecture even when cross-compiling,
|
||||
# since the program itself never needs to be run (only the compiler/preprocessor)
|
||||
try_run(
|
||||
run_result_unused
|
||||
compile_result_unused
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}/arch.c"
|
||||
COMPILE_OUTPUT_VARIABLE ARCH
|
||||
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
|
||||
)
|
||||
|
||||
# Parse the architecture name from the compiler output
|
||||
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
|
||||
|
||||
# Get rid of the value marker leaving just the architecture name
|
||||
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
|
||||
|
||||
# If we are compiling with an unknown architecture this variable should
|
||||
# already be set to "unknown" but in the case that it's empty (i.e. due
|
||||
# to a typo in the code), then set it to unknown
|
||||
if (NOT ARCH)
|
||||
set(ARCH unknown)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${output_var} "${ARCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Name=Perfect Dark
|
||||
Comment=Modern source port of Perfect Dark
|
||||
Exec=io.github.fgsfdsfgs.perfect_dark.sh
|
||||
Icon=io.github.fgsfdsfgs.perfect_dark
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Game;ActionGame;
|
||||
StartupNotify=false
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>io.github.fgsfdsfgs.perfect_dark</id>
|
||||
<name>Perfect Dark</name>
|
||||
<developer id="io.github.fgsfdsfgs.perfect_dark">
|
||||
<name>Perfect Dark Contributors</name>
|
||||
<url>https://github.com/fgsfdsfgs/perfect_dark/graphs/contributors</url>
|
||||
</developer>
|
||||
<launchable type="desktop-id">io.github.fgsfdsfgs.perfect_dark.desktop</launchable>
|
||||
<summary>Modern cross-platform port of Perfect Dark</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
<url type="homepage">https://github.com/fgsfdsfgs/perfect_dark/</url>
|
||||
<description>
|
||||
<p>This is a port of Ryan Dywer's decompilation of classic N64 shooter Perfect Dark to modern systems.</p>
|
||||
</description>
|
||||
<!--
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source">https://gitlab.com/fpiesche/dxx-rebirth-assets/-/raw/c6e7e79eebe92905f84f07a635ffab5122a94bd1/d1x/screenshots/retromode.png</image>
|
||||
<caption>"Retro mode": the default graphics setup, like the original game but in high resolution</caption>
|
||||
<screenshots>
|
||||
-->
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
<category>ActionGame</category>
|
||||
<category>Shooter</category>
|
||||
</categories>
|
||||
<keywords>
|
||||
<keyword>n64</keyword>
|
||||
<keyword>scifi</keyword>
|
||||
<keyword>cyberpunk</keyword>
|
||||
<keyword>retro</keyword>
|
||||
<keyword>sourceport</keyword>
|
||||
<keyword>port</keyword>
|
||||
</keywords>
|
||||
<releases>
|
||||
<release version="latest" date="2024-05-14"/>
|
||||
</releases>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="violence-realistic">moderate</content_attribute>
|
||||
<content_attribute id="violence-bloodshed">mild</content_attribute>
|
||||
</content_rating>
|
||||
<update_contact>https://github.com/fgsfdsfgs/perfect_dark/</update_contact>
|
||||
</component>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Create user data directories if necessary
|
||||
userdirs=( roms saves mods )
|
||||
for path in "${userdirs[@]}"; do
|
||||
if [ ! -d "${XDG_DATA_HOME}/${path}" ]; then
|
||||
mkdir -p "${XDG_DATA_HOME}/${path}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Default to pd as executable but switch to jpn/pal if the NTSC rom
|
||||
# is missing but JPN/PAL are present.
|
||||
# TODO: Other arch
|
||||
executable="pd.x86_64"
|
||||
if [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-final.z64 ] | \
|
||||
[ -f ${XDG_DATA_HOME}/roms/pd.ntsc-1.0.z64 ]; then
|
||||
executable="pd.x86_64"
|
||||
elif [ -f ${XDG_DATA_HOME}/roms/pd.jpn-final.z64 ]; then
|
||||
executable="pd.jpn.x86_64"
|
||||
elif [ -f ${XDG_DATA_HOME}/roms/pd.pal-final.z64 ]; then
|
||||
executable="pd.pal.x86_64"
|
||||
fi
|
||||
|
||||
# If first parameter passed to this script is one of the pd executables,
|
||||
# run that regardless of ROM auto-detection above and pass the remaining
|
||||
# parameters to it; otherwise pass all arguments to the executable selected
|
||||
# above
|
||||
case $1 in
|
||||
"pd."*)
|
||||
executable=$1
|
||||
params="${@:2}"
|
||||
;;
|
||||
*)
|
||||
params="$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Run game
|
||||
$executable --basedir ${XDG_DATA_HOME}/roms --savedir ${XDG_DATA_HOME}/saves $params
|
||||
@@ -0,0 +1,41 @@
|
||||
app-id: io.github.fgsfdsfgs.perfect_dark
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: "23.08"
|
||||
sdk: org.freedesktop.Sdk
|
||||
command: io.github.fgsfdsfgs.perfect_dark.sh
|
||||
|
||||
finish-args:
|
||||
- --device=all
|
||||
- --share=ipc
|
||||
- --socket=x11
|
||||
# Audio
|
||||
- --socket=pulseaudio
|
||||
# Enable network for multiplayer
|
||||
- --share=network
|
||||
|
||||
modules:
|
||||
- name: perfect_dark
|
||||
buildsystem: simple
|
||||
sources:
|
||||
- type: file
|
||||
path: bin/pd.x86_64
|
||||
- type: file
|
||||
path: bin/pd.jpn.x86_64
|
||||
- type: file
|
||||
path: bin/pd.pal.x86_64
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.sh
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.png
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.metainfo.xml
|
||||
- type: file
|
||||
path: io.github.fgsfdsfgs.perfect_dark.desktop
|
||||
build-commands: []
|
||||
post-install:
|
||||
# Install the binaries
|
||||
- install -Dm 755 -t /app/bin/ pd.*
|
||||
- install -Dm 755 ${FLATPAK_ID}.sh /app/bin/${FLATPAK_ID}.sh
|
||||
- install -Dm 644 ${FLATPAK_ID}.desktop /app/share/applications/${FLATPAK_ID}.desktop
|
||||
- install -Dm 644 ${FLATPAK_ID}.metainfo.xml /app/share/metainfo/${FLATPAK_ID}.metainfo.xml
|
||||
- install -Dm 644 ${FLATPAK_ID}.png /app/share/icons/hicolor/256x256/apps/${FLATPAK_ID}.png
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
# Switch (SDL_GetPlatform is not changed in switch-sdl2)
|
||||
000038f853776974636820436f6e7400,Switch Controller,a:b0,b:b1,back:b11,dpdown:b15,dpleft:b12,dpright:b14,dpup:b13,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Unknown (see SDL_platform.h),
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
Vendored
+1
@@ -0,0 +1 @@
|
||||
id ICON icon.ico
|
||||
@@ -22,6 +22,7 @@
|
||||
#define __R4300_H__
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "platform.h"
|
||||
|
||||
/*
|
||||
* Segment base addresses and sizes
|
||||
|
||||
+62
-30
@@ -22,6 +22,12 @@
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "gbiex.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* To use the F3DEX ucodes, define F3DEX_GBI before include this file.
|
||||
@@ -594,10 +600,10 @@
|
||||
#define G_BL_0 3
|
||||
|
||||
#define GBL_c1(m1a, m1b, m2a, m2b) \
|
||||
(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18
|
||||
(u32)(m1a) << 30 | (u32)(m1b) << 26 | (u32)(m2a) << 22 | (u32)(m2b) << 18
|
||||
|
||||
#define GBL_c2(m1a, m1b, m2a, m2b) \
|
||||
(m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16
|
||||
(u32)(m1a) << 28 | (u32)(m1b) << 24 | (u32)(m2a) << 20 | (u32)(m2b) << 16
|
||||
|
||||
#define RM_AA_ZB_OPA_SURF(clk) \
|
||||
AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
|
||||
@@ -1053,7 +1059,7 @@ typedef struct {
|
||||
// 4x4 float matrix
|
||||
typedef float Mtx_t[4][4];
|
||||
#else
|
||||
typedef long Mtx_t[4][4];
|
||||
typedef int32_t Mtx_t[4][4];
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
@@ -1306,6 +1312,14 @@ typedef union {
|
||||
/*
|
||||
* Graphics DMA Packet
|
||||
*/
|
||||
#ifdef PLATFORM_64BIT
|
||||
typedef struct {
|
||||
intptr_t par : 24;
|
||||
intptr_t cmd : 8;
|
||||
intptr_t len : 32;
|
||||
uintptr_t addr;
|
||||
} Gdma;
|
||||
#else
|
||||
typedef struct {
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
int cmd:8;
|
||||
@@ -1319,6 +1333,7 @@ typedef struct {
|
||||
unsigned int addr;
|
||||
#endif
|
||||
} Gdma;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Graphics Immediate Mode Packet types
|
||||
@@ -1357,6 +1372,9 @@ typedef struct {
|
||||
unsigned char z4:4;
|
||||
unsigned char pad:8;
|
||||
unsigned char cmd:8;
|
||||
#ifdef PLATFORM_64BIT
|
||||
unsigned char pad2[4];
|
||||
#endif
|
||||
unsigned char x1:4;
|
||||
unsigned char y1:4;
|
||||
unsigned char x2:4;
|
||||
@@ -1365,6 +1383,9 @@ typedef struct {
|
||||
unsigned char y3:4;
|
||||
unsigned char x4:4;
|
||||
unsigned char y4:4;
|
||||
#ifdef PLATFORM_64BIT
|
||||
unsigned char pad3[4];
|
||||
#endif
|
||||
#endif
|
||||
} Gtri4;
|
||||
|
||||
@@ -1538,8 +1559,8 @@ typedef struct {
|
||||
* Generic Gfx Packet
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int w0;
|
||||
unsigned int w1;
|
||||
uintptr_t w0;
|
||||
uintptr_t w1;
|
||||
} Gwords;
|
||||
|
||||
// xxxxxxxx 11223344 44555566 66666777
|
||||
@@ -1596,7 +1617,11 @@ typedef struct {
|
||||
*/
|
||||
typedef union {
|
||||
Gwords words;
|
||||
#ifdef PLATFORM_64BIT
|
||||
u8 bytes[16];
|
||||
#else
|
||||
u8 bytes[8];
|
||||
#endif
|
||||
Gdma dma;
|
||||
Gvtx vtx;
|
||||
Gtri tri;
|
||||
@@ -1619,12 +1644,19 @@ typedef union {
|
||||
Gloadtlut loadtlut;
|
||||
#endif
|
||||
GunkC0 unkc0;
|
||||
#ifdef PLATFORM_64BIT
|
||||
long long int force_structure_alignment[2];
|
||||
#else
|
||||
long long int force_structure_alignment;
|
||||
#endif
|
||||
} Gfx;
|
||||
|
||||
#ifdef PLATFORM_BIG_ENDIAN
|
||||
#define GFX_W0_BYTE(i) (i)
|
||||
#define GFX_W1_BYTE(i) (4 + (i))
|
||||
#elif PLATFORM_64BIT
|
||||
#define GFX_W0_BYTE(i) (3 - (i))
|
||||
#define GFX_W1_BYTE(i) (11 - (i))
|
||||
#else
|
||||
#define GFX_W0_BYTE(i) (3 - (i))
|
||||
#define GFX_W1_BYTE(i) (7 - (i))
|
||||
@@ -1642,12 +1674,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \
|
||||
_g->words.w1 = (unsigned int)(s); \
|
||||
_g->words.w1 = (uintptr_t)(s); \
|
||||
}
|
||||
|
||||
#define gsDma0p(c, s, l) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (unsigned int)(s) \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s) \
|
||||
}
|
||||
|
||||
#define gDma1p(pkt, c, s, l, p) \
|
||||
@@ -1656,14 +1688,14 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
|
||||
_SHIFTL((l), 0, 16)); \
|
||||
_g->words.w1 = (unsigned int)(s); \
|
||||
_g->words.w1 = (uintptr_t)(s); \
|
||||
}
|
||||
|
||||
#define gsDma1p(c, s, l, p) \
|
||||
{ \
|
||||
(_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
|
||||
_SHIFTL((l), 0, 16)), \
|
||||
(unsigned int)(s) \
|
||||
(uintptr_t)(s) \
|
||||
}
|
||||
|
||||
#define gDma2p(pkt, c, adrs, len, idx, ofs) \
|
||||
@@ -1671,14 +1703,14 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
_g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
|
||||
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \
|
||||
_g->words.w1 = (unsigned int)(adrs); \
|
||||
_g->words.w1 = (uintptr_t)(adrs); \
|
||||
}
|
||||
|
||||
#define gsDma2p(c, adrs, len, idx, ofs) \
|
||||
{ \
|
||||
(_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
|
||||
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \
|
||||
(unsigned int)(adrs) \
|
||||
(uintptr_t)(adrs) \
|
||||
}
|
||||
|
||||
#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
|
||||
@@ -1727,12 +1759,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL((c), 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(p0); \
|
||||
_g->words.w1 = (uintptr_t)(p0); \
|
||||
}
|
||||
|
||||
#define gsImmp1(c, p0) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8), (unsigned int)(p0) \
|
||||
_SHIFTL((c), 24, 8), (uintptr_t)(p0) \
|
||||
}
|
||||
|
||||
#define gImmp2(pkt, c, p0, p1) \
|
||||
@@ -1769,13 +1801,13 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \
|
||||
_SHIFTL((p1), 0, 8)); \
|
||||
_g->words.w1 = (unsigned int) (dat); \
|
||||
_g->words.w1 = (uintptr_t) (dat); \
|
||||
}
|
||||
|
||||
#define gsImmp21(c, p0, p1, dat) \
|
||||
{ \
|
||||
_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \
|
||||
(unsigned int) (dat) \
|
||||
(uintptr_t) (dat) \
|
||||
}
|
||||
|
||||
#define gMoveWd(pkt, index, offset, data) \
|
||||
@@ -1918,7 +1950,7 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
|
||||
((0x0f & (vstart))*40); \
|
||||
_g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \
|
||||
_g->words.w1 = (uintptr_t)((0x0f & ((vend)+1))*40); \
|
||||
}
|
||||
|
||||
// Removed in PD
|
||||
@@ -2239,12 +2271,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(word); \
|
||||
_g->words.w1 = (uintptr_t)(word); \
|
||||
}
|
||||
|
||||
#define gsSPSetGeometryMode(word) \
|
||||
{ \
|
||||
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \
|
||||
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
|
||||
}
|
||||
|
||||
#define gSPClearGeometryMode(pkt, word) \
|
||||
@@ -2252,12 +2284,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(word); \
|
||||
_g->words.w1 = (uintptr_t)(word); \
|
||||
}
|
||||
|
||||
#define gsSPClearGeometryMode(word) \
|
||||
{ \
|
||||
_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) \
|
||||
_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
|
||||
}
|
||||
|
||||
#define gSPSetOtherMode(pkt, cmd, sft, len, data) \
|
||||
@@ -2266,13 +2298,13 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
|
||||
_SHIFTL(len, 0, 8)); \
|
||||
_g->words.w1 = (unsigned int)(data); \
|
||||
_g->words.w1 = (uintptr_t)(data); \
|
||||
}
|
||||
|
||||
#define gsSPSetOtherMode(cmd, sft, len, data) \
|
||||
{ \
|
||||
_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
|
||||
(unsigned int)(data) \
|
||||
(uintptr_t)(data) \
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2323,14 +2355,14 @@ typedef union {
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
|
||||
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \
|
||||
_g->words.w1 = (unsigned int)(i); \
|
||||
_g->words.w1 = (uintptr_t)(i); \
|
||||
}
|
||||
|
||||
#define gsSetImage(cmd, fmt, siz, width, i) \
|
||||
{ \
|
||||
_SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
|
||||
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \
|
||||
(unsigned int)(i) \
|
||||
(uintptr_t)(i) \
|
||||
}
|
||||
|
||||
#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i)
|
||||
@@ -2356,13 +2388,13 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \
|
||||
_g->words.w1 = (unsigned int)(muxs1); \
|
||||
_g->words.w1 = (uintptr_t)(muxs1); \
|
||||
}
|
||||
|
||||
#define gsDPSetCombine(muxs0, muxs1) \
|
||||
{ \
|
||||
_SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
|
||||
(unsigned int)(muxs1) \
|
||||
(uintptr_t)(muxs1) \
|
||||
}
|
||||
|
||||
#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \
|
||||
@@ -2435,12 +2467,12 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(c, 24, 8); \
|
||||
_g->words.w1 = (unsigned int)(d); \
|
||||
_g->words.w1 = (uintptr_t)(d); \
|
||||
}
|
||||
|
||||
#define gsDPSetColor(c, d) \
|
||||
{ \
|
||||
_SHIFTL(c, 24, 8), (unsigned int)(d) \
|
||||
_SHIFTL(c, 24, 8), (uintptr_t)(d) \
|
||||
}
|
||||
|
||||
#define DPRGBColor(pkt, cmd, r, g, b, a) \
|
||||
@@ -2521,13 +2553,13 @@ typedef union {
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24); \
|
||||
_g->words.w1 = (unsigned int)(mode1); \
|
||||
_g->words.w1 = (uintptr_t)(mode1); \
|
||||
}
|
||||
|
||||
#define gsDPSetOtherMode(mode0, mode1) \
|
||||
{ \
|
||||
_SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \
|
||||
(unsigned int)(mode1) \
|
||||
(uintptr_t)(mode1) \
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
#define OS_M_PI 3.14159265358979323846
|
||||
#define M_DTOR (3.14159265358979323846/180.0)
|
||||
|
||||
#define FTOFIX32(x) (long)((x) * (float)0x00010000)
|
||||
#define FTOFIX32(x) (int)((x) * (float)0x00010000)
|
||||
#define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000))
|
||||
#define FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff)
|
||||
|
||||
|
||||
+12
-1
@@ -28,6 +28,7 @@ extern "C" {
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/mbi.h>
|
||||
#include "platform.h"
|
||||
|
||||
struct var8009c340 {
|
||||
u8 surround;
|
||||
@@ -256,7 +257,7 @@ typedef struct {
|
||||
ALOscStop stopOsc;
|
||||
ALSeqMarker *loopStart;
|
||||
ALSeqMarker *loopEnd;
|
||||
s32 loopCount; /* -1 = loop forever, 0 = no loop */
|
||||
intptr_t loopCount; /* -1 = loop forever, 0 = no loop */
|
||||
u8 unk88;
|
||||
u8 unk89;
|
||||
} N_ALSeqPlayer;
|
||||
@@ -284,9 +285,19 @@ typedef struct {
|
||||
ALOscInit initOsc;
|
||||
ALOscUpdate updateOsc;
|
||||
ALOscStop stopOsc;
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
s32 _pad1_;
|
||||
f32 unk7c;
|
||||
s32 _pad2_;
|
||||
f32 unk80;
|
||||
#else
|
||||
f32 unk7c;
|
||||
f32 unk80;
|
||||
#endif
|
||||
|
||||
void *queue;
|
||||
|
||||
u8 unk88;
|
||||
u8 unk89;
|
||||
} N_ALCSPlayer;
|
||||
|
||||
@@ -31,10 +31,14 @@
|
||||
#define _OS_LIBC_H_
|
||||
|
||||
#include "os_pfs.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_OSX
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LANGUAGE_C_PLUS_PLUS
|
||||
extern "C" {
|
||||
@@ -84,15 +88,20 @@ extern "C" {
|
||||
|
||||
/* byte string operations */
|
||||
|
||||
#ifndef PLATFORM_OSX
|
||||
extern void bcopy(const void *, void *, size_t);
|
||||
extern int bcmp(const void *, const void *, size_t);
|
||||
extern void bzero(void *, size_t);
|
||||
#endif
|
||||
|
||||
/* Printf */
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
extern int sprintf(char *s, const char *fmt, ...);
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
extern void osSyncPrintf(const char *fmt, ...);
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ extern "C" {
|
||||
#include <PR/ultratypes.h>
|
||||
#include "os_thread.h"
|
||||
#include "os_message.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
|
||||
|
||||
@@ -198,7 +198,7 @@ extern u32 osPiGetStatus(void);
|
||||
extern s32 osPiGetDeviceType(void);
|
||||
extern s32 osPiWriteIo(u32, u32);
|
||||
extern s32 osPiReadIo(u32, u32 *);
|
||||
extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32,
|
||||
extern s32 osPiStartDma(OSIoMesg *, s32, s32, uintptr_t, void *, u32,
|
||||
OSMesgQueue *);
|
||||
extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32);
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ 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_set_texture_filter(enum FilteringMode mode);
|
||||
void gfx_texture_cache_clear(void);
|
||||
void gfx_texture_cache_delete(const uint8_t *orig_addr);
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize);
|
||||
@@ -52,7 +52,5 @@ void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale
|
||||
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
|
||||
+296
-195
@@ -32,6 +32,7 @@ struct ShaderProgram {
|
||||
uint8_t num_attribs;
|
||||
GLint frame_count_location;
|
||||
GLint noise_scale_location;
|
||||
GLint three_point_filter_locations[2];
|
||||
};
|
||||
|
||||
struct Framebuffer {
|
||||
@@ -54,9 +55,12 @@ static std::vector<Framebuffer> framebuffers;
|
||||
static size_t current_framebuffer;
|
||||
static float current_noise_scale;
|
||||
static FilteringMode current_filter_mode = FILTER_LINEAR;
|
||||
static bool current_textures_linear_filter[2] = {false, false};
|
||||
|
||||
static int gl_glsl_version = 130;
|
||||
static char gl_glsl_version_str[16] = "130";
|
||||
static GLenum gl_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE;
|
||||
|
||||
static bool gl_es = false;
|
||||
static bool gl_core_profile = false;
|
||||
|
||||
static int gfx_opengl_get_max_texture_size() {
|
||||
@@ -94,6 +98,12 @@ static void gfx_opengl_set_uniforms(struct ShaderProgram* prg) {
|
||||
if (prg->noise_scale_location >= 0) {
|
||||
glUniform1f(prg->noise_scale_location, current_noise_scale);
|
||||
}
|
||||
if (prg->three_point_filter_locations[0] >= 0) {
|
||||
glUniform1i(prg->three_point_filter_locations[0], current_textures_linear_filter[0]);
|
||||
}
|
||||
if (prg->three_point_filter_locations[1] >= 0) {
|
||||
glUniform1i(prg->three_point_filter_locations[1], current_textures_linear_filter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_opengl_unload_shader(struct ShaderProgram* old_prg) {
|
||||
@@ -234,144 +244,138 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
size_t num_floats = 4;
|
||||
|
||||
// Vertex shader
|
||||
#ifdef __APPLE__
|
||||
append_line(vs_buf, &vs_len, "#version 410 core");
|
||||
append_line(vs_buf, &vs_len, "in vec4 aVtxPos;");
|
||||
#else
|
||||
append_line(vs_buf, &vs_len, "#version 110");
|
||||
append_line(vs_buf, &vs_len, "attribute vec4 aVtxPos;");
|
||||
#endif
|
||||
|
||||
vs_len += sprintf(vs_buf + vs_len, "#version %s\n", gl_glsl_version_str);
|
||||
|
||||
if (gl_es) {
|
||||
append_line(vs_buf, &vs_len, "precision mediump float;");
|
||||
}
|
||||
|
||||
if (gl_glsl_version >= 130) {
|
||||
append_line(vs_buf, &vs_len, "#define INPUT in");
|
||||
append_line(vs_buf, &vs_len, "#define OUTPUT out");
|
||||
} else {
|
||||
append_line(vs_buf, &vs_len, "#define INPUT attribute");
|
||||
append_line(vs_buf, &vs_len, "#define OUTPUT varying");
|
||||
}
|
||||
|
||||
append_line(vs_buf, &vs_len, "INPUT vec4 aVtxPos;");
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
#ifdef __APPLE__
|
||||
vs_len += sprintf(vs_buf + vs_len, "in vec2 aTexCoord%d;\n", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "out vec2 vTexCoord%d;\n", i);
|
||||
#else
|
||||
vs_len += sprintf(vs_buf + vs_len, "attribute vec2 aTexCoord%d;\n", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "varying vec2 vTexCoord%d;\n", i);
|
||||
#endif
|
||||
vs_len += sprintf(vs_buf + vs_len, "INPUT vec2 aTexCoord%d;\n", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec2 vTexCoord%d;\n", i);
|
||||
num_floats += 2;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (cc_features.clamp[i][j]) {
|
||||
#ifdef __APPLE__
|
||||
vs_len += sprintf(vs_buf + vs_len, "in float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "out float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
#else
|
||||
vs_len += sprintf(vs_buf + vs_len, "attribute float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
#endif
|
||||
vs_len += sprintf(vs_buf + vs_len, "INPUT float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
vs_len += sprintf(vs_buf + vs_len, "OUTPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
num_floats += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cc_features.opt_fog) {
|
||||
#ifdef __APPLE__
|
||||
append_line(vs_buf, &vs_len, "in vec4 aFog;");
|
||||
append_line(vs_buf, &vs_len, "out vec4 vFog;");
|
||||
#else
|
||||
append_line(vs_buf, &vs_len, "attribute vec4 aFog;");
|
||||
append_line(vs_buf, &vs_len, "varying vec4 vFog;");
|
||||
#endif
|
||||
append_line(vs_buf, &vs_len, "INPUT vec4 aFog;");
|
||||
append_line(vs_buf, &vs_len, "OUTPUT vec4 vFog;");
|
||||
num_floats += 4;
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
#ifdef __APPLE__
|
||||
append_line(vs_buf, &vs_len, "in vec4 aGrayscaleColor;");
|
||||
append_line(vs_buf, &vs_len, "out vec4 vGrayscaleColor;");
|
||||
#else
|
||||
append_line(vs_buf, &vs_len, "attribute vec4 aGrayscaleColor;");
|
||||
append_line(vs_buf, &vs_len, "varying vec4 vGrayscaleColor;");
|
||||
#endif
|
||||
append_line(vs_buf, &vs_len, "INPUT vec4 aGrayscaleColor;");
|
||||
append_line(vs_buf, &vs_len, "OUTPUT vec4 vGrayscaleColor;");
|
||||
num_floats += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
#ifdef __APPLE__
|
||||
vs_len += sprintf(vs_buf + vs_len, "in vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
vs_len += sprintf(vs_buf + vs_len, "out vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
#else
|
||||
vs_len += sprintf(vs_buf + vs_len, "attribute vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
#endif
|
||||
vs_len += sprintf(vs_buf + vs_len, "INPUT vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
num_floats += cc_features.opt_alpha ? 4 : 3;
|
||||
}
|
||||
|
||||
append_line(vs_buf, &vs_len, "void main() {");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
vs_len += sprintf(vs_buf + vs_len, "vTexCoord%d = aTexCoord%d;\n", i, i);
|
||||
vs_len += sprintf(vs_buf + vs_len, " vTexCoord%d = aTexCoord%d;\n", i, i);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (cc_features.clamp[i][j]) {
|
||||
vs_len += sprintf(vs_buf + vs_len, "vTexClamp%s%d = aTexClamp%s%d;\n", j == 0 ? "S" : "T", i,
|
||||
vs_len += sprintf(vs_buf + vs_len, " vTexClamp%s%d = aTexClamp%s%d;\n", j == 0 ? "S" : "T", i,
|
||||
j == 0 ? "S" : "T", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cc_features.opt_fog) {
|
||||
append_line(vs_buf, &vs_len, "vFog = aFog;");
|
||||
append_line(vs_buf, &vs_len, " vFog = aFog;");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(vs_buf, &vs_len, "vGrayscaleColor = aGrayscaleColor;");
|
||||
append_line(vs_buf, &vs_len, " vGrayscaleColor = aGrayscaleColor;");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
vs_len += sprintf(vs_buf + vs_len, "vInput%d = aInput%d;\n", i + 1, i + 1);
|
||||
vs_len += sprintf(vs_buf + vs_len, " vInput%d = aInput%d;\n", i + 1, i + 1);
|
||||
}
|
||||
|
||||
append_line(vs_buf, &vs_len, " gl_Position = aVtxPos;");
|
||||
if (!GLAD_GL_ARB_depth_clamp) {
|
||||
// HACK: workaround for no GL_DEPTH_CLAMP
|
||||
append_line(vs_buf, &vs_len, " gl_Position.z *= 0.3f;");
|
||||
}
|
||||
append_line(vs_buf, &vs_len, "gl_Position = aVtxPos;");
|
||||
append_line(vs_buf, &vs_len, "}");
|
||||
|
||||
// Fragment shader
|
||||
#ifdef __APPLE__
|
||||
append_line(fs_buf, &fs_len, "#version 410 core");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "#version 130");
|
||||
#endif
|
||||
|
||||
fs_len += sprintf(fs_buf + fs_len, "#version %s\n", gl_glsl_version_str);
|
||||
|
||||
if (gl_es) {
|
||||
append_line(fs_buf, &fs_len, "precision mediump float;");
|
||||
}
|
||||
|
||||
if (gl_glsl_version >= 130) {
|
||||
append_line(fs_buf, &fs_len, "#define INPUT in");
|
||||
append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR outColor");
|
||||
append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture(tex, uv)");
|
||||
} else {
|
||||
append_line(fs_buf, &fs_len, "#define INPUT varying");
|
||||
append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR gl_FragColor");
|
||||
append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture2D(tex, uv)");
|
||||
}
|
||||
|
||||
// Reference approach to color wrapping as per GLideN64
|
||||
// Return wrapped value of x in interval [low, high)
|
||||
append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)");
|
||||
|
||||
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(tex, uv, texSize, off) SAMPLE_TEX(tex, uv - (off)/texSize)");
|
||||
|
||||
// append_line(fs_buf, &fs_len, "precision mediump float;");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
#ifdef __APPLE__
|
||||
fs_len += sprintf(fs_buf + fs_len, "in vec2 vTexCoord%d;\n", i);
|
||||
#else
|
||||
fs_len += sprintf(fs_buf + fs_len, "varying vec2 vTexCoord%d;\n", i);
|
||||
#endif
|
||||
fs_len += sprintf(fs_buf + fs_len, "INPUT vec2 vTexCoord%d;\n", i);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (cc_features.clamp[i][j]) {
|
||||
#ifdef __APPLE__
|
||||
fs_len += sprintf(fs_buf + fs_len, "in float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
#else
|
||||
fs_len += sprintf(fs_buf + fs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
#endif
|
||||
fs_len += sprintf(fs_buf + fs_len, "INPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cc_features.opt_fog) {
|
||||
#ifdef __APPLE__
|
||||
append_line(fs_buf, &fs_len, "in vec4 vFog;");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "varying vec4 vFog;");
|
||||
#endif
|
||||
append_line(fs_buf, &fs_len, "INPUT vec4 vFog;");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
#ifdef __APPLE__
|
||||
append_line(fs_buf, &fs_len, "in vec4 vGrayscaleColor;");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "varying vec4 vGrayscaleColor;");
|
||||
#endif
|
||||
append_line(fs_buf, &fs_len, "INPUT vec4 vGrayscaleColor;");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
#ifdef __APPLE__
|
||||
fs_len += sprintf(fs_buf + fs_len, "in vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
#else
|
||||
fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
#endif
|
||||
fs_len += sprintf(fs_buf + fs_len, "INPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
}
|
||||
|
||||
if (cc_features.used_textures[0]) {
|
||||
append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;");
|
||||
if (current_filter_mode == FILTER_THREE_POINT)
|
||||
append_line(fs_buf, &fs_len, "uniform int three_point_filter0;");
|
||||
}
|
||||
if (cc_features.used_textures[1]) {
|
||||
append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;");
|
||||
if (current_filter_mode == FILTER_THREE_POINT)
|
||||
append_line(fs_buf, &fs_len, "uniform int three_point_filter1;");
|
||||
}
|
||||
|
||||
append_line(fs_buf, &fs_len, "uniform int frame_count;");
|
||||
@@ -382,92 +386,97 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
|
||||
if (current_filter_mode == FILTER_THREE_POINT) {
|
||||
append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));");
|
||||
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(tex, texCoord, texSize, offset);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x - sign(offset.x), offset.y));");
|
||||
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x, offset.y - sign(offset.y)));");
|
||||
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
}
|
||||
|
||||
if (cc_features.opt_blur) {
|
||||
// blur filter, used for menu backgrounds
|
||||
// used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it
|
||||
// used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers
|
||||
append_line(fs_buf, &fs_len, R"(
|
||||
lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) {
|
||||
lowp vec4 cw = vec4(0.0);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
vec2 xy = vec2(float(i & 3), float(i >> 2));
|
||||
lowp float w = 0.009947 - length(xy) * 0.001;
|
||||
cw += vec4(texture2D(t, uv + (vec2(-1.5) + xy) / tsize).rgb * w, w);
|
||||
}
|
||||
return vec4(cw.rgb / cw.a, 1.0);
|
||||
})"
|
||||
);
|
||||
} else if (current_filter_mode == FILTER_THREE_POINT) {
|
||||
#if __APPLE__
|
||||
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture(tex, texCoord - (off)/texSize)");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize)");
|
||||
#endif
|
||||
append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));");
|
||||
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(offset);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y));");
|
||||
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)));");
|
||||
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " return filter3point(tex, uv, texSize);");
|
||||
|
||||
if (current_filter_mode == FILTER_THREE_POINT)
|
||||
append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize, in int three_point_filter) {");
|
||||
else
|
||||
append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize) {");
|
||||
|
||||
append_line(fs_buf, &fs_len, " lowp vec4 cw = vec4(0.0);");
|
||||
append_line(fs_buf, &fs_len, " for (int i = 0; i < 16; ++i) {");
|
||||
append_line(fs_buf, &fs_len, " vec2 xy = vec2(float(i & 3), float(i >> 2));");
|
||||
append_line(fs_buf, &fs_len, " lowp float w = 0.009947 - length(xy) * 0.001;");
|
||||
append_line(fs_buf, &fs_len, " vec2 scaled_uv = uv + (vec2(-1.5) + xy) / texSize;");
|
||||
|
||||
if (current_filter_mode == FILTER_THREE_POINT)
|
||||
append_line(fs_buf, &fs_len, " lowp vec4 tex = mix(SAMPLE_TEX(t, scaled_uv), filter3point(t, scaled_uv, texSize), three_point_filter);");
|
||||
else
|
||||
append_line(fs_buf, &fs_len, " lowp vec4 tex = SAMPLE_TEX(t, scaled_uv);");
|
||||
|
||||
append_line(fs_buf, &fs_len, " cw += vec4(tex.rgb * w, w);");
|
||||
append_line(fs_buf, &fs_len, " }");
|
||||
append_line(fs_buf, &fs_len, " return vec4(cw.rgb / cw.a, 1.0);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
} else {
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
|
||||
#if __APPLE__
|
||||
append_line(fs_buf, &fs_len, " return texture(tex, uv);");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, " return texture2D(tex, uv);");
|
||||
#endif
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
if (current_filter_mode == FILTER_THREE_POINT) {
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize, in int three_point_filter) {");
|
||||
append_line(fs_buf, &fs_len, " return mix(SAMPLE_TEX(tex, uv), filter3point(tex, uv, texSize), three_point_filter);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
} else {
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " return SAMPLE_TEX(tex, uv);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
}
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
append_line(fs_buf, &fs_len, "out vec4 outColor;");
|
||||
#endif
|
||||
if (gl_glsl_version >= 130) {
|
||||
append_line(fs_buf, &fs_len, "out vec4 outColor;");
|
||||
}
|
||||
|
||||
append_line(fs_buf, &fs_len, "void main() {");
|
||||
|
||||
// Reference approach to color wrapping as per GLideN64
|
||||
// Return wrapped value of x in interval [low, high)
|
||||
append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)");
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1];
|
||||
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, " vec2 texSize%d = vec2(textureSize(uTex%d, 0));\n", i, i);
|
||||
|
||||
if (!s && !t) {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec2 vTexCoordAdj%d = vTexCoord%d;\n", i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, " vec2 vTexCoordAdj%d = vTexCoord%d;\n", i, i);
|
||||
} else {
|
||||
if (s && t) {
|
||||
fs_len += sprintf(fs_buf + fs_len,
|
||||
"vec2 vTexCoordAdj%d = clamp(vTexCoord%d, 0.5 / texSize%d, "
|
||||
" vec2 vTexCoordAdj%d = clamp(vTexCoord%d, 0.5 / texSize%d, "
|
||||
"vec2(vTexClampS%d, vTexClampT%d));\n",
|
||||
i, i, i, i, i);
|
||||
} else if (s) {
|
||||
fs_len += sprintf(fs_buf + fs_len,
|
||||
"vec2 vTexCoordAdj%d = vec2(clamp(vTexCoord%d.s, 0.5 / "
|
||||
" vec2 vTexCoordAdj%d = vec2(clamp(vTexCoord%d.s, 0.5 / "
|
||||
"texSize%d.s, vTexClampS%d), vTexCoord%d.t);\n",
|
||||
i, i, i, i, i);
|
||||
} else {
|
||||
fs_len += sprintf(fs_buf + fs_len,
|
||||
"vec2 vTexCoordAdj%d = vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, "
|
||||
" vec2 vTexCoordAdj%d = vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, "
|
||||
"0.5 / texSize%d.t, vTexClampT%d));\n",
|
||||
i, i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i);
|
||||
if (current_filter_mode == FILTER_THREE_POINT)
|
||||
fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d, three_point_filter%d);\n", i, i, i, i, i);
|
||||
else
|
||||
fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
append_line(fs_buf, &fs_len, cc_features.opt_alpha ? "vec4 texel;" : "vec3 texel;");
|
||||
append_line(fs_buf, &fs_len, cc_features.opt_alpha ? " vec4 texel;" : " vec3 texel;");
|
||||
for (int c = 0; c < (cc_features.opt_2cyc ? 2 : 1); c++) {
|
||||
append_str(fs_buf, &fs_len, "texel = ");
|
||||
append_str(fs_buf, &fs_len, " texel = ");
|
||||
if (!cc_features.color_alpha_same[c] && cc_features.opt_alpha) {
|
||||
append_str(fs_buf, &fs_len, "vec4(");
|
||||
append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0],
|
||||
@@ -484,56 +493,50 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
append_line(fs_buf, &fs_len, ";");
|
||||
|
||||
if (c == 0) {
|
||||
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -1.01, 1.01);");
|
||||
append_line(fs_buf, &fs_len, " texel = WRAP(texel, -1.01, 1.01);");
|
||||
}
|
||||
}
|
||||
|
||||
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -0.51, 1.51);");
|
||||
append_str(fs_buf, &fs_len, "texel = clamp(texel, 0.0, 1.0);");
|
||||
append_line(fs_buf, &fs_len, " texel = WRAP(texel, -0.51, 1.51);");
|
||||
append_line(fs_buf, &fs_len, " texel = clamp(texel, 0.0, 1.0);");
|
||||
// TODO discard if alpha is 0?
|
||||
if (cc_features.opt_fog) {
|
||||
if (cc_features.opt_alpha) {
|
||||
append_line(fs_buf, &fs_len, "texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);");
|
||||
append_line(fs_buf, &fs_len, " texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);");
|
||||
} else {
|
||||
append_line(fs_buf, &fs_len, "texel = mix(texel, vFog.rgb, vFog.a);");
|
||||
append_line(fs_buf, &fs_len, " texel = mix(texel, vFog.rgb, vFog.a);");
|
||||
}
|
||||
}
|
||||
|
||||
if (cc_features.opt_texture_edge && cc_features.opt_alpha) {
|
||||
append_line(fs_buf, &fs_len, "if (texel.a > 0.19) texel.a = 1.0; else discard;");
|
||||
append_line(fs_buf, &fs_len, " if (texel.a > 0.19) texel.a = 1.0; else discard;");
|
||||
}
|
||||
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(fs_buf, &fs_len,
|
||||
"texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + "
|
||||
" texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + "
|
||||
"texel.a, 0.0, 1.0));");
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(fs_buf, &fs_len, "float intensity = (texel.r + texel.g + texel.b) / 3.0;");
|
||||
append_line(fs_buf, &fs_len, "vec3 new_texel = vGrayscaleColor.rgb * intensity;");
|
||||
append_line(fs_buf, &fs_len, "texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);");
|
||||
append_line(fs_buf, &fs_len, " float intensity = (texel.r + texel.g + texel.b) / 3.0;");
|
||||
append_line(fs_buf, &fs_len, " vec3 new_texel = vGrayscaleColor.rgb * intensity;");
|
||||
append_line(fs_buf, &fs_len, " texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);");
|
||||
}
|
||||
|
||||
if (cc_features.opt_alpha) {
|
||||
if (cc_features.opt_alpha_threshold) {
|
||||
append_line(fs_buf, &fs_len, "if (texel.a < 8.0 / 256.0) discard;");
|
||||
append_line(fs_buf, &fs_len, " if (texel.a < 8.0 / 256.0) discard;");
|
||||
}
|
||||
if (cc_features.opt_invisible) {
|
||||
append_line(fs_buf, &fs_len, "texel.a = 0.0;");
|
||||
append_line(fs_buf, &fs_len, " texel.a = 0.0;");
|
||||
}
|
||||
#if __APPLE__
|
||||
append_line(fs_buf, &fs_len, "outColor = texel;");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "gl_FragColor = texel;");
|
||||
#endif
|
||||
|
||||
append_line(fs_buf, &fs_len, " OUTPUT_COLOR = texel;");
|
||||
} else {
|
||||
#if __APPLE__
|
||||
append_line(fs_buf, &fs_len, "outColor = vec4(texel, 1.0);");
|
||||
#else
|
||||
append_line(fs_buf, &fs_len, "gl_FragColor = vec4(texel, 1.0);");
|
||||
#endif
|
||||
append_line(fs_buf, &fs_len, " OUTPUT_COLOR = vec4(texel, 1.0);");
|
||||
}
|
||||
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
|
||||
vs_buf[vs_len] = '\0';
|
||||
@@ -574,6 +577,11 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
glAttachShader(shader_program, fragment_shader);
|
||||
glLinkProgram(shader_program);
|
||||
|
||||
glDetachShader(shader_program, vertex_shader);
|
||||
glDetachShader(shader_program, fragment_shader);
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
|
||||
size_t cnt = 0;
|
||||
|
||||
struct ShaderProgram* prg = &shader_program_pool[make_pair(shader_id0, shader_id1)];
|
||||
@@ -640,6 +648,8 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
|
||||
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
|
||||
prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
|
||||
prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0");
|
||||
prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1");
|
||||
|
||||
gfx_opengl_load_shader(prg);
|
||||
|
||||
@@ -657,6 +667,14 @@ static void gfx_opengl_shader_get_info(struct ShaderProgram* prg, uint8_t* num_i
|
||||
used_textures[1] = prg->used_textures[1];
|
||||
}
|
||||
|
||||
static void gfx_opengl_clear_shaders(void) {
|
||||
glUseProgram(0);
|
||||
for (auto& pair : shader_program_pool) {
|
||||
glDeleteProgram(pair.second.opengl_program_id);
|
||||
}
|
||||
shader_program_pool.clear();
|
||||
}
|
||||
|
||||
static GLuint gfx_opengl_new_texture(void) {
|
||||
GLuint ret;
|
||||
glGenTextures(1, &ret);
|
||||
@@ -667,9 +685,11 @@ static void gfx_opengl_delete_texture(uint32_t texID) {
|
||||
glDeleteTextures(1, &texID);
|
||||
}
|
||||
|
||||
static void gfx_opengl_select_texture(int tile, GLuint texture_id) {
|
||||
static void gfx_opengl_select_texture(int tile, GLuint texture_id, bool linear_filter) {
|
||||
glActiveTexture(GL_TEXTURE0 + tile);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
|
||||
current_textures_linear_filter[tile] = linear_filter;
|
||||
}
|
||||
|
||||
static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height) {
|
||||
@@ -699,28 +719,52 @@ static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt));
|
||||
}
|
||||
|
||||
static void gfx_opengl_set_depth_test_and_mask(bool depth_test, bool z_upd) {
|
||||
if (depth_test || z_upd) {
|
||||
static void gfx_opengl_set_depth_mode(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode) {
|
||||
if (depth_test) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(z_upd ? GL_TRUE : GL_FALSE);
|
||||
glDepthFunc(depth_test ? GL_LEQUAL : GL_ALWAYS);
|
||||
current_depth_mask = z_upd;
|
||||
glDepthMask(depth_update ? GL_TRUE : GL_FALSE);
|
||||
current_depth_mask = depth_update;
|
||||
|
||||
if (depth_compare) {
|
||||
switch (zmode) {
|
||||
case ZMODE_INTER:
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0, 0);
|
||||
break;
|
||||
|
||||
case ZMODE_OPA:
|
||||
case ZMODE_XLU:
|
||||
if (depth_source_prim) {
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
} else {
|
||||
glDepthFunc(GL_LESS);
|
||||
}
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0, 0);
|
||||
break;
|
||||
|
||||
case ZMODE_DEC:
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-2, -2);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0, 0);
|
||||
}
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_opengl_set_depth_range(float znear, float zfar) {
|
||||
glDepthRange(znear, zfar);
|
||||
}
|
||||
|
||||
static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
|
||||
if (zmode_decal) {
|
||||
glPolygonOffset(-2, -2);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
if (glDepthRangef) {
|
||||
glDepthRangef(znear, zfar);
|
||||
} else {
|
||||
glPolygonOffset(0, 0);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDepthRange(znear, zfar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,18 +835,6 @@ static bool gfx_opengl_supports_framebuffers(void) {
|
||||
return (glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample);
|
||||
}
|
||||
if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) {
|
||||
// because of the way glad works we'll have to copy the pointers over
|
||||
glad_glGenFramebuffers = glad_glGenFramebuffersEXT;
|
||||
glad_glGenRenderbuffers = glad_glGenRenderbuffersEXT;
|
||||
glad_glDeleteFramebuffers = glad_glDeleteFramebuffersEXT;
|
||||
glad_glDeleteRenderbuffers = glad_glDeleteRenderbuffersEXT;
|
||||
glad_glBindFramebuffer = glad_glBindFramebufferEXT;
|
||||
glad_glBindRenderbuffer = glad_glBindRenderbufferEXT;
|
||||
glad_glFramebufferRenderbuffer = glad_glFramebufferRenderbufferEXT;
|
||||
glad_glFramebufferTexture2D = glad_glFramebufferTexture2DEXT;
|
||||
glad_glRenderbufferStorage = glad_glRenderbufferStorageEXT;
|
||||
glad_glRenderbufferStorageMultisample = glad_glRenderbufferStorageMultisampleEXT;
|
||||
glad_glBlitFramebuffer = glad_glBlitFramebufferEXT;
|
||||
// sanity check
|
||||
return (glad_glFramebufferRenderbuffer && glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample);
|
||||
}
|
||||
@@ -867,11 +899,52 @@ static void *gl_load_proc(const char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void gfx_opengl_init_extensions(void) {
|
||||
// patch up some extension values and pointers
|
||||
if (!GLAD_GL_ARB_depth_clamp) {
|
||||
if (GLAD_GL_EXT_depth_clamp || GLAD_GL_NV_depth_clamp) {
|
||||
GLAD_GL_ARB_depth_clamp = 1;
|
||||
} else if (!gl_es && GLVersion.major >= 3) {
|
||||
// GL3.2+ should have depth_clamp as part of the spec, but some devices don't report it for some reason
|
||||
GLAD_GL_ARB_depth_clamp = (GLVersion.major > 3 || (GLVersion.major == 3 && GLVersion.minor >= 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) {
|
||||
GLAD_GL_ARB_texture_mirror_clamp_to_edge = GLAD_GL_EXT_texture_mirror_clamp_to_edge;
|
||||
}
|
||||
|
||||
if (GLVersion.major < 3 && !GLAD_GL_ARB_framebuffer_object) {
|
||||
if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) {
|
||||
// because of the way glad works we'll have to copy the pointers over
|
||||
glad_glGenFramebuffers = glad_glGenFramebuffersEXT;
|
||||
glad_glGenRenderbuffers = glad_glGenRenderbuffersEXT;
|
||||
glad_glDeleteFramebuffers = glad_glDeleteFramebuffersEXT;
|
||||
glad_glDeleteRenderbuffers = glad_glDeleteRenderbuffersEXT;
|
||||
glad_glBindFramebuffer = glad_glBindFramebufferEXT;
|
||||
glad_glBindRenderbuffer = glad_glBindRenderbufferEXT;
|
||||
glad_glFramebufferRenderbuffer = glad_glFramebufferRenderbufferEXT;
|
||||
glad_glFramebufferTexture2D = glad_glFramebufferTexture2DEXT;
|
||||
glad_glRenderbufferStorage = glad_glRenderbufferStorageEXT;
|
||||
glad_glRenderbufferStorageMultisample = glad_glRenderbufferStorageMultisampleEXT;
|
||||
glad_glBlitFramebuffer = glad_glBlitFramebufferEXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_opengl_init(void) {
|
||||
if (!gladLoadGLLoader(gl_load_proc) || glGetString == NULL || glEnable == NULL) {
|
||||
sysFatalError("Could not load OpenGL.\nReported SDL error: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
// check if we're using ES or core, which have more limited feature sets
|
||||
int val = 0;
|
||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &val);
|
||||
gl_core_profile = (val == SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
gl_es = (val == SDL_GL_CONTEXT_PROFILE_ES);
|
||||
|
||||
gfx_opengl_init_extensions();
|
||||
|
||||
if (sysArgCheck("--debug-gl")) {
|
||||
gfx_opengl_enable_debug();
|
||||
// dump version info as early as possible
|
||||
@@ -885,7 +958,7 @@ static void gfx_opengl_init(void) {
|
||||
}
|
||||
|
||||
if (!gfx_opengl_supports_shaders()) {
|
||||
sysLogPrintf(LOG_WARNING, "GL: GLSL 1.30 unsupported");
|
||||
sysLogPrintf(LOG_WARNING, "GL: GLSL 1.30 may be unsupported");
|
||||
// maybe replace this with sysFatalError, though the GLSL compiler will cause that later anyway
|
||||
}
|
||||
|
||||
@@ -901,20 +974,35 @@ static void gfx_opengl_init(void) {
|
||||
gl_mirror_clamp = GL_MIRRORED_REPEAT;
|
||||
}
|
||||
|
||||
if ((GLVersion.major == 3 && GLVersion.minor >= 2) || GLVersion.major > 3) {
|
||||
// check if we're using core profile, which is more strict
|
||||
int val = 0;
|
||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &val);
|
||||
gl_core_profile = (val == SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
// determine GLSL version
|
||||
if (gl_es) {
|
||||
// ES has its own numbering scheme, but it should support 300 even on 3.1 and 3.2
|
||||
gl_glsl_version = 300;
|
||||
snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d es", gl_glsl_version);
|
||||
} else if (!gl_core_profile) {
|
||||
// in compat profile we can just request the lowest possible
|
||||
gl_glsl_version = 130;
|
||||
snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d", gl_glsl_version);
|
||||
} else {
|
||||
// otherwise we have to pick a specific version
|
||||
if (GLVersion.major == 3 && GLVersion.minor == 2) {
|
||||
// 3.2core is the earliest core version and it follows the old numbering scheme
|
||||
gl_glsl_version = 150;
|
||||
} else {
|
||||
// 3.3+ follow the new numbering scheme
|
||||
gl_glsl_version = GLVersion.major * 100 + GLVersion.minor * 10;
|
||||
}
|
||||
snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d core", gl_glsl_version);
|
||||
}
|
||||
sysLogPrintf(LOG_NOTE, "GL: using GLSL version %s", gl_glsl_version_str);
|
||||
|
||||
glGenBuffers(1, &opengl_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
|
||||
|
||||
if (gl_core_profile) {
|
||||
if (gl_core_profile || gl_es) {
|
||||
// warn user that funny things can happen
|
||||
sysLogPrintf(LOG_WARNING, "GL: using core profile, watch out for errors");
|
||||
// core will explode if we don't use a VAO for our VBO
|
||||
sysLogPrintf(LOG_WARNING, "GL: using core profile or ES, watch out for errors");
|
||||
// core/es will explode if we don't use a VAO for our VBO
|
||||
glGenVertexArrays(1, &opengl_vao);
|
||||
glBindVertexArray(opengl_vao);
|
||||
}
|
||||
@@ -1045,12 +1133,23 @@ bool gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_opengl_clear_framebuffer() {
|
||||
void gfx_opengl_clear_framebuffer(bool clear_color, bool clear_depth) {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
|
||||
|
||||
GLbitfield mask = 0;
|
||||
if (clear_color) {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
mask |= GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
if (clear_depth) {
|
||||
glDepthMask(GL_TRUE);
|
||||
mask |= GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
glClear(mask);
|
||||
if (clear_depth) {
|
||||
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
@@ -1078,6 +1177,8 @@ void gfx_opengl_select_texture_fb(int fb_id) {
|
||||
// glDisable(GL_DEPTH_TEST);
|
||||
glActiveTexture(GL_TEXTURE0 + 0);
|
||||
glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf);
|
||||
|
||||
current_textures_linear_filter[0] = true;
|
||||
}
|
||||
|
||||
void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back) {
|
||||
@@ -1120,7 +1221,8 @@ void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool
|
||||
}
|
||||
|
||||
if (fb_src == 0) {
|
||||
glReadBuffer(use_back ? GL_BACK : GL_FRONT);
|
||||
// GLES does not support GL_FRONT here
|
||||
glReadBuffer((use_back || gl_es) ? GL_BACK : GL_FRONT);
|
||||
} else {
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
}
|
||||
@@ -1136,7 +1238,6 @@ void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool
|
||||
|
||||
void gfx_opengl_set_texture_filter(FilteringMode mode) {
|
||||
current_filter_mode = mode;
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
FilteringMode gfx_opengl_get_texture_filter(void) {
|
||||
@@ -1152,13 +1253,13 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
||||
gfx_opengl_create_and_load_new_shader,
|
||||
gfx_opengl_lookup_shader,
|
||||
gfx_opengl_shader_get_info,
|
||||
gfx_opengl_clear_shaders,
|
||||
gfx_opengl_new_texture,
|
||||
gfx_opengl_select_texture,
|
||||
gfx_opengl_upload_texture,
|
||||
gfx_opengl_set_sampler_parameters,
|
||||
gfx_opengl_set_depth_test_and_mask,
|
||||
gfx_opengl_set_depth_mode,
|
||||
gfx_opengl_set_depth_range,
|
||||
gfx_opengl_set_zmode_decal,
|
||||
gfx_opengl_set_viewport,
|
||||
gfx_opengl_set_scissor,
|
||||
gfx_opengl_set_use_alpha,
|
||||
|
||||
+72
-69
@@ -125,8 +125,6 @@ static struct RSP {
|
||||
float aspect_ofs;
|
||||
float aspect_scale;
|
||||
|
||||
float depth_zfar;
|
||||
|
||||
struct {
|
||||
// U0.16
|
||||
uint16_t s, t;
|
||||
@@ -194,12 +192,13 @@ static struct RDP {
|
||||
bool viewport_or_scissor_changed;
|
||||
void* z_buf_address;
|
||||
void* color_image_address;
|
||||
|
||||
int16_t subpixel_ofs_x;
|
||||
int16_t subpixel_ofs_y;
|
||||
} rdp;
|
||||
|
||||
static struct RenderingState {
|
||||
uint8_t depth_test_and_mask; // 1: depth test, 2: depth mask
|
||||
float depth_zfar;
|
||||
bool decal_mode;
|
||||
uint8_t depth_mode;
|
||||
bool alpha_blend;
|
||||
bool modulate;
|
||||
struct XYWidthHeight viewport, scissor;
|
||||
@@ -523,7 +522,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
|
||||
TextureCacheNode** n = &rendering_state.textures[i];
|
||||
|
||||
if (it != gfx_texture_cache.map.end()) {
|
||||
gfx_rapi->select_texture(i, it->second.texture_id);
|
||||
gfx_rapi->select_texture(i, it->second.texture_id, it->second.linear_filter);
|
||||
*n = &*it;
|
||||
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru,
|
||||
it->second.lru_location); // move to back
|
||||
@@ -551,7 +550,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
|
||||
node->second.texture_id = texture_id;
|
||||
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
|
||||
|
||||
gfx_rapi->select_texture(i, texture_id);
|
||||
gfx_rapi->select_texture(i, texture_id, false);
|
||||
gfx_rapi->set_sampler_parameters(i, false, 0, 0);
|
||||
*n = node;
|
||||
return false;
|
||||
@@ -1240,25 +1239,18 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
}
|
||||
}
|
||||
|
||||
bool depth_test = (rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER;
|
||||
bool depth_mask = (rdp.other_mode_l & Z_UPD) == Z_UPD;
|
||||
uint8_t depth_test_and_mask = (depth_test ? 1 : 0) | (depth_mask ? 2 : 0);
|
||||
if (depth_test_and_mask != rendering_state.depth_test_and_mask) {
|
||||
gfx_flush();
|
||||
gfx_rapi->set_depth_test_and_mask(depth_test, depth_mask);
|
||||
rendering_state.depth_test_and_mask = depth_test_and_mask;
|
||||
}
|
||||
if (rsp.depth_zfar != rendering_state.depth_zfar) {
|
||||
gfx_flush();
|
||||
gfx_rapi->set_depth_range(0.0f, rsp.depth_zfar);
|
||||
rendering_state.depth_zfar = rsp.depth_zfar;
|
||||
}
|
||||
bool depth_test = ((rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER || (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM) &&
|
||||
((rdp.other_mode_h & G_CYC_1CYCLE) == G_CYC_1CYCLE || (rdp.other_mode_h & G_CYC_2CYCLE) == G_CYC_2CYCLE);
|
||||
bool depth_update = (rdp.other_mode_l & Z_UPD) == Z_UPD;
|
||||
bool depth_compare = (rdp.other_mode_l & Z_CMP) == Z_CMP;
|
||||
bool depth_source_prim = (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM /* && gDP.primDepth.z == 1.0f */;
|
||||
uint16_t zmode = rdp.other_mode_l & ZMODE_DEC;
|
||||
uint8_t depth_mode = (depth_test ? 1 : 0) | (depth_update ? 2 : 0) | (depth_compare ? 4 : 0) | (depth_source_prim ? 8 : 0) | (zmode >> 6);
|
||||
|
||||
bool zmode_decal = (rdp.other_mode_l & ZMODE_DEC) == ZMODE_DEC;
|
||||
if (zmode_decal != rendering_state.decal_mode) {
|
||||
if (depth_mode != rendering_state.depth_mode) {
|
||||
gfx_flush();
|
||||
gfx_rapi->set_zmode_decal(zmode_decal);
|
||||
rendering_state.decal_mode = zmode_decal;
|
||||
gfx_rapi->set_depth_mode(depth_test, depth_update, depth_compare, depth_source_prim, zmode);
|
||||
rendering_state.depth_mode = depth_mode;
|
||||
}
|
||||
|
||||
if (rdp.viewport_or_scissor_changed) {
|
||||
@@ -1584,7 +1576,7 @@ static inline void gfx_sp_tri4(Gfx *cmd) {
|
||||
uint8_t x = C1(0, 4);
|
||||
uint8_t y = C1(4, 4);
|
||||
uint8_t z = C0(0, 4);
|
||||
|
||||
|
||||
if(x || y || z) {
|
||||
gfx_sp_tri1(x, y, z, false);
|
||||
}
|
||||
@@ -1648,34 +1640,27 @@ static void gfx_sp_extra_geometry_mode(uint32_t clear, uint32_t set) {
|
||||
}
|
||||
|
||||
static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area, bool preserve_aspect = false) {
|
||||
if (!fbActive) {
|
||||
area->width *= RATIO_X;
|
||||
area->x *= RATIO_X;
|
||||
area->height *= RATIO_Y;
|
||||
area->y = SCREEN_HEIGHT - area->y;
|
||||
area->y *= RATIO_Y;
|
||||
if (preserve_aspect) {
|
||||
// preserve native aspect ratio
|
||||
const float ratio = gfx_current_native_aspect / gfx_current_dimensions.aspect_ratio;
|
||||
const float midx = gfx_current_dimensions.width * 0.5f;
|
||||
area->x = midx + (area->x - midx) * ratio;
|
||||
area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f;
|
||||
area->width *= ratio;
|
||||
}
|
||||
// HACK: assume all target framebuffers have the same aspect
|
||||
area->width *= RATIO_X;
|
||||
area->x *= RATIO_X;
|
||||
area->height *= RATIO_Y;
|
||||
area->y = SCREEN_HEIGHT - area->y;
|
||||
area->y *= RATIO_Y;
|
||||
if (preserve_aspect) {
|
||||
// preserve native aspect ratio
|
||||
const float ratio = gfx_current_native_aspect / gfx_current_dimensions.aspect_ratio;
|
||||
const float midx = gfx_current_dimensions.width * 0.5f;
|
||||
area->x = midx + (area->x - midx) * ratio;
|
||||
area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f;
|
||||
area->width *= ratio;
|
||||
}
|
||||
|
||||
if (!game_renders_to_framebuffer ||
|
||||
(gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width &&
|
||||
gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
|
||||
area->x += gfx_current_game_window_viewport.x;
|
||||
area->y += gfx_current_window_dimensions.height -
|
||||
(gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
|
||||
}
|
||||
} else {
|
||||
area->width *= RATIO_Y;
|
||||
area->height *= RATIO_Y;
|
||||
area->x *= RATIO_Y;
|
||||
area->y = active_fb->second.orig_height - area->y;
|
||||
area->y *= RATIO_Y;
|
||||
if (!game_renders_to_framebuffer ||
|
||||
(gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width &&
|
||||
gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
|
||||
area->x += gfx_current_game_window_viewport.x;
|
||||
area->y += gfx_current_window_dimensions.height -
|
||||
(gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1733,18 +1718,6 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
|
||||
case G_MW_SEGMENT:
|
||||
segmentPointers[(offset >> 2) & 0xff] = data;
|
||||
break;
|
||||
case G_MW_PERSPNORM:
|
||||
// the default z range is around [100, 10000]
|
||||
// data is 2 / (znear + zfar) represented as a 0.16 fixed point
|
||||
// => (znear + zfar) = (2 / (data / 65536)) = 131072 / data
|
||||
constexpr float full_range_mul = 1.f / 11000.f; // that's around the biggest value I got when testing
|
||||
if (data == 0) {
|
||||
rsp.depth_zfar = 1.f;
|
||||
} else {
|
||||
// sometimes this will overshoot 1 but GL can handle that
|
||||
rsp.depth_zfar =((131072.f * full_range_mul) / (float)data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,6 +1972,11 @@ static void gfx_dp_set_fill_color(uint32_t packed_color) {
|
||||
rdp.fill_color.a = a * 255;
|
||||
}
|
||||
|
||||
static void gfx_dp_set_subpixel_offset(int16_t x, int16_t y) {
|
||||
rdp.subpixel_ofs_x = x;
|
||||
rdp.subpixel_ofs_y = y;
|
||||
}
|
||||
|
||||
static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) {
|
||||
uint32_t saved_other_mode_h = rdp.other_mode_h;
|
||||
uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE));
|
||||
@@ -2007,6 +1985,11 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr
|
||||
rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT;
|
||||
}
|
||||
|
||||
ulx += rdp.subpixel_ofs_x;
|
||||
lrx += rdp.subpixel_ofs_x;
|
||||
uly += rdp.subpixel_ofs_y;
|
||||
lry += rdp.subpixel_ofs_y;
|
||||
|
||||
// U10.2 coordinates
|
||||
float ulxf = ulx;
|
||||
float ulyf = uly;
|
||||
@@ -2391,6 +2374,10 @@ static void gfx_run_dl(Gfx* cmd) {
|
||||
break;
|
||||
// G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard
|
||||
// G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1
|
||||
case G_SETSUBPIXELOFFSET_EXT: {
|
||||
gfx_dp_set_subpixel_offset(C0(0, 16), C1(0, 16));
|
||||
break;
|
||||
}
|
||||
case G_TEXRECT:
|
||||
case G_TEXRECTFLIP: {
|
||||
int32_t lrx, lry, tile, ulx, uly;
|
||||
@@ -2504,6 +2491,10 @@ static void gfx_run_dl(Gfx* cmd) {
|
||||
case G_RDPFLUSH_EXT:
|
||||
gfx_flush();
|
||||
break;
|
||||
case G_CLEAR_DEPTH_EXT:
|
||||
gfx_flush();
|
||||
gfx_rapi->clear_framebuffer(false, true);
|
||||
break;
|
||||
case G_RDPPIPESYNC:
|
||||
case G_RDPFULLSYNC:
|
||||
case G_RDPLOADSYNC:
|
||||
@@ -2554,8 +2545,6 @@ extern "C" void gfx_init(const GfxInitSettings *settings) {
|
||||
tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4);
|
||||
}
|
||||
|
||||
rsp.depth_zfar = 1.0f;
|
||||
|
||||
rsp.lookat[0].dir[0] = rsp.lookat[1].dir[1] = 0x7F;
|
||||
rsp.current_lookat_coeffs[0][0] = rsp.current_lookat_coeffs[1][1] = 1.f;
|
||||
rsp.lookat_enabled = true;
|
||||
@@ -2661,7 +2650,7 @@ extern "C" void gfx_run(Gfx* commands) {
|
||||
gfx_rapi->start_frame();
|
||||
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0,
|
||||
(float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
gfx_rapi->clear_framebuffer(true, false);
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
rendering_state.viewport = {};
|
||||
rendering_state.scissor = {};
|
||||
@@ -2671,7 +2660,7 @@ extern "C" void gfx_run(Gfx* commands) {
|
||||
|
||||
if (game_renders_to_framebuffer) {
|
||||
gfx_rapi->start_draw_to_framebuffer(0, 1);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
gfx_rapi->clear_framebuffer(true, true);
|
||||
|
||||
if (gfx_msaa_level > 1) {
|
||||
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width ||
|
||||
@@ -2703,6 +2692,18 @@ extern "C" void gfx_set_target_fps(int fps) {
|
||||
gfx_wapi->set_target_fps(fps);
|
||||
}
|
||||
|
||||
extern "C" void gfx_set_texture_filter(enum FilteringMode mode) {
|
||||
gfx_texture_cache_clear();
|
||||
if (rendering_state.shader_program) {
|
||||
gfx_rapi->unload_shader(rendering_state.shader_program);
|
||||
rendering_state.shader_program = nullptr;
|
||||
}
|
||||
gfx_rapi->clear_shaders();
|
||||
color_combiner_pool.clear();
|
||||
prev_combiner = color_combiner_pool.end();
|
||||
gfx_rapi->set_texture_filter(mode);
|
||||
}
|
||||
|
||||
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) {
|
||||
int fb = gfx_rapi->create_framebuffer();
|
||||
gfx_resize_framebuffer(fb, width, height, upscale, autoresize);
|
||||
@@ -2734,7 +2735,8 @@ extern "C" void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height,
|
||||
|
||||
extern "C" void gfx_set_framebuffer(int fb, float noise_scale) {
|
||||
gfx_rapi->start_draw_to_framebuffer(fb, noise_scale);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
gfx_rapi->clear_framebuffer(true, true);
|
||||
active_fb = framebuffers.find(fb);
|
||||
}
|
||||
|
||||
extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back) {
|
||||
@@ -2759,4 +2761,5 @@ extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top,
|
||||
|
||||
extern "C" void gfx_reset_framebuffer(void) {
|
||||
gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
active_fb = framebuffers.end();
|
||||
}
|
||||
@@ -23,13 +23,13 @@ struct GfxRenderingAPI {
|
||||
struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
|
||||
struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1);
|
||||
void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]);
|
||||
void (*clear_shaders)(void);
|
||||
uint32_t (*new_texture)(void);
|
||||
void (*select_texture)(int tile, uint32_t texture_id);
|
||||
void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter);
|
||||
void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height);
|
||||
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
|
||||
void (*set_depth_test_and_mask)(bool depth_test, bool z_upd);
|
||||
void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode);
|
||||
void (*set_depth_range)(float znear, float zfar);
|
||||
void (*set_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);
|
||||
@@ -45,7 +45,7 @@ struct GfxRenderingAPI {
|
||||
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 (*clear_framebuffer)(bool clear_color, bool clear_depth);
|
||||
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
|
||||
void* (*get_framebuffer_texture_id)(int fb_id);
|
||||
void (*select_texture_fb)(int fb_id);
|
||||
|
||||
+150
-29
@@ -30,10 +30,30 @@ 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;
|
||||
static int32_t gfx_sdl_get_maximized_state(void) {
|
||||
return (int32_t)maximized_state;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_fullscreen_state(void) {
|
||||
return (int32_t)fullscreen_state;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_fullscreen_flag_mode(void) {
|
||||
return fullscreen_flag == SDL_WINDOW_FULLSCREEN_DESKTOP ? 0 : 1;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen_flag(int32_t mode) {
|
||||
switch (mode) {
|
||||
case 0: {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
} break;
|
||||
case 1: {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_fullscreen(bool on, bool call_callback) {
|
||||
fullscreen_state = on;
|
||||
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
|
||||
if (call_callback && on_fullscreen_changed_callback) {
|
||||
@@ -42,9 +62,6 @@ static void set_fullscreen(bool on, bool call_callback) {
|
||||
}
|
||||
|
||||
static void set_maximize_window(bool on) {
|
||||
if (maximized_state == on) {
|
||||
return;
|
||||
}
|
||||
maximized_state = on;
|
||||
if (on) {
|
||||
SDL_MaximizeWindow(wnd);
|
||||
@@ -83,7 +100,6 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
|
||||
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);
|
||||
}
|
||||
@@ -96,11 +112,19 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
|
||||
posY = 100;
|
||||
}
|
||||
|
||||
if (set->centered) {
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetCurrentDisplayMode(0, &mode);
|
||||
posX = mode.w / 2 - window_width / 2;
|
||||
posY = mode.h / 2 - window_height / 2;
|
||||
}
|
||||
|
||||
if (set->fullscreen_is_exclusive) {
|
||||
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
|
||||
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
|
||||
// we will unhide the window once the GL context is successfully created
|
||||
Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
|
||||
|
||||
// if fullscreen was requested, start the window in fullscreen right away
|
||||
if (set->fullscreen) {
|
||||
@@ -119,28 +143,25 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
|
||||
}
|
||||
#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 },
|
||||
{ 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 3.0: default, has all the features required
|
||||
{ 4, 1, SDL_GL_CONTEXT_PROFILE_CORE }, // 4.1core: macs only have core profile and this is the latest
|
||||
{ 3, 2, SDL_GL_CONTEXT_PROFILE_CORE }, // 3.2core: older macs will only have this at best
|
||||
{ 3, 0, SDL_GL_CONTEXT_PROFILE_ES }, // es3: don't really support ES properly, but we can try
|
||||
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 2.1: absolute last resort, will still require GLSL130 as an extension
|
||||
};
|
||||
|
||||
u32 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;
|
||||
(strstr(verstr, "es") ? SDL_GL_CONTEXT_PROFILE_ES :
|
||||
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]);
|
||||
if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) {
|
||||
verstart = 0;
|
||||
@@ -148,31 +169,44 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
|
||||
}
|
||||
|
||||
ctx = NULL;
|
||||
u32 vmin = 0, vmaj = 0;
|
||||
for (u32 i = verstart; i < verend; ++i) {
|
||||
u32 vmin = 0, vmaj = 0, vprof = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
|
||||
const char *vprofstr = "";
|
||||
for (u32 i = verstart; i < verend && !ctx; ++i) {
|
||||
vmaj = glver[i][0];
|
||||
vmin = glver[i][1];
|
||||
vprof = glver[i][2];
|
||||
vprofstr = (vprof == SDL_GL_CONTEXT_PROFILE_CORE ? "core" :
|
||||
(vprof == SDL_GL_CONTEXT_PROFILE_ES ? "es" : ""));
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, glver[i][2]);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, vprof);
|
||||
|
||||
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
|
||||
if (!wnd) {
|
||||
sysLogPrintf(LOG_WARNING, "SDL: could not open SDL window for GL%d.%d%s:\n%s", vmaj, vmin, vprofstr, SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx = SDL_GL_CreateContext(wnd);
|
||||
if (!ctx) {
|
||||
sysLogPrintf(LOG_WARNING, "GL: could not create GL%d.%d context: %s", vmaj, vmin, SDL_GetError());
|
||||
} else {
|
||||
glcore = (glver[i][2] == SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
break;
|
||||
sysLogPrintf(LOG_WARNING, "SDL: could not create GL%d.%d%s context: %s", vmaj, vmin, vprofstr, SDL_GetError());
|
||||
SDL_DestroyWindow(wnd);
|
||||
wnd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
sysFatalError("Could not create an OpenGL context of any supported version.\nSDL error: %s", SDL_GetError());
|
||||
if (!wnd || !ctx) {
|
||||
sysFatalError("Could not open SDL window with an OpenGL context of any supported version:\n%s", SDL_GetError());
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "GL: created GL%d.%d%s context", vmaj, vmin, glcore ? "core" : "");
|
||||
sysLogPrintf(LOG_NOTE, "SDL: created GL%d.%d%s context", vmaj, vmin, vprofstr);
|
||||
}
|
||||
|
||||
SDL_GL_MakeCurrent(wnd, ctx);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
SDL_ShowWindow(wnd);
|
||||
|
||||
qpc_freq = SDL_GetPerformanceFrequency();
|
||||
}
|
||||
|
||||
@@ -212,6 +246,43 @@ static void gfx_sdl_set_cursor_visibility(bool visible) {
|
||||
}
|
||||
}
|
||||
|
||||
static void get_centered_positions_native(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetDesktopDisplayMode(disp_idx, &mode);
|
||||
*posX = mode.w / 2 - width / 2;
|
||||
*posY = mode.h / 2 - height / 2;
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_centered_positions(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode mode = {};
|
||||
SDL_GetCurrentDisplayMode(disp_idx, &mode);
|
||||
*posX = mode.w / 2 - width / 2;
|
||||
*posY = mode.h / 2 - height / 2;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_closest_resolution(int32_t width, int32_t height, bool should_center) {
|
||||
const SDL_DisplayMode mode = {.w = width, .h = height};
|
||||
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode closest = {};
|
||||
if (SDL_GetClosestDisplayMode(disp_idx, &mode, &closest)) {
|
||||
SDL_SetWindowDisplayMode(wnd, &closest);
|
||||
SDL_SetWindowSize(wnd, closest.w, closest.h);
|
||||
if (should_center) {
|
||||
int32_t posX = 0;
|
||||
int32_t posY = 0;
|
||||
get_centered_positions_native(closest.w, closest.h, &posX, &posY);
|
||||
SDL_SetWindowPosition(wnd, posX, posY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_dimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) {
|
||||
SDL_SetWindowSize(wnd, width, height);
|
||||
SDL_SetWindowPosition(wnd, posX, posY);
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) {
|
||||
SDL_GL_GetDrawableSize(wnd, static_cast<int*>((void*)width), static_cast<int*>((void*)height));
|
||||
SDL_GetWindowPosition(wnd, static_cast<int*>(posX), static_cast<int*>(posY));
|
||||
@@ -230,6 +301,9 @@ static void gfx_sdl_handle_events(void) {
|
||||
case SDL_WINDOWEVENT:
|
||||
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);
|
||||
if (!fullscreen_state) {
|
||||
maximized_state = SDL_GetWindowFlags(wnd) & SDL_WINDOW_MAXIMIZED ? true : false;
|
||||
}
|
||||
} else if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
|
||||
event.window.windowID == SDL_GetWindowID(wnd)) {
|
||||
// We listen specifically for main window close because closing main window
|
||||
@@ -294,6 +368,10 @@ static double gfx_sdl_get_time(void) {
|
||||
return SDL_GetPerformanceCounter() / (double)qpc_freq;
|
||||
}
|
||||
|
||||
static int32_t gfx_sdl_get_target_fps(void) {
|
||||
return target_fps;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_target_fps(int fps) {
|
||||
target_fps = fps;
|
||||
}
|
||||
@@ -310,6 +388,10 @@ static void gfx_sdl_set_window_title(const char *title) {
|
||||
SDL_SetWindowTitle(wnd, title);
|
||||
}
|
||||
|
||||
static int gfx_sdl_get_swap_interval(void) {
|
||||
return SDL_GL_GetSwapInterval();
|
||||
}
|
||||
|
||||
static bool gfx_sdl_set_swap_interval(int interval) {
|
||||
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
|
||||
vsync_enabled = success && (interval != 0);
|
||||
@@ -319,24 +401,63 @@ static bool gfx_sdl_set_swap_interval(int interval) {
|
||||
return success;
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
int gfx_sdl_get_display_mode(int modenum, int *out_w, int *out_h) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode sdlmode;
|
||||
if (SDL_GetDisplayMode(display_in_use, modenum, &sdlmode) == 0) {
|
||||
*out_w = sdlmode.w;
|
||||
*out_h = sdlmode.h;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfx_sdl_get_current_display_mode(int *out_w, int *out_h) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
SDL_DisplayMode sdlmode;
|
||||
if (SDL_GetCurrentDisplayMode(display_in_use, &sdlmode) == 0) {
|
||||
*out_w = sdlmode.w;
|
||||
*out_h = sdlmode.h;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfx_sdl_get_num_display_modes(void) {
|
||||
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
return SDL_GetNumDisplayModes(display_in_use);
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_init,
|
||||
gfx_sdl_close,
|
||||
gfx_sdl_get_display_mode,
|
||||
gfx_sdl_get_current_display_mode,
|
||||
gfx_sdl_get_num_display_modes,
|
||||
gfx_sdl_get_fullscreen_state,
|
||||
gfx_sdl_set_fullscreen_changed_callback,
|
||||
gfx_sdl_set_fullscreen,
|
||||
gfx_sdl_set_fullscreen_exclusive,
|
||||
gfx_sdl_set_fullscreen_flag,
|
||||
gfx_sdl_get_fullscreen_flag_mode,
|
||||
gfx_sdl_get_maximized_state,
|
||||
gfx_sdl_set_maximize_window,
|
||||
gfx_sdl_get_active_window_refresh_rate,
|
||||
gfx_sdl_set_cursor_visibility,
|
||||
gfx_sdl_set_closest_resolution,
|
||||
gfx_sdl_set_dimensions,
|
||||
gfx_sdl_get_dimensions,
|
||||
gfx_sdl_get_centered_positions,
|
||||
gfx_sdl_handle_events,
|
||||
gfx_sdl_start_frame,
|
||||
gfx_sdl_swap_buffers_begin,
|
||||
gfx_sdl_swap_buffers_end,
|
||||
gfx_sdl_get_time,
|
||||
gfx_sdl_get_target_fps,
|
||||
gfx_sdl_set_target_fps,
|
||||
gfx_sdl_can_disable_vsync,
|
||||
gfx_sdl_get_window_handle,
|
||||
gfx_sdl_set_window_title,
|
||||
gfx_sdl_get_swap_interval,
|
||||
gfx_sdl_set_swap_interval,
|
||||
};
|
||||
@@ -13,28 +13,41 @@ struct GfxWindowInitSettings {
|
||||
bool fullscreen;
|
||||
bool fullscreen_is_exclusive;
|
||||
bool maximized;
|
||||
bool centered;
|
||||
bool allow_hidpi;
|
||||
};
|
||||
|
||||
struct GfxWindowManagerAPI {
|
||||
void (*init)(const struct GfxWindowInitSettings *settings);
|
||||
void (*close)(void);
|
||||
int (*get_display_mode)(int modenum, int *out_w, int *out_h);
|
||||
int (*get_current_display_mode)(int *out_w, int *out_h);
|
||||
int (*get_num_display_modes)(void);
|
||||
int32_t (*get_fullscreen_state)(void);
|
||||
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
|
||||
void (*set_fullscreen)(bool enable);
|
||||
void (*set_fullscreen_exclusive)(bool exc);
|
||||
void (*set_fullscreen_flag)(int32_t mode);
|
||||
int32_t (*get_fullscreen_flag_mode)(void);
|
||||
int32_t (*get_maximized_state)(void);
|
||||
void (*set_maximize)(bool enable);
|
||||
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
|
||||
void (*set_cursor_visibility)(bool visible);
|
||||
void (*set_closest_resolution)(int32_t width, int32_t height, bool should_center);
|
||||
void (*set_dimensions)(uint32_t width, uint32_t height, int32_t posX, int32_t posY);
|
||||
void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
|
||||
void (*get_centered_positions)(int32_t width, int32_t height, int32_t *posX, int32_t *posY);
|
||||
void (*handle_events)(void);
|
||||
bool (*start_frame)(void);
|
||||
void (*swap_buffers_begin)(void);
|
||||
void (*swap_buffers_end)(void);
|
||||
double (*get_time)(void); // For debug
|
||||
int32_t (*get_target_fps)(void);
|
||||
void (*set_target_fps)(int fps);
|
||||
bool (*can_disable_vsync)(void);
|
||||
void *(*get_window_handle)(void);
|
||||
void (*set_window_title)(const char *);
|
||||
int (*get_swap_interval)(void);
|
||||
bool (*set_swap_interval)(int);
|
||||
};
|
||||
|
||||
|
||||
+766
-844
File diff suppressed because it is too large.
Load diff
+842
-1492
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,21 @@
|
||||
#ifndef _IN_DEBUGGER_H
|
||||
#define _IN_DEBUGGER_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
extern s32 g_DebuggerActive;
|
||||
extern s32 g_DebuggerTimePasses;
|
||||
extern s32 g_DebuggerFrameAdvance;
|
||||
|
||||
void debuggerInit(void);
|
||||
void debuggerProcessEvent(void *event);
|
||||
|
||||
void debuggerStartFrame(void);
|
||||
void debuggerFrame(void);
|
||||
void debuggerEndFrame(void);
|
||||
|
||||
void debuggerUpdatePropInfo(s32 clear);
|
||||
Gfx *debuggerDrawPropInfo(Gfx *gdl);
|
||||
|
||||
#endif
|
||||
+2
-1
@@ -19,8 +19,9 @@ s32 fsFileSize(const char *name);
|
||||
|
||||
FILE *fsFileOpenWrite(const char *name);
|
||||
FILE *fsFileOpenRead(const char *name);
|
||||
void fsFileClose(FILE *f);
|
||||
void fsFileFree(FILE *f);
|
||||
|
||||
const char *fsGetModDir(void);
|
||||
s32 fsCreateDir(const char *path);
|
||||
|
||||
#endif
|
||||
+128
-61
@@ -17,68 +17,108 @@
|
||||
#define CONT_NUM_BUTTONS 32 // not including the stick axes
|
||||
|
||||
enum virtkey {
|
||||
/* same order as SDL scancodes */
|
||||
VK_KEYBOARD_BEGIN = 0,
|
||||
VK_RETURN = 40,
|
||||
VK_ESCAPE = 41,
|
||||
VK_DELETE = 76,
|
||||
/* same order as SDL scancodes */
|
||||
VK_KEYBOARD_BEGIN = 0,
|
||||
VK_A = 4,
|
||||
VK_Z = 29,
|
||||
VK_1 = 30,
|
||||
VK_9 = 38,
|
||||
VK_0 = 39,
|
||||
VK_RETURN = 40,
|
||||
VK_ESCAPE = 41,
|
||||
VK_BACKSPACE = 42,
|
||||
VK_SPACE = 44,
|
||||
VK_MINUS = 45,
|
||||
VK_LEFTBRACKET = 47,
|
||||
VK_RIGHTBRACKET = 48,
|
||||
VK_SEMICOLON = 51,
|
||||
VK_GRAVE = 53,
|
||||
VK_COMMA = 54,
|
||||
VK_PERIOD = 55,
|
||||
VK_F1 = 58,
|
||||
VK_F9 = 66,
|
||||
VK_DELETE = 76,
|
||||
VK_LCTRL = 224,
|
||||
VK_LSHIFT = 225,
|
||||
VK_LALT = 226,
|
||||
VK_RCTRL = 228,
|
||||
VK_RSHIFT = 229,
|
||||
|
||||
/* same order as SDL mouse buttons */
|
||||
VK_MOUSE_BEGIN = 512,
|
||||
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
|
||||
VK_MOUSE_MIDDLE,
|
||||
VK_MOUSE_RIGHT,
|
||||
VK_MOUSE_X1,
|
||||
VK_MOUSE_X2,
|
||||
VK_MOUSE_WHEEL_UP,
|
||||
VK_MOUSE_WHEEL_DN,
|
||||
/* same order as SDL 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,
|
||||
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
|
||||
VK_JOY_BEGIN,
|
||||
VK_JOY1_BEGIN = VK_JOY_BEGIN,
|
||||
VK_JOY1_LSHOULDER = VK_JOY1_BEGIN + 9,
|
||||
VK_JOY1_RSHOULDER = VK_JOY1_BEGIN + 10,
|
||||
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
|
||||
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
|
||||
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
|
||||
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
};
|
||||
|
||||
enum keymod {
|
||||
/* same order as SDL keymods */
|
||||
KM_LSHIFT = 0x0001,
|
||||
KM_RSHIFT = 0x0002,
|
||||
KM_LCTRL = 0x0040,
|
||||
KM_RCTRL = 0x0080,
|
||||
KM_CAPS = 0x2000,
|
||||
KM_CTRL = KM_LCTRL | KM_RCTRL,
|
||||
KM_SHIFT = KM_LSHIFT | KM_RSHIFT
|
||||
};
|
||||
|
||||
enum contkey {
|
||||
CK_C_R,
|
||||
CK_C_L,
|
||||
CK_C_D,
|
||||
CK_C_U,
|
||||
CK_RTRIG,
|
||||
CK_LTRIG,
|
||||
CK_X, // gap in CONT_
|
||||
CK_Y, // gap in CONT_
|
||||
CK_DPAD_R,
|
||||
CK_DPAD_L,
|
||||
CK_DPAD_D,
|
||||
CK_DPAD_U,
|
||||
CK_START,
|
||||
CK_ZTRIG,
|
||||
CK_B,
|
||||
CK_A,
|
||||
CK_STICK_XNEG,
|
||||
CK_STICK_XPOS,
|
||||
CK_STICK_YNEG,
|
||||
CK_STICK_YPOS,
|
||||
CK_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
|
||||
CK_C_R,
|
||||
CK_C_L,
|
||||
CK_C_D,
|
||||
CK_C_U,
|
||||
CK_RTRIG,
|
||||
CK_LTRIG,
|
||||
CK_X, // gap in CONT_
|
||||
CK_Y, // gap in CONT_
|
||||
CK_DPAD_R,
|
||||
CK_DPAD_L,
|
||||
CK_DPAD_D,
|
||||
CK_DPAD_U,
|
||||
CK_START,
|
||||
CK_ZTRIG,
|
||||
CK_B,
|
||||
CK_A,
|
||||
CK_STICK_XNEG,
|
||||
CK_STICK_XPOS,
|
||||
CK_STICK_YNEG,
|
||||
CK_STICK_YPOS,
|
||||
CK_ACCEPT,
|
||||
CK_CANCEL,
|
||||
CK_0040,
|
||||
CK_0080,
|
||||
CK_0100,
|
||||
CK_0200,
|
||||
CK_0400,
|
||||
CK_0800,
|
||||
CK_1000,
|
||||
CK_2000,
|
||||
CK_4000,
|
||||
CK_8000,
|
||||
CK_TOTAL_COUNT
|
||||
};
|
||||
|
||||
enum mouselockmode {
|
||||
MLOCK_OFF = 0,
|
||||
MLOCK_ON = 1,
|
||||
MLOCK_AUTO = 2
|
||||
};
|
||||
|
||||
// returns bitmask of connected controllers or -1 if failed
|
||||
@@ -105,6 +145,10 @@ void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);
|
||||
s32 inputControllerGetDualAnalog(s32 cidx);
|
||||
void inputControllerSetDualAnalog(s32 cidx, s32 enable);
|
||||
|
||||
// get/set Input.Player%d.CancelCButtons
|
||||
s32 inputControllerGetCancelCButtons(s32 cidx);
|
||||
void inputControllerSetCancelCButtons(s32 cidx, s32 cancel);
|
||||
|
||||
// get/set sensitivity for a given player
|
||||
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
|
||||
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);
|
||||
@@ -132,6 +176,7 @@ s32 inputAssignController(s32 cidx, s32 id);
|
||||
|
||||
// vk is a value from the virtkey enum above
|
||||
s32 inputKeyPressed(u32 vk);
|
||||
s32 inputKeyJustPressed(u32 vk);
|
||||
|
||||
// idx is controller index, contbtn is one of the CONT_ constants
|
||||
s32 inputButtonPressed(s32 idx, u32 contbtn);
|
||||
@@ -166,8 +211,9 @@ 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);
|
||||
// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time)
|
||||
// returns true if mouse has moved this input frame
|
||||
s32 inputMouseGetPosition(s32 *x, s32 *y);
|
||||
|
||||
// returns changes in mouse position since last frame, in window coordinates
|
||||
void inputMouseGetRawDelta(s32 *dx, s32 *dy);
|
||||
@@ -199,8 +245,29 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode);
|
||||
void inputClearLastKey(void);
|
||||
s32 inputGetLastKey(void);
|
||||
|
||||
// get/set Input.MouseDefaultLocked
|
||||
s32 inputGetMouseDefaultLocked(void);
|
||||
void inputSetMouseDefaultLocked(s32 defaultLocked);
|
||||
// get/set Input.MouseLockMode
|
||||
s32 inputGetMouseLockMode(void);
|
||||
void inputSetMouseLockMode(s32 lockmode);
|
||||
|
||||
// same as inputLockMouse but works only if mouse is enabled and lockmode == MLOCK_AUTO
|
||||
s32 inputAutoLockMouse(s32 wantlock);
|
||||
|
||||
// show/hide mouse cursor; if mouse lock is on the cursor is always hidden
|
||||
void inputMouseShowCursor(s32 show);
|
||||
|
||||
void inputStartTextInput(void);
|
||||
void inputStopTextInput(void);
|
||||
s32 inputIsTextInputActive(void);
|
||||
|
||||
void inputClearLastTextChar(void);
|
||||
char inputGetLastTextChar(void);
|
||||
|
||||
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly);
|
||||
|
||||
void inputClearClipboard(void);
|
||||
const char *inputGetClipboard(void);
|
||||
|
||||
// returns keymod values
|
||||
u32 inputGetKeyModState(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _IN_MPSETUPS_H
|
||||
#define _IN_MPSETUPS_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
s32 mpsetupLoadCurrentFile(void);
|
||||
s32 mpsetupSaveCurrentFile(void);
|
||||
void mpsetupLoadSetup(s32 slotindex);
|
||||
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile);
|
||||
void mpsetupCopyAllFromPak(void);
|
||||
|
||||
#endif
|
||||
+20
-22
@@ -3,32 +3,30 @@
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
typedef void (*preprocessfunc)(u8 *data, u32 size);
|
||||
typedef u8 *(*preprocessfunc)(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
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);
|
||||
u8* preprocessAnimations(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessMpConfigs(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessFont(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessJpnFont(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessALBankFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessSequences(u8 *data, u32 size, u32 *outSize);
|
||||
u8* preprocessTexturesList(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
void preprocessBgSection1Header(u8 *data, u32 size);
|
||||
void preprocessBgSection1(u8 *data, u32 size);
|
||||
void preprocessBgSection2Header(u8 *data, u32 size);
|
||||
void preprocessBgSection1(u8* data, u32 size, u32 ofs);
|
||||
void preprocessBgSection2(u8 *data, u32 size);
|
||||
void preprocessBgSection3(u8* data, u32 size);
|
||||
void preprocessBgSection1Header(u8 *data, u32 size);
|
||||
void preprocessBgSection2Header(u8 *data, u32 size);
|
||||
void preprocessBgSection3Header(u8 *data, u32 size);
|
||||
void preprocessBgSection3(u8 *data, u32 size);
|
||||
void preprocessBgRoom(u8 *data, u32 ofs);
|
||||
void preprocessBgLights(u8 *data, u32 ofs);
|
||||
u32 preprocessBgRoom(u8* data, u32 size, u32 room_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);
|
||||
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessPadsFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessSetupFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessModelFile(u8 *data, u32 size, u32 *outSize);
|
||||
u8 *preprocessGunFile(u8 *data, u32 size, u32 *outSize);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _IN_PREPROCESS_COMMON_H
|
||||
#define _IN_PREPROCESS_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "romdata.h"
|
||||
#include "preprocess.h"
|
||||
|
||||
#define MAX_PTR_MARKERS (1024 * 8)
|
||||
|
||||
#define PD_ALIGN(val, size) (((val) + ((size) - 1)) & ~((size) - 1))
|
||||
|
||||
#define PD_PTR_BASE(x, b) (void *)((u8 *)b + (uintptr_t)x)
|
||||
#define PD_PTR_BASEOFS(x, b, d) (void *)((u8 *)b - d + (uintptr_t)x)
|
||||
|
||||
static inline f32 swapF32(f32 x) { *(u32*)&x = PD_BE32(*(u32*)&x); return x; }
|
||||
static inline u32 swapU32(u32 x) { return PD_BE32(x); }
|
||||
static inline s32 swapS32(s32 x) { return PD_BE32(x); }
|
||||
static inline u16 swapU16(u16 x) { return PD_BE16(x); }
|
||||
static inline s16 swapS16(s16 x) { return PD_BE16(x); }
|
||||
static inline void* swapPtr(void** x) { return (void*)PD_BEPTR((uintptr_t)x); }
|
||||
static inline struct coord swapCrd(struct coord crd) { crd.x = swapF32(crd.x); crd.y = swapF32(crd.y); crd.z = swapF32(crd.z); return crd; }
|
||||
static inline u32 swapUnk(u32 x) { assert(0 && "unknown type"); return x; }
|
||||
|
||||
#define PD_SWAPPED_VAL(x) _Generic((x), \
|
||||
f32: swapF32, \
|
||||
u32: swapU32, \
|
||||
s32: swapS32, \
|
||||
u16: swapU16, \
|
||||
s16: swapS16, \
|
||||
struct coord: swapCrd, \
|
||||
default: swapUnk \
|
||||
)(x)
|
||||
|
||||
#define PD_SWAP_VAL(x) x = PD_SWAPPED_VAL(x)
|
||||
|
||||
#define PD_SWAP_PTR(x) x = swapPtr((void *)(x))
|
||||
|
||||
// ptr marker functions
|
||||
|
||||
struct ptrmarker {
|
||||
u32 ptr_src;
|
||||
uintptr_t ptr_host;
|
||||
};
|
||||
|
||||
void ptrAdd(u32 ptr_src, uintptr_t ptr_host);
|
||||
struct ptrmarker* ptrFind(uintptr_t ptr_src);
|
||||
void ptrReset(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _IN_PREPROCESS_GBI_H
|
||||
#define _IN_PREPROCESS_GBI_H
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
// gbi related functions
|
||||
void gbiReset(void);
|
||||
void gbiSetSegment(int segment, u32 offset);
|
||||
void gbiSetVtx(u32 src_offset, u32 dst_offset);
|
||||
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds);
|
||||
void gbiConvertVtx(u8* dst, u32 dstpos, int count);
|
||||
void gbiGdlRewriteAddrs(u8* dst, u32 offset);
|
||||
void gbiAddTexAddr(u32 src_offset, u32 dst_offset);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,640 @@
|
||||
#ifndef _IN_SETUP_DECL
|
||||
#define _IN_SETUP_DECL
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct n64_stagesetup {
|
||||
u32 ptr_waypoints;
|
||||
u32 ptr_waygroups;
|
||||
u32 ptr_cover;
|
||||
u32 ptr_intro;
|
||||
u32 ptr_props;
|
||||
u32 ptr_paths;
|
||||
u32 ptr_ailists;
|
||||
u32 ptr_padfiledata;
|
||||
};
|
||||
|
||||
struct n64_coord {
|
||||
f32 x;
|
||||
f32 y;
|
||||
f32 z;
|
||||
};
|
||||
|
||||
struct n64_defaultobj {
|
||||
u16 extrascale;
|
||||
u8 hidden2;
|
||||
u8 type;
|
||||
s16 modelnum;
|
||||
s16 pad;
|
||||
u32 flags;
|
||||
u32 flags2;
|
||||
u32 flags3;
|
||||
u32 ptr_prop;
|
||||
u32 ptr_model;
|
||||
f32 realrot[3][3];
|
||||
u32 hidden;
|
||||
union {
|
||||
u32 ptr_geotilef;
|
||||
u32 ptr_geoblock;
|
||||
u32 ptr_geocyl;
|
||||
u32 ptr_unkgeo;
|
||||
};
|
||||
union {
|
||||
u32 ptr_projectile;
|
||||
u32 ptr_embedment;
|
||||
};
|
||||
s16 damage;
|
||||
s16 maxdamage;
|
||||
u8 shadecol[4];
|
||||
u8 nextcol[4];
|
||||
u16 floorcol;
|
||||
s8 geocount;
|
||||
s8 _pad_;
|
||||
};
|
||||
|
||||
struct n64_doorobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 maxfrac;
|
||||
f32 perimfrac;
|
||||
f32 accel;
|
||||
f32 decel;
|
||||
f32 maxspeed;
|
||||
u16 doorflags;
|
||||
u16 doortype;
|
||||
u32 keyflags;
|
||||
s32 autoclosetime;
|
||||
f32 frac;
|
||||
f32 fracspeed;
|
||||
s8 mode;
|
||||
s8 glasshits;
|
||||
s16 fadealpha;
|
||||
s16 xludist;
|
||||
s16 opadist;
|
||||
struct n64_coord startpos;
|
||||
f32 mtx98[3][3];
|
||||
u32 ptr_sibling;
|
||||
s32 lastopen60;
|
||||
s16 portalnum;
|
||||
s8 soundtype;
|
||||
s8 fadetime60;
|
||||
s32 lastcalc60;
|
||||
u8 laserfade;
|
||||
u8 unusedmaybe[3];
|
||||
u8 shadeinfo1[4];
|
||||
u8 shadeinfo2[4];
|
||||
u8 actual1;
|
||||
u8 actual2;
|
||||
u8 extra1;
|
||||
u8 extra2;
|
||||
};
|
||||
|
||||
struct n64_doorscaleobj {
|
||||
u32 unk00;
|
||||
s32 scale;
|
||||
};
|
||||
|
||||
struct n64_keyobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 keyflags;
|
||||
};
|
||||
|
||||
struct n64_alarmobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_cctvobj {
|
||||
struct n64_defaultobj base;
|
||||
|
||||
s16 lookatpadnum;
|
||||
s16 toleft;
|
||||
//Mtxf camrotm;
|
||||
f32 m[4][4];
|
||||
f32 yzero;
|
||||
f32 yrot;
|
||||
f32 yleft;
|
||||
f32 yright;
|
||||
f32 yspeed;
|
||||
f32 ymaxspeed;
|
||||
s32 seebondtime60;
|
||||
f32 maxdist;
|
||||
f32 xzero;
|
||||
};
|
||||
|
||||
struct n64_ammocrateobj {
|
||||
struct n64_defaultobj base;
|
||||
s32 ammotype;
|
||||
};
|
||||
|
||||
struct n64_gset {
|
||||
u8 weaponnum;
|
||||
u8 unk0639;
|
||||
u8 unk063a;
|
||||
u8 weaponfunc;
|
||||
};
|
||||
|
||||
struct n64_weaponobj {
|
||||
struct n64_defaultobj base;
|
||||
|
||||
union {
|
||||
struct n64_gset gset;
|
||||
struct {
|
||||
u8 weaponnum;
|
||||
s8 unk5d;
|
||||
s8 unk5e;
|
||||
u8 gunfunc;
|
||||
};
|
||||
};
|
||||
|
||||
s8 fadeouttimer60;
|
||||
s8 dualweaponnum;
|
||||
|
||||
union {
|
||||
s16 timer240;
|
||||
s16 team;
|
||||
};
|
||||
|
||||
u32 ptr_dualweapon;
|
||||
};
|
||||
|
||||
struct n64_packedchr {
|
||||
s16 chrindex;
|
||||
s8 unk02;
|
||||
s8 typenum;
|
||||
u32 spawnflags;
|
||||
s16 chrnum;
|
||||
u16 padnum;
|
||||
u8 bodynum;
|
||||
s8 headnum;
|
||||
u16 ailistnum;
|
||||
u16 padpreset;
|
||||
u16 chrpreset;
|
||||
u16 hearscale;
|
||||
u16 viewdist;
|
||||
u32 flags;
|
||||
u32 flags2;
|
||||
u8 team;
|
||||
u8 squadron;
|
||||
s16 chair;
|
||||
u32 convtalk;
|
||||
u8 tude;
|
||||
u8 naturalanim;
|
||||
u8 yvisang;
|
||||
u8 teamscandist;
|
||||
};
|
||||
|
||||
struct n64_tvscreen {
|
||||
u32 ptr_cmdlist;
|
||||
u16 offset;
|
||||
s16 pause60;
|
||||
u32 ptr_tconfig;
|
||||
f32 rot;
|
||||
f32 xscale;
|
||||
f32 xscalefrac;
|
||||
f32 xscaleinc;
|
||||
f32 xscaleold;
|
||||
f32 xscalenew;
|
||||
f32 yscale;
|
||||
f32 yscalefrac;
|
||||
f32 yscaleinc;
|
||||
f32 yscaleold;
|
||||
f32 yscalenew;
|
||||
f32 xmid;
|
||||
f32 xmidfrac;
|
||||
f32 xmidinc;
|
||||
f32 xmidold;
|
||||
f32 xmidnew;
|
||||
f32 ymid;
|
||||
f32 ymidfrac;
|
||||
f32 ymidinc;
|
||||
f32 ymidold;
|
||||
f32 ymidnew;
|
||||
u8 red;
|
||||
u8 redold;
|
||||
u8 rednew;
|
||||
u8 green;
|
||||
u8 greenold;
|
||||
u8 greennew;
|
||||
u8 blue;
|
||||
u8 blueold;
|
||||
u8 bluenew;
|
||||
u8 alpha;
|
||||
u8 alphaold;
|
||||
u8 alphanew;
|
||||
f32 colfrac;
|
||||
f32 colinc;
|
||||
};
|
||||
|
||||
struct n64_singlemonitorobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_tvscreen screen;
|
||||
s16 owneroffset;
|
||||
s8 ownerpart;
|
||||
u8 imagenum;
|
||||
};
|
||||
|
||||
struct n64_multimonitorobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_tvscreen screens[4];
|
||||
u8 imagenums[4];
|
||||
};
|
||||
|
||||
struct n64_hangingmonitorsobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_autogunobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 targetpad;
|
||||
s8 firing;
|
||||
u8 firecount;
|
||||
f32 yzero;
|
||||
f32 ymaxleft;
|
||||
f32 ymaxright;
|
||||
f32 yrot;
|
||||
f32 yspeed;
|
||||
f32 xzero;
|
||||
f32 xrot;
|
||||
f32 xspeed;
|
||||
f32 maxspeed;
|
||||
f32 aimdist;
|
||||
f32 barrelspeed;
|
||||
f32 barrelrot;
|
||||
s32 lastseebond60;
|
||||
s32 lastaimbond60;
|
||||
s32 allowsoundframe;
|
||||
u32 ptr_beam;
|
||||
f32 shotbondsum;
|
||||
u32 ptr_target;
|
||||
u8 targetteam;
|
||||
u8 ammoquantity;
|
||||
s16 nextchrtest;
|
||||
};
|
||||
|
||||
struct n64_linkgunsobj {
|
||||
u32 unk00;
|
||||
s16 offset1;
|
||||
s16 offset2;
|
||||
};
|
||||
|
||||
struct n64_debrisobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_hatobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_grenadeprobobj { // objtype 0x12
|
||||
u32 unk00;
|
||||
s16 chrnum;
|
||||
u16 probability;
|
||||
};
|
||||
|
||||
struct n64_linkliftdoorobj {
|
||||
u32 unk00;
|
||||
u32 ptr_door;
|
||||
u32 ptr_lift;
|
||||
u32 ptr_next;
|
||||
s32 stopnum;
|
||||
};
|
||||
|
||||
struct n64_multiammocrateslot {
|
||||
u16 modelnum;
|
||||
u16 quantity;
|
||||
};
|
||||
|
||||
struct n64_multiammocrateobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_multiammocrateslot slots[19];
|
||||
};
|
||||
|
||||
struct n64_shieldobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 initialamount;
|
||||
f32 amount;
|
||||
u32 unk64;
|
||||
};
|
||||
|
||||
struct n64_tag {
|
||||
u32 identifier;
|
||||
u16 tagnum;
|
||||
s16 cmdoffset;
|
||||
u32 ptr_next;
|
||||
u32 ptr_obj;
|
||||
};
|
||||
|
||||
struct n64_objective {
|
||||
u32 unk00;
|
||||
s32 index;
|
||||
u32 text;
|
||||
u16 unk0c;
|
||||
u8 flags;
|
||||
s8 difficulties;
|
||||
};
|
||||
|
||||
struct n64_stdobjective {
|
||||
u32 cmd;
|
||||
};
|
||||
|
||||
struct n64_objectivecmd {
|
||||
u8 cmd0[4];
|
||||
u32 cmd1;
|
||||
};
|
||||
|
||||
struct n64_briefingobj {
|
||||
u32 unk00;
|
||||
u32 type;
|
||||
u32 text;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_padlockeddoorobj {
|
||||
u32 unk00;
|
||||
u32 ptr_door;
|
||||
u32 ptr_lock;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_truckobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 speed;
|
||||
f32 wheelxrot;
|
||||
f32 wheelyrot;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
};
|
||||
|
||||
struct n64_tankobj {
|
||||
u8 _pad_[128];
|
||||
};
|
||||
|
||||
struct n64_heliobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 rotoryrot;
|
||||
f32 rotoryspeed;
|
||||
f32 rotoryspeedaim;
|
||||
f32 rotoryspeedtime;
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 yrot;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
};
|
||||
|
||||
struct n64_glassobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 portalnum;
|
||||
s16 _pad_;
|
||||
};
|
||||
|
||||
struct n64_safeobj {
|
||||
struct n64_defaultobj base;
|
||||
};
|
||||
|
||||
struct n64_safeitemobj {
|
||||
u32 unk00;
|
||||
u32 ptr_item;
|
||||
u32 ptr_safe;
|
||||
u32 ptr_door;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_cameraposobj {
|
||||
s32 type;
|
||||
f32 x;
|
||||
f32 y;
|
||||
f32 z;
|
||||
f32 theta;
|
||||
f32 verta;
|
||||
s32 pad;
|
||||
};
|
||||
|
||||
struct n64_tintedglassobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 xludist;
|
||||
s16 opadist;
|
||||
s16 opacity;
|
||||
s16 portalnum;
|
||||
f32 unk64;
|
||||
};
|
||||
|
||||
struct n64_liftobj {
|
||||
struct n64_defaultobj base;
|
||||
s16 pads[4];
|
||||
u32 ptr_doors[4];
|
||||
f32 dist;
|
||||
f32 speed;
|
||||
f32 accel;
|
||||
f32 maxspeed;
|
||||
s8 soundtype;
|
||||
s8 levelcur;
|
||||
s8 levelaim;
|
||||
s8 _pad_;
|
||||
struct n64_coord prevpos;
|
||||
};
|
||||
|
||||
struct n64_linksceneryobj {
|
||||
u32 unk00;
|
||||
u32 ptr_trigger;
|
||||
u32 ptr_unexp;
|
||||
u32 ptr_exp;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_blockedpathobj {
|
||||
u32 unk00;
|
||||
u32 ptr_blocker;
|
||||
s16 waypoint1;
|
||||
s16 waypoint2;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_hov {
|
||||
u8 type;
|
||||
u8 flags;
|
||||
s16 _pad_;
|
||||
f32 bobycur;
|
||||
f32 bobytarget;
|
||||
f32 bobyspeed;
|
||||
f32 yrot;
|
||||
f32 bobpitchcur;
|
||||
f32 bobpitchtarget;
|
||||
f32 bobpitchspeed;
|
||||
f32 bobrollcur;
|
||||
f32 bobrolltarget;
|
||||
f32 bobrollspeed;
|
||||
f32 groundpitch;
|
||||
f32 y;
|
||||
f32 ground;
|
||||
s32 prevframe60;
|
||||
s32 prevgroundframe60;
|
||||
};
|
||||
|
||||
struct n64_hoverbikeobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_hov hov;
|
||||
f32 speed[2];
|
||||
f32 prevpos[2];
|
||||
f32 w;
|
||||
f32 rels[2];
|
||||
f32 exreal;
|
||||
f32 ezreal;
|
||||
f32 ezreal2;
|
||||
f32 leanspeed;
|
||||
f32 leandiff;
|
||||
s32 maxspeedtime240;
|
||||
f32 speedabs[2];
|
||||
f32 speedrel[2];
|
||||
};
|
||||
|
||||
struct n64_hoverpropobj {
|
||||
struct n64_defaultobj base;
|
||||
struct n64_hov hov;
|
||||
};
|
||||
|
||||
struct n64_fanobj {
|
||||
struct n64_defaultobj base;
|
||||
f32 yrot;
|
||||
f32 yrotprev;
|
||||
f32 ymaxspeed;
|
||||
f32 yspeed;
|
||||
f32 yaccel;
|
||||
s8 on;
|
||||
u8 _pad_[3];
|
||||
};
|
||||
|
||||
struct n64_hovercarobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
f32 turnyspeed60;
|
||||
f32 turnxspeed60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
f32 rotx;
|
||||
f32 rotz;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;
|
||||
s16 status;
|
||||
s16 dead;
|
||||
s16 deadtimer60;
|
||||
s16 sparkstimer60;
|
||||
};
|
||||
|
||||
struct n64_chopperobj {
|
||||
struct n64_defaultobj base;
|
||||
u32 ptr_ailist;
|
||||
u16 aioffset;
|
||||
s16 aireturnlist;
|
||||
union {
|
||||
struct {
|
||||
f32 speed;
|
||||
f32 speedaim;
|
||||
f32 speedtime60;
|
||||
};
|
||||
struct n64_coord fall;
|
||||
};
|
||||
f32 turnyspeed60;
|
||||
f32 turnxspeed60;
|
||||
f32 turnrot60;
|
||||
f32 roty;
|
||||
f32 rotx;
|
||||
f32 rotz;
|
||||
u32 ptr_path;
|
||||
s32 nextstep;//
|
||||
s16 weaponsarmed;
|
||||
s16 ontarget;
|
||||
s16 target;
|
||||
u8 attackmode;
|
||||
u8 cw;
|
||||
f32 vx;
|
||||
f32 vy;
|
||||
f32 vz;
|
||||
f32 power;
|
||||
f32 otx;
|
||||
f32 oty;
|
||||
f32 otz;
|
||||
f32 bob;
|
||||
f32 bobstrength;
|
||||
s32 targetvisible;
|
||||
s32 timer60;
|
||||
s32 patroltimer60;
|
||||
f32 gunturnyspeed60;
|
||||
f32 gunturnxspeed60;
|
||||
f32 gunroty;
|
||||
f32 gunrotx;
|
||||
f32 barrelrotspeed;
|
||||
f32 barrelrot;
|
||||
u32 ptr_fireslotthing;
|
||||
s32 dead;
|
||||
};
|
||||
|
||||
struct n64_escalatorobj {
|
||||
struct n64_defaultobj base;
|
||||
s32 frame;
|
||||
struct n64_coord prevpos;
|
||||
};
|
||||
|
||||
struct n64_textoverride {
|
||||
u32 unk00;
|
||||
s32 objoffset;
|
||||
s32 weapon;
|
||||
u32 obtaintext;
|
||||
u32 ownertext;
|
||||
u32 inventorytext;
|
||||
u32 inventory2text;
|
||||
u32 pickuptext;
|
||||
u32 ptr_next;
|
||||
u32 ptr_obj;
|
||||
};
|
||||
|
||||
struct n64_criteria_roomentered {
|
||||
u32 unk00;
|
||||
u32 pad;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_criteria_throwinroom {
|
||||
u32 unk00;
|
||||
u32 unk04;
|
||||
u32 pad;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_criteria_holograph {
|
||||
u32 unk00;
|
||||
u32 obj;
|
||||
u32 status;
|
||||
u32 ptr_next;
|
||||
};
|
||||
|
||||
struct n64_ailist {
|
||||
u32 ptr_list;
|
||||
s32 id;
|
||||
};
|
||||
|
||||
struct n64_path {
|
||||
u32 ptr_pads;
|
||||
u8 id;
|
||||
u8 flags;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,7 @@ extern u32 g_RomFileSize;
|
||||
s32 romdataInit(void);
|
||||
|
||||
u8 *romdataFileLoad(s32 fileNum, u32 *outSize);
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size);
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize);
|
||||
void romdataFileFree(s32 fileNum);
|
||||
const char *romdataFileGetName(s32 fileNum);
|
||||
|
||||
@@ -21,5 +21,8 @@ s32 romdataFileGetNumForName(const char *name);
|
||||
u8 *romdataSegGetData(const char *segName);
|
||||
u8 *romdataSegGetDataEnd(const char *segName);
|
||||
u32 romdataSegGetSize(const char *segName);
|
||||
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype);
|
||||
|
||||
s32 romdataCheckGbcRom(void);
|
||||
|
||||
#endif
|
||||
@@ -32,6 +32,7 @@ void sysGetHomePath(char *outPath, const u32 outLen);
|
||||
|
||||
void *sysMemAlloc(const u32 size);
|
||||
void *sysMemZeroAlloc(const u32 size);
|
||||
void *sysMemRealloc(void *ptr, const u32 newSize);
|
||||
void sysMemFree(void *ptr);
|
||||
|
||||
// hns is specified in 100ns units
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef _IN_VERSIONINFO_H
|
||||
#define _IN_VERSIONINFO_H
|
||||
|
||||
#define VERSION_TARGET "@VERSION_TARGET@"
|
||||
#define VERSION_ARCH "@VERSION_ARCH@"
|
||||
#define VERSION_ROMID "@VERSION_ROMID@"
|
||||
#define VERSION_BUILD "@VERSION_BUILD@"
|
||||
#define VERSION_HASH "@VERSION_HASH@"
|
||||
#define VERSION_BRANCH "@VERSION_BRANCH@"
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,11 @@
|
||||
#define VIDEO_MAX_FPS 240
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
s32 width;
|
||||
s32 height;
|
||||
} displaymode;
|
||||
|
||||
s32 videoInit(void);
|
||||
void videoStartFrame(void);
|
||||
void videoSubmitCommands(Gfx *cmds);
|
||||
@@ -27,17 +32,36 @@ s32 videoGetWidth(void);
|
||||
s32 videoGetHeight(void);
|
||||
f32 videoGetAspect(void);
|
||||
s32 videoGetFullscreen(void);
|
||||
s32 videoGetFullscreenMode(void);
|
||||
s32 videoGetMaximizeWindow(void);
|
||||
void videoSetMaximizeWindow(s32 fs);
|
||||
s32 videoGetCenterWindow(void);
|
||||
void videoSetCenterWindow(s32 center);
|
||||
u32 videoGetTextureFilter(void);
|
||||
s32 videoGetTextureFilter2D(void);
|
||||
s32 videoGetDetailTextures(void);
|
||||
s32 videoGetDisplayModeIndex(void);
|
||||
s32 videoGetDisplayMode(displaymode *out, const s32 index);
|
||||
s32 videoGetNumDisplayModes(void);
|
||||
s32 videoGetVsync(void);
|
||||
s32 videoGetFramerateLimit(void);
|
||||
s32 videoGetDisplayFPS(void);
|
||||
s32 videoGetMSAA(void);
|
||||
|
||||
f32 videoGetAverageFPS(void);
|
||||
f64 videoGetLastRenderTime(void);
|
||||
|
||||
void videoSetWindowOffset(s32 x, s32 y);
|
||||
void videoSetFullscreen(s32 fs);
|
||||
void videoSetFullscreenMode(s32 mode);
|
||||
void videoSetTextureFilter(u32 filter);
|
||||
void videoSetTextureFilter2D(s32 filter);
|
||||
void videoSetDetailTextures(s32 detail);
|
||||
void videoSetDisplayMode(const s32 index);
|
||||
void videoSetVsync(const s32 vsync);
|
||||
void videoSetFramerateLimit(const s32 limit);
|
||||
void videoSetDisplayFPS(const s32 displayfps);
|
||||
void videoSetMSAA(const s32 msaa);
|
||||
|
||||
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
|
||||
void videoSetFramebuffer(s32 target);
|
||||
@@ -49,4 +73,6 @@ s32 videoFramebuffersSupported(void);
|
||||
void videoResetTextureCache(void);
|
||||
void videoFreeCachedTexture(const void *texptr);
|
||||
|
||||
void videoShutdown(void);
|
||||
|
||||
#endif
|
||||
+9
-4
@@ -10,7 +10,7 @@
|
||||
|
||||
#define CONFIG_MAX_SECNAME 128
|
||||
#define CONFIG_MAX_KEYNAME 256
|
||||
#define CONFIG_MAX_SETTINGS 256
|
||||
#define CONFIG_MAX_SETTINGS 300
|
||||
|
||||
typedef enum {
|
||||
CFG_NONE,
|
||||
@@ -34,6 +34,7 @@ struct configentry {
|
||||
} settings[CONFIG_MAX_SETTINGS];
|
||||
|
||||
static s32 numSettings = 0;
|
||||
static u8 configMaxWarningLogged = 0;
|
||||
|
||||
static inline s32 configClampInt(s32 val, s32 min, s32 max)
|
||||
{
|
||||
@@ -64,11 +65,15 @@ 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);
|
||||
snprintf(cfg->key, CONFIG_MAX_KEYNAME, "%s", key);
|
||||
const char *delim = strrchr(cfg->key, '.');
|
||||
cfg->seclen = delim ? (delim - cfg->key) : 0;
|
||||
return cfg;
|
||||
}
|
||||
if (!configMaxWarningLogged) {
|
||||
sysLogPrintf(LOG_WARNING, "Maximum number of configuration entries exceeded: %d", CONFIG_MAX_SETTINGS);
|
||||
configMaxWarningLogged = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -228,7 +233,7 @@ s32 configSave(const char *fname)
|
||||
configSaveEntry(cfg, f);
|
||||
}
|
||||
|
||||
fsFileClose(f);
|
||||
fsFileFree(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -282,7 +287,7 @@ s32 configLoad(const char *fname)
|
||||
}
|
||||
}
|
||||
|
||||
fsFileClose(f);
|
||||
fsFileFree(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,905 @@
|
||||
#include <string>
|
||||
#include <SDL.h>
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/backends/imgui_impl_sdlrenderer2.h"
|
||||
#include "imgui/backends/imgui_impl_sdl2.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
#include <gbiex.h>
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
#include "constants.h"
|
||||
#include "game/stagetable.h"
|
||||
#include "game/chr.h"
|
||||
#include "game/chraction.h"
|
||||
#include "game/bg.h"
|
||||
#include "game/player.h"
|
||||
#include "game/propobj.h"
|
||||
#include "game/prop.h"
|
||||
#include "game/sight.h"
|
||||
#include "game/game_1531a0.h"
|
||||
#include "lib/memp.h"
|
||||
#include "lib/mema.h"
|
||||
#include "lib/vi.h"
|
||||
#include "lib/lib_17ce0.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
#include "romdata.h"
|
||||
|
||||
#undef bool
|
||||
#undef true
|
||||
#undef false
|
||||
|
||||
s32 g_DebuggerActive = FALSE;
|
||||
s32 g_DebuggerTimePasses = TRUE;
|
||||
s32 g_DebuggerFrameAdvance = 0;
|
||||
|
||||
u32 memaGetSize(void);
|
||||
|
||||
}
|
||||
|
||||
static SDL_Window *dbgwin = nullptr;
|
||||
static SDL_Renderer *dbgren = nullptr;
|
||||
|
||||
static char xstr[64] = "0";
|
||||
static char ystr[64] = "0";
|
||||
static char zstr[64] = "0";
|
||||
static char gotostr[64] = "";
|
||||
|
||||
static bool advanceHeld = false;
|
||||
|
||||
static s32 propFilter = 0;
|
||||
static s32 objFilter = 0;
|
||||
|
||||
static const char *propTypes[9];
|
||||
static const char *objTypes[0x3c];
|
||||
|
||||
static bool expandLatch = false;
|
||||
static bool expandValue = false;
|
||||
|
||||
static bool showPropInfo = false;
|
||||
static bool showActiveProps = true;
|
||||
|
||||
static void *focusPtr = nullptr;
|
||||
|
||||
static struct prop *lookatprop = nullptr;
|
||||
static struct hitthing lookathit;
|
||||
static bool lookathitset;
|
||||
|
||||
static inline const char *fmtCoord(const coord& crd)
|
||||
{
|
||||
static char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "(%.2f, %.2f, %.2f)", crd.x, crd.y, crd.z);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#define DEF_ACT_NAME(x) case x: return #x;
|
||||
|
||||
static inline const char *fmtActionType(s8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(ACT_INIT )
|
||||
DEF_ACT_NAME(ACT_STAND )
|
||||
DEF_ACT_NAME(ACT_KNEEL )
|
||||
DEF_ACT_NAME(ACT_ANIM )
|
||||
DEF_ACT_NAME(ACT_DIE )
|
||||
DEF_ACT_NAME(ACT_DEAD )
|
||||
DEF_ACT_NAME(ACT_ARGH )
|
||||
DEF_ACT_NAME(ACT_PREARGH )
|
||||
DEF_ACT_NAME(ACT_ATTACK )
|
||||
DEF_ACT_NAME(ACT_ATTACKWALK )
|
||||
DEF_ACT_NAME(ACT_ATTACKROLL )
|
||||
DEF_ACT_NAME(ACT_SIDESTEP )
|
||||
DEF_ACT_NAME(ACT_JUMPOUT )
|
||||
DEF_ACT_NAME(ACT_RUNPOS )
|
||||
DEF_ACT_NAME(ACT_PATROL )
|
||||
DEF_ACT_NAME(ACT_GOPOS )
|
||||
DEF_ACT_NAME(ACT_SURRENDER )
|
||||
DEF_ACT_NAME(ACT_LOOKATTARGET )
|
||||
DEF_ACT_NAME(ACT_SURPRISED )
|
||||
DEF_ACT_NAME(ACT_STARTALARM )
|
||||
DEF_ACT_NAME(ACT_THROWGRENADE )
|
||||
DEF_ACT_NAME(ACT_TURNDIR )
|
||||
DEF_ACT_NAME(ACT_TEST )
|
||||
DEF_ACT_NAME(ACT_BONDINTRO )
|
||||
DEF_ACT_NAME(ACT_BONDDIE )
|
||||
DEF_ACT_NAME(ACT_BONDMULTI )
|
||||
DEF_ACT_NAME(ACT_NULL )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKSTAND )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKKNEEL )
|
||||
DEF_ACT_NAME(ACT_BOT_ATTACKSTRAFE)
|
||||
DEF_ACT_NAME(ACT_DRUGGEDDROP )
|
||||
DEF_ACT_NAME(ACT_DRUGGEDKO )
|
||||
DEF_ACT_NAME(ACT_DRUGGEDCOMINGUP )
|
||||
DEF_ACT_NAME(ACT_ATTACKAMOUNT )
|
||||
DEF_ACT_NAME(ACT_ROBOTATTACK )
|
||||
DEF_ACT_NAME(ACT_SKJUMP )
|
||||
DEF_ACT_NAME(ACT_PUNCH )
|
||||
DEF_ACT_NAME(ACT_CUTFIRE )
|
||||
default: return "ACT";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *fmtPropType(u8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(PROPTYPE_OBJ)
|
||||
DEF_ACT_NAME(PROPTYPE_DOOR)
|
||||
DEF_ACT_NAME(PROPTYPE_CHR)
|
||||
DEF_ACT_NAME(PROPTYPE_WEAPON)
|
||||
DEF_ACT_NAME(PROPTYPE_EYESPY)
|
||||
DEF_ACT_NAME(PROPTYPE_PLAYER)
|
||||
DEF_ACT_NAME(PROPTYPE_EXPLOSION)
|
||||
DEF_ACT_NAME(PROPTYPE_SMOKE)
|
||||
default: return "Prop";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *fmtObjType(u8 at)
|
||||
{
|
||||
switch (at) {
|
||||
DEF_ACT_NAME(OBJTYPE_DOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_DOORSCALE )
|
||||
DEF_ACT_NAME(OBJTYPE_BASIC )
|
||||
DEF_ACT_NAME(OBJTYPE_KEY )
|
||||
DEF_ACT_NAME(OBJTYPE_ALARM )
|
||||
DEF_ACT_NAME(OBJTYPE_CCTV )
|
||||
DEF_ACT_NAME(OBJTYPE_AMMOCRATE )
|
||||
DEF_ACT_NAME(OBJTYPE_WEAPON )
|
||||
DEF_ACT_NAME(OBJTYPE_CHR )
|
||||
DEF_ACT_NAME(OBJTYPE_SINGLEMONITOR )
|
||||
DEF_ACT_NAME(OBJTYPE_MULTIMONITOR )
|
||||
DEF_ACT_NAME(OBJTYPE_HANGINGMONITORS )
|
||||
DEF_ACT_NAME(OBJTYPE_AUTOGUN )
|
||||
DEF_ACT_NAME(OBJTYPE_LINKGUNS )
|
||||
DEF_ACT_NAME(OBJTYPE_DEBRIS )
|
||||
DEF_ACT_NAME(OBJTYPE_10 )
|
||||
DEF_ACT_NAME(OBJTYPE_HAT )
|
||||
DEF_ACT_NAME(OBJTYPE_GRENADEPROB )
|
||||
DEF_ACT_NAME(OBJTYPE_LINKLIFTDOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_MULTIAMMOCRATE )
|
||||
DEF_ACT_NAME(OBJTYPE_SHIELD )
|
||||
DEF_ACT_NAME(OBJTYPE_TAG )
|
||||
DEF_ACT_NAME(OBJTYPE_BEGINOBJECTIVE )
|
||||
DEF_ACT_NAME(OBJTYPE_ENDOBJECTIVE )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_DESTROYOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_COMPFLAGS )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_FAILFLAGS )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_COLLECTOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_THROWOBJ )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_HOLOGRAPH )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_1F )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_ENTERROOM )
|
||||
DEF_ACT_NAME(OBJECTIVETYPE_THROWINROOM )
|
||||
DEF_ACT_NAME(OBJTYPE_22 )
|
||||
DEF_ACT_NAME(OBJTYPE_BRIEFING )
|
||||
DEF_ACT_NAME(OBJTYPE_GASBOTTLE )
|
||||
DEF_ACT_NAME(OBJTYPE_RENAMEOBJ )
|
||||
DEF_ACT_NAME(OBJTYPE_PADLOCKEDDOOR )
|
||||
DEF_ACT_NAME(OBJTYPE_TRUCK )
|
||||
DEF_ACT_NAME(OBJTYPE_HELI )
|
||||
DEF_ACT_NAME(OBJTYPE_29 )
|
||||
DEF_ACT_NAME(OBJTYPE_GLASS )
|
||||
DEF_ACT_NAME(OBJTYPE_SAFE )
|
||||
DEF_ACT_NAME(OBJTYPE_SAFEITEM )
|
||||
DEF_ACT_NAME(OBJTYPE_TANK )
|
||||
DEF_ACT_NAME(OBJTYPE_CAMERAPOS )
|
||||
DEF_ACT_NAME(OBJTYPE_TINTEDGLASS )
|
||||
DEF_ACT_NAME(OBJTYPE_LIFT )
|
||||
DEF_ACT_NAME(OBJTYPE_CONDITIONALSCENERY)
|
||||
DEF_ACT_NAME(OBJTYPE_BLOCKEDPATH )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERBIKE )
|
||||
DEF_ACT_NAME(OBJTYPE_END )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERPROP )
|
||||
DEF_ACT_NAME(OBJTYPE_FAN )
|
||||
DEF_ACT_NAME(OBJTYPE_HOVERCAR )
|
||||
DEF_ACT_NAME(OBJTYPE_PADEFFECT )
|
||||
DEF_ACT_NAME(OBJTYPE_CHOPPER )
|
||||
DEF_ACT_NAME(OBJTYPE_MINE )
|
||||
DEF_ACT_NAME(OBJTYPE_ESCASTEP )
|
||||
default: return "Obj";
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEF_ACT_NAME
|
||||
|
||||
extern "C" void debuggerInit(void)
|
||||
{
|
||||
SDL_Window *parent = (SDL_Window *)videoGetWindowHandle();
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
int pw = 0;
|
||||
int ph = 0;
|
||||
// in windowed mode put the debugger to the right of the window
|
||||
if ((SDL_GetWindowFlags(parent) & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
|
||||
SDL_GetWindowPosition(parent, &px, &py);
|
||||
SDL_GetWindowSize(parent, &pw, &ph);
|
||||
}
|
||||
|
||||
const Uint32 winflags = SDL_WINDOW_RESIZABLE;
|
||||
dbgwin = SDL_CreateWindow("Debugger", px + pw + 4, py, 320, ph, winflags);
|
||||
if (!dbgwin) {
|
||||
sysLogPrintf(LOG_ERROR, "DBG: could not create SDL window: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// can't trust any hardware accelerated windows to live in harmony with our main window, so force SW
|
||||
dbgren = SDL_CreateRenderer(dbgwin, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (!dbgren) {
|
||||
sysLogPrintf(LOG_ERROR, "DBG: could not create SDL renderer: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
io.IniFilename = nullptr;
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(dbgwin, dbgren);
|
||||
ImGui_ImplSDLRenderer2_Init(dbgren);
|
||||
|
||||
propTypes[0] = "NONE";
|
||||
for (s32 i = 1; i < ARRAYCOUNT(propTypes); ++i) {
|
||||
propTypes[i] = fmtPropType(i);
|
||||
}
|
||||
|
||||
objTypes[0] = "NONE";
|
||||
for (s32 i = 1; i < ARRAYCOUNT(objTypes); ++i) {
|
||||
objTypes[i] = fmtObjType(i);
|
||||
}
|
||||
|
||||
g_DebuggerActive = TRUE;
|
||||
}
|
||||
|
||||
static inline void debuggerHotKey(const s32 key, const bool pressed)
|
||||
{
|
||||
switch (key) {
|
||||
case SDLK_F1:
|
||||
if (pressed)
|
||||
g_DebuggerTimePasses ^= 1;
|
||||
break;
|
||||
case SDLK_F2:
|
||||
if (pressed)
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
break;
|
||||
case SDLK_F3:
|
||||
if (pressed)
|
||||
g_DebuggerFrameAdvance = 5;
|
||||
break;
|
||||
case SDLK_F4:
|
||||
advanceHeld = pressed;
|
||||
break;
|
||||
case SDLK_F5:
|
||||
if (pressed) {
|
||||
if (g_TickRateDiv <= 1) {
|
||||
g_TickRateDiv = 2;
|
||||
} else {
|
||||
g_TickRateDiv = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_F6:
|
||||
if (pressed) {
|
||||
g_TickRateDiv++;
|
||||
if (g_TickRateDiv > 5) {
|
||||
g_TickRateDiv = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerProcessEvent(void *data)
|
||||
{
|
||||
if (g_DebuggerActive) {
|
||||
SDL_Event *e = (SDL_Event *)data;
|
||||
if (e->type == SDL_KEYDOWN || e->type == SDL_KEYUP) {
|
||||
debuggerHotKey(e->key.keysym.sym, e->type == SDL_KEYDOWN);
|
||||
} else if (e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEBUTTONUP) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->button.windowID) {
|
||||
return;
|
||||
}
|
||||
} else if (e->type == SDL_MOUSEMOTION) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->motion.windowID) {
|
||||
return;
|
||||
}
|
||||
} else if (e->type == SDL_MOUSEWHEEL) {
|
||||
if (SDL_GetMouseFocus() != dbgwin || SDL_GetWindowID(dbgwin) != e->wheel.windowID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ImGui_ImplSDL2_ProcessEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerStartFrame(void)
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
static inline bool debuggerGetSurfaceInfo(struct hitthing *hit)
|
||||
{
|
||||
struct coord endpos;
|
||||
endpos.x = g_Vars.currentplayer->cam_pos.x + g_Vars.currentplayer->cam_look.x * 10000.f;
|
||||
endpos.y = g_Vars.currentplayer->cam_pos.y + g_Vars.currentplayer->cam_look.y * 10000.f;
|
||||
endpos.z = g_Vars.currentplayer->cam_pos.z + g_Vars.currentplayer->cam_look.z * 10000.f;
|
||||
|
||||
// get what rooms the LOS goes through
|
||||
RoomNum outrooms[17], tmprooms[8], srcrooms[2];
|
||||
srcrooms[0] = g_Vars.currentplayer->cam_room;
|
||||
srcrooms[1] = -1;
|
||||
outrooms[16] = -1;
|
||||
portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16);
|
||||
|
||||
// no prop was hit; check for bg hits
|
||||
for (s32 i = 0; outrooms[i] != -1; ++i) {
|
||||
if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], hit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void debuggerUpdatePropInfo(s32 clear)
|
||||
{
|
||||
if (showPropInfo) {
|
||||
if (clear) {
|
||||
lookatprop = nullptr;
|
||||
lookathitset = false;
|
||||
} else {
|
||||
lookatprop = propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
|
||||
if (!lookatprop) {
|
||||
// if we aren't looking at a prop, try to get the surface we're looking at
|
||||
lookathitset = debuggerGetSurfaceInfo(&lookathit);
|
||||
} else {
|
||||
lookathitset = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lookatprop = nullptr;
|
||||
lookathitset = false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void debuggerTeleportPlayer(struct coord& crd)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: teleporting player 1 to (%.2f, %.2f, %.2f)", crd.x, crd.y, crd.z);
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
struct chrdata *playerchr = g_Vars.players[0]->prop->chr;
|
||||
if (!playerchr) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: player 1 has no chr");
|
||||
return;
|
||||
}
|
||||
|
||||
RoomNum inrooms[9] = { -1 };
|
||||
RoomNum aboverooms[9] = { -1 };
|
||||
|
||||
bgFindRoomsByPos(&crd, inrooms, aboverooms, 8, NULL);
|
||||
|
||||
RoomNum *rooms = NULL;
|
||||
if (inrooms[0] != -1) {
|
||||
rooms = inrooms;
|
||||
} else if (aboverooms[0] != -1) {
|
||||
rooms = aboverooms;
|
||||
}
|
||||
|
||||
if (rooms) {
|
||||
const u32 old = playerchr->hidden;
|
||||
playerchr->hidden |= CHRHFLAG_WARPONSCREEN;
|
||||
chrMoveToPos(playerchr, &crd, rooms, g_Vars.players[0]->vv_theta, true);
|
||||
if ((old & CHRHFLAG_WARPONSCREEN) == 0) {
|
||||
playerchr->hidden &= ~CHRHFLAG_WARPONSCREEN;
|
||||
}
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: could not find any rooms at teleport destination");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void debuggerKillChr(struct chrdata *chr)
|
||||
{
|
||||
struct coord dmgdir = { 0.f, 0.f, 0.f };
|
||||
chrDamageByImpact(chr, 10000.f, &dmgdir, nullptr, nullptr, HITPART_GENERAL);
|
||||
}
|
||||
|
||||
static inline void debuggerKillPlayer(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: killing player 1");
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
struct chrdata *playerchr = g_Vars.players[0]->prop->chr;
|
||||
if (!playerchr) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: player 1 has no chr");
|
||||
return;
|
||||
}
|
||||
|
||||
debuggerKillChr(playerchr);
|
||||
}
|
||||
|
||||
static inline void debuggerHealPlayer(void)
|
||||
{
|
||||
sysLogPrintf(LOG_NOTE, "DBG: healing player 1");
|
||||
|
||||
if (!g_Vars.players[0] || !g_Vars.players[0]->prop) {
|
||||
sysLogPrintf(LOG_NOTE, "DBG: no player 1 or player 1 has no prop");
|
||||
return;
|
||||
}
|
||||
|
||||
player *prev = g_Vars.currentplayer;
|
||||
g_Vars.currentplayer = g_Vars.players[0];
|
||||
playerDisplayHealth();
|
||||
g_Vars.currentplayer->bondhealth = 1.f;
|
||||
g_Vars.currentplayer = prev;
|
||||
}
|
||||
|
||||
static inline void describeHand(hand *hand)
|
||||
{
|
||||
ImGui::Text("Gun num: %02x", hand->gset.weaponnum);
|
||||
ImGui::Text("Gun func: %02x", hand->gset.weaponfunc);
|
||||
ImGui::Text("Aim pos: %s", fmtCoord(hand->aimpos));
|
||||
ImGui::Text("Hit pos: %s", fmtCoord(hand->hitpos));
|
||||
}
|
||||
|
||||
static inline std::string& describeRoomList(RoomNum *rooms, s32 maxRooms, std::string& out)
|
||||
{
|
||||
for (s32 i = 0; i < maxRooms && rooms[i] >= 0; ++i) {
|
||||
out += strFmt("%03x ", rooms[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline void describeProjectile(projectile *prj)
|
||||
{
|
||||
ImGui::Text("Drop type: %04x", (u16)prj->droptype);
|
||||
ImGui::Text("Flags: %08x", prj->flags);
|
||||
ImGui::Text("Vel: %s", fmtCoord(prj->speed));
|
||||
}
|
||||
|
||||
static inline void describeObj(defaultobj *obj)
|
||||
{
|
||||
ImGui::Text("Type: %s (%02x)", fmtObjType(obj->type), obj->type);
|
||||
ImGui::Text("Model: %04x", (u16)obj->modelnum);
|
||||
ImGui::Text("Pad: %04x", (u16)obj->pad);
|
||||
ImGui::Text("Flags 1: %08x", obj->flags);
|
||||
ImGui::Text("Flags 2: %08x", obj->flags2);
|
||||
ImGui::Text("Flags 3: %08x", obj->flags3);
|
||||
ImGui::Text("Hidden 1: %08x", obj->hidden);
|
||||
ImGui::Text("Hidden 2: %02x", obj->hidden2);
|
||||
|
||||
if ((obj->hidden & OBJHFLAG_PROJECTILE) && obj->projectile) {
|
||||
if (ImGui::TreeNode(strFmt("Projectile (%p)", obj->projectile))) {
|
||||
describeProjectile(obj->projectile);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describeWeapon(weaponobj *wpn)
|
||||
{
|
||||
ImGui::Text("Gun num: %02x", wpn->weaponnum);
|
||||
ImGui::Text("Gun func: %02x", wpn->gunfunc);
|
||||
ImGui::Text("Fade out timer (60hz): %d", wpn->fadeouttimer60);
|
||||
ImGui::Text("Timer (240hz): %d", wpn->timer240);
|
||||
}
|
||||
|
||||
static inline void describeProp(prop *prop);
|
||||
|
||||
static inline void describeChr(chrdata *chr)
|
||||
{
|
||||
ImGui::Text("Number: %04x", (u16)chr->chrnum);
|
||||
ImGui::Text("Flags 1: %08x", chr->flags);
|
||||
ImGui::Text("Flags 2: %08x", chr->flags2);
|
||||
ImGui::Text("Hidden 1: %08x", chr->hidden);
|
||||
ImGui::Text("Hidden 2: %04x", chr->hidden2);
|
||||
ImGui::Text("Chr flags: %08x", chr->chrflags);
|
||||
ImGui::Text("Damage: %.3f", chr->damage);
|
||||
ImGui::Text("Shield: %.3f", chr->cshield);
|
||||
ImGui::Text("Body: %04x", (u16)chr->bodynum);
|
||||
ImGui::Text("Head: %02x", (u8)chr->headnum);
|
||||
ImGui::Text("Team: %02x", chr->team);
|
||||
ImGui::Text("Tude: %02x", chr->tude);
|
||||
ImGui::Text("Action: %s (%02x)", fmtActionType(chr->actiontype), (u8)chr->actiontype);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (chr->weapons_held[HAND_RIGHT]) {
|
||||
if (ImGui::TreeNode(strFmt("Right hand prop (%p)", chr->weapons_held[HAND_RIGHT]))) {
|
||||
describeProp(chr->weapons_held[HAND_RIGHT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
if (chr->weapons_held[HAND_LEFT]) {
|
||||
if (ImGui::TreeNode(strFmt("Left hand prop (%p)", chr->weapons_held[HAND_LEFT]))) {
|
||||
describeProp(chr->weapons_held[HAND_LEFT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
if (chr->weapons_held[2]) {
|
||||
if (ImGui::TreeNode(strFmt("Hat prop (%p)", chr->weapons_held[2]))) {
|
||||
describeProp(chr->weapons_held[2]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Controls");
|
||||
|
||||
if (ImGui::Button("Kill")) {
|
||||
debuggerKillChr(chr);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Heal")) {
|
||||
chr->damage = 0.f;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Sleep")) {
|
||||
chr->sleep = 127;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Wake")) {
|
||||
chr->sleep = 0;
|
||||
}
|
||||
|
||||
// line break
|
||||
|
||||
if (ImGui::Button("Drop guns")) {
|
||||
chrDropItemsForOwnerReap(chr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describeProp(prop *prop)
|
||||
{
|
||||
ImGui::Text(prop->active ? "Active" : "Inactive");
|
||||
ImGui::Text("Type: %s (%02x)", fmtPropType(prop->type), prop->type);
|
||||
ImGui::Text("Flags: %02x", prop->flags);
|
||||
ImGui::Text("Pos: %s", fmtCoord(prop->pos));
|
||||
|
||||
std::string roomstr = "";
|
||||
ImGui::Text("Rooms: %s", describeRoomList(prop->rooms, ARRAYCOUNT(prop->rooms), roomstr).c_str());
|
||||
|
||||
if (prop->obj) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("%s (%p)", fmtObjType(prop->obj->type), prop->obj))) {
|
||||
describeObj(prop->obj);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if ((prop->type == PROPTYPE_CHR || prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_EYESPY) && prop->chr) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("Chr (%p)", prop->chr))) {
|
||||
describeChr(prop->chr);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
} else if (prop->type == PROPTYPE_WEAPON && prop->weapon) {
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("Weapon (%p)", prop->weapon))) {
|
||||
describeWeapon(prop->weapon);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void describePlayer(player *plr)
|
||||
{
|
||||
ImGui::Text("Cam pos: %s", fmtCoord(plr->cam_pos));
|
||||
ImGui::Text("Cam look: %s", fmtCoord(plr->cam_look));
|
||||
ImGui::Text("Cam room: %03x", (u32)plr->cam_room);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Health: %.3f", plr->bondhealth);
|
||||
ImGui::Text("Shield: %.3f", plr->apparentarmour);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (plr->prop) {
|
||||
if (ImGui::TreeNode(strFmt("Prop (%p)", plr->prop))) {
|
||||
describeProp(plr->prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode("Right hand")) {
|
||||
describeHand(&plr->hands[HAND_RIGHT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Left hand")) {
|
||||
describeHand(&plr->hands[HAND_LEFT]);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void debuggerFrame(void)
|
||||
{
|
||||
if (!g_DebuggerActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (advanceHeld) {
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
}
|
||||
|
||||
expandLatch = false;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0.f, 0.f));
|
||||
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||
ImGui::Begin("Debugger", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
if (ImGui::CollapsingHeader("Debug")) {
|
||||
ImGui::SeparatorText("Player");
|
||||
|
||||
ImGui::PushItemWidth(56.f);
|
||||
ImGui::InputText("X", xstr, IM_ARRAYSIZE(xstr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("Y", ystr, IM_ARRAYSIZE(ystr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("Z", zstr, IM_ARRAYSIZE(zstr) - 1, ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::SameLine();
|
||||
ImGui::PopItemWidth();
|
||||
if (ImGui::Button("Warp")) {
|
||||
struct coord crd;
|
||||
crd.x = std::atof(xstr);
|
||||
crd.y = std::atof(ystr);
|
||||
crd.z = std::atof(zstr);
|
||||
debuggerTeleportPlayer(crd);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Kill")) {
|
||||
debuggerKillPlayer();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Heal")) {
|
||||
debuggerHealPlayer();
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Time");
|
||||
|
||||
bool timePasses = (g_DebuggerTimePasses != 0);
|
||||
if (ImGui::Checkbox("Time passes", &timePasses)) {
|
||||
g_DebuggerTimePasses = (s32)timePasses;
|
||||
}
|
||||
|
||||
s32 framediv = g_TickRateDiv;
|
||||
if (ImGui::InputInt("Tickrate", &framediv, 1, 2)) {
|
||||
if (framediv >= 0 && framediv < 60) {
|
||||
g_TickRateDiv = framediv;
|
||||
g_Vars.mininc60 = framediv;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("+1 frame")) {
|
||||
g_DebuggerFrameAdvance = 1;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+5 frames")) {
|
||||
g_DebuggerFrameAdvance = 5;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+10 frames")) {
|
||||
g_DebuggerFrameAdvance = 10;
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Other");
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Time")) {
|
||||
ImGui::Text("Level Frame#: %d", g_Vars.lvframenum);
|
||||
ImGui::Text("Level Tick (60hz): %d", g_Vars.lvframe60);
|
||||
ImGui::Text("Level Tick (240hz): %d", g_Vars.lvframe240);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Frame Time (60hz): %.2f", g_Vars.diffframe60f);
|
||||
ImGui::Text("Frame Time (240hz): %.2f", g_Vars.diffframe240f);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Lost Time (60hz): %d", g_Vars.lostframetime60t);
|
||||
ImGui::Text("Lost Time (240hz): %d", g_Vars.lostframetime240t);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Players")) {
|
||||
for (s32 i = 0; i < ARRAYCOUNT(g_Vars.players); ++i) {
|
||||
auto plr = g_Vars.players[i];
|
||||
if (plr) {
|
||||
if (ImGui::TreeNode(strFmt("Player %d (%p)###Player%p", i + 1, plr, plr))) {
|
||||
describePlayer(plr);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_Vars.activeprops && g_Vars.activeprops != g_Vars.activepropstail) {
|
||||
if (ImGui::CollapsingHeader("Props")) {
|
||||
ImGui::Text("Visible: %d", g_Vars.numonscreenprops);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox("Active props only", &showActiveProps);
|
||||
|
||||
ImGui::Combo("Filter prop", &propFilter, propTypes, ARRAYCOUNT(propTypes));
|
||||
ImGui::Combo("Filter obj", &objFilter, objTypes, ARRAYCOUNT(objTypes));
|
||||
|
||||
if (ImGui::Button("Expand all")) {
|
||||
expandLatch = true;
|
||||
expandValue = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Close all")) {
|
||||
expandLatch = true;
|
||||
expandValue = false;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto showProp = [&](struct prop *prop) {
|
||||
if (prop && (!propFilter || propFilter == prop->type)) {
|
||||
if (!objFilter || (prop->obj && prop->obj->type == objFilter)) {
|
||||
const bool focus = (focusPtr && ((void *)prop == focusPtr || (void *)prop->obj == focusPtr));
|
||||
if (expandLatch) {
|
||||
ImGui::SetNextItemOpen(expandValue);
|
||||
} else if (focus) {
|
||||
ImGui::SetNextItemOpen(true);
|
||||
focusPtr = nullptr;
|
||||
}
|
||||
if (ImGui::TreeNode(strFmt("%s (%p)###Prop%p", fmtPropType(prop->type), prop, prop))) {
|
||||
if (focus) {
|
||||
ImGui::SetScrollHereY();
|
||||
}
|
||||
describeProp(prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (showActiveProps) {
|
||||
// show the active props list
|
||||
struct prop *prop;
|
||||
struct prop *next;
|
||||
bool done;
|
||||
prop = g_Vars.activeprops;
|
||||
do {
|
||||
next = prop->next;
|
||||
done = next == g_Vars.pausedprops;
|
||||
showProp(prop);
|
||||
prop = next;
|
||||
} while (!done);
|
||||
} else {
|
||||
// show all props
|
||||
for (s32 i = 0; i < g_Vars.maxprops; ++i) {
|
||||
struct prop *prop = &g_Vars.props[i];
|
||||
showProp(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_ChrSlots && g_NumChrSlots) {
|
||||
if (ImGui::CollapsingHeader("Characters")) {
|
||||
ImGui::Text("Count: %d/%d", g_NumChrs, g_NumChrSlots);
|
||||
ImGui::Separator();
|
||||
for (s32 i = 0; i < g_NumChrSlots; ++i) {
|
||||
if (g_ChrSlots[i].chrnum >= 0) {
|
||||
if (ImGui::TreeNode(strFmt("Slot %3d: %04x (%p)", i, g_ChrSlots[i].chrnum, &g_ChrSlots[i]))) {
|
||||
describeChr(&g_ChrSlots[i]);
|
||||
if (g_ChrSlots[i].prop && ImGui::TreeNode(strFmt("Prop (%p)##chr", g_ChrSlots[i].prop))) {
|
||||
describeProp(g_ChrSlots[i].prop);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Stage")) {
|
||||
ImGui::Text("Number: %02x", g_Vars.stagenum);
|
||||
ImGui::Text("Index: %02x", g_StageIndex);
|
||||
ImGui::Text("Setup: %s", romdataFileGetName(g_Stages[g_StageIndex].setupfileid));
|
||||
ImGui::Text("Room count: %d", g_Vars.roomcount);
|
||||
if (g_Rooms && ImGui::TreeNode("Rooms")) {
|
||||
ImGui::Separator();
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
if (ImGui::TreeNode(strFmt("Room %03x", i))) {
|
||||
ImGui::Text("Loaded: %d", g_Rooms[i].loaded240);
|
||||
ImGui::Text("Flags: %04x", g_Rooms[i].flags);
|
||||
ImGui::Text("Portals: %d", g_Rooms[i].numportals);
|
||||
ImGui::Text("Centre: %s", fmtCoord(g_Rooms[i].centre));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Memory")) {
|
||||
ImGui::Text("Mema size: %uk", memaGetSize() / 1024);
|
||||
ImGui::Spacing();
|
||||
if (ImGui::TreeNode("Memp state")) {
|
||||
if (ImGui::BeginTable("MemaTab", 3)) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Pool");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Onboard");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Expansion");
|
||||
for (u8 i = MEMPOOL_STAGE; i <= MEMPOOL_PERMANENT; i += 2) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text((i == MEMPOOL_STAGE) ? "Stage" : "Permanent");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%uk/%uk", mempGetPoolFree(i, MEMBANK_ONBOARD) / 1024, mempGetPoolSize(i, MEMBANK_ONBOARD) / 1024);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%uk/%uk", mempGetPoolFree(i, MEMBANK_EXPANSION) / 1024, mempGetPoolSize(i, MEMBANK_EXPANSION) / 1024);
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if ((showPropInfo = ImGui::CollapsingHeader("Looking at"))) {
|
||||
if (lookatprop) {
|
||||
ImGui::Text("Looking at prop");
|
||||
describeProp(lookatprop);
|
||||
} else if (lookathitset) {
|
||||
ImGui::Text("Looking at surface");
|
||||
ImGui::Text("Hit pos: %s", fmtCoord(lookathit.pos));
|
||||
ImGui::Text("Texture: %04x", lookathit.texturenum);
|
||||
} else {
|
||||
ImGui::Text("Looking at nothing");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
extern "C" void debuggerEndFrame(void)
|
||||
{
|
||||
ImGui::Render();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
SDL_RenderSetScale(dbgren, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
|
||||
SDL_SetRenderDrawColor(dbgren, 0, 0, 0, 255);
|
||||
SDL_RenderClear(dbgren);
|
||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_RenderPresent(dbgren);
|
||||
}
|
||||
+14
-2
@@ -11,6 +11,9 @@
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
#include "fs.h"
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_BASEDIR_NAME "data"
|
||||
|
||||
@@ -149,7 +152,7 @@ s32 fsInit(void)
|
||||
if (portable) {
|
||||
path = "$E";
|
||||
} else {
|
||||
#ifdef PLATFORM_LINUX
|
||||
#if defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
|
||||
// check if there's a config in the working directory, otherwise default to homeDir
|
||||
if (fsFileSize("./" CONFIG_FNAME) >= 0) {
|
||||
path = ".";
|
||||
@@ -276,7 +279,16 @@ FILE *fsFileOpenRead(const char *name)
|
||||
return fopen(fsFullPath(name), "rb");
|
||||
}
|
||||
|
||||
void fsFileClose(FILE *f)
|
||||
void fsFileFree(FILE *f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
s32 fsCreateDir(const char *path)
|
||||
{
|
||||
#ifdef PLATFORM_WIN32
|
||||
return _mkdir(fsFullPath(path));
|
||||
#else
|
||||
return mkdir(fsFullPath(path), 0777);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2023 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,46 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features:
|
||||
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,268 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Note how SDL_Renderer is an _optional_ component of SDL2.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
|
||||
// it might be difficult to step out of those boundaries.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// CHANGELOG
|
||||
// 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3.
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
|
||||
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||
// 2021-09-21: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_sdlrenderer2.h"
|
||||
#include <stdint.h> // intptr_t
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||
#endif
|
||||
|
||||
// SDL_Renderer data
|
||||
struct ImGui_ImplSDLRenderer2_Data
|
||||
{
|
||||
SDL_Renderer* SDLRenderer;
|
||||
SDL_Texture* FontTexture;
|
||||
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_sdlrenderer2";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
bd->SDLRenderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLRenderer2_SetupRenderState()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// Clear out any viewports and cliprect set by the user
|
||||
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, nullptr);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, nullptr);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplSDLRenderer2_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// If there's a scale factor set by the user, use that instead
|
||||
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||
float rsx = 1.0f;
|
||||
float rsy = 1.0f;
|
||||
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
|
||||
ImVec2 render_scale;
|
||||
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||
struct BackupSDLRendererState
|
||||
{
|
||||
SDL_Rect Viewport;
|
||||
bool ClipEnabled;
|
||||
SDL_Rect ClipRect;
|
||||
};
|
||||
BackupSDLRendererState old = {};
|
||||
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
|
||||
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = render_scale;
|
||||
|
||||
// Render command lists
|
||||
ImGui_ImplSDLRenderer2_SetupRenderState();
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplSDLRenderer2_SetupRenderState();
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
|
||||
|
||||
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos));
|
||||
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv));
|
||||
#if SDL_VERSION_ATLEAST(2,0,19)
|
||||
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+
|
||||
#else
|
||||
const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
|
||||
#endif
|
||||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||
xy, (int)sizeof(ImDrawVert),
|
||||
color, (int)sizeof(ImDrawVert),
|
||||
uv, (int)sizeof(ImDrawVert),
|
||||
cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
|
||||
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified SDL_Renderer state
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
||||
}
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
bool ImGui_ImplSDLRenderer2_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
|
||||
if (bd->FontTexture == nullptr)
|
||||
{
|
||||
SDL_Log("error creating texture");
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
|
||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
io.Fonts->SetTexID(0);
|
||||
SDL_DestroyTexture(bd->FontTexture);
|
||||
bd->FontTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDLRenderer2_CreateDeviceObjects()
|
||||
{
|
||||
return ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,41 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Note how SDL_Renderer is an _optional_ component of SDL2.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
|
||||
// it might be difficult to step out of those boundaries.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Renderer;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -0,0 +1,129 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+320
-49
@@ -10,6 +10,7 @@
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "system.h"
|
||||
#include "debugger.h"
|
||||
#include "fs.h"
|
||||
|
||||
#if !SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
@@ -28,6 +29,9 @@
|
||||
#define WHEEL_UP_MASK SDL_BUTTON(VK_MOUSE_WHEEL_UP - VK_MOUSE_BEGIN + 1)
|
||||
#define WHEEL_DN_MASK SDL_BUTTON(VK_MOUSE_WHEEL_DN - VK_MOUSE_BEGIN + 1)
|
||||
|
||||
#define CURSOR_HIDE_THRESHOLD 1
|
||||
#define CURSOR_HIDE_TIME 3000000 // us
|
||||
|
||||
static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
|
||||
|
||||
#define CONTROLLERCFG_DEFAULT { \
|
||||
@@ -41,7 +45,8 @@ static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
|
||||
.deadzone = { DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE_RY }, \
|
||||
.stickCButtons = 0, \
|
||||
.swapSticks = 1, \
|
||||
.deviceIndex = -1 \
|
||||
.deviceIndex = -1, \
|
||||
.cancelCButtons = 0, \
|
||||
}
|
||||
|
||||
static struct controllercfg {
|
||||
@@ -53,6 +58,7 @@ static struct controllercfg {
|
||||
s32 stickCButtons;
|
||||
s32 swapSticks;
|
||||
s32 deviceIndex;
|
||||
s32 cancelCButtons;
|
||||
} padsCfg[INPUT_MAX_CONTROLLERS] = {
|
||||
CONTROLLERCFG_DEFAULT,
|
||||
CONTROLLERCFG_DEFAULT,
|
||||
@@ -69,18 +75,28 @@ static s32 connectedMask = 0;
|
||||
|
||||
static s32 numJoysticks = 0;
|
||||
|
||||
static s32 useHIDAPI = 1;
|
||||
static s32 useRawInput = 1;
|
||||
|
||||
static s32 mouseEnabled = 1;
|
||||
static s32 mouseLocked = 0;
|
||||
static s32 mouseDefaultLocked = 0;
|
||||
static s32 mouseX, mouseY;
|
||||
static s32 mouseDX, mouseDY;
|
||||
static u32 mouseButtons;
|
||||
static s32 mouseWheel = 0;
|
||||
|
||||
static f32 mouseSensX = 1.5f;
|
||||
static f32 mouseSensY = 1.5f;
|
||||
static s32 mouseLocked = 0;
|
||||
static s32 mouseLockMode = MLOCK_AUTO;
|
||||
static u64 mouseCursorTime = 0;
|
||||
static s32 mouseShowCursor = 1;
|
||||
|
||||
static f32 mouseSensX = 2.5f;
|
||||
static f32 mouseSensY = 2.5f;
|
||||
|
||||
static s32 lastKey = 0;
|
||||
static char lastChar = 0;
|
||||
static s32 textInput = 0;
|
||||
|
||||
static char *clipboardText = NULL;
|
||||
|
||||
static const char *ckNames[CK_TOTAL_COUNT] = {
|
||||
"R_CBUTTONS",
|
||||
@@ -103,8 +119,8 @@ static const char *ckNames[CK_TOTAL_COUNT] = {
|
||||
"STICK_XPOS",
|
||||
"STICK_YNEG",
|
||||
"STICK_YPOS",
|
||||
"CK_0010",
|
||||
"CK_0020",
|
||||
"ACCEPT_BUTTON",
|
||||
"CANCEL_BUTTON",
|
||||
"CK_0040",
|
||||
"CK_0080",
|
||||
"CK_0100",
|
||||
@@ -169,6 +185,8 @@ static const char *vkJoyNames[] = {
|
||||
|
||||
static char vkNames[VK_TOTAL_COUNT][64];
|
||||
|
||||
static s8 vkPrevState[VK_TOTAL_COUNT];
|
||||
|
||||
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
|
||||
{
|
||||
// TODO: make VK constants for all these
|
||||
@@ -209,6 +227,8 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
|
||||
{ CK_C_U, SDL_CONTROLLER_BUTTON_DPAD_UP },
|
||||
{ CK_C_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT },
|
||||
{ CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT },
|
||||
{ CK_ACCEPT, SDL_CONTROLLER_BUTTON_A },
|
||||
{ CK_CANCEL, SDL_CONTROLLER_BUTTON_B },
|
||||
{ CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK },
|
||||
};
|
||||
|
||||
@@ -319,6 +339,14 @@ static inline void inputInitController(const s32 cidx, const s32 jidx)
|
||||
|
||||
sysLogPrintf(LOG_NOTE, "input: assigned controller '%d: (%s)' (id %d) to player %d",
|
||||
jidx, SDL_GameControllerName(pads[cidx]), inputControllerGetId(pads[cidx]), cidx);
|
||||
|
||||
SDL_Joystick* joy = SDL_GameControllerGetJoystick(pads[cidx]);
|
||||
if (joy) {
|
||||
char guidStr[1024] = "";
|
||||
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
|
||||
SDL_JoystickGetGUIDString(guid, guidStr, sizeof(guidStr));
|
||||
sysLogPrintf(LOG_NOTE, "input: GUID for controller %d: %s", jidx, guidStr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void inputCloseController(const s32 cidx)
|
||||
@@ -512,10 +540,18 @@ static int inputEventFilter(void *data, SDL_Event *event)
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_TEXTINPUT:
|
||||
if (!lastChar && event->text.text[0] && (u8)event->text.text[0] < 0x80) {
|
||||
lastChar = event->text.text[0];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
debuggerProcessEvent(event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -644,6 +680,38 @@ static inline void inputLoadBinds(void)
|
||||
|
||||
s32 inputInit(void)
|
||||
{
|
||||
// Set SDL hints before initializing the controller subsystem.
|
||||
if (useHIDAPI) {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1");
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1");
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 22)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
|
||||
// the two hints below enable Rumble and Motion Sensor for PS4/5 pads connected via bluetooth
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 23, 2)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1");
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 25, 1)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 26, 0)
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1");
|
||||
#endif
|
||||
}
|
||||
if (useRawInput) {
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1");
|
||||
}
|
||||
|
||||
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC)) {
|
||||
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
|
||||
}
|
||||
@@ -668,7 +736,9 @@ s32 inputInit(void)
|
||||
inputSetDefaultKeyBinds(i, 0);
|
||||
}
|
||||
|
||||
inputLockMouse(mouseDefaultLocked);
|
||||
if (mouseLockMode != MLOCK_AUTO) {
|
||||
inputLockMouse(mouseLockMode);
|
||||
}
|
||||
|
||||
// update the axis maps
|
||||
// NOTE: by default sticks get swapped for 1.2: "right stick" here means left stick on your controller
|
||||
@@ -719,6 +789,14 @@ s32 inputReadController(s32 idx, OSContPad *npad)
|
||||
|
||||
npad->button = 0;
|
||||
|
||||
if (textInput) {
|
||||
npad->stick_x = 0;
|
||||
npad->stick_y = 0;
|
||||
npad->rstick_x = 0;
|
||||
npad->rstick_y = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < CONT_NUM_BUTTONS; ++i) {
|
||||
if (inputBindPressed(idx, i)) {
|
||||
npad->button |= 1U << i;
|
||||
@@ -730,12 +808,22 @@ s32 inputReadController(s32 idx, OSContPad *npad)
|
||||
npad->stick_x = xdiff < 0 ? -0x80 : (xdiff > 0 ? 0x7F : 0);
|
||||
npad->stick_y = ydiff < 0 ? -0x80 : (ydiff > 0 ? 0x7F : 0);
|
||||
|
||||
const struct controllercfg *cfg = &padsCfg[idx];
|
||||
|
||||
if (cfg->cancelCButtons) {
|
||||
// opposite C buttons cancel each other out
|
||||
if ((npad->button & (L_CBUTTONS | R_CBUTTONS)) == (L_CBUTTONS | R_CBUTTONS)) {
|
||||
npad->button &= ~(L_CBUTTONS | R_CBUTTONS);
|
||||
}
|
||||
if ((npad->button & (U_CBUTTONS | D_CBUTTONS)) == (U_CBUTTONS | D_CBUTTONS)) {
|
||||
npad->button &= ~(U_CBUTTONS | D_CBUTTONS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pads[idx]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct controllercfg *cfg = &padsCfg[idx];
|
||||
|
||||
s32 leftX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][0]);
|
||||
s32 leftY = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][1]);
|
||||
s32 rightX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[1][0]);
|
||||
@@ -790,8 +878,12 @@ static inline void inputUpdateMouse(void)
|
||||
|
||||
mouseWheel = 0;
|
||||
|
||||
s32 mdx = 0;
|
||||
s32 mdy = 0;
|
||||
SDL_GetRelativeMouseState(&mdx, &mdy);
|
||||
if (mouseLocked) {
|
||||
SDL_GetRelativeMouseState(&mouseDX, &mouseDY);
|
||||
mouseDX = mdx;
|
||||
mouseDY = mdy;
|
||||
} else {
|
||||
mouseDX = mx - mouseX;
|
||||
mouseDY = my - mouseY;
|
||||
@@ -800,10 +892,29 @@ static inline void inputUpdateMouse(void)
|
||||
mouseX = mx;
|
||||
mouseY = my;
|
||||
|
||||
if (!mouseLocked && (mouseButtons & SDL_BUTTON_LMASK)) {
|
||||
inputLockMouse(1);
|
||||
} else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) {
|
||||
inputLockMouse(0);
|
||||
const s32 mouseFocus = (SDL_GetMouseFocus() == videoGetWindowHandle());
|
||||
if (!mouseFocus) {
|
||||
mouseDX = 0;
|
||||
mouseDY = 0;
|
||||
mouseWheel = 0;
|
||||
mouseButtons = 0;
|
||||
if (!mouseShowCursor) {
|
||||
inputMouseShowCursor(1);
|
||||
}
|
||||
} else {
|
||||
// if MLOCK_AUTO is enabled, disable cursor if mouse is unlocked
|
||||
// and we haven't moved it for a few seconds
|
||||
if (mouseLockMode == MLOCK_AUTO && !mouseLocked) {
|
||||
if (abs(mouseDX) > CURSOR_HIDE_THRESHOLD || abs(mouseDY) > CURSOR_HIDE_THRESHOLD) {
|
||||
if (!mouseShowCursor) {
|
||||
inputMouseShowCursor(1);
|
||||
}
|
||||
} else if (sysGetMicroseconds() > mouseCursorTime) {
|
||||
if (mouseShowCursor) {
|
||||
inputMouseShowCursor(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -901,6 +1012,16 @@ void inputControllerSetDualAnalog(s32 cidx, s32 enable)
|
||||
padsCfg[cidx].stickCButtons = !enable;
|
||||
}
|
||||
|
||||
s32 inputControllerGetCancelCButtons(s32 cidx)
|
||||
{
|
||||
return padsCfg[cidx].cancelCButtons;
|
||||
}
|
||||
|
||||
void inputControllerSetCancelCButtons(s32 cidx, s32 cancel)
|
||||
{
|
||||
padsCfg[cidx].cancelCButtons = cancel;
|
||||
}
|
||||
|
||||
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis)
|
||||
{
|
||||
return padsCfg[cidx].sens[stick * 2 + axis];
|
||||
@@ -970,6 +1091,13 @@ const char *inputGetConnectedControllerName(s32 id)
|
||||
|
||||
snprintf(fullName, sizeof(fullName), "%d: %s", jidx, name);
|
||||
|
||||
// replace non-ascii chars with spaces
|
||||
for (char *p = fullName; *p; ++p) {
|
||||
if ((u32)*p >= 0x7f) {
|
||||
*p = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return fullName;
|
||||
}
|
||||
|
||||
@@ -1051,9 +1179,13 @@ s32 inputKeyPressed(u32 vk)
|
||||
if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) {
|
||||
const u8 *state = SDL_GetKeyboardState(NULL);
|
||||
return state[vk - VK_KEYBOARD_BEGIN];
|
||||
} else if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) {
|
||||
return mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1);
|
||||
} else if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) {
|
||||
}
|
||||
|
||||
if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) {
|
||||
return (mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1)) != 0;
|
||||
}
|
||||
|
||||
if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) {
|
||||
vk -= VK_JOY_BEGIN;
|
||||
const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS;
|
||||
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) {
|
||||
@@ -1067,9 +1199,18 @@ s32 inputKeyPressed(u32 vk)
|
||||
}
|
||||
return SDL_GameControllerGetButton(pads[idx], vk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 inputKeyJustPressed(u32 vk)
|
||||
{
|
||||
const s8 pressed = inputKeyPressed(vk);
|
||||
const s32 result = pressed && !vkPrevState[vk];
|
||||
vkPrevState[vk] = pressed;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline u32 inputContToContKey(const u32 cont)
|
||||
{
|
||||
if (cont == 0) {
|
||||
@@ -1099,10 +1240,11 @@ s32 inputMouseIsLocked(void)
|
||||
return mouseLocked;
|
||||
}
|
||||
|
||||
void inputMouseGetPosition(s32 *x, s32 *y)
|
||||
s32 inputMouseGetPosition(s32 *x, s32 *y)
|
||||
{
|
||||
if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth();
|
||||
if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight();
|
||||
return (mouseDX != 0 || mouseDY != 0);
|
||||
}
|
||||
|
||||
void inputMouseGetRawDelta(s32 *dx, s32 *dy)
|
||||
@@ -1111,32 +1253,28 @@ void inputMouseGetRawDelta(s32 *dx, s32 *dy)
|
||||
if (dy) *dy = mouseDY;
|
||||
}
|
||||
|
||||
void inputMouseGetScaledDelta(f32 *dx, f32 *dy)
|
||||
void inputMouseGetScaledDelta(f32* dx, f32* dy)
|
||||
{
|
||||
f32 mdx, mdy;
|
||||
if (mouseLocked) {
|
||||
mdx = mouseSensX * (f32)mouseDX / 100.0f;
|
||||
mdy = mouseSensY * (f32)mouseDY / 100.0f;
|
||||
} else {
|
||||
mdx = 0.f;
|
||||
mdy = 0.f;
|
||||
}
|
||||
if (dx) *dx = mdx;
|
||||
if (dy) *dy = mdy;
|
||||
f32 mdx = 0.f, mdy = 0.f;
|
||||
|
||||
if (mouseLocked) {
|
||||
mdx = mouseSensX * ((f32)mouseDX / 3.5f) * 0.022f;
|
||||
mdy = mouseSensY * ((f32)mouseDY / 3.5f) * 0.022f;
|
||||
}
|
||||
if (dx) *dx = mdx;
|
||||
if (dy) *dy = mdy;
|
||||
}
|
||||
|
||||
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy)
|
||||
void inputMouseGetAbsScaledDelta(f32* dx, f32* dy)
|
||||
{
|
||||
f32 mdx, mdy;
|
||||
if (mouseLocked) {
|
||||
mdx = fabsf(mouseSensX) * (f32)mouseDX / 100.0f;
|
||||
mdy = fabsf(mouseSensY) * (f32)mouseDY / 100.0f;
|
||||
} else {
|
||||
mdx = 0.f;
|
||||
mdy = 0.f;
|
||||
}
|
||||
if (dx) *dx = mdx;
|
||||
if (dy) *dy = mdy;
|
||||
f32 mdx = 0.f, mdy = 0.f;
|
||||
|
||||
if (mouseLocked) {
|
||||
mdx = fabsf(mouseSensX) * ((f32)mouseDX / 3.5f) * 0.022f;
|
||||
mdy = fabsf(mouseSensY) * ((f32)mouseDY / 3.5f) * 0.022f;
|
||||
}
|
||||
if (dx) *dx = mdx;
|
||||
if (dy) *dy = mdy;
|
||||
}
|
||||
|
||||
void inputMouseGetSpeed(f32 *x, f32 *y)
|
||||
@@ -1159,21 +1297,41 @@ s32 inputMouseIsEnabled(void)
|
||||
void inputMouseEnable(s32 enabled)
|
||||
{
|
||||
mouseEnabled = !!enabled;
|
||||
if (!mouseEnabled && mouseLocked) {
|
||||
if (!mouseEnabled && mouseLockMode != MLOCK_ON && mouseLocked) {
|
||||
inputLockMouse(0);
|
||||
}
|
||||
}
|
||||
|
||||
s32 inputGetMouseDefaultLocked(void)
|
||||
s32 inputAutoLockMouse(s32 wantlock)
|
||||
{
|
||||
return mouseDefaultLocked;
|
||||
if (mouseEnabled && mouseLockMode == MLOCK_AUTO) {
|
||||
inputLockMouse(wantlock);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void inputSetMouseDefaultLocked(s32 defaultLocked)
|
||||
void inputMouseShowCursor(s32 show)
|
||||
{
|
||||
mouseDefaultLocked = !!defaultLocked;
|
||||
if (mouseEnabled) {
|
||||
inputLockMouse(mouseDefaultLocked);
|
||||
mouseShowCursor = !!show;
|
||||
SDL_ShowCursor(mouseShowCursor);
|
||||
if (show) {
|
||||
mouseCursorTime = sysGetMicroseconds() + CURSOR_HIDE_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
s32 inputGetMouseLockMode(void)
|
||||
{
|
||||
return mouseLockMode;
|
||||
}
|
||||
|
||||
void inputSetMouseLockMode(s32 lockmode)
|
||||
{
|
||||
mouseLockMode = lockmode;
|
||||
if (lockmode == MLOCK_ON) {
|
||||
inputLockMouse(1);
|
||||
} else {
|
||||
inputLockMouse(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1251,14 +1409,126 @@ s32 inputGetLastKey(void)
|
||||
return lastKey;
|
||||
}
|
||||
|
||||
void inputStartTextInput(void)
|
||||
{
|
||||
lastChar = 0;
|
||||
lastKey = 0;
|
||||
textInput = 1;
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
|
||||
void inputClearLastTextChar(void)
|
||||
{
|
||||
lastChar = 0;
|
||||
}
|
||||
|
||||
char inputGetLastTextChar(void)
|
||||
{
|
||||
return lastChar;
|
||||
}
|
||||
|
||||
static inline s32 filterChar(const char ch)
|
||||
{
|
||||
return isalnum(ch) || ch == ' ' || ch == '?' || ch == '!' || ch == '.';
|
||||
}
|
||||
|
||||
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly)
|
||||
{
|
||||
const s32 ctrlHeld = inputGetKeyModState() & KM_CTRL;
|
||||
|
||||
if (!ctrlHeld) {
|
||||
const char chr = inputGetLastTextChar();
|
||||
inputClearLastTextChar();
|
||||
const s32 valid = chr && (oskCharsOnly ? filterChar(chr) : isprint(chr));
|
||||
if (valid) {
|
||||
if (*curCol < outSize - 1) {
|
||||
out[(*curCol)++] = chr;
|
||||
out[*curCol] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const s32 key = inputGetLastKey();
|
||||
inputClearLastKey();
|
||||
if (ctrlHeld && (key == VK_A + ('v' - 'a'))) {
|
||||
// CTRL+V; paste from clipboard
|
||||
const char *clip = inputGetClipboard();
|
||||
if (clip) {
|
||||
const s32 remain = outSize - *curCol - 1;
|
||||
inputClearClipboard();
|
||||
*curCol += snprintf(out + *curCol, remain, "%s", clip);
|
||||
if (*curCol > outSize) {
|
||||
*curCol = outSize;
|
||||
}
|
||||
}
|
||||
} else if (key == VK_BACKSPACE) {
|
||||
if (*curCol) {
|
||||
out[--*curCol] = '\0';
|
||||
} else {
|
||||
out[0] = '\0';
|
||||
}
|
||||
} else if (key == VK_RETURN) {
|
||||
if (out[0] && *curCol) {
|
||||
return 1;
|
||||
}
|
||||
} else if (key == VK_ESCAPE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void inputClearClipboard(void)
|
||||
{
|
||||
if (clipboardText) {
|
||||
SDL_free(clipboardText);
|
||||
clipboardText = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char *inputGetClipboard(void)
|
||||
{
|
||||
if (!clipboardText) {
|
||||
char *text = SDL_GetClipboardText();
|
||||
if (text) {
|
||||
clipboardText = text;
|
||||
// remove non-printable and multibyte chars
|
||||
for (; *text; ++text) {
|
||||
if ((u8)*text < 0x20 || (u8)*text >= 0x7F) {
|
||||
*text = '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return clipboardText;
|
||||
}
|
||||
|
||||
void inputStopTextInput(void)
|
||||
{
|
||||
SDL_StopTextInput();
|
||||
textInput = 0;
|
||||
}
|
||||
|
||||
s32 inputIsTextInputActive(void)
|
||||
{
|
||||
return textInput;
|
||||
}
|
||||
|
||||
u32 inputGetKeyModState(void)
|
||||
{
|
||||
return SDL_GetModState();
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void inputConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1);
|
||||
configRegisterInt("Input.MouseDefaultLocked", &mouseDefaultLocked, 0, 1);
|
||||
configRegisterInt("Input.MouseLockMode", &mouseLockMode, MLOCK_OFF, MLOCK_AUTO);
|
||||
configRegisterFloat("Input.MouseSpeedX", &mouseSensX, -10.f, 10.f);
|
||||
configRegisterFloat("Input.MouseSpeedY", &mouseSensY, -10.f, 10.f);
|
||||
configRegisterInt("Input.FakeGamepads", &fakeControllers, 0, 4);
|
||||
configRegisterInt("Input.FirstGamepadNum", &firstController, 0, 3);
|
||||
configRegisterInt("Input.UseHIDAPI", &useHIDAPI, 0, 1);
|
||||
configRegisterInt("Input.UseRawInput", &useRawInput, 0, 1);
|
||||
|
||||
char secname[] = "Input.Player1.Binds";
|
||||
char keyname[256] = { 0 };
|
||||
@@ -1275,6 +1545,7 @@ PD_CONSTRUCTOR static void inputConfigInit(void)
|
||||
configRegisterFloat(strFmt("%s.RStickScaleX", secname), &padsCfg[c].sens[2], -10.f, 10.f);
|
||||
configRegisterFloat(strFmt("%s.RStickScaleY", secname), &padsCfg[c].sens[3], -10.f, 10.f);
|
||||
configRegisterInt(strFmt("%s.StickCButtons", secname), &padsCfg[c].stickCButtons, 0, 1);
|
||||
configRegisterInt(strFmt("%s.CancelCButtons", secname), &padsCfg[c].cancelCButtons, 0, 1);
|
||||
configRegisterInt(strFmt("%s.SwapSticks", secname), &padsCfg[c].swapSticks, 0, 1);
|
||||
configRegisterInt(strFmt("%s.ControllerIndex", secname), &padsCfg[c].deviceIndex, -1, 0x7FFFFFFF);
|
||||
secname[13] = '.';
|
||||
|
||||
+7
-8
@@ -6,6 +6,7 @@
|
||||
#include <errno.h>
|
||||
#include <PR/os_internal.h>
|
||||
#include <PR/rcp.h>
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
#include "input.h"
|
||||
#include "video.h"
|
||||
@@ -277,7 +278,7 @@ static inline void osEeepromLoad(const char *fname)
|
||||
FILE *fp = fsFileOpenRead(fname);
|
||||
if (fp) {
|
||||
fread(eeprom, 1, EEPROM_SIZE, fp);
|
||||
fsFileClose(fp);
|
||||
fsFileFree(fp);
|
||||
} else {
|
||||
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
|
||||
}
|
||||
@@ -289,7 +290,7 @@ static inline void osEeepromSave(const char *fname)
|
||||
FILE* fp = fsFileOpenWrite(fname);
|
||||
if (fp) {
|
||||
fwrite(eeprom, 1, EEPROM_SIZE, fp);
|
||||
fsFileClose(fp);
|
||||
fsFileFree(fp);
|
||||
} else {
|
||||
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
|
||||
}
|
||||
@@ -433,7 +434,7 @@ void osInvalDCache(void *a, s32 b)
|
||||
|
||||
}
|
||||
|
||||
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, size_t nbytes, OSMesgQueue *mq)
|
||||
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq)
|
||||
{
|
||||
memcpy(vAddr, (const void *)devAddr, nbytes);
|
||||
return 0;
|
||||
@@ -466,23 +467,21 @@ OSIntMask osSetIntMask(OSIntMask mask)
|
||||
|
||||
/* libc compatibility wrappers */
|
||||
|
||||
#ifndef HAVE_BZERO
|
||||
#ifndef PLATFORM_OSX
|
||||
|
||||
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
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "config.h"
|
||||
#include "mod.h"
|
||||
#include "system.h"
|
||||
#include "debugger.h"
|
||||
#include "utils.h"
|
||||
|
||||
u32 g_OsMemSize = 0;
|
||||
@@ -88,6 +89,7 @@ static void cleanup(void)
|
||||
sysLogPrintf(LOG_NOTE, "shutdown");
|
||||
inputSaveBinds();
|
||||
configSave(CONFIG_PATH);
|
||||
videoShutdown();
|
||||
crashShutdown();
|
||||
// TODO: actually shut down all subsystems
|
||||
}
|
||||
@@ -107,6 +109,9 @@ int main(int argc, const char **argv)
|
||||
inputInit();
|
||||
audioInit();
|
||||
romdataInit();
|
||||
debuggerInit();
|
||||
|
||||
g_ValidGbcRomFound = romdataCheckGbcRom();
|
||||
|
||||
gameInit();
|
||||
|
||||
@@ -159,6 +164,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
|
||||
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
|
||||
configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1);
|
||||
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
|
||||
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
|
||||
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
|
||||
@@ -179,5 +185,6 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
|
||||
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
|
||||
configRegisterInt(strFmt("Game.Player%d.UseKeyReloads", i), &g_PlayerExtCfg[j].usereloads, 0, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
#include "types.h"
|
||||
#include "constants.h"
|
||||
#include "bss.h"
|
||||
#include "game/pak.h"
|
||||
#include "game/filelist.h"
|
||||
#include "game/menu.h"
|
||||
#include "game/savebuffer.h"
|
||||
#include "game/mplayer/mplayer.h"
|
||||
#include <string.h>
|
||||
#include "fs.h"
|
||||
#include "system.h"
|
||||
#include "mpsetups.h"
|
||||
|
||||
/*
|
||||
MP Setup File Format
|
||||
# header
|
||||
[version{1}]
|
||||
[defaultsetup{1}]
|
||||
[numsetups{1}]
|
||||
# setups
|
||||
[setup_1{80}]
|
||||
...
|
||||
[setup_n{80}]
|
||||
*/
|
||||
|
||||
#define MPSETUP_VERSION 1
|
||||
|
||||
#define MPSETUP_EXPORTDIR "$S/exported/"
|
||||
#define MPSETUP_FILENAME "mpsetups"
|
||||
#define MPSETUP_FILENAME_EXP "mpsetups-ext"
|
||||
|
||||
#define MPSETUP_OP_DEFAULT 0
|
||||
#define MPSETUP_OP_IMPORT 1
|
||||
#define MPSETUP_OP_EXPORT 2
|
||||
|
||||
#define MPSETUP_IMPORT_OVERWRITE 0
|
||||
#define MPSETUP_IMPORT_ADD 1
|
||||
|
||||
#define MPSETUP_IMPORT_CONFLICT 0x1313
|
||||
|
||||
extern struct menudialogdef g_MpSaveSetupNameMenuDialog;
|
||||
|
||||
s16 g_MpCurrentSetup = -1;
|
||||
struct mpsetupfile g_MpSetupFile;
|
||||
|
||||
static struct mpsetupfile g_ImportMpSetupFile;
|
||||
static u64 g_MpImportExportFilter[2];
|
||||
|
||||
static char g_StatusText[128];
|
||||
static char g_TitleImportExportDialog[20];
|
||||
static char g_LabelSetDefault[20] = "Set Default\n";
|
||||
|
||||
/* extended mpsetup menu definitions */
|
||||
|
||||
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data);
|
||||
|
||||
static struct menuitem g_StatusOkMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)g_StatusText,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_347, // "OK"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_StatusOkDialog = {
|
||||
MENUDIALOGTYPE_SUCCESS,
|
||||
L_OPTIONS_345, // "Cool!"
|
||||
g_StatusOkMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_DISABLEBANNER,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_StatusErrorMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)g_StatusText,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_347, // "OK"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
/* public */
|
||||
struct menudialogdef g_StatusErrorDialog = {
|
||||
MENUDIALOGTYPE_DANGER,
|
||||
L_OPTIONS_277, // "Failed"
|
||||
g_StatusErrorMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_DISABLEBANNER,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_RenameSetupItems[] = {
|
||||
#if VERSION != VERSION_JPN_FINAL
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)"Enter the setup name:\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_KEYBOARD,
|
||||
18,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
menuhandlerRenameSetup,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_RenameSetupDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Setup Name:\n",
|
||||
g_RenameSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_DeleteSetupItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t)"Delete Setup?\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_385, // "No"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CENTRE,
|
||||
L_OPTIONS_386, // "Yes"
|
||||
0,
|
||||
menuhandlerDeleteSetup,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_DeleteSetupDialog = {
|
||||
MENUDIALOGTYPE_DANGER,
|
||||
(uintptr_t)"Delete Setup\n",
|
||||
g_DeleteSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ImportExportItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LIST,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
|
||||
140,
|
||||
0x0000004d,
|
||||
menuhandlerImportOrExportSettings,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ImportExportDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) g_TitleImportExportDialog,
|
||||
g_ImportExportItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ManageImportExportItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_OP_IMPORT,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Import Settings\n",
|
||||
0,
|
||||
menuhandlerOpenImportExportDialog,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_OP_EXPORT,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Export Settings\n",
|
||||
0,
|
||||
menuhandlerOpenImportExportDialog,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ManageImportExportDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) "Import/Export\n",
|
||||
g_ManageImportExportItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_MpManageSettingsListItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LIST,
|
||||
0,
|
||||
MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
|
||||
160,
|
||||
0x00000042,
|
||||
menuhandlerSelectSetupHandler,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
|
||||
};
|
||||
|
||||
/* public */
|
||||
struct menudialogdef g_ManageSettingsDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t) "Manage Settings\n",
|
||||
g_MpManageSettingsListItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
&g_ManageImportExportDialog,
|
||||
};
|
||||
|
||||
static struct menuitem g_ManageSetupItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Rename\n",
|
||||
0,
|
||||
menuhandlerSetupRename,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Delete\n",
|
||||
0,
|
||||
menuhandlerSetupDelete,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)g_LabelSetDefault,
|
||||
0,
|
||||
menuhandlerSetupSetDefault,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ManageSetupDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Manage Setup",
|
||||
g_ManageSetupItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct menuitem g_ImportOverrideItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_LABEL,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
|
||||
(uintptr_t) "How to resolve setups\nwith the same name?\n",
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_IMPORT_ADD,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
(uintptr_t) "Add\n",
|
||||
0,
|
||||
menuhandlerImportAction,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
MPSETUP_IMPORT_OVERWRITE,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
(uintptr_t) "Overwrite\n",
|
||||
0,
|
||||
menuhandlerImportAction,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
static struct menudialogdef g_ImportOverrideDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Name Conflicts\n",
|
||||
g_ImportOverrideItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* common utils */
|
||||
|
||||
static s32 mpsetupDeserialize(FILE *f, struct mpsetupfile *setupfile)
|
||||
{
|
||||
s32 rx = 0;
|
||||
|
||||
rx += fread(&setupfile->version, sizeof(setupfile->version), 1, f);
|
||||
rx += fread(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
|
||||
rx += fread(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
|
||||
|
||||
for (int i = 0; i < setupfile->numsetups; ++i) {
|
||||
rx += fread(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
|
||||
}
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
static s32 mpsetupSerialize(FILE *f, struct mpsetupfile *setupfile)
|
||||
{
|
||||
s32 wx = 0;
|
||||
|
||||
wx += fwrite(&setupfile->version, sizeof(setupfile->version), 1, f);
|
||||
wx += fwrite(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
|
||||
wx += fwrite(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
|
||||
|
||||
for (int i = 0; i < setupfile->numsetups; ++i) {
|
||||
wx += fwrite(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
|
||||
}
|
||||
|
||||
return wx;
|
||||
}
|
||||
|
||||
static FILE *mpsetupOpenFile(bool write, u8 op) {
|
||||
const char *filename = fsFullPath("$S/" MPSETUP_FILENAME ".bin");
|
||||
|
||||
if (op == MPSETUP_OP_EXPORT) {
|
||||
// create export directory if it doesn't exist
|
||||
if (fsFileSize(MPSETUP_EXPORTDIR) < 0) {
|
||||
if (fsCreateDir(MPSETUP_EXPORTDIR) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
filename = fsFullPath(MPSETUP_EXPORTDIR MPSETUP_FILENAME_EXP ".bin");
|
||||
} else if (op == MPSETUP_OP_IMPORT) {
|
||||
// same name as export but different folder
|
||||
filename = fsFullPath("$S/" MPSETUP_FILENAME_EXP ".bin");
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
if (fsFileSize(filename) < 0) {
|
||||
// setup file doesn't exist: create one
|
||||
f = fsFileOpenWrite(filename);
|
||||
fsFileFree(f);
|
||||
}
|
||||
|
||||
if (write) {
|
||||
f = fsFileOpenWrite(filename);
|
||||
} else {
|
||||
f = fsFileOpenRead(filename);
|
||||
}
|
||||
|
||||
if (f == NULL) {
|
||||
sysLogPrintf(LOG_ERROR, "Unable to open mp setup file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile)
|
||||
{
|
||||
FILE *f = mpsetupOpenFile(true, op);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 nwritten = mpsetupSerialize(f, setupfile);
|
||||
if (nwritten < 1) {
|
||||
fsFileFree(f);
|
||||
sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file");
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write the setup file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op)
|
||||
{
|
||||
FILE *f = mpsetupOpenFile(false, op);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mpsetupDeserialize(f, setupfile);
|
||||
|
||||
if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) {
|
||||
mpsetupLoadSetup(setupfile->defaultsetup - 1);
|
||||
}
|
||||
|
||||
fsFileFree(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 mpsetupImportFile(u8 op, u8 skipOverlap)
|
||||
{
|
||||
if (!skipOverlap) {
|
||||
// check for names overlap
|
||||
u8 overlap = false;
|
||||
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
|
||||
for (int j = 0; j < g_MpSetupFile.numsetups; ++j) {
|
||||
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
|
||||
overlap = true;
|
||||
return MPSETUP_IMPORT_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
|
||||
s16 overlapIdx = -1;
|
||||
for (int j = g_MpSetupFile.numsetups-1; j >= 0; --j) {
|
||||
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
|
||||
overlapIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s16 importIdx = overlapIdx;
|
||||
if (overlapIdx < 0 || op == MPSETUP_IMPORT_ADD) {
|
||||
if (g_MpSetupFile.numsetups == MPSETUP_MAXSETUPS) {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS);
|
||||
return -1;
|
||||
}
|
||||
importIdx = g_MpSetupFile.numsetups++;
|
||||
}
|
||||
|
||||
memcpy(g_MpSetupFile.setups[importIdx].bytes, g_ImportMpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
|
||||
}
|
||||
|
||||
return mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
static s32 mpsetupExportFile(void)
|
||||
{
|
||||
struct mpsetupfile expMpSetupFile;
|
||||
expMpSetupFile.numsetups = 0;
|
||||
expMpSetupFile.defaultsetup = 0;
|
||||
expMpSetupFile.version = MPSETUP_VERSION;
|
||||
|
||||
u8 maxsetups = MPSETUP_MAXSETUPS;
|
||||
maxsetups = MIN(maxsetups, g_MpSetupFile.numsetups);
|
||||
for (int i = 0; i < maxsetups; ++i) {
|
||||
u8 bank = i < 64 ? 0 : 1;
|
||||
u8 bit = i - bank * 64;
|
||||
if (g_MpImportExportFilter[bank] & (1 << bit)) {
|
||||
u8 n = expMpSetupFile.numsetups;
|
||||
expMpSetupFile.numsetups++;
|
||||
char *name = g_MpSetupFile.setups[i].bytes;
|
||||
memcpy(expMpSetupFile.setups[n].bytes, g_MpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
|
||||
expMpSetupFile.numsetups = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
s32 err = mpsetupSaveFile(MPSETUP_OP_EXPORT, &expMpSetupFile);
|
||||
if (err) {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write\nsetup file\n");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static s32 mpsetupDelete(void)
|
||||
{
|
||||
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) {
|
||||
u8* dst = g_MpSetupFile.setups[i].bytes;
|
||||
u8* src = g_MpSetupFile.setups[i+1].bytes;
|
||||
memcpy(dst, src, MPSETUP_BLOCKSIZE);
|
||||
}
|
||||
|
||||
if (g_MpCurrentSetup > slotindex) {
|
||||
g_MpCurrentSetup--;
|
||||
}
|
||||
else if (g_MpCurrentSetup == slotindex) {
|
||||
g_MpCurrentSetup = -1;
|
||||
}
|
||||
|
||||
if (g_MpSetupFile.defaultsetup > slotindex + 1) {
|
||||
g_MpSetupFile.defaultsetup--;
|
||||
}
|
||||
else if (g_MpSetupFile.defaultsetup == slotindex + 1) {
|
||||
g_MpSetupFile.defaultsetup = 0;
|
||||
}
|
||||
|
||||
g_MpSetupFile.numsetups--;
|
||||
return mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
/* menu handlers */
|
||||
|
||||
// Rename setup dialog
|
||||
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
char *name = data->keyboard.string;
|
||||
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
struct setupblock *setup = &g_MpSetupFile.setups[slotindex];
|
||||
s32 err;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETTEXT:
|
||||
strcpy(name, setup->bytes);
|
||||
break;
|
||||
case MENUOP_SETTEXT:
|
||||
strcpy(g_MpSetup.name, name);
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
strcpy(setup->bytes, name);
|
||||
err = mpsetupSaveSetup(slotindex, true);
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
} else {
|
||||
// TODO
|
||||
// menuPushDialog(&g_FilemgrFileSavedMenuDialog);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Delete setup dialog
|
||||
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 err = mpsetupDelete();
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
menuPopDialog();
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Import (or Export) settings dialog
|
||||
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *labels[] = {
|
||||
"Select All",
|
||||
"Select None",
|
||||
"Import",
|
||||
"Export",
|
||||
};
|
||||
|
||||
s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24;
|
||||
|
||||
struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile;
|
||||
|
||||
u8 numsetups = setupfile->numsetups;
|
||||
u8 numitems = numsetups + 3;
|
||||
u8 bank = data->list.value < 64 ? 0 : 1;
|
||||
u8 bit = data->list.value - bank * 64;
|
||||
u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0;
|
||||
u8 ofs;
|
||||
s32 err;
|
||||
u32 colour;
|
||||
s32 index;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETCOLOUR:
|
||||
colour = data->list.unk04;
|
||||
if (data->list.value == numitems - 1) {
|
||||
data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66;
|
||||
}
|
||||
break;
|
||||
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->list.value = numitems;
|
||||
break;
|
||||
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
if (data->list.value < numsetups) {
|
||||
return (uintptr_t) setupfile->setups[data->list.value].bytes;
|
||||
} else {
|
||||
// creates an offset to select the "Export" or "Import" label for the last item
|
||||
ofs = (data->list.value == numitems - 1) ? op - 1 : 0;
|
||||
return (intptr_t)labels[data->list.value - numsetups + ofs];
|
||||
}
|
||||
|
||||
case MENUOP_SET:
|
||||
if (data->list.value < setupfile->numsetups) {
|
||||
g_MpImportExportFilter[bank] ^= (1 << bit);
|
||||
} else {
|
||||
index = data->list.value - setupfile->numsetups;
|
||||
|
||||
switch (index) {
|
||||
// Select All
|
||||
case 0:
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
|
||||
break;
|
||||
// Select None
|
||||
case 1:
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0;
|
||||
break;
|
||||
// Export (or Import)
|
||||
case 2:
|
||||
if (hasselection) {
|
||||
err = op == MPSETUP_OP_IMPORT ? mpsetupImportFile(0, false) : mpsetupExportFile();
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
if (op == MPSETUP_OP_IMPORT) {
|
||||
// back to the 'Manage Settings' screen
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ManageSettingsDialog);
|
||||
} else {
|
||||
snprintf(g_StatusText, sizeof(g_StatusText), "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP);
|
||||
menuPushDialog(&g_StatusOkDialog);
|
||||
}
|
||||
} else {
|
||||
if (err == MPSETUP_IMPORT_CONFLICT) {
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ImportOverrideDialog);
|
||||
} else {
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->list.value = 0x000fffff;
|
||||
break;
|
||||
|
||||
case MENUOP_GETLISTITEMCHECKBOX:
|
||||
if (data->list.value < numsetups) {
|
||||
data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Import: overwrite dialog
|
||||
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 err = mpsetupImportFile(item->param, true);
|
||||
if (!err) {
|
||||
menuPopDialog();
|
||||
menuPushDialog(&g_ManageSettingsDialog);
|
||||
} else {
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Manage Import/Export settings dialog
|
||||
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_SET:
|
||||
if (item->param == MPSETUP_OP_IMPORT) {
|
||||
strcpy(g_TitleImportExportDialog, "Import Settings\n");
|
||||
if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) {
|
||||
snprintf(
|
||||
g_StatusText, sizeof(g_StatusText),
|
||||
"No import file found.\n"
|
||||
"Place the file %s.bin\n"
|
||||
"Next to your %s.bin file\n",
|
||||
MPSETUP_FILENAME_EXP, MPSETUP_FILENAME
|
||||
);
|
||||
menuPushDialog(&g_StatusErrorDialog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT);
|
||||
} else {
|
||||
strcpy(g_TitleImportExportDialog, "Export Settings\n");
|
||||
}
|
||||
g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param;
|
||||
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
|
||||
menuPushDialog(&g_ImportExportDialog);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Manage settings dialog
|
||||
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
u32 colour;
|
||||
switch (operation) {
|
||||
case MENUOP_GETCOLOUR:
|
||||
colour = data->list.unk04;
|
||||
if (data->list.value + 1 == g_MpSetupFile.defaultsetup) {
|
||||
data->list.unk04 = (colour & 0xffff0000) | 0xff;
|
||||
}
|
||||
break;
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->list.value = g_MpSetupFile.numsetups;
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes;
|
||||
case MENUOP_SET:
|
||||
g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value;
|
||||
if (data->list.value == g_MpSetupFile.defaultsetup - 1) {
|
||||
strcpy(g_LabelSetDefault, "Clear Default\n");
|
||||
} else {
|
||||
strcpy(g_LabelSetDefault, "Set Default\n");
|
||||
}
|
||||
menuPushDialog(&g_ManageSetupDialog);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->list.value = 0xfffff;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
menuPushDialog(&g_RenameSetupDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
menuPushDialog(&g_DeleteSetupDialog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
if (operation == MENUOP_SET) {
|
||||
s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
|
||||
// clicked on "clear default"
|
||||
if (selected == g_MpSetupFile.defaultsetup - 1) {
|
||||
g_MpSetupFile.defaultsetup = -1;
|
||||
strcpy(g_LabelSetDefault, "Set Default\n");
|
||||
} else {
|
||||
g_MpSetupFile.defaultsetup = selected + 1;
|
||||
strcpy(g_LabelSetDefault, "Clear Default\n");
|
||||
}
|
||||
|
||||
mpsetupSaveCurrentFile();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
|
||||
s32 mpsetupLoadCurrentFile(void)
|
||||
{
|
||||
return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT);
|
||||
}
|
||||
|
||||
s32 mpsetupSaveCurrentFile(void)
|
||||
{
|
||||
g_MpSetupFile.version = MPSETUP_VERSION;
|
||||
return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile);
|
||||
}
|
||||
|
||||
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile)
|
||||
{
|
||||
struct savebuffer setup;
|
||||
|
||||
// request to add a new setup
|
||||
if (slotindex == g_MpSetupFile.numsetups) {
|
||||
g_MpCurrentSetup = g_MpSetupFile.numsetups++;
|
||||
}
|
||||
|
||||
savebufferClear(&setup);
|
||||
mpsetupfileSaveWad(&setup);
|
||||
|
||||
memcpy(g_MpSetupFile.setups[slotindex].bytes, setup.bytes, MPSETUP_BLOCKSIZE);
|
||||
|
||||
return savefile ? mpsetupSaveCurrentFile() : 0;
|
||||
}
|
||||
|
||||
void mpsetupLoadSetup(s32 index)
|
||||
{
|
||||
struct savebuffer buffer;
|
||||
savebufferClear(&buffer);
|
||||
struct setupblock *block = &g_MpSetupFile.setups[index];
|
||||
memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE);
|
||||
mpsetupfileLoadWad(&buffer, g_MpSetupFile.version);
|
||||
g_MpCurrentSetup = index;
|
||||
}
|
||||
|
||||
void mpsetupCopyAllFromPak(void)
|
||||
{
|
||||
if (fsFileSize("$S/" MPSETUP_FILENAME ".bin") > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
filelistCreate(1, FILETYPE_MPSETUP);
|
||||
filelistsTick();
|
||||
|
||||
for (int i = 0; i < g_FileLists[1]->numfiles; ++i) {
|
||||
struct savebuffer buffer;
|
||||
savebufferClear(&buffer);
|
||||
struct filelistfile *file = &g_FileLists[1]->files[i];
|
||||
s32 device = pakFindBySerial(file->deviceserial);
|
||||
s32 err = pakReadBodyAtGuid(device, file->fileid, buffer.bytes, 0);
|
||||
|
||||
if (err != 0) {
|
||||
sysLogPrintf(LOG_ERROR, "Unable to read pak. device %d fileid %d deviceserial %d err %d",
|
||||
device, file->fileid, file->deviceserial, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
mpsetupfileLoadWad(&buffer, 0);
|
||||
|
||||
// save the file when writing the last setup
|
||||
u8 savefile = i == g_FileLists[1]->numfiles - 1;
|
||||
mpsetupSaveSetup(g_MpSetupFile.numsetups, savefile);
|
||||
}
|
||||
|
||||
// to reset the mp setup
|
||||
mpInit(false);
|
||||
}
|
||||
+378
-39
@@ -9,6 +9,8 @@
|
||||
#include "game/mainmenu.h"
|
||||
#include "game/menu.h"
|
||||
#include "game/gamefile.h"
|
||||
#include "game/player.h"
|
||||
#include "lib/joy.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "config.h"
|
||||
@@ -119,13 +121,40 @@ static MenuItemHandlerResult menuhandlerMouseAimLock(s32 operation, struct menui
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerMouseDefaultLocked(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
static MenuItemHandlerResult menuhandlerMouseLockMode(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
"Always Off",
|
||||
"Always On",
|
||||
"Auto"
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = ARRAYCOUNT(opts);
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (intptr_t)opts[data->dropdown.value];
|
||||
case MENUOP_SET:
|
||||
inputSetMouseLockMode(data->checkbox.value);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = inputGetMouseLockMode();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerMenuMouseControl(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return inputGetMouseDefaultLocked();
|
||||
return g_MenuMouseControl;
|
||||
case MENUOP_SET:
|
||||
inputSetMouseDefaultLocked(data->checkbox.value);
|
||||
g_MenuMouseControl = data->checkbox.value;
|
||||
if (!g_MenuMouseControl) {
|
||||
g_MenuUsingMouse = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -142,15 +171,17 @@ static MenuItemHandlerResult menuhandlerMouseSpeedX(s32 operation, struct menuit
|
||||
if (x < 0.f) {
|
||||
data->slider.value = 0;
|
||||
} else if (x > 10.f) {
|
||||
data->slider.value = 100;
|
||||
data->slider.value = 1000;
|
||||
} else {
|
||||
data->slider.value = x * 10.f + 0.5f;
|
||||
data->slider.value = x * 100.f + 0.5f;
|
||||
}
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
inputMouseGetSpeed(&x, &y);
|
||||
inputMouseSetSpeed((f32)data->slider.value / 10.f, y);
|
||||
inputMouseSetSpeed((f32)data->slider.value / 100.f, y);
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -166,15 +197,17 @@ static MenuItemHandlerResult menuhandlerMouseSpeedY(s32 operation, struct menuit
|
||||
if (y < 0.f) {
|
||||
data->slider.value = 0;
|
||||
} else if (y > 10.f) {
|
||||
data->slider.value = 100;
|
||||
data->slider.value = 1000;
|
||||
} else {
|
||||
data->slider.value = y * 10.f + 0.5f;
|
||||
data->slider.value = y * 100.f + 0.5f;
|
||||
}
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
inputMouseGetSpeed(&x, &y);
|
||||
inputMouseSetSpeed(x, (f32)data->slider.value / 10.f);
|
||||
inputMouseSetSpeed(x, (f32)data->slider.value / 100.f);
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -187,14 +220,16 @@ static MenuItemHandlerResult menuhandlerMouseAimSpeedX(s32 operation, struct men
|
||||
if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx < 0.f) {
|
||||
data->slider.value = 0;
|
||||
} else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx > 10.f) {
|
||||
data->slider.value = 100;
|
||||
data->slider.value = 1000;
|
||||
} else {
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx * 10.f + 0.5f;
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx * 100.f + 0.5f;
|
||||
}
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx = (f32)data->slider.value / 10.f;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx = (f32)data->slider.value / 100.f;
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -207,14 +242,16 @@ static MenuItemHandlerResult menuhandlerMouseAimSpeedY(s32 operation, struct men
|
||||
if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy < 0.f) {
|
||||
data->slider.value = 0;
|
||||
} else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy > 10.f) {
|
||||
data->slider.value = 100;
|
||||
data->slider.value = 1000;
|
||||
} else {
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy * 10.f + 0.5f;
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy * 100.f + 0.5f;
|
||||
}
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy = (f32)data->slider.value / 10.f;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy = (f32)data->slider.value / 100.f;
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -227,14 +264,16 @@ static MenuItemHandlerResult menuhandlerRadialMenuSpeed(s32 operation, struct me
|
||||
if (g_PlayerExtCfg[0].radialmenuspeed < 0.f) {
|
||||
data->slider.value = 0;
|
||||
} else if (g_PlayerExtCfg[0].radialmenuspeed > 10.f) {
|
||||
data->slider.value = 100;
|
||||
data->slider.value = 1000;
|
||||
} else {
|
||||
data->slider.value = g_PlayerExtCfg[0].radialmenuspeed * 10.f + 0.5f;
|
||||
data->slider.value = g_PlayerExtCfg[0].radialmenuspeed * 100.f + 0.5f;
|
||||
}
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[0].radialmenuspeed = (f32)data->slider.value / 10.f;
|
||||
g_PlayerExtCfg[0].radialmenuspeed = (f32)data->slider.value / 100.f;
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -257,13 +296,21 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
menuhandlerMouseAimLock,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Mouse Lock Mode",
|
||||
0,
|
||||
menuhandlerMouseLockMode,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Grab Mouse Input by Default",
|
||||
(uintptr_t)"Mouse Menu Navigation",
|
||||
0,
|
||||
menuhandlerMouseDefaultLocked,
|
||||
menuhandlerMenuMouseControl,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
@@ -278,7 +325,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Mouse Speed X",
|
||||
100,
|
||||
1000,
|
||||
menuhandlerMouseSpeedX,
|
||||
},
|
||||
{
|
||||
@@ -286,7 +333,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Mouse Speed Y",
|
||||
100,
|
||||
1000,
|
||||
menuhandlerMouseSpeedY,
|
||||
},
|
||||
{
|
||||
@@ -294,7 +341,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Crosshair Speed X",
|
||||
100,
|
||||
1000,
|
||||
menuhandlerMouseAimSpeedX,
|
||||
},
|
||||
{
|
||||
@@ -302,7 +349,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Crosshair Speed Y",
|
||||
100,
|
||||
1000,
|
||||
menuhandlerMouseAimSpeedY,
|
||||
},
|
||||
{
|
||||
@@ -310,7 +357,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Radial Menu Speed",
|
||||
100,
|
||||
1000,
|
||||
menuhandlerRadialMenuSpeed,
|
||||
},
|
||||
{
|
||||
@@ -551,8 +598,10 @@ static MenuItemHandlerResult menuhandlerController(s32 operation, struct menuite
|
||||
if (data->dropdown.value == 0) {
|
||||
// unassign controller
|
||||
inputAssignController(g_ExtMenuPlayer, -1);
|
||||
joyReset();
|
||||
} else if (data->dropdown.value <= numCtrls) {
|
||||
inputAssignController(g_ExtMenuPlayer, ctrls[data->dropdown.value - 1]);
|
||||
joyReset();
|
||||
}
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
@@ -652,27 +701,183 @@ static MenuItemHandlerResult menuhandlerFullScreen(s32 operation, struct menuite
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
static MenuItemHandlerResult menuhandlerFullScreenMode(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
"Borderless",
|
||||
"Exclusive"
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = ARRAYCOUNT(opts);
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (intptr_t)opts[data->dropdown.value];
|
||||
case MENUOP_SET:
|
||||
videoSetFullscreenMode(data->dropdown.value);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = videoGetFullscreenMode();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCenterWindow(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return videoGetMaximizeWindow();
|
||||
return videoGetCenterWindow();
|
||||
case MENUOP_SET:
|
||||
videoSetMaximizeWindow(data->checkbox.value);
|
||||
videoSetCenterWindow(data->checkbox.value);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerVsync(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const s32 numOpts = 10;
|
||||
static const char *constOpts[] = {
|
||||
"Adaptive",
|
||||
"Off",
|
||||
"On"
|
||||
};
|
||||
static char dynOpt[20];
|
||||
s32 vblanks;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = numOpts;
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
if (data->dropdown.value < ARRAYCOUNT(constOpts))
|
||||
return (intptr_t)constOpts[data->dropdown.value];
|
||||
vblanks = (s32)data->dropdown.value - 1;
|
||||
snprintf(dynOpt, sizeof(dynOpt), "On (%d frames)", vblanks);
|
||||
return (intptr_t)dynOpt;
|
||||
case MENUOP_SET:
|
||||
videoSetVsync(data->dropdown.value - 1);
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = videoGetVsync() + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerFramerateLimit(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = videoGetFramerateLimit();
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
videoSetFramerateLimit(data->slider.value);
|
||||
break;
|
||||
case MENUOP_GETSLIDERLABEL:
|
||||
// NOTE: data->slider.label length must not exceed 15.
|
||||
if (data->slider.value == 0) {
|
||||
strcpy(data->slider.label, "Off");
|
||||
} else {
|
||||
sprintf(data->slider.label, "%d FPS", data->slider.value);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerMSAA(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
s32 msaa;
|
||||
static const char *opts[] = {
|
||||
"Off",
|
||||
"2x (MSAA)",
|
||||
"4x (MSAA)",
|
||||
"8x (MSAA)",
|
||||
"16x (MSAA)"
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = ARRAYCOUNT(opts);
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (intptr_t)opts[data->dropdown.value];
|
||||
case MENUOP_SET:
|
||||
videoSetMSAA(1 << data->dropdown.value);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
msaa = videoGetMSAA();
|
||||
if (msaa < 2) {
|
||||
data->dropdown.value = 0;
|
||||
} else if (msaa < 4) {
|
||||
data->dropdown.value = 1;
|
||||
} else if (msaa < 8) {
|
||||
data->dropdown.value = 2;
|
||||
} else if (msaa < 16) {
|
||||
data->dropdown.value = 3;
|
||||
} else {
|
||||
data->dropdown.value = 4;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerResolution(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static char resstring[32];
|
||||
static const char *rescustom = "Custom";
|
||||
displaymode mode;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_CHECKDISABLED:
|
||||
if (videoGetFullscreen() && videoGetFullscreenMode() == 0) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = videoGetNumDisplayModes();
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
videoGetDisplayMode(&mode, data->dropdown.value);
|
||||
if (mode.width == 0 && mode.height == 0) {
|
||||
return (intptr_t)rescustom;
|
||||
} else {
|
||||
snprintf(resstring, sizeof(resstring), "%dx%d", mode.width, mode.height);
|
||||
}
|
||||
return (intptr_t)resstring;
|
||||
case MENUOP_SET:
|
||||
videoSetDisplayMode(data->dropdown.value);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = videoGetDisplayModeIndex();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
"Nearest",
|
||||
"Bilinear",
|
||||
"Three Point"
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return (videoGetTextureFilter() != 0);
|
||||
case MENUOP_SET:
|
||||
videoSetTextureFilter(data->checkbox.value);
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = ARRAYCOUNT(opts);
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (intptr_t)opts[data->dropdown.value];
|
||||
case MENUOP_SET:
|
||||
videoSetTextureFilter(data->dropdown.value);
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = videoGetTextureFilter();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -698,12 +903,25 @@ static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuit
|
||||
return videoGetTextureFilter2D();
|
||||
case MENUOP_SET:
|
||||
videoSetTextureFilter2D(data->checkbox.value);
|
||||
g_TexFilter2D = videoGetTextureFilter2D() ? G_TF_BILERP : G_TF_POINT;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerDisplayFPS(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return videoGetDisplayFPS();
|
||||
case MENUOP_SET:
|
||||
videoSetDisplayFPS(data->checkbox.value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
@@ -717,6 +935,19 @@ static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct me
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerUncapTickrate(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return (g_TickRateDiv == 0);
|
||||
case MENUOP_SET:
|
||||
g_TickRateDiv = !data->checkbox.value;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCenterHUD(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
@@ -775,25 +1006,89 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
menuhandlerFullScreen,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Maximize Window",
|
||||
(uintptr_t)"Full Screen Mode",
|
||||
0,
|
||||
menuhandlerMaximizeWindow,
|
||||
menuhandlerFullScreenMode,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Resolution",
|
||||
0,
|
||||
menuhandlerResolution,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Detail Textures",
|
||||
(uintptr_t)"Center Window",
|
||||
0,
|
||||
menuhandlerTexDetail,
|
||||
menuhandlerCenterWindow,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Anti-aliasing",
|
||||
0,
|
||||
menuhandlerMSAA,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Vsync",
|
||||
0,
|
||||
menuhandlerVsync,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE | MENUITEMFLAG_SLIDER_DEFERRED,
|
||||
(uintptr_t)"Framerate Limit",
|
||||
VIDEO_MAX_FPS,
|
||||
menuhandlerFramerateLimit,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Uncap Tickrate",
|
||||
0,
|
||||
menuhandlerUncapTickrate,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Display FPS",
|
||||
0,
|
||||
menuhandlerDisplayFPS,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Texture Filtering",
|
||||
0,
|
||||
menuhandlerTexFilter,
|
||||
@@ -810,9 +1105,17 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"GE64-style Muzzle Flashes",
|
||||
(uintptr_t)"Detail Textures",
|
||||
0,
|
||||
menuhandlerGeMuzzleFlashes,
|
||||
menuhandlerTexDetail,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
@@ -822,6 +1125,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
0,
|
||||
menuhandlerCenterHUD,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"GE64-style Muzzle Flashes",
|
||||
0,
|
||||
menuhandlerGeMuzzleFlashes,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
@@ -908,6 +1219,21 @@ struct menudialogdef g_ExtendedAudioMenuDialog = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static MenuItemHandlerResult menuhandlerUseKeyReloads(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_CHECKDISABLED:
|
||||
return !g_PlayerExtCfg[g_ExtMenuPlayer].extcontrols;
|
||||
case MENUOP_GET:
|
||||
return g_PlayerExtCfg[g_ExtMenuPlayer].usereloads;
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].usereloads = data->checkbox.value;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrouchMode(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
@@ -944,6 +1270,7 @@ static MenuItemHandlerResult menuhandlerFieldOfView(s32 operation, struct menuit
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].fovy = data->slider.value;
|
||||
if (g_PlayerExtCfg[g_ExtMenuPlayer].fovzoom) {
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].fovzoommult = g_PlayerExtCfg[g_ExtMenuPlayer].fovy / 60.f;
|
||||
playerClampGunZoomFovY(g_ExtMenuPlayer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1211,6 +1538,14 @@ struct menuitem g_ExtendedGameMenuItems[] = {
|
||||
0,
|
||||
menuhandlerCrosshairHealth,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Use Key Reloads",
|
||||
0,
|
||||
menuhandlerUseKeyReloads,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
@@ -1313,6 +1648,8 @@ static const struct menubind menuBinds[] = {
|
||||
{ CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" },
|
||||
{ CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" },
|
||||
{ CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" },
|
||||
{ CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" },
|
||||
{ CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" },
|
||||
};
|
||||
|
||||
static const char *menutextBind(struct menuitem *item);
|
||||
@@ -1350,6 +1687,8 @@ struct menuitem g_ExtendedBindsMenuItems[] = {
|
||||
DEFINE_MENU_BIND(),
|
||||
DEFINE_MENU_BIND(),
|
||||
DEFINE_MENU_BIND(),
|
||||
DEFINE_MENU_BIND(),
|
||||
DEFINE_MENU_BIND(),
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
|
||||
+16
-5
@@ -72,6 +72,7 @@
|
||||
#include "lib/str.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
#include "debugger.h"
|
||||
#include "system.h"
|
||||
|
||||
extern u8 *g_MempHeap;
|
||||
@@ -225,6 +226,8 @@ void mainInit(void)
|
||||
joyInit();
|
||||
joyReset();
|
||||
|
||||
var8005d9b0 = rmonIsDisabled();
|
||||
|
||||
g_Is4Mb = (osGetMemSize() <= 0x400000);
|
||||
g_VmShowStats = 0;
|
||||
|
||||
@@ -257,7 +260,7 @@ void mainInit(void)
|
||||
frametimeInit();
|
||||
profileInit();
|
||||
smokesInit();
|
||||
mpInit();
|
||||
mpInit(true);
|
||||
pheadInit();
|
||||
paksInit();
|
||||
pheadInit2();
|
||||
@@ -531,6 +534,15 @@ void mainTick(void)
|
||||
joyDebugJoy();
|
||||
schedSetCrashEnable2(false);
|
||||
|
||||
if (g_DebuggerTimePasses) {
|
||||
g_MainGameLogicEnabled = true;
|
||||
} else {
|
||||
g_MainGameLogicEnabled = (g_DebuggerFrameAdvance > 0);
|
||||
if (g_MainGameLogicEnabled) {
|
||||
--g_DebuggerFrameAdvance;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_MainGameLogicEnabled) {
|
||||
gdl = gdlstart = gfxGetMasterDisplayList();
|
||||
|
||||
@@ -568,11 +580,10 @@ void mainTick(void)
|
||||
if (g_MainGameLogicEnabled) {
|
||||
gfxSwapBuffers();
|
||||
viUpdateMode();
|
||||
rdpCreateTask(gdlstart, gdl, 0, (uintptr_t) &msg);
|
||||
memaPrint();
|
||||
profileSetMarker(PROFILE_MAINTICK_END);
|
||||
}
|
||||
|
||||
rdpCreateTask(gdlstart, gdl, 0, (s32) &msg);
|
||||
memaPrint();
|
||||
profileSetMarker(PROFILE_MAINTICK_END);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "audio.h"
|
||||
#include "input.h"
|
||||
#include "mixer.h"
|
||||
#include "debugger.h"
|
||||
|
||||
/*
|
||||
* private typedefs and defines
|
||||
@@ -239,6 +240,7 @@ void schedSubmitTask(OSSched *sc, OSScTask *t)
|
||||
|
||||
void schedStartFrame(OSSched *sc)
|
||||
{
|
||||
debuggerStartFrame();
|
||||
videoStartFrame();
|
||||
}
|
||||
|
||||
@@ -288,6 +290,8 @@ void schedEndFrame(OSSched *sc)
|
||||
viHandleRetrace();
|
||||
}
|
||||
|
||||
debuggerFrame();
|
||||
|
||||
inputUpdate();
|
||||
|
||||
joyStartReadData(&g_PiMesgQueue);
|
||||
@@ -297,6 +301,8 @@ void schedEndFrame(OSSched *sc)
|
||||
sndHandleRetrace();
|
||||
schedAudioFrame(sc);
|
||||
schedRenderCrashPeriodically(sc->frameCount);
|
||||
|
||||
debuggerEndFrame();
|
||||
videoEndFrame();
|
||||
|
||||
if (g_MainIsBooting == 0) {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,31 @@
|
||||
#include "preprocess/common.h"
|
||||
|
||||
static struct ptrmarker ptrMarkers[MAX_PTR_MARKERS];
|
||||
static int numPtrMarkers;
|
||||
|
||||
void ptrAdd(u32 ptr_src, uintptr_t ptr_host)
|
||||
{
|
||||
if (numPtrMarkers >= ARRAYCOUNT(ptrMarkers)) {
|
||||
sysFatalError("ptrAdd(%p, %p): ptrmarker limit exceeded", (void *)(uintptr_t)ptr_src, (void *)ptr_host);
|
||||
}
|
||||
|
||||
ptrMarkers[numPtrMarkers].ptr_src = ptr_src;
|
||||
ptrMarkers[numPtrMarkers].ptr_host = ptr_host;
|
||||
numPtrMarkers++;
|
||||
}
|
||||
|
||||
struct ptrmarker *ptrFind(uintptr_t ptr_src)
|
||||
{
|
||||
for (int i = 0; i < numPtrMarkers; i++) {
|
||||
if (ptrMarkers[i].ptr_src == ptr_src) {
|
||||
return &ptrMarkers[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ptrReset(void)
|
||||
{
|
||||
numPtrMarkers = 0;
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
#include "preprocess/gbi.h"
|
||||
|
||||
/**
|
||||
* 4 bytes decompressed size of primary data
|
||||
* 4 bytes compressed size of section 1 in its entirety
|
||||
* 4 bytes compressed size of primary data
|
||||
* Section 1:
|
||||
* Primary: (zipped)
|
||||
* 4 bytes null
|
||||
* 4 bytes pointer to room table
|
||||
* 4 bytes pointer to portal table
|
||||
* 4 bytes pointer to bgcmds
|
||||
* 4 bytes pointer to lights table
|
||||
* 4 bytes null
|
||||
* (room table)
|
||||
* (portal table)
|
||||
* (bgcmds)
|
||||
* (lights table)
|
||||
* room 1 (zipped)
|
||||
* room 2 (zipped)
|
||||
* ...
|
||||
* Section 2:
|
||||
* 2 bytes decompressed size of section (mask with 0x7fff)
|
||||
* 2 bytes compressed size of section
|
||||
* Texture ID list (zipped)
|
||||
* Section 3:
|
||||
* 2 bytes decompressed size of section (mask with 0x7fff)
|
||||
* 2 bytes compressed size of section
|
||||
* Zipped:
|
||||
* (room bbox table)
|
||||
* (list of roomgfxdata sizes)
|
||||
* (list of light counts per room)
|
||||
*/
|
||||
|
||||
struct fileheader {
|
||||
u32 primary_infsize;
|
||||
u32 section1_cmpsize;
|
||||
u32 primary_cmpsize;
|
||||
};
|
||||
|
||||
struct sectionheader {
|
||||
u16 infsize;
|
||||
u16 cmpsize;
|
||||
};
|
||||
|
||||
struct n64_primaryheader {
|
||||
u32 unused1;
|
||||
u32 ptr_rooms;
|
||||
u32 ptr_portals;
|
||||
u32 ptr_bgcmds;
|
||||
u32 ptr_lights;
|
||||
u32 unused2;
|
||||
};
|
||||
|
||||
struct host_primaryheader {
|
||||
uintptr_t unused1;
|
||||
uintptr_t ptr_rooms;
|
||||
uintptr_t ptr_portals;
|
||||
uintptr_t ptr_bgcmds;
|
||||
uintptr_t ptr_lights;
|
||||
uintptr_t unused2;
|
||||
};
|
||||
|
||||
struct n64_bgroom {
|
||||
u32 ptr_gfxdata;
|
||||
struct coord pos;
|
||||
u8 br_light_min;
|
||||
u8 br_light_max;
|
||||
};
|
||||
|
||||
struct n64_roomblock {
|
||||
u8 type;
|
||||
u32 ptr_next;
|
||||
u32 ptr_gdl;
|
||||
u32 ptr_vertices;
|
||||
u32 ptr_colours;
|
||||
};
|
||||
|
||||
struct n64_roomgfxdata {
|
||||
u32 ptr_vertices;
|
||||
u32 ptr_colours;
|
||||
u32 ptr_opablocks;
|
||||
u32 ptr_xlublocks;
|
||||
s16 lightsindex;
|
||||
s16 numlights;
|
||||
s16 numvertices;
|
||||
s16 numcolours;
|
||||
// roomblocks[]
|
||||
};
|
||||
|
||||
struct vtx {
|
||||
s16 coord[3];
|
||||
u8 flag;
|
||||
u8 color;
|
||||
u16 s;
|
||||
u16 t;
|
||||
};
|
||||
|
||||
static void convertPrimaryRooms(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos)
|
||||
{
|
||||
struct n64_bgroom *n64_rooms = (struct n64_bgroom *) &src[*srcpos];
|
||||
struct bgroom *host_rooms = (struct bgroom *) &dst[*dstpos];
|
||||
|
||||
s32 numRooms = 0;
|
||||
|
||||
for (int i = 1; n64_rooms[i].ptr_gfxdata != 0; i++) {
|
||||
numRooms++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numRooms + 1; i++) {
|
||||
host_rooms[i].unk00 = PD_BE32(n64_rooms[i].ptr_gfxdata);
|
||||
host_rooms[i].pos = PD_SWAPPED_VAL(n64_rooms[i].pos);
|
||||
host_rooms[i].br_light_min = n64_rooms[i].br_light_min;
|
||||
host_rooms[i].br_light_max = n64_rooms[i].br_light_max;
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_rooms) * (numRooms + 2);
|
||||
*dstpos += sizeof(*host_rooms) * (numRooms +2);
|
||||
}
|
||||
|
||||
static void convertPrimaryPortals(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 *src_portalvtxs, u32 *dst_portalvtxs)
|
||||
{
|
||||
struct bgportal *n64_portals = (struct bgportal *) &src[*srcpos];
|
||||
struct bgportal *host_portals = (struct bgportal *) &dst[*dstpos];
|
||||
|
||||
// Count portals
|
||||
int numportals = 0;
|
||||
|
||||
for (int i = 0; n64_portals[i].verticesoffset != 0; i++) {
|
||||
numportals++;
|
||||
}
|
||||
|
||||
// Convert portals
|
||||
for (int i = 0; i < numportals; i++) {
|
||||
host_portals[i].verticesoffset = PD_BE16(n64_portals[i].verticesoffset);
|
||||
host_portals[i].roomnum1 = PD_BE16(n64_portals[i].roomnum1);
|
||||
host_portals[i].roomnum2 = PD_BE16(n64_portals[i].roomnum2);
|
||||
host_portals[i].flags = n64_portals[i].flags;
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_portals) * (numportals + 1);
|
||||
*dstpos += sizeof(*host_portals) * (numportals + 1);
|
||||
|
||||
*src_portalvtxs = *srcpos;
|
||||
*dst_portalvtxs = *dstpos;
|
||||
|
||||
while (1) {
|
||||
struct portalvertices *n64_pvertices = (struct portalvertices *)&src[*srcpos];
|
||||
struct portalvertices *host_pvertices = (struct portalvertices *)&dst[*dstpos];
|
||||
|
||||
host_pvertices->count = n64_pvertices->count;
|
||||
|
||||
for (int j = 0; j < host_pvertices->count; j++) {
|
||||
host_pvertices->vertices[j] = PD_SWAPPED_VAL(n64_pvertices->vertices[j]);
|
||||
}
|
||||
|
||||
*srcpos += 4 + host_pvertices->count * 12;
|
||||
*dstpos += 4 + host_pvertices->count * 12;
|
||||
|
||||
if (host_pvertices->count == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void convertPrimaryBgCmds(u8 *dst, u32 *dstpos, u8 *src, u32 dst_portalvtxs, u32 src_portalvtxs)
|
||||
{
|
||||
struct bgcmd *n64_cmds = (struct bgcmd *) src;
|
||||
struct bgcmd *host_cmds = (struct bgcmd *) &dst[*dstpos];
|
||||
int num_cmds = 0;
|
||||
|
||||
for (int i = 0; n64_cmds[i].type != 0; i++) {
|
||||
num_cmds++;
|
||||
}
|
||||
|
||||
num_cmds++;
|
||||
|
||||
for (int i = 0; i < num_cmds; i++) {
|
||||
host_cmds[i].type = n64_cmds[i].type;
|
||||
host_cmds[i].len = n64_cmds[i].len;
|
||||
host_cmds[i].param = PD_BE32(n64_cmds[i].param);
|
||||
|
||||
if (host_cmds[i].type == 0x64) {
|
||||
u32 offset = host_cmds[i].param - src_portalvtxs;
|
||||
host_cmds[i].param = dst_portalvtxs + offset;
|
||||
}
|
||||
}
|
||||
|
||||
*dstpos += sizeof(*host_cmds) * num_cmds;
|
||||
}
|
||||
|
||||
static void convertPrimaryLights(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 end)
|
||||
{
|
||||
struct light *n64_lights = (struct light *) &src[*srcpos];
|
||||
struct light *host_lights = (struct light *) &dst[*dstpos];
|
||||
int num_lights = (end - *srcpos) / sizeof(struct light);
|
||||
|
||||
for (int i = 0; i < num_lights; i++) {
|
||||
host_lights[i].roomnum = PD_BE16(n64_lights[i].roomnum);
|
||||
host_lights[i].colour = PD_BE16(n64_lights[i].colour);
|
||||
host_lights[i].brightness = n64_lights[i].brightness;
|
||||
host_lights[i].sparkable = n64_lights[i].sparkable;
|
||||
host_lights[i].healthy = n64_lights[i].healthy;
|
||||
host_lights[i].on = n64_lights[i].on;
|
||||
host_lights[i].sparking = n64_lights[i].sparking;
|
||||
host_lights[i].vulnerable = n64_lights[i].vulnerable;
|
||||
host_lights[i].brightnessmult = n64_lights[i].brightnessmult;
|
||||
host_lights[i].dirx = n64_lights[i].dirx;
|
||||
host_lights[i].diry = n64_lights[i].diry;
|
||||
host_lights[i].dirz = n64_lights[i].dirz;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
host_lights[i].bbox[j].x = PD_BE16(n64_lights[i].bbox[j].x);
|
||||
host_lights[i].bbox[j].y = PD_BE16(n64_lights[i].bbox[j].y);
|
||||
host_lights[i].bbox[j].z = PD_BE16(n64_lights[i].bbox[j].z);
|
||||
}
|
||||
}
|
||||
|
||||
*srcpos += sizeof(*n64_lights) * num_lights;
|
||||
*dstpos += ALIGN(sizeof(*host_lights) * num_lights, 4);
|
||||
}
|
||||
|
||||
#define BLOCK_LEAF 0
|
||||
#define BLOCK_PARENT 1
|
||||
|
||||
void relinkPtr(uintptr_t* ptr)
|
||||
{
|
||||
if (!*ptr) return;
|
||||
|
||||
struct ptrmarker* marker = ptrFind(*ptr);
|
||||
if (!marker) {
|
||||
sysFatalError("[BG] WARNING: Unable to relink pointer: %p\n", ptr);
|
||||
}
|
||||
|
||||
*ptr = marker->ptr_host;
|
||||
}
|
||||
|
||||
static u32 convertRoomGfxData(u8 *dst, u8 *src, u32 infsize, u32 src_ofs)
|
||||
{
|
||||
ptrReset();
|
||||
gbiReset();
|
||||
|
||||
u32 dst_roomoffset = src_ofs;
|
||||
|
||||
uintptr_t gdls_addr[64];
|
||||
int numgdls = 0;
|
||||
|
||||
struct n64_roomgfxdata *src_header = (struct n64_roomgfxdata*)src;
|
||||
struct roomgfxdata *dst_header = (struct roomgfxdata*)dst;
|
||||
|
||||
dst_header->vertices = (void *)(uintptr_t)PD_BE32(src_header->ptr_vertices);
|
||||
dst_header->colours = (void *)(uintptr_t)PD_BE32(src_header->ptr_colours);
|
||||
dst_header->opablocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_opablocks);
|
||||
dst_header->xlublocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_xlublocks);
|
||||
dst_header->lightsindex = PD_BE16(src_header->lightsindex);
|
||||
dst_header->numlights = PD_BE16(src_header->numlights);
|
||||
dst_header->numvertices = PD_BE16(src_header->numvertices);
|
||||
dst_header->numcolours = PD_BE16(src_header->numcolours);
|
||||
|
||||
intptr_t endpos = (uintptr_t)dst_header->vertices - src_ofs;
|
||||
uintptr_t curpos_src = sizeof(struct n64_roomgfxdata);
|
||||
uintptr_t curpos_dst = sizeof(struct roomgfxdata) - sizeof(struct roomblock); // compensate for the [1]
|
||||
|
||||
// roomblocks
|
||||
int ncoords = 0;
|
||||
|
||||
// save the ptr to roomblocks here to iterate later to fix the pointers
|
||||
struct roomblock *ptr_dst_roomblocks = (struct roomblock*)&dst[curpos_dst];
|
||||
|
||||
int numblocks = 0;
|
||||
while ((intptr_t)(curpos_src + sizeof(struct n64_roomblock)) <= endpos) {
|
||||
struct n64_roomblock *src_roomblock = (struct n64_roomblock*)&src[curpos_src];
|
||||
struct roomblock *dest_roomblock = (struct roomblock*)&dst[curpos_dst];
|
||||
|
||||
dest_roomblock->type = src_roomblock->type;
|
||||
dest_roomblock->next = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_next);
|
||||
dest_roomblock->gdl = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_gdl);
|
||||
dest_roomblock->vertices = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_vertices);
|
||||
dest_roomblock->colours = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_colours);
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
if (src_roomblock->type == BLOCK_PARENT) {
|
||||
ncoords++;
|
||||
uintptr_t vtx_ptr = (uintptr_t)dest_roomblock->vertices - src_ofs;
|
||||
if (vtx_ptr < endpos) endpos = vtx_ptr;
|
||||
}
|
||||
else if (src_roomblock->ptr_gdl) {
|
||||
gdls_addr[numgdls++] = PD_BE32(src_roomblock->ptr_gdl) - src_ofs;
|
||||
}
|
||||
|
||||
curpos_src += sizeof(struct n64_roomblock);
|
||||
curpos_dst += sizeof(struct roomblock);
|
||||
numblocks++;
|
||||
}
|
||||
|
||||
// block coords
|
||||
for (size_t i = 0; i < ncoords; i++) {
|
||||
u32 *src_coord = (u32*)(src + curpos_src);
|
||||
u32 *dst_coord = (u32*)(dst + curpos_dst);
|
||||
|
||||
dst_coord[0] = PD_BE32(src_coord[0]);
|
||||
dst_coord[1] = PD_BE32(src_coord[1]);
|
||||
dst_coord[2] = PD_BE32(src_coord[2]);
|
||||
|
||||
dst_coord[3] = PD_BE32(src_coord[3]);
|
||||
dst_coord[4] = PD_BE32(src_coord[4]);
|
||||
dst_coord[5] = PD_BE32(src_coord[5]);
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
curpos_src += 6 * sizeof(u32);
|
||||
curpos_dst += 6 * sizeof(u32);
|
||||
}
|
||||
|
||||
curpos_dst = ALIGN8(curpos_dst);
|
||||
|
||||
// vertices
|
||||
uintptr_t ptr_src_vertices = curpos_src = ALIGN8((uintptr_t)dst_header->vertices - src_ofs);
|
||||
uintptr_t ptr_dst_vertices = curpos_dst + dst_roomoffset;
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
uintptr_t vtx_end = (uintptr_t)dst_header->colours - src_ofs;
|
||||
|
||||
while (dst_header->colours && curpos_src < vtx_end) {
|
||||
struct vtx *src_vtx = (struct vtx*)(src + curpos_src);
|
||||
struct vtx *dst_vtx = (struct vtx*)(dst + curpos_dst);
|
||||
|
||||
dst_vtx->coord[0] = PD_BE16(src_vtx->coord[0]);
|
||||
dst_vtx->coord[1] = PD_BE16(src_vtx->coord[1]);
|
||||
dst_vtx->coord[2] = PD_BE16(src_vtx->coord[2]);
|
||||
|
||||
dst_vtx->flag = src_vtx->flag;
|
||||
dst_vtx->color = src_vtx->color;
|
||||
|
||||
dst_vtx->s = PD_BE16(src_vtx->s);
|
||||
dst_vtx->t = PD_BE16(src_vtx->t);
|
||||
|
||||
curpos_src += sizeof(struct vtx);
|
||||
curpos_dst += sizeof(struct vtx);
|
||||
}
|
||||
|
||||
curpos_dst = ALIGN8(curpos_dst);
|
||||
|
||||
// colors
|
||||
uintptr_t ptr_src_colors = 0;
|
||||
uintptr_t ptr_dst_colors = 0;
|
||||
|
||||
if (dst_header->colours) {
|
||||
ptr_src_colors = curpos_src = ALIGN8((uintptr_t)dst_header->colours - src_ofs);
|
||||
ptr_dst_colors = curpos_dst + dst_roomoffset;
|
||||
|
||||
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
|
||||
|
||||
uintptr_t col_end = (numgdls > 0) ? gdls_addr[0] : infsize;
|
||||
size_t col_len = col_end - curpos_src;
|
||||
|
||||
memcpy(dst + curpos_dst, src + curpos_src, col_len);
|
||||
curpos_src += col_len;
|
||||
curpos_dst += col_len;
|
||||
}
|
||||
|
||||
// gdls
|
||||
gbiSetVtx(src_header->ptr_vertices, ptr_src_vertices);
|
||||
gbiSetSegment(0x0e, (uintptr_t)dst_header->vertices);
|
||||
|
||||
uintptr_t gdlstart = curpos_dst;
|
||||
for (size_t i = 0; i < numgdls; i++) {
|
||||
ptrAdd(gdls_addr[i] + src_ofs, curpos_dst + dst_roomoffset);
|
||||
curpos_dst = gbiConvertGdl(dst, curpos_dst, src, gdls_addr[i], 1);
|
||||
}
|
||||
|
||||
// relink ptrs: roomblocks
|
||||
for (size_t i = 0; i < numblocks; i++) {
|
||||
struct roomblock *block = (struct roomblock*)&ptr_dst_roomblocks[i];
|
||||
|
||||
relinkPtr((uintptr_t*)&block->next);
|
||||
|
||||
if (block->type == BLOCK_LEAF) {
|
||||
relinkPtr((uintptr_t*)&block->gdl);
|
||||
u32 offset_vtx = (uintptr_t)block->vertices - ptr_src_vertices - src_ofs;
|
||||
u32 offset_col = (uintptr_t)block->colours - ptr_src_colors - src_ofs;
|
||||
|
||||
block->vertices = (void *)(ptr_dst_vertices + offset_vtx);
|
||||
block->colours = (void *)(ptr_dst_colors + offset_col);
|
||||
}
|
||||
else {
|
||||
relinkPtr((uintptr_t*)&block->gdl); // child
|
||||
relinkPtr((uintptr_t*)&block->vertices); // coord
|
||||
}
|
||||
}
|
||||
|
||||
// relink ptrs: header
|
||||
relinkPtr((uintptr_t*)&dst_header->vertices);
|
||||
relinkPtr((uintptr_t*)&dst_header->colours);
|
||||
relinkPtr((uintptr_t*)&dst_header->opablocks);
|
||||
relinkPtr((uintptr_t*)&dst_header->xlublocks);
|
||||
|
||||
return curpos_dst;
|
||||
}
|
||||
|
||||
static u32 convertSection1(u8 *dst, u8 *src, u32 ofs)
|
||||
{
|
||||
// Convert primary
|
||||
u32 srcpos = 0;
|
||||
u32 dstpos = 0;
|
||||
struct host_primaryheader *host_primary_header = (struct host_primaryheader *) dst;
|
||||
struct n64_primaryheader *n64_primary_header = (struct n64_primaryheader *) src;
|
||||
srcpos += sizeof(struct n64_primaryheader);
|
||||
dstpos += sizeof(*host_primary_header);
|
||||
|
||||
u32 src_bgcmds = PD_BE32(n64_primary_header->ptr_bgcmds) - ofs;
|
||||
|
||||
host_primary_header->unused1 = 0;
|
||||
host_primary_header->unused2 = 0;
|
||||
|
||||
host_primary_header->ptr_rooms = dstpos + ofs;
|
||||
convertPrimaryRooms(dst, &dstpos, src, &srcpos);
|
||||
|
||||
if (n64_primary_header->ptr_lights) {
|
||||
host_primary_header->ptr_lights = dstpos + ofs;
|
||||
srcpos = PD_BE32(n64_primary_header->ptr_lights) - ofs;
|
||||
convertPrimaryLights(dst, &dstpos, src, &srcpos, src_bgcmds);
|
||||
}
|
||||
|
||||
host_primary_header->ptr_portals = dstpos + ofs;
|
||||
srcpos = PD_BE32(n64_primary_header->ptr_portals) - ofs;
|
||||
u32 src_portalvtxs, dst_portalvtxs;
|
||||
convertPrimaryPortals(dst, &dstpos, src, &srcpos, &src_portalvtxs, &dst_portalvtxs);
|
||||
|
||||
host_primary_header->ptr_bgcmds = dstpos + ofs;
|
||||
convertPrimaryBgCmds(dst, &dstpos, &src[src_bgcmds], dst_portalvtxs, src_portalvtxs);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
void preprocessBgSection1(u8 *data, u32 size, u32 ofs)
|
||||
{
|
||||
u8 *dst = sysMemZeroAlloc(size);
|
||||
|
||||
u32 newSize = convertSection1(dst, data, ofs);
|
||||
|
||||
if (newSize > size) {
|
||||
sysFatalError("overflow when trying to preprocess a bg file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
}
|
||||
|
||||
u32 preprocessBgRoom(u8 *data, u32 size, u32 room_ofs)
|
||||
{
|
||||
size *= 2;
|
||||
u8 *dst = sysMemZeroAlloc(size);
|
||||
u32 newSize = convertRoomGfxData(dst, data, size, room_ofs);
|
||||
|
||||
if (newSize > size) {
|
||||
sysFatalError("overflow when trying to preprocess a bg room, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
void preprocessBgSection1Header(u8* data, u32 size)
|
||||
{
|
||||
u32* header = (u32*)data;
|
||||
PD_SWAP_VAL(header[0]); // inflatedsize
|
||||
PD_SWAP_VAL(header[1]); // section1size
|
||||
PD_SWAP_VAL(header[2]); // primcompsize
|
||||
}
|
||||
|
||||
void preprocessBgSection2Header(u8* data, u32 size)
|
||||
{
|
||||
u16* header = (u16*)data;
|
||||
PD_SWAP_VAL(header[0]); // inflatedsize
|
||||
PD_SWAP_VAL(header[1]); // section2compsize
|
||||
}
|
||||
|
||||
void preprocessBgSection2(u8* data, u32 size)
|
||||
{
|
||||
// section2 is a texture id list
|
||||
u16* section2 = (u16*)data;
|
||||
for (s32 i = 0; i < size; ++i) {
|
||||
PD_SWAP_VAL(section2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void preprocessBgSection3Header(u8* data, u32 size)
|
||||
{
|
||||
u16* header = (u16*)data;
|
||||
PD_SWAP_VAL(header[0]);
|
||||
PD_SWAP_VAL(header[1]);
|
||||
}
|
||||
|
||||
void preprocessBgSection3(u8* data, u32 size)
|
||||
{
|
||||
// room bounding boxes, 6x s16 per room
|
||||
s16* bbox = (s16*)data;
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
PD_SWAP_VAL(*bbox); ++bbox;
|
||||
}
|
||||
|
||||
// gfxdatalen list
|
||||
u16* gfxdatalen = (u16*)bbox;
|
||||
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
|
||||
PD_SWAP_VAL(*gfxdatalen); ++gfxdatalen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
static int getNextNonZero(u8 *src, u32 offset, size_t len)
|
||||
{
|
||||
u32 *ptr = (u32 *) &src[offset];
|
||||
u32 *end = (u32 *) &src[len];
|
||||
|
||||
while (ptr < end) {
|
||||
if (*ptr != 0) {
|
||||
return PD_BE32(*ptr);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getNumStrings(u8 *src, size_t len)
|
||||
{
|
||||
u32 ptr_table_len = getNextNonZero(src, 0, len);
|
||||
|
||||
if (ptr_table_len) {
|
||||
return ptr_table_len / sizeof(u32);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 convertLangFile(u8 *dst, u8 *src, size_t srclen)
|
||||
{
|
||||
// Convert it
|
||||
u32 *src_offsets = (u32 *) src;
|
||||
size_t src_ptr_table_len = PD_BE32(src_offsets[0]);
|
||||
size_t src_str_table_len = srclen - src_ptr_table_len;
|
||||
int num_strings = getNumStrings(src, srclen);
|
||||
size_t dst_ptr_table_len = num_strings * sizeof(uintptr_t);
|
||||
size_t dst_str_table_len = src_str_table_len;
|
||||
|
||||
int cur_dst_offset = dst_ptr_table_len;
|
||||
|
||||
uintptr_t *dst_offsets = (uintptr_t *) dst;
|
||||
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
u32 src_offset = PD_BE32(src_offsets[i]);
|
||||
|
||||
if (src_offset) {
|
||||
// Write pointer
|
||||
dst_offsets[i] = (cur_dst_offset);
|
||||
|
||||
// Write string
|
||||
u32 end = getNextNonZero(src, (i + 1) * 4, num_strings * 4);
|
||||
|
||||
if (!end) {
|
||||
end = srclen;
|
||||
}
|
||||
|
||||
size_t len = end - src_offset;
|
||||
len = ALIGN4(len);
|
||||
memcpy(&dst[cur_dst_offset], &src[src_offset], len);
|
||||
|
||||
cur_dst_offset += len;
|
||||
} else {
|
||||
// Write pointer
|
||||
dst_offsets[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ALIGN16(cur_dst_offset);
|
||||
}
|
||||
|
||||
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize) {
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_LANG);
|
||||
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertLangFile(dst, data, size);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a lang file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,292 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
struct n64_header {
|
||||
s32 num_pads;
|
||||
s32 num_covers;
|
||||
u32 ptr_waypoints;
|
||||
u32 ptr_waygroups;
|
||||
u32 ptr_cover;
|
||||
};
|
||||
|
||||
struct host_header {
|
||||
s32 num_pads;
|
||||
s32 num_covers;
|
||||
uintptr_t ptr_waypoints;
|
||||
uintptr_t ptr_waygroups;
|
||||
uintptr_t ptr_cover;
|
||||
};
|
||||
|
||||
struct padheader {
|
||||
u32 flags : 18;
|
||||
u32 room : 10;
|
||||
u32 liftnum : 4;
|
||||
};
|
||||
|
||||
struct n64_waypoint {
|
||||
s32 padnum;
|
||||
u32 ptr_neighbours;
|
||||
s32 groupnum;
|
||||
s32 step;
|
||||
};
|
||||
|
||||
struct n64_waygroup {
|
||||
u32 ptr_neighbours;
|
||||
u32 ptr_waypoints;
|
||||
s32 step;
|
||||
};
|
||||
|
||||
static u32 convertPads(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_pads)
|
||||
{
|
||||
u16 *src_offsets = (u16 *) &src[srcpos];
|
||||
u16 *dst_offsets = (u16 *) &dst[dstpos];
|
||||
|
||||
dstpos += num_pads * sizeof(u16);
|
||||
|
||||
for (int i = 0; i < num_pads; i++) {
|
||||
srcpos = PD_BE16(src_offsets[i]);
|
||||
|
||||
dst_offsets[i] = (dstpos);
|
||||
|
||||
// Header
|
||||
u32 n64_padheader = PD_BE32(*(u32 *) &src[srcpos]);
|
||||
struct padheader *host_padheader = (struct padheader *) &dst[dstpos];
|
||||
u32 flags = (n64_padheader >> 14) & 0x3ffff;
|
||||
|
||||
*(u32*)host_padheader = (n64_padheader);
|
||||
|
||||
srcpos += sizeof(struct padheader);
|
||||
dstpos += sizeof(struct padheader);
|
||||
|
||||
// Position
|
||||
if (flags & PADFLAG_INTPOS) {
|
||||
s16 *srcptr = (s16 *) &src[srcpos];
|
||||
s16 *dstptr = (s16 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE16(srcptr[0]);
|
||||
dstptr[1] = PD_BE16(srcptr[1]);
|
||||
dstptr[2] = PD_BE16(srcptr[2]);
|
||||
|
||||
srcpos += 8;
|
||||
dstpos += 8;
|
||||
} else {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Up
|
||||
if ((flags & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ)) == 0) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Look
|
||||
if ((flags & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ)) == 0) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
|
||||
srcpos += 12;
|
||||
dstpos += 12;
|
||||
}
|
||||
|
||||
// Bbox
|
||||
if (flags & PADFLAG_HASBBOXDATA) {
|
||||
u32 *srcptr = (u32 *) &src[srcpos];
|
||||
u32 *dstptr = (u32 *) &dst[dstpos];
|
||||
|
||||
dstptr[0] = PD_BE32(srcptr[0]);
|
||||
dstptr[1] = PD_BE32(srcptr[1]);
|
||||
dstptr[2] = PD_BE32(srcptr[2]);
|
||||
dstptr[3] = PD_BE32(srcptr[3]);
|
||||
dstptr[4] = PD_BE32(srcptr[4]);
|
||||
dstptr[5] = PD_BE32(srcptr[5]);
|
||||
|
||||
srcpos += 4 * 6;
|
||||
dstpos += 4 * 6;
|
||||
}
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertWayPoints(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_waypoint *n64_waypoints = (struct n64_waypoint *) &src[srcpos];
|
||||
struct waypoint *host_waypoints = (struct waypoint *) &dst[dstpos];
|
||||
int num_waypoints;
|
||||
|
||||
for (num_waypoints = 0; n64_waypoints[num_waypoints].padnum != -1; num_waypoints++);
|
||||
|
||||
dstpos += (num_waypoints + 1) * sizeof(struct waypoint);
|
||||
|
||||
u32 *host_neighbours = (u32 *) &dst[dstpos];
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < num_waypoints; i++) {
|
||||
host_waypoints[i].padnum = PD_BE32(n64_waypoints[i].padnum);
|
||||
host_waypoints[i].neighbours = (void *)(uintptr_t)dstpos;
|
||||
host_waypoints[i].groupnum = PD_BE32(n64_waypoints[i].groupnum);
|
||||
host_waypoints[i].step = 0;
|
||||
|
||||
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waypoints[i].ptr_neighbours)];
|
||||
|
||||
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
|
||||
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_neighbours[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
// Terminator
|
||||
host_waypoints[num_waypoints].padnum = 0xffffffff;
|
||||
host_waypoints[num_waypoints].neighbours = NULL;
|
||||
host_waypoints[num_waypoints].groupnum = 0;
|
||||
host_waypoints[num_waypoints].step = 0;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertWayGroups(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_waygroup *n64_waygroups = (struct n64_waygroup *) &src[srcpos];
|
||||
struct waygroup *host_waygroups = (struct waygroup *) &dst[dstpos];
|
||||
int num_waygroups;
|
||||
|
||||
for (num_waygroups = 0; n64_waygroups[num_waygroups].ptr_neighbours != 0; num_waygroups++);
|
||||
|
||||
dstpos += (num_waygroups + 1) * sizeof(struct waygroup);
|
||||
|
||||
// Waygroups and child waypoints
|
||||
u32 *host_waypoints = (u32 *) &dst[dstpos];
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < num_waygroups; i++) {
|
||||
host_waygroups[i].waypoints = (void *)(uintptr_t)dstpos;
|
||||
host_waygroups[i].step = 0;
|
||||
|
||||
u32 *n64_waypoints = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_waypoints)];
|
||||
|
||||
for (int j = 0; n64_waypoints[j] != 0xffffffff; j++) {
|
||||
host_waypoints[n++] = PD_BE32(n64_waypoints[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_waypoints[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
// Terminator
|
||||
host_waygroups[num_waygroups].neighbours = NULL;
|
||||
host_waygroups[num_waygroups].waypoints = NULL;
|
||||
host_waygroups[num_waygroups].step = 0;
|
||||
|
||||
// Waygroup neighbours
|
||||
u32 *host_neighbours = (u32 *) &dst[dstpos];
|
||||
n = 0;
|
||||
|
||||
for (int i = 0; i < num_waygroups; i++) {
|
||||
host_waygroups[i].neighbours = (void *)(uintptr_t)dstpos;
|
||||
|
||||
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_neighbours)];
|
||||
|
||||
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
|
||||
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
host_neighbours[n++] = 0xffffffff;
|
||||
dstpos += 4;
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertCover(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_covers)
|
||||
{
|
||||
struct coverdefinition *n64_covers = (struct coverdefinition *) &src[srcpos];
|
||||
struct coverdefinition *host_covers = (struct coverdefinition *) &dst[dstpos];
|
||||
|
||||
for (int i = 0; i < num_covers; i++) {
|
||||
host_covers[i].pos = PD_SWAPPED_VAL(n64_covers[i].pos);
|
||||
host_covers[i].look = PD_SWAPPED_VAL(n64_covers[i].look);
|
||||
host_covers[i].flags = PD_BE16(n64_covers[i].flags);
|
||||
}
|
||||
|
||||
dstpos += num_covers * sizeof(struct coverdefinition);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertPadsFile(u8 *dst, u8 *src)
|
||||
{
|
||||
u32 dstpos = 0;
|
||||
struct n64_header *n64_header = (struct n64_header *) src;
|
||||
struct host_header *host_header = (struct host_header *) dst;
|
||||
|
||||
int num_pads = PD_BE32(n64_header->num_pads);
|
||||
int num_covers = PD_BE32(n64_header->num_covers);
|
||||
host_header->num_pads = (num_pads);
|
||||
host_header->num_covers = (num_covers);
|
||||
|
||||
dstpos += sizeof(struct host_header);
|
||||
|
||||
// Pads
|
||||
dstpos = convertPads(dst, dstpos, src, sizeof(struct n64_header), num_pads);
|
||||
|
||||
// Waypoints
|
||||
host_header->ptr_waypoints = (dstpos);
|
||||
dstpos = convertWayPoints(dst, dstpos, src, PD_BE32(n64_header->ptr_waypoints));
|
||||
|
||||
// Waygroups
|
||||
host_header->ptr_waygroups = (dstpos);
|
||||
dstpos = convertWayGroups(dst, dstpos, src, PD_BE32(n64_header->ptr_waygroups));
|
||||
|
||||
// Cover
|
||||
host_header->ptr_cover = (dstpos);
|
||||
dstpos = convertCover(dst, dstpos, src, PD_BE32(n64_header->ptr_cover), num_covers);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
u8* preprocessPadsFile(u8 *data, u32 size, u32 *outSize) {
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_PADS);
|
||||
u8* dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertPadsFile(dst, data);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a pads file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct tile {
|
||||
u8 type;
|
||||
u8 numvertices;
|
||||
u16 flags;
|
||||
u16 floortype;
|
||||
u8 xmin;
|
||||
u8 ymin;
|
||||
u8 zmin;
|
||||
u8 xmax;
|
||||
u8 ymax;
|
||||
u8 zmax;
|
||||
u16 floorcol;
|
||||
};
|
||||
|
||||
static u32 convertTiles(u8 *dst, u8 *src, size_t srclen)
|
||||
{
|
||||
int num_rooms = PD_BE32(*(u32 *) src);
|
||||
|
||||
size_t src_ptr_table_len = (num_rooms + 1) * 4;
|
||||
size_t dst_ptr_table_len = (num_rooms + 1) * sizeof(u32);
|
||||
|
||||
u32 *src_offsets = (u32 *) &src[4];
|
||||
|
||||
size_t data_len = srclen - src_ptr_table_len - 4;
|
||||
|
||||
*(u32 *) dst = (num_rooms);
|
||||
|
||||
u32 *dst_offsets = (u32 *) (dst + sizeof(u32));
|
||||
u32 cur_dst_offset = dst_ptr_table_len + sizeof(u32);
|
||||
|
||||
u32 cur_src_offset = PD_BE32(src_offsets[0]);
|
||||
u32 end_src_offset = PD_BE32(src_offsets[num_rooms]);
|
||||
int room = 0;
|
||||
|
||||
while (1) {
|
||||
// Check if this is a new room and write the pointer offset if so
|
||||
while (room < (num_rooms + 1) && PD_BE32(src_offsets[room]) == cur_src_offset) {
|
||||
dst_offsets[room] = (cur_dst_offset);
|
||||
room++;
|
||||
}
|
||||
|
||||
if (cur_src_offset >= end_src_offset) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write tile data
|
||||
struct tile *n64tile = (struct tile *) &src[cur_src_offset];
|
||||
struct tile hosttile;
|
||||
|
||||
hosttile.type = n64tile->type;
|
||||
hosttile.numvertices = n64tile->numvertices;
|
||||
hosttile.flags = PD_BE16(n64tile->flags);
|
||||
hosttile.floortype = PD_BE16(n64tile->floortype);
|
||||
hosttile.xmin = n64tile->xmin;
|
||||
hosttile.ymin = n64tile->ymin;
|
||||
hosttile.zmin = n64tile->zmin;
|
||||
hosttile.xmax = n64tile->xmax;
|
||||
hosttile.ymax = n64tile->ymax;
|
||||
hosttile.zmax = n64tile->zmax;
|
||||
hosttile.floorcol = PD_BE16(n64tile->floorcol);
|
||||
|
||||
memcpy(&dst[cur_dst_offset], &hosttile, sizeof(struct tile));
|
||||
|
||||
cur_dst_offset += sizeof(struct tile);
|
||||
cur_src_offset += sizeof(struct tile);
|
||||
|
||||
// Write tile vertices
|
||||
for (int i = 0; i < hosttile.numvertices; i++) {
|
||||
*(s16 *) &dst[cur_dst_offset + 0] = PD_BE16(*(s16 *) &src[cur_src_offset + 0]);
|
||||
*(s16 *) &dst[cur_dst_offset + 2] = PD_BE16(*(s16 *) &src[cur_src_offset + 2]);
|
||||
*(s16 *) &dst[cur_dst_offset + 4] = PD_BE16(*(s16 *) &src[cur_src_offset + 4]);
|
||||
cur_dst_offset += 6;
|
||||
cur_src_offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
return ALIGN16(cur_dst_offset);
|
||||
}
|
||||
|
||||
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize)
|
||||
{
|
||||
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_TILES);
|
||||
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
|
||||
|
||||
u32 newSize = convertTiles(dst, data, size);
|
||||
|
||||
if (newSize > newSizeEstimated) {
|
||||
sysFatalError("overflow when trying to preprocess a tiles file, size %d newsize %d", size, newSize);
|
||||
}
|
||||
|
||||
memcpy(data, dst, newSize);
|
||||
sysMemFree(dst);
|
||||
|
||||
*outSize = newSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
#include "preprocess/gbi.h"
|
||||
|
||||
#if UINTPTR_MAX > 0xFFFFFFFFu
|
||||
#define HOST_DWORDS_PER_CMD 2
|
||||
#else
|
||||
#define HOST_DWORDS_PER_CMD 1
|
||||
#endif
|
||||
|
||||
struct vtx {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 z;
|
||||
u8 flags;
|
||||
u8 colour;
|
||||
s16 s;
|
||||
s16 t;
|
||||
};
|
||||
|
||||
struct texaddr {
|
||||
u32 src;
|
||||
u32 dst;
|
||||
};
|
||||
|
||||
static u32 gbiSegments[16];
|
||||
static u32 srcVtxOffset;
|
||||
static u32 dstVtxOffset;
|
||||
|
||||
static struct texaddr texAddrs[64];
|
||||
static int numTexAddrs;
|
||||
|
||||
void gbiReset(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAYCOUNT(gbiSegments); i++) {
|
||||
gbiSegments[i] = 0;
|
||||
}
|
||||
|
||||
srcVtxOffset = 0;
|
||||
dstVtxOffset = 0;
|
||||
numTexAddrs = 0;
|
||||
}
|
||||
|
||||
void gbiSetSegment(int segment, u32 offset)
|
||||
{
|
||||
gbiSegments[segment] = offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
void gbiSetVtx(u32 src_offset, u32 dst_offset)
|
||||
{
|
||||
srcVtxOffset = src_offset & 0x00ffffff;
|
||||
dstVtxOffset = dst_offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
void gbiAddTexAddr(u32 src_offset, u32 dst_offset)
|
||||
{
|
||||
texAddrs[numTexAddrs].src = src_offset & 0x00ffffff;
|
||||
texAddrs[numTexAddrs++].dst = dst_offset & 0x00ffffff;
|
||||
}
|
||||
|
||||
u32 gbiFindTexAddr(u32 src_offset)
|
||||
{
|
||||
for (int i = 0; i < numTexAddrs; i++) {
|
||||
if (texAddrs[i].src == src_offset)
|
||||
return texAddrs[i].dst;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gbiConvertVtx(u8 *dst, u32 offset, int count)
|
||||
{
|
||||
if (!offset) return;
|
||||
struct vtx* vtxs = (struct vtx*)(dst + offset);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct vtx* vtx = &vtxs[i];
|
||||
|
||||
vtx->x = PD_BE16(vtx->x);
|
||||
vtx->y = PD_BE16(vtx->y);
|
||||
vtx->z = PD_BE16(vtx->z);
|
||||
vtx->s = PD_BE16(vtx->s);
|
||||
vtx->t = PD_BE16(vtx->t);
|
||||
}
|
||||
}
|
||||
|
||||
#define CMD_IS_VTX(cmd) ((cmd & 0xff00000000000000) == 0x0400000000000000)
|
||||
#define CMD_IS_DL(cmd) ((cmd & 0xff00000000000000) == 0x0600000000000000)
|
||||
#define CMD_IS_COL(cmd) ((cmd & 0xff00000000000000) == 0x0700000000000000)
|
||||
#define CMD_IS_ENDDL(cmd) ((cmd & 0xff00000000000000) == 0xb800000000000000)
|
||||
#define CMD_IS_MOVEWORD(cmd) ((cmd & 0xff00000000000000) == 0xbc00000000000000)
|
||||
#define CMD_IS_MOVEMEM(cmd) ((cmd & 0xff00000000000000) == 0x0300000000000000)
|
||||
#define CMD_IS_MTX(cmd) ((cmd & 0xff00000000000000) == 0x0100000000000000)
|
||||
#define CMD_IS_SETTIMG(cmd) ((cmd & 0xff00000000000000) == 0xfd00000000000000)
|
||||
#define CMD_IS_SETZIMG(cmd) ((cmd & 0xff00000000000000) == 0xfe00000000000000)
|
||||
#define CMD_IS_SETCIMG(cmd) ((cmd & 0xff00000000000000) == 0xff00000000000000)
|
||||
|
||||
#define CMD_HAS_ADDR(cmd) CMD_IS_VTX(cmd) \
|
||||
|| CMD_IS_COL(cmd) \
|
||||
|| CMD_IS_MOVEWORD(cmd) \
|
||||
|| CMD_IS_SETTIMG(cmd)
|
||||
|
||||
|
||||
#define CMD_IS_SEGMENTED(cmd) ( CMD_IS_MOVEMEM(cmd) \
|
||||
|| CMD_IS_MTX(cmd) \
|
||||
|| CMD_IS_VTX(cmd) \
|
||||
|| CMD_IS_COL(cmd) \
|
||||
|| CMD_IS_DL(cmd) \
|
||||
|| CMD_IS_SETTIMG(cmd) \
|
||||
|| CMD_IS_SETCIMG(cmd) \
|
||||
|| CMD_IS_SETZIMG(cmd))
|
||||
|
||||
/**
|
||||
* Segment 5 is the start of the model file. The data in these files shifts
|
||||
* depending on the pointer size, so this function adjusts the offset accordingly.
|
||||
*/
|
||||
static u64 gbiRewriteAddr(u64 cmd, u8 opcode)
|
||||
{
|
||||
u8 segment = (cmd & 0x0f000000) >> 24;
|
||||
u32 offset = cmd & 0x00ffffff;
|
||||
|
||||
if (segment == 5) {
|
||||
if (opcode == 0xfd) {
|
||||
offset = gbiFindTexAddr(offset);
|
||||
}
|
||||
else {
|
||||
if (offset < srcVtxOffset) {
|
||||
sysFatalError("Tried to load data from offset 0x%x but segment starts at 0x%x\n", offset, srcVtxOffset);
|
||||
}
|
||||
|
||||
offset = offset - srcVtxOffset + dstVtxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
return (cmd & 0xffffffffff000000) | offset;
|
||||
}
|
||||
|
||||
void gbiGdlRewriteAddrs(u8 *dst, u32 offset)
|
||||
{
|
||||
if (!offset) return;
|
||||
|
||||
u64 *cmds = (u64 *)(dst + (offset & 0x00ffffff));
|
||||
if (!cmds) return;
|
||||
|
||||
u64 cmd;
|
||||
|
||||
do {
|
||||
cmd = *cmds;
|
||||
Gfx* gfxcmd = (Gfx *)cmds;
|
||||
int idx = 0;
|
||||
u8 opcode = (cmd >> 24) & 0xff;
|
||||
|
||||
#if HOST_DWORDS_PER_CMD == 2
|
||||
idx = 1;
|
||||
opcode = (cmd >> 24) & 0xff;
|
||||
#endif
|
||||
cmd = (u64)opcode << 56;
|
||||
|
||||
if (CMD_HAS_ADDR(cmd)) {
|
||||
cmds[idx] = gbiRewriteAddr(cmds[idx], opcode);
|
||||
}
|
||||
|
||||
if (CMD_IS_SEGMENTED(cmd)) {
|
||||
gfxcmd->words.w1 |= 1;
|
||||
}
|
||||
|
||||
cmds += HOST_DWORDS_PER_CMD;
|
||||
} while (!CMD_IS_ENDDL(cmd));
|
||||
}
|
||||
|
||||
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds)
|
||||
{
|
||||
dstpos = ALIGN8(dstpos);
|
||||
|
||||
u64 *n64_cmd = (u64*)&src[srcpos];
|
||||
u64 *host_cmd = (u64*)&dst[dstpos];
|
||||
u64 cmd;
|
||||
|
||||
do {
|
||||
cmd = PD_BE64(*n64_cmd);
|
||||
|
||||
#if HOST_DWORDS_PER_CMD == 2
|
||||
host_cmd[0] = ((cmd & 0xffffffff00000000) >> 32);
|
||||
host_cmd[1] = (cmd & 0xffffffff);
|
||||
|
||||
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
||||
host_cmd[1] |= 1;
|
||||
}
|
||||
#else
|
||||
host_cmd[0] = (cmd >> 32) | ((cmd & 0xffffffff) << 32);
|
||||
|
||||
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
|
||||
Gfx* gfxcmd = (Gfx*)host_cmd;
|
||||
gfxcmd->words.w1 |= 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
dstpos += sizeof(*host_cmd) * HOST_DWORDS_PER_CMD;
|
||||
host_cmd += HOST_DWORDS_PER_CMD;
|
||||
n64_cmd++;
|
||||
} while (!CMD_IS_ENDDL(cmd));
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
#include "data.h"
|
||||
#include "bss.h"
|
||||
#include "game/setuputils.h"
|
||||
#include "game/texdecompress.h"
|
||||
#include "mod.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
u8 *preprocessAnimations(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
// set the anim table pointers as well
|
||||
extern u8 *_animationsTableRomStart;
|
||||
extern u8 *_animationsTableRomEnd;
|
||||
|
||||
// the animation table is at the end of the segment
|
||||
u32 *animtbl = (void *)(data + size - 0x38a0);
|
||||
_animationsTableRomStart = (u8 *)animtbl;
|
||||
_animationsTableRomEnd = data + size;
|
||||
|
||||
PD_SWAP_VAL(*animtbl);
|
||||
const u32 count = *animtbl++;
|
||||
|
||||
struct animtableentry *anim = (struct animtableentry *)animtbl;
|
||||
for (u32 i = 0; i < count; ++i, ++anim) {
|
||||
PD_SWAP_VAL(anim->numframes);
|
||||
PD_SWAP_VAL(anim->bytesperframe);
|
||||
PD_SWAP_VAL(anim->headerlen);
|
||||
PD_SWAP_VAL(anim->data);
|
||||
// if an external replacement exists, replace the table entry and mark the offset
|
||||
if (modAnimationLoadDescriptor(i, anim) > 0) {
|
||||
anim->data = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessMpConfigs(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
const u32 count = size / sizeof(struct mpconfig);
|
||||
struct mpconfig *cfg = (struct mpconfig *)data;
|
||||
for (u32 i = 0; i < count; ++i, ++cfg) {
|
||||
PD_SWAP_VAL(cfg->setup.options);
|
||||
PD_SWAP_VAL(cfg->setup.teamscorelimit);
|
||||
PD_SWAP_VAL(cfg->setup.chrslots);
|
||||
// TODO: are these required or are they always 0?
|
||||
PD_SWAP_VAL(cfg->setup.fileguid.deviceserial);
|
||||
PD_SWAP_VAL(cfg->setup.fileguid.fileid);
|
||||
// convert MPWEAPON_ to take classic weapons and JPN weapons into account
|
||||
for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) {
|
||||
#if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */
|
||||
if (cfg->setup.weapons[j] >= 0x24) {
|
||||
// weapons after and including the shield need to be shifted (for classic weapons)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x22) {
|
||||
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x19) {
|
||||
// weapons after the combat knife also need to be shifted up in JPN
|
||||
cfg->setup.weapons[j]++;
|
||||
}
|
||||
#else
|
||||
if (cfg->setup.weapons[j] >= 0x25) {
|
||||
// weapons after and including the shield need to be shifted (for classic weapons)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
|
||||
}
|
||||
if (cfg->setup.weapons[j] >= 0x23) {
|
||||
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
|
||||
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessTexturesList(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
struct texture *tex = (struct texture *)data;
|
||||
const u32 count = size / sizeof(*tex);
|
||||
for (u32 i = 0; i < count; ++i, ++tex) {
|
||||
// TODO: it sure looks like none of the fields except soundsurfacetype, surfacetype and dataoffset are set
|
||||
// just swap the last 3 bytes of the first word...
|
||||
const u32 dofs = (u32)tex->dataoffset << 8;
|
||||
tex->dataoffset = PD_BE32(dofs);
|
||||
// ...and the surface types in the first byte
|
||||
const u8 tmp = tex->soundsurfacetype;
|
||||
tex->soundsurfacetype = tex->surfacetype;
|
||||
tex->surfacetype = tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libaudio.h"
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct n64_adpcm_waveinfo {
|
||||
u32 loop; // ptr to ALADPCMloop
|
||||
u32 book; // ptr to ALADPCMBook
|
||||
};
|
||||
|
||||
struct n64_raw_waveinfo {
|
||||
u32 loop; // ptr to ALRawLoop
|
||||
};
|
||||
|
||||
struct n64_wavetable {
|
||||
u32 base;
|
||||
s32 len;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
union {
|
||||
struct n64_adpcm_waveinfo adpcmWave;
|
||||
struct n64_raw_waveinfo rawWave;
|
||||
} waveInfo;
|
||||
};
|
||||
|
||||
struct n64_sound {
|
||||
u32 envelope; // ptr to ALEnvelope
|
||||
u32 keyMap; // ptr to ALKeyMap
|
||||
u32 wavetable; // ptr to struct n64_wavetable
|
||||
u8 samplePan;
|
||||
u8 sampleVolume;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct n64_instrument {
|
||||
u8 volume;
|
||||
u8 pan;
|
||||
u8 priority;
|
||||
u8 flags;
|
||||
u8 tremType;
|
||||
u8 tremRate;
|
||||
u8 tremDepth;
|
||||
u8 tremDelay;
|
||||
u8 vibType;
|
||||
u8 vibRate;
|
||||
u8 vibDepth;
|
||||
u8 vibDelay;
|
||||
s16 bendRange;
|
||||
s16 soundCount;
|
||||
u32 soundArray[1]; // ptr to struct n64_sound
|
||||
};
|
||||
|
||||
struct n64_bank {
|
||||
s16 instCount;
|
||||
u8 flags;
|
||||
u8 pad;
|
||||
s32 sampleRate;
|
||||
u32 percussion; // ptr to struct n64_instrument
|
||||
u32 instArray[1]; // ptr to struct n64_instrument
|
||||
};
|
||||
|
||||
struct n64_bankfile {
|
||||
s16 revision;
|
||||
s16 bankCount;
|
||||
u32 bankArray[1]; // ptr to struct n64_bank
|
||||
};
|
||||
|
||||
// only proceeds to convert the next item if it's not already converted
|
||||
#define AL_NEXT_ITEM(field, func) { \
|
||||
struct ptrmarker *marker = ptrFind(srcpos); \
|
||||
if (marker == NULL) { \
|
||||
field = (void *)(uintptr_t)(dstpos); \
|
||||
ptrAdd(srcpos, (uintptr_t)(field)); \
|
||||
dstpos = func(dst, dstpos, src, srcpos); \
|
||||
} else { \
|
||||
field = (void *)marker->ptr_host; } \
|
||||
}
|
||||
|
||||
static u32 convertAudioEnvelope(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALEnvelope *n64_envelope = (ALEnvelope *) &src[srcpos];
|
||||
ALEnvelope *host_envelope = (ALEnvelope *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALEnvelope);
|
||||
|
||||
host_envelope->attackTime = PD_BE32(n64_envelope->attackTime);
|
||||
host_envelope->decayTime = PD_BE32(n64_envelope->decayTime);
|
||||
host_envelope->releaseTime = PD_BE32(n64_envelope->releaseTime);
|
||||
host_envelope->attackVolume = n64_envelope->attackVolume;
|
||||
host_envelope->decayVolume = n64_envelope->decayVolume;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioKeyMap(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALKeyMap *n64_keymap = (ALKeyMap *) &src[srcpos];
|
||||
ALKeyMap *host_keymap = (ALKeyMap *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALKeyMap);
|
||||
|
||||
host_keymap->velocityMin = n64_keymap->velocityMin;
|
||||
host_keymap->velocityMax = n64_keymap->velocityMax;
|
||||
host_keymap->keyMin = n64_keymap->keyMin;
|
||||
host_keymap->keyMax = n64_keymap->keyMax;
|
||||
host_keymap->keyBase = n64_keymap->keyBase;
|
||||
host_keymap->detune = n64_keymap->detune;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioAdpcmLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALADPCMloop *n64_loop = (ALADPCMloop *) &src[srcpos];
|
||||
ALADPCMloop *host_loop = (ALADPCMloop *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALADPCMloop);
|
||||
|
||||
host_loop->start = PD_BE32(n64_loop->start);
|
||||
host_loop->end = PD_BE32(n64_loop->end);
|
||||
host_loop->count = PD_BE32(n64_loop->count);
|
||||
|
||||
for (int i = 0; i < ARRAYCOUNT(host_loop->state); i++) {
|
||||
host_loop->state[i] = PD_BE16(n64_loop->state[i]);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioAdpcmBook(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALADPCMBook *n64_book = (ALADPCMBook *) &src[srcpos];
|
||||
ALADPCMBook *host_book = (ALADPCMBook *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALADPCMBook);
|
||||
|
||||
host_book->order = PD_BE32(n64_book->order);
|
||||
host_book->npredictors = PD_BE32(n64_book->npredictors);
|
||||
|
||||
for (int i = 0; i < ARRAYCOUNT(host_book->book); i++) {
|
||||
host_book->book[i] = PD_BE16(n64_book->book[i]);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioRawLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
ALRawLoop *n64_loop = (ALRawLoop *) &src[srcpos];
|
||||
ALRawLoop *host_loop = (ALRawLoop *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALRawLoop);
|
||||
|
||||
host_loop->start = PD_BE32(n64_loop->start);
|
||||
host_loop->end = PD_BE32(n64_loop->end);
|
||||
host_loop->count = PD_BE32(n64_loop->count);
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioWaveTable(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_wavetable *n64_wavetable = (struct n64_wavetable *) &src[srcpos];
|
||||
ALWaveTable *host_wavetable = (ALWaveTable *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALWaveTable);
|
||||
|
||||
host_wavetable->base = (void *)(uintptr_t)PD_BE32(n64_wavetable->base);
|
||||
host_wavetable->len = PD_BE32(n64_wavetable->len);
|
||||
host_wavetable->type = n64_wavetable->type;
|
||||
host_wavetable->flags = n64_wavetable->flags;
|
||||
|
||||
if (host_wavetable->type == AL_ADPCM_WAVE) {
|
||||
if (n64_wavetable->waveInfo.adpcmWave.loop) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.loop);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.loop, convertAudioAdpcmLoop);
|
||||
} else {
|
||||
host_wavetable->waveInfo.adpcmWave.loop = NULL;
|
||||
}
|
||||
|
||||
if (n64_wavetable->waveInfo.adpcmWave.book) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.book);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.book, convertAudioAdpcmBook);
|
||||
} else {
|
||||
host_wavetable->waveInfo.adpcmWave.book = NULL;
|
||||
}
|
||||
} else if (host_wavetable->type == AL_RAW16_WAVE) {
|
||||
if (n64_wavetable->waveInfo.rawWave.loop) {
|
||||
srcpos = PD_BE32(n64_wavetable->waveInfo.rawWave.loop);
|
||||
AL_NEXT_ITEM(host_wavetable->waveInfo.rawWave.loop, convertAudioRawLoop);
|
||||
} else {
|
||||
host_wavetable->waveInfo.rawWave.loop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioSound(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_sound *n64_sound = (struct n64_sound *) &src[srcpos];
|
||||
ALSound *host_sound = (ALSound *) &dst[dstpos];
|
||||
|
||||
dstpos += sizeof(ALSound);
|
||||
|
||||
if (n64_sound->envelope) {
|
||||
srcpos = PD_BE32(n64_sound->envelope);
|
||||
AL_NEXT_ITEM(host_sound->envelope, convertAudioEnvelope);
|
||||
} else {
|
||||
host_sound->envelope = NULL;
|
||||
}
|
||||
|
||||
if (n64_sound->keyMap) {
|
||||
srcpos = PD_BE32(n64_sound->keyMap);
|
||||
AL_NEXT_ITEM(host_sound->keyMap, convertAudioKeyMap);
|
||||
} else {
|
||||
host_sound->keyMap = NULL;
|
||||
}
|
||||
|
||||
if (n64_sound->wavetable) {
|
||||
srcpos = PD_BE32(n64_sound->wavetable);
|
||||
AL_NEXT_ITEM(host_sound->wavetable, convertAudioWaveTable);
|
||||
} else {
|
||||
host_sound->wavetable = NULL;
|
||||
}
|
||||
|
||||
host_sound->samplePan = n64_sound->samplePan;
|
||||
host_sound->sampleVolume = n64_sound->sampleVolume;
|
||||
host_sound->flags = n64_sound->flags;
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioInstrument(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_instrument *n64_instrument = (struct n64_instrument *) &src[srcpos];
|
||||
ALInstrument *host_instrument = (ALInstrument *) &dst[dstpos];
|
||||
const s16 soundCount = PD_BE16(n64_instrument->soundCount);
|
||||
|
||||
host_instrument->volume = n64_instrument->volume;
|
||||
host_instrument->pan = n64_instrument->pan;
|
||||
host_instrument->priority = n64_instrument->priority;
|
||||
host_instrument->flags = n64_instrument->flags;
|
||||
host_instrument->tremType = n64_instrument->tremType;
|
||||
host_instrument->tremRate = n64_instrument->tremRate;
|
||||
host_instrument->tremDepth = n64_instrument->tremDepth;
|
||||
host_instrument->tremDelay = n64_instrument->tremDelay;
|
||||
host_instrument->vibType = n64_instrument->vibType;
|
||||
host_instrument->vibRate = n64_instrument->vibRate;
|
||||
host_instrument->vibDepth = n64_instrument->vibDepth;
|
||||
host_instrument->vibDelay = n64_instrument->vibDelay;
|
||||
host_instrument->bendRange = PD_BE16(n64_instrument->bendRange);
|
||||
host_instrument->soundCount = (soundCount);
|
||||
|
||||
dstpos = dstpos + sizeof(ALInstrument) + sizeof(uintptr_t) * (soundCount - 1);
|
||||
|
||||
for (int i = 0; i < soundCount; i++) {
|
||||
srcpos = PD_BE32(n64_instrument->soundArray[i]);
|
||||
AL_NEXT_ITEM(host_instrument->soundArray[i], convertAudioSound);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioBank(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
|
||||
{
|
||||
struct n64_bank *n64_bank = (struct n64_bank *) &src[srcpos];
|
||||
ALBank *host_bank = (ALBank *) &dst[dstpos];
|
||||
const s16 instCount = PD_BE16(n64_bank->instCount);
|
||||
|
||||
host_bank->instCount = (instCount);
|
||||
host_bank->flags = n64_bank->flags;
|
||||
host_bank->pad = n64_bank->pad;
|
||||
host_bank->sampleRate = PD_BE32(n64_bank->sampleRate);
|
||||
|
||||
dstpos = dstpos + sizeof(ALBank) + sizeof(uintptr_t) * (instCount - 1);
|
||||
|
||||
if (n64_bank->percussion) {
|
||||
srcpos = PD_BE32(n64_bank->percussion);
|
||||
AL_NEXT_ITEM(host_bank->percussion, convertAudioInstrument);
|
||||
} else {
|
||||
host_bank->percussion = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < instCount; i++) {
|
||||
srcpos = PD_BE32(n64_bank->instArray[i]);
|
||||
AL_NEXT_ITEM(host_bank->instArray[i], convertAudioInstrument);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
static u32 convertAudioBankFile(u8 *dst, u8 *src)
|
||||
{
|
||||
struct n64_bankfile *n64_bankfile = (struct n64_bankfile *)src;
|
||||
ALBankFile *host_bankfile = (ALBankFile *)dst;
|
||||
const s16 bankCount = PD_BE16(n64_bankfile->bankCount);
|
||||
|
||||
host_bankfile->revision = PD_BE16(n64_bankfile->revision);
|
||||
host_bankfile->bankCount = (bankCount);
|
||||
|
||||
u32 dstpos = sizeof(ALBankFile) + sizeof(uintptr_t) * (bankCount - 1);
|
||||
|
||||
for (int i = 0; i < bankCount; i++) {
|
||||
host_bankfile->bankArray[i] = (void *)(uintptr_t)(dstpos);
|
||||
u32 srcpos = PD_BE32(n64_bankfile->bankArray[i]);
|
||||
dstpos = convertAudioBank(dst, dstpos, src, srcpos);
|
||||
}
|
||||
|
||||
return dstpos;
|
||||
}
|
||||
|
||||
u8 *preprocessALBankFile(u8 *src, u32 size, u32 *outSize)
|
||||
{
|
||||
ptrReset();
|
||||
|
||||
const u32 dstlen = size * 3; // this should overshoot any possible bank size, but * 2 also works for vanilla banks
|
||||
u8 *dst = sysMemZeroAlloc(dstlen);
|
||||
|
||||
u32 reallen = convertAudioBankFile(dst, src);
|
||||
if (reallen > dstlen || ALIGN16(reallen) > dstlen) {
|
||||
sysFatalError("overflow when trying to preprocess an ALBankFile, size %u dstlen %u reallen %u", size, dstlen, reallen);
|
||||
}
|
||||
|
||||
reallen = ALIGN16(reallen);
|
||||
|
||||
if (reallen < dstlen) {
|
||||
dst = sysMemRealloc(dst, reallen);
|
||||
}
|
||||
|
||||
*outSize = reallen;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize)
|
||||
{
|
||||
ALCMidiHdr *hdr = (ALCMidiHdr *)data;
|
||||
PD_SWAP_VAL(hdr->division);
|
||||
for (s32 i = 0; i < ARRAYCOUNT(hdr->trackOffset); ++i) {
|
||||
PD_SWAP_VAL(hdr->trackOffset[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *preprocessSequences(u8* data, u32 size, u32 *outSize)
|
||||
{
|
||||
struct seqtable *seq = (struct seqtable *)data;
|
||||
PD_SWAP_VAL(seq->count);
|
||||
|
||||
for (s16 i = 0; i < seq->count; ++i) {
|
||||
PD_SWAP_VAL(seq->entries[i].binlen);
|
||||
PD_SWAP_VAL(seq->entries[i].ziplen);
|
||||
PD_SWAP_VAL(seq->entries[i].romaddr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess/common.h"
|
||||
|
||||
struct n64_fontchar {
|
||||
u8 index;
|
||||
s8 baseline;
|
||||
u8 height;
|
||||
u8 width;
|
||||
s32 kerningindex;
|
||||
u32 pixeldata;
|
||||
};
|
||||
|
||||
struct n64_fontcharjpn {
|
||||
u16 index;
|
||||
s8 baseline;
|
||||
u8 height;
|
||||
u8 width;
|
||||
s16 kerningindex;
|
||||
u32 pixeldata;
|
||||
};
|
||||
|
||||
u8 *preprocessFont(u8 *src, u32 srclen, u32 *outSize)
|
||||
{
|
||||
int num_chars = 94;
|
||||
#if VERSION == VERSION_PAL_FINAL
|
||||
// PAL has more characters in these fonts
|
||||
extern u8* _fonthandelgothicsmSegmentRomStart;
|
||||
extern u8* _fonthandelgothicxsSegmentRomStart;
|
||||
extern u8* _fonthandelgothicmdSegmentRomStart;
|
||||
if (src == _fonthandelgothicsmSegmentRomStart
|
||||
|| src == _fonthandelgothicxsSegmentRomStart
|
||||
|| src == _fonthandelgothicmdSegmentRomStart) {
|
||||
num_chars = 135;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t dstlen = srclen - (num_chars * sizeof(struct n64_fontchar)) + (num_chars * sizeof(struct fontchar)) + 0x20;
|
||||
u8* dst = sysMemZeroAlloc(dstlen);
|
||||
|
||||
// Kerning table
|
||||
s32 *src_kerning_table = (s32 *)src;
|
||||
s32 *dst_kerning_table = (s32 *)dst;
|
||||
|
||||
for (int i = 0; i < 13 * 13; i++) {
|
||||
dst_kerning_table[i] = PD_BE32(src_kerning_table[i]);
|
||||
}
|
||||
|
||||
u32 src_offset = PD_ALIGN(13 * 13 * 4, sizeof(u32));
|
||||
u32 dst_offset = PD_ALIGN(13 * 13 * 4, sizeof(uintptr_t));
|
||||
|
||||
// Character table
|
||||
#if VERSION == VERSION_JPN_FINAL
|
||||
struct n64_fontcharjpn *src_char_table = (struct n64_fontcharjpn *) &src[src_offset];
|
||||
struct fontchar *dst_char_table = (struct fontchar *) &dst[dst_offset];
|
||||
u32 diff = (dst_offset + num_chars * sizeof(struct fontchar)) - (src_offset + num_chars * sizeof(struct n64_fontcharjpn));
|
||||
|
||||
for (int i = 0; i < num_chars; i++) {
|
||||
dst_char_table[i].index = PD_BE16(src_char_table[i].index);
|
||||
dst_char_table[i].baseline = src_char_table[i].baseline;
|
||||
dst_char_table[i].height = src_char_table[i].height;
|
||||
dst_char_table[i].width = src_char_table[i].width;
|
||||
dst_char_table[i].kerningindex = PD_BE16(src_char_table[i].kerningindex);
|
||||
dst_char_table[i].pixeldata = (void *)(uintptr_t)(src_char_table[i].pixeldata ? PD_BE32(src_char_table[i].pixeldata) + diff : 0);
|
||||
}
|
||||
|
||||
src_offset += num_chars * sizeof(struct n64_fontcharjpn);
|
||||
dst_offset += num_chars * sizeof(struct fontchar);
|
||||
#else
|
||||
struct n64_fontchar *src_char_table = (struct n64_fontchar *) &src[src_offset];
|
||||
struct fontchar *dst_char_table = (struct fontchar *) &dst[dst_offset];
|
||||
u32 diff = (dst_offset + num_chars * sizeof(struct fontchar)) - (src_offset + num_chars * sizeof(struct n64_fontchar));
|
||||
|
||||
for (int i = 0; i < num_chars; i++) {
|
||||
dst_char_table[i].index = src_char_table[i].index;
|
||||
dst_char_table[i].baseline = src_char_table[i].baseline;
|
||||
dst_char_table[i].height = src_char_table[i].height;
|
||||
dst_char_table[i].width = src_char_table[i].width;
|
||||
dst_char_table[i].kerningindex = PD_BE32(src_char_table[i].kerningindex);
|
||||
dst_char_table[i].pixeldata = (void *)(uintptr_t)(src_char_table[i].pixeldata ? PD_BE32(src_char_table[i].pixeldata) + diff : 0);
|
||||
}
|
||||
|
||||
src_offset += num_chars * sizeof(struct n64_fontchar);
|
||||
dst_offset += num_chars * sizeof(struct fontchar);
|
||||
#endif
|
||||
|
||||
// Pixel data
|
||||
u32 len = srclen - src_offset;
|
||||
memcpy(&dst[dst_offset], &src[src_offset], len);
|
||||
|
||||
if (outSize) *outSize = ALIGN16(dst_offset + len);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
u8 *preprocessJpnFont(u8* data, u32 size, u32* outSize)
|
||||
{
|
||||
// ???
|
||||
return NULL;
|
||||
}
|
||||
+93
-13
@@ -4,7 +4,6 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/ultratypes.h>
|
||||
#include "lib/rzip.h"
|
||||
#include "romdata.h"
|
||||
#include "fs.h"
|
||||
@@ -51,6 +50,9 @@
|
||||
|
||||
#define ROMDATA_MAX_FILES 2048
|
||||
|
||||
#define GBC_ROM_NAME "pd.gbc"
|
||||
#define GBC_ROM_SIZE 4194304
|
||||
|
||||
u8 *g_RomFile;
|
||||
u32 g_RomFileSize;
|
||||
|
||||
@@ -236,6 +238,17 @@ static inline void romdataLoadRom(void)
|
||||
romDataSegSize = dataSegLen;
|
||||
}
|
||||
|
||||
static inline void romdataUpdateSegStartEnd(struct romfile* seg)
|
||||
{
|
||||
if (seg->segstart) {
|
||||
*seg->segstart = seg->data;
|
||||
}
|
||||
|
||||
if (seg->segend) {
|
||||
*seg->segend = seg->data + seg->size;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void romdataInitSegment(struct romfile *seg)
|
||||
{
|
||||
if (!seg->data) {
|
||||
@@ -251,7 +264,7 @@ static inline void romdataInitSegment(struct romfile *seg)
|
||||
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;
|
||||
seg->size = (uintptr_t)g_RomFileSize - (uintptr_t)seg->data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +282,7 @@ static inline void romdataInitSegment(struct romfile *seg)
|
||||
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);
|
||||
sysLogPrintf(LOG_NOTE, "loading segment %s from ROM (offset %08x pointer %p)", seg->name, (uintptr_t)seg->data, newData);
|
||||
} else {
|
||||
sysFatalError("No ROM or external file for segment:\n%s", seg->name);
|
||||
}
|
||||
@@ -281,17 +294,19 @@ static inline void romdataInitSegment(struct romfile *seg)
|
||||
|
||||
seg->data = newData;
|
||||
|
||||
if (seg->segstart) {
|
||||
*seg->segstart = seg->data;
|
||||
}
|
||||
|
||||
if (seg->segend) {
|
||||
*seg->segend = seg->data + seg->size;
|
||||
}
|
||||
romdataUpdateSegStartEnd(seg);
|
||||
|
||||
// call the post load function if any
|
||||
if (seg->preprocess && !seg->preprocessed) {
|
||||
seg->preprocess(seg->data, seg->size);
|
||||
newData = seg->preprocess(seg->data, seg->size, &seg->size);
|
||||
|
||||
if (newData) {
|
||||
if (seg->source == SRC_EXTERNAL)
|
||||
sysMemFree(seg->data);
|
||||
seg->data = newData;
|
||||
romdataUpdateSegStartEnd(seg);
|
||||
}
|
||||
|
||||
seg->preprocessed = 1;
|
||||
}
|
||||
}
|
||||
@@ -386,6 +401,53 @@ s32 romdataInit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool romdataCheckGbcRomContents(const u8 *gbcRomFile, const u32 gbcRomSize)
|
||||
{
|
||||
if (gbcRomSize != GBC_ROM_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ROM title
|
||||
if (memcmp(gbcRomFile + 0x134, "PerfDark VPDE", 15) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Licensee code
|
||||
if (memcmp(gbcRomFile + 0x144, "4Y", 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Header and global checksums
|
||||
if (gbcRomFile[0x14D] != 0xA1 || gbcRomFile[0x14E] != 0xAD || gbcRomFile[0x14F] != 0x0F) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 romdataCheckGbcRom(void)
|
||||
{
|
||||
if (fsFileSize(GBC_ROM_NAME) < 0) {
|
||||
// bail early if it doesn't exist to avoid generating error messages
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 gbcRomSize = 0;
|
||||
u8 *gbcRomFile = fsFileLoad(GBC_ROM_NAME, &gbcRomSize);
|
||||
if (!gbcRomFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool ret = romdataCheckGbcRomContents(gbcRomFile, gbcRomSize);
|
||||
sysMemFree(gbcRomFile);
|
||||
|
||||
if (ret) {
|
||||
sysLogPrintf(LOG_NOTE, "romdataCheckGbcRom: valid GBC rom found");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 romdataFileGetSize(s32 fileNum)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
@@ -447,7 +509,7 @@ u8 *romdataFileLoad(s32 fileNum, u32 *outSize)
|
||||
return out;
|
||||
}
|
||||
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
|
||||
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize)
|
||||
{
|
||||
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
|
||||
sysLogPrintf(LOG_ERROR, "romdataFilePreprocess: invalid file num %d", fileNum);
|
||||
@@ -465,7 +527,7 @@ void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
|
||||
}
|
||||
}
|
||||
// then preprocess
|
||||
filePreprocFuncs[loadType](data, size);
|
||||
filePreprocFuncs[loadType](data, size, outSize);
|
||||
// fileSlots[fileNum].preprocessed = 1;
|
||||
}
|
||||
}
|
||||
@@ -524,3 +586,21 @@ u32 romdataSegGetSize(const char *segName)
|
||||
{
|
||||
return romdataGetSeg(segName)->size;
|
||||
}
|
||||
|
||||
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype)
|
||||
{
|
||||
#ifdef PLATFORM_64BIT
|
||||
switch (loadtype) {
|
||||
case LOADTYPE_BG: return (u32)(size * 1.1f);
|
||||
case LOADTYPE_TILES: return (u32)(size * 1.1f);
|
||||
case LOADTYPE_LANG: return (u32)(size * 1.3f);
|
||||
case LOADTYPE_SETUP: return (u32)(size * 1.5f);
|
||||
case LOADTYPE_PADS: return (u32)(size * 1.7f);
|
||||
case LOADTYPE_MODEL: return (u32)(size * 1.7f);
|
||||
case LOADTYPE_GUN: return (u32)(size * 1.7f);
|
||||
default:
|
||||
sysLogPrintf(LOG_WARNING, "romdataFileGetEstimatedSize: wrong loadtype %d", loadtype);
|
||||
}
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
+6
-1
@@ -40,7 +40,7 @@ __attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
|
||||
// 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)
|
||||
#elif defined(PLATFORM_ARM) && (defined(PLATFORM_64BIT) || PLATFORM_ARM == 7 || PLATFORM_ARM == 8)
|
||||
// same as YieldProcessor() on ARM Windows
|
||||
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
|
||||
#else
|
||||
@@ -288,6 +288,11 @@ void *sysMemZeroAlloc(const u32 size)
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
void *sysMemRealloc(void *ptr, const u32 newSize)
|
||||
{
|
||||
return realloc(ptr, newSize);
|
||||
}
|
||||
|
||||
void sysMemFree(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
|
||||
+273
-24
@@ -6,36 +6,63 @@
|
||||
#include <PR/gbi.h>
|
||||
#include "platform.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "video.h"
|
||||
|
||||
#include "../fast3d/gfx_api.h"
|
||||
#include "../fast3d/gfx_sdl.h"
|
||||
#include "../fast3d/gfx_opengl.h"
|
||||
|
||||
#ifdef PLATFORM_NSWITCH
|
||||
#define DEFAULT_VID_WIDTH 1280
|
||||
#define DEFAULT_VID_HEIGHT 720
|
||||
#define DEFAULT_VID_FULLSCREEN true
|
||||
#define DEFAULT_VID_FULLSCREEN_EXCLUSIVE true
|
||||
#else
|
||||
#define DEFAULT_VID_WIDTH 640
|
||||
#define DEFAULT_VID_HEIGHT 480
|
||||
#define DEFAULT_VID_FULLSCREEN false
|
||||
#define DEFAULT_VID_FULLSCREEN_EXCLUSIVE false
|
||||
#endif
|
||||
|
||||
static struct GfxWindowManagerAPI *wmAPI;
|
||||
static struct GfxRenderingAPI *renderingAPI;
|
||||
|
||||
static bool initDone = false;
|
||||
|
||||
static s32 vidWidth = 640;
|
||||
static s32 vidHeight = 480;
|
||||
static s32 vidWidth = DEFAULT_VID_WIDTH;
|
||||
static s32 vidHeight = DEFAULT_VID_HEIGHT;
|
||||
static s32 vidFramebuffers = true;
|
||||
static s32 vidFullscreen = false;
|
||||
static s32 vidFullscreenExclusive = false;
|
||||
static s32 vidFullscreen = DEFAULT_VID_FULLSCREEN;
|
||||
static s32 vidFullscreenExclusive = DEFAULT_VID_FULLSCREEN_EXCLUSIVE;
|
||||
static s32 vidMaximize = false;
|
||||
static s32 vidCenter = false;
|
||||
static s32 vidAllowHiDpi = false;
|
||||
static s32 vidVsync = 1;
|
||||
static s32 vidMSAA = 1;
|
||||
static s32 vidFramerateLimit = 0;
|
||||
|
||||
static s32 vidDisplayFPS = 0;
|
||||
static f32 vidDisplayFPSInterval = 1.f;
|
||||
static f32 vidAvgFPS = 0;
|
||||
static f64 vidLastRenderTime;
|
||||
|
||||
static s32 vidNumModes = 1;
|
||||
static displaymode vidModeDefault;
|
||||
static displaymode *vidModes = &vidModeDefault;
|
||||
|
||||
static s32 texFilter = FILTER_LINEAR;
|
||||
static s32 texFilter2D = true;
|
||||
static s32 texDetail = true;
|
||||
static s32 texDetail = false;
|
||||
|
||||
static u32 dlcount = 0;
|
||||
static u32 frames = 0;
|
||||
static u32 framesPerSec = 0;
|
||||
static f64 startTime, endTime, fpsTime;
|
||||
static f64 startTime, endTime;
|
||||
static f64 accumDelta = 0.0;
|
||||
static f64 fpsTime = 0.0;
|
||||
static s32 fpsNumFrames = 0;
|
||||
|
||||
static s32 videoInitDisplayModes(void);
|
||||
|
||||
s32 videoInit(void)
|
||||
{
|
||||
@@ -61,23 +88,18 @@ s32 videoInit(void)
|
||||
.fullscreen = vidFullscreen,
|
||||
.fullscreen_is_exclusive = vidFullscreenExclusive,
|
||||
.maximized = vidMaximize,
|
||||
.centered = vidCenter,
|
||||
.allow_hidpi = vidAllowHiDpi
|
||||
}
|
||||
};
|
||||
|
||||
gfx_init(&set);
|
||||
|
||||
if (!wmAPI->set_swap_interval(vidVsync)) {
|
||||
vidVsync = 0;
|
||||
}
|
||||
videoInitDisplayModes();
|
||||
videoSetVsync(vidVsync);
|
||||
videoSetFramerateLimit(vidFramerateLimit);
|
||||
|
||||
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);
|
||||
gfx_set_texture_filter((enum FilteringMode)texFilter);
|
||||
|
||||
initDone = true;
|
||||
return 0;
|
||||
@@ -89,6 +111,10 @@ void videoStartFrame(void)
|
||||
startTime = wmAPI->get_time();
|
||||
gfx_start_frame();
|
||||
}
|
||||
|
||||
// Synchronize with their backend counterparts.
|
||||
vidFullscreen = videoGetFullscreen();
|
||||
vidMaximize = videoGetMaximizeWindow();
|
||||
}
|
||||
|
||||
void videoSubmitCommands(Gfx *cmds)
|
||||
@@ -107,20 +133,35 @@ void videoEndFrame(void)
|
||||
|
||||
gfx_end_frame();
|
||||
|
||||
endTime = wmAPI->get_time();
|
||||
|
||||
++frames;
|
||||
++framesPerSec;
|
||||
++fpsNumFrames;
|
||||
|
||||
const f64 flipTime = wmAPI->get_time();
|
||||
accumDelta += flipTime - endTime;
|
||||
endTime = flipTime;
|
||||
vidLastRenderTime = endTime - startTime;
|
||||
|
||||
if (endTime >= fpsTime) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames);
|
||||
vidAvgFPS = fpsNumFrames ? ((f64)fpsNumFrames / accumDelta) : 0.f;
|
||||
fpsNumFrames = 0;
|
||||
accumDelta = 0.0;
|
||||
snprintf(tmp, sizeof(tmp), "fps %4.1f frt %lf frm %u", vidAvgFPS, vidLastRenderTime, frames);
|
||||
wmAPI->set_window_title(tmp);
|
||||
framesPerSec = 0;
|
||||
fpsTime = endTime + 1.0;
|
||||
fpsTime = endTime + vidDisplayFPSInterval;
|
||||
}
|
||||
}
|
||||
|
||||
f64 videoGetLastRenderTime(void)
|
||||
{
|
||||
return vidLastRenderTime;
|
||||
}
|
||||
|
||||
f32 videoGetAverageFPS(void)
|
||||
{
|
||||
return vidAvgFPS;
|
||||
}
|
||||
|
||||
void videoClearScreen(void)
|
||||
{
|
||||
videoStartFrame();
|
||||
@@ -165,19 +206,159 @@ s32 videoGetHeight(void)
|
||||
|
||||
s32 videoGetFullscreen(void)
|
||||
{
|
||||
vidFullscreen = wmAPI->get_fullscreen_state();
|
||||
return vidFullscreen;
|
||||
}
|
||||
|
||||
s32 videoGetFullscreenMode(void)
|
||||
{
|
||||
vidFullscreenExclusive = wmAPI->get_fullscreen_flag_mode();
|
||||
return vidFullscreenExclusive;
|
||||
}
|
||||
|
||||
s32 videoGetMaximizeWindow(void)
|
||||
{
|
||||
vidMaximize = wmAPI->get_maximized_state();
|
||||
return vidMaximize;
|
||||
}
|
||||
|
||||
s32 videoGetCenterWindow(void)
|
||||
{
|
||||
return vidCenter;
|
||||
}
|
||||
|
||||
f32 videoGetAspect(void)
|
||||
{
|
||||
return gfx_current_dimensions.aspect_ratio;
|
||||
}
|
||||
|
||||
s32 videoGetDisplayModeIndex(void)
|
||||
{
|
||||
for (s32 i = 1; i < vidNumModes; ++i) {
|
||||
if (vidModes[i].width == gfx_current_dimensions.width &&
|
||||
vidModes[i].height == gfx_current_dimensions.height) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Current dimensions don't match any known mode, so return index 0, "Custom".
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 videoGetMSAA(void)
|
||||
{
|
||||
vidMSAA = (s32)gfx_msaa_level;
|
||||
return vidMSAA;
|
||||
}
|
||||
|
||||
s32 videoGetVsync(void)
|
||||
{
|
||||
vidVsync = wmAPI->get_swap_interval();
|
||||
return vidVsync;
|
||||
}
|
||||
|
||||
s32 videoGetFramerateLimit(void)
|
||||
{
|
||||
vidFramerateLimit = wmAPI->get_target_fps();
|
||||
return vidFramerateLimit;
|
||||
}
|
||||
|
||||
s32 videoGetDisplayFPS(void)
|
||||
{
|
||||
return vidDisplayFPS;
|
||||
}
|
||||
|
||||
static s32 videoInitDisplayModes(void)
|
||||
{
|
||||
if (!wmAPI->get_current_display_mode(&vidModeDefault.width, &vidModeDefault.height)) {
|
||||
vidModeDefault.width = 640;
|
||||
vidModeDefault.height = 480;
|
||||
return false;
|
||||
}
|
||||
|
||||
const s32 numBaseModes = wmAPI->get_num_display_modes();
|
||||
if (!numBaseModes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const s32 numCustomModes = 1;
|
||||
displaymode *modeList = sysMemZeroAlloc((numBaseModes + numCustomModes) * sizeof(displaymode));
|
||||
if (!modeList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
modeList[0].width = 0;
|
||||
modeList[0].height = 0;
|
||||
|
||||
s32 numModes = 1;
|
||||
s32 w = -1, h = w, neww = w, newh = w;
|
||||
|
||||
// SDL modes are guaranteed to be sorted high to low
|
||||
for (s32 i = 0; i < numBaseModes; ++i) {
|
||||
wmAPI->get_display_mode(i, &neww, &newh);
|
||||
|
||||
if (neww != w || newh != h) {
|
||||
w = neww;
|
||||
h = newh;
|
||||
modeList[numModes].width = w;
|
||||
modeList[numModes].height = h;
|
||||
++numModes;
|
||||
}
|
||||
}
|
||||
|
||||
modeList = sysMemRealloc(modeList, numModes * sizeof(displaymode));
|
||||
if (!modeList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vidModes = modeList;
|
||||
vidNumModes = numModes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 videoGetDisplayMode(displaymode *out, const s32 index)
|
||||
{
|
||||
if (index >= 0 && index < vidNumModes) {
|
||||
*out = vidModes[index];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 videoGetNumDisplayModes(void)
|
||||
{
|
||||
return vidNumModes;
|
||||
}
|
||||
|
||||
void videoSetDisplayMode(const s32 index)
|
||||
{
|
||||
const displaymode dm = vidModes[index];
|
||||
|
||||
if (index == 0) {
|
||||
// "Custom" video mode.
|
||||
return;
|
||||
}
|
||||
|
||||
vidWidth = dm.width;
|
||||
vidHeight = dm.height;
|
||||
|
||||
s32 posX = 100;
|
||||
s32 posY = 100;
|
||||
if (vidCenter) {
|
||||
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
|
||||
}
|
||||
|
||||
if (vidFullscreen) {
|
||||
wmAPI->set_closest_resolution(vidWidth, vidHeight, vidCenter);
|
||||
} else {
|
||||
if (vidMaximize) {
|
||||
videoSetMaximizeWindow(false);
|
||||
} else {
|
||||
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 videoGetTextureFilter2D(void)
|
||||
{
|
||||
return texFilter2D;
|
||||
@@ -203,7 +384,22 @@ void videoSetFullscreen(s32 fs)
|
||||
{
|
||||
if (fs != vidFullscreen) {
|
||||
vidFullscreen = !!fs;
|
||||
wmAPI->set_closest_resolution(vidWidth, vidHeight, vidCenter);
|
||||
wmAPI->set_fullscreen(vidFullscreen);
|
||||
if (!vidFullscreen && vidMaximize) {
|
||||
wmAPI->set_maximize(false);
|
||||
wmAPI->set_maximize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetFullscreenMode(s32 mode)
|
||||
{
|
||||
vidFullscreenExclusive = mode;
|
||||
wmAPI->set_fullscreen_flag(mode);
|
||||
if (vidFullscreen) {
|
||||
wmAPI->set_fullscreen(false);
|
||||
wmAPI->set_fullscreen(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,14 +408,32 @@ void videoSetMaximizeWindow(s32 fs)
|
||||
if (fs != vidMaximize) {
|
||||
vidMaximize = !!fs;
|
||||
wmAPI->set_maximize(vidMaximize);
|
||||
if (vidCenter && !vidMaximize) {
|
||||
s32 posX = 0;
|
||||
s32 posY = 0;
|
||||
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
|
||||
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetCenterWindow(s32 center)
|
||||
{
|
||||
vidCenter = center;
|
||||
if (vidCenter && !vidMaximize) {
|
||||
s32 posX = 0;
|
||||
s32 posY = 0;
|
||||
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
|
||||
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetTextureFilter(u32 filter)
|
||||
{
|
||||
if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT;
|
||||
if (texFilter == filter) return;
|
||||
texFilter = filter;
|
||||
renderingAPI->set_texture_filter((enum FilteringMode)filter);
|
||||
gfx_set_texture_filter((enum FilteringMode)filter);
|
||||
}
|
||||
|
||||
void videoSetTextureFilter2D(s32 filter)
|
||||
@@ -238,6 +452,33 @@ s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
|
||||
return gfx_create_framebuffer(w, h, upscale, autoresize);
|
||||
}
|
||||
|
||||
void videoSetMSAA(const s32 msaa)
|
||||
{
|
||||
vidMSAA = msaa;
|
||||
gfx_msaa_level = (u32)vidMSAA;
|
||||
}
|
||||
|
||||
void videoSetVsync(const s32 vsync)
|
||||
{
|
||||
vidVsync = wmAPI->set_swap_interval(vsync) ? vsync : 0;
|
||||
|
||||
if (vidVsync == 0 && vidFramerateLimit == 0) {
|
||||
// cap FPS if there's no vsync to prevent the game from exploding
|
||||
videoSetFramerateLimit(VIDEO_MAX_FPS);
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetFramerateLimit(const s32 limit)
|
||||
{
|
||||
vidFramerateLimit = (vidVsync == 0 && limit == 0) ? VIDEO_MAX_FPS : limit;
|
||||
wmAPI->set_target_fps(vidFramerateLimit);
|
||||
}
|
||||
|
||||
void videoSetDisplayFPS(const s32 displayfps)
|
||||
{
|
||||
vidDisplayFPS = displayfps;
|
||||
}
|
||||
|
||||
void videoSetFramebuffer(s32 target)
|
||||
{
|
||||
return gfx_set_framebuffer(target, 1.f);
|
||||
@@ -274,6 +515,11 @@ void videoFreeCachedTexture(const void *texptr)
|
||||
gfx_texture_cache_delete(texptr);
|
||||
}
|
||||
|
||||
void videoShutdown(void)
|
||||
{
|
||||
free(vidModes);
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1);
|
||||
@@ -281,10 +527,13 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
|
||||
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
|
||||
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
|
||||
configRegisterInt("Video.CenterWindow", &vidCenter, 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.DisplayFPS", &vidDisplayFPS, 0, 1);
|
||||
configRegisterFloat("Video.DisplayFPSInterval", &vidDisplayFPSInterval, 0.01f, 32.f);
|
||||
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
|
||||
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
|
||||
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
|
||||
|
||||
@@ -177,7 +177,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
gdl = text0f153628(gdl);
|
||||
gdl = textRenderProjected(gdl, &x, &y, g_MpAllChrConfigPtrs[chrindex]->name, g_CharsHandelGothicSm, g_FontHandelGothicSm, colour, viGetWidth(), viGetHeight(), 0, 0);
|
||||
gdl = text0f153780(gdl);
|
||||
return (s32)gdl;
|
||||
return (uintptr_t)gdl;
|
||||
}
|
||||
case MENUOP_GETOPTIONHEIGHT:
|
||||
data->list.value = LINEHEIGHT;
|
||||
|
||||
+22
-15
@@ -47,6 +47,7 @@
|
||||
#include "preprocess.h"
|
||||
#include "system.h"
|
||||
#include "video.h"
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
#define BGCMD_END 0x00
|
||||
@@ -97,7 +98,7 @@ u16 g_BgUnloadDelay240;
|
||||
u16 g_BgUnloadDelay240_2;
|
||||
u32 var800a4bf4;
|
||||
RoomNum g_GlareRooms[100];
|
||||
u32 *g_BgPrimaryData2;
|
||||
uintptr_t *g_BgPrimaryData2;
|
||||
struct bgroom *g_BgRooms;
|
||||
struct bgportal *g_BgPortals;
|
||||
struct portalmetric *g_PortalMetrics;
|
||||
@@ -113,7 +114,7 @@ struct portalcamcacheitem *g_PortalCameraCache;
|
||||
struct bgsnake g_BgSnake;
|
||||
|
||||
s32 g_StageIndex = 1;
|
||||
u32 var8007fc04 = 0;
|
||||
uintptr_t var8007fc04 = 0;
|
||||
u8 *var8007fc08 = NULL;
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
@@ -763,7 +764,7 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
|
||||
gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]);
|
||||
}
|
||||
|
||||
readgdl += 8;
|
||||
readgdl += sizeof(Gfx);
|
||||
}
|
||||
|
||||
gdl = bgRenderXrayData(gdl, &xraydata);
|
||||
@@ -1468,7 +1469,7 @@ void bgReset(s32 stagenum)
|
||||
u32 section2compsize;
|
||||
u32 section2start;
|
||||
u32 section1compsize;
|
||||
u32 scratch;
|
||||
uintptr_t scratch;
|
||||
|
||||
var8007fc0c = 8;
|
||||
|
||||
@@ -1509,6 +1510,11 @@ void bgReset(s32 stagenum)
|
||||
primcompsize = *(u32 *)&header[8];
|
||||
var8007fc54 = inflatedsize - primcompsize;
|
||||
var8007fc54 -= 0xc;
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
inflatedsize = romdataFileGetEstimatedSize(inflatedsize, LOADTYPE_BG);
|
||||
#endif
|
||||
|
||||
inflatedsize = ALIGN16(inflatedsize);
|
||||
|
||||
// Allocate space for the primary bg data
|
||||
@@ -1529,7 +1535,7 @@ void bgReset(s32 stagenum)
|
||||
bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgSection1(g_BgPrimaryData, 0x0f000000);
|
||||
preprocessBgSection1(g_BgPrimaryData, inflatedsize, 0x0f000000);
|
||||
#endif
|
||||
|
||||
// Shrink the allocation (ie. free the scratch space)
|
||||
@@ -1598,7 +1604,7 @@ void bgReset(s32 stagenum)
|
||||
// Copy 0x40 bytes from a random location in ROM to a random
|
||||
// location in RAM. The write address can be anywhere in the
|
||||
// boot segment or in the lib segment up to modelRenderNodeDl.
|
||||
dmaExec((void *)(PHYS_TO_K0(0x1000) + (random() & 0x1fff8)), random() & 0x1fffe, 0x40);
|
||||
dmaExec((void *)(PHYS_TO_K0(0x1000) + (rngRandom() & 0x1fff8)), rngRandom() & 0x1fffe, 0x40);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1606,7 +1612,7 @@ void bgReset(s32 stagenum)
|
||||
var800a4920 = *(u32 *)g_BgPrimaryData;
|
||||
|
||||
if (var800a4920 == 0) {
|
||||
g_BgPrimaryData2 = (u32 *)g_BgPrimaryData;
|
||||
g_BgPrimaryData2 = (uintptr_t*)g_BgPrimaryData;
|
||||
g_BgRooms = (struct bgroom *)(g_BgPrimaryData2[1] + g_BgPrimaryData - 0x0f000000);
|
||||
goto foo; foo:;
|
||||
g_Vars.roomcount = 0;
|
||||
@@ -1998,10 +2004,6 @@ void bgBuildTables(s32 stagenum)
|
||||
numlightsptr++;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
preprocessBgLights(g_BgLightsFileData, 0);
|
||||
#endif
|
||||
|
||||
// Free the section 3 allocation
|
||||
mempRealloc(section3, 0, MEMPOOL_STAGE);
|
||||
|
||||
@@ -2820,6 +2822,11 @@ void bgLoadRoom(s32 roomnum)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
alloclen = alloclen * 4; // just to be safe for now, adjust properly later #TODO
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
bgGarbageCollectRooms(alloclen, false);
|
||||
|
||||
@@ -2856,7 +2863,7 @@ 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);
|
||||
inflatedlen = preprocessBgRoom(allocation, inflatedlen, g_BgRooms[roomnum].unk00);
|
||||
#endif
|
||||
|
||||
g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation;
|
||||
@@ -2937,7 +2944,7 @@ void bgLoadRoom(s32 roomnum)
|
||||
|
||||
// Copy gdls to the right-side of the allocation
|
||||
// and build a pointer array to them
|
||||
texCopyGdls((void *) gfxblocks[0], (void *) (allocation + alloclen - (gfxblocks[numgdls] - gfxblocks[0])), (u32) (gfxblocks[numgdls] - gfxblocks[0]));
|
||||
texCopyGdls((void *) gfxblocks[0], (void *) (allocation + alloclen - (gfxblocks[numgdls] - gfxblocks[0])), (uintptr_t) (gfxblocks[numgdls] - gfxblocks[0]));
|
||||
|
||||
for (i = 0; i < numgdls + 1; i++) {
|
||||
gdlpointers[i] = gfxblocks[i] + (allocation + alloclen - gfxblocks[numgdls]);
|
||||
@@ -3640,7 +3647,7 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
|
||||
Gfx *imggdl = NULL;
|
||||
s32 texturenum;
|
||||
f32 lowestsqdist = MAXFLOAT;
|
||||
s32 offset;
|
||||
uintptr_t offset;
|
||||
s32 numvertices;
|
||||
Gfx *tri4gdl;
|
||||
s32 count;
|
||||
@@ -4243,7 +4250,7 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
|
||||
|
||||
vtx = bgFindVerticesForGdl(roomnum, gdl);
|
||||
iter = &gdl[batch->gbicmdindex];
|
||||
vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (s32)vtx);
|
||||
vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (uintptr_t)vtx);
|
||||
numvertices = (((u32) iter->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
|
||||
ptr = var800a6470;
|
||||
|
||||
|
||||
+7
-7
@@ -299,7 +299,7 @@ struct model *bodyAllocateModel(s32 bodynum, s32 headnum, u32 spawnflags)
|
||||
if (spawnflags & SPAWNFLAG_FORCESUNGLASSES) {
|
||||
sunglasses = true;
|
||||
} else if (spawnflags & SPAWNFLAG_MAYBESUNGLASSES) {
|
||||
sunglasses = random() % 2 == 0;
|
||||
sunglasses = rngRandom() % 2 == 0;
|
||||
}
|
||||
|
||||
if (spawnflags & SPAWNFLAG_FIXEDHEIGHT) {
|
||||
@@ -325,7 +325,7 @@ s32 bodyChooseHead(s32 bodynum)
|
||||
g_ActiveMaleHeadsIndex = 0;
|
||||
}
|
||||
} else if (bodynum == BODY_FEM_GUARD) {
|
||||
head = g_FemGuardHeads[random() % 3];
|
||||
head = g_FemGuardHeads[rngRandom() % 3];
|
||||
} else {
|
||||
head = g_ActiveFemaleHeads[g_ActiveFemaleHeadsIndex++];
|
||||
|
||||
@@ -493,10 +493,10 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
|
||||
if (packed->tude != 4) {
|
||||
chr->tude = packed->tude;
|
||||
} else {
|
||||
chr->tude = random() % 4;
|
||||
chr->tude = rngRandom() % 4;
|
||||
}
|
||||
|
||||
chr->voicebox = random() % 3;
|
||||
chr->voicebox = rngRandom() % 3;
|
||||
|
||||
if (!g_HeadsAndBodies[chr->bodynum].ismale) {
|
||||
chr->voicebox = VOICEBOX_FEMALE;
|
||||
@@ -519,7 +519,7 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
|
||||
chr->flags |= CHRFLAG0_AIVSAI;
|
||||
}
|
||||
|
||||
if (random() % 5 == 0) {
|
||||
if (rngRandom() % 5 == 0) {
|
||||
// Make chr punch slower
|
||||
chr->flags2 |= CHRFLAG1_ADJUSTPUNCHSPEED;
|
||||
}
|
||||
@@ -596,8 +596,8 @@ struct prop *bodyAllocateEyespy(struct pad *pad, RoomNum room)
|
||||
chr->team = 0;
|
||||
chr->squadron = 0;
|
||||
chr->maxdamage = 2;
|
||||
chr->tude = random() & 3;
|
||||
chr->voicebox = random() % 3;
|
||||
chr->tude = rngRandom() & 3;
|
||||
chr->voicebox = rngRandom() % 3;
|
||||
chr->naturalanim = 0;
|
||||
chr->myspecial = 0;
|
||||
chr->yvisang = 0;
|
||||
|
||||
@@ -26,7 +26,7 @@ void bodiesReset(s32 stagenum)
|
||||
g_HeadsAndBodies[i].modeldef = NULL;
|
||||
}
|
||||
|
||||
var80062c80 = random() % g_NumBondBodies;
|
||||
var80062c80 = rngRandom() % g_NumBondBodies;
|
||||
var80062b14 = 0;
|
||||
var80062b18 = 0;
|
||||
|
||||
@@ -67,7 +67,7 @@ void bodiesReset(s32 stagenum)
|
||||
for (i = 0; i < g_NumActiveHeadsPerGender; i++) {
|
||||
do {
|
||||
done = true;
|
||||
g_ActiveMaleHeads[i] = headsavailablelist[random() % headsavailablelen];
|
||||
g_ActiveMaleHeads[i] = headsavailablelist[rngRandom() % headsavailablelen];
|
||||
|
||||
if (headsavailablelen > g_NumActiveHeadsPerGender) {
|
||||
for (j = 0; j < i; j++) {
|
||||
@@ -97,7 +97,7 @@ void bodiesReset(s32 stagenum)
|
||||
for (i = 0; i < g_NumActiveHeadsPerGender; i++) {
|
||||
do {
|
||||
done = true;
|
||||
g_ActiveFemaleHeads[i] = headsavailablelist[random() % headsavailablelen];
|
||||
g_ActiveFemaleHeads[i] = headsavailablelist[rngRandom() % headsavailablelen];
|
||||
|
||||
if (headsavailablelen > g_NumActiveHeadsPerGender) {
|
||||
for (j = 0; j < i; j++) {
|
||||
|
||||
+66
-68
@@ -56,6 +56,7 @@
|
||||
#ifndef PLATFORM_N64
|
||||
#include "game/stagetable.h"
|
||||
#include "video.h"
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
#define GUNLOADSTATE_FLUX 0
|
||||
@@ -165,8 +166,13 @@ u32 fill2[1];
|
||||
|
||||
Lights1 var80070090 = gdSPDefLights1(0x96, 0x96, 0x96, 0xff, 0xff, 0xff, 0xb2, 0x4d, 0x2e);
|
||||
|
||||
#ifdef PLATFORM_64BIT
|
||||
u32 g_BgunGunMemBaseSizeDefault = 150 * 1024 * 2; // #TODO adjust these values properly
|
||||
u32 g_BgunGunMemBaseSize4Mb2P = 120 * 1024 * 2;
|
||||
#else
|
||||
u32 g_BgunGunMemBaseSizeDefault = 150 * 1024;
|
||||
u32 g_BgunGunMemBaseSize4Mb2P = 120 * 1024;
|
||||
#endif
|
||||
|
||||
u16 g_CartFileNums[] = {
|
||||
FILE_GCARTRIDGE,
|
||||
@@ -890,7 +896,7 @@ void bgunStartAnimation(struct guncmd *cmd, s32 handnum, struct hand *hand)
|
||||
if (cmd->type != GUNCMD_PLAYANIMATION) {
|
||||
struct guncmd *loopcmd = cmd;
|
||||
s32 done = false;
|
||||
u32 rand = random() % 100;
|
||||
u32 rand = rngRandom() % 100;
|
||||
|
||||
while (loopcmd->type != GUNCMD_END) {
|
||||
if (bgun0f098884(loopcmd, &hand->gset) && !done) {
|
||||
@@ -3794,17 +3800,17 @@ void bgunTickGunLoad(void)
|
||||
{
|
||||
s32 i;
|
||||
s32 numthistick;
|
||||
u32 remaining;
|
||||
u64 remaining;
|
||||
s32 padding;
|
||||
u32 allocsize;
|
||||
u32 loadsize;
|
||||
u32 ptr;
|
||||
u64 allocsize;
|
||||
u64 loadsize;
|
||||
uintptr_t ptr;
|
||||
struct player *player = g_Vars.currentplayer;
|
||||
struct modeldef *modeldef;
|
||||
struct fileinfo *fileinfo;
|
||||
struct fileinfo *gunfileinfo;
|
||||
s32 newvalue;
|
||||
u32 end;
|
||||
uintptr_t newvalue;
|
||||
uintptr_t end;
|
||||
u32 stack;
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
u32 stack2;
|
||||
@@ -3826,7 +3832,7 @@ void bgunTickGunLoad(void)
|
||||
*player->gunctrl.loadmemptr = ptr;
|
||||
*player->gunctrl.loadmemremaining = remaining;
|
||||
|
||||
loadsize = ALIGN64(fileGetInflatedSize(player->gunctrl.loadfilenum)) + 0x8000;
|
||||
loadsize = ALIGN64(fileGetInflatedSize(player->gunctrl.loadfilenum, LOADTYPE_MODEL)) + 0x8000;
|
||||
|
||||
osSyncPrintf("BriGun: Loading - %s, pMem 0x%08x Size %d\n");
|
||||
|
||||
@@ -3844,6 +3850,9 @@ void bgunTickGunLoad(void)
|
||||
|
||||
// Reserve some space for textures
|
||||
allocsize = fileGetLoadedSize(player->gunctrl.loadfilenum) + 0xe00;
|
||||
#ifdef PLATFORM_64BIT
|
||||
allocsize += 0xe00;
|
||||
#endif
|
||||
|
||||
osSyncPrintf("BriGun: Used size %d (Ob Size %d)\n");
|
||||
osSyncPrintf("BriGun: block len %d usedsize %d\n");
|
||||
@@ -3854,7 +3863,7 @@ void bgunTickGunLoad(void)
|
||||
|
||||
fileinfo = &g_FileInfo[player->gunctrl.loadfilenum];
|
||||
fileinfo->allocsize = allocsize;
|
||||
end = ALIGN16((s32)ptr + allocsize);
|
||||
end = ALIGN16((uintptr_t)ptr + allocsize);
|
||||
allocsize = end - ptr;
|
||||
if (1);
|
||||
remaining -= allocsize;
|
||||
@@ -3925,7 +3934,7 @@ void bgunTickGunLoad(void)
|
||||
|
||||
modeldef0f1a7560(modeldef, player->gunctrl.loadfilenum, 0x05000000, modeldef, &player->gunctrl.texpool, false);
|
||||
|
||||
fileGetInflatedSize(player->gunctrl.loadfilenum);
|
||||
fileGetInflatedSize(player->gunctrl.loadfilenum, LOADTYPE_MODEL);
|
||||
fileGetLoadedSize(player->gunctrl.loadfilenum);
|
||||
fileGetLoadedSize(player->gunctrl.loadfilenum);
|
||||
fileGetLoadedSize(player->gunctrl.loadfilenum);
|
||||
@@ -3938,7 +3947,7 @@ void bgunTickGunLoad(void)
|
||||
|
||||
newvalue = ALIGN64(texGetPoolLeftPos(&player->gunctrl.texpool));
|
||||
remaining = *player->gunctrl.loadmemremaining;
|
||||
remaining -= (s32)(newvalue - *player->gunctrl.loadmemptr);
|
||||
remaining -= (intptr_t)(newvalue - *player->gunctrl.loadmemptr);
|
||||
|
||||
*player->gunctrl.loadmemptr = newvalue;
|
||||
*player->gunctrl.loadmemremaining = remaining;
|
||||
@@ -4087,8 +4096,8 @@ void bgunTickMasterLoad(void)
|
||||
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
|
||||
player->gunctrl.loadfilenum = handfilenum;
|
||||
player->gunctrl.loadtomodeldef = &player->gunctrl.handmodeldef;
|
||||
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.handmemloadptr;
|
||||
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.handmemloadremaining;
|
||||
player->gunctrl.loadmemptr = (uintptr_t *) &player->gunctrl.handmemloadptr;
|
||||
player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.handmemloadremaining;
|
||||
}
|
||||
|
||||
bgunTickGunLoad();
|
||||
@@ -4115,8 +4124,8 @@ void bgunTickMasterLoad(void)
|
||||
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
|
||||
player->gunctrl.loadfilenum = filenum;
|
||||
player->gunctrl.loadtomodeldef = &player->gunctrl.gunmodeldef;
|
||||
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.memloadptr;
|
||||
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.memloadremaining;
|
||||
player->gunctrl.loadmemptr = (uintptr_t*) &player->gunctrl.memloadptr;
|
||||
player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.memloadremaining;
|
||||
}
|
||||
|
||||
bgunTickGunLoad();
|
||||
@@ -4157,8 +4166,8 @@ void bgunTickMasterLoad(void)
|
||||
player->gunctrl.loadfilenum = filenum;
|
||||
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
|
||||
player->gunctrl.loadtomodeldef = &player->gunctrl.cartmodeldef;
|
||||
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.memloadptr;
|
||||
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.memloadremaining;
|
||||
player->gunctrl.loadmemptr = (uintptr_t *) &player->gunctrl.memloadptr;
|
||||
player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.memloadremaining;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4184,18 +4193,18 @@ void bgunTickMasterLoad(void)
|
||||
modelInit(&hand->handmodel, player->gunctrl.handmodeldef, hand->handsavedata, false);
|
||||
}
|
||||
|
||||
hand->unk0dcc = (s32 *) player->gunctrl.memloadptr;
|
||||
hand->unk0dcc = (uintptr_t *) player->gunctrl.memloadptr;
|
||||
|
||||
value = bgunCreateModelCmdList(&hand->gunmodel, player->gunctrl.gunmodeldef->rootnode, (s32 *) player->gunctrl.memloadptr);
|
||||
value = bgunCreateModelCmdList(&hand->gunmodel, player->gunctrl.gunmodeldef->rootnode, (uintptr_t *) player->gunctrl.memloadptr);
|
||||
|
||||
sum += value;
|
||||
player->gunctrl.memloadptr += value;
|
||||
player->gunctrl.memloadremaining -= value;
|
||||
|
||||
if (player->gunctrl.handmodeldef != 0) {
|
||||
hand->unk0dd0 = (s32 *) player->gunctrl.memloadptr;
|
||||
hand->unk0dd0 = (uintptr_t*) player->gunctrl.memloadptr;
|
||||
|
||||
value = bgunCreateModelCmdList(&hand->handmodel, player->gunctrl.handmodeldef->rootnode, (s32 *) player->gunctrl.memloadptr);
|
||||
value = bgunCreateModelCmdList(&hand->handmodel, player->gunctrl.handmodeldef->rootnode, (uintptr_t*) player->gunctrl.memloadptr);
|
||||
|
||||
sum += value;
|
||||
player->gunctrl.memloadptr += value;
|
||||
@@ -6415,7 +6424,7 @@ void bgunDisarm(struct prop *attackerprop)
|
||||
*
|
||||
* With this function stubbed, part of the CMP150 model does not render.
|
||||
*/
|
||||
void bgunExecuteModelCmdList(s32 *ptr)
|
||||
void bgunExecuteModelCmdList(uintptr_t *ptr)
|
||||
{
|
||||
union modelrwdata *rwdata;
|
||||
struct modelnode *node;
|
||||
@@ -6472,7 +6481,7 @@ void bgunExecuteModelCmdList(s32 *ptr)
|
||||
* iterate the command list to update part visibility rather than iterate the
|
||||
* full model tree.
|
||||
*/
|
||||
s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *ptr)
|
||||
s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, uintptr_t *ptr)
|
||||
{
|
||||
s32 len = 0;
|
||||
struct modelnode *node = nodearg;
|
||||
@@ -6489,11 +6498,11 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
|
||||
rwdata->distance.visible = false;
|
||||
node->child = rodata->distance.target;
|
||||
ptr[0] = 0;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[2] = (s32)node;
|
||||
ptr[3] = (s32)rodata->distance.target;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr[2] = (uintptr_t)node;
|
||||
ptr[3] = (uintptr_t)rodata->distance.target;
|
||||
ptr += 4;
|
||||
len += 16;
|
||||
len += 4 * sizeof(uintptr_t);
|
||||
break;
|
||||
case MODELNODETYPE_TOGGLE:
|
||||
rodata = node->rodata;
|
||||
@@ -6501,36 +6510,36 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
|
||||
rwdata->toggle.visible = true;
|
||||
node->child = rodata->toggle.target;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[2] = (s32)node;
|
||||
ptr[3] = (s32)rodata->toggle.target;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr[2] = (uintptr_t)node;
|
||||
ptr[3] = (uintptr_t)rodata->toggle.target;
|
||||
ptr += 4;
|
||||
len += 16;
|
||||
len += 4 * sizeof(uintptr_t);
|
||||
break;
|
||||
case MODELNODETYPE_HEADSPOT:
|
||||
rwdata = modelGetNodeRwData(model, node);
|
||||
rwdata->headspot.headmodeldef = NULL;
|
||||
rwdata->headspot.rwdatas = NULL;
|
||||
ptr[0] = 2;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr += 2;
|
||||
len += 8;
|
||||
len += 2 * sizeof(uintptr_t);
|
||||
break;
|
||||
case MODELNODETYPE_0B:
|
||||
rwdata = modelGetNodeRwData(model, node);
|
||||
rwdata->type0b.unk00 = 0;
|
||||
ptr[0] = 3;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr += 2;
|
||||
len += 8;
|
||||
len += 2 * sizeof(uintptr_t);
|
||||
break;
|
||||
case MODELNODETYPE_CHRGUNFIRE:
|
||||
rwdata = modelGetNodeRwData(model, node);
|
||||
rwdata->chrgunfire.visible = false;
|
||||
ptr[0] = 4;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr += 2;
|
||||
len += 8;
|
||||
len += 2 * sizeof(uintptr_t);
|
||||
break;
|
||||
case MODELNODETYPE_DL:
|
||||
rodata = node->rodata;
|
||||
@@ -6539,12 +6548,12 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
|
||||
rwdata->dl.gdl = rodata->dl.opagdl;
|
||||
rwdata->dl.colours = (void *)ALIGN8((uintptr_t)&rodata->dl.vertices[rodata->dl.numvertices]);
|
||||
ptr[0] = 5;
|
||||
ptr[1] = (s32)rwdata;
|
||||
ptr[2] = (s32)rwdata->dl.vertices;
|
||||
ptr[3] = (s32)rwdata->dl.gdl;
|
||||
ptr[4] = (s32)rwdata->dl.colours;
|
||||
ptr[1] = (uintptr_t)rwdata;
|
||||
ptr[2] = (uintptr_t)rwdata->dl.vertices;
|
||||
ptr[3] = (uintptr_t)rwdata->dl.gdl;
|
||||
ptr[4] = (uintptr_t)rwdata->dl.colours;
|
||||
ptr += 5;
|
||||
len += 20;
|
||||
len += 5 * sizeof(uintptr_t);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6568,7 +6577,7 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
|
||||
}
|
||||
|
||||
*ptr = 6;
|
||||
len += 4;
|
||||
len += sizeof(uintptr_t);
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -7161,7 +7170,7 @@ void bgunUpdateMagnum(struct hand *hand, s32 handnum, struct modeldef *modeldef,
|
||||
|
||||
if (modeldef != NULL) {
|
||||
for (i = 0; i < hand->unk0cc8_04; i++) {
|
||||
struct modelnode *node = modelGetPart(modeldef, 0x0a + random() % 6);
|
||||
struct modelnode *node = modelGetPart(modeldef, 0x0a + rngRandom() % 6);
|
||||
|
||||
if (node) {
|
||||
s32 index = modelFindNodeMtxIndex(node, 0);
|
||||
@@ -10933,7 +10942,6 @@ 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
|
||||
|
||||
@@ -10999,7 +11007,7 @@ void bgunRender(Gfx **gdlptr)
|
||||
gSPLookAt(gdl++, camGetLookAt());
|
||||
}
|
||||
|
||||
gSPPerspNormalize(gdl++, wnorm);
|
||||
gSPPerspNormalize(gdl++, mtx00016dcc(0, 300));
|
||||
|
||||
// There is support for guns having a TV screen on them
|
||||
// but no guns have this model part so it's not used.
|
||||
@@ -11174,17 +11182,7 @@ 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);
|
||||
@@ -11216,8 +11214,8 @@ struct sndstate **bgunAllocateAudioHandle(void)
|
||||
void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
|
||||
{
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
u32 rand1 = random();
|
||||
u32 rand2 = random();
|
||||
u32 rand1 = rngRandom();
|
||||
u32 rand2 = rngRandom();
|
||||
struct sndstate **handle;
|
||||
|
||||
if (g_Vars.lvupdate240 <= 0) {
|
||||
@@ -11296,8 +11294,8 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
|
||||
if (texturenum == 10000) {
|
||||
soundnum = SFX_SHIELD_DAMAGE;
|
||||
} else if (gset->weaponnum == WEAPON_LASER) {
|
||||
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (random() % 2))) {
|
||||
if ((random() % 2) == 0) {
|
||||
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (rngRandom() % 2))) {
|
||||
if ((rngRandom() % 2) == 0) {
|
||||
soundnum = SFX_CLOAK_ON;
|
||||
} else {
|
||||
soundnum = SFX_CLOAK_OFF;
|
||||
@@ -11361,8 +11359,8 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
|
||||
}
|
||||
}
|
||||
#else
|
||||
u32 rand1 = random();
|
||||
u32 rand2 = random();
|
||||
u32 rand1 = rngRandom();
|
||||
u32 rand2 = rngRandom();
|
||||
struct sndstate **handle;
|
||||
|
||||
if (g_Vars.lvupdate240 <= 0) {
|
||||
@@ -11435,7 +11433,7 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
|
||||
soundnum = SFX_SHIELD_DAMAGE;
|
||||
} else if (gset->weaponnum == WEAPON_LASER) {
|
||||
if (gset->weaponfunc == FUNC_PRIMARY || (gset->unk063a % 8) == 0) {
|
||||
if ((random() % 2) == 0) {
|
||||
if ((rngRandom() % 2) == 0) {
|
||||
soundnum = SFX_CLOAK_ON;
|
||||
} else {
|
||||
soundnum = SFX_CLOAK_OFF;
|
||||
@@ -11513,8 +11511,8 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
|
||||
{
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
struct sndstate **handle;
|
||||
u32 rand1 = random();
|
||||
u32 rand2 = random();
|
||||
u32 rand1 = rngRandom();
|
||||
u32 rand2 = rngRandom();
|
||||
bool playdefault;
|
||||
s16 soundnum;
|
||||
bool overridden;
|
||||
@@ -11537,7 +11535,7 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
|
||||
if (gset->weaponnum == WEAPON_LASER) {
|
||||
playdefault = false;
|
||||
|
||||
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (random() % 2))) {
|
||||
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (rngRandom() % 2))) {
|
||||
// Laser sounds
|
||||
s16 sounds[] = {SFX_CLOAK_ON, SFX_CLOAK_OFF};
|
||||
soundnum = sounds[rand1 % ARRAYCOUNT(sounds)];
|
||||
@@ -11612,8 +11610,8 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
|
||||
}
|
||||
#else
|
||||
struct sndstate **handle;
|
||||
u32 rand1 = random();
|
||||
u32 rand2 = random();
|
||||
u32 rand1 = rngRandom();
|
||||
u32 rand2 = rngRandom();
|
||||
s16 soundnum;
|
||||
bool overridden;
|
||||
|
||||
|
||||
+25
-6
@@ -780,6 +780,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
movedata.freelookdy = -movedata.freelookdy;
|
||||
}
|
||||
}
|
||||
// always pause with ESC
|
||||
if (allowc1buttons && g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED) {
|
||||
if (inputKeyJustPressed(VK_ESCAPE)) {
|
||||
c1buttonsthisframe |= START_BUTTON;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Pausing
|
||||
@@ -901,7 +907,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
aimoffhist[i] = !aimonhist[i];
|
||||
}
|
||||
|
||||
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
|
||||
if (numsamples > 0) {
|
||||
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!lvIsPaused()) {
|
||||
@@ -1232,7 +1240,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
aimoffhist[i] = !aimonhist[i];
|
||||
}
|
||||
|
||||
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
|
||||
if (numsamples > 0) {
|
||||
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!lvIsPaused()) {
|
||||
@@ -1573,6 +1583,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
}
|
||||
|
||||
// Handle xbla-style crouch cycling
|
||||
const s32 oldcrouchpos = g_Vars.currentplayer->crouchpos;
|
||||
for (i = 0; i < numsamples; i++) {
|
||||
// handle 1964GEPD style crouch setting
|
||||
s32 crouchsample;
|
||||
@@ -1614,6 +1625,10 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
}
|
||||
}
|
||||
}
|
||||
// prevent uncrouching if we don't fit
|
||||
while (g_Vars.currentplayer->crouchpos > oldcrouchpos && !bwalkCanUncrouch()) {
|
||||
g_Vars.currentplayer->crouchpos--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1795,7 +1810,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
|
||||
g_Vars.currentplayer->bondactivateorreload = 0;
|
||||
|
||||
s32 usereloads = (controlmode != CONTROLMODE_PC);
|
||||
#ifndef PLATFORM_N64
|
||||
usereloads = usereloads || PLAYER_EXTCFG().usereloads;
|
||||
if (controlmode == CONTROLMODE_PC && movedata.alt1tapcount) {
|
||||
g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_RELOAD;
|
||||
}
|
||||
@@ -1803,7 +1820,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
if (movedata.btapcount) {
|
||||
g_Vars.currentplayer->activatetimelast = g_Vars.currentplayer->activatetimethis;
|
||||
g_Vars.currentplayer->activatetimethis = g_Vars.lvframe60;
|
||||
if (controlmode == CONTROLMODE_PC) {
|
||||
if (!usereloads) {
|
||||
g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_ACTIVATE;
|
||||
} else {
|
||||
g_Vars.currentplayer->bondactivateorreload = movedata.btapcount ?
|
||||
@@ -2189,8 +2206,10 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
#ifndef PLATFORM_N64
|
||||
if (allowmcross) {
|
||||
// joystick is inactive, move crosshair using the mouse
|
||||
const f32 xscale = PLAYER_EXTCFG().mouseaimspeedx * 320.f / (f32)videoGetWidth();
|
||||
const f32 yscale = PLAYER_EXTCFG().mouseaimspeedy * 240.f / (f32)videoGetHeight();
|
||||
const f32 xcoeff = 320.f / 1080.f;
|
||||
const f32 ycoeff = 240.f / 1080.f;
|
||||
const f32 xscale = (PLAYER_EXTCFG().mouseaimspeedx * xcoeff) / g_Vars.currentplayer->aspect;
|
||||
const f32 yscale = PLAYER_EXTCFG().mouseaimspeedy * ycoeff;
|
||||
f32 x = g_Vars.currentplayer->swivelpos[0] + movedata.freelookdx * xscale;
|
||||
f32 y = g_Vars.currentplayer->swivelpos[1] + movedata.freelookdy * yscale;
|
||||
x = (x < -1.f) ? -1.f : ((x > 1.f) ? 1.f : x);
|
||||
@@ -2483,7 +2502,7 @@ void bmoveUpdateHead(f32 arg0, f32 arg1, f32 arg2, Mtxf *arg3, f32 arg4)
|
||||
}
|
||||
} else {
|
||||
if (g_Vars.currentplayer->startnewbonddie) {
|
||||
bheadStartDeathAnimation(g_DeathAnimations[random() % g_NumDeathAnimations], random() % 2, 0, 1);
|
||||
bheadStartDeathAnimation(g_DeathAnimations[rngRandom() % g_NumDeathAnimations], rngRandom() % 2, 0, 1);
|
||||
g_Vars.currentplayer->startnewbonddie = false;
|
||||
}
|
||||
|
||||
|
||||
+48
-13
@@ -31,7 +31,7 @@ char var800a41c0[26];
|
||||
char var800a41c0[24];
|
||||
#endif
|
||||
|
||||
u8 g_IrScanlines[2][480];
|
||||
u8 g_IrScanlines[4][480];
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
u8 var800a8b58nb[0x1c0];
|
||||
@@ -335,7 +335,7 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
|
||||
s32 viewheight = viGetViewHeight();
|
||||
s32 viewwidth = viGetViewWidth();
|
||||
s32 viewleft = viGetViewLeft();
|
||||
u16 *fb2 = (u16 *) PHYS_TO_K0(random() & 0xfff00);
|
||||
u16 *fb2 = (u16 *) PHYS_TO_K0(rngRandom() & 0xfff00);
|
||||
s32 y;
|
||||
|
||||
gDPPipeSync(gdl++);
|
||||
@@ -344,7 +344,7 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
for (y = viewtop; y < viewtop + viewheight; y++) {
|
||||
gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth);
|
||||
gdl = bviewCopyPixels(gdl, fb2, rngRandom() % 240, 5, y, 1.0f, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
gDPSetCombineLERP(gdl++,
|
||||
@@ -468,8 +468,8 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
}
|
||||
}
|
||||
|
||||
if (random() % 20 == 1) {
|
||||
tmpy = random() % 200;
|
||||
if (rngRandom() % 20 == 1) {
|
||||
tmpy = rngRandom() % 200;
|
||||
}
|
||||
|
||||
gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth);
|
||||
@@ -490,8 +490,8 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
|
||||
}
|
||||
}
|
||||
|
||||
if (random() % 20 == 1) {
|
||||
tmpy += random() % 200;
|
||||
if (rngRandom() % 20 == 1) {
|
||||
tmpy += rngRandom() % 200;
|
||||
}
|
||||
|
||||
gDPFillRectangle(gdl++, viewleft, tmpy, viewleft + viewwidth, tmpy + 1);
|
||||
@@ -762,9 +762,9 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
|
||||
|
||||
for (i = viewtop; i < viewtop + viewheight; i++) {
|
||||
if (hit == EYESPYHIT_DAMAGE) {
|
||||
alpha2 = (random() % 120) + 120;
|
||||
alpha2 = (rngRandom() % 120) + 120;
|
||||
colour = 0xff333300 | (alpha2 & 0xff);
|
||||
f22 = ((random() % 32) + (f32) FBALLOC_HEIGHT) * (1.0f / 256.0f);
|
||||
f22 = ((rngRandom() % 32) + (f32) FBALLOC_HEIGHT) * (1.0f / 256.0f);
|
||||
|
||||
gDPSetEnvColorViaWord(gdl++, colour);
|
||||
} else {
|
||||
@@ -1109,6 +1109,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
s32 x = viewleft + (viewwidth >> 1);
|
||||
s32 y = viewtop + (viewheight >> 1);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gDPSetSubpixelOffsetEXT(gdl++, -2, -2);
|
||||
#endif
|
||||
|
||||
gDPFillRectangle(gdl++, x + 2, y + 0, x + 7, y + 1);
|
||||
gDPFillRectangle(gdl++, x + 2, y + 0, x + 5, y + 1);
|
||||
gDPFillRectangle(gdl++, x - 6, y + 0, x - 1, y + 1);
|
||||
@@ -1117,6 +1121,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
|
||||
gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 5);
|
||||
gDPFillRectangle(gdl++, x + 0, y - 6, x + 1, y - 1);
|
||||
gDPFillRectangle(gdl++, x + 0, y - 4, x + 1, y - 1);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gDPSetSubpixelOffsetEXT(gdl++, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
|
||||
@@ -2163,7 +2171,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
u8 green;
|
||||
|
||||
if (((var8007f878 & 1) != (y & 1)) != 0) {
|
||||
u8 tmp = random() % 12;
|
||||
u8 tmp = rngRandom() % 12;
|
||||
green = 0xff - tmp;
|
||||
} else {
|
||||
green = 0x94;
|
||||
@@ -2181,7 +2189,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
|
||||
u8 green;
|
||||
|
||||
if (((var8007f878 & 1) != (y & 1)) != 0) {
|
||||
u8 tmp = random() % 12;
|
||||
u8 tmp = rngRandom() % 12;
|
||||
green = 0xff - tmp;
|
||||
} else {
|
||||
green = 0x94;
|
||||
@@ -2348,6 +2356,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
|
||||
#endif
|
||||
|
||||
// fixes off by one error w/ two top players
|
||||
if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) {
|
||||
scanbottom++;
|
||||
}
|
||||
for (i = scantop; i < scanbottom; i++) {
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (i & 1) {
|
||||
@@ -2363,7 +2375,7 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
}
|
||||
#endif
|
||||
|
||||
red += random() % 8;
|
||||
red += rngRandom() % 8;
|
||||
|
||||
if (red > 255) {
|
||||
red = 255;
|
||||
@@ -2384,6 +2396,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
s32 semicirclewidth = sqrtf(sqinnerradius - (s32) (f0 * f0)) * (viewwidth / (f32) SCREEN_WIDTH_LO);
|
||||
s32 semicircleright = viewcentrex + semicirclewidth;
|
||||
s32 rightsidewidth = viewwidth - semicircleright;
|
||||
// if playernum is 1 or 3, shift to the right by viewwidth
|
||||
if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) {
|
||||
rightsidewidth += viewwidth;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
// Left and right of semicircle
|
||||
@@ -2397,14 +2413,22 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
|
||||
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth);
|
||||
}
|
||||
#else
|
||||
// Left and right of semicircle
|
||||
|
||||
// Scanlines to the left and right of the semicircle
|
||||
gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1);
|
||||
if (PLAYERCOUNT() <= 2 && g_Vars.currentplayernum == 0 && i == viewcentrey) {
|
||||
semicircleright -= 1;
|
||||
}
|
||||
else if (PLAYERCOUNT() > 2 && (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3 ) && i == viewcentrey) {
|
||||
semicircleright -= 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 {
|
||||
// scanlines above and below the semicircle
|
||||
gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1);
|
||||
}
|
||||
#endif
|
||||
@@ -2773,6 +2797,10 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl)
|
||||
s32 viewleft = viGetViewLeft();
|
||||
s32 viewright = viewleft + viewwidth;
|
||||
s32 viewbottom = viewtop + viewheight;
|
||||
// fixes off by one error w/ two top players
|
||||
if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) {
|
||||
viewbottom++;
|
||||
}
|
||||
s32 leftx = viewleft + viewwidth / 3;
|
||||
s32 rightx = viewleft + (viewwidth * 2) / 3;
|
||||
s32 centrey = (viewtop + viewbottom) / 2;
|
||||
@@ -2790,6 +2818,13 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl)
|
||||
for (y = viewtop; y < viewbottom; y++) {
|
||||
s32 ytocentre = centrey - y;
|
||||
s32 sqytocentre = ytocentre * ytocentre;
|
||||
if (PLAYERCOUNT() <= 2) {
|
||||
sqytocentre += 1;
|
||||
} else if (PLAYERCOUNT() > 2) {
|
||||
if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) {
|
||||
sqytocentre += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sqytocentre < sqradius) {
|
||||
s32 xoffset = (viewwidth / (f32) SCREEN_WIDTH_LO) * sqrtf(sqradius - sqytocentre);
|
||||
|
||||
+77
-1
@@ -237,6 +237,47 @@ s32 bwalkTryMoveUpwards(f32 amount)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool bwalkCanMoveUpwards(f32 amount)
|
||||
{
|
||||
bool result;
|
||||
struct coord newpos;
|
||||
RoomNum rooms[8];
|
||||
u32 stack;
|
||||
u32 types;
|
||||
f32 ymax;
|
||||
f32 ymin;
|
||||
f32 radius;
|
||||
|
||||
if (g_Vars.currentplayer->floorflags & GEOFLAG_SLOPE) {
|
||||
g_Vars.enableslopes = false;
|
||||
} else {
|
||||
g_Vars.enableslopes = true;
|
||||
}
|
||||
|
||||
newpos.x = g_Vars.currentplayer->prop->pos.x;
|
||||
newpos.y = g_Vars.currentplayer->prop->pos.y + amount;
|
||||
newpos.z = g_Vars.currentplayer->prop->pos.z;
|
||||
|
||||
types = g_Vars.bondcollisions ? CDTYPE_ALL : CDTYPE_BG;
|
||||
|
||||
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
|
||||
func0f065e74(&g_Vars.currentplayer->prop->pos, g_Vars.currentplayer->prop->rooms, &newpos, rooms);
|
||||
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &newpos, rooms);
|
||||
propSetPerimEnabled(g_Vars.currentplayer->prop, false);
|
||||
|
||||
ymin -= 0.1f;
|
||||
|
||||
result = cdTestVolume(&newpos, radius, rooms, types, CHECKVERTICAL_YES,
|
||||
ymax - g_Vars.currentplayer->prop->pos.y,
|
||||
ymin - g_Vars.currentplayer->prop->pos.y);
|
||||
|
||||
propSetPerimEnabled(g_Vars.currentplayer->prop, true);
|
||||
|
||||
g_Vars.enableslopes = true;
|
||||
|
||||
return (result == CDRESULT_NOCOLLISION);
|
||||
}
|
||||
|
||||
bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply, f32 extrawidth, s32 checktypes)
|
||||
{
|
||||
s32 result = CDRESULT_NOCOLLISION;
|
||||
@@ -1070,7 +1111,7 @@ void bwalkUpdateVertical(void)
|
||||
SFX_JO_LANDING_05B7
|
||||
};
|
||||
|
||||
psCreate(NULL, g_Vars.currentplayer->prop, sounds[random() % 3],
|
||||
psCreate(NULL, g_Vars.currentplayer->prop, sounds[rngRandom() % 3],
|
||||
-1, -1, PSFLAG_0400 | PSFLAG_IGNOREROOMS, 0, PSTYPE_NONE, 0, -1, NULL, -1, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
@@ -1168,6 +1209,41 @@ void bwalkUpdateCrouchOffsetReal(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool bwalkCanUncrouch(void)
|
||||
{
|
||||
f32 targetoffset = 0;
|
||||
|
||||
if (g_Vars.currentplayer->crouchpos == CROUCHPOS_SQUAT) {
|
||||
targetoffset = -90;
|
||||
} else if (g_Vars.currentplayer->crouchpos == CROUCHPOS_DUCK) {
|
||||
targetoffset = -45;
|
||||
}
|
||||
|
||||
if (targetoffset != g_Vars.currentplayer->crouchoffset) {
|
||||
f32 prevcrouchoffset = g_Vars.currentplayer->crouchoffset;
|
||||
f32 prevcrouchoffsetreal = g_Vars.currentplayer->crouchoffsetreal;
|
||||
f32 prevcrouchoffsetsmall = g_Vars.currentplayer->crouchoffsetsmall;
|
||||
f32 prevcrouchoffsetrealsmall = g_Vars.currentplayer->crouchoffsetrealsmall;
|
||||
f32 prevcrouchspeed = g_Vars.currentplayer->crouchspeed;
|
||||
|
||||
g_Vars.currentplayer->crouchoffset = targetoffset;
|
||||
|
||||
bwalkUpdateCrouchOffsetReal();
|
||||
|
||||
const bool result = bwalkCanMoveUpwards(0);
|
||||
|
||||
g_Vars.currentplayer->crouchoffset = prevcrouchoffset;
|
||||
g_Vars.currentplayer->crouchoffsetreal = prevcrouchoffsetreal;
|
||||
g_Vars.currentplayer->crouchoffsetsmall = prevcrouchoffsetsmall;
|
||||
g_Vars.currentplayer->crouchoffsetrealsmall = prevcrouchoffsetrealsmall;
|
||||
g_Vars.currentplayer->crouchspeed = prevcrouchspeed;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bwalkUpdateCrouchOffset(void)
|
||||
{
|
||||
f32 targetoffset = 0;
|
||||
|
||||
+1
-5
@@ -138,8 +138,6 @@ void bossfileLoad(void)
|
||||
g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1);
|
||||
g_AltTitleUnlocked = savebufferReadBits(&buffer, 1);
|
||||
g_AltTitleEnabled = savebufferReadBits(&buffer, 1);
|
||||
|
||||
func0f0d54c4(&buffer);
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
@@ -168,7 +166,7 @@ void bossfileSave(void)
|
||||
savebufferOr(&buffer, g_Vars.language, 4);
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(g_BossFile.teamnames); i++) {
|
||||
func0f0d55a4(&buffer, g_BossFile.teamnames[i]);
|
||||
savebufferWriteString(&buffer, g_BossFile.teamnames[i]);
|
||||
}
|
||||
|
||||
if (g_BossFile.tracknum == -1) {
|
||||
@@ -185,8 +183,6 @@ void bossfileSave(void)
|
||||
savebufferOr(&buffer, g_AltTitleUnlocked, 1);
|
||||
savebufferOr(&buffer, g_AltTitleEnabled, 1);
|
||||
|
||||
func0f0d54c4(&buffer);
|
||||
|
||||
fileid = bossfileFindFileId();
|
||||
|
||||
if (fileid == 0) {
|
||||
|
||||
+50
-42
@@ -185,13 +185,13 @@ void botReset(struct chrdata *chr, u8 respawning)
|
||||
|
||||
aibot->waypoints[0] = NULL;
|
||||
aibot->numwaystepstotarget = 0;
|
||||
aibot->random1 = random();
|
||||
aibot->random1 = rngRandom();
|
||||
aibot->random1ttl60 = 0;
|
||||
aibot->targetcloaktimer60 = 0;
|
||||
aibot->canseecloaked = 0;
|
||||
aibot->rcpcloaktimer60 = 0;
|
||||
aibot->random2ttl60 = 0;
|
||||
aibot->random2 = random();
|
||||
aibot->random2 = rngRandom();
|
||||
aibot->randomfrac = RANDOMFRAC();
|
||||
aibot->cheap = 0;
|
||||
|
||||
@@ -264,10 +264,18 @@ void botSpawn(struct chrdata *chr, u8 respawning)
|
||||
#ifndef PLATFORM_N64
|
||||
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_SHIELD) {
|
||||
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
|
||||
botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
|
||||
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2);
|
||||
const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype;
|
||||
if (ammotype) {
|
||||
s32 startammo = mpweapon->priammoqty / 2;
|
||||
if (startammo == 0) {
|
||||
startammo = 1;
|
||||
}
|
||||
botactGiveAmmoByType(aibot, ammotype, startammo);
|
||||
}
|
||||
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
|
||||
}
|
||||
#endif
|
||||
@@ -1409,8 +1417,8 @@ void bot0f192a74(struct chrdata *chr)
|
||||
aibot->random3ttl60 -= g_Vars.lvupdate60;
|
||||
|
||||
if (aibot->random3ttl60 <= 0) {
|
||||
aibot->random3 = random();
|
||||
aibot->random3ttl60 = TICKS(20) + random() % TICKS(20);
|
||||
aibot->random3 = rngRandom();
|
||||
aibot->random3ttl60 = TICKS(20) + rngRandom() % TICKS(20);
|
||||
}
|
||||
|
||||
if (g_Vars.lvupdate240 > 0) {
|
||||
@@ -1551,7 +1559,7 @@ void botChooseGeneralTarget(struct chrdata *botchr)
|
||||
// However, the usage of canseecloaked appears to be botched.
|
||||
// It is implemented in botIsTargetInvisible, but that function is not
|
||||
// called here while canseecloaked is true.
|
||||
if (random() % TICKS(4 * 60 * 60) < g_MpNumChrs * g_Vars.lvupdate60) {
|
||||
if (rngRandom() % TICKS(4 * 60 * 60) < g_MpNumChrs * g_Vars.lvupdate60) {
|
||||
aibot->canseecloaked = true;
|
||||
}
|
||||
|
||||
@@ -1746,7 +1754,7 @@ s32 botFindTeammateToFollow(struct chrdata *chr, f32 range)
|
||||
|
||||
if ((g_MpSetup.options & MPOPTION_TEAMSENABLED)
|
||||
&& chr->myaction != MA_AIBOTFOLLOW
|
||||
&& (random() % 100) < chr->aibot->followchance) {
|
||||
&& (rngRandom() % 100) < chr->aibot->followchance) {
|
||||
f32 closestdistance = 0;
|
||||
s32 closestplayernum = -1;
|
||||
s32 i;
|
||||
@@ -1884,8 +1892,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(weaponnums); i++) {
|
||||
if (weaponnums[i] > WEAPON_UNARMED && weaponnums[i] == weapon->weaponnum) {
|
||||
if (random() % 16) {
|
||||
if (weapproplist[i] == NULL || sqdist1 < weapdistlist[i] || random() % 16 == 0) {
|
||||
if (rngRandom() % 16) {
|
||||
if (weapproplist[i] == NULL || sqdist1 < weapdistlist[i] || rngRandom() % 16 == 0) {
|
||||
weapproplist[i] = prop;
|
||||
weapdistlist[i] = sqdist1;
|
||||
}
|
||||
@@ -1896,8 +1904,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
|
||||
|
||||
ammotype = botactGetAmmoTypeByFunction(weapon->weaponnum, FUNC_PRIMARY);
|
||||
|
||||
if (ammotype > 0 && random() % 16) {
|
||||
if (ammoproplist[ammotype] == NULL || sqdist1 < ammodistlist[ammotype] || random() % 16 == 0) {
|
||||
if (ammotype > 0 && rngRandom() % 16) {
|
||||
if (ammoproplist[ammotype] == NULL || sqdist1 < ammodistlist[ammotype] || rngRandom() % 16 == 0) {
|
||||
ammoproplist[ammotype] = prop;
|
||||
ammodistlist[ammotype] = sqdist1;
|
||||
}
|
||||
@@ -1920,8 +1928,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
|
||||
if (weaponnum > 0) {
|
||||
for (j = 0; j < ARRAYCOUNT(weaponnums); j++) {
|
||||
if (weaponnums[j] > WEAPON_UNARMED && weaponnum == weaponnums[j]) {
|
||||
if (random() % 16) {
|
||||
if (weapproplist[j] == NULL || sqdist2 < weapdistlist[j] || random() % 16 == 0) {
|
||||
if (rngRandom() % 16) {
|
||||
if (weapproplist[j] == NULL || sqdist2 < weapdistlist[j] || rngRandom() % 16 == 0) {
|
||||
weapproplist[j] = prop;
|
||||
weapdistlist[j] = sqdist2;
|
||||
}
|
||||
@@ -1931,8 +1939,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
|
||||
}
|
||||
}
|
||||
|
||||
if (random() % 16) {
|
||||
if (ammoproplist[ammotype] == NULL || sqdist2 < ammodistlist[ammotype] || random() % 16 == 0) {
|
||||
if (rngRandom() % 16) {
|
||||
if (ammoproplist[ammotype] == NULL || sqdist2 < ammodistlist[ammotype] || rngRandom() % 16 == 0) {
|
||||
ammoproplist[ammotype] = prop;
|
||||
ammodistlist[ammotype] = sqdist2;
|
||||
}
|
||||
@@ -1944,11 +1952,11 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
|
||||
if (weaponnums[i] == WEAPON_MPSHIELD) {
|
||||
sqdist2 = chrGetSquaredDistanceToCoord(chr, &prop->pos);
|
||||
|
||||
if (random() % 16 == 0) {
|
||||
if (rngRandom() % 16 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (weapproplist[i] == NULL || sqdist2 < weapdistlist[i] || random() % 16 == 0) {
|
||||
if (weapproplist[i] == NULL || sqdist2 < weapdistlist[i] || rngRandom() % 16 == 0) {
|
||||
weapproplist[i] = prop;
|
||||
weapdistlist[i] = sqdist2;
|
||||
}
|
||||
@@ -2399,8 +2407,8 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
aibot->random2ttl60 -= g_Vars.lvupdate60;
|
||||
|
||||
if (aibot->random2ttl60 < 0) {
|
||||
aibot->random2ttl60 = TICKS(1800) + random() % TICKS(60 * 240);
|
||||
aibot->random2 = random();
|
||||
aibot->random2ttl60 = TICKS(1800) + rngRandom() % TICKS(60 * 240);
|
||||
aibot->random2 = rngRandom();
|
||||
aibot->randomfrac = RANDOMFRAC();
|
||||
}
|
||||
|
||||
@@ -2531,7 +2539,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
if (g_MpSetup.scenario == MPSCENARIO_HOLDTHEBRIEFCASE) {
|
||||
s32 numgetting = botGetCountInTeamDoingCommand(chr, AIBOTCMD_GETCASE2, false);
|
||||
|
||||
if (numgetting <= 0 || (numgetting < (teamsize + 1) / 2 || random() % 100 < 66)) {
|
||||
if (numgetting <= 0 || (numgetting < (teamsize + 1) / 2 || rngRandom() % 100 < 66)) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE2);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
|
||||
@@ -2539,7 +2547,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
} else if (g_MpSetup.scenario == MPSCENARIO_HACKERCENTRAL) {
|
||||
s32 numbots = botGetCountInTeamDoingCommand(chr, AIBOTCMD_DOWNLOAD, false);
|
||||
|
||||
if (aibot->hasuplink || numbots <= 0 || (numbots < (teamsize + 1) / 2 || random() % 100 < 50)) {
|
||||
if (aibot->hasuplink || numbots <= 0 || (numbots < (teamsize + 1) / 2 || rngRandom() % 100 < 50)) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_DOWNLOAD);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
|
||||
@@ -2547,7 +2555,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
} else if (g_MpSetup.scenario == MPSCENARIO_POPACAP) {
|
||||
s32 numchasing = botGetCountInTeamDoingCommand(chr, AIBOTCMD_POPCAP, false);
|
||||
|
||||
if (numchasing <= 0 || numchasing < (teamsize + 1) / 2 || random() % 100 < 50) {
|
||||
if (numchasing <= 0 || numchasing < (teamsize + 1) / 2 || rngRandom() % 100 < 50) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_POPCAP);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
|
||||
@@ -2563,7 +2571,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
if (numinhill <= 0 || numinhill < teamsize / 2) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_HOLDHILL);
|
||||
} else if (numinhill > botGetNumOpponentsInHill(chr)) {
|
||||
if (random() % 100 < 50) {
|
||||
if (rngRandom() % 100 < 50) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_DEFHILL);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
|
||||
@@ -2579,13 +2587,13 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
if (botShouldReturnCtcToken(chr)) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else if (botIsChrsCtcTokenHeld(chr)) {
|
||||
if (random() % 100 < 30) {
|
||||
if (rngRandom() % 100 < 30) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
|
||||
}
|
||||
} else {
|
||||
if (random() % 100 < 70 || numgetting <= 0) {
|
||||
if (rngRandom() % 100 < 70 || numgetting <= 0) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
|
||||
@@ -2599,7 +2607,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
if (botShouldReturnCtcToken(chr)) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else if (botIsChrsCtcTokenHeld(chr)) {
|
||||
if (numsaving <= 0 || random() % 100 < 70) {
|
||||
if (numsaving <= 0 || rngRandom() % 100 < 70) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
@@ -2608,9 +2616,9 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else if (numsaving <= 0 || numsaving < teamsize / 4) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
|
||||
} else if (random() % 100 < 30) {
|
||||
} else if (rngRandom() % 100 < 30) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
|
||||
} else if (random() % 100 < 30) {
|
||||
} else if (rngRandom() % 100 < 30) {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
|
||||
} else {
|
||||
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
|
||||
@@ -2619,7 +2627,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
}
|
||||
|
||||
// Consider changing command in 20 to 60 seconds
|
||||
aibot->commandtimer60 = TICKS(1200) + random() % TICKS(2400);
|
||||
aibot->commandtimer60 = TICKS(1200) + rngRandom() % TICKS(2400);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2716,7 +2724,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
s32 index;
|
||||
s32 i;
|
||||
|
||||
index = random() % numtokens;
|
||||
index = rngRandom() % numtokens;
|
||||
|
||||
i = (index + 1) % numtokens;
|
||||
|
||||
@@ -2744,7 +2752,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
aibot->gotoprop = tokens[index];
|
||||
} else if (botCanFollow(chr, tokens[index]->chr)) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = mpPlayerGetIndex(tokens[index]->chr);
|
||||
}
|
||||
}
|
||||
@@ -2762,7 +2770,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Held by a teammate - follow/protect them
|
||||
if (botCanFollow(chr, tokenchr)) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = mpPlayerGetIndex(tokenchr);
|
||||
}
|
||||
} else {
|
||||
@@ -2852,7 +2860,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Uplink is held by teammate - protect them
|
||||
if (botCanFollow(chr, uplinkchr)) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = mpPlayerGetIndex(uplinkchr);
|
||||
}
|
||||
} else {
|
||||
@@ -2883,7 +2891,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Briefcase is held by teammate - protect them
|
||||
if (botCanFollow(chr, tokenchr)) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = mpPlayerGetIndex(tokenchr);
|
||||
}
|
||||
} else if (!botIsTargetInvisible(chr, tokenchr) && botPassesCowardCheck(chr, tokenchr)) {
|
||||
@@ -2911,7 +2919,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Victim is a teammate - protect them
|
||||
if (botCanFollow(chr, victimchr)) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = mpPlayerGetIndex(victimchr);
|
||||
}
|
||||
} else {
|
||||
@@ -2936,13 +2944,13 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Current bot has the briefcase - follow a teammate for protection
|
||||
s32 playernum = -1;
|
||||
|
||||
if (random() % 100 < 66) {
|
||||
if (rngRandom() % 100 < 66) {
|
||||
playernum = botFindTeammateToFollow(chr, 100000);
|
||||
}
|
||||
|
||||
if (playernum >= 0) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = playernum;
|
||||
}
|
||||
}
|
||||
@@ -2954,13 +2962,13 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
// Current bot is the victim - follow a teammate for protection
|
||||
s32 playernum = -1;
|
||||
|
||||
if (random() % 100 < 66) {
|
||||
if (rngRandom() % 100 < 66) {
|
||||
playernum = botFindTeammateToFollow(chr, 100000);
|
||||
}
|
||||
|
||||
if (playernum >= 0) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = playernum;
|
||||
}
|
||||
}
|
||||
@@ -3087,7 +3095,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
|
||||
if (playernum >= 0) {
|
||||
newaction = MA_AIBOTFOLLOW;
|
||||
aibot->canbreakfollow = random() % 4 == 0;
|
||||
aibot->canbreakfollow = rngRandom() % 4 == 0;
|
||||
aibot->followingplayernum = playernum;
|
||||
}
|
||||
}
|
||||
@@ -3427,7 +3435,7 @@ void botTickUnpaused(struct chrdata *chr)
|
||||
aibot->punchtimer60[0] = TICKS(30);
|
||||
}
|
||||
|
||||
if (random() % 3 == 0) {
|
||||
if (rngRandom() % 3 == 0) {
|
||||
aibot->punchtimer60[1] = aibot->punchtimer60[0] - TICKS(20);
|
||||
}
|
||||
break;
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ bool botactShootFarsight(struct chrdata *chr, s32 arg1, struct coord *vector, st
|
||||
aibot = chr->aibot;
|
||||
|
||||
if (aibot->weaponnum == WEAPON_FARSIGHT) {
|
||||
rand = random() % 100;
|
||||
rand = rngRandom() % 100;
|
||||
|
||||
// 3 in 10 chance of this passing
|
||||
if (rand < 30) {
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ void botcmdTickDistMode(struct chrdata *chr)
|
||||
if (!insight) {
|
||||
newmode = BOTDISTMODE_ADVANCE;
|
||||
aibot->distoverrideprop = targetprop;
|
||||
aibot->distoverridetimer60 = TICKS(20) + (random() % TICKS(120));
|
||||
aibot->distoverridetimer60 = TICKS(20) + (rngRandom() % TICKS(120));
|
||||
} else if (aibot->distoverrideprop) {
|
||||
if (g_Vars.lvupdate60 < aibot->distoverridetimer60) {
|
||||
aibot->distoverridetimer60 -= g_Vars.lvupdate60;
|
||||
|
||||
+14
-14
@@ -71,14 +71,14 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
|
||||
/*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
|
||||
/*0x24*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I
|
||||
/*0x25*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13
|
||||
/*0x26*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313
|
||||
/*0x27*/ { 124, 148, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL
|
||||
/*0x28*/ { 116, 128, 136, 152, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT
|
||||
/*0x29*/ { 124, 148, 0, 0, 1, 0, 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
|
||||
/*0x2b*/ { 164, 188, 0, 0, 1, 0, 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
|
||||
@@ -904,7 +904,7 @@ void botinvTick(struct chrdata *chr)
|
||||
aibot->dampensuicidesttl60 -= g_Vars.lvupdate60;
|
||||
|
||||
if (aibot->dampensuicidesttl60 < 0) {
|
||||
aibot->dampensuicidesttl60 = TICKS(3600) + random() % TICKS(60);
|
||||
aibot->dampensuicidesttl60 = TICKS(3600) + rngRandom() % TICKS(60);
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(aibot->suicidesbygunfunc); i++) {
|
||||
aibot->suicidesbygunfunc[i][0] *= 0.9f;
|
||||
@@ -916,15 +916,15 @@ void botinvTick(struct chrdata *chr)
|
||||
aibot->equipextrascorestimer60 -= g_Vars.lvupdate60;
|
||||
|
||||
if (aibot->equipextrascorestimer60 < 0) {
|
||||
aibot->equipextrascorestimer60 = TICKS(600) + random() % TICKS(3000);
|
||||
aibot->equipextrascorestimer60 = TICKS(600) + rngRandom() % TICKS(3000);
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(aibot->equipextrascores); i++) {
|
||||
if (aibot->config->difficulty == BOTDIFF_MEAT) {
|
||||
aibot->equipextrascores[i] = random() % 200 - 100; // -100 to +100
|
||||
aibot->equipextrascores[i] = rngRandom() % 200 - 100; // -100 to +100
|
||||
} else if (aibot->config->difficulty == BOTDIFF_EASY) {
|
||||
aibot->equipextrascores[i] = random() % 100 - 50; // -50 to +50
|
||||
aibot->equipextrascores[i] = rngRandom() % 100 - 50; // -50 to +50
|
||||
} else {
|
||||
aibot->equipextrascores[i] = random() % 30 - 15; // -15 to +15
|
||||
aibot->equipextrascores[i] = rngRandom() % 30 - 15; // -15 to +15
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -934,8 +934,8 @@ void botinvTick(struct chrdata *chr)
|
||||
aibot->random1ttl60 -= g_Vars.lvupdate60;
|
||||
|
||||
if (aibot->random1ttl60 < 0) {
|
||||
aibot->random1ttl60 = TICKS(120) + random() % TICKS(600);
|
||||
aibot->random1 = random();
|
||||
aibot->random1ttl60 = TICKS(120) + rngRandom() % TICKS(600);
|
||||
aibot->random1 = rngRandom();
|
||||
}
|
||||
|
||||
if (aibot->cyclonedischarging[HAND_LEFT] == 0
|
||||
|
||||
+3
-3
@@ -85,7 +85,7 @@ void botmgrAllocateBot(s32 chrnum, s32 aibotnum)
|
||||
|
||||
if (aibot != NULL) {
|
||||
chr->tude = 0;
|
||||
chr->voicebox = random() % 3;
|
||||
chr->voicebox = rngRandom() % 3;
|
||||
|
||||
if (g_HeadsAndBodies[chr->bodynum].ismale == false) {
|
||||
chr->voicebox = VOICEBOX_FEMALE;
|
||||
@@ -235,7 +235,7 @@ void botmgrAllocateBot(s32 chrnum, s32 aibotnum)
|
||||
aibot->realignangleframe = -1;
|
||||
aibot->waypoints[0] = NULL;
|
||||
aibot->numwaystepstotarget = 0;
|
||||
aibot->random1 = random();
|
||||
aibot->random1 = rngRandom();
|
||||
aibot->random1ttl60 = 0;
|
||||
|
||||
for (i = 0; i < ARRAYCOUNT(aibot->killsbygunfunc); i++) {
|
||||
@@ -258,7 +258,7 @@ void botmgrAllocateBot(s32 chrnum, s32 aibotnum)
|
||||
aibot->canseecloaked = false;
|
||||
|
||||
aibot->random2ttl60 = 0;
|
||||
aibot->random2 = random();
|
||||
aibot->random2 = rngRandom();
|
||||
aibot->randomfrac = RANDOMFRAC();
|
||||
aibot->cheap = false;
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ bool botroomFindPos(RoomNum room, struct coord *pos, f32 *angleptr, s32 *padnump
|
||||
return false;
|
||||
}
|
||||
|
||||
i = random() % totalcount;
|
||||
i = rngRandom() % totalcount;
|
||||
|
||||
if (i < covercount) {
|
||||
coverUnpack(covernums[i], &cover);
|
||||
|
||||
Loaded 100 of 230 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user