Split the various stages of the fragment shader into functions

This commit is contained in:
Magnus Norddahl 2019-12-08 03:18:05 +01:00
parent c97d02ae51
commit 844b203971

View file

@ -639,251 +639,325 @@ static uint32_t SampleTexture(uint32_t u, uint32_t v, const void* texPixels, int
}
}
static void RunShader(int x0, int x1, PolyTriangleThreadData* thread)
static void EffectFogBoundary(int x0, int x1, PolyTriangleThreadData* thread)
{
auto constants = thread->PushConstants;
auto& streamdata = thread->mainVertexShader.Data;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp
for (int x = x0; x < x1; x++)
{
/*float fogdist = pixelpos.w;
float fogfactor = exp2(uFogDensity * fogdist);
FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor);*/
for (int x = x0; x < x1; x++)
{
fragcolor[x] = 0;
}
return;
fragcolor[x] = 0;
}
else if (thread->SpecialEffect == EFF_BURN) // burn.fp
}
static void EffectBurn(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
int tex2Width = thread->textures[1].width;
int tex2Height = thread->textures[1].height;
const void* tex2Pixels = thread->textures[1].pixels;
bool tex2Bgra = thread->textures[1].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t frag_r = thread->scanline.vColorR[x];
uint32_t frag_g = thread->scanline.vColorG[x];
uint32_t frag_b = thread->scanline.vColorB[x];
uint32_t frag_a = thread->scanline.vColorA[x];
frag_r += frag_r >> 7; // 255 -> 256
frag_g += frag_g >> 7; // 255 -> 256
frag_b += frag_b >> 7; // 255 -> 256
frag_a += frag_a >> 7; // 255 -> 256
int tex2Width = thread->textures[1].width;
int tex2Height = thread->textures[1].height;
const void* tex2Pixels = thread->textures[1].pixels;
bool tex2Bgra = thread->textures[1].bgra;
uint32_t t1 = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
uint32_t t2 = SampleTexture(u[x], 0xffff - v[x], tex2Pixels, tex2Width, tex2Height, tex2Bgra);
for (int x = x0; x < x1; x++)
{
uint32_t frag_r = thread->scanline.vColorR[x];
uint32_t frag_g = thread->scanline.vColorG[x];
uint32_t frag_b = thread->scanline.vColorB[x];
uint32_t frag_a = thread->scanline.vColorA[x];
frag_r += frag_r >> 7; // 255 -> 256
frag_g += frag_g >> 7; // 255 -> 256
frag_b += frag_b >> 7; // 255 -> 256
frag_a += frag_a >> 7; // 255 -> 256
uint32_t r = (frag_r * RPART(t1)) >> 8;
uint32_t g = (frag_g * GPART(t1)) >> 8;
uint32_t b = (frag_b * BPART(t1)) >> 8;
uint32_t a = (frag_a * APART(t2)) >> 8;
uint32_t t1 = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
uint32_t t2 = SampleTexture(u[x], 0xffff - v[x], tex2Pixels, tex2Width, tex2Height, tex2Bgra);
uint32_t r = (frag_r * RPART(t1)) >> 8;
uint32_t g = (frag_g * GPART(t1)) >> 8;
uint32_t b = (frag_b * BPART(t1)) >> 8;
uint32_t a = (frag_a * APART(t2)) >> 8;
fragcolor[x] = MAKEARGB(a, r, g, b);
}
return;
fragcolor[x] = MAKEARGB(a, r, g, b);
}
else if (thread->SpecialEffect == EFF_STENCIL) // stencil.fp
}
static void EffectStencil(int x0, int x1, PolyTriangleThreadData* thread)
{
/*for (int x = x0; x < x1; x++)
{
/*for (int x = x0; x < x1; x++)
{
fragcolor[x] = 0x00ffffff;
}*/
return;
}
else if (thread->EffectState == SHADER_Paletted) // func_paletted
fragcolor[x] = 0x00ffffff;
}*/
}
static void FuncPaletted(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
const uint32_t* lut = (const uint32_t*)thread->textures[1].pixels;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
const uint32_t* lut = (const uint32_t*)thread->textures[1].pixels;
for (int x = x0; x < x1; x++)
{
fragcolor[x] = lut[RPART(SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra))] | 0xff000000;
}
fragcolor[x] = lut[RPART(SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra))] | 0xff000000;
}
else if (thread->EffectState == SHADER_NoTexture) // func_notexture
}
static void FuncNoTexture(int x0, int x1, PolyTriangleThreadData* thread)
{
auto& streamdata = thread->mainVertexShader.Data;
uint32_t a = (int)(streamdata.uObjectColor.a * 255.0f);
uint32_t r = (int)(streamdata.uObjectColor.r * 255.0f);
uint32_t g = (int)(streamdata.uObjectColor.g * 255.0f);
uint32_t b = (int)(streamdata.uObjectColor.b * 255.0f);
uint32_t texel = MAKEARGB(a, r, g, b);
if (streamdata.uDesaturationFactor > 0.0f)
{
uint32_t a = (int)(streamdata.uObjectColor.a * 255.0f);
uint32_t r = (int)(streamdata.uObjectColor.r * 255.0f);
uint32_t g = (int)(streamdata.uObjectColor.g * 255.0f);
uint32_t b = (int)(streamdata.uObjectColor.b * 255.0f);
uint32_t texel = MAKEARGB(a, r, g, b);
if (streamdata.uDesaturationFactor > 0.0f)
{
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
uint32_t inv_t = 256 - t;
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
texel = MAKEARGB(
APART(texel),
(RPART(texel) * inv_t + gray * t + 127) >> 8,
(GPART(texel) * inv_t + gray * t + 127) >> 8,
(BPART(texel) * inv_t + gray * t + 127) >> 8);
}
for (int x = x0; x < x1; x++)
{
fragcolor[x] = texel;
}
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
uint32_t inv_t = 256 - t;
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
texel = MAKEARGB(
APART(texel),
(RPART(texel) * inv_t + gray * t + 127) >> 8,
(GPART(texel) * inv_t + gray * t + 127) >> 8,
(BPART(texel) * inv_t + gray * t + 127) >> 8);
}
else // func_normal
uint32_t* fragcolor = thread->scanline.FragColor;
for (int x = x0; x < x1; x++)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
switch (constants->uTextureMode)
{
default:
case TM_NORMAL:
case TM_FOGLAYER:
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel;
}
break;
case TM_STENCIL: // TM_STENCIL
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel | 0x00ffffff;
}
break;
case TM_OPAQUE:
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel | 0xff000000;
}
break;
case TM_INVERSE:
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = MAKEARGB(APART(texel), 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
}
break;
case TM_ALPHATEXTURE:
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
uint32_t alpha = APART(texel);
alpha += alpha >> 7;
alpha = (alpha * gray + 127) >> 8;
texel = (alpha << 24) | 0x00ffffff;
fragcolor[x] = texel;
}
break;
case TM_CLAMPY:
for (int x = x0; x < x1; x++)
{
fragcolor[x] = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
if (v[x] < 0.0 || v[x] > 1.0)
fragcolor[x] &= 0x00ffffff;
}
break;
case TM_INVERTOPAQUE:
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = MAKEARGB(0xff, 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
}
}
if (constants->uTextureMode != TM_FOGLAYER)
{
if (streamdata.uAddColor.r != 0.0f || streamdata.uAddColor.g != 0.0f || streamdata.uAddColor.b != 0.0f)
{
uint32_t r = (int)(streamdata.uAddColor.r * 255.0f);
uint32_t g = (int)(streamdata.uAddColor.g * 255.0f);
uint32_t b = (int)(streamdata.uAddColor.b * 255.0f);
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN(r + RPART(texel), (uint32_t)255),
MIN(g + GPART(texel), (uint32_t)255),
MIN(b + BPART(texel), (uint32_t)255));
}
}
if (streamdata.uObjectColor2.a == 0.0f)
{
if (streamdata.uObjectColor.r != 1.0f || streamdata.uObjectColor.g != 1.0f || streamdata.uObjectColor.b != 1.0f)
{
uint32_t r = (int)(streamdata.uObjectColor.r * 256.0f);
uint32_t g = (int)(streamdata.uObjectColor.g * 256.0f);
uint32_t b = (int)(streamdata.uObjectColor.b * 256.0f);
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN((r * RPART(texel)) >> 8, (uint32_t)255),
MIN((g * GPART(texel)) >> 8, (uint32_t)255),
MIN((b * BPART(texel)) >> 8, (uint32_t)255));
}
}
}
else
{
float* gradientdistZ = thread->scanline.GradientdistZ;
for (int x = x0; x < x1; x++)
{
float t = gradientdistZ[x];
float inv_t = 1.0f - t;
uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f);
uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f);
uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f);
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN((r * RPART(texel)) >> 8, (uint32_t)255),
MIN((g * GPART(texel)) >> 8, (uint32_t)255),
MIN((b * BPART(texel)) >> 8, (uint32_t)255));
}
}
if (streamdata.uDesaturationFactor > 0.0f)
{
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
uint32_t inv_t = 256 - t;
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
fragcolor[x] = MAKEARGB(
APART(texel),
(RPART(texel) * inv_t + gray * t + 127) >> 8,
(GPART(texel) * inv_t + gray * t + 127) >> 8,
(BPART(texel) * inv_t + gray * t + 127) >> 8);
}
}
}
fragcolor[x] = texel;
}
}
static void FuncNormal(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel;
}
}
static void FuncNormal_Stencil(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel | 0x00ffffff;
}
}
static void FuncNormal_Opaque(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = texel | 0xff000000;
}
}
static void FuncNormal_Inverse(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = MAKEARGB(APART(texel), 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
}
}
static void FuncNormal_AlphaTexture(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
uint32_t alpha = APART(texel);
alpha += alpha >> 7;
alpha = (alpha * gray + 127) >> 8;
texel = (alpha << 24) | 0x00ffffff;
fragcolor[x] = texel;
}
}
static void FuncNormal_ClampY(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
fragcolor[x] = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
if (v[x] < 0.0 || v[x] > 1.0)
fragcolor[x] &= 0x00ffffff;
}
}
static void FuncNormal_InvertOpaque(int x0, int x1, PolyTriangleThreadData* thread)
{
int texWidth = thread->textures[0].width;
int texHeight = thread->textures[0].height;
const void* texPixels = thread->textures[0].pixels;
bool texBgra = thread->textures[0].bgra;
uint32_t* fragcolor = thread->scanline.FragColor;
uint16_t* u = thread->scanline.U;
uint16_t* v = thread->scanline.V;
for (int x = x0; x < x1; x++)
{
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
fragcolor[x] = MAKEARGB(0xff, 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
}
}
static void FuncNormal_AddColor(int x0, int x1, PolyTriangleThreadData* thread)
{
auto& streamdata = thread->mainVertexShader.Data;
uint32_t r = (int)(streamdata.uAddColor.r * 255.0f);
uint32_t g = (int)(streamdata.uAddColor.g * 255.0f);
uint32_t b = (int)(streamdata.uAddColor.b * 255.0f);
uint32_t* fragcolor = thread->scanline.FragColor;
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN(r + RPART(texel), (uint32_t)255),
MIN(g + GPART(texel), (uint32_t)255),
MIN(b + BPART(texel), (uint32_t)255));
}
}
static void FuncNormal_AddObjectColor(int x0, int x1, PolyTriangleThreadData* thread)
{
auto& streamdata = thread->mainVertexShader.Data;
uint32_t r = (int)(streamdata.uObjectColor.r * 256.0f);
uint32_t g = (int)(streamdata.uObjectColor.g * 256.0f);
uint32_t b = (int)(streamdata.uObjectColor.b * 256.0f);
uint32_t* fragcolor = thread->scanline.FragColor;
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN((r * RPART(texel)) >> 8, (uint32_t)255),
MIN((g * GPART(texel)) >> 8, (uint32_t)255),
MIN((b * BPART(texel)) >> 8, (uint32_t)255));
}
}
static void FuncNormal_AddObjectColor2(int x0, int x1, PolyTriangleThreadData* thread)
{
auto& streamdata = thread->mainVertexShader.Data;
float* gradientdistZ = thread->scanline.GradientdistZ;
uint32_t* fragcolor = thread->scanline.FragColor;
for (int x = x0; x < x1; x++)
{
float t = gradientdistZ[x];
float inv_t = 1.0f - t;
uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f);
uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f);
uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f);
uint32_t texel = fragcolor[x];
fragcolor[x] = MAKEARGB(
APART(texel),
MIN((r * RPART(texel)) >> 8, (uint32_t)255),
MIN((g * GPART(texel)) >> 8, (uint32_t)255),
MIN((b * BPART(texel)) >> 8, (uint32_t)255));
}
}
static void FuncNormal_DesaturationFactor(int x0, int x1, PolyTriangleThreadData* thread)
{
auto& streamdata = thread->mainVertexShader.Data;
uint32_t* fragcolor = thread->scanline.FragColor;
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
uint32_t inv_t = 256 - t;
for (int x = x0; x < x1; x++)
{
uint32_t texel = fragcolor[x];
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
fragcolor[x] = MAKEARGB(
APART(texel),
(RPART(texel) * inv_t + gray * t + 127) >> 8,
(GPART(texel) * inv_t + gray * t + 127) >> 8,
(BPART(texel) * inv_t + gray * t + 127) >> 8);
}
}
static void RunAlphaTest(int x0, int x1, PolyTriangleThreadData* thread)
{
uint32_t alphaThreshold = thread->AlphaThreshold;
uint32_t* fragcolor = thread->scanline.FragColor;
uint8_t* discard = thread->scanline.discard;
for (int x = x0; x < x1; x++)
{
discard[x] = fragcolor[x] <= alphaThreshold;
}
}
static void ApplyVertexColor(int x0, int x1, PolyTriangleThreadData* thread)
{
uint32_t* fragcolor = thread->scanline.FragColor;
for (int x = x0; x < x1; x++)
{
uint32_t r = thread->scanline.vColorR[x];
uint32_t g = thread->scanline.vColorG[x];
@ -896,14 +970,90 @@ static void RunShader(int x0, int x1, PolyTriangleThreadData* thread)
b += b >> 7;
uint32_t texel = fragcolor[x];
discard[x] = texel <= alphaThreshold;
fragcolor[x] = MAKEARGB(
(APART(texel) * a + 127) >> 8,
(RPART(texel) * r + 127) >> 8,
(GPART(texel) * g + 127) >> 8,
(BPART(texel) * b + 127) >> 8);
}
}
static void RunShader(int x0, int x1, PolyTriangleThreadData* thread)
{
if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp
{
EffectFogBoundary(x0, x1, thread);
return;
}
else if (thread->SpecialEffect == EFF_BURN) // burn.fp
{
EffectBurn(x0, x1, thread);
return;
}
else if (thread->SpecialEffect == EFF_STENCIL) // stencil.fp
{
EffectStencil(x0, x1, thread);
return;
}
else if (thread->EffectState == SHADER_Paletted) // func_paletted
{
FuncPaletted(x0, x1, thread);
}
else if (thread->EffectState == SHADER_NoTexture) // func_notexture
{
FuncNoTexture(x0, x1, thread);
}
else // func_normal
{
auto constants = thread->PushConstants;
auto& streamdata = thread->mainVertexShader.Data;
switch (constants->uTextureMode)
{
default:
case TM_NORMAL:
case TM_FOGLAYER: FuncNormal(x0, x1, thread); break;
case TM_STENCIL: FuncNormal_Stencil(x0, x1, thread); break;
case TM_OPAQUE: FuncNormal_Opaque(x0, x1, thread); break;
case TM_INVERSE: FuncNormal_Inverse(x0, x1, thread); break;
case TM_ALPHATEXTURE: FuncNormal_AlphaTexture(x0, x1, thread); break;
case TM_CLAMPY: FuncNormal_ClampY(x0, x1, thread); break;
case TM_INVERTOPAQUE: FuncNormal_InvertOpaque(x0, x1, thread); break;
}
if (constants->uTextureMode != TM_FOGLAYER)
{
if (streamdata.uAddColor.r != 0.0f || streamdata.uAddColor.g != 0.0f || streamdata.uAddColor.b != 0.0f)
{
FuncNormal_AddColor(x0, x1, thread);
}
if (streamdata.uObjectColor2.a == 0.0f)
{
if (streamdata.uObjectColor.r != 1.0f || streamdata.uObjectColor.g != 1.0f || streamdata.uObjectColor.b != 1.0f)
{
FuncNormal_AddObjectColor(x0, x1, thread);
}
}
else
{
FuncNormal_AddObjectColor2(x0, x1, thread);
}
if (streamdata.uDesaturationFactor > 0.0f)
{
FuncNormal_DesaturationFactor(x0, x1, thread);
}
}
}
if (thread->AlphaTest)
RunAlphaTest(x0, x1, thread);
ApplyVertexColor(x0, x1, thread);
auto constants = thread->PushConstants;
uint32_t* fragcolor = thread->scanline.FragColor;
if (constants->uLightLevel >= 0.0f && thread->numPolyLights > 0)
{
uint16_t* lightarray = thread->scanline.lightarray;