]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/writebsp.c
q3map2: -fs_nobasepath implies -fs_nomagicpath
[xonotic/netradiant.git] / tools / quake2 / q2map / writebsp.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 #include "qbsp.h"
22
23 int c_nofaces;
24 int c_facenodes;
25
26
27 /*
28    =========================================================
29
30    ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
31
32    =========================================================
33  */
34
35 int planeused[MAX_MAP_PLANES];
36
37 /*
38    ============
39    EmitPlanes
40
41    There is no oportunity to discard planes, because all of the original
42    brushes will be saved in the map.
43    ============
44  */
45 void EmitPlanes( void ){
46         int i;
47         dplane_t    *dp;
48         plane_t     *mp;
49         int planetranslate[MAX_MAP_PLANES];
50
51         mp = mapplanes;
52         for ( i = 0 ; i < nummapplanes ; i++, mp++ )
53         {
54                 dp = &dplanes[numplanes];
55                 planetranslate[i] = numplanes;
56                 VectorCopy( mp->normal, dp->normal );
57                 dp->dist = mp->dist;
58                 dp->type = mp->type;
59                 numplanes++;
60         }
61 }
62
63
64 //========================================================
65
66 void EmitMarkFace( dleaf_t *leaf_p, face_t *f ){
67         int i;
68         int facenum;
69
70         while ( f->merged )
71                 f = f->merged;
72
73         if ( f->split[0] ) {
74                 EmitMarkFace( leaf_p, f->split[0] );
75                 EmitMarkFace( leaf_p, f->split[1] );
76                 return;
77         }
78
79         facenum = f->outputnumber;
80         if ( facenum == -1 ) {
81                 return; // degenerate face
82
83         }
84         if ( facenum < 0 || facenum >= numfaces ) {
85                 Error( "Bad leafface" );
86         }
87         for ( i = leaf_p->firstleafface ; i < numleaffaces ; i++ )
88                 if ( dleaffaces[i] == facenum ) {
89                         break;
90                 }               // merged out face
91         if ( i == numleaffaces ) {
92                 if ( numleaffaces >= MAX_MAP_LEAFFACES ) {
93                         Error( "MAX_MAP_LEAFFACES" );
94                 }
95
96                 dleaffaces[numleaffaces] =  facenum;
97                 numleaffaces++;
98         }
99
100 }
101
102
103 /*
104    ==================
105    EmitLeaf
106    ==================
107  */
108 void EmitLeaf( node_t *node ){
109         dleaf_t     *leaf_p;
110         portal_t    *p;
111         int s;
112         face_t      *f;
113         bspbrush_t  *b;
114         int i;
115         int brushnum;
116
117         // emit a leaf
118         if ( numleafs >= MAX_MAP_LEAFS ) {
119                 Error( "MAX_MAP_LEAFS" );
120         }
121
122         leaf_p = &dleafs[numleafs];
123         numleafs++;
124
125         leaf_p->contents = node->contents;
126         leaf_p->cluster = node->cluster;
127         leaf_p->area = node->area;
128
129         //
130         // write bounding box info
131         //
132         VectorCopy( (short) node->mins, leaf_p->mins );
133         VectorCopy( (short) node->maxs, leaf_p->maxs );
134
135         //
136         // write the leafbrushes
137         //
138         leaf_p->firstleafbrush = numleafbrushes;
139         for ( b = node->brushlist ; b ; b = b->next )
140         {
141                 if ( numleafbrushes >= MAX_MAP_LEAFBRUSHES ) {
142                         Error( "MAX_MAP_LEAFBRUSHES" );
143                 }
144
145                 brushnum = b->original - mapbrushes;
146                 for ( i = leaf_p->firstleafbrush ; i < numleafbrushes ; i++ )
147                         if ( dleafbrushes[i] == brushnum ) {
148                                 break;
149                         }
150                 if ( i == numleafbrushes ) {
151                         dleafbrushes[numleafbrushes] = brushnum;
152                         numleafbrushes++;
153                 }
154         }
155         leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
156
157         //
158         // write the leaffaces
159         //
160         if ( leaf_p->contents & CONTENTS_SOLID ) {
161                 return;     // no leaffaces in solids
162
163         }
164         leaf_p->firstleafface = numleaffaces;
165
166         for ( p = node->portals ; p ; p = p->next[s] )
167         {
168                 s = ( p->nodes[1] == node );
169                 f = p->face[s];
170                 if ( !f ) {
171                         continue;   // not a visible portal
172
173                 }
174                 EmitMarkFace( leaf_p, f );
175         }
176
177         leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
178 }
179
180
181 /*
182    ==================
183    EmitFace
184    ==================
185  */
186 void EmitFace( face_t *f ){
187         dface_t *df;
188         int i;
189         int e;
190
191         f->outputnumber = -1;
192
193         if ( f->numpoints < 3 ) {
194                 return;     // degenerated
195         }
196         if ( f->merged || f->split[0] || f->split[1] ) {
197                 return;     // not a final face
198         }
199
200         // save output number so leaffaces can use
201         f->outputnumber = numfaces;
202
203         if ( numfaces >= MAX_MAP_FACES ) {
204                 Error( "numfaces == MAX_MAP_FACES" );
205         }
206         df = &dfaces[numfaces];
207         numfaces++;
208
209         // planenum is used by qlight, but not quake
210         df->planenum = f->planenum & ( ~1 );
211         df->side = f->planenum & 1;
212
213         df->firstedge = numsurfedges;
214         df->numedges = f->numpoints;
215         df->texinfo = f->texinfo;
216         for ( i = 0 ; i < f->numpoints ; i++ )
217         {
218 //              e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
219                 e = GetEdge2( f->vertexnums[i], f->vertexnums[( i + 1 ) % f->numpoints], f );
220                 if ( numsurfedges >= MAX_MAP_SURFEDGES ) {
221                         Error( "numsurfedges == MAX_MAP_SURFEDGES" );
222                 }
223                 dsurfedges[numsurfedges] = e;
224                 numsurfedges++;
225         }
226 }
227
228 /*
229    ============
230    EmitDrawingNode_r
231    ============
232  */
233 int EmitDrawNode_r( node_t *node ){
234         dnode_t *n;
235         face_t  *f;
236         int i;
237
238         if ( node->planenum == PLANENUM_LEAF ) {
239                 EmitLeaf( node );
240                 return -numleafs;
241         }
242
243         // emit a node
244         if ( numnodes == MAX_MAP_NODES ) {
245                 Error( "MAX_MAP_NODES" );
246         }
247         n = &dnodes[numnodes];
248         numnodes++;
249
250         VectorCopy( (short) node->mins, n->mins );
251         VectorCopy( (short) node->maxs, n->maxs );
252
253         planeused[node->planenum]++;
254         planeused[node->planenum ^ 1]++;
255
256         if ( node->planenum & 1 ) {
257                 Error( "WriteDrawNodes_r: odd planenum" );
258         }
259         n->planenum = node->planenum;
260         n->firstface = numfaces;
261
262         if ( !node->faces ) {
263                 c_nofaces++;
264         }
265         else{
266                 c_facenodes++;
267         }
268
269         for ( f = node->faces ; f ; f = f->next )
270                 EmitFace( f );
271
272         n->numfaces = numfaces - n->firstface;
273
274
275         //
276         // recursively output the other nodes
277         //
278         for ( i = 0 ; i < 2 ; i++ )
279         {
280                 if ( node->children[i]->planenum == PLANENUM_LEAF ) {
281                         n->children[i] = -( numleafs + 1 );
282                         EmitLeaf( node->children[i] );
283                 }
284                 else
285                 {
286                         n->children[i] = numnodes;
287                         EmitDrawNode_r( node->children[i] );
288                 }
289         }
290
291         return n - dnodes;
292 }
293
294 //=========================================================
295
296
297 /*
298    ============
299    WriteBSP
300    ============
301  */
302 void WriteBSP( node_t *headnode ){
303         int oldfaces;
304
305         c_nofaces = 0;
306         c_facenodes = 0;
307
308         Sys_FPrintf( SYS_VRB, "--- WriteBSP ---\n" );
309
310         oldfaces = numfaces;
311         dmodels[nummodels].headnode = EmitDrawNode_r( headnode );
312         EmitAreaPortals( headnode );
313
314         Sys_FPrintf( SYS_VRB, "%5i nodes with faces\n", c_facenodes );
315         Sys_FPrintf( SYS_VRB, "%5i nodes without faces\n", c_nofaces );
316         Sys_FPrintf( SYS_VRB, "%5i faces\n", numfaces - oldfaces );
317 }
318
319 //===========================================================
320
321 /*
322    ============
323    SetModelNumbers
324    ============
325  */
326 void SetModelNumbers( void ){
327         int i;
328         int models;
329         char value[10];
330
331         models = 1;
332         for ( i = 1 ; i < num_entities ; i++ )
333         {
334                 if ( entities[i].numbrushes ) {
335                         sprintf( value, "*%i", models );
336                         models++;
337                         SetKeyValue( &entities[i], "model", value );
338                 }
339         }
340
341 }
342
343 /*
344    ============
345    SetLightStyles
346    ============
347  */
348 #define MAX_SWITCHED_LIGHTS 32
349 void SetLightStyles( void ){
350         int stylenum;
351         char    *t;
352         entity_t    *e;
353         int i, j;
354         char value[10];
355         char lighttargets[MAX_SWITCHED_LIGHTS][64];
356
357
358         // any light that is controlled (has a targetname)
359         // must have a unique style number generated for it
360
361         stylenum = 0;
362         for ( i = 1 ; i < num_entities ; i++ )
363         {
364                 e = &entities[i];
365
366                 t = ValueForKey( e, "classname" );
367                 if ( Q_strncasecmp( t, "light", 5 ) ) {
368                         continue;
369                 }
370                 t = ValueForKey( e, "targetname" );
371                 if ( !t[0] ) {
372                         continue;
373                 }
374
375                 // find this targetname
376                 for ( j = 0 ; j < stylenum ; j++ )
377                         if ( !strcmp( lighttargets[j], t ) ) {
378                                 break;
379                         }
380                 if ( j == stylenum ) {
381                         if ( stylenum == MAX_SWITCHED_LIGHTS ) {
382                                 Error( "stylenum == MAX_SWITCHED_LIGHTS" );
383                         }
384                         strcpy( lighttargets[j], t );
385                         stylenum++;
386                 }
387                 sprintf( value, "%i", 32 + j );
388                 SetKeyValue( e, "style", value );
389         }
390
391 }
392
393 //===========================================================
394
395 /*
396    ============
397    EmitBrushes
398    ============
399  */
400 void EmitBrushes( void ){
401         int i, j, bnum, s, x;
402         dbrush_t    *db;
403         mapbrush_t      *b;
404         dbrushside_t    *cp;
405         vec3_t normal;
406         vec_t dist;
407         int planenum;
408
409         numbrushsides = 0;
410         numbrushes = nummapbrushes;
411
412         for ( bnum = 0 ; bnum < nummapbrushes ; bnum++ )
413         {
414                 b = &mapbrushes[bnum];
415                 db = &dbrushes[bnum];
416
417                 db->contents = b->contents;
418                 db->firstside = numbrushsides;
419                 db->numsides = b->numsides;
420                 for ( j = 0 ; j < b->numsides ; j++ )
421                 {
422                         if ( numbrushsides == MAX_MAP_BRUSHSIDES ) {
423                                 Error( "MAX_MAP_BRUSHSIDES" );
424                         }
425                         cp = &dbrushsides[numbrushsides];
426                         numbrushsides++;
427                         cp->planenum = b->original_sides[j].planenum;
428                         cp->texinfo = b->original_sides[j].texinfo;
429                 }
430
431                 // add any axis planes not contained in the brush to bevel off corners
432                 for ( x = 0 ; x < 3 ; x++ )
433                         for ( s = -1 ; s <= 1 ; s += 2 )
434                         {
435                                 // add the plane
436                                 VectorCopy( vec3_origin, normal );
437                                 normal[x] = (float) s;
438                                 if ( s == -1 ) {
439                                         dist = -b->mins[x];
440                                 }
441                                 else{
442                                         dist = b->maxs[x];
443                                 }
444                                 planenum = FindFloatPlane( normal, dist );
445                                 for ( i = 0 ; i < b->numsides ; i++ )
446                                         if ( b->original_sides[i].planenum == planenum ) {
447                                                 break;
448                                         }
449                                 if ( i == b->numsides ) {
450                                         if ( numbrushsides >= MAX_MAP_BRUSHSIDES ) {
451                                                 Error( "MAX_MAP_BRUSHSIDES" );
452                                         }
453
454                                         dbrushsides[numbrushsides].planenum = planenum;
455                                         dbrushsides[numbrushsides].texinfo =
456                                                 dbrushsides[numbrushsides - 1].texinfo;
457                                         numbrushsides++;
458                                         db->numsides++;
459                                 }
460                         }
461
462         }
463
464 }
465
466 //===========================================================
467
468 /*
469    ==================
470    BeginBSPFile
471    ==================
472  */
473 void BeginBSPFile( void ){
474         // these values may actually be initialized
475         // if the file existed when loaded, so clear them explicitly
476         nummodels = 0;
477         numfaces = 0;
478         numnodes = 0;
479         numbrushsides = 0;
480         numvertexes = 0;
481         numleaffaces = 0;
482         numleafbrushes = 0;
483         numsurfedges = 0;
484
485         // edge 0 is not used, because 0 can't be negated
486         numedges = 1;
487
488         // leave vertex 0 as an error
489         numvertexes = 1;
490
491         // leave leaf 0 as an error
492         numleafs = 1;
493         dleafs[0].contents = CONTENTS_SOLID;
494 }
495
496
497 /*
498    ============
499    EndBSPFile
500    ============
501  */
502 void EndBSPFile( void ){
503         char path[1024];
504
505 #if 0
506         int len;
507         byte    *buf;
508 #endif
509
510         EmitBrushes();
511         EmitPlanes();
512         UnparseEntities();
513
514         // load the pop
515 #if 0
516         sprintf( path, "%s/pics/pop.lmp", gamedir );
517         len = LoadFile( path, &buf );
518         memcpy( dpop, buf, sizeof( dpop ) );
519         free( buf );
520 #endif
521
522         // write the map
523         sprintf( path, "%s.bsp", source );
524         Sys_Printf( "Writing %s\n", path );
525         WriteBSPFile( path );
526 }
527
528
529 /*
530    ==================
531    BeginModel
532    ==================
533  */
534 int firstmodleaf;
535 extern int firstmodeledge;
536 extern int firstmodelface;
537 void BeginModel( void ){
538         dmodel_t    *mod;
539         int start, end;
540         mapbrush_t  *b;
541         int j;
542         entity_t    *e;
543         vec3_t mins, maxs;
544
545         if ( nummodels == MAX_MAP_MODELS ) {
546                 Error( "MAX_MAP_MODELS" );
547         }
548         mod = &dmodels[nummodels];
549
550         mod->firstface = numfaces;
551
552         firstmodleaf = numleafs;
553         firstmodeledge = numedges;
554         firstmodelface = numfaces;
555
556         //
557         // bound the brushes
558         //
559         e = &entities[entity_num];
560
561         start = e->firstbrush;
562         end = start + e->numbrushes;
563         ClearBounds( mins, maxs );
564
565         for ( j = start ; j < end ; j++ )
566         {
567                 b = &mapbrushes[j];
568                 if ( !b->numsides ) {
569                         continue;   // not a real brush (origin brush)
570                 }
571                 AddPointToBounds( b->mins, mins, maxs );
572                 AddPointToBounds( b->maxs, mins, maxs );
573         }
574
575         VectorCopy( mins, mod->mins );
576         VectorCopy( maxs, mod->maxs );
577 }
578
579
580 /*
581    ==================
582    EndModel
583    ==================
584  */
585 void EndModel( void ){
586         dmodel_t    *mod;
587
588         mod = &dmodels[nummodels];
589
590         mod->numfaces = numfaces - mod->firstface;
591
592         nummodels++;
593 }