mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
[spline/bezier]Improve basic spline/bezier structures.
This commit is contained in:
parent
8ad38dfaae
commit
10afcf2dbb
3 changed files with 151 additions and 198 deletions
|
@ -343,37 +343,29 @@ void ControlPoints::Convert(const SimpleVertex *const *points, int size) {
|
|||
defcolor = points[0]->color_32;
|
||||
}
|
||||
|
||||
template<class Patch>
|
||||
template<class Surface>
|
||||
class SubdivisionSurface {
|
||||
private:
|
||||
const ControlPoints &points;
|
||||
const Patch &patch;
|
||||
const Weight2D &weights;
|
||||
public:
|
||||
SubdivisionSurface(const ControlPoints &points, const Patch &patch, const Weight2D &weights)
|
||||
: points(points), patch(patch), weights(weights) {
|
||||
}
|
||||
|
||||
template <bool sampleNrm, bool sampleCol, bool sampleTex, bool useSSE4, bool patchFacing>
|
||||
void Tessellate(OutputBuffers &output) {
|
||||
const float inv_u = 1.0f / (float)patch.tess_u;
|
||||
const float inv_v = 1.0f / (float)patch.tess_v;
|
||||
static void Tessellate(OutputBuffers &output, const Surface &surface, const ControlPoints &points, const Weight2D &weights) {
|
||||
const float inv_u = 1.0f / (float)surface.tess_u;
|
||||
const float inv_v = 1.0f / (float)surface.tess_v;
|
||||
|
||||
for (int patch_u = 0; patch_u < patch.num_patches_u; ++patch_u) {
|
||||
const int start_u = patch.GetTessStart(patch_u);
|
||||
for (int patch_v = 0; patch_v < patch.num_patches_v; ++patch_v) {
|
||||
const int start_v = patch.GetTessStart(patch_v);
|
||||
for (int patch_u = 0; patch_u < surface.num_patches_u; ++patch_u) {
|
||||
const int start_u = surface.GetTessStart(patch_u);
|
||||
for (int patch_v = 0; patch_v < surface.num_patches_v; ++patch_v) {
|
||||
const int start_v = surface.GetTessStart(patch_v);
|
||||
|
||||
// Prepare 4x4 control points to tessellate
|
||||
const int idx = patch.GetPointIndex(patch_u, patch_v);
|
||||
const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 };
|
||||
const int idx = surface.GetPointIndex(patch_u, patch_v);
|
||||
const int idx_v[4] = { idx, idx + surface.num_points_u, idx + surface.num_points_u * 2, idx + surface.num_points_u * 3 };
|
||||
Tessellator<Vec3f> tess_pos(points.pos, idx_v);
|
||||
Tessellator<Vec4f> tess_col(points.col, idx_v);
|
||||
Tessellator<Vec2f> tess_tex(points.tex, idx_v);
|
||||
Tessellator<Vec3f> tess_nrm(points.pos, idx_v);
|
||||
|
||||
for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) {
|
||||
const int index_u = patch.GetIndexU(patch_u, tile_u);
|
||||
for (int tile_u = start_u; tile_u <= surface.tess_u; ++tile_u) {
|
||||
const int index_u = surface.GetIndexU(patch_u, tile_u);
|
||||
const Weight &wu = weights.u[index_u];
|
||||
|
||||
// Pre-tessellate U lines
|
||||
|
@ -385,11 +377,11 @@ public:
|
|||
if (sampleNrm)
|
||||
tess_nrm.SampleU(wu.deriv);
|
||||
|
||||
for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) {
|
||||
const int index_v = patch.GetIndexV(patch_v, tile_v);
|
||||
for (int tile_v = start_v; tile_v <= surface.tess_v; ++tile_v) {
|
||||
const int index_v = surface.GetIndexV(patch_v, tile_v);
|
||||
const Weight &wv = weights.v[index_v];
|
||||
|
||||
SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)];
|
||||
SimpleVertex &vert = output.vertices[surface.GetIndex(index_u, index_v, patch_u, patch_v)];
|
||||
|
||||
// Tessellate
|
||||
vert.pos = tess_pos.SampleV(wv.basis);
|
||||
|
@ -420,62 +412,60 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
patch.BuildIndex(output.indices, output.count);
|
||||
surface.BuildIndex(output.indices, output.count);
|
||||
}
|
||||
|
||||
using TessFunc = void(SubdivisionSurface::*)(OutputBuffers &);
|
||||
using TessFunc = void(*)(OutputBuffers &, const Surface &, const ControlPoints &, const Weight2D &);
|
||||
TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate, TessFunc);
|
||||
|
||||
void Tessellate(OutputBuffers &output, u32 origVertType) {
|
||||
constexpr int NumParams = 5;
|
||||
static TemplateParameterDispatcher<TessFunc, NumParams, Tess> dispatcher; // Initialize only once
|
||||
|
||||
const bool params[NumParams] = {
|
||||
static void Tessellate(OutputBuffers &output, const Surface &surface, const ControlPoints &points, const Weight2D &weights, u32 origVertType) {
|
||||
const bool params[] = {
|
||||
(origVertType & GE_VTYPE_NRM_MASK) != 0,
|
||||
(origVertType & GE_VTYPE_COL_MASK) != 0,
|
||||
(origVertType & GE_VTYPE_TC_MASK) != 0,
|
||||
cpu_info.bSSE4_1,
|
||||
patch.patchFacing,
|
||||
surface.patchFacing,
|
||||
};
|
||||
static TemplateParameterDispatcher<TessFunc, ARRAY_SIZE(params), Tess> dispatcher; // Initialize only once
|
||||
|
||||
TessFunc func = dispatcher.GetFunc(params);
|
||||
(this->*func)(output);
|
||||
func(output, surface, points, weights);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Patch>
|
||||
void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points) {
|
||||
using WeightType = typename Patch::WeightType;
|
||||
u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u);
|
||||
u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v);
|
||||
template<class Surface>
|
||||
void SoftwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType, const ControlPoints &points) {
|
||||
using WeightType = typename Surface::WeightType;
|
||||
u32 key_u = WeightType::ToKey(surface.tess_u, surface.num_points_u, surface.type_u);
|
||||
u32 key_v = WeightType::ToKey(surface.tess_v, surface.num_points_v, surface.type_v);
|
||||
Weight2D weights(WeightType::weightsCache, key_u, key_v);
|
||||
|
||||
SubdivisionSurface<Patch> surface(points, patch, weights);
|
||||
surface.Tessellate(output, origVertType);
|
||||
SubdivisionSurface<Surface>::Tessellate(output, surface, points, weights, origVertType);
|
||||
}
|
||||
|
||||
template<class Patch>
|
||||
static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType,
|
||||
template<class Surface>
|
||||
static void HardwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType,
|
||||
const SimpleVertex *const *points, TessellationDataTransfer *tessDataTransfer) {
|
||||
using WeightType = typename Patch::WeightType;
|
||||
u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u);
|
||||
u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v);
|
||||
using WeightType = typename Surface::WeightType;
|
||||
u32 key_u = WeightType::ToKey(surface.tess_u, surface.num_points_u, surface.type_u);
|
||||
u32 key_v = WeightType::ToKey(surface.tess_v, surface.num_points_v, surface.type_v);
|
||||
Weight2D weights(WeightType::weightsCache, key_u, key_v);
|
||||
weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u);
|
||||
weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v);
|
||||
tessDataTransfer->SendDataToShader(points, patch.count_u, patch.count_v, origVertType, weights);
|
||||
weights.size_u = WeightType::CalcSize(surface.tess_u, surface.num_points_u);
|
||||
weights.size_v = WeightType::CalcSize(surface.tess_v, surface.num_points_v);
|
||||
tessDataTransfer->SendDataToShader(points, surface.num_points_u, surface.num_points_v, origVertType, weights);
|
||||
|
||||
// Generating simple input vertices for the spline-computing vertex shader.
|
||||
float inv_u = 1.0f / (float)patch.tess_u;
|
||||
float inv_v = 1.0f / (float)patch.tess_v;
|
||||
for (int patch_u = 0; patch_u < patch.num_patches_u; ++patch_u) {
|
||||
const int start_u = patch.GetTessStart(patch_u);
|
||||
for (int patch_v = 0; patch_v < patch.num_patches_v; ++patch_v) {
|
||||
const int start_v = patch.GetTessStart(patch_v);
|
||||
for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) {
|
||||
const int index_u = patch.GetIndexU(patch_u, tile_u);
|
||||
for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) {
|
||||
const int index_v = patch.GetIndexV(patch_v, tile_v);
|
||||
SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)];
|
||||
float inv_u = 1.0f / (float)surface.tess_u;
|
||||
float inv_v = 1.0f / (float)surface.tess_v;
|
||||
for (int patch_u = 0; patch_u < surface.num_patches_u; ++patch_u) {
|
||||
const int start_u = surface.GetTessStart(patch_u);
|
||||
for (int patch_v = 0; patch_v < surface.num_patches_v; ++patch_v) {
|
||||
const int start_v = surface.GetTessStart(patch_v);
|
||||
for (int tile_u = start_u; tile_u <= surface.tess_u; ++tile_u) {
|
||||
const int index_u = surface.GetIndexU(patch_u, tile_u);
|
||||
for (int tile_v = start_v; tile_v <= surface.tess_v; ++tile_v) {
|
||||
const int index_v = surface.GetIndexV(patch_v, tile_v);
|
||||
SimpleVertex &vert = output.vertices[surface.GetIndex(index_u, index_v, patch_u, patch_v)];
|
||||
// Index for the weights
|
||||
vert.pos.x = index_u;
|
||||
vert.pos.y = index_v;
|
||||
|
@ -489,7 +479,7 @@ static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32
|
|||
}
|
||||
}
|
||||
}
|
||||
patch.BuildIndex(output.indices, output.count);
|
||||
surface.BuildIndex(output.indices, output.count);
|
||||
}
|
||||
|
||||
void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) {
|
||||
|
@ -525,10 +515,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
|
|||
ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex));
|
||||
}
|
||||
|
||||
// If specified as 0, uses 1.
|
||||
if (tess_u < 1) tess_u = 1;
|
||||
if (tess_v < 1) tess_v = 1;
|
||||
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v);
|
||||
for (int idx = 0; idx < count_u * count_v; idx++)
|
||||
|
@ -539,24 +525,24 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
|
|||
output.indices = quadIndices_;
|
||||
output.count = 0;
|
||||
|
||||
SplinePatchLocal patch;
|
||||
patch.tess_u = tess_u;
|
||||
patch.tess_v = tess_v;
|
||||
patch.type_u = type_u;
|
||||
patch.type_v = type_v;
|
||||
patch.count_u = count_u;
|
||||
patch.count_v = count_v;
|
||||
patch.num_patches_u = count_u - 3;
|
||||
patch.num_patches_v = count_v - 3;
|
||||
patch.primType = prim_type;
|
||||
patch.patchFacing = patchFacing;
|
||||
patch.Init(SPLINE_BUFFER_SIZE / vertexSize);
|
||||
SplineSurface surface;
|
||||
surface.tess_u = tess_u;
|
||||
surface.tess_v = tess_v;
|
||||
surface.type_u = type_u;
|
||||
surface.type_v = type_v;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.num_patches_u = count_u - 3;
|
||||
surface.num_patches_v = count_v - 3;
|
||||
surface.primType = prim_type;
|
||||
surface.patchFacing = patchFacing;
|
||||
surface.Init(SPLINE_BUFFER_SIZE / vertexSize);
|
||||
|
||||
if (CanUseHardwareTessellation(prim_type)) {
|
||||
HardwareTessellation(output, patch, origVertType, points, tessDataTransfer);
|
||||
HardwareTessellation(output, surface, origVertType, points, tessDataTransfer);
|
||||
} else {
|
||||
ControlPoints cpoints(points, count_u * count_v, managedBuf);
|
||||
SoftwareTessellation(output, patch, origVertType, cpoints);
|
||||
SoftwareTessellation(output, surface, origVertType, cpoints);
|
||||
}
|
||||
|
||||
u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
|
||||
|
@ -618,10 +604,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
|||
ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex));
|
||||
}
|
||||
|
||||
// If specified as 0, uses 1.
|
||||
if (tess_u < 1) tess_u = 1;
|
||||
if (tess_v < 1) tess_v = 1;
|
||||
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v);
|
||||
for (int idx = 0; idx < count_u * count_v; idx++)
|
||||
|
@ -632,22 +614,22 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
|||
output.indices = quadIndices_;
|
||||
output.count = 0;
|
||||
|
||||
BezierPatch patch;
|
||||
patch.tess_u = tess_u;
|
||||
patch.tess_v = tess_v;
|
||||
patch.count_u = count_u;
|
||||
patch.count_v = count_v;
|
||||
patch.num_patches_u = (count_u - 1) / 3;
|
||||
patch.num_patches_v = (count_v - 1) / 3;
|
||||
patch.primType = prim_type;
|
||||
patch.patchFacing = patchFacing;
|
||||
patch.Init(SPLINE_BUFFER_SIZE / vertexSize);
|
||||
BezierSurface surface;
|
||||
surface.tess_u = tess_u;
|
||||
surface.tess_v = tess_v;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.num_patches_u = (count_u - 1) / 3;
|
||||
surface.num_patches_v = (count_v - 1) / 3;
|
||||
surface.primType = prim_type;
|
||||
surface.patchFacing = patchFacing;
|
||||
surface.Init(SPLINE_BUFFER_SIZE / vertexSize);
|
||||
|
||||
if (CanUseHardwareTessellation(prim_type)) {
|
||||
HardwareTessellation(output, patch, origVertType, points, tessDataTransfer);
|
||||
HardwareTessellation(output, surface, origVertType, points, tessDataTransfer);
|
||||
} else {
|
||||
ControlPoints cpoints(points, count_u * count_v, managedBuf);
|
||||
SoftwareTessellation(output, patch, origVertType, cpoints);
|
||||
SoftwareTessellation(output, surface, origVertType, cpoints);
|
||||
}
|
||||
|
||||
u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
|
||||
|
|
|
@ -50,21 +50,20 @@ class Spline3DWeight;
|
|||
|
||||
// We decode all vertices into a common format for easy interpolation and stuff.
|
||||
// Not fast but can be optimized later.
|
||||
struct BezierPatch {
|
||||
using WeightType = Bezier3DWeight;
|
||||
|
||||
int tess_u;
|
||||
int tess_v;
|
||||
int count_u;
|
||||
int count_v;
|
||||
int type_u;
|
||||
int type_v;
|
||||
int num_patches_u;
|
||||
int num_patches_v;
|
||||
struct SurfaceInfo {
|
||||
int tess_u, tess_v;
|
||||
int num_points_u, num_points_v;
|
||||
int num_patches_u, num_patches_v;
|
||||
int type_u, type_v;
|
||||
GEPatchPrimType primType;
|
||||
bool patchFacing;
|
||||
|
||||
void Init(int maxVertices) {
|
||||
void Init() {
|
||||
// If specified as 0, uses 1.
|
||||
if (tess_u < 1) tess_u = 1;
|
||||
if (tess_v < 1) tess_v = 1;
|
||||
|
||||
switch (g_Config.iSplineBezierQuality) {
|
||||
case LOW_QUALITY:
|
||||
tess_u = 2;
|
||||
|
@ -74,93 +73,77 @@ struct BezierPatch {
|
|||
// Don't cut below 2, though.
|
||||
if (tess_u > 2) tess_u = HALF_CEIL(tess_u);
|
||||
if (tess_v > 2) tess_v = HALF_CEIL(tess_v);
|
||||
// Pass through
|
||||
case HIGH_QUALITY:
|
||||
// Downsample until it fits, in case crazy tessellation factors are sent.
|
||||
while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) {
|
||||
tess_u--;
|
||||
tess_v--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct BezierSurface : public SurfaceInfo {
|
||||
using WeightType = Bezier3DWeight;
|
||||
|
||||
int num_verts_per_patch;
|
||||
|
||||
void Init(int maxVertices) {
|
||||
SurfaceInfo::Init();
|
||||
// Downsample until it fits, in case crazy tessellation factors are sent.
|
||||
while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) {
|
||||
tess_u--;
|
||||
tess_v--;
|
||||
}
|
||||
num_verts_per_patch = (tess_u + 1) * (tess_v + 1);
|
||||
}
|
||||
|
||||
int GetTessStart(int patch) const { return 0; }
|
||||
|
||||
int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * count_u + patch_u * 3;}
|
||||
int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * num_points_u + patch_u * 3; }
|
||||
|
||||
int GetIndexU(int patch_u, int tile_u) const { return tile_u; }
|
||||
int GetIndexV(int patch_v, int tile_v) const { return tile_v; }
|
||||
|
||||
int GetPatchIndex(int patch_u, int patch_v) const { return patch_v * num_patches_u + patch_u;}
|
||||
int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const {
|
||||
return index_v * (tess_u + 1) + index_u + (tess_u + 1) * (tess_v + 1) * GetPatchIndex(patch_u, patch_v);
|
||||
int patch_index = patch_v * num_patches_u + patch_u;
|
||||
return index_v * (tess_u + 1) + index_u + num_verts_per_patch * patch_index;
|
||||
}
|
||||
|
||||
void BuildIndex(u16 *indices, int &count) const {
|
||||
for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) {
|
||||
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 * (tess_u + 1) * (tess_v + 1);
|
||||
int total = patch_index * num_verts_per_patch;
|
||||
::BuildIndex(indices + count, count, tess_u, tess_v, primType, total);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct SplinePatchLocal {
|
||||
struct SplineSurface : public SurfaceInfo {
|
||||
using WeightType = Spline3DWeight;
|
||||
|
||||
int tess_u;
|
||||
int tess_v;
|
||||
int count_u;
|
||||
int count_v;
|
||||
int type_u;
|
||||
int type_v;
|
||||
int num_patches_u;
|
||||
int num_patches_v;
|
||||
int num_divisions_u;
|
||||
int num_divisions_v;
|
||||
bool patchFacing;
|
||||
GEPatchPrimType primType;
|
||||
int num_vertices_u;
|
||||
|
||||
void Init(int maxVertices) {
|
||||
switch (g_Config.iSplineBezierQuality) {
|
||||
case LOW_QUALITY:
|
||||
tess_u = 2;
|
||||
tess_v = 2;
|
||||
break;
|
||||
case MEDIUM_QUALITY:
|
||||
// Don't cut below 2, though.
|
||||
if (tess_u > 2) tess_u = HALF_CEIL(tess_u);
|
||||
if (tess_v > 2) tess_v = HALF_CEIL(tess_v);
|
||||
// Pass through
|
||||
case HIGH_QUALITY:
|
||||
// Downsample until it fits, in case crazy tessellation factors are sent.
|
||||
while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) {
|
||||
tess_u--;
|
||||
tess_v--;
|
||||
}
|
||||
break;
|
||||
SurfaceInfo::Init();
|
||||
// Downsample until it fits, in case crazy tessellation factors are sent.
|
||||
while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) {
|
||||
tess_u--;
|
||||
tess_v--;
|
||||
}
|
||||
|
||||
num_divisions_u = num_patches_u * tess_u;
|
||||
num_divisions_v = num_patches_v * tess_v;
|
||||
num_vertices_u = num_patches_u * tess_u + 1;
|
||||
}
|
||||
|
||||
int GetTessStart(int patch) const { return (patch == 0) ? 0 : 1; }
|
||||
|
||||
int GetPointIndex(int patch_u, int patch_v) const { return patch_v * count_u + patch_u;}
|
||||
int GetPointIndex(int patch_u, int patch_v) const { return patch_v * num_points_u + patch_u; }
|
||||
|
||||
int GetIndexU(int patch_u, int tile_u) const { return patch_u * tess_u + tile_u; }
|
||||
int GetIndexV(int patch_v, int tile_v) const { return patch_v * tess_v + tile_v; }
|
||||
|
||||
int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const {
|
||||
return index_v * (num_divisions_u + 1) + index_u;
|
||||
return index_v * num_vertices_u + index_u;
|
||||
}
|
||||
|
||||
void BuildIndex(u16 *indices, int &count) const {
|
||||
::BuildIndex(indices, count, num_divisions_u, num_divisions_v, primType);
|
||||
::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -171,45 +171,39 @@ static void ExpandBezier(int &count, int op, const std::vector<SimpleVertex> &si
|
|||
if (count_u < 4 || count_v < 4)
|
||||
return;
|
||||
|
||||
int tess_u = gstate.getPatchDivisionU();
|
||||
int tess_v = gstate.getPatchDivisionV();
|
||||
// If specified as 0, uses 1.
|
||||
if (tess_u < 1) tess_u = 1;
|
||||
if (tess_v < 1) tess_v = 1;
|
||||
|
||||
BezierPatch patch;
|
||||
patch.count_u = count_u;
|
||||
patch.count_v = count_v;
|
||||
patch.tess_u = tess_u;
|
||||
patch.tess_v = tess_v;
|
||||
patch.num_patches_u = (count_u - 1) / 3;
|
||||
patch.num_patches_v = (count_v - 1) / 3;
|
||||
patch.primType = gstate.getPatchPrimitiveType();
|
||||
patch.patchFacing = false;
|
||||
BezierSurface surface;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.tess_u = gstate.getPatchDivisionU();
|
||||
surface.tess_v = gstate.getPatchDivisionV();
|
||||
surface.num_patches_u = (count_u - 1) / 3;
|
||||
surface.num_patches_v = (count_v - 1) / 3;
|
||||
surface.primType = gstate.getPatchPrimitiveType();
|
||||
surface.patchFacing = false;
|
||||
|
||||
int size = count_u * count_v;
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
std::vector<const SimpleVertex *> points(count_u * count_v);
|
||||
for (int idx = 0; idx < count_u * count_v; idx++)
|
||||
std::vector<const SimpleVertex *> points(size);
|
||||
for (int idx = 0; idx < size; idx++)
|
||||
points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx);
|
||||
|
||||
int total_patches = patch.num_patches_u * patch.num_patches_v;
|
||||
generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches);
|
||||
generatedInds.resize(tess_u * tess_v * 6 * total_patches);
|
||||
int total_patches = surface.num_patches_u * surface.num_patches_v;
|
||||
generatedVerts.resize((surface.tess_u + 1) * (surface.tess_v + 1) * total_patches);
|
||||
generatedInds.resize(surface.tess_u * surface.tess_v * 6 * total_patches);
|
||||
|
||||
OutputBuffers output;
|
||||
output.vertices = generatedVerts.data();
|
||||
output.indices = generatedInds.data();
|
||||
output.count = 0;
|
||||
|
||||
int size = count_u * count_v;
|
||||
ControlPoints cpoints;
|
||||
cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16);
|
||||
cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16);
|
||||
cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16);
|
||||
cpoints.Convert(points.data(), size);
|
||||
|
||||
patch.Init(generatedVerts.size());
|
||||
SoftwareTessellation(output, patch, gstate.vertType, cpoints);
|
||||
surface.Init(generatedVerts.size());
|
||||
SoftwareTessellation(output, surface, gstate.vertType, cpoints);
|
||||
count = output.count;
|
||||
|
||||
FreeAlignedMemory(cpoints.pos);
|
||||
|
@ -224,31 +218,26 @@ static void ExpandSpline(int &count, int op, const std::vector<SimpleVertex> &si
|
|||
if (count_u < 4 || count_v < 4)
|
||||
return;
|
||||
|
||||
int tess_u = gstate.getPatchDivisionU();
|
||||
int tess_v = gstate.getPatchDivisionV();
|
||||
// If specified as 0, uses 1.
|
||||
if (tess_u < 1) tess_u = 1;
|
||||
if (tess_v < 1) tess_v = 1;
|
||||
|
||||
SplinePatchLocal patch;
|
||||
patch.count_u = count_u;
|
||||
patch.count_v = count_v;
|
||||
patch.tess_u = tess_u;
|
||||
patch.tess_v = tess_v;
|
||||
patch.type_u = (op >> 16) & 0x3;
|
||||
patch.type_v = (op >> 18) & 0x3;
|
||||
patch.num_patches_u = count_u - 3;
|
||||
patch.num_patches_v = count_v - 3;
|
||||
patch.primType = gstate.getPatchPrimitiveType();
|
||||
patch.patchFacing = false;
|
||||
SplineSurface surface;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.tess_u = gstate.getPatchDivisionU();
|
||||
surface.tess_v = gstate.getPatchDivisionV();
|
||||
surface.type_u = (op >> 16) & 0x3;
|
||||
surface.type_v = (op >> 18) & 0x3;
|
||||
surface.num_patches_u = count_u - 3;
|
||||
surface.num_patches_v = count_v - 3;
|
||||
surface.primType = gstate.getPatchPrimitiveType();
|
||||
surface.patchFacing = false;
|
||||
|
||||
int size = count_u * count_v;
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
std::vector<const SimpleVertex *> points(count_u * count_v);
|
||||
for (int idx = 0; idx < count_u * count_v; idx++)
|
||||
std::vector<const SimpleVertex *> points(size);
|
||||
for (int idx = 0; idx < size; idx++)
|
||||
points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx);
|
||||
|
||||
int patch_div_s = patch.num_patches_u * patch.tess_u;
|
||||
int patch_div_t = patch.num_patches_v * patch.tess_v;
|
||||
int patch_div_s = surface.num_patches_u * surface.tess_u;
|
||||
int patch_div_t = surface.num_patches_v * surface.tess_v;
|
||||
generatedVerts.resize((patch_div_s + 1) * (patch_div_t + 1));
|
||||
generatedInds.resize(patch_div_s * patch_div_t * 6);
|
||||
|
||||
|
@ -257,15 +246,14 @@ static void ExpandSpline(int &count, int op, const std::vector<SimpleVertex> &si
|
|||
output.indices = generatedInds.data();
|
||||
output.count = 0;
|
||||
|
||||
int size = count_u * count_v;
|
||||
ControlPoints cpoints;
|
||||
cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16);
|
||||
cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16);
|
||||
cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16);
|
||||
cpoints.Convert(points.data(), size);
|
||||
|
||||
patch.Init(generatedVerts.size());
|
||||
SoftwareTessellation(output, patch, gstate.vertType, cpoints);
|
||||
surface.Init(generatedVerts.size());
|
||||
SoftwareTessellation(output, surface, gstate.vertType, cpoints);
|
||||
count = output.count;
|
||||
|
||||
FreeAlignedMemory(cpoints.pos);
|
||||
|
|
Loading…
Add table
Reference in a new issue