diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index b3fe40949e..5f4f76d3a3 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -49,16 +49,11 @@ static inline int CalcClipMask(const ClipCoords& v) return mask; } -#define AddInterpolatedVertex(t, out, in, numVertices) \ -{ \ - Vertices[numVertices++]->Lerp(t, *Vertices[out], *Vertices[in]); \ -} - -inline bool DIFFERENT_SIGNS(float x, float y) { +inline bool different_signs(float x, float y) { return ((x <= 0 && y > 0) || (x > 0 && y <= 0)); } -inline float CLIP_DOTPROD(const VertexData &vert, float A, float B, float C, float D) { +inline float clip_dotprod(const VertexData &vert, float A, float B, float C, float D) { return (vert.clippos.x * A + vert.clippos.y * B + vert.clippos.z * C + vert.clippos.w * D); } @@ -66,24 +61,24 @@ inline float CLIP_DOTPROD(const VertexData &vert, float A, float B, float C, flo { \ if (mask & PLANE_BIT) { \ int idxPrev = inlist[0]; \ - float dpPrev = CLIP_DOTPROD(*Vertices[idxPrev], A, B, C, D );\ + float dpPrev = clip_dotprod(*Vertices[idxPrev], A, B, C, D );\ int outcount = 0; \ \ inlist[n] = inlist[0]; \ for (int j = 1; j <= n; j++) { \ int idx = inlist[j]; \ - float dp = CLIP_DOTPROD(*Vertices[idx], A, B, C, D ); \ + float dp = clip_dotprod(*Vertices[idx], A, B, C, D ); \ if (dpPrev >= 0) { \ outlist[outcount++] = idxPrev; \ } \ \ - if (DIFFERENT_SIGNS(dp, dpPrev)) { \ + if (different_signs(dp, dpPrev)) { \ if (dp < 0) { \ float t = dp / (dp - dpPrev); \ - AddInterpolatedVertex(t, idx, idxPrev, numVertices); \ + Vertices[numVertices++]->Lerp(t, *Vertices[idx], *Vertices[idxPrev]); \ } else { \ float t = dpPrev / (dpPrev - dp); \ - AddInterpolatedVertex(t, idxPrev, idx, numVertices); \ + Vertices[numVertices++]->Lerp(t, *Vertices[idxPrev], *Vertices[idx]); \ } \ outlist[outcount++] = numVertices - 1; \ } \ @@ -107,24 +102,22 @@ inline float CLIP_DOTPROD(const VertexData &vert, float A, float B, float C, flo #define CLIP_LINE(PLANE_BIT, A, B, C, D) \ { \ if (mask & PLANE_BIT) { \ - float dp0 = CLIP_DOTPROD(*Vertices[0], A, B, C, D ); \ - float dp1 = CLIP_DOTPROD(*Vertices[1], A, B, C, D ); \ - int i = 0; \ + float dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \ + float dp1 = clip_dotprod(*Vertices[1], A, B, C, D ); \ + int numVertices = 0; \ \ if (mask0 & PLANE_BIT) { \ if (dp0 < 0) { \ float t = dp1 / (dp1 - dp0); \ - i = 0; \ - AddInterpolatedVertex(t, 1, 0, i); \ + Vertices[0]->Lerp(t, *Vertices[1], *Vertices[0]); \ } \ } \ - dp0 = CLIP_DOTPROD(*Vertices[0], A, B, C, D ); \ + dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \ \ if (mask1 & PLANE_BIT) { \ if (dp1 < 0) { \ float t = dp1 / (dp1- dp0); \ - i = 1; \ - AddInterpolatedVertex(t, 1, 0, i); \ + Vertices[1]->Lerp(t, *Vertices[1], *Vertices[0]); \ } \ } \ } \ @@ -185,17 +178,14 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) } else { // through mode handling - // Check for simple case: No depth, alpha != 0 testing only, no blend, texture mapping 1:1 etc. - // Also check for scissor rectangle etc. - // That is, state commonly used in PSX games and ports like Darkstalker. - // In that case we can call DrawPSXSprite. + // Check for 1:1 texture mapping. In that case we can call DrawSprite. int xdiff = v1.screenpos.x - v0.screenpos.x; int ydiff = v1.screenpos.y - v0.screenpos.y; int udiff = (v1.texturecoords.x - v0.texturecoords.x) * 16.0f; int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * 16.0f; bool coord_check = - (xdiff == udiff /* || xdiff == -udiff*/) && - (ydiff == vdiff /* || ydiff == -vdiff*/); + (xdiff == udiff || xdiff == -udiff) && + (ydiff == vdiff || ydiff == -vdiff); // TODO: The U/V mirror support is off by one somehow. Predecrement? /* diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 88841eeced..cd90f89fac 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1287,8 +1287,20 @@ void DrawTriangleSlice( } } +// Slow but can handle all input. +void SafeScanline(int s, int ds, int t, int x1, int x2, int y, int z, const u8 *texptr, int texbufw, Sampler::Funcs &sampler, Vec4 v0_color) { + for (int x = x1; x < x2; x++) { + Vec4 prim_color = v0_color; + Vec4 tex_color = Vec4::FromRGBA(sampler.nearest(s, t, texptr, texbufw, 0)); + prim_color = GetTextureFunctionOutput(prim_color, tex_color); + DrawingCoords pos(x, y, z); + DrawSinglePixel(pos, (u16)z, 1.0f, prim_color); + s += ds; + } +} + void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { - u8 *texptr = nullptr; + const u8 *texptr = nullptr; GETextureFormat texfmt = gstate.getTextureFormat(); u32 texaddr = gstate.getTextureAddress(0); @@ -1302,17 +1314,44 @@ void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { DrawingCoords pos0 = TransformUnit::ScreenToDrawing(v0.screenpos); DrawingCoords pos1 = TransformUnit::ScreenToDrawing(v1.screenpos); + DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0); + DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0); + int z = pos0.z; float fog = 1.0f; if (gstate.isTextureMapEnabled()) { // 1:1 (but with mirror support) texture mapping! - int s = v0.texturecoords.x; - int t = v0.texturecoords.y; + int s_start = v0.texturecoords.x; + int t_start = v0.texturecoords.y; int ds = v1.texturecoords.x > v0.texturecoords.x ? 1 : -1; int dt = v1.texturecoords.y > v0.texturecoords.y ? 1 : -1; + + if (ds < 0) { + s_start += ds; + } + if (dt < 0) { + t_start += dt; + } + + // First clip the right and bottom sides, since we don't need to adjust the deltas. + if (pos1.x > scissorBR.x) pos1.x = scissorBR.x; + if (pos1.y > scissorBR.y) pos1.y = scissorBR.y; + // Now clip the other sides. + if (pos0.x < scissorTL.x) { + s_start += (scissorTL.x - pos0.x) * ds; + pos0.x = scissorTL.x; + } + if (pos0.y < scissorTL.y) { + t_start += (scissorTL.y - pos0.y) * dt; + pos0.y = scissorTL.y; + } + + int t = t_start; for (int y = pos0.y; y < pos1.y; y++) { - s = v0.texturecoords.x; + int s = s_start; + SafeScanline(s, ds, t, pos0.x, pos1.x, y, z, texptr, texbufw, sampler, v0.color0); + /* for (int x = pos0.x; x < pos1.x; x++) { Vec4 prim_color = v0.color0; Vec4 tex_color = Vec4::FromRGBA(sampler.nearest(s, t, texptr, texbufw, 0)); @@ -1321,10 +1360,14 @@ void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { DrawSinglePixel(pos, (u16)z, fog, prim_color); s += ds; } + */ t += dt; } - } - else { + } else { + if (pos1.x > scissorBR.x) pos1.x = scissorBR.x; + if (pos1.y > scissorBR.y) pos1.y = scissorBR.y; + if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; + if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; for (int y = pos0.y; y < pos1.y; y++) { for (int x = pos0.x; x < pos1.x; x++) { Vec4 prim_color = v0.color0;