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