enable q3map2 out of tree compilation
[xonotic/netradiant.git] / tools / quake3 / q3map2 / prtfile.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 PRTFILE_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42    ==============================================================================
43
44    PORTAL FILE GENERATION
45
46    Save out name.prt for qvis to read
47    ==============================================================================
48  */
49
50
51 #define PORTALFILE  "PRT1"
52
53 FILE    *pf;
54 int num_visclusters;                    // clusters the player can be in
55 int num_visportals;
56 int num_solidfaces;
57
58 void WriteFloat( FILE *f, vec_t v ){
59         if ( fabs( v - Q_rint( v ) ) < 0.001 ) {
60                 fprintf( f,"%i ",(int)Q_rint( v ) );
61         }
62         else{
63                 fprintf( f,"%f ",v );
64         }
65 }
66
67 void CountVisportals_r( node_t *node ){
68         int s;
69         portal_t    *p;
70         winding_t   *w;
71
72         // decision node
73         if ( node->planenum != PLANENUM_LEAF ) {
74                 CountVisportals_r( node->children[0] );
75                 CountVisportals_r( node->children[1] );
76                 return;
77         }
78
79         if ( node->opaque ) {
80                 return;
81         }
82
83         for ( p = node->portals ; p ; p = p->next[s] )
84         {
85                 w = p->winding;
86                 s = ( p->nodes[1] == node );
87                 if ( w && p->nodes[0] == node ) {
88                         if ( !PortalPassable( p ) ) {
89                                 continue;
90                         }
91                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
92                                 continue;
93                         }
94                         ++num_visportals;
95                 }
96         }
97 }
98
99 /*
100    =================
101    WritePortalFile_r
102    =================
103  */
104 void WritePortalFile_r( node_t *node ){
105         int i, s, flags;
106         portal_t    *p;
107         winding_t   *w;
108         vec3_t normal;
109         vec_t dist;
110
111         // decision node
112         if ( node->planenum != PLANENUM_LEAF ) {
113                 WritePortalFile_r( node->children[0] );
114                 WritePortalFile_r( node->children[1] );
115                 return;
116         }
117
118         if ( node->opaque ) {
119                 return;
120         }
121
122         for ( p = node->portals ; p ; p = p->next[s] )
123         {
124                 w = p->winding;
125                 s = ( p->nodes[1] == node );
126                 if ( w && p->nodes[0] == node ) {
127                         if ( !PortalPassable( p ) ) {
128                                 continue;
129                         }
130                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
131                                 continue;
132                         }
133                         --num_visportals;
134                         // write out to the file
135
136                         // sometimes planes get turned around when they are very near
137                         // the changeover point between different axis.  interpret the
138                         // plane the same way vis will, and flip the side orders if needed
139                         // FIXME: is this still relevent?
140                         WindingPlane( w, normal, &dist );
141
142                         if ( DotProduct( p->plane.normal, normal ) < 0.99 ) { // backwards...
143                                 fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster );
144                         }
145                         else{
146                                 fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster );
147                         }
148
149                         flags = 0;
150
151                         /* ydnar: added this change to make antiportals work */
152                         if( p->compileFlags & C_HINT ) {
153                                 flags |= 1;
154                         }
155
156                         /* divVerent: I want farplanedist to not kill skybox. So... */
157                         if( p->compileFlags & C_SKY ) {
158                                 flags |= 2;
159                         }
160
161                         fprintf( pf, "%d ", flags );
162
163                         /* write the winding */
164                         for ( i = 0 ; i < w->numpoints ; i++ )
165                         {
166                                 fprintf( pf,"(" );
167                                 WriteFloat( pf, w->p[i][0] );
168                                 WriteFloat( pf, w->p[i][1] );
169                                 WriteFloat( pf, w->p[i][2] );
170                                 fprintf( pf,") " );
171                         }
172                         fprintf( pf,"\n" );
173                 }
174         }
175
176 }
177
178 void CountSolidFaces_r( node_t *node ){
179         int s;
180         portal_t    *p;
181         winding_t   *w;
182
183         // decision node
184         if ( node->planenum != PLANENUM_LEAF ) {
185                 CountSolidFaces_r( node->children[0] );
186                 CountSolidFaces_r( node->children[1] );
187                 return;
188         }
189
190         if ( node->opaque ) {
191                 return;
192         }
193
194         for ( p = node->portals ; p ; p = p->next[s] )
195         {
196                 w = p->winding;
197                 s = ( p->nodes[1] == node );
198                 if ( w ) {
199                         if ( PortalPassable( p ) ) {
200                                 continue;
201                         }
202                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
203                                 continue;
204                         }
205                         // write out to the file
206
207                         ++num_solidfaces;
208                 }
209         }
210 }
211
212 /*
213    =================
214    WriteFaceFile_r
215    =================
216  */
217 void WriteFaceFile_r( node_t *node ){
218         int i, s;
219         portal_t    *p;
220         winding_t   *w;
221
222         // decision node
223         if ( node->planenum != PLANENUM_LEAF ) {
224                 WriteFaceFile_r( node->children[0] );
225                 WriteFaceFile_r( node->children[1] );
226                 return;
227         }
228
229         if ( node->opaque ) {
230                 return;
231         }
232
233         for ( p = node->portals ; p ; p = p->next[s] )
234         {
235                 w = p->winding;
236                 s = ( p->nodes[1] == node );
237                 if ( w ) {
238                         if ( PortalPassable( p ) ) {
239                                 continue;
240                         }
241                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
242                                 continue;
243                         }
244                         // write out to the file
245
246                         if ( p->nodes[0] == node ) {
247                                 fprintf( pf,"%i %i ",w->numpoints, p->nodes[0]->cluster );
248                                 for ( i = 0 ; i < w->numpoints ; i++ )
249                                 {
250                                         fprintf( pf,"(" );
251                                         WriteFloat( pf, w->p[i][0] );
252                                         WriteFloat( pf, w->p[i][1] );
253                                         WriteFloat( pf, w->p[i][2] );
254                                         fprintf( pf,") " );
255                                 }
256                                 fprintf( pf,"\n" );
257                         }
258                         else
259                         {
260                                 fprintf( pf,"%i %i ",w->numpoints, p->nodes[1]->cluster );
261                                 for ( i = w->numpoints - 1; i >= 0; i-- )
262                                 {
263                                         fprintf( pf,"(" );
264                                         WriteFloat( pf, w->p[i][0] );
265                                         WriteFloat( pf, w->p[i][1] );
266                                         WriteFloat( pf, w->p[i][2] );
267                                         fprintf( pf,") " );
268                                 }
269                                 fprintf( pf,"\n" );
270                         }
271                 }
272         }
273 }
274
275 /*
276    ================
277    NumberLeafs_r
278    ================
279  */
280 void NumberLeafs_r( node_t *node, int c ){
281 #if 0
282         portal_t    *p;
283 #endif
284         if ( node->planenum != PLANENUM_LEAF ) {
285                 // decision node
286                 node->cluster = -99;
287
288                 if ( node->has_structural_children ) {
289 #if 0
290                         if ( c >= 0 ) {
291                                 Sys_FPrintf( SYS_ERR,"THIS CANNOT HAPPEN\n" );
292                         }
293 #endif
294                         NumberLeafs_r( node->children[0], c );
295                         NumberLeafs_r( node->children[1], c );
296                 }
297                 else
298                 {
299                         if ( c < 0 ) {
300                                 c = num_visclusters++;
301                         }
302                         NumberLeafs_r( node->children[0], c );
303                         NumberLeafs_r( node->children[1], c );
304                 }
305                 return;
306         }
307
308         node->area = -1;
309
310         if ( node->opaque ) {
311                 // solid block, viewpoint never inside
312                 node->cluster = -1;
313                 return;
314         }
315
316         if ( c < 0 ) {
317                 c = num_visclusters++;
318         }
319
320         node->cluster = c;
321
322 #if 0
323         // count the portals
324         for ( p = node->portals ; p ; )
325         {
326                 if ( p->nodes[0] == node ) {      // only write out from first leaf
327                         if ( PortalPassable( p ) ) {
328                                 num_visportals++;
329                         }
330                         else{
331                                 num_solidfaces++;
332                         }
333                         p = p->next[0];
334                 }
335                 else
336                 {
337                         if ( !PortalPassable( p ) ) {
338                                 num_solidfaces++;
339                         }
340                         p = p->next[1];
341                 }
342         }
343 #endif
344 }
345
346
347 /*
348    ================
349    NumberClusters
350    ================
351  */
352 void NumberClusters( tree_t *tree ) {
353         num_visclusters = 0;
354         num_visportals = 0;
355         num_solidfaces = 0;
356
357         Sys_FPrintf( SYS_VRB,"--- NumberClusters ---\n" );
358
359         // set the cluster field in every leaf and count the total number of portals
360         NumberLeafs_r( tree->headnode, -1 );
361         CountVisportals_r( tree->headnode );
362         CountSolidFaces_r( tree->headnode );
363
364         Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters );
365         Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals );
366         Sys_FPrintf( SYS_VRB, "%9d solidfaces\n", num_solidfaces );
367 }
368
369 /*
370    ================
371    WritePortalFile
372    ================
373  */
374 void WritePortalFile( tree_t *tree, const char *portalFilePath ){
375
376         Sys_FPrintf( SYS_VRB,"--- WritePortalFile ---\n" );
377
378         // write the file
379         Sys_Printf( "writing %s\n", portalFilePath );
380         pf = fopen( portalFilePath, "w" );
381         if ( !pf ) {
382                 Error( "Error opening %s", portalFilePath );
383         }
384
385         fprintf( pf, "%s\n", PORTALFILE );
386         fprintf( pf, "%i\n", num_visclusters );
387         fprintf( pf, "%i\n", num_visportals );
388         fprintf( pf, "%i\n", num_solidfaces );
389
390         WritePortalFile_r( tree->headnode );
391         WriteFaceFile_r( tree->headnode );
392
393         fclose( pf );
394 }