Splines: Draw a line patch's shared quad edges once

A patch drawn as lines is a zigzag per quad (gpu/probe exp175), but the GE
draws a quad's right edge only in the patch's last column, since the next
quad's left edge is the same line. Edges between patches are still drawn
twice. Opaque lines can't show the difference; NFS Most Wanted's
alpha-blended spline visualizer (#22104) came out brighter wherever the
edges were drawn twice. gpu/probe exp257 counts the draws per pixel with
additive blending, for Bezier and spline patches; both are now exact, as is
the NFS frame against the PSP.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-20 14:11:06 +02:00
1 parent 5471f5fe88
commit 7adf0c15ee
2 files changed
+15 -8

No files matched your search

+11 -5
View File
@@ -57,14 +57,20 @@ public:
namespace Spline {
static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) {
// Returns the number of indices written.
static int CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3, bool rightEdge) {
if (type == GE_PATCHPRIM_LINES) {
// A zigzag per quad: left edge down, the diagonal up to the top right, right edge down (gpu/probe exp175,
// exact: line colors and lit start pixels show the directions, and overlapping pixels the order).
// exact: line colors and lit start pixels show the directions, and overlapping pixels the order). The right
// edge only on a patch's last column, as the next quad's left edge is the same line (exp257, counted with
// additive blending).
*(indices++) = idx0;
*(indices++) = idx2;
*(indices++) = idx2;
*(indices++) = idx1;
if (!rightEdge) {
return 4;
}
*(indices++) = idx1;
*(indices++) = idx3;
} else {
@@ -75,16 +81,16 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c
*(indices++) = idx2;
*(indices++) = idx3;
}
return 6;
}
void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total) {
void BuildIndex(u16 *indices, int &count, int num_u, int num_v, int patch_u, GEPatchPrimType prim_type, int total) {
for (int v = 0; v < num_v; ++v) {
for (int u = 0; u < num_u; ++u) {
int idx0 = v * (num_u + 1) + u + total; // Top left
int idx2 = (v + 1) * (num_u + 1) + u + total; // Bottom left
CopyQuadIndex(indices, prim_type, idx0, idx0 + 1, idx2, idx2 + 1);
count += 6;
count += CopyQuadIndex(indices, prim_type, idx0, idx0 + 1, idx2, idx2 + 1, (u + 1) % patch_u == 0);
}
}
}
+4 -3
View File
@@ -34,7 +34,8 @@ class SimpleBufferManager;
namespace Spline {
void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0);
// patch_u is the number of quads per patch along u.
void BuildIndex(u16 *indices, int &count, int num_u, int num_v, int patch_u, GEPatchPrimType prim_type, int total = 0);
class Bezier3DWeight;
class Spline3DWeight;
@@ -99,7 +100,7 @@ struct BezierSurface : public SurfaceInfo {
for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) {
int patch_index = patch_v * num_patches_u + patch_u;
int total = patch_index * num_verts_per_patch;
Spline::BuildIndex(indices + count, count, tess_u, tess_v, primType, total);
Spline::BuildIndex(indices + count, count, tess_u, tess_v, tess_u, primType, total);
}
}
}
@@ -133,7 +134,7 @@ struct SplineSurface : public SurfaceInfo {
}
void BuildIndex(u16 *indices, int &count) const {
Spline::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType);
Spline::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, tess_u, primType);
}
};