X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Frice_gles%2Fsrc%2FRSP_GBI2.h;fp=source%2Frice_gles%2Fsrc%2FRSP_GBI2.h;h=22eb286216150ad02ada8f722ac9b9ed5cc0835a;hb=d07c171fa694cae985ad7045f9ce2b2f1a5699b4;hp=0000000000000000000000000000000000000000;hpb=ca22e7b76883b946060a6b40bb8709c1981e1cf6;p=mupen64plus-pandora.git diff --git a/source/rice_gles/src/RSP_GBI2.h b/source/rice_gles/src/RSP_GBI2.h new file mode 100644 index 0000000..22eb286 --- /dev/null +++ b/source/rice_gles/src/RSP_GBI2.h @@ -0,0 +1,923 @@ +/* +Copyright (C) 2002 Rice1964 + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "Render.h" +#include "Timing.h" + +void RSP_GBI2_Vtx(Gfx *gfx) +{ + uint32 addr = RSPSegmentAddr((gfx->gbi2vtx.addr)); + int vend = gfx->gbi2vtx.vend/2; + int n = gfx->gbi2vtx.n; + int v0 = vend - n; + + LOG_UCODE(" Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", addr, vend, v0, n); + + if( vend > 64 ) + { + DebuggerAppendMsg("Warning, attempting to load into invalid vertex positions, v0=%d, n=%d", v0, n); + return; + } + + if ((addr + (n*16)) > g_dwRamSize) + { + DebuggerAppendMsg("ProcessVertexData: Address out of range (0x%08x)", addr); + } + else + { + ProcessVertexData(addr, v0, n); + status.dwNumVertices += n; + DisplayVertexInfo(addr, v0, n); + } +} + +void RSP_GBI2_EndDL(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_EndDL); + + RDP_GFX_PopDL(); +} + +void RSP_GBI2_CullDL(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_CullDL); + +#ifdef DEBUGGER + if( !debuggerEnableCullFace ) + { + return; //Disable Culling + } +#endif + if( g_curRomInfo.bDisableCulling ) + { + return; //Disable Culling + } + + uint32 dwVFirst = (((gfx->words.w0)) & 0xfff) / gRSP.vertexMult; + uint32 dwVLast = (((gfx->words.w1)) & 0xfff) / gRSP.vertexMult; + + LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); + + // Mask into range + dwVFirst &= 0x1f; + dwVLast &= 0x1f; + + if( dwVLast < dwVFirst ) return; + if( !gRSP.bRejectVtx ) return; + + for (uint32 i = dwVFirst; i <= dwVLast; i++) + { + //if (g_dwVtxFlags[i] == 0) + if (g_clipFlag[i] == 0) + { + LOG_UCODE(" Vertex %d is visible, returning", i); + return; + } + } + + status.dwNumDListsCulled++; + + LOG_UCODE(" No vertices were visible, culling"); + + RDP_GFX_PopDL(); +} + +void RSP_GBI2_MoveWord(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_MoveWord); + + switch (gfx->gbi2moveword.type) + { + case RSP_MOVE_WORD_MATRIX: + RSP_RDP_InsertMatrix(gfx); + break; + case RSP_MOVE_WORD_NUMLIGHT: + { + uint32 dwNumLights = gfx->gbi2moveword.value/24; + gRSP.ambientLightIndex = dwNumLights; + SetNumLights(dwNumLights); + } + break; + + case RSP_MOVE_WORD_CLIP: + { + switch (gfx->gbi2moveword.offset) + { + case RSP_MV_WORD_OFFSET_CLIP_RNX: + case RSP_MV_WORD_OFFSET_CLIP_RNY: + case RSP_MV_WORD_OFFSET_CLIP_RPX: + case RSP_MV_WORD_OFFSET_CLIP_RPY: + CRender::g_pRender->SetClipRatio(gfx->gbi2moveword.offset, gfx->gbi2moveword.value); + default: + LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); + break; + } + } + break; + + case RSP_MOVE_WORD_SEGMENT: + { + uint32 dwSeg = gfx->gbi2moveword.offset / 4; + uint32 dwAddr = gfx->gbi2moveword.value & 0x00FFFFFF; // Hack - convert to physical + + LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Segment[%d] = 0x%08x", dwSeg, dwAddr); + if( dwAddr > g_dwRamSize ) + { + gRSP.segments[dwSeg] = dwAddr; +#ifdef DEBUGGER + if( pauseAtNext ) + DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSeg, dwAddr); +#endif + } + else + { + gRSP.segments[dwSeg] = dwAddr; + } + } + break; + case RSP_MOVE_WORD_FOG: + { + uint16 wMult = (uint16)((gfx->gbi2moveword.value >> 16) & 0xFFFF); + uint16 wOff = (uint16)((gfx->gbi2moveword.value ) & 0xFFFF); + + float fMult = (float)(short)wMult; + float fOff = (float)(short)wOff; + + float rng = 128000.0f / fMult; + float fMin = 500.0f - (fOff*rng/256.0f); + float fMax = rng + fMin; + + FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); + //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) + if( fMult <= 0 || fMax < 0 ) + { + // Hack + fMin = 996; + fMax = 1000; + fMult = 0; + fOff = 1; + } + + SetFogMinMax(fMin, fMax, fMult, fOff); + FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=0x%08X", fMin, fMax, gfx->gbi2moveword.value)); + } + break; + case RSP_MOVE_WORD_LIGHTCOL: + { + uint32 dwLight = gfx->gbi2moveword.offset / 0x18; + uint32 dwField = (gfx->gbi2moveword.offset & 0x7); + + switch (dwField) + { + case 0: + if (dwLight == gRSP.ambientLightIndex) + { + SetAmbientLight( (gfx->gbi2moveword.value>>8) ); + } + else + { + SetLightCol(dwLight, gfx->gbi2moveword.value); + } + break; + + case 4: + break; + + default: + DebuggerAppendMsg("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); + break; + } + + + } + break; + + case RSP_MOVE_WORD_PERSPNORM: + LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM 0x%04x", (short)gfx->words.w1); + break; + + case RSP_MOVE_WORD_POINTS: + LOG_UCODE(" 2nd cmd of Force Matrix"); + break; + + default: + { + LOG_UCODE(" Ignored!!"); + + } + break; + } +} + +void RSP_GBI2_Tri1(Gfx *gfx) +{ + if( gfx->words.w0 == 0x05000017 && gfx->gbi2tri1.flag == 0x80 ) + { + // The ObjLoadTxtr / Tlut cmd for Evangelion.v64 + RSP_S2DEX_SPObjLoadTxtr(gfx); + DebuggerAppendMsg("Fix me, SPObjLoadTxtr as RSP_GBI2_Tri2"); + } + else + { + status.primitiveType = PRIM_TRI1; + bool bTrisAdded = false; + bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); + + // While the next command pair is Tri1, add vertices + uint32 dwPC = gDlistStack[gDlistStackPointer].pc; + //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); + + do + { + uint32 dwV2 = gfx->gbi2tri1.v2/gRSP.vertexMult; + uint32 dwV1 = gfx->gbi2tri1.v1/gRSP.vertexMult; + uint32 dwV0 = gfx->gbi2tri1.v0/gRSP.vertexMult; + + if (IsTriangleVisible(dwV0, dwV1, dwV2)) + { + DEBUG_DUMP_VERTEXES("ZeldaTri1", dwV0, dwV1, dwV2); + LOG_UCODE(" ZeldaTri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); + if (!bTrisAdded) + { + if( bTexturesAreEnabled ) + { + PrepareTextures(); + InitVertexTextureConstants(); + } + + CRender::g_pRender->SetCombinerAndBlender(); + bTrisAdded = true; + } + PrepareTriangle(dwV0, dwV1, dwV2); + } + + gfx++; + dwPC += 8; + +#ifdef DEBUGGER + } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI1); +#else + } while( gfx->words.cmd == (uint8)RSP_ZELDATRI1); +#endif + + gDlistStack[gDlistStackPointer].pc = dwPC-8; + + if (bTrisAdded) + { + CRender::g_pRender->DrawTriangles(); + } + + DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI1")); + } +} + +void RSP_GBI2_Tri2(Gfx *gfx) +{ + if( gfx->words.w0 == 0x0600002f && gfx->gbi2tri2.flag == 0x80 ) + { + // The ObjTxSprite cmd for Evangelion.v64 + RSP_S2DEX_SPObjLoadTxSprite(gfx); + DebuggerAppendMsg("Fix me, SPObjLoadTxSprite as RSP_GBI2_Tri2"); + } + else + { + status.primitiveType = PRIM_TRI2; + BOOL bTrisAdded = FALSE; + + // While the next command pair is Tri2, add vertices + uint32 dwPC = gDlistStack[gDlistStackPointer].pc; + bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); + + do { + uint32 dwV2 = gfx->gbi2tri2.v2; + uint32 dwV1 = gfx->gbi2tri2.v1; + uint32 dwV0 = gfx->gbi2tri2.v0; + + uint32 dwV5 = gfx->gbi2tri2.v5; + uint32 dwV4 = gfx->gbi2tri2.v4; + uint32 dwV3 = gfx->gbi2tri2.v3; + + LOG_UCODE(" ZeldaTri2: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); + LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); + LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); + + // Do first tri + if (IsTriangleVisible(dwV0, dwV1, dwV2)) + { + DEBUG_DUMP_VERTEXES("ZeldaTri2 1/2", dwV0, dwV1, dwV2); + if (!bTrisAdded) + { + if( bTexturesAreEnabled ) + { + PrepareTextures(); + InitVertexTextureConstants(); + } + + CRender::g_pRender->SetCombinerAndBlender(); + bTrisAdded = true; + } + + PrepareTriangle(dwV0, dwV1, dwV2); + } + + // Do second tri + if (IsTriangleVisible(dwV3, dwV4, dwV5)) + { + DEBUG_DUMP_VERTEXES("ZeldaTri2 2/2", dwV3, dwV4, dwV5); + if (!bTrisAdded) + { + if( bTexturesAreEnabled ) + { + PrepareTextures(); + InitVertexTextureConstants(); + } + + CRender::g_pRender->SetCombinerAndBlender(); + bTrisAdded = true; + } + + PrepareTriangle(dwV3, dwV4, dwV5); + } + + gfx++; + dwPC += 8; + +#ifdef DEBUGGER + } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI2); +#else + } while ( gfx->words.cmd == (uint8)RSP_ZELDATRI2 );//&& status.dwNumTrisRendered < 50); +#endif + + + gDlistStack[gDlistStackPointer].pc = dwPC-8; + + if (bTrisAdded) + { + CRender::g_pRender->DrawTriangles(); + } + + DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI2")); + } +} + +void RSP_GBI2_Line3D(Gfx *gfx) +{ + if( gfx->words.w0 == 0x0700002f && (gfx->words.w1>>24) == 0x80 ) + { + // The ObjTxSprite cmd for Evangelion.v64 + RSP_S2DEX_SPObjLoadTxRect(gfx); + } + else + { + status.primitiveType = PRIM_TRI3; + + uint32 dwPC = gDlistStack[gDlistStackPointer].pc; + + BOOL bTrisAdded = FALSE; + + do { + uint32 dwV0 = gfx->gbi2line3d.v0/gRSP.vertexMult; + uint32 dwV1 = gfx->gbi2line3d.v1/gRSP.vertexMult; + uint32 dwV2 = gfx->gbi2line3d.v2/gRSP.vertexMult; + + uint32 dwV3 = gfx->gbi2line3d.v3/gRSP.vertexMult; + uint32 dwV4 = gfx->gbi2line3d.v4/gRSP.vertexMult; + uint32 dwV5 = gfx->gbi2line3d.v5/gRSP.vertexMult; + + LOG_UCODE(" ZeldaTri3: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); + LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); + LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); + + // Do first tri + if (IsTriangleVisible(dwV0, dwV1, dwV2)) + { + DEBUG_DUMP_VERTEXES("ZeldaTri3 1/2", dwV0, dwV1, dwV2); + if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) + { + PrepareTextures(); + InitVertexTextureConstants(); + } + + if( !bTrisAdded ) + { + CRender::g_pRender->SetCombinerAndBlender(); + } + + bTrisAdded = true; + PrepareTriangle(dwV0, dwV1, dwV2); + } + + // Do second tri + if (IsTriangleVisible(dwV3, dwV4, dwV5)) + { + DEBUG_DUMP_VERTEXES("ZeldaTri3 2/2", dwV3, dwV4, dwV5); + if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) + { + PrepareTextures(); + InitVertexTextureConstants(); + } + + if( !bTrisAdded ) + { + CRender::g_pRender->SetCombinerAndBlender(); + } + + bTrisAdded = true; + PrepareTriangle(dwV3, dwV4, dwV5); + } + + gfx++; + dwPC += 8; + +#ifdef DEBUGGER + } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_LINE3D); +#else + } while ( gfx->words.cmd == (uint8)RSP_LINE3D); +#endif + + gDlistStack[gDlistStackPointer].pc = dwPC-8; + + + if (bTrisAdded) + { + CRender::g_pRender->DrawTriangles(); + } + + DEBUG_TRIANGLE(TRACE0("Pause at GBI2 Line3D")); + } +} + +void RSP_GBI2_Texture(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_Texture); + + float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f); + float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); + + if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) + { + fTextureScaleS = 1/32.0f; + } + else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) + { + fTextureScaleS = 1/64.0f; + } + if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) + { + fTextureScaleT = 1/32.0f; + } + else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) + { + fTextureScaleT = 1/64.0f; + } + + CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); + + /* + if( g_curRomInfo.bTextureScaleHack ) + { + // Hack, need to verify, refer to N64 programming manual + // that if scale = 0.5 (1/64), vtx s,t are also doubled + + if( ((word1>>16)&0xFFFF) == 0x8000 ) + { + fTextureScaleS = 1/128.0f; + if( ((word1)&0xFFFF) == 0xFFFF ) + { + fTextureScaleT = 1/64.0f; + } + } + + if( ((word1 )&0xFFFF) == 0x8000 ) + { + fTextureScaleT = 1/128.0f; + if( ((word1>>16)&0xFFFF) == 0xFFFF ) + { + fTextureScaleS = 1/64.0f; + } + } + } + */ + + CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); + + LOG_TEXTURE( + { + DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); + DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); + }); + + DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); + + LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); + LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); +} + + + +void RSP_GBI2_PopMtx(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_PopMtx); + + uint8 nCommand = (uint8)(gfx->words.w0 & 0xFF); + + LOG_UCODE(" PopMtx: 0x%02x (%s)", + nCommand, + (nCommand & RSP_ZELDA_MTX_PROJECTION) ? "Projection" : "ModelView"); + + +/* if (nCommand & RSP_ZELDA_MTX_PROJECTION) + { + CRender::g_pRender->PopProjection(); + } + else*/ + { + CRender::g_pRender->PopWorldView(); + } +#ifdef DEBUGGER + if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) + { + pauseAtNext = false; + debuggerPause = true; + TRACE0("Pause after Pop GBI2_PopMtx:"); + } + else + { + if( pauseAtNext && logMatrix ) + { + TRACE0("Pause after Pop GBI2_PopMtx:"); + } + } +#endif + +} + + +#define RSP_ZELDA_ZBUFFER 0x00000001 // Guess +#define RSP_ZELDA_CULL_BACK 0x00000200 +#define RSP_ZELDA_CULL_FRONT 0x00000400 +#define RSP_ZELDA_FOG 0x00010000 +#define RSP_ZELDA_LIGHTING 0x00020000 +#define RSP_ZELDA_TEXTURE_GEN 0x00040000 +#define RSP_ZELDA_TEXTURE_GEN_LINEAR 0x00080000 +#define RSP_ZELDA_SHADING_SMOOTH 0x00200000 + +void RSP_GBI2_GeometryMode(Gfx *gfx) +{ + SP_Timing(RSP_GBI2_GeometryMode); + + uint32 dwAnd = ((gfx->words.w0)) & 0x00FFFFFF; + uint32 dwOr = ((gfx->words.w1)) & 0x00FFFFFF; + +#ifdef DEBUGGER + LOG_UCODE(" 0x%08x 0x%08x =(x & 0x%08x) | 0x%08x", gfx->words.w0, gfx->words.w1, dwAnd, dwOr); + + if ((~dwAnd) & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); + //if ((~dwAnd) & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); + //if ((~dwAnd) & RSP_ZELDA_SHADE) LOG_UCODE(" Disabling Shade"); + if ((~dwAnd) & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Disabling Flat Shading"); + if ((~dwAnd) & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); + if ((~dwAnd) & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); + if ((~dwAnd) & RSP_ZELDA_FOG) LOG_UCODE(" Disabling Fog"); + if ((~dwAnd) & RSP_ZELDA_LIGHTING) LOG_UCODE(" Disabling Lighting"); + if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); + if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); + // if ((~dwAnd) & RSP_ZELDA_LOD) LOG_UCODE(" Disabling LOD (no impl)"); + + if (dwOr & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); + //if (dwOr & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); + //if (dwOr & RSP_ZELDA_SHADE) LOG_UCODE(" Enabling Shade"); + if (dwOr & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Enabling Flat Shading"); + if (dwOr & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); + if (dwOr & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); + if (dwOr & RSP_ZELDA_FOG) LOG_UCODE(" Enabling Fog"); + if (dwOr & RSP_ZELDA_LIGHTING) LOG_UCODE(" Enabling Lighting"); + if (dwOr & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); + if (dwOr & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); + ///if (dwOr & RSP_ZELDA_LOD) LOG_UCODE(" Enabling LOD (no impl)"); +#endif // DEBUGGER + + gRDP.geometryMode &= dwAnd; + gRDP.geometryMode |= dwOr; + + + bool bCullFront = (gRDP.geometryMode & RSP_ZELDA_CULL_FRONT) ? true : false; + bool bCullBack = (gRDP.geometryMode & RSP_ZELDA_CULL_BACK) ? true : false; + + //BOOL bShade = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE; + //BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_SHADING_SMOOTH) ? TRUE : FALSE; + BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN_LINEAR) ? TRUE : FALSE; + if( options.enableHackForGames == HACK_FOR_TIGER_HONEY_HUNT ) + bFlatShade = FALSE; + + bool bFog = (gRDP.geometryMode & RSP_ZELDA_FOG) ? true : false; + bool bTextureGen = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN) ? true : false; + + bool bLighting = (gRDP.geometryMode & RSP_ZELDA_LIGHTING) ? true : false; + BOOL bZBuffer = (gRDP.geometryMode & RSP_ZELDA_ZBUFFER) ? TRUE : FALSE; + + CRender::g_pRender->SetCullMode(bCullFront, bCullBack); + + //if (bFlatShade||!bShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); + if (bFlatShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); + else CRender::g_pRender->SetShadeMode( SHADE_SMOOTH ); + + SetTextureGen(bTextureGen); + + SetLighting( bLighting ); + CRender::g_pRender->ZBufferEnable( bZBuffer ); + CRender::g_pRender->SetFogEnable( bFog ); +} + + +int dlistMtxCount=0; +extern uint32 dwConkerVtxZAddr; + +void RSP_GBI2_Mtx(Gfx *gfx) +{ + SP_Timing(RSP_GBI0_Mtx); + dwConkerVtxZAddr = 0; // For Conker BFD + + uint32 addr = RSPSegmentAddr((gfx->gbi2matrix.addr)); + + if( gfx->gbi2matrix.param == 0 && gfx->gbi2matrix.len == 0 ) + { + DLParser_Bomberman2TextRect(gfx); + return; + } + + LOG_UCODE(" Mtx: %s %s %s Length %d Address 0x%08x", + gfx->gbi2matrix.projection ? "Projection" : "ModelView", + gfx->gbi2matrix.load ? "Load" : "Mul", + gfx->gbi2matrix.nopush==0 ? "Push" : "No Push", + gfx->gbi2matrix.len, addr); + + if (addr + 64 > g_dwRamSize) + { + DebuggerAppendMsg("ZeldaMtx: Address invalid (0x%08x)", addr); + return; + } + + LoadMatrix(addr); + + if (gfx->gbi2matrix.projection) + { + // So far only Extreme-G seems to Push/Pop projection matrices + CRender::g_pRender->SetProjection(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); + } + else + { + CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); + + if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY ) + { + dlistMtxCount++; + if( dlistMtxCount == 2 ) + { + CRender::g_pRender->ClearZBuffer(1.0f); + } + } + } + +#ifdef DEBUGGER + const char *loadstr = gfx->gbi2matrix.load?"Load":"Mul"; + const char *pushstr = gfx->gbi2matrix.nopush==0?"Push":"Nopush"; + int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); + int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); + if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) + { + pauseAtNext = false; + debuggerPause = true; + if (gfx->gbi2matrix.projection) + { + DebuggerAppendMsg("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); + } + else + { + DebuggerAppendMsg("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); + } + } + else + { + if( pauseAtNext && logMatrix ) + { + if (gfx->gbi2matrix.projection) + { + DebuggerAppendMsg("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); + } + else + { + DebuggerAppendMsg("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); + } + } + } +#endif +} + +void RSP_GBI2_MoveMem(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_MoveMem); + + uint32 addr = RSPSegmentAddr((gfx->words.w1)); + uint32 type = ((gfx->words.w0) ) & 0xFE; + + //uint32 dwLen = ((gfx->words.w0) >> 16) & 0xFF; + //uint32 dwOffset = ((gfx->words.w0) >> 8) & 0xFFFF; + + switch (type) + { + case RSP_GBI2_MV_MEM__VIEWPORT: + { + RSP_MoveMemViewport(addr); + } + break; + case RSP_GBI2_MV_MEM__LIGHT: + { + uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF; + switch (dwOffset2) + { + case 0x00: + { + s8 * pcBase = g_pRDRAMs8 + addr; + LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX %f %f %f", + (float)pcBase[8 ^ 0x3], + (float)pcBase[9 ^ 0x3], + (float)pcBase[10 ^ 0x3]); + + } + break; + case 0x18: + { + s8 * pcBase = g_pRDRAMs8 + addr; + LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY %f %f %f", + (float)pcBase[8 ^ 0x3], + (float)pcBase[9 ^ 0x3], + (float)pcBase[10 ^ 0x3]); + } + break; + default: //0x30/48/60 + { + uint32 dwLight = (dwOffset2 - 0x30)/0x18; + LOG_UCODE(" Light %d:", dwLight); + RSP_MoveMemLight(dwLight, addr); + } + break; + } + break; + + } + case RSP_GBI2_MV_MEM__MATRIX: + LOG_UCODE("Force Matrix: addr=%08X", addr); + RSP_GFX_Force_Matrix(addr); + break; + case RSP_GBI2_MV_MEM_O_L0: + case RSP_GBI2_MV_MEM_O_L1: + case RSP_GBI2_MV_MEM_O_L2: + case RSP_GBI2_MV_MEM_O_L3: + case RSP_GBI2_MV_MEM_O_L4: + case RSP_GBI2_MV_MEM_O_L5: + case RSP_GBI2_MV_MEM_O_L6: + case RSP_GBI2_MV_MEM_O_L7: + LOG_UCODE("Zelda Move Light"); + RDP_NOIMPL_WARN("Zelda Move Light"); + break; + + case RSP_GBI2_MV_MEM__POINT: + LOG_UCODE("Zelda Move Point"); + void RDP_NOIMPL_WARN(const char* op); + RDP_NOIMPL_WARN("Zelda Move Point"); + break; + + case RSP_GBI2_MV_MEM_O_LOOKATX: + if( (gfx->words.w0) == 0xDC170000 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) + { + // Ucode for Evangelion.v64, the ObjMatrix cmd + RSP_S2DEX_OBJ_MOVEMEM(gfx); + } + break; + case RSP_GBI2_MV_MEM_O_LOOKATY: + RSP_RDP_NOIMPL("Not implemented ZeldaMoveMem LOOKATY, Cmd0=0x%08X, Cmd1=0x%08X", gfx->words.w0, gfx->words.w1); + break; + case 0x02: + if( (gfx->words.w0) == 0xDC070002 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) + { + RSP_S2DEX_OBJ_MOVEMEM(gfx); + break; + } + default: + LOG_UCODE("ZeldaMoveMem Type: Unknown"); + RSP_RDP_NOIMPL("Unknown ZeldaMoveMem Type, type=0x%X, Addr=%08X", type, addr); + break; + } +} + + + +void RSP_GBI2_DL(Gfx *gfx) +{ + SP_Timing(RSP_GBI0_DL); + + uint32 dwPush = ((gfx->words.w0) >> 16) & 0xFF; + uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); + + if( dwAddr > g_dwRamSize ) + { + RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc ); + dwAddr &= (g_dwRamSize-1); + DebuggerPauseCountN( NEXT_DLIST ); + } + + LOG_UCODE(" DL: Push:0x%02x Addr: 0x%08x", dwPush, dwAddr); + + switch (dwPush) + { + case RSP_DLIST_PUSH: + LOG_UCODE(" Pushing ZeldaDisplayList 0x%08x", dwAddr); + gDlistStackPointer++; + gDlistStack[gDlistStackPointer].pc = dwAddr; + gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; + + break; + case RSP_DLIST_NOPUSH: + LOG_UCODE(" Jumping to ZeldaDisplayList 0x%08x", dwAddr); + if( gDlistStack[gDlistStackPointer].pc == dwAddr+8 ) //Is this a loop + { + //Hack for Gauntlet Legends + gDlistStack[gDlistStackPointer].pc = dwAddr+8; + } + else + gDlistStack[gDlistStackPointer].pc = dwAddr; + gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; + break; + } + + LOG_UCODE(""); + LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); + LOG_UCODE("#############################################"); +} + + +void RSP_GBI2_SetOtherModeL(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_SetOtherModeL); + + uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; + uint32 dwLength= ((gfx->words.w0) )&0xFF; + uint32 dwData = (gfx->words.w1); + + // Mask is constructed slightly differently + uint32 dwMask = (uint32)((s32)(0x80000000)>>dwLength)>>dwShift; + dwData &= dwMask; + + uint32 modeL = gRDP.otherModeL; + modeL = (modeL&(~dwMask)) | dwData; + + Gfx tempgfx; + tempgfx.words.w0 = gRDP.otherModeH; + tempgfx.words.w1 = modeL; + DLParser_RDPSetOtherMode(&tempgfx ); +} + + +void RSP_GBI2_SetOtherModeH(Gfx *gfx) +{ + SP_Timing(RSP_GBI1_SetOtherModeH); + + uint32 dwLength= (((gfx->words.w0))&0xFF)+1; + uint32 dwShift = 32 - (((gfx->words.w0)>>8)&0xFF) - dwLength; + uint32 dwData = (gfx->words.w1); + + uint32 dwMask2 = ((1<words.w0), (gfx->words.w1)); +} +