Merge remote-tracking branch 'ttimo/master'
[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;
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                         /* ydnar: added this change to make antiportals work */
150                         if ( p->compileFlags & C_HINT ) {
151                                 fprintf( pf, "1 " );
152                         }
153                         else{
154                                 fprintf( pf, "0 " );
155                         }
156
157                         /* write the winding */
158                         for ( i = 0 ; i < w->numpoints ; i++ )
159                         {
160                                 fprintf( pf,"(" );
161                                 WriteFloat( pf, w->p[i][0] );
162                                 WriteFloat( pf, w->p[i][1] );
163                                 WriteFloat( pf, w->p[i][2] );
164                                 fprintf( pf,") " );
165                         }
166                         fprintf( pf,"\n" );
167                 }
168         }
169
170 }
171
172 void CountSolidFaces_r( node_t *node ){
173         int s;
174         portal_t    *p;
175         winding_t   *w;
176
177         // decision node
178         if ( node->planenum != PLANENUM_LEAF ) {
179                 CountSolidFaces_r( node->children[0] );
180                 CountSolidFaces_r( node->children[1] );
181                 return;
182         }
183
184         if ( node->opaque ) {
185                 return;
186         }
187
188         for ( p = node->portals ; p ; p = p->next[s] )
189         {
190                 w = p->winding;
191                 s = ( p->nodes[1] == node );
192                 if ( w ) {
193                         if ( PortalPassable( p ) ) {
194                                 continue;
195                         }
196                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
197                                 continue;
198                         }
199                         // write out to the file
200
201                         ++num_solidfaces;
202                 }
203         }
204 }
205
206 /*
207    =================
208    WriteFaceFile_r
209    =================
210  */
211 void WriteFaceFile_r( node_t *node ){
212         int i, s;
213         portal_t    *p;
214         winding_t   *w;
215
216         // decision node
217         if ( node->planenum != PLANENUM_LEAF ) {
218                 WriteFaceFile_r( node->children[0] );
219                 WriteFaceFile_r( node->children[1] );
220                 return;
221         }
222
223         if ( node->opaque ) {
224                 return;
225         }
226
227         for ( p = node->portals ; p ; p = p->next[s] )
228         {
229                 w = p->winding;
230                 s = ( p->nodes[1] == node );
231                 if ( w ) {
232                         if ( PortalPassable( p ) ) {
233                                 continue;
234                         }
235                         if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) {
236                                 continue;
237                         }
238                         // write out to the file
239
240                         if ( p->nodes[0] == node ) {
241                                 fprintf( pf,"%i %i ",w->numpoints, p->nodes[0]->cluster );
242                                 for ( i = 0 ; i < w->numpoints ; i++ )
243                                 {
244                                         fprintf( pf,"(" );
245                                         WriteFloat( pf, w->p[i][0] );
246                                         WriteFloat( pf, w->p[i][1] );
247                                         WriteFloat( pf, w->p[i][2] );
248                                         fprintf( pf,") " );
249                                 }
250                                 fprintf( pf,"\n" );
251                         }
252                         else
253                         {
254                                 fprintf( pf,"%i %i ",w->numpoints, p->nodes[1]->cluster );
255                                 for ( i = w->numpoints - 1; i >= 0; i-- )
256                                 {
257                                         fprintf( pf,"(" );
258                                         WriteFloat( pf, w->p[i][0] );
259                                         WriteFloat( pf, w->p[i][1] );
260                                         WriteFloat( pf, w->p[i][2] );
261                                         fprintf( pf,") " );
262                                 }
263                                 fprintf( pf,"\n" );
264                         }
265                 }
266         }
267 }
268
269 /*
270    ================
271    NumberLeafs_r
272    ================
273  */
274 void NumberLeafs_r( node_t *node, int c ){
275 #if 0
276         portal_t    *p;
277 #endif
278         if ( node->planenum != PLANENUM_LEAF ) {
279                 // decision node
280                 node->cluster = -99;
281
282                 if ( node->has_structural_children ) {
283 #if 0
284                         if ( c >= 0 ) {
285                                 Sys_FPrintf( SYS_ERR,"THIS CANNOT HAPPEN\n" );
286                         }
287 #endif
288                         NumberLeafs_r( node->children[0], c );
289                         NumberLeafs_r( node->children[1], c );
290                 }
291                 else
292                 {
293                         if ( c < 0 ) {
294                                 c = num_visclusters++;
295                         }
296                         NumberLeafs_r( node->children[0], c );
297                         NumberLeafs_r( node->children[1], c );
298                 }
299                 return;
300         }
301
302         node->area = -1;
303
304         if ( node->opaque ) {
305                 // solid block, viewpoint never inside
306                 node->cluster = -1;
307                 return;
308         }
309
310         if ( c < 0 ) {
311                 c = num_visclusters++;
312         }
313
314         node->cluster = c;
315
316 #if 0
317         // count the portals
318         for ( p = node->portals ; p ; )
319         {
320                 if ( p->nodes[0] == node ) {      // only write out from first leaf
321                         if ( PortalPassable( p ) ) {
322                                 num_visportals++;
323                         }
324                         else{
325                                 num_solidfaces++;
326                         }
327                         p = p->next[0];
328                 }
329                 else
330                 {
331                         if ( !PortalPassable( p ) ) {
332                                 num_solidfaces++;
333                         }
334                         p = p->next[1];
335                 }
336         }
337 #endif
338 }
339
340
341 /*
342    ================
343    NumberClusters
344    ================
345  */
346 void NumberClusters( tree_t *tree ) {
347         num_visclusters = 0;
348         num_visportals = 0;
349         num_solidfaces = 0;
350
351         Sys_FPrintf( SYS_VRB,"--- NumberClusters ---\n" );
352
353         // set the cluster field in every leaf and count the total number of portals
354         NumberLeafs_r( tree->headnode, -1 );
355         CountVisportals_r( tree->headnode );
356         CountSolidFaces_r( tree->headnode );
357
358         Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters );
359         Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals );
360         Sys_FPrintf( SYS_VRB, "%9d solidfaces\n", num_solidfaces );
361 }
362
363 /*
364    ================
365    WritePortalFile
366    ================
367  */
368 void WritePortalFile( tree_t *tree ){
369         char filename[1024];
370
371         Sys_FPrintf( SYS_VRB,"--- WritePortalFile ---\n" );
372
373         // write the file
374         sprintf( filename, "%s.prt", source );
375         Sys_Printf( "writing %s\n", filename );
376         pf = fopen( filename, "w" );
377         if ( !pf ) {
378                 Error( "Error opening %s", filename );
379         }
380
381         fprintf( pf, "%s\n", PORTALFILE );
382         fprintf( pf, "%i\n", num_visclusters );
383         fprintf( pf, "%i\n", num_visportals );
384         fprintf( pf, "%i\n", num_solidfaces );
385
386         WritePortalFile_r( tree->headnode );
387         WriteFaceFile_r( tree->headnode );
388
389         fclose( pf );
390 }