1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
43 ydnar: gs mods: changed to force an explicit type when allocating
46 mapDrawSurface_t *AllocDrawSurface( surfaceType_t type ){
50 /* ydnar: gs mods: only allocate valid types */
51 if ( type <= SURFACE_BAD || type >= NUM_SURFACE_TYPES ) {
52 Error( "AllocDrawSurface: Invalid surface type %d specified", type );
56 if ( numMapDrawSurfs >= MAX_MAP_DRAW_SURFS ) {
57 Error( "MAX_MAP_DRAW_SURFS (%d) exceeded", MAX_MAP_DRAW_SURFS );
59 ds = &mapDrawSurfs[ numMapDrawSurfs ];
62 /* ydnar: do initial surface setup */
63 memset( ds, 0, sizeof( mapDrawSurface_t ) );
66 ds->fogNum = defaultFogNum; /* ydnar 2003-02-12 */
67 ds->outputNum = -1; /* ydnar 2002-08-13 */
68 ds->surfaceNum = numMapDrawSurfs - 1; /* ydnar 2003-02-16 */
77 ydnar: general surface finish pass
80 void FinishSurface( mapDrawSurface_t *ds ){
81 mapDrawSurface_t *ds2;
85 if ( ds == NULL || ds->shaderInfo == NULL || ds->type <= SURFACE_BAD || ds->type >= NUM_SURFACE_TYPES ) {
89 /* ydnar: rocking tek-fu celshading */
90 if ( ds->celShader != NULL ) {
91 MakeCelSurface( ds, ds->celShader );
94 /* backsides stop here */
99 /* ydnar: rocking surface cloning (fur baby yeah!) */
100 if ( ds->shaderInfo->cloneShader != NULL && ds->shaderInfo->cloneShader[ 0 ] != '\0' ) {
101 CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->cloneShader ) );
104 /* ydnar: q3map_backShader support */
105 if ( ds->shaderInfo->backShader != NULL && ds->shaderInfo->backShader[ 0 ] != '\0' ) {
106 ds2 = CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->backShader ) );
107 ds2->backSide = qtrue;
115 clones a map drawsurface, using the specified shader
118 mapDrawSurface_t *CloneSurface( mapDrawSurface_t *src, shaderInfo_t *si ){
119 mapDrawSurface_t *ds;
123 if ( src == NULL || si == NULL ) {
127 /* allocate a new surface */
128 ds = AllocDrawSurface( src->type );
134 memcpy( ds, src, sizeof( *ds ) );
136 /* destroy side reference */
143 if ( ds->numVerts > 0 ) {
144 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
145 memcpy( ds->verts, src->verts, ds->numVerts * sizeof( *ds->verts ) );
149 if ( ds->numIndexes <= 0 ) {
152 ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
153 memcpy( ds->indexes, src->indexes, ds->numIndexes * sizeof( *ds->indexes ) );
155 /* return the surface */
162 MakeCelSurface() - ydnar
163 makes a copy of a surface, but specific to cel shading
166 mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si ){
167 mapDrawSurface_t *ds;
171 if ( src == NULL || si == NULL ) {
175 /* don't create cel surfaces for certain types of shaders */
176 if ( ( src->shaderInfo->compileFlags & C_TRANSLUCENT ) ||
177 ( src->shaderInfo->compileFlags & C_SKY ) ) {
182 ds = CloneSurface( src, si );
187 /* do some fixups for celshading */
190 ds->celShader = NULL; /* don't cel shade cels :P */
192 /* return the surface */
199 MakeSkyboxSurface() - ydnar
200 generates a skybox surface, viewable from everywhere there is sky
203 mapDrawSurface_t *MakeSkyboxSurface( mapDrawSurface_t *src ){
205 mapDrawSurface_t *ds;
214 ds = CloneSurface( src, src->shaderInfo );
222 /* scale the surface vertexes */
223 for ( i = 0; i < ds->numVerts; i++ )
225 m4x4_transform_point( skyboxTransform, ds->verts[ i ].xyz );
228 //% bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 1 ] = 0;
229 //% bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 2 ] = 0;
232 /* so backface culling creep doesn't bork the surface */
233 VectorClear( ds->lightmapVecs[ 2 ] );
235 /* return the surface */
243 returns qtrue if all three points are colinear, backwards, or the triangle is just plain bogus
246 #define TINY_AREA 1.0f
248 qboolean IsTriangleDegenerate( bspDrawVert_t *points, int a, int b, int c ){
253 /* calcuate the area of the triangle */
254 VectorSubtract( points[ b ].xyz, points[ a ].xyz, v1 );
255 VectorSubtract( points[ c ].xyz, points[ a ].xyz, v2 );
256 CrossProduct( v1, v2, v3 );
257 d = VectorLength( v3 );
259 /* assume all very small or backwards triangles will cause problems */
260 if ( d < TINY_AREA ) {
264 /* must be a good triangle */
271 ClearSurface() - ydnar
272 clears a surface and frees any allocated memory
275 void ClearSurface( mapDrawSurface_t *ds ){
276 ds->type = SURFACE_BAD;
280 if ( ds->verts != NULL ) {
285 if ( ds->indexes != NULL ) {
289 numClearedSurfaces++;
295 TidyEntitySurfaces() - ydnar
296 deletes all empty or bad surfaces from the surface list
299 void TidyEntitySurfaces( entity_t *e ){
301 mapDrawSurface_t *out, *in = NULL;
305 Sys_FPrintf( SYS_VRB, "--- TidyEntitySurfaces ---\n" );
307 /* walk the surface list */
309 for ( i = e->firstDrawSurf, j = e->firstDrawSurf; j < numMapDrawSurfs; i++, j++ )
311 /* get out surface */
312 out = &mapDrawSurfs[ i ];
314 /* walk the surface list again until a proper surface is found */
315 for ( ; j < numMapDrawSurfs; j++ )
318 in = &mapDrawSurfs[ j ];
320 /* this surface ok? */
321 if ( in->type == SURFACE_FLARE || in->type == SURFACE_SHADER ||
322 ( in->type != SURFACE_BAD && in->numVerts > 0 ) ) {
331 /* copy if necessary */
333 memcpy( out, in, sizeof( mapDrawSurface_t ) );
337 /* set the new number of drawsurfs */
340 /* emit some stats */
341 Sys_FPrintf( SYS_VRB, "%9d empty or malformed surfaces deleted\n", deleted );
347 CalcSurfaceTextureRange() - ydnar
348 calculates the clamped texture range for a given surface, returns qtrue if it's within [-texRange,texRange]
351 qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds ){
352 int i, j, v, size[ 2 ];
353 float mins[ 2 ], maxs[ 2 ];
356 /* try to early out */
357 if ( ds->numVerts <= 0 ) {
361 /* walk the verts and determine min/max st values */
366 for ( i = 0; i < ds->numVerts; i++ )
368 for ( j = 0; j < 2; j++ )
370 if ( ds->verts[ i ].st[ j ] < mins[ j ] ) {
371 mins[ j ] = ds->verts[ i ].st[ j ];
373 if ( ds->verts[ i ].st[ j ] > maxs[ j ] ) {
374 maxs[ j ] = ds->verts[ i ].st[ j ];
379 /* clamp to integer range and calculate surface bias values */
380 for ( j = 0; j < 2; j++ )
381 ds->bias[ j ] = -floor( 0.5f * ( mins[ j ] + maxs[ j ] ) );
383 /* find biased texture coordinate mins/maxs */
384 size[ 0 ] = ds->shaderInfo->shaderWidth;
385 size[ 1 ] = ds->shaderInfo->shaderHeight;
386 ds->texMins[ 0 ] = 999999;
387 ds->texMins[ 1 ] = 999999;
388 ds->texMaxs[ 0 ] = -999999;
389 ds->texMaxs[ 1 ] = -999999;
390 for ( i = 0; i < ds->numVerts; i++ )
392 for ( j = 0; j < 2; j++ )
394 v = ( (float) ds->verts[ i ].st[ j ] + ds->bias[ j ] ) * size[ j ];
395 if ( v < ds->texMins[ j ] ) {
396 ds->texMins[ j ] = v;
398 if ( v > ds->texMaxs[ j ] ) {
399 ds->texMaxs[ j ] = v;
405 for ( j = 0; j < 2; j++ )
406 ds->texRange[ j ] = ( ds->texMaxs[ j ] - ds->texMins[ j ] );
408 /* if range is zero, then assume unlimited precision */
409 if ( texRange == 0 ) {
414 for ( j = 0; j < 2; j++ )
416 if ( ds->texMins[ j ] < -texRange || ds->texMaxs[ j ] > texRange ) {
428 CalcLightmapAxis() - ydnar
429 gives closed lightmap axis for a plane normal
432 qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis ){
437 if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && normal[ 2 ] == 0.0f ) {
442 /* get absolute normal */
443 absolute[ 0 ] = fabs( normal[ 0 ] );
444 absolute[ 1 ] = fabs( normal[ 1 ] );
445 absolute[ 2 ] = fabs( normal[ 2 ] );
448 if ( absolute[ 2 ] > absolute[ 0 ] - 0.0001f && absolute[ 2 ] > absolute[ 1 ] - 0.0001f ) {
449 if ( normal[ 2 ] > 0.0f ) {
450 VectorSet( axis, 0.0f, 0.0f, 1.0f );
453 VectorSet( axis, 0.0f, 0.0f, -1.0f );
456 else if ( absolute[ 0 ] > absolute[ 1 ] - 0.0001f && absolute[ 0 ] > absolute[ 2 ] - 0.0001f ) {
457 if ( normal[ 0 ] > 0.0f ) {
458 VectorSet( axis, 1.0f, 0.0f, 0.0f );
461 VectorSet( axis, -1.0f, 0.0f, 0.0f );
466 if ( normal[ 1 ] > 0.0f ) {
467 VectorSet( axis, 0.0f, 1.0f, 0.0f );
470 VectorSet( axis, 0.0f, -1.0f, 0.0f );
481 ClassifySurfaces() - ydnar
482 fills out a bunch of info in the surfaces, including planar status, lightmap projection, and bounding box
485 #define PLANAR_EPSILON 0.5f //% 0.126f 0.25f
487 void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
492 static vec3_t axii[ 6 ] =
503 /* walk the list of surfaces */
504 for ( ; numSurfs > 0; numSurfs--, ds++ )
506 /* ignore bogus (or flare) surfaces */
507 if ( ds->type == SURFACE_BAD || ds->numVerts <= 0 ) {
514 /* -----------------------------------------------------------------
515 force meta if vertex count is too high or shader requires it
516 ----------------------------------------------------------------- */
518 if ( ds->type != SURFACE_PATCH && ds->type != SURFACE_FACE ) {
519 if ( ds->numVerts > SHADER_MAX_VERTEXES ) {
520 ds->type = SURFACE_FORCED_META;
524 /* -----------------------------------------------------------------
525 plane and bounding box classification
526 ----------------------------------------------------------------- */
528 /* set surface bounding box */
529 ClearBounds( ds->mins, ds->maxs );
530 for ( i = 0; i < ds->numVerts; i++ )
531 AddPointToBounds( ds->verts[ i ].xyz, ds->mins, ds->maxs );
533 /* try to get an existing plane */
534 if ( ds->planeNum >= 0 ) {
535 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
536 plane[ 3 ] = mapplanes[ ds->planeNum ].dist;
539 /* construct one from the first vert with a valid normal */
542 VectorClear( plane );
544 for ( i = 0; i < ds->numVerts; i++ )
546 if ( ds->verts[ i ].normal[ 0 ] != 0.0f && ds->verts[ i ].normal[ 1 ] != 0.0f && ds->verts[ i ].normal[ 2 ] != 0.0f ) {
547 VectorCopy( ds->verts[ i ].normal, plane );
548 plane[ 3 ] = DotProduct( ds->verts[ i ].xyz, plane );
554 /* test for bogus plane */
555 if ( VectorLength( plane ) <= 0.0f ) {
561 /* determine if surface is planar */
565 for ( i = 0; i < ds->numVerts; i++ )
567 /* point-plane test */
568 dist = DotProduct( ds->verts[ i ].xyz, plane ) - plane[ 3 ];
569 if ( fabs( dist ) > PLANAR_EPSILON ) {
570 //% if( ds->planeNum >= 0 )
572 //% Sys_FPrintf( SYS_WRN, "WARNING: Planar surface marked unplanar (%f > %f)\n", fabs( dist ), PLANAR_EPSILON );
573 //% ds->verts[ i ].color[ 0 ][ 0 ] = ds->verts[ i ].color[ 0 ][ 2 ] = 0;
581 /* find map plane if necessary */
583 if ( ds->planeNum < 0 ) {
584 ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &ds->verts[ 0 ].xyz );
586 VectorCopy( plane, ds->lightmapVecs[ 2 ] );
591 VectorClear( ds->lightmapVecs[ 2 ] );
592 //% if( ds->type == SURF_META || ds->type == SURF_FACE )
593 //% Sys_FPrintf( SYS_WRN, "WARNING: Non-planar face (%d): %s\n", ds->planeNum, ds->shaderInfo->shader );
596 /* -----------------------------------------------------------------
597 lightmap bounds and axis projection
598 ----------------------------------------------------------------- */
600 /* vertex lit surfaces don't need this information */
601 if ( si->compileFlags & C_VERTEXLIT || ds->type == SURFACE_TRIANGLES || nolm == qtrue ) {
602 VectorClear( ds->lightmapAxis );
603 //% VectorClear( ds->lightmapVecs[ 2 ] );
608 /* the shader can specify an explicit lightmap axis */
609 if ( si->lightmapAxis[ 0 ] || si->lightmapAxis[ 1 ] || si->lightmapAxis[ 2 ] ) {
610 VectorCopy( si->lightmapAxis, ds->lightmapAxis );
612 else if ( ds->type == SURFACE_FORCED_META ) {
613 VectorClear( ds->lightmapAxis );
615 else if ( ds->planar ) {
616 CalcLightmapAxis( plane, ds->lightmapAxis );
620 /* find best lightmap axis */
621 for ( bestAxis = 0; bestAxis < 6; bestAxis++ )
623 for ( i = 0; i < ds->numVerts && bestAxis < 6; i++ )
625 //% Sys_Printf( "Comparing %1.3f %1.3f %1.3f to %1.3f %1.3f %1.3f\n",
626 //% ds->verts[ i ].normal[ 0 ], ds->verts[ i ].normal[ 1 ], ds->verts[ i ].normal[ 2 ],
627 //% axii[ bestAxis ][ 0 ], axii[ bestAxis ][ 1 ], axii[ bestAxis ][ 2 ] );
628 if ( DotProduct( ds->verts[ i ].normal, axii[ bestAxis ] ) < 0.25f ) { /* fixme: adjust this tolerance to taste */
633 if ( i == ds->numVerts ) {
638 /* set axis if possible */
639 if ( bestAxis < 6 ) {
640 //% if( ds->type == SURFACE_PATCH )
641 //% Sys_Printf( "Mapped axis %d onto patch\n", bestAxis );
642 VectorCopy( axii[ bestAxis ], ds->lightmapAxis );
646 //% if( ds->type == SURFACE_PATCH )
647 //% Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis );
650 /* calculate lightmap sample size */
651 if ( ds->shaderInfo->lightmapSampleSize > 0 ) { /* shader value overrides every other */
652 ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
654 else if ( ds->sampleSize <= 0 ) { /* may contain the entity asigned value */
655 ds->sampleSize = sampleSize; /* otherwise use global default */
658 if ( ds->lightmapScale > 0.0f ) { /* apply surface lightmap scaling factor */
659 ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize;
660 ds->lightmapScale = 0; /* applied */
663 if ( ds->sampleSize < minSampleSize ) {
664 ds->sampleSize = minSampleSize;
667 if ( ds->sampleSize < 1 ) {
671 if ( ds->sampleSize > 16384 ) { /* powers of 2 are preferred */
672 ds->sampleSize = 16384;
680 ClassifyEntitySurfaces() - ydnar
681 classifies all surfaces in an entity
684 void ClassifyEntitySurfaces( entity_t *e ){
689 Sys_FPrintf( SYS_VRB, "--- ClassifyEntitySurfaces ---\n" );
691 /* walk the surface list */
692 for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
694 FinishSurface( &mapDrawSurfs[ i ] );
695 ClassifySurfaces( 1, &mapDrawSurfs[ i ] );
699 TidyEntitySurfaces( e );
705 GetShaderIndexForPoint() - ydnar
706 for shader-indexed surfaces (terrain), find a matching index from the indexmap
709 byte GetShaderIndexForPoint( indexMap_t *im, vec3_t eMins, vec3_t eMaxs, vec3_t point ){
712 vec3_t mins, maxs, size;
715 /* early out if no indexmap */
720 /* this code is really broken */
722 /* legacy precision fudges for terrain */
723 for ( i = 0; i < 3; i++ )
725 mins[ i ] = floor( eMins[ i ] + 0.1 );
726 maxs[ i ] = floor( eMaxs[ i ] + 0.1 );
727 size[ i ] = maxs[ i ] - mins[ i ];
730 /* find st (fixme: support more than just z-axis projection) */
731 s = floor( point[ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
732 t = floor( maxs[ 1 ] - point[ 1 ] + 0.1f ) / size[ 1 ];
736 else if ( s > 1.0f ) {
742 else if ( t > 1.0f ) {
747 x = ( im->w - 1 ) * s;
748 y = ( im->h - 1 ) * t;
751 for ( i = 0; i < 3; i++ )
753 mins[ i ] = eMins[ i ];
754 maxs[ i ] = eMaxs[ i ];
755 size[ i ] = maxs[ i ] - mins[ i ];
759 s = ( point[ 0 ] - mins[ 0 ] ) / size[ 0 ];
760 t = ( maxs[ 1 ] - point[ 1 ] ) / size[ 1 ];
768 else if ( x > ( im->w - 1 ) ) {
774 else if ( y > ( im->h - 1 ) ) {
780 return im->pixels[ y * im->w + x ];
784 #define snprintf_ignore(s, n, format, ...) do { \
785 size_t __n = snprintf(s, n, format, __VA_ARGS__); \
786 if (n >= n) {} /* truncated, ignore */ \
790 GetIndexedShader() - ydnar
791 for a given set of indexes and an indexmap, get a shader and set the vertex alpha in-place
792 this combines a couple different functions from terrain.c
795 shaderInfo_t *GetIndexedShader( shaderInfo_t *parent, indexMap_t *im, int numPoints, byte *shaderIndexes ){
797 byte minShaderIndex, maxShaderIndex;
798 char shader[ MAX_QPATH ];
802 /* early out if bad data */
803 if ( im == NULL || numPoints <= 0 || shaderIndexes == NULL ) {
804 return ShaderInfoForShader( "default" );
807 /* determine min/max index */
808 minShaderIndex = 255;
810 for ( i = 0; i < numPoints; i++ )
812 if ( shaderIndexes[ i ] < minShaderIndex ) {
813 minShaderIndex = shaderIndexes[ i ];
815 if ( shaderIndexes[ i ] > maxShaderIndex ) {
816 maxShaderIndex = shaderIndexes[ i ];
820 /* set alpha inline */
821 for ( i = 0; i < numPoints; i++ )
823 /* straight rip from terrain.c */
824 if ( shaderIndexes[ i ] < maxShaderIndex ) {
825 shaderIndexes[ i ] = 0;
828 shaderIndexes[ i ] = 255;
832 /* make a shader name */
833 if ( minShaderIndex == maxShaderIndex ) {
834 snprintf_ignore( shader, sizeof shader, "textures/%s_%d", im->shader, maxShaderIndex );
837 snprintf_ignore( shader, sizeof shader, "textures/%s_%dto%d", im->shader, minShaderIndex, maxShaderIndex );
841 si = ShaderInfoForShader( shader );
843 /* inherit a few things from parent shader */
844 if ( parent->globalTexture ) {
845 si->globalTexture = qtrue;
847 if ( parent->forceMeta ) {
848 si->forceMeta = qtrue;
850 if ( parent->nonplanar ) {
851 si->nonplanar = qtrue;
853 if ( si->shadeAngleDegrees == 0.0 ) {
854 si->shadeAngleDegrees = parent->shadeAngleDegrees;
856 if ( parent->tcGen && si->tcGen == qfalse ) {
857 /* set xy texture projection */
859 VectorCopy( parent->vecs[ 0 ], si->vecs[ 0 ] );
860 VectorCopy( parent->vecs[ 1 ], si->vecs[ 1 ] );
862 if ( VectorLength( parent->lightmapAxis ) > 0.0f && VectorLength( si->lightmapAxis ) <= 0.0f ) {
863 /* set lightmap projection axis */
864 VectorCopy( parent->lightmapAxis, si->lightmapAxis );
867 /* return the shader */
876 creates a SURF_FACE drawsurface from a given brush side and winding
879 #define SNAP_FLOAT_TO_INT 8
880 #define SNAP_INT_TO_FLOAT ( 1.0 / SNAP_FLOAT_TO_INT )
882 mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w ){
884 mapDrawSurface_t *ds;
885 shaderInfo_t *si, *parent;
891 byte shaderIndexes[ 256 ];
892 float offsets[ 256 ];
893 char tempShader[ MAX_QPATH ];
896 /* ydnar: don't make a drawsurf for culled sides */
902 if ( w->numpoints > MAX_POINTS_ON_WINDING ) {
903 Error( "DrawSurfaceForSide: w->numpoints = %d (> %d)", w->numpoints, MAX_POINTS_ON_WINDING );
909 /* ydnar: gs mods: check for indexed shader */
910 if ( si->indexed && b->im != NULL ) {
914 /* get shader indexes for each point */
915 for ( i = 0; i < w->numpoints; i++ )
917 shaderIndexes[ i ] = GetShaderIndexForPoint( b->im, b->eMins, b->eMaxs, w->p[ i ] );
918 offsets[ i ] = b->im->offsets[ shaderIndexes[ i ] ];
919 //% Sys_Printf( "%f ", offsets[ i ] );
922 /* get matching shader and set alpha */
924 si = GetIndexedShader( parent, b->im, w->numpoints, shaderIndexes );
930 /* ydnar: sky hack/fix for GL_CLAMP borders on ati cards */
931 if ( skyFixHack && si->skyParmsImageBase[ 0 ] != '\0' ) {
932 //% Sys_FPrintf( SYS_VRB, "Enabling sky hack for shader %s using env %s\n", si->shader, si->skyParmsImageBase );
933 snprintf_ignore( tempShader, sizeof tempShader, "%s_lf", si->skyParmsImageBase );
934 DrawSurfaceForShader( tempShader );
935 snprintf_ignore( tempShader, sizeof tempShader, "%s_rt", si->skyParmsImageBase );
936 DrawSurfaceForShader( tempShader );
937 snprintf_ignore( tempShader, sizeof tempShader, "%s_ft", si->skyParmsImageBase );
938 DrawSurfaceForShader( tempShader );
939 snprintf_ignore( tempShader, sizeof tempShader, "%s_bk", si->skyParmsImageBase );
940 DrawSurfaceForShader( tempShader );
941 snprintf_ignore( tempShader, sizeof tempShader, "%s_up", si->skyParmsImageBase );
942 DrawSurfaceForShader( tempShader );
943 snprintf_ignore( tempShader, sizeof tempShader, "%s_dn", si->skyParmsImageBase );
944 DrawSurfaceForShader( tempShader );
948 ds = AllocDrawSurface( SURFACE_FACE );
949 ds->entityNum = b->entityNum;
950 ds->castShadows = b->castShadows;
951 ds->recvShadows = b->recvShadows;
954 ds->planeNum = s->planenum;
955 VectorCopy( mapplanes[ s->planenum ].normal, ds->lightmapVecs[ 2 ] );
959 ds->sideRef = AllocSideRef( s, NULL );
961 ds->sampleSize = b->lightmapSampleSize;
962 ds->lightmapScale = b->lightmapScale;
963 ds->numVerts = w->numpoints;
964 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
965 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
967 /* compute s/t coordinates from brush primitive texture matrix (compute axis base) */
968 ComputeAxisBase( mapplanes[ s->planenum ].normal, texX, texY );
970 /* create the vertexes */
971 for ( j = 0; j < w->numpoints; j++ )
973 /* get the drawvert */
976 /* copy xyz and do potential z offset */
977 VectorCopy( w->p[ j ], dv->xyz );
979 dv->xyz[ 2 ] += offsets[ j ];
982 /* round the xyz to a given precision and translate by origin */
983 for ( i = 0 ; i < 3 ; i++ )
984 dv->xyz[ i ] = SNAP_INT_TO_FLOAT * floor( dv->xyz[ i ] * SNAP_FLOAT_TO_INT + 0.5f );
985 VectorAdd( dv->xyz, e->origin, vTranslated );
987 /* ydnar: tek-fu celshading support for flat shaded shit */
989 dv->st[ 0 ] = si->stFlat[ 0 ];
990 dv->st[ 1 ] = si->stFlat[ 1 ];
993 /* ydnar: gs mods: added support for explicit shader texcoord generation */
994 else if ( si->tcGen ) {
995 dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
996 dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
999 /* old quake-style texturing */
1000 else if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
1001 /* nearest-axial projection */
1002 dv->st[ 0 ] = s->vecs[ 0 ][ 3 ] + DotProduct( s->vecs[ 0 ], vTranslated );
1003 dv->st[ 1 ] = s->vecs[ 1 ][ 3 ] + DotProduct( s->vecs[ 1 ], vTranslated );
1004 dv->st[ 0 ] /= si->shaderWidth;
1005 dv->st[ 1 ] /= si->shaderHeight;
1008 /* brush primitive texturing */
1011 /* calculate texture s/t from brush primitive texture matrix */
1012 x = DotProduct( vTranslated, texX );
1013 y = DotProduct( vTranslated, texY );
1014 dv->st[ 0 ] = s->texMat[ 0 ][ 0 ] * x + s->texMat[ 0 ][ 1 ] * y + s->texMat[ 0 ][ 2 ];
1015 dv->st[ 1 ] = s->texMat[ 1 ][ 0 ] * x + s->texMat[ 1 ][ 1 ] * y + s->texMat[ 1 ][ 2 ];
1019 VectorCopy( mapplanes[ s->planenum ].normal, dv->normal );
1021 /* ydnar: set color */
1022 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1024 dv->color[ k ][ 0 ] = 255;
1025 dv->color[ k ][ 1 ] = 255;
1026 dv->color[ k ][ 2 ] = 255;
1028 /* ydnar: gs mods: handle indexed shader blending */
1029 dv->color[ k ][ 3 ] = ( indexed ? shaderIndexes[ j ] : 255 );
1033 /* set cel shader */
1034 ds->celShader = b->celShader;
1036 /* set shade angle */
1037 if ( b->shadeAngleDegrees > 0.0f ) {
1038 ds->shadeAngleDegrees = b->shadeAngleDegrees;
1041 /* ydnar: gs mods: moved st biasing elsewhere */
1048 DrawSurfaceForMesh()
1049 moved here from patch.c
1052 #define YDNAR_NORMAL_EPSILON 0.50f
1054 qboolean VectorCompareExt( vec3_t n1, vec3_t n2, float epsilon ){
1059 for ( i = 0; i < 3; i++ )
1060 if ( fabs( n1[ i ] - n2[ i ] ) > epsilon ) {
1066 mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh ){
1071 mapDrawSurface_t *ds;
1072 shaderInfo_t *si, *parent;
1077 byte shaderIndexes[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1078 float offsets[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1081 /* get mesh and shader shader */
1082 if ( mesh == NULL ) {
1086 if ( mesh == NULL || si == NULL ) {
1090 /* get vertex count */
1091 numVerts = mesh->width * mesh->height;
1093 /* to make valid normals for patches with degenerate edges,
1094 we need to make a copy of the mesh and put the aproximating
1095 points onto the curve */
1097 /* create a copy of the mesh */
1098 copy = CopyMesh( mesh );
1100 /* store off the original (potentially bad) normals */
1101 MakeMeshNormals( *copy );
1102 for ( i = 0; i < numVerts; i++ )
1103 VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1105 /* put the mesh on the curve */
1106 PutMeshOnCurve( *copy );
1108 /* find new normals (to take into account degenerate/flipped edges */
1109 MakeMeshNormals( *copy );
1110 for ( i = 0; i < numVerts; i++ )
1112 /* ydnar: only copy normals that are significantly different from the originals */
1113 if ( DotProduct( copy->verts[ i ].normal, mesh->verts[ i ].normal ) < 0.75f ) {
1114 VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1118 /* free the old mesh */
1121 /* ydnar: gs mods: check for indexed shader */
1122 if ( si->indexed && p->im != NULL ) {
1126 /* get shader indexes for each point */
1127 for ( i = 0; i < numVerts; i++ )
1129 shaderIndexes[ i ] = GetShaderIndexForPoint( p->im, p->eMins, p->eMaxs, mesh->verts[ i ].xyz );
1130 offsets[ i ] = p->im->offsets[ shaderIndexes[ i ] ];
1133 /* get matching shader and set alpha */
1135 si = GetIndexedShader( parent, p->im, numVerts, shaderIndexes );
1142 /* ydnar: gs mods */
1143 ds = AllocDrawSurface( SURFACE_PATCH );
1144 ds->entityNum = p->entityNum;
1145 ds->castShadows = p->castShadows;
1146 ds->recvShadows = p->recvShadows;
1148 ds->shaderInfo = si;
1150 ds->sampleSize = p->lightmapSampleSize;
1151 ds->lightmapScale = p->lightmapScale; /* ydnar */
1152 ds->patchWidth = mesh->width;
1153 ds->patchHeight = mesh->height;
1154 ds->numVerts = ds->patchWidth * ds->patchHeight;
1155 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
1156 memcpy( ds->verts, mesh->verts, ds->numVerts * sizeof( *ds->verts ) );
1161 ds->longestCurve = p->longestCurve;
1162 ds->maxIterations = p->maxIterations;
1164 /* construct a plane from the first vert */
1165 VectorCopy( mesh->verts[ 0 ].normal, plane );
1166 plane[ 3 ] = DotProduct( mesh->verts[ 0 ].xyz, plane );
1169 /* spew forth errors */
1170 if ( VectorLength( plane ) < 0.001f ) {
1171 Sys_Printf( "DrawSurfaceForMesh: bogus plane\n" );
1174 /* test each vert */
1175 for ( i = 1; i < ds->numVerts && planar; i++ )
1178 if ( VectorCompare( plane, mesh->verts[ i ].normal ) == qfalse ) {
1182 /* point-plane test */
1183 dist = DotProduct( mesh->verts[ i ].xyz, plane ) - plane[ 3 ];
1184 if ( fabs( dist ) > EQUAL_EPSILON ) {
1189 /* add a map plane */
1191 /* make a map plane */
1192 ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &mesh->verts[ 0 ].xyz );
1193 VectorCopy( plane, ds->lightmapVecs[ 2 ] );
1195 /* push this normal to all verts (ydnar 2003-02-14: bad idea, small patches get screwed up) */
1196 for ( i = 0; i < ds->numVerts; i++ )
1197 VectorCopy( plane, ds->verts[ i ].normal );
1200 /* walk the verts to do special stuff */
1201 for ( i = 0; i < ds->numVerts; i++ )
1203 /* get the drawvert */
1204 dv = &ds->verts[ i ];
1206 /* ydnar: tek-fu celshading support for flat shaded shit */
1208 dv->st[ 0 ] = si->stFlat[ 0 ];
1209 dv->st[ 1 ] = si->stFlat[ 1 ];
1212 /* ydnar: gs mods: added support for explicit shader texcoord generation */
1213 else if ( si->tcGen ) {
1214 /* translate by origin and project the texture */
1215 VectorAdd( dv->xyz, e->origin, vTranslated );
1216 dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
1217 dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
1220 /* ydnar: set color */
1221 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1223 dv->color[ k ][ 0 ] = 255;
1224 dv->color[ k ][ 1 ] = 255;
1225 dv->color[ k ][ 2 ] = 255;
1227 /* ydnar: gs mods: handle indexed shader blending */
1228 dv->color[ k ][ 3 ] = ( indexed ? shaderIndexes[ i ] : 255 );
1233 dv->xyz[ 2 ] += offsets[ i ];
1237 /* set cel shader */
1238 ds->celShader = p->celShader;
1240 /* return the drawsurface */
1247 DrawSurfaceForFlare() - ydnar
1248 creates a flare draw surface
1251 mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle ){
1252 mapDrawSurface_t *ds;
1256 if ( emitFlares == qfalse ) {
1260 /* allocate drawsurface */
1261 ds = AllocDrawSurface( SURFACE_FLARE );
1262 ds->entityNum = entNum;
1265 if ( flareShader != NULL && flareShader[ 0 ] != '\0' ) {
1266 ds->shaderInfo = ShaderInfoForShader( flareShader );
1269 ds->shaderInfo = ShaderInfoForShader( game->flareShader );
1271 if ( origin != NULL ) {
1272 VectorCopy( origin, ds->lightmapOrigin );
1274 if ( normal != NULL ) {
1275 VectorCopy( normal, ds->lightmapVecs[ 2 ] );
1277 if ( color != NULL ) {
1278 VectorCopy( color, ds->lightmapVecs[ 0 ] );
1281 /* store light style */
1282 ds->lightStyle = lightStyle;
1283 if ( ds->lightStyle < 0 || ds->lightStyle >= LS_NONE ) {
1284 ds->lightStyle = LS_NORMAL;
1289 /* return to sender */
1296 DrawSurfaceForShader() - ydnar
1297 creates a bogus surface to forcing the game to load a shader
1300 mapDrawSurface_t *DrawSurfaceForShader( char *shader ){
1303 mapDrawSurface_t *ds;
1307 si = ShaderInfoForShader( shader );
1309 /* find existing surface */
1310 for ( i = 0; i < numMapDrawSurfs; i++ )
1313 ds = &mapDrawSurfs[ i ];
1316 if ( ds->shaderInfo == si ) {
1321 /* create a new surface */
1322 ds = AllocDrawSurface( SURFACE_SHADER );
1324 ds->shaderInfo = ShaderInfoForShader( shader );
1326 /* return to sender */
1333 AddSurfaceFlare() - ydnar
1334 creates flares (coronas) centered on surfaces
1337 static void AddSurfaceFlare( mapDrawSurface_t *ds, vec3_t entityOrigin ){
1343 VectorClear( origin );
1344 for ( i = 0; i < ds->numVerts; i++ )
1345 VectorAdd( origin, ds->verts[ i ].xyz, origin );
1346 VectorScale( origin, ( 1.0f / ds->numVerts ), origin );
1347 if ( entityOrigin != NULL ) {
1348 VectorAdd( origin, entityOrigin, origin );
1351 /* push origin off surface a bit */
1352 VectorMA( origin, 2.0f, ds->lightmapVecs[ 2 ], origin );
1354 /* create the drawsurface */
1355 DrawSurfaceForFlare( ds->entityNum, origin, ds->lightmapVecs[ 2 ], ds->shaderInfo->color, ds->shaderInfo->flareShader, ds->shaderInfo->lightStyle );
1362 subdivides a face surface until it is smaller than the specified size (subdivisions)
1365 static void SubdivideFace_r( entity_t *e, brush_t *brush, side_t *side, winding_t *w, int fogNum, float subdivisions ){
1369 const float epsilon = 0.1;
1370 int subFloor, subCeil;
1371 winding_t *frontWinding, *backWinding;
1372 mapDrawSurface_t *ds;
1379 if ( w->numpoints < 3 ) {
1380 Error( "SubdivideFace_r: Bad w->numpoints (%d < 3)", w->numpoints );
1383 /* determine surface bounds */
1384 ClearBounds( bounds[ 0 ], bounds[ 1 ] );
1385 for ( i = 0; i < w->numpoints; i++ )
1386 AddPointToBounds( w->p[ i ], bounds[ 0 ], bounds[ 1 ] );
1388 /* split the face */
1389 for ( axis = 0; axis < 3; axis++ )
1391 vec3_t planePoint = { 0, 0, 0 };
1392 vec3_t planeNormal = { 0, 0, 0 };
1396 /* create an axial clipping plane */
1397 subFloor = floor( bounds[ 0 ][ axis ] / subdivisions ) * subdivisions;
1398 subCeil = ceil( bounds[ 1 ][ axis ] / subdivisions ) * subdivisions;
1399 planePoint[ axis ] = subFloor + subdivisions;
1400 planeNormal[ axis ] = -1;
1401 d = DotProduct( planePoint, planeNormal );
1403 /* subdivide if necessary */
1404 if ( ( subCeil - subFloor ) > subdivisions ) {
1405 /* clip the winding */
1406 ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding ); /* not strict; we assume we always keep a winding */
1408 /* the clip may not produce two polygons if it was epsilon close */
1409 if ( frontWinding == NULL ) {
1412 else if ( backWinding == NULL ) {
1417 SubdivideFace_r( e, brush, side, frontWinding, fogNum, subdivisions );
1418 SubdivideFace_r( e, brush, side, backWinding, fogNum, subdivisions );
1424 /* create a face surface */
1425 ds = DrawSurfaceForSide( e, brush, side, w );
1427 /* set correct fog num */
1428 ds->fogNum = fogNum;
1434 SubdivideFaceSurfaces()
1435 chop up brush face surfaces that have subdivision attributes
1436 ydnar: and subdivide surfaces that exceed specified texture coordinate range
1439 void SubdivideFaceSurfaces( entity_t *e, tree_t *tree ){
1440 int i, j, numBaseDrawSurfs, fogNum;
1441 mapDrawSurface_t *ds;
1446 float range, size, subdivisions, s2;
1450 Sys_FPrintf( SYS_VRB, "--- SubdivideFaceSurfaces ---\n" );
1452 /* walk the list of surfaces */
1453 numBaseDrawSurfs = numMapDrawSurfs;
1454 for ( i = e->firstDrawSurf; i < numBaseDrawSurfs; i++ )
1457 ds = &mapDrawSurfs[ i ];
1459 /* only subdivide brush sides */
1460 if ( ds->type != SURFACE_FACE || ds->mapBrush == NULL || ds->sideRef == NULL || ds->sideRef->side == NULL ) {
1465 brush = ds->mapBrush;
1466 side = ds->sideRef->side;
1468 /* check subdivision for shader */
1469 si = side->shaderInfo;
1474 /* ydnar: don't subdivide sky surfaces */
1475 if ( si->compileFlags & C_SKY ) {
1479 /* do texture coordinate range check */
1480 ClassifySurfaces( 1, ds );
1481 if ( CalcSurfaceTextureRange( ds ) == qfalse ) {
1482 /* calculate subdivisions texture range (this code is shit) */
1483 range = ( ds->texRange[ 0 ] > ds->texRange[ 1 ] ? ds->texRange[ 0 ] : ds->texRange[ 1 ] );
1484 size = ds->maxs[ 0 ] - ds->mins[ 0 ];
1485 for ( j = 1; j < 3; j++ )
1486 if ( ( ds->maxs[ j ] - ds->mins[ j ] ) > size ) {
1487 size = ds->maxs[ j ] - ds->mins[ j ];
1489 subdivisions = ( size / range ) * texRange;
1490 subdivisions = ceil( subdivisions / 2 ) * 2;
1491 for ( j = 1; j < 8; j++ )
1493 s2 = ceil( (float) texRange / j );
1494 if ( fabs( subdivisions - s2 ) <= 4.0 ) {
1501 subdivisions = si->subdivisions;
1504 /* get subdivisions from shader */
1505 if ( si->subdivisions > 0 && si->subdivisions < subdivisions ) {
1506 subdivisions = si->subdivisions;
1508 if ( subdivisions < 1.0f ) {
1512 /* preserve fog num */
1513 fogNum = ds->fogNum;
1515 /* make a winding and free the surface */
1516 w = WindingFromDrawSurf( ds );
1520 SubdivideFace_r( e, brush, side, w, fogNum, subdivisions );
1527 ====================
1530 Adds non-opaque leaf fragments to the convex hull
1531 ====================
1534 void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ){
1536 winding_t *front, *back;
1542 if ( node->planenum != PLANENUM_LEAF ) {
1543 if ( side->planenum == node->planenum ) {
1544 ClipSideIntoTree_r( w, side, node->children[0] );
1547 if ( side->planenum == ( node->planenum ^ 1 ) ) {
1548 ClipSideIntoTree_r( w, side, node->children[1] );
1552 plane = &mapplanes[ node->planenum ];
1553 ClipWindingEpsilonStrict( w, plane->normal, plane->dist,
1554 ON_EPSILON, &front, &back ); /* strict, we handle the "winding disappeared" case */
1555 if ( !front && !back ) {
1556 /* in doubt, register it in both nodes */
1557 front = CopyWinding( w );
1558 back = CopyWinding( w );
1562 ClipSideIntoTree_r( front, side, node->children[0] );
1563 ClipSideIntoTree_r( back, side, node->children[1] );
1568 // if opaque leaf, don't add
1569 if ( !node->opaque ) {
1570 AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
1581 static int g_numHiddenFaces, g_numCoinFaces;
1586 CullVectorCompare() - ydnar
1587 compares two vectors with an epsilon
1590 #define CULL_EPSILON 0.1f
1592 qboolean CullVectorCompare( const vec3_t v1, const vec3_t v2 ){
1596 for ( i = 0; i < 3; i++ )
1597 if ( fabs( v1[ i ] - v2[ i ] ) > CULL_EPSILON ) {
1606 SideInBrush() - ydnar
1607 determines if a brushside lies inside another brush
1610 qboolean SideInBrush( side_t *side, brush_t *b ){
1615 /* ignore sides w/o windings or shaders */
1616 if ( side->winding == NULL || side->shaderInfo == NULL ) {
1620 /* ignore culled sides and translucent brushes */
1621 if ( side->culled == qtrue || ( b->compileFlags & C_TRANSLUCENT ) ) {
1626 for ( i = 0; i < b->numsides; i++ )
1628 /* fail if any sides are caulk */
1629 if ( b->sides[ i ].compileFlags & C_NODRAW ) {
1633 /* check if side's winding is on or behind the plane */
1634 plane = &mapplanes[ b->sides[ i ].planenum ];
1635 s = WindingOnPlaneSide( side->winding, plane->normal, plane->dist );
1636 if ( s == SIDE_FRONT || s == SIDE_CROSS ) {
1641 /* don't cull autosprite or polygonoffset surfaces */
1642 if ( side->shaderInfo ) {
1643 if ( side->shaderInfo->autosprite || side->shaderInfo->polygonOffset ) {
1649 side->culled = qtrue;
1657 culls obscured or buried brushsides from the map
1660 void CullSides( entity_t *e ){
1662 int i, j, k, l, first, second, dir;
1665 side_t *side1, *side2;
1669 Sys_FPrintf( SYS_VRB, "--- CullSides ---\n" );
1671 g_numHiddenFaces = 0;
1674 /* brush interator 1 */
1675 for ( b1 = e->brushes; b1; b1 = b1->next )
1678 if ( b1->numsides < 1 ) {
1682 /* brush iterator 2 */
1683 for ( b2 = b1->next; b2; b2 = b2->next )
1686 if ( b2->numsides < 1 ) {
1690 /* original check */
1691 if ( b1->original == b2->original && b1->original != NULL ) {
1697 for ( i = 0; i < 3; i++ )
1698 if ( b1->mins[ i ] > b2->maxs[ i ] || b1->maxs[ i ] < b2->mins[ i ] ) {
1705 /* cull inside sides */
1706 for ( i = 0; i < b1->numsides; i++ )
1707 SideInBrush( &b1->sides[ i ], b2 );
1708 for ( i = 0; i < b2->numsides; i++ )
1709 SideInBrush( &b2->sides[ i ], b1 );
1711 /* side iterator 1 */
1712 for ( i = 0; i < b1->numsides; i++ )
1715 side1 = &b1->sides[ i ];
1716 w1 = side1->winding;
1720 numPoints = w1->numpoints;
1721 if ( side1->shaderInfo == NULL ) {
1725 /* side iterator 2 */
1726 for ( j = 0; j < b2->numsides; j++ )
1729 side2 = &b2->sides[ j ];
1730 w2 = side2->winding;
1734 if ( side2->shaderInfo == NULL ) {
1737 if ( w1->numpoints != w2->numpoints ) {
1740 if ( side1->culled == qtrue && side2->culled == qtrue ) {
1744 /* compare planes */
1745 if ( ( side1->planenum & ~0x00000001 ) != ( side2->planenum & ~0x00000001 ) ) {
1749 /* get autosprite and polygonoffset status */
1750 if ( side1->shaderInfo &&
1751 ( side1->shaderInfo->autosprite || side1->shaderInfo->polygonOffset ) ) {
1754 if ( side2->shaderInfo &&
1755 ( side2->shaderInfo->autosprite || side2->shaderInfo->polygonOffset ) ) {
1759 /* find first common point */
1761 for ( k = 0; k < numPoints; k++ )
1763 if ( VectorCompare( w1->p[ 0 ], w2->p[ k ] ) ) {
1768 if ( first == -1 ) {
1772 /* find second common point (regardless of winding order) */
1775 if ( ( first + 1 ) < numPoints ) {
1781 if ( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) ) {
1790 second = numPoints - 1;
1792 if ( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) ) {
1800 /* compare the rest of the points */
1802 for ( k = 0; k < numPoints; k++ )
1804 if ( !CullVectorCompare( w1->p[ k ], w2->p[ l ] ) ) {
1812 else if ( l >= numPoints ) {
1816 if ( k >= 100000 ) {
1821 if ( !side2->culled && !( side2->compileFlags & C_TRANSLUCENT ) && !( side2->compileFlags & C_NODRAW ) ) {
1822 side1->culled = qtrue;
1826 if ( side1->planenum == side2->planenum && side1->culled == qtrue ) {
1831 if ( !side1->culled && !( side1->compileFlags & C_TRANSLUCENT ) && !( side1->compileFlags & C_NODRAW ) ) {
1832 side2->culled = qtrue;
1840 /* emit some stats */
1841 Sys_FPrintf( SYS_VRB, "%9d hidden faces culled\n", g_numHiddenFaces );
1842 Sys_FPrintf( SYS_VRB, "%9d coincident faces culled\n", g_numCoinFaces );
1851 creates side->visibleHull for all visible sides
1853 the drawsurf for a side will consist of the convex hull of
1854 all points in non-opaque clusters, which allows overlaps
1855 to be trimmed off automatically.
1858 void ClipSidesIntoTree( entity_t *e, tree_t *tree ){
1862 side_t *side, *newSide;
1866 /* ydnar: cull brush sides */
1870 Sys_FPrintf( SYS_VRB, "--- ClipSidesIntoTree ---\n" );
1872 /* walk the brush list */
1873 for ( b = e->brushes; b; b = b->next )
1875 /* walk the brush sides */
1876 for ( i = 0; i < b->numsides; i++ )
1879 side = &b->sides[ i ];
1880 if ( side->winding == NULL ) {
1884 /* copy the winding */
1885 w = CopyWinding( side->winding );
1886 side->visibleHull = NULL;
1887 ClipSideIntoTree_r( w, side, tree->headnode );
1889 /* anything left? */
1890 w = side->visibleHull;
1896 si = side->shaderInfo;
1901 /* don't create faces for non-visible sides */
1902 /* ydnar: except indexed shaders, like common/terrain and nodraw fog surfaces */
1903 if ( ( si->compileFlags & C_NODRAW ) && si->indexed == qfalse && !( si->compileFlags & C_FOG ) ) {
1907 /* always use the original winding for autosprites and noclip faces */
1908 if ( si->autosprite || si->noClip ) {
1912 /* save this winding as a visible surface */
1913 DrawSurfaceForSide( e, b, side, w );
1915 /* make a back side for fog */
1916 if ( !( si->compileFlags & C_FOG ) ) {
1920 /* duplicate the up-facing side */
1921 w = ReverseWinding( w );
1922 newSide = safe_malloc( sizeof( *side ) );
1924 newSide->visibleHull = w;
1925 newSide->planenum ^= 1;
1927 /* save this winding as a visible surface */
1928 DrawSurfaceForSide( e, b, newSide, w );
1937 this section deals with filtering drawsurfaces into the bsp tree,
1938 adding references to each leaf a surface touches
1943 AddReferenceToLeaf() - ydnar
1944 adds a reference to surface ds in the bsp leaf node
1947 int AddReferenceToLeaf( mapDrawSurface_t *ds, node_t *node ){
1952 if ( node->planenum != PLANENUM_LEAF || node->opaque ) {
1956 /* try to find an existing reference */
1957 for ( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef )
1959 if ( dsr->outputNum == numBSPDrawSurfaces ) {
1964 /* add a new reference */
1965 dsr = safe_malloc( sizeof( *dsr ) );
1966 dsr->outputNum = numBSPDrawSurfaces;
1967 dsr->nextRef = node->drawSurfReferences;
1968 node->drawSurfReferences = dsr;
1970 /* ydnar: sky/skybox surfaces */
1971 if ( node->skybox ) {
1974 if ( ds->shaderInfo->compileFlags & C_SKY ) {
1985 AddReferenceToTree_r() - ydnar
1986 adds a reference to the specified drawsurface to every leaf in the tree
1989 int AddReferenceToTree_r( mapDrawSurface_t *ds, node_t *node, qboolean skybox ){
1994 if ( node == NULL ) {
1998 /* is this a decision node? */
1999 if ( node->planenum != PLANENUM_LEAF ) {
2000 /* add to child nodes and return */
2001 refs += AddReferenceToTree_r( ds, node->children[ 0 ], skybox );
2002 refs += AddReferenceToTree_r( ds, node->children[ 1 ], skybox );
2008 /* skybox surfaces only get added to sky leaves */
2013 /* increase the leaf bounds */
2014 for ( i = 0; i < ds->numVerts; i++ )
2015 AddPointToBounds( ds->verts[ i ].xyz, node->mins, node->maxs );
2018 /* add a reference */
2019 return AddReferenceToLeaf( ds, node );
2025 FilterPointIntoTree_r() - ydnar
2026 filters a single point from a surface into the tree
2029 int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ){
2035 /* is this a decision node? */
2036 if ( node->planenum != PLANENUM_LEAF ) {
2037 /* classify the point in relation to the plane */
2038 plane = &mapplanes[ node->planenum ];
2039 d = DotProduct( point, plane->normal ) - plane->dist;
2041 /* filter by this plane */
2043 if ( d >= -ON_EPSILON ) {
2044 refs += FilterPointIntoTree_r( point, ds, node->children[ 0 ] );
2046 if ( d <= ON_EPSILON ) {
2047 refs += FilterPointIntoTree_r( point, ds, node->children[ 1 ] );
2054 /* add a reference */
2055 return AddReferenceToLeaf( ds, node );
2061 FilterPointConvexHullIntoTree_r() - ydnar
2062 filters the convex hull of multiple points from a surface into the tree
2065 int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node ){
2066 float d, dmin, dmax;
2075 /* is this a decision node? */
2076 if ( node->planenum != PLANENUM_LEAF ) {
2077 /* classify the point in relation to the plane */
2078 plane = &mapplanes[ node->planenum ];
2080 dmin = dmax = DotProduct( *( points[0] ), plane->normal ) - plane->dist;
2081 for ( i = 1; i < npoints; ++i )
2083 d = DotProduct( *( points[i] ), plane->normal ) - plane->dist;
2092 /* filter by this plane */
2094 if ( dmax >= -ON_EPSILON ) {
2095 refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] );
2097 if ( dmin <= ON_EPSILON ) {
2098 refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] );
2105 /* add a reference */
2106 return AddReferenceToLeaf( ds, node );
2112 FilterWindingIntoTree_r() - ydnar
2113 filters a winding from a drawsurface into the tree
2116 int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ){
2119 vec4_t plane1, plane2;
2120 winding_t *fat, *front, *back;
2124 /* get shaderinfo */
2125 si = ds->shaderInfo;
2127 /* ydnar: is this the head node? */
2128 if ( node->parent == NULL && si != NULL &&
2129 ( si->mins[ 0 ] != 0.0f || si->maxs[ 0 ] != 0.0f ||
2130 si->mins[ 1 ] != 0.0f || si->maxs[ 1 ] != 0.0f ||
2131 si->mins[ 2 ] != 0.0f || si->maxs[ 2 ] != 0.0f ) ) {
2132 static qboolean warned = qfalse;
2134 Sys_FPrintf( SYS_WRN, "WARNING: this map uses the deformVertexes move hack\n" );
2138 /* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */
2139 /* note this winding is completely invalid (concave, nonplanar, etc) */
2140 fat = AllocWinding( w->numpoints * 3 + 3 );
2141 fat->numpoints = w->numpoints * 3 + 3;
2142 for ( i = 0; i < w->numpoints; i++ )
2144 VectorCopy( w->p[ i ], fat->p[ i ] );
2145 VectorAdd( w->p[ i ], si->mins, fat->p[ i + ( w->numpoints + 1 ) ] );
2146 VectorAdd( w->p[ i ], si->maxs, fat->p[ i + ( w->numpoints + 1 ) * 2 ] );
2148 VectorCopy( w->p[ 0 ], fat->p[ i ] );
2149 VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] );
2150 VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] );
2153 * note: this winding is STILL not suitable for ClipWindingEpsilon, and
2154 * also does not really fulfill the intention as it only contains
2155 * origin, +mins, +maxs, but thanks to the "closing" points I just
2156 * added to the three sub-windings, the fattening at least doesn't make
2164 /* is this a decision node? */
2165 if ( node->planenum != PLANENUM_LEAF ) {
2166 /* get node plane */
2167 p1 = &mapplanes[ node->planenum ];
2168 VectorCopy( p1->normal, plane1 );
2169 plane1[ 3 ] = p1->dist;
2171 /* check if surface is planar */
2172 if ( ds->planeNum >= 0 ) {
2173 /* get surface plane */
2174 p2 = &mapplanes[ ds->planeNum ];
2175 VectorCopy( p2->normal, plane2 );
2176 plane2[ 3 ] = p2->dist;
2179 /* div0: this is the plague (inaccurate) */
2182 /* invert surface plane */
2183 VectorSubtract( vec3_origin, plane2, reverse );
2184 reverse[ 3 ] = -plane2[ 3 ];
2186 /* compare planes */
2187 if ( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f ) {
2188 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2190 if ( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) {
2191 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2195 /* div0: this is the cholera (doesn't hit enough) */
2197 /* the drawsurf might have an associated plane, if so, force a filter here */
2198 if ( ds->planeNum == node->planenum ) {
2199 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2201 if ( ds->planeNum == ( node->planenum ^ 1 ) ) {
2202 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2207 /* clip the winding by this plane */
2208 ClipWindingEpsilonStrict( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); /* strict; we handle the "winding disappeared" case */
2210 /* filter by this plane */
2212 if ( front == NULL && back == NULL ) {
2213 /* same plane, this is an ugly hack */
2214 /* but better too many than too few refs */
2215 refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 0 ] );
2216 refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 1 ] );
2218 if ( front != NULL ) {
2219 refs += FilterWindingIntoTree_r( front, ds, node->children[ 0 ] );
2221 if ( back != NULL ) {
2222 refs += FilterWindingIntoTree_r( back, ds, node->children[ 1 ] );
2230 /* add a reference */
2231 return AddReferenceToLeaf( ds, node );
2237 FilterFaceIntoTree()
2238 filters a planar winding face drawsurface into the bsp tree
2241 int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2246 /* make a winding and filter it into the tree */
2247 w = WindingFromDrawSurf( ds );
2248 refs = FilterWindingIntoTree_r( w, ds, tree->headnode );
2257 FilterPatchIntoTree()
2258 subdivides a patch into an approximate curve and filters it into the tree
2261 #define FILTER_SUBDIVISION 8
2263 static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2266 for ( y = 0; y + 2 < ds->patchHeight; y += 2 )
2267 for ( x = 0; x + 2 < ds->patchWidth; x += 2 )
2270 points[0] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 0 )].xyz;
2271 points[1] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 1 )].xyz;
2272 points[2] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 2 )].xyz;
2273 points[3] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 0 )].xyz;
2274 points[4] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 1 )].xyz;
2275 points[5] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 2 )].xyz;
2276 points[6] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 0 )].xyz;
2277 points[7] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 1 )].xyz;
2278 points[8] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 2 )].xyz;
2279 refs += FilterPointConvexHullIntoTree_r( points, 9, ds, tree->headnode );
2288 FilterTrianglesIntoTree()
2289 filters a triangle surface (meta, model) into the bsp
2292 static int FilterTrianglesIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2297 /* ydnar: gs mods: this was creating bogus triangles before */
2299 for ( i = 0; i < ds->numIndexes; i += 3 )
2302 if ( ds->indexes[ i ] >= ds->numVerts ||
2303 ds->indexes[ i + 1 ] >= ds->numVerts ||
2304 ds->indexes[ i + 2 ] >= ds->numVerts ) {
2305 Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2308 /* make a triangle winding and filter it into the tree */
2309 w = AllocWinding( 3 );
2311 VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2312 VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2313 VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2314 refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2317 /* use point filtering as well */
2318 for ( i = 0; i < ds->numVerts; i++ )
2319 refs += FilterPointIntoTree_r( ds->verts[ i ].xyz, ds, tree->headnode );
2327 FilterFoliageIntoTree()
2328 filters a foliage surface (wolf et/splash damage)
2331 static int FilterFoliageIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2333 bspDrawVert_t *instance;
2338 /* walk origin list */
2340 for ( f = 0; f < ds->numFoliageInstances; f++ )
2343 instance = ds->verts + ds->patchHeight + f;
2345 /* walk triangle list */
2346 for ( i = 0; i < ds->numIndexes; i += 3 )
2349 if ( ds->indexes[ i ] >= ds->numVerts ||
2350 ds->indexes[ i + 1 ] >= ds->numVerts ||
2351 ds->indexes[ i + 2 ] >= ds->numVerts ) {
2352 Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2355 /* make a triangle winding and filter it into the tree */
2356 w = AllocWinding( 3 );
2358 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2359 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2360 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2361 refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2364 /* use point filtering as well */
2365 for ( i = 0; i < ( ds->numVerts - ds->numFoliageInstances ); i++ )
2367 VectorAdd( instance->xyz, ds->verts[ i ].xyz, xyz );
2368 refs += FilterPointIntoTree_r( xyz, ds, tree->headnode );
2378 FilterFlareIntoTree()
2379 simple point filtering for flare surfaces
2381 static int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2382 return FilterPointIntoTree_r( ds->lightmapOrigin, ds, tree->headnode );
2388 EmitDrawVerts() - ydnar
2389 emits bsp drawverts from a map drawsurface
2392 void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2400 si = ds->shaderInfo;
2401 offset = si->offset;
2403 /* copy the verts */
2404 out->firstVert = numBSPDrawVerts;
2405 out->numVerts = ds->numVerts;
2406 for ( i = 0; i < ds->numVerts; i++ )
2408 /* allocate a new vert */
2410 dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
2413 memcpy( dv, &ds->verts[ i ], sizeof( *dv ) );
2416 if ( offset != 0.0f ) {
2417 VectorMA( dv->xyz, offset, dv->normal, dv->xyz );
2420 /* expand model bounds
2421 necessary because of misc_model surfaces on entities
2422 note: does not happen on worldspawn as its bounds is only used for determining lightgrid bounds */
2423 if ( numBSPModels > 0 ) {
2424 AddPointToBounds( dv->xyz, bspModels[ numBSPModels ].mins, bspModels[ numBSPModels ].maxs );
2428 if ( debugSurfaces ) {
2429 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
2430 VectorCopy( debugColors[ ( ds - mapDrawSurfs ) % 12 ], dv->color[ k ] );
2438 FindDrawIndexes() - ydnar
2439 this attempts to find a run of indexes in the bsp that match the given indexes
2440 this tends to reduce the size of the bsp index pool by 1/3 or more
2441 returns numIndexes + 1 if the search failed
2444 int FindDrawIndexes( int numIndexes, int *indexes ){
2445 int i, j, numTestIndexes;
2449 if ( numIndexes < 3 || numBSPDrawIndexes < numIndexes || indexes == NULL ) {
2450 return numBSPDrawIndexes;
2454 numTestIndexes = 1 + numBSPDrawIndexes - numIndexes;
2456 /* handle 3 indexes as a special case for performance */
2457 if ( numIndexes == 3 ) {
2458 /* run through all indexes */
2459 for ( i = 0; i < numTestIndexes; i++ )
2461 /* test 3 indexes */
2462 if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2463 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2464 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] ) {
2465 numRedundantIndexes += numIndexes;
2471 return numBSPDrawIndexes;
2474 /* handle 4 or more indexes */
2475 for ( i = 0; i < numTestIndexes; i++ )
2477 /* test first 4 indexes */
2478 if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2479 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2480 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] &&
2481 indexes[ 3 ] == bspDrawIndexes[ i + 3 ] ) {
2482 /* handle 4 indexes */
2483 if ( numIndexes == 4 ) {
2487 /* test the remainder */
2488 for ( j = 4; j < numIndexes; j++ )
2490 if ( indexes[ j ] != bspDrawIndexes[ i + j ] ) {
2493 else if ( j == ( numIndexes - 1 ) ) {
2494 numRedundantIndexes += numIndexes;
2502 return numBSPDrawIndexes;
2508 EmitDrawIndexes() - ydnar
2509 attempts to find an existing run of drawindexes before adding new ones
2512 void EmitDrawIndexes( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2516 /* attempt to use redundant indexing */
2517 out->firstIndex = FindDrawIndexes( ds->numIndexes, ds->indexes );
2518 out->numIndexes = ds->numIndexes;
2519 if ( out->firstIndex == numBSPDrawIndexes ) {
2520 /* copy new unique indexes */
2521 for ( i = 0; i < ds->numIndexes; i++ )
2523 AUTOEXPAND_BY_REALLOC_BSP( DrawIndexes, 1024 );
2524 bspDrawIndexes[ numBSPDrawIndexes ] = ds->indexes[ i ];
2526 /* validate the index */
2527 if ( ds->type != SURFACE_PATCH ) {
2528 if ( bspDrawIndexes[ numBSPDrawIndexes ] < 0 || bspDrawIndexes[ numBSPDrawIndexes ] >= ds->numVerts ) {
2529 Sys_FPrintf( SYS_WRN, "WARNING: %d %s has invalid index %d (%d)\n",
2531 ds->shaderInfo->shader,
2532 bspDrawIndexes[ numBSPDrawIndexes ],
2534 bspDrawIndexes[ numBSPDrawIndexes ] = 0;
2538 /* increment index count */
2539 numBSPDrawIndexes++;
2549 emits a bsp flare drawsurface
2552 void EmitFlareSurface( mapDrawSurface_t *ds ){
2554 bspDrawSurface_t *out;
2557 /* ydnar: nuking useless flare drawsurfaces */
2558 if ( emitFlares == qfalse && ds->type != SURFACE_SHADER ) {
2563 if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2564 Error( "MAX_MAP_DRAW_SURFS" );
2567 /* allocate a new surface */
2568 if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2569 Error( "MAX_MAP_DRAW_SURFS" );
2571 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2572 ds->outputNum = numBSPDrawSurfaces;
2573 numBSPDrawSurfaces++;
2574 memset( out, 0, sizeof( *out ) );
2577 out->surfaceType = MST_FLARE;
2578 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2579 out->fogNum = ds->fogNum;
2582 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2584 out->lightmapNum[ i ] = -3;
2585 out->lightmapStyles[ i ] = LS_NONE;
2586 out->vertexStyles[ i ] = LS_NONE;
2588 out->lightmapStyles[ 0 ] = ds->lightStyle;
2589 out->vertexStyles[ 0 ] = ds->lightStyle;
2591 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin ); /* origin */
2592 VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] ); /* color */
2593 VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2594 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] ); /* normal */
2597 numSurfacesByType[ ds->type ]++;
2604 emits a bsp patch drawsurface
2607 void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ){
2609 bspDrawSurface_t *out;
2610 int surfaceFlags, contentFlags;
2613 /* vortex: _patchMeta support */
2614 forcePatchMeta = IntForKey( e, "_patchMeta" );
2615 if ( !forcePatchMeta ) {
2616 forcePatchMeta = IntForKey( e, "patchMeta" );
2619 /* invert the surface if necessary */
2620 if ( ds->backSide || ds->shaderInfo->invert ) {
2621 bspDrawVert_t *dv1, *dv2, temp;
2623 /* walk the verts, flip the normal */
2624 for ( i = 0; i < ds->numVerts; i++ )
2625 VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2627 /* walk the verts again, but this time reverse their order */
2628 for ( j = 0; j < ds->patchHeight; j++ )
2630 for ( i = 0; i < ( ds->patchWidth / 2 ); i++ )
2632 dv1 = &ds->verts[ j * ds->patchWidth + i ];
2633 dv2 = &ds->verts[ j * ds->patchWidth + ( ds->patchWidth - i - 1 ) ];
2634 memcpy( &temp, dv1, sizeof( bspDrawVert_t ) );
2635 memcpy( dv1, dv2, sizeof( bspDrawVert_t ) );
2636 memcpy( dv2, &temp, sizeof( bspDrawVert_t ) );
2641 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2644 /* allocate a new surface */
2645 if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2646 Error( "MAX_MAP_DRAW_SURFS" );
2648 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2649 ds->outputNum = numBSPDrawSurfaces;
2650 numBSPDrawSurfaces++;
2651 memset( out, 0, sizeof( *out ) );
2654 out->surfaceType = MST_PATCH;
2655 if ( debugSurfaces ) {
2656 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2658 else if ( patchMeta || forcePatchMeta ) {
2659 /* patch meta requires that we have nodraw patches for collision */
2660 surfaceFlags = ds->shaderInfo->surfaceFlags;
2661 contentFlags = ds->shaderInfo->contentFlags;
2662 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, NULL );
2663 ApplySurfaceParm( "pointlight", &contentFlags, &surfaceFlags, NULL );
2665 /* we don't want this patch getting lightmapped */
2666 VectorClear( ds->lightmapVecs[ 2 ] );
2667 VectorClear( ds->lightmapAxis );
2670 /* emit the new fake shader */
2671 out->shaderNum = EmitShader( ds->shaderInfo->shader, &contentFlags, &surfaceFlags );
2674 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2676 out->patchWidth = ds->patchWidth;
2677 out->patchHeight = ds->patchHeight;
2678 out->fogNum = ds->fogNum;
2681 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2683 out->lightmapNum[ i ] = -3;
2684 out->lightmapStyles[ i ] = LS_NONE;
2685 out->vertexStyles[ i ] = LS_NONE;
2687 out->lightmapStyles[ 0 ] = LS_NORMAL;
2688 out->vertexStyles[ 0 ] = LS_NORMAL;
2690 /* ydnar: gs mods: previously, the lod bounds were stored in lightmapVecs[ 0 ] and [ 1 ], moved to bounds[ 0 ] and [ 1 ] */
2691 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2692 VectorCopy( ds->bounds[ 0 ], out->lightmapVecs[ 0 ] );
2693 VectorCopy( ds->bounds[ 1 ], out->lightmapVecs[ 1 ] );
2694 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2696 /* ydnar: gs mods: clear out the plane normal */
2697 if ( ds->planar == qfalse ) {
2698 VectorClear( out->lightmapVecs[ 2 ] );
2701 /* emit the verts and indexes */
2702 EmitDrawVerts( ds, out );
2703 EmitDrawIndexes( ds, out );
2706 numSurfacesByType[ ds->type ]++;
2712 OptimizeTriangleSurface() - ydnar
2713 optimizes the vertex/index data in a triangle surface
2716 #define VERTEX_CACHE_SIZE 16
2718 static void OptimizeTriangleSurface( mapDrawSurface_t *ds ){
2719 int i, j, k, temp, first, best, bestScore, score;
2720 int vertexCache[ VERTEX_CACHE_SIZE + 1 ]; /* one more for optimizing insert */
2724 /* certain surfaces don't get optimized */
2725 if ( ds->numIndexes <= VERTEX_CACHE_SIZE ||
2726 ds->shaderInfo->autosprite ) {
2730 /* create index scratch pad */
2731 indexes = safe_malloc( ds->numIndexes * sizeof( *indexes ) );
2732 memcpy( indexes, ds->indexes, ds->numIndexes * sizeof( *indexes ) );
2735 for ( i = 0; i <= VERTEX_CACHE_SIZE && i < ds->numIndexes; i++ )
2736 vertexCache[ i ] = indexes[ i ];
2738 /* add triangles in a vertex cache-aware order */
2739 for ( i = 0; i < ds->numIndexes; i += 3 )
2741 /* find best triangle given the current vertex cache */
2745 for ( j = 0; j < ds->numIndexes; j += 3 )
2747 /* valid triangle? */
2748 if ( indexes[ j ] != -1 ) {
2749 /* set first if necessary */
2754 /* score the triangle */
2756 for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2758 if ( indexes[ j ] == vertexCache[ k ] || indexes[ j + 1 ] == vertexCache[ k ] || indexes[ j + 2 ] == vertexCache[ k ] ) {
2763 /* better triangle? */
2764 if ( score > bestScore ) {
2769 /* a perfect score of 3 means this triangle's verts are already present in the vertex cache */
2776 /* check if no decent triangle was found, and use first available */
2781 /* valid triangle? */
2783 /* add triangle to vertex cache */
2784 for ( j = 0; j < 3; j++ )
2786 for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2788 if ( indexes[ best + j ] == vertexCache[ k ] ) {
2793 if ( k >= VERTEX_CACHE_SIZE ) {
2794 /* pop off top of vertex cache */
2795 for ( k = VERTEX_CACHE_SIZE; k > 0; k-- )
2796 vertexCache[ k ] = vertexCache[ k - 1 ];
2799 vertexCache[ 0 ] = indexes[ best + j ];
2803 /* add triangle to surface */
2804 ds->indexes[ i ] = indexes[ best ];
2805 ds->indexes[ i + 1 ] = indexes[ best + 1 ];
2806 ds->indexes[ i + 2 ] = indexes[ best + 2 ];
2808 /* clear from input pool */
2809 indexes[ best ] = -1;
2810 indexes[ best + 1 ] = -1;
2811 indexes[ best + 2 ] = -1;
2813 /* sort triangle windings (312 -> 123) */
2814 while ( ds->indexes[ i ] > ds->indexes[ i + 1 ] || ds->indexes[ i ] > ds->indexes[ i + 2 ] )
2816 temp = ds->indexes[ i ];
2817 ds->indexes[ i ] = ds->indexes[ i + 1 ];
2818 ds->indexes[ i + 1 ] = ds->indexes[ i + 2 ];
2819 ds->indexes[ i + 2 ] = temp;
2831 EmitTriangleSurface()
2832 creates a bsp drawsurface from arbitrary triangle surfaces
2835 void EmitTriangleSurface( mapDrawSurface_t *ds ){
2837 bspDrawSurface_t *out;
2839 /* invert the surface if necessary */
2840 if ( ds->backSide || ds->shaderInfo->invert ) {
2841 /* walk the indexes, reverse the triangle order */
2842 for ( i = 0; i < ds->numIndexes; i += 3 )
2844 temp = ds->indexes[ i ];
2845 ds->indexes[ i ] = ds->indexes[ i + 1 ];
2846 ds->indexes[ i + 1 ] = temp;
2849 /* walk the verts, flip the normal */
2850 for ( i = 0; i < ds->numVerts; i++ )
2851 VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2854 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2857 /* allocate a new surface */
2858 if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2859 Error( "MAX_MAP_DRAW_SURFS" );
2861 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2862 ds->outputNum = numBSPDrawSurfaces;
2863 numBSPDrawSurfaces++;
2864 memset( out, 0, sizeof( *out ) );
2866 /* ydnar/sd: handle wolf et foliage surfaces */
2867 if ( ds->type == SURFACE_FOLIAGE ) {
2868 out->surfaceType = MST_FOLIAGE;
2871 /* ydnar: gs mods: handle lightmapped terrain (force to planar type) */
2872 //% else if( VectorLength( ds->lightmapAxis ) <= 0.0f || ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FOGHULL || debugSurfaces )
2873 else if ( ( VectorLength( ds->lightmapAxis ) <= 0.0f && ds->planar == qfalse ) ||
2874 ds->type == SURFACE_TRIANGLES ||
2875 ds->type == SURFACE_FOGHULL ||
2876 ds->numVerts > maxLMSurfaceVerts ||
2878 out->surfaceType = MST_TRIANGLE_SOUP;
2881 /* set to a planar face */
2883 out->surfaceType = MST_PLANAR;
2887 if ( debugSurfaces ) {
2888 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2891 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2893 out->patchWidth = ds->patchWidth;
2894 out->patchHeight = ds->patchHeight;
2895 out->fogNum = ds->fogNum;
2897 /* debug inset (push each triangle vertex towards the center of each triangle it is on */
2899 bspDrawVert_t *a, *b, *c;
2903 /* walk triangle list */
2904 for ( i = 0; i < ds->numIndexes; i += 3 )
2907 a = &ds->verts[ ds->indexes[ i ] ];
2908 b = &ds->verts[ ds->indexes[ i + 1 ] ];
2909 c = &ds->verts[ ds->indexes[ i + 2 ] ];
2911 /* calculate centroid */
2912 VectorCopy( a->xyz, cent );
2913 VectorAdd( cent, b->xyz, cent );
2914 VectorAdd( cent, c->xyz, cent );
2915 VectorScale( cent, 1.0f / 3.0f, cent );
2917 /* offset each vertex */
2918 VectorSubtract( cent, a->xyz, dir );
2919 VectorNormalize( dir, dir );
2920 VectorAdd( a->xyz, dir, a->xyz );
2921 VectorSubtract( cent, b->xyz, dir );
2922 VectorNormalize( dir, dir );
2923 VectorAdd( b->xyz, dir, b->xyz );
2924 VectorSubtract( cent, c->xyz, dir );
2925 VectorNormalize( dir, dir );
2926 VectorAdd( c->xyz, dir, c->xyz );
2931 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2933 out->lightmapNum[ i ] = -3;
2934 out->lightmapStyles[ i ] = LS_NONE;
2935 out->vertexStyles[ i ] = LS_NONE;
2937 out->lightmapStyles[ 0 ] = LS_NORMAL;
2938 out->vertexStyles[ 0 ] = LS_NORMAL;
2940 /* lightmap vectors (lod bounds for patches */
2941 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2942 VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );
2943 VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2944 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2946 /* ydnar: gs mods: clear out the plane normal */
2947 if ( ds->planar == qfalse ) {
2948 VectorClear( out->lightmapVecs[ 2 ] );
2951 /* optimize the surface's triangles */
2952 OptimizeTriangleSurface( ds );
2954 /* emit the verts and indexes */
2955 EmitDrawVerts( ds, out );
2956 EmitDrawIndexes( ds, out );
2959 numSurfacesByType[ ds->type ]++;
2966 emits a bsp planar winding (brush face) drawsurface
2969 static void EmitFaceSurface( mapDrawSurface_t *ds ){
2970 /* strip/fan finding was moved elsewhere */
2971 if ( maxAreaFaceSurface ) {
2972 MaxAreaFaceSurface( ds );
2975 StripFaceSurface( ds );
2977 EmitTriangleSurface( ds );
2983 MakeDebugPortalSurfs_r() - ydnar
2984 generates drawsurfaces for passable portals in the bsp
2987 static void MakeDebugPortalSurfs_r( node_t *node, shaderInfo_t *si ){
2991 mapDrawSurface_t *ds;
2995 /* recurse if decision node */
2996 if ( node->planenum != PLANENUM_LEAF ) {
2997 MakeDebugPortalSurfs_r( node->children[ 0 ], si );
2998 MakeDebugPortalSurfs_r( node->children[ 1 ], si );
3002 /* don't bother with opaque leaves */
3003 if ( node->opaque ) {
3007 /* walk the list of portals */
3008 for ( c = 0, p = node->portals; p != NULL; c++, p = p->next[ s ] )
3010 /* get winding and side even/odd */
3012 s = ( p->nodes[ 1 ] == node );
3014 /* is this a valid portal for this leaf? */
3015 if ( w && p->nodes[ 0 ] == node ) {
3016 /* is this portal passable? */
3017 if ( PortalPassable( p ) == qfalse ) {
3021 /* check max points */
3022 if ( w->numpoints > 64 ) {
3023 Error( "MakePortalSurfs_r: w->numpoints = %d", w->numpoints );
3026 /* allocate a drawsurface */
3027 ds = AllocDrawSurface( SURFACE_FACE );
3028 ds->shaderInfo = si;
3030 ds->sideRef = AllocSideRef( p->side, NULL );
3031 ds->planeNum = FindFloatPlane( p->plane.normal, p->plane.dist, 0, NULL );
3032 VectorCopy( p->plane.normal, ds->lightmapVecs[ 2 ] );
3034 ds->numVerts = w->numpoints;
3035 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3036 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3038 /* walk the winding */
3039 for ( i = 0; i < ds->numVerts; i++ )
3045 VectorCopy( w->p[ i ], dv->xyz );
3046 VectorCopy( p->plane.normal, dv->normal );
3049 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
3051 VectorCopy( debugColors[ c % 12 ], dv->color[ k ] );
3052 dv->color[ k ][ 3 ] = 32;
3062 MakeDebugPortalSurfs() - ydnar
3063 generates drawsurfaces for passable portals in the bsp
3066 void MakeDebugPortalSurfs( tree_t *tree ){
3071 Sys_FPrintf( SYS_VRB, "--- MakeDebugPortalSurfs ---\n" );
3073 /* get portal debug shader */
3074 si = ShaderInfoForShader( "debugportals" );
3077 MakeDebugPortalSurfs_r( tree->headnode, si );
3084 generates drawsurfaces for a foghull (this MUST use a sky shader)
3087 void MakeFogHullSurfs( entity_t *e, tree_t *tree, char *shader ){
3089 mapDrawSurface_t *ds;
3090 vec3_t fogMins, fogMaxs;
3103 if ( shader == NULL || shader[ 0 ] == '\0' ) {
3108 Sys_FPrintf( SYS_VRB, "--- MakeFogHullSurfs ---\n" );
3110 /* get hull bounds */
3111 VectorCopy( mapMins, fogMins );
3112 VectorCopy( mapMaxs, fogMaxs );
3113 for ( i = 0; i < 3; i++ )
3115 fogMins[ i ] -= 128;
3116 fogMaxs[ i ] += 128;
3119 /* get foghull shader */
3120 si = ShaderInfoForShader( shader );
3122 /* allocate a drawsurface */
3123 ds = AllocDrawSurface( SURFACE_FOGHULL );
3124 ds->shaderInfo = si;
3127 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3128 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3129 ds->numIndexes = 36;
3130 ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
3131 memset( ds->indexes, 0, ds->numIndexes * sizeof( *ds->indexes ) );
3134 VectorSet( ds->verts[ 0 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3135 VectorSet( ds->verts[ 1 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3136 VectorSet( ds->verts[ 2 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3137 VectorSet( ds->verts[ 3 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3139 VectorSet( ds->verts[ 4 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3140 VectorSet( ds->verts[ 5 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3141 VectorSet( ds->verts[ 6 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3142 VectorSet( ds->verts[ 7 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3145 memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( *ds->indexes ) );
3151 BiasSurfaceTextures()
3152 biases a surface's texcoords as close to 0 as possible
3155 void BiasSurfaceTextures( mapDrawSurface_t *ds ){
3159 /* calculate the surface texture bias */
3160 CalcSurfaceTextureRange( ds );
3162 /* don't bias globaltextured shaders */
3163 if ( ds->shaderInfo->globalTexture ) {
3167 /* bias the texture coordinates */
3168 for ( i = 0; i < ds->numVerts; i++ )
3170 ds->verts[ i ].st[ 0 ] += ds->bias[ 0 ];
3171 ds->verts[ i ].st[ 1 ] += ds->bias[ 1 ];
3178 AddSurfaceModelsToTriangle_r()
3179 adds models to a specified triangle, returns the number of models added
3182 int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, bspDrawVert_t **tri ){
3183 bspDrawVert_t mid, *tri2[ 3 ];
3184 int max, n, localNumSurfaceModels;
3188 localNumSurfaceModels = 0;
3190 /* subdivide calc */
3193 float *a, *b, dx, dy, dz, dist, maxDist;
3196 /* find the longest edge and split it */
3199 for ( i = 0; i < 3; i++ )
3203 b = tri[ ( i + 1 ) % 3 ]->xyz;
3206 dx = a[ 0 ] - b[ 0 ];
3207 dy = a[ 1 ] - b[ 1 ];
3208 dz = a[ 2 ] - b[ 2 ];
3209 dist = ( dx * dx ) + ( dy * dy ) + ( dz * dz );
3212 if ( dist > maxDist ) {
3218 /* is the triangle small enough? */
3219 if ( max < 0 || maxDist <= ( model->density * model->density ) ) {
3220 float odds, r, angle;
3221 vec3_t origin, normal, scale, axis[ 3 ], angles;
3222 m4x4_t transform, temp;
3225 /* roll the dice (model's odds scaled by vertex alpha) */
3226 odds = model->odds * ( tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] ) / 765.0f;
3232 /* calculate scale */
3233 r = model->minScale + Random() * ( model->maxScale - model->minScale );
3234 VectorSet( scale, r, r, r );
3236 /* calculate angle */
3237 angle = model->minAngle + Random() * ( model->maxAngle - model->minAngle );
3239 /* calculate average origin */
3240 VectorCopy( tri[ 0 ]->xyz, origin );
3241 VectorAdd( origin, tri[ 1 ]->xyz, origin );
3242 VectorAdd( origin, tri[ 2 ]->xyz, origin );
3243 VectorScale( origin, ( 1.0f / 3.0f ), origin );
3245 /* clear transform matrix */
3246 m4x4_identity( transform );
3248 /* handle oriented models */
3249 if ( model->oriented ) {
3251 VectorSet( angles, 0.0f, 0.0f, angle );
3253 /* calculate average normal */
3254 VectorCopy( tri[ 0 ]->normal, normal );
3255 VectorAdd( normal, tri[ 1 ]->normal, normal );
3256 VectorAdd( normal, tri[ 2 ]->normal, normal );
3257 if ( VectorNormalize( normal, axis[ 2 ] ) == 0.0f ) {
3258 VectorCopy( tri[ 0 ]->normal, axis[ 2 ] );
3261 /* make perpendicular vectors */
3262 MakeNormalVectors( axis[ 2 ], axis[ 1 ], axis[ 0 ] );
3264 /* copy to matrix */
3265 m4x4_identity( temp );
3266 temp[ 0 ] = axis[ 0 ][ 0 ]; temp[ 1 ] = axis[ 0 ][ 1 ]; temp[ 2 ] = axis[ 0 ][ 2 ];
3267 temp[ 4 ] = axis[ 1 ][ 0 ]; temp[ 5 ] = axis[ 1 ][ 1 ]; temp[ 6 ] = axis[ 1 ][ 2 ];
3268 temp[ 8 ] = axis[ 2 ][ 0 ]; temp[ 9 ] = axis[ 2 ][ 1 ]; temp[ 10 ] = axis[ 2 ][ 2 ];
3271 m4x4_scale_by_vec3( temp, scale );
3273 /* rotate around z axis */
3274 m4x4_rotate_by_vec3( temp, angles, eXYZ );
3277 m4x4_translate_by_vec3( transform, origin );
3279 /* tranform into axis space */
3280 m4x4_multiply_by_m4x4( transform, temp );
3283 /* handle z-up models */
3287 VectorSet( angles, 0.0f, 0.0f, angle );
3290 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
3293 /* insert the model */
3294 InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0, clipDepthGlobal );
3296 /* return to sender */
3301 /* split the longest edge and map it */
3302 LerpDrawVert( tri[ max ], tri[ ( max + 1 ) % 3 ], &mid );
3304 /* recurse to first triangle */
3305 VectorCopy( tri, tri2 );
3307 n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3311 localNumSurfaceModels += n;
3313 /* recurse to second triangle */
3314 VectorCopy( tri, tri2 );
3315 tri2[ ( max + 1 ) % 3 ] = ∣
3316 n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3320 localNumSurfaceModels += n;
3323 return localNumSurfaceModels;
3330 adds a surface's shader models to the surface
3333 int AddSurfaceModels( mapDrawSurface_t *ds ){
3334 surfaceModel_t *model;
3335 int i, x, y, n, pw[ 5 ], r, localNumSurfaceModels, iterations;
3336 mesh_t src, *mesh, *subdivided;
3337 bspDrawVert_t centroid, *tri[ 3 ];
3342 if ( ds == NULL || ds->shaderInfo == NULL || ds->shaderInfo->surfaceModel == NULL ) {
3347 localNumSurfaceModels = 0;
3349 /* walk the model list */
3350 for ( model = ds->shaderInfo->surfaceModel; model != NULL; model = model->next )
3352 /* switch on type */
3355 /* handle brush faces and decals */
3358 /* calculate centroid */
3359 memset( ¢roid, 0, sizeof( centroid ) );
3363 for ( i = 0; i < ds->numVerts; i++ )
3365 VectorAdd( centroid.xyz, ds->verts[ i ].xyz, centroid.xyz );
3366 VectorAdd( centroid.normal, ds->verts[ i ].normal, centroid.normal );
3367 centroid.st[ 0 ] += ds->verts[ i ].st[ 0 ];
3368 centroid.st[ 1 ] += ds->verts[ i ].st[ 1 ];
3369 alpha += ds->verts[ i ].color[ 0 ][ 3 ];
3373 centroid.xyz[ 0 ] /= ds->numVerts;
3374 centroid.xyz[ 1 ] /= ds->numVerts;
3375 centroid.xyz[ 2 ] /= ds->numVerts;
3376 if ( VectorNormalize( centroid.normal, centroid.normal ) == 0.0f ) {
3377 VectorCopy( ds->verts[ 0 ].normal, centroid.normal );
3379 centroid.st[ 0 ] /= ds->numVerts;
3380 centroid.st[ 1 ] /= ds->numVerts;
3381 alpha /= ds->numVerts;
3382 centroid.color[ 0 ][ 0 ] = 0xFF;
3383 centroid.color[ 0 ][ 1 ] = 0xFF;
3384 //centroid.color[ 0 ][ 2 ] = 0xFF;
3385 centroid.color[ 0 ][ 2 ] = ( alpha > 255.0f ? 0xFF : alpha );
3387 /* head vert is centroid */
3388 tri[ 0 ] = ¢roid;
3390 /* walk fanned triangles */
3391 for ( i = 0; i < ds->numVerts; i++ )
3394 tri[ 1 ] = &ds->verts[ i ];
3395 tri[ 2 ] = &ds->verts[ ( i + 1 ) % ds->numVerts ];
3398 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3402 localNumSurfaceModels += n;
3406 /* handle patches */
3408 /* subdivide the surface */
3409 src.width = ds->patchWidth;
3410 src.height = ds->patchHeight;
3411 src.verts = ds->verts;
3412 //% subdivided = SubdivideMesh( src, 8.0f, 512 );
3413 iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
3414 subdivided = SubdivideMesh2( src, iterations );
3416 /* fit it to the curve and remove colinear verts on rows/columns */
3417 PutMeshOnCurve( *subdivided );
3418 mesh = RemoveLinearMeshColumnsRows( subdivided );
3419 FreeMesh( subdivided );
3421 /* subdivide each quad to place the models */
3422 for ( y = 0; y < ( mesh->height - 1 ); y++ )
3424 for ( x = 0; x < ( mesh->width - 1 ); x++ )
3427 pw[ 0 ] = x + ( y * mesh->width );
3428 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
3429 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
3430 pw[ 3 ] = x + 1 + ( y * mesh->width );
3431 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
3437 tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3438 tri[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
3439 tri[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
3440 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3444 localNumSurfaceModels += n;
3447 tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3448 tri[ 1 ] = &mesh->verts[ pw[ r + 2 ] ];
3449 tri[ 2 ] = &mesh->verts[ pw[ r + 3 ] ];
3450 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3454 localNumSurfaceModels += n;
3458 /* free the subdivided mesh */
3462 /* handle triangle surfaces */
3463 case SURFACE_TRIANGLES:
3464 case SURFACE_FORCED_META:
3466 /* walk the triangle list */
3467 for ( i = 0; i < ds->numIndexes; i += 3 )
3469 tri[ 0 ] = &ds->verts[ ds->indexes[ i ] ];
3470 tri[ 1 ] = &ds->verts[ ds->indexes[ i + 1 ] ];
3471 tri[ 2 ] = &ds->verts[ ds->indexes[ i + 2 ] ];
3472 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3476 localNumSurfaceModels += n;
3480 /* no support for flares, foghull, etc */
3487 return localNumSurfaceModels;
3493 AddEntitySurfaceModels() - ydnar
3494 adds surfacemodels to an entity's surfaces
3497 void AddEntitySurfaceModels( entity_t *e ){
3502 Sys_FPrintf( SYS_VRB, "--- AddEntitySurfaceModels ---\n" );
3504 /* walk the surface list */
3505 for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3506 numSurfaceModels += AddSurfaceModels( &mapDrawSurfs[ i ] );
3512 VolumeColorMods() - ydnar
3513 applies brush/volumetric color/alpha modulation to vertexes
3516 static void VolumeColorMods( entity_t *e, mapDrawSurface_t *ds ){
3524 if ( e->colorModBrushes == NULL ) {
3528 /* iterate brushes */
3529 for ( b = e->colorModBrushes; b != NULL; b = b->nextColorModBrush )
3531 /* worldspawn alpha brushes affect all, grouped ones only affect original entity */
3532 if ( b->entityNum != 0 && b->entityNum != ds->entityNum ) {
3537 if ( b->mins[ 0 ] > ds->maxs[ 0 ] || b->maxs[ 0 ] < ds->mins[ 0 ] ||
3538 b->mins[ 1 ] > ds->maxs[ 1 ] || b->maxs[ 1 ] < ds->mins[ 1 ] ||
3539 b->mins[ 2 ] > ds->maxs[ 2 ] || b->maxs[ 2 ] < ds->mins[ 2 ] ) {
3544 for ( i = 0; i < ds->numVerts; i++ )
3546 /* iterate planes */
3547 for ( j = 0; j < b->numsides; j++ )
3549 /* point-plane test */
3550 plane = &mapplanes[ b->sides[ j ].planenum ];
3551 d = DotProduct( ds->verts[ i ].xyz, plane->normal ) - plane->dist;
3557 /* apply colormods */
3558 if ( j == b->numsides ) {
3559 ColorMod( b->contentShader->colorMod, 1, &ds->verts[ i ] );
3568 FilterDrawsurfsIntoTree()
3569 upon completion, all drawsurfs that actually generate a reference
3570 will have been emited to the bspfile arrays, and the references
3571 will have valid final indexes
3574 void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
3576 mapDrawSurface_t *ds;
3578 vec3_t origin, mins, maxs;
3580 int numSurfs, numRefs, numSkyboxSurfaces;
3585 Sys_FPrintf( SYS_VRB, "--- FilterDrawsurfsIntoTree ---\n" );
3587 /* filter surfaces into the tree */
3590 numSkyboxSurfaces = 0;
3591 for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3593 /* get surface and try to early out */
3594 ds = &mapDrawSurfs[ i ];
3595 if ( ds->numVerts == 0 && ds->type != SURFACE_FLARE && ds->type != SURFACE_SHADER ) {
3600 si = ds->shaderInfo;
3602 /* ydnar: skybox surfaces are special */
3604 refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
3605 ds->skybox = qfalse;
3612 /* refs initially zero */
3615 /* apply texture coordinate mods */
3616 for ( j = 0; j < ds->numVerts; j++ )
3617 TCMod( si->mod, ds->verts[ j ].st );
3619 /* ydnar: apply shader colormod */
3620 ColorMod( ds->shaderInfo->colorMod, ds->numVerts, ds->verts );
3622 /* ydnar: apply brush colormod */
3623 VolumeColorMods( e, ds );
3625 /* ydnar: make fur surfaces */
3626 if ( si->furNumLayers > 0 ) {
3630 /* ydnar/sd: make foliage surfaces */
3631 if ( si->foliage != NULL ) {
3635 /* create a flare surface if necessary */
3636 if ( si->flareShader != NULL && si->flareShader[ 0 ] ) {
3637 AddSurfaceFlare( ds, e->origin );
3640 /* ydnar: don't emit nodraw surfaces (like nodraw fog) */
3641 if ( ( si->compileFlags & C_NODRAW ) && ds->type != SURFACE_PATCH ) {
3645 /* ydnar: bias the surface textures */
3646 BiasSurfaceTextures( ds );
3648 /* ydnar: globalizing of fog volume handling (eek a hack) */
3649 if ( e != entities && si->noFog == qfalse ) {
3650 /* find surface origin and offset by entity origin */
3651 VectorAdd( ds->mins, ds->maxs, origin );
3652 VectorScale( origin, 0.5f, origin );
3653 VectorAdd( origin, e->origin, origin );
3655 VectorAdd( ds->mins, e->origin, mins );
3656 VectorAdd( ds->maxs, e->origin, maxs );
3658 /* set the fog number for this surface */
3659 ds->fogNum = FogForBounds( mins, maxs, 1.0f ); //% FogForPoint( origin, 0.0f );
3663 /* ydnar: remap shader */
3664 /* if ( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] ) {
3665 ds->shaderInfo = ShaderInfoForShader( ds->shaderInfo->remapShader );
3668 /* ydnar: gs mods: handle the various types of surfaces */
3671 /* handle brush faces */
3675 refs = FilterFaceIntoTree( ds, tree );
3678 EmitFaceSurface( ds );
3682 /* handle patches */
3685 refs = FilterPatchIntoTree( ds, tree );
3688 EmitPatchSurface( e, ds );
3692 /* handle triangle surfaces */
3693 case SURFACE_TRIANGLES:
3694 case SURFACE_FORCED_META:
3696 //% Sys_FPrintf( SYS_VRB, "Surface %4d: [%1d] %4d verts %s\n", numSurfs, ds->planar, ds->numVerts, si->shader );
3698 refs = FilterTrianglesIntoTree( ds, tree );
3701 EmitTriangleSurface( ds );
3705 /* handle foliage surfaces (splash damage/wolf et) */
3706 case SURFACE_FOLIAGE:
3707 //% Sys_FPrintf( SYS_VRB, "Surface %4d: [%d] %4d verts %s\n", numSurfs, ds->numFoliageInstances, ds->numVerts, si->shader );
3709 refs = FilterFoliageIntoTree( ds, tree );
3712 EmitTriangleSurface( ds );
3716 /* handle foghull surfaces */
3717 case SURFACE_FOGHULL:
3719 refs = AddReferenceToTree_r( ds, tree->headnode, qfalse );
3722 EmitTriangleSurface( ds );
3729 refs = FilterFlareSurfIntoTree( ds, tree );
3732 EmitFlareSurface( ds );
3736 /* handle shader-only surfaces */
3737 case SURFACE_SHADER:
3739 EmitFlareSurface( ds );
3748 /* maybe surface got marked as skybox again */
3749 /* if we keep that flag, it will get scaled up AGAIN */
3751 ds->skybox = qfalse;
3754 /* tot up the references */
3760 /* emit extra surface data */
3761 SetSurfaceExtra( ds, numBSPDrawSurfaces - 1 );
3762 //% Sys_FPrintf( SYS_VRB, "%d verts %d indexes\n", ds->numVerts, ds->numIndexes );
3764 /* one last sanity check */
3766 bspDrawSurface_t *out;
3767 out = &bspDrawSurfaces[ numBSPDrawSurfaces - 1 ];
3768 if ( out->numVerts == 3 && out->numIndexes > 3 ) {
3769 Sys_FPrintf( SYS_WRN, "WARNING: Potentially bad %s surface (%d: %d, %d)\n %s\n",
3770 surfaceTypes[ ds->type ],
3771 numBSPDrawSurfaces - 1, out->numVerts, out->numIndexes, si->shader );
3775 /* ydnar: handle skybox surfaces */
3777 MakeSkyboxSurface( ds );
3778 numSkyboxSurfaces++;
3783 /* emit some statistics */
3784 Sys_FPrintf( SYS_VRB, "%9d references\n", numRefs );
3785 Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces );
3786 Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces );
3787 Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces );
3788 Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces );
3789 Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels );
3790 Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces );
3791 for ( i = 0; i < NUM_SURFACE_TYPES; i++ )
3792 Sys_FPrintf( SYS_VRB, "%9d %s surfaces\n", numSurfacesByType[ i ], surfaceTypes[ i ] );
3794 Sys_FPrintf( SYS_VRB, "%9d redundant indexes supressed, saving %d Kbytes\n", numRedundantIndexes, ( numRedundantIndexes * 4 / 1024 ) );