diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index f5b4dfcde..ffa8fb026 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -2,7 +2,7 @@ Copyright (C) 2006 yopyop Copyright (C) 2006-2007 Theo Berkau Copyright (C) 2007 shash - Copyright (C) 2009-2022 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -581,7 +581,7 @@ typedef union u8 PolygonShading:1; // 1: Polygon shading mode, interacts with POLYGON_ATTR (0x40004A4); 0=Toon Shading, 1=Highlight Shading u8 EnableAlphaTest:1; // 2: Perform alpha test, interacts with ALPHA_TEST_REF (0x4000340); 0=Disable, 1=Enable u8 EnableAlphaBlending:1; // 3: Perform alpha blending, interacts with POLYGON_ATTR (0x40004A4); 0=Disable, 1=Enable - u8 EnableAntiAliasing:1; // 4: Render polygon edges with antialiasing; 0=Disable, 1=Enable + u8 EnableAntialiasing:1; // 4: Render polygon edges with antialiasing; 0=Disable, 1=Enable u8 EnableEdgeMarking:1; // 5: Perform polygon edge marking, interacts with EDGE_COLOR (0x4000330); 0=Disable, 1=Enable u8 FogOnlyAlpha:1; // 6: Apply fog to the alpha channel only, interacts with FOG_COLOR (0x4000358) / FOG_TABLE (0x4000360); 0=Color+Alpha, 1=Alpha u8 EnableFog:1; // 7: Perform fog rendering, interacts with FOG_COLOR (0x4000358) / FOG_OFFSET (0x400035C) / FOG_TABLE (0x4000360); @@ -600,7 +600,7 @@ typedef union // 0=Disable, 1=Enable u8 FogOnlyAlpha:1; // 6: Apply fog to the alpha channel only, interacts with FOG_COLOR (0x4000358) / FOG_TABLE (0x4000360); 0=Color+Alpha, 1=Alpha u8 EnableEdgeMarking:1; // 5: Perform polygon edge marking, interacts with EDGE_COLOR (0x4000330); 0=Disable, 1=Enable - u8 EnableAntiAliasing:1; // 4: Render polygon edges with antialiasing; 0=Disable, 1=Enable + u8 EnableAntialiasing:1; // 4: Render polygon edges with antialiasing; 0=Disable, 1=Enable u8 EnableAlphaBlending:1; // 3: Perform alpha blending, interacts with POLYGON_ATTR (0x40004A4); 0=Disable, 1=Enable u8 EnableAlphaTest:1; // 2: Perform alpha test, interacts with ALPHA_TEST_REF (0x4000340); 0=Disable, 1=Enable u8 PolygonShading:1; // 1: Polygon shading mode, interacts with POLYGON_ATTR (0x40004A4); 0=Toon Shading, 1=Highlight Shading diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index 5295a3ce8..5074ebd2e 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2007 shash - Copyright (C) 2007-2022 DeSmuME team + Copyright (C) 2007-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1830,13 +1830,28 @@ static void writereg_POWCNT1(const int size, const u32 adr, const u32 val) if(wasGeomEnabled && !isGeomEnabled) { //kill the geometry data when the power goes off - //but save these tables, first. they shouldnt be cleared. //so, so bad. we need to model this with hardware-like operations instead of c++ code - GFX3D_State prior = gfx3d.state; - reconstruct(&gfx3d.state); - memcpy(gfx3d.state.u16ToonTable, prior.u16ToonTable, sizeof(prior.u16ToonTable)); - //dont think we should save this one: it's sent with 3d commands, not random bonus immediate register writes like the toon table - //memcpy(gfx3d.state.shininessTable, prior.shininessTable, sizeof(prior.shininessTable)); + + // TODO: Test which geometry data should be cleared on power off. + // The code below doesn't make any sense. You would think that only the data that + // is derived from geometry commands (either via GXFIFO or if writing to registers + // 0x04000440 - 0x040006A4) is what should be cleared. And that outside of geometry + // command data, other data (even if related to the 3D engine) shouldn't be touched. + // This will need further testing, but for now, we'll leave things as they are. + // - 2023/01/22, rogerman + gfx3d.pendingState.DISP3DCNT.value = 0; + gfx3d.pendingState.DISP3DCNT.EnableTexMapping = 1; + gfx3d.pendingState.DISP3DCNT.PolygonShading = PolygonShadingMode_Toon; + gfx3d.pendingState.DISP3DCNT.EnableAlphaTest = 1; + gfx3d.pendingState.DISP3DCNT.EnableAlphaBlending = 1; + gfx3d.pendingState.SWAP_BUFFERS.value = 0; + gfx3d.pendingState.alphaTestRef = 0; + gfx3d.pendingState.clearDepth = DS_DEPTH15TO24(0x7FFF); + gfx3d.pendingState.clearColor = 0; + gfx3d.pendingState.fogColor = 0; + gfx3d.pendingState.fogOffset = 0; + gfx3d.pendingState.fogShift = 0; + memset(gfx3d.pendingState.shininessTable, 0, sizeof(gfx3d.pendingState.shininessTable)); } } @@ -3271,6 +3286,28 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) return; } + switch (adr >> 4) + { + case 0x400033: // Edge Mark Color Table + MMU.ARM9_REG[adr & 0xFFF] = val; + gfx3d_UpdateEdgeMarkColorTable((u8)(adr & 0x0000000F), val); + return; + + case 0x400036: + case 0x400037: // Fog Table + MMU.ARM9_REG[adr & 0xFFF] = val & 0x7F; + gfx3d_UpdateFogTable((u8)(adr & 0x0000001F), val & 0x7F); // Drop the highest bit of each 8-bit value to limit the range to [0...127] + return; + + case 0x400038: + case 0x400039: + case 0x40003A: + case 0x40003B: // Toon Table + MMU.ARM9_REG[adr & 0xFFF] = val; + gfx3d_UpdateToonTable((u8)(adr & 0x0000003F), val); + return; + } + GPUEngineA *mainEngine = GPU->GetEngineMain(); GPUEngineB *subEngine = GPU->GetEngineSub(); @@ -3615,18 +3652,6 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) case REG_DIVCNT+3: printf("ERROR 8bit DIVCNT+3 WRITE\n"); return; #endif - //fog table: only write bottom 7 bits - case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x01: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x03: - case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x05: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x07: - case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x09: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0B: - case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0D: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x0F: - case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x11: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x13: - case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x15: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x17: - case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x19: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1B: - case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1D: case eng_3D_FOG_TABLE+0x1E: case eng_3D_FOG_TABLE+0x1F: - val &= 0x7F; - break; - //ensata putchar port case 0x04FFF000: if(nds.ensataEmulation) @@ -3663,9 +3688,29 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) case eng_3D_CLEAR_COLOR+0: case eng_3D_CLEAR_COLOR+1: case eng_3D_CLEAR_COLOR+2: case eng_3D_CLEAR_COLOR+3: - T1WriteByte((u8*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val); + T1WriteByte((u8*)&gfx3d.pendingState.clearColor, adr-eng_3D_CLEAR_COLOR, val); break; + case eng_3D_CLEAR_DEPTH: + HostWriteByte(MMU.ARM9_REG, 0x0354, val); + gfx3d_glClearDepth(val); + return; + + case eng_3D_CLEAR_DEPTH+1: + HostWriteByte(MMU.ARM9_REG, 0x0355, val); + gfx3d_glClearDepth(val); + return; + + case eng_3D_CLRIMAGE_OFFSET: + HostWriteByte(MMU.ARM9_REG, 0x0356, val); + gfx3d_glClearImageOffset(val); + return; + + case eng_3D_CLRIMAGE_OFFSET+1: + HostWriteByte(MMU.ARM9_REG, 0x0357, val); + gfx3d_glClearImageOffset(val); + return; + case REG_VRAMCNTA: case REG_VRAMCNTB: case REG_VRAMCNTC: @@ -3761,13 +3806,23 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) switch (adr >> 4) { - //toon table - case 0x0400038: - case 0x0400039: - case 0x040003A: - case 0x040003B: - ((u16 *)(MMU.ARM9_REG))[(adr & 0xFFF)>>1] = val; - gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val); + case 0x400033: // Edge Mark Color Table + ((u16 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u16) >> 1)] = val; + gfx3d_UpdateEdgeMarkColorTable((u8)(adr & 0x0000000F), val); + return; + + case 0x400036: + case 0x400037: // Fog Table + ((u16 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u16) >> 1)] = val & 0x7F7F; + gfx3d_UpdateFogTable((u8)(adr & 0x0000001F), val & 0x7F7F); // Drop the highest bit of each 8-bit value to limit the range to [0...127] + return; + + case 0x400038: + case 0x400039: + case 0x40003A: + case 0x40003B: // Toon Table + ((u16 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u16) >> 1)] = val; + gfx3d_UpdateToonTable((u8)(adr & 0x0000003F), val); return; } @@ -4262,14 +4317,6 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) MMU_new.gxstat.write(16,adr,val); break; - //fog table: only write bottom 7 bits - case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x06: - case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0E: - case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x16: - case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1E: - val &= 0x7F7F; - break; - // Alpha test reference value - Parameters:1 case eng_3D_ALPHA_TEST_REF: HostWriteWord(MMU.ARM9_REG, 0x0340, val); @@ -4278,13 +4325,18 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) case eng_3D_CLEAR_COLOR: case eng_3D_CLEAR_COLOR+2: - T1WriteWord((u8*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val); + T1WriteWord((u8 *)&gfx3d.pendingState.clearColor, adr-eng_3D_CLEAR_COLOR, val); break; // Clear background depth setup - Parameters:2 case eng_3D_CLEAR_DEPTH: HostWriteWord(MMU.ARM9_REG, 0x0354, val); - gfx3d_glClearDepth(val); + gfx3d_glClearDepth(val); + return; + + case eng_3D_CLRIMAGE_OFFSET: + HostWriteWord(MMU.ARM9_REG, 0x0356, val); + gfx3d_glClearImageOffset(val); return; // Fog Color - Parameters:4b @@ -4477,16 +4529,23 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) // lookups by the compiler switch (adr >> 4) { - case 0x400033: //edge color table - ((u32 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> 2] = val; + case 0x400033: // Edge Mark Color Table + ((u32 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u32) >> 1)] = val; + gfx3d_UpdateEdgeMarkColorTable((u8)(adr & 0x0000000F), val); + return; + + case 0x400036: + case 0x400037: // Fog Table + ((u32 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u32) >> 1)] = val & 0x7F7F7F7F; + gfx3d_UpdateFogTable((u8)(adr & 0x0000001F), val & 0x7F7F7F7F); // Drop the highest bit of each 8-bit value to limit the range to [0...127] return; case 0x400038: case 0x400039: case 0x40003A: - case 0x40003B: //toon table - ((u32 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> 2] = val; - gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val); + case 0x40003B: // Toon Table + ((u32 *)(MMU.ARM9_REG))[(adr & 0xFFF) >> (sizeof(u32) >> 1)] = val; + gfx3d_UpdateToonTable((u8)(adr & 0x0000003F), val); return; case 0x400040: @@ -4790,12 +4849,6 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) case REG_POWCNT1: writereg_POWCNT1(32,adr,val); break; - //fog table: only write bottom 7 bits - case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0C: - case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1C: - val &= 0x7F7F7F7F; - break; - //ensata handshaking port? case 0x04FFF010: if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_ack && val == 0x13579bdf) @@ -4828,13 +4881,14 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) return; case eng_3D_CLEAR_COLOR: - T1WriteLong((u8*)&gfx3d.state.clearColor,0,val); + T1WriteLong((u8 *)&gfx3d.pendingState.clearColor, 0, val); break; // Clear background depth setup - Parameters:2 case eng_3D_CLEAR_DEPTH: HostWriteLong(MMU.ARM9_REG, 0x0354, val); - gfx3d_glClearDepth(val); + gfx3d_glClearDepth((u16)(val & 0x0000FFFF)); + gfx3d_glClearImageOffset((u16)(val >> 16)); return; // Fog Color - Parameters:4b diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 9cacd123d..60be4eb05 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1777,7 +1777,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const CPoly *clippedPolyList, c const POLY &initialPoly = *clippedPolyList[firstIndex].poly; TEXIMAGE_PARAM lastTexParams = initialPoly.texParam; u32 lastTexPalette = initialPoly.texPalette; - u32 lastViewport = initialPoly.viewport; + GFX3D_Viewport lastViewport = initialPoly.viewport; this->SetupTexture(initialPoly, firstIndex); this->SetupViewport(initialPoly.viewport); @@ -1806,7 +1806,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const CPoly *clippedPolyList, c } // Set up the viewport if it changed - if (lastViewport != thePoly.viewport) + if (lastViewport.value != thePoly.viewport.value) { lastViewport = thePoly.viewport; this->SetupViewport(thePoly.viewport); @@ -1833,7 +1833,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const CPoly *clippedPolyList, c if (lastPolyAttr.value == nextPoly.attribute.value && lastTexParams.value == nextPoly.texParam.value && lastTexPalette == nextPoly.texPalette && - lastViewport == nextPoly.viewport && + lastViewport.value == nextPoly.viewport.value && polyPrimitive == oglPrimitiveType[nextPoly.vtxFormat] && polyPrimitive != GL_LINE_LOOP && polyPrimitive != GL_LINE_STRIP && @@ -3874,7 +3874,7 @@ Render3DError OpenGLRenderer_1_2::DisableVertexAttributes() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr) +Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr) { OGLRenderRef &OGLRef = *this->ref; @@ -3957,7 +3957,7 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); - this->DrawPolygonsForIndexRange(clippedPolyList, clippedPolyCount, this->_clippedPolyOpaqueCount, clippedPolyCount - 1, indexOffset, lastPolyAttr); + this->DrawPolygonsForIndexRange(clippedPolyList, clippedPolyCount, clippedPolyOpaqueCount, clippedPolyCount - 1, indexOffset, lastPolyAttr); // Restore OpenGL states back to normal. this->_geometryProgramFlags = oldGProgramFlags; @@ -4157,7 +4157,7 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) +Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { OGLRenderRef &OGLRef = *this->ref; @@ -4166,11 +4166,11 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) return OGLERROR_BEGINGL_FAILED; } - this->_clippedPolyCount = engine.clippedPolyCount; - this->_clippedPolyOpaqueCount = engine.clippedPolyOpaqueCount; - this->_clippedPolyList = engine.clippedPolyList; + this->_clippedPolyCount = renderGList.clippedPolyCount; + this->_clippedPolyOpaqueCount = renderGList.clippedPolyOpaqueCount; + this->_clippedPolyList = (CPoly *)renderGList.clippedPolyList; - this->_enableAlphaBlending = (engine.renderState.enableAlphaBlending) ? true : false; + this->_enableAlphaBlending = (renderState.DISP3DCNT.EnableAlphaBlending) ? true : false; if (this->isVBOSupported) { @@ -4178,14 +4178,14 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); // Only copy as much vertex data as we need to, since this can be a potentially large upload size. - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * renderGList.vertListCount, renderGList.vertList); } else { // If VBOs aren't supported, we need to use the client-side buffers here. - OGLRef.vtxPtrPosition = &engine.vertList[0].coord; - OGLRef.vtxPtrTexCoord = &engine.vertList[0].texcoord; - OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&engine.vertList[0].color : OGLRef.color4fBuffer; + OGLRef.vtxPtrPosition = (GLvoid *)&renderGList.vertList[0].coord; + OGLRef.vtxPtrTexCoord = (GLvoid *)&renderGList.vertList[0].texcoord; + OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&renderGList.vertList[0].color : OGLRef.color4fBuffer; } // Generate the clipped polygon list. @@ -4197,10 +4197,10 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) const size_t polyType = thePoly.type; const VERT vert[4] = { - engine.vertList[thePoly.vertIndexes[0]], - engine.vertList[thePoly.vertIndexes[1]], - engine.vertList[thePoly.vertIndexes[2]], - engine.vertList[thePoly.vertIndexes[3]] + renderGList.vertList[thePoly.vertIndexes[0]], + renderGList.vertList[thePoly.vertIndexes[1]], + renderGList.vertList[thePoly.vertIndexes[2]], + renderGList.vertList[thePoly.vertIndexes[3]] }; if (this->isShaderSupported) @@ -4238,7 +4238,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) // Consolidate the vertex color and the poly alpha to our internal color buffer // so that OpenGL can use it. - const VERT *vertForAlpha = &engine.vertList[vertIndex]; + const VERT *vertForAlpha = &renderGList.vertList[vertIndex]; OGLRef.color4fBuffer[colorIndex+0] = divide6bitBy63_LUT[vertForAlpha->color[0]]; OGLRef.color4fBuffer[colorIndex+1] = divide6bitBy63_LUT[vertForAlpha->color[1]]; OGLRef.color4fBuffer[colorIndex+2] = divide6bitBy63_LUT[vertForAlpha->color[2]]; @@ -4289,29 +4289,29 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) } // Set up rendering states that will remain constant for the entire frame. - this->_pendingRenderStates.enableAntialiasing = (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE; - this->_pendingRenderStates.enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableAntialiasing = (renderState.DISP3DCNT.EnableAntialiasing) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableFogAlphaOnly = (renderState.DISP3DCNT.FogOnlyAlpha) ? GL_TRUE : GL_FALSE; this->_pendingRenderStates.clearPolyID = this->_clearAttributes.opaquePolyID; this->_pendingRenderStates.clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF; - this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef]; + this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[renderState.alphaTestRef]; if (this->_enableFog && this->_deviceInfo.isFogSupported) { this->_fogProgramKey.key = 0; - this->_fogProgramKey.offset = engine.renderState.fogOffset & 0x7FFF; - this->_fogProgramKey.shift = engine.renderState.fogShift; + this->_fogProgramKey.offset = renderState.fogOffset & 0x7FFF; + this->_fogProgramKey.shift = renderState.fogShift; - this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F]; - this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F]; - this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(engine.renderState.fogColor >> 10) & 0x0000001F]; - this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(engine.renderState.fogColor >> 16) & 0x0000001F]; - this->_pendingRenderStates.fogOffset = (GLfloat)(engine.renderState.fogOffset & 0x7FFF) / 32767.0f; - this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> engine.renderState.fogShift) / 32767.0f; + this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(renderState.fogColor ) & 0x0000001F]; + this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(renderState.fogColor >> 5) & 0x0000001F]; + this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(renderState.fogColor >> 10) & 0x0000001F]; + this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(renderState.fogColor >> 16) & 0x0000001F]; + this->_pendingRenderStates.fogOffset = (GLfloat)(renderState.fogOffset & 0x7FFF) / 32767.0f; + this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> renderState.fogShift) / 32767.0f; u8 fogDensityTable[32]; for (size_t i = 0; i < 32; i++) { - fogDensityTable[i] = (engine.renderState.fogDensityTable[i] == 127) ? 255 : engine.renderState.fogDensityTable[i] << 1; + fogDensityTable[i] = (renderState.fogDensityTable[i] == 127) ? 255 : renderState.fogDensityTable[i] << 1; } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -4321,12 +4321,12 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - const u8 alpha8 = (engine.renderState.enableAntialiasing) ? 0x80 : 0xFF; + const u8 alpha8 = (renderState.DISP3DCNT.EnableAntialiasing) ? 0x80 : 0xFF; FragmentColor edgeColor32[8]; for (size_t i = 0; i < 8; i++) { - edgeColor32[i].color = COLOR555TO8888(engine.renderState.edgeMarkColorTable[i] & 0x7FFF, alpha8); + edgeColor32[i].color = COLOR555TO8888(renderState.edgeMarkColorTable[i] & 0x7FFF, alpha8); } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -4337,10 +4337,10 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) if (this->isShaderSupported) { this->_geometryProgramFlags.value = 0; - this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0; - this->_geometryProgramFlags.EnableAlphaTest = (engine.renderState.enableAlphaTest) ? 1 : 0; + this->_geometryProgramFlags.EnableWDepth = renderState.SWAP_BUFFERS.DepthMode; + this->_geometryProgramFlags.EnableAlphaTest = renderState.DISP3DCNT.EnableAlphaTest; this->_geometryProgramFlags.EnableTextureSampling = (this->_enableTextureSampling) ? 1 : 0; - this->_geometryProgramFlags.ToonShadingMode = (engine.renderState.shading) ? 1 : 0; + this->_geometryProgramFlags.ToonShadingMode = renderState.DISP3DCNT.PolygonShading; this->_geometryProgramFlags.EnableFog = (this->_enableFog && this->_deviceInfo.isFogSupported) ? 1 : 0; this->_geometryProgramFlags.EnableEdgeMark = (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) ? 1 : 0; this->_geometryProgramFlags.OpaqueDrawMode = (this->_isDepthLEqualPolygonFacingSupported) ? 1 : 0; @@ -4351,14 +4351,14 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, engine.renderState.u16ToonTable); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderState.toonTable16); } } else { - if (engine.renderState.enableAlphaTest && (engine.renderState.alphaTestRef > 0)) + if (renderState.DISP3DCNT.EnableAlphaTest && (renderState.alphaTestRef > 0)) { - glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[engine.renderState.alphaTestRef]); + glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[renderState.alphaTestRef]); } else { @@ -4426,7 +4426,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() this->SetupPolygon(firstPoly, true, false); } - this->ZeroDstAlphaPass(this->_clippedPolyList, this->_clippedPolyCount, this->_enableAlphaBlending, indexOffset, lastPolyAttr); + this->ZeroDstAlphaPass(this->_clippedPolyList, this->_clippedPolyCount, this->_clippedPolyOpaqueCount, this->_enableAlphaBlending, indexOffset, lastPolyAttr); if (this->_clippedPolyOpaqueCount > 0) { @@ -4956,23 +4956,15 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, size_t polyR return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::SetupViewport(const u32 viewportValue) +Render3DError OpenGLRenderer_1_2::SetupViewport(const GFX3D_Viewport viewport) { const GLfloat wScalar = this->_framebufferWidth / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; const GLfloat hScalar = this->_framebufferHeight / (GLfloat)GPU_FRAMEBUFFER_NATIVE_HEIGHT; - VIEWPORT viewport; - viewport.decode(viewportValue); - - // The maximum viewport y-value is 191. Values above 191 need to wrap - // around and go negative. - // - // Test case: The Homie Rollerz character select screen sets the y-value - // to 253, which then wraps around to -2. - glViewport( viewport.x * wScalar, - (viewport.y > 191) ? (viewport.y - 0xFF) * hScalar : viewport.y * hScalar, - viewport.width * wScalar, - viewport.height * hScalar); + glViewport(viewport.x * wScalar, + viewport.y * hScalar, + viewport.width * wScalar, + viewport.height * hScalar); return OGLERROR_NOERR; } @@ -5446,7 +5438,7 @@ Render3DError OpenGLRenderer_2_0::DisableVertexAttributes() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) +Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { OGLRenderRef &OGLRef = *this->ref; @@ -5455,17 +5447,17 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) return OGLERROR_BEGINGL_FAILED; } - this->_clippedPolyCount = engine.clippedPolyCount; - this->_clippedPolyOpaqueCount = engine.clippedPolyOpaqueCount; - this->_clippedPolyList = engine.clippedPolyList; + this->_clippedPolyCount = renderGList.clippedPolyCount; + this->_clippedPolyOpaqueCount = renderGList.clippedPolyOpaqueCount; + this->_clippedPolyList = (CPoly *)renderGList.clippedPolyList; - this->_enableAlphaBlending = (engine.renderState.enableAlphaBlending) ? true : false; + this->_enableAlphaBlending = (renderState.DISP3DCNT.EnableAlphaBlending) ? true : false; glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); // Only copy as much vertex data as we need to, since this can be a potentially large upload size. - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * renderGList.vertListCount, renderGList.vertList); // Generate the clipped polygon list. bool renderNeedsToonTable = false; @@ -5476,10 +5468,10 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) const size_t polyType = thePoly.type; const VERT vert[4] = { - engine.vertList[thePoly.vertIndexes[0]], - engine.vertList[thePoly.vertIndexes[1]], - engine.vertList[thePoly.vertIndexes[2]], - engine.vertList[thePoly.vertIndexes[3]] + renderGList.vertList[thePoly.vertIndexes[0]], + renderGList.vertList[thePoly.vertIndexes[1]], + renderGList.vertList[thePoly.vertIndexes[2]], + renderGList.vertList[thePoly.vertIndexes[3]] }; for (size_t j = 0; j < polyType; j++) @@ -5527,29 +5519,29 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); // Set up rendering states that will remain constant for the entire frame. - this->_pendingRenderStates.enableAntialiasing = (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE; - this->_pendingRenderStates.enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableAntialiasing = (renderState.DISP3DCNT.EnableAntialiasing) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableFogAlphaOnly = (renderState.DISP3DCNT.FogOnlyAlpha) ? GL_TRUE : GL_FALSE; this->_pendingRenderStates.clearPolyID = this->_clearAttributes.opaquePolyID; this->_pendingRenderStates.clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF; - this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef]; + this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[renderState.alphaTestRef]; if (this->_enableFog && this->_deviceInfo.isFogSupported) { this->_fogProgramKey.key = 0; - this->_fogProgramKey.offset = engine.renderState.fogOffset & 0x7FFF; - this->_fogProgramKey.shift = engine.renderState.fogShift; + this->_fogProgramKey.offset = renderState.fogOffset & 0x7FFF; + this->_fogProgramKey.shift = renderState.fogShift; - this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F]; - this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F]; - this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(engine.renderState.fogColor >> 10) & 0x0000001F]; - this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(engine.renderState.fogColor >> 16) & 0x0000001F]; - this->_pendingRenderStates.fogOffset = (GLfloat)(engine.renderState.fogOffset & 0x7FFF) / 32767.0f; - this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> engine.renderState.fogShift) / 32767.0f; + this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(renderState.fogColor ) & 0x0000001F]; + this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(renderState.fogColor >> 5) & 0x0000001F]; + this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(renderState.fogColor >> 10) & 0x0000001F]; + this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(renderState.fogColor >> 16) & 0x0000001F]; + this->_pendingRenderStates.fogOffset = (GLfloat)(renderState.fogOffset & 0x7FFF) / 32767.0f; + this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> renderState.fogShift) / 32767.0f; u8 fogDensityTable[32]; for (size_t i = 0; i < 32; i++) { - fogDensityTable[i] = (engine.renderState.fogDensityTable[i] == 127) ? 255 : engine.renderState.fogDensityTable[i] << 1; + fogDensityTable[i] = (renderState.fogDensityTable[i] == 127) ? 255 : renderState.fogDensityTable[i] << 1; } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -5559,12 +5551,12 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - const u8 alpha8 = (engine.renderState.enableAntialiasing) ? 0x80 : 0xFF; + const u8 alpha8 = (renderState.DISP3DCNT.EnableAntialiasing) ? 0x80 : 0xFF; FragmentColor edgeColor32[8]; for (size_t i = 0; i < 8; i++) { - edgeColor32[i].color = COLOR555TO8888(engine.renderState.edgeMarkColorTable[i] & 0x7FFF, alpha8); + edgeColor32[i].color = COLOR555TO8888(renderState.edgeMarkColorTable[i] & 0x7FFF, alpha8); } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -5574,10 +5566,10 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) // Setup render states this->_geometryProgramFlags.value = 0; - this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0; - this->_geometryProgramFlags.EnableAlphaTest = (engine.renderState.enableAlphaTest) ? 1 : 0; + this->_geometryProgramFlags.EnableWDepth = renderState.SWAP_BUFFERS.DepthMode; + this->_geometryProgramFlags.EnableAlphaTest = renderState.DISP3DCNT.EnableAlphaTest; this->_geometryProgramFlags.EnableTextureSampling = (this->_enableTextureSampling) ? 1 : 0; - this->_geometryProgramFlags.ToonShadingMode = (engine.renderState.shading) ? 1 : 0; + this->_geometryProgramFlags.ToonShadingMode = renderState.DISP3DCNT.PolygonShading; this->_geometryProgramFlags.EnableFog = (this->_enableFog && this->_deviceInfo.isFogSupported) ? 1 : 0; this->_geometryProgramFlags.EnableEdgeMark = (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) ? 1 : 0; this->_geometryProgramFlags.OpaqueDrawMode = (this->_isDepthLEqualPolygonFacingSupported) ? 1 : 0; @@ -5588,7 +5580,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, engine.renderState.u16ToonTable); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderState.toonTable16); } glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 9a997549a..6c2e72fb4 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -323,7 +323,7 @@ enum OGLTextureUnitID OGLTextureUnitID_DepthStencil, OGLTextureUnitID_GPolyID, OGLTextureUnitID_FogAttr, - OGLTextureUnitID_PolyStates, + OGLTextureUnitID_PolyStates, OGLTextureUnitID_LookupTable, }; @@ -604,8 +604,6 @@ struct OGLRenderRef }; struct GFX3D_State; -struct POLYLIST; -struct INDEXLIST; struct POLY; class OpenGLRenderer; @@ -876,13 +874,13 @@ protected: virtual void _SetupGeometryShaders(const OGLGeometryFlags flags); virtual Render3DError EnableVertexAttributes(); virtual Render3DError DisableVertexAttributes(); - virtual Render3DError ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); + virtual Render3DError ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); virtual void _ResolveWorkingBackFacing(); virtual void _ResolveGeometry(); virtual Render3DError ReadBackPixels(); // Base rendering methods - virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError RenderGeometry(); virtual Render3DError PostprocessFramebuffer(); virtual Render3DError EndRender(); @@ -893,7 +891,7 @@ protected: virtual void SetPolygonIndex(const size_t index); virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer); virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); - virtual Render3DError SetupViewport(const u32 viewportValue); + virtual Render3DError SetupViewport(const GFX3D_Viewport viewport); virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID); @@ -916,7 +914,7 @@ protected: virtual Render3DError EnableVertexAttributes(); virtual Render3DError DisableVertexAttributes(); - virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); }; diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index b61a251dd..100719ab7 100755 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1758,7 +1758,7 @@ Render3DError OpenGLRenderer_3_2::DisableVertexAttributes() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr) +Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr) { OGLRenderRef &OGLRef = *this->ref; @@ -1816,7 +1816,7 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const CPoly *clippedPolyList, glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); - this->DrawPolygonsForIndexRange(clippedPolyList, clippedPolyCount, this->_clippedPolyOpaqueCount, clippedPolyCount - 1, indexOffset, lastPolyAttr); + this->DrawPolygonsForIndexRange(clippedPolyList, clippedPolyCount, clippedPolyOpaqueCount, clippedPolyCount - 1, indexOffset, lastPolyAttr); // Restore OpenGL states back to normal. this->_geometryProgramFlags = oldGProgramFlags; @@ -1973,7 +1973,7 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) +Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { OGLRenderRef &OGLRef = *this->ref; @@ -1982,11 +1982,11 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) return OGLERROR_BEGINGL_FAILED; } - this->_clippedPolyCount = engine.clippedPolyCount; - this->_clippedPolyOpaqueCount = engine.clippedPolyOpaqueCount; - this->_clippedPolyList = engine.clippedPolyList; + this->_clippedPolyCount = renderGList.clippedPolyCount; + this->_clippedPolyOpaqueCount = renderGList.clippedPolyOpaqueCount; + this->_clippedPolyList = (CPoly *)renderGList.clippedPolyList; - this->_enableAlphaBlending = (engine.renderState.enableAlphaBlending) ? true : false; + this->_enableAlphaBlending = (renderState.DISP3DCNT.EnableAlphaBlending) ? true : false; glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); @@ -1999,9 +1999,9 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) glDeleteSync(this->_syncBufferSetup); } - const size_t vtxBufferSize = sizeof(VERT) * engine.vertListCount; + const size_t vtxBufferSize = sizeof(VERT) * renderGList.vertListCount; VERT *vtxPtr = (VERT *)glMapBufferRange(GL_ARRAY_BUFFER, 0, vtxBufferSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - memcpy(vtxPtr, engine.vertList, vtxBufferSize); + memcpy(vtxPtr, renderGList.vertList, vtxBufferSize); glUnmapBuffer(GL_ARRAY_BUFFER); this->_syncBufferSetup = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -2025,10 +2025,10 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) const size_t polyType = thePoly.type; const VERT vert[4] = { - engine.vertList[thePoly.vertIndexes[0]], - engine.vertList[thePoly.vertIndexes[1]], - engine.vertList[thePoly.vertIndexes[2]], - engine.vertList[thePoly.vertIndexes[3]] + renderGList.vertList[thePoly.vertIndexes[0]], + renderGList.vertList[thePoly.vertIndexes[1]], + renderGList.vertList[thePoly.vertIndexes[2]], + renderGList.vertList[thePoly.vertIndexes[3]] }; for (size_t j = 0; j < polyType; j++) @@ -2075,19 +2075,19 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); // Set up rendering states that will remain constant for the entire frame. - this->_pendingRenderStates.enableAntialiasing = (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE; - this->_pendingRenderStates.enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableAntialiasing = (renderState.DISP3DCNT.EnableAntialiasing) ? GL_TRUE : GL_FALSE; + this->_pendingRenderStates.enableFogAlphaOnly = (renderState.DISP3DCNT.FogOnlyAlpha) ? GL_TRUE : GL_FALSE; this->_pendingRenderStates.clearPolyID = this->_clearAttributes.opaquePolyID; this->_pendingRenderStates.clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF; - this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef]; + this->_pendingRenderStates.alphaTestRef = divide5bitBy31_LUT[renderState.alphaTestRef]; if (renderNeedsToonTable) { for (size_t i = 0; i < 32; i++) { - this->_pendingRenderStates.toonColor[i].r = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] ) & 0x001F]; - this->_pendingRenderStates.toonColor[i].g = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 5) & 0x001F]; - this->_pendingRenderStates.toonColor[i].b = divide5bitBy31_LUT[(engine.renderState.u16ToonTable[i] >> 10) & 0x001F]; + this->_pendingRenderStates.toonColor[i].r = divide5bitBy31_LUT[(renderState.toonTable16[i] ) & 0x001F]; + this->_pendingRenderStates.toonColor[i].g = divide5bitBy31_LUT[(renderState.toonTable16[i] >> 5) & 0x001F]; + this->_pendingRenderStates.toonColor[i].b = divide5bitBy31_LUT[(renderState.toonTable16[i] >> 10) & 0x001F]; this->_pendingRenderStates.toonColor[i].a = 1.0f; } } @@ -2095,20 +2095,20 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) if (this->_enableFog) { this->_fogProgramKey.key = 0; - this->_fogProgramKey.offset = engine.renderState.fogOffset & 0x7FFF; - this->_fogProgramKey.shift = engine.renderState.fogShift; + this->_fogProgramKey.offset = renderState.fogOffset & 0x7FFF; + this->_fogProgramKey.shift = renderState.fogShift; - this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F]; - this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F]; - this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(engine.renderState.fogColor >> 10) & 0x0000001F]; - this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(engine.renderState.fogColor >> 16) & 0x0000001F]; - this->_pendingRenderStates.fogOffset = (GLfloat)(engine.renderState.fogOffset & 0x7FFF) / 32767.0f; - this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> engine.renderState.fogShift) / 32767.0f; + this->_pendingRenderStates.fogColor.r = divide5bitBy31_LUT[(renderState.fogColor ) & 0x0000001F]; + this->_pendingRenderStates.fogColor.g = divide5bitBy31_LUT[(renderState.fogColor >> 5) & 0x0000001F]; + this->_pendingRenderStates.fogColor.b = divide5bitBy31_LUT[(renderState.fogColor >> 10) & 0x0000001F]; + this->_pendingRenderStates.fogColor.a = divide5bitBy31_LUT[(renderState.fogColor >> 16) & 0x0000001F]; + this->_pendingRenderStates.fogOffset = (GLfloat)(renderState.fogOffset & 0x7FFF) / 32767.0f; + this->_pendingRenderStates.fogStep = (GLfloat)(0x0400 >> renderState.fogShift) / 32767.0f; u8 fogDensityTable[32]; for (size_t i = 0; i < 32; i++) { - fogDensityTable[i] = (engine.renderState.fogDensityTable[i] == 127) ? 255 : engine.renderState.fogDensityTable[i] << 1; + fogDensityTable[i] = (renderState.fogDensityTable[i] == 127) ? 255 : renderState.fogDensityTable[i] << 1; } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -2117,12 +2117,12 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) if (this->_enableEdgeMark) { - const GLfloat edgeColorAlpha = (engine.renderState.enableAntialiasing) ? (16.0f/31.0f) : 1.0f; + const GLfloat edgeColorAlpha = (renderState.DISP3DCNT.EnableAntialiasing) ? (16.0f/31.0f) : 1.0f; for (size_t i = 0; i < 8; i++) { - this->_pendingRenderStates.edgeColor[i].r = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] ) & 0x001F]; - this->_pendingRenderStates.edgeColor[i].g = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 5) & 0x001F]; - this->_pendingRenderStates.edgeColor[i].b = divide5bitBy31_LUT[(engine.renderState.edgeMarkColorTable[i] >> 10) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].r = divide5bitBy31_LUT[(renderState.edgeMarkColorTable[i] ) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].g = divide5bitBy31_LUT[(renderState.edgeMarkColorTable[i] >> 5) & 0x001F]; + this->_pendingRenderStates.edgeColor[i].b = divide5bitBy31_LUT[(renderState.edgeMarkColorTable[i] >> 10) & 0x001F]; this->_pendingRenderStates.edgeColor[i].a = edgeColorAlpha; } } @@ -2176,10 +2176,10 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine) // Set up the default draw call states. this->_geometryProgramFlags.value = 0; - this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0; - this->_geometryProgramFlags.EnableAlphaTest = (engine.renderState.enableAlphaTest) ? 1 : 0; + this->_geometryProgramFlags.EnableWDepth = renderState.SWAP_BUFFERS.DepthMode; + this->_geometryProgramFlags.EnableAlphaTest = renderState.DISP3DCNT.EnableAlphaTest; this->_geometryProgramFlags.EnableTextureSampling = (this->_enableTextureSampling) ? 1 : 0; - this->_geometryProgramFlags.ToonShadingMode = (engine.renderState.shading) ? 1 : 0; + this->_geometryProgramFlags.ToonShadingMode = renderState.DISP3DCNT.PolygonShading; this->_geometryProgramFlags.EnableFog = (this->_enableFog) ? 1 : 0; this->_geometryProgramFlags.EnableEdgeMark = (this->_enableEdgeMark) ? 1 : 0; this->_geometryProgramFlags.OpaqueDrawMode = 1; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index db38cfaba..a14bac89a 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2019 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -98,11 +98,11 @@ protected: virtual void _SetupGeometryShaders(const OGLGeometryFlags flags); virtual Render3DError EnableVertexAttributes(); virtual Render3DError DisableVertexAttributes(); - virtual Render3DError ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); + virtual Render3DError ZeroDstAlphaPass(const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); virtual void _ResolveWorkingBackFacing(); virtual void _ResolveGeometry(); virtual Render3DError ReadBackPixels(); - virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError PostprocessFramebuffer(); virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID); diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 3bf13beae..a409a878e 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,12 +20,6 @@ //This handles almost all of the work of 3d rendering, leaving the renderer //plugin responsible only for drawing primitives. -//--------------- -//TODO TODO TODO TODO -//make up mind once and for all whether fog, toon, etc. should reside in memory buffers (for easier handling in MMU) -//if they do, then we need to copy them out in doFlush!!! -//--------------- - //old tests of matrix stack: //without the mymode==(texture) namco classics galaxian will try to use pos=1 and overrun the stack, corrupting emu //according to gbatek, 31 works but sets the stack overflow flag. spider-man 2 tests this on the spiderman model (and elsewhere) @@ -266,9 +260,13 @@ using std::max; using std::min; GFX3D gfx3d; -Viewer3d_State* viewer3d_state = NULL; +GFX3D_IOREG *_GFX3D_IORegisterMap = NULL; +Viewer3D_State viewer3D; static GFX3D_Clipper boxtestClipper; +LegacyGFX3DStateSFormat legacyGFX3DStateSFormatPending; +LegacyGFX3DStateSFormat legacyGFX3DStateSFormatApplied; + //tables that are provided to anyone CACHE_ALIGN u32 dsDepthExtend_15bit_to_24bit[32768]; @@ -305,7 +303,9 @@ static CACHE_ALIGN s32 trans[4] = {0, 0, 0, 0}; static u8 transind = 0; static CACHE_ALIGN s32 scale[4] = {0, 0, 0, 0}; static u8 scaleind = 0; -static u32 viewport = 0; + +static GFX3D_Viewport gfx3dViewport; +static IOREG_VIEWPORT viewportLegacySave; // For save state compatibility //various other registers static s32 _t=0, _s=0; @@ -360,21 +360,14 @@ static CACHE_ALIGN s32 cacheHalfVector[4][4]; #define RENDER_BACK_SURFACE 0X40 -//-------------poly and vertex lists and such things -POLYLIST* polylists = NULL; -POLYLIST* polylist = NULL; -VERT *vertLists = NULL; -VERT *vertList = NULL; - +//-------------working polygon lists GFX3D_Clipper *_clipper = NULL; -CPoly _clippedPolyWorkingList[POLYLIST_SIZE * 2]; -CPoly _clippedPolyUnsortedList[POLYLIST_SIZE]; -CPoly _clippedPolySortedList[POLYLIST_SIZE]; +static PAGE_ALIGN int _polyWorkingIndexList[INDEXLIST_SIZE]; +static PAGE_ALIGN CPoly _clippedPolyWorkingList[POLYLIST_SIZE * 2]; +static PAGE_ALIGN CPoly _clippedPolyUnsortedList[POLYLIST_SIZE]; -size_t vertListCount[2] = {0, 0}; int polygonListCompleted = 0; -static int listTwiddle = 1; static u8 triStripToggle; //list-building state @@ -388,18 +381,6 @@ struct tmpVertInfo BOOL first; } tempVertInfo; - -static void twiddleLists() -{ - listTwiddle++; - listTwiddle &= 1; - polylist = &polylists[listTwiddle]; - vertList = vertLists + (VERTLIST_SIZE * listTwiddle); - polylist->count = 0; - polylist->opaqueCount = 0; - vertListCount[listTwiddle] = 0; -} - static BOOL drawPending = FALSE; //------------------------------------------------------------ @@ -412,10 +393,37 @@ static void makeTables() // Is GBATEK actually correct here? Let's try using a simplified formula and see if it's // more accurate. - dsDepthExtend_15bit_to_24bit[i] = (i * 0x0200) + 0x01FF; + dsDepthExtend_15bit_to_24bit[i] = (u32)((i * 0x0200) + 0x01FF); } } +GFX3D_Viewport GFX3D_ViewportParse(const u32 inValue) +{ + GFX3D_Viewport outViewport; + IOREG_VIEWPORT reg; + + reg.value = inValue; + + //I'm 100% sure this is basically 99% correct + //the modular math is right. the details of how the +1 is handled may be wrong (this might should be dealt with in the viewport transformation instead) + //Its an off by one error in any event so we may never know + outViewport.width = (u8)(reg.X2 - reg.X1) + 1; + outViewport.height = (u8)(reg.Y2 - reg.Y1) + 1; + outViewport.x = (s16)reg.X1; + + //test: homie rollerz character select chooses nonsense for Y. they did the math backwards. their goal was a fullscreen viewport, they just messed up. + //they also messed up the width... + + // The maximum viewport y-value is 191. Values above 191 need to wrap + // around and go negative. + // + // Test case: The Homie Rollerz character select screen sets the y-value + // to 253, which then wraps around to -2. + outViewport.y = (reg.Y1 > 191) ? ((s16)reg.Y1 - 0x00FF) : (s16)reg.Y1; + + return outViewport; +} + void POLY::save(EMUFILE &os) { os.write_32LE((u32)type); @@ -426,7 +434,7 @@ void POLY::save(EMUFILE &os) os.write_32LE(attribute.value); os.write_32LE(texParam.value); os.write_32LE(texPalette); - os.write_32LE(viewport); + os.write_32LE(viewportLegacySave.value); os.write_floatLE(miny); os.write_floatLE(maxy); } @@ -444,9 +452,11 @@ void POLY::load(EMUFILE &is) is.read_32LE(attribute.value); is.read_32LE(texParam.value); is.read_32LE(texPalette); - is.read_32LE(viewport); + is.read_32LE(viewportLegacySave.value); is.read_floatLE(miny); is.read_floatLE(maxy); + + viewport = GFX3D_ViewportParse(viewportLegacySave.value); } void VERT::save(EMUFILE &os) @@ -482,6 +492,8 @@ void VERT::load(EMUFILE &is) void gfx3d_init() { + _GFX3D_IORegisterMap = (GFX3D_IOREG *)(&MMU.ARM9_REG[0x0320]); + _clipper = new GFX3D_Clipper; _clipper->SetClippedPolyBufferPtr(_clippedPolyWorkingList); @@ -506,37 +518,6 @@ void gfx3d_init() //DWORD diff2 = end-start; //printf("SPEED TEST %d %d\n",diff,diff2); - - // Use malloc() instead of new because, for some unknown reason, GCC 4.9 has a bug - // that causes a std::bad_alloc exception on certain memory allocations. Right now, - // POLYLIST and VERT are POD-style structs, so malloc() can substitute for new - // in this case. - if (polylists == NULL) - { - polylists = (POLYLIST *)malloc_alignedPage(sizeof(POLYLIST) * 2); - polylist = &polylists[0]; - } - - if (vertLists == NULL) - { - vertLists = (VERT *)malloc_alignedPage(VERTLIST_SIZE * sizeof(VERT) * 2); - vertList = vertLists; - - vertListCount[0] = 0; - vertListCount[1] = 0; - } - - gfx3d.state.savedDISP3DCNT.value = 0; - gfx3d.state.fogDensityTable = MMU.ARM9_REG+0x0360; - gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.ARM9_REG+0x0330); - - //TODO: these should probably be copied into renderState when it's latched.. - //THIS IS A SUPER BAD HACK - //see TODO TODO TODO TODO - gfx3d.renderState.fogDensityTable = MMU.ARM9_REG+0x0360; - gfx3d.renderState.edgeMarkColorTable = (u16 *)(MMU.ARM9_REG+0x0330); - - gfx3d.render3DFrameCount = 0; makeTables(); Render3D_Init(); @@ -545,15 +526,6 @@ void gfx3d_init() void gfx3d_deinit() { Render3D_DeInit(); - - free_aligned(polylists); - polylists = NULL; - polylist = NULL; - - free_aligned(vertLists); - vertLists = NULL; - vertList = NULL; - delete _clipper; } @@ -570,24 +542,28 @@ void gfx3d_reset() max_polys = max_verts = 0; #endif - reconstruct(&gfx3d); - delete viewer3d_state; - viewer3d_state = new Viewer3d_State(); + memset(&viewer3D, 0, sizeof(Viewer3D_State)); gxf_hardware.reset(); drawPending = FALSE; - memset(polylists, 0, sizeof(POLYLIST)*2); - memset(vertLists, 0, VERTLIST_SIZE * sizeof(VERT) * 2); - gfx3d.state.invalidateToon = true; - listTwiddle = 1; - twiddleLists(); - gfx3d.polylist = polylist; - gfx3d.vertList = vertList; - gfx3d.vertListCount = vertListCount[listTwiddle]; - gfx3d.clippedPolyCount = 0; - gfx3d.clippedPolyOpaqueCount = 0; - gfx3d.clippedPolyList = _clippedPolySortedList; + + memset(&gfx3d, 0, sizeof(GFX3D)); + + gfx3d.pendingState.DISP3DCNT.EnableTexMapping = 1; + gfx3d.pendingState.DISP3DCNT.PolygonShading = PolygonShadingMode_Toon; + gfx3d.pendingState.DISP3DCNT.EnableAlphaTest = 1; + gfx3d.pendingState.DISP3DCNT.EnableAlphaBlending = 1; + gfx3d.pendingState.clearDepth = DS_DEPTH15TO24(0x7FFF); + + gfx3d.appliedState.DISP3DCNT.EnableTexMapping = 1; + gfx3d.appliedState.DISP3DCNT.PolygonShading = PolygonShadingMode_Toon; + gfx3d.appliedState.DISP3DCNT.EnableAlphaTest = 1; + gfx3d.appliedState.DISP3DCNT.EnableAlphaBlending = 1; + gfx3d.appliedState.clearDepth = DS_DEPTH15TO24(0x7FFF); + + gfx3d.pendingListIndex = 0; + gfx3d.appliedListIndex = 1; polyAttrInProcess.value = 0; currentPolyAttr.value = 0; @@ -601,7 +577,6 @@ void gfx3d_reset() transind = 0; memset(scale, 0, sizeof(scale)); scaleind = 0; - viewport = 0; memset(gxPIPE.cmd, 0, sizeof(gxPIPE.cmd)); memset(gxPIPE.param, 0, sizeof(gxPIPE.param)); memset(colorRGB, 0, sizeof(colorRGB)); @@ -640,7 +615,17 @@ void gfx3d_reset() _s=0; last_t = 0; last_s = 0; - viewport = 0xBFFF0000; + + gfx3dViewport.x = 0; + gfx3dViewport.y = 0; + gfx3dViewport.width = 256; + gfx3dViewport.height = 192; + + // Init for save state compatibility + _GFX3D_IORegisterMap->VIEWPORT.X1 = viewportLegacySave.X1 = 0; + _GFX3D_IORegisterMap->VIEWPORT.Y1 = viewportLegacySave.Y1 = 0; + _GFX3D_IORegisterMap->VIEWPORT.X2 = viewportLegacySave.X2 = 255; + _GFX3D_IORegisterMap->VIEWPORT.Y2 = viewportLegacySave.Y2 = 191; clInd2 = 0; isSwapBuffers = FALSE; @@ -648,8 +633,6 @@ void gfx3d_reset() GFX_PIPEclear(); GFX_FIFOclear(); - gfx3d.render3DFrameCount = 0; - CurrentRenderer->Reset(); } @@ -696,10 +679,12 @@ static void GEM_TransformVertex(const s32 (&__restrict mtx)[16], s32 (&__restric //--------------- -#define SUBMITVERTEX(ii, nn) polylist->list[polylist->count].vertIndexes[ii] = tempVertInfo.map[nn]; +#define SUBMITVERTEX(ii, nn) pendingGList.polyList[pendingGList.polyCount].vertIndexes[ii] = tempVertInfo.map[nn]; //Submit a vertex to the GE static void SetVertex() { + GFX3D_GeometryList &pendingGList = gfx3d.gList[gfx3d.pendingListIndex]; + s32 coord[3] = { s16coord[0], s16coord[1], @@ -718,10 +703,15 @@ static void SetVertex() //refuse to do anything if we have too many verts or polys polygonListCompleted = 0; - if(vertListCount[listTwiddle] >= VERTLIST_SIZE) - return; - if(polylist->count >= POLYLIST_SIZE) - return; + if (pendingGList.vertListCount >= VERTLIST_SIZE) + { + return; + } + + if (pendingGList.polyCount >= POLYLIST_SIZE) + { + return; + } if(freelookMode == 2) { @@ -748,21 +738,20 @@ static void SetVertex() //TODO - culling should be done here. //TODO - viewport transform? - int continuation = 0; + s32 continuation = 0; if (vtxFormat==GFX3D_TRIANGLE_STRIP && !tempVertInfo.first) continuation = 2; else if (vtxFormat==GFX3D_QUAD_STRIP && !tempVertInfo.first) continuation = 2; //record the vertex - //VERT &vert = tempVertList.list[tempVertList.count]; - const size_t vertIndex = vertListCount[listTwiddle] + tempVertInfo.count - continuation; + const size_t vertIndex = pendingGList.vertListCount + tempVertInfo.count - continuation; if (vertIndex >= VERTLIST_SIZE) { printf("wtf\n"); } - VERT &vert = vertList[vertIndex]; + VERT &vert = pendingGList.vertList[vertIndex]; //printf("%f %f %f\n",coordTransformed[0],coordTransformed[1],coordTransformed[2]); //if(coordTransformed[1] > 20) @@ -786,7 +775,7 @@ static void SetVertex() vert.color[1] = GFX3D_5TO6_LOOKUP(colorRGB[1]); vert.color[2] = GFX3D_5TO6_LOOKUP(colorRGB[2]); vert.color_to_float(); - tempVertInfo.map[tempVertInfo.count] = vertListCount[listTwiddle] + tempVertInfo.count - continuation; + tempVertInfo.map[tempVertInfo.count] = (s32)pendingGList.vertListCount + tempVertInfo.count - continuation; tempVertInfo.count++; //possibly complete a polygon @@ -798,12 +787,11 @@ static void SetVertex() if(tempVertInfo.count!=3) break; polygonListCompleted = 1; - //vertlist->list[polylist->list[polylist->count].vertIndexes[i] = vertlist->count++] = tempVertList.list[n]; SUBMITVERTEX(0,0); SUBMITVERTEX(1,1); SUBMITVERTEX(2,2); - vertListCount[listTwiddle] += 3; - polylist->list[polylist->count].type = POLYGON_TYPE_TRIANGLE; + gfx3d.gList[gfx3d.pendingListIndex].vertListCount += 3; + pendingGList.polyList[pendingGList.polyCount].type = POLYGON_TYPE_TRIANGLE; tempVertInfo.count = 0; break; @@ -815,8 +803,8 @@ static void SetVertex() SUBMITVERTEX(1,1); SUBMITVERTEX(2,2); SUBMITVERTEX(3,3); - vertListCount[listTwiddle] += 4; - polylist->list[polylist->count].type = POLYGON_TYPE_QUAD; + gfx3d.gList[gfx3d.pendingListIndex].vertListCount += 4; + pendingGList.polyList[pendingGList.polyCount].type = POLYGON_TYPE_QUAD; tempVertInfo.count = 0; break; @@ -827,17 +815,17 @@ static void SetVertex() SUBMITVERTEX(0,0); SUBMITVERTEX(1,1); SUBMITVERTEX(2,2); - polylist->list[polylist->count].type = POLYGON_TYPE_TRIANGLE; + pendingGList.polyList[pendingGList.polyCount].type = POLYGON_TYPE_TRIANGLE; if(triStripToggle) - tempVertInfo.map[1] = vertListCount[listTwiddle]+2-continuation; + tempVertInfo.map[1] = (s32)pendingGList.vertListCount + 2 - continuation; else - tempVertInfo.map[0] = vertListCount[listTwiddle]+2-continuation; + tempVertInfo.map[0] = (s32)pendingGList.vertListCount + 2 - continuation; if(tempVertInfo.first) - vertListCount[listTwiddle] += 3; + pendingGList.vertListCount += 3; else - vertListCount[listTwiddle] += 1; + pendingGList.vertListCount += 1; triStripToggle ^= 1; tempVertInfo.first = false; @@ -852,12 +840,12 @@ static void SetVertex() SUBMITVERTEX(1,1); SUBMITVERTEX(2,3); SUBMITVERTEX(3,2); - polylist->list[polylist->count].type = POLYGON_TYPE_QUAD; - tempVertInfo.map[0] = vertListCount[listTwiddle]+2-continuation; - tempVertInfo.map[1] = vertListCount[listTwiddle]+3-continuation; + pendingGList.polyList[pendingGList.polyCount].type = POLYGON_TYPE_QUAD; + tempVertInfo.map[0] = (s32)pendingGList.vertListCount + 2 - continuation; + tempVertInfo.map[1] = (s32)pendingGList.vertListCount + 3 - continuation; if(tempVertInfo.first) - vertListCount[listTwiddle] += 4; - else vertListCount[listTwiddle] += 2; + pendingGList.vertListCount += 4; + else pendingGList.vertListCount += 2; tempVertInfo.first = false; tempVertInfo.count = 2; break; @@ -868,7 +856,7 @@ static void SetVertex() if (polygonListCompleted == 1) { - POLY &poly = polylist->list[polylist->count]; + POLY &poly = pendingGList.polyList[pendingGList.polyCount]; poly.vtxFormat = vtxFormat; @@ -877,9 +865,9 @@ static void SetVertex() if (currentPolyTexParam.PackedFormat == TEXMODE_NONE) { bool duplicated = false; - const VERT &vert0 = vertList[poly.vertIndexes[0]]; - const VERT &vert1 = vertList[poly.vertIndexes[1]]; - const VERT &vert2 = vertList[poly.vertIndexes[2]]; + const VERT &vert0 = pendingGList.vertList[poly.vertIndexes[0]]; + const VERT &vert1 = pendingGList.vertList[poly.vertIndexes[1]]; + const VERT &vert2 = pendingGList.vertList[poly.vertIndexes[2]]; if ( (vert0.x == vert1.x) && (vert0.y == vert1.y) ) duplicated = true; else if ( (vert1.x == vert2.x) && (vert1.y == vert2.y) ) duplicated = true; @@ -897,8 +885,9 @@ static void SetVertex() poly.attribute = polyAttrInProcess; poly.texParam = currentPolyTexParam; poly.texPalette = currentPolyTexPalette; - poly.viewport = viewport; - polylist->count++; + poly.viewport = gfx3dViewport; + poly.viewportLegacySave = viewportLegacySave; + pendingGList.polyCount++; } } } @@ -1421,7 +1410,7 @@ static void gfx3d_glNormal(s32 v) //shininess is 20.12 fixed point, so >>5 gives us .7 which is 128 entries //the entries are 8bits each so <<4 gives us .12 again, compatible with the lighting formulas below //(according to other normal nds procedures, we might should fill the bottom bits with 1 or 0 according to rules...) - fixedshininess = gfx3d.state.shininessTable[fixedshininess>>5]<<4; + fixedshininess = gfx3d.pendingState.shininessTable[fixedshininess>>5]<<4; } for (size_t c = 0; c < 3; c++) @@ -1600,10 +1589,10 @@ static void gfx3d_glLightColor(u32 v) static BOOL gfx3d_glShininess(u32 val) { - gfx3d.state.shininessTable[shininessInd++] = (val & 0xFF); - gfx3d.state.shininessTable[shininessInd++] = (((val >> 8) & 0xFF)); - gfx3d.state.shininessTable[shininessInd++] = (((val >> 16) & 0xFF)); - gfx3d.state.shininessTable[shininessInd++] = (((val >> 24) & 0xFF)); + gfx3d.pendingState.shininessTable[shininessInd++] = (u8)(val & 0x000000FF); + gfx3d.pendingState.shininessTable[shininessInd++] = (u8)(((val >> 8) & 0x000000FF)); + gfx3d.pendingState.shininessTable[shininessInd++] = (u8)(((val >> 16) & 0x000000FF)); + gfx3d.pendingState.shininessTable[shininessInd++] = (u8)(((val >> 24) & 0x000000FF)); if (shininessInd < 128) return FALSE; shininessInd = 0; @@ -1632,9 +1621,12 @@ static void gfx3d_glEnd(void) // swap buffers - skipped -static void gfx3d_glViewPort(u32 v) +static void gfx3d_glViewport(u32 v) { - viewport = v; + _GFX3D_IORegisterMap->VIEWPORT.value = v; + viewportLegacySave.value = v; + gfx3dViewport = GFX3D_ViewportParse(v); + GFX_DELAY(1); } @@ -1824,6 +1816,10 @@ static BOOL gfx3d_glPosTest(u32 v) MatrixMultVec4x4(mtxCurrent[MATRIXMODE_PROJECTION], PTcoords); MMU_new.gxstat.tb = 0; + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x620, (u32)PTcoords[0]); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x624, (u32)PTcoords[1]); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x628, (u32)PTcoords[2]); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x62C, (u32)PTcoords[3]); GFX_DELAY(9); @@ -1863,78 +1859,106 @@ static void gfx3d_glVecTest(u32 v) const u16 z = (u16)((s16)normal[2]); MMU_new.gxstat.tb = 0; // clear busy - T1WriteWord(MMU.MMU_MEM[0][0x40], 0x630, x); - T1WriteWord(MMU.MMU_MEM[0][0x40], 0x632, y); - T1WriteWord(MMU.MMU_MEM[0][0x40], 0x634, z); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x630, x); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x632, y); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x634, z); } //================================================================================= Geometry Engine //================================================================================= (end) //================================================================================= - -void VIEWPORT::decode(const u32 v) -{ - //test: homie rollerz character select chooses nonsense for Y. they did the math backwards. their goal was a fullscreen viewport, they just messed up. - //they also messed up the width... - - u8 x1 = (v>> 0)&0xFF; - u8 y1 = (v>> 8)&0xFF; - u8 x2 = (v>>16)&0xFF; - u8 y2 = (v>>24)&0xFF; - - //I'm 100% sure this is basically 99% correct - //the modular math is right. the details of how the +1 is handled may be wrong (this might should be dealt with in the viewport transformation instead) - //Its an off by one error in any event so we may never know - width = (u8)(x2-x1)+1; - height = (u8)(y2-y1)+1; - x = x1; - y = y1; -} - void gfx3d_glFogColor(u32 v) { - gfx3d.state.fogColor = v; + gfx3d.pendingState.fogColor = v; } void gfx3d_glFogOffset(u32 v) { - gfx3d.state.fogOffset = (v & 0x7FFF); + gfx3d.pendingState.fogOffset = (v & 0x7FFF); } -void gfx3d_glClearDepth(u32 v) +template +void gfx3d_glClearDepth(const T val) { - gfx3d.state.clearDepth = DS_DEPTH15TO24(v); + const size_t numBytes = sizeof(T); + + switch (numBytes) + { + case 1: + { + if (ADDROFFSET == 1) + { + gfx3d.pendingState.clearDepth = DS_DEPTH15TO24(_GFX3D_IORegisterMap->CLEAR_DEPTH); + } + break; + } + + case 2: + gfx3d.pendingState.clearDepth = DS_DEPTH15TO24(val); + break; + + default: + break; + } } -int gfx3d_GetNumPolys() +template void gfx3d_glClearDepth< u8, 0>(const u8 val); +template void gfx3d_glClearDepth< u8, 1>(const u8 val); +template void gfx3d_glClearDepth(const u16 val); + +template +void gfx3d_glClearImageOffset(const T val) +{ + ((T *)&gfx3d.pendingState.clearImageOffset)[ADDROFFSET >> (sizeof(T) >> 1)] = val; +} + +template void gfx3d_glClearImageOffset< u8, 0>(const u8 val); +template void gfx3d_glClearImageOffset< u8, 1>(const u8 val); +template void gfx3d_glClearImageOffset(const u16 val); + +u32 gfx3d_GetNumPolys() { //so is this in the currently-displayed or currently-built list? - return (polylists[listTwiddle].count); + return (u32)(gfx3d.gList[gfx3d.pendingListIndex].polyCount); } -int gfx3d_GetNumVertex() +u32 gfx3d_GetNumVertex() { //so is this in the currently-displayed or currently-built list? - return (vertListCount[listTwiddle]); + return (u32)gfx3d.gList[gfx3d.pendingListIndex].vertListCount; } -void gfx3d_UpdateToonTable(u8 offset, u16 val) +template +void gfx3d_UpdateEdgeMarkColorTable(const u8 offset, const T val) { - gfx3d.state.invalidateToon = true; - gfx3d.state.u16ToonTable[offset] = val; - //printf("toon %d set to %04X\n",offset,val); + ((T *)(gfx3d.pendingState.edgeMarkColorTable))[offset >> (sizeof(T) >> 1)] = val; } -void gfx3d_UpdateToonTable(u8 offset, u32 val) +template void gfx3d_UpdateEdgeMarkColorTable< u8>(const u8 offset, const u8 val); +template void gfx3d_UpdateEdgeMarkColorTable(const u8 offset, const u16 val); +template void gfx3d_UpdateEdgeMarkColorTable(const u8 offset, const u32 val); + +template +void gfx3d_UpdateFogTable(const u8 offset, const T val) +{ + ((T *)(gfx3d.pendingState.fogDensityTable))[offset >> (sizeof(T) >> 1)] = val; +} + +template void gfx3d_UpdateFogTable< u8>(const u8 offset, const u8 val); +template void gfx3d_UpdateFogTable(const u8 offset, const u16 val); +template void gfx3d_UpdateFogTable(const u8 offset, const u32 val); + +template +void gfx3d_UpdateToonTable(const u8 offset, const T val) { //C.O.P. sets toon table via this method - gfx3d.state.invalidateToon = true; - gfx3d.state.u16ToonTable[offset] = val & 0xFFFF; - gfx3d.state.u16ToonTable[offset+1] = val >> 16; - //printf("toon %d set to %04X\n",offset,gfx3d.state.u16ToonTable[offset]); - //printf("toon %d set to %04X\n",offset+1,gfx3d.state.u16ToonTable[offset+1]); + ((T *)(gfx3d.pendingState.toonTable16))[offset >> (sizeof(T) >> 1)] = val; } +template void gfx3d_UpdateToonTable< u8>(const u8 offset, const u8 val); +template void gfx3d_UpdateToonTable(const u8 offset, const u16 val); +template void gfx3d_UpdateToonTable(const u8 offset, const u32 val); + s32 gfx3d_GetClipMatrix(const u32 index) { //printf("reading clip matrix: %d\n",index); @@ -1951,7 +1975,7 @@ s32 gfx3d_GetDirectionalMatrix(const u32 index) void gfx3d_glAlphaFunc(u32 v) { - gfx3d.state.alphaTestRef = v & 0x1F; + gfx3d.pendingState.alphaTestRef = (u8)(v & 0x0000001F); } u32 gfx3d_glGetPosRes(const size_t index) @@ -2193,7 +2217,7 @@ static void gfx3d_execute(u8 cmd, u32 param) gfx3d_glFlush(param); break; case 0x60: // VIEWPORT - Set Viewport (W) - gfx3d_glViewPort(param); + gfx3d_glViewport(param); break; case 0x70: // BOX_TEST - Test if Cuboid Sits inside View Volume (W) gfx3d_glBoxTest(param); @@ -2256,7 +2280,7 @@ void gfx3d_execute3D() void gfx3d_glFlush(u32 v) { //printf("-------------FLUSH------------- (vcount=%d\n",nds.VCount); - gfx3d.state.pendingFlushCommand = v; + gfx3d.pendingState.SWAP_BUFFERS.value = v; #if 0 if (isSwapBuffers) { @@ -2293,20 +2317,20 @@ static bool gfx3d_ysort_compare(int num1, int num2) } template -void gfx3d_PerformClipping(const VERT *vtxList, const POLYLIST *polyList) +void gfx3d_PerformClipping(const GFX3D_GeometryList &gList) { bool isPolyUnclipped = false; _clipper->Reset(); - for (size_t polyIndex = 0, clipCount = 0; polyIndex < polyList->count; polyIndex++) + for (size_t polyIndex = 0, clipCount = 0; polyIndex < gList.polyCount; polyIndex++) { - const POLY &poly = polyList->list[polyIndex]; + const POLY &poly = gList.polyList[polyIndex]; const VERT *clipVerts[4] = { - &vtxList[poly.vertIndexes[0]], - &vtxList[poly.vertIndexes[1]], - &vtxList[poly.vertIndexes[2]], - (poly.type == POLYGON_TYPE_QUAD) ? &vtxList[poly.vertIndexes[3]] : NULL + &gList.vertList[poly.vertIndexes[0]], + &gList.vertList[poly.vertIndexes[1]], + &gList.vertList[poly.vertIndexes[2]], + (poly.type == POLYGON_TYPE_QUAD) ? &gList.vertList[poly.vertIndexes[3]] : NULL }; isPolyUnclipped = _clipper->ClipPoly(polyIndex, poly, clipVerts); @@ -2331,49 +2355,51 @@ void gfx3d_PerformClipping(const VERT *vtxList, const POLYLIST *polyList) } } -void gfx3d_GenerateRenderLists(const ClipperMode clippingMode) +void GFX3D_GenerateRenderLists(const ClipperMode clippingMode, const GFX3D_State &inState, GFX3D_GeometryList &outGList) { + const VERT *__restrict appliedVertList = outGList.vertList; + switch (clippingMode) { case ClipperMode_Full: - gfx3d_PerformClipping(gfx3d.vertList, gfx3d.polylist); + gfx3d_PerformClipping(outGList); break; case ClipperMode_FullColorInterpolate: - gfx3d_PerformClipping(gfx3d.vertList, gfx3d.polylist); + gfx3d_PerformClipping(outGList); break; case ClipperMode_DetermineClipOnly: - gfx3d_PerformClipping(gfx3d.vertList, gfx3d.polylist); + gfx3d_PerformClipping(outGList); break; } - gfx3d.clippedPolyCount = _clipper->GetPolyCount(); + outGList.clippedPolyCount = _clipper->GetPolyCount(); #ifdef _SHOW_VTX_COUNTERS - max_polys = max((u32)polycount, max_polys); - max_verts = max((u32)vertListCount[listTwiddle], max_verts); - osd->addFixed(180, 20, "%i/%i", polycount, vertListCount[listTwiddle]); // current + max_polys = max((u32)outGList.polyCount, max_polys); + max_verts = max((u32)outGList.vertListCount, max_verts); + osd->addFixed(180, 20, "%i/%i", outGList.polyCount, outGList.vertListCount); // current osd->addFixed(180, 35, "%i/%i", max_polys, max_verts); // max #endif //we need to sort the poly list with alpha polys last //first, look for opaque polys size_t ctr = 0; - for (size_t i = 0; i < gfx3d.clippedPolyCount; i++) + for (size_t i = 0; i < outGList.clippedPolyCount; i++) { const CPoly &clippedPoly = _clipper->GetClippedPolyByIndex(i); if (!clippedPoly.poly->isTranslucent()) - gfx3d.indexlist.list[ctr++] = clippedPoly.index; + _polyWorkingIndexList[ctr++] = (int)clippedPoly.index; } - gfx3d.clippedPolyOpaqueCount = ctr; + outGList.clippedPolyOpaqueCount = ctr; //then look for translucent polys - for (size_t i = 0; i < gfx3d.clippedPolyCount; i++) + for (size_t i = 0; i < outGList.clippedPolyCount; i++) { const CPoly &clippedPoly = _clipper->GetClippedPolyByIndex(i); if (clippedPoly.poly->isTranslucent()) - gfx3d.indexlist.list[ctr++] = clippedPoly.index; + _polyWorkingIndexList[ctr++] = (int)clippedPoly.index; } //find the min and max y values for each poly. @@ -2382,22 +2408,22 @@ void gfx3d_GenerateRenderLists(const ClipperMode clippingMode) //we process all polys here instead of just the opaque ones (which have been sorted to the beginning of the index list earlier) because //1. otherwise it is basically two passes through the list and will probably run slower than one pass through the list //2. most geometry is opaque which is always sorted anyway - for (size_t i = 0; i < gfx3d.clippedPolyCount; i++) + for (size_t i = 0; i < outGList.clippedPolyCount; i++) { // TODO: Possible divide by zero with the w-coordinate. // Is the vertex being read correctly? Is 0 a valid value for w? // If both of these questions answer to yes, then how does the NDS handle a NaN? // For now, simply prevent w from being zero. POLY &poly = *_clipper->GetClippedPolyByIndex(i).poly; - float verty = gfx3d.vertList[poly.vertIndexes[0]].y; - float vertw = (gfx3d.vertList[poly.vertIndexes[0]].w != 0.0f) ? gfx3d.vertList[poly.vertIndexes[0]].w : 0.00000001f; + float verty = appliedVertList[poly.vertIndexes[0]].y; + float vertw = (appliedVertList[poly.vertIndexes[0]].w != 0.0f) ? appliedVertList[poly.vertIndexes[0]].w : 0.00000001f; verty = 1.0f-(verty+vertw)/(2*vertw); poly.miny = poly.maxy = verty; for (size_t j = 1; j < (size_t)poly.type; j++) { - verty = gfx3d.vertList[poly.vertIndexes[j]].y; - vertw = (gfx3d.vertList[poly.vertIndexes[j]].w != 0.0f) ? gfx3d.vertList[poly.vertIndexes[j]].w : 0.00000001f; + verty = appliedVertList[poly.vertIndexes[j]].y; + vertw = (appliedVertList[poly.vertIndexes[j]].w != 0.0f) ? appliedVertList[poly.vertIndexes[j]].w : 0.00000001f; verty = 1.0f-(verty+vertw)/(2*vertw); poly.miny = min(poly.miny, verty); poly.maxy = max(poly.maxy, verty); @@ -2407,72 +2433,75 @@ void gfx3d_GenerateRenderLists(const ClipperMode clippingMode) //now we have to sort the opaque polys by y-value. //(test case: harvest moon island of happiness character creator UI) //should this be done after clipping?? - std::sort(gfx3d.indexlist.list, gfx3d.indexlist.list + gfx3d.clippedPolyOpaqueCount, gfx3d_ysort_compare); + std::sort(_polyWorkingIndexList, _polyWorkingIndexList + outGList.clippedPolyOpaqueCount, gfx3d_ysort_compare); - if (!gfx3d.state.sortmode) + if (inState.SWAP_BUFFERS.YSortMode == 0) { //if we are autosorting translucent polys, we need to do this also //TODO - this is unverified behavior. need a test case - std::sort(gfx3d.indexlist.list + gfx3d.clippedPolyOpaqueCount, gfx3d.indexlist.list + gfx3d.clippedPolyCount, gfx3d_ysort_compare); + std::sort(_polyWorkingIndexList + outGList.clippedPolyOpaqueCount, _polyWorkingIndexList + outGList.clippedPolyCount, gfx3d_ysort_compare); } // Reorder the clipped polygon list to match our sorted index list. if (clippingMode == ClipperMode_DetermineClipOnly) { - for (size_t i = 0; i < gfx3d.clippedPolyCount; i++) + for (size_t i = 0; i < outGList.clippedPolyCount; i++) { - _clippedPolySortedList[i].poly = _clippedPolyUnsortedList[gfx3d.indexlist.list[i]].poly; + outGList.clippedPolyList[i].poly = _clippedPolyUnsortedList[_polyWorkingIndexList[i]].poly; } } else { - for (size_t i = 0; i < gfx3d.clippedPolyCount; i++) + for (size_t i = 0; i < outGList.clippedPolyCount; i++) { - _clippedPolySortedList[i] = _clippedPolyUnsortedList[gfx3d.indexlist.list[i]]; + outGList.clippedPolyList[i] = _clippedPolyUnsortedList[_polyWorkingIndexList[i]]; } } } static void gfx3d_doFlush() { - gfx3d.render3DFrameCount++; - - //the renderer will get the lists we just built - gfx3d.polylist = polylist; - gfx3d.vertList = vertList; - gfx3d.vertListCount = vertListCount[listTwiddle]; - - //and also our current render state - gfx3d.state.sortmode = BIT0(gfx3d.state.activeFlushCommand); - gfx3d.state.wbuffer = BIT1(gfx3d.state.activeFlushCommand); - //latch the current renderer and geometry engine states //NOTE: the geometry lists are copied elsewhere by another operation. //that's pretty annoying. - //TODO: see TODO TODO TODO TODO - gfx3d.renderState = gfx3d.state; - - gfx3d.state.activeFlushCommand = gfx3d.state.pendingFlushCommand; + gfx3d.appliedListIndex = gfx3d.pendingListIndex; + gfx3d.appliedState = gfx3d.pendingState; + // Finalize the geometry lists for our 3D renderers. + GFX3D_GeometryList &appliedGList = gfx3d.gList[gfx3d.appliedListIndex]; const ClipperMode clippingMode = CurrentRenderer->GetPreferredPolygonClippingMode(); - gfx3d_GenerateRenderLists(clippingMode); + GFX3D_GenerateRenderLists(clippingMode, gfx3d.appliedState, appliedGList); //switch to the new lists - twiddleLists(); + gfx3d.pendingListIndex++; + gfx3d.pendingListIndex &= 1; + + GFX3D_GeometryList &pendingGList = gfx3d.gList[gfx3d.pendingListIndex]; + pendingGList.polyCount = 0; + pendingGList.polyOpaqueCount = 0; + pendingGList.vertListCount = 0; + pendingGList.clippedPolyCount = 0; + pendingGList.clippedPolyOpaqueCount = 0; if (driver->view3d->IsRunning()) { - viewer3d_state->frameNumber = currFrameCounter; - viewer3d_state->state = gfx3d.state; - viewer3d_state->polylist = *gfx3d.polylist; - viewer3d_state->indexlist = gfx3d.indexlist; - viewer3d_state->vertListCount = gfx3d.vertListCount; + viewer3D.frameNumber = currFrameCounter; + viewer3D.state = gfx3d.appliedState; + viewer3D.gList.polyCount = appliedGList.polyCount; + viewer3D.gList.polyOpaqueCount = appliedGList.polyOpaqueCount; + viewer3D.gList.clippedPolyCount = appliedGList.clippedPolyCount; + viewer3D.gList.clippedPolyOpaqueCount = appliedGList.clippedPolyOpaqueCount; + viewer3D.gList.vertListCount = appliedGList.vertListCount; - memcpy(viewer3d_state->vertList, gfx3d.vertList, gfx3d.vertListCount * sizeof(VERT)); + memcpy(viewer3D.gList.polyList, appliedGList.polyList, appliedGList.polyCount * sizeof(POLY)); + memcpy(viewer3D.gList.vertList, appliedGList.vertList, appliedGList.vertListCount * sizeof(VERT)); + memcpy(viewer3D.gList.clippedPolyList, appliedGList.clippedPolyList, appliedGList.clippedPolyCount * sizeof(CPoly)); + memcpy(viewer3D.indexList, _polyWorkingIndexList, appliedGList.clippedPolyCount * sizeof(int)); driver->view3d->NewFrame(); } - + + gfx3d.render3DFrameCount++; drawPending = TRUE; } @@ -2521,13 +2550,9 @@ void gfx3d_VBlankEndSignal(bool skipFrame) //The time to fix this will be when we rearchitect things to have more geometry processing lower-level in GFX3D.. //..since we'll be ripping a lot of stuff apart anyway bool forceDraw = false; - if(gfx3d.state.enableClearImage) { + if (gfx3d.appliedState.DISP3DCNT.RearPlaneMode) + { forceDraw = true; - //Well, now this makes it definite HACK caliber - //We're using this as a sentinel for whether anything's ever been drawn--since we glitch out and crashing trying to render (if only for the clear image) - //when no geometry's ever been swapped in - if(!gfx3d.renderState.fogDensityTable) - forceDraw = false; } if (!drawPending && !forceDraw) @@ -2545,10 +2570,10 @@ void gfx3d_VBlankEndSignal(bool skipFrame) if (oldClippingMode != newClippingMode) { - gfx3d_GenerateRenderLists(newClippingMode); + GFX3D_GenerateRenderLists(newClippingMode, gfx3d.appliedState, gfx3d.gList[gfx3d.appliedListIndex]); } - CurrentRenderer->ApplyRenderingSettings(gfx3d.renderState); + CurrentRenderer->ApplyRenderingSettings(gfx3d.appliedState); GPU->GetEventHandler()->DidApplyRender3DSettingsEnd(); GPU->GetEventHandler()->DidRender3DBegin(); @@ -2558,7 +2583,7 @@ void gfx3d_VBlankEndSignal(bool skipFrame) if (GPU->GetEngineMain()->GetEnableStateApplied() && nds.power_render) { CurrentRenderer->SetTextureProcessingProperties(); - CurrentRenderer->Render(gfx3d); + CurrentRenderer->Render(gfx3d.appliedState, gfx3d.gList[gfx3d.appliedListIndex]); } else { @@ -2686,7 +2711,7 @@ void gfx3d_glGetLightColor(const size_t index, u32 &dst) //consider building a little state structure that looks exactly like this describes SFORMAT SF_GFX3D[]={ - { "GCTL", 4, 1, &gfx3d.state.savedDISP3DCNT}, + { "GCTL", 4, 1, &gfx3d.pendingState.DISP3DCNT}, { "GPAT", 4, 1, &polyAttrInProcess.value}, { "GPAP", 4, 1, ¤tPolyAttr.value}, { "GINB", 4, 1, &inBegin}, @@ -2738,51 +2763,51 @@ SFORMAT SF_GFX3D[]={ { "GMSP", 2, 1, &dsSpecular}, { "GMEM", 2, 1, &dsEmission}, { "GDRP", 4, 1, &drawPending}, - { "GSET", 4, 1, &gfx3d.state.enableTexturing}, - { "GSEA", 4, 1, &gfx3d.state.enableAlphaTest}, - { "GSEB", 4, 1, &gfx3d.state.enableAlphaBlending}, - { "GSEX", 4, 1, &gfx3d.state.enableAntialiasing}, - { "GSEE", 4, 1, &gfx3d.state.enableEdgeMarking}, - { "GSEC", 4, 1, &gfx3d.state.enableClearImage}, - { "GSEF", 4, 1, &gfx3d.state.enableFog}, - { "GSEO", 4, 1, &gfx3d.state.enableFogAlphaOnly}, - { "GFSH", 4, 1, &gfx3d.state.fogShift}, - { "GSSH", 4, 1, &gfx3d.state.shading}, - { "GSWB", 4, 1, &gfx3d.state.wbuffer}, - { "GSSM", 4, 1, &gfx3d.state.sortmode}, - { "GSAR", 1, 1, &gfx3d.state.alphaTestRef}, - { "GSCC", 4, 1, &gfx3d.state.clearColor}, - { "GSCD", 4, 1, &gfx3d.state.clearDepth}, - { "GSFC", 4, 4, &gfx3d.state.fogColor}, - { "GSFO", 4, 1, &gfx3d.state.fogOffset}, - { "GST4", 2, 32, gfx3d.state.u16ToonTable}, - { "GSSU", 1, 128, &gfx3d.state.shininessTable[0]}, - { "GSAF", 4, 1, &gfx3d.state.activeFlushCommand}, - { "GSPF", 4, 1, &gfx3d.state.pendingFlushCommand}, + { "GSET", 4, 1, &legacyGFX3DStateSFormatPending.enableTexturing}, + { "GSEA", 4, 1, &legacyGFX3DStateSFormatPending.enableAlphaTest}, + { "GSEB", 4, 1, &legacyGFX3DStateSFormatPending.enableAlphaBlending}, + { "GSEX", 4, 1, &legacyGFX3DStateSFormatPending.enableAntialiasing}, + { "GSEE", 4, 1, &legacyGFX3DStateSFormatPending.enableEdgeMarking}, + { "GSEC", 4, 1, &legacyGFX3DStateSFormatPending.enableClearImage}, + { "GSEF", 4, 1, &legacyGFX3DStateSFormatPending.enableFog}, + { "GSEO", 4, 1, &legacyGFX3DStateSFormatPending.enableFogAlphaOnly}, + { "GFSH", 4, 1, &legacyGFX3DStateSFormatPending.fogShift}, + { "GSSH", 4, 1, &legacyGFX3DStateSFormatPending.toonShadingMode}, + { "GSWB", 4, 1, &legacyGFX3DStateSFormatPending.enableWDepth}, + { "GSSM", 4, 1, &legacyGFX3DStateSFormatPending.polygonTransparentSortMode}, + { "GSAR", 1, 1, &legacyGFX3DStateSFormatPending.alphaTestRef}, + { "GSCC", 4, 1, &legacyGFX3DStateSFormatPending.clearColor}, + { "GSCD", 4, 1, &legacyGFX3DStateSFormatPending.clearDepth}, + { "GSFC", 4, 4, legacyGFX3DStateSFormatPending.fogColor}, + { "GSFO", 4, 1, &legacyGFX3DStateSFormatPending.fogOffset}, + { "GST4", 2, 32, legacyGFX3DStateSFormatPending.toonTable16}, + { "GSSU", 1, 128, legacyGFX3DStateSFormatPending.shininessTable}, + { "GSAF", 4, 1, &legacyGFX3DStateSFormatPending.activeFlushCommand}, + { "GSPF", 4, 1, &legacyGFX3DStateSFormatPending.pendingFlushCommand}, - { "gSET", 4, 1, &gfx3d.renderState.enableTexturing}, - { "gSEA", 4, 1, &gfx3d.renderState.enableAlphaTest}, - { "gSEB", 4, 1, &gfx3d.renderState.enableAlphaBlending}, - { "gSEX", 4, 1, &gfx3d.renderState.enableAntialiasing}, - { "gSEE", 4, 1, &gfx3d.renderState.enableEdgeMarking}, - { "gSEC", 4, 1, &gfx3d.renderState.enableClearImage}, - { "gSEF", 4, 1, &gfx3d.renderState.enableFog}, - { "gSEO", 4, 1, &gfx3d.renderState.enableFogAlphaOnly}, - { "gFSH", 4, 1, &gfx3d.renderState.fogShift}, - { "gSSH", 4, 1, &gfx3d.renderState.shading}, - { "gSWB", 4, 1, &gfx3d.renderState.wbuffer}, - { "gSSM", 4, 1, &gfx3d.renderState.sortmode}, - { "gSAR", 1, 1, &gfx3d.renderState.alphaTestRef}, - { "gSCC", 4, 1, &gfx3d.renderState.clearColor}, - { "gSCD", 4, 1, &gfx3d.renderState.clearDepth}, - { "gSFC", 4, 4, &gfx3d.renderState.fogColor}, - { "gSFO", 4, 1, &gfx3d.renderState.fogOffset}, - { "gST4", 2, 32, gfx3d.renderState.u16ToonTable}, - { "gSSU", 1, 128, &gfx3d.renderState.shininessTable[0]}, - { "gSAF", 4, 1, &gfx3d.renderState.activeFlushCommand}, - { "gSPF", 4, 1, &gfx3d.renderState.pendingFlushCommand}, + { "gSET", 4, 1, &legacyGFX3DStateSFormatApplied.enableTexturing}, + { "gSEA", 4, 1, &legacyGFX3DStateSFormatApplied.enableAlphaTest}, + { "gSEB", 4, 1, &legacyGFX3DStateSFormatApplied.enableAlphaBlending}, + { "gSEX", 4, 1, &legacyGFX3DStateSFormatApplied.enableAntialiasing}, + { "gSEE", 4, 1, &legacyGFX3DStateSFormatApplied.enableEdgeMarking}, + { "gSEC", 4, 1, &legacyGFX3DStateSFormatApplied.enableClearImage}, + { "gSEF", 4, 1, &legacyGFX3DStateSFormatApplied.enableFog}, + { "gSEO", 4, 1, &legacyGFX3DStateSFormatApplied.enableFogAlphaOnly}, + { "gFSH", 4, 1, &legacyGFX3DStateSFormatApplied.fogShift}, + { "gSSH", 4, 1, &legacyGFX3DStateSFormatApplied.toonShadingMode}, + { "gSWB", 4, 1, &legacyGFX3DStateSFormatApplied.enableWDepth}, + { "gSSM", 4, 1, &legacyGFX3DStateSFormatApplied.polygonTransparentSortMode}, + { "gSAR", 1, 1, &legacyGFX3DStateSFormatApplied.alphaTestRef}, + { "gSCC", 4, 1, &legacyGFX3DStateSFormatApplied.clearColor}, + { "gSCD", 4, 1, &legacyGFX3DStateSFormatApplied.clearDepth}, + { "gSFC", 4, 4, legacyGFX3DStateSFormatApplied.fogColor}, + { "gSFO", 4, 1, &legacyGFX3DStateSFormatApplied.fogOffset}, + { "gST4", 2, 32, legacyGFX3DStateSFormatApplied.toonTable16}, + { "gSSU", 1, 128, legacyGFX3DStateSFormatApplied.shininessTable}, + { "gSAF", 4, 1, &legacyGFX3DStateSFormatApplied.activeFlushCommand}, + { "gSPF", 4, 1, &legacyGFX3DStateSFormatApplied.pendingFlushCommand}, - { "GSVP", 4, 1, &viewport}, + { "GSVP", 4, 1, &viewportLegacySave}, { "GSSI", 1, 1, &shininessInd}, //------------------------ { "GTST", 1, 1, &triStripToggle}, @@ -2839,6 +2864,56 @@ void gfx3d_PrepareSaveStateBufferWrite() PTcoords_legacySave[1] = (float)PTcoords[1] / 4096.0f; PTcoords_legacySave[2] = (float)PTcoords[2] / 4096.0f; PTcoords_legacySave[3] = (float)PTcoords[3] / 4096.0f; + + legacyGFX3DStateSFormatPending.enableTexturing = (gfx3d.pendingState.DISP3DCNT.EnableTexMapping) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableAlphaTest = (gfx3d.pendingState.DISP3DCNT.EnableAlphaTest) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableAlphaBlending = (gfx3d.pendingState.DISP3DCNT.EnableAlphaBlending) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableAntialiasing = (gfx3d.pendingState.DISP3DCNT.EnableAntialiasing) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableEdgeMarking = (gfx3d.pendingState.DISP3DCNT.EnableEdgeMarking) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableClearImage = (gfx3d.pendingState.DISP3DCNT.RearPlaneMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableFog = (gfx3d.pendingState.DISP3DCNT.EnableFog) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.enableFogAlphaOnly = (gfx3d.pendingState.DISP3DCNT.FogOnlyAlpha) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.fogShift = gfx3d.pendingState.fogShift; + legacyGFX3DStateSFormatPending.toonShadingMode = gfx3d.pendingState.DISP3DCNT.PolygonShading; + legacyGFX3DStateSFormatPending.enableWDepth = (gfx3d.pendingState.SWAP_BUFFERS.DepthMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.polygonTransparentSortMode = (gfx3d.pendingState.SWAP_BUFFERS.YSortMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatPending.alphaTestRef = gfx3d.pendingState.alphaTestRef; + legacyGFX3DStateSFormatPending.clearColor = gfx3d.pendingState.clearColor; + legacyGFX3DStateSFormatPending.clearDepth = gfx3d.pendingState.clearDepth; + legacyGFX3DStateSFormatPending.fogColor[0] = gfx3d.pendingState.fogColor; + legacyGFX3DStateSFormatPending.fogColor[1] = gfx3d.pendingState.fogColor; + legacyGFX3DStateSFormatPending.fogColor[2] = gfx3d.pendingState.fogColor; + legacyGFX3DStateSFormatPending.fogColor[3] = gfx3d.pendingState.fogColor; + legacyGFX3DStateSFormatPending.fogOffset = gfx3d.pendingState.fogOffset; + legacyGFX3DStateSFormatPending.activeFlushCommand = gfx3d.appliedState.SWAP_BUFFERS.value; + legacyGFX3DStateSFormatPending.pendingFlushCommand = gfx3d.pendingState.SWAP_BUFFERS.value; + memcpy(legacyGFX3DStateSFormatPending.toonTable16, gfx3d.pendingState.toonTable16, sizeof(gfx3d.pendingState.toonTable16)); + memcpy(legacyGFX3DStateSFormatPending.shininessTable, gfx3d.pendingState.shininessTable, sizeof(gfx3d.pendingState.shininessTable)); + + legacyGFX3DStateSFormatApplied.enableTexturing = (gfx3d.appliedState.DISP3DCNT.EnableTexMapping) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableAlphaTest = (gfx3d.appliedState.DISP3DCNT.EnableAlphaTest) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableAlphaBlending = (gfx3d.appliedState.DISP3DCNT.EnableAlphaBlending) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableAntialiasing = (gfx3d.appliedState.DISP3DCNT.EnableAntialiasing) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableEdgeMarking = (gfx3d.appliedState.DISP3DCNT.EnableEdgeMarking) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableClearImage = (gfx3d.appliedState.DISP3DCNT.RearPlaneMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableFog = (gfx3d.appliedState.DISP3DCNT.EnableFog) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.enableFogAlphaOnly = (gfx3d.appliedState.DISP3DCNT.FogOnlyAlpha) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.fogShift = gfx3d.appliedState.fogShift; + legacyGFX3DStateSFormatApplied.toonShadingMode = gfx3d.appliedState.DISP3DCNT.PolygonShading; + legacyGFX3DStateSFormatApplied.enableWDepth = (gfx3d.appliedState.SWAP_BUFFERS.DepthMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.polygonTransparentSortMode = (gfx3d.appliedState.SWAP_BUFFERS.YSortMode) ? TRUE : FALSE; + legacyGFX3DStateSFormatApplied.alphaTestRef = gfx3d.appliedState.alphaTestRef; + legacyGFX3DStateSFormatApplied.clearColor = gfx3d.appliedState.clearColor; + legacyGFX3DStateSFormatApplied.clearDepth = gfx3d.appliedState.clearDepth; + legacyGFX3DStateSFormatApplied.fogColor[0] = gfx3d.appliedState.fogColor; + legacyGFX3DStateSFormatApplied.fogColor[1] = gfx3d.appliedState.fogColor; + legacyGFX3DStateSFormatApplied.fogColor[2] = gfx3d.appliedState.fogColor; + legacyGFX3DStateSFormatApplied.fogColor[3] = gfx3d.appliedState.fogColor; + legacyGFX3DStateSFormatApplied.fogOffset = gfx3d.appliedState.fogOffset; + legacyGFX3DStateSFormatApplied.activeFlushCommand = gfx3d.appliedState.SWAP_BUFFERS.value; + legacyGFX3DStateSFormatApplied.pendingFlushCommand = gfx3d.pendingState.SWAP_BUFFERS.value; + memcpy(legacyGFX3DStateSFormatApplied.toonTable16, gfx3d.appliedState.toonTable16, sizeof(gfx3d.appliedState.toonTable16)); + memcpy(legacyGFX3DStateSFormatApplied.shininessTable, gfx3d.appliedState.shininessTable, sizeof(gfx3d.appliedState.shininessTable)); } void gfx3d_savestate(EMUFILE &os) @@ -2847,13 +2922,13 @@ void gfx3d_savestate(EMUFILE &os) os.write_32LE(4); //dump the render lists - os.write_32LE((u32)vertListCount[listTwiddle]); - for (size_t i = 0; i < vertListCount[listTwiddle]; i++) - vertList[i].save(os); + os.write_32LE((u32)gfx3d.gList[gfx3d.pendingListIndex].vertListCount); + for (size_t i = 0; i < gfx3d.gList[gfx3d.pendingListIndex].vertListCount; i++) + gfx3d.gList[gfx3d.pendingListIndex].vertList[i].save(os); - os.write_32LE((u32)polylist->count); - for (size_t i = 0; i < polylist->count; i++) - polylist->list[i].save(os); + os.write_32LE((u32)gfx3d.gList[gfx3d.pendingListIndex].polyCount); + for (size_t i = 0; i < gfx3d.gList[gfx3d.pendingListIndex].polyCount; i++) + gfx3d.gList[gfx3d.pendingListIndex].polyList[i].save(os); // Write matrix stack data os.write_32LE(mtxStackIndex[MATRIXMODE_PROJECTION]); @@ -2924,11 +2999,6 @@ bool gfx3d_loadstate(EMUFILE &is, int size) gfx3d_glLightDirection_cache(2); gfx3d_glLightDirection_cache(3); - //jiggle the lists. and also wipe them. this is clearly not the best thing to be doing. - listTwiddle = 0; - polylist = &polylists[0]; - vertList = vertLists; - gfx3d_parseCurrentDISP3DCNT(); if (version >= 1) @@ -2937,14 +3007,22 @@ bool gfx3d_loadstate(EMUFILE &is, int size) u32 polyListCount32 = 0; is.read_32LE(vertListCount32); - vertListCount[0] = vertListCount32; - for (size_t i = 0; i < vertListCount[0]; i++) - vertList[i].load(is); + gfx3d.gList[gfx3d.pendingListIndex].vertListCount = vertListCount32; + gfx3d.gList[gfx3d.appliedListIndex].vertListCount = vertListCount32; + for (size_t i = 0; i < gfx3d.gList[gfx3d.appliedListIndex].vertListCount; i++) + { + gfx3d.gList[gfx3d.pendingListIndex].vertList[i].load(is); + gfx3d.gList[gfx3d.appliedListIndex].vertList[i].load(is); + } is.read_32LE(polyListCount32); - polylist->count = polyListCount32; - for (size_t i = 0; i < polylist->count; i++) - polylist->list[i].load(is); + gfx3d.gList[gfx3d.pendingListIndex].polyCount = polyListCount32; + gfx3d.gList[gfx3d.appliedListIndex].polyCount = polyListCount32; + for (size_t i = 0; i < gfx3d.gList[gfx3d.appliedListIndex].polyCount; i++) + { + gfx3d.gList[gfx3d.pendingListIndex].polyList[i].load(is); + gfx3d.gList[gfx3d.appliedListIndex].polyList[i].load(is); + } } if (version >= 2) @@ -2986,11 +3064,6 @@ bool gfx3d_loadstate(EMUFILE &is, int size) gxf_hardware.loadstate(is); } - gfx3d.polylist = &polylists[listTwiddle^1]; - gfx3d.vertList = vertLists + VERTLIST_SIZE; - gfx3d.polylist->count = 0; - gfx3d.vertListCount = 0; - if (version >= 4) { for (size_t i = 0; i < 4; i++) @@ -3066,42 +3139,81 @@ void gfx3d_FinishLoadStateBufferRead() } // For save state compatibility + const GPU_IOREG &GPUREG = GPU->GetEngineMain()->GetIORegisterMap(); + const GFX3D_IOREG &GFX3DREG = GFX3D_GetIORegisterMap(); + PTcoords[0] = (s32)(PTcoords_legacySave[0] * 4096.0f); PTcoords[1] = (s32)(PTcoords_legacySave[1] * 4096.0f); PTcoords[2] = (s32)(PTcoords_legacySave[2] * 4096.0f); PTcoords[3] = (s32)(PTcoords_legacySave[3] * 4096.0f); + + gfx3dViewport = GFX3D_ViewportParse(GFX3DREG.VIEWPORT.value); + + gfx3d.pendingState.DISP3DCNT = GPUREG.DISP3DCNT; + gfx3d_parseCurrentDISP3DCNT(); + + gfx3d.pendingState.SWAP_BUFFERS = GFX3DREG.SWAP_BUFFERS; + gfx3d.pendingState.clearColor = legacyGFX3DStateSFormatPending.clearColor; + gfx3d.pendingState.clearDepth = legacyGFX3DStateSFormatPending.clearDepth; + gfx3d.pendingState.fogColor = legacyGFX3DStateSFormatPending.fogColor[0]; + gfx3d.pendingState.fogOffset = legacyGFX3DStateSFormatPending.fogOffset; + gfx3d.pendingState.alphaTestRef = legacyGFX3DStateSFormatPending.alphaTestRef; + memcpy(gfx3d.pendingState.toonTable16, legacyGFX3DStateSFormatPending.toonTable16, sizeof(gfx3d.pendingState.toonTable16)); + memcpy(gfx3d.pendingState.shininessTable, legacyGFX3DStateSFormatPending.shininessTable, sizeof(gfx3d.pendingState.shininessTable)); + memcpy(gfx3d.pendingState.edgeMarkColorTable, GFX3DREG.EDGE_COLOR, sizeof(GFX3DREG.EDGE_COLOR)); + memcpy(gfx3d.pendingState.fogDensityTable, GFX3DREG.FOG_TABLE, sizeof(GFX3DREG.FOG_TABLE)); + + gfx3d.appliedState.DISP3DCNT.value = 0; + gfx3d.appliedState.DISP3DCNT.EnableTexMapping = (legacyGFX3DStateSFormatApplied.enableTexturing) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.EnableAlphaTest = (legacyGFX3DStateSFormatApplied.enableAlphaTest) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.EnableAlphaBlending = (legacyGFX3DStateSFormatApplied.enableAlphaBlending) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.EnableAntialiasing = (legacyGFX3DStateSFormatApplied.enableAntialiasing) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.EnableEdgeMarking = (legacyGFX3DStateSFormatApplied.enableEdgeMarking) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.RearPlaneMode = (legacyGFX3DStateSFormatApplied.enableClearImage) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.EnableFog = (legacyGFX3DStateSFormatApplied.enableFog) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.FogOnlyAlpha = (legacyGFX3DStateSFormatApplied.enableFogAlphaOnly) ? 1 : 0; + gfx3d.appliedState.DISP3DCNT.PolygonShading = (legacyGFX3DStateSFormatApplied.toonShadingMode) ? 1 : 0; + gfx3d.appliedState.SWAP_BUFFERS.value = 0; + gfx3d.appliedState.SWAP_BUFFERS.DepthMode = (legacyGFX3DStateSFormatApplied.enableWDepth) ? 1 : 0; + gfx3d.appliedState.SWAP_BUFFERS.YSortMode = (legacyGFX3DStateSFormatApplied.polygonTransparentSortMode) ? 1 : 0; + gfx3d.appliedState.fogShift = legacyGFX3DStateSFormatApplied.fogShift; + gfx3d.appliedState.clearColor = legacyGFX3DStateSFormatApplied.clearColor; + gfx3d.appliedState.clearDepth = legacyGFX3DStateSFormatApplied.clearDepth; + gfx3d.appliedState.fogColor = legacyGFX3DStateSFormatApplied.fogColor[0]; + gfx3d.appliedState.fogOffset = legacyGFX3DStateSFormatApplied.fogOffset; + gfx3d.appliedState.alphaTestRef = legacyGFX3DStateSFormatApplied.alphaTestRef; + gfx3d.appliedState.SWAP_BUFFERS.value = legacyGFX3DStateSFormatApplied.activeFlushCommand; + memcpy(gfx3d.appliedState.toonTable16, legacyGFX3DStateSFormatApplied.toonTable16, sizeof(gfx3d.appliedState.toonTable16)); + memcpy(gfx3d.appliedState.shininessTable, legacyGFX3DStateSFormatApplied.shininessTable, sizeof(gfx3d.appliedState.shininessTable)); + memcpy(gfx3d.appliedState.edgeMarkColorTable, GFX3DREG.EDGE_COLOR, sizeof(GFX3DREG.EDGE_COLOR)); + memcpy(gfx3d.appliedState.fogDensityTable, GFX3DREG.FOG_TABLE, sizeof(GFX3DREG.FOG_TABLE)); } void gfx3d_parseCurrentDISP3DCNT() { - const IOREG_DISP3DCNT &DISP3DCNT = gfx3d.state.savedDISP3DCNT; - - gfx3d.state.enableTexturing = (DISP3DCNT.EnableTexMapping != 0); - gfx3d.state.shading = DISP3DCNT.PolygonShading; - gfx3d.state.enableAlphaTest = (DISP3DCNT.EnableAlphaTest != 0); - gfx3d.state.enableAlphaBlending = (DISP3DCNT.EnableAlphaBlending != 0); - gfx3d.state.enableAntialiasing = (DISP3DCNT.EnableAntiAliasing != 0); - gfx3d.state.enableEdgeMarking = (DISP3DCNT.EnableEdgeMarking != 0); - gfx3d.state.enableFogAlphaOnly = (DISP3DCNT.FogOnlyAlpha != 0); - gfx3d.state.enableFog = (DISP3DCNT.EnableFog != 0); - gfx3d.state.enableClearImage = (DISP3DCNT.RearPlaneMode != 0); + const IOREG_DISP3DCNT &DISP3DCNT = gfx3d.pendingState.DISP3DCNT; // According to GBATEK, values greater than 10 force FogStep (0x400 >> FogShiftSHR) to become 0. // So set FogShiftSHR to 11 in this case so that calculations using (0x400 >> FogShiftSHR) will // equal 0. - gfx3d.state.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11; + gfx3d.pendingState.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11; +} + +const GFX3D_IOREG& GFX3D_GetIORegisterMap() +{ + return *_GFX3D_IORegisterMap; } void ParseReg_DISP3DCNT() { const IOREG_DISP3DCNT &DISP3DCNT = GPU->GetEngineMain()->GetIORegisterMap().DISP3DCNT; - if (gfx3d.state.savedDISP3DCNT.value == DISP3DCNT.value) + if (gfx3d.pendingState.DISP3DCNT.value == DISP3DCNT.value) { return; } - gfx3d.state.savedDISP3DCNT.value = DISP3DCNT.value; + gfx3d.pendingState.DISP3DCNT.value = DISP3DCNT.value; gfx3d_parseCurrentDISP3DCNT(); } diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index eb99dea05..2fdf80346 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -144,6 +144,57 @@ void gfx3d_init(); void gfx3d_deinit(); void gfx3d_reset(); +typedef union +{ + u16 value; + + struct + { +#ifndef MSB_FIRST + u8 XOffset; + u8 YOffset; +#else + u8 YOffset; + u8 XOffset; +#endif + }; +} IOREG_CLRIMAGE_OFFSET; + +typedef union +{ + u8 cmd[4]; // 0- 7: Unpacked command OR packed command #1 + // 8-15: Packed command #2 + // 16-23: Packed command #3 + // 24-31: Packed command #4 + + u32 command; // 8-bit unpacked command + u32 param; // Parameter(s) for previous command(s) + +} IOREG_GXFIFO; // 0x04000400: Geometry command/parameter sent to FIFO + +typedef union +{ +#ifndef MSB_FIRST + u8 MtxMode:2; // 0- 1: Set matrix mode; + // 0=Projection + // 1=Position + // 2=Position+Vector + // 3=Texture + u8 :6; // 2- 7: Unused bits + + u32 :24; // 8-31: Unused bits +#else + u8 :6; // 2- 7: Unused bits + u8 MtxMode:2; // 0- 1: Set matrix mode; + // 0=Projection + // 1=Position + // 2=Position+Vector + // 3=Texture + + u32 :24; // 8-31: Unused bits +#endif +} IOREG_MTX_MODE; // 0x04000440: MTX_MODE command port + typedef union { u32 value; @@ -230,7 +281,7 @@ typedef union u8 LightMask:4; // 0- 3: Light enable mask #endif }; -} POLYGON_ATTR; +} POLYGON_ATTR; // 0x040004A4: POLYGON_ATTR command port typedef union { @@ -301,7 +352,173 @@ typedef union u16 :16; #endif }; -} TEXIMAGE_PARAM; +} TEXIMAGE_PARAM; // 0x040004A8: TEXIMAGE_PARAM command port + +typedef union +{ + u32 value; + + struct + { +#ifndef MSB_FIRST + u8 YSortMode:1; // 0: Translucent polygon Y-sorting mode; 0=Auto-sort, 1=Manual-sort + u8 DepthMode:1; // 1: Depth buffering select; 0=Z 1=W + u8 :6; // 2- 7: Unused bits + + u32 :24; // 8-31: Unused bits +#else + u8 :6; // 2- 7: Unused bits + u8 DepthMode:1; // 1: Depth buffering select; 0=Z 1=W + u8 YSortMode:1; // 0: Translucent polygon Y-sorting mode; 0=Auto-sort, 1=Manual-sort + + u32 :24; // 8-31: Unused bits +#endif + }; +} IOREG_SWAP_BUFFERS; // 0x04000540: SWAP_BUFFERS command port + +typedef union +{ + u32 value; + + struct + { + // Coordinate (0,0) represents the bottom-left of the screen. + // Coordinate (255,191) represents the top-right of the screen. + u8 X1; // 0- 7: First X-coordinate; 0...255 + u8 Y1; // 8-15: First Y-coordinate; 0...191 + u8 X2; // 16-23: Second X-coordinate; 0...255 + u8 Y2; // 24-31: Second Y-coordinate; 0...191 + }; +} IOREG_VIEWPORT; // 0x04000580: VIEWPORT command port + +typedef union +{ + u32 value; + + struct + { + u8 TestBusy:1; + u8 BoxTestResult:1; + u8 :6; + + u8 PosVecMtxStackLevel:5; + u8 ProjMtxStackLevel:1; + u8 MtxStackBusy:1; + u8 AckMtxStackError:1; + + u16 CommandListCount:9; + u8 CommandListLessThanHalf:1; + u8 CommandListEmpty:1; + u8 EngineBusy:1; + u8 :2; + u8 CommandListIRQ:2; + }; + +} IOREG_GXSTAT; // 0x04000600: Geometry engine status + +typedef union +{ + u32 value; + + struct + { + u16 PolygonCount; // 0-15: Number of polygons currently stored in polygon list RAM; 0...2048 + u16 VertexCount; // 16-31: Number of vertices currently stored in vertex RAM; 0...6144 + }; +} IOREG_RAM_COUNT; // 0x04000604: Polygon list and vertex RAM count + +struct GFX3D_IOREG +{ + u8 RDLINES_COUNT; // 0x04000320 + u8 __unused1[15]; + u16 EDGE_COLOR[8]; // 0x04000330 + u8 ALPHA_TEST_REF; // 0x04000340 + u8 __unused2[15]; + u32 CLEAR_COLOR; // 0x04000350 + u16 CLEAR_DEPTH; // 0x04000354 + IOREG_CLRIMAGE_OFFSET CLRIMAGE_OFFSET; // 0x04000356 + u32 FOG_COLOR; // 0x04000358 + u16 FOG_OFFSET; // 0x0400035C + u8 __unused3[2]; + u8 FOG_TABLE[32]; // 0x04000360 + u16 TOON_TABLE[32]; // 0x04000380 + u8 __unused4[64]; + + IOREG_GXFIFO GXFIFO; // 0x04000400 + u8 __unused5[60]; + + // Geometry command ports + u32 MTX_MODE; // 0x04000440 + u32 MTX_PUSH; // 0x04000444 + u32 MTX_POP; // 0x04000448 + u32 MTX_STORE; // 0x0400044C + u32 MTX_RESTORE; // 0x04000450 + u32 MTX_IDENTITY; // 0x04000454 + u32 MTX_LOAD_4x4; // 0x04000458 + u32 MTX_LOAD_4x3; // 0x0400045C + u32 MTX_MULT_4x4; // 0x04000460 + u32 MTX_MULT_4x3; // 0x04000464 + u32 MTX_MULT_3x3; // 0x04000468 + u32 MTX_SCALE; // 0x0400046C + u32 MTX_TRANS; // 0x04000470 + u8 __unused6[12]; + u32 COLOR; // 0x04000480 + u32 NORMAL; // 0x04000484 + u32 TEXCOORD; // 0x04000488 + u32 VTX_16; // 0x0400048C + u32 VTX_10; // 0x04000490 + u32 VTX_XY; // 0x04000494 + u32 VTX_XZ; // 0x04000498 + u32 VTX_YZ; // 0x0400049C + u32 VTX_DIFF; // 0x040004A0 + u32 POLYGON_ATTR; // 0x040004A4 + u32 TEXIMAGE_PARAM; // 0x040004A8 + u32 PLTT_BASE; // 0x040004AC + u8 __unused7[16]; + u32 DIF_AMB; // 0x040004C0 + u32 SPE_EMI; // 0x040004C4 + u32 LIGHT_VECTOR; // 0x040004C8 + u32 LIGHT_COLOR; // 0x040004CC + u32 SHININESS; // 0x040004D0 + u8 __unused8[44]; + u32 BEGIN_VTXS; // 0x04000500 + u32 END_VTXS; // 0x04000504 + u8 __unused9[56]; + IOREG_SWAP_BUFFERS SWAP_BUFFERS; // 0x04000540 + u8 __unused10[60]; + IOREG_VIEWPORT VIEWPORT; // 0x04000580 + u8 __unused11[60]; + u32 BOX_TEST; // 0x040005C0 + u32 POS_TEST; // 0x040005C4 + u32 VEC_TEST; // 0x040005C8 + u8 __unused12[52]; + + IOREG_GXSTAT GXSTAT; // 0x04000600 + IOREG_RAM_COUNT RAM_COUNT; // 0x04000604 + u8 __unused13[8]; + u16 DISP_1DOT_DEPTH; // 0x04000610 + u8 __unused14[14]; + u32 POS_RESULT[4]; // 0x04000620 + u16 VEC_RESULT[3]; // 0x04000630 + u8 __unused15[10]; + u8 CLIPMTX_RESULT[64]; // 0x04000640 + u8 VECMTX_RESULT[36]; // 0x04000680 +}; +typedef struct GFX3D_IOREG GFX3D_IOREG; // 0x04000320 - 0x040006A4 + +union GFX3D_Viewport +{ + u64 value; + + struct + { + s16 x; + s16 y; + u16 width; + u16 height; + }; +}; +typedef union GFX3D_Viewport GFX3D_Viewport; struct POLY { PolygonType type; //tri or quad @@ -310,7 +527,8 @@ struct POLY { POLYGON_ATTR attribute; TEXIMAGE_PARAM texParam; u32 texPalette; //the hardware rendering params - u32 viewport; + GFX3D_Viewport viewport; + IOREG_VIEWPORT viewportLegacySave; // Exists for save state compatibility. float miny, maxy; void setVertIndexes(int a, int b, int c, int d=-1) @@ -360,12 +578,7 @@ struct POLY { #define POLYLIST_SIZE 20000 #define VERTLIST_SIZE (POLYLIST_SIZE * 4) - -struct POLYLIST { - POLY list[POLYLIST_SIZE]; - size_t count; - size_t opaqueCount; -}; +#define INDEXLIST_SIZE (POLYLIST_SIZE * 4) //just a vert with a 4 float position struct VERT_POS4f @@ -483,17 +696,6 @@ union VtxTexCoord16 }; typedef union VtxTexCoord16 VtxTexCoord16; -#define INDEXLIST_SIZE (POLYLIST_SIZE * 4) -struct INDEXLIST { - int list[INDEXLIST_SIZE]; -}; - -struct VIEWPORT { - u8 x, y; - u16 width, height; - void decode(u32 v); -}; - //ok, imagine the plane that cuts diagonally across a cube such that it clips //out to be a hexagon. within that plane, draw a quad such that it cuts off //four corners of the hexagon, and you will observe a decagon @@ -513,6 +715,7 @@ struct CPoly POLY *poly; VERT clipVerts[MAX_CLIPPED_VERTS]; }; +typedef struct CPoly CPoly; class GFX3D_Clipper { @@ -536,103 +739,94 @@ public: //used to communicate state to the renderer struct GFX3D_State { - GFX3D_State() - : enableTexturing(true) - , enableAlphaTest(true) - , enableAlphaBlending(true) - , enableAntialiasing(false) - , enableEdgeMarking(false) - , enableClearImage(false) - , enableFog(false) - , enableFogAlphaOnly(false) - , shading(PolygonShadingMode_Toon) - , alphaTestRef(0) - , activeFlushCommand(0) - , pendingFlushCommand(0) - , clearDepth(DS_DEPTH15TO24(0x7FFF)) - , clearColor(0) - , fogColor(0) - , fogOffset(0) - , fogShift(0) - , invalidateToon(true) - { - for(u32 i=0;i void gfx3d_glClearDepth(const T val); +template void gfx3d_glClearImageOffset(const T val); void gfx3d_glSwapScreen(u32 screen); -int gfx3d_GetNumPolys(); -int gfx3d_GetNumVertex(); -void gfx3d_UpdateToonTable(u8 offset, u16 val); -void gfx3d_UpdateToonTable(u8 offset, u32 val); +u32 gfx3d_GetNumPolys(); +u32 gfx3d_GetNumVertex(); +template void gfx3d_UpdateEdgeMarkColorTable(const u8 offset, const T val); +template void gfx3d_UpdateFogTable(const u8 offset, const T val); +template void gfx3d_UpdateToonTable(const u8 offset, const T val); s32 gfx3d_GetClipMatrix (const u32 index); s32 gfx3d_GetDirectionalMatrix(const u32 index); void gfx3d_glAlphaFunc(u32 v); @@ -678,6 +874,7 @@ void gfx3d_FinishLoadStateBufferRead(); void gfx3d_ClearStack(); void gfx3d_parseCurrentDISP3DCNT(); +const GFX3D_IOREG& GFX3D_GetIORegisterMap(); void ParseReg_DISP3DCNT(); #endif //_GFX3D_H_ diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index 7fa5c66b4..56f3af2d0 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2022 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -313,25 +313,25 @@ FORCEINLINE int edge_fx_fl::Step() { -static FORCEINLINE void alphaBlend(FragmentColor &dst, const FragmentColor src) +static FORCEINLINE void alphaBlend(const bool isAlphaBlendingEnabled, const FragmentColor inSrc, FragmentColor &outDst) { - if (src.a == 0) + if (inSrc.a == 0) { return; } - if (src.a == 31 || dst.a == 0 || !gfx3d.renderState.enableAlphaBlending) + if (inSrc.a == 31 || outDst.a == 0 || !isAlphaBlendingEnabled) { - dst = src; + outDst = inSrc; } else { - const u8 alpha = src.a + 1; + const u8 alpha = inSrc.a + 1; const u8 invAlpha = 32 - alpha; - dst.r = (alpha*src.r + invAlpha*dst.r) >> 5; - dst.g = (alpha*src.g + invAlpha*dst.g) >> 5; - dst.b = (alpha*src.b + invAlpha*dst.b) >> 5; - dst.a = max(src.a, dst.a); + outDst.r = (alpha*inSrc.r + invAlpha*outDst.r) >> 5; + outDst.g = (alpha*inSrc.g + invAlpha*outDst.g) >> 5; + outDst.b = (alpha*inSrc.b + invAlpha*outDst.b) >> 5; + outDst.a = max(inSrc.a, outDst.a); } } @@ -424,6 +424,8 @@ FORCEINLINE void RasterizerUnit::_shade(const PolygonMode polygonMode, return; } + const GFX3D_State &renderState = *this->_softRender->currentRenderState; + static const FragmentColor colorWhite = MakeFragmentColor(0x3F, 0x3F, 0x3F, 0x1F); const FragmentColor mainTexColor = (this->_currentTexture->IsSamplingEnabled()) ? this->_sample(texCoordU, texCoordV) : colorWhite; @@ -468,7 +470,7 @@ FORCEINLINE void RasterizerUnit::_shade(const PolygonMode polygonMode, { const FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1]; - if (gfx3d.renderState.shading == PolygonShadingMode_Highlight) + if (renderState.DISP3DCNT.PolygonShading == PolygonShadingMode_Highlight) { // Tested in the "Shadows of Almia" logo in the Pokemon Ranger: Shadows of Almia title screen. // Also tested in Advance Wars: Dual Strike and Advance Wars: Days of Ruin when tiles highlight @@ -502,6 +504,7 @@ FORCEINLINE void RasterizerUnit::_shade(const PolygonMode polygonMode, template template FORCEINLINE void RasterizerUnit::_pixel(const POLYGON_ATTR polyAttr, const bool isTranslucent, const size_t fragmentIndex, FragmentColor &dstColor, float r, float g, float b, float invu, float invv, float z, float w) { + const GFX3D_State &renderState = *this->_softRender->currentRenderState; FragmentColor newDstColor32; FragmentColor shaderOutput; bool isOpaquePixel; @@ -522,7 +525,7 @@ FORCEINLINE void RasterizerUnit::_pixel(const POLYGON_ATTR polyAttr, c // Note that an IEEE-754 single-precision float uses a 23-bit significand. Therefore, we will multiply the // Z-depth by a 22-bit significand for safety. - const u32 newDepth = (gfx3d.renderState.wbuffer) ? u32floor(w * 4096.0f) : u32floor(z * 4194303.0f) << 2; + const u32 newDepth = (renderState.SWAP_BUFFERS.DepthMode) ? u32floor(w * 4096.0f) : u32floor(z * 4194303.0f) << 2; // run the depth test bool depthFail = false; @@ -642,7 +645,7 @@ FORCEINLINE void RasterizerUnit::_pixel(const POLYGON_ATTR polyAttr, c dstAttributeTranslucentPolyID = polyAttr.PolygonID; //alpha blending and write color - alphaBlend(dstColor, shaderOutput); + alphaBlend((renderState.DISP3DCNT.EnableAlphaBlending != 0), shaderOutput, dstColor); dstAttributeIsFogged = (dstAttributeIsFogged && polyAttr.Fog_Enable); } @@ -779,6 +782,7 @@ FORCEINLINE void RasterizerUnit::_drawscanline(const POLYGON_ATTR poly template template FORCEINLINE void RasterizerUnit::_pixel_SSE2(const POLYGON_ATTR polyAttr, const bool isTranslucent, const size_t fragmentIndex, FragmentColor &dstColor, const __m128 &srcColorf, float invu, float invv, float z, float w) { + const GFX3D_State &renderState = *this->_softRender->currentRenderState; FragmentColor newDstColor32; FragmentColor shaderOutput; bool isOpaquePixel; @@ -799,7 +803,7 @@ FORCEINLINE void RasterizerUnit::_pixel_SSE2(const POLYGON_ATTR polyAt // Note that an IEEE-754 single-precision float uses a 23-bit significand. Therefore, we will multiply the // Z-depth by a 22-bit significand for safety. - const u32 newDepth = (gfx3d.renderState.wbuffer) ? u32floor(w * 4096.0f) : u32floor(z * 4194303.0f) << 2; + const u32 newDepth = (renderState.SWAP_BUFFERS.DepthMode) ? u32floor(w * 4096.0f) : u32floor(z * 4194303.0f) << 2; // run the depth test bool depthFail = false; @@ -891,7 +895,7 @@ FORCEINLINE void RasterizerUnit::_pixel_SSE2(const POLYGON_ATTR polyAt this->_shade((PolygonMode)polyAttr.Mode, newDstColor32, shaderOutput, invu * w, invv * w); // handle alpha test - if ( shaderOutput.a == 0 || (this->_softRender->currentRenderState->enableAlphaTest && shaderOutput.a < this->_softRender->currentRenderState->alphaTestRef) ) + if ( shaderOutput.a == 0 || (renderState.DISP3DCNT.EnableAlphaTest && (shaderOutput.a < renderState.alphaTestRef)) ) { return; } @@ -917,7 +921,7 @@ FORCEINLINE void RasterizerUnit::_pixel_SSE2(const POLYGON_ATTR polyAt dstAttributeTranslucentPolyID = polyAttr.PolygonID; //alpha blending and write color - alphaBlend(dstColor, shaderOutput); + alphaBlend((renderState.DISP3DCNT.EnableAlphaBlending != 0), shaderOutput, dstColor); dstAttributeIsFogged = (dstAttributeIsFogged && polyAttr.Fog_Enable); } @@ -1910,21 +1914,13 @@ void SoftRasterizerRenderer::_TransformVertices() vert.fcolor[2] /= vertw; //viewport transformation - VIEWPORT viewport; - viewport.decode(poly.poly->viewport); - vert.coord[0] *= viewport.width; - vert.coord[0] += viewport.x; - - // The maximum viewport y-value is 191. Values above 191 need to wrap - // around and go negative. - // - // Test case: The Homie Rollerz character select screen sets the y-value - // to 253, which then wraps around to -2. - vert.coord[1] *= viewport.height; - vert.coord[1] += (viewport.y > 191) ? (viewport.y - 0xFF) : viewport.y; - vert.coord[1] = 192 - vert.coord[1]; - + vert.coord[0] *= poly.poly->viewport.width; + vert.coord[0] += poly.poly->viewport.x; vert.coord[0] *= wScalar; + + vert.coord[1] *= poly.poly->viewport.height; + vert.coord[1] += poly.poly->viewport.y; + vert.coord[1] = 192 - vert.coord[1]; vert.coord[1] *= hScalar; //here is a hack which needs to be removed. @@ -2010,7 +2006,7 @@ Render3DError SoftRasterizerRenderer::ApplyRenderingSettings(const GFX3D_State & return Render3D::ApplyRenderingSettings(renderState); } -Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine) +Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { // Force all threads to finish before rendering with new data for (size_t i = 0; i < this->_threadCount; i++) @@ -2019,10 +2015,10 @@ Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine) } // Keep the current render states for later use - this->currentRenderState = (GFX3D_State *)&engine.renderState; - this->_clippedPolyCount = engine.clippedPolyCount; - this->_clippedPolyOpaqueCount = engine.clippedPolyOpaqueCount; - memcpy(this->_clippedPolyList, engine.clippedPolyList, this->_clippedPolyCount * sizeof(CPoly)); + this->currentRenderState = (GFX3D_State *)&renderState; + this->_clippedPolyCount = renderGList.clippedPolyCount; + this->_clippedPolyOpaqueCount = renderGList.clippedPolyOpaqueCount; + memcpy(this->_clippedPolyList, renderGList.clippedPolyList, this->_clippedPolyCount * sizeof(CPoly)); const bool doMultithreadedStateSetup = (this->_threadCount >= 2); @@ -2038,16 +2034,16 @@ Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine) } // Convert the toon table colors - ColorspaceConvertBuffer555To6665Opaque(engine.renderState.u16ToonTable, (u32 *)this->toonColor32LUT, 32); + ColorspaceConvertBuffer555To6665Opaque(renderState.toonTable16, (u32 *)this->toonColor32LUT, 32); if (this->_enableEdgeMark) { - this->_UpdateEdgeMarkColorTable(this->currentRenderState->edgeMarkColorTable); + this->_UpdateEdgeMarkColorTable(renderState.edgeMarkColorTable); } if (this->_enableFog) { - this->_UpdateFogTable(this->currentRenderState->fogDensityTable); + this->_UpdateFogTable(renderState.fogDensityTable); } if (doMultithreadedStateSetup) @@ -2107,7 +2103,7 @@ void SoftRasterizerRenderer::_UpdateEdgeMarkColorTable(const u16 *edgeMarkColorT //we can do this by rendering a 3d frame and then freezing the system, but only changing the edge mark colors for (size_t i = 0; i < 8; i++) { - this->_edgeMarkTable[i].color = LE_TO_LOCAL_32( COLOR555TO6665(edgeMarkColorTable[i] & 0x7FFF, (this->currentRenderState->enableAntialiasing) ? 0x10 : 0x1F) ); + this->_edgeMarkTable[i].color = LE_TO_LOCAL_32( COLOR555TO6665(edgeMarkColorTable[i] & 0x7FFF, (this->currentRenderState->DISP3DCNT.EnableAntialiasing) ? 0x10 : 0x1F) ); //zero 20-jun-2013 - this doesnt make any sense. at least, it should be related to the 0x8000 bit. if this is undocumented behaviour, lets write about which scenario proves it here, or which scenario is requiring this code. //// this seems to be the only thing that selectively disables edge marking @@ -2390,7 +2386,7 @@ Render3DError SoftRasterizerRenderer::EndRender() this->_threadPostprocessParam[0].enableEdgeMarking = this->_enableEdgeMark; this->_threadPostprocessParam[0].enableFog = this->_enableFog; this->_threadPostprocessParam[0].fogColor = this->currentRenderState->fogColor; - this->_threadPostprocessParam[0].fogAlphaOnly = this->currentRenderState->enableFogAlphaOnly; + this->_threadPostprocessParam[0].fogAlphaOnly = (this->currentRenderState->DISP3DCNT.FogOnlyAlpha != 0); this->RenderEdgeMarkingAndFog(this->_threadPostprocessParam[0]); } @@ -2426,7 +2422,7 @@ Render3DError SoftRasterizerRenderer::RenderFinish() this->_threadPostprocessParam[i].enableEdgeMarking = this->_enableEdgeMark; this->_threadPostprocessParam[i].enableFog = this->_enableFog; this->_threadPostprocessParam[i].fogColor = this->currentRenderState->fogColor; - this->_threadPostprocessParam[i].fogAlphaOnly = this->currentRenderState->enableFogAlphaOnly; + this->_threadPostprocessParam[i].fogAlphaOnly = (this->currentRenderState->DISP3DCNT.FogOnlyAlpha != 0); this->_task[i].execute(&SoftRasterizer_RunRenderEdgeMarkAndFog, &this->_threadPostprocessParam[i]); } diff --git a/desmume/src/rasterize.h b/desmume/src/rasterize.h index 6006f91e1..38886cb00 100644 --- a/desmume/src/rasterize.h +++ b/desmume/src/rasterize.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2022 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -176,7 +176,7 @@ protected: void _GetPolygonStates(); // Base rendering methods - virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError RenderGeometry(); virtual Render3DError EndRender(); diff --git a/desmume/src/render3D.cpp b/desmume/src/render3D.cpp index 26d5ca94d..7ef3210d2 100644 --- a/desmume/src/render3D.cpp +++ b/desmume/src/render3D.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006-2007 shash - Copyright (C) 2008-2022 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -412,12 +412,12 @@ size_t Render3D::GetClippedPolyCount() const Render3DError Render3D::ApplyRenderingSettings(const GFX3D_State &renderState) { - this->_enableEdgeMark = (CommonSettings.GFX3D_EdgeMark) ? renderState.enableEdgeMarking : false; - this->_enableFog = (CommonSettings.GFX3D_Fog) ? renderState.enableFog : false; + this->_enableEdgeMark = (CommonSettings.GFX3D_EdgeMark) ? (renderState.DISP3DCNT.EnableEdgeMarking != 0) : false; + this->_enableFog = (CommonSettings.GFX3D_Fog) ? (renderState.DISP3DCNT.EnableFog != 0) : false; this->_enableTextureSmoothing = CommonSettings.GFX3D_Renderer_TextureSmoothing; this->_prevEnableTextureSampling = this->_enableTextureSampling; - this->_enableTextureSampling = (CommonSettings.GFX3D_Texture) ? renderState.enableTexturing : false; + this->_enableTextureSampling = (CommonSettings.GFX3D_Texture) ? (renderState.DISP3DCNT.EnableTexMapping != 0) : false; this->_prevEnableTextureDeposterize = this->_enableTextureDeposterize; this->_enableTextureDeposterize = CommonSettings.GFX3D_Renderer_TextureDeposterize; @@ -436,7 +436,7 @@ Render3DError Render3D::ApplyRenderingSettings(const GFX3D_State &renderState) return RENDER3DERROR_NOERR; } -Render3DError Render3D::BeginRender(const GFX3D &engine) +Render3DError Render3D::BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { return RENDER3DERROR_NOERR; } @@ -579,15 +579,14 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState) { Render3DError error = RENDER3DERROR_NOERR; - if (renderState.enableClearImage) + if (renderState.DISP3DCNT.RearPlaneMode) { //the lion, the witch, and the wardrobe (thats book 1, suck it you new-school numberers) //uses the scroll registers in the main game engine const u16 *__restrict clearColorBuffer = (u16 *__restrict)MMU.texInfo.textureSlotAddr[2]; const u16 *__restrict clearDepthBuffer = (u16 *__restrict)MMU.texInfo.textureSlotAddr[3]; - const u16 scrollBits = T1ReadWord(MMU.ARM9_REG, 0x356); //CLRIMAGE_OFFSET - const u8 xScroll = scrollBits & 0xFF; - const u8 yScroll = (scrollBits >> 8) & 0xFF; + const u8 xScroll = renderState.clearImageOffset.XOffset; + const u8 yScroll = renderState.clearImageOffset.YOffset; if (xScroll == 0 && yScroll == 0) { @@ -649,7 +648,7 @@ Render3DError Render3D::SetupTexture(const POLY &thePoly, size_t polyRenderIndex return RENDER3DERROR_NOERR; } -Render3DError Render3D::SetupViewport(const u32 viewportValue) +Render3DError Render3D::SetupViewport(const GFX3D_Viewport viewport) { return RENDER3DERROR_NOERR; } @@ -688,12 +687,12 @@ Render3DError Render3D::RenderPowerOff() return RENDER3DERROR_NOERR; } -Render3DError Render3D::Render(const GFX3D &engine) +Render3DError Render3D::Render(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList) { Render3DError error = RENDER3DERROR_NOERR; this->_isPoweredOn = true; - const u32 clearColorSwapped = LE_TO_LOCAL_32(engine.renderState.clearColor); + const u32 clearColorSwapped = LE_TO_LOCAL_32(renderState.clearColor); this->_clearColor6665.color = LE_TO_LOCAL_32( COLOR555TO6665(clearColorSwapped & 0x7FFF, (clearColorSwapped >> 16) & 0x1F) ); this->_clearAttributes.opaquePolyID = (clearColorSwapped >> 24) & 0x3F; @@ -701,20 +700,20 @@ Render3DError Render3D::Render(const GFX3D &engine) //I am not sure whether it is right, though. previously this was cleared to 0, as a guess, //but in spiderman2 some fires with polyid 0 try to render on top of the background this->_clearAttributes.translucentPolyID = kUnsetTranslucentPolyID; - this->_clearAttributes.depth = engine.renderState.clearDepth; + this->_clearAttributes.depth = renderState.clearDepth; this->_clearAttributes.stencil = 0; this->_clearAttributes.isTranslucentPoly = 0; this->_clearAttributes.polyFacing = PolyFacing_Unwritten; this->_clearAttributes.isFogged = BIT15(clearColorSwapped); - error = this->BeginRender(engine); + error = this->BeginRender(renderState, renderGList); if (error != RENDER3DERROR_NOERR) { this->EndRender(); return error; } - error = this->ClearFramebuffer(engine.renderState); + error = this->ClearFramebuffer(renderState); if (error != RENDER3DERROR_NOERR) { this->EndRender(); diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index 8dfe55dff..47598599b 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006-2007 shash - Copyright (C) 2007-2022 DeSmuME team + Copyright (C) 2007-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -198,7 +198,7 @@ protected: u16 *__restrict outColor16, u32 *__restrict outDepth24, u8 *__restrict outFog); - virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError RenderGeometry(); virtual Render3DError PostprocessFramebuffer(); virtual Render3DError EndRender(); @@ -208,7 +208,7 @@ protected: virtual Render3DError ClearUsingValues(const FragmentColor &clearColor6665, const FragmentAttributes &clearAttributes); virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); - virtual Render3DError SetupViewport(const u32 viewportValue); + virtual Render3DError SetupViewport(const GFX3D_Viewport viewport); public: static void* operator new(size_t size); @@ -232,7 +232,7 @@ public: virtual Render3DError RenderPowerOff(); // Called when the renderer needs to handle a power-off condition by clearing its framebuffers. - virtual Render3DError Render(const GFX3D &engine); // Called when the renderer should do its job and render the current display lists. + virtual Render3DError Render(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); // Called whenever the 3D renderer needs to render the geometry lists. virtual Render3DError RenderFinish(); // Called whenever 3D rendering needs to finish. This function should block the calling thread // and only release the block when 3D rendering is finished. (Before reading the 3D layer, be