Skip to content

Commit

Permalink
[spline/bezier]Use real tessellation in low-quality with "fixed to 2"…
Browse files Browse the repository at this point in the history
… tessellation factor.

# Conflicts:
#	GPU/Common/SplineCommon.cpp
  • Loading branch information
xebra committed Oct 7, 2018
1 parent 36ed61d commit c8e45ae
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 152 deletions.
163 changes: 11 additions & 152 deletions GPU/Common/SplineCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,6 @@ inline __m128 SSENormalizeMultiplier(bool useSSE4, __m128 v)

#endif


#define START_OPEN 1
#define END_OPEN 2



static void CopyQuad(u8 *&dest, const SimpleVertex *v1, const SimpleVertex *v2, const SimpleVertex *v3, const SimpleVertex *v4) {
int vertexSize = sizeof(SimpleVertex);
memcpy(dest, v1, vertexSize);
dest += vertexSize;
memcpy(dest, v2, vertexSize);
dest += vertexSize;
memcpy(dest, v3, vertexSize);
dest += vertexSize;
memcpy(dest, v4, vertexSize);
dest += vertexSize;
}

static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) {
if (type == GE_PATCHPRIM_LINES) {
*(indices++) = idx0;
Expand Down Expand Up @@ -243,6 +225,7 @@ static void spline_knot(int n, int type, float *knots, KnotDiv *divs) {
knots[i] = (float)i - 2;
}

// The first edge is open
if ((type & 1) != 0) {
knots[0] = 0;
knots[1] = 0;
Expand All @@ -253,6 +236,7 @@ static void spline_knot(int n, int type, float *knots, KnotDiv *divs) {
if (n > 1)
divs[1]._3_0 = 1.0f / 2.0f;
}
// The last edge is open
if ((type & 2) != 0) {
// knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv
// knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv
Expand Down Expand Up @@ -296,76 +280,6 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c
BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType);
}

static void _SplinePatchLowQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType) {
// Fast and easy way - just draw the control points, generate some very basic normal vector substitutes.
// Very inaccurate but okay for Loco Roco. Maybe should keep it as an option because it's fast.

const int tile_min_u = (spatch.type_u & START_OPEN) ? 0 : 1;
const int tile_min_v = (spatch.type_v & START_OPEN) ? 0 : 1;
const int tile_max_u = (spatch.type_u & END_OPEN) ? spatch.count_u - 1 : spatch.count_u - 2;
const int tile_max_v = (spatch.type_v & END_OPEN) ? spatch.count_v - 1 : spatch.count_v - 2;

float tu_width = (float)spatch.count_u - 3.0f;
float tv_height = (float)spatch.count_v - 3.0f;
tu_width /= (float)(tile_max_u - tile_min_u);
tv_height /= (float)(tile_max_v - tile_min_v);

GEPatchPrimType prim_type = spatch.primType;
bool computeNormals = spatch.computeNormals;
bool patchFacing = spatch.patchFacing;

int i = 0;
for (int tile_v = tile_min_v; tile_v < tile_max_v; ++tile_v) {
for (int tile_u = tile_min_u; tile_u < tile_max_u; ++tile_u) {
int point_index = tile_u + tile_v * spatch.count_u;

SimpleVertex v0 = *spatch.points[point_index];
SimpleVertex v1 = *spatch.points[point_index + 1];
SimpleVertex v2 = *spatch.points[point_index + spatch.count_u];
SimpleVertex v3 = *spatch.points[point_index + spatch.count_u + 1];

// Generate UV. TODO: Do this even if UV specified in control points?
if ((origVertType & GE_VTYPE_TC_MASK) == 0) {
float u = (tile_u - tile_min_u) * tu_width;
float v = (tile_v - tile_min_v) * tv_height;

v0.uv[0] = u;
v0.uv[1] = v;
v1.uv[0] = u + tu_width;
v1.uv[1] = v;
v2.uv[0] = u;
v2.uv[1] = v + tv_height;
v3.uv[0] = u + tu_width;
v3.uv[1] = v + tv_height;
}

// Generate normal if lighting is enabled (otherwise there's no point).
// This is a really poor quality algorithm, we get facet normals.
if (computeNormals) {
Vec3Packedf norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos);
norm.Normalize();
if (patchFacing)
norm *= -1.0f;
v0.nrm = norm;
v1.nrm = norm;
v2.nrm = norm;
v3.nrm = norm;
}

int idx0 = i * 4 + 0;
int idx1 = i * 4 + 1;
int idx2 = i * 4 + 2;
int idx3 = i * 4 + 3;
i++;

CopyQuad(dest, &v0, &v1, &v2, &v3);
CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3);
count += 6;
}
}

}

static inline void AccumulateWeighted(Vec3f &out, const Vec3f &in, const Vec4f &w) {
#ifdef _M_SSE
out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec));
Expand Down Expand Up @@ -405,6 +319,11 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp
// Increase tessellation based on the size. Should be approximately right?
int patch_div_s = (spatch.count_u - 3) * spatch.tess_u;
int patch_div_t = (spatch.count_v - 3) * spatch.tess_v;
if (quality == 0) {
// Low quality
patch_div_s = (spatch.count_u - 3) * 2;
patch_div_t = (spatch.count_v - 3) * 2;
}
if (quality > 1) {
// Don't cut below 2, though.
if (patch_div_s > 2) {
Expand Down Expand Up @@ -460,7 +379,7 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp
if (origCol) {
vert_color.SetZero();
} else {
memcpy(vert->color, spatch.points[0]->color, 4);
vert->color_32 = spatch.defcolor;
}
if (origTc) {
vert_tex.SetZero();
Expand Down Expand Up @@ -596,7 +515,7 @@ static void SplinePatchFullQualityDispatch(u8 *&dest, u16 *indices, int &count,
void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertexCount) {
switch (g_Config.iSplineBezierQuality) {
case LOW_QUALITY:
_SplinePatchLowQuality(dest, indices, count, spatch, origVertType);
SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 0, maxVertexCount);
break;
case MEDIUM_QUALITY:
SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 2, maxVertexCount);
Expand All @@ -607,66 +526,6 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc
}
}

static void _BezierPatchLowQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) {
const float third = 1.0f / 3.0f;
// Fast and easy way - just draw the control points, generate some very basic normal vector subsitutes.
// Very inaccurate though but okay for Loco Roco. Maybe should keep it as an option.

float u_base = patch.u_index / 3.0f;
float v_base = patch.v_index / 3.0f;

GEPatchPrimType prim_type = patch.primType;

for (int tile_v = 0; tile_v < 3; tile_v++) {
for (int tile_u = 0; tile_u < 3; tile_u++) {
int point_index = tile_u + tile_v * 4;

SimpleVertex v0 = *patch.points[point_index];
SimpleVertex v1 = *patch.points[point_index + 1];
SimpleVertex v2 = *patch.points[point_index + 4];
SimpleVertex v3 = *patch.points[point_index + 5];

// Generate UV. TODO: Do this even if UV specified in control points?
if ((origVertType & GE_VTYPE_TC_MASK) == 0) {
float u = u_base + tile_u * third;
float v = v_base + tile_v * third;
v0.uv[0] = u;
v0.uv[1] = v;
v1.uv[0] = u + third;
v1.uv[1] = v;
v2.uv[0] = u;
v2.uv[1] = v + third;
v3.uv[0] = u + third;
v3.uv[1] = v + third;
}

// Generate normal if lighting is enabled (otherwise there's no point).
// This is a really poor quality algorithm, we get facet normals.
if (patch.computeNormals) {
Vec3Packedf norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos);
norm.Normalize();
if (patch.patchFacing)
norm *= -1.0f;
v0.nrm = norm;
v1.nrm = norm;
v2.nrm = norm;
v3.nrm = norm;
}

int total = patch.index * 3 * 3 * 4; // A patch has 3x3 tiles, and each tiles have 4 vertices.
int tile_index = tile_u + tile_v * 3;
int idx0 = total + tile_index * 4 + 0;
int idx1 = total + tile_index * 4 + 1;
int idx2 = total + tile_index * 4 + 2;
int idx3 = total + tile_index * 4 + 3;

CopyQuad(dest, &v0, &v1, &v2, &v3);
CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3);
count += 6;
}
}
}

template <typename T>
struct PrecomputedCurves {
PrecomputedCurves(int count) {
Expand Down Expand Up @@ -818,7 +677,7 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i
void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) {
switch (g_Config.iSplineBezierQuality) {
case LOW_QUALITY:
_BezierPatchLowQuality(dest, indices, count, tess_u, tess_v, patch, origVertType);
_BezierPatchHighQuality(dest, indices, count, 2, 2, patch, origVertType);
break;
case MEDIUM_QUALITY:
_BezierPatchHighQuality(dest, indices, count, std::max(tess_u / 2, 1), std::max(tess_v / 2, 1), patch, origVertType);
Expand Down Expand Up @@ -917,10 +776,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
patch.type_v = type_v;
patch.count_u = count_u;
patch.count_v = count_v;
patch.points = points;
patch.computeNormals = computeNormals;
patch.primType = prim_type;
patch.patchFacing = patchFacing;
patch.defcolor = points[0]->color_32;

if (CanUseHardwareTessellation(prim_type)) {
tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType);
Expand Down
1 change: 1 addition & 0 deletions GPU/Common/SplineCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct SplinePatchLocal {
Vec3f *pos;
Vec4f *col;
Vec2f *tex;
u32_le defcolor;
int tess_u;
int tess_v;
int count_u;
Expand Down

0 comments on commit c8e45ae

Please sign in to comment.