153 lines
4.5 KiB
C
153 lines
4.5 KiB
C
|
//=======================================================================
|
|||
|
// Copyright XashXT Group 2009 <20>
|
|||
|
// patch.c - generate bezier curves
|
|||
|
//=======================================================================
|
|||
|
|
|||
|
#include "launch.h"
|
|||
|
#include "mathlib.h"
|
|||
|
|
|||
|
/*
|
|||
|
===============
|
|||
|
Patch_FlatnessTest
|
|||
|
===============
|
|||
|
*/
|
|||
|
static int Patch_FlatnessTest( float maxflat2, const float *point0, const float *point1, const float *point2 )
|
|||
|
{
|
|||
|
float d;
|
|||
|
int ft0, ft1;
|
|||
|
vec3_t t, n;
|
|||
|
vec3_t v1, v2, v3;
|
|||
|
|
|||
|
VectorSubtract( point2, point0, n );
|
|||
|
if( !VectorNormalizeLength( n ))
|
|||
|
return 0;
|
|||
|
|
|||
|
VectorSubtract( point1, point0, t );
|
|||
|
d = -DotProduct( t, n );
|
|||
|
VectorMA( t, d, n, t );
|
|||
|
if( DotProduct( t, t ) < maxflat2 )
|
|||
|
return 0;
|
|||
|
|
|||
|
VectorAverage( point1, point0, v1 );
|
|||
|
VectorAverage( point2, point1, v2 );
|
|||
|
VectorAverage( v1, v2, v3 );
|
|||
|
|
|||
|
ft0 = Patch_FlatnessTest( maxflat2, point0, v1, v3 );
|
|||
|
ft1 = Patch_FlatnessTest( maxflat2, v3, v2, point2 );
|
|||
|
|
|||
|
return 1 + (int)( floor( max( ft0, ft1 )) + 0.5f );
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
===============
|
|||
|
Patch_GetFlatness
|
|||
|
===============
|
|||
|
*/
|
|||
|
void Patch_GetFlatness( float maxflat, const float *points, int comp, const int *patch_cp, int *flat )
|
|||
|
{
|
|||
|
int i, p, u, v;
|
|||
|
float maxflat2 = maxflat * maxflat;
|
|||
|
|
|||
|
flat[0] = flat[1] = 0;
|
|||
|
for( v = 0; v < patch_cp[1] - 1; v += 2 )
|
|||
|
{
|
|||
|
for( u = 0; u < patch_cp[0] - 1; u += 2 )
|
|||
|
{
|
|||
|
p = v * patch_cp[0] + u;
|
|||
|
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[p*comp], &points[(p+1)*comp], &points[(p+2)*comp] );
|
|||
|
flat[0] = max( flat[0], i );
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[(p+patch_cp[0])*comp], &points[(p+patch_cp[0]+1)*comp], &points[(p+patch_cp[0]+2)*comp] );
|
|||
|
flat[0] = max( flat[0], i );
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[(p+2*patch_cp[0])*comp], &points[(p+2*patch_cp[0]+1)*comp], &points[(p+2*patch_cp[0]+2)*comp] );
|
|||
|
flat[0] = max( flat[0], i );
|
|||
|
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[p*comp], &points[(p+patch_cp[0])*comp], &points[(p+2*patch_cp[0])*comp] );
|
|||
|
flat[1] = max( flat[1], i );
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[(p+1)*comp], &points[(p+patch_cp[0]+1)*comp], &points[(p+2*patch_cp[0]+1)*comp] );
|
|||
|
flat[1] = max( flat[1], i );
|
|||
|
i = Patch_FlatnessTest( maxflat2, &points[(p+2)*comp], &points[(p+patch_cp[0]+2)*comp], &points[(p+2*patch_cp[0]+2)*comp] );
|
|||
|
flat[1] = max( flat[1], i );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
===============
|
|||
|
Patch_Evaluate_QuadricBezier
|
|||
|
===============
|
|||
|
*/
|
|||
|
static void Patch_Evaluate_QuadricBezier( float t, const float *point0, const float *point1, const float *point2, float *out, int comp )
|
|||
|
{
|
|||
|
int i;
|
|||
|
float qt = t * t;
|
|||
|
float dt = 2.0f * t, tt, tt2;
|
|||
|
|
|||
|
tt = 1.0f - dt + qt;
|
|||
|
tt2 = dt - 2.0f * qt;
|
|||
|
|
|||
|
for( i = 0; i < comp; i++ )
|
|||
|
out[i] = point0[i] * tt + point1[i] * tt2 + point2[i] * qt;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
===============
|
|||
|
Patch_Evaluate
|
|||
|
===============
|
|||
|
*/
|
|||
|
void Patch_Evaluate( const float *p, int *numcp, const int *tess, float *dest, int comp )
|
|||
|
{
|
|||
|
int num_patches[2], num_tess[2];
|
|||
|
int index[3], dstpitch, i, u, v, x, y;
|
|||
|
float s, t, step[2];
|
|||
|
float *tvec, *tvec2;
|
|||
|
const float *pv[3][3];
|
|||
|
vec4_t v1, v2, v3;
|
|||
|
|
|||
|
num_patches[0] = numcp[0] / 2;
|
|||
|
num_patches[1] = numcp[1] / 2;
|
|||
|
dstpitch = (num_patches[0] * tess[0] + 1) * comp;
|
|||
|
|
|||
|
step[0] = 1.0f / (float)tess[0];
|
|||
|
step[1] = 1.0f / (float)tess[1];
|
|||
|
|
|||
|
for( v = 0; v < num_patches[1]; v++ )
|
|||
|
{
|
|||
|
// last patch has one more row
|
|||
|
if( v < num_patches[1] - 1 )
|
|||
|
num_tess[1] = tess[1];
|
|||
|
else num_tess[1] = tess[1] + 1;
|
|||
|
|
|||
|
for( u = 0; u < num_patches[0]; u++ )
|
|||
|
{
|
|||
|
// last patch has one more column
|
|||
|
if( u < num_patches[0] - 1 )
|
|||
|
num_tess[0] = tess[0];
|
|||
|
else num_tess[0] = tess[0] + 1;
|
|||
|
|
|||
|
index[0] = (v * numcp[0] + u) * 2;
|
|||
|
index[1] = index[0] + numcp[0];
|
|||
|
index[2] = index[1] + numcp[0];
|
|||
|
|
|||
|
// current 3x3 patch control points
|
|||
|
for( i = 0; i < 3; i++ )
|
|||
|
{
|
|||
|
pv[i][0] = &p[(index[0]+i) * comp];
|
|||
|
pv[i][1] = &p[(index[1]+i) * comp];
|
|||
|
pv[i][2] = &p[(index[2]+i) * comp];
|
|||
|
}
|
|||
|
|
|||
|
tvec = dest + v * tess[1] * dstpitch + u * tess[0] * comp;
|
|||
|
for( y = 0, t = 0.0f; y < num_tess[1]; y++, t += step[1], tvec += dstpitch )
|
|||
|
{
|
|||
|
Patch_Evaluate_QuadricBezier( t, pv[0][0], pv[0][1], pv[0][2], v1, comp );
|
|||
|
Patch_Evaluate_QuadricBezier( t, pv[1][0], pv[1][1], pv[1][2], v2, comp );
|
|||
|
Patch_Evaluate_QuadricBezier( t, pv[2][0], pv[2][1], pv[2][2], v3, comp );
|
|||
|
|
|||
|
for( x = 0, tvec2 = tvec, s = 0.0f; x < num_tess[0]; x++, s += step[0], tvec2 += comp )
|
|||
|
Patch_Evaluate_QuadricBezier( s, v1, v2, v3, tvec2, comp );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|