forked from Ports/goldeneye-pc-port
Repo cleanup: reference footage to docs/reference/, ignore local artifacts
- Move the two N64 reference screenshots out of the repo root into docs/reference/ (n64-footage-2026-08-24.jpg, n64-footage-gun-barrel.png); HANDOFF.md now points there. - Gitignore screenshots/ (session captures) and tools_pc/mupen64/ (local Mupen64 Plus checkout used for N64 reference footage; 8 MB of binaries). - Commit tools_pc/mtxtest.c, the standalone fast3d matrix-convention harness that HANDOFF/D72.3 docs reference as kept-for-reference. - Refresh PORTING.md: status was still 'scaffolding / building once implementation lands'; now reflects Phase 2 in progress and points at docs/HANDOFF.md for current session state.
This commit is contained in:
1 parent
d3b3fe53ce
commit
0010270f1b
5 files changed
+229
-13
No files matched your search
@@ -125,6 +125,9 @@ ge007.crash.log
|
||||
.pi/
|
||||
run_out.log
|
||||
ppm/
|
||||
screenshots/
|
||||
# local Mupen64 Plus checkout (N64 reference footage); binaries, do not commit
|
||||
tools_pc/mupen64/
|
||||
|
||||
# PC port run/scratch logs
|
||||
run_*.log
|
||||
|
||||
+14
-13
@@ -8,9 +8,10 @@ It follows the approach of the
|
||||
[Perfect Dark PC port](https://github.com/perfect-dark-pc-port/perfect_dark),
|
||||
which ports the same Rare "Indy" engine (a later revision).
|
||||
|
||||
> **Status: scaffolding.** The directory structure, build system, and port-layer
|
||||
> interfaces are in place. The actual implementation is being brought in phase
|
||||
> by phase. See below.
|
||||
> **Status: Phase 2 (rendering) in progress.** The game boots on PC, plays the
|
||||
> intro music, and renders the entire intro (logo → gun barrel → cast);
|
||||
> the current blocker is first stage load (BG-file endianness, finding D69).
|
||||
> Current session state and immediate tasks: **[docs/HANDOFF.md](docs/HANDOFF.md)**.
|
||||
|
||||
## Read this first
|
||||
|
||||
@@ -45,23 +46,23 @@ docs/PCPortResearch.md
|
||||
|
||||
The N64 build (`Makefile`, `tools/`, `rsp/`, etc.) is **untouched**.
|
||||
|
||||
## Building (once implementation lands)
|
||||
## Building
|
||||
|
||||
```sh
|
||||
./build-pc.sh ntsc-final # or pal-final / jpn-final
|
||||
```
|
||||
|
||||
Then put your ROM in `./data/` and run the binary. (The ROM is not
|
||||
distributed; you must own the game.)
|
||||
Then put your ROM in `./data/` and run the binary from the repo root.
|
||||
(The ROM is not distributed; you must own the game.)
|
||||
|
||||
## Phased plan (summary)
|
||||
|
||||
| Phase | Goal |
|
||||
|-------|------|
|
||||
| 0 | Scaffolding (this change) |
|
||||
| 1 | Boot to a window: system/fs/rom/config/video + OS shims |
|
||||
| 2 | Rendering: bring in fast3d, add `G_SETTEX`, port scheduler |
|
||||
| 3 | Audio + input |
|
||||
| 4 | Saves + polish (widescreen, mouse-look, FPS, config) |
|
||||
| Phase | Goal | Status |
|
||||
|-------|------|--------|
|
||||
| 0 | Scaffolding: build system + port-layer interfaces | done |
|
||||
| 1 (+1.5) | Boot to window / first frame: ROM map, OS shims, ABI reconciliation | done |
|
||||
| 2 | Rendering: fast3d software RSP, asset conversion/fixups | **in progress** (full intro renders; stage load = D69) |
|
||||
| 3 | Audio + input (SDL device, mixer, gamepad) | not started |
|
||||
| 4 | Saves + polish (file-backed EEPROM, widescreen, config) | not started |
|
||||
|
||||
Details and risks: [docs/PCPortResearch.md §8–9](docs/PCPortResearch.md).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
@@ -0,0 +1,212 @@
|
||||
/* Standalone numerical test of the fast3d matrix pipeline conventions.
|
||||
* Replicates: GE guPerspectiveF (swapped), guLookAtF, guRotateF, guMtxF2L
|
||||
* packing, gfx_sp_matrix unpacking + MUL order, and the row-vector vertex
|
||||
* transform in gfx_pc.cpp. Compares against the standard column-vector
|
||||
* pipeline P_std * MV * v for two scenes: gun barrel (known-good render)
|
||||
* and rareware logo (D72.3 off-screen bug).
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef float f32;
|
||||
|
||||
/* ---- GE libultra functions (verbatim math) ---- */
|
||||
|
||||
static void guMtxIdentF(float mf[4][4]) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++) mf[i][j] = (i == j);
|
||||
}
|
||||
|
||||
/* GE's SWAPPED perspective: mf[2][3]=-1, mf[3][2]=2nf/(n-f) */
|
||||
static void guPerspectiveF_GE(float mf[4][4], float fovy, float aspect, float near_, float far_) {
|
||||
float cot;
|
||||
guMtxIdentF(mf);
|
||||
fovy *= 3.1415926f / 180.0f;
|
||||
cot = cosf(fovy / 2) / sinf(fovy / 2);
|
||||
mf[0][0] = cot / aspect;
|
||||
mf[1][1] = cot;
|
||||
mf[2][2] = (near_ + far_) / (near_ - far_);
|
||||
mf[2][3] = -1;
|
||||
mf[3][2] = (2 * near_ * far_) / (near_ - far_);
|
||||
mf[3][3] = 0;
|
||||
}
|
||||
|
||||
/* standard libultra perspective (for the "true" pipeline) */
|
||||
static void guPerspectiveF_STD(float mf[4][4], float fovy, float aspect, float near_, float far_) {
|
||||
float cot;
|
||||
guMtxIdentF(mf);
|
||||
fovy *= 3.1415926f / 180.0f;
|
||||
cot = cosf(fovy / 2) / sinf(fovy / 2);
|
||||
mf[0][0] = cot / aspect;
|
||||
mf[1][1] = cot;
|
||||
mf[2][2] = (near_ + far_) / (near_ - far_);
|
||||
mf[2][3] = (2 * near_ * far_) / (near_ - far_);
|
||||
mf[3][2] = -1;
|
||||
mf[3][3] = 0;
|
||||
}
|
||||
|
||||
static void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye,
|
||||
float xAt, float yAt, float zAt,
|
||||
float xUp, float yUp, float zUp) {
|
||||
float len, xLook, yLook, zLook, xRight, yRight, zRight;
|
||||
guMtxIdentF(mf);
|
||||
xLook = xAt - xEye; yLook = yAt - yEye; zLook = zAt - zEye;
|
||||
len = -1.0f / sqrtf(xLook*xLook + yLook*yLook + zLook*zLook);
|
||||
xLook *= len; yLook *= len; zLook *= len;
|
||||
xRight = yUp * zLook - zUp * yLook;
|
||||
yRight = zUp * xLook - xUp * zLook;
|
||||
zRight = xUp * yLook - yUp * xLook;
|
||||
len = 1.0f / sqrtf(xRight*xRight + yRight*yRight + zRight*zRight);
|
||||
xRight *= len; yRight *= len; zRight *= len;
|
||||
xUp = yLook * zRight - zLook * yRight;
|
||||
yUp = zLook * xRight - xLook * zRight;
|
||||
zUp = xLook * yRight - yLook * xRight;
|
||||
len = 1.0f / sqrtf(xUp*xUp + yUp*yUp + zUp*zUp);
|
||||
xUp *= len; yUp *= len; zUp *= len;
|
||||
mf[0][0] = xRight; mf[1][0] = yRight; mf[2][0] = zRight;
|
||||
mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
|
||||
mf[0][1] = xUp; mf[1][1] = yUp; mf[2][1] = zUp;
|
||||
mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
|
||||
mf[0][2] = xLook; mf[1][2] = yLook; mf[2][2] = zLook;
|
||||
mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
|
||||
mf[0][3] = 0; mf[1][3] = 0; mf[2][3] = 0; mf[3][3] = 1;
|
||||
}
|
||||
|
||||
static void guRotateF(float mf[4][4], float a, float x, float y, float z) {
|
||||
static float dtor = 3.1415926f / 180.0f;
|
||||
float sine, cosine, ab, bc, ca, t;
|
||||
float l = sqrtf(x*x + y*y + z*z);
|
||||
if (l != 0) { x /= l; y /= l; z /= l; }
|
||||
a *= dtor;
|
||||
sine = sinf(a); cosine = cosf(a);
|
||||
t = (1 - cosine);
|
||||
ab = x * y * t; bc = y * z * t; ca = z * x * t;
|
||||
guMtxIdentF(mf);
|
||||
t = x * x;
|
||||
mf[0][0] = t + cosine * (1 - t);
|
||||
mf[2][1] = bc - x * sine;
|
||||
mf[1][2] = bc + x * sine;
|
||||
t = y * y;
|
||||
mf[1][1] = t + cosine * (1 - t);
|
||||
mf[2][0] = ca + y * sine;
|
||||
mf[0][2] = ca - y * sine;
|
||||
t = z * z;
|
||||
mf[2][2] = t + cosine * (1 - t);
|
||||
mf[1][0] = ab - z * sine;
|
||||
mf[0][1] = ab + z * sine;
|
||||
}
|
||||
|
||||
/* ---- guMtxF2L pack / gfx_sp_matrix unpack (bit-exact path) ---- */
|
||||
|
||||
static void mtxf2l(const float mf[4][4], int32_t m[16]) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int e1 = (int)(mf[i][j*2] * 65536.0f);
|
||||
int e2 = (int)(mf[i][j*2+1] * 65536.0f);
|
||||
/* real guMtxF2L uses *(ai++)/*(af++): slot = i*2+j */
|
||||
m[i*2 + j] = (e1 & 0xffff0000) | ((e2 >> 16) & 0xffff);
|
||||
m[8 + i*2 + j] = ((e1 << 16) & 0xffff0000) | (e2 & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
static void sp_matrix_unpack(const int32_t addr[16], float matrix[4][4]) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j += 2) {
|
||||
int32_t int_part = addr[i * 2 + j / 2];
|
||||
uint32_t frac_part = addr[8 + i * 2 + j / 2];
|
||||
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
|
||||
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- gfx_pc.cpp conventions ---- */
|
||||
|
||||
static void mmul(float res[4][4], const float a[4][4], const float b[4][4]) {
|
||||
float tmp[4][4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
tmp[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j];
|
||||
for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) res[i][j] = tmp[i][j];
|
||||
}
|
||||
|
||||
/* row-vector vertex transform exactly as in gfx_sp_vertex */
|
||||
static void xform_row(const float MP[4][4], const float v[3], float c[4]) {
|
||||
c[0] = v[0]*MP[0][0] + v[1]*MP[1][0] + v[2]*MP[2][0] + MP[3][0];
|
||||
c[1] = v[0]*MP[0][1] + v[1]*MP[1][1] + v[2]*MP[2][1] + MP[3][1];
|
||||
c[2] = v[0]*MP[0][2] + v[1]*MP[1][2] + v[2]*MP[2][2] + MP[3][2];
|
||||
c[3] = v[0]*MP[0][3] + v[1]*MP[1][3] + v[2]*MP[2][3] + MP[3][3];
|
||||
}
|
||||
|
||||
/* standard column-vector transform c = A*B*v */
|
||||
static void xform_col(const float A[4][4], const float B[4][4], const float v[3], float c[4]) {
|
||||
float M[4][4];
|
||||
mmul(M, A, B);
|
||||
for (int i = 0; i < 4; i++)
|
||||
c[i] = M[i][0]*v[0] + M[i][1]*v[1] + M[i][2]*v[2] + M[i][3];
|
||||
}
|
||||
|
||||
static void report(const char *tag, const float c[4]) {
|
||||
float xw = c[3] != 0 ? c[0]/c[3] : 1e9f;
|
||||
float yw = c[3] != 0 ? c[1]/c[3] : 1e9f;
|
||||
printf(" %-34s clip=(%12.1f,%12.1f,%12.1f,%12.1f) x/w=%8.4f y/w=%8.4f %s\n",
|
||||
tag, c[0], c[1], c[2], c[3], xw, yw,
|
||||
(fabsf(xw) <= 1 && fabsf(yw) <= 1) ? "ON-SCREEN" : "off-screen");
|
||||
}
|
||||
|
||||
/* pack+unpack round-trip so we exercise the exact bit path */
|
||||
static void rt(const float mf[4][4], float out[4][4]) {
|
||||
int32_t m[16];
|
||||
mtxf2l(mf, m);
|
||||
sp_matrix_unpack(m, out);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
float Pge[4][4], Pstd[4][4], MVla[4][4], Rot[4][4];
|
||||
float MPours[4][4], MPalt[4][4], Mtot[4][4];
|
||||
float c[4];
|
||||
|
||||
printf("== SCENE 1: gun barrel (eye 1758.3,220,684.3 dir -0.97,0,0.24 up 0,1,0; fov46 n10 f10000) ==\n");
|
||||
guPerspectiveF_GE(Pge, 46.0f, 320.0f/240.0f, 10.0f, 10000.0f);
|
||||
guPerspectiveF_STD(Pstd, 46.0f, 320.0f/240.0f, 10.0f, 10000.0f);
|
||||
guLookAtF(MVla, 1758.2957f, 220.0f, 684.28143f,
|
||||
1758.2957f - 0.97f, 220.0f, 684.28143f + 0.24f, 0, 1, 0);
|
||||
rt(Pge, Pge); rt(MVla, MVla);
|
||||
|
||||
float v[3] = { -57.3f, -20.0f, 16.3f }; /* sample point offset from target */
|
||||
mmul(MPours, MVla, Pge); /* our MP for LOAD-only */
|
||||
xform_row(MPours, v, c);
|
||||
report("OURS row: v.MV.P_ge", c);
|
||||
xform_col(Pstd, MVla, v, c);
|
||||
report("TRUE col: P_std*MV*v", c);
|
||||
|
||||
printf("\n== SCENE 2: rareware logo (eye 0,0,880 at 0,0,879 up 0,1,0; fov60 n100 f5000; rotY -40deg) ==\n");
|
||||
guPerspectiveF_GE(Pge, 60.0f, 320.0f/240.0f, 100.0f, 5000.0f);
|
||||
guPerspectiveF_STD(Pstd, 60.0f, 320.0f/240.0f, 100.0f, 5000.0f);
|
||||
guLookAtF(MVla, 0, 0, 880.0f, 0, 0, 879.0f, 0, 1, 0);
|
||||
guRotateF(Rot, -40.0f, 0, 1, 0);
|
||||
rt(Pge, Pge); rt(MVla, MVla); rt(Rot, Rot);
|
||||
|
||||
float lv[3] = { 55.0f, 61.0f, 15.0f }; /* verts4258[0].ob */
|
||||
mmul(MPours, Rot, MVla); /* our code: new = matrix*old */
|
||||
mmul(MPours, MPours, Pge);
|
||||
xform_row(MPours, lv, c);
|
||||
report("OURS MUL (Rot*MV) then P", c);
|
||||
|
||||
mmul(MPalt, MVla, Rot); /* alt: new = old*matrix */
|
||||
mmul(MPalt, MPalt, Pge);
|
||||
xform_row(MPalt, lv, c);
|
||||
report("ALT MUL (MV*Rot) then P", c);
|
||||
|
||||
/* true standard pipeline: P_std * (MVla*Rot) * v [Rot applied first] */
|
||||
mmul(Mtot, MVla, Rot);
|
||||
xform_col(Pstd, Mtot, lv, c);
|
||||
report("TRUE col: P_std*MV*Rot*v", c);
|
||||
|
||||
/* and the other hardware-MUL interpretation: P_std * (Rot*MV) * v */
|
||||
mmul(Mtot, Rot, MVla);
|
||||
xform_col(Pstd, Mtot, lv, c);
|
||||
report("TRUE col: P_std*Rot*MV*v", c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user