This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/launch/patch.c

153 lines
4.5 KiB
C

//=======================================================================
// Copyright XashXT Group 2009 ©
// 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 );
}
}
}
}