- Fix bug where the depth LUT wasn’t being generated correctly, causing the clear image depth buffer to malfunction. (Regression from r5187.)
- In SoftRasterizer, obsolete GFX3D_Zelda_Shadow_Depth_Hack for depth-equals tests. We’re now using a fixed tolerance of +/-0x200, according to GBATEK.
- In SoftRasterizer, z-depth is now calculated using the depth LUT instead of with << 9. This spreads the depth value more evenly across the range of [0 - 0x00FFFFFF]. This change will need additional testing.
- Do some small optimizations to SoftRasterizer.
- Do more code cleanup.
This commit is contained in:
rogerman 2015-05-10 23:38:35 +00:00
parent 9d6f284681
commit 28d40ffcf5
7 changed files with 186 additions and 190 deletions

View File

@ -161,7 +161,6 @@ int NDS_Init()
NDS_RunAdvansceneAutoImport(); NDS_RunAdvansceneAutoImport();
} }
Render3D_Init();
gfx3d_init(); gfx3d_init();
armcpu_new(&NDS_ARM9,0); armcpu_new(&NDS_ARM9,0);
@ -191,7 +190,6 @@ void NDS_DeInit(void)
SPU_DeInit(); SPU_DeInit();
Screen_DeInit(); Screen_DeInit();
MMU_DeInit(); MMU_DeInit();
Render3D_DeInit();
gfx3d_deinit(); gfx3d_deinit();
WIFI_DeInit(); WIFI_DeInit();

View File

@ -2288,7 +2288,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
// Set up depth test mode // Set up depth test mode
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL}; static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
glDepthFunc(oglDepthFunc[attr.enableDepthTest]); glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
// Set up culling mode // Set up culling mode
static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0};
@ -2309,9 +2309,9 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
// Handle shadow polys. Do this after checking for depth write, since shadow polys // Handle shadow polys. Do this after checking for depth write, since shadow polys
// can change this too. // can change this too.
if(attr.polygonMode == 3) if (attr.polygonMode == POLYGON_MODE_SHADOW)
{ {
if(attr.polygonID == 0) if (attr.polygonID == 0)
{ {
//when the polyID is zero, we are writing the shadow mask. //when the polyID is zero, we are writing the shadow mask.
//set stencilbuf = 1 where the shadow volume is obstructed by geometry. //set stencilbuf = 1 where the shadow volume is obstructed by geometry.
@ -2334,7 +2334,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
} }
else else
{ {
if(attr.isTranslucent) if (attr.isTranslucent)
{ {
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255); glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
@ -2348,7 +2348,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
} }
} }
if(attr.isTranslucent && !attr.enableAlphaDepthWrite) if (attr.isTranslucent && !attr.enableAlphaDepthWrite)
{ {
enableDepthWrite = GL_FALSE; enableDepthWrite = GL_FALSE;
} }
@ -3583,7 +3583,7 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
// Set up depth test mode // Set up depth test mode
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL}; static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
glDepthFunc(oglDepthFunc[attr.enableDepthTest]); glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
// Set up culling mode // Set up culling mode
static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0};
@ -3604,9 +3604,9 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
// Handle shadow polys. Do this after checking for depth write, since shadow polys // Handle shadow polys. Do this after checking for depth write, since shadow polys
// can change this too. // can change this too.
if(attr.polygonMode == 3) if (attr.polygonMode == POLYGON_MODE_SHADOW)
{ {
if(attr.polygonID == 0) if (attr.polygonID == 0)
{ {
//when the polyID is zero, we are writing the shadow mask. //when the polyID is zero, we are writing the shadow mask.
//set stencilbuf = 1 where the shadow volume is obstructed by geometry. //set stencilbuf = 1 where the shadow volume is obstructed by geometry.
@ -3629,7 +3629,7 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
} }
else else
{ {
if(attr.isTranslucent) if (attr.isTranslucent)
{ {
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255); glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
@ -3643,7 +3643,7 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
} }
} }
if(attr.isTranslucent && !attr.enableAlphaDepthWrite) if (attr.isTranslucent && !attr.enableAlphaDepthWrite)
{ {
enableDepthWrite = GL_FALSE; enableDepthWrite = GL_FALSE;
} }

View File

@ -1118,7 +1118,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine)
polyStates[i].enableTexture = (texParams.texFormat != TEXMODE_NONE && engine.renderState.enableTexturing) ? GL_TRUE : GL_FALSE; polyStates[i].enableTexture = (texParams.texFormat != TEXMODE_NONE && engine.renderState.enableTexturing) ? GL_TRUE : GL_FALSE;
polyStates[i].enableFog = (polyAttr.enableRenderFog) ? GL_TRUE : GL_FALSE; polyStates[i].enableFog = (polyAttr.enableRenderFog) ? GL_TRUE : GL_FALSE;
polyStates[i].enableDepthWrite = ((!polyAttr.isTranslucent || polyAttr.enableAlphaDepthWrite) && !(polyAttr.polygonMode == 3 && polyAttr.polygonID == 0)) ? GL_TRUE : GL_FALSE; polyStates[i].enableDepthWrite = ((!polyAttr.isTranslucent || polyAttr.enableAlphaDepthWrite) && !(polyAttr.polygonMode == POLYGON_MODE_SHADOW && polyAttr.polygonID == 0)) ? GL_TRUE : GL_FALSE;
polyStates[i].setNewDepthForTranslucent = (polyAttr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE; polyStates[i].setNewDepthForTranslucent = (polyAttr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE;
polyStates[i].polyAlpha = (!polyAttr.isWireframe && polyAttr.isTranslucent) ? polyAttr.alpha : 0x1F; polyStates[i].polyAlpha = (!polyAttr.isWireframe && polyAttr.isTranslucent) ? polyAttr.alpha : 0x1F;
polyStates[i].polyMode = polyAttr.polygonMode; polyStates[i].polyMode = polyAttr.polygonMode;
@ -1302,7 +1302,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
// Set up depth test mode // Set up depth test mode
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL}; static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
glDepthFunc(oglDepthFunc[attr.enableDepthTest]); glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
// Set up culling mode // Set up culling mode
static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; static const GLenum oglCullingMode[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0};
@ -1323,7 +1323,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
// Handle shadow polys. Do this after checking for depth write, since shadow polys // Handle shadow polys. Do this after checking for depth write, since shadow polys
// can change this too. // can change this too.
if(attr.polygonMode == 3) if (attr.polygonMode == POLYGON_MODE_SHADOW)
{ {
if(attr.polygonID == 0) if(attr.polygonID == 0)
{ {
@ -1348,7 +1348,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
} }
else else
{ {
if(attr.isTranslucent) if (attr.isTranslucent)
{ {
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255); glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
@ -1362,7 +1362,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
} }
} }
if(attr.isTranslucent && !attr.enableAlphaDepthWrite) if (attr.isTranslucent && !attr.enableAlphaDepthWrite)
{ {
enableDepthWrite = GL_FALSE; enableDepthWrite = GL_FALSE;
} }

View File

@ -552,11 +552,14 @@ void gfx3d_init()
gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330); gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330);
makeTables(); makeTables();
Render3D_Init();
gfx3d_reset(); gfx3d_reset();
} }
void gfx3d_deinit() void gfx3d_deinit()
{ {
Render3D_DeInit();
free(polylists); free(polylists);
polylists = NULL; polylists = NULL;
polylist = NULL; polylist = NULL;

View File

@ -132,6 +132,15 @@ enum
GFX3D_LINE = 4 GFX3D_LINE = 4
}; };
// POLYGON MODES
enum PolygonMode
{
POLYGON_MODE_MODULATE = 0,
POLYGON_MODE_DECAL = 1,
POLYGON_MODE_TOONHIGHLIGHT = 2,
POLYGON_MODE_SHADOW = 3
};
// POLYGON ATTRIBUTES - BIT LOCATIONS // POLYGON ATTRIBUTES - BIT LOCATIONS
enum enum
{ {
@ -146,7 +155,7 @@ enum
POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT = 11, POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT = 11,
POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT = 12, POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT = 12,
POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT = 13, POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT = 13,
POLYGON_ATTR_ENABLE_DEPTH_TEST_BIT = 14, POLYGON_ATTR_ENABLE_DEPTH_EQUAL_TEST_BIT = 14,
POLYGON_ATTR_ENABLE_FOG_BIT = 15, POLYGON_ATTR_ENABLE_FOG_BIT = 15,
POLYGON_ATTR_ALPHA_BIT = 16, // Bits 16 - 20 POLYGON_ATTR_ALPHA_BIT = 16, // Bits 16 - 20
// Bits 21 - 23 unused // Bits 21 - 23 unused
@ -167,7 +176,7 @@ enum
POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_MASK = 0x01 << POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT, POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_MASK = 0x01 << POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT,
POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_MASK = 0x01 << POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT, POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_MASK = 0x01 << POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT,
POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK = 0x01 << POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT, POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK = 0x01 << POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT,
POLYGON_ATTR_ENABLE_DEPTH_TEST_MASK = 0x01 << POLYGON_ATTR_ENABLE_DEPTH_TEST_BIT, POLYGON_ATTR_ENABLE_DEPTH_EQUAL_TEST_MASK = 0x01 << POLYGON_ATTR_ENABLE_DEPTH_EQUAL_TEST_BIT,
POLYGON_ATTR_ENABLE_FOG_MASK = 0x01 << POLYGON_ATTR_ENABLE_FOG_BIT, POLYGON_ATTR_ENABLE_FOG_MASK = 0x01 << POLYGON_ATTR_ENABLE_FOG_BIT,
POLYGON_ATTR_ALPHA_MASK = 0x1F << POLYGON_ATTR_ALPHA_BIT, POLYGON_ATTR_ALPHA_MASK = 0x1F << POLYGON_ATTR_ALPHA_BIT,
POLYGON_ATTR_POLYGON_ID_MASK = 0x3F << POLYGON_ATTR_POLYGON_ID_BIT POLYGON_ATTR_POLYGON_ID_MASK = 0x3F << POLYGON_ATTR_POLYGON_ID_BIT
@ -226,25 +235,25 @@ void gfx3d_setFramebufferSize(size_t w, size_t h);
typedef struct typedef struct
{ {
u8 enableLightFlags; u8 enableLightFlags;
bool enableLight0; bool enableLight0;
bool enableLight1; bool enableLight1;
bool enableLight2; bool enableLight2;
bool enableLight3; bool enableLight3;
u8 polygonMode; PolygonMode polygonMode;
u8 surfaceCullingMode; u8 surfaceCullingMode;
bool enableRenderBackSurface; bool enableRenderBackSurface;
bool enableRenderFrontSurface; bool enableRenderFrontSurface;
bool enableAlphaDepthWrite; bool enableAlphaDepthWrite;
bool enableRenderOnFarPlaneIntersect; bool enableRenderOnFarPlaneIntersect;
bool enableRenderOneDot; bool enableRenderOneDot;
bool enableDepthTest; bool enableDepthEqualTest;
bool enableRenderFog; bool enableRenderFog;
bool isWireframe; bool isWireframe;
bool isOpaque; bool isOpaque;
bool isTranslucent; bool isTranslucent;
u8 alpha; u8 alpha;
u8 polygonID; u8 polygonID;
} PolygonAttributes; } PolygonAttributes;
typedef struct typedef struct
@ -306,9 +315,9 @@ struct POLY {
return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT3_MASK) > 0); return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT3_MASK) > 0);
} }
u8 getAttributePolygonMode() const PolygonMode getAttributePolygonMode() const
{ {
return ((polyAttr & POLYGON_ATTR_MODE_MASK) >> POLYGON_ATTR_MODE_BIT); return (PolygonMode)((polyAttr & POLYGON_ATTR_MODE_MASK) >> POLYGON_ATTR_MODE_BIT);
} }
u8 getAttributeEnableFaceCullingFlags() const u8 getAttributeEnableFaceCullingFlags() const
@ -342,9 +351,9 @@ struct POLY {
return ((polyAttr & POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK) > 0); return ((polyAttr & POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK) > 0);
} }
bool getAttributeEnableDepthTest() const bool getAttributeEnableDepthEqualTest() const
{ {
return ((polyAttr & POLYGON_ATTR_ENABLE_DEPTH_TEST_MASK) > 0); return ((polyAttr & POLYGON_ATTR_ENABLE_DEPTH_EQUAL_TEST_MASK) > 0);
} }
bool getAttributeEnableFog() const bool getAttributeEnableFog() const
@ -378,7 +387,7 @@ struct POLY {
theAttr.enableAlphaDepthWrite = this->getAttributeEnableAlphaDepthWrite(); theAttr.enableAlphaDepthWrite = this->getAttributeEnableAlphaDepthWrite();
theAttr.enableRenderOnFarPlaneIntersect = this->getAttributeEnableRenderOnFarPlaneIntersect(); theAttr.enableRenderOnFarPlaneIntersect = this->getAttributeEnableRenderOnFarPlaneIntersect();
theAttr.enableRenderOneDot = this->getAttributeEnableOneDotRender(); theAttr.enableRenderOneDot = this->getAttributeEnableOneDotRender();
theAttr.enableDepthTest = this->getAttributeEnableDepthTest(); theAttr.enableDepthEqualTest = this->getAttributeEnableDepthEqualTest();
theAttr.enableRenderFog = this->getAttributeEnableFog(); theAttr.enableRenderFog = this->getAttributeEnableFog();
theAttr.alpha = this->getAttributeAlpha(); theAttr.alpha = this->getAttributeAlpha();
theAttr.isWireframe = this->isWireframe(); theAttr.isWireframe = this->isWireframe();

View File

@ -452,9 +452,6 @@ public:
FORCEINLINE FragmentColor sample(const float u, const float v) FORCEINLINE FragmentColor sample(const float u, const float v)
{ {
static const FragmentColor white = MakeFragmentColor(63,63,63,31);
if(!sampler.enabled) return white;
//finally, we can use floor here. but, it is slower than we want. //finally, we can use floor here. but, it is slower than we want.
//the best solution is probably to wait until the pipeline is full of fixed point //the best solution is probably to wait until the pipeline is full of fixed point
s32 iu = 0; s32 iu = 0;
@ -490,18 +487,18 @@ public:
} }
} }
FORCEINLINE void shade(const u8 polygonMode, const FragmentColor src, FragmentColor &dst, const float texCoordU, const float texCoordV) FORCEINLINE void shade(const PolygonMode polygonMode, const FragmentColor src, FragmentColor &dst, const float texCoordU, const float texCoordV)
{ {
FragmentColor texColor; static const FragmentColor colorWhite = MakeFragmentColor(0x3F, 0x3F, 0x3F, 0x1F);
const FragmentColor mainTexColor = (sampler.enabled) ? sample(texCoordU, texCoordV) : colorWhite;
switch(polygonMode) switch (polygonMode)
{ {
case 0: //modulate case POLYGON_MODE_MODULATE:
texColor = sample(texCoordU, texCoordV); dst.r = modulate_table[mainTexColor.r][src.r];
dst.r = modulate_table[texColor.r][src.r]; dst.g = modulate_table[mainTexColor.g][src.g];
dst.g = modulate_table[texColor.g][src.g]; dst.b = modulate_table[mainTexColor.b][src.b];
dst.b = modulate_table[texColor.b][src.b]; dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)]>>1;
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)]>>1;
//dst.a = 28; //dst.a = 28;
//#ifdef _MSC_VER //#ifdef _MSC_VER
//if(GetAsyncKeyState(VK_SHIFT)) { //if(GetAsyncKeyState(VK_SHIFT)) {
@ -516,14 +513,13 @@ public:
//#endif //#endif
break; break;
case 1: //decal case POLYGON_MODE_DECAL:
{ {
if(sampler.enabled) if(sampler.enabled)
{ {
texColor = sample(texCoordU, texCoordV); dst.r = decal_table[mainTexColor.a][mainTexColor.r][src.r];
dst.r = decal_table[texColor.a][texColor.r][src.r]; dst.g = decal_table[mainTexColor.a][mainTexColor.g][src.g];
dst.g = decal_table[texColor.a][texColor.g][src.g]; dst.b = decal_table[mainTexColor.a][mainTexColor.b][src.b];
dst.b = decal_table[texColor.a][texColor.b][src.b];
dst.a = src.a; dst.a = src.a;
} }
else else
@ -533,75 +529,59 @@ public:
} }
break; break;
case 2: //toon/highlight shading case POLYGON_MODE_TOONHIGHLIGHT:
{ {
texColor = sample(texCoordU, texCoordV); const FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1];
FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1];
if(gfx3d.renderState.shading == GFX3D_State::HIGHLIGHT) if(gfx3d.renderState.shading == GFX3D_State::HIGHLIGHT)
{ {
dst.r = modulate_table[texColor.r][src.r]; dst.r = modulate_table[mainTexColor.r][src.r];
dst.g = modulate_table[texColor.g][src.r]; dst.g = modulate_table[mainTexColor.g][src.r];
dst.b = modulate_table[texColor.b][src.r]; dst.b = modulate_table[mainTexColor.b][src.r];
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)] >> 1; dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)] >> 1;
dst.r = min<u8>(63, (dst.r + toonColor.r)); dst.r = min<u8>(0x3F, (dst.r + toonColor.r));
dst.g = min<u8>(63, (dst.g + toonColor.g)); dst.g = min<u8>(0x3F, (dst.g + toonColor.g));
dst.b = min<u8>(63, (dst.b + toonColor.b)); dst.b = min<u8>(0x3F, (dst.b + toonColor.b));
} }
else else
{ {
dst.r = modulate_table[texColor.r][toonColor.r]; dst.r = modulate_table[mainTexColor.r][toonColor.r];
dst.g = modulate_table[texColor.g][toonColor.g]; dst.g = modulate_table[mainTexColor.g][toonColor.g];
dst.b = modulate_table[texColor.b][toonColor.b]; dst.b = modulate_table[mainTexColor.b][toonColor.b];
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)] >> 1; dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)] >> 1;
} }
} }
break; break;
case 3: //shadows case POLYGON_MODE_SHADOW:
//is this right? only with the material color? //is this right? only with the material color?
dst = src; dst = src;
break; break;
} }
} }
template<bool isShadowPolygon>
FORCEINLINE void pixel(const PolygonAttributes &polyAttr, FragmentAttributes &dstAttributes, FragmentColor &dstColor, 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)
{ {
FragmentColor srcColor; FragmentColor srcColor;
FragmentColor shaderOutput; FragmentColor shaderOutput;
bool isOpaquePixel;
u32 depth;
if (gfx3d.renderState.wbuffer) //not sure about the w-buffer depth value
//this value was chosen to make the skybox, castle window decals, and water level render correctly in SM64
const u32 depth = (gfx3d.renderState.wbuffer) ? u32floor(4096*w) : DS_DEPTH15TO24( u32floor(z*0x7FFF) );
// run the depth test
if (polyAttr.enableDepthEqualTest)
{ {
//not sure about this const u32 minDepth = max<u32>(0x00000000, dstAttributes.depth - SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE);
//this value was chosen to make the skybox, castle window decals, and water level render correctly in SM64 const u32 maxDepth = min<u32>(0x00FFFFFF, dstAttributes.depth + SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE);
depth = u32floor(4096*w);
} if (depth < minDepth || depth > maxDepth)
else
{
depth = u32floor(z*0x7FFF);
depth <<= 9;
}
//if(polyAttr.decalMode)
if (polyAttr.enableDepthTest) // Why was this originally called "decalMode"?
{
if (CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack > 0)
{ {
if( depth < dstAttributes.depth - CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack goto depth_fail;
|| depth > dstAttributes.depth + CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack)
{
goto depth_fail;
}
}
else
{
if (depth != dstAttributes.depth)
{
goto depth_fail;
}
} }
} }
else else
@ -613,7 +593,7 @@ public:
} }
//handle shadow polys //handle shadow polys
if (polyAttr.polygonMode == 3) if (isShadowPolygon)
{ {
if (polyAttr.polygonID == 0) if (polyAttr.polygonID == 0)
{ {
@ -644,55 +624,50 @@ public:
//this is a HACK: //this is a HACK:
//we are being very sloppy with our interpolation precision right now //we are being very sloppy with our interpolation precision right now
//and rather than fix it, i just want to clamp it //and rather than fix it, i just want to clamp it
srcColor = MakeFragmentColor(max(0U,min(63U,u32floor(r))), srcColor = MakeFragmentColor(max<u8>(0x00, min<u32>(0x3F,u32floor(r))),
max(0U,min(63U,u32floor(g))), max<u8>(0x00, min<u32>(0x3F,u32floor(g))),
max(0U,min(63U,u32floor(b))), max<u8>(0x00, min<u32>(0x3F,u32floor(b))),
polyAttr.alpha); polyAttr.alpha);
//pixel shader //pixel shader
shade(polyAttr.polygonMode, srcColor, shaderOutput, invu * w, invv * w); shade(polyAttr.polygonMode, srcColor, shaderOutput, invu * w, invv * w);
//we shouldnt do any of this if we generated a totally transparent pixel // handle alpha test
if (shaderOutput.a != 0) if ( shaderOutput.a == 0 ||
(this->_softRender->currentRenderState->enableAlphaTest && shaderOutput.a < this->_softRender->currentRenderState->alphaTestRef) )
{ {
//alpha test (don't have any test cases for this...? is it in the right place...?) goto rejected_fragment;
if (gfx3d.renderState.enableAlphaTest)
{
if (shaderOutput.a < gfx3d.renderState.alphaTestRef)
goto rejected_fragment;
}
//handle polyids
bool isOpaquePixel = shaderOutput.a == 31;
if (isOpaquePixel)
{
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 (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
dstAttributes.translucentPolyID = polyAttr.polygonID;
//alpha blending and write color
alphaBlend(dstColor, shaderOutput);
dstAttributes.isFogged = (dstAttributes.isFogged && polyAttr.enableRenderFog);
}
//depth writing
if (isOpaquePixel || polyAttr.enableAlphaDepthWrite)
dstAttributes.depth = depth;
} }
// write pixel values to the framebuffer
isOpaquePixel = (shaderOutput.a == 0x1F);
if (isOpaquePixel)
{
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 (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
dstAttributes.translucentPolyID = polyAttr.polygonID;
//alpha blending and write color
alphaBlend(dstColor, shaderOutput);
dstAttributes.isFogged = (dstAttributes.isFogged && polyAttr.enableRenderFog);
}
//depth writing
if (isOpaquePixel || polyAttr.enableAlphaDepthWrite)
dstAttributes.depth = depth;
//shadow cases: (need multi-bit stencil buffer to cope with all of these, especially the mariokart complex shadows) //shadow cases: (need multi-bit stencil buffer to cope with all of these, especially the mariokart complex shadows)
//1. sm64 (standing near signs and blocks) //1. sm64 (standing near signs and blocks)
@ -702,17 +677,19 @@ public:
goto done; goto done;
depth_fail: depth_fail:
if (polyAttr.polygonMode == 3 && polyAttr.polygonID == 0) if (isShadowPolygon && polyAttr.polygonID == 0)
dstAttributes.stencil++; dstAttributes.stencil++;
rejected_fragment: rejected_fragment:
done: done:
; ;
if (polyAttr.polygonMode == 3 && polyAttr.polygonID != 0 && dstAttributes.stencil) if (isShadowPolygon && polyAttr.polygonID != 0 && dstAttributes.stencil)
dstAttributes.stencil--; dstAttributes.stencil--;
} }
//draws a single scanline //draws a single scanline
template <bool isShadowPolygon>
FORCEINLINE void drawscanline(const PolygonAttributes &polyAttr, FragmentColor *dstColor, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *pLeft, edge_fx_fl *pRight, bool lineHack) FORCEINLINE void drawscanline(const PolygonAttributes &polyAttr, FragmentColor *dstColor, const size_t framebufferWidth, const size_t framebufferHeight, edge_fx_fl *pLeft, edge_fx_fl *pRight, bool lineHack)
{ {
int XStart = pLeft->X; int XStart = pLeft->X;
@ -798,7 +775,7 @@ public:
while (width-- > 0) while (width-- > 0)
{ {
pixel(polyAttr, this->_softRender->_framebufferAttributes[adr], dstColor[adr], color[0], color[1], color[2], u, v, 1.0f/invw, z); pixel<isShadowPolygon>(polyAttr, this->_softRender->_framebufferAttributes[adr], dstColor[adr], color[0], color[1], color[2], u, v, 1.0f/invw, z);
adr++; adr++;
x++; x++;
@ -813,7 +790,7 @@ public:
} }
//runs several scanlines, until an edge is finished //runs several scanlines, until an edge is finished
template<bool SLI> template<bool SLI, bool isShadowPolygon>
void runscanlines(const PolygonAttributes &polyAttr, FragmentColor *dstColor, 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 *dstColor, 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 //oh lord, hack city for edge drawing
@ -826,13 +803,13 @@ public:
if (lineHack && left->Height == 0 && right->Height == 0 && left->Y<framebufferHeight && left->Y>=0) if (lineHack && left->Height == 0 && right->Height == 0 && left->Y<framebufferHeight && left->Y>=0)
{ {
bool draw = (!SLI || (left->Y & SLI_MASK) == SLI_VALUE); bool draw = (!SLI || (left->Y & SLI_MASK) == SLI_VALUE);
if(draw) drawscanline(polyAttr, dstColor, framebufferWidth, framebufferHeight, left,right,lineHack); if(draw) drawscanline<isShadowPolygon>(polyAttr, dstColor, framebufferWidth, framebufferHeight, left,right,lineHack);
} }
while(Height--) while(Height--)
{ {
bool draw = (!SLI || (left->Y & SLI_MASK) == SLI_VALUE); bool draw = (!SLI || (left->Y & SLI_MASK) == SLI_VALUE);
if(draw) drawscanline(polyAttr, dstColor, framebufferWidth, framebufferHeight, left,right,lineHack); if(draw) drawscanline<isShadowPolygon>(polyAttr, dstColor, framebufferWidth, framebufferHeight, left,right,lineHack);
const int xl = left->X; const int xl = left->X;
const int xr = right->X; const int xr = right->X;
const int y = left->Y; const int y = left->Y;
@ -952,7 +929,7 @@ public:
//verts must be clockwise. //verts must be clockwise.
//I didnt reference anything for this algorithm but it seems like I've seen it somewhere before. //I didnt reference anything for this algorithm but it seems like I've seen it somewhere before.
//Maybe it is like crow's algorithm //Maybe it is like crow's algorithm
template<bool SLI> template<bool SLI, bool isShadowPolygon>
void shape_engine(const PolygonAttributes &polyAttr, FragmentColor *dstColor, const size_t framebufferWidth, const size_t framebufferHeight, int type, const bool backwards, bool lineHack) void shape_engine(const PolygonAttributes &polyAttr, FragmentColor *dstColor, const size_t framebufferWidth, const size_t framebufferHeight, int type, const bool backwards, bool lineHack)
{ {
bool failure = false; bool failure = false;
@ -993,7 +970,7 @@ public:
return; return;
bool horizontal = left.Y == right.Y; bool horizontal = left.Y == right.Y;
runscanlines<SLI>(polyAttr, dstColor, framebufferWidth, framebufferHeight, &left, &right, horizontal, lineHack); runscanlines<SLI, isShadowPolygon>(polyAttr, dstColor, framebufferWidth, framebufferHeight, &left, &right, horizontal, lineHack);
//if we ran out of an edge, step to the next one //if we ran out of an edge, step to the next one
if (right.Height == 0) if (right.Height == 0)
@ -1015,44 +992,50 @@ public:
template<bool SLI> template<bool SLI>
FORCEINLINE void mainLoop() FORCEINLINE void mainLoop()
{ {
const size_t polyCount = this->_softRender->_clippedPolyCount;
if (polyCount == 0)
{
return;
}
FragmentColor *dstColor = this->_softRender->GetFramebuffer(); FragmentColor *dstColor = this->_softRender->GetFramebuffer();
size_t dstWidth = this->_softRender->GetFramebufferWidth(); const size_t dstWidth = this->_softRender->GetFramebufferWidth();
size_t dstHeight = this->_softRender->GetFramebufferHeight(); const size_t dstHeight = this->_softRender->GetFramebufferHeight();
lastTexKey = NULL; lastTexKey = NULL;
PolygonAttributes polyAttr; GFX3D_Clipper::TClippedPoly &firstClippedPoly = this->_softRender->clippedPolys[0];
u32 lastPolyAttr = 0; POLY &firstPoly = *firstClippedPoly.poly;
u32 lastTextureFormat = 0, lastTexturePalette = 0; PolygonAttributes polyAttr = firstPoly.getAttributes();
u32 lastPolyAttr = firstPoly.polyAttr;
u32 lastTexParams = firstPoly.texParam;
u32 lastTexPalette = firstPoly.texPalette;
sampler.setup(firstPoly.texParam);
//iterate over polys //iterate over polys
bool first=true; for (size_t i = 0; i < polyCount; i++)
for (size_t i = 0; i < this->_softRender->_clippedPolyCount; i++)
{ {
if (!RENDERER) _debug_thisPoly = (i == this->_softRender->_debug_drawClippedUserPoly); if (!RENDERER) _debug_thisPoly = (i == this->_softRender->_debug_drawClippedUserPoly);
if (!this->_softRender->polyVisible[i]) continue; if (!this->_softRender->polyVisible[i]) continue;
polynum = i; polynum = i;
GFX3D_Clipper::TClippedPoly &clippedPoly = this->_softRender->clippedPolys[i]; GFX3D_Clipper::TClippedPoly &clippedPoly = this->_softRender->clippedPolys[i];
POLY *thePoly = clippedPoly.poly; POLY &thePoly = *clippedPoly.poly;
int type = clippedPoly.type; int type = clippedPoly.type;
if (first || lastPolyAttr != thePoly->polyAttr) if (lastPolyAttr != thePoly.polyAttr)
{ {
polyAttr = thePoly->getAttributes(); polyAttr = thePoly.getAttributes();
lastPolyAttr = thePoly->polyAttr; lastPolyAttr = thePoly.polyAttr;
} }
if (lastTexParams != thePoly.texParam || lastTexPalette != thePoly.texPalette)
if (first || lastTextureFormat != thePoly->texParam || lastTexturePalette != thePoly->texPalette)
{ {
sampler.setup(thePoly->texParam); sampler.setup(thePoly.texParam);
lastTextureFormat = thePoly->texParam; lastTexParams = thePoly.texParam;
lastTexturePalette = thePoly->texPalette; lastTexPalette = thePoly.texPalette;
} }
first = false;
lastTexKey = this->_softRender->polyTexKeys[i]; lastTexKey = this->_softRender->polyTexKeys[i];
for (int j = 0; j < type; j++) for (int j = 0; j < type; j++)
@ -1060,7 +1043,14 @@ public:
for (int j = type; j < MAX_CLIPPED_VERTS; j++) for (int j = type; j < MAX_CLIPPED_VERTS; j++)
this->verts[j] = NULL; this->verts[j] = NULL;
shape_engine<SLI>(polyAttr, dstColor, dstWidth, dstHeight, type, !this->_softRender->polyBackfacing[i], (thePoly->vtxFormat & 4) && CommonSettings.GFX3D_LineHack); if (polyAttr.polygonMode == POLYGON_MODE_SHADOW)
{
shape_engine<SLI, true>(polyAttr, dstColor, dstWidth, dstHeight, type, !this->_softRender->polyBackfacing[i], (thePoly.vtxFormat & 4) && CommonSettings.GFX3D_LineHack);
}
else
{
shape_engine<SLI, false>(polyAttr, dstColor, dstWidth, dstHeight, type, !this->_softRender->polyBackfacing[i], (thePoly.vtxFormat & 4) && CommonSettings.GFX3D_LineHack);
}
} }
} }
@ -1402,7 +1392,7 @@ bool PolygonIsVisible(const PolygonAttributes &polyAttr, const bool backfacing)
{ {
//this was added after adding multi-bit stencil buffer //this was added after adding multi-bit stencil buffer
//it seems that we also need to prevent drawing back faces of shadow polys for rendering //it seems that we also need to prevent drawing back faces of shadow polys for rendering
if (polyAttr.polygonMode == 3 && polyAttr.polygonID != 0) return !backfacing; if (polyAttr.polygonMode == POLYGON_MODE_SHADOW && polyAttr.polygonID != 0) return !backfacing;
//another reasonable possibility is that we should be forcing back faces to draw (mariokart doesnt use them) //another reasonable possibility is that we should be forcing back faces to draw (mariokart doesnt use them)
//and then only using a single bit buffer (but a cursory test of this doesnt actually work) //and then only using a single bit buffer (but a cursory test of this doesnt actually work)
@ -1776,14 +1766,14 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasteriz
#define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy))) #define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy)))
#define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID != this->_framebufferAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID && depth >= this->_framebufferAttributes[i+PIXOFFSET(dx,dy)].depth) #define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID != this->_framebufferAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID && depth >= this->_framebufferAttributes[i+PIXOFFSET(dx,dy)].depth)
if (this->edgeMarkDisabled[polyID>>3] || dstAttributes.isTranslucentPoly)
goto END_EDGE_MARK;
up = ISEDGE( 0,-1); up = ISEDGE( 0,-1);
left = ISEDGE(-1, 0); left = ISEDGE(-1, 0);
right = ISEDGE( 1, 0); right = ISEDGE( 1, 0);
down = ISEDGE( 0, 1); down = ISEDGE( 0, 1);
if(this->edgeMarkDisabled[polyID>>3]) goto END_EDGE_MARK;
if(dstAttributes.isTranslucentPoly) goto END_EDGE_MARK;
if (right) if (right)
{ {
edgeColor = this->edgeMarkTable[this->_framebufferAttributes[i+PIXOFFSET( 1, 0)].opaquePolyID >> 3]; edgeColor = this->edgeMarkTable[this->_framebufferAttributes[i+PIXOFFSET( 1, 0)].opaquePolyID >> 3];
@ -1860,14 +1850,11 @@ Render3DError SoftRasterizerRenderer::UpdateToonTable(const u16 *toonTableBuffer
Render3DError SoftRasterizerRenderer::ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer) Render3DError SoftRasterizerRenderer::ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer)
{ {
// The clear image buffer is y-flipped, so we need to flip it back to normal here. // The clear image buffer is y-flipped, so we need to flip it back to normal here.
for (size_t y = 0; y < this->_framebufferHeight; y++) for (size_t y = 0, iw = 0, ir = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, ir -= (this->_framebufferWidth * 2))
{ {
for (size_t x = 0; x < this->_framebufferWidth; x++) for (size_t x = 0; x < this->_framebufferWidth; x++, iw++, ir++)
{ {
size_t ir = x + (y * this->_framebufferWidth); this->_framebufferColor[iw].color = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 0x1F);
size_t iw = x + ((this->_framebufferHeight - 1 - y) * this->_framebufferWidth);
this->_framebufferColor[iw].color = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 31);
this->_framebufferAttributes[iw].isFogged = fogBuffer[ir]; this->_framebufferAttributes[iw].isFogged = fogBuffer[ir];
this->_framebufferAttributes[iw].depth = depthBuffer[ir]; this->_framebufferAttributes[iw].depth = depthBuffer[ir];
this->_framebufferAttributes[iw].opaquePolyID = polyIDBuffer[ir]; this->_framebufferAttributes[iw].opaquePolyID = polyIDBuffer[ir];
@ -1948,9 +1935,6 @@ Render3DError SoftRasterizerRenderer::EndRender(const u64 frameCount)
{ {
if (this->currentRenderState->enableEdgeMarking || this->currentRenderState->enableFog) if (this->currentRenderState->enableEdgeMarking || this->currentRenderState->enableFog)
{ {
this->postprocessParam[0].renderer = this;
this->postprocessParam[0].startLine = 0;
this->postprocessParam[0].endLine = this->_framebufferHeight;
this->postprocessParam[0].enableEdgeMarking = this->currentRenderState->enableEdgeMarking; this->postprocessParam[0].enableEdgeMarking = this->currentRenderState->enableEdgeMarking;
this->postprocessParam[0].enableFog = this->currentRenderState->enableFog; this->postprocessParam[0].enableFog = this->currentRenderState->enableFog;
this->postprocessParam[0].fogColor = this->currentRenderState->fogColor; this->postprocessParam[0].fogColor = this->currentRenderState->fogColor;

View File

@ -21,6 +21,8 @@
#include "render3D.h" #include "render3D.h"
#include "gfx3d.h" #include "gfx3d.h"
#define SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE 0x200
extern GPU3DInterface gpu3DRasterize; extern GPU3DInterface gpu3DRasterize;
class TexCacheItem; class TexCacheItem;