Use dedicated path for flat shading (#248)

This commit is contained in:
Anders Jenbo 2025-06-09 05:06:19 +02:00 committed by GitHub
parent cd4a24ec9e
commit de82e8477a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 53 additions and 22 deletions

View File

@ -146,15 +146,15 @@ void Direct3DRMSoftwareRenderer::BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g,
memcpy(pixelAddr, &blended, m_bytesPerPixel); memcpy(pixelAddr, &blended, m_bytesPerPixel);
} }
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const D3DRMVERTEX& vertex, const Appearance& appearance) SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(
const D3DVECTOR& position,
const D3DVECTOR& normal,
const Appearance& appearance
)
{ {
FColor specular = {0, 0, 0, 0}; FColor specular = {0, 0, 0, 0};
FColor diffuse = {0, 0, 0, 0}; FColor diffuse = {0, 0, 0, 0};
// Position and normal
D3DVECTOR position = vertex.position;
D3DVECTOR normal = Normalize(vertex.normal);
for (const auto& light : m_lights) { for (const auto& light : m_lights) {
FColor lightColor = light.color; FColor lightColor = light.color;
@ -201,6 +201,16 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const D3DRMVERTEX& vertex, c
}; };
} }
inline float EdgeFloat(float x0, float y0, float x1, float y1, float x, float y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
inline float EdgeDouble(double x0, double y0, double x1, double y1, double x, double y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
void Direct3DRMSoftwareRenderer::DrawTriangleProjected( void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
const D3DRMVERTEX& v0, const D3DRMVERTEX& v0,
const D3DRMVERTEX& v1, const D3DRMVERTEX& v1,
@ -235,19 +245,20 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
return; return;
} }
auto edge = [](double x0, double y0, double x1, double y1, double x, double y) { // Cull backfaces
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0); float area = EdgeFloat(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
};
float area = edge(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
if (area >= 0) { if (area >= 0) {
return; return;
} }
float invArea = 1.0f / area; float invArea = 1.0f / area;
// Per-vertex lighting using vertex normals Uint8 r, g, b;
SDL_Color c0 = ApplyLighting(v0, appearance); SDL_Color c0 = ApplyLighting(v0.position, v0.normal, appearance);
SDL_Color c1 = ApplyLighting(v1, appearance); SDL_Color c1, c2;
SDL_Color c2 = ApplyLighting(v2, appearance); if (!appearance.flat) {
c1 = ApplyLighting(v1.position, v1.normal, appearance);
c2 = ApplyLighting(v2.position, v2.normal, appearance);
}
Uint32 textureId = appearance.textureId; Uint32 textureId = appearance.textureId;
int texturePitch; int texturePitch;
@ -271,12 +282,12 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
for (int x = minX; x <= maxX; ++x) { for (int x = minX; x <= maxX; ++x) {
float px = x + 0.5f; float px = x + 0.5f;
float py = y + 0.5f; float py = y + 0.5f;
float w0 = edge(p1.x, p1.y, p2.x, p2.y, px, py) * invArea; float w0 = EdgeDouble(p1.x, p1.y, p2.x, p2.y, px, py) * invArea;
if (w0 < 0.0f || w0 > 1.0f) { if (w0 < 0.0f || w0 > 1.0f) {
continue; continue;
} }
float w1 = edge(p2.x, p2.y, p0.x, p0.y, px, py) * invArea; float w1 = EdgeDouble(p2.x, p2.y, p0.x, p0.y, px, py) * invArea;
if (w1 < 0.0f || w1 > 1.0f - w0) { if (w1 < 0.0f || w1 > 1.0f - w0) {
continue; continue;
} }
@ -290,10 +301,16 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
continue; continue;
} }
// Interpolate color if (appearance.flat) {
Uint8 r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r); r = c0.r;
Uint8 g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g); g = c0.g;
Uint8 b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b); b = c0.b;
}
else {
r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r);
g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g);
b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
}
Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel; Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel;
if (appearance.color.a == 255) { if (appearance.color.a == 255) {
@ -322,8 +339,22 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
Uint8* texelAddr = texels + texY * texturePitch + texX * m_bytesPerPixel; Uint8* texelAddr = texels + texY * texturePitch + texX * m_bytesPerPixel;
Uint32 texelColor = 0; Uint32 texelColor;
memcpy(&texelColor, texelAddr, m_bytesPerPixel); switch (m_bytesPerPixel) {
case 1:
texelColor = *texelAddr;
break;
case 2:
texelColor = *(Uint16*) texelAddr;
break;
case 3:
// Manually build the 24-bit color (assuming byte order)
texelColor = texelAddr[0] | (texelAddr[1] << 8) | (texelAddr[2] << 16);
break;
case 4:
texelColor = *(Uint32*) texelAddr;
break;
}
Uint8 tr, tg, tb, ta; Uint8 tr, tg, tb, ta;
SDL_GetRGBA(texelColor, m_format, m_palette, &tr, &tg, &tb, &ta); SDL_GetRGBA(texelColor, m_format, m_palette, &tr, &tg, &tb, &ta);

View File

@ -49,7 +49,7 @@ private:
void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance); void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance);
void ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const; void ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const;
void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a); void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
SDL_Color ApplyLighting(const D3DRMVERTEX& vertex, const Appearance& appearance); SDL_Color ApplyLighting(const D3DVECTOR& position, const D3DVECTOR& normal, const Appearance& appearance);
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
DWORD m_width; DWORD m_width;