diff --git a/.appveyor/AfterBuild.macos.sh b/.appveyor/AfterBuild.macos.sh new file mode 100755 index 000000000..7907091a5 --- /dev/null +++ b/.appveyor/AfterBuild.macos.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -ex + +cd "$APPVEYOR_BUILD_FOLDER/src_rebuild" + +for renderer in opengl vulkan +do + for config in Debug Release Release_dev + do + cd "$APPVEYOR_BUILD_FOLDER/src_rebuild/bin/macos_arm64_${renderer}/${config}" + cp -R "$APPVEYOR_BUILD_FOLDER/data/"* ./ + tar -czf "REDRIVER2_macOS_arm64_${renderer}_${config}.tar.gz" * + mv "REDRIVER2_macOS_arm64_${renderer}_${config}.tar.gz" "$APPVEYOR_BUILD_FOLDER/src_rebuild/bin/${config}/" + done +done diff --git a/.appveyor/AfterBuild.sh b/.appveyor/AfterBuild.sh index 942b83fc5..cf9fc58f7 100755 --- a/.appveyor/AfterBuild.sh +++ b/.appveyor/AfterBuild.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash set -ex +if [ "$(uname -s)" = "Darwin" ]; then + exec "${APPVEYOR_BUILD_FOLDER}/.appveyor/AfterBuild.macos.sh" +fi + for config in debug release release_dev do cd "${APPVEYOR_BUILD_FOLDER}/src_rebuild/bin/${config^}" diff --git a/.appveyor/Build.macos.sh b/.appveyor/Build.macos.sh new file mode 100755 index 000000000..5f251b112 --- /dev/null +++ b/.appveyor/Build.macos.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -ex + +cd "$APPVEYOR_BUILD_FOLDER/src_rebuild" + +# Strip any cached project files between renderer variants so premake +# regenerates the makefile with the right --renderer option. +rm -rf project_gmake_macosx + +NCPU=$(sysctl -n hw.ncpu) + +# ---------- OpenGL build (default) ---------- +premake5 gmake +pushd project_gmake_macosx > /dev/null +for config in debug_arm64 release_arm64 release_dev_arm64 +do + make config=$config -j$NCPU +done +popd > /dev/null + +# Stash the OpenGL artifacts before regenerating for Vulkan. +mkdir -p bin/macos_arm64_opengl +cp -R bin/Debug bin/Release bin/Release_dev bin/macos_arm64_opengl/ + +# ---------- Vulkan / MoltenVK build ---------- +rm -rf project_gmake_macosx +premake5 --renderer=vulkan gmake +pushd project_gmake_macosx > /dev/null +for config in debug_arm64 release_arm64 release_dev_arm64 +do + make config=$config -j$NCPU +done +popd > /dev/null + +mkdir -p bin/macos_arm64_vulkan +cp -R bin/Debug bin/Release bin/Release_dev bin/macos_arm64_vulkan/ diff --git a/.appveyor/Build.sh b/.appveyor/Build.sh index a0efff856..d3e2df0af 100755 --- a/.appveyor/Build.sh +++ b/.appveyor/Build.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash set -ex +if [ "$(uname -s)" = "Darwin" ]; then + exec "${APPVEYOR_BUILD_FOLDER}/.appveyor/Build.macos.sh" +fi + # Configure cd "$APPVEYOR_BUILD_FOLDER/src_rebuild" ./premake5 gmake2 diff --git a/.appveyor/Install.macos.sh b/.appveyor/Install.macos.sh new file mode 100755 index 000000000..780f96ab4 --- /dev/null +++ b/.appveyor/Install.macos.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -ex + +# AppVeyor's macOS image ships Homebrew but not the package set we need. +# This installs everything required to build both renderer backends — +# OpenGL (default) and Vulkan/MoltenVK (opt-in via --renderer=vulkan). + +brew update + +# Common deps for both backends +brew install premake sdl2 jpeg openal-soft + +# Vulkan backend deps. shaderc is statically linked from libshaderc_combined.a +# at link time so the produced binary doesn't need a runtime SPIR-V compiler. +brew install vulkan-headers vulkan-loader molten-vk shaderc diff --git a/.appveyor/Install.sh b/.appveyor/Install.sh index 7ca639f0b..929f6427f 100755 --- a/.appveyor/Install.sh +++ b/.appveyor/Install.sh @@ -1,6 +1,13 @@ #!/usr/bin/env bash set -ex +# AppVeyor runs `sh:` steps on every non-Windows image. Delegate to a +# macOS-specific script when the worker is macOS so the Linux-only +# apt/flatpak path below doesn't try to run. +if [ "$(uname -s)" = "Darwin" ]; then + exec "${APPVEYOR_BUILD_FOLDER}/.appveyor/Install.macos.sh" +fi + cd "$APPVEYOR_BUILD_FOLDER/src_rebuild" # Download premake5 diff --git a/.gitignore b/.gitignore index ed742dba2..55ab642c9 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,15 @@ src_rebuild/obj/* src_rebuild/project_* src_rebuild/*.make src_rebuild/Makefile + +# Driver 2 game data (CD images + extracted FMV/XA — too large for git) +data/install/*.bin +data/install/*.cue +data/DRIVER2/FMV/ +data/DRIVER2/XA/ +data/REDRIVER2.log + +# Build outputs +src_rebuild/bin/ +src_rebuild/obj/ +src_rebuild/project_gmake_*/ diff --git a/BUILD_MACOS.md b/BUILD_MACOS.md new file mode 100644 index 000000000..bd3d10de6 --- /dev/null +++ b/BUILD_MACOS.md @@ -0,0 +1,167 @@ +# REDRIVER2 — Building on macOS Apple Silicon + +Build port of REDRIVER2 for macOS arm64 (Apple Silicon — M1/M2/M3/M4). +Also works on Intel macs (x86_64) via the same automatic prefix +detection. + +## Prerequisites + +1. **Xcode Command Line Tools** + + ```bash + xcode-select --install + ``` + +2. **Homebrew** — https://brew.sh + +3. **Dependencies via Homebrew** + + OpenGL build (default): + + ```bash + brew install premake sdl2 jpeg openal-soft + ``` + + Vulkan / MoltenVK build (optional): + + ```bash + brew install premake sdl2 jpeg openal-soft \ + vulkan-headers vulkan-loader molten-vk shaderc + ``` + + On Apple Silicon brew installs under `/opt/homebrew`; on Intel macs + it's `/usr/local`. `premake5.lua` detects either automatically. + +## Build + +```bash +git clone https://github.com/OpenDriver2/REDRIVER2.git +cd REDRIVER2 +git submodule update --init --recursive +cd src_rebuild + +# OpenGL backend (default) +premake5 gmake + +# OR: Vulkan / MoltenVK backend +premake5 --renderer=vulkan gmake + +cd project_gmake_macosx + +# Apple Silicon +make config=release_arm64 -j$(sysctl -n hw.ncpu) + +# Intel +make config=release_x64 -j$(sysctl -n hw.ncpu) +``` + +Available configurations: `debug_arm64`, `release_arm64`, +`release_dev_arm64` (and the matching `x64` variants). + +Final binary: `src_rebuild/bin/Release/REDRIVER2`. + +## Running the game + +REDRIVER2 needs the original Driver 2 (PSX) data files alongside the +executable. See the +[installation wiki](https://github.com/OpenDriver2/REDRIVER2/wiki/Installation-instructions) +for the asset extraction steps. + +## Optional environment variables + +To point at non-Homebrew dependency installs: + +```bash +export MAC_SDL2_DIR=/path/to/sdl2 +export MAC_OPENAL_DIR=/path/to/openal-soft +export MAC_JPEG_DIR=/path/to/jpeg +# Vulkan-only: +export MAC_VULKAN_HEADERS=/path/to/vulkan-headers +export MAC_VULKAN_LOADER=/path/to/vulkan-loader +export MAC_MOLTENVK=/path/to/molten-vk +``` + +## What changed for macOS arm64 + +Summary of the deltas vs upstream: + +### Build system +- `src_rebuild/premake5.lua` — `system:macosx` filter with `x64` and + `arm64` platforms, Homebrew `includedirs`/`libdirs`, framework links + (`Cocoa`, `OpenGL` or `Metal`+`QuartzCore`+`IOSurface`+`vulkan`), + rpaths for the brew dylibs. Adds the `--renderer={opengl|vulkan}` + option that gates the OpenGL vs Vulkan source files. +- `src_rebuild/premake5_psycross.lua` — equivalent macOS filter on the + static-lib side, plus `removefiles` to switch `PsyX_render.cpp` ↔ + `PsyX_render_vk.cpp` based on the renderer option. +- `src_rebuild/premake_modules/usage/usage.lua` — guard so the custom + `uses` API doesn't collide with the one premake5 ≥ beta8 ships in + core. + +### arm64 / 64-bit portability +- `src_rebuild/Game/driver2.h` — `trap()` now uses `__builtin_trap()` + instead of the x86-only `__asm__("int3")`. +- `src_rebuild/PsyCross/include/psx/libgpu.h` — `P_LEN = 3` on arm64 + (same value used for x86_64), so the prim-tag struct lays out + identically across all 64-bit targets. +- `src_rebuild/PsyCross/include/psx/types.h` — on LP64 (macOS arm64/x64, + Linux x64) `u_long` and `ulong` map to `uint32_t` so the PSX 32-bit + semantics are preserved. Pre-defines `_U_LONG`/`_U_INT`/`_U_CHAR`/ + `_U_SHORT` on macOS to stop `` from re-declaring those + types as 64-bit. +- `premake5.lua` adds a forced `-include` of `psx/types.h` on the macOS + filter so those guards are seen before any system header. + +### macOS-specific headers +- `` (non-existent on macOS) replaced by `` with a + guard in: + - `src_rebuild/PsyCross/src/psx/LIBCD.C` + - `src_rebuild/utils/fs.cpp` + - `src_rebuild/utils/audio_source/snd_wav_cache.cpp` + - `src_rebuild/utils/targa.cpp` + - `src_rebuild/Game/dr2locale.c` + - `src_rebuild/tools/font_tool/font_tool_main.cpp` +- `LIBCD.C` and `utils/fs.{cpp,h}` — `__unix__` guards extended to + include `__APPLE__` (macOS doesn't define `__unix__`). + +### Pointer→int casts on LP64 +Pointers are 64-bit on arm64/x86_64; `(int)ptr` loses information and +clang treats that as an error. Routed through `intptr_t` / +`u_intptr`: +- `src_rebuild/Game/dr2locale.h` — `GET_GAME_TXT`/`GET_MISSION_TXT` +- `src_rebuild/Game/C/civ_ai.c` — `Random2((int)straight)` +- `src_rebuild/Game/C/dr2roads.c` — `(int)plane & 3` +- `src_rebuild/Game/C/draw.c` — `primtab`/`primptr` checks +- `src_rebuild/Game/C/event.c` — `FIXEDH((int)ev->node * RSIN(...))` +- `src_rebuild/Game/C/glaunch.c` — `(int)param` in several callbacks +- `src_rebuild/Game/C/mission.c` — `(u_int)((char*)...)` + +### Stricter C++ checks +- `src_rebuild/PsyCross/src/psx/LIBETC.C` — pointer→int cast routed + via `intptr_t` (`ResetCallback`/`VSyncCallback`). +- `src_rebuild/PsyCross/src/psx/LIBGPU.C` — explicit `(DR_TPAGE*)opri` + cast. +- `src_rebuild/PsyCross/src/psx/LIBSPU.C` — added `psx/libetc.h` + include for `ResetCallback()`. + +### Missing GTE function +- `src_rebuild/Game/C/targets.c:327` — `RotTransPers()` is declared but + not defined inside PsyCross. Replaced with the equivalent + `gte_RotTransPers()` macro and the otz output captured locally. + +## Status + +- ✅ Clean build on arm64 (Apple Silicon). +- ✅ Native Mach-O arm64 binary (`file` confirms `arm64`). +- ⚠️ macOS OpenGL has been *deprecated* since 10.14 but the legacy + driver still works up to OpenGL 4.1. PsyCross uses GL 2.x so it + runs, though Apple's GL-on-Metal compatibility layer has subtly + different sync behaviour and produces flicker / dropped primitives + on some scenes. +- ⚠️ The Vulkan / MoltenVK backend (opt-in via `--renderer=vulkan`) + side-steps the GL-on-Metal issues. Currently a work-in-progress — + Driver 2 main menu, HUD and 3D world geometry render; some passes + (blend modes, stencil, scissor, framebuffer-back-to-VRAM) are still + in flight. +- ⚠️ A full playtest hasn't been run end-to-end — the game requires + the original Driver 2 assets to launch. diff --git a/README.md b/README.md index 2349b5e86..8d08b1363 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,4 @@ See [Contributing to project](https://github.com/OpenDriver2/REDRIVER2/wiki/Cont - **Gh0stBlade** - HLE Emulator code used as a base for Psy-Cross [(link)](https://github.com/TOMB5/TOMB5/tree/master/EMULATOR) - **Ben Lincoln** - [This Dust Remembers What It Once Was](https://www.beneaththewaves.net/Software/This_Dust_Remembers_What_It_Once_Was.html) (*TDR*) - **Stohrendorf** - [Symdump](https://github.com/stohrendorf/symdump) utility +- **ebellumat** - macOS Apple Silicon (arm64) port, Vulkan / MoltenVK backend diff --git a/appveyor.yml b/appveyor.yml index 876327b53..534632bcb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,6 +10,7 @@ skip_tags: true image: - Visual Studio 2019 - Ubuntu2004 +- macos-sonoma environment: data_folder: '%APPVEYOR_BUILD_FOLDER%\data' @@ -50,6 +51,9 @@ artifacts: - path: src_rebuild\bin\*\*.tar.gz name: Linux Binaries - + - path: io.github.opendriver2.Redriver2.flatpak name: Linux Flatpak + + - path: src_rebuild/bin/*/REDRIVER2_macOS_arm64_*.tar.gz + name: macOS Binaries diff --git a/data/config.ini b/data/config.ini index 1ae3f6a91..31f4bb77e 100644 --- a/data/config.ini +++ b/data/config.ini @@ -81,7 +81,7 @@ pad1device=-1 # player 1 controller device; -1 for automatic assignment pad2device=-1 # player 2 controller device; -1 for automatic assignment [render] -windowWidth=1280 +windowWidth=960 windowHeight=720 fullscreen=0 # enable full screen mode; it takes screen resolution pgxpTextureMapping=1 @@ -97,7 +97,7 @@ fieldOfView=256 # 128..384, 256 is default disableChicagoBridges=0 # Experimental: also activate AI roads freeCamera=1 # Press F7 in game to enable fastLoadingScreens=1 -widescreenOverlays=1 # set 1 to see map, bars and stats aligned to screen corners +widescreenOverlays=0 # set 1 to see map, bars and stats aligned to screen corners driver1music=0 # put Driver 1's MUSIC.BIN as D1MUSIC.BIN to DRIVER2\SOUND folder overrideContent=0 # this enables texture and car model modding userChases=RacingFreak,Snoopi,Olanov,Vortex,Fireboyd78 \ No newline at end of file diff --git a/src_rebuild/Game/ASM/rndrasm.c b/src_rebuild/Game/ASM/rndrasm.c index 3ed7af1ec..3db61a618 100644 --- a/src_rebuild/Game/ASM/rndrasm.c +++ b/src_rebuild/Game/ASM/rndrasm.c @@ -1,9 +1,34 @@ #include "driver2.h" #include "C/camera.h" #include "C/draw.h" +#include "C/cell.h" #define FRUSTUM_THRESHOLD (-80) +#ifndef PSX +static int FixedDot(const MATRIX& matrix, int row, int vx, int vy, int vz) +{ + return (int)(((long long)matrix.m[row][0] * vx + + (long long)matrix.m[row][1] * vy + + (long long)matrix.m[row][2] * vz) >> ONE_BITS); +} + +static void ApplyMatrixFull(const MATRIX& matrix, VECTOR* out, int vx, int vy, int vz) +{ + out->vx = FixedDot(matrix, 0, vx, vy, vz); + out->vy = FixedDot(matrix, 1, vx, vy, vz); + out->vz = FixedDot(matrix, 2, vx, vy, vz); + out->pad = 0; +} + +static void ApplyMatrixFullNoPad(const MATRIX& matrix, VECTOR_NOPAD* out, int vx, int vy, int vz) +{ + out->vx = FixedDot(matrix, 0, vx, vy, vz); + out->vy = FixedDot(matrix, 1, vx, vy, vz); + out->vz = FixedDot(matrix, 2, vx, vy, vz); +} +#endif + // [D] [T] void SetCameraVector(void) { @@ -19,13 +44,7 @@ void Apply_Inv_CameraMatrix(VECTOR* v) gte_stlvl(v); #else VECTOR local = *v; - MATRIX& lc = inv_camera_matrix; - //gte_ReadColorMatrix(&lc); // in general this is a inv_camera_matrix - - // lcir is limited to short vector values so we do this instead - v->vx = FIXED(lc.m[0][0] * local.vx + lc.m[0][1] * local.vy + lc.m[0][2] * local.vz); - v->vy = FIXED(lc.m[1][0] * local.vx + lc.m[1][1] * local.vy + lc.m[1][2] * local.vz); - v->vz = FIXED(lc.m[2][0] * local.vx + lc.m[2][1] * local.vy + lc.m[2][2] * local.vz); + ApplyMatrixFull(inv_camera_matrix, v, local.vx, local.vy, local.vz); #endif } @@ -33,23 +52,17 @@ void Apply_Inv_CameraMatrix(VECTOR* v) int Apply_InvCameraMatrixSetTrans(VECTOR_NOPAD* pos) { VECTOR vfc, vec; - SVECTOR local; gte_stfc(&vfc); +#ifdef PSX + SVECTOR local; VecSubtract(&local, pos, &vfc); -#ifdef PSX gte_ldsv(&local); gte_lcir(); gte_stlvl(&vec); #else - MATRIX& lc = inv_camera_matrix; - //gte_ReadColorMatrix(&lc); // in general this is a inv_camera_matrix - - // lcir is limited to short vector values so we do this instead - vec.vx = FIXED(lc.m[0][0] * local.vx + lc.m[0][1] * local.vy + lc.m[0][2] * local.vz); - vec.vy = FIXED(lc.m[1][0] * local.vx + lc.m[1][1] * local.vy + lc.m[1][2] * local.vz); - vec.vz = FIXED(lc.m[2][0] * local.vx + lc.m[2][1] * local.vy + lc.m[2][2] * local.vz); + ApplyMatrixFull(inv_camera_matrix, &vec, pos->vx - vfc.vx, pos->vy - vfc.vy, pos->vz - vfc.vz); #endif gte_SetTransVector(&vec); @@ -63,24 +76,17 @@ int Apply_InvCameraMatrixSetTrans(VECTOR_NOPAD* pos) int Apply_InvCameraMatrixAndSetMatrix(VECTOR_NOPAD* pos, MATRIX2* mtx) { VECTOR vfc, vec; - SVECTOR local; gte_stfc(&vfc); +#ifdef PSX + SVECTOR local; VecSubtract(&local, pos, &vfc); -#ifdef PSX gte_ldsv(&local); gte_lcir(); gte_stlvl(&vec); #else - - MATRIX& lc = inv_camera_matrix; - //gte_ReadColorMatrix(&lc); // in general this is a inv_camera_matrix - - // lcir is limited to short vector values so we do this instead - vec.vx = FIXED(lc.m[0][0] * local.vx + lc.m[0][1] * local.vy + lc.m[0][2] * local.vz); - vec.vy = FIXED(lc.m[1][0] * local.vx + lc.m[1][1] * local.vy + lc.m[1][2] * local.vz); - vec.vz = FIXED(lc.m[2][0] * local.vx + lc.m[2][1] * local.vy + lc.m[2][2] * local.vz); + ApplyMatrixFull(inv_camera_matrix, &vec, pos->vx - vfc.vx, pos->vy - vfc.vy, pos->vz - vfc.vz); #endif gte_SetRotMatrix(mtx); @@ -93,17 +99,27 @@ int Apply_InvCameraMatrixAndSetMatrix(VECTOR_NOPAD* pos, MATRIX2* mtx) } // [D] [T] -int FrustrumCheck16(PACKED_CELL_OBJECT* pcop, int bounding_sphere) +int FrustrumCheck16(PACKED_CELL_OBJECT* pcop, XZPAIR* near, int bounding_sphere) { VECTOR_NOPAD result; SVECTOR local; int ang; + +#ifdef PSX VecSubtract(&local, &pcop->pos, &camera_position); gte_ldsv(&local); gte_llir(); gte_stlvnl(&result); +#else + CELL_OBJECT cellObject; + QuickUnpackCellObject(pcop, near, &cellObject); + ApplyMatrixFullNoPad(frustrum_matrix, &result, + cellObject.pos.vx - camera_position.vx, + cellObject.pos.vy - camera_position.vy, + cellObject.pos.vz - camera_position.vz); +#endif ang = FRUSTUM_THRESHOLD - bounding_sphere; @@ -119,14 +135,22 @@ int FrustrumCheck16(PACKED_CELL_OBJECT* pcop, int bounding_sphere) int FrustrumCheck(VECTOR* pos, int bounding_sphere) { VECTOR_NOPAD result; - SVECTOR local; int ang; + +#ifdef PSX + SVECTOR local; VecSubtract(&local, pos, &camera_position); gte_ldsv(&local); gte_llir(); gte_stlvnl(&result); +#else + ApplyMatrixFullNoPad(frustrum_matrix, &result, + pos->vx - camera_position.vx, + pos->vy - camera_position.vy, + pos->vz - camera_position.vz); +#endif ang = FRUSTUM_THRESHOLD - bounding_sphere; diff --git a/src_rebuild/Game/ASM/rndrasm.h b/src_rebuild/Game/ASM/rndrasm.h index 4b358453a..94f24c862 100644 --- a/src_rebuild/Game/ASM/rndrasm.h +++ b/src_rebuild/Game/ASM/rndrasm.h @@ -8,7 +8,7 @@ extern void Apply_Inv_CameraMatrix(VECTOR* v); // 0x0001BCFC extern int Apply_InvCameraMatrixSetTrans(VECTOR_NOPAD* pos); extern int Apply_InvCameraMatrixAndSetMatrix(VECTOR_NOPAD* pos, MATRIX2* mtx); -extern int FrustrumCheck16(PACKED_CELL_OBJECT* pcop, int bounding_sphere); // 0x0001BD30 +extern int FrustrumCheck16(PACKED_CELL_OBJECT* pcop, XZPAIR* near, int bounding_sphere); // 0x0001BD30 extern int FrustrumCheck(VECTOR* pos, int bounding_sphere); // 0x0001BDEC diff --git a/src_rebuild/Game/C/camera.c b/src_rebuild/Game/C/camera.c index 9dfe2548d..bffdac222 100644 --- a/src_rebuild/Game/C/camera.c +++ b/src_rebuild/Game/C/camera.c @@ -593,7 +593,7 @@ void PlaceCameraInCar(PLAYER *lp, int BumperCam) else camera_angle.vy = (lp->headPos >> 16) - baseDir & 4095; - if (cp) + if (cp && cp->ap.carCos) { // build custom matrix using car draw matrix InvertMatrix(&cp->hd.drawCarMat, &inv_camera_matrix); diff --git a/src_rebuild/Game/C/civ_ai.c b/src_rebuild/Game/C/civ_ai.c index fd6822f2e..0452f24e1 100644 --- a/src_rebuild/Game/C/civ_ai.c +++ b/src_rebuild/Game/C/civ_ai.c @@ -1083,7 +1083,7 @@ int CheckChangeLanes(DRIVER2_STRAIGHT* straight, DRIVER2_CURVE* curve, int distA segLen = straight->length; } - newLane = currentLane + (Random2((int)straight) >> 7 & 2U) + 0xff & 0xff; + newLane = currentLane + (Random2((int)(intptr_t)straight) >> 7 & 2U) + 0xff & 0xff; if (tryToPark) { diff --git a/src_rebuild/Game/C/dr2roads.c b/src_rebuild/Game/C/dr2roads.c index bade3a62b..10009673d 100644 --- a/src_rebuild/Game/C/dr2roads.c +++ b/src_rebuild/Game/C/dr2roads.c @@ -407,7 +407,7 @@ sdPlane* sdGetCell(VECTOR *pos) plane = &planeData[*surface]; - if (((int)plane & 3) == 0 && *(int *)plane != -1) + if (((intptr_t)plane & 3) == 0 && *(int *)plane != -1) { if (plane->surface - 16U < 16) plane = EventSurface(pos, plane); diff --git a/src_rebuild/Game/C/draw.c b/src_rebuild/Game/C/draw.c index 1c1ae2229..726de4f8c 100644 --- a/src_rebuild/Game/C/draw.c +++ b/src_rebuild/Game/C/draw.c @@ -1,5 +1,7 @@ #include "driver2.h" +#include + #include "draw.h" #include "main.h" #include "map.h" @@ -8,6 +10,7 @@ #include "camera.h" #include "mission.h" #include "cell.h" +#include "spool.h" #include "tile.h" #include "objanim.h" #include "texture.h" @@ -89,6 +92,8 @@ void* model_object_ptrs[MAX_DRAWN_BUILDINGS]; void* model_tile_ptrs[MAX_DRAWN_TILES]; void* anim_obj_buffer[MAX_DRAWN_ANIMATING]; void* spriteList[MAX_DRAWN_SPRITES]; +CELL_OBJECT model_tile_objects[MAX_DRAWN_TILES]; +CELL_OBJECT sprite_objects[MAX_DRAWN_SPRITES]; MATRIX inv_camera_matrix; MATRIX face_camera; @@ -105,12 +110,93 @@ int fasterToggle = 0; int combointensity; -char CurrentPVS[PVS_CELL_COUNT * PVS_CELL_COUNT + 3]; // 20*20+4 +char CurrentPVS[PVS_CELL_COUNT * PVS_CELL_COUNT + 3]; MATRIX2 matrixtable[64]; int setupYet = 0; int gDrawDistance = PVS_CELL_COUNT * PVS_CELL_COUNT; +#ifndef PSX +struct DrawMapDiagStats +{ + int cells_tested; + int cells_visible; + int cells_range_rejected; + int cells_plane_rejected; + int cells_pvs_rejected; + int cells_unloaded_region; + int pvs_oob_reads; + int packed_objects; + int frustum_passed; + int frustum_rejected; + int sprites_overflow; + int tiles_overflow; + int buildings_overflow; + int anim_overflow; +}; + +struct DrawPvsDiagState +{ + int source_region; + int region; + int cell; + int reloaded; + int reload_count; + int last_reload_frame; + int loaded_region; + int loading_region; + int visible_entries; +}; + +static DrawPvsDiagState gDrawPvsDiag; + +static int DrawDiagEnabled(void) +{ + static int initialized = 0; + static int enabled = 0; + + if (!initialized) + { + const char* value = getenv("REDRIVER2_DRAW_DIAG"); + + if (value == NULL) + value = getenv("REDRIVER2_VK_DIAG"); + + enabled = value != NULL && value[0] != '\0' && value[0] != '0'; + initialized = 1; + } + + return enabled; +} + +static int DrawDiagInterval(void) +{ + static int initialized = 0; + static int interval = 60; + + if (!initialized) + { + const char* value = getenv("REDRIVER2_DRAW_DIAG_INTERVAL"); + + if (value == NULL) + value = getenv("REDRIVER2_VK_DIAG_INTERVAL"); + + if (value != NULL) + { + int parsed = atoi(value); + + if (parsed > 0) + interval = parsed; + } + + initialized = 1; + } + + return interval; +} + +#endif + #ifndef PSX _pct& plotContext = *(_pct*)((u_char*)getScratchAddr(0) + 1024 - sizeof(_pct)); // orig offset: 0x1f800020 #endif @@ -162,15 +248,15 @@ void addSubdivSpriteShadow(POLYFT4* src, SVECTOR* verts, int z) } // [D] [T] [A] -void DrawSprites(PACKED_CELL_OBJECT** sprites, int numFound) +void DrawSprites(CELL_OBJECT** sprites, int numFound) { int i; int z; u_int spriteColour, lightdd; u_char lightLevel; MODEL* model; - PACKED_CELL_OBJECT* pco; - PACKED_CELL_OBJECT** list; + CELL_OBJECT* pco; + CELL_OBJECT** list; int numShadows; #if 0 //def PSX @@ -228,10 +314,10 @@ void DrawSprites(PACKED_CELL_OBJECT** sprites, int numFound) pco = *list; list++; - modelnumber = (pco->value >> 6) | (pco->pos.vy & 1) << 10; + modelnumber = pco->type; model = modelpointers[modelnumber]; - if ((pco->value & 63) == 63 || litSprites[modelnumber >> 5] & 1 << (modelnumber & 31)) // [A] multiple sprites lighting fixes + if (pco->yang == 63 || litSprites[modelnumber >> 5] & 1 << (modelnumber & 31)) // [A] multiple sprites lighting fixes { plotContext.colour = 0x2c808080; } @@ -240,11 +326,7 @@ void DrawSprites(PACKED_CELL_OBJECT** sprites, int numFound) plotContext.colour = spriteColour; } - plotContext.scribble[0] = pco->pos.vx; - plotContext.scribble[1] = (pco->pos.vy << 0x10) >> 0x11; - plotContext.scribble[2] = pco->pos.vz; - - z = Apply_InvCameraMatrixAndSetMatrix((VECTOR_NOPAD*)plotContext.scribble, (MATRIX2*)&face_camera); + z = Apply_InvCameraMatrixAndSetMatrix(&pco->pos, (MATRIX2*)&face_camera); if (z < 1000) { @@ -299,7 +381,7 @@ void DrawSprites(PACKED_CELL_OBJECT** sprites, int numFound) #endif if (wetness == 0 && gTimeOfDay != TIME_NIGHT && - (pco->value & 32) == 0 && + (pco->yang & 32) == 0 && z < MAX_TREE_SHADOW_DISTANCE && numShadows < 40) { @@ -364,7 +446,11 @@ void SetupPlaneColours(u_int ambient) } -int current_pvs_cell; +int current_pvs_cell = -1; +int current_pvs_region = -1; +int current_pvs_source_region = -1; +int current_pvs_loaded_region = -2; +int current_pvs_loading_region = -2; // [D] [T] @@ -373,6 +459,14 @@ void SetupDrawMapPSX(void) int cell_x, cell_z; int theta; int pvs_cell; + int region_x1; + int region_z1; + int current_barrel_region_x1; + int current_barrel_region_z1; + int pvs_region; + int pvs_source_region; + int pvs_loaded_region; + int pvs_loading_region; if (setupYet != 0) { @@ -385,23 +479,55 @@ void SetupDrawMapPSX(void) current_cell_x = cell_x; current_cell_z = cell_z; - pvs_cell = (cell_z % MAP_REGION_SIZE) * MAP_REGION_SIZE + (cell_x % MAP_REGION_SIZE); - if (pvs_cell != current_pvs_cell) - { - int region_x1, region_z1; - int current_barrel_region_x1, current_barrel_region_z1; + region_x1 = cell_x / MAP_REGION_SIZE; + region_z1 = cell_z / MAP_REGION_SIZE; + + current_barrel_region_x1 = (region_x1 & 1); + current_barrel_region_z1 = (region_z1 & 1); - region_x1 = cell_x / MAP_REGION_SIZE; - region_z1 = cell_z / MAP_REGION_SIZE; + pvs_region = region_x1 + region_z1 * regions_across; + pvs_source_region = current_barrel_region_x1 + current_barrel_region_z1 * 2; + pvs_cell = (cell_z - region_z1 * MAP_REGION_SIZE) * MAP_REGION_SIZE + cell_x - region_x1 * MAP_REGION_SIZE; + pvs_loaded_region = regions_unpacked[pvs_source_region]; + pvs_loading_region = loading_region[pvs_source_region]; - current_barrel_region_x1 = (region_x1 & 1); - current_barrel_region_z1 = (region_z1 & 1); +#ifndef PSX + gDrawPvsDiag.source_region = pvs_source_region; + gDrawPvsDiag.region = pvs_region; + gDrawPvsDiag.cell = pvs_cell; + gDrawPvsDiag.reloaded = (gDrawPvsDiag.reload_count > 0 && gDrawPvsDiag.last_reload_frame == FrameCnt); + gDrawPvsDiag.loaded_region = pvs_loaded_region; + gDrawPvsDiag.loading_region = pvs_loading_region; +#endif + if (pvs_cell != current_pvs_cell || + pvs_region != current_pvs_region || + pvs_source_region != current_pvs_source_region || + pvs_loaded_region != current_pvs_loaded_region || + pvs_loading_region != current_pvs_loading_region) + { current_pvs_cell = pvs_cell; + current_pvs_region = pvs_region; + current_pvs_source_region = pvs_source_region; + current_pvs_loaded_region = pvs_loaded_region; + current_pvs_loading_region = pvs_loading_region; GetPVSRegionCell2( - current_barrel_region_x1 + current_barrel_region_z1 * 2, - region_x1 + region_z1 * regions_across, + pvs_source_region, + pvs_region, pvs_cell, CurrentPVS); + +#ifndef PSX + gDrawPvsDiag.reloaded = 1; + gDrawPvsDiag.reload_count++; + gDrawPvsDiag.last_reload_frame = FrameCnt; + gDrawPvsDiag.visible_entries = 0; + + for (int i = 0; i < pvs_square_sq; i++) + { + if (CurrentPVS[i]) + gDrawPvsDiag.visible_entries++; + } +#endif } InitFrustrumMatrix(); @@ -555,11 +681,11 @@ void DrawAllTheCars(int view) for (i = 0; i < num_cars_to_draw; i++) { // Don't exceed draw buffers - if ((int)(current->primtab + (-3000 - (int)(current->primptr - PRIMTAB_SIZE))) < 5800) + if ((int)(intptr_t)(current->primtab + (-3000 - (int)(intptr_t)(current->primptr - PRIMTAB_SIZE))) < 5800) return; // make cars look uglier - if ((int)(current->primtab + (-3000 - (int)(current->primptr - PRIMTAB_SIZE)) - spacefree) < 5800) + if ((int)(intptr_t)(current->primtab + (-3000 - (int)(intptr_t)(current->primptr - PRIMTAB_SIZE)) - spacefree) < 5800) gForceLowDetailCars = 1; if (cars_to_draw[i]->controlType == CONTROL_TYPE_PLAYER) @@ -1301,6 +1427,10 @@ void DrawMapPSX(int* comp_val) static int treecount = 0; static int alleycount = 0; +#ifndef PSX + DrawMapDiagStats diag = {}; +#endif + SetupDrawMapPSX(); // clean cell cache @@ -1344,7 +1474,7 @@ void DrawMapPSX(int* comp_val) drawData.cellzpos = current_cell_z; drawData.cellxpos = current_cell_x; - PVS_ptr = CurrentPVS + 220; + PVS_ptr = CurrentPVS + view_dist * pvs_square + view_dist; vloop = 0; hloop = 0; @@ -1364,38 +1494,99 @@ void DrawMapPSX(int* comp_val) { if (ABS(hloop) + ABS(vloop) < PVS_CELL_COUNT) { +#ifndef PSX + diag.cells_tested++; +#endif // clamped vis values - int vis_h = MIN(MAX(hloop, -9), PVS_CELL_COUNT / 2); - int vis_v = MIN(MAX(vloop, -9), PVS_CELL_COUNT / 2); + int vis_h = MIN(MAX(hloop, 1 - view_dist), view_dist); + int vis_v = MIN(MAX(vloop, 1 - view_dist), view_dist); + int pvs_index = view_dist * pvs_square + view_dist + vis_v * pvs_square + vis_h; cellx = drawData.cellxpos + hloop; cellz = drawData.cellzpos + vloop; - if (drawData.rightPlane < 0 && - drawData.leftPlane > 0 && - drawData.backPlane < drawData.farClipLimit && // check planes - cellx > -1 && cellx < cells_across && // check cell ranges - cellz > -1 && cellz < cells_down && - PVS_ptr[vis_v * pvs_square + vis_h]) // check PVS table + if (pvs_index < 0 || pvs_index >= pvs_square_sq) { +#ifndef PSX + diag.pvs_oob_reads++; +#endif + } + else if (drawData.rightPlane >= 0 || + drawData.leftPlane <= 0 || + drawData.backPlane >= drawData.farClipLimit) + { +#ifndef PSX + diag.cells_plane_rejected++; +#endif + } + else if (cellx <= -1 || cellx >= cells_across || + cellz <= -1 || cellz >= cells_down) + { +#ifndef PSX + diag.cells_range_rejected++; +#endif + } + else if (!PVS_ptr[vis_v * pvs_square + vis_h]) + { +#ifndef PSX + diag.cells_pvs_rejected++; +#endif + } + else + { +#ifndef PSX + diag.cells_visible++; + { + int region_x = cellx / MAP_REGION_SIZE; + int region_z = cellz / MAP_REGION_SIZE; + int source_region = (region_x & 1) + (region_z & 1) * 2; + int region = region_x + region_z * regions_across; + + if (loading_region[source_region] != -1 || RoadMapRegions[source_region] != region) + diag.cells_unloaded_region++; + } +#endif // walk each cell object in cell for (ppco = GetFirstPackedCop(cellx, cellz, &ci, 1, drawData.cellLevel); ppco; ppco = GetNextPackedCop(&ci)) { model = modelpointers[(ppco->value >> 6) | ((ppco->pos).vy & 1) << 10]; - if (FrustrumCheck16(ppco, model->bounding_sphere) != -1) +#ifndef PSX + diag.packed_objects++; +#endif + + if (FrustrumCheck16(ppco, &ci.nearCell, model->bounding_sphere) != -1) { +#ifndef PSX + diag.frustum_passed++; +#endif // sprity type if (model->shape_flags & SHAPE_FLAG_SPRITE) { if (drawData.sprites_found < MAX_DRAWN_SPRITES) - spriteList[drawData.sprites_found++] = ppco; + { + QuickUnpackCellObject(ppco, &ci.nearCell, &sprite_objects[drawData.sprites_found]); + spriteList[drawData.sprites_found] = &sprite_objects[drawData.sprites_found]; + drawData.sprites_found++; + } +#ifndef PSX + else + { + diag.sprites_overflow++; + } +#endif if ((model->flags2 & MODEL_FLAG_ANIMOBJ) && drawData.anim_objs_found < MAX_DRAWN_ANIMATING) { cop = UnpackCellObject(ppco, &ci.nearCell); anim_obj_buffer[drawData.anim_objs_found++] = cop; } +#ifndef PSX + else if (model->flags2 & MODEL_FLAG_ANIMOBJ) + { + diag.anim_overflow++; + } +#endif if (model->flags2 & MODEL_FLAG_TREE) { @@ -1453,7 +1644,17 @@ void DrawMapPSX(int* comp_val) } if (drawData.tiles_found < MAX_DRAWN_TILES) - model_tile_ptrs[drawData.tiles_found++] = ppco; + { + QuickUnpackCellObject(ppco, &ci.nearCell, &model_tile_objects[drawData.tiles_found]); + model_tile_ptrs[drawData.tiles_found] = &model_tile_objects[drawData.tiles_found]; + drawData.tiles_found++; + } +#ifndef PSX + else + { + diag.tiles_overflow++; + } +#endif } else { @@ -1461,12 +1662,26 @@ void DrawMapPSX(int* comp_val) if (drawData.other_models_found < MAX_DRAWN_BUILDINGS) model_object_ptrs[drawData.other_models_found++] = cop; +#ifndef PSX + else + diag.buildings_overflow++; +#endif if (drawData.anim_objs_found < MAX_DRAWN_ANIMATING && (model->flags2 & MODEL_FLAG_ANIMOBJ)) anim_obj_buffer[drawData.anim_objs_found++] = cop; +#ifndef PSX + else if (model->flags2 & MODEL_FLAG_ANIMOBJ) + diag.anim_overflow++; +#endif } } } +#ifndef PSX + else + { + diag.frustum_rejected++; + } +#endif } } } @@ -1503,6 +1718,33 @@ void DrawMapPSX(int* comp_val) } }while (i-- > 0); +#ifndef PSX + if (DrawDiagEnabled()) + { + int interval = DrawDiagInterval(); + + if (FrameCnt % interval == 0) + { + printInfo("[DRAWDIAG] frame=%d cam=%d,%d,%d cell=%d,%d pvs src/reg/cell=%d/%d/%d reload=%d last/count=%d/%d loaded/loading=%d/%d entries=%d cells vis/test=%d/%d reject plane/range/pvs/oob=%d/%d/%d/%d unloaded=%d objects=%d frustum=%d/%d draw b/s/t/a=%d/%d/%d/%d overflow b/s/t/a=%d/%d/%d/%d\n", + FrameCnt, + camera_position.vx, camera_position.vy, camera_position.vz, + drawData.cellxpos, drawData.cellzpos, + gDrawPvsDiag.source_region, gDrawPvsDiag.region, gDrawPvsDiag.cell, + gDrawPvsDiag.reloaded, + gDrawPvsDiag.last_reload_frame, gDrawPvsDiag.reload_count, + gDrawPvsDiag.loaded_region, gDrawPvsDiag.loading_region, + gDrawPvsDiag.visible_entries, + diag.cells_visible, diag.cells_tested, + diag.cells_plane_rejected, diag.cells_range_rejected, diag.cells_pvs_rejected, diag.pvs_oob_reads, + diag.cells_unloaded_region, + diag.packed_objects, + diag.frustum_passed, diag.frustum_rejected, + drawData.other_models_found, drawData.sprites_found, drawData.tiles_found, drawData.anim_objs_found, + diag.buildings_overflow, diag.sprites_overflow, diag.tiles_overflow, diag.anim_overflow); + } + } +#endif + #if 0 char tempBuf[512]; @@ -1530,10 +1772,10 @@ void DrawMapPSX(int* comp_val) DrawAllAnimatingObjects((CELL_OBJECT**)anim_obj_buffer, drawData.anim_objs_found); if (drawData.sprites_found) - DrawSprites((PACKED_CELL_OBJECT**)spriteList, drawData.sprites_found); + DrawSprites((CELL_OBJECT**)spriteList, drawData.sprites_found); if (drawData.tiles_found) - DrawTILES((PACKED_CELL_OBJECT**)model_tile_ptrs, drawData.tiles_found); + DrawTILES((CELL_OBJECT**)model_tile_ptrs, drawData.tiles_found); if (drawData.other_models_found) DrawAllBuildings((CELL_OBJECT**)model_object_ptrs, drawData.other_models_found); @@ -1608,4 +1850,4 @@ void GetDLightLevel(SVECTOR* position, u_int* inOutColor) *inOutColor = MIN(lightB, 255) << 16 | MIN(lightG, 255) << 8 | MIN(lightR, 255) | (*inOutColor & 0xFF000000); } -#endif // DYNAMIC_LIGHTING \ No newline at end of file +#endif // DYNAMIC_LIGHTING diff --git a/src_rebuild/Game/C/draw.h b/src_rebuild/Game/C/draw.h index 862974f69..d595bb751 100644 --- a/src_rebuild/Game/C/draw.h +++ b/src_rebuild/Game/C/draw.h @@ -46,6 +46,7 @@ extern MATRIX aspect; extern MATRIX identity; extern MATRIX inv_camera_matrix; extern MATRIX face_camera; +extern MATRIX frustrum_matrix; extern MATRIX2 matrixtable[64]; extern MATRIX2 CompoundMatrix[64]; @@ -85,6 +86,11 @@ extern int pvs_square_sq; extern int PolySizes[56]; extern int setupYet; +extern int current_pvs_cell; +extern int current_pvs_region; +extern int current_pvs_source_region; +extern int current_pvs_loaded_region; +extern int current_pvs_loading_region; extern int combointensity; diff --git a/src_rebuild/Game/C/event.c b/src_rebuild/Game/C/event.c index a063a284b..3b18ba643 100644 --- a/src_rebuild/Game/C/event.c +++ b/src_rebuild/Game/C/event.c @@ -2989,7 +2989,7 @@ void DrawEvents(int camera) pos.vx = pos.vx - boatOffset.vx; pos.vz = pos.vz - boatOffset.vz; - pos.vy = (pos.vy - boatOffset.vy) + FIXEDH((int)ev->node * RSIN(*ev->data)); + pos.vy = (pos.vy - boatOffset.vy) + FIXEDH((int)(intptr_t)ev->node * RSIN(*ev->data)); } else if (type == 0x400) { diff --git a/src_rebuild/Game/C/glaunch.c b/src_rebuild/Game/C/glaunch.c index f4dd417af..35409a6cf 100644 --- a/src_rebuild/Game/C/glaunch.c +++ b/src_rebuild/Game/C/glaunch.c @@ -288,14 +288,14 @@ void State_GameStart(void* param) void State_InitFrontEnd(void* param) { - if ((int)param == 2) + if ((int)(intptr_t)param == 2) { InitFrontend(); InitFrontendDisplay(); } else { - ReInitFrontend((int)param == 0); + ReInitFrontend((int)(intptr_t)param == 0); } SetState(STATE_FRONTEND); @@ -304,7 +304,7 @@ void State_InitFrontEnd(void* param) // [D] [T] void State_FMVPlay(void* param) { - PlayFMV((int)param); + PlayFMV((int)(intptr_t)param); SetState(STATE_INITFRONTEND, (void*)1); } @@ -376,7 +376,7 @@ void State_MissionLadder(void* param) MISSION_STEP* CurrentStep; RENDER_ARGS RenderArgs; - newgame = (int)param; + newgame = (int)(intptr_t)param; quit = 0; RenderArgs.nRenders = 0; diff --git a/src_rebuild/Game/C/map.c b/src_rebuild/Game/C/map.c index be17294d9..31d32f0d6 100644 --- a/src_rebuild/Game/C/map.c +++ b/src_rebuild/Game/C/map.c @@ -101,6 +101,11 @@ void ProcessMapLump(char* lump_ptr, int lump_size) view_dist = PVS_CELL_COUNT / 2; pvs_square = PVS_CELL_COUNT; pvs_square_sq = PVS_CELL_COUNT * PVS_CELL_COUNT; + current_pvs_cell = -1; + current_pvs_region = -1; + current_pvs_source_region = -1; + current_pvs_loaded_region = -2; + current_pvs_loading_region = -2; units_across_halved = cells_across / 2 * MAP_CELL_SIZE; units_down_halved = cells_down / 2 * MAP_CELL_SIZE; @@ -167,14 +172,14 @@ int newPositionVisible(VECTOR *pos, char *pvs, int ccx, int ccz) cellz = (dz / MAP_CELL_SIZE) - ccz; #ifndef PSX - cellx = MIN(MAX(cellx, -9), PVS_CELL_COUNT / 2); - cellz = MIN(MAX(cellz, -9), PVS_CELL_COUNT / 2); + cellx = MIN(MAX(cellx, 1 - view_dist), view_dist); + cellz = MIN(MAX(cellz, 1 - view_dist), view_dist); #endif // PSX if (ABS(cellx) <= view_dist && ABS(cellz) <= view_dist) { - return pvs[cellx + 10 + (cellz + 10) * pvs_square] != 0; + return pvs[cellx + view_dist + (cellz + view_dist) * pvs_square] != 0; } return 0; @@ -534,7 +539,9 @@ void PVSDecode(char *output, char *celldata, ushort sz, int havanaCorruptCellBod goto spod; } - sym = ((sym & 3) * 16 + nybblearray[i++]) * 16 + nybblearray[i++ + 1]; + int symMid = nybblearray[i++]; + int symLow = nybblearray[i++]; + sym = ((sym & 3) * 16 + symMid) * 16 + symLow; } pixelIndex += (sym >> 1); @@ -586,7 +593,7 @@ void PVSDecode(char *output, char *celldata, ushort sz, int havanaCorruptCellBod } printf("=========================\n"); #endif - memcpy((u_char*)output, decodebuf, pvs_square_sq-1); // 110*4 + memcpy((u_char*)output, decodebuf, pvs_square_sq); } @@ -638,7 +645,3 @@ void GetPVSRegionCell2(int source_region, int region, int cell, char *output) } } - - - - diff --git a/src_rebuild/Game/C/mission.c b/src_rebuild/Game/C/mission.c index 4f419bd6d..0a2390660 100644 --- a/src_rebuild/Game/C/mission.c +++ b/src_rebuild/Game/C/mission.c @@ -441,7 +441,7 @@ void LoadMission(int missionnum) MissionStrings = (char*)(MissionScript + MissionLoadAddress->strings); if (MissionLoadAddress->route && !NewLevel) - loadsize = (u_int)((char*)MissionStrings + ((char*)MissionLoadAddress->route - (char*)MissionLoadAddress)); + loadsize = (u_int)(uintptr_t)((char*)MissionStrings + ((char*)MissionLoadAddress->route - (char*)MissionLoadAddress)); else loadsize = length; diff --git a/src_rebuild/Game/C/sky.c b/src_rebuild/Game/C/sky.c index 4ed0c087f..55a4aea42 100644 --- a/src_rebuild/Game/C/sky.c +++ b/src_rebuild/Game/C/sky.c @@ -862,14 +862,14 @@ void PlotSkyPoly(POLYFT4* polys, int skytexnum, unsigned char r, unsigned char g poly->clut = skyclut[skytexnum]; poly->tpage = skytpage[skytexnum]; - addPrim(current->ot + OTSIZE - 1, poly); + addPrim(current->ot + OTSIZE - 1, poly); #if USE_PGXP && USE_EXTENDED_PRIM_POINTERS - poly->pgxp_index = outpoints[src->v0].pgxp_index; + poly->pgxp_index = 0xffff; #endif - current->primptr += sizeof(POLY_FT4); - } + current->primptr += sizeof(POLY_FT4); + } } // [D] [T] @@ -906,14 +906,9 @@ void PlotHorizonMDL(MODEL* model, int horizontaboffset, RGB16* skycolor) if(count == 15) gte_stszotz(&z); -#if USE_PGXP - // store PGXP index - // HACK: -1 is needed here for some reason - dv[0].pgxp_index = dv[1].pgxp_index = dv[2].pgxp_index = PGXP_GetIndex(0) - 1; -#endif - dv += 3; - verts += 3; - count -= 3; + dv += 3; + verts += 3; + count -= 3; } while (count); #if USE_PGXP @@ -986,4 +981,3 @@ void DrawSkyDome(void) #endif } - diff --git a/src_rebuild/Game/C/targets.c b/src_rebuild/Game/C/targets.c index c8f0722e6..d22828ae1 100644 --- a/src_rebuild/Game/C/targets.c +++ b/src_rebuild/Game/C/targets.c @@ -324,7 +324,10 @@ void DrawStopZone(VECTOR *pPosition) temp.vy = pVector->vy; temp.vz = pVector->vz; - RotTransPers(&temp, pOut, &p, &flag); + { + long otz; + gte_RotTransPers(&temp, pOut, &p, &flag, &otz); + } if (pOut == (long*)&pPoly->x0) pOut = (long*)&pPoly->x1; diff --git a/src_rebuild/Game/C/tile.c b/src_rebuild/Game/C/tile.c index 28a647713..4ec4ad9cb 100644 --- a/src_rebuild/Game/C/tile.c +++ b/src_rebuild/Game/C/tile.c @@ -211,11 +211,11 @@ inline int fst_div_3(int x) // [D] [T] -void DrawTILES(PACKED_CELL_OBJECT** tiles, int tile_amount) +void DrawTILES(CELL_OBJECT** tiles, int tile_amount) { MODEL* pModel; - PACKED_CELL_OBJECT *ppco; - PACKED_CELL_OBJECT** tilePointers; + CELL_OBJECT *pco; + CELL_OBJECT** tilePointers; int previous_matrix, yang, dofse, Z; int model_number; @@ -255,26 +255,22 @@ void DrawTILES(PACKED_CELL_OBJECT** tiles, int tile_amount) plotContext.flags = 0; plotContext.polySizes = PolySizes; - tilePointers = (PACKED_CELL_OBJECT **)tiles; + tilePointers = (CELL_OBJECT **)tiles; while (tile_amount--) { - ppco = *tilePointers++; - - plotContext.scribble[0] = ppco->pos.vx; - plotContext.scribble[1] = (ppco->pos.vy << 0x10) >> 0x11; - plotContext.scribble[2] = ppco->pos.vz; + pco = *tilePointers++; - yang = ppco->value & 0x3f; - model_number = (ppco->value >> 6) | (ppco->pos.vy & 1) << 10; + yang = pco->yang; + model_number = pco->type; if (previous_matrix == yang) { - Z = Apply_InvCameraMatrixSetTrans((VECTOR_NOPAD *)plotContext.scribble); + Z = Apply_InvCameraMatrixSetTrans(&pco->pos); } else { - Z = Apply_InvCameraMatrixAndSetMatrix((VECTOR_NOPAD *)plotContext.scribble, &CompoundMatrix[previous_matrix = yang]); + Z = Apply_InvCameraMatrixAndSetMatrix(&pco->pos, &CompoundMatrix[previous_matrix = yang]); } if (Z <= DRAW_LOD_DIST_HIGH) @@ -706,4 +702,3 @@ void ProcessLowDetailTable(char *lump_ptr, int lump_size) - diff --git a/src_rebuild/Game/C/tile.h b/src_rebuild/Game/C/tile.h index 8c6a927ca..e07cda16c 100644 --- a/src_rebuild/Game/C/tile.h +++ b/src_rebuild/Game/C/tile.h @@ -22,7 +22,7 @@ struct VERTEX u_char pad[2]; }; -extern void DrawTILES(PACKED_CELL_OBJECT** tiles, int tile_amount); // 0x00041D7C +extern void DrawTILES(CELL_OBJECT** tiles, int tile_amount); // 0x00041D7C extern void Tile1x1(MODEL *model); // 0x00041B10 diff --git a/src_rebuild/Game/dr2locale.c b/src_rebuild/Game/dr2locale.c index 61f8d98ae..e3915bd29 100644 --- a/src_rebuild/Game/dr2locale.c +++ b/src_rebuild/Game/dr2locale.c @@ -5,8 +5,11 @@ #ifndef PSX #include +#include +#if !defined(__APPLE__) #include #endif +#endif int gUserLanguage = 0; diff --git a/src_rebuild/Game/dr2locale.h b/src_rebuild/Game/dr2locale.h index 1e1449a7b..5ac472c9b 100644 --- a/src_rebuild/Game/dr2locale.h +++ b/src_rebuild/Game/dr2locale.h @@ -267,8 +267,8 @@ extern char* gMissionLangTable[MAX_LANGUAGE_TEXT]; #define M_LTXT_ID(id) (char*)(id) // fancy logic -#define GET_GAME_TXT(st) (((u_intptr)st < MAX_LANGUAGE_TEXT && st) ? gGameLangTable[(int)st] : st) -#define GET_MISSION_TXT(st) (((u_intptr)st < MAX_LANGUAGE_TEXT && st) ? gMissionLangTable[(int)st] : st) +#define GET_GAME_TXT(st) (((u_intptr)st < MAX_LANGUAGE_TEXT && st) ? gGameLangTable[(int)(u_intptr)st] : st) +#define GET_MISSION_TXT(st) (((u_intptr)st < MAX_LANGUAGE_TEXT && st) ? gMissionLangTable[(int)(u_intptr)st] : st) extern int InitStringMng(); extern void DeinitStringMng(); diff --git a/src_rebuild/Game/driver2.h b/src_rebuild/Game/driver2.h index e9fc5ce6f..27b02b276 100644 --- a/src_rebuild/Game/driver2.h +++ b/src_rebuild/Game/driver2.h @@ -58,8 +58,8 @@ #define trap(ode) {printError("EXCEPTION code: %x\n", ode);} #elif _MSC_VER >= 1400 #define trap(ode) {printError("EXCEPTION code: %x\n", ode); __debugbreak();} -#elif defined(__GNUC__) -#define trap(ode) {__asm__("int3");} +#elif defined(__clang__) || defined(__GNUC__) +#define trap(ode) {__builtin_trap();} #else #define trap(ode) {_asm int 0x03} #endif diff --git a/src_rebuild/Game/psyx_compat.h b/src_rebuild/Game/psyx_compat.h index d444706c5..52434eb02 100644 --- a/src_rebuild/Game/psyx_compat.h +++ b/src_rebuild/Game/psyx_compat.h @@ -27,7 +27,7 @@ typedef u_int u_intptr; #else -#if defined(_M_X64) || defined(__amd64__) +#if defined(_M_X64) || defined(__amd64__) || defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) typedef OT_TAG OTTYPE; #else typedef unsigned long long OTTYPE; diff --git a/src_rebuild/PsyCross b/src_rebuild/PsyCross index c3e81487e..aeb16b409 160000 --- a/src_rebuild/PsyCross +++ b/src_rebuild/PsyCross @@ -1 +1 @@ -Subproject commit c3e81487e9da4f43dc5ac9858b3da3126d2ff639 +Subproject commit aeb16b4091d320aa7a19d5ec11216d0869111b21 diff --git a/src_rebuild/premake5.lua b/src_rebuild/premake5.lua index bcb805ad9..a48195b06 100644 --- a/src_rebuild/premake5.lua +++ b/src_rebuild/premake5.lua @@ -1,6 +1,7 @@ -- premake5.lua -require "premake_modules/usage" +-- "usage"/"uses" custom API was incompatible with premake5 5.0.0-beta8+; +-- we now use plain dependson+links+includedirs in each project. require "premake_modules/emscripten" IS_ANDROID = (_ACTION == "androidndk") @@ -12,6 +13,19 @@ newoption { description = "adds specific define for compiling on Raspberry Pi" } +newoption { + trigger = "renderer", + value = "API", + description = "Rendering backend (default: opengl)", + allowed = { { "opengl", "OpenGL / OpenGL ES (default)" }, + { "vulkan", "Vulkan / MoltenVK" } } +} + +if _OPTIONS["renderer"] == nil then + _OPTIONS["renderer"] = "opengl" +end +USE_VULKAN_RENDERER = (_OPTIONS["renderer"] == "vulkan") + table.insert(premake.option.get("os").allowed, { "emscripten", "Emscripten" }) ------------------------------------------ @@ -21,6 +35,26 @@ SDL2_DIR = os.getenv("SDL2_DIR") or "dependencies/SDL2" OPENAL_DIR = os.getenv("OPENAL_DIR") or "dependencies/openal-soft" JPEG_DIR = os.getenv("JPEG_DIR") or "dependencies/jpeg" +-- macOS Homebrew prefixes (Apple Silicon: /opt/homebrew, Intel: /usr/local) +HOMEBREW_PREFIX = os.getenv("HOMEBREW_PREFIX") +if HOMEBREW_PREFIX == nil and os.target() == "macosx" then + if os.isdir("/opt/homebrew") then + HOMEBREW_PREFIX = "/opt/homebrew" + else + HOMEBREW_PREFIX = "/usr/local" + end +end +if os.target() == "macosx" then + MAC_SDL2_DIR = os.getenv("MAC_SDL2_DIR") or (HOMEBREW_PREFIX .. "/opt/sdl2") + MAC_OPENAL_DIR = os.getenv("MAC_OPENAL_DIR") or (HOMEBREW_PREFIX .. "/opt/openal-soft") + MAC_JPEG_DIR = os.getenv("MAC_JPEG_DIR") or (HOMEBREW_PREFIX .. "/opt/jpeg") + if USE_VULKAN_RENDERER then + MAC_VULKAN_HEADERS = os.getenv("MAC_VULKAN_HEADERS") or (HOMEBREW_PREFIX .. "/opt/vulkan-headers") + MAC_VULKAN_LOADER = os.getenv("MAC_VULKAN_LOADER") or (HOMEBREW_PREFIX .. "/opt/vulkan-loader") + MAC_MOLTENVK = os.getenv("MAC_MOLTENVK") or (HOMEBREW_PREFIX .. "/opt/molten-vk") + end +end + WEBDEMO_DIR = os.getenv("WEBDEMO_DIR") or "../../../../content/web_demo@/" -- FIXME: make it better RED2_DIR = os.getenv("RED2_DIR") or "../../data@/" WEBSHELL_PATH = "../platform/Emscripten" -- must be relative to makefile path (SADLY) @@ -128,14 +162,23 @@ workspace "REDRIVER2" filter "platforms:*-arm64" architecture "arm64" + elseif os.target() == "macosx" then + platforms { "x64", "arm64" } + + filter "platforms:x64" + architecture "x86_64" + + filter "platforms:arm64" + architecture "ARM64" else platforms { "x86", "x64" } end startproject "REDRIVER2" - configuration "raspberry-pi" + filter "options:raspberry-pi" defines { "__RPI__" } + filter {} filter "system:Linux" buildoptions { @@ -146,18 +189,34 @@ workspace "REDRIVER2" "-Wno-unused-result", "-fpermissive" } - + cppdialect "C++11" - + filter {"system:Linux", "platforms:x86"} buildoptions { "-m32" } - + linkoptions { "-m32" } + filter "system:macosx" + buildoptions { + "-Wno-narrowing", + "-Wno-endif-labels", + "-Wno-write-strings", + "-Wno-format-security", + "-Wno-unused-result", + "-Wno-deprecated-declarations", -- OpenGL is deprecated on macOS but still works (4.1) + "-fpermissive", + -- Force-include types.h so its u_long override (uint32_t) wins over + -- macOS which would otherwise typedef u_long as 64-bit. + "-include " .. path.getabsolute("PsyCross/include/psx/types.h"), + } + + cppdialect "C++11" + filter "system:Windows" disablewarnings { "4996", "4554", "4244", "4101", "4838", "4309" } @@ -199,13 +258,14 @@ project "REDRIVER2" language "c++" targetdir "bin/%{cfg.buildcfg}" - includedirs { - "Game", + includedirs { + "Game", + "PsyCross/include", + "PsyCross/include/psx", } - - uses { - "PsyCross", - } + + dependson { "PsyCross" } + links { "PsyCross" } defines { GAME_REGION } defines { "BUILD_CONFIGURATION_STRING=\"%{cfg.buildcfg}\"" } @@ -221,10 +281,10 @@ project "REDRIVER2" "Game/**.c" } - filter {"system:Windows or linux or platforms:emscripten"} + filter {"system:Windows or linux or macosx or platforms:emscripten"} --dependson { "PsyX" } links { "jpeg" } - + files { "utils/**.h", "utils/**.cpp", @@ -278,6 +338,57 @@ project "REDRIVER2" "dl", } + filter "system:macosx" + includedirs { + MAC_SDL2_DIR.."/include", + MAC_SDL2_DIR.."/include/SDL2", + MAC_OPENAL_DIR.."/include", + MAC_JPEG_DIR.."/include", + } + + libdirs { + MAC_SDL2_DIR.."/lib", + MAC_OPENAL_DIR.."/lib", + MAC_JPEG_DIR.."/lib", + } + + links { + "Cocoa.framework", + "openal", + "SDL2", + "jpeg", + "dl", + } + + -- Embed Homebrew rpaths so the binary finds dylibs at runtime + linkoptions { + "-Wl,-rpath," .. MAC_SDL2_DIR .. "/lib", + "-Wl,-rpath," .. MAC_OPENAL_DIR .. "/lib", + "-Wl,-rpath," .. MAC_JPEG_DIR .. "/lib", + } + + if USE_VULKAN_RENDERER then + local SHADERC_DIR = HOMEBREW_PREFIX .. "/opt/shaderc" + defines { "RENDERER_VK", "USE_VULKAN", "USE_OPENGL_RENDERER=0" } + includedirs { + MAC_VULKAN_HEADERS .. "/include", + SHADERC_DIR .. "/include", + } + libdirs { + MAC_VULKAN_LOADER .. "/lib", + SHADERC_DIR .. "/lib", + } + links { "vulkan", "Metal.framework", "QuartzCore.framework", "IOSurface.framework" } + -- libshaderc_combined.a is referenced from libPsyCross.a; the + -- final executable must pull it in directly to satisfy symbols. + linkoptions { + "-Wl,-rpath," .. MAC_VULKAN_LOADER .. "/lib", + SHADERC_DIR .. "/lib/libshaderc_combined.a", + } + else + links { "OpenGL.framework" } + end + filter "configurations:Debug" targetsuffix "_dbg" defines { diff --git a/src_rebuild/premake5_psycross.lua b/src_rebuild/premake5_psycross.lua index 015a73479..75fcbce3d 100644 --- a/src_rebuild/premake5_psycross.lua +++ b/src_rebuild/premake5_psycross.lua @@ -56,6 +56,57 @@ project "PsyCross" "SDL2", } + filter "system:macosx" + includedirs { + MAC_SDL2_DIR.."/include", + MAC_SDL2_DIR.."/include/SDL2", + MAC_OPENAL_DIR.."/include", + } + + libdirs { + MAC_SDL2_DIR.."/lib", + MAC_OPENAL_DIR.."/lib", + } + + links { + "Cocoa.framework", + "openal", + "SDL2", + } + + if USE_VULKAN_RENDERER then + local SHADERC_DIR = HOMEBREW_PREFIX .. "/opt/shaderc" + defines { "RENDERER_VK", "USE_VULKAN", "USE_OPENGL_RENDERER=0" } + includedirs { + MAC_VULKAN_HEADERS .. "/include", + SHADERC_DIR .. "/include", + } + libdirs { + MAC_VULKAN_LOADER .. "/lib", + SHADERC_DIR .. "/lib", + } + -- libshaderc_combined.a bundles glslang+SPIRV-Tools statically; + -- gives us GLSL→SPIR-V compilation at runtime without any dylib. + linkoptions { SHADERC_DIR .. "/lib/libshaderc_combined.a" } + links { + "vulkan", + "Metal.framework", + "QuartzCore.framework", + "IOSurface.framework", + } + -- Exclude OpenGL backend sources when building Vulkan + removefiles { + "PsyCross/src/render/PsyX_render.cpp", + "PsyCross/src/render/glad.c", + } + else + links { "OpenGL.framework" } + -- Exclude Vulkan backend sources when building OpenGL + removefiles { + "PsyCross/src/render/PsyX_render_vk.cpp", + } + end + filter "configurations:Release" optimize "Speed" diff --git a/src_rebuild/premake_modules/usage/usage.lua b/src_rebuild/premake_modules/usage/usage.lua index d3ecc3271..a47a3fafe 100644 --- a/src_rebuild/premake_modules/usage/usage.lua +++ b/src_rebuild/premake_modules/usage/usage.lua @@ -72,14 +72,17 @@ local sourcesStack = Stack:Create() -- --- 'uses' api +-- 'uses' api (only register if not already provided by core premake) -- -p.api.register { - name = "uses", - scope = { "config" }, - kind = "list:string", - } +if not (p.field and p.field.get and p.field.get("uses")) then + local ok = pcall(p.api.register, { + name = "uses", + scope = { "config" }, + kind = "list:string", + }) + -- if already registered by core premake, that's fine +end -- -- 'usage' container diff --git a/src_rebuild/tools/font_tool/font_tool_main.cpp b/src_rebuild/tools/font_tool/font_tool_main.cpp index 407d29161..f421936f8 100644 --- a/src_rebuild/tools/font_tool/font_tool_main.cpp +++ b/src_rebuild/tools/font_tool/font_tool_main.cpp @@ -1,6 +1,8 @@ #include #include +#if !defined(__APPLE__) #include +#endif #include #include diff --git a/src_rebuild/utils/audio_source/snd_wav_cache.cpp b/src_rebuild/utils/audio_source/snd_wav_cache.cpp index 0f36aaaf1..dfe07acba 100644 --- a/src_rebuild/utils/audio_source/snd_wav_cache.cpp +++ b/src_rebuild/utils/audio_source/snd_wav_cache.cpp @@ -1,5 +1,8 @@ #include "snd_wav_cache.h" +#if !defined(__APPLE__) #include +#endif +#include #include bool CSoundSource_WaveCache::Load(const char* szFilename) diff --git a/src_rebuild/utils/fs.cpp b/src_rebuild/utils/fs.cpp index a02048b1c..4f8146ee7 100644 --- a/src_rebuild/utils/fs.cpp +++ b/src_rebuild/utils/fs.cpp @@ -8,8 +8,6 @@ #include #include -#define HOME_ENV "USERPROFILE" - void FS_FixPathSlashes(char* pathbuff) { while (*pathbuff) @@ -20,11 +18,14 @@ void FS_FixPathSlashes(char* pathbuff) } } -#elif defined (__unix__) +#elif defined (__unix__) || defined(__APPLE__) #include #include // glob(), globfree() +#include // malloc(), free() +#if !defined(__APPLE__) #include +#endif void FS_FixPathSlashes(char* pathbuff) { diff --git a/src_rebuild/utils/fs.h b/src_rebuild/utils/fs.h index c06fdacb6..0f6e7153c 100644 --- a/src_rebuild/utils/fs.h +++ b/src_rebuild/utils/fs.h @@ -5,7 +5,7 @@ #include #define HOME_ENV "USERPROFILE" -#elif defined (__unix__) +#elif defined (__unix__) || defined(__APPLE__) #include #define HOME_ENV "HOME" diff --git a/src_rebuild/utils/targa.cpp b/src_rebuild/utils/targa.cpp index ffecd628c..e085a0265 100644 --- a/src_rebuild/utils/targa.cpp +++ b/src_rebuild/utils/targa.cpp @@ -1,7 +1,10 @@ #include "targa.h" #include #include +#include +#if !defined(__APPLE__) #include +#endif bool LoadTGAImage(const char* filename, u_char** data, int& width, int& height, int& bpp) { diff --git a/src_rebuild/utils/video_source/VideoPlayer.cpp b/src_rebuild/utils/video_source/VideoPlayer.cpp index 666b105e4..1f2503916 100644 --- a/src_rebuild/utils/video_source/VideoPlayer.cpp +++ b/src_rebuild/utils/video_source/VideoPlayer.cpp @@ -448,10 +448,12 @@ void DrawFrame(ReadAVI::stream_format_t& stream_format, int frame_number, int cr PsyX_BeginScene(); GR_Clear(0, 0, windowWidth, windowHeight, 0, 0, 0); - + +#if defined(RENDERER_OGL) || defined(RENDERER_OGLES) glBindTexture(GL_TEXTURE_2D, g_FMVTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image_w, image_h, 0, GL_RGB, GL_UNSIGNED_BYTE, g_FMVDecodedImageBuffer); glBindTexture(GL_TEXTURE_2D, 0); +#endif GR_SetShader(g_FMVShader); GR_SetTexture(g_FMVTexture, (TexFormat)-1);