Compare commits

...

41 Commits

Author SHA1 Message Date
Falco Girgis
430ab335de Fixed really stupid mistake.
- Whoops, accidentally took x to the 4th power in MATH_Fast_Invert().
2025-02-28 23:01:15 -06:00
Falco Girgis
f0052c79b9 TnL micro gainz: faster inverse + mat3 loading
This PR is just for a couple of quick micro-gainz which caught my eye:

1) The rw_mat_load_3x3() routine now has better instruction scheduling
   for (mostly) superscalar dual dispatch.
2) Every time we used MATH_Fast_Inverse() for perspective division, we
   were doing extra work to maintain the value's sign.
    - Added MATH_Very_Fast_Invert(x) which doesn't maintain sign bit
2025-02-28 17:02:00 -06:00
Stefanos Kornilios Mitsis Poiitidis
3a4aa88259 Merge branch 'skmp/oix-emulator-workarounds' into 'main'
Submit via OCR path if emulator is detected with no support for OIX

See merge request skmp/dca3-game!26
2025-02-25 17:07:58 +00:00
Stefanos Kornilios Mitsis Poiitidis
97a4e0d3a4 Merge branch 'skmp/fix-sniper' into 'main'
Fix sniper bug / bulletInfoInUse counting

See merge request skmp/dca3-game!25
2025-02-25 17:01:28 +00:00
Stefanos Kornilios Mitsis Poiitidis
7748c85d6b Submit via OCR path if emulator is detected with no support for OIX 2025-02-25 18:55:51 +02:00
Stefanos Kornilios Mitsis Poiitidis
e5308dea97 Fix sniper bug / bulletInfoInUse counting 2025-02-25 18:54:32 +02:00
Stefanos Kornilios Mitsis Poiitidis
87bfbcab2d Merge branch 'skmp/texconv-edit-txds' into 'main'
texconv: Add support for modifying txds, add gamepad assets

See merge request skmp/dca3-game!22
2025-02-07 17:19:21 +00:00
Stefanos Kornilios Mitsis Poiitidis
bdc27bf2fc texconv: Add support for modifying txds, add gamepad assets 2025-02-07 19:06:03 +02:00
Stefanos Kornilios Mitsis Poiitidis
1ee51d5136 Merge branch 'ph3nom/updated-fog-2.0' into 'main'
Fog Parameters Updated

See merge request skmp/dca3-game!21
2025-02-06 08:22:59 +00:00
Stefanos Kornilios Mitsis Poiitidis
725d60a9fb Merge branch 'ph3nom/audio-volume-fixes' into 'main'
Fixes for audio volume

See merge request skmp/dca3-game!20
2025-02-06 08:20:45 +00:00
Josh Pearson
05e9e7452e Custom Fog Table index fix 2025-02-05 09:24:02 -07:00
Josh Pearson
51b21c02b9 Merge branch 'ph3nom/updated-fog' into ph3nom/updated-fog-2.0 2025-02-03 16:47:41 -07:00
Josh Pearson
86806215a5 Revert "Fixes for audio volume"
This reverts commit 8c81349c69.
2025-02-03 16:47:27 -07:00
Josh Pearson
a056fdecc7 Custom Fog Table
KOS fog functions always start at 0, meaning fog is not really applied near the camera.  This custom table allows fog to "psuedo" start before the camera so that vertices near the camera have fog applied as this game expects
2025-02-03 15:53:05 -07:00
Josh Pearson
b6d5c628b2 Fixes for audio volume
Main menu will now adjust music and sfx volume.  Fade in and fade out for cutscenes now working.
2025-02-03 13:05:49 -07:00
Josh Pearson
8c81349c69 Fixes for audio volume
Main menu will now adjust music and sfx volume.  Fade in and fade out for cutscenes now working.
2025-02-03 12:59:12 -07:00
Josh Pearson
282b639a4c Fog Parameters Updated
Hook timecycle to get fog start value.  This is then converted into a density value (based on known range) to produce a nicer fog cutoff value using EXP fog instead of linear table mode.
2025-01-29 15:58:40 -07:00
Stefanos Kornilios Mitsis Poiitidis
69f9bbcf7b Merge branch 'skmp/fix-audio-sample-calculations' into 'main'
audio: Do sample <-> milisecond in 64 bit precision, as intermediate steps might overflow int32

See merge request skmp/dca3-game!19
2025-01-26 14:43:07 +00:00
Stefanos Kornilios Mitsis Poiitidis
40f212e131 audio: Do sample <-> milisecond in 64 bit precision, as intermediate steps might overflow int32 2025-01-26 15:36:43 +01:00
Stefanos Kornilios Mitsis Poiitidis
43c0e99ebf Merge branch 'skmp/fix-dam-flamethrower' into 'main'
Fix Dynamic Acoustic Modelling: off & Flamethrower SFX

See merge request skmp/dca3-game!18
2025-01-26 13:55:55 +00:00
Stefanos Kornilios Mitsis Poiitidis
42647ddc6b Fix Dynamic Acoustic Modelling: off & Flamethrower SFX 2025-01-26 14:44:29 +01:00
Stefanos Kornilios Mitsis Poiitidis
b3ccf1f900 Merge branch 'ph3nom/fix-throwing-controls' into 'main'
Fix Throwing Grenade and Moltov Coctail Controls

See merge request skmp/dca3-game!17
2025-01-25 10:50:26 +00:00
Josh Pearson
baf7612fcf Fix Throwing Grenade and Moltov Coctail Controls 2025-01-24 17:08:55 -07:00
Stefanos Kornilios Mitsis Poiitidis
33b9dd1c8a Merge branch 'skmp/protect-from-zero-delta-times' into 'main'
CAnimBlendNode::GetCurrentTranslation: Protect against zero delta times

See merge request skmp/dca3-game!15
2025-01-16 06:13:03 +00:00
Stefanos Kornilios Mitsis Poiitidis
5786eeecb8 Merge branch 'falco/fuck_da_fences' into 'main'
Fixed the goddamn fences.

See merge request skmp/dca3-game!14
2025-01-16 06:11:54 +00:00
Stefanos Kornilios Mitsis Poiitidis
20864fdac6 Merge branch '49-game-crash-when-entering-parking-garage-on-staunton-island' into 'main'
Resolve "Parking garage crash fix"

See merge request skmp/dca3-game!16
2025-01-16 06:09:08 +00:00
mark wallace
1587d707a8 Parking garage bug fix. 2025-01-16 04:11:34 +00:00
Stefanos Kornilios Mitsis Poiitidis
911b93bd0f CAnimBlendNode::GetCurrentTranslation: Protect against zero delta times 2025-01-14 23:18:24 +02:00
Falco Girgis
e86fb27a48 Fixed the goddamn fences.
Colliding with and/or brushing against the metal chain-linked fences in
the game caused severe performance degredation as the SH4 struggled to
keep up with the physics.

The PSVita REGTA3 port also struggled, somehow, with its bazillion times
faster CPU. The PS2 version has no fences. The Xbox version implemented
an interesting compromise, where fences could be collided with and
knocked over, but individual links did not interact with one-another,
only with the car.

So that's what I've essentially done here. Intersection testing is still
happening between all of the previous CPhysical entities in question
(player vs fences vs fences); however, the contact resolution for fence vs
fence collisions is now being essentially canceled.

Apparently that's all that was needed, as you can now mow down long-ass
fences with no performance impact and a response that looks like what
the Xbox does.
2025-01-12 00:29:42 -06:00
Stefanos Kornilios Mitsis Poiitidis
2065c9a93f Merge branch 'skmp/fix-AllocateBoatWakeArray' into 'main'
Some checks failed
re3 conan+cmake / build-cmake (openal, glfw, macos-latest, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, glfw, ubuntu-18.04, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, glfw, windows-latest, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, windows-latest, d3d9) (push) Has been cancelled
re3 cmake devkitA64 (Nintendo Switch) / build-nintendo-switch (push) Has been cancelled
re3 premake amd64 / build (Debug, win-amd64-librw_d3d9-oal) (push) Has been cancelled
re3 premake amd64 / build (Debug, win-amd64-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake amd64 / build (Release, win-amd64-librw_d3d9-oal) (push) Has been cancelled
re3 premake amd64 / build (Release, win-amd64-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
Fix AllocateBoatWakeArray, it needs RpGeometryCreate with HAS_TRIANGLES

See merge request skmp/dca3-game!12
2025-01-06 11:46:50 +00:00
Stefanos Kornilios Mitsis Poiitidis
a2caa56275 Merge branch 'skmp/material-alpha-override-pt' into 'main'
Perform full blending for mat.a != 0xFF, should fade-in sprites (eg, Trees)

See merge request skmp/dca3-game!11
2025-01-06 11:41:11 +00:00
Stefanos Kornilios Mitsis Poiitidis
fa65f637ad Fix AllocateBoatWakeArray, it needs RpGeometryCreate with HAS_TRIANGLES 2025-01-06 13:40:31 +02:00
Stefanos Kornilios Mitsis Poiitidis
0a0a664428 Perform full blending for mat.a != 0xFF, should fade-in sprites (eg, Trees) 2025-01-05 15:40:18 +02:00
Stefanos Kornilios Mitsis Poiitidis
5abd0641a4 Merge branch 'skmp/fix-staring-into-the-void' into 'main'
Some checks are pending
re3 conan+cmake / build-cmake (openal, glfw, macos-latest, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, glfw, ubuntu-18.04, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, glfw, windows-latest, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, windows-latest, d3d9) (push) Waiting to run
re3 cmake devkitA64 (Nintendo Switch) / build-nintendo-switch (push) Waiting to run
re3 premake amd64 / build (Debug, win-amd64-librw_d3d9-oal) (push) Waiting to run
re3 premake amd64 / build (Debug, win-amd64-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake amd64 / build (Release, win-amd64-librw_d3d9-oal) (push) Waiting to run
re3 premake amd64 / build (Release, win-amd64-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
Revert buggy optimizations in CMatrix::Rotate*. Didn't investigate much, they aren't often called

Closes #8 and #6

See merge request skmp/dca3-game!9
2025-01-05 08:21:54 +00:00
Stefanos Kornilios Mitsis Poiitidis
ca866bdb2a Fix sim build 2025-01-05 10:15:30 +02:00
Stefanos Kornilios Mitsis Poiitidis
bf0e36858e Use fipr in CMatrix::Rotate, simplifies it so it doesn't ICE
Some checks failed
re3 conan+cmake / build-cmake (openal, glfw, macos-latest, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, glfw, ubuntu-18.04, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, glfw, windows-latest, gl3) (push) Has been cancelled
re3 conan+cmake / build-cmake (openal, windows-latest, d3d9) (push) Has been cancelled
re3 cmake devkitA64 (Nintendo Switch) / build-nintendo-switch (push) Has been cancelled
re3 premake amd64 / build (Debug, win-amd64-librw_d3d9-oal) (push) Has been cancelled
re3 premake amd64 / build (Debug, win-amd64-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake amd64 / build (Release, win-amd64-librw_d3d9-oal) (push) Has been cancelled
re3 premake amd64 / build (Release, win-amd64-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-mss) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-oal) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-mss) (push) Has been cancelled
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-oal) (push) Has been cancelled
2025-01-05 09:19:02 +02:00
Stefanos Kornilios Mitsis Poiitidis
b90e8433da Revert buggy optimizations in CMatrix::Rotate*. Didn't investigate much, they aren't often called 2025-01-05 09:12:56 +02:00
Stefanos Kornilios Mitsis Poiitidis
133110c15c Merge branch 'skmp/async-pedsfx-load' into 'main'
Some checks are pending
re3 conan+cmake / build-cmake (openal, glfw, macos-latest, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, glfw, ubuntu-18.04, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, glfw, windows-latest, gl3) (push) Waiting to run
re3 conan+cmake / build-cmake (openal, windows-latest, d3d9) (push) Waiting to run
re3 cmake devkitA64 (Nintendo Switch) / build-nintendo-switch (push) Waiting to run
re3 premake amd64 / build (Debug, win-amd64-librw_d3d9-oal) (push) Waiting to run
re3 premake amd64 / build (Debug, win-amd64-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake amd64 / build (Release, win-amd64-librw_d3d9-oal) (push) Waiting to run
re3 premake amd64 / build (Release, win-amd64-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Debug, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Release, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-mss) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_d3d9-oal) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-mss) (push) Waiting to run
re3 premake x86 / build (Vanilla, win-x86-librw_gl3_glfw-oal) (push) Waiting to run
PedSfx: Read from I/O thread, load them on the background

See merge request skmp/dca3-game!10
2025-01-04 19:15:39 +00:00
Stefanos Kornilios Mitsis Poiitidis
6f71cfc458 PedSfx: Read from I/O thread, load them on the background 2025-01-04 17:46:48 +02:00
Stefanos Kornilios Mitsis Poiitidis
02d0103b20 Redirect to dca3.net 2024-12-31 09:05:08 +00:00
Stefanos Kornilios Mitsis Poiitidis
72da27ef0b Edit README.md 2024-12-29 22:23:08 +00:00
28 changed files with 592 additions and 198 deletions

View File

@@ -28,12 +28,12 @@ You will also need the following tools installed
### Cloning the dca3-game repo and downloading the prebuilt elf
- Open dreamsdk shell
- type `git clone https://gitlab.com/skmp/dca3-game.git` (and press enter)
- type `git clone --branch alpha https://gitlab.com/skmp/dca3-game.git` (and press enter)
- It should take a moment and successfully clone the repo
- type `cd dca3-game/dreamcast` (and press enter)
- type `explorer .` (and press enter).
- A folder named dreamcast with some files should be open. Keep it on the side.
- Download the artifacts from https://gitlab.com/skmp/dca3-game/-/jobs/8725216645
- Download the Alpha Prebuilt Elf from https://gitlab.com/skmp/dca3-game/-/releases
- Open artifacts.zip and extract dca3.elf to the folder that was kept open before.
- Close the folder and dreamsdk shell

View File

@@ -79,6 +79,9 @@ OBJS_TEXCONV += \
../vendor/librw/src/d3d-x/d3d.texconv.o \
../vendor/librw/src/d3d-x/d3d8.texconv.o \
../vendor/librw/src/d3d-x/d3d8render.texconv.o \
../vendor/librw/src/bmp.texconv.o \
../vendor/librw/src/png.texconv.o \
../vendor/librw/src/lodepng/lodepng.texconv.o
# Add compilation units to this list to explicity compile them with
# -O3 optimizations, while the rest get the default (-Os) treatment
@@ -316,6 +319,22 @@ TXD_OPTS_NEWS = 512 512
TXD_OPTS_SPLASH1 = 512 512
TXD_OPTS_SPLASH2 = 512 512
TXD_OPTS_SPLASH3 = 512 512
TXD_OPTS_frontend = 512 512 \
--delete-tex "fe_arrows4" \
--delete-tex "fe_arrows2" \
--delete-tex "fe_arrows1" \
--delete-tex "fe_controllersh" \
--delete-tex "fe_controller" \
\
--include-tex assets/dc_ps2d.png dc_ps2d \
--include-tex assets/dc_ps2f.png dc_ps2f \
--include-tex assets/dc_xboxd.png dc_xboxd \
--include-tex assets/dc_xboxf.png dc_xboxf \
--include-tex assets/ps4_d.png ps4_d \
--include-tex assets/ps4_f.png ps4_f \
--include-tex assets/xbox_d.png xbox_d \
--include-tex assets/xbox_f.png xbox_f
DEFAULT_RES = 512
PVR_ENCODER ?= PVRTEX

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
dreamcast/assets/ps4_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
dreamcast/assets/ps4_f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
dreamcast/assets/xbox_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
dreamcast/assets/xbox_f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -3,6 +3,7 @@
#include <cstring>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
@@ -238,6 +239,40 @@ PluginAttach(void)
const char* currentFile;
namespace rw {
Image* readBMP(const char *filename);
Image* readPNG(const char *filename);
}
void InsertImage(RwTexDictionary* texDict, const char* file, const char* texName) {
RwTexture *tex;
RwRaster *raster;
RwInt32 width, height, depth, format;
RwImage *image = rw::readBMP(file);
if (!image) {
image = rw::readPNG(file);
}
assert(image);
RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
raster = RwRasterCreate(width, height, depth, format);
RwRasterSetFromImage(raster, image);
tex = RwTextureCreate(raster);
RwTextureSetName(tex, texName);
RwTextureSetFilterMode(tex, rwFILTERLINEAR);
RwTexDictionaryAddTexture(texDict, tex);
RwImageDestroy(image);
}
std::vector<std::pair<const char*, const char*>> ImagesToAdd;
std::vector<const char*> ImagesToRemove;
bool listTextures = false;
int main(int argc, const char** argv) {
if (argc >= 5) {
int width = atoi(argv[3]);
@@ -247,7 +282,7 @@ int main(int argc, const char** argv) {
if(height >= 16 && height <= 1024)
rw::dc::maxRasterHeight = height;
}
for (int i = 0; i < argc; i++) {
for (int i = 5; i < argc; i++) {
if (argv[i] != nullptr) {
// Downsample Parameter
if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "-D") == 0) {
@@ -271,6 +306,22 @@ int main(int argc, const char** argv) {
}
}
}
if (strcmp(argv[i], "--include-tex") == 0) {
assert(i + 2 < argc);
ImagesToAdd.emplace_back(argv[i+1], argv[i+2]);
i += 2;
}
if (strcmp(argv[i], "--delete-tex") == 0) {
assert(i + 1 < argc);
ImagesToRemove.emplace_back(argv[i+1]);
i += 1;
}
if (strcmp(argv[i], "--list-tex") == 0) {
listTextures = true;
}
}
}
@@ -298,6 +349,31 @@ int main(int argc, const char** argv) {
RwStreamClose(stream, nil);
if (listTextures) {
fprintf(stdout, "Incoming textures:\n");
FORLIST(lnk, texDict->textures) {
auto tex = rw::Texture::fromDict(lnk);
fprintf(stdout, "texture: '%s'\n", tex->name);
}
}
for (auto&& removedTextureName: ImagesToRemove) {
auto removedTexture = texDict->find(removedTextureName);
assert(removedTexture);
texDict->remove(removedTexture);
}
for (auto&& extraTexture: ImagesToAdd) {
InsertImage(texDict, extraTexture.first, extraTexture.second);
}
if (listTextures) {
fprintf(stdout, "Processing textures:\n");
FORLIST(lnk, texDict->textures) {
auto tex = rw::Texture::fromDict(lnk);
fprintf(stdout, "texture: '%s'\n", tex->name);
}
}
auto streamOut = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, argv[2]);
assert(streamOut && "failed to open output");

View File

@@ -3,100 +3,10 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DCA3 - A port of RE3 for Dreamcast</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #121212;
color: #ffffff;
}
.navbar {
background-color: #1f1f1f;
}
.hero {
text-align: center;
padding: 100px 20px;
background-color: #333333;
border-radius: 10px;
}
.features {
margin-top: 50px;
}
.footer {
text-align: center;
padding: 20px;
background-color: #1f1f1f;
margin-top: 20px;
border-radius: 10px;
}
</style>
<title>DCA3 Redirect</title>
<meta http-equiv="refresh" content="5;url=https://dca3.net">
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container">
<a class="navbar-brand" href="#">DCA3</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#features">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#download">Download</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Hero Section -->
<div class="container">
<div class="hero mt-4">
<h1>DCA3</h1>
<p>The first-ever port of Grand Theft Auto III to the SEGA Dreamcast, built from the REGTA reverse engineering project.</p>
<a href="#download" class="btn btn-primary">Download Now</a>
</div>
</div>
<!-- Features Section -->
<div class="container features text-center">
<h2 id="features" class="mb-4">Key Features</h2>
<div class="row">
<div class="col-md-4">
<h3>Faithful Port</h3>
<p>Experience GTA3 as it was meant to be, now on the Dreamcast with okay visuals and sluggish gameplay.</p>
</div>
<div class="col-md-4">
<h3>Open Source</h3>
<p>Built on the REGTA reverse engineering project, ensuring accuracy and community-driven development.</p>
</div>
<div class="col-md-4">
<h3>First Release</h3>
<p>Celebrating our first release with not very much optimized performance and compatibility for Dreamcast hardware.</p>
</div>
</div>
</div>
<!-- Download Section -->
<div class="container text-center mt-5">
<h2 id="download" class="mb-4">Download DCA3</h2>
<p>Get started with the first release of and bring GTA3 to your Dreamcast. You'll need a PC copy of GTA3 to create your .cdi</p>
<a href="#" class="btn btn-success btn-lg">Download Version 1.0</a>
</div>
<!-- Footer -->
<footer class="footer mt-4">
<p>No rights reserved. Made with love for the Dreamcast community.</p>
</footer>
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<p>You will be redirected to <a href="https://dca3.net">dca3.net</a> in 5 seconds.</p>
</body>
</html>
</html>

View File

@@ -140,7 +140,7 @@ CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight)
float blend = association->GetBlendAmount(weight);
if(blend > 0.0f){
auto kfAdt = sequence->GetDeltaTime(frameA);
float t = (kfAdt - remainingTime)/kfAdt;
float t = kfAdt == 0.0f ? 0.0f : (kfAdt - remainingTime)/kfAdt;
if(sequence->type & CAnimBlendSequence::KF_TRANS){
auto kfAt = sequence->GetTranslation(frameA);
auto kfBt = sequence->GetTranslation(frameB);

View File

@@ -3789,6 +3789,10 @@ cAudioManager::ProcessPedOneShots(cPedParams &params)
if (iSound > 60)
iSound = 21;
}
// In some cases the left and right channels have different loop points
// This looks like a data file issue where the left and right channels have different loop points
// This is a hot fix to always have the correct loop point for each channel individually
SET_LOOP_OFFSETS(m_sQueueSample.m_nSampleIndex)
AddSampleToRequestedQueue();
}
}
@@ -6302,7 +6306,7 @@ cPedComments::Process()
{
case LOADING_STATUS_NOT_LOADED:
SampleManager.LoadPedComment(sampleIndex);
#ifdef GTA_PS2 // on PC ped comment is loaded at once
#if defined(GTA_PS2) || defined(RW_DC) // on PC ped comment is loaded at once
break;
#endif
case LOADING_STATUS_LOADED:

View File

@@ -174,6 +174,10 @@ public:
void UpdateEffectsVolume(void);
#ifdef DC_SH4
void UpdateChannelVolume(uint32 nChannel);
#endif
void SetEffectsMasterVolume(uint8 nVolume);
void SetMusicMasterVolume (uint8 nVolume);
void SetEffectsFadeVolume (uint8 nVolume);

View File

@@ -151,7 +151,6 @@ void aica_snd_sfx_freq_vol(int chn, int freq, int vol) {
cSampleManager SampleManager;
bool8 _bSampmanInitialised = FALSE;
bool _dcAudioInitialized = false;
uint32 BankStartOffset[MAX_SFX_BANKS];
char SampleBankDescFilename[] = "sfx/sfx_all.dsc";
@@ -166,8 +165,12 @@ struct sfx_bank {
std::map<int, sfx_bank> sfx_banks;
int nPedSlotSfx[MAX_PEDSFX];
uint32 nPedSlotSfxReqId[MAX_PEDSFX];
uintptr_t nPedSlotSfxAddr[MAX_PEDSFX];
uint8_t nCurrentPedSlot;
file_t fdPedSfx;
volatile uint32 nPedSfxReqReadId = 1;
volatile uint32 nPedSfxReqNextId = 1;
struct WavHeader {
// RIFF Header
@@ -442,23 +445,30 @@ cSampleManager::Initialise(void)
}
});
nPedSfxReqNextId = 1;
nPedSfxReqReadId = 1;
for ( int32 i = 0; i < MAX_PEDSFX; i++ )
{
nPedSlotSfx[i] = -1;
nPedSlotSfxReqId[i] = 0;
nPedSlotSfxAddr[i] = snd_mem_malloc(PED_BLOCKSIZE_ADPCM);
debugf("PedSlot %d buffer: %p\n", i, (void*)nPedSlotSfxAddr[i]);
}
nCurrentPedSlot = 0;
_dcAudioInitialized = true;
fdPedSfx = fs_open(SampleBankDataFilename, O_RDONLY);
assert(fdPedSfx >= 0);
_bSampmanInitialised = true;
return TRUE;
}
void
cSampleManager::Terminate(void)
{
fs_close(fdPedSfx);
}
bool8 cSampleManager::CheckForAnAudioFileOnCD(void)
@@ -474,7 +484,14 @@ char cSampleManager::GetCDAudioDriveLetter(void)
void
cSampleManager::UpdateEffectsVolume(void)
{
// TODO
if(_bSampmanInitialised) {
std::lock_guard<std::mutex> lk(channel_mtx);
for (int i = 0; i < MAXCHANNELS+MAX2DCHANNELS; i++) {
if (channels[i].ch != -1) {
UpdateChannelVolume(i);
}
}
}
}
@@ -637,7 +654,7 @@ cSampleManager::IsPedCommentLoaded(uint32 nComment)
slot += ARRAY_SIZE(nPedSlotSfx);
#endif
if ( nComment == nPedSlotSfx[slot] )
return LOADING_STATUS_LOADED;
return nPedSlotSfxReqId[slot] <= nPedSfxReqReadId ? LOADING_STATUS_LOADED : LOADING_STATUS_LOADING;
}
return LOADING_STATUS_NOT_LOADED;
@@ -698,27 +715,28 @@ cSampleManager::LoadPedComment(uint32 nComment)
assert(m_aSamples[nComment].nByteSize < PED_BLOCKSIZE_ADPCM);
file_t fd = fs_open(SampleBankDataFilename, O_RDONLY);
assert(fd >= 0);
debugf("Loading ped comment %d, offset: %d, size: %d\n", nComment, m_aSamples[nComment].nFileOffset, m_aSamples[nComment].nByteSize);
fs_seek(fd, m_aSamples[nComment].nFileOffset, SEEK_SET);
CdStreamQueueAudioRead(nComment, (void*)nPedSlotSfxAddr[nCurrentPedSlot], m_aSamples[nComment].nByteSize, m_aSamples[nComment].nFileOffset, [](AudioReadCmd* cmd) {
debugf("Loading ped comment %d, offset: %d, size: %d\n", nComment, m_aSamples[nComment].nFileOffset, m_aSamples[nComment].nByteSize);
fs_seek(fdPedSfx, cmd->seek, SEEK_SET);
// TODO: When we can dma directly to AICA, we can use this instead
// fs_read(fd, SPU_BASE_U8 + nPedSlotSfxAddr[nCurrentPedSlot], sizeof(nPedSlotSfxAddr));
// TODO: When we can dma directly to AICA, we can use this instead
// fs_read(fdPedSfx, SPU_BASE_U8 + (uintptr_t)cmd->dest, cmd->size);
void* stagingBuffer = memalign(32, m_aSamples[nComment].nByteSize);
assert(stagingBuffer != 0);
debugf("Allocated %d bytes at %p\n", m_aSamples[nComment].nByteSize, stagingBuffer);
int rs = fs_read(fd, stagingBuffer, m_aSamples[nComment].nByteSize);
debugf("Read %d bytes, expected %d\n", rs, m_aSamples[nComment].nByteSize);
assert(rs == m_aSamples[nComment].nByteSize);
void* stagingBuffer = memalign(32, cmd->size);
assert(stagingBuffer != 0);
debugf("Allocated %d bytes at %p\n", cmd->size, stagingBuffer);
int rs = fs_read(fdPedSfx, stagingBuffer, cmd->size);
debugf("Read %d bytes, expected %d\n", rs, cmd->size);
assert(rs == cmd->size);
fs_close(fd);
spu_memload((uintptr_t)cmd->dest, stagingBuffer, cmd->size);
free(stagingBuffer);
nPedSfxReqReadId = nPedSfxReqReadId + 1;
});
spu_memload(nPedSlotSfxAddr[nCurrentPedSlot], stagingBuffer, m_aSamples[nComment].nByteSize);
free(stagingBuffer);
nPedSlotSfxReqId[nCurrentPedSlot] = ++nPedSfxReqNextId;
nPedSlotSfx[nCurrentPedSlot] = nComment;
if ( ++nCurrentPedSlot >= MAX_PEDSFX )
@@ -839,9 +857,10 @@ cSampleManager::InitialiseChannel(uint32 nChannel, uint32 nSfx, uint8 nBank)
return TRUE;
}
void updateVol(uint32 nChannel) {
void cSampleManager::UpdateChannelVolume(uint32 nChannel) {
auto newVol = channels[nChannel].emittingVol * channels[nChannel].attenuationVol / 255;
newVol = m_nEffectsFadeVolume * newVol * m_nEffectsVolume >> 14;
// newVol = 255;
// printf("updateVol(nChannel: %d) vol: %d, newVol: %d\n", nChannel, channels[nChannel].vol, newVol);
if (channels[nChannel].vol != newVol) {
@@ -864,7 +883,7 @@ cSampleManager::SetChannelVolume(uint32 nChannel, uint32 nVolume)
channels[nChannel].emittingVol = linearlize_volume(nVolume);// nVolume * 255 / MAX_VOLUME;
channels[nChannel].attenuationVol = 255;
updateVol(nChannel);
UpdateChannelVolume(nChannel);
verbosef("SetChannelVolume(nChannel: %d) vol: %d\n", nChannel, nVolume);
}
@@ -1120,7 +1139,8 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
debugf("StartStreamedFile(%d, %d, %d)\n", nFile, nPos, nStream);
uint32_t seek_aligned = 0;
if (nPos) {
uint32 seek_bytes = nPos * streams[nStream].rate / (streams[nStream].stereo ? 1000: 2000);
uint64_t seek_bytes = (uint64_t)nPos * streams[nStream].rate / (streams[nStream].stereo ? 1000: 2000);
assert(seek_bytes <= INT32_MAX);
seek_aligned = seek_bytes & ~(streams[nStream].stereo ? (STREAM_STAGING_READ_SIZE_STEREO-1) : (STREAM_STAGING_READ_SIZE_MONO-1));
}
PreloadStreamedFile(nFile, nStream, seek_aligned);
@@ -1152,7 +1172,9 @@ cSampleManager::GetStreamedFilePosition(uint8 nStream)
ASSERT( nStream < MAX_STREAMS );
int32 rv = 0;
return streams[nStream].played_samples * 1000 / streams[nStream].rate;
int64_t rv64 = (int64_t)streams[nStream].played_samples * 1000 / streams[nStream].rate;
assert(rv64 <= INT32_MAX);
rv = (int32)rv64;
// if(streams[nStream].fd >= 0) {
// rv = fs_tell(streams[nStream].fd);
// }
@@ -1167,6 +1189,7 @@ cSampleManager::SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffect
if (nVolume > MAX_VOLUME)
nVolume = MAX_VOLUME;
nVolume = linearlize_volume(nVolume); //nVolume * 255 / MAX_VOLUME;
nVolume = m_nMusicFadeVolume * nVolume * m_nMusicVolume >> 14;
if (streams[nStream].vol != nVolume || streams[nStream].nPan != nPan) {
streams[nStream].vol = nVolume;
streams[nStream].nPan = nPan;
@@ -1195,7 +1218,10 @@ cSampleManager::GetStreamedFileLength(uint8 nFile)
WavHeader hdr;
assert(fs_read(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
rv = hdr.dataSize * 2000 / hdr.numOfChan / hdr.samplesPerSec;
uint64_t rv64 = (uint64_t)hdr.dataSize * 2000 / hdr.numOfChan / hdr.samplesPerSec;
assert(rv64 <= INT32_MAX);
rv = (int32)rv64;
fs_close(fd);
@@ -1275,9 +1301,17 @@ void cSampleManager::SetChannelEmittingVolume(uint32 nChannel, uint32 nVolume)
if (nVolume > MAX_VOLUME)
nVolume = MAX_VOLUME;
// reduce channel volume when JB.MP3 or S4_BDBD.MP3 playing
if ( MusicManager.GetMusicMode() == MUSICMODE_CUTSCENE
&& MusicManager.GetNextTrack() != STREAMED_SOUND_NEWS_INTRO
&& MusicManager.GetNextTrack() != STREAMED_SOUND_CUTSCENE_SAL4_BDBD )
{
nVolume /= 4;
}
std::lock_guard<std::mutex> lk(channel_mtx);
channels[nChannel].emittingVol = linearlize_volume(nVolume); // nVolume * 255 / MAX_VOLUME;
updateVol(nChannel);
UpdateChannelVolume(nChannel);
}
float calculatePan(float x, float z) {
@@ -1322,7 +1356,7 @@ void cSampleManager::SetChannel3DPosition (uint32 nChannel, float fX, float
channels[nChannel].fY = fY;
channels[nChannel].fZ = fZ;
channels[nChannel].attenuationVol = calculateAttenuation(channels[nChannel].fX, channels[nChannel].fY, channels[nChannel].fZ, channels[nChannel].distMin, channels[nChannel].distMax) * 255;
updateVol(nChannel);
UpdateChannelVolume(nChannel);
}
SetChannelPan(nChannel, calculatePan(-fX, fZ) * 63 + 64);
@@ -1335,7 +1369,7 @@ void cSampleManager::SetChannel3DDistances (uint32 nChannel, float fMax, floa
channels[nChannel].distMin = fMin;
channels[nChannel].distMax = fMax;
channels[nChannel].attenuationVol = calculateAttenuation(channels[nChannel].fX, channels[nChannel].fY, channels[nChannel].fZ, channels[nChannel].distMin, channels[nChannel].distMax) * 255;
updateVol(nChannel);
UpdateChannelVolume(nChannel);
}
#endif

View File

@@ -1721,8 +1721,8 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
return 0;
int attempts;
int model = -1;
int index = CGeneral::GetRandomNumberInRange(0, 50);
for (attempts = 0; attempts < 50; attempts++) {
int index = CGeneral::GetRandomNumberInRange(0, MAXVEHICLESLOADED);
for (attempts = 0; attempts < MAXVEHICLESLOADED; attempts++) {
if (model != -1)
break;
model = CStreaming::ms_vehiclesLoaded[index];

View File

@@ -1,4 +1,5 @@
#pragma once
#include <functional>
#define CDSTREAM_SECTOR_SIZE 2048
@@ -43,7 +44,14 @@ char *CdStreamGetImageName(int32 cd);
void CdStreamRemoveImages(void);
int32 CdStreamGetNumImages(void);
void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek);
struct AudioReadCmd {
void* dest;
int fd;
size_t size;
size_t seek;
std::function<void(AudioReadCmd*)> callback;
};
void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, std::function<void(AudioReadCmd*)> callback = nullptr);
void CdStreamDiscardAudioRead(int fd);
#ifdef FLUSHABLE_STREAMING

View File

@@ -26,12 +26,6 @@
#include "CdStream.h"
#include "rwcore.h"
#include "MemoryMgr.h"
struct AudioReadCmd {
void* dest;
int fd;
size_t size;
size_t seek;
};
#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
@@ -489,8 +483,16 @@ std::vector<AudioReadCmd> pendingAudioReads;
std::mutex pendingAudioReadsMutex;
#endif
// Will replace a previous read request for the same file descriptor
void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek) {
void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, std::function<void(AudioReadCmd*)> callback) {
AudioReadCmd cmd = { pBuffer, fd, bytes, seek};
if (!callback) {
cmd.callback = [](AudioReadCmd* cmd){
lseek(cmd->fd, cmd->seek, SEEK_SET);
read(cmd->fd, cmd->dest, cmd->size);
};
} else {
cmd.callback = callback;
}
{
#if !defined(DC_SH4)
std::lock_guard<std::mutex> lock(pendingAudioReadsMutex);
@@ -514,6 +516,7 @@ void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek) {
sem_post(gCdStreamSema);
}
void CdStreamDiscardAudioRead(int fd) {
#if !defined(DC_SH4)
std::lock_guard<std::mutex> lock(pendingAudioReadsMutex);
@@ -564,8 +567,7 @@ int read_loop(int fd, void* pBuffer, size_t bytes) {
total_read += read_bytes;
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
lseek(cmd.fd, cmd.seek, SEEK_SET);
read(cmd.fd, cmd.dest, cmd.size);
cmd.callback(&cmd);
cmd = CdStreamNextAudioRead();
}
}
@@ -581,8 +583,7 @@ void *CdStreamThread(void *param)
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
lseek(cmd.fd, cmd.seek, SEEK_SET);
read(cmd.fd, cmd.dest, cmd.size);
cmd.callback(&cmd);
cmd = CdStreamNextAudioRead();
}

View File

@@ -2785,22 +2785,22 @@ bool CPad::WeaponJustDown(void)
case 0: //Xbox Mode
if (CPad::GetPad(0)->IsDualAnalog)
{
if (NewState.RightTrigger > 128)
if (NewState.RightTrigger > 128 && !(OldState.RightTrigger > 128))
return true;
}
else
{
if (NewState.RightTrigger > 128)
if (NewState.RightTrigger > 128 && !(OldState.RightTrigger > 128))
return true;
}
case 1: //PS2 Mode
if (CPad::GetPad(0)->IsDualAnalog)
{
return NewState.B;
return NewState.B && !OldState.B;
}
else
{
return NewState.B;
return NewState.B && !OldState.B;
}
}

View File

@@ -83,6 +83,11 @@ CEntity::~CEntity(void)
ResolveReferences();
}
bool
CEntity::IsFence(void) {
return IsObject() && ::IsFence(static_cast<CObject *>(this)->GetModelIndex());
}
void
CEntity::SetModelIndex(uint32 id)
{

View File

@@ -131,6 +131,7 @@ public:
bool IsPed(void) { return m_type == ENTITY_TYPE_PED; }
bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; }
bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; }
bool IsFence(void);
RpAtomic *GetAtomic(void) {
assert(RwObjectGetType(m_rwObject) == rpATOMIC);

View File

@@ -59,7 +59,7 @@ CPhysical::CPhysical(void)
bInfiniteMass = false;
bIsInWater = false;
bHitByTrain = false;
bSkipLineCol = false;
bSkipLineCol = IsFence();
m_fDistanceTravelled = 0.0f;
m_treadable[PATH_CAR] = nil;
@@ -1461,6 +1461,10 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
skipCollision = false;
altcollision = false;
if(A->IsFence() && B->IsFence()) {
skipCollision = true;
A->bSkipLineCol = true;
}
if(B->IsBuilding())
skipCollision = false;
else if(IsStreetLight(A->GetModelIndex()) &&
@@ -1922,12 +1926,12 @@ CPhysical::ProcessCollision(void)
n = NUMSTEPS(0.09f);
step = savedTimeStep / n;
}
}else if(responsecase == COLLRESPONSE_SMALLBOX || responsecase == COLLRESPONSE_FENCEPART){
}else if(responsecase == COLLRESPONSE_SMALLBOX){
if(distSq >= sq(0.15f)){
n = NUMSTEPS(0.15f);
step = savedTimeStep / n;
}
}else{
}else if(responsecase != COLLRESPONSE_FENCEPART){
if(distSq >= sq(0.3f)){
n = NUMSTEPS(0.3f);
step = savedTimeStep / n;

View File

@@ -282,7 +282,7 @@ CMatrix::SetRotate(float xAngle, float yAngle, float zAngle)
void
CMatrix::RotateX(float x)
{
#ifdef DC_SH4
#if 0 && defined(DC_SH4) // this is bugged and does not yield correct results
mat_load(reinterpret_cast<matrix_t *>(this));
mat_rotate_x(x);
mat_store(reinterpret_cast<matrix_t *>(this));
@@ -312,7 +312,7 @@ CMatrix::RotateX(float x)
void
CMatrix::RotateY(float y)
{
#ifdef DC_SH4
#if 0 && defined(DC_SH4) // this is bugged and does not yield correct results
mat_load(reinterpret_cast<matrix_t *>(this));
mat_rotate_y(y);
mat_store(reinterpret_cast<matrix_t *>(this));
@@ -342,7 +342,7 @@ CMatrix::RotateY(float y)
void
CMatrix::RotateZ(float z)
{
#ifdef DC_SH4
#if 0 && defined(DC_SH4) // this is bugged and does not yield correct results
mat_load(reinterpret_cast<matrix_t *>(this));
mat_rotate_z(z);
mat_store(reinterpret_cast<matrix_t *>(this));
@@ -372,7 +372,7 @@ CMatrix::RotateZ(float z)
void
CMatrix::Rotate(float x, float y, float z)
{
#ifdef DC_SH4
#if 0 && defined(DC_SH4) // this is bugged and does not yield correct results
mat_load(reinterpret_cast<matrix_t *>(this));
mat_rotate(x, y, z);
mat_store(reinterpret_cast<matrix_t *>(this));
@@ -404,6 +404,20 @@ CMatrix::Rotate(float x, float y, float z)
float z2 = sZ * sY - (cZ * sX) * cY;
float z3 = cX * cY;
#if !defined(DC_TEXCONV) && !defined(DC_SIM)
this->rx = fipr(x1, y1, z1, 0, rx, ry, rz, 0);
this->ry = fipr(x2, y2, z2, 0, rx, ry, rz, 0);
this->rz = fipr(x3, y3, z3, 0, rx, ry, rz, 0);
this->fx = fipr(x1, y1, z1, 0, ux, uy, uz, 0);
this->fy = fipr(x2, y2, z2, 0, ux, uy, uz, 0);
this->fz = fipr(x3, y3, z3, 0, ux, uy, uz, 0);
this->ux = fipr(x1, y1, z1, 0, ax, ay, az, 0);
this->uy = fipr(x2, y2, z2, 0, ax, ay, az, 0);
this->uz = fipr(x3, y3, z3, 0, ax, ay, az, 0);
this->px = fipr(x1, y1, z1, 0, px, py, pz, 0);
this->py = fipr(x2, y2, z2, 0, px, py, pz, 0);
this->pz = fipr(x3, y3, z3, 0, px, py, pz, 0);
#else
this->rx = x1 * rx + y1 * ry + z1 * rz;
this->ry = x2 * rx + y2 * ry + z2 * rz;
this->rz = x3 * rx + y3 * ry + z3 * rz;
@@ -416,6 +430,7 @@ CMatrix::Rotate(float x, float y, float z)
this->px = x1 * px + y1 * py + z1 * pz;
this->py = x2 * px + y2 * py + z2 * pz;
this->pz = x3 * px + y3 * py + z3 * pz;
#endif
#endif
}

View File

@@ -1479,7 +1479,8 @@ CWaterLevel::AllocateBoatWakeArray()
apGeomArray[geom] = RpGeometryCreate(9*9, 8*8*2, rpGEOMETRYTRISTRIP
| rpGEOMETRYPRELIT
| rpGEOMETRYMODULATEMATERIALCOLOR
| rpGEOMETRYTEXTURED);
| rpGEOMETRYTEXTURED
| rw::Geometry::HAS_TRIANGLES/* RW_DC specific */);
ASSERT(apGeomArray[geom] != nil);
RpTriangle *geomTriangles = RpGeometryGetTriangles(apGeomArray[geom]);

View File

@@ -10,7 +10,7 @@
# include <dc/sound/sound.h>
# endif
extern bool _dcAudioInitialized;
extern bool _bSampmanInitialised;
// ====== STATIC METHODS =====
@@ -86,7 +86,7 @@ void VmuProfiler::run() {
#ifdef DC_SH4
if(auto *dev = maple_enum_type(0, MAPLE_FUNC_MEMCARD);
dev && _dcAudioInitialized && updated_)
dev && _bSampmanInitialised && updated_)
{
pvr_stats_t pvrStats; pvr_get_stats(&pvrStats);
uint32_t sramStats = snd_mem_available();

View File

@@ -126,6 +126,28 @@ void CBulletInfo::Update(void)
}
pPed->InflictDamage(pBullet->m_pSource, pBullet->m_eWeaponType, pBullet->m_nDamage, (ePedPieceTypes)point.pieceB, pPed->GetLocalDirection(pPed->GetPosition() - point.point));
CEventList::RegisterEvent(pPed->m_nPedType == PEDTYPE_COP ? EVENT_SHOOT_COP : EVENT_SHOOT_PED, EVENT_ENTITY_PED, pPed, (CPed*)pBullet->m_pSource, 1000);
if (CGame::nastyGame) {
CVector vecParticleDirection = (point.point - pPed->GetPosition()) * 0.01f;
vecParticleDirection.z = 0.01f;
if (pPed->GetIsOnScreen()) {
for (int j = 0; j < NUM_PED_BLOOD_PARTICLES; j++)
CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point + BLOOD_PARTICLE_OFFSET, vecParticleDirection);
}
if (pPed->GetPedState() == PED_DEAD) {
CAnimBlendAssociation* pAnim;
if (RpAnimBlendClumpGetFirstAssociation(pPed->GetClump(), ASSOC_FRONTAL))
pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR_FRONT, 8.0f);
else
pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR, 8.0f);
if (pAnim) {
pAnim->SetCurrentTime(0.0f);
pAnim->flags |= ASSOC_RUNNING;
pAnim->flags &= ~ASSOC_FADEOUTWHENDONE;
}
}
}
pBullet->m_bInUse = false;
#ifdef SQUEEZE_PERFORMANCE
bulletInfoInUse--;
@@ -136,31 +158,6 @@ void CBulletInfo::Update(void)
bAddSound = false;
}
}
if (CGame::nastyGame) {
CVector vecParticleDirection = (point.point - pPed->GetPosition()) * 0.01f;
vecParticleDirection.z = 0.01f;
if (pPed->GetIsOnScreen()) {
for (int j = 0; j < NUM_PED_BLOOD_PARTICLES; j++)
CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point + BLOOD_PARTICLE_OFFSET, vecParticleDirection);
}
if (pPed->GetPedState() == PED_DEAD) {
CAnimBlendAssociation* pAnim;
if (RpAnimBlendClumpGetFirstAssociation(pPed->GetClump(), ASSOC_FRONTAL))
pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR_FRONT, 8.0f);
else
pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR, 8.0f);
if (pAnim) {
pAnim->SetCurrentTime(0.0f);
pAnim->flags |= ASSOC_RUNNING;
pAnim->flags &= ~ASSOC_FADEOUTWHENDONE;
}
}
pBullet->m_bInUse = false;
#ifdef SQUEEZE_PERFORMANCE
bulletInfoInUse--;
#endif
vecNewPos = point.point;
}
}
else if (pHitEntity->IsVehicle()) {
CVehicle* pVehicle = (CVehicle*)pHitEntity;

View File

@@ -164,8 +164,18 @@ struct alignas(32) pvr_vertex32_ut {
static_assert(sizeof(pvr_vertex16_t) == 32, "pvr_vertex16_t size mismatch");
static_assert(alignof(pvr_vertex16_t) == 32, "pvr_vertex16_t alignof mismatch");
#define MATH_Very_Fast_Invert(x) ({ 1.0f / sqrtf((x) * (x)); })
#define MATH_Fast_Invert(x) ({ (((x) < 0.0f)? -1.0f : 1.0f) * frsqrt((x) * (x)); })
__always_inline float MATH_Fast_Invert(float x) {
bool neg = 0;
if(x < 0.0f)
neg = true;
x = MATH_Very_Fast_Invert(x); // 1.0f / sqrt(x^2)
return (neg)? -x : x;
}
#define logf(...) // printf(__VA_ARGS__)
@@ -221,19 +231,21 @@ static pvr_dr_state_t drState;
frchg
fmov @%[mtx]+, dr0
fldi0 fr12
fldi0 fr13
fmov @%[mtx]+, dr2
fmov @%[mtx]+, dr4
fmov @%[mtx]+, dr6
fmov @%[mtx]+, dr8
fmov @%[mtx]+, dr10
fldi0 fr13
fmov @%[mtx]+, dr4
fldi0 fr3
fmov @%[mtx]+, dr6
fldi0 fr7
fmov @%[mtx]+, dr8
fldi0 fr11
fmov @%[mtx]+, dr10
fmov dr12, dr14
fschg
@@ -305,6 +317,8 @@ void rw_mat_load_4x4(rw::Matrix* mtx) {
#define mat_identity(a)
#define pvr_fog_table_color(a,r,g,b)
#define pvr_fog_table_linear(s,e)
#define pvr_fog_table_exp(d)
#define pvr_fog_table_custom(d)
#endif
#define mat_trans_single3_nomod(x_, y_, z_, x2, y2, z2) do { \
@@ -416,6 +430,66 @@ void leave_oix_() {
#endif
}
void enter_ocr_() {
#if defined(DC_SH4)
auto mask = irq_disable();
dcache_purge_all();
volatile uint32_t * CCN_CCR = (uint32_t *)0xFF00001C;
*CCN_CCR |= (1 << 5); // enable OCR (ORA)
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
irq_restore(mask);
#endif
}
void leave_ocr_() {
#if defined(DC_SH4)
auto mask = irq_disable();
dcache_inval_range(0x92000000, 8192);
dcache_purge_all();
volatile uint32_t * CCN_CCR = (uint32_t *)0xFF00001C;
*CCN_CCR &= ~( 1 << 5); // disable OCR (ORA)
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
irq_restore(mask);
#endif
}
#if defined(DC_SH4)
#define FLUSH_TA_DATA(src) do { __asm__ __volatile__("ocbwb @%0" : : "r" (src) : "memory"); } while(0)
#else
@@ -604,7 +678,7 @@ struct atomic_context_t {
__always_inline void DCE_RenderSubmitVertex(const pvr_vertex_t *v, uint32_t flags) {
auto *sq = reinterpret_cast<uint32_t *>(pvr_dr_target(drState));
auto *src = reinterpret_cast<const uint32_t *>(v);
float sz = MATH_Fast_Invert(v->z);
float sz = MATH_Very_Fast_Invert(v->z);
float sx = v->x * sz;
float sy = v->y * sz;
@@ -631,7 +705,7 @@ __always_inline void DCE_RenderSubmitVertexIM3D(float x, float y, float w,
{
auto *sq = reinterpret_cast<uint32_t *>(pvr_dr_target(drState));
auto *uv32 = reinterpret_cast<const uint32_t *>(uv);
float sz = MATH_Fast_Invert(w);
float sz = MATH_Very_Fast_Invert(w);
float sx = x * sz;
float sy = y * sz;
@@ -663,7 +737,10 @@ void malloc_stats() { }
#define UNIMPL_LOGV(...)
#endif
Camera* rwdcCam;
void beginUpdate(Camera* cam) {
rwdcCam = cam;
float view[16], proj[16];
// View Matrix
@@ -1098,6 +1175,7 @@ static bool doAlphaTest;
static uint8_t fogFuncPvr = PVR_FOG_DISABLE;
static uint32_t fogColor = 0;
static float fogStart = 0.0f;
static uint32 cullModePvr;
static inline unsigned pvrCullMode(uint32_t cullMode) {
@@ -1198,8 +1276,9 @@ setRenderState(int32 state, void *pvalue)
fogFuncPvr = value ? PVR_FOG_TABLE : PVR_FOG_DISABLE;
break;
case FOGCOLOR:
#if !defined(DC_TEXCONV)
// Set fog color when state changes
if(fogColor != value) {
if(fogColor != value || fogStart != RwCameraGetFogDistance(rwdcCam)) {
fogColor = value;
RGBA c;
c.red = value;
@@ -1207,9 +1286,22 @@ setRenderState(int32 state, void *pvalue)
c.blue = value>>16;
c.alpha = value>>24;
pvr_fog_table_color(c.alpha / 255.0f, c.red / 255.0f, c.green / 255.0f, c.blue / 255.0f);
pvr_fog_table_linear(50.0f, 450.0f);
fogStart = RwCameraGetFogDistance(rwdcCam);
float fogEnd = RwCameraGetFarClipPlane(rwdcCam);
float fogIntensity[129];
uint8_t idx = 0;
float startIntensity = (-fogStart) / (fogEnd - fogStart); //interpolate between start and end to get initial intensity
float step = (1.0f - startIntensity) / 129; // we have 129 entries, create a step such that start + (step*129) = 1.0
for(int i = 128; i >= 0; i--) {
fogIntensity[i] = startIntensity + (idx++ * step);
}
pvr_fog_far_depth(fogEnd);
pvr_fog_table_custom(fogIntensity);
}
#endif
break;
// case CULLMODE:
// if(rwStateCache.cullmode != value){
// rwStateCache.cullmode = value;
@@ -1409,7 +1501,7 @@ void im2DRenderPrimitive(PrimitiveType primType, void *vertices, int32_t numVert
pvrVert->flags = flags;
pvrVert->x = gtaVert.x;
pvrVert->y = gtaVert.y;
pvrVert->z = MATH_Fast_Invert(gtaVert.w); // this is perfect for almost every case...
pvrVert->z = MATH_Very_Fast_Invert(gtaVert.w); // this is perfect for almost every case...
pvrVert->u = gtaVert.u;
pvrVert->v = gtaVert.v;
pvrVert->argb = (gtaVert.a << 24) |
@@ -2342,6 +2434,36 @@ __attribute__ ((noinline)) void submitMeshlet(uint8_t* OCR, const int8_t* indexD
} while(--indexCount);
}
template<bool textured>
__attribute__ ((noinline)) void submitMeshletFallback(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) {
struct SQBUF {
union {
uint32_t flags;
uint64_t data[4];
uint8_t data8[32];
};
};
SQBUF* sq = (SQBUF*)pvr_dr_target(drState);
static_assert(sizeof(SQBUF) == 32);
do {
auto idx = *indexData++;
auto flags = idx & 0x80 ? PVR_CMD_VERTEX_EOL : PVR_CMD_VERTEX;
auto lookup_idx = idx & 0x7F;
auto src = (SQBUF*)(OCR + lookup_idx * 64);
src[0].flags = flags;
*sq = src[0];
pvr_dr_commit(sq);
if (textured) {
*sq = src[1];
pvr_dr_commit(sq);
}
} while(--indexCount);
}
#if defined(DC_SH4)
template<>
@@ -2421,7 +2543,7 @@ __attribute__ ((noinline)) void submitMeshlet<true>(uint8_t* OCR, const int8_t*
// 8 kb in total
#if defined(DC_SH4)
uint8_t* OCR_SPACE = (uint8_t*)0x92000000;
uint8_t* OCR_SPACE;
#else
uint8_t OCR_SPACE[32 * 256] __attribute__((aligned(32)));
#endif
@@ -2652,6 +2774,159 @@ __attribute__ ((noinline)) void clipAndsubmitMeshlet(uint8_t* vertexData, const
}
};
} while(indexCount != 0);
#undef FILLVERT
#undef SUBMIT_VTX
#undef SUBMIT_INTERPOLATE
}
template<bool textured>
__attribute__ ((noinline)) void clipAndsubmitMeshletFallback(uint8_t* vertexData, const int8_t* indexData, uint32_t indexCount) {
struct SQBUF {
union {
uint32_t flags;
uint64_t data[4];
uint8_t data8[32];
};
};
static_assert(sizeof(SQBUF) == 32);
SQBUF* sq = (SQBUF*)pvr_dr_target(drState);
constexpr int8_t VERTEX = 0;
constexpr int8_t VERTEX_EOL = 0x80;
#define FILLVERT(n) \
do { \
auto idx = *indexData++; \
auto local_idx = idx & 0x7f; \
eol_now = idx & 0x80; \
auto local_ptr = (vertexData + local_idx * 64); \
vpp[n] = local_ptr; \
auto v = (const pvr_vertex64_t*)local_ptr; \
vismask >>= 1; \
if((textured?v->tex_z:v->o_b) >= -v->o_g) vismask |= 0b100; \
indexCount--; \
currentCount++; \
} while(0)
#define SUBMIT_VTX(vid, eolf) \
do { \
auto src = (SQBUF*) vpp[vid]; \
src[0].flags = eolf ? PVR_CMD_VERTEX_EOL : PVR_CMD_VERTEX; \
*sq = src[0]; \
pvr_dr_commit(sq); \
if (textured) { \
*sq = src[1]; \
pvr_dr_commit(sq); \
} \
} while(0)
#define SUBMIT_INTERPOLATE(vid1, vid2, eolf) \
do { \
sq = (SQBUF*)interpolateAndSubmit<textured>(sq, vpp[vid1], vpp[vid2], eolf ? PVR_CMD_VERTEX_EOL : PVR_CMD_VERTEX); \
} while(0)
uint32_t vismask = 0;
uint8_t* vpp[3];
int8_t eol = 0;
int8_t eol_now = 0;
do {
uint32_t currentCount = -1;
FILLVERT(0);
FILLVERT(1);
FILLVERT(2);
if (vismask & 1) {
SUBMIT_VTX(0, VERTEX);
if (vismask & 2) {
// both first verts visible
SUBMIT_VTX(1, VERTEX);
} else {
// 0 visible, 1 hidden
SUBMIT_INTERPOLATE(0, 1, VERTEX);
}
} else if (vismask & 2) {
// 0 hidden, 1 visible
SUBMIT_INTERPOLATE(1, 0, VERTEX);
SUBMIT_VTX(1, VERTEX);
}
eol = 0;
// each remaining vertex of the strip
while(!eol) {
// "ring buffery" indices
uint8_t vertZeroIdx = (currentCount - 2) % 3;
uint8_t vertOneIdx = (currentCount - 1) % 3;
uint8_t vertTwoIdx = currentCount % 3;
//dcache_pref_block(&vph[vertZeroIdx]); not sure where to put this honestly -jaxyn
eol = eol_now;
if (!vismask) {
if (!eol) {
// "ring buffery" filling
FILLVERT(vertZeroIdx);
}
continue;
}
if (vismask == 7) {
// all visible
SUBMIT_VTX(vertTwoIdx, eol);
if (!eol) {
// "ring buffery" filling
FILLVERT(vertZeroIdx);
}
continue;
}
switch (vismask) {
case 1: // 0 visible, 1 and 2 hidden
// pause strip
SUBMIT_INTERPOLATE(vertZeroIdx, vertTwoIdx, VERTEX_EOL);
break;
case 3: // 0 and 1 visible, 2 hidden
SUBMIT_INTERPOLATE(vertZeroIdx, vertTwoIdx, VERTEX);
SUBMIT_VTX(vertOneIdx, VERTEX);
case 2: // 0 hidden, 1 visible, 2 hidden
SUBMIT_INTERPOLATE(vertOneIdx, vertTwoIdx, eol);
break;
case 4: // 0 and 1 hidden, 2 visible
SUBMIT_INTERPOLATE(vertTwoIdx, vertZeroIdx, VERTEX);
if (currentCount & 0x01) { // flip directionality
case 5: // 0 visible, 1 hidden, 2 visible
SUBMIT_VTX(vertTwoIdx, VERTEX);
}
SUBMIT_INTERPOLATE(vertTwoIdx, vertOneIdx, VERTEX);
SUBMIT_VTX(vertTwoIdx, eol);
break;
case 6: // 0 hidden, 1 and 2 visible
SUBMIT_INTERPOLATE(vertTwoIdx, vertZeroIdx, VERTEX);
SUBMIT_VTX(vertOneIdx, VERTEX);
SUBMIT_VTX(vertTwoIdx, eol);
break;
default:
break;
}
if (!eol) {
// "ring buffery" filling
FILLVERT(vertZeroIdx);
}
};
} while(indexCount != 0);
#undef FILLVERT
#undef SUBMIT_VTX
#undef SUBMIT_INTERPOLATE
}
@@ -2918,16 +3193,26 @@ static constexpr void (*tnlMeshletDiffuseColorSelector[8])(uint8_t* dstCol, cons
&tnlMeshletDiffuseColor<4, true>,
};
static constexpr void (*submitMeshletSelector[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
static void (*submitMeshletSelector[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
&submitMeshlet<false>,
&submitMeshlet<true>,
};
static constexpr void (*clipAndsubmitMeshletSelector[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
static void (*submitMeshletSelectorFallback[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
&submitMeshletFallback<false>,
&submitMeshletFallback<true>,
};
static void (*clipAndsubmitMeshletSelector[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
&clipAndsubmitMeshlet<false>,
&clipAndsubmitMeshlet<true>,
};
static void (*clipAndsubmitMeshletSelectorFallback[2])(uint8_t* OCR, const int8_t* indexData, uint32_t indexCount) = {
&clipAndsubmitMeshletFallback<false>,
&clipAndsubmitMeshletFallback<true>,
};
static constexpr void(*tnlMeshletSkinVerticesSelector[4])(uint8_t *OCR, uint8_t *OCR_normal, const uint8_t* vertex, const uint8_t* normals, const uint8_t* skinWeights, const uint8_t* skinIndexes, int vertexCount, int vertexSize, Matrix* skinMatrices) = {
&tnlMeshletSkinVertices<false, false>,
&tnlMeshletSkinVertices<true , false>,
@@ -3294,6 +3579,8 @@ void defaultRenderCB(ObjPipeline *pipe, Atomic *atomic) {
for (int16_t n = 0; n < numMeshes; n++) {
bool doBlend = meshes[n].material->color.alpha != 255; // TODO: check all vertexes for alpha?
bool doBlendMaterial = doBlend;
bool textured = geo->numTexCoordSets && meshes[n].material->texture;
if (textured) {
doBlend |= Raster::formatHasAlpha(meshes[n].material->texture->raster->format);
@@ -3343,7 +3630,7 @@ void defaultRenderCB(ObjPipeline *pipe, Atomic *atomic) {
pvr_poly_cxt_t cxt;
int pvrList;
if (doBlend || isMatFX) {
if (doAlphaTest) {
if (doAlphaTest && !doBlendMaterial) {
pvrList = PVR_LIST_PT_POLY;
} else {
pvrList = PVR_LIST_TR_POLY;
@@ -3709,7 +3996,7 @@ void defaultRenderCB(ObjPipeline *pipe, Atomic *atomic) {
};
if (doBlend || isMatFX) {
if (doAlphaTest) {
if (doAlphaTest && !doBlendMaterial) {
ptCallbacks.emplace_back(std::move(renderCB));
} else {
blendCallbacks.emplace_back(std::move(renderCB));
@@ -4360,6 +4647,34 @@ ObjPipeline* makeDefaultPipeline(void)
static void*
driverOpen(void *o, int32, int32)
{
#if defined(DC_SH4)
OCR_SPACE = (uint8_t*)0x92000000;
bool has_oix = true;
enter_oix();
*(volatile uint8_t*)OCR_SPACE = 1;
if (*(volatile uint8_t*)OCR_SPACE != 1) {
has_oix = false;
}
leave_oix();
if (!has_oix) {
dbglog(DBG_CRITICAL, "You appear to be using an emulator that does not support OIX. Attempting fallback to OCR\n");
OCR_SPACE = (uint8_t*)0x7c001000;
enter_oix = (void(*)())(((uintptr_t)&enter_ocr_) - 0x8c000000 + 0xAc000000);
leave_oix = (void(*)())(((uintptr_t)&leave_ocr_) - 0x8c000000 + 0xAc000000);
for (size_t i = 0; i < ARRAY_SIZE(submitMeshletSelector); i++) {
submitMeshletSelector[i] = submitMeshletSelectorFallback[i];
}
for (size_t i = 0; i < ARRAY_SIZE(clipAndsubmitMeshletSelector); i++) {
clipAndsubmitMeshletSelector[i] = clipAndsubmitMeshletSelectorFallback[i];
}
}
#endif
pvr_init(&pvr_params);
fake_tex = pvr_mem_malloc(sizeof(fake_tex_data));