xash3d-fwgs/ref/vk/common_geometry.c
2023-02-16 10:30:31 -08:00

190 lines
4.7 KiB
C

#include "vk_common.h"
#include "xash3d_types.h"
#include "const.h"
#include "com_model.h"
#include "xash3d_mathlib.h"
#include "mod_local.h"
#define SUBDIVIDE_SIZE 64
// FIXME this is defined dynamically based on if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_LARGE_LIGHTMAPS ))
// tr.block_size = BLOCK_SIZE_MAX; else tr.block_size = BLOCK_SIZE_DEFAULT;
#define BLOCK_SIZE BLOCK_SIZE_DEFAULT
#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility
#define BLOCK_SIZE_MAX 1024
static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs )
{
int i, j;
float *v;
ClearBounds( mins, maxs );
for( i = 0, v = verts; i < numverts; i++ )
{
for( j = 0; j < 3; j++, v++ )
{
if( *v < mins[j] ) mins[j] = *v;
if( *v > maxs[j] ) maxs[j] = *v;
}
}
}
static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts )
{
vec3_t front[SUBDIVIDE_SIZE], back[SUBDIVIDE_SIZE];
mextrasurf_t *warpinfo = warpface->info;
float dist[SUBDIVIDE_SIZE];
float m, frac, s, t, *v;
int i, j, k, f, b;
float sample_size;
vec3_t mins, maxs;
glpoly_t *poly;
model_t *loadmodel = gEngine.Mod_GetCurrentLoadingModel();
if( numverts > ( SUBDIVIDE_SIZE - 4 ))
gEngine.Host_Error( "Mod_SubdividePolygon: too many vertexes on face ( %i )\n", numverts );
sample_size = gEngine.Mod_SampleSizeForFace( warpface );
BoundPoly( numverts, verts, mins, maxs );
for( i = 0; i < 3; i++ )
{
m = ( mins[i] + maxs[i] ) * 0.5f;
m = SUBDIVIDE_SIZE * floor( m / SUBDIVIDE_SIZE + 0.5f );
if( maxs[i] - m < 8 ) continue;
if( m - mins[i] < 8 ) continue;
// cut it
v = verts + i;
for( j = 0; j < numverts; j++, v += 3 )
dist[j] = *v - m;
// wrap cases
dist[j] = dist[0];
v -= i;
VectorCopy( verts, v );
f = b = 0;
v = verts;
for( j = 0; j < numverts; j++, v += 3 )
{
if( dist[j] >= 0 )
{
VectorCopy( v, front[f] );
f++;
}
if( dist[j] <= 0 )
{
VectorCopy (v, back[b]);
b++;
}
if( dist[j] == 0 || dist[j+1] == 0 )
continue;
if(( dist[j] > 0 ) != ( dist[j+1] > 0 ))
{
// clip point
frac = dist[j] / ( dist[j] - dist[j+1] );
for( k = 0; k < 3; k++ )
front[f][k] = back[b][k] = v[k] + frac * (v[3+k] - v[k]);
f++;
b++;
}
}
SubdividePolygon_r( warpface, f, front[0] );
SubdividePolygon_r( warpface, b, back[0] );
return;
}
if( numverts != 4 )
ClearBits( warpface->flags, SURF_DRAWTURB_QUADS );
// add a point in the center to help keep warp valid
poly = Mem_Calloc( loadmodel->mempool, sizeof( glpoly_t ) + (numverts - 4) * VERTEXSIZE * sizeof( float ));
poly->next = warpface->polys;
poly->flags = warpface->flags;
warpface->polys = poly;
poly->numverts = numverts;
for( i = 0; i < numverts; i++, verts += 3 )
{
VectorCopy( verts, poly->verts[i] );
if( FBitSet( warpface->flags, SURF_DRAWTURB ))
{
s = DotProduct( verts, warpface->texinfo->vecs[0] );
t = DotProduct( verts, warpface->texinfo->vecs[1] );
}
else
{
s = DotProduct( verts, warpface->texinfo->vecs[0] ) + warpface->texinfo->vecs[0][3];
t = DotProduct( verts, warpface->texinfo->vecs[1] ) + warpface->texinfo->vecs[1][3];
s /= warpface->texinfo->texture->width;
t /= warpface->texinfo->texture->height;
}
poly->verts[i][3] = s;
poly->verts[i][4] = t;
// for speed reasons
if( !FBitSet( warpface->flags, SURF_DRAWTURB ))
{
// lightmap texture coordinates
s = DotProduct( verts, warpinfo->lmvecs[0] ) + warpinfo->lmvecs[0][3];
s -= warpinfo->lightmapmins[0];
s += warpface->light_s * sample_size;
s += sample_size * 0.5f;
s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
t = DotProduct( verts, warpinfo->lmvecs[1] ) + warpinfo->lmvecs[1][3];
t -= warpinfo->lightmapmins[1];
t += warpface->light_t * sample_size;
t += sample_size * 0.5f;
t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
poly->verts[i][5] = s;
poly->verts[i][6] = t;
}
}
}
/*
================
GL_SubdivideSurface
Breaks a polygon up along axial 64 unit
boundaries so that turbulent and sky warps
can be done reasonably.
================
*/
void GL_SubdivideSurface( msurface_t *fa )
{
vec3_t verts[SUBDIVIDE_SIZE];
int numverts;
int i, lindex;
float *vec;
model_t *loadmodel = gEngine.Mod_GetCurrentLoadingModel();
// convert edges back to a normal polygon
numverts = 0;
for( i = 0; i < fa->numedges; i++ )
{
lindex = loadmodel->surfedges[fa->firstedge + i];
if( lindex > 0 ) vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
else vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
VectorCopy( vec, verts[numverts] );
numverts++;
}
SetBits( fa->flags, SURF_DRAWTURB_QUADS ); // predict state
// do subdivide
SubdividePolygon_r( fa, numverts, verts[0] );
}