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 )
51 /* ydnar: gs mods: only allocate valid types */
52 if( type <= SURFACE_BAD || type >= NUM_SURFACE_TYPES )
53 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 );
58 ds = &mapDrawSurfs[ numMapDrawSurfs ];
61 /* ydnar: do initial surface setup */
62 memset( ds, 0, sizeof( mapDrawSurface_t ) );
65 ds->fogNum = defaultFogNum; /* ydnar 2003-02-12 */
66 ds->outputNum = -1; /* ydnar 2002-08-13 */
67 ds->surfaceNum = numMapDrawSurfs - 1; /* ydnar 2003-02-16 */
76 ydnar: general surface finish pass
79 void FinishSurface( mapDrawSurface_t *ds )
81 mapDrawSurface_t *ds2;
85 if( ds->type <= SURFACE_BAD || ds->type >= NUM_SURFACE_TYPES || ds == NULL || ds->shaderInfo == NULL )
88 /* ydnar: rocking tek-fu celshading */
89 if( ds->celShader != NULL )
90 MakeCelSurface( ds, ds->celShader );
92 /* backsides stop here */
96 /* ydnar: rocking surface cloning (fur baby yeah!) */
97 if( ds->shaderInfo->cloneShader != NULL && ds->shaderInfo->cloneShader[ 0 ] != '\0' )
98 CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->cloneShader ) );
100 /* ydnar: q3map_backShader support */
101 if( ds->shaderInfo->backShader != NULL && ds->shaderInfo->backShader[ 0 ] != '\0' )
103 ds2 = CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->backShader ) );
104 ds2->backSide = qtrue;
112 clones a map drawsurface, using the specified shader
115 mapDrawSurface_t *CloneSurface( mapDrawSurface_t *src, shaderInfo_t *si )
117 mapDrawSurface_t *ds;
121 if( src == NULL || si == NULL )
124 /* allocate a new surface */
125 ds = AllocDrawSurface( src->type );
130 memcpy( ds, src, sizeof( *ds ) );
132 /* destroy side reference */
139 if( ds->numVerts > 0 )
141 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
142 memcpy( ds->verts, src->verts, ds->numVerts * sizeof( *ds->verts ) );
146 if( ds->numIndexes <= 0 )
148 ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
149 memcpy( ds->indexes, src->indexes, ds->numIndexes * sizeof( *ds->indexes ) );
151 /* return the surface */
158 MakeCelSurface() - ydnar
159 makes a copy of a surface, but specific to cel shading
162 mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si )
164 mapDrawSurface_t *ds;
168 if( src == NULL || si == NULL )
171 /* don't create cel surfaces for certain types of shaders */
172 if( (src->shaderInfo->compileFlags & C_TRANSLUCENT) ||
173 (src->shaderInfo->compileFlags & C_SKY) )
177 ds = CloneSurface( src, si );
181 /* do some fixups for celshading */
184 ds->celShader = NULL; /* don't cel shade cels :P */
186 /* return the surface */
193 MakeSkyboxSurface() - ydnar
194 generates a skybox surface, viewable from everywhere there is sky
197 mapDrawSurface_t *MakeSkyboxSurface( mapDrawSurface_t *src )
200 mapDrawSurface_t *ds;
208 ds = CloneSurface( src, src->shaderInfo );
215 /* scale the surface vertexes */
216 for( i = 0; i < ds->numVerts; i++ )
218 m4x4_transform_point( skyboxTransform, ds->verts[ i ].xyz );
221 //% bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 1 ] = 0;
222 //% bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 2 ] = 0;
225 /* so backface culling creep doesn't bork the surface */
226 VectorClear( ds->lightmapVecs[ 2 ] );
228 /* return the surface */
236 returns qtrue if all three points are colinear, backwards, or the triangle is just plain bogus
239 #define TINY_AREA 1.0f
241 qboolean IsTriangleDegenerate( bspDrawVert_t *points, int a, int b, int c )
247 /* calcuate the area of the triangle */
248 VectorSubtract( points[ b ].xyz, points[ a ].xyz, v1 );
249 VectorSubtract( points[ c ].xyz, points[ a ].xyz, v2 );
250 CrossProduct( v1, v2, v3 );
251 d = VectorLength( v3 );
253 /* assume all very small or backwards triangles will cause problems */
257 /* must be a good triangle */
264 ClearSurface() - ydnar
265 clears a surface and frees any allocated memory
268 void ClearSurface( mapDrawSurface_t *ds )
270 ds->type = SURFACE_BAD;
274 if( ds->verts != NULL )
278 if( ds->indexes != NULL )
281 numClearedSurfaces++;
287 TidyEntitySurfaces() - ydnar
288 deletes all empty or bad surfaces from the surface list
291 void TidyEntitySurfaces( entity_t *e )
294 mapDrawSurface_t *out, *in = NULL;
298 Sys_FPrintf( SYS_VRB, "--- TidyEntitySurfaces ---\n" );
300 /* walk the surface list */
302 for( i = e->firstDrawSurf, j = e->firstDrawSurf; j < numMapDrawSurfs; i++, j++ )
304 /* get out surface */
305 out = &mapDrawSurfs[ i ];
307 /* walk the surface list again until a proper surface is found */
308 for( ; j < numMapDrawSurfs; j++ )
311 in = &mapDrawSurfs[ j ];
313 /* this surface ok? */
314 if( in->type == SURFACE_FLARE || in->type == SURFACE_SHADER ||
315 (in->type != SURFACE_BAD && in->numVerts > 0) )
323 /* copy if necessary */
325 memcpy( out, in, sizeof( mapDrawSurface_t ) );
328 /* set the new number of drawsurfs */
331 /* emit some stats */
332 Sys_FPrintf( SYS_VRB, "%9d empty or malformed surfaces deleted\n", deleted );
338 CalcSurfaceTextureRange() - ydnar
339 calculates the clamped texture range for a given surface, returns qtrue if it's within [-texRange,texRange]
342 qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds )
344 int i, j, v, size[ 2 ];
345 float mins[ 2 ], maxs[ 2 ];
348 /* try to early out */
349 if( ds->numVerts <= 0 )
352 /* walk the verts and determine min/max st values */
357 for( i = 0; i < ds->numVerts; i++ )
359 for( j = 0; j < 2; j++ )
361 if( ds->verts[ i ].st[ j ] < mins[ j ] )
362 mins[ j ] = ds->verts[ i ].st[ j ];
363 if( ds->verts[ i ].st[ j ] > maxs[ j ] )
364 maxs[ j ] = ds->verts[ i ].st[ j ];
368 /* clamp to integer range and calculate surface bias values */
369 for( j = 0; j < 2; j++ )
370 ds->bias[ j ] = -floor( 0.5f * (mins[ j ] + maxs[ j ]) );
372 /* find biased texture coordinate mins/maxs */
373 size[ 0 ] = ds->shaderInfo->shaderWidth;
374 size[ 1 ] = ds->shaderInfo->shaderHeight;
375 ds->texMins[ 0 ] = 999999;
376 ds->texMins[ 1 ] = 999999;
377 ds->texMaxs[ 0 ] = -999999;
378 ds->texMaxs[ 1 ] = -999999;
379 for( i = 0; i < ds->numVerts; i++ )
381 for( j = 0; j < 2; j++ )
383 v = ((float) ds->verts[ i ].st[ j ] + ds->bias[ j ]) * size[ j ];
384 if( v < ds->texMins[ j ] )
385 ds->texMins[ j ] = v;
386 if( v > ds->texMaxs[ j ] )
387 ds->texMaxs[ j ] = v;
392 for( j = 0; j < 2; j++ )
393 ds->texRange[ j ] = (ds->texMaxs[ j ] - ds->texMins[ j ]);
395 /* if range is zero, then assume unlimited precision */
400 for( j = 0; j < 2; j++ )
402 if( ds->texMins[ j ] < -texRange || ds->texMaxs[ j ] > texRange )
413 CalcLightmapAxis() - ydnar
414 gives closed lightmap axis for a plane normal
417 qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis )
423 if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && normal[ 2 ] == 0.0f )
429 /* get absolute normal */
430 absolute[ 0 ] = fabs( normal[ 0 ] );
431 absolute[ 1 ] = fabs( normal[ 1 ] );
432 absolute[ 2 ] = fabs( normal[ 2 ] );
435 if( absolute[ 2 ] > absolute[ 0 ] - 0.0001f && absolute[ 2 ] > absolute[ 1 ] - 0.0001f )
437 if( normal[ 2 ] > 0.0f )
438 VectorSet( axis, 0.0f, 0.0f, 1.0f );
440 VectorSet( axis, 0.0f, 0.0f, -1.0f );
442 else if( absolute[ 0 ] > absolute[ 1 ] - 0.0001f && absolute[ 0 ] > absolute[ 2 ] - 0.0001f )
444 if( normal[ 0 ] > 0.0f )
445 VectorSet( axis, 1.0f, 0.0f, 0.0f );
447 VectorSet( axis, -1.0f, 0.0f, 0.0f );
451 if( normal[ 1 ] > 0.0f )
452 VectorSet( axis, 0.0f, 1.0f, 0.0f );
454 VectorSet( axis, 0.0f, -1.0f, 0.0f );
464 ClassifySurfaces() - ydnar
465 fills out a bunch of info in the surfaces, including planar status, lightmap projection, and bounding box
468 #define PLANAR_EPSILON 0.5f //% 0.126f 0.25f
470 void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds )
476 static vec3_t axii[ 6 ] =
487 /* walk the list of surfaces */
488 for( ; numSurfs > 0; numSurfs--, ds++ )
490 /* ignore bogus (or flare) surfaces */
491 if( ds->type == SURFACE_BAD || ds->numVerts <= 0 )
497 /* -----------------------------------------------------------------
498 force meta if vertex count is too high or shader requires it
499 ----------------------------------------------------------------- */
501 if( ds->type != SURFACE_PATCH && ds->type != SURFACE_FACE )
503 if( ds->numVerts > SHADER_MAX_VERTEXES )
504 ds->type = SURFACE_FORCED_META;
507 /* -----------------------------------------------------------------
508 plane and bounding box classification
509 ----------------------------------------------------------------- */
511 /* set surface bounding box */
512 ClearBounds( ds->mins, ds->maxs );
513 for( i = 0; i < ds->numVerts; i++ )
514 AddPointToBounds( ds->verts[ i ].xyz, ds->mins, ds->maxs );
516 /* try to get an existing plane */
517 if( ds->planeNum >= 0 )
519 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
520 plane[ 3 ] = mapplanes[ ds->planeNum ].dist;
523 /* construct one from the first vert with a valid normal */
526 VectorClear( plane );
528 for( i = 0; i < ds->numVerts; i++ )
530 if( ds->verts[ i ].normal[ 0 ] != 0.0f && ds->verts[ i ].normal[ 1 ] != 0.0f && ds->verts[ i ].normal[ 2 ] != 0.0f )
532 VectorCopy( ds->verts[ i ].normal, plane );
533 plane[ 3 ] = DotProduct( ds->verts[ i ].xyz, plane );
539 /* test for bogus plane */
540 if( VectorLength( plane ) <= 0.0f )
547 /* determine if surface is planar */
551 for( i = 0; i < ds->numVerts; i++ )
553 /* point-plane test */
554 dist = DotProduct( ds->verts[ i ].xyz, plane ) - plane[ 3 ];
555 if( fabs( dist ) > PLANAR_EPSILON )
557 //% if( ds->planeNum >= 0 )
559 //% Sys_Printf( "WARNING: Planar surface marked unplanar (%f > %f)\n", fabs( dist ), PLANAR_EPSILON );
560 //% ds->verts[ i ].color[ 0 ][ 0 ] = ds->verts[ i ].color[ 0 ][ 2 ] = 0;
568 /* find map plane if necessary */
571 if( ds->planeNum < 0 )
572 ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &ds->verts[ 0 ].xyz );
573 VectorCopy( plane, ds->lightmapVecs[ 2 ] );
578 VectorClear( ds->lightmapVecs[ 2 ] );
579 //% if( ds->type == SURF_META || ds->type == SURF_FACE )
580 //% Sys_Printf( "WARNING: Non-planar face (%d): %s\n", ds->planeNum, ds->shaderInfo->shader );
583 /* -----------------------------------------------------------------
584 lightmap bounds and axis projection
585 ----------------------------------------------------------------- */
587 /* vertex lit surfaces don't need this information */
588 if( si->compileFlags & C_VERTEXLIT || ds->type == SURFACE_TRIANGLES )
590 VectorClear( ds->lightmapAxis );
591 //% VectorClear( ds->lightmapVecs[ 2 ] );
596 /* the shader can specify an explicit lightmap axis */
597 if( si->lightmapAxis[ 0 ] || si->lightmapAxis[ 1 ] || si->lightmapAxis[ 2 ] )
598 VectorCopy( si->lightmapAxis, ds->lightmapAxis );
599 else if( ds->type == SURFACE_FORCED_META )
600 VectorClear( ds->lightmapAxis );
601 else if( ds->planar )
602 CalcLightmapAxis( plane, ds->lightmapAxis );
605 /* find best lightmap axis */
606 for( bestAxis = 0; bestAxis < 6; bestAxis++ )
608 for( i = 0; i < ds->numVerts && bestAxis < 6; i++ )
610 //% Sys_Printf( "Comparing %1.3f %1.3f %1.3f to %1.3f %1.3f %1.3f\n",
611 //% ds->verts[ i ].normal[ 0 ], ds->verts[ i ].normal[ 1 ], ds->verts[ i ].normal[ 2 ],
612 //% axii[ bestAxis ][ 0 ], axii[ bestAxis ][ 1 ], axii[ bestAxis ][ 2 ] );
613 if( DotProduct( ds->verts[ i ].normal, axii[ bestAxis ] ) < 0.25f ) /* fixme: adjust this tolerance to taste */
617 if( i == ds->numVerts )
621 /* set axis if possible */
624 //% if( ds->type == SURFACE_PATCH )
625 //% Sys_Printf( "Mapped axis %d onto patch\n", bestAxis );
626 VectorCopy( axii[ bestAxis ], ds->lightmapAxis );
630 //% if( ds->type == SURFACE_PATCH )
631 //% Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis );
634 /* calculate lightmap sample size */
635 if( ds->shaderInfo->lightmapSampleSize > 0 ) /* shader value overrides every other */
636 ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
637 else if( ds->sampleSize <= 0 ) /* may contain the entity asigned value */
638 ds->sampleSize = sampleSize; /* otherwise use global default */
640 if( ds->lightmapScale > 0.0f ) /* apply surface lightmap scaling factor */
642 ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize;
643 ds->lightmapScale = 0; /* applied */
646 if( ds->sampleSize < minSampleSize )
647 ds->sampleSize = minSampleSize;
649 if( ds->sampleSize < 1 )
652 if( ds->sampleSize > 16384 ) /* powers of 2 are preferred */
653 ds->sampleSize = 16384;
660 ClassifyEntitySurfaces() - ydnar
661 classifies all surfaces in an entity
664 void ClassifyEntitySurfaces( entity_t *e )
670 Sys_FPrintf( SYS_VRB, "--- ClassifyEntitySurfaces ---\n" );
672 /* walk the surface list */
673 for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
675 FinishSurface( &mapDrawSurfs[ i ] );
676 ClassifySurfaces( 1, &mapDrawSurfs[ i ] );
680 TidyEntitySurfaces( e );
686 GetShaderIndexForPoint() - ydnar
687 for shader-indexed surfaces (terrain), find a matching index from the indexmap
690 byte GetShaderIndexForPoint( indexMap_t *im, vec3_t eMins, vec3_t eMaxs, vec3_t point )
694 vec3_t mins, maxs, size;
697 /* early out if no indexmap */
701 /* this code is really broken */
703 /* legacy precision fudges for terrain */
704 for( i = 0; i < 3; i++ )
706 mins[ i ] = floor( eMins[ i ] + 0.1 );
707 maxs[ i ] = floor( eMaxs[ i ] + 0.1 );
708 size[ i ] = maxs[ i ] - mins[ i ];
711 /* find st (fixme: support more than just z-axis projection) */
712 s = floor( point[ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
713 t = floor( maxs[ 1 ] - point[ 1 ] + 0.1f ) / size[ 1 ];
728 for( i = 0; i < 3; i++ )
730 mins[ i ] = eMins[ i ];
731 maxs[ i ] = eMaxs[ i ];
732 size[ i ] = maxs[ i ] - mins[ i ];
736 s = (point[ 0 ] - mins[ 0 ]) / size[ 0 ];
737 t = (maxs[ 1 ] - point[ 1 ]) / size[ 1 ];
744 else if( x > (im->w - 1) )
748 else if( y > (im->h - 1) )
753 return im->pixels[ y * im->w + x ];
759 GetIndexedShader() - ydnar
760 for a given set of indexes and an indexmap, get a shader and set the vertex alpha in-place
761 this combines a couple different functions from terrain.c
764 shaderInfo_t *GetIndexedShader( shaderInfo_t *parent, indexMap_t *im, int numPoints, byte *shaderIndexes )
767 byte minShaderIndex, maxShaderIndex;
768 char shader[ MAX_QPATH ];
772 /* early out if bad data */
773 if( im == NULL || numPoints <= 0 || shaderIndexes == NULL )
774 return ShaderInfoForShader( "default" );
776 /* determine min/max index */
777 minShaderIndex = 255;
779 for( i = 0; i < numPoints; i++ )
781 if( shaderIndexes[ i ] < minShaderIndex )
782 minShaderIndex = shaderIndexes[ i ];
783 if( shaderIndexes[ i ] > maxShaderIndex )
784 maxShaderIndex = shaderIndexes[ i ];
787 /* set alpha inline */
788 for( i = 0; i < numPoints; i++ )
790 /* straight rip from terrain.c */
791 if( shaderIndexes[ i ] < maxShaderIndex )
792 shaderIndexes[ i ] = 0;
794 shaderIndexes[ i ] = 255;
797 /* make a shader name */
798 if( minShaderIndex == maxShaderIndex )
799 sprintf( shader, "textures/%s_%d", im->shader, maxShaderIndex );
801 sprintf( shader, "textures/%s_%dto%d", im->shader, minShaderIndex, maxShaderIndex );
804 si = ShaderInfoForShader( shader );
806 /* inherit a few things from parent shader */
807 if( parent->globalTexture )
808 si->globalTexture = qtrue;
809 if( parent->forceMeta )
810 si->forceMeta = qtrue;
811 if( parent->nonplanar )
812 si->nonplanar = qtrue;
813 if( si->shadeAngleDegrees == 0.0 )
814 si->shadeAngleDegrees = parent->shadeAngleDegrees;
815 if( parent->tcGen && si->tcGen == qfalse )
817 /* set xy texture projection */
819 VectorCopy( parent->vecs[ 0 ], si->vecs[ 0 ] );
820 VectorCopy( parent->vecs[ 1 ], si->vecs[ 1 ] );
822 if( VectorLength( parent->lightmapAxis ) > 0.0f && VectorLength( si->lightmapAxis ) <= 0.0f )
824 /* set lightmap projection axis */
825 VectorCopy( parent->lightmapAxis, si->lightmapAxis );
828 /* return the shader */
837 creates a SURF_FACE drawsurface from a given brush side and winding
840 #define SNAP_FLOAT_TO_INT 8
841 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
843 mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w )
846 mapDrawSurface_t *ds;
847 shaderInfo_t *si, *parent;
853 byte shaderIndexes[ 256 ];
854 float offsets[ 256 ];
855 char tempShader[ MAX_QPATH ];
858 /* ydnar: don't make a drawsurf for culled sides */
863 if( w->numpoints > MAX_POINTS_ON_WINDING )
864 Error( "DrawSurfaceForSide: w->numpoints = %d (> %d)", w->numpoints, MAX_POINTS_ON_WINDING );
869 /* ydnar: gs mods: check for indexed shader */
870 if( si->indexed && b->im != NULL )
875 /* get shader indexes for each point */
876 for( i = 0; i < w->numpoints; i++ )
878 shaderIndexes[ i ] = GetShaderIndexForPoint( b->im, b->eMins, b->eMaxs, w->p[ i ] );
879 offsets[ i ] = b->im->offsets[ shaderIndexes[ i ] ];
880 //% Sys_Printf( "%f ", offsets[ i ] );
883 /* get matching shader and set alpha */
885 si = GetIndexedShader( parent, b->im, w->numpoints, shaderIndexes );
890 /* ydnar: sky hack/fix for GL_CLAMP borders on ati cards */
891 if( skyFixHack && si->skyParmsImageBase[ 0 ] != '\0' )
893 //% Sys_FPrintf( SYS_VRB, "Enabling sky hack for shader %s using env %s\n", si->shader, si->skyParmsImageBase );
894 sprintf( tempShader, "%s_lf", si->skyParmsImageBase );
895 DrawSurfaceForShader( tempShader );
896 sprintf( tempShader, "%s_rt", si->skyParmsImageBase );
897 DrawSurfaceForShader( tempShader );
898 sprintf( tempShader, "%s_ft", si->skyParmsImageBase );
899 DrawSurfaceForShader( tempShader );
900 sprintf( tempShader, "%s_bk", si->skyParmsImageBase );
901 DrawSurfaceForShader( tempShader );
902 sprintf( tempShader, "%s_up", si->skyParmsImageBase );
903 DrawSurfaceForShader( tempShader );
904 sprintf( tempShader, "%s_dn", si->skyParmsImageBase );
905 DrawSurfaceForShader( tempShader );
909 ds = AllocDrawSurface( SURFACE_FACE );
910 ds->entityNum = b->entityNum;
911 ds->castShadows = b->castShadows;
912 ds->recvShadows = b->recvShadows;
915 ds->planeNum = s->planenum;
916 VectorCopy( mapplanes[ s->planenum ].normal, ds->lightmapVecs[ 2 ] );
920 ds->sideRef = AllocSideRef( s, NULL );
922 ds->sampleSize = b->lightmapSampleSize;
923 ds->lightmapScale = b->lightmapScale;
924 ds->numVerts = w->numpoints;
925 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
926 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
928 /* compute s/t coordinates from brush primitive texture matrix (compute axis base) */
929 ComputeAxisBase( mapplanes[ s->planenum ].normal, texX, texY );
931 /* create the vertexes */
932 for( j = 0; j < w->numpoints; j++ )
934 /* get the drawvert */
937 /* copy xyz and do potential z offset */
938 VectorCopy( w->p[ j ], dv->xyz );
940 dv->xyz[ 2 ] += offsets[ j ];
942 /* round the xyz to a given precision and translate by origin */
943 for( i = 0 ; i < 3 ; i++ )
944 dv->xyz[ i ] = SNAP_INT_TO_FLOAT * floor( dv->xyz[ i ] * SNAP_FLOAT_TO_INT + 0.5f );
945 VectorAdd( dv->xyz, e->origin, vTranslated );
947 /* ydnar: tek-fu celshading support for flat shaded shit */
950 dv->st[ 0 ] = si->stFlat[ 0 ];
951 dv->st[ 1 ] = si->stFlat[ 1 ];
954 /* ydnar: gs mods: added support for explicit shader texcoord generation */
957 dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
958 dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
961 /* old quake-style texturing */
962 else if( g_bBrushPrimit == BPRIMIT_OLDBRUSHES )
964 /* nearest-axial projection */
965 dv->st[ 0 ] = s->vecs[ 0 ][ 3 ] + DotProduct( s->vecs[ 0 ], vTranslated );
966 dv->st[ 1 ] = s->vecs[ 1 ][ 3 ] + DotProduct( s->vecs[ 1 ], vTranslated );
967 dv->st[ 0 ] /= si->shaderWidth;
968 dv->st[ 1 ] /= si->shaderHeight;
971 /* brush primitive texturing */
974 /* calculate texture s/t from brush primitive texture matrix */
975 x = DotProduct( vTranslated, texX );
976 y = DotProduct( vTranslated, texY );
977 dv->st[ 0 ] = s->texMat[ 0 ][ 0 ] * x + s->texMat[ 0 ][ 1 ] * y + s->texMat[ 0 ][ 2 ];
978 dv->st[ 1 ] = s->texMat[ 1 ][ 0 ] * x + s->texMat[ 1 ][ 1 ] * y + s->texMat[ 1 ][ 2 ];
982 VectorCopy( mapplanes[ s->planenum ].normal, dv->normal );
984 /* ydnar: set color */
985 for( k = 0; k < MAX_LIGHTMAPS; k++ )
987 dv->color[ k ][ 0 ] = 255;
988 dv->color[ k ][ 1 ] = 255;
989 dv->color[ k ][ 2 ] = 255;
991 /* ydnar: gs mods: handle indexed shader blending */
992 dv->color[ k ][ 3 ] = (indexed ? shaderIndexes[ j ] : 255);
997 ds->celShader = b->celShader;
999 /* set shade angle */
1000 if( b->shadeAngleDegrees > 0.0f )
1001 ds->shadeAngleDegrees = b->shadeAngleDegrees;
1003 /* ydnar: gs mods: moved st biasing elsewhere */
1010 DrawSurfaceForMesh()
1011 moved here from patch.c
1014 #define YDNAR_NORMAL_EPSILON 0.50f
1016 qboolean VectorCompareExt( vec3_t n1, vec3_t n2, float epsilon )
1022 for( i= 0; i < 3; i++ )
1023 if( fabs( n1[ i ] - n2[ i ]) > epsilon )
1028 mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh )
1034 mapDrawSurface_t *ds;
1035 shaderInfo_t *si, *parent;
1040 byte shaderIndexes[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1041 float offsets[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1044 /* get mesh and shader shader */
1048 if( mesh == NULL || si == NULL )
1051 /* get vertex count */
1052 numVerts = mesh->width * mesh->height;
1054 /* to make valid normals for patches with degenerate edges,
1055 we need to make a copy of the mesh and put the aproximating
1056 points onto the curve */
1058 /* create a copy of the mesh */
1059 copy = CopyMesh( mesh );
1061 /* store off the original (potentially bad) normals */
1062 MakeMeshNormals( *copy );
1063 for( i = 0; i < numVerts; i++ )
1064 VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1066 /* put the mesh on the curve */
1067 PutMeshOnCurve( *copy );
1069 /* find new normals (to take into account degenerate/flipped edges */
1070 MakeMeshNormals( *copy );
1071 for( i = 0; i < numVerts; i++ )
1073 /* ydnar: only copy normals that are significantly different from the originals */
1074 if( DotProduct( copy->verts[ i ].normal, mesh->verts[ i ].normal ) < 0.75f )
1075 VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1078 /* free the old mesh */
1081 /* ydnar: gs mods: check for indexed shader */
1082 if( si->indexed && p->im != NULL )
1087 /* get shader indexes for each point */
1088 for( i = 0; i < numVerts; i++ )
1090 shaderIndexes[ i ] = GetShaderIndexForPoint( p->im, p->eMins, p->eMaxs, mesh->verts[ i ].xyz );
1091 offsets[ i ] = p->im->offsets[ shaderIndexes[ i ] ];
1094 /* get matching shader and set alpha */
1096 si = GetIndexedShader( parent, p->im, numVerts, shaderIndexes );
1102 /* ydnar: gs mods */
1103 ds = AllocDrawSurface( SURFACE_PATCH );
1104 ds->entityNum = p->entityNum;
1105 ds->castShadows = p->castShadows;
1106 ds->recvShadows = p->recvShadows;
1108 ds->shaderInfo = si;
1110 ds->sampleSize = p->lightmapSampleSize;
1111 ds->lightmapScale = p->lightmapScale; /* ydnar */
1112 ds->patchWidth = mesh->width;
1113 ds->patchHeight = mesh->height;
1114 ds->numVerts = ds->patchWidth * ds->patchHeight;
1115 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
1116 memcpy( ds->verts, mesh->verts, ds->numVerts * sizeof( *ds->verts ) );
1121 ds->longestCurve = p->longestCurve;
1122 ds->maxIterations = p->maxIterations;
1124 /* construct a plane from the first vert */
1125 VectorCopy( mesh->verts[ 0 ].normal, plane );
1126 plane[ 3 ] = DotProduct( mesh->verts[ 0 ].xyz, plane );
1129 /* spew forth errors */
1130 if( VectorLength( plane ) < 0.001f )
1131 Sys_Printf( "BOGUS " );
1133 /* test each vert */
1134 for( i = 1; i < ds->numVerts && planar; i++ )
1137 if( VectorCompare( plane, mesh->verts[ i ].normal ) == qfalse )
1140 /* point-plane test */
1141 dist = DotProduct( mesh->verts[ i ].xyz, plane ) - plane[ 3 ];
1142 if( fabs( dist ) > EQUAL_EPSILON )
1146 /* add a map plane */
1149 /* make a map plane */
1150 ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &mesh->verts[ 0 ].xyz );
1151 VectorCopy( plane, ds->lightmapVecs[ 2 ] );
1153 /* push this normal to all verts (ydnar 2003-02-14: bad idea, small patches get screwed up) */
1154 for( i = 0; i < ds->numVerts; i++ )
1155 VectorCopy( plane, ds->verts[ i ].normal );
1158 /* walk the verts to do special stuff */
1159 for( i = 0; i < ds->numVerts; i++ )
1161 /* get the drawvert */
1162 dv = &ds->verts[ i ];
1164 /* ydnar: tek-fu celshading support for flat shaded shit */
1167 dv->st[ 0 ] = si->stFlat[ 0 ];
1168 dv->st[ 1 ] = si->stFlat[ 1 ];
1171 /* ydnar: gs mods: added support for explicit shader texcoord generation */
1172 else if( si->tcGen )
1174 /* translate by origin and project the texture */
1175 VectorAdd( dv->xyz, e->origin, vTranslated );
1176 dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
1177 dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
1180 /* ydnar: set color */
1181 for( k = 0; k < MAX_LIGHTMAPS; k++ )
1183 dv->color[ k ][ 0 ] = 255;
1184 dv->color[ k ][ 1 ] = 255;
1185 dv->color[ k ][ 2 ] = 255;
1187 /* ydnar: gs mods: handle indexed shader blending */
1188 dv->color[ k ][ 3 ] = (indexed ? shaderIndexes[ i ] : 255);
1193 dv->xyz[ 2 ] += offsets[ i ];
1196 /* set cel shader */
1197 ds->celShader = p->celShader;
1199 /* return the drawsurface */
1206 DrawSurfaceForFlare() - ydnar
1207 creates a flare draw surface
1210 mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle )
1212 mapDrawSurface_t *ds;
1216 if( emitFlares == qfalse )
1219 /* allocate drawsurface */
1220 ds = AllocDrawSurface( SURFACE_FLARE );
1221 ds->entityNum = entNum;
1224 if( flareShader != NULL && flareShader[ 0 ] != '\0' )
1225 ds->shaderInfo = ShaderInfoForShader( flareShader );
1227 ds->shaderInfo = ShaderInfoForShader( game->flareShader );
1228 if( origin != NULL )
1229 VectorCopy( origin, ds->lightmapOrigin );
1230 if( normal != NULL )
1231 VectorCopy( normal, ds->lightmapVecs[ 2 ] );
1233 VectorCopy( color, ds->lightmapVecs[ 0 ] );
1235 /* store light style */
1236 ds->lightStyle = lightStyle;
1237 if( ds->lightStyle < 0 || ds->lightStyle >= LS_NONE )
1238 ds->lightStyle = LS_NORMAL;
1242 /* return to sender */
1249 DrawSurfaceForShader() - ydnar
1250 creates a bogus surface to forcing the game to load a shader
1253 mapDrawSurface_t *DrawSurfaceForShader( char *shader )
1257 mapDrawSurface_t *ds;
1261 si = ShaderInfoForShader( shader );
1263 /* find existing surface */
1264 for( i = 0; i < numMapDrawSurfs; i++ )
1267 ds = &mapDrawSurfs[ i ];
1270 if( ds->shaderInfo == si )
1274 /* create a new surface */
1275 ds = AllocDrawSurface( SURFACE_SHADER );
1277 ds->shaderInfo = ShaderInfoForShader( shader );
1279 /* return to sender */
1286 AddSurfaceFlare() - ydnar
1287 creates flares (coronas) centered on surfaces
1290 static void AddSurfaceFlare( mapDrawSurface_t *ds, vec3_t entityOrigin )
1297 VectorClear( origin );
1298 for ( i = 0; i < ds->numVerts; i++ )
1299 VectorAdd( origin, ds->verts[ i ].xyz, origin );
1300 VectorScale( origin, (1.0f / ds->numVerts), origin );
1301 if( entityOrigin != NULL )
1302 VectorAdd( origin, entityOrigin, origin );
1304 /* push origin off surface a bit */
1305 VectorMA( origin, 2.0f, ds->lightmapVecs[ 2 ], origin );
1307 /* create the drawsurface */
1308 DrawSurfaceForFlare( ds->entityNum, origin, ds->lightmapVecs[ 2 ], ds->shaderInfo->color, ds->shaderInfo->flareShader, ds->shaderInfo->lightStyle );
1315 subdivides a face surface until it is smaller than the specified size (subdivisions)
1318 static void SubdivideFace_r( entity_t *e, brush_t *brush, side_t *side, winding_t *w, int fogNum, float subdivisions )
1323 const float epsilon = 0.1;
1324 int subFloor, subCeil;
1325 winding_t *frontWinding, *backWinding;
1326 mapDrawSurface_t *ds;
1332 if( w->numpoints < 3 )
1333 Error( "SubdivideFace_r: Bad w->numpoints (%d < 3)", w->numpoints );
1335 /* determine surface bounds */
1336 ClearBounds( bounds[ 0 ], bounds[ 1 ] );
1337 for( i = 0; i < w->numpoints; i++ )
1338 AddPointToBounds( w->p[ i ], bounds[ 0 ], bounds[ 1 ] );
1340 /* split the face */
1341 for( axis = 0; axis < 3; axis++ )
1343 vec3_t planePoint = { 0, 0, 0 };
1344 vec3_t planeNormal = { 0, 0, 0 };
1348 /* create an axial clipping plane */
1349 subFloor = floor( bounds[ 0 ][ axis ] / subdivisions) * subdivisions;
1350 subCeil = ceil( bounds[ 1 ][ axis ] / subdivisions) * subdivisions;
1351 planePoint[ axis ] = subFloor + subdivisions;
1352 planeNormal[ axis ] = -1;
1353 d = DotProduct( planePoint, planeNormal );
1355 /* subdivide if necessary */
1356 if( (subCeil - subFloor) > subdivisions )
1358 /* clip the winding */
1359 ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding ); /* not strict; we assume we always keep a winding */
1361 /* the clip may not produce two polygons if it was epsilon close */
1362 if( frontWinding == NULL )
1364 else if( backWinding == NULL )
1368 SubdivideFace_r( e, brush, side, frontWinding, fogNum, subdivisions );
1369 SubdivideFace_r( e, brush, side, backWinding, fogNum, subdivisions );
1375 /* create a face surface */
1376 ds = DrawSurfaceForSide( e, brush, side, w );
1378 /* set correct fog num */
1379 ds->fogNum = fogNum;
1385 SubdivideFaceSurfaces()
1386 chop up brush face surfaces that have subdivision attributes
1387 ydnar: and subdivide surfaces that exceed specified texture coordinate range
1390 void SubdivideFaceSurfaces( entity_t *e, tree_t *tree )
1392 int i, j, numBaseDrawSurfs, fogNum;
1393 mapDrawSurface_t *ds;
1398 float range, size, subdivisions, s2;
1402 Sys_FPrintf( SYS_VRB, "--- SubdivideFaceSurfaces ---\n" );
1404 /* walk the list of surfaces */
1405 numBaseDrawSurfs = numMapDrawSurfs;
1406 for( i = e->firstDrawSurf; i < numBaseDrawSurfs; i++ )
1409 ds = &mapDrawSurfs[ i ];
1411 /* only subdivide brush sides */
1412 if( ds->type != SURFACE_FACE || ds->mapBrush == NULL || ds->sideRef == NULL || ds->sideRef->side == NULL )
1416 brush = ds->mapBrush;
1417 side = ds->sideRef->side;
1419 /* check subdivision for shader */
1420 si = side->shaderInfo;
1424 /* ydnar: don't subdivide sky surfaces */
1425 if( si->compileFlags & C_SKY )
1428 /* do texture coordinate range check */
1429 ClassifySurfaces( 1, ds );
1430 if( CalcSurfaceTextureRange( ds ) == qfalse )
1432 /* calculate subdivisions texture range (this code is shit) */
1433 range = (ds->texRange[ 0 ] > ds->texRange[ 1 ] ? ds->texRange[ 0 ] : ds->texRange[ 1 ]);
1434 size = ds->maxs[ 0 ] - ds->mins[ 0 ];
1435 for( j = 1; j < 3; j++ )
1436 if( (ds->maxs[ j ] - ds->mins[ j ]) > size )
1437 size = ds->maxs[ j ] - ds->mins[ j ];
1438 subdivisions = (size / range) * texRange;
1439 subdivisions = ceil( subdivisions / 2 ) * 2;
1440 for( j = 1; j < 8; j++ )
1442 s2 = ceil( (float) texRange / j );
1443 if( fabs( subdivisions - s2 ) <= 4.0 )
1451 subdivisions = si->subdivisions;
1453 /* get subdivisions from shader */
1454 if( si->subdivisions > 0 && si->subdivisions < subdivisions )
1455 subdivisions = si->subdivisions;
1456 if( subdivisions < 1.0f )
1459 /* preserve fog num */
1460 fogNum = ds->fogNum;
1462 /* make a winding and free the surface */
1463 w = WindingFromDrawSurf( ds );
1467 SubdivideFace_r( e, brush, side, w, fogNum, subdivisions );
1474 ====================
1477 Adds non-opaque leaf fragments to the convex hull
1478 ====================
1481 void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node )
1484 winding_t *front, *back;
1490 if ( node->planenum != PLANENUM_LEAF ) {
1491 if ( side->planenum == node->planenum ) {
1492 ClipSideIntoTree_r( w, side, node->children[0] );
1495 if ( side->planenum == ( node->planenum ^ 1) ) {
1496 ClipSideIntoTree_r( w, side, node->children[1] );
1500 plane = &mapplanes[ node->planenum ];
1501 ClipWindingEpsilonStrict ( w, plane->normal, plane->dist,
1502 ON_EPSILON, &front, &back ); /* strict, we handle the "winding disappeared" case */
1505 /* in doubt, register it in both nodes */
1506 front = CopyWinding(w);
1507 back = CopyWinding(w);
1511 ClipSideIntoTree_r( front, side, node->children[0] );
1512 ClipSideIntoTree_r( back, side, node->children[1] );
1517 // if opaque leaf, don't add
1518 if ( !node->opaque ) {
1519 AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
1530 static int g_numHiddenFaces, g_numCoinFaces;
1535 CullVectorCompare() - ydnar
1536 compares two vectors with an epsilon
1539 #define CULL_EPSILON 0.1f
1541 qboolean CullVectorCompare( const vec3_t v1, const vec3_t v2 )
1546 for( i = 0; i < 3; i++ )
1547 if( fabs( v1[ i ] - v2[ i ] ) > CULL_EPSILON )
1555 SideInBrush() - ydnar
1556 determines if a brushside lies inside another brush
1559 qboolean SideInBrush( side_t *side, brush_t *b )
1565 /* ignore sides w/o windings or shaders */
1566 if( side->winding == NULL || side->shaderInfo == NULL )
1569 /* ignore culled sides and translucent brushes */
1570 if( side->culled == qtrue || (b->compileFlags & C_TRANSLUCENT) )
1574 for( i = 0; i < b->numsides; i++ )
1576 /* fail if any sides are caulk */
1577 if( b->sides[ i ].compileFlags & C_NODRAW )
1580 /* check if side's winding is on or behind the plane */
1581 plane = &mapplanes[ b->sides[ i ].planenum ];
1582 s = WindingOnPlaneSide( side->winding, plane->normal, plane->dist );
1583 if( s == SIDE_FRONT || s == SIDE_CROSS )
1587 /* don't cull autosprite or polygonoffset surfaces */
1588 if( side->shaderInfo )
1590 if( side->shaderInfo->autosprite || side->shaderInfo->polygonOffset )
1595 side->culled = qtrue;
1603 culls obscured or buried brushsides from the map
1606 void CullSides( entity_t *e )
1609 int i, j, k, l, first, second, dir;
1612 side_t *side1, *side2;
1616 Sys_FPrintf( SYS_VRB, "--- CullSides ---\n" );
1618 g_numHiddenFaces = 0;
1621 /* brush interator 1 */
1622 for( b1 = e->brushes; b1; b1 = b1->next )
1625 if( b1->numsides < 1 )
1628 /* brush iterator 2 */
1629 for( b2 = b1->next; b2; b2 = b2->next )
1632 if( b2->numsides < 1 )
1635 /* original check */
1636 if( b1->original == b2->original && b1->original != NULL )
1641 for( i = 0; i < 3; i++ )
1642 if( b1->mins[ i ] > b2->maxs[ i ] || b1->maxs[ i ] < b2->mins[ i ] )
1647 /* cull inside sides */
1648 for( i = 0; i < b1->numsides; i++ )
1649 SideInBrush( &b1->sides[ i ], b2 );
1650 for( i = 0; i < b2->numsides; i++ )
1651 SideInBrush( &b2->sides[ i ], b1 );
1653 /* side iterator 1 */
1654 for( i = 0; i < b1->numsides; i++ )
1657 side1 = &b1->sides[ i ];
1658 w1 = side1->winding;
1661 numPoints = w1->numpoints;
1662 if( side1->shaderInfo == NULL )
1665 /* side iterator 2 */
1666 for( j = 0; j < b2->numsides; j++ )
1669 side2 = &b2->sides[ j ];
1670 w2 = side2->winding;
1673 if( side2->shaderInfo == NULL )
1675 if( w1->numpoints != w2->numpoints )
1677 if( side1->culled == qtrue && side2->culled == qtrue )
1680 /* compare planes */
1681 if( (side1->planenum & ~0x00000001) != (side2->planenum & ~0x00000001) )
1684 /* get autosprite and polygonoffset status */
1685 if( side1->shaderInfo &&
1686 (side1->shaderInfo->autosprite || side1->shaderInfo->polygonOffset) )
1688 if( side2->shaderInfo &&
1689 (side2->shaderInfo->autosprite || side2->shaderInfo->polygonOffset) )
1692 /* find first common point */
1694 for( k = 0; k < numPoints; k++ )
1696 if( VectorCompare( w1->p[ 0 ], w2->p[ k ] ) )
1705 /* find second common point (regardless of winding order) */
1708 if( (first + 1) < numPoints )
1712 if( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) )
1719 second = numPoints - 1;
1720 if( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) )
1726 /* compare the rest of the points */
1728 for( k = 0; k < numPoints; k++ )
1730 if( !CullVectorCompare( w1->p[ k ], w2->p[ l ] ) )
1736 else if( l >= numPoints )
1743 if( !side2->culled && !(side2->compileFlags & C_TRANSLUCENT) && !(side2->compileFlags & C_NODRAW) )
1745 side1->culled = qtrue;
1749 if( side1->planenum == side2->planenum && side1->culled == qtrue )
1753 if( !side1->culled && !(side1->compileFlags & C_TRANSLUCENT) && !(side1->compileFlags & C_NODRAW) )
1755 side2->culled = qtrue;
1763 /* emit some stats */
1764 Sys_FPrintf( SYS_VRB, "%9d hidden faces culled\n", g_numHiddenFaces );
1765 Sys_FPrintf( SYS_VRB, "%9d coincident faces culled\n", g_numCoinFaces );
1774 creates side->visibleHull for all visible sides
1776 the drawsurf for a side will consist of the convex hull of
1777 all points in non-opaque clusters, which allows overlaps
1778 to be trimmed off automatically.
1781 void ClipSidesIntoTree( entity_t *e, tree_t *tree )
1786 side_t *side, *newSide;
1790 /* ydnar: cull brush sides */
1794 Sys_FPrintf( SYS_VRB, "--- ClipSidesIntoTree ---\n" );
1796 /* walk the brush list */
1797 for( b = e->brushes; b; b = b->next )
1799 /* walk the brush sides */
1800 for( i = 0; i < b->numsides; i++ )
1803 side = &b->sides[ i ];
1804 if( side->winding == NULL )
1807 /* copy the winding */
1808 w = CopyWinding( side->winding );
1809 side->visibleHull = NULL;
1810 ClipSideIntoTree_r( w, side, tree->headnode );
1812 /* anything left? */
1813 w = side->visibleHull;
1818 si = side->shaderInfo;
1822 /* don't create faces for non-visible sides */
1823 /* ydnar: except indexed shaders, like common/terrain and nodraw fog surfaces */
1824 if( (si->compileFlags & C_NODRAW) && si->indexed == qfalse && !(si->compileFlags & C_FOG) )
1827 /* always use the original winding for autosprites and noclip faces */
1828 if( si->autosprite || si->noClip )
1831 /* save this winding as a visible surface */
1832 DrawSurfaceForSide( e, b, side, w );
1834 /* make a back side for fog */
1835 if( !(si->compileFlags & C_FOG) )
1838 /* duplicate the up-facing side */
1839 w = ReverseWinding( w );
1840 newSide = safe_malloc( sizeof( *side ) );
1842 newSide->visibleHull = w;
1843 newSide->planenum ^= 1;
1845 /* save this winding as a visible surface */
1846 DrawSurfaceForSide( e, b, newSide, w );
1855 this section deals with filtering drawsurfaces into the bsp tree,
1856 adding references to each leaf a surface touches
1861 AddReferenceToLeaf() - ydnar
1862 adds a reference to surface ds in the bsp leaf node
1865 int AddReferenceToLeaf( mapDrawSurface_t *ds, node_t *node )
1871 if( node->planenum != PLANENUM_LEAF || node->opaque )
1874 /* try to find an existing reference */
1875 for( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef )
1877 if( dsr->outputNum == numBSPDrawSurfaces )
1881 /* add a new reference */
1882 dsr = safe_malloc( sizeof( *dsr ) );
1883 dsr->outputNum = numBSPDrawSurfaces;
1884 dsr->nextRef = node->drawSurfReferences;
1885 node->drawSurfReferences = dsr;
1887 /* ydnar: sky/skybox surfaces */
1890 if( ds->shaderInfo->compileFlags & C_SKY )
1900 AddReferenceToTree_r() - ydnar
1901 adds a reference to the specified drawsurface to every leaf in the tree
1904 int AddReferenceToTree_r( mapDrawSurface_t *ds, node_t *node, qboolean skybox )
1913 /* is this a decision node? */
1914 if( node->planenum != PLANENUM_LEAF )
1916 /* add to child nodes and return */
1917 refs += AddReferenceToTree_r( ds, node->children[ 0 ], skybox );
1918 refs += AddReferenceToTree_r( ds, node->children[ 1 ], skybox );
1925 /* skybox surfaces only get added to sky leaves */
1929 /* increase the leaf bounds */
1930 for( i = 0; i < ds->numVerts; i++ )
1931 AddPointToBounds( ds->verts[ i ].xyz, node->mins, node->maxs );
1934 /* add a reference */
1935 return AddReferenceToLeaf( ds, node );
1941 FilterPointIntoTree_r() - ydnar
1942 filters a single point from a surface into the tree
1945 int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node )
1952 /* is this a decision node? */
1953 if( node->planenum != PLANENUM_LEAF )
1955 /* classify the point in relation to the plane */
1956 plane = &mapplanes[ node->planenum ];
1957 d = DotProduct( point, plane->normal ) - plane->dist;
1959 /* filter by this plane */
1961 if( d >= -ON_EPSILON )
1962 refs += FilterPointIntoTree_r( point, ds, node->children[ 0 ] );
1963 if( d <= ON_EPSILON )
1964 refs += FilterPointIntoTree_r( point, ds, node->children[ 1 ] );
1970 /* add a reference */
1971 return AddReferenceToLeaf( ds, node );
1975 FilterPointConvexHullIntoTree_r() - ydnar
1976 filters the convex hull of multiple points from a surface into the tree
1979 int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node )
1981 float d, dmin, dmax;
1989 /* is this a decision node? */
1990 if( node->planenum != PLANENUM_LEAF )
1992 /* classify the point in relation to the plane */
1993 plane = &mapplanes[ node->planenum ];
1995 dmin = dmax = DotProduct( *(points[0]), plane->normal ) - plane->dist;
1996 for(i = 1; i < npoints; ++i)
1998 d = DotProduct( *(points[i]), plane->normal ) - plane->dist;
2005 /* filter by this plane */
2007 if( dmax >= -ON_EPSILON )
2008 refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] );
2009 if( dmin <= ON_EPSILON )
2010 refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] );
2016 /* add a reference */
2017 return AddReferenceToLeaf( ds, node );
2022 FilterWindingIntoTree_r() - ydnar
2023 filters a winding from a drawsurface into the tree
2026 int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node )
2030 vec4_t plane1, plane2, reverse;
2031 winding_t *fat, *front, *back;
2035 /* get shaderinfo */
2036 si = ds->shaderInfo;
2038 /* ydnar: is this the head node? */
2039 if( node->parent == NULL && si != NULL &&
2040 (si->mins[ 0 ] != 0.0f || si->maxs[ 0 ] != 0.0f ||
2041 si->mins[ 1 ] != 0.0f || si->maxs[ 1 ] != 0.0f ||
2042 si->mins[ 2 ] != 0.0f || si->maxs[ 2 ] != 0.0f) )
2044 static qboolean warned = qfalse;
2047 Sys_Printf( "WARNING: this map uses the deformVertexes move hack\n" );
2051 /* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */
2052 /* note this winding is completely invalid (concave, nonplanar, etc) */
2053 fat = AllocWinding( w->numpoints * 3 + 3 );
2054 fat->numpoints = w->numpoints * 3 + 3;
2055 for( i = 0; i < w->numpoints; i++ )
2057 VectorCopy( w->p[ i ], fat->p[ i ] );
2058 VectorAdd( w->p[ i ], si->mins, fat->p[ i + (w->numpoints+1) ] );
2059 VectorAdd( w->p[ i ], si->maxs, fat->p[ i + (w->numpoints+1) * 2 ] );
2061 VectorCopy( w->p[ 0 ], fat->p[ i ] );
2062 VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] );
2063 VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] );
2066 * note: this winding is STILL not suitable for ClipWindingEpsilon, and
2067 * also does not really fulfill the intention as it only contains
2068 * origin, +mins, +maxs, but thanks to the "closing" points I just
2069 * added to the three sub-windings, the fattening at least doesn't make
2077 /* is this a decision node? */
2078 if( node->planenum != PLANENUM_LEAF )
2080 /* get node plane */
2081 p1 = &mapplanes[ node->planenum ];
2082 VectorCopy( p1->normal, plane1 );
2083 plane1[ 3 ] = p1->dist;
2085 /* check if surface is planar */
2086 if( ds->planeNum >= 0 )
2088 /* get surface plane */
2089 p2 = &mapplanes[ ds->planeNum ];
2090 VectorCopy( p2->normal, plane2 );
2091 plane2[ 3 ] = p2->dist;
2094 /* div0: this is the plague (inaccurate) */
2096 /* invert surface plane */
2097 VectorSubtract( vec3_origin, plane2, reverse );
2098 reverse[ 3 ] = -plane2[ 3 ];
2100 /* compare planes */
2101 if( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f )
2102 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2103 if( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f )
2104 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2106 /* div0: this is the cholera (doesn't hit enough) */
2108 /* the drawsurf might have an associated plane, if so, force a filter here */
2109 if( ds->planeNum == node->planenum )
2110 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2111 if( ds->planeNum == (node->planenum ^ 1) )
2112 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2116 /* clip the winding by this plane */
2117 ClipWindingEpsilonStrict( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); /* strict; we handle the "winding disappeared" case */
2119 /* filter by this plane */
2121 if( front == NULL && back == NULL )
2123 /* same plane, this is an ugly hack */
2124 /* but better too many than too few refs */
2125 refs += FilterWindingIntoTree_r( CopyWinding(w), ds, node->children[ 0 ] );
2126 refs += FilterWindingIntoTree_r( CopyWinding(w), ds, node->children[ 1 ] );
2129 refs += FilterWindingIntoTree_r( front, ds, node->children[ 0 ] );
2131 refs += FilterWindingIntoTree_r( back, ds, node->children[ 1 ] );
2138 /* add a reference */
2139 return AddReferenceToLeaf( ds, node );
2145 FilterFaceIntoTree()
2146 filters a planar winding face drawsurface into the bsp tree
2149 int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree )
2155 /* make a winding and filter it into the tree */
2156 w = WindingFromDrawSurf( ds );
2157 refs = FilterWindingIntoTree_r( w, ds, tree->headnode );
2166 FilterPatchIntoTree()
2167 subdivides a patch into an approximate curve and filters it into the tree
2170 #define FILTER_SUBDIVISION 8
2172 static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree )
2176 for(y = 0; y + 2 < ds->patchHeight; y += 2)
2177 for(x = 0; x + 2 < ds->patchWidth; x += 2)
2180 points[0] = &ds->verts[(y+0) * ds->patchWidth + (x+0)].xyz;
2181 points[1] = &ds->verts[(y+0) * ds->patchWidth + (x+1)].xyz;
2182 points[2] = &ds->verts[(y+0) * ds->patchWidth + (x+2)].xyz;
2183 points[3] = &ds->verts[(y+1) * ds->patchWidth + (x+0)].xyz;
2184 points[4] = &ds->verts[(y+1) * ds->patchWidth + (x+1)].xyz;
2185 points[5] = &ds->verts[(y+1) * ds->patchWidth + (x+2)].xyz;
2186 points[6] = &ds->verts[(y+2) * ds->patchWidth + (x+0)].xyz;
2187 points[7] = &ds->verts[(y+2) * ds->patchWidth + (x+1)].xyz;
2188 points[8] = &ds->verts[(y+2) * ds->patchWidth + (x+2)].xyz;
2189 refs += FilterPointConvexHullIntoTree_r(points, 9, ds, tree->headnode);
2198 FilterTrianglesIntoTree()
2199 filters a triangle surface (meta, model) into the bsp
2202 static int FilterTrianglesIntoTree( mapDrawSurface_t *ds, tree_t *tree )
2208 /* ydnar: gs mods: this was creating bogus triangles before */
2210 for( i = 0; i < ds->numIndexes; i += 3 )
2213 if( ds->indexes[ i ] >= ds->numVerts ||
2214 ds->indexes[ i + 1 ] >= ds->numVerts ||
2215 ds->indexes[ i + 2 ] >= ds->numVerts )
2216 Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2218 /* make a triangle winding and filter it into the tree */
2219 w = AllocWinding( 3 );
2221 VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2222 VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2223 VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2224 refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2227 /* use point filtering as well */
2228 for( i = 0; i < ds->numVerts; i++ )
2229 refs += FilterPointIntoTree_r( ds->verts[ i ].xyz, ds, tree->headnode );
2237 FilterFoliageIntoTree()
2238 filters a foliage surface (wolf et/splash damage)
2241 static int FilterFoliageIntoTree( mapDrawSurface_t *ds, tree_t *tree )
2244 bspDrawVert_t *instance;
2249 /* walk origin list */
2251 for( f = 0; f < ds->numFoliageInstances; f++ )
2254 instance = ds->verts + ds->patchHeight + f;
2256 /* walk triangle list */
2257 for( i = 0; i < ds->numIndexes; i += 3 )
2260 if( ds->indexes[ i ] >= ds->numVerts ||
2261 ds->indexes[ i + 1 ] >= ds->numVerts ||
2262 ds->indexes[ i + 2 ] >= ds->numVerts )
2263 Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2265 /* make a triangle winding and filter it into the tree */
2266 w = AllocWinding( 3 );
2268 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2269 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2270 VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2271 refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2274 /* use point filtering as well */
2275 for( i = 0; i < (ds->numVerts - ds->numFoliageInstances); i++ )
2277 VectorAdd( instance->xyz, ds->verts[ i ].xyz, xyz );
2278 refs += FilterPointIntoTree_r( xyz, ds, tree->headnode );
2288 FilterFlareIntoTree()
2289 simple point filtering for flare surfaces
2291 static int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree )
2293 return FilterPointIntoTree_r( ds->lightmapOrigin, ds, tree->headnode );
2299 EmitDrawVerts() - ydnar
2300 emits bsp drawverts from a map drawsurface
2303 void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out )
2312 si = ds->shaderInfo;
2313 offset = si->offset;
2315 /* copy the verts */
2316 out->firstVert = numBSPDrawVerts;
2317 out->numVerts = ds->numVerts;
2318 for( i = 0; i < ds->numVerts; i++ )
2320 /* allocate a new vert */
2322 dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
2325 memcpy( dv, &ds->verts[ i ], sizeof( *dv ) );
2328 if( offset != 0.0f )
2329 VectorMA( dv->xyz, offset, dv->normal, dv->xyz );
2331 /* expand model bounds
2332 necessary because of misc_model surfaces on entities
2333 note: does not happen on worldspawn as its bounds is only used for determining lightgrid bounds */
2334 if( numBSPModels > 0 )
2335 AddPointToBounds( dv->xyz, bspModels[ numBSPModels ].mins, bspModels[ numBSPModels ].maxs );
2340 for( k = 0; k < MAX_LIGHTMAPS; k++ )
2341 VectorCopy( debugColors[ (ds - mapDrawSurfs) % 12 ], dv->color[ k ] );
2349 FindDrawIndexes() - ydnar
2350 this attempts to find a run of indexes in the bsp that match the given indexes
2351 this tends to reduce the size of the bsp index pool by 1/3 or more
2352 returns numIndexes + 1 if the search failed
2355 int FindDrawIndexes( int numIndexes, int *indexes )
2357 int i, j, numTestIndexes;
2361 if( numIndexes < 3 || numBSPDrawIndexes < numIndexes || indexes == NULL )
2362 return numBSPDrawIndexes;
2365 numTestIndexes = 1 + numBSPDrawIndexes - numIndexes;
2367 /* handle 3 indexes as a special case for performance */
2368 if( numIndexes == 3 )
2370 /* run through all indexes */
2371 for( i = 0; i < numTestIndexes; i++ )
2373 /* test 3 indexes */
2374 if( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2375 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2376 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] )
2378 numRedundantIndexes += numIndexes;
2384 return numBSPDrawIndexes;
2387 /* handle 4 or more indexes */
2388 for( i = 0; i < numTestIndexes; i++ )
2390 /* test first 4 indexes */
2391 if( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2392 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2393 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] &&
2394 indexes[ 3 ] == bspDrawIndexes[ i + 3 ] )
2396 /* handle 4 indexes */
2397 if( numIndexes == 4 )
2400 /* test the remainder */
2401 for( j = 4; j < numIndexes; j++ )
2403 if( indexes[ j ] != bspDrawIndexes[ i + j ] )
2405 else if( j == (numIndexes - 1) )
2407 numRedundantIndexes += numIndexes;
2415 return numBSPDrawIndexes;
2421 EmitDrawIndexes() - ydnar
2422 attempts to find an existing run of drawindexes before adding new ones
2425 void EmitDrawIndexes( mapDrawSurface_t *ds, bspDrawSurface_t *out )
2430 /* attempt to use redundant indexing */
2431 out->firstIndex = FindDrawIndexes( ds->numIndexes, ds->indexes );
2432 out->numIndexes = ds->numIndexes;
2433 if( out->firstIndex == numBSPDrawIndexes )
2435 /* copy new unique indexes */
2436 for( i = 0; i < ds->numIndexes; i++ )
2438 if( numBSPDrawIndexes == MAX_MAP_DRAW_INDEXES )
2439 Error( "MAX_MAP_DRAW_INDEXES" );
2440 bspDrawIndexes[ numBSPDrawIndexes ] = ds->indexes[ i ];
2442 /* validate the index */
2443 if( ds->type != SURFACE_PATCH )
2445 if( bspDrawIndexes[ numBSPDrawIndexes ] < 0 || bspDrawIndexes[ numBSPDrawIndexes ] >= ds->numVerts )
2447 Sys_Printf( "WARNING: %d %s has invalid index %d (%d)\n",
2449 ds->shaderInfo->shader,
2450 bspDrawIndexes[ numBSPDrawIndexes ],
2452 bspDrawIndexes[ numBSPDrawIndexes ] = 0;
2456 /* increment index count */
2457 numBSPDrawIndexes++;
2467 emits a bsp flare drawsurface
2470 void EmitFlareSurface( mapDrawSurface_t *ds )
2473 bspDrawSurface_t *out;
2476 /* ydnar: nuking useless flare drawsurfaces */
2477 if( emitFlares == qfalse && ds->type != SURFACE_SHADER )
2481 if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
2482 Error( "MAX_MAP_DRAW_SURFS" );
2484 /* allocate a new surface */
2485 if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
2486 Error( "MAX_MAP_DRAW_SURFS" );
2487 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2488 ds->outputNum = numBSPDrawSurfaces;
2489 numBSPDrawSurfaces++;
2490 memset( out, 0, sizeof( *out ) );
2493 out->surfaceType = MST_FLARE;
2494 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2495 out->fogNum = ds->fogNum;
2498 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2500 out->lightmapNum[ i ] = -3;
2501 out->lightmapStyles[ i ] = LS_NONE;
2502 out->vertexStyles[ i ] = LS_NONE;
2504 out->lightmapStyles[ 0 ] = ds->lightStyle;
2505 out->vertexStyles[ 0 ] = ds->lightStyle;
2507 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin ); /* origin */
2508 VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] ); /* color */
2509 VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2510 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] ); /* normal */
2513 numSurfacesByType[ ds->type ]++;
2518 emits a bsp patch drawsurface
2521 void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds )
2524 bspDrawSurface_t *out;
2525 int surfaceFlags, contentFlags;
2528 /* vortex: _patchMeta support */
2529 forcePatchMeta = IntForKey(e, "_patchMeta" );
2530 if (!forcePatchMeta)
2531 forcePatchMeta = IntForKey(e, "patchMeta" );
2533 /* invert the surface if necessary */
2534 if( ds->backSide || ds->shaderInfo->invert )
2536 bspDrawVert_t *dv1, *dv2, temp;
2538 /* walk the verts, flip the normal */
2539 for( i = 0; i < ds->numVerts; i++ )
2540 VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2542 /* walk the verts again, but this time reverse their order */
2543 for( j = 0; j < ds->patchHeight; j++ )
2545 for( i = 0; i < (ds->patchWidth / 2); i++ )
2547 dv1 = &ds->verts[ j * ds->patchWidth + i ];
2548 dv2 = &ds->verts[ j * ds->patchWidth + (ds->patchWidth - i - 1) ];
2549 memcpy( &temp, dv1, sizeof( bspDrawVert_t ) );
2550 memcpy( dv1, dv2, sizeof( bspDrawVert_t ) );
2551 memcpy( dv2, &temp, sizeof( bspDrawVert_t ) );
2556 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2559 /* allocate a new surface */
2560 if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
2561 Error( "MAX_MAP_DRAW_SURFS" );
2562 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2563 ds->outputNum = numBSPDrawSurfaces;
2564 numBSPDrawSurfaces++;
2565 memset( out, 0, sizeof( *out ) );
2568 out->surfaceType = MST_PATCH;
2570 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2571 else if( patchMeta || forcePatchMeta )
2573 /* patch meta requires that we have nodraw patches for collision */
2574 surfaceFlags = ds->shaderInfo->surfaceFlags;
2575 contentFlags = ds->shaderInfo->contentFlags;
2576 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, NULL );
2577 ApplySurfaceParm( "pointlight", &contentFlags, &surfaceFlags, NULL );
2579 /* we don't want this patch getting lightmapped */
2580 VectorClear( ds->lightmapVecs[ 2 ] );
2581 VectorClear( ds->lightmapAxis );
2584 /* emit the new fake shader */
2585 out->shaderNum = EmitShader( ds->shaderInfo->shader, &contentFlags, &surfaceFlags );
2588 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2589 out->patchWidth = ds->patchWidth;
2590 out->patchHeight = ds->patchHeight;
2591 out->fogNum = ds->fogNum;
2594 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2596 out->lightmapNum[ i ] = -3;
2597 out->lightmapStyles[ i ] = LS_NONE;
2598 out->vertexStyles[ i ] = LS_NONE;
2600 out->lightmapStyles[ 0 ] = LS_NORMAL;
2601 out->vertexStyles[ 0 ] = LS_NORMAL;
2603 /* ydnar: gs mods: previously, the lod bounds were stored in lightmapVecs[ 0 ] and [ 1 ], moved to bounds[ 0 ] and [ 1 ] */
2604 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2605 VectorCopy( ds->bounds[ 0 ], out->lightmapVecs[ 0 ] );
2606 VectorCopy( ds->bounds[ 1 ], out->lightmapVecs[ 1 ] );
2607 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2609 /* ydnar: gs mods: clear out the plane normal */
2610 if( ds->planar == qfalse )
2611 VectorClear( out->lightmapVecs[ 2 ] );
2613 /* emit the verts and indexes */
2614 EmitDrawVerts( ds, out );
2615 EmitDrawIndexes( ds, out );
2618 numSurfacesByType[ ds->type ]++;
2622 OptimizeTriangleSurface() - ydnar
2623 optimizes the vertex/index data in a triangle surface
2626 #define VERTEX_CACHE_SIZE 16
2628 static void OptimizeTriangleSurface( mapDrawSurface_t *ds )
2630 int i, j, k, temp, first, best, bestScore, score;
2631 int vertexCache[ VERTEX_CACHE_SIZE + 1 ]; /* one more for optimizing insert */
2635 /* certain surfaces don't get optimized */
2636 if( ds->numIndexes <= VERTEX_CACHE_SIZE ||
2637 ds->shaderInfo->autosprite )
2640 /* create index scratch pad */
2641 indexes = safe_malloc( ds->numIndexes * sizeof( *indexes ) );
2642 memcpy( indexes, ds->indexes, ds->numIndexes * sizeof( *indexes ) );
2645 for( i = 0; i <= VERTEX_CACHE_SIZE && i < ds->numIndexes; i++ )
2646 vertexCache[ i ] = indexes[ i ];
2648 /* add triangles in a vertex cache-aware order */
2649 for( i = 0; i < ds->numIndexes; i += 3 )
2651 /* find best triangle given the current vertex cache */
2655 for( j = 0; j < ds->numIndexes; j += 3 )
2657 /* valid triangle? */
2658 if( indexes[ j ] != -1 )
2660 /* set first if necessary */
2664 /* score the triangle */
2666 for( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2668 if( indexes[ j ] == vertexCache[ k ] || indexes[ j + 1 ] == vertexCache[ k ] || indexes[ j + 2 ] == vertexCache[ k ] )
2672 /* better triangle? */
2673 if( score > bestScore )
2679 /* a perfect score of 3 means this triangle's verts are already present in the vertex cache */
2685 /* check if no decent triangle was found, and use first available */
2689 /* valid triangle? */
2692 /* add triangle to vertex cache */
2693 for( j = 0; j < 3; j++ )
2695 for( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2697 if( indexes[ best + j ] == vertexCache[ k ] )
2701 if( k >= VERTEX_CACHE_SIZE )
2703 /* pop off top of vertex cache */
2704 for( k = VERTEX_CACHE_SIZE; k > 0; k-- )
2705 vertexCache[ k ] = vertexCache[ k - 1 ];
2708 vertexCache[ 0 ] = indexes[ best + j ];
2712 /* add triangle to surface */
2713 ds->indexes[ i ] = indexes[ best ];
2714 ds->indexes[ i + 1 ] = indexes[ best + 1 ];
2715 ds->indexes[ i + 2 ] = indexes[ best + 2 ];
2717 /* clear from input pool */
2718 indexes[ best ] = -1;
2719 indexes[ best + 1 ] = -1;
2720 indexes[ best + 2 ] = -1;
2722 /* sort triangle windings (312 -> 123) */
2723 while( ds->indexes[ i ] > ds->indexes[ i + 1 ] || ds->indexes[ i ] > ds->indexes[ i + 2 ] )
2725 temp = ds->indexes[ i ];
2726 ds->indexes[ i ] = ds->indexes[ i + 1 ];
2727 ds->indexes[ i + 1 ] = ds->indexes[ i + 2 ];
2728 ds->indexes[ i + 2 ] = temp;
2740 EmitTriangleSurface()
2741 creates a bsp drawsurface from arbitrary triangle surfaces
2744 void EmitTriangleSurface( mapDrawSurface_t *ds )
2747 bspDrawSurface_t *out;
2749 /* invert the surface if necessary */
2750 if( ds->backSide || ds->shaderInfo->invert )
2752 /* walk the indexes, reverse the triangle order */
2753 for( i = 0; i < ds->numIndexes; i += 3 )
2755 temp = ds->indexes[ i ];
2756 ds->indexes[ i ] = ds->indexes[ i + 1 ];
2757 ds->indexes[ i + 1 ] = temp;
2760 /* walk the verts, flip the normal */
2761 for( i = 0; i < ds->numVerts; i++ )
2762 VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2765 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2768 /* allocate a new surface */
2769 if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
2770 Error( "MAX_MAP_DRAW_SURFS" );
2771 out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2772 ds->outputNum = numBSPDrawSurfaces;
2773 numBSPDrawSurfaces++;
2774 memset( out, 0, sizeof( *out ) );
2776 /* ydnar/sd: handle wolf et foliage surfaces */
2777 if( ds->type == SURFACE_FOLIAGE )
2778 out->surfaceType = MST_FOLIAGE;
2780 /* ydnar: gs mods: handle lightmapped terrain (force to planar type) */
2781 //% else if( VectorLength( ds->lightmapAxis ) <= 0.0f || ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FOGHULL || debugSurfaces )
2782 else if( (VectorLength( ds->lightmapAxis ) <= 0.0f && ds->planar == qfalse) ||
2783 ds->type == SURFACE_TRIANGLES ||
2784 ds->type == SURFACE_FOGHULL ||
2785 ds->numVerts > maxLMSurfaceVerts ||
2787 out->surfaceType = MST_TRIANGLE_SOUP;
2789 /* set to a planar face */
2791 out->surfaceType = MST_PLANAR;
2795 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2797 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2798 out->patchWidth = ds->patchWidth;
2799 out->patchHeight = ds->patchHeight;
2800 out->fogNum = ds->fogNum;
2802 /* debug inset (push each triangle vertex towards the center of each triangle it is on */
2805 bspDrawVert_t *a, *b, *c;
2809 /* walk triangle list */
2810 for( i = 0; i < ds->numIndexes; i += 3 )
2813 a = &ds->verts[ ds->indexes[ i ] ];
2814 b = &ds->verts[ ds->indexes[ i + 1 ] ];
2815 c = &ds->verts[ ds->indexes[ i + 2 ] ];
2817 /* calculate centroid */
2818 VectorCopy( a->xyz, cent );
2819 VectorAdd( cent, b->xyz, cent );
2820 VectorAdd( cent, c->xyz, cent );
2821 VectorScale( cent, 1.0f / 3.0f, cent );
2823 /* offset each vertex */
2824 VectorSubtract( cent, a->xyz, dir );
2825 VectorNormalize( dir, dir );
2826 VectorAdd( a->xyz, dir, a->xyz );
2827 VectorSubtract( cent, b->xyz, dir );
2828 VectorNormalize( dir, dir );
2829 VectorAdd( b->xyz, dir, b->xyz );
2830 VectorSubtract( cent, c->xyz, dir );
2831 VectorNormalize( dir, dir );
2832 VectorAdd( c->xyz, dir, c->xyz );
2837 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2839 out->lightmapNum[ i ] = -3;
2840 out->lightmapStyles[ i ] = LS_NONE;
2841 out->vertexStyles[ i ] = LS_NONE;
2843 out->lightmapStyles[ 0 ] = LS_NORMAL;
2844 out->vertexStyles[ 0 ] = LS_NORMAL;
2846 /* lightmap vectors (lod bounds for patches */
2847 VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2848 VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );
2849 VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2850 VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2852 /* ydnar: gs mods: clear out the plane normal */
2853 if( ds->planar == qfalse )
2854 VectorClear( out->lightmapVecs[ 2 ] );
2856 /* optimize the surface's triangles */
2857 OptimizeTriangleSurface( ds );
2859 /* emit the verts and indexes */
2860 EmitDrawVerts( ds, out );
2861 EmitDrawIndexes( ds, out );
2864 numSurfacesByType[ ds->type ]++;
2871 emits a bsp planar winding (brush face) drawsurface
2874 static void EmitFaceSurface(mapDrawSurface_t *ds )
2876 /* strip/fan finding was moved elsewhere */
2877 if(maxAreaFaceSurface)
2878 MaxAreaFaceSurface( ds );
2880 StripFaceSurface( ds );
2881 EmitTriangleSurface(ds);
2886 MakeDebugPortalSurfs_r() - ydnar
2887 generates drawsurfaces for passable portals in the bsp
2890 static void MakeDebugPortalSurfs_r( node_t *node, shaderInfo_t *si )
2895 mapDrawSurface_t *ds;
2899 /* recurse if decision node */
2900 if( node->planenum != PLANENUM_LEAF)
2902 MakeDebugPortalSurfs_r( node->children[ 0 ], si );
2903 MakeDebugPortalSurfs_r( node->children[ 1 ], si );
2907 /* don't bother with opaque leaves */
2911 /* walk the list of portals */
2912 for( c = 0, p = node->portals; p != NULL; c++, p = p->next[ s ] )
2914 /* get winding and side even/odd */
2916 s = (p->nodes[ 1 ] == node);
2918 /* is this a valid portal for this leaf? */
2919 if( w && p->nodes[ 0 ] == node )
2921 /* is this portal passable? */
2922 if( PortalPassable( p ) == qfalse )
2925 /* check max points */
2926 if( w->numpoints > 64 )
2927 Error( "MakePortalSurfs_r: w->numpoints = %d", w->numpoints );
2929 /* allocate a drawsurface */
2930 ds = AllocDrawSurface( SURFACE_FACE );
2931 ds->shaderInfo = si;
2933 ds->sideRef = AllocSideRef( p->side, NULL );
2934 ds->planeNum = FindFloatPlane( p->plane.normal, p->plane.dist, 0, NULL );
2935 VectorCopy( p->plane.normal, ds->lightmapVecs[ 2 ] );
2937 ds->numVerts = w->numpoints;
2938 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
2939 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
2941 /* walk the winding */
2942 for( i = 0; i < ds->numVerts; i++ )
2948 VectorCopy( w->p[ i ], dv->xyz );
2949 VectorCopy( p->plane.normal, dv->normal );
2952 for( k = 0; k < MAX_LIGHTMAPS; k++ )
2954 VectorCopy( debugColors[ c % 12 ], dv->color[ k ] );
2955 dv->color[ k ][ 3 ] = 32;
2965 MakeDebugPortalSurfs() - ydnar
2966 generates drawsurfaces for passable portals in the bsp
2969 void MakeDebugPortalSurfs( tree_t *tree )
2975 Sys_FPrintf( SYS_VRB, "--- MakeDebugPortalSurfs ---\n" );
2977 /* get portal debug shader */
2978 si = ShaderInfoForShader( "debugportals" );
2981 MakeDebugPortalSurfs_r( tree->headnode, si );
2988 generates drawsurfaces for a foghull (this MUST use a sky shader)
2991 void MakeFogHullSurfs( entity_t *e, tree_t *tree, char *shader )
2994 mapDrawSurface_t *ds;
2995 vec3_t fogMins, fogMaxs;
3008 if( shader == NULL || shader[ 0 ] == '\0' )
3012 Sys_FPrintf( SYS_VRB, "--- MakeFogHullSurfs ---\n" );
3014 /* get hull bounds */
3015 VectorCopy( mapMins, fogMins );
3016 VectorCopy( mapMaxs, fogMaxs );
3017 for( i = 0; i < 3; i++ )
3019 fogMins[ i ] -= 128;
3020 fogMaxs[ i ] += 128;
3023 /* get foghull shader */
3024 si = ShaderInfoForShader( shader );
3026 /* allocate a drawsurface */
3027 ds = AllocDrawSurface( SURFACE_FOGHULL );
3028 ds->shaderInfo = si;
3031 ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3032 memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3033 ds->numIndexes = 36;
3034 ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
3035 memset( ds->indexes, 0, ds->numIndexes * sizeof( *ds->indexes ) );
3038 VectorSet( ds->verts[ 0 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3039 VectorSet( ds->verts[ 1 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3040 VectorSet( ds->verts[ 2 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3041 VectorSet( ds->verts[ 3 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3043 VectorSet( ds->verts[ 4 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3044 VectorSet( ds->verts[ 5 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3045 VectorSet( ds->verts[ 6 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3046 VectorSet( ds->verts[ 7 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3049 memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( *ds->indexes ) );
3055 BiasSurfaceTextures()
3056 biases a surface's texcoords as close to 0 as possible
3059 void BiasSurfaceTextures( mapDrawSurface_t *ds )
3064 /* calculate the surface texture bias */
3065 CalcSurfaceTextureRange( ds );
3067 /* don't bias globaltextured shaders */
3068 if( ds->shaderInfo->globalTexture )
3071 /* bias the texture coordinates */
3072 for( i = 0; i < ds->numVerts; i++ )
3074 ds->verts[ i ].st[ 0 ] += ds->bias[ 0 ];
3075 ds->verts[ i ].st[ 1 ] += ds->bias[ 1 ];
3082 AddSurfaceModelsToTriangle_r()
3083 adds models to a specified triangle, returns the number of models added
3086 int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, bspDrawVert_t **tri )
3088 bspDrawVert_t mid, *tri2[ 3 ];
3089 int max, n, localNumSurfaceModels;
3093 localNumSurfaceModels = 0;
3095 /* subdivide calc */
3098 float *a, *b, dx, dy, dz, dist, maxDist;
3101 /* find the longest edge and split it */
3104 for( i = 0; i < 3; i++ )
3108 b = tri[ (i + 1) % 3 ]->xyz;
3111 dx = a[ 0 ] - b[ 0 ];
3112 dy = a[ 1 ] - b[ 1 ];
3113 dz = a[ 2 ] - b[ 2 ];
3114 dist = (dx * dx) + (dy * dy) + (dz * dz);
3117 if( dist > maxDist )
3124 /* is the triangle small enough? */
3125 if( max < 0 || maxDist <= (model->density * model->density) )
3127 float odds, r, angle;
3128 vec3_t origin, normal, scale, axis[ 3 ], angles;
3129 m4x4_t transform, temp;
3132 /* roll the dice (model's odds scaled by vertex alpha) */
3133 odds = model->odds * (tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ]) / 765.0f;
3138 /* calculate scale */
3139 r = model->minScale + Random() * (model->maxScale - model->minScale);
3140 VectorSet( scale, r, r, r );
3142 /* calculate angle */
3143 angle = model->minAngle + Random() * (model->maxAngle - model->minAngle);
3145 /* calculate average origin */
3146 VectorCopy( tri[ 0 ]->xyz, origin );
3147 VectorAdd( origin, tri[ 1 ]->xyz, origin );
3148 VectorAdd( origin, tri[ 2 ]->xyz, origin );
3149 VectorScale( origin, (1.0f / 3.0f), origin );
3151 /* clear transform matrix */
3152 m4x4_identity( transform );
3154 /* handle oriented models */
3155 if( model->oriented )
3158 VectorSet( angles, 0.0f, 0.0f, angle );
3160 /* calculate average normal */
3161 VectorCopy( tri[ 0 ]->normal, normal );
3162 VectorAdd( normal, tri[ 1 ]->normal, normal );
3163 VectorAdd( normal, tri[ 2 ]->normal, normal );
3164 if( VectorNormalize( normal, axis[ 2 ] ) == 0.0f )
3165 VectorCopy( tri[ 0 ]->normal, axis[ 2 ] );
3167 /* make perpendicular vectors */
3168 MakeNormalVectors( axis[ 2 ], axis[ 1 ], axis[ 0 ] );
3170 /* copy to matrix */
3171 m4x4_identity( temp );
3172 temp[ 0 ] = axis[ 0 ][ 0 ]; temp[ 1 ] = axis[ 0 ][ 1 ]; temp[ 2 ] = axis[ 0 ][ 2 ];
3173 temp[ 4 ] = axis[ 1 ][ 0 ]; temp[ 5 ] = axis[ 1 ][ 1 ]; temp[ 6 ] = axis[ 1 ][ 2 ];
3174 temp[ 8 ] = axis[ 2 ][ 0 ]; temp[ 9 ] = axis[ 2 ][ 1 ]; temp[ 10 ] = axis[ 2 ][ 2 ];
3177 m4x4_scale_by_vec3( temp, scale );
3179 /* rotate around z axis */
3180 m4x4_rotate_by_vec3( temp, angles, eXYZ );
3183 m4x4_translate_by_vec3( transform, origin );
3185 /* tranform into axis space */
3186 m4x4_multiply_by_m4x4( transform, temp );
3189 /* handle z-up models */
3193 VectorSet( angles, 0.0f, 0.0f, angle );
3196 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
3199 /* insert the model */
3200 InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 );
3202 /* return to sender */
3207 /* split the longest edge and map it */
3208 LerpDrawVert( tri[ max ], tri[ (max + 1) % 3 ], &mid );
3210 /* recurse to first triangle */
3211 VectorCopy( tri, tri2 );
3213 n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3216 localNumSurfaceModels += n;
3218 /* recurse to second triangle */
3219 VectorCopy( tri, tri2 );
3220 tri2[ (max + 1) % 3 ] = ∣
3221 n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3224 localNumSurfaceModels += n;
3227 return localNumSurfaceModels;
3234 adds a surface's shader models to the surface
3237 int AddSurfaceModels( mapDrawSurface_t *ds )
3239 surfaceModel_t *model;
3240 int i, x, y, n, pw[ 5 ], r, localNumSurfaceModels, iterations;
3241 mesh_t src, *mesh, *subdivided;
3242 bspDrawVert_t centroid, *tri[ 3 ];
3247 if( ds == NULL || ds->shaderInfo == NULL || ds->shaderInfo->surfaceModel == NULL )
3251 localNumSurfaceModels = 0;
3253 /* walk the model list */
3254 for( model = ds->shaderInfo->surfaceModel; model != NULL; model = model->next )
3256 /* switch on type */
3259 /* handle brush faces and decals */
3262 /* calculate centroid */
3263 memset( ¢roid, 0, sizeof( centroid ) );
3267 for( i = 0; i < ds->numVerts; i++ )
3269 VectorAdd( centroid.xyz, ds->verts[ i ].xyz, centroid.xyz );
3270 VectorAdd( centroid.normal, ds->verts[ i ].normal, centroid.normal );
3271 centroid.st[ 0 ] += ds->verts[ i ].st[ 0 ];
3272 centroid.st[ 1 ] += ds->verts[ i ].st[ 1 ];
3273 alpha += ds->verts[ i ].color[ 0 ][ 3 ];
3277 centroid.xyz[ 0 ] /= ds->numVerts;
3278 centroid.xyz[ 1 ] /= ds->numVerts;
3279 centroid.xyz[ 2 ] /= ds->numVerts;
3280 if( VectorNormalize( centroid.normal, centroid.normal ) == 0.0f )
3281 VectorCopy( ds->verts[ 0 ].normal, centroid.normal );
3282 centroid.st[ 0 ] /= ds->numVerts;
3283 centroid.st[ 1 ] /= ds->numVerts;
3284 alpha /= ds->numVerts;
3285 centroid.color[ 0 ][ 0 ] = 0xFF;
3286 centroid.color[ 0 ][ 1 ] = 0xFF;
3287 centroid.color[ 0 ][ 2 ] = 0xFF;
3288 centroid.color[ 0 ][ 2 ] = (alpha > 255.0f ? 0xFF : alpha);
3290 /* head vert is centroid */
3291 tri[ 0 ] = ¢roid;
3293 /* walk fanned triangles */
3294 for( i = 0; i < ds->numVerts; i++ )
3297 tri[ 1 ] = &ds->verts[ i ];
3298 tri[ 2 ] = &ds->verts[ (i + 1) % ds->numVerts ];
3301 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3304 localNumSurfaceModels += n;
3308 /* handle patches */
3310 /* subdivide the surface */
3311 src.width = ds->patchWidth;
3312 src.height = ds->patchHeight;
3313 src.verts = ds->verts;
3314 //% subdivided = SubdivideMesh( src, 8.0f, 512 );
3315 iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
3316 subdivided = SubdivideMesh2( src, iterations );
3318 /* fit it to the curve and remove colinear verts on rows/columns */
3319 PutMeshOnCurve( *subdivided );
3320 mesh = RemoveLinearMeshColumnsRows( subdivided );
3321 FreeMesh( subdivided );
3323 /* subdivide each quad to place the models */
3324 for( y = 0; y < (mesh->height - 1); y++ )
3326 for( x = 0; x < (mesh->width - 1); x++ )
3329 pw[ 0 ] = x + (y * mesh->width);
3330 pw[ 1 ] = x + ((y + 1) * mesh->width);
3331 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
3332 pw[ 3 ] = x + 1 + (y * mesh->width);
3333 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
3339 tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3340 tri[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
3341 tri[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
3342 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3345 localNumSurfaceModels += n;
3348 tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3349 tri[ 1 ] = &mesh->verts[ pw[ r + 2 ] ];
3350 tri[ 2 ] = &mesh->verts[ pw[ r + 3 ] ];
3351 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3354 localNumSurfaceModels += n;
3358 /* free the subdivided mesh */
3362 /* handle triangle surfaces */
3363 case SURFACE_TRIANGLES:
3364 case SURFACE_FORCED_META:
3366 /* walk the triangle list */
3367 for( i = 0; i < ds->numIndexes; i += 3 )
3369 tri[ 0 ] = &ds->verts[ ds->indexes[ i ] ];
3370 tri[ 1 ] = &ds->verts[ ds->indexes[ i + 1 ] ];
3371 tri[ 2 ] = &ds->verts[ ds->indexes[ i + 2 ] ];
3372 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3375 localNumSurfaceModels += n;
3379 /* no support for flares, foghull, etc */
3386 return localNumSurfaceModels;
3392 AddEntitySurfaceModels() - ydnar
3393 adds surfacemodels to an entity's surfaces
3396 void AddEntitySurfaceModels( entity_t *e )
3402 Sys_FPrintf( SYS_VRB, "--- AddEntitySurfaceModels ---\n" );
3404 /* walk the surface list */
3405 for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3406 numSurfaceModels += AddSurfaceModels( &mapDrawSurfs[ i ] );
3412 VolumeColorMods() - ydnar
3413 applies brush/volumetric color/alpha modulation to vertexes
3416 static void VolumeColorMods( entity_t *e, mapDrawSurface_t *ds )
3425 if( e->colorModBrushes == NULL )
3428 /* iterate brushes */
3429 for( b = e->colorModBrushes; b != NULL; b = b->nextColorModBrush )
3431 /* worldspawn alpha brushes affect all, grouped ones only affect original entity */
3432 if( b->entityNum != 0 && b->entityNum != ds->entityNum )
3436 if( b->mins[ 0 ] > ds->maxs[ 0 ] || b->maxs[ 0 ] < ds->mins[ 0 ] ||
3437 b->mins[ 1 ] > ds->maxs[ 1 ] || b->maxs[ 1 ] < ds->mins[ 1 ] ||
3438 b->mins[ 2 ] > ds->maxs[ 2 ] || b->maxs[ 2 ] < ds->mins[ 2 ] )
3442 for( i = 0; i < ds->numVerts; i++ )
3444 /* iterate planes */
3445 for( j = 0; j < b->numsides; j++ )
3447 /* point-plane test */
3448 plane = &mapplanes[ b->sides[ j ].planenum ];
3449 d = DotProduct( ds->verts[ i ].xyz, plane->normal ) - plane->dist;
3454 /* apply colormods */
3455 if( j == b->numsides )
3456 ColorMod( b->contentShader->colorMod, 1, &ds->verts[ i ] );
3464 FilterDrawsurfsIntoTree()
3465 upon completion, all drawsurfs that actually generate a reference
3466 will have been emited to the bspfile arrays, and the references
3467 will have valid final indexes
3470 void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree )
3473 mapDrawSurface_t *ds;
3475 vec3_t origin, mins, maxs;
3477 int numSurfs, numRefs, numSkyboxSurfaces;
3482 Sys_FPrintf( SYS_VRB, "--- FilterDrawsurfsIntoTree ---\n" );
3484 /* filter surfaces into the tree */
3487 numSkyboxSurfaces = 0;
3488 for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3490 /* get surface and try to early out */
3491 ds = &mapDrawSurfs[ i ];
3492 if( ds->numVerts == 0 && ds->type != SURFACE_FLARE && ds->type != SURFACE_SHADER )
3496 si = ds->shaderInfo;
3498 /* ydnar: skybox surfaces are special */
3501 refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
3502 ds->skybox = qfalse;
3509 /* refs initially zero */
3512 /* apply texture coordinate mods */
3513 for( j = 0; j < ds->numVerts; j++ )
3514 TCMod( si->mod, ds->verts[ j ].st );
3516 /* ydnar: apply shader colormod */
3517 ColorMod( ds->shaderInfo->colorMod, ds->numVerts, ds->verts );
3519 /* ydnar: apply brush colormod */
3520 VolumeColorMods( e, ds );
3522 /* ydnar: make fur surfaces */
3523 if( si->furNumLayers > 0 )
3526 /* ydnar/sd: make foliage surfaces */
3527 if( si->foliage != NULL )
3530 /* create a flare surface if necessary */
3531 if( si->flareShader != NULL && si->flareShader[ 0 ] )
3532 AddSurfaceFlare( ds, e->origin );
3534 /* ydnar: don't emit nodraw surfaces (like nodraw fog) */
3535 if( si != NULL && (si->compileFlags & C_NODRAW) && ds->type != SURFACE_PATCH )
3538 /* ydnar: bias the surface textures */
3539 BiasSurfaceTextures( ds );
3541 /* ydnar: globalizing of fog volume handling (eek a hack) */
3542 if( e != entities && si->noFog == qfalse )
3544 /* find surface origin and offset by entity origin */
3545 VectorAdd( ds->mins, ds->maxs, origin );
3546 VectorScale( origin, 0.5f, origin );
3547 VectorAdd( origin, e->origin, origin );
3549 VectorAdd( ds->mins, e->origin, mins );
3550 VectorAdd( ds->maxs, e->origin, maxs );
3552 /* set the fog number for this surface */
3553 ds->fogNum = FogForBounds( mins, maxs, 1.0f ); //% FogForPoint( origin, 0.0f );
3557 /* ydnar: remap shader */
3558 if( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] )
3559 ds->shaderInfo = ShaderInfoForShader( ds->shaderInfo->remapShader );
3561 /* ydnar: gs mods: handle the various types of surfaces */
3564 /* handle brush faces */
3568 refs = FilterFaceIntoTree( ds, tree );
3570 EmitFaceSurface( ds );
3573 /* handle patches */
3576 refs = FilterPatchIntoTree( ds, tree );
3578 EmitPatchSurface( e, ds );
3581 /* handle triangle surfaces */
3582 case SURFACE_TRIANGLES:
3583 case SURFACE_FORCED_META:
3585 //% Sys_FPrintf( SYS_VRB, "Surface %4d: [%1d] %4d verts %s\n", numSurfs, ds->planar, ds->numVerts, si->shader );
3587 refs = FilterTrianglesIntoTree( ds, tree );
3589 EmitTriangleSurface( ds );
3592 /* handle foliage surfaces (splash damage/wolf et) */
3593 case SURFACE_FOLIAGE:
3594 //% Sys_FPrintf( SYS_VRB, "Surface %4d: [%d] %4d verts %s\n", numSurfs, ds->numFoliageInstances, ds->numVerts, si->shader );
3596 refs = FilterFoliageIntoTree( ds, tree );
3598 EmitTriangleSurface( ds );
3601 /* handle foghull surfaces */
3602 case SURFACE_FOGHULL:
3604 refs = AddReferenceToTree_r( ds, tree->headnode, qfalse );
3606 EmitTriangleSurface( ds );
3612 refs = FilterFlareSurfIntoTree( ds, tree );
3614 EmitFlareSurface( ds );
3617 /* handle shader-only surfaces */
3618 case SURFACE_SHADER:
3620 EmitFlareSurface( ds );
3629 /* maybe surface got marked as skybox again */
3630 /* if we keep that flag, it will get scaled up AGAIN */
3632 ds->skybox = qfalse;
3634 /* tot up the references */
3641 /* emit extra surface data */
3642 SetSurfaceExtra( ds, numBSPDrawSurfaces - 1 );
3643 //% Sys_FPrintf( SYS_VRB, "%d verts %d indexes\n", ds->numVerts, ds->numIndexes );
3645 /* one last sanity check */
3647 bspDrawSurface_t *out;
3648 out = &bspDrawSurfaces[ numBSPDrawSurfaces - 1 ];
3649 if( out->numVerts == 3 && out->numIndexes > 3 )
3651 Sys_Printf( "\nWARNING: Potentially bad %s surface (%d: %d, %d)\n %s\n",
3652 surfaceTypes[ ds->type ],
3653 numBSPDrawSurfaces - 1, out->numVerts, out->numIndexes, si->shader );
3657 /* ydnar: handle skybox surfaces */
3660 MakeSkyboxSurface( ds );
3661 numSkyboxSurfaces++;
3666 /* emit some statistics */
3667 Sys_FPrintf( SYS_VRB, "%9d references\n", numRefs );
3668 Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces );
3669 Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces );
3670 Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces );
3671 Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces );
3672 Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels );
3673 Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces );
3674 for( i = 0; i < NUM_SURFACE_TYPES; i++ )
3675 Sys_FPrintf( SYS_VRB, "%9d %s surfaces\n", numSurfacesByType[ i ], surfaceTypes[ i ] );
3677 Sys_FPrintf( SYS_VRB, "%9d redundant indexes supressed, saving %d Kbytes\n", numRedundantIndexes, (numRedundantIndexes * 4 / 1024) );