diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 2c4d21cf0..694ff77c0 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -1774,13 +1774,14 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const }; // Set up the initial polygon - const POLY &initialPoly = rawPolyList[clippedPolyList[firstIndex].index]; - TEXIMAGE_PARAM lastTexParams = initialPoly.texParam; - u32 lastTexPalette = initialPoly.texPalette; - GFX3D_Viewport lastViewport = initialPoly.viewport; + const CPoly &initialClippedPoly = clippedPolyList[firstIndex]; + const POLY &initialRawPoly = rawPolyList[initialClippedPoly.index]; + TEXIMAGE_PARAM lastTexParams = initialRawPoly.texParam; + u32 lastTexPalette = initialRawPoly.texPalette; + GFX3D_Viewport lastViewport = initialRawPoly.viewport; - this->SetupTexture(initialPoly, firstIndex); - this->SetupViewport(initialPoly.viewport); + this->SetupTexture(initialRawPoly, firstIndex); + this->SetupViewport(initialRawPoly.viewport); // Enumerate through all polygons and render GLsizei vertIndexCount = 0; @@ -1788,7 +1789,8 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const for (size_t i = firstIndex; i <= lastIndex; i++) { - const POLY &rawPoly = rawPolyList[clippedPolyList[i].index]; + const CPoly &clippedPoly = clippedPolyList[i]; + const POLY &rawPoly = rawPolyList[clippedPoly.index]; // Set up the polygon if it changed if (lastPolyAttr.value != rawPoly.attribute.value) @@ -1828,18 +1830,19 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const // the same and we're not drawing a line loop or line strip. if (i+1 <= lastIndex) { - const POLY &nextPoly = rawPolyList[clippedPolyList[i+1].index]; + const CPoly &nextClippedPoly = clippedPolyList[i+1]; + const POLY &nextRawPoly = rawPolyList[nextClippedPoly.index]; - if (lastPolyAttr.value == nextPoly.attribute.value && - lastTexParams.value == nextPoly.texParam.value && - lastTexPalette == nextPoly.texPalette && - lastViewport.value == nextPoly.viewport.value && - polyPrimitive == oglPrimitiveType[nextPoly.vtxFormat] && + if (lastPolyAttr.value == nextRawPoly.attribute.value && + lastTexParams.value == nextRawPoly.texParam.value && + lastTexPalette == nextRawPoly.texPalette && + lastViewport.value == nextRawPoly.viewport.value && + polyPrimitive == oglPrimitiveType[nextRawPoly.vtxFormat] && polyPrimitive != GL_LINE_LOOP && polyPrimitive != GL_LINE_STRIP && - oglPrimitiveType[nextPoly.vtxFormat] != GL_LINE_LOOP && - oglPrimitiveType[nextPoly.vtxFormat] != GL_LINE_STRIP && - this->_isPolyFrontFacing[i] == this->_isPolyFrontFacing[i+1]) + oglPrimitiveType[nextRawPoly.vtxFormat] != GL_LINE_LOOP && + oglPrimitiveType[nextRawPoly.vtxFormat] != GL_LINE_STRIP && + clippedPoly.isPolyBackFacing == nextClippedPoly.isPolyBackFacing) { continue; } @@ -1869,7 +1872,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const rawPoly.attribute.TranslucentDepthWrite_Enable, GFX3D_IsPolyWireframe(rawPoly) || GFX3D_IsPolyOpaque(rawPoly), rawPoly.attribute.PolygonID, - this->_isPolyFrontFacing[i]); + !clippedPoly.isPolyBackFacing); } else { @@ -1879,7 +1882,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const rawPoly.attribute.DepthEqualTest_Enable, rawPoly.attribute.TranslucentDepthWrite_Enable, rawPoly.attribute.PolygonID, - this->_isPolyFrontFacing[i]); + !clippedPoly.isPolyBackFacing); } indexBufferPtr += vertIndexCount; @@ -3912,7 +3915,6 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons glDisable(GL_BLEND); glEnable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); glStencilFunc(GL_ALWAYS, 0x40, 0x40); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -4097,7 +4099,6 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); @@ -4199,15 +4200,9 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++) { - const POLY &rawPoly = this->_rawPolyList[this->_clippedPolyList[i].index]; - + const CPoly &cPoly = this->_clippedPolyList[i]; + const POLY &rawPoly = this->_rawPolyList[cPoly.index]; const size_t polyType = rawPoly.type; - const VERT vert[4] = { - renderGList.rawVertList[rawPoly.vertIndexes[0]], - renderGList.rawVertList[rawPoly.vertIndexes[1]], - renderGList.rawVertList[rawPoly.vertIndexes[2]], - renderGList.rawVertList[rawPoly.vertIndexes[3]] - }; if (this->isShaderSupported) { @@ -4269,19 +4264,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co } } - // Get this polygon's facing. - const size_t n = polyType - 1; - float facing = (vert[0].y + vert[n].y) * (vert[0].x - vert[n].x) + - (vert[1].y + vert[0].y) * (vert[1].x - vert[0].x) + - (vert[2].y + vert[1].y) * (vert[2].x - vert[1].x); - - for (size_t j = 2; j < n; j++) - { - facing += (vert[j+1].y + vert[j].y) * (vert[j+1].x - vert[j].x); - } - renderNeedsToonTable = (renderNeedsToonTable || (rawPoly.attribute.Mode == POLYGON_MODE_TOONHIGHLIGHT)) && this->isShaderSupported; - this->_isPolyFrontFacing[i] = (facing < 0); // Get the texture that is to be attached to this polygon. this->_textureList[i] = this->GetLoadedTextureFromPolygon(rawPoly, this->_enableTextureSampling); @@ -4394,6 +4377,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() { if (this->_clippedPolyCount > 0) { + glDisable(GL_CULL_FACE); // Polygons should already be culled before we get here. glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); @@ -4488,7 +4472,6 @@ Render3DError OpenGLRenderer_1_2::PostprocessFramebuffer() // Set up the postprocessing states glViewport(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); @@ -4803,20 +4786,6 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly, bool treatAs // Set up depth test mode glDepthFunc((thePoly.attribute.DepthEqualTest_Enable) ? GL_EQUAL : GL_LESS); - // Set up culling mode - static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; - GLenum cullingMode = oglCullingMode[thePoly.attribute.SurfaceCullingMode]; - - if (cullingMode == 0) - { - glDisable(GL_CULL_FACE); - } - else - { - glEnable(GL_CULL_FACE); - glCullFace(cullingMode); - } - if (willChangeStencilBuffer) { // Handle drawing states for the polygon @@ -5162,7 +5131,6 @@ Render3DError OpenGLRenderer_1_2::Reset() OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)offsetof(VERT, color) : OGLRef.color4fBuffer; memset(&this->_pendingRenderStates, 0, sizeof(this->_pendingRenderStates)); - memset(this->_isPolyFrontFacing, 0, sizeof(this->_isPolyFrontFacing)); texCache.Reset(); @@ -5472,15 +5440,9 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++) { - const POLY &rawPoly = this->_rawPolyList[this->_clippedPolyList[i].index]; - + const CPoly &cPoly = this->_clippedPolyList[i]; + const POLY &rawPoly = this->_rawPolyList[cPoly.index]; const size_t polyType = rawPoly.type; - const VERT vert[4] = { - renderGList.rawVertList[rawPoly.vertIndexes[0]], - renderGList.rawVertList[rawPoly.vertIndexes[1]], - renderGList.rawVertList[rawPoly.vertIndexes[2]], - renderGList.rawVertList[rawPoly.vertIndexes[3]] - }; for (size_t j = 0; j < polyType; j++) { @@ -5504,19 +5466,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co } } - // Get this polygon's facing. - const size_t n = polyType - 1; - float facing = (vert[0].y + vert[n].y) * (vert[0].x - vert[n].x) + - (vert[1].y + vert[0].y) * (vert[1].x - vert[0].x) + - (vert[2].y + vert[1].y) * (vert[2].x - vert[1].x); - - for (size_t j = 2; j < n; j++) - { - facing += (vert[j+1].y + vert[j].y) * (vert[j+1].x - vert[j].x); - } - renderNeedsToonTable = renderNeedsToonTable || (rawPoly.attribute.Mode == POLYGON_MODE_TOONHIGHLIGHT); - this->_isPolyFrontFacing[i] = (facing < 0); // Get the texture that is to be attached to this polygon. this->_textureList[i] = this->GetLoadedTextureFromPolygon(rawPoly, this->_enableTextureSampling); diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 4aa64a3e5..6a2079787 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -736,7 +736,6 @@ protected: bool _enableMultisampledRendering; int _selectedMultisampleSize; - bool _isPolyFrontFacing[CLIPPED_POLYLIST_SIZE]; size_t _clearImageIndex; Render3DError FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16); diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 49f0c7cc7..f67746a7b 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1788,7 +1788,6 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons glDisable(GL_BLEND); glEnable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); glStencilFunc(GL_ALWAYS, 0x40, 0x40); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -1926,7 +1925,6 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels() glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); glBindVertexArray(OGLRef.vaoPostprocessStatesID); @@ -2023,15 +2021,9 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++) { - const POLY &rawPoly = this->_rawPolyList[this->_clippedPolyList[i].index]; - + const CPoly &cPoly = this->_clippedPolyList[i]; + const POLY &rawPoly = this->_rawPolyList[cPoly.index]; const size_t polyType = rawPoly.type; - const VERT vert[4] = { - renderGList.rawVertList[rawPoly.vertIndexes[0]], - renderGList.rawVertList[rawPoly.vertIndexes[1]], - renderGList.rawVertList[rawPoly.vertIndexes[2]], - renderGList.rawVertList[rawPoly.vertIndexes[3]] - }; for (size_t j = 0; j < polyType; j++) { @@ -2055,19 +2047,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co } } - // Get the polygon's facing. - const size_t n = polyType - 1; - float facing = (vert[0].y + vert[n].y) * (vert[0].x - vert[n].x) + - (vert[1].y + vert[0].y) * (vert[1].x - vert[0].x) + - (vert[2].y + vert[1].y) * (vert[2].x - vert[1].x); - - for (size_t j = 2; j < n; j++) - { - facing += (vert[j+1].y + vert[j].y) * (vert[j+1].x - vert[j].x); - } - renderNeedsToonTable = renderNeedsToonTable || (rawPoly.attribute.Mode == POLYGON_MODE_TOONHIGHLIGHT); - this->_isPolyFrontFacing[i] = (facing < 0); // Get the texture that is to be attached to this polygon. this->_textureList[i] = this->GetLoadedTextureFromPolygon(rawPoly, this->_enableTextureSampling); @@ -2206,7 +2186,6 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() // Set up the postprocessing states glViewport(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); glBindVertexArray(OGLRef.vaoPostprocessStatesID); @@ -2430,20 +2409,6 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly, bool treatAs glDepthFunc((thePoly.attribute.DepthEqualTest_Enable) ? GL_EQUAL : GL_LESS); glUniform1f(OGLRef.uniformPolyDepthOffset[this->_geometryProgramFlags.value], 0.0f); - // Set up culling mode - static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; - GLenum cullingMode = oglCullingMode[thePoly.attribute.SurfaceCullingMode]; - - if (cullingMode == 0) - { - glDisable(GL_CULL_FACE); - } - else - { - glEnable(GL_CULL_FACE); - glCullFace(cullingMode); - } - if (willChangeStencilBuffer) { // Handle drawing states for the polygon diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 9d81a2013..ff752eca2 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -3257,12 +3257,20 @@ static bool gfx3d_ysort_compare(const u16 idx1, const u16 idx2) return (idx1 < idx2); } +static FORCEINLINE s32 iround(const float f) +{ + return (s32)f; //lol +} + template size_t gfx3d_PerformClipping(const GFX3D_GeometryList &gList, CPoly *outCPolyUnsortedList) { size_t clipCount = 0; PolygonType cpType = POLYGON_TYPE_UNDEFINED; + const float wScalar = (float)CurrentRenderer->GetFramebufferWidth() / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH; + const float hScalar = (float)CurrentRenderer->GetFramebufferHeight() / (float)GPU_FRAMEBUFFER_NATIVE_HEIGHT; + for (size_t polyIndex = 0; polyIndex < gList.rawPolyCount; polyIndex++) { const POLY &rawPoly = gList.rawPolyList[polyIndex]; @@ -3274,11 +3282,106 @@ size_t gfx3d_PerformClipping(const GFX3D_GeometryList &gList, CPoly *outCPolyUns (rawPoly.type == POLYGON_TYPE_QUAD) ? &gList.rawVertList[rawPoly.vertIndexes[3]] : NULL }; - cpType = GFX3D_GenerateClippedPoly(polyIndex, rawPoly.type, rawVerts, outCPolyUnsortedList[clipCount]); - if (cpType != POLYGON_TYPE_UNDEFINED) + CPoly &cPoly = outCPolyUnsortedList[clipCount]; + + cpType = GFX3D_GenerateClippedPoly(polyIndex, rawPoly.type, rawVerts, cPoly); + if (cpType == POLYGON_TYPE_UNDEFINED) { - clipCount++; + continue; } + + for (size_t j = 0; j < (size_t)cPoly.type; j++) + { + VERT &vtx = cPoly.clipVerts[j]; + + // 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. + // + // Test case: Dance scenes in Princess Debut can generate undefined vertices + // when the -ffast-math option (relaxed IEEE754 compliance) is used. + const float vtxW = (vtx.coord[3] != 0.0f) ? vtx.coord[3] : 0.00000001f; + + //homogeneous divide + vtx.coord[0] = (vtx.coord[0]+vtxW) / (2*vtxW); + vtx.coord[1] = (vtx.coord[1]+vtxW) / (2*vtxW); + vtx.coord[2] = (vtx.coord[2]+vtxW) / (2*vtxW); + + //CONSIDER: do we need to guarantee that these are in bounds? perhaps not. + //vtx.coord[0] = max( 0.0f, min(1.0f, vtx.coord[0]) ); + //vtx.coord[1] = max( 0.0f, min(1.0f, vtx.coord[1]) ); + //vtx.coord[2] = max( 0.0f, min(1.0f, vtx.coord[2]) ); + + //viewport transformation + const GFX3D_Viewport theViewport = rawPoly.viewport; + vtx.coord[0] *= (float)theViewport.width; + vtx.coord[0] += (float)theViewport.x; + vtx.coord[0] *= wScalar; + + vtx.coord[1] *= (float)theViewport.height; + vtx.coord[1] += (float)theViewport.y; + vtx.coord[1] = 192 - vtx.coord[1]; + vtx.coord[1] *= hScalar; + + //here is a hack which needs to be removed. + //at some point our shape engine needs these to be converted to "fixed point" + //which is currently just a float + vtx.coord[0] = (float)iround(16.0f * vtx.coord[0]); + vtx.coord[1] = (float)iround(16.0f * vtx.coord[1]); + + if (CLIPPERMODE != ClipperMode_DetermineClipOnly) + { + vtx.texcoord[0] /= vtxW; + vtx.texcoord[1] /= vtxW; + + //perspective-correct the colors + vtx.fcolor[0] /= vtxW; + vtx.fcolor[1] /= vtxW; + vtx.fcolor[2] /= vtxW; + } + } + + // Perform face culling. + + //an older approach + //(not good enough for quads and other shapes) + //float ab[2], ac[2]; Vector2Copy(ab, verts[1].coord); Vector2Copy(ac, verts[2].coord); Vector2Subtract(ab, verts[0].coord); + //Vector2Subtract(ac, verts[0].coord); float cross = Vector2Cross(ab, ac); polyAttr.backfacing = (cross>0); + + //a better approach + // we have to support somewhat non-convex polygons (see NSMB world map 1st screen). + // this version should handle those cases better. + + const VERT *vtx = cPoly.clipVerts; + const size_t n = cPoly.type - 1; + float facing = (vtx[0].y + vtx[n].y) * (vtx[0].x - vtx[n].x) + + (vtx[1].y + vtx[0].y) * (vtx[1].x - vtx[0].x) + + (vtx[2].y + vtx[1].y) * (vtx[2].x - vtx[1].x); + + for (size_t j = 2; j < n; j++) + { + facing += (vtx[j+1].y + vtx[j].y) * (vtx[j+1].x - vtx[j].x); + } + + cPoly.isPolyBackFacing = (facing < 0); + + static const bool visibleFunction[2][4] = { + //always false, backfacing, !backfacing, always true + { false, false, true, true }, + { false, true, false, true } + }; + + const u8 cullingMode = rawPoly.attribute.SurfaceCullingMode; + const bool isPolyVisible = visibleFunction[(cPoly.isPolyBackFacing) ? 1 : 0][cullingMode]; + if (!isPolyVisible) + { + // If the polygon is to be culled, then don't count it. + continue; + } + + // Incrementing the count will keep the polygon in the list. + clipCount++; } return clipCount; diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 468d23dab..619d027bf 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -748,6 +748,7 @@ struct CPoly { u16 index; // The index number of this polygon in the full polygon list. PolygonType type; //otherwise known as "count" of verts + bool isPolyBackFacing; VERT clipVerts[MAX_CLIPPED_VERTS]; NDSVertex clipVtxFixed[MAX_CLIPPED_VERTS]; }; diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index 5d076c2f1..fc3a34f63 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -543,7 +543,7 @@ FORCEINLINE void RasterizerUnit::_pixel(const POLYGON_ATTR polyAttr, c depthFail = true; } } - else if ( (ISFRONTFACING && (dstAttributePolyFacing == PolyFacing_Back)) && (dstColor.a == 0x1F)) + else if ( (ISFRONTFACING && (dstAttributePolyFacing == PolyFacing_Back)) && (dstColor.a == 0x1F) ) { // The LEQUAL test is used in the special case where an incoming front-facing polygon's pixel // is to be drawn on top of a back-facing polygon's opaque pixel. @@ -1289,8 +1289,7 @@ FORCEINLINE void RasterizerUnit::Render() for (size_t i = 0; i < clippedPolyCount; i++) { if (!RENDERER) _debug_thisPoly = (i == this->_softRender->_debug_drawClippedUserPoly); - if (!this->_softRender->isPolyVisible[i]) continue; - + const CPoly &clippedPoly = this->_softRender->GetClippedPolyByIndex(i); const POLY &rawPoly = rawPolyList[clippedPoly.index]; const size_t vertCount = (size_t)clippedPoly.type; @@ -1311,7 +1310,7 @@ FORCEINLINE void RasterizerUnit::Render() for (size_t j = vertCount; j < MAX_CLIPPED_VERTS; j++) this->_verts[j] = NULL; - if (!this->_softRender->isPolyBackFacing[i]) + if (!clippedPoly.isPolyBackFacing) { if (polyAttr.Mode == POLYGON_MODE_SHADOW) { @@ -1382,14 +1381,6 @@ void* SoftRasterizer_RunRasterizerUnit(void *arg) return 0; } -static void* SoftRasterizer_RunProcessAllVertices(void *arg) -{ - SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; - softRender->ProcessAllVertices(); - - return NULL; -} - static void* SoftRasterizer_RunGetAndLoadAllTextures(void *arg) { SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg; @@ -1875,112 +1866,6 @@ ClipperMode SoftRasterizerRenderer::GetPreferredPolygonClippingMode() const return (this->_enableHighPrecisionColorInterpolation) ? ClipperMode_FullColorInterpolate : ClipperMode_Full; } -void SoftRasterizerRenderer::_TransformVertices() -{ - const POLY *rawPolyList = this->_rawPolyList; - const float wScalar = (float)this->_framebufferWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH; - const float hScalar = (float)this->_framebufferHeight / (float)GPU_FRAMEBUFFER_NATIVE_HEIGHT; - - //viewport transforms - for (size_t i = 0; i < this->_clippedPolyCount; i++) - { - CPoly &cPoly = this->_clippedPolyList[i]; - for (size_t j = 0; j < (size_t)cPoly.type; j++) - { - VERT &vert = cPoly.clipVerts[j]; - - // 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. - // - // Test case: Dance scenes in Princess Debut can generate undefined vertices - // when the -ffast-math option (relaxed IEEE754 compliance) is used. - const float vertw = (vert.coord[3] != 0.0f) ? vert.coord[3] : 0.00000001f; - - //homogeneous divide - vert.coord[0] = (vert.coord[0]+vertw) / (2*vertw); - vert.coord[1] = (vert.coord[1]+vertw) / (2*vertw); - vert.coord[2] = (vert.coord[2]+vertw) / (2*vertw); - vert.texcoord[0] /= vertw; - vert.texcoord[1] /= vertw; - - //CONSIDER: do we need to guarantee that these are in bounds? perhaps not. - //vert.coord[0] = max(0.0f,min(1.0f,vert.coord[0])); - //vert.coord[1] = max(0.0f,min(1.0f,vert.coord[1])); - //vert.coord[2] = max(0.0f,min(1.0f,vert.coord[2])); - - //perspective-correct the colors - vert.fcolor[0] /= vertw; - vert.fcolor[1] /= vertw; - vert.fcolor[2] /= vertw; - - //viewport transformation - const GFX3D_Viewport theViewport = rawPolyList[cPoly.index].viewport; - vert.coord[0] *= theViewport.width; - vert.coord[0] += theViewport.x; - vert.coord[0] *= wScalar; - - vert.coord[1] *= theViewport.height; - vert.coord[1] += theViewport.y; - vert.coord[1] = 192 - vert.coord[1]; - vert.coord[1] *= hScalar; - - //here is a hack which needs to be removed. - //at some point our shape engine needs these to be converted to "fixed point" - //which is currently just a float - vert.coord[0] = (float)iround(16.0f * vert.coord[0]); - vert.coord[1] = (float)iround(16.0f * vert.coord[1]); - } - } -} - -void SoftRasterizerRenderer::_GetPolygonStates() -{ - static const bool visibleFunction[2][4] = { - //always false, backfacing, !backfacing, always true - { false, false, true, true }, - { false, true, false, true } - }; - - const POLY *rawPolyList = this->_rawPolyList; - - for (size_t i = 0; i < this->_clippedPolyCount; i++) - { - const CPoly &clippedPoly = this->_clippedPolyList[i]; - const POLY &rawPoly = rawPolyList[clippedPoly.index]; - const PolygonType polyType = clippedPoly.type; - const VERT *vert = &clippedPoly.clipVerts[0]; - const u8 cullingMode = rawPoly.attribute.SurfaceCullingMode; - - //HACK: backface culling - //this should be moved to gfx3d, but first we need to redo the way the lists are built - //because it is too convoluted right now. - //(must we throw out verts if a poly gets backface culled? if not, then it might be easier) - - //an older approach - //(not good enough for quads and other shapes) - //float ab[2], ac[2]; Vector2Copy(ab, verts[1].coord); Vector2Copy(ac, verts[2].coord); Vector2Subtract(ab, verts[0].coord); - //Vector2Subtract(ac, verts[0].coord); float cross = Vector2Cross(ab, ac); polyAttr.backfacing = (cross>0); - - //a better approach - // we have to support somewhat non-convex polygons (see NSMB world map 1st screen). - // this version should handle those cases better. - const size_t n = polyType - 1; - float facing = (vert[0].y + vert[n].y) * (vert[0].x - vert[n].x) + - (vert[1].y + vert[0].y) * (vert[1].x - vert[0].x) + - (vert[2].y + vert[1].y) * (vert[2].x - vert[1].x); - - for (size_t j = 2; j < n; j++) - { - facing += (vert[j+1].y + vert[j].y) * (vert[j+1].x - vert[j].x); - } - - this->isPolyBackFacing[i] = (facing < 0); - this->isPolyVisible[i] = visibleFunction[this->isPolyBackFacing[i]][cullingMode]; - } -} - void SoftRasterizerRenderer::GetAndLoadAllTextures() { const POLY *rawPolyList = this->_rawPolyList; @@ -1998,12 +1883,6 @@ void SoftRasterizerRenderer::GetAndLoadAllTextures() } } -void SoftRasterizerRenderer::ProcessAllVertices() -{ - this->_TransformVertices(); - this->_GetPolygonStates(); -} - Render3DError SoftRasterizerRenderer::ApplyRenderingSettings(const GFX3D_State &renderState) { this->_enableHighPrecisionColorInterpolation = CommonSettings.GFX3D_HighResolutionInterpolateColor; @@ -2033,12 +1912,10 @@ Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D_State &renderState if (doMultithreadedStateSetup) { this->_task[0].execute(&SoftRasterizer_RunGetAndLoadAllTextures, this); - this->_task[1].execute(&SoftRasterizer_RunProcessAllVertices, this); } else { this->GetAndLoadAllTextures(); - this->ProcessAllVertices(); } // Convert the toon table colors diff --git a/desmume/src/rasterize.h b/desmume/src/rasterize.h index 6f9c2685e..74f94275f 100644 --- a/desmume/src/rasterize.h +++ b/desmume/src/rasterize.h @@ -171,8 +171,6 @@ protected: // SoftRasterizer-specific methods void _UpdateEdgeMarkColorTable(const u16 *edgeMarkColorTable); void _UpdateFogTable(const u8 *fogDensityTable); - void _TransformVertices(); - void _GetPolygonStates(); // Base rendering methods virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); @@ -186,8 +184,6 @@ public: int _debug_drawClippedUserPoly; CACHE_ALIGN FragmentColor toonColor32LUT[32]; FragmentAttributesBuffer *_framebufferAttributes; - bool isPolyVisible[CLIPPED_POLYLIST_SIZE]; - bool isPolyBackFacing[CLIPPED_POLYLIST_SIZE]; GFX3D_State *currentRenderState; bool _enableFragmentSamplingHack; @@ -198,7 +194,6 @@ public: virtual ClipperMode GetPreferredPolygonClippingMode() const; void GetAndLoadAllTextures(); - void ProcessAllVertices(); Render3DError RenderEdgeMarkingAndFog(const SoftRasterizerPostProcessParams ¶m); SoftRasterizerTexture* GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing);