diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index e292c2b937..1cddb1ddb2 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -67,4 +67,4 @@ enum SplineQuality { }; void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertices); -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); +void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType); diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index 8acb1ed4ea..d334385691 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -162,9 +162,9 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { int sp_utype = (data >> 16) & 0x3; int sp_vtype = (data >> 18) & 0x3; if (data & 0xF00000) - snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i, %i x %i (extra %x)", sp_ucount, sp_vcount, sp_utype, sp_vtype, data >> 20); + snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i (type %ix%i, extra %x)", sp_ucount, sp_vcount, sp_utype, sp_vtype, data >> 20); else - snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i, %i x %i", sp_ucount, sp_vcount, sp_utype, sp_vtype); + snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i (type %ix%i)", sp_ucount, sp_vcount, sp_utype, sp_vtype); } break; diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index f3888669d6..e878105fdd 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -281,6 +281,10 @@ int CtrlVertexList::GetRowCount() { u32 cmd = Memory::Read_U32(list.pc); if ((cmd >> 24) == GE_CMD_PRIM) { rowCount_ = cmd & 0xFFFF; + } else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) { + u32 u = (cmd & 0x00FF) >> 0; + u32 v = (cmd & 0xFF00) >> 8; + rowCount_ = u * v; } } diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 1f78554d91..8714aa05e3 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -24,6 +24,7 @@ #include "Core/Config.h" #include "GPU/GPUInterface.h" #include "GPU/Common/GPUDebugInterface.h" +#include "GPU/Common/SplineCommon.h" #include "GPU/GPUState.h" static const char preview_fs[] = @@ -153,11 +154,10 @@ static void ExpandRectangles(std::vector &vertices, std::vector< u32 CGEDebugger::PrimPreviewOp() { DisplayList list; - if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list)) { + if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list) && !showClut_) { const u32 op = Memory::Read_U32(list.pc); const u32 cmd = op >> 24; - // TODO: Bezier/spline? - if (cmd == GE_CMD_PRIM && !showClut_) { + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { return op; } } @@ -165,9 +165,160 @@ u32 CGEDebugger::PrimPreviewOp() { return 0; } +static void ExpandBezier(int &count, int op, std::vector &vertices, std::vector &indices) { + int count_u = (op & 0x00FF) >> 0; + int count_v = (op & 0xFF00) >> 8; + + int tess_u = gstate.getPatchDivisionU(); + int tess_v = gstate.getPatchDivisionV(); + if (tess_u < 1) { + tess_u = 1; + } + if (tess_v < 1) { + tess_v = 1; + } + + std::vector simpleVerts; + simpleVerts.resize(vertices.size()); + for (size_t i = 0; i < vertices.size(); ++i) { + // For now, let's just copy back so we can use TessellateBezierPatch... + simpleVerts[i].uv[0] = vertices[i].u; + simpleVerts[i].uv[1] = vertices[i].v; + simpleVerts[i].pos = Vec3Packedf(vertices[i].x, vertices[i].y, vertices[i].z); + } + + // Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing) + int num_patches_u = (count_u - 1) / 3; + int num_patches_v = (count_v - 1) / 3; + int total_patches = num_patches_u * num_patches_v; + std::vector patches; + patches.resize(total_patches); + for (int patch_u = 0; patch_u < num_patches_u; patch_u++) { + for (int patch_v = 0; patch_v < num_patches_v; patch_v++) { + BezierPatch &patch = patches[patch_u + patch_v * num_patches_u]; + for (int point = 0; point < 16; ++point) { + int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * count_u; + patch.points[point] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); + } + patch.u_index = patch_u * 3; + patch.v_index = patch_v * 3; + patch.index = patch_v * num_patches_u + patch_u; + patch.primType = gstate.getPatchPrimitiveType(); + patch.computeNormals = false; + patch.patchFacing = false; + } + } + + std::vector generatedVerts; + std::vector generatedInds; + generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches); + generatedInds.resize(tess_u * tess_v * 6); + + count = 0; + u8 *dest = (u8 *)&generatedVerts[0]; + u16 *inds = &generatedInds[0]; + for (int patch_idx = 0; patch_idx < total_patches; ++patch_idx) { + const BezierPatch &patch = patches[patch_idx]; + TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, gstate.vertType); + } + + vertices.resize(generatedVerts.size()); + for (size_t i = 0; i < vertices.size(); ++i) { + vertices[i].u = generatedVerts[i].uv[0]; + vertices[i].v = generatedVerts[i].uv[1]; + vertices[i].x = generatedVerts[i].pos.x; + vertices[i].y = generatedVerts[i].pos.y; + vertices[i].z = generatedVerts[i].pos.z; + } + indices = generatedInds; +} + +static void ExpandSpline(int &count, int op, std::vector &vertices, std::vector &indices) { + SplinePatchLocal patch; + patch.computeNormals = false; + patch.primType = gstate.getPatchPrimitiveType(); + patch.patchFacing = false; + + patch.count_u = (op & 0x00FF) >> 0; + patch.count_v = (op & 0xFF00) >> 8; + patch.type_u = (op >> 16) & 0x3; + patch.type_v = (op >> 18) & 0x3; + + patch.tess_u = gstate.getPatchDivisionU(); + patch.tess_v = gstate.getPatchDivisionV(); + if (patch.tess_u < 1) { + patch.tess_u = 1; + } + if (patch.tess_v < 1) { + patch.tess_v = 1; + } + + // Real hardware seems to draw nothing when given < 4 either U or V. + if (patch.count_u < 4 || patch.count_v < 4) { + return; + } + + std::vector simpleVerts; + simpleVerts.resize(vertices.size()); + for (size_t i = 0; i < vertices.size(); ++i) { + // For now, let's just copy back so we can use TessellateBezierPatch... + simpleVerts[i].uv[0] = vertices[i].u; + simpleVerts[i].uv[1] = vertices[i].v; + simpleVerts[i].pos = Vec3Packedf(vertices[i].x, vertices[i].y, vertices[i].z); + } + + std::vector points; + points.resize(patch.count_u * patch.count_v); + + // Make an array of pointers to the control points, to get rid of indices. + for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) { + points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); + } + patch.points = &points[0]; + + int patch_div_s = (patch.count_u - 3) * patch.tess_u; + int patch_div_t = (patch.count_v - 3) * patch.tess_v; + int maxVertexCount = (patch_div_s + 1) * (patch_div_t + 1); + + std::vector generatedVerts; + std::vector generatedInds; + generatedVerts.resize(maxVertexCount); + generatedInds.resize(patch_div_s * patch_div_t * 6); + + count = 0; + u8 *dest = (u8 *)&generatedVerts[0]; + TessellateSplinePatch(dest, &generatedInds[0], count, patch, gstate.vertType, maxVertexCount); + + vertices.resize(generatedVerts.size()); + for (size_t i = 0; i < vertices.size(); ++i) { + vertices[i].u = generatedVerts[i].uv[0]; + vertices[i].v = generatedVerts[i].uv[1]; + vertices[i].x = generatedVerts[i].pos.x; + vertices[i].y = generatedVerts[i].pos.y; + vertices[i].z = generatedVerts[i].pos.z; + } + indices = generatedInds; +} + void CGEDebugger::UpdatePrimPreview(u32 op, int which) { - const u32 prim_type = (op >> 16) & 0x7; - int count = op & 0xFFFF; + u32 prim_type = GE_PRIM_INVALID; + int count = 0; + int count_u = 0; + int count_v = 0; + + const u32 cmd = op >> 24; + if (cmd == GE_CMD_PRIM) { + prim_type = (op >> 16) & 0x7; + count = op & 0xFFFF; + } else { + const GEPrimitiveType primLookup[] = { GE_PRIM_TRIANGLES, GE_PRIM_LINES, GE_PRIM_POINTS, GE_PRIM_POINTS }; + if (gstate.getPatchPrimitiveType() < ARRAY_SIZE(primLookup)) + prim_type = primLookup[gstate.getPatchPrimitiveType()]; + count_u = (op & 0x00FF) >> 0; + count_v = (op & 0xFF00) >> 8; + count = count_u * count_v; + } + if (prim_type >= 7) { ERROR_LOG(G3D, "Unsupported prim type: %x", op); return; @@ -190,6 +341,12 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { return; } + if (cmd == GE_CMD_BEZIER) { + ExpandBezier(count, op, vertices, indices); + } else if (cmd == GE_CMD_SPLINE) { + ExpandSpline(count, op, vertices, indices); + } + if (prim == GE_PRIM_RECTANGLES) { ExpandRectangles(vertices, indices, count, gpuDebug->GetGState().isModeThrough()); }