mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #15399 from unknownbrackets/softgpu-vertices
Convert more verts to rects, fix strip/fan skew on clip
This commit is contained in:
commit
df1a15938d
6 changed files with 119 additions and 109 deletions
|
@ -128,8 +128,6 @@ static void RotateUV(const VertexData &tl, const VertexData &br, VertexData &tr,
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessTriangleInternal(VertexData &v0, VertexData &v1, VertexData &v2, const VertexData &provoking, BinManager &binner, bool fromRectangle);
|
||||
|
||||
static inline bool CheckOutsideZ(ClipCoords p, int &pos, int &neg) {
|
||||
constexpr float outsideValue = 1.000030517578125f;
|
||||
float z = p.z / p.w;
|
||||
|
@ -197,10 +195,11 @@ void ProcessRect(const VertexData &v0, const VertexData &v1, BinManager &binner)
|
|||
RotateUV(*topleft, *bottomright, *topright, *bottomleft);
|
||||
|
||||
// Four triangles to do backfaces as well. Two of them will get backface culled.
|
||||
ProcessTriangleInternal(*topleft, *topright, *bottomright, buf[3], binner, true);
|
||||
ProcessTriangleInternal(*bottomright, *topright, *topleft, buf[3], binner, true);
|
||||
ProcessTriangleInternal(*bottomright, *bottomleft, *topleft, buf[3], binner, true);
|
||||
ProcessTriangleInternal(*topleft, *bottomleft, *bottomright, buf[3], binner, true);
|
||||
// We already clipped, so we don't need additional processing.
|
||||
binner.AddTriangle(*topleft, *topright, *bottomright);
|
||||
binner.AddTriangle(*bottomright, *topright, *topleft);
|
||||
binner.AddTriangle(*bottomright, *bottomleft, *topleft);
|
||||
binner.AddTriangle(*topleft, *bottomleft, *bottomright);
|
||||
} else {
|
||||
// through mode handling
|
||||
|
||||
|
@ -257,12 +256,12 @@ void ProcessRect(const VertexData &v0, const VertexData &v1, BinManager &binner)
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessPoint(VertexData &v0, BinManager &binner) {
|
||||
void ProcessPoint(const VertexData &v0, BinManager &binner) {
|
||||
// Points need no clipping. Will be bounds checked in the rasterizer (which seems backwards?)
|
||||
binner.AddPoint(v0);
|
||||
}
|
||||
|
||||
void ProcessLine(VertexData &v0, VertexData &v1, BinManager &binner) {
|
||||
void ProcessLine(const VertexData &v0, const VertexData &v1, BinManager &binner) {
|
||||
if (gstate.isModeThrough()) {
|
||||
// Actually, should clip this one too so we don't need to do bounds checks in the rasterizer.
|
||||
binner.AddLine(v0, v1);
|
||||
|
@ -280,16 +279,19 @@ void ProcessLine(VertexData &v0, VertexData &v1, BinManager &binner) {
|
|||
else if (outsidePos >= 2 || outsideNeg >= 2)
|
||||
return;
|
||||
|
||||
VertexData *Vertices[2] = {&v0, &v1};
|
||||
|
||||
int mask0 = CalcClipMask(v0.clippos);
|
||||
int mask1 = CalcClipMask(v1.clippos);
|
||||
int mask = mask0 | mask1;
|
||||
bool clipped = false;
|
||||
if (mask) {
|
||||
CLIP_LINE(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
if ((mask & CLIP_NEG_Z_BIT) == 0) {
|
||||
binner.AddLine(v0, v1);
|
||||
return;
|
||||
}
|
||||
|
||||
VertexData ClippedVertices[2] = { v0, v1 };
|
||||
VertexData *Vertices[2] = { &ClippedVertices[0], &ClippedVertices[1] };
|
||||
bool clipped = false;
|
||||
CLIP_LINE(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
VertexData data[2] = { *Vertices[0], *Vertices[1] };
|
||||
if (clipped) {
|
||||
data[0].screenpos = TransformUnit::ClipToScreen(data[0].clippos);
|
||||
|
@ -298,10 +300,31 @@ void ProcessLine(VertexData &v0, VertexData &v1, BinManager &binner) {
|
|||
binner.AddLine(data[0], data[1]);
|
||||
}
|
||||
|
||||
void ProcessTriangleInternal(VertexData &v0, VertexData &v1, VertexData &v2, const VertexData &provoking, BinManager &binner, bool fromRectangle) {
|
||||
if (gstate.isModeThrough()) {
|
||||
// In case of cull reordering, make sure the right color is on the final vertex.
|
||||
void ProcessTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const VertexData &provoking, BinManager &binner) {
|
||||
int mask = 0;
|
||||
if (!gstate.isModeThrough()) {
|
||||
mask |= CalcClipMask(v0.clippos);
|
||||
mask |= CalcClipMask(v1.clippos);
|
||||
mask |= CalcClipMask(v2.clippos);
|
||||
|
||||
// We may discard the entire triangle based on depth values. First check what's outside.
|
||||
int outsidePos = 0, outsideNeg = 0;
|
||||
CheckOutsideZ(v0.clippos, outsidePos, outsideNeg);
|
||||
CheckOutsideZ(v1.clippos, outsidePos, outsideNeg);
|
||||
CheckOutsideZ(v2.clippos, outsidePos, outsideNeg);
|
||||
|
||||
// With depth clamp off, we discard the triangle if even one vert is outside.
|
||||
if (outsidePos + outsideNeg > 0 && !gstate.isDepthClampEnabled())
|
||||
return;
|
||||
// With it on, all three must be outside in the same direction.
|
||||
else if (outsidePos >= 3 || outsideNeg >= 3)
|
||||
return;
|
||||
}
|
||||
|
||||
// No clipping is common, let's skip processing if we can.
|
||||
if ((mask & CLIP_NEG_Z_BIT) == 0) {
|
||||
if (gstate.getShadeMode() == GE_SHADE_FLAT) {
|
||||
// So that the order of clipping doesn't matter...
|
||||
VertexData corrected2 = v2;
|
||||
corrected2.color0 = provoking.color0;
|
||||
corrected2.color1 = provoking.color1;
|
||||
|
@ -312,52 +335,22 @@ void ProcessTriangleInternal(VertexData &v0, VertexData &v1, VertexData &v2, con
|
|||
return;
|
||||
}
|
||||
|
||||
int mask = 0;
|
||||
mask |= CalcClipMask(v0.clippos);
|
||||
mask |= CalcClipMask(v1.clippos);
|
||||
mask |= CalcClipMask(v2.clippos);
|
||||
|
||||
// No clipping is common, let's skip processing if we can.
|
||||
if ((mask & CLIP_NEG_Z_BIT) == 0 || fromRectangle) {
|
||||
if (gstate.getShadeMode() == GE_SHADE_FLAT) {
|
||||
// So that the order of clipping doesn't matter...
|
||||
v2.color0 = provoking.color0;
|
||||
v2.color1 = provoking.color1;
|
||||
}
|
||||
|
||||
binner.AddTriangle(v0, v1, v2);
|
||||
return;
|
||||
}
|
||||
|
||||
enum { NUM_CLIPPED_VERTICES = 3, NUM_INDICES = NUM_CLIPPED_VERTICES + 3 };
|
||||
|
||||
VertexData* Vertices[NUM_INDICES];
|
||||
VertexData ClippedVertices[NUM_CLIPPED_VERTICES];
|
||||
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
|
||||
Vertices[i+3] = &ClippedVertices[i];
|
||||
VertexData ClippedVertices[NUM_INDICES];
|
||||
for (int i = 0; i < NUM_INDICES; ++i)
|
||||
Vertices[i] = &ClippedVertices[i];
|
||||
|
||||
// TODO: Change logic when it's a backface (why? In what way?)
|
||||
Vertices[0] = &v0;
|
||||
Vertices[1] = &v1;
|
||||
Vertices[2] = &v2;
|
||||
ClippedVertices[0] = v0;
|
||||
ClippedVertices[1] = v1;
|
||||
ClippedVertices[2] = v2;
|
||||
|
||||
int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG };
|
||||
int numIndices = 3;
|
||||
bool clipped = false;
|
||||
|
||||
// We may discard the entire triangle based on depth values. First check what's outside.
|
||||
int outsidePos = 0, outsideNeg = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
CheckOutsideZ(Vertices[i]->clippos, outsidePos, outsideNeg);
|
||||
}
|
||||
|
||||
// With depth clamp off, we discard the triangle if even one vert is outside.
|
||||
if (outsidePos + outsideNeg > 0 && !gstate.isDepthClampEnabled())
|
||||
return;
|
||||
// With it on, all three must be outside in the same direction.
|
||||
else if (outsidePos >= 3 || outsideNeg >= 3)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 3; i += 3) {
|
||||
int vlist[2][2*6+1];
|
||||
int *inlist = vlist[0], *outlist = vlist[1];
|
||||
|
@ -409,8 +402,4 @@ void ProcessTriangleInternal(VertexData &v0, VertexData &v1, VertexData &v2, con
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessTriangle(VertexData &v0, VertexData &v1, VertexData &v2, const VertexData &provoking, BinManager &binner) {
|
||||
ProcessTriangleInternal(v0, v1, v2, provoking, binner, false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -26,9 +26,9 @@ class BinManager;
|
|||
|
||||
namespace Clipper {
|
||||
|
||||
void ProcessPoint(VertexData &v0, BinManager &binner);
|
||||
void ProcessLine(VertexData &v0, VertexData &v1, BinManager &binner);
|
||||
void ProcessTriangle(VertexData &v0, VertexData &v1, VertexData &v2, const VertexData &provoking, BinManager &binner);
|
||||
void ProcessPoint(const VertexData &v0, BinManager &binner);
|
||||
void ProcessLine(const VertexData &v0, const VertexData &v1, BinManager &binner);
|
||||
void ProcessTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const VertexData &provoking, BinManager &binner);
|
||||
void ProcessRect(const VertexData &v0, const VertexData &v1, BinManager &binner);
|
||||
|
||||
}
|
||||
|
|
|
@ -765,9 +765,9 @@ void DrawTriangleSlice(
|
|||
if (AnyMask<useSSE4>(mask)) {
|
||||
Vec4<float> wsum_recip = EdgeRecip(w0, w1, w2);
|
||||
|
||||
// Color interpolation is not perspective corrected on the PSP.
|
||||
Vec4<int> prim_color[4];
|
||||
if (!flatColor0) {
|
||||
// Does the PSP do perspective-correct color interpolation? The GC doesn't.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mask[i] >= 0)
|
||||
prim_color[i] = Interpolate(v0.color0, v1.color0, v2.color0, w0[i], w1[i], w2[i], wsum_recip[i]);
|
||||
|
@ -831,7 +831,7 @@ void DrawTriangleSlice(
|
|||
if (flatZ) {
|
||||
z = Vec4<int>::AssignToAll(v2.screenpos.z);
|
||||
} else {
|
||||
// TODO: Is that the correct way to interpolate?
|
||||
// Z is interpolated pretty much directly.
|
||||
Vec4<float> zfloats = w0.Cast<float>() * v0.screenpos.z + w1.Cast<float>() * v1.screenpos.z + w2.Cast<float>() * v2.screenpos.z;
|
||||
z = (zfloats * wsum_recip).Cast<int>();
|
||||
}
|
||||
|
|
|
@ -306,41 +306,50 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DetectRectangleFromThroughModeStrip(const VertexData data[4]) {
|
||||
// We'll only do this when the color is flat.
|
||||
if (!(data[0].color0 == data[1].color0))
|
||||
return false;
|
||||
if (!(data[1].color0 == data[2].color0))
|
||||
return false;
|
||||
if (!(data[2].color0 == data[3].color0))
|
||||
return false;
|
||||
bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData data[4], int *tlIndex, int *brIndex) {
|
||||
// Color and Z must be flat. Also find the TL and BR meanwhile.
|
||||
int tl = 0, br = 0;
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
if (!(data[i].color0 == data[0].color0))
|
||||
return false;
|
||||
if (!(data[i].screenpos.z == data[0].screenpos.z)) {
|
||||
// Sometimes, we don't actually care about z.
|
||||
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
|
||||
return false;
|
||||
}
|
||||
if (!state.throughMode) {
|
||||
if (!state.throughMode && !(data[i].color1 == data[0].color1))
|
||||
return false;
|
||||
// Do we have to think about perspective correction or slope mip level?
|
||||
if (state.enableTextures && data[i].clippos.w != data[0].clippos.w)
|
||||
return false;
|
||||
if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth)
|
||||
return false;
|
||||
}
|
||||
|
||||
// And the depth must also be flat.
|
||||
if (!(data[0].screenpos.z == data[1].screenpos.z))
|
||||
return false;
|
||||
if (!(data[1].screenpos.z == data[2].screenpos.z))
|
||||
return false;
|
||||
if (!(data[2].screenpos.z == data[3].screenpos.z))
|
||||
return false;
|
||||
if (data[i].screenpos.x <= data[tl].screenpos.x && data[i].screenpos.y <= data[tl].screenpos.y)
|
||||
tl = i;
|
||||
if (data[i].screenpos.x >= data[br].screenpos.x && data[i].screenpos.y >= data[br].screenpos.y)
|
||||
br = i;
|
||||
}
|
||||
|
||||
*tlIndex = tl;
|
||||
*brIndex = br;
|
||||
|
||||
// OK, now let's look at data to detect rectangles. There are a few possibilities
|
||||
// but we focus on Darkstalkers for now.
|
||||
if (data[0].screenpos.x == data[1].screenpos.x &&
|
||||
data[0].screenpos.y == data[2].screenpos.y &&
|
||||
data[2].screenpos.x == data[3].screenpos.x &&
|
||||
data[1].screenpos.y == data[3].screenpos.y &&
|
||||
data[1].screenpos.y > data[0].screenpos.y &&
|
||||
data[2].screenpos.x > data[0].screenpos.x) {
|
||||
// Okay, this is in the shape of a triangle, but what about rotation/texture?
|
||||
if (!gstate.isTextureMapEnabled())
|
||||
data[1].screenpos.y == data[3].screenpos.y) {
|
||||
// Okay, this is in the shape of a rectangle, but what about texture?
|
||||
if (!state.enableTextures)
|
||||
return true;
|
||||
|
||||
if (data[0].texturecoords.x == data[1].texturecoords.x &&
|
||||
data[0].texturecoords.y == data[2].texturecoords.y &&
|
||||
data[2].texturecoords.x == data[3].texturecoords.x &&
|
||||
data[1].texturecoords.y == data[3].texturecoords.y &&
|
||||
data[1].texturecoords.y > data[0].texturecoords.y &&
|
||||
data[2].texturecoords.x > data[0].texturecoords.x) {
|
||||
data[1].texturecoords.y == data[3].texturecoords.y) {
|
||||
// It's a rectangle!
|
||||
return true;
|
||||
}
|
||||
|
@ -350,19 +359,15 @@ bool DetectRectangleFromThroughModeStrip(const VertexData data[4]) {
|
|||
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 &&
|
||||
data[1].screenpos.x > data[0].screenpos.x) {
|
||||
// Okay, this is in the shape of a triangle, but what about rotation/texture?
|
||||
if (!gstate.isTextureMapEnabled())
|
||||
data[2].screenpos.y == data[3].screenpos.y) {
|
||||
// Okay, this is in the shape of a rectangle, but what about texture?
|
||||
if (!state.enableTextures)
|
||||
return true;
|
||||
|
||||
if (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[2].texturecoords.y == data[3].texturecoords.y) {
|
||||
// It's a rectangle!
|
||||
return true;
|
||||
}
|
||||
|
@ -371,13 +376,25 @@ bool DetectRectangleFromThroughModeStrip(const VertexData data[4]) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DetectRectangleFromThroughModeFan(const VertexData *data, int c, int *tlIndex, int *brIndex) {
|
||||
bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data, int c, int *tlIndex, int *brIndex) {
|
||||
// Color and Z must be flat.
|
||||
for (int i = 1; i < c; ++i) {
|
||||
if (!(data[i].color0 == data[0].color0))
|
||||
return false;
|
||||
if (!(data[i].screenpos.z == data[0].screenpos.z))
|
||||
return false;
|
||||
if (!(data[i].screenpos.z == data[0].screenpos.z)) {
|
||||
// Sometimes, we don't actually care about z.
|
||||
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
|
||||
return false;
|
||||
}
|
||||
if (!state.throughMode) {
|
||||
if (!state.throughMode && !(data[i].color1 == data[0].color1))
|
||||
return false;
|
||||
// Do we have to think about perspective correction or slope mip level?
|
||||
if (state.enableTextures && data[i].clippos.w != data[0].clippos.w)
|
||||
return false;
|
||||
if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for the common case: a single TL-TR-BR-BL.
|
||||
|
@ -395,7 +412,7 @@ bool DetectRectangleFromThroughModeFan(const VertexData *data, int c, int *tlInd
|
|||
}
|
||||
|
||||
// Do we need to think about rotation?
|
||||
if (!gstate.isTextureMapEnabled())
|
||||
if (!state.enableTextures)
|
||||
return true;
|
||||
|
||||
const auto &textl = data[*tlIndex].texturecoords, &textr = data[*tlIndex ^ 1].texturecoords;
|
||||
|
@ -411,13 +428,16 @@ bool DetectRectangleFromThroughModeFan(const VertexData *data, int c, int *tlInd
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DetectRectangleSlices(const VertexData data[4]) {
|
||||
bool DetectRectangleThroughModeSlices(const RasterizerState &state, const VertexData data[4]) {
|
||||
// Color and Z must be flat.
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
if (!(data[i].color0 == data[0].color0))
|
||||
return false;
|
||||
if (!(data[i].screenpos.z == data[0].screenpos.z))
|
||||
return false;
|
||||
if (!(data[i].screenpos.z == data[0].screenpos.z)) {
|
||||
// Sometimes, we don't actually care about z.
|
||||
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Games very commonly use vertical strips of rectangles. Detect and combine.
|
||||
|
@ -425,7 +445,7 @@ bool DetectRectangleSlices(const VertexData data[4]) {
|
|||
const auto &tl2 = data[2].screenpos, &br2 = data[3].screenpos;
|
||||
if (tl1.y == tl2.y && br1.y == br2.y && br1.y > tl1.y) {
|
||||
if (br1.x == tl2.x && tl1.x < br1.x && tl2.x < br2.x) {
|
||||
if (!gstate.isTextureMapEnabled() || gstate.isModeClear())
|
||||
if (!state.enableTextures)
|
||||
return true;
|
||||
|
||||
const auto &textl1 = data[0].texturecoords, &texbr1 = data[1].texturecoords;
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Rasterizer {
|
|||
bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &binner);
|
||||
void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state);
|
||||
|
||||
bool DetectRectangleFromThroughModeStrip(const VertexData data[4]);
|
||||
bool DetectRectangleFromThroughModeFan(const VertexData *data, int c, int *tlIndex, int *brIndex);
|
||||
bool DetectRectangleSlices(const VertexData data[4]);
|
||||
bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData data[4], int *tlIndex, int *brIndex);
|
||||
bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data, int c, int *tlIndex, int *brIndex);
|
||||
bool DetectRectangleThroughModeSlices(const RasterizerState &state, const VertexData data[4]);
|
||||
}
|
||||
|
|
|
@ -593,7 +593,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
|||
}
|
||||
|
||||
if (data_index == 4 && gstate.isModeThrough() && cullType == CullType::OFF) {
|
||||
if (Rasterizer::DetectRectangleSlices(data)) {
|
||||
if (Rasterizer::DetectRectangleThroughModeSlices(binner_->State(), data)) {
|
||||
data[1] = data[3];
|
||||
data_index = 2;
|
||||
}
|
||||
|
@ -649,7 +649,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
|||
|
||||
// If index count == 4, check if we can convert to a rectangle.
|
||||
// This is for Darkstalkers (and should speed up many 2D games).
|
||||
if (data_index == 0 && vertex_count == 4 && gstate.isModeThrough() && cullType == CullType::OFF) {
|
||||
if (data_index == 0 && vertex_count == 4 && cullType == CullType::OFF) {
|
||||
for (int vtx = 0; vtx < 4; ++vtx) {
|
||||
if (indices) {
|
||||
vreader.Goto(ConvertIndex(vtx) - index_lower_bound);
|
||||
|
@ -661,8 +661,9 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
|||
}
|
||||
|
||||
// If a strip is effectively a rectangle, draw it as such!
|
||||
if (!outside_range_flag && Rasterizer::DetectRectangleFromThroughModeStrip(data)) {
|
||||
Clipper::ProcessRect(data[0], data[3], *binner_);
|
||||
int tl = -1, br = -1;
|
||||
if (!outside_range_flag && Rasterizer::DetectRectangleFromStrip(binner_->State(), data, &tl, &br)) {
|
||||
Clipper::ProcessRect(data[tl], data[br], *binner_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -726,7 +727,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
|||
break;
|
||||
}
|
||||
|
||||
if (data_index == 1 && vertex_count == 4 && gstate.isModeThrough() && cullType == CullType::OFF) {
|
||||
if (data_index == 1 && vertex_count == 4 && cullType == CullType::OFF) {
|
||||
for (int vtx = start_vtx; vtx < vertex_count; ++vtx) {
|
||||
if (indices) {
|
||||
vreader.Goto(ConvertIndex(vtx) - index_lower_bound);
|
||||
|
@ -737,7 +738,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
|||
}
|
||||
|
||||
int tl = -1, br = -1;
|
||||
if (!outside_range_flag && Rasterizer::DetectRectangleFromThroughModeFan(data, vertex_count, &tl, &br)) {
|
||||
if (!outside_range_flag && Rasterizer::DetectRectangleFromFan(binner_->State(), data, vertex_count, &tl, &br)) {
|
||||
Clipper::ProcessRect(data[tl], data[br], *binner_);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue