diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 84ac40634..56b12ee31 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -763,7 +763,7 @@ static void OGLRender() if(!BEGINGL()) return; - _OGLRenderer->Render(&gfx3d.renderState, gfx3d.vertlist, gfx3d.polylist, &gfx3d.indexlist, gfx3d.frameCtr); + _OGLRenderer->Render(gfx3d); ENDGL(); } @@ -2050,7 +2050,7 @@ Render3DError OpenGLRenderer_1_2::DeleteTexture(const TexCacheItem *item) return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) +Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine) { OGLRenderRef &OGLRef = *this->ref; this->doubleBufferIndex = (this->doubleBufferIndex + 1) & 0x01; @@ -2060,12 +2060,12 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) if (this->isShaderSupported) { glUseProgram(OGLRef.programGeometryID); - glUniform1i(OGLRef.uniformStateToonShadingMode, renderState->shading); - glUniform1i(OGLRef.uniformStateEnableAlphaTest, (renderState->enableAlphaTest) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateEnableAntialiasing, (renderState->enableAntialiasing) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (renderState->enableEdgeMarking) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateUseWDepth, (renderState->wbuffer) ? GL_TRUE : GL_FALSE); - glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[renderState->alphaTestRef]); + glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading); + glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE); + glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]); glUniform1i(OGLRef.uniformTexRenderObject, 0); glUniform1i(OGLRef.uniformTexToonTable, OGLTextureUnitID_ToonTable); @@ -2074,9 +2074,9 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) } else { - if(renderState->enableAlphaTest && (renderState->alphaTestRef > 0)) + if(engine.renderState.enableAlphaTest && (engine.renderState.alphaTestRef > 0)) { - glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[renderState->alphaTestRef]); + glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[engine.renderState.alphaTestRef]); } else { @@ -2087,7 +2087,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) glLoadIdentity(); } - if(renderState->enableAlphaBlending) + if(engine.renderState.enableAlphaBlending) { glEnable(GL_BLEND); } @@ -2101,7 +2101,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) +Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) { OGLRenderRef &OGLRef = *this->ref; const size_t polyCount = polyList->count; @@ -2130,7 +2130,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State *renderState, u32 lastViewport = firstPoly->viewport; this->SetupPolygon(firstPoly); - this->SetupTexture(firstPoly, renderState->enableTexturing); + this->SetupTexture(firstPoly, renderState.enableTexturing); this->SetupViewport(lastViewport); GLsizei vertIndexCount = 0; @@ -2153,7 +2153,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State *renderState, { lastTexParams = poly->texParam; lastTexPalette = poly->texPalette; - this->SetupTexture(poly, renderState->enableTexturing); + this->SetupTexture(poly, renderState.enableTexturing); } // Set up the viewport if it changed @@ -2279,34 +2279,34 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const +Render3DError OpenGLRenderer_1_2::ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const { if (this->isShaderSupported && this->isFBOSupported) { glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); // texGColorID - glClearColor(divide5bitBy31_LUT[r], divide5bitBy31_LUT[g], divide5bitBy31_LUT[b], divide5bitBy31_LUT[a]); - glClearDepth((GLclampd)clearDepth / (GLclampd)0x00FFFFFF); + glClearColor(divide5bitBy31_LUT[clearColor.r], divide5bitBy31_LUT[clearColor.g], divide5bitBy31_LUT[clearColor.b], divide5bitBy31_LUT[clearColor.a]); + glClearDepth((GLclampd)clearAttributes.depth / (GLclampd)0x00FFFFFF); glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); // texGDepthID - glClearColor((GLfloat)(clearDepth & 0x000000FF)/255.0f, (GLfloat)((clearDepth >> 8) & 0x000000FF)/255.0f, (GLfloat)((clearDepth >> 16) & 0x000000FF)/255.0f, 1.0); + glClearColor((GLfloat)(clearAttributes.depth & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 8) & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 16) & 0x000000FF)/255.0f, 1.0); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT); // texGPolyID - glClearColor((GLfloat)clearPolyID/63.0f, 0.0, 0.0, 1.0); + glClearColor((GLfloat)clearAttributes.opaquePolyID/63.0f, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT); // texGFogAttrID - glClearColor((enableFog) ? 1.0 : 0.0, 0.0, 0.0, 1.0); + glClearColor((clearAttributes.isFogged) ? 1.0 : 0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffers(4, RenderDrawList); } else { - glClearColor(divide5bitBy31_LUT[r], divide5bitBy31_LUT[g], divide5bitBy31_LUT[b], divide5bitBy31_LUT[a]); - glClearDepth((GLclampd)clearDepth / (GLclampd)0x00FFFFFF); + glClearColor(divide5bitBy31_LUT[clearColor.r], divide5bitBy31_LUT[clearColor.g], divide5bitBy31_LUT[clearColor.b], divide5bitBy31_LUT[clearColor.a]); + glClearDepth((GLclampd)clearAttributes.depth / (GLclampd)0x00FFFFFF); glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } @@ -3352,7 +3352,7 @@ Render3DError OpenGLRenderer_2_0::DisableVertexAttributes() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State *renderState) +Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine) { OGLRenderRef &OGLRef = *this->ref; this->doubleBufferIndex = (this->doubleBufferIndex + 1) & 0x01; @@ -3360,19 +3360,19 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State *renderState) this->SelectRenderingFramebuffer(); glUseProgram(OGLRef.programGeometryID); - glUniform1i(OGLRef.uniformStateToonShadingMode, renderState->shading); - glUniform1i(OGLRef.uniformStateEnableAlphaTest, (renderState->enableAlphaTest) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateEnableAntialiasing, (renderState->enableAntialiasing) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (renderState->enableEdgeMarking) ? GL_TRUE : GL_FALSE); - glUniform1i(OGLRef.uniformStateUseWDepth, (renderState->wbuffer) ? GL_TRUE : GL_FALSE); - glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[renderState->alphaTestRef]); + glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading); + glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE); + glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]); glUniform1i(OGLRef.uniformTexRenderObject, 0); glUniform1i(OGLRef.uniformTexToonTable, OGLTextureUnitID_ToonTable); glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); - if(renderState->enableAlphaBlending) + if(engine.renderState.enableAlphaBlending) { glEnable(GL_BLEND); } diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index c9e69e6a2..42f06b41b 100644 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -561,14 +561,12 @@ protected: virtual Render3DError ReadBackPixels(); // Base rendering methods - virtual Render3DError BeginRender(const GFX3D_State *renderState); - virtual Render3DError RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); + virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); virtual Render3DError EndRender(const u64 frameCount); - virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); - virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer); - virtual Render3DError ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const; + virtual Render3DError ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const; virtual Render3DError SetupPolygon(const POLY *thePoly); virtual Render3DError SetupTexture(const POLY *thePoly, bool enableTexturing); @@ -579,6 +577,7 @@ public: ~OpenGLRenderer_1_2(); virtual Render3DError InitExtensions(); + virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); virtual Render3DError Reset(); virtual Render3DError RenderFinish(); @@ -631,7 +630,7 @@ protected: virtual Render3DError EnableVertexAttributes(const VERTLIST *vertList, const GLushort *indexBuffer, const size_t vertIndexCount); virtual Render3DError DisableVertexAttributes(); - virtual Render3DError BeginRender(const GFX3D_State *renderState); + virtual Render3DError BeginRender(const GFX3D &engine); virtual Render3DError RenderEdgeMarking(const u16 *colorTable, const bool useAntialias); virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly); diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index dfd2d2399..fc8aa3554 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1012,3 +1012,19 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf return OGLERROR_NOERR; } + +Render3DError OpenGLRenderer_3_2::ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const +{ + const GLfloat oglColor[4] = {divide5bitBy31_LUT[clearColor.r], divide5bitBy31_LUT[clearColor.g], divide5bitBy31_LUT[clearColor.b], divide5bitBy31_LUT[clearColor.a]}; + const GLfloat oglDepth[4] = {(GLfloat)(clearAttributes.depth & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 8) & 0x000000FF)/255.0f, (GLfloat)((clearAttributes.depth >> 16) & 0x000000FF)/255.0f, 1.0}; + const GLfloat oglPolyID[4] = {(GLfloat)clearAttributes.opaquePolyID/63.0f, 0.0, 0.0, 1.0}; + const GLfloat oglFogAttr[4] = {(clearAttributes.isFogged) ? 1.0 : 0.0, 0.0, 0.0, 1.0}; + + glClearBufferfi(GL_DEPTH_STENCIL, 0, (GLfloat)clearAttributes.depth / (GLfloat)0x00FFFFFF, 0); + glClearBufferfv(GL_COLOR, 0, oglColor); // texGColorID + glClearBufferfv(GL_COLOR, 1, oglDepth); // texGDepthID + glClearBufferfv(GL_COLOR, 2, oglPolyID); // texGPolyID + glClearBufferfv(GL_COLOR, 3, oglFogAttr); // texGFogAttrID + + return OGLERROR_NOERR; +} diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 3e50178f2..a3cbd556f 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-2013 DeSmuME team + Copyright (C) 2008-2015 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 @@ -82,6 +82,7 @@ protected: virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly); virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer); + virtual Render3DError ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const; public: ~OpenGLRenderer_3_2(); diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index f491b2b19..be89dc99f 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -537,6 +537,9 @@ void gfx3d_init() vertlist = &vertlists[0]; } + gfx3d.state.fogDensityTable = MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360; + gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330); + makeTables(); gfx3d_reset(); } diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 73f271203..beefdf696 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -658,6 +658,8 @@ struct GFX3D_State bool invalidateToon; u16 u16ToonTable[32]; u8 shininessTable[128]; + u8 *fogDensityTable; // Alias to MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360 + u16 *edgeMarkColorTable; // Alias to MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330 }; struct Viewer3d_State diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index 0b9a7a41d..fa4699a77 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -69,8 +69,6 @@ template T _max(T a, T b, T c) { return max(max(a,b),c); } template T _min(T a, T b, T c, T d) { return min(_min(a,b,d),c); } template T _max(T a, T b, T c, T d) { return max(_max(a,b,d),c); } -static const int kUnsetTranslucentPolyID = 255; - static u8 modulate_table[64][64]; static u8 decal_table[32][64][64]; static u8 index_lookup_table[65]; @@ -540,7 +538,7 @@ public: case 2: //toon/highlight shading { texColor = sample(texCoordU, texCoordV); - FragmentColor toonColor = this->_softRender->_toonColor32LUT[src.r >> 1]; + FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1]; if(gfx3d.renderState.shading == GFX3D_State::HIGHLIGHT) { @@ -571,10 +569,8 @@ public: } } - FORCEINLINE void pixel(PolygonAttributes &polyAttr, FragmentAttributes *fragmentAttributes, FragmentColor *fragmentColor, int adr, float r, float g, float b, float invu, float invv, float w, float z) + FORCEINLINE void pixel(const PolygonAttributes &polyAttr, FragmentAttributes &dstAttributes, FragmentColor &dstColor, float r, float g, float b, float invu, float invv, float w, float z) { - FragmentAttributes &destFragment = fragmentAttributes[adr]; - FragmentColor &destFragmentColor = fragmentColor[adr]; FragmentColor srcColor; FragmentColor shaderOutput; @@ -596,15 +592,15 @@ public: { if (CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack > 0) { - if( depthdestFragment.depth + CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack) + if( depth < dstAttributes.depth - CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack + || depth > dstAttributes.depth + CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack) { goto depth_fail; } } else { - if (depth != destFragment.depth) + if (depth != dstAttributes.depth) { goto depth_fail; } @@ -612,7 +608,7 @@ public: } else { - if (depth >= destFragment.depth) + if (depth >= dstAttributes.depth) { goto depth_fail; } @@ -627,7 +623,7 @@ public: } else { - if (destFragment.stencil == 0) + if (dstAttributes.stencil == 0) { goto rejected_fragment; } @@ -635,7 +631,7 @@ public: //shadow polys have a special check here to keep from self-shadowing when user //has tried to prevent it from happening //if this isnt here, then the vehicle select in mariokart will look terrible - if (destFragment.opaquePolyID == polyAttr.polygonID) + if (dstAttributes.opaquePolyID == polyAttr.polygonID) { goto rejected_fragment; } @@ -672,31 +668,31 @@ public: bool isOpaquePixel = shaderOutput.a == 31; if (isOpaquePixel) { - destFragment.opaquePolyID = polyAttr.polygonID; - destFragment.isTranslucentPoly = polyAttr.isTranslucent; - destFragment.isFogged = polyAttr.enableRenderFog; - destFragmentColor = shaderOutput; + dstAttributes.opaquePolyID = polyAttr.polygonID; + dstAttributes.isTranslucentPoly = polyAttr.isTranslucent; + dstAttributes.isFogged = polyAttr.enableRenderFog; + dstColor = shaderOutput; } else { //dont overwrite pixels on translucent polys with the same polyids - if (destFragment.translucentPolyID == polyAttr.polygonID) + if (dstAttributes.translucentPolyID == polyAttr.polygonID) goto rejected_fragment; //originally we were using a test case of shadows-behind-trees in sm64ds //but, it looks bad in that game. this is actually correct //if this isnt correct, then complex shape cart shadows in mario kart don't work right - destFragment.translucentPolyID = polyAttr.polygonID; + dstAttributes.translucentPolyID = polyAttr.polygonID; //alpha blending and write color - alphaBlend(destFragmentColor, shaderOutput); + alphaBlend(dstColor, shaderOutput); - destFragment.isFogged = (destFragment.isFogged && polyAttr.enableRenderFog); + dstAttributes.isFogged = (dstAttributes.isFogged && polyAttr.enableRenderFog); } //depth writing if (isOpaquePixel || polyAttr.enableAlphaDepthWrite) - destFragment.depth = depth; + dstAttributes.depth = depth; } @@ -709,17 +705,17 @@ public: goto done; depth_fail: if (polyAttr.polygonMode == 3 && polyAttr.polygonID == 0) - destFragment.stencil++; + dstAttributes.stencil++; rejected_fragment: done: ; - if (polyAttr.polygonMode == 3 && polyAttr.polygonID != 0 && destFragment.stencil) - destFragment.stencil--; + if (polyAttr.polygonMode == 3 && polyAttr.polygonID != 0 && dstAttributes.stencil) + dstAttributes.stencil--; } //draws a single scanline - FORCEINLINE void drawscanline(PolygonAttributes &polyAttr, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *pLeft, edge_fx_fl *pRight, bool lineHack) + FORCEINLINE void drawscanline(const PolygonAttributes &polyAttr, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *pLeft, edge_fx_fl *pRight, bool lineHack) { int XStart = pLeft->X; int width = pRight->X - XStart; @@ -802,7 +798,7 @@ public: while(width-- > 0) { - pixel(polyAttr, this->_softRender->screenAttributes, this->_softRender->screenColor, adr,color[0],color[1],color[2],u,v,1.0f/invw,z); + pixel(polyAttr, this->_softRender->screenAttributes[adr], this->_softRender->screenColor[adr], color[0], color[1], color[2], u, v, 1.0f/invw, z); adr++; x++; @@ -818,7 +814,7 @@ public: //runs several scanlines, until an edge is finished template - void runscanlines(PolygonAttributes &polyAttr, FragmentColor *color, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *left, edge_fx_fl *right, bool horizontal, bool lineHack) + void runscanlines(const PolygonAttributes &polyAttr, FragmentColor *color, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *left, edge_fx_fl *right, bool horizontal, bool lineHack) { //oh lord, hack city for edge drawing @@ -957,7 +953,7 @@ public: //I didnt reference anything for this algorithm but it seems like I've seen it somewhere before. //Maybe it is like crow's algorithm template - void shape_engine(PolygonAttributes &polyAttr, FragmentColor *color, const size_t framebufferWidth, const size_t framebufferHeight, int type, const bool backwards, bool lineHack) + void shape_engine(const PolygonAttributes &polyAttr, FragmentColor *color, const size_t framebufferWidth, const size_t framebufferHeight, int type, const bool backwards, bool lineHack) { bool failure = false; @@ -1081,6 +1077,42 @@ static void* execRasterizerUnit(void *arg) return 0; } +static void* SoftRasterizer_RunCalculateVertices(void *arg) +{ + SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; + softRender->performViewportTransforms(); + softRender->performBackfaceTests(); + softRender->performCoordAdjustment(); + + return NULL; +} + +static void* SoftRasterizer_RunSetupTextures(void *arg) +{ + SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; + softRender->setupTextures(); + + return NULL; +} + +static void* SoftRasterizer_RunUpdateTables(void *arg) +{ + SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; + softRender->UpdateToonTable(softRender->currentRenderState->u16ToonTable); + softRender->UpdateFogTable(softRender->currentRenderState->fogDensityTable); + softRender->UpdateEdgeMarkColorTable(softRender->currentRenderState->edgeMarkColorTable); + + return NULL; +} + +static void* SoftRasterizer_RunClearFramebuffer(void *arg) +{ + SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; + softRender->ClearFramebuffer(*softRender->currentRenderState); + + return NULL; +} + void _HACK_Viewer_ExecUnit() { _HACK_viewer_rasterizerUnit.mainLoop(); @@ -1115,7 +1147,7 @@ static void SoftRastClose() static void SoftRastRender() { - _SoftRastRenderer->Render(&gfx3d.renderState, gfx3d.vertlist, gfx3d.polylist, &gfx3d.indexlist, gfx3d.frameCtr); + _SoftRastRenderer->Render(gfx3d); } static void SoftRastVramReconfigureSignal() @@ -1143,6 +1175,7 @@ SoftRasterizerRenderer::SoftRasterizerRenderer() _debug_drawClippedUserPoly = -1; clippedPolys = clipper.clippedPolys = new GFX3D_Clipper::TClippedPoly[POLYLIST_SIZE*2]; + _stateSetupNeedsFinish = false; _renderGeometryNeedsFinish = false; _framebufferWidth = GFX3D_FRAMEBUFFER_WIDTH; _framebufferHeight = GFX3D_FRAMEBUFFER_HEIGHT; @@ -1268,7 +1301,7 @@ size_t SoftRasterizerRenderer::performClipping(bool hirez, const VERTLIST *vertL return clipper.clippedPolyCounter; } -template void SoftRasterizerRenderer::performViewportTransforms(const size_t polyCount) +template void SoftRasterizerRenderer::performViewportTransforms() { const float xfactor = (float)this->_framebufferWidth/(float)GFX3D_FRAMEBUFFER_WIDTH; const float yfactor = (float)this->_framebufferHeight/(float)GFX3D_FRAMEBUFFER_HEIGHT; @@ -1276,7 +1309,7 @@ template void SoftRasterizerRenderer::performViewportTransforms(con const float ymax = GFX3D_FRAMEBUFFER_HEIGHT*yfactor-(CUSTOM?0.001f:0); //viewport transforms - for (size_t i = 0; i < polyCount; i++) + for (size_t i = 0; i < this->_clippedPolyCount; i++) { GFX3D_Clipper::TClippedPoly &poly = clippedPolys[i]; for (size_t j = 0; j < poly.type; j++) @@ -1317,12 +1350,12 @@ template void SoftRasterizerRenderer::performViewportTransforms(con } } //these templates needed to be instantiated manually -template void SoftRasterizerRenderer::performViewportTransforms(const size_t polyCount); -template void SoftRasterizerRenderer::performViewportTransforms(const size_t polyCount); +template void SoftRasterizerRenderer::performViewportTransforms(); +template void SoftRasterizerRenderer::performViewportTransforms(); -void SoftRasterizerRenderer::performCoordAdjustment(const size_t polyCount) +void SoftRasterizerRenderer::performCoordAdjustment() { - for (size_t i = 0; i < polyCount; i++) + for (size_t i = 0; i < this->_clippedPolyCount; i++) { GFX3D_Clipper::TClippedPoly &clippedPoly = clippedPolys[i]; int type = clippedPoly.type; @@ -1337,13 +1370,14 @@ void SoftRasterizerRenderer::performCoordAdjustment(const size_t polyCount) } } -void SoftRasterizerRenderer::setupTextures(const size_t polyCount) + +void SoftRasterizerRenderer::setupTextures() { TexCacheItem *lastTexKey = NULL; u32 lastTextureFormat = 0, lastTexturePalette = 0; bool needInitTexture = true; - for (size_t i = 0; i < polyCount; i++) + for (size_t i = 0; i < this->_clippedPolyCount; i++) { GFX3D_Clipper::TClippedPoly &clippedPoly = clippedPolys[i]; POLY *thePoly = clippedPoly.poly; @@ -1388,9 +1422,9 @@ bool PolygonIsVisible(const PolygonAttributes &polyAttr, const bool backfacing) return false; } -void SoftRasterizerRenderer::performBackfaceTests(const size_t polyCount) +void SoftRasterizerRenderer::performBackfaceTests() { - for (size_t i = 0; i < polyCount; i++) + for (size_t i = 0; i < this->_clippedPolyCount; i++) { GFX3D_Clipper::TClippedPoly &clippedPoly = clippedPolys[i]; POLY *thePoly = clippedPoly.poly; @@ -1423,40 +1457,82 @@ void SoftRasterizerRenderer::performBackfaceTests(const size_t polyCount) } } -Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D_State *renderState) +Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine) { - // Force threads to finish before rendering with new data if (rasterizerCores > 1) { + // Force all threads to finish before rendering with new data for (size_t i = 0; i < rasterizerCores; i++) { rasterizerUnitTask[i].finish(); } } + // Keep the current render states for later use + this->currentRenderState = (GFX3D_State *)&engine.renderState; + + this->_clippedPolyCount = this->performClipping(CommonSettings.GFX3D_HighResolutionInterpolateColor, engine.vertlist, engine.polylist, &engine.indexlist); + + if (rasterizerCores >= 4) + { + rasterizerUnitTask[0].execute(&SoftRasterizer_RunCalculateVertices, this); + rasterizerUnitTask[1].execute(&SoftRasterizer_RunSetupTextures, this); + rasterizerUnitTask[2].execute(&SoftRasterizer_RunUpdateTables, this); + rasterizerUnitTask[3].execute(&SoftRasterizer_RunClearFramebuffer, this); + this->_stateSetupNeedsFinish = true; + } + else + { + this->performViewportTransforms(); + this->performBackfaceTests(); + this->performCoordAdjustment(); + this->setupTextures(); + this->UpdateToonTable(engine.renderState.u16ToonTable); + + if (this->currentRenderState->enableEdgeMarking) + { + this->UpdateEdgeMarkColorTable(this->currentRenderState->edgeMarkColorTable); + } + + if (this->currentRenderState->enableFog) + { + this->UpdateFogTable(this->currentRenderState->fogDensityTable); + } + + this->ClearFramebuffer(engine.renderState); + + this->_stateSetupNeedsFinish = false; + } + return RENDER3DERROR_NOERR; } -Render3DError SoftRasterizerRenderer::RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) +Render3DError SoftRasterizerRenderer::RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) { - const size_t polyCount = this->performClipping(CommonSettings.GFX3D_HighResolutionInterpolateColor, vertList, polyList, indexList); - this->_clippedPolyCount = polyCount; - - this->performViewportTransforms(polyCount); - this->performBackfaceTests(polyCount); - this->performCoordAdjustment(polyCount); - this->setupTextures(polyCount); + // If multithreaded, allow for states to finish setting up + if (this->_stateSetupNeedsFinish) + { + rasterizerUnitTask[0].finish(); + rasterizerUnitTask[1].finish(); + rasterizerUnitTask[2].finish(); + rasterizerUnitTask[3].finish(); + this->_stateSetupNeedsFinish = false; + } + // Render the geometry if (rasterizerCores > 1) { for (size_t i = 0; i < rasterizerCores; i++) { rasterizerUnitTask[i].execute(&execRasterizerUnit, (void *)i); } + + this->_renderGeometryNeedsFinish = true; } else { rasterizerUnit[0].mainLoop(); + this->_renderGeometryNeedsFinish = false; } // printf("rendered %d of %d polys after backface culling\n",gfx3d.polylist->count-culled,gfx3d.polylist->count); @@ -1474,24 +1550,6 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, c // - the edges are completely sharp/opaque on the very brief title screen intro, // - the level-start intro gets a pseudo-antialiasing effect around the silhouette, // - the character edges in-level are clearly transparent, and also show well through shield powerups. - //TODO - need to test and find out whether these get grabbed at flush time, or at render time - //we can do this by rendering a 3d frame and then freezing the system, but only changing the edge mark colors - FragmentColor edgeMarkColors[8]; - int edgeMarkDisabled[8]; - - for (size_t i = 0; i < 8; i++) - { - u16 col = colorTable[i]; - edgeMarkColors[i].color = RGB15TO5555(col, (useAntialias) ? 0x0F : 0x1F); - edgeMarkColors[i].r = GFX3D_5TO6(edgeMarkColors[i].r); - edgeMarkColors[i].g = GFX3D_5TO6(edgeMarkColors[i].g); - edgeMarkColors[i].b = GFX3D_5TO6(edgeMarkColors[i].b); - - //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 - //edgeMarkDisabled[i] = (col == 0x7FFF); - edgeMarkDisabled[i] = 0; - } for (size_t i = 0, y = 0; y < this->_framebufferHeight; y++) { @@ -1507,7 +1565,7 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, c // also note that the edge generally goes on the outside, not the inside, (maybe needs to change later) // and that polys with the same edge color can make edges against each other. - FragmentColor edgeColor = edgeMarkColors[self>>3]; + FragmentColor edgeColor = this->edgeMarkTable[self>>3]; #define PIXOFFSET(dx,dy) ((dx)+(GFX3D_FRAMEBUFFER_WIDTH*(dy))) #define ISEDGE(dx,dy) ((x+(dx)!=GFX3D_FRAMEBUFFER_WIDTH) && (x+(dx)!=-1) && (y+(dy)!=GFX3D_FRAMEBUFFER_HEIGHT) && (y+(dy)!=-1) && self > screenAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID) @@ -1549,7 +1607,28 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, c return RENDER3DERROR_NOERR; } -Render3DError SoftRasterizerRenderer::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly) +Render3DError SoftRasterizerRenderer::UpdateEdgeMarkColorTable(const u16 *edgeMarkColorTable) +{ + //TODO: need to test and find out whether these get grabbed at flush time, or at render time + //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++) + { + u16 col = edgeMarkColorTable[i]; + this->edgeMarkTable[i].color = RGB15TO5555(col, (this->currentRenderState->enableAntialiasing) ? 0x0F : 0x1F); + this->edgeMarkTable[i].r = GFX3D_5TO6(this->edgeMarkTable[i].r); + this->edgeMarkTable[i].g = GFX3D_5TO6(this->edgeMarkTable[i].g); + this->edgeMarkTable[i].b = GFX3D_5TO6(this->edgeMarkTable[i].b); + + //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 + //edgeMarkDisabled[i] = (col == 0x7FFF); + this->edgeMarkDisabled[i] = false; + } + + return RENDER3DERROR_NOERR; +} + +Render3DError SoftRasterizerRenderer::UpdateFogTable(const u8 *fogDensityTable) { #if 0 //TODO - this might be a little slow; @@ -1587,46 +1666,71 @@ Render3DError SoftRasterizerRenderer::RenderFog(const u8 *densityTable, const u3 // this should behave exactly the same as the previous loop, // except much faster. (because it's not a 2d loop and isn't so branchy either) // maybe it's fast enough to not need to be cached, now. - const int increment = ((1 << 10) >> shift); - const int incrementDivShift = 10 - shift; - u32 fogOffset = min(max(offset, 0), 32768); + const int increment = ((1 << 10) >> this->currentRenderState->fogShift); + const int incrementDivShift = 10 - this->currentRenderState->fogShift; + u32 fogOffset = min(max(this->currentRenderState->fogOffset, 0), 32768); u32 iMin = min(32768, (( 1 + 1) << incrementDivShift) + fogOffset + 1 - increment); u32 iMax = min(32768, ((32 + 1) << incrementDivShift) + fogOffset + 1 - increment); assert(iMin <= iMax); - memset(fogTable, densityTable[0], iMin); - for(u32 i = iMin; i < iMax; i++) { + + // If the fog factor is 127, then treat it as 128. + u8 fogFactor = (fogDensityTable[0] == 127) ? 128 : fogDensityTable[0]; + memset(this->fogTable, fogFactor, iMin); + + for(u32 i = iMin; i < iMax; i++) + { int num = (i - fogOffset + (increment-1)); int j = (num >> incrementDivShift) - 1; u32 value = (num & ~(increment-1)) + fogOffset; u32 diff = value - i; assert(j >= 1 && j < 32); - fogTable[i] = ((diff*(densityTable[j-1]) + (increment-diff)*(densityTable[j])) >> incrementDivShift); + fogFactor = ((diff*(fogDensityTable[j-1]) + (increment-diff)*(fogDensityTable[j])) >> incrementDivShift); + this->fogTable[i] = (fogFactor == 127) ? 128 : fogFactor; } - memset(fogTable+iMax, densityTable[31], 32768-iMax); + + fogFactor = (fogDensityTable[31] == 127) ? 128 : fogDensityTable[31]; + memset(this->fogTable+iMax, fogFactor, 32768-iMax); #endif + return RENDER3DERROR_NOERR; +} + +Render3DError SoftRasterizerRenderer::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly) +{ u32 r = GFX3D_5TO6((color)&0x1F); u32 g = GFX3D_5TO6((color>>5)&0x1F); u32 b = GFX3D_5TO6((color>>10)&0x1F); u32 a = (color>>16)&0x1F; + const size_t framebufferFragmentCount = this->_framebufferWidth * this->_framebufferHeight; - for (size_t i = 0; i < (this->_framebufferWidth * this->_framebufferHeight); i++) + if (!alphaOnly) { - FragmentAttributes &destFragment = screenAttributes[i]; - if (!destFragment.isFogged) continue; - - FragmentColor &destFragmentColor = screenColor[i]; - u32 fogIndex = destFragment.depth>>9; - assert(fogIndex < 32768); - u8 fog = fogTable[fogIndex]; - if (fog == 127) fog = 128; - if (!alphaOnly) + for (size_t i = 0; i < framebufferFragmentCount; i++) { + const FragmentAttributes &destFragment = screenAttributes[i]; + const size_t fogIndex = destFragment.depth >> 9; + assert(fogIndex < 32768); + const u8 fog = (destFragment.isFogged) ? this->fogTable[fogIndex] : 0; + + FragmentColor &destFragmentColor = screenColor[i]; destFragmentColor.r = ((128-fog)*destFragmentColor.r + r*fog)>>7; destFragmentColor.g = ((128-fog)*destFragmentColor.g + g*fog)>>7; destFragmentColor.b = ((128-fog)*destFragmentColor.b + b*fog)>>7; + destFragmentColor.a = ((128-fog)*destFragmentColor.a + a*fog)>>7; + } + } + else + { + for (size_t i = 0; i < framebufferFragmentCount; i++) + { + const FragmentAttributes &destFragment = screenAttributes[i]; + const size_t fogIndex = destFragment.depth >> 9; + assert(fogIndex < 32768); + const u8 fog = (destFragment.isFogged) ? this->fogTable[fogIndex] : 0; + + FragmentColor &destFragmentColor = screenColor[i]; + destFragmentColor.a = ((128-fog)*destFragmentColor.a + a*fog)>>7; } - destFragmentColor.a = ((128-fog)*destFragmentColor.a + a*fog)>>7; } return RENDER3DERROR_NOERR; @@ -1639,13 +1743,13 @@ Render3DError SoftRasterizerRenderer::UpdateToonTable(const u16 *toonTableBuffer { #ifdef WORDS_BIGENDIAN u32 u32temp = RGB15TO32_NOALPHA(toonTableBuffer[i]); - this->_toonColor32LUT[i].r = (u32temp >> 2) & 0x3F; - this->_toonColor32LUT[i].g = (u32temp >> 10) & 0x3F; - this->_toonColor32LUT[i].b = (u32temp >> 18) & 0x3F; + this->toonColor32LUT[i].r = (u32temp >> 2) & 0x3F; + this->toonColor32LUT[i].g = (u32temp >> 10) & 0x3F; + this->toonColor32LUT[i].b = (u32temp >> 18) & 0x3F; #else - this->_toonColor32LUT[i].color = (RGB15TO32_NOALPHA(toonTableBuffer[i])>>2)&0x3F3F3F3F; + this->toonColor32LUT[i].color = (RGB15TO32_NOALPHA(toonTableBuffer[i])>>2)&0x3F3F3F3F; #endif - //printf("%d %d %d %d\n", this->_toonColor32LUT[i].r, this->_toonColor32LUT[i].g, this->_toonColor32LUT[i].b, this->_toonColor32LUT[i].a); + //printf("%d %d %d %d\n", this->toonColor32LUT[i].r, this->toonColor32LUT[i].g, this->toonColor32LUT[i].b, this->toonColor32LUT[i].a); } return RENDER3DERROR_NOERR; @@ -1662,41 +1766,30 @@ Render3DError SoftRasterizerRenderer::ClearUsingImage(const u16 *__restrict colo size_t iw = x + ((this->_framebufferHeight - 1 - y) * this->_framebufferWidth); ((u32 *)this->screenColor)[iw] = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 31); - screenAttributes[iw].isFogged = fogBuffer[ir]; - screenAttributes[iw].depth = depthBuffer[ir]; - screenAttributes[iw].opaquePolyID = polyIDBuffer[ir]; - screenAttributes[iw].translucentPolyID = kUnsetTranslucentPolyID; - screenAttributes[iw].isTranslucentPoly = false; - screenAttributes[iw].stencil = 0; + this->screenAttributes[iw].isFogged = fogBuffer[ir]; + this->screenAttributes[iw].depth = depthBuffer[ir]; + this->screenAttributes[iw].opaquePolyID = polyIDBuffer[ir]; + this->screenAttributes[iw].translucentPolyID = kUnsetTranslucentPolyID; + this->screenAttributes[iw].isTranslucentPoly = false; + this->screenAttributes[iw].stencil = 0; } } return RENDER3DERROR_NOERR; } -Render3DError SoftRasterizerRenderer::ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const +Render3DError SoftRasterizerRenderer::ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const { - FragmentColor clearFragmentColor; - clearFragmentColor.r = GFX3D_5TO6(r); - clearFragmentColor.g = GFX3D_5TO6(g); - clearFragmentColor.b = GFX3D_5TO6(b); - clearFragmentColor.a = a; - - FragmentAttributes clearFragment; - clearFragment.opaquePolyID = clearPolyID; - //special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display - //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 - clearFragment.translucentPolyID = kUnsetTranslucentPolyID; - clearFragment.depth = clearDepth; - clearFragment.stencil = 0; - clearFragment.isTranslucentPoly = false; - clearFragment.isFogged = enableFog; + FragmentColor convertedClearColor; + convertedClearColor.r = GFX3D_5TO6(clearColor.r); + convertedClearColor.g = GFX3D_5TO6(clearColor.g); + convertedClearColor.b = GFX3D_5TO6(clearColor.b); + convertedClearColor.a = clearColor.a; for (size_t i = 0; i < (this->_framebufferWidth * this->_framebufferHeight); i++) { - screenAttributes[i] = clearFragment; - screenColor[i] = clearFragmentColor; + this->screenAttributes[i] = clearAttributes; + this->screenColor[i] = convertedClearColor; } return RENDER3DERROR_NOERR; @@ -1717,57 +1810,48 @@ Render3DError SoftRasterizerRenderer::Reset() rasterizerUnit[0].SetRenderer(this); } + this->_stateSetupNeedsFinish = false; this->_renderGeometryNeedsFinish = false; Default3D_Reset(); return RENDER3DERROR_NOERR; } -Render3DError SoftRasterizerRenderer::Render(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, const u64 frameCount) +Render3DError SoftRasterizerRenderer::Render(const GFX3D &engine) { Render3DError error = RENDER3DERROR_NOERR; - error = this->BeginRender(renderState); + error = this->BeginRender(engine); if (error != RENDER3DERROR_NOERR) { return error; } - this->UpdateToonTable(renderState->u16ToonTable); - this->ClearFramebuffer(renderState); - this->RenderGeometry(renderState, vertList, polyList, indexList); - this->EndRender(frameCount); + this->RenderGeometry(engine.renderState, engine.vertlist, engine.polylist, &engine.indexlist); + this->EndRender(engine.frameCtr); - if (rasterizerCores > 1) + return error; +} + +Render3DError SoftRasterizerRenderer::EndRender(const u64 frameCount) +{ + // If we're not multithreaded, then just do the post-processing steps now. + if (!this->_renderGeometryNeedsFinish) { - this->_enableAntialias = renderState->enableAntialiasing; - this->_enableEdgeMark = renderState->enableEdgeMarking; - this->_enableFog = renderState->enableFog; - this->_enableFogAlphaOnly = renderState->enableFogAlphaOnly; - this->_fogColor = renderState->fogColor; - this->_fogOffset = renderState->fogOffset; - this->_fogShift = renderState->fogShift; - - this->_renderGeometryNeedsFinish = true; - } - else - { - this->_renderGeometryNeedsFinish = false; - - if (renderState->enableEdgeMarking) + if (this->currentRenderState->enableEdgeMarking) { - this->RenderEdgeMarking((const u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330), renderState->enableAntialiasing); + this->RenderEdgeMarking(this->currentRenderState->edgeMarkColorTable, this->currentRenderState->enableAntialiasing); } - if (renderState->enableFog) + if (this->currentRenderState->enableFog) { - this->RenderFog(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360, renderState->fogColor, renderState->fogOffset, renderState->fogShift, renderState->enableFogAlphaOnly); + this->RenderFog(this->currentRenderState->fogDensityTable, this->currentRenderState->fogColor, this->currentRenderState->fogOffset, this->currentRenderState->fogShift, this->currentRenderState->enableFogAlphaOnly); } memcpy(gfx3d_convertedScreen, this->screenColor, this->_framebufferWidth * this->_framebufferHeight * sizeof(FragmentColor)); } - return error; + return RENDER3DERROR_NOERR; } Render3DError SoftRasterizerRenderer::RenderFinish() @@ -1784,14 +1868,14 @@ Render3DError SoftRasterizerRenderer::RenderFinish() rasterizerUnitTask[i].finish(); } - if (this->_enableEdgeMark) + if (this->currentRenderState->enableEdgeMarking) { - this->RenderEdgeMarking((const u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330), this->_enableAntialias); + this->RenderEdgeMarking(this->currentRenderState->edgeMarkColorTable, this->currentRenderState->enableAntialiasing); } - if (this->_enableFog) + if (this->currentRenderState->enableFog) { - this->RenderFog(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360, this->_fogColor, this->_fogOffset, this->_fogShift, this->_enableFogAlphaOnly); + this->RenderFog(this->currentRenderState->fogDensityTable, this->currentRenderState->fogColor, this->currentRenderState->fogOffset, this->currentRenderState->fogShift, this->currentRenderState->enableFogAlphaOnly); } memcpy(gfx3d_convertedScreen, this->screenColor, this->_framebufferWidth * this->_framebufferHeight * sizeof(FragmentColor)); diff --git a/desmume/src/rasterize.h b/desmume/src/rasterize.h index 80f649a55..267639451 100644 --- a/desmume/src/rasterize.h +++ b/desmume/src/rasterize.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2010 DeSmuME team + Copyright (C) 2009-2015 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 @@ -23,32 +23,6 @@ extern GPU3DInterface gpu3DRasterize; -union FragmentColor -{ - u32 color; - struct - { - u8 r,g,b,a; - }; -}; - -inline FragmentColor MakeFragmentColor(u8 r, u8 g,u8 b,u8 a) -{ - FragmentColor ret; - ret.r = r; ret.g = g; ret.b = b; ret.a = a; - return ret; -} - -struct FragmentAttributes -{ - u32 depth; - u8 opaquePolyID; - u8 translucentPolyID; - u8 stencil; - bool isFogged; - bool isTranslucentPoly; -}; - class TexCacheItem; class SoftRasterizerRenderer : public Render3D @@ -56,39 +30,31 @@ class SoftRasterizerRenderer : public Render3D protected: GFX3D_Clipper clipper; u8 fogTable[32768]; - bool _enableAntialias; - bool _enableEdgeMark; - bool _enableFog; - bool _enableFogAlphaOnly; - u32 _fogColor; - u32 _fogOffset; - u32 _fogShift; + FragmentColor edgeMarkTable[8]; + bool edgeMarkDisabled[8]; + + bool _stateSetupNeedsFinish; bool _renderGeometryNeedsFinish; // SoftRasterizer-specific methods virtual Render3DError InitTables(); size_t performClipping(bool hirez, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); - template void performViewportTransforms(const size_t polyCount); - void performCoordAdjustment(const size_t polyCount); - void performBackfaceTests(const size_t polyCount); - void setupTextures(const size_t polyCount); // Base rendering methods - virtual Render3DError BeginRender(const GFX3D_State *renderState); - virtual Render3DError RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); + virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); virtual Render3DError RenderEdgeMarking(const u16 *colorTable, const bool useAntialias); virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly); - - virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); + virtual Render3DError EndRender(const u64 frameCount); virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer); - virtual Render3DError ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const; + virtual Render3DError ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const; public: int _debug_drawClippedUserPoly; size_t _clippedPolyCount; - FragmentColor _toonColor32LUT[32]; + FragmentColor toonColor32LUT[32]; GFX3D_Clipper::TClippedPoly *clippedPolys; FragmentAttributes *screenAttributes; FragmentColor *screenColor; @@ -97,12 +63,22 @@ public: bool polyBackfacing[POLYLIST_SIZE]; size_t _framebufferWidth; size_t _framebufferHeight; + GFX3D_State *currentRenderState; SoftRasterizerRenderer(); virtual ~SoftRasterizerRenderer(); + template void performViewportTransforms(); + void performBackfaceTests(); + void performCoordAdjustment(); + void setupTextures(); + Render3DError UpdateEdgeMarkColorTable(const u16 *edgeMarkColorTable); + Render3DError UpdateFogTable(const u8 *fogDensityTable); + + // Base rendering methods + virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); virtual Render3DError Reset(); - virtual Render3DError Render(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, const u64 frameCount); + virtual Render3DError Render(const GFX3D &engine); virtual Render3DError RenderFinish(); }; diff --git a/desmume/src/render3D.cpp b/desmume/src/render3D.cpp index c4250f60b..fba4cbae2 100644 --- a/desmume/src/render3D.cpp +++ b/desmume/src/render3D.cpp @@ -116,12 +116,12 @@ Render3D::Render3D() Reset(); } -Render3DError Render3D::BeginRender(const GFX3D_State *renderState) +Render3DError Render3D::BeginRender(const GFX3D &engine) { return RENDER3DERROR_NOERR; } -Render3DError Render3D::RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) +Render3DError Render3D::RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) { return RENDER3DERROR_NOERR; } @@ -146,27 +146,28 @@ Render3DError Render3D::UpdateToonTable(const u16 *toonTableBuffer) return RENDER3DERROR_NOERR; } -Render3DError Render3D::ClearFramebuffer(const GFX3D_State *renderState) +Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState) { Render3DError error = RENDER3DERROR_NOERR; - struct GFX3D_ClearColor - { - u8 r; - u8 g; - u8 b; - u8 a; - } clearColor; + FragmentColor clearColor; + clearColor.r = renderState.clearColor & 0x1F; + clearColor.g = (renderState.clearColor >> 5) & 0x1F; + clearColor.b = (renderState.clearColor >> 10) & 0x1F; + clearColor.a = (renderState.clearColor >> 16) & 0x1F; - clearColor.r = renderState->clearColor & 0x1F; - clearColor.g = (renderState->clearColor >> 5) & 0x1F; - clearColor.b = (renderState->clearColor >> 10) & 0x1F; - clearColor.a = (renderState->clearColor >> 16) & 0x1F; + FragmentAttributes clearFragment; + clearFragment.opaquePolyID = (renderState.clearColor >> 24) & 0x3F; + //special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display + //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 + clearFragment.translucentPolyID = kUnsetTranslucentPolyID; + clearFragment.depth = renderState.clearDepth; + clearFragment.stencil = 0; + clearFragment.isTranslucentPoly = false; + clearFragment.isFogged = BIT15(renderState.clearColor); - const u8 polyID = (renderState->clearColor >> 24) & 0x3F; - const bool enableFog = BIT15(renderState->clearColor); - - if (renderState->enableClearImage) + if (renderState.enableClearImage) { //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 @@ -197,7 +198,7 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State *renderState) this->clearImageDepthBuffer[dd] = dsDepthToD24S8_LUT[clearDepthBuffer[adr] & 0x7FFF]; this->clearImageFogBuffer[dd] = BIT15(clearDepthBuffer[adr]); - this->clearImagePolyIDBuffer[dd] = polyID; + this->clearImagePolyIDBuffer[dd] = clearFragment.opaquePolyID; dd++; } @@ -208,12 +209,12 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State *renderState) error = this->ClearUsingImage(this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer); if (error != RENDER3DERROR_NOERR) { - error = this->ClearUsingValues(clearColor.r, clearColor.g, clearColor.b, clearColor.a, renderState->clearDepth, polyID, enableFog); + error = this->ClearUsingValues(clearColor, clearFragment); } } else { - error = this->ClearUsingValues(clearColor.r, clearColor.g, clearColor.b, clearColor.a, renderState->clearDepth, polyID, enableFog); + error = this->ClearUsingValues(clearColor, clearFragment); } return error; @@ -224,7 +225,7 @@ Render3DError Render3D::ClearUsingImage(const u16 *__restrict colorBuffer, const return RENDER3DERROR_NOERR; } -Render3DError Render3D::ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const +Render3DError Render3D::ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const { return RENDER3DERROR_NOERR; } @@ -254,32 +255,32 @@ Render3DError Render3D::Reset() return RENDER3DERROR_NOERR; } -Render3DError Render3D::Render(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, const u64 frameCount) +Render3DError Render3D::Render(const GFX3D &engine) { Render3DError error = RENDER3DERROR_NOERR; - error = this->BeginRender(renderState); + error = this->BeginRender(engine); if (error != RENDER3DERROR_NOERR) { return error; } - this->UpdateToonTable(renderState->u16ToonTable); - this->ClearFramebuffer(renderState); + this->UpdateToonTable(engine.renderState.u16ToonTable); + this->ClearFramebuffer(engine.renderState); - this->RenderGeometry(renderState, vertList, polyList, indexList); + this->RenderGeometry(engine.renderState, engine.vertlist, engine.polylist, &engine.indexlist); - if (renderState->enableEdgeMarking) + if (engine.renderState.enableEdgeMarking) { - this->RenderEdgeMarking((const u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330), renderState->enableAntialiasing); + this->RenderEdgeMarking(engine.renderState.edgeMarkColorTable, engine.renderState.enableAntialiasing); } - if (renderState->enableFog) + if (engine.renderState.enableFog) { - this->RenderFog(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360, renderState->fogColor, renderState->fogOffset, renderState->fogShift, renderState->enableFogAlphaOnly); + this->RenderFog(engine.renderState.fogDensityTable, engine.renderState.fogColor, engine.renderState.fogOffset, engine.renderState.fogShift, engine.renderState.enableFogAlphaOnly); } - this->EndRender(frameCount); + this->EndRender(engine.frameCtr); return error; } diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index 50357f5bb..d1df39b26 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -25,6 +25,8 @@ //not using this right now #define CALL_CONVENTION +#define kUnsetTranslucentPolyID 255 + typedef struct Render3DInterface { // The name of the plugin, this name will appear in the plugins list @@ -81,6 +83,32 @@ enum Render3DErrorCode typedef int Render3DError; +union FragmentColor +{ + u32 color; + struct + { + u8 r,g,b,a; + }; +}; + +struct FragmentAttributes +{ + u32 depth; + u8 opaquePolyID; + u8 translucentPolyID; + u8 stencil; + bool isFogged; + bool isTranslucentPoly; +}; + +inline FragmentColor MakeFragmentColor(u8 r, u8 g,u8 b,u8 a) +{ + FragmentColor ret; + ret.r = r; ret.g = g; ret.b = b; ret.a = a; + return ret; +} + class Render3D { protected: @@ -89,17 +117,14 @@ protected: CACHE_ALIGN bool clearImageFogBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; CACHE_ALIGN u8 clearImagePolyIDBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; - virtual Render3DError BeginRender(const GFX3D_State *renderState); - virtual Render3DError RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); + virtual Render3DError BeginRender(const GFX3D &engine); + virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); virtual Render3DError RenderEdgeMarking(const u16 *colorTable, const bool useAntialias); virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly); virtual Render3DError EndRender(const u64 frameCount); - virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); - - virtual Render3DError ClearFramebuffer(const GFX3D_State *renderState); virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer); - virtual Render3DError ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearPolyID, const bool enableFog) const; + virtual Render3DError ClearUsingValues(const FragmentColor &clearColor, const FragmentAttributes &clearAttributes) const; virtual Render3DError SetupPolygon(const POLY *thePoly); virtual Render3DError SetupTexture(const POLY *thePoly, bool enableTexturing); @@ -108,8 +133,11 @@ protected: public: Render3D(); + virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); + virtual Render3DError ClearFramebuffer(const GFX3D_State &renderState); + virtual Render3DError Reset(); - virtual Render3DError Render(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, const u64 frameCount); + virtual Render3DError Render(const GFX3D &engine); virtual Render3DError RenderFinish(); virtual Render3DError VramReconfigureSignal(); };