softgpu: Implement spline surface drawing (without patch subdivision).
This commit is contained in:
parent
f4cb929073
commit
11a94e1d14
5 changed files with 115 additions and 1 deletions
|
@ -351,6 +351,8 @@ struct GPUgstate
|
||||||
int getWeightMask() const { return vertType & GE_VTYPE_WEIGHT_MASK; }
|
int getWeightMask() const { return vertType & GE_VTYPE_WEIGHT_MASK; }
|
||||||
int getNumBoneWeights() const { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); }
|
int getNumBoneWeights() const { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); }
|
||||||
|
|
||||||
|
GEPatchPrimType getPatchPrimitiveType() const { return static_cast<GEPatchPrimType>(patchprimitive & 3); }
|
||||||
|
|
||||||
// Real data in the context ends here
|
// Real data in the context ends here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,28 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
|
||||||
int sp_vcount = (data >> 8) & 0xFF;
|
int sp_vcount = (data >> 8) & 0xFF;
|
||||||
int sp_utype = (data >> 16) & 0x3;
|
int sp_utype = (data >> 16) & 0x3;
|
||||||
int sp_vtype = (data >> 18) & 0x3;
|
int sp_vtype = (data >> 18) & 0x3;
|
||||||
//drawSpline(sp_ucount, sp_vcount, sp_utype, sp_vtype);
|
|
||||||
|
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
|
||||||
|
ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *control_points = Memory::GetPointer(gstate_c.vertexAddr);
|
||||||
|
void *indices = NULL;
|
||||||
|
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
|
||||||
|
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
|
||||||
|
ERROR_LOG(G3D, "Bad index address %08x!", gstate_c.indexAddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indices = Memory::GetPointer(gstate_c.indexAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gstate.getPatchPrimitiveType() != GE_PATCHPRIM_TRIANGLES) {
|
||||||
|
ERROR_LOG(G3D, "Unsupported patch primitive %x", gstate.patchprimitive&3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformUnit::SubmitSpline(control_points, indices, sp_ucount, sp_vcount, sp_utype, sp_vtype, gstate.patchprimitive&3, gstate.vertType);
|
||||||
DEBUG_LOG(G3D,"DL DRAW SPLINE: %i x %i, %i x %i", sp_ucount, sp_vcount, sp_utype, sp_vtype);
|
DEBUG_LOG(G3D,"DL DRAW SPLINE: %i x %i, %i x %i", sp_ucount, sp_vcount, sp_utype, sp_vtype);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -138,6 +138,89 @@ static VertexData ReadVertex(VertexReader& vreader)
|
||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define START_OPEN_U 1
|
||||||
|
#define END_OPEN_U 2
|
||||||
|
#define START_OPEN_V 4
|
||||||
|
#define END_OPEN_V 8
|
||||||
|
|
||||||
|
struct SplinePatch {
|
||||||
|
VertexData points[16];
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
void TransformUnit::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type)
|
||||||
|
{
|
||||||
|
VertexDecoder vdecoder;
|
||||||
|
vdecoder.SetVertexType(vertex_type);
|
||||||
|
const DecVtxFormat& vtxfmt = vdecoder.GetDecVtxFmt();
|
||||||
|
|
||||||
|
static u8 buf[65536 * 48]; // yolo
|
||||||
|
u16 index_lower_bound = 0;
|
||||||
|
u16 index_upper_bound = count_u * count_v - 1;
|
||||||
|
bool indices_16bit = (vertex_type & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT;
|
||||||
|
u8* indices8 = (u8*)indices;
|
||||||
|
u16* indices16 = (u16*)indices;
|
||||||
|
if (indices)
|
||||||
|
GetIndexBounds(indices, count_u*count_v, vertex_type, &index_lower_bound, &index_upper_bound);
|
||||||
|
vdecoder.DecodeVerts(buf, control_points, index_lower_bound, index_upper_bound);
|
||||||
|
|
||||||
|
VertexReader vreader(buf, vtxfmt, vertex_type);
|
||||||
|
|
||||||
|
int num_patches_u = count_u - 3;
|
||||||
|
int num_patches_v = count_v - 3;
|
||||||
|
|
||||||
|
// TODO: Do something less idiotic to manage this buffer
|
||||||
|
SplinePatch* patches = new SplinePatch[num_patches_u * num_patches_v];
|
||||||
|
|
||||||
|
for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) {
|
||||||
|
for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) {
|
||||||
|
SplinePatch& patch = patches[patch_u + patch_v * num_patches_u];
|
||||||
|
|
||||||
|
for (int point = 0; point < 16; ++point) {
|
||||||
|
int idx = (patch_u + point%4) + (patch_v + point/4) * count_u;
|
||||||
|
if (indices)
|
||||||
|
vreader.Goto(indices_16bit ? indices16[idx] : indices8[idx]);
|
||||||
|
else
|
||||||
|
vreader.Goto(idx);
|
||||||
|
|
||||||
|
patch.points[point] = ReadVertex(vreader);
|
||||||
|
}
|
||||||
|
patch.type = (type_u | (type_v<<2));
|
||||||
|
if (patch_u != 0) patch.type &= ~START_OPEN_U;
|
||||||
|
if (patch_v != 0) patch.type &= ~START_OPEN_V;
|
||||||
|
if (patch_u != num_patches_u-1) patch.type &= ~END_OPEN_U;
|
||||||
|
if (patch_v != num_patches_v-1) patch.type &= ~END_OPEN_V;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int patch_idx = 0; patch_idx < num_patches_u*num_patches_v; ++patch_idx) {
|
||||||
|
SplinePatch& patch = patches[patch_idx];
|
||||||
|
|
||||||
|
// TODO: Should do actual patch subdivision instead of just drawing the control points!
|
||||||
|
const int tile_min_u = (patch.type & START_OPEN_U) ? 0 : 1;
|
||||||
|
const int tile_min_v = (patch.type & START_OPEN_V) ? 0 : 1;
|
||||||
|
const int tile_max_u = (patch.type & END_OPEN_U) ? 3 : 2;
|
||||||
|
const int tile_max_v = (patch.type & END_OPEN_V) ? 3 : 2;
|
||||||
|
for (int tile_u = tile_min_u; tile_u < tile_max_u; ++tile_u) {
|
||||||
|
for (int tile_v = tile_min_v; tile_v < tile_max_v; ++tile_v) {
|
||||||
|
int point_index = tile_u + tile_v*4;
|
||||||
|
|
||||||
|
VertexData v0 = patch.points[point_index];
|
||||||
|
VertexData v1 = patch.points[point_index+1];
|
||||||
|
VertexData v2 = patch.points[point_index+4];
|
||||||
|
VertexData v3 = patch.points[point_index+5];
|
||||||
|
|
||||||
|
// TODO: Backface culling etc
|
||||||
|
Clipper::ProcessTriangle(v0, v1, v2);
|
||||||
|
Clipper::ProcessTriangle(v2, v1, v0);
|
||||||
|
Clipper::ProcessTriangle(v2, v1, v3);
|
||||||
|
Clipper::ProcessTriangle(v3, v1, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] patches;
|
||||||
|
}
|
||||||
|
|
||||||
void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type)
|
void TransformUnit::SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type)
|
||||||
{
|
{
|
||||||
// TODO: Cache VertexDecoder objects
|
// TODO: Cache VertexDecoder objects
|
||||||
|
|
|
@ -107,5 +107,6 @@ public:
|
||||||
static ScreenCoords ClipToScreen(const ClipCoords& coords);
|
static ScreenCoords ClipToScreen(const ClipCoords& coords);
|
||||||
static DrawingCoords ScreenToDrawing(const ScreenCoords& coords);
|
static DrawingCoords ScreenToDrawing(const ScreenCoords& coords);
|
||||||
|
|
||||||
|
static void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type);
|
||||||
static void SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type);
|
static void SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type);
|
||||||
};
|
};
|
||||||
|
|
|
@ -503,6 +503,13 @@ enum GELogicOp
|
||||||
GE_LOGIC_SET=15
|
GE_LOGIC_SET=15
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum GEPatchPrimType
|
||||||
|
{
|
||||||
|
GE_PATCHPRIM_TRIANGLES=0,
|
||||||
|
GE_PATCHPRIM_LINES=1,
|
||||||
|
GE_PATCHPRIM_POINTS=2,
|
||||||
|
};
|
||||||
|
|
||||||
enum GEPaletteFormat
|
enum GEPaletteFormat
|
||||||
{
|
{
|
||||||
GE_CMODE_16BIT_BGR5650,
|
GE_CMODE_16BIT_BGR5650,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue