From de82e8477abf31111bcc617db4526dfc4ca7872e Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Mon, 9 Jun 2025 05:06:19 +0200 Subject: [PATCH] Use dedicated path for flat shading (#248) --- .../src/d3drm/backends/software/renderer.cpp | 73 +++++++++++++------ miniwin/src/internal/d3drmrenderer_software.h | 2 +- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index a19f6a47..0fc243c1 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -146,15 +146,15 @@ void Direct3DRMSoftwareRenderer::BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, 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 diffuse = {0, 0, 0, 0}; - // Position and normal - D3DVECTOR position = vertex.position; - D3DVECTOR normal = Normalize(vertex.normal); - for (const auto& light : m_lights) { 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( const D3DRMVERTEX& v0, const D3DRMVERTEX& v1, @@ -235,19 +245,20 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( return; } - auto edge = [](double x0, double y0, double x1, double y1, double x, double y) { - return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0); - }; - float area = edge(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y); + // Cull backfaces + float area = EdgeFloat(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y); if (area >= 0) { return; } float invArea = 1.0f / area; - // Per-vertex lighting using vertex normals - SDL_Color c0 = ApplyLighting(v0, appearance); - SDL_Color c1 = ApplyLighting(v1, appearance); - SDL_Color c2 = ApplyLighting(v2, appearance); + Uint8 r, g, b; + SDL_Color c0 = ApplyLighting(v0.position, v0.normal, appearance); + SDL_Color c1, c2; + if (!appearance.flat) { + c1 = ApplyLighting(v1.position, v1.normal, appearance); + c2 = ApplyLighting(v2.position, v2.normal, appearance); + } Uint32 textureId = appearance.textureId; int texturePitch; @@ -271,12 +282,12 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( for (int x = minX; x <= maxX; ++x) { float px = x + 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) { 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) { continue; } @@ -290,10 +301,16 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( continue; } - // Interpolate color - Uint8 r = static_cast(w0 * c0.r + w1 * c1.r + w2 * c2.r); - Uint8 g = static_cast(w0 * c0.g + w1 * c1.g + w2 * c2.g); - Uint8 b = static_cast(w0 * c0.b + w1 * c1.b + w2 * c2.b); + if (appearance.flat) { + r = c0.r; + g = c0.g; + b = c0.b; + } + else { + r = static_cast(w0 * c0.r + w1 * c1.r + w2 * c2.r); + g = static_cast(w0 * c0.g + w1 * c1.g + w2 * c2.g); + b = static_cast(w0 * c0.b + w1 * c1.b + w2 * c2.b); + } Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel; if (appearance.color.a == 255) { @@ -322,8 +339,22 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( Uint8* texelAddr = texels + texY * texturePitch + texX * m_bytesPerPixel; - Uint32 texelColor = 0; - memcpy(&texelColor, texelAddr, m_bytesPerPixel); + Uint32 texelColor; + 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; SDL_GetRGBA(texelColor, m_format, m_palette, &tr, &tg, &tb, &ta); diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index d253cd52..4ceb343c 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -49,7 +49,7 @@ private: void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance); void ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const; 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); DWORD m_width;