#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] ); }