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