]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/surface_meta.c
already apply some safe changes:
[divverent/netradiant.git] / tools / quake3 / q3map2 / surface_meta.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
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.
12
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.
17
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
21
22 ----------------------------------------------------------------------------------
23
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."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define SURFACE_META_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 #define LIGHTMAP_EXCEEDED       -1
42 #define S_EXCEEDED                      -2
43 #define T_EXCEEDED                      -3
44 #define ST_EXCEEDED                     -4
45 #define UNSUITABLE_TRIANGLE     -10
46 #define VERTS_EXCEEDED          -1000
47 #define INDEXES_EXCEEDED        -2000
48
49 #define GROW_META_VERTS         1024
50 #define GROW_META_TRIANGLES     1024
51
52 static int                                      numMetaSurfaces, numPatchMetaSurfaces;
53
54 static int                                      maxMetaVerts = 0;
55 static int                                      numMetaVerts = 0;
56 static int                                      firstSearchMetaVert = 0;
57 static bspDrawVert_t            *metaVerts = NULL;
58
59 static int                                      maxMetaTriangles = 0;
60 static int                                      numMetaTriangles = 0;
61 static metaTriangle_t           *metaTriangles = NULL;
62
63
64
65 /*
66 ClearMetaVertexes()
67 called before staring a new entity to clear out the triangle list
68 */
69
70 void ClearMetaTriangles( void )
71 {
72         numMetaVerts = 0;
73         numMetaTriangles = 0;
74 }
75
76
77
78 /*
79 FindMetaVertex()
80 finds a matching metavertex in the global list, returning its index
81 */
82
83 static int FindMetaVertex( bspDrawVert_t *src )
84 {
85         int                     i;
86         bspDrawVert_t   *v, *temp;
87         
88         
89         /* try to find an existing drawvert */
90         for( i = firstSearchMetaVert, v = &metaVerts[ i ]; i < numMetaVerts; i++, v++ )
91         {
92                 if( memcmp( src, v, sizeof( bspDrawVert_t ) ) == 0 )
93                         return i;
94         }
95         
96         /* enough space? */
97         if( numMetaVerts >= maxMetaVerts )
98         {
99                 /* reallocate more room */
100                 maxMetaVerts += GROW_META_VERTS;
101                 temp = safe_malloc( maxMetaVerts * sizeof( bspDrawVert_t ) );
102                 if( metaVerts != NULL )
103                 {
104                         memcpy( temp, metaVerts, numMetaVerts * sizeof( bspDrawVert_t ) );
105                         free( metaVerts );
106                 }
107                 metaVerts = temp;
108         }
109         
110         /* add the triangle */
111         memcpy( &metaVerts[ numMetaVerts ], src, sizeof( bspDrawVert_t ) );
112         numMetaVerts++;
113         
114         /* return the count */
115         return (numMetaVerts - 1);
116 }
117
118
119
120 /*
121 AddMetaTriangle()
122 adds a new meta triangle, allocating more memory if necessary
123 */
124
125 static int AddMetaTriangle( void )
126 {
127         metaTriangle_t  *temp;
128         
129         
130         /* enough space? */
131         if( numMetaTriangles >= maxMetaTriangles )
132         {
133                 /* reallocate more room */
134                 maxMetaTriangles += GROW_META_TRIANGLES;
135                 temp = safe_malloc( maxMetaTriangles * sizeof( metaTriangle_t ) );
136                 if( metaTriangles != NULL )
137                 {
138                         memcpy( temp, metaTriangles, numMetaTriangles * sizeof( metaTriangle_t ) );
139                         free( metaTriangles );
140                 }
141                 metaTriangles = temp;
142         }
143         
144         /* increment and return */
145         numMetaTriangles++;
146         return numMetaTriangles - 1;
147 }
148
149
150
151 /*
152 FindMetaTriangle()
153 finds a matching metatriangle in the global list,
154 otherwise adds it and returns the index to the metatriangle
155 */
156
157 int FindMetaTriangle( metaTriangle_t *src, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c, int planeNum )
158 {
159         int                             triIndex;
160         vec3_t                  dir;
161
162         
163         
164         /* detect degenerate triangles fixme: do something proper here */
165         VectorSubtract( a->xyz, b->xyz, dir );
166         if( VectorLength( dir ) < 0.125f )
167                 return -1;
168         VectorSubtract( b->xyz, c->xyz, dir );
169         if( VectorLength( dir ) < 0.125f )
170                 return -1;
171         VectorSubtract( c->xyz, a->xyz, dir );
172         if( VectorLength( dir ) < 0.125f )
173                 return -1;
174         
175         /* find plane */
176         if( planeNum >= 0 )
177         {
178                 /* because of precision issues with small triangles, try to use the specified plane */
179                 src->planeNum = planeNum;
180                 VectorCopy( mapplanes[ planeNum ].normal, src->plane );
181                 src->plane[ 3 ] = mapplanes[ planeNum ].dist;
182         }
183         else
184         {
185                 /* calculate a plane from the triangle's points (and bail if a plane can't be constructed) */
186                 src->planeNum = -1;
187                 if( PlaneFromPoints( src->plane, a->xyz, b->xyz, c->xyz ) == qfalse )
188                         return -1;
189         }
190         
191         /* ydnar 2002-10-03: repair any bogus normals (busted ase import kludge) */
192         if( VectorLength( a->normal ) <= 0.0f )
193                 VectorCopy( src->plane, a->normal );
194         if( VectorLength( b->normal ) <= 0.0f )
195                 VectorCopy( src->plane, b->normal );
196         if( VectorLength( c->normal ) <= 0.0f )
197                 VectorCopy( src->plane, c->normal );
198         
199         /* ydnar 2002-10-04: set lightmap axis if not already set */
200         if( !(src->si->compileFlags & C_VERTEXLIT) &&
201                 src->lightmapAxis[ 0 ] == 0.0f && src->lightmapAxis[ 1 ] == 0.0f && src->lightmapAxis[ 2 ] == 0.0f )
202         {
203                 /* the shader can specify an explicit lightmap axis */
204                 if( src->si->lightmapAxis[ 0 ] || src->si->lightmapAxis[ 1 ] || src->si->lightmapAxis[ 2 ] )
205                         VectorCopy( src->si->lightmapAxis, src->lightmapAxis );
206                 
207                 /* new axis-finding code */
208                 else
209                         CalcLightmapAxis( src->plane, src->lightmapAxis );
210         }
211         
212         /* fill out the src triangle */
213         src->indexes[ 0 ] = FindMetaVertex( a );
214         src->indexes[ 1 ] = FindMetaVertex( b );
215         src->indexes[ 2 ] = FindMetaVertex( c );
216         
217         /* try to find an existing triangle */
218         #ifdef USE_EXHAUSTIVE_SEARCH
219         {
220                 int                             i;
221                 metaTriangle_t  *tri;
222                 
223                 
224                 for( i = 0, tri = metaTriangles; i < numMetaTriangles; i++, tri++ )
225                 {
226                         if( memcmp( src, tri, sizeof( metaTriangle_t ) ) == 0 )
227                                 return i;
228                 }
229         }
230         #endif
231         
232         /* get a new triangle */
233         triIndex = AddMetaTriangle();
234         
235         /* add the triangle */
236         memcpy( &metaTriangles[ triIndex ], src, sizeof( metaTriangle_t ) );
237         
238         /* return the triangle index */
239         return triIndex;
240 }
241
242
243
244 /*
245 SurfaceToMetaTriangles()
246 converts a classified surface to metatriangles
247 */
248
249 static void SurfaceToMetaTriangles( mapDrawSurface_t *ds )
250 {
251         int                             i;
252         metaTriangle_t  src;
253         bspDrawVert_t   a, b, c;
254         
255         
256         /* only handle certain types of surfaces */
257         if( ds->type != SURFACE_FACE &&
258                 ds->type != SURFACE_META &&
259                 ds->type != SURFACE_FORCED_META &&
260                 ds->type != SURFACE_DECAL )
261                 return;
262         
263         /* speed at the expense of memory */
264         firstSearchMetaVert = numMetaVerts;
265         
266         /* only handle valid surfaces */
267         if( ds->type != SURFACE_BAD && ds->numVerts >= 3 && ds->numIndexes >= 3 )
268         {
269                 /* walk the indexes and create triangles */
270                 for( i = 0; i < ds->numIndexes; i += 3 )
271                 {
272                         /* sanity check the indexes */
273                         if( ds->indexes[ i ] == ds->indexes[ i + 1 ] ||
274                                 ds->indexes[ i ] == ds->indexes[ i + 2 ] ||
275                                 ds->indexes[ i + 1 ] == ds->indexes[ i + 2 ] )
276                         {
277                                 //%     Sys_Printf( "%d! ", ds->numVerts );
278                                 continue;
279                         }
280                         
281                         /* build a metatriangle */
282                         src.si = ds->shaderInfo;
283                         src.side = (ds->sideRef != NULL ? ds->sideRef->side : NULL);
284                         src.entityNum = ds->entityNum;
285                         src.surfaceNum = ds->surfaceNum;
286                         src.planeNum = ds->planeNum;
287                         src.castShadows = ds->castShadows;
288                         src.recvShadows = ds->recvShadows;
289                         src.fogNum = ds->fogNum;
290                         src.sampleSize = ds->sampleSize;
291                         VectorCopy( ds->lightmapAxis, src.lightmapAxis );
292                         
293                         /* copy drawverts */
294                         memcpy( &a, &ds->verts[ ds->indexes[ i ] ], sizeof( a ) );
295                         memcpy( &b, &ds->verts[ ds->indexes[ i + 1 ] ], sizeof( b ) );
296                         memcpy( &c, &ds->verts[ ds->indexes[ i + 2 ] ], sizeof( c ) );
297                         FindMetaTriangle( &src, &a, &b, &c, ds->planeNum );
298                 }
299                 
300                 /* add to count */
301                 numMetaSurfaces++;
302         }
303         
304         /* clear the surface (free verts and indexes, sets it to SURFACE_BAD) */
305         ClearSurface( ds );
306 }
307
308
309
310 /*
311 TriangulatePatchSurface()
312 creates triangles from a patch
313 */
314
315 void TriangulatePatchSurface( mapDrawSurface_t *ds )
316 {
317         int                                     iterations, x, y, pw[ 5 ], r;
318         mapDrawSurface_t        *dsNew;
319         mesh_t                          src, *subdivided, *mesh;
320         
321         
322         /* try to early out */
323         if( ds->numVerts == 0 || ds->type != SURFACE_PATCH || patchMeta == qfalse )
324                 return;
325         
326         /* make a mesh from the drawsurf */ 
327         src.width = ds->patchWidth;
328         src.height = ds->patchHeight;
329         src.verts = ds->verts;
330         //%     subdivided = SubdivideMesh( src, 8, 999 );
331         iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
332         subdivided = SubdivideMesh2( src, iterations ); //%     ds->maxIterations
333         
334         /* fit it to the curve and remove colinear verts on rows/columns */
335         PutMeshOnCurve( *subdivided );
336         mesh = RemoveLinearMeshColumnsRows( subdivided );
337         FreeMesh( subdivided );
338         //% MakeMeshNormals( mesh );
339         
340         /* make a copy of the drawsurface */
341         dsNew = AllocDrawSurface( SURFACE_META );
342         memcpy( dsNew, ds, sizeof( *ds ) );
343         
344         /* if the patch is nonsolid, then discard it */
345         if( !(ds->shaderInfo->compileFlags & C_SOLID) )
346                 ClearSurface( ds );
347         
348         /* set new pointer */
349         ds = dsNew;
350         
351         /* basic transmogrification */
352         ds->type = SURFACE_META;
353         ds->numIndexes = 0;
354         ds->indexes = safe_malloc( mesh->width * mesh->height * 6 * sizeof( int ) );
355         
356         /* copy the verts in */
357         ds->numVerts = (mesh->width * mesh->height);
358         ds->verts = mesh->verts;
359         
360         /* iterate through the mesh quads */
361         for( y = 0; y < (mesh->height - 1); y++ )
362         {
363                 for( x = 0; x < (mesh->width - 1); x++ )
364                 {
365                         /* set indexes */
366                         pw[ 0 ] = x + (y * mesh->width);
367                         pw[ 1 ] = x + ((y + 1) * mesh->width);
368                         pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
369                         pw[ 3 ] = x + 1 + (y * mesh->width);
370                         pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
371                         
372                         /* set radix */
373                         r = (x + y) & 1;
374                         
375                         /* make first triangle */
376                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 0 ];
377                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 1 ];
378                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 2 ];
379                         
380                         /* make second triangle */
381                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 0 ];
382                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 2 ];
383                         ds->indexes[ ds->numIndexes++ ] = pw[ r + 3 ];
384                 }
385         }
386         
387         /* free the mesh, but not the verts */
388         free( mesh );
389         
390         /* add to count */
391         numPatchMetaSurfaces++;
392         
393         /* classify it */
394         ClassifySurfaces( 1, ds );
395 }
396
397
398
399 /*
400 FanFaceSurface() - ydnar
401 creates a tri-fan from a brush face winding
402 loosely based on SurfaceAsTriFan()
403 */
404
405 void FanFaceSurface( mapDrawSurface_t *ds )
406 {
407         int                             i, j, k, a, b, c, color[ MAX_LIGHTMAPS ][ 4 ];
408         bspDrawVert_t   *verts, *centroid, *dv;
409         double                  iv;
410         
411         
412         /* try to early out */
413         if( !ds->numVerts || (ds->type != SURFACE_FACE && ds->type != SURFACE_DECAL) )
414                 return;
415         
416         /* add a new vertex at the beginning of the surface */
417         verts = safe_malloc( (ds->numVerts + 1) * sizeof( bspDrawVert_t ) );
418         memset( verts, 0, sizeof( bspDrawVert_t ) );
419         memcpy( &verts[ 1 ], ds->verts, ds->numVerts * sizeof( bspDrawVert_t ) );
420         free( ds->verts );
421         ds->verts = verts;
422         
423         /* add up the drawverts to create a centroid */
424         centroid = &verts[ 0 ];
425         memset( color, 0,  4 * MAX_LIGHTMAPS * sizeof( int ) );
426         for( i = 1, dv = &verts[ 1 ]; i < (ds->numVerts + 1); i++, dv++ )
427         {
428                 VectorAdd( centroid->xyz, dv->xyz, centroid->xyz );
429                 VectorAdd( centroid->normal, dv->normal, centroid->normal );
430                 for( j = 0; j < 4; j++ )
431                 {
432                         for( k = 0; k < MAX_LIGHTMAPS; k++ )
433                                 color[ k ][ j ] += dv->color[ k ][ j ];
434                         if( j < 2 )
435                         {
436                                 centroid->st[ j ] += dv->st[ j ];
437                                 for( k = 0; k < MAX_LIGHTMAPS; k++ )
438                                         centroid->lightmap[ k ][ j ] += dv->lightmap[ k ][ j ];
439                         }
440                 }
441         }
442         
443         /* average the centroid */
444         iv = 1.0f / ds->numVerts;
445         VectorScale( centroid->xyz, iv, centroid->xyz );
446         if( VectorNormalize( centroid->normal, centroid->normal ) <= 0 )
447                 VectorCopy( verts[ 1 ].normal, centroid->normal );
448         for( j = 0; j < 4; j++ )
449         {
450                 for( k = 0; k < MAX_LIGHTMAPS; k++ )
451                 {
452                         color[ k ][ j ] /= ds->numVerts;
453                         centroid->color[ k ][ j ] = (color[ k ][ j ] < 255.0f ? color[ k ][ j ] : 255);
454                 }
455                 if( j < 2 )
456                 {
457                         centroid->st[ j ] *= iv;
458                         for( k = 0; k < MAX_LIGHTMAPS; k++ )
459                                 centroid->lightmap[ k ][ j ] *= iv;
460                 }
461         }
462         
463         /* add to vert count */
464         ds->numVerts++;
465         
466         /* fill indexes in triangle fan order */
467         ds->numIndexes = 0;
468         ds->indexes = safe_malloc( ds->numVerts * 3 * sizeof( int ) );
469         for( i = 1; i < ds->numVerts; i++ )
470         {
471                 a = 0;
472                 b = i;
473                 c = (i + 1) % ds->numVerts;
474                 c = c ? c : 1;
475                 ds->indexes[ ds->numIndexes++ ] = a;
476                 ds->indexes[ ds->numIndexes++ ] = b;
477                 ds->indexes[ ds->numIndexes++ ] = c;
478         }
479         
480         /* add to count */
481         numFanSurfaces++;
482
483         /* classify it */
484         ClassifySurfaces( 1, ds );
485 }
486
487
488
489 /*
490 StripFaceSurface() - ydnar
491 attempts to create a valid tri-strip w/o degenerate triangles from a brush face winding
492 based on SurfaceAsTriStrip()
493 */
494
495 #define MAX_INDEXES             1024
496
497 void StripFaceSurface( mapDrawSurface_t *ds ) 
498 {
499         int                     i, r, least, rotate, numIndexes, ni, a, b, c, indexes[ MAX_INDEXES ];
500         vec_t           *v1, *v2;
501         
502         
503         /* try to early out  */
504         if( !ds->numVerts || (ds->type != SURFACE_FACE && ds->type != SURFACE_DECAL) )
505                 return;
506         
507         /* is this a simple triangle? */
508         if( ds->numVerts == 3 )
509         {
510                 numIndexes = 3;
511                 VectorSet( indexes, 0, 1, 2 );
512         }
513         else
514         {
515                 /* ydnar: find smallest coordinate */
516                 least = 0;
517                 if( ds->shaderInfo != NULL && ds->shaderInfo->autosprite == qfalse )
518                 {
519                         for( i = 0; i < ds->numVerts; i++ )
520                         {
521                                 /* get points */
522                                 v1 = ds->verts[ i ].xyz;
523                                 v2 = ds->verts[ least ].xyz;
524                                 
525                                 /* compare */
526                                 if( v1[ 0 ] < v2[ 0 ] ||
527                                         (v1[ 0 ] == v2[ 0 ] && v1[ 1 ] < v2[ 1 ]) ||
528                                         (v1[ 0 ] == v2[ 0 ] && v1[ 1 ] == v2[ 1 ] && v1[ 2 ] < v2[ 2 ]) )
529                                         least = i;
530                         }
531                 }
532                 
533                 /* determine the triangle strip order */
534                 numIndexes = (ds->numVerts - 2) * 3;
535                 if( numIndexes > MAX_INDEXES )
536                         Error( "MAX_INDEXES exceeded for surface (%d > %d) (%d verts)", numIndexes, MAX_INDEXES, ds->numVerts );
537                 
538                 /* try all possible orderings of the points looking for a non-degenerate strip order */
539                 for( r = 0; r < ds->numVerts; r++ )
540                 {
541                         /* set rotation */
542                         rotate = (r + least) % ds->numVerts;
543                         
544                         /* walk the winding in both directions */
545                         for( ni = 0, i = 0; i < ds->numVerts - 2 - i; i++ )
546                         {
547                                 /* make indexes */
548                                 a = (ds->numVerts - 1 - i + rotate) % ds->numVerts;
549                                 b = (i + rotate ) % ds->numVerts;
550                                 c = (ds->numVerts - 2 - i + rotate) % ds->numVerts;
551                                 
552                                 /* test this triangle */
553                                 if( ds->numVerts > 4 && IsTriangleDegenerate( ds->verts, a, b, c ) )
554                                         break;
555                                 indexes[ ni++ ] = a;
556                                 indexes[ ni++ ] = b;
557                                 indexes[ ni++ ] = c;
558                                 
559                                 /* handle end case */
560                                 if( i + 1 != ds->numVerts - 1 - i )
561                                 {
562                                         /* make indexes */
563                                         a = (ds->numVerts - 2 - i + rotate ) % ds->numVerts;
564                                         b = (i + rotate ) % ds->numVerts;
565                                         c = (i + 1 + rotate ) % ds->numVerts;
566                                         
567                                         /* test triangle */
568                                         if( ds->numVerts > 4 && IsTriangleDegenerate( ds->verts, a, b, c ) )
569                                                 break;
570                                         indexes[ ni++ ] = a;
571                                         indexes[ ni++ ] = b;
572                                         indexes[ ni++ ] = c;
573                                 }
574                         }
575                         
576                         /* valid strip? */
577                         if( ni == numIndexes )
578                                 break;
579                 }
580                 
581                 /* if any triangle in the strip is degenerate, render from a centered fan point instead */
582                 if( ni < numIndexes )
583                 {
584                         FanFaceSurface( ds );
585                         return;
586                 }
587         }
588         
589         /* copy strip triangle indexes */
590         ds->numIndexes = numIndexes;
591         ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) );
592         memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( int ) );
593         
594         /* add to count */
595         numStripSurfaces++;
596         
597         /* classify it */
598         ClassifySurfaces( 1, ds );
599 }
600  
601  
602 /*
603 EmitMetaStatictics
604 vortex: prints meta statistics in general output
605 */
606
607 void EmitMetaStats()
608 {
609         Sys_Printf( "--- EmitMetaStats ---\n" );
610         Sys_Printf( "%9d total meta surfaces\n", numMetaSurfaces );
611         Sys_Printf( "%9d stripped surfaces\n", numStripSurfaces );
612         Sys_Printf( "%9d fanned surfaces\n", numFanSurfaces );
613         Sys_Printf( "%9d patch meta surfaces\n", numPatchMetaSurfaces );
614         Sys_Printf( "%9d meta verts\n", numMetaVerts );
615         Sys_Printf( "%9d meta triangles\n", numMetaTriangles );
616 }
617
618 /*
619 MakeEntityMetaTriangles()
620 builds meta triangles from brush faces (tristrips and fans)
621 */
622
623 void MakeEntityMetaTriangles( entity_t *e )
624 {
625         int                                     i, f, fOld, start;
626         mapDrawSurface_t        *ds;
627         
628         
629         /* note it */
630         Sys_FPrintf( SYS_VRB, "--- MakeEntityMetaTriangles ---\n" );
631         
632         /* init pacifier */
633         fOld = -1;
634         start = I_FloatTime();
635         
636         /* walk the list of surfaces in the entity */
637         for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
638         {
639                 /* print pacifier */
640                 f = 10 * (i - e->firstDrawSurf) / (numMapDrawSurfs - e->firstDrawSurf);
641                 if( f != fOld )
642                 {
643                         fOld = f;
644                         Sys_FPrintf( SYS_VRB, "%d...", f );
645                 }
646                 
647                 /* get surface */
648                 ds = &mapDrawSurfs[ i ];
649                 if( ds->numVerts <= 0 )
650                         continue;
651                 
652                 /* ignore autosprite surfaces */
653                 if( ds->shaderInfo->autosprite )
654                         continue;
655                 
656                 /* meta this surface? */
657                 if( meta == qfalse && ds->shaderInfo->forceMeta == qfalse )
658                         continue;
659                 
660                 /* switch on type */
661                 switch( ds->type )
662                 {
663                         case SURFACE_FACE:
664                         case SURFACE_DECAL:
665                                 StripFaceSurface( ds );
666                                 SurfaceToMetaTriangles( ds );
667                                 break;
668                         
669                         case SURFACE_PATCH:
670                                 TriangulatePatchSurface( ds );
671                                 break;
672                         
673                         case SURFACE_TRIANGLES:
674                                 break;
675                         
676                         case SURFACE_FORCED_META:
677                         case SURFACE_META:
678                                 SurfaceToMetaTriangles( ds );
679                                 break;
680                         
681                         default:
682                                 break;
683                 }
684         }
685         
686         /* print time */
687         if( (numMapDrawSurfs - e->firstDrawSurf) )
688                 Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
689         
690         /* emit some stats */
691         Sys_FPrintf( SYS_VRB, "%9d total meta surfaces\n", numMetaSurfaces );
692         Sys_FPrintf( SYS_VRB, "%9d stripped surfaces\n", numStripSurfaces );
693         Sys_FPrintf( SYS_VRB, "%9d fanned surfaces\n", numFanSurfaces );
694         Sys_FPrintf( SYS_VRB, "%9d patch meta surfaces\n", numPatchMetaSurfaces );
695         Sys_FPrintf( SYS_VRB, "%9d meta verts\n", numMetaVerts );
696         Sys_FPrintf( SYS_VRB, "%9d meta triangles\n", numMetaTriangles );
697         
698         /* tidy things up */
699         TidyEntitySurfaces( e );
700 }
701
702
703
704 /*
705 PointTriangleIntersect()
706 assuming that all points lie in plane, determine if pt
707 is inside the triangle abc
708 code originally (c) 2001 softSurfer (www.softsurfer.com)
709 */
710
711 #define MIN_OUTSIDE_EPSILON             -0.01f
712 #define MAX_OUTSIDE_EPSILON             1.01f
713
714 static qboolean PointTriangleIntersect( vec3_t pt, vec4_t plane, vec3_t a, vec3_t b, vec3_t c, vec3_t bary )
715 {
716         vec3_t  u, v, w;
717         float   uu, uv, vv, wu, wv, d;
718         
719         
720         /* make vectors */
721         VectorSubtract( b, a, u );
722         VectorSubtract( c, a, v );
723         VectorSubtract( pt, a, w );
724         
725         /* more setup */
726         uu = DotProduct( u, u );
727         uv = DotProduct( u, v );
728         vv = DotProduct( v, v );
729         wu = DotProduct( w, u );
730         wv = DotProduct( w, v );
731         d = uv * uv - uu * vv;
732         
733         /* calculate barycentric coordinates */
734         bary[ 1 ] = (uv * wv - vv * wu) / d;
735         if( bary[ 1 ] < MIN_OUTSIDE_EPSILON || bary[ 1 ] > MAX_OUTSIDE_EPSILON )
736                 return qfalse;
737         bary[ 2 ] = (uv * wv - uu * wv) / d;
738         if( bary[ 2 ] < MIN_OUTSIDE_EPSILON || bary[ 2 ] > MAX_OUTSIDE_EPSILON )
739                 return qfalse;
740         bary[ 0 ] = 1.0f - (bary[ 1 ] + bary[ 2 ]);
741         
742         /* point is in triangle */
743         return qtrue;
744 }
745
746
747
748 /*
749 CreateEdge()
750 sets up an edge structure from a plane and 2 points that the edge ab falls lies in
751 */
752
753 typedef struct edge_s
754 {
755         vec3_t  origin, edge;
756         vec_t   length, kingpinLength;
757         int             kingpin;
758         vec4_t  plane;
759 }
760 edge_t;
761
762 void CreateEdge( vec4_t plane, vec3_t a, vec3_t b, edge_t *edge )
763 {
764         /* copy edge origin */
765         VectorCopy( a, edge->origin );
766         
767         /* create vector aligned with winding direction of edge */
768         VectorSubtract( b, a, edge->edge );
769         
770         if( fabs( edge->edge[ 0 ] ) > fabs( edge->edge[ 1 ] ) && fabs( edge->edge[ 0 ] ) > fabs( edge->edge[ 2 ] ) )
771                 edge->kingpin = 0;
772         else if( fabs( edge->edge[ 1 ] ) > fabs( edge->edge[ 0 ] ) && fabs( edge->edge[ 1 ] ) > fabs( edge->edge[ 2 ] ) )
773                 edge->kingpin = 1;
774         else
775                 edge->kingpin = 2;
776         edge->kingpinLength = edge->edge[ edge->kingpin ];
777         
778         VectorNormalize( edge->edge, edge->edge );
779         edge->edge[ 3 ] = DotProduct( a, edge->edge );
780         edge->length = DotProduct( b, edge->edge ) - edge->edge[ 3 ];
781         
782         /* create perpendicular plane that edge lies in */
783         CrossProduct( plane, edge->edge, edge->plane );
784         edge->plane[ 3 ] = DotProduct( a, edge->plane );
785 }
786
787
788
789 /*
790 FixMetaTJunctions()
791 fixes t-junctions on meta triangles
792 */
793
794 #define TJ_PLANE_EPSILON        (1.0f / 8.0f)
795 #define TJ_EDGE_EPSILON         (1.0f / 8.0f)
796 #define TJ_POINT_EPSILON        (1.0f / 8.0f)
797
798 void FixMetaTJunctions( void )
799 {
800         int                             i, j, k, f, fOld, start, vertIndex, triIndex, numTJuncs;
801         metaTriangle_t  *tri, *newTri;
802         shaderInfo_t    *si;
803         bspDrawVert_t   *a, *b, *c, junc;
804         float                   dist, amount;
805         vec3_t                  pt;
806         vec4_t                  plane;
807         edge_t                  edges[ 3 ];
808         
809         
810         /* this code is crap; revisit later */
811         return;
812         
813         /* note it */
814         Sys_FPrintf( SYS_VRB, "--- FixMetaTJunctions ---\n" );
815         
816         /* init pacifier */
817         fOld = -1;
818         start = I_FloatTime();
819         
820         /* walk triangle list */
821         numTJuncs = 0;
822         for( i = 0; i < numMetaTriangles; i++ )
823         {
824                 /* get triangle */
825                 tri = &metaTriangles[ i ];
826                 
827                 /* print pacifier */
828                 f = 10 * i / numMetaTriangles;
829                 if( f != fOld )
830                 {
831                         fOld = f;
832                         Sys_FPrintf( SYS_VRB, "%d...", f );
833                 }
834                 
835                 /* attempt to early out */
836                 si = tri->si;
837                 if( (si->compileFlags & C_NODRAW) || si->autosprite || si->notjunc )
838                         continue;
839                 
840                 /* calculate planes */
841                 VectorCopy( tri->plane, plane );
842                 plane[ 3 ] = tri->plane[ 3 ];
843                 CreateEdge( plane, metaVerts[ tri->indexes[ 0 ] ].xyz, metaVerts[ tri->indexes[ 1 ] ].xyz, &edges[ 0 ] );
844                 CreateEdge( plane, metaVerts[ tri->indexes[ 1 ] ].xyz, metaVerts[ tri->indexes[ 2 ] ].xyz, &edges[ 1 ] );
845                 CreateEdge( plane, metaVerts[ tri->indexes[ 2 ] ].xyz, metaVerts[ tri->indexes[ 0 ] ].xyz, &edges[ 2 ] );
846                 
847                 /* walk meta vert list */
848                 for( j = 0; j < numMetaVerts; j++ )
849                 {
850                         /* get vert */
851                         VectorCopy( metaVerts[ j ].xyz, pt );
852
853                         /* debug code: darken verts */
854                         if( i == 0 )
855                                 VectorSet( metaVerts[ j ].color[ 0 ], 8, 8, 8 );
856                         
857                         /* determine if point lies in the triangle's plane */
858                         dist = DotProduct( pt, plane ) - plane[ 3 ];
859                         if( fabs( dist ) > TJ_PLANE_EPSILON )
860                                 continue;
861                         
862                         /* skip this point if it already exists in the triangle */
863                         for( k = 0; k < 3; k++ )
864                         {
865                                 if( fabs( pt[ 0 ] - metaVerts[ tri->indexes[ k ] ].xyz[ 0 ] ) <= TJ_POINT_EPSILON &&
866                                         fabs( pt[ 1 ] - metaVerts[ tri->indexes[ k ] ].xyz[ 1 ] ) <= TJ_POINT_EPSILON &&
867                                         fabs( pt[ 2 ] - metaVerts[ tri->indexes[ k ] ].xyz[ 2 ] ) <= TJ_POINT_EPSILON )
868                                         break;
869                         }
870                         if( k < 3 )
871                                 continue;
872                         
873                         /* walk edges */
874                         for( k = 0; k < 3; k++ )
875                         {
876                                 /* ignore bogus edges */
877                                 if( fabs( edges[ k ].kingpinLength ) < TJ_EDGE_EPSILON )
878                                         continue;
879                                 
880                                 /* determine if point lies on the edge */
881                                 dist = DotProduct( pt, edges[ k ].plane ) - edges[ k ].plane[ 3 ];
882                                 if( fabs( dist ) > TJ_EDGE_EPSILON )
883                                         continue;
884                                 
885                                 /* determine how far along the edge the point lies */
886                                 amount = (pt[ edges[ k ].kingpin ] - edges[ k ].origin[ edges[ k ].kingpin ]) / edges[ k ].kingpinLength;
887                                 if( amount <= 0.0f || amount >= 1.0f )
888                                         continue;
889                                 
890                                 #if 0
891                                 dist = DotProduct( pt, edges[ k ].edge ) - edges[ k ].edge[ 3 ];
892                                 if( dist <= -0.0f || dist >= edges[ k ].length )
893                                         continue;
894                                 amount = dist / edges[ k ].length;
895                                 #endif
896                                 
897                                 /* debug code: brighten this point */
898                                 //%     metaVerts[ j ].color[ 0 ][ 0 ] += 5;
899                                 //%     metaVerts[ j ].color[ 0 ][ 1 ] += 4;
900                                 VectorSet( metaVerts[ tri->indexes[ k ] ].color[ 0 ], 255, 204, 0 );
901                                 VectorSet( metaVerts[ tri->indexes[ (k + 1) % 3 ] ].color[ 0 ], 255, 204, 0 );
902                                 
903
904                                 /* the edge opposite the zero-weighted vertex was hit, so use that as an amount */
905                                 a = &metaVerts[ tri->indexes[ k % 3 ] ];
906                                 b = &metaVerts[ tri->indexes[ (k + 1) % 3 ] ];
907                                 c = &metaVerts[ tri->indexes[ (k + 2) % 3 ] ];
908                                 
909                                 /* make new vert */
910                                 LerpDrawVertAmount( a, b, amount, &junc );
911                                 VectorCopy( pt, junc.xyz );
912                                 
913                                 /* compare against existing verts */
914                                 if( VectorCompare( junc.xyz, a->xyz ) || VectorCompare( junc.xyz, b->xyz ) || VectorCompare( junc.xyz, c->xyz ) )
915                                         continue;
916                                 
917                                 /* see if we can just re-use the existing vert */
918                                 if( !memcmp( &metaVerts[ j ], &junc, sizeof( junc ) ) )
919                                         vertIndex = j;
920                                 else
921                                 {
922                                         /* find new vertex (note: a and b are invalid pointers after this) */
923                                         firstSearchMetaVert = numMetaVerts;
924                                         vertIndex = FindMetaVertex( &junc );
925                                         if( vertIndex < 0 )
926                                                 continue;
927                                 }
928                                                 
929                                 /* make new triangle */
930                                 triIndex = AddMetaTriangle();
931                                 if( triIndex < 0 )
932                                         continue;
933                                 
934                                 /* get triangles */
935                                 tri = &metaTriangles[ i ];
936                                 newTri = &metaTriangles[ triIndex ];
937                                 
938                                 /* copy the triangle */
939                                 memcpy( newTri, tri, sizeof( *tri ) );
940                                 
941                                 /* fix verts */
942                                 tri->indexes[ (k + 1) % 3 ] = vertIndex;
943                                 newTri->indexes[ k ] = vertIndex;
944                                 
945                                 /* recalculate edges */
946                                 CreateEdge( plane, metaVerts[ tri->indexes[ 0 ] ].xyz, metaVerts[ tri->indexes[ 1 ] ].xyz, &edges[ 0 ] );
947                                 CreateEdge( plane, metaVerts[ tri->indexes[ 1 ] ].xyz, metaVerts[ tri->indexes[ 2 ] ].xyz, &edges[ 1 ] );
948                                 CreateEdge( plane, metaVerts[ tri->indexes[ 2 ] ].xyz, metaVerts[ tri->indexes[ 0 ] ].xyz, &edges[ 2 ] );
949                                 
950                                 /* debug code */
951                                 metaVerts[ vertIndex ].color[ 0 ][ 0 ] = 255;
952                                 metaVerts[ vertIndex ].color[ 0 ][ 1 ] = 204;
953                                 metaVerts[ vertIndex ].color[ 0 ][ 2 ] = 0;
954                                 
955                                 /* add to counter and end processing of this vert */
956                                 numTJuncs++;
957                                 break;
958                         }
959                 }
960         }
961         
962         /* print time */
963         Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
964         
965         /* emit some stats */
966         Sys_FPrintf( SYS_VRB, "%9d T-junctions added\n", numTJuncs );
967 }
968
969
970
971 /*
972 SmoothMetaTriangles()
973 averages coincident vertex normals in the meta triangles
974 */
975
976 #define MAX_SAMPLES                             256
977 #define THETA_EPSILON                   0.000001
978 #define EQUAL_NORMAL_EPSILON    0.01
979
980 void SmoothMetaTriangles( void )
981 {
982         int                             i, j, k, f, fOld, start, cs, numVerts, numVotes, numSmoothed;
983         float                   shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
984         metaTriangle_t  *tri;
985         float                   *shadeAngles;
986         byte                    *smoothed;
987         vec3_t                  average, diff;
988         int                             indexes[ MAX_SAMPLES ];
989         vec3_t                  votes[ MAX_SAMPLES ];
990         
991         
992         /* note it */
993         Sys_FPrintf( SYS_VRB, "--- SmoothMetaTriangles ---\n" );
994         
995         /* allocate shade angle table */
996         shadeAngles = safe_malloc( numMetaVerts * sizeof( float ) );
997         memset( shadeAngles, 0, numMetaVerts * sizeof( float ) );
998         
999         /* allocate smoothed table */
1000         cs = (numMetaVerts / 8) + 1;
1001         smoothed = safe_malloc( cs );
1002         memset( smoothed, 0, cs );
1003         
1004         /* set default shade angle */
1005         defaultShadeAngle = DEG2RAD( npDegrees );
1006         maxShadeAngle = 0.0f;
1007         
1008         /* run through every surface and flag verts belonging to non-lightmapped surfaces
1009            and set per-vertex smoothing angle */
1010         for( i = 0, tri = &metaTriangles[ i ]; i < numMetaTriangles; i++, tri++ )
1011         {
1012                 /* get shader for shade angle */
1013                 if( tri->si->shadeAngleDegrees > 0.0f )
1014                         shadeAngle = DEG2RAD( tri->si->shadeAngleDegrees );
1015                 else
1016                         shadeAngle = defaultShadeAngle;
1017                 if( shadeAngle > maxShadeAngle )
1018                         maxShadeAngle = shadeAngle;
1019                 
1020                 /* flag its verts */
1021                 for( j = 0; j < 3; j++ )
1022                 {
1023                         shadeAngles[ tri->indexes[ j ] ] = shadeAngle;
1024                         if( shadeAngle <= 0 )
1025                                 smoothed[ tri->indexes[ j ] >> 3 ] |= (1 << (tri->indexes[ j ] & 7));
1026                 }
1027         }
1028         
1029         /* bail if no surfaces have a shade angle */
1030         if( maxShadeAngle <= 0 )
1031         {
1032                 Sys_FPrintf( SYS_VRB, "No smoothing angles specified, aborting\n" );
1033                 free( shadeAngles );
1034                 free( smoothed );
1035                 return;
1036         }
1037         
1038         /* init pacifier */
1039         fOld = -1;
1040         start = I_FloatTime();
1041         
1042         /* go through the list of vertexes */
1043         numSmoothed = 0;
1044         for( i = 0; i < numMetaVerts; i++ )
1045         {
1046                 /* print pacifier */
1047                 f = 10 * i / numMetaVerts;
1048                 if( f != fOld )
1049                 {
1050                         fOld = f;
1051                         Sys_FPrintf( SYS_VRB, "%d...", f );
1052                 }
1053                 
1054                 /* already smoothed? */
1055                 if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
1056                         continue;
1057                 
1058                 /* clear */
1059                 VectorClear( average );
1060                 numVerts = 0;
1061                 numVotes = 0;
1062                 
1063                 /* build a table of coincident vertexes */
1064                 for( j = i; j < numMetaVerts && numVerts < MAX_SAMPLES; j++ )
1065                 {
1066                         /* already smoothed? */
1067                         if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
1068                                 continue;
1069                         
1070                         /* test vertexes */
1071                         if( VectorCompare( metaVerts[ i ].xyz, metaVerts[ j ].xyz ) == qfalse )
1072                                 continue;
1073                         
1074                         /* use smallest shade angle */
1075                         shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
1076                         
1077                         /* check shade angle */
1078                         dot = DotProduct( metaVerts[ i ].normal, metaVerts[ j ].normal );
1079                         if( dot > 1.0 )
1080                                 dot = 1.0;
1081                         else if( dot < -1.0 )
1082                                 dot = -1.0;
1083                         testAngle = acos( dot ) + THETA_EPSILON;
1084                         if( testAngle >= shadeAngle )
1085                                 continue;
1086                         
1087                         /* add to the list */
1088                         indexes[ numVerts++ ] = j;
1089                         
1090                         /* flag vertex */
1091                         smoothed[ j >> 3 ] |= (1 << (j & 7));
1092                         
1093                         /* see if this normal has already been voted */
1094                         for( k = 0; k < numVotes; k++ )
1095                         {
1096                                 VectorSubtract( metaVerts[ j ].normal, votes[ k ], diff );
1097                                 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
1098                                         fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
1099                                         fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
1100                                         break;
1101                         }
1102                         
1103                         /* add a new vote? */
1104                         if( k == numVotes && numVotes < MAX_SAMPLES )
1105                         {
1106                                 VectorAdd( average, metaVerts[ j ].normal, average );
1107                                 VectorCopy( metaVerts[ j ].normal, votes[ numVotes ] );
1108                                 numVotes++;
1109                         }
1110                 }
1111                 
1112                 /* don't average for less than 2 verts */
1113                 if( numVerts < 2 )
1114                         continue;
1115                 
1116                 /* average normal */
1117                 if( VectorNormalize( average, average ) > 0 )
1118                 {
1119                         /* smooth */
1120                         for( j = 0; j < numVerts; j++ )
1121                                 VectorCopy( average, metaVerts[ indexes[ j ] ].normal );
1122                         numSmoothed++;
1123                 }
1124         }
1125         
1126         /* free the tables */
1127         free( shadeAngles );
1128         free( smoothed );
1129         
1130         /* print time */
1131         Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
1132
1133         /* emit some stats */
1134         Sys_FPrintf( SYS_VRB, "%9d smoothed vertexes\n", numSmoothed );
1135 }
1136
1137
1138
1139 /*
1140 AddMetaVertToSurface()
1141 adds a drawvert to a surface unless an existing vert matching already exists
1142 returns the index of that vert (or < 0 on failure)
1143 */
1144
1145 int AddMetaVertToSurface( mapDrawSurface_t *ds, bspDrawVert_t *dv1, int *coincident )
1146 {
1147         int                             i;
1148         bspDrawVert_t   *dv2;
1149         
1150         
1151         /* go through the verts and find a suitable candidate */
1152         for( i = 0; i < ds->numVerts; i++ )
1153         {
1154                 /* get test vert */
1155                 dv2 = &ds->verts[ i ];
1156                 
1157                 /* compare xyz and normal */
1158                 if( VectorCompare( dv1->xyz, dv2->xyz ) == qfalse )
1159                         continue;
1160                 if( VectorCompare( dv1->normal, dv2->normal ) == qfalse )
1161                         continue;
1162                 
1163                 /* good enough at this point */
1164                 (*coincident)++;
1165                 
1166                 /* compare texture coordinates and color */
1167                 if( dv1->st[ 0 ] != dv2->st[ 0 ] || dv1->st[ 1 ] != dv2->st[ 1 ] )
1168                         continue;
1169                 if( dv1->color[ 0 ][ 3 ] != dv2->color[ 0 ][ 3 ] )
1170                         continue;
1171                 
1172                 /* found a winner */
1173                 numMergedVerts++;
1174                 return i;
1175         }
1176
1177         /* overflow check */
1178         if( ds->numVerts >= ((ds->shaderInfo->compileFlags & C_VERTEXLIT) ? maxSurfaceVerts : maxLMSurfaceVerts) )
1179                 return VERTS_EXCEEDED;
1180         
1181         /* made it this far, add the vert and return */
1182         dv2 = &ds->verts[ ds->numVerts++ ];
1183         *dv2 = *dv1;
1184         return (ds->numVerts - 1);
1185 }
1186
1187
1188
1189
1190 /*
1191 AddMetaTriangleToSurface()
1192 attempts to add a metatriangle to a surface
1193 returns the score of the triangle added
1194 */
1195
1196 #define AXIS_SCORE                      100000
1197 #define AXIS_MIN                        100000
1198 #define VERT_SCORE                      10000
1199 #define SURFACE_SCORE           1000
1200 #define ST_SCORE                        50
1201 #define ST_SCORE2                       (2 * (ST_SCORE))
1202
1203 #define ADEQUATE_SCORE          ((AXIS_MIN) + 1 * (VERT_SCORE))
1204 #define GOOD_SCORE                      ((AXIS_MIN) + 2 * (VERT_SCORE) + 4 * (ST_SCORE))
1205 #define PERFECT_SCORE           ((AXIS_MIN) + + 3 * (VERT_SCORE) + (SURFACE_SCORE) + 4 * (ST_SCORE))
1206
1207 static int AddMetaTriangleToSurface( mapDrawSurface_t *ds, metaTriangle_t *tri, qboolean testAdd )
1208 {
1209         int                                     i, score, coincident, ai, bi, ci, oldTexRange[ 2 ];
1210         float                           lmMax;
1211         vec3_t                          mins, maxs;
1212         qboolean                        inTexRange, es, et;
1213         mapDrawSurface_t        old;
1214         
1215         
1216         /* overflow check */
1217         if( ds->numIndexes >= maxSurfaceIndexes )
1218                 return 0;
1219         
1220         /* test the triangle */
1221         if( ds->entityNum != tri->entityNum )   /* ydnar: added 2002-07-06 */
1222                 return 0;
1223         if( ds->castShadows != tri->castShadows || ds->recvShadows != tri->recvShadows )
1224                 return 0;
1225         if( ds->shaderInfo != tri->si || ds->fogNum != tri->fogNum || ds->sampleSize != tri->sampleSize )
1226                 return 0;
1227         #if 0
1228                 if( !(ds->shaderInfo->compileFlags & C_VERTEXLIT) &&
1229                         //% VectorCompare( ds->lightmapAxis, tri->lightmapAxis ) == qfalse )
1230                         DotProduct( ds->lightmapAxis, tri->plane ) < 0.25f )
1231                         return 0;
1232         #endif
1233         
1234         /* planar surfaces will only merge with triangles in the same plane */
1235         if( npDegrees == 0.0f && ds->shaderInfo->nonplanar == qfalse && ds->planeNum >= 0 )
1236         {
1237                 if( VectorCompare( mapplanes[ ds->planeNum ].normal, tri->plane ) == qfalse || mapplanes[ ds->planeNum ].dist != tri->plane[ 3 ] )
1238                         return 0;
1239                 if( tri->planeNum >= 0 && tri->planeNum != ds->planeNum )
1240                         return 0;
1241         }
1242         
1243         /* set initial score */
1244         score = tri->surfaceNum == ds->surfaceNum ? SURFACE_SCORE : 0;
1245         
1246         /* score the the dot product of lightmap axis to plane */
1247         if( (ds->shaderInfo->compileFlags & C_VERTEXLIT) || VectorCompare( ds->lightmapAxis, tri->lightmapAxis ) )
1248                 score += AXIS_SCORE;
1249         else
1250                 score += AXIS_SCORE * DotProduct( ds->lightmapAxis, tri->plane );
1251         
1252         /* preserve old drawsurface if this fails */
1253         memcpy( &old, ds, sizeof( *ds ) );
1254         
1255         /* attempt to add the verts */
1256         coincident = 0;
1257         ai = AddMetaVertToSurface( ds, &metaVerts[ tri->indexes[ 0 ] ], &coincident );
1258         bi = AddMetaVertToSurface( ds, &metaVerts[ tri->indexes[ 1 ] ], &coincident );
1259         ci = AddMetaVertToSurface( ds, &metaVerts[ tri->indexes[ 2 ] ], &coincident );
1260         
1261         /* check vertex underflow */
1262         if( ai < 0 || bi < 0 || ci < 0 )
1263         {
1264                 memcpy( ds, &old, sizeof( *ds ) );
1265                 return 0;
1266         }
1267         
1268         /* score coincident vertex count (2003-02-14: changed so this only matters on planar surfaces) */
1269         score += (coincident * VERT_SCORE);
1270         
1271         /* add new vertex bounds to mins/maxs */
1272         VectorCopy( ds->mins, mins );
1273         VectorCopy( ds->maxs, maxs );
1274         AddPointToBounds( metaVerts[ tri->indexes[ 0 ] ].xyz, mins, maxs );
1275         AddPointToBounds( metaVerts[ tri->indexes[ 1 ] ].xyz, mins, maxs );
1276         AddPointToBounds( metaVerts[ tri->indexes[ 2 ] ].xyz, mins, maxs );
1277         
1278         /* check lightmap bounds overflow (after at least 1 triangle has been added) */
1279         if( !(ds->shaderInfo->compileFlags & C_VERTEXLIT) &&
1280                 ds->numIndexes > 0 && VectorLength( ds->lightmapAxis ) > 0.0f &&
1281                 (VectorCompare( ds->mins, mins ) == qfalse || VectorCompare( ds->maxs, maxs ) == qfalse) )
1282         {
1283                 /* set maximum size before lightmap scaling (normally 2032 units) */
1284                 /* 2004-02-24: scale lightmap test size by 2 to catch larger brush faces */
1285                 /* 2004-04-11: reverting to actual lightmap size */
1286                 lmMax = (ds->sampleSize * (ds->shaderInfo->lmCustomWidth - 1));
1287                 for( i = 0; i < 3; i++ )
1288                 {
1289                         if( (maxs[ i ] - mins[ i ]) > lmMax )
1290                         {
1291                                 memcpy( ds, &old, sizeof( *ds ) );
1292                                 return 0;
1293                         }
1294                 }
1295         }
1296         
1297         /* check texture range overflow */
1298         oldTexRange[ 0 ] = ds->texRange[ 0 ];
1299         oldTexRange[ 1 ] = ds->texRange[ 1 ];
1300         inTexRange = CalcSurfaceTextureRange( ds );
1301         
1302         es = (ds->texRange[ 0 ] > oldTexRange[ 0 ]) ? qtrue : qfalse;
1303         et = (ds->texRange[ 1 ] > oldTexRange[ 1 ]) ? qtrue : qfalse;
1304         
1305         if( inTexRange == qfalse && ds->numIndexes > 0 )
1306         {
1307                 memcpy( ds, &old, sizeof( *ds ) );
1308                 return UNSUITABLE_TRIANGLE;
1309         }
1310         
1311         /* score texture range */
1312         if( ds->texRange[ 0 ] <= oldTexRange[ 0 ] )
1313                 score += ST_SCORE2;
1314         else if( ds->texRange[ 0 ] > oldTexRange[ 0 ] && oldTexRange[ 1 ] > oldTexRange[ 0 ] )
1315                 score += ST_SCORE;
1316         
1317         if( ds->texRange[ 1 ] <= oldTexRange[ 1 ] )
1318                 score += ST_SCORE2;
1319         else if( ds->texRange[ 1 ] > oldTexRange[ 1 ] && oldTexRange[ 0 ] > oldTexRange[ 1 ] )
1320                 score += ST_SCORE;
1321         
1322         
1323         /* go through the indexes and try to find an existing triangle that matches abc */
1324         for( i = 0; i < ds->numIndexes; i += 3 )
1325         {
1326                 /* 2002-03-11 (birthday!): rotate the triangle 3x to find an existing triangle */
1327                 if( (ai == ds->indexes[ i ] && bi == ds->indexes[ i + 1 ] && ci == ds->indexes[ i + 2 ]) ||
1328                         (bi == ds->indexes[ i ] && ci == ds->indexes[ i + 1 ] && ai == ds->indexes[ i + 2 ]) ||
1329                         (ci == ds->indexes[ i ] && ai == ds->indexes[ i + 1 ] && bi == ds->indexes[ i + 2 ]) )
1330                 {
1331                         /* triangle already present */
1332                         memcpy( ds, &old, sizeof( *ds ) );
1333                         tri->si = NULL;
1334                         return 0;
1335                 }
1336                 
1337                 /* rotate the triangle 3x to find an inverse triangle (error case) */
1338                 if( (ai == ds->indexes[ i ] && bi == ds->indexes[ i + 2 ] && ci == ds->indexes[ i + 1 ]) ||
1339                         (bi == ds->indexes[ i ] && ci == ds->indexes[ i + 2 ] && ai == ds->indexes[ i + 1 ]) ||
1340                         (ci == ds->indexes[ i ] && ai == ds->indexes[ i + 2 ] && bi == ds->indexes[ i + 1 ]) )
1341                 {
1342                         /* warn about it */
1343                         Sys_Printf( "WARNING: Flipped triangle: (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f)\n",
1344                                 ds->verts[ ai ].xyz[ 0 ], ds->verts[ ai ].xyz[ 1 ], ds->verts[ ai ].xyz[ 2 ],
1345                                 ds->verts[ bi ].xyz[ 0 ], ds->verts[ bi ].xyz[ 1 ], ds->verts[ bi ].xyz[ 2 ],
1346                                 ds->verts[ ci ].xyz[ 0 ], ds->verts[ ci ].xyz[ 1 ], ds->verts[ ci ].xyz[ 2 ] );
1347                         
1348                         /* reverse triangle already present */
1349                         memcpy( ds, &old, sizeof( *ds ) );
1350                         tri->si = NULL;
1351                         return 0;
1352                 }
1353         }
1354         
1355         /* add the triangle indexes */
1356         if( ds->numIndexes < maxSurfaceIndexes )
1357                 ds->indexes[ ds->numIndexes++ ] = ai;
1358         if( ds->numIndexes < maxSurfaceIndexes )
1359                 ds->indexes[ ds->numIndexes++ ] = bi;
1360         if( ds->numIndexes < maxSurfaceIndexes )
1361                 ds->indexes[ ds->numIndexes++ ] = ci;
1362         
1363         /* check index overflow */
1364         if( ds->numIndexes >= maxSurfaceIndexes  )
1365         {
1366                 memcpy( ds, &old, sizeof( *ds ) );
1367                 return 0;
1368         }
1369         
1370         /* sanity check the indexes */
1371         if( ds->numIndexes >= 3 &&
1372                 (ds->indexes[ ds->numIndexes - 3 ] == ds->indexes[ ds->numIndexes - 2 ] ||
1373                 ds->indexes[ ds->numIndexes - 3 ] == ds->indexes[ ds->numIndexes - 1 ] ||
1374                 ds->indexes[ ds->numIndexes - 2 ] == ds->indexes[ ds->numIndexes - 1 ]) )
1375                 Sys_Printf( "DEG:%d! ", ds->numVerts );
1376         
1377         /* testing only? */
1378         if( testAdd )
1379                 memcpy( ds, &old, sizeof( *ds ) );
1380         else
1381         {
1382                 /* copy bounds back to surface */
1383                 VectorCopy( mins, ds->mins );
1384                 VectorCopy( maxs, ds->maxs );
1385                 
1386                 /* mark triangle as used */
1387                 tri->si = NULL;
1388         }
1389         
1390         /* add a side reference */
1391         ds->sideRef = AllocSideRef( tri->side, ds->sideRef );
1392         
1393         /* return to sender */
1394         return score;
1395 }
1396
1397
1398
1399 /*
1400 MetaTrianglesToSurface()
1401 creates map drawsurface(s) from the list of possibles
1402 */
1403
1404 static void MetaTrianglesToSurface( int numPossibles, metaTriangle_t *possibles, int *fOld, int *numAdded )
1405 {
1406         int                                     i, j, f, best, score, bestScore;
1407         metaTriangle_t          *seed, *test;
1408         mapDrawSurface_t        *ds;
1409         bspDrawVert_t           *verts;
1410         int                                     *indexes;
1411         qboolean                        added;
1412         
1413         
1414         /* allocate arrays */
1415         verts = safe_malloc( sizeof( *verts ) * maxSurfaceVerts );
1416         indexes = safe_malloc( sizeof( *indexes ) * maxSurfaceIndexes );
1417         
1418         /* walk the list of triangles */
1419         for( i = 0, seed = possibles; i < numPossibles; i++, seed++ )
1420         {
1421                 /* skip this triangle if it has already been merged */
1422                 if( seed->si == NULL )
1423                         continue;
1424                 
1425                 /* -----------------------------------------------------------------
1426                    initial drawsurf construction
1427                    ----------------------------------------------------------------- */
1428                 
1429                 /* start a new drawsurface */
1430                 ds = AllocDrawSurface( SURFACE_META );
1431                 ds->entityNum = seed->entityNum;
1432                 ds->surfaceNum = seed->surfaceNum;
1433                 ds->castShadows = seed->castShadows;
1434                 ds->recvShadows = seed->recvShadows;
1435                 
1436                 ds->shaderInfo = seed->si;
1437                 ds->planeNum = seed->planeNum;
1438                 ds->fogNum = seed->fogNum;
1439                 ds->sampleSize = seed->sampleSize;
1440                 ds->verts = verts;
1441                 ds->indexes = indexes;
1442                 VectorCopy( seed->lightmapAxis, ds->lightmapAxis );
1443                 ds->sideRef = AllocSideRef( seed->side, NULL );
1444                 
1445                 ClearBounds( ds->mins, ds->maxs );
1446                 
1447                 /* clear verts/indexes */
1448                 memset( verts, 0, sizeof( verts ) );
1449                 memset( indexes, 0, sizeof( indexes ) );
1450                 
1451                 /* add the first triangle */
1452                 if( AddMetaTriangleToSurface( ds, seed, qfalse ) )
1453                         (*numAdded)++;
1454                 
1455                 /* -----------------------------------------------------------------
1456                    add triangles
1457                    ----------------------------------------------------------------- */
1458                 
1459                 /* progressively walk the list until no more triangles can be added */
1460                 added = qtrue;
1461                 while( added )
1462                 {
1463                         /* print pacifier */
1464                         f = 10 * *numAdded / numMetaTriangles;
1465                         if( f > *fOld )
1466                         {
1467                                 *fOld = f;
1468                                 Sys_FPrintf( SYS_VRB, "%d...", f );
1469                         }
1470                         
1471                         /* reset best score */
1472                         best = -1;
1473                         bestScore = 0;
1474                         added = qfalse;
1475                         
1476                         /* walk the list of possible candidates for merging */
1477                         for( j = i + 1, test = &possibles[ j ]; j < numPossibles; j++, test++ )
1478                         {
1479                                 /* skip this triangle if it has already been merged */
1480                                 if( test->si == NULL )
1481                                         continue;
1482                                 
1483                                 /* score this triangle */
1484                                 score = AddMetaTriangleToSurface( ds, test, qtrue );
1485                                 if( score > bestScore )
1486                                 {
1487                                         best = j;
1488                                         bestScore = score;
1489                                         
1490                                         /* if we have a score over a certain threshold, just use it */
1491                                         if( bestScore >= GOOD_SCORE )
1492                                         {
1493                                                 if( AddMetaTriangleToSurface( ds, &possibles[ best ], qfalse ) )
1494                                                         (*numAdded)++;
1495                                                 
1496                                                 /* reset */
1497                                                 best = -1;
1498                                                 bestScore = 0;
1499                                                 added = qtrue;
1500                                         }
1501                                 }
1502                         }
1503                         
1504                         /* add best candidate */
1505                         if( best >= 0 && bestScore > ADEQUATE_SCORE )
1506                         {
1507                                 if( AddMetaTriangleToSurface( ds, &possibles[ best ], qfalse ) )
1508                                         (*numAdded)++;
1509                                 
1510                                 /* reset */
1511                                 added = qtrue;
1512                         }
1513                 }
1514                 
1515                 /* copy the verts and indexes to the new surface */
1516                 ds->verts = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
1517                 memcpy( ds->verts, verts, ds->numVerts * sizeof( bspDrawVert_t ) );
1518                 ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) );
1519                 memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( int ) );
1520                 
1521                 /* classify the surface */
1522                 ClassifySurfaces( 1, ds );
1523                 
1524                 /* add to count */
1525                 numMergedSurfaces++;
1526         }
1527         
1528         /* free arrays */
1529         free( verts );
1530         free( indexes );
1531 }
1532
1533
1534
1535 /*
1536 CompareMetaTriangles()
1537 compare function for qsort()
1538 */
1539
1540 static int CompareMetaTriangles( const void *a, const void *b )
1541 {
1542         int             i, j, av, bv;
1543         vec3_t  aMins, bMins;
1544         
1545         
1546         /* shader first */
1547         if( ((metaTriangle_t*) a)->si < ((metaTriangle_t*) b)->si )
1548                 return 1;
1549         else if( ((metaTriangle_t*) a)->si > ((metaTriangle_t*) b)->si )
1550                 return -1;
1551         
1552         /* then fog */
1553         else if( ((metaTriangle_t*) a)->fogNum < ((metaTriangle_t*) b)->fogNum )
1554                 return 1;
1555         else if( ((metaTriangle_t*) a)->fogNum > ((metaTriangle_t*) b)->fogNum )
1556                 return -1;
1557         
1558         /* then plane */
1559         #if 0
1560                 else if( npDegrees == 0.0f && ((metaTriangle_t*) a)->si->nonplanar == qfalse &&
1561                         ((metaTriangle_t*) a)->planeNum >= 0 && ((metaTriangle_t*) a)->planeNum >= 0 )
1562                 {
1563                         if( ((metaTriangle_t*) a)->plane[ 3 ] < ((metaTriangle_t*) b)->plane[ 3 ] )
1564                                 return 1;
1565                         else if( ((metaTriangle_t*) a)->plane[ 3 ] > ((metaTriangle_t*) b)->plane[ 3 ] )
1566                                 return -1;
1567                         else if( ((metaTriangle_t*) a)->plane[ 0 ] < ((metaTriangle_t*) b)->plane[ 0 ] )
1568                                 return 1;
1569                         else if( ((metaTriangle_t*) a)->plane[ 0 ] > ((metaTriangle_t*) b)->plane[ 0 ] )
1570                                 return -1;
1571                         else if( ((metaTriangle_t*) a)->plane[ 1 ] < ((metaTriangle_t*) b)->plane[ 1 ] )
1572                                 return 1;
1573                         else if( ((metaTriangle_t*) a)->plane[ 1 ] > ((metaTriangle_t*) b)->plane[ 1 ] )
1574                                 return -1;
1575                         else if( ((metaTriangle_t*) a)->plane[ 2 ] < ((metaTriangle_t*) b)->plane[ 2 ] )
1576                                 return 1;
1577                         else if( ((metaTriangle_t*) a)->plane[ 2 ] > ((metaTriangle_t*) b)->plane[ 2 ] )
1578                                 return -1;
1579                 }
1580         #endif
1581         
1582         /* then position in world */
1583         
1584         /* find mins */
1585         VectorSet( aMins, 999999, 999999, 999999 );
1586         VectorSet( bMins, 999999, 999999, 999999 );
1587         for( i = 0; i < 3; i++ )
1588         {
1589                 av = ((metaTriangle_t*) a)->indexes[ i ];
1590                 bv = ((metaTriangle_t*) b)->indexes[ i ];
1591                 for( j = 0; j < 3; j++ )
1592                 {
1593                         if( metaVerts[ av ].xyz[ j ] < aMins[ j ] )
1594                                 aMins[ j ] = metaVerts[ av ].xyz[ j ];
1595                         if( metaVerts[ bv ].xyz[ j ] < bMins[ j ] )
1596                                 bMins[ j ] = metaVerts[ bv ].xyz[ j ];
1597                 }
1598         }
1599         
1600         /* test it */
1601         for( i = 0; i < 3; i++ )
1602         {
1603                 if( aMins[ i ] < bMins[ i ] )
1604                         return 1;
1605                 else if( aMins[ i ] > bMins[ i ] )
1606                         return -1;
1607         }
1608         
1609         /* functionally equivalent */
1610         return 0;
1611 }
1612
1613
1614
1615 /*
1616 MergeMetaTriangles()
1617 merges meta triangles into drawsurfaces
1618 */
1619
1620 void MergeMetaTriangles( void )
1621 {
1622         int                                     i, j, fOld, start, numAdded;
1623         metaTriangle_t          *head, *end;
1624         
1625         
1626         /* only do this if there are meta triangles */
1627         if( numMetaTriangles <= 0 )
1628                 return;
1629         
1630         /* note it */
1631         Sys_FPrintf( SYS_VRB, "--- MergeMetaTriangles ---\n" );
1632         
1633         /* sort the triangles by shader major, fognum minor */
1634         qsort( metaTriangles, numMetaTriangles, sizeof( metaTriangle_t ), CompareMetaTriangles );
1635
1636         /* init pacifier */
1637         fOld = -1;
1638         start = I_FloatTime();
1639         numAdded = 0;
1640         
1641         /* merge */
1642         for( i = 0, j = 0; i < numMetaTriangles; i = j )
1643         {
1644                 /* get head of list */
1645                 head = &metaTriangles[ i ];
1646                 
1647                 /* skip this triangle if it has already been merged */
1648                 if( head->si == NULL )
1649                         continue;
1650                 
1651                 /* find end */
1652                 if( j <= i )
1653                 {
1654                         for( j = i + 1; j < numMetaTriangles; j++ )
1655                         {
1656                                 /* get end of list */
1657                                 end = &metaTriangles[ j ];
1658                                 if( head->si != end->si || head->fogNum != end->fogNum )
1659                                         break;
1660                         }
1661                 }
1662                 
1663                 /* try to merge this list of possible merge candidates */
1664                 MetaTrianglesToSurface( (j - i), head, &fOld, &numAdded );
1665         }
1666         
1667         /* clear meta triangle list */
1668         ClearMetaTriangles();
1669         
1670         /* print time */
1671         if( i )
1672                 Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
1673         
1674         /* emit some stats */
1675         Sys_FPrintf( SYS_VRB, "%9d surfaces merged\n", numMergedSurfaces );
1676         Sys_FPrintf( SYS_VRB, "%9d vertexes merged\n", numMergedVerts );
1677 }