diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj
index 53903c75c1..44da128934 100644
--- a/GPU/GPU.vcxproj
+++ b/GPU/GPU.vcxproj
@@ -197,6 +197,7 @@
MultiThreadedDebug
Common/DbgNew.h
ProgramDatabase
+ false
true
diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp
index 746896c431..b3fe40949e 100644
--- a/GPU/Software/Clipper.cpp
+++ b/GPU/Software/Clipper.cpp
@@ -184,6 +184,39 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]);
} 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.
+ 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*/);
+ // TODO: The U/V mirror support is off by one somehow. Predecrement?
+
+ /*
+ bool state_check =
+ !gstate.isModeClear() &&
+ !gstate.isFogEnabled() &&
+ gstate.isTextureMapEnabled() &&
+ !gstate.isDepthTestEnabled() &&
+ !gstate.isStencilTestEnabled();
+ bool alpha_check =
+ gstate.getAlphaTestFunction() == GEComparison::GE_COMP_GREATER &&
+ gstate.getAlphaTestMask() == 0xFF &&
+ gstate.getAlphaTestRef() == 0;
+ */
+ bool state_check = !gstate.isModeClear();
+ bool alpha_check = true;
+ if ((coord_check || !gstate.isTextureMapEnabled()) && state_check && alpha_check) {
+ Rasterizer::DrawPSXSprite(v0, v1);
+ return;
+ }
+
VertexData buf[4];
buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z);
buf[0].texturecoords = v0.texturecoords;
diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp
index 5db77b9407..88841eeced 100644
--- a/GPU/Software/Rasterizer.cpp
+++ b/GPU/Software/Rasterizer.cpp
@@ -1287,6 +1287,54 @@ void DrawTriangleSlice(
}
}
+void DrawPSXSprite(const VertexData& v0, const VertexData& v1) {
+ u8 *texptr = nullptr;
+
+ GETextureFormat texfmt = gstate.getTextureFormat();
+ u32 texaddr = gstate.getTextureAddress(0);
+ int texbufw = GetTextureBufw(0, texaddr, texfmt);
+ if (Memory::IsValidAddress(texaddr))
+ texptr = Memory::GetPointerUnchecked(texaddr);
+
+ ScreenCoords pprime(v0.screenpos.x, v0.screenpos.y, 0);
+ Sampler::Funcs sampler = Sampler::GetFuncs();
+
+ DrawingCoords pos0 = TransformUnit::ScreenToDrawing(v0.screenpos);
+ DrawingCoords pos1 = TransformUnit::ScreenToDrawing(v1.screenpos);
+
+ 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 ds = v1.texturecoords.x > v0.texturecoords.x ? 1 : -1;
+ int dt = v1.texturecoords.y > v0.texturecoords.y ? 1 : -1;
+ for (int y = pos0.y; y < pos1.y; y++) {
+ s = v0.texturecoords.x;
+ 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));
+ prim_color = GetTextureFunctionOutput(prim_color, tex_color);
+ DrawingCoords pos(x, y, z);
+ DrawSinglePixel(pos, (u16)z, fog, prim_color);
+ s += ds;
+ }
+ t += dt;
+ }
+ }
+ else {
+ for (int y = pos0.y; y < pos1.y; y++) {
+ for (int x = pos0.x; x < pos1.x; x++) {
+ Vec4 prim_color = v0.color0;
+ DrawingCoords pos(x, y, z);
+ DrawSinglePixel(pos, (u16)z, fog, prim_color);
+ }
+ }
+ }
+}
+
// Draws triangle, vertices specified in counter-clockwise direction
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2)
{
diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h
index 53d44e8af0..076a0421a5 100644
--- a/GPU/Software/Rasterizer.h
+++ b/GPU/Software/Rasterizer.h
@@ -27,6 +27,7 @@ namespace Rasterizer {
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2);
void DrawPoint(const VertexData &v0);
void DrawLine(const VertexData &v0, const VertexData &v1);
+void DrawPSXSprite(const VertexData &v0, const VertexData &v1);
void ClearRectangle(const VertexData &v0, const VertexData &v1);
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp
index 2848ce600f..82a8497684 100644
--- a/GPU/Software/TransformUnit.cpp
+++ b/GPU/Software/TransformUnit.cpp
@@ -470,6 +470,27 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
data[2].color0 == data[3].color0) {
// It's a rectangle!
Clipper::ProcessRect(data[0], data[3]);
+ break;
+ }
+ // There's the other vertex order too...
+ if (data[0].screenpos.x == data[2].screenpos.x &&
+ data[0].screenpos.y == data[1].screenpos.y &&
+ data[1].screenpos.x == data[3].screenpos.x &&
+ data[2].screenpos.y == data[3].screenpos.y &&
+ data[2].screenpos.y > data[0].screenpos.y && // Avoid rotation handling
+ data[1].screenpos.x > data[0].screenpos.x &&
+ data[0].texturecoords.x == data[2].texturecoords.x &&
+ data[0].texturecoords.y == data[1].texturecoords.y &&
+ data[1].texturecoords.x == data[3].texturecoords.x &&
+ data[2].texturecoords.y == data[3].texturecoords.y &&
+ data[2].texturecoords.y > data[0].texturecoords.y &&
+ data[1].texturecoords.x > data[0].texturecoords.x &&
+ data[0].color0 == data[1].color0 &&
+ data[1].color0 == data[2].color0 &&
+ data[2].color0 == data[3].color0) {
+ // It's a rectangle!
+ Clipper::ProcessRect(data[0], data[3]);
+ break;
}
}