]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/writebsp.c
Q3map2:
[xonotic/netradiant.git] / tools / quake3 / q3map2 / writebsp.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 WRITEBSP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42    EmitShader()
43    emits a bsp shader entry
44  */
45
46 int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ){
47         int i;
48         shaderInfo_t    *si;
49
50
51         /* handle special cases */
52         if ( shader == NULL ) {
53                 shader = "noshader";
54         }
55
56         /* try to find an existing shader */
57         for ( i = 0; i < numBSPShaders; i++ )
58         {
59                         /* ydnar: handle custom surface/content flags */
60                 if ( surfaceFlags != NULL && bspShaders[ i ].surfaceFlags != *surfaceFlags ) {
61                         continue;
62                 }
63                 if ( contentFlags != NULL && bspShaders[ i ].contentFlags != *contentFlags ) {
64                         continue;
65                 }
66                 if ( !doingBSP ){
67                         si = ShaderInfoForShader( shader );
68                         if ( si->remapShader && si->remapShader[ 0 ] ) {
69                                 shader = si->remapShader;
70                         }
71                 }
72                 /* compare name */
73                 if ( !Q_stricmp( shader, bspShaders[ i ].shader ) ) {
74                         return i;
75                 }
76         }
77
78         // i == numBSPShaders
79
80         /* get shaderinfo */
81         si = ShaderInfoForShader( shader );
82
83         /* emit a new shader */
84         AUTOEXPAND_BY_REALLOC_BSP( Shaders, 1024 );
85
86         numBSPShaders++;
87         strcpy( bspShaders[ i ].shader, shader );
88         bspShaders[ i ].surfaceFlags = si->surfaceFlags;
89         bspShaders[ i ].contentFlags = si->contentFlags;
90
91         /* handle custom content/surface flags */
92         if ( surfaceFlags != NULL ) {
93                 bspShaders[ i ].surfaceFlags = *surfaceFlags;
94         }
95         if ( contentFlags != NULL ) {
96                 bspShaders[ i ].contentFlags = *contentFlags;
97         }
98
99         /* recursively emit any damage shaders */
100         if ( si->damageShader != NULL && si->damageShader[ 0 ] != '\0' ) {
101                 Sys_FPrintf( SYS_VRB, "Shader %s has damage shader %s\n", si->shader, si->damageShader );
102                 EmitShader( si->damageShader, NULL, NULL );
103         }
104
105         /* return it */
106         return i;
107 }
108
109
110
111 /*
112    EmitPlanes()
113    there is no oportunity to discard planes, because all of the original
114    brushes will be saved in the map
115  */
116
117 void EmitPlanes( void ){
118         int i;
119         bspPlane_t  *bp;
120         plane_t     *mp;
121
122
123         /* walk plane list */
124         mp = mapplanes;
125         for ( i = 0; i < nummapplanes; i++, mp++ )
126         {
127                 AUTOEXPAND_BY_REALLOC_BSP( Planes, 1024 );
128                 bp = &bspPlanes[ numBSPPlanes ];
129                 VectorCopy( mp->normal, bp->normal );
130                 bp->dist = mp->dist;
131                 numBSPPlanes++;
132         }
133
134         /* emit some statistics */
135         Sys_FPrintf( SYS_VRB, "%9d BSP planes\n", numBSPPlanes );
136 }
137
138
139
140 /*
141    EmitLeaf()
142    emits a leafnode to the bsp file
143  */
144
145 void EmitLeaf( node_t *node ){
146         bspLeaf_t       *leaf_p;
147         brush_t         *b;
148         drawSurfRef_t   *dsr;
149
150
151         /* check limits */
152         if ( numBSPLeafs >= MAX_MAP_LEAFS ) {
153                 Error( "MAX_MAP_LEAFS" );
154         }
155
156         leaf_p = &bspLeafs[numBSPLeafs];
157         numBSPLeafs++;
158
159         leaf_p->cluster = node->cluster;
160         leaf_p->area = node->area;
161
162         /* emit bounding box */
163         VectorCopy( node->mins, leaf_p->mins );
164         VectorCopy( node->maxs, leaf_p->maxs );
165
166         /* emit leaf brushes */
167         leaf_p->firstBSPLeafBrush = numBSPLeafBrushes;
168         for ( b = node->brushlist; b; b = b->next )
169         {
170                 /* something is corrupting brushes */
171                 if ( (size_t) b < 256 ) {
172                         Sys_Printf( "WARNING: Node brush list corrupted (0x%08X)\n", b );
173                         break;
174                 }
175                 //%     if( b->guard != 0xDEADBEEF )
176                 //%             Sys_Printf( "Brush %6d: 0x%08X Guard: 0x%08X Next: 0x%08X Original: 0x%08X Sides: %d\n", b->brushNum, b, b, b->next, b->original, b->numsides );
177
178                 AUTOEXPAND_BY_REALLOC_BSP( LeafBrushes, 1024 );
179                 bspLeafBrushes[ numBSPLeafBrushes ] = b->original->outputNum;
180                 numBSPLeafBrushes++;
181         }
182
183         leaf_p->numBSPLeafBrushes = numBSPLeafBrushes - leaf_p->firstBSPLeafBrush;
184
185         /* emit leaf surfaces */
186         if ( node->opaque ) {
187                 return;
188         }
189
190         /* add the drawSurfRef_t drawsurfs */
191         leaf_p->firstBSPLeafSurface = numBSPLeafSurfaces;
192         for ( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef )
193         {
194                 AUTOEXPAND_BY_REALLOC_BSP( LeafSurfaces, 1024 );
195                 bspLeafSurfaces[ numBSPLeafSurfaces ] = dsr->outputNum;
196                 numBSPLeafSurfaces++;
197         }
198
199         leaf_p->numBSPLeafSurfaces = numBSPLeafSurfaces - leaf_p->firstBSPLeafSurface;
200 }
201
202
203 /*
204    EmitDrawNode_r()
205    recursively emit the bsp nodes
206  */
207
208 int EmitDrawNode_r( node_t *node ){
209         bspNode_t   *n;
210         int i, n0;
211
212
213         /* check for leafnode */
214         if ( node->planenum == PLANENUM_LEAF ) {
215                 EmitLeaf( node );
216                 return -numBSPLeafs;
217         }
218
219         /* emit a node */
220         AUTOEXPAND_BY_REALLOC_BSP( Nodes, 1024 );
221         n0 = numBSPNodes;
222         n = &bspNodes[ n0 ];
223         numBSPNodes++;
224
225         VectorCopy( node->mins, n->mins );
226         VectorCopy( node->maxs, n->maxs );
227
228         if ( node->planenum & 1 ) {
229                 Error( "WriteDrawNodes_r: odd planenum" );
230         }
231         n->planeNum = node->planenum;
232
233         //
234         // recursively output the other nodes
235         //
236         for ( i = 0 ; i < 2 ; i++ )
237         {
238                 if ( node->children[i]->planenum == PLANENUM_LEAF ) {
239                         n->children[i] = -( numBSPLeafs + 1 );
240                         EmitLeaf( node->children[i] );
241                 }
242                 else
243                 {
244                         n->children[i] = numBSPNodes;
245                         EmitDrawNode_r( node->children[i] );
246                         // n may have become invalid here, so...
247                         n = &bspNodes[ n0 ];
248                 }
249         }
250
251         return n - bspNodes;
252 }
253
254
255
256 /*
257    ============
258    SetModelNumbers
259    ============
260  */
261 void SetModelNumbers( void ){
262         int i;
263         int models;
264         char value[10];
265
266         models = 1;
267         for ( i = 1 ; i < numEntities ; i++ ) {
268                 if ( entities[i].brushes || entities[i].patches ) {
269                         sprintf( value, "*%i", models );
270                         models++;
271                         SetKeyValue( &entities[i], "model", value );
272                 }
273         }
274
275 }
276
277
278
279
280 /*
281    SetLightStyles()
282    sets style keys for entity lights
283  */
284
285 void SetLightStyles( void ){
286         int i, j, style, numStyles;
287         const char  *t;
288         entity_t    *e;
289         epair_t     *ep, *next;
290         char value[ 10 ];
291         char lightTargets[ MAX_SWITCHED_LIGHTS ][ 64 ];
292         int lightStyles[ MAX_SWITCHED_LIGHTS ];
293
294         /* -keeplights option: force lights to be kept and ignore what the map file says */
295         if ( keepLights ) {
296                 SetKeyValue( &entities[0], "_keepLights", "1" );
297         }
298
299         /* ydnar: determine if we keep lights in the bsp */
300         if ( KeyExists( &entities[ 0 ], "_keepLights" ) == qtrue ) {
301                 t = ValueForKey( &entities[ 0 ], "_keepLights" );
302                 keepLights = ( t[ 0 ] == '1' ) ? qtrue : qfalse;
303         }
304
305         /* any light that is controlled (has a targetname) must have a unique style number generated for it */
306         numStyles = 0;
307         for ( i = 1; i < numEntities; i++ )
308         {
309                 e = &entities[ i ];
310
311                 t = ValueForKey( e, "classname" );
312                 if ( Q_strncasecmp( t, "light", 5 ) ) {
313                         continue;
314                 }
315                 t = ValueForKey( e, "targetname" );
316                 if ( t[ 0 ] == '\0' ) {
317                         /* ydnar: strip the light from the BSP file */
318                         if ( keepLights == qfalse ) {
319                                 ep = e->epairs;
320                                 while ( ep != NULL )
321                                 {
322                                         next = ep->next;
323                                         free( ep->key );
324                                         free( ep->value );
325                                         free( ep );
326                                         ep = next;
327                                 }
328                                 e->epairs = NULL;
329                                 numStrippedLights++;
330                         }
331
332                         /* next light */
333                         continue;
334                 }
335
336                 /* get existing style */
337                 style = IntForKey( e, "style" );
338                 if ( style < LS_NORMAL || style > LS_NONE ) {
339                         Error( "Invalid lightstyle (%d) on entity %d", style, i );
340                 }
341
342                 /* find this targetname */
343                 for ( j = 0; j < numStyles; j++ )
344                         if ( lightStyles[ j ] == style && !strcmp( lightTargets[ j ], t ) ) {
345                                 break;
346                         }
347
348                 /* add a new style */
349                 if ( j >= numStyles ) {
350                         if ( numStyles == MAX_SWITCHED_LIGHTS ) {
351                                 Error( "MAX_SWITCHED_LIGHTS (%d) exceeded, reduce the number of lights with targetnames", MAX_SWITCHED_LIGHTS );
352                         }
353                         strcpy( lightTargets[ j ], t );
354                         lightStyles[ j ] = style;
355                         numStyles++;
356                 }
357
358                 /* set explicit style */
359                 sprintf( value, "%d", 32 + j );
360                 SetKeyValue( e, "style", value );
361
362                 /* set old style */
363                 if ( style != LS_NORMAL ) {
364                         sprintf( value, "%d", style );
365                         SetKeyValue( e, "switch_style", value );
366                 }
367         }
368
369         /* emit some statistics */
370         Sys_FPrintf( SYS_VRB, "%9d light entities stripped\n", numStrippedLights );
371 }
372
373
374
375 /*
376    BeginBSPFile()
377    starts a new bsp file
378  */
379
380 void BeginBSPFile( void ){
381         /* these values may actually be initialized if the file existed when loaded, so clear them explicitly */
382         numBSPModels = 0;
383         numBSPNodes = 0;
384         numBSPBrushSides = 0;
385         numBSPLeafSurfaces = 0;
386         numBSPLeafBrushes = 0;
387
388         /* leave leaf 0 as an error, because leafs are referenced as negative number nodes */
389         numBSPLeafs = 1;
390
391
392         /* ydnar: gs mods: set the first 6 drawindexes to 0 1 2 2 1 3 for triangles and quads */
393         numBSPDrawIndexes = 6;
394         AUTOEXPAND_BY_REALLOC_BSP( DrawIndexes, 1024 );
395         bspDrawIndexes[ 0 ] = 0;
396         bspDrawIndexes[ 1 ] = 1;
397         bspDrawIndexes[ 2 ] = 2;
398         bspDrawIndexes[ 3 ] = 0;
399         bspDrawIndexes[ 4 ] = 2;
400         bspDrawIndexes[ 5 ] = 3;
401 }
402
403
404
405 /*
406    EndBSPFile()
407    finishes a new bsp and writes to disk
408  */
409
410 void EndBSPFile( qboolean do_write ){
411         char path[ 1024 ];
412
413
414         Sys_FPrintf( SYS_VRB, "--- EndBSPFile ---\n" );
415
416         EmitPlanes();
417
418         numBSPEntities = numEntities;
419         UnparseEntities();
420
421         if ( do_write ) {
422                 /* write the surface extra file */
423                 WriteSurfaceExtraFile( source );
424
425                 /* write the bsp */
426                 sprintf( path, "%s.bsp", source );
427                 Sys_Printf( "Writing %s\n", path );
428                 WriteBSPFile( path );
429         }
430 }
431
432
433
434 /*
435    EmitBrushes()
436    writes the brush list to the bsp
437  */
438
439 void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes ){
440         int j;
441         brush_t         *b;
442         bspBrush_t      *db;
443         bspBrushSide_t  *cp;
444
445
446         /* set initial brush */
447         if ( firstBrush != NULL ) {
448                 *firstBrush = numBSPBrushes;
449         }
450         if ( numBrushes != NULL ) {
451                 *numBrushes = 0;
452         }
453
454         /* walk list of brushes */
455         for ( b = brushes; b != NULL; b = b->next )
456         {
457                 /* check limits */
458                 AUTOEXPAND_BY_REALLOC_BSP( Brushes, 1024 );
459
460                 /* get bsp brush */
461                 b->outputNum = numBSPBrushes;
462                 db = &bspBrushes[ numBSPBrushes ];
463                 numBSPBrushes++;
464                 if ( numBrushes != NULL ) {
465                         ( *numBrushes )++;
466                 }
467
468                 db->shaderNum = EmitShader( b->contentShader->shader, &b->contentShader->contentFlags, &b->contentShader->surfaceFlags );
469                 db->firstSide = numBSPBrushSides;
470
471                 /* walk sides */
472                 db->numSides = 0;
473                 for ( j = 0; j < b->numsides; j++ )
474                 {
475                         /* set output number to bogus initially */
476                         b->sides[ j ].outputNum = -1;
477
478                         /* check count */
479                         AUTOEXPAND_BY_REALLOC_BSP( BrushSides, 1024 );
480
481                         /* emit side */
482                         b->sides[ j ].outputNum = numBSPBrushSides;
483                         cp = &bspBrushSides[ numBSPBrushSides ];
484                         db->numSides++;
485                         numBSPBrushSides++;
486                         cp->planeNum = b->sides[ j ].planenum;
487
488                         /* emit shader */
489                         if ( b->sides[ j ].shaderInfo ) {
490                                 cp->shaderNum = EmitShader( b->sides[ j ].shaderInfo->shader, &b->sides[ j ].shaderInfo->contentFlags, &b->sides[ j ].shaderInfo->surfaceFlags );
491                         }
492                         else{
493                                 cp->shaderNum = EmitShader( NULL, NULL, NULL );
494                         }
495                 }
496         }
497 }
498
499
500
501 /*
502    EmitFogs() - ydnar
503    turns map fogs into bsp fogs
504  */
505
506 void EmitFogs( void ){
507         int i, j;
508
509
510         /* setup */
511         numBSPFogs = numMapFogs;
512
513         /* walk list */
514         for ( i = 0; i < numMapFogs; i++ )
515         {
516                 /* set shader */
517                 strcpy( bspFogs[ i ].shader, mapFogs[ i ].si->shader );
518
519                 /* global fog doesn't have an associated brush */
520                 if ( mapFogs[ i ].brush == NULL ) {
521                         bspFogs[ i ].brushNum = -1;
522                         bspFogs[ i ].visibleSide = -1;
523                 }
524                 else
525                 {
526                         /* set brush */
527                         bspFogs[ i ].brushNum = mapFogs[ i ].brush->outputNum;
528
529                         /* try to use forced visible side */
530                         if ( mapFogs[ i ].visibleSide >= 0 ) {
531                                 bspFogs[ i ].visibleSide = mapFogs[ i ].visibleSide;
532                                 continue;
533                         }
534
535                         /* find visible side */
536                         for ( j = 0; j < 6; j++ )
537                         {
538                                 if ( mapFogs[ i ].brush->sides[ j ].visibleHull != NULL ) {
539                                         Sys_Printf( "Fog %d has visible side %d\n", i, j );
540                                         bspFogs[ i ].visibleSide = j;
541                                         break;
542                                 }
543                         }
544                 }
545         }
546 }
547
548
549
550 /*
551    BeginModel()
552    sets up a new brush model
553  */
554
555 void BeginModel( void ){
556         bspModel_t  *mod;
557         brush_t     *b;
558         entity_t    *e;
559         vec3_t mins, maxs;
560         vec3_t lgMins, lgMaxs;          /* ydnar: lightgrid mins/maxs */
561         parseMesh_t *p;
562         int i;
563
564
565         /* test limits */
566         AUTOEXPAND_BY_REALLOC_BSP( Models, 256 );
567
568         /* get model and entity */
569         mod = &bspModels[ numBSPModels ];
570         e = &entities[ mapEntityNum ];
571
572         /* ydnar: lightgrid mins/maxs */
573         ClearBounds( lgMins, lgMaxs );
574
575         /* bound the brushes */
576         ClearBounds( mins, maxs );
577         for ( b = e->brushes; b; b = b->next )
578         {
579                 /* ignore non-real brushes (origin, etc) */
580                 if ( b->numsides == 0 ) {
581                         continue;
582                 }
583                 AddPointToBounds( b->mins, mins, maxs );
584                 AddPointToBounds( b->maxs, mins, maxs );
585
586                 /* ydnar: lightgrid bounds */
587                 if ( b->compileFlags & C_LIGHTGRID ) {
588                         AddPointToBounds( b->mins, lgMins, lgMaxs );
589                         AddPointToBounds( b->maxs, lgMins, lgMaxs );
590                 }
591         }
592
593         /* bound patches */
594         for ( p = e->patches; p; p = p->next )
595         {
596                 for ( i = 0; i < ( p->mesh.width * p->mesh.height ); i++ )
597                         AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs );
598         }
599
600         /* ydnar: lightgrid mins/maxs */
601         if ( lgMins[ 0 ] < 99999 ) {
602                 /* use lightgrid bounds */
603                 VectorCopy( lgMins, mod->mins );
604                 VectorCopy( lgMaxs, mod->maxs );
605         }
606         else
607         {
608                 /* use brush/patch bounds */
609                 VectorCopy( mins, mod->mins );
610                 VectorCopy( maxs, mod->maxs );
611         }
612
613         /* note size */
614         Sys_FPrintf( SYS_VRB, "BSP bounds: { %f %f %f } { %f %f %f }\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
615         Sys_FPrintf( SYS_VRB, "Lightgrid bounds: { %f %f %f } { %f %f %f }\n", lgMins[ 0 ], lgMins[ 1 ], lgMins[ 2 ], lgMaxs[ 0 ], lgMaxs[ 1 ], lgMaxs[ 2 ] );
616
617         /* set firsts */
618         mod->firstBSPSurface = numBSPDrawSurfaces;
619         mod->firstBSPBrush = numBSPBrushes;
620 }
621
622
623
624
625 /*
626    EndModel()
627    finish a model's processing
628  */
629
630 void EndModel( entity_t *e, node_t *headnode ){
631         bspModel_t  *mod;
632
633
634         /* note it */
635         Sys_FPrintf( SYS_VRB, "--- EndModel ---\n" );
636
637         /* emit the bsp */
638         mod = &bspModels[ numBSPModels ];
639         EmitDrawNode_r( headnode );
640
641         /* set surfaces and brushes */
642         mod->numBSPSurfaces = numBSPDrawSurfaces - mod->firstBSPSurface;
643         mod->firstBSPBrush = e->firstBrush;
644         mod->numBSPBrushes = e->numBrushes;
645
646         /* increment model count */
647         numBSPModels++;
648 }