diff --git a/F3D.cpp b/F3D.cpp index 36fde62d..c1ed6685 100644 --- a/F3D.cpp +++ b/F3D.cpp @@ -72,8 +72,10 @@ void F3D_MoveMem( u32 w0, u32 w1 ) gSPLight( w1, LIGHT_8 ); break; case G_MV_LOOKATX: + gSPLookAt(w1, 0); break; case G_MV_LOOKATY: + gSPLookAt(w1, 1); break; } } diff --git a/F3DEX2.cpp b/F3DEX2.cpp index c7329a65..0ac5983c 100644 --- a/F3DEX2.cpp +++ b/F3DEX2.cpp @@ -33,16 +33,14 @@ void F3DEX2_MoveMem( u32 w0, u32 w1 ) RSP.PC[RSP.PCi] += 8; break; case G_MV_LIGHT: - u32 offset = _SHIFTR( w0, 8, 8 ) << 3; - - if (offset >= 48) { - gSPLight( w1, (offset - 24) / 24); + const u32 offset = (_SHIFTR(w0, 5, 11))&0x7F8; + const u32 n = offset / 24; + if (n < 2) + gSPLookAt(w1, n); + else + gSPLight(w1, n - 1); } -/* else - { - // Do lookat stuff - }*/ break; } } diff --git a/RSP.cpp b/RSP.cpp index 2efbb791..cab5321d 100644 --- a/RSP.cpp +++ b/RSP.cpp @@ -268,4 +268,6 @@ void RSP_Init() gDP.loadTile = &gDP.tiles[7]; gSP.textureTile[0] = &gDP.tiles[0]; gSP.textureTile[1] = &gDP.tiles[1]; + gSP.lookat[0].x = gSP.lookat[1].x = 1.0f; + gSP.lookatEnable = false; } diff --git a/gSP.cpp b/gSP.cpp index f35915a1..46aa430e 100644 --- a/gSP.cpp +++ b/gSP.cpp @@ -326,15 +326,22 @@ void gSPProcessVertex( u32 v ) gSPLightVertex(v); if (gSP.geometryMode & G_TEXTURE_GEN) { - float fLightDir[3] = {vtx.nx, vtx.ny, vtx.nz}; + f32 fLightDir[3] = {vtx.nx, vtx.ny, vtx.nz}; TransformVectorNormalize(fLightDir, gSP.matrix.projection); - + f32 x, y; + if (gSP.lookatEnable) { + x = DotProduct(&gSP.lookat[0].x, fLightDir); + y = DotProduct(&gSP.lookat[1].x, fLightDir); + } else { + x = fLightDir[0]; + y = fLightDir[1]; + } if (gSP.geometryMode & G_TEXTURE_GEN_LINEAR) { - vtx.s = acosf(fLightDir[0]) * 325.94931f; - vtx.t = acosf(fLightDir[1]) * 325.94931f; + vtx.s = acosf(x) * 325.94931f; + vtx.t = acosf(y) * 325.94931f; } else { // G_TEXTURE_GEN - vtx.s = (fLightDir[0] + 1.0f) * 512.0f; - vtx.t = (fLightDir[1] + 1.0f) * 512.0f; + vtx.s = (x + 1.0f) * 512.0f; + vtx.t = (y + 1.0f) * 512.0f; } } } @@ -525,7 +532,7 @@ void gSPForceMatrix( u32 mptr ) void gSPLight( u32 l, s32 n ) { - n--; + --n; u32 address = RSP_SegmentToPhysical( l ); if ((address + sizeof( Light )) > RDRAMSize) { @@ -564,8 +571,28 @@ void gSPLight( u32 l, s32 n ) #endif } -void gSPLookAt( u32 l ) +void gSPLookAt( u32 _l, u32 _n ) { + u32 address = RSP_SegmentToPhysical(_l); + + if ((address + sizeof(Light)) > RDRAMSize) { +#ifdef DEBUG + DebugMsg(DEBUG_HIGH | DEBUG_ERROR, "// Attempting to load light from invalid address\n"); + DebugMsg(DEBUG_HIGH | DEBUG_HANDLED, "gSPLookAt( 0x%08X, LOOKAT_%i );\n", + l, n); +#endif + return; + } + + Light *light = (Light*)&RDRAM[address]; + + gSP.lookat[_n].x = light->x; + gSP.lookat[_n].y = light->y; + gSP.lookat[_n].z = light->z; + + gSP.lookatEnable = (_n == 0) || (_n == 1 && light->x != 0 && light->y != 0); + + Normalize(&gSP.lookat[_n].x); } void gSPVertex( u32 a, u32 n, u32 v0 ) diff --git a/gSP.h b/gSP.h index b3357951..c15a063c 100644 --- a/gSP.h +++ b/gSP.h @@ -106,6 +106,8 @@ struct gSPInfo u32 vertexi; SPLight lights[8]; + SPLight lookat[2]; + bool lookatEnable; struct { @@ -156,7 +158,7 @@ void gSPDMAMatrix( u32 matrix, u8 index, u8 multiply ); void gSPViewport( u32 v ); void gSPForceMatrix( u32 mptr ); void gSPLight( u32 l, s32 n ); -void gSPLookAt( u32 l ); +void gSPLookAt( u32 l, u32 n ); void gSPVertex( u32 v, u32 n, u32 v0 ); void gSPCIVertex( u32 v, u32 n, u32 v0 ); void gSPDMAVertex( u32 v, u32 n, u32 v0 );