GFX3D:
- 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:
parent
9d6f284681
commit
28d40ffcf5
|
@ -161,7 +161,6 @@ int NDS_Init()
|
|||
NDS_RunAdvansceneAutoImport();
|
||||
}
|
||||
|
||||
Render3D_Init();
|
||||
gfx3d_init();
|
||||
|
||||
armcpu_new(&NDS_ARM9,0);
|
||||
|
@ -191,7 +190,6 @@ void NDS_DeInit(void)
|
|||
SPU_DeInit();
|
||||
Screen_DeInit();
|
||||
MMU_DeInit();
|
||||
Render3D_DeInit();
|
||||
gfx3d_deinit();
|
||||
|
||||
WIFI_DeInit();
|
||||
|
|
|
@ -2288,7 +2288,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
|
|||
|
||||
// Set up depth test mode
|
||||
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthTest]);
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
|
||||
|
||||
// Set up culling mode
|
||||
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
|
||||
// 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.
|
||||
//set stencilbuf = 1 where the shadow volume is obstructed by geometry.
|
||||
|
@ -2334,7 +2334,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(attr.isTranslucent)
|
||||
if (attr.isTranslucent)
|
||||
{
|
||||
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
|
||||
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;
|
||||
}
|
||||
|
@ -3583,7 +3583,7 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
|
|||
|
||||
// Set up depth test mode
|
||||
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthTest]);
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
|
||||
|
||||
// Set up culling mode
|
||||
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
|
||||
// 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.
|
||||
//set stencilbuf = 1 where the shadow volume is obstructed by geometry.
|
||||
|
@ -3629,7 +3629,7 @@ Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY &thePoly)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(attr.isTranslucent)
|
||||
if (attr.isTranslucent)
|
||||
{
|
||||
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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].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].polyAlpha = (!polyAttr.isWireframe && polyAttr.isTranslucent) ? polyAttr.alpha : 0x1F;
|
||||
polyStates[i].polyMode = polyAttr.polygonMode;
|
||||
|
@ -1302,7 +1302,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
|
|||
|
||||
// Set up depth test mode
|
||||
static const GLenum oglDepthFunc[2] = {GL_LESS, GL_EQUAL};
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthTest]);
|
||||
glDepthFunc(oglDepthFunc[attr.enableDepthEqualTest]);
|
||||
|
||||
// Set up culling mode
|
||||
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
|
||||
// can change this too.
|
||||
if(attr.polygonMode == 3)
|
||||
if (attr.polygonMode == POLYGON_MODE_SHADOW)
|
||||
{
|
||||
if(attr.polygonID == 0)
|
||||
{
|
||||
|
@ -1348,7 +1348,7 @@ Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(attr.isTranslucent)
|
||||
if (attr.isTranslucent)
|
||||
{
|
||||
glStencilFunc(GL_NOTEQUAL, attr.polygonID, 255);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -552,11 +552,14 @@ void gfx3d_init()
|
|||
gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330);
|
||||
|
||||
makeTables();
|
||||
Render3D_Init();
|
||||
gfx3d_reset();
|
||||
}
|
||||
|
||||
void gfx3d_deinit()
|
||||
{
|
||||
Render3D_DeInit();
|
||||
|
||||
free(polylists);
|
||||
polylists = NULL;
|
||||
polylist = NULL;
|
||||
|
|
|
@ -132,6 +132,15 @@ enum
|
|||
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
|
||||
enum
|
||||
{
|
||||
|
@ -146,7 +155,7 @@ enum
|
|||
POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT = 11,
|
||||
POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT = 12,
|
||||
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_ALPHA_BIT = 16, // Bits 16 - 20
|
||||
// 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_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_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_ALPHA_MASK = 0x1F << POLYGON_ATTR_ALPHA_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
|
||||
{
|
||||
u8 enableLightFlags;
|
||||
bool enableLight0;
|
||||
bool enableLight1;
|
||||
bool enableLight2;
|
||||
bool enableLight3;
|
||||
u8 polygonMode;
|
||||
u8 surfaceCullingMode;
|
||||
bool enableRenderBackSurface;
|
||||
bool enableRenderFrontSurface;
|
||||
bool enableAlphaDepthWrite;
|
||||
bool enableRenderOnFarPlaneIntersect;
|
||||
bool enableRenderOneDot;
|
||||
bool enableDepthTest;
|
||||
bool enableRenderFog;
|
||||
bool isWireframe;
|
||||
bool isOpaque;
|
||||
bool isTranslucent;
|
||||
u8 alpha;
|
||||
u8 polygonID;
|
||||
u8 enableLightFlags;
|
||||
bool enableLight0;
|
||||
bool enableLight1;
|
||||
bool enableLight2;
|
||||
bool enableLight3;
|
||||
PolygonMode polygonMode;
|
||||
u8 surfaceCullingMode;
|
||||
bool enableRenderBackSurface;
|
||||
bool enableRenderFrontSurface;
|
||||
bool enableAlphaDepthWrite;
|
||||
bool enableRenderOnFarPlaneIntersect;
|
||||
bool enableRenderOneDot;
|
||||
bool enableDepthEqualTest;
|
||||
bool enableRenderFog;
|
||||
bool isWireframe;
|
||||
bool isOpaque;
|
||||
bool isTranslucent;
|
||||
u8 alpha;
|
||||
u8 polygonID;
|
||||
} PolygonAttributes;
|
||||
|
||||
typedef struct
|
||||
|
@ -306,9 +315,9 @@ struct POLY {
|
|||
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
|
||||
|
@ -342,9 +351,9 @@ struct POLY {
|
|||
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
|
||||
|
@ -378,7 +387,7 @@ struct POLY {
|
|||
theAttr.enableAlphaDepthWrite = this->getAttributeEnableAlphaDepthWrite();
|
||||
theAttr.enableRenderOnFarPlaneIntersect = this->getAttributeEnableRenderOnFarPlaneIntersect();
|
||||
theAttr.enableRenderOneDot = this->getAttributeEnableOneDotRender();
|
||||
theAttr.enableDepthTest = this->getAttributeEnableDepthTest();
|
||||
theAttr.enableDepthEqualTest = this->getAttributeEnableDepthEqualTest();
|
||||
theAttr.enableRenderFog = this->getAttributeEnableFog();
|
||||
theAttr.alpha = this->getAttributeAlpha();
|
||||
theAttr.isWireframe = this->isWireframe();
|
||||
|
|
|
@ -452,9 +452,6 @@ public:
|
|||
|
||||
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.
|
||||
//the best solution is probably to wait until the pipeline is full of fixed point
|
||||
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
|
||||
texColor = sample(texCoordU, texCoordV);
|
||||
dst.r = modulate_table[texColor.r][src.r];
|
||||
dst.g = modulate_table[texColor.g][src.g];
|
||||
dst.b = modulate_table[texColor.b][src.b];
|
||||
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)]>>1;
|
||||
case POLYGON_MODE_MODULATE:
|
||||
dst.r = modulate_table[mainTexColor.r][src.r];
|
||||
dst.g = modulate_table[mainTexColor.g][src.g];
|
||||
dst.b = modulate_table[mainTexColor.b][src.b];
|
||||
dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)]>>1;
|
||||
//dst.a = 28;
|
||||
//#ifdef _MSC_VER
|
||||
//if(GetAsyncKeyState(VK_SHIFT)) {
|
||||
|
@ -516,14 +513,13 @@ public:
|
|||
//#endif
|
||||
break;
|
||||
|
||||
case 1: //decal
|
||||
case POLYGON_MODE_DECAL:
|
||||
{
|
||||
if(sampler.enabled)
|
||||
{
|
||||
texColor = sample(texCoordU, texCoordV);
|
||||
dst.r = decal_table[texColor.a][texColor.r][src.r];
|
||||
dst.g = decal_table[texColor.a][texColor.g][src.g];
|
||||
dst.b = decal_table[texColor.a][texColor.b][src.b];
|
||||
dst.r = decal_table[mainTexColor.a][mainTexColor.r][src.r];
|
||||
dst.g = decal_table[mainTexColor.a][mainTexColor.g][src.g];
|
||||
dst.b = decal_table[mainTexColor.a][mainTexColor.b][src.b];
|
||||
dst.a = src.a;
|
||||
}
|
||||
else
|
||||
|
@ -533,75 +529,59 @@ public:
|
|||
}
|
||||
break;
|
||||
|
||||
case 2: //toon/highlight shading
|
||||
case POLYGON_MODE_TOONHIGHLIGHT:
|
||||
{
|
||||
texColor = sample(texCoordU, texCoordV);
|
||||
FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1];
|
||||
const FragmentColor toonColor = this->_softRender->toonColor32LUT[src.r >> 1];
|
||||
|
||||
if(gfx3d.renderState.shading == GFX3D_State::HIGHLIGHT)
|
||||
{
|
||||
dst.r = modulate_table[texColor.r][src.r];
|
||||
dst.g = modulate_table[texColor.g][src.r];
|
||||
dst.b = modulate_table[texColor.b][src.r];
|
||||
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)] >> 1;
|
||||
dst.r = modulate_table[mainTexColor.r][src.r];
|
||||
dst.g = modulate_table[mainTexColor.g][src.r];
|
||||
dst.b = modulate_table[mainTexColor.b][src.r];
|
||||
dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)] >> 1;
|
||||
|
||||
dst.r = min<u8>(63, (dst.r + toonColor.r));
|
||||
dst.g = min<u8>(63, (dst.g + toonColor.g));
|
||||
dst.b = min<u8>(63, (dst.b + toonColor.b));
|
||||
dst.r = min<u8>(0x3F, (dst.r + toonColor.r));
|
||||
dst.g = min<u8>(0x3F, (dst.g + toonColor.g));
|
||||
dst.b = min<u8>(0x3F, (dst.b + toonColor.b));
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.r = modulate_table[texColor.r][toonColor.r];
|
||||
dst.g = modulate_table[texColor.g][toonColor.g];
|
||||
dst.b = modulate_table[texColor.b][toonColor.b];
|
||||
dst.a = modulate_table[GFX3D_5TO6(texColor.a)][GFX3D_5TO6(src.a)] >> 1;
|
||||
dst.r = modulate_table[mainTexColor.r][toonColor.r];
|
||||
dst.g = modulate_table[mainTexColor.g][toonColor.g];
|
||||
dst.b = modulate_table[mainTexColor.b][toonColor.b];
|
||||
dst.a = modulate_table[GFX3D_5TO6(mainTexColor.a)][GFX3D_5TO6(src.a)] >> 1;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: //shadows
|
||||
case POLYGON_MODE_SHADOW:
|
||||
//is this right? only with the material color?
|
||||
dst = src;
|
||||
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)
|
||||
{
|
||||
FragmentColor srcColor;
|
||||
FragmentColor shaderOutput;
|
||||
|
||||
u32 depth;
|
||||
if (gfx3d.renderState.wbuffer)
|
||||
bool isOpaquePixel;
|
||||
|
||||
//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
|
||||
//this value was chosen to make the skybox, castle window decals, and water level render correctly in SM64
|
||||
depth = u32floor(4096*w);
|
||||
}
|
||||
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)
|
||||
const u32 minDepth = max<u32>(0x00000000, dstAttributes.depth - SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE);
|
||||
const u32 maxDepth = min<u32>(0x00FFFFFF, dstAttributes.depth + SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE);
|
||||
|
||||
if (depth < minDepth || depth > maxDepth)
|
||||
{
|
||||
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 != dstAttributes.depth)
|
||||
{
|
||||
goto depth_fail;
|
||||
}
|
||||
goto depth_fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -613,7 +593,7 @@ public:
|
|||
}
|
||||
|
||||
//handle shadow polys
|
||||
if (polyAttr.polygonMode == 3)
|
||||
if (isShadowPolygon)
|
||||
{
|
||||
if (polyAttr.polygonID == 0)
|
||||
{
|
||||
|
@ -644,55 +624,50 @@ public:
|
|||
//this is a HACK:
|
||||
//we are being very sloppy with our interpolation precision right now
|
||||
//and rather than fix it, i just want to clamp it
|
||||
srcColor = MakeFragmentColor(max(0U,min(63U,u32floor(r))),
|
||||
max(0U,min(63U,u32floor(g))),
|
||||
max(0U,min(63U,u32floor(b))),
|
||||
srcColor = MakeFragmentColor(max<u8>(0x00, min<u32>(0x3F,u32floor(r))),
|
||||
max<u8>(0x00, min<u32>(0x3F,u32floor(g))),
|
||||
max<u8>(0x00, min<u32>(0x3F,u32floor(b))),
|
||||
polyAttr.alpha);
|
||||
|
||||
//pixel shader
|
||||
shade(polyAttr.polygonMode, srcColor, shaderOutput, invu * w, invv * w);
|
||||
|
||||
//we shouldnt do any of this if we generated a totally transparent pixel
|
||||
if (shaderOutput.a != 0)
|
||||
// handle alpha test
|
||||
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...?)
|
||||
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;
|
||||
|
||||
goto rejected_fragment;
|
||||
}
|
||||
|
||||
// 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)
|
||||
//1. sm64 (standing near signs and blocks)
|
||||
|
@ -702,17 +677,19 @@ public:
|
|||
|
||||
goto done;
|
||||
depth_fail:
|
||||
if (polyAttr.polygonMode == 3 && polyAttr.polygonID == 0)
|
||||
if (isShadowPolygon && polyAttr.polygonID == 0)
|
||||
dstAttributes.stencil++;
|
||||
|
||||
rejected_fragment:
|
||||
done:
|
||||
;
|
||||
|
||||
if (polyAttr.polygonMode == 3 && polyAttr.polygonID != 0 && dstAttributes.stencil)
|
||||
if (isShadowPolygon && polyAttr.polygonID != 0 && dstAttributes.stencil)
|
||||
dstAttributes.stencil--;
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
int XStart = pLeft->X;
|
||||
|
@ -798,7 +775,7 @@ public:
|
|||
|
||||
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++;
|
||||
x++;
|
||||
|
||||
|
@ -813,7 +790,7 @@ public:
|
|||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
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--)
|
||||
{
|
||||
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 xr = right->X;
|
||||
const int y = left->Y;
|
||||
|
@ -952,7 +929,7 @@ public:
|
|||
//verts must be clockwise.
|
||||
//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<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)
|
||||
{
|
||||
bool failure = false;
|
||||
|
@ -993,7 +970,7 @@ public:
|
|||
return;
|
||||
|
||||
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 (right.Height == 0)
|
||||
|
@ -1015,44 +992,50 @@ public:
|
|||
template<bool SLI>
|
||||
FORCEINLINE void mainLoop()
|
||||
{
|
||||
const size_t polyCount = this->_softRender->_clippedPolyCount;
|
||||
if (polyCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FragmentColor *dstColor = this->_softRender->GetFramebuffer();
|
||||
size_t dstWidth = this->_softRender->GetFramebufferWidth();
|
||||
size_t dstHeight = this->_softRender->GetFramebufferHeight();
|
||||
const size_t dstWidth = this->_softRender->GetFramebufferWidth();
|
||||
const size_t dstHeight = this->_softRender->GetFramebufferHeight();
|
||||
|
||||
lastTexKey = NULL;
|
||||
|
||||
PolygonAttributes polyAttr;
|
||||
u32 lastPolyAttr = 0;
|
||||
u32 lastTextureFormat = 0, lastTexturePalette = 0;
|
||||
GFX3D_Clipper::TClippedPoly &firstClippedPoly = this->_softRender->clippedPolys[0];
|
||||
POLY &firstPoly = *firstClippedPoly.poly;
|
||||
PolygonAttributes polyAttr = firstPoly.getAttributes();
|
||||
u32 lastPolyAttr = firstPoly.polyAttr;
|
||||
u32 lastTexParams = firstPoly.texParam;
|
||||
u32 lastTexPalette = firstPoly.texPalette;
|
||||
sampler.setup(firstPoly.texParam);
|
||||
|
||||
//iterate over polys
|
||||
bool first=true;
|
||||
for (size_t i = 0; i < this->_softRender->_clippedPolyCount; i++)
|
||||
for (size_t i = 0; i < polyCount; i++)
|
||||
{
|
||||
if (!RENDERER) _debug_thisPoly = (i == this->_softRender->_debug_drawClippedUserPoly);
|
||||
if (!this->_softRender->polyVisible[i]) continue;
|
||||
polynum = i;
|
||||
|
||||
GFX3D_Clipper::TClippedPoly &clippedPoly = this->_softRender->clippedPolys[i];
|
||||
POLY *thePoly = clippedPoly.poly;
|
||||
POLY &thePoly = *clippedPoly.poly;
|
||||
int type = clippedPoly.type;
|
||||
|
||||
if (first || lastPolyAttr != thePoly->polyAttr)
|
||||
|
||||
if (lastPolyAttr != thePoly.polyAttr)
|
||||
{
|
||||
polyAttr = thePoly->getAttributes();
|
||||
lastPolyAttr = thePoly->polyAttr;
|
||||
polyAttr = thePoly.getAttributes();
|
||||
lastPolyAttr = thePoly.polyAttr;
|
||||
}
|
||||
|
||||
|
||||
if (first || lastTextureFormat != thePoly->texParam || lastTexturePalette != thePoly->texPalette)
|
||||
|
||||
if (lastTexParams != thePoly.texParam || lastTexPalette != thePoly.texPalette)
|
||||
{
|
||||
sampler.setup(thePoly->texParam);
|
||||
lastTextureFormat = thePoly->texParam;
|
||||
lastTexturePalette = thePoly->texPalette;
|
||||
sampler.setup(thePoly.texParam);
|
||||
lastTexParams = thePoly.texParam;
|
||||
lastTexPalette = thePoly.texPalette;
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
|
||||
lastTexKey = this->_softRender->polyTexKeys[i];
|
||||
|
||||
for (int j = 0; j < type; j++)
|
||||
|
@ -1060,7 +1043,14 @@ public:
|
|||
for (int j = type; j < MAX_CLIPPED_VERTS; j++)
|
||||
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
|
||||
//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)
|
||||
//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 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);
|
||||
left = ISEDGE(-1, 0);
|
||||
right = ISEDGE( 1, 0);
|
||||
down = ISEDGE( 0, 1);
|
||||
|
||||
if(this->edgeMarkDisabled[polyID>>3]) goto END_EDGE_MARK;
|
||||
if(dstAttributes.isTranslucentPoly) goto END_EDGE_MARK;
|
||||
|
||||
if (right)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
size_t iw = x + ((this->_framebufferHeight - 1 - y) * this->_framebufferWidth);
|
||||
|
||||
this->_framebufferColor[iw].color = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 31);
|
||||
this->_framebufferColor[iw].color = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 0x1F);
|
||||
this->_framebufferAttributes[iw].isFogged = fogBuffer[ir];
|
||||
this->_framebufferAttributes[iw].depth = depthBuffer[ir];
|
||||
this->_framebufferAttributes[iw].opaquePolyID = polyIDBuffer[ir];
|
||||
|
@ -1948,9 +1935,6 @@ Render3DError SoftRasterizerRenderer::EndRender(const u64 frameCount)
|
|||
{
|
||||
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].enableFog = this->currentRenderState->enableFog;
|
||||
this->postprocessParam[0].fogColor = this->currentRenderState->fogColor;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "render3D.h"
|
||||
#include "gfx3d.h"
|
||||
|
||||
#define SOFTRASTERIZER_DEPTH_EQUAL_TEST_TOLERANCE 0x200
|
||||
|
||||
extern GPU3DInterface gpu3DRasterize;
|
||||
|
||||
class TexCacheItem;
|
||||
|
|
Loading…
Reference in New Issue