//======================================================================= // Copyright XashXT Group 2010 © // gl_rsurf.c - surface-related refresh code //======================================================================= #include "common.h" #include "client.h" #include "gl_local.h" #include "cm_local.h" #define LIGHTMAP_BYTES 4 #define BLOCK_WIDTH 128 #define BLOCK_HEIGHT 128 #define MAX_LIGHTMAPS 128 #define SUBDIVIDE_SIZE 64 //#define SUBDIVIDE_SIZE 1024 byte *Mod_GetCurrentVis( void ) { // return Mod_LeafPVS( r_viewleaf, r_worldmodel ); return NULL; } static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs ) { int i, j; float *v; mins[0] = mins[1] = mins[2] = 9999; maxs[0] = maxs[1] = maxs[2] = -9999; 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 ) { int i, j, k, f, b; vec3_t mins, maxs; float m, frac, s, t, *v; vec3_t front[SUBDIVIDE_SIZE], back[SUBDIVIDE_SIZE], total; float dist[SUBDIVIDE_SIZE], total_s, total_t; glpoly_t *poly; if( numverts > ( SUBDIVIDE_SIZE - 4 )) Host_Error( "Mod_SubdividePolygon: too many vertexes on face ( %i )\n", numverts ); 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; } // add a point in the center to help keep warp valid poly = Mem_Alloc( loadmodel->mempool, sizeof( glpoly_t ) + ((numverts-4)+2) * VERTEXSIZE * sizeof( float )); poly->next = warpface->polys; warpface->polys = poly; poly->numverts = numverts + 2; VectorClear( total ); total_s = 0; total_t = 0; for( i = 0; i < numverts; i++, verts += 3 ) { VectorCopy( verts, poly->verts[i+1] ); s = DotProduct( verts, warpface->texinfo->vecs[0] ); t = DotProduct( verts, warpface->texinfo->vecs[1] ); total_s += s; total_t += t; VectorAdd( total, verts, total ); poly->verts[i+1][3] = s; poly->verts[i+1][4] = t; } VectorScale( total, ( 1.0f / numverts ), poly->verts[0] ); poly->verts[0][3] = total_s / numverts; poly->verts[0][4] = total_t / numverts; // copy first vertex to last Mem_Copy( poly->verts[i+1], poly->verts[1], sizeof( poly->verts[0] )); } /* ================ 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; // 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++; } // do subdivide SubdividePolygon_r( fa, numverts, verts[0] ); } /* ================ GL_BuildPolygonFromSurface ================ */ void GL_BuildPolygonFromSurface( msurface_t *fa ) { int i, lindex, lnumverts; medge_t *pedges, *r_pedge; int vertpage; float *vec; float s, t; glpoly_t *poly; vec3_t total; // reconstruct the polygon pedges = loadmodel->edges; lnumverts = fa->numedges; vertpage = 0; VectorClear( total ); // draw texture poly = Mem_Alloc( loadmodel->mempool, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float )); poly->next = fa->polys; poly->flags = fa->flags; fa->polys = poly; poly->numverts = lnumverts; for( i = 0; i < lnumverts; i++ ) { lindex = loadmodel->surfedges[fa->firstedge + i]; if( lindex > 0 ) { r_pedge = &pedges[lindex]; vec = loadmodel->vertexes[r_pedge->v[0]].position; } else { r_pedge = &pedges[-lindex]; vec = loadmodel->vertexes[r_pedge->v[1]].position; } s = DotProduct( vec, fa->texinfo->vecs[0] ) + fa->texinfo->vecs[0][3]; s /= fa->texinfo->texture->width; t = DotProduct( vec, fa->texinfo->vecs[1] ) + fa->texinfo->vecs[1][3]; t /= fa->texinfo->texture->height; VectorAdd( total, vec, total ); VectorCopy( vec, poly->verts[i] ); poly->verts[i][3] = s; poly->verts[i][4] = t; // lightmap texture coordinates s = DotProduct( vec, fa->texinfo->vecs[0] ) + fa->texinfo->vecs[0][3]; s -= fa->texturemins[0]; s += fa->light_s * 16; s += 8; s /= BLOCK_WIDTH * 16; //fa->texinfo->texture->width; t = DotProduct( vec, fa->texinfo->vecs[1] ) + fa->texinfo->vecs[1][3]; t -= fa->texturemins[1]; t += fa->light_t * 16; t += 8; t /= BLOCK_HEIGHT * 16; //fa->texinfo->texture->height; poly->verts[i][5] = s; poly->verts[i][6] = t; } poly->numverts = lnumverts; }