/* ------------------------------------------------------------------------------- Copyright (C) 1999-2007 id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ---------------------------------------------------------------------------------- This code has been altered significantly from its original form, to support several games based on the Quake III Arena engine, in the form of "Q3Map2." ------------------------------------------------------------------------------- */ /* marker */ #define PRTFILE_C /* dependencies */ #include "vmap.h" /* ============================================================================== PORTAL FILE GENERATION Save out name.prt for qvis to read ============================================================================== */ #define PORTALFILE "PRT1" FILE *pf; int num_visclusters; // clusters the player can be in int num_visportals; int num_solidfaces; void WriteFloat( FILE *f, vec_t v ){ if ( fabs( v - Q_rint( v ) ) < 0.001 ) { fprintf( f,"%i ",(int)Q_rint( v ) ); } else{ fprintf( f,"%f ",v ); } } void CountVisportals_r( node_t *node ){ int s; portal_t *p; winding_t *w; // decision node if ( node->planenum != PLANENUM_LEAF ) { CountVisportals_r( node->children[0] ); CountVisportals_r( node->children[1] ); return; } if ( node->opaque ) { return; } for ( p = node->portals ; p ; p = p->next[s] ) { w = p->winding; s = ( p->nodes[1] == node ); if ( w && p->nodes[0] == node ) { if ( !PortalPassable( p ) ) { continue; } if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) { continue; } ++num_visportals; } } } /* ================= WritePortalFile_r ================= */ void WritePortalFile_r( node_t *node ){ int i, s, flags; portal_t *p; winding_t *w; vec3_t normal; vec_t dist; // decision node if ( node->planenum != PLANENUM_LEAF ) { WritePortalFile_r( node->children[0] ); WritePortalFile_r( node->children[1] ); return; } if ( node->opaque ) { return; } for ( p = node->portals ; p ; p = p->next[s] ) { w = p->winding; s = ( p->nodes[1] == node ); if ( w && p->nodes[0] == node ) { if ( !PortalPassable( p ) ) { continue; } if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) { continue; } --num_visportals; // write out to the file // sometimes planes get turned around when they are very near // the changeover point between different axis. interpret the // plane the same way vis will, and flip the side orders if needed // FIXME: is this still relevent? WindingPlane( w, normal, &dist ); if ( DotProduct( p->plane.normal, normal ) < 0.99 ) { // backwards... fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster ); } else{ fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster ); } flags = 0; /* ydnar: added this change to make antiportals work */ if( p->compileFlags & C_HINT ) { flags |= 1; } /* divVerent: I want farplanedist to not kill skybox. So... */ if( p->compileFlags & C_SKY ) { flags |= 2; } fprintf( pf, "%d ", flags ); /* write the winding */ for ( i = 0 ; i < w->numpoints ; i++ ) { fprintf( pf,"(" ); WriteFloat( pf, w->p[i][0] ); WriteFloat( pf, w->p[i][1] ); WriteFloat( pf, w->p[i][2] ); fprintf( pf,") " ); } fprintf( pf,"\n" ); } } } void CountSolidFaces_r( node_t *node ){ int s; portal_t *p; winding_t *w; // decision node if ( node->planenum != PLANENUM_LEAF ) { CountSolidFaces_r( node->children[0] ); CountSolidFaces_r( node->children[1] ); return; } if ( node->opaque ) { return; } for ( p = node->portals ; p ; p = p->next[s] ) { w = p->winding; s = ( p->nodes[1] == node ); if ( w ) { if ( PortalPassable( p ) ) { continue; } if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) { continue; } // write out to the file ++num_solidfaces; } } } /* ================= WriteFaceFile_r ================= */ void WriteFaceFile_r( node_t *node ){ int i, s; portal_t *p; winding_t *w; // decision node if ( node->planenum != PLANENUM_LEAF ) { WriteFaceFile_r( node->children[0] ); WriteFaceFile_r( node->children[1] ); return; } if ( node->opaque ) { return; } for ( p = node->portals ; p ; p = p->next[s] ) { w = p->winding; s = ( p->nodes[1] == node ); if ( w ) { if ( PortalPassable( p ) ) { continue; } if ( p->nodes[0]->cluster == p->nodes[1]->cluster ) { continue; } // write out to the file if ( p->nodes[0] == node ) { fprintf( pf,"%i %i ",w->numpoints, p->nodes[0]->cluster ); for ( i = 0 ; i < w->numpoints ; i++ ) { fprintf( pf,"(" ); WriteFloat( pf, w->p[i][0] ); WriteFloat( pf, w->p[i][1] ); WriteFloat( pf, w->p[i][2] ); fprintf( pf,") " ); } fprintf( pf,"\n" ); } else { fprintf( pf,"%i %i ",w->numpoints, p->nodes[1]->cluster ); for ( i = w->numpoints - 1; i >= 0; i-- ) { fprintf( pf,"(" ); WriteFloat( pf, w->p[i][0] ); WriteFloat( pf, w->p[i][1] ); WriteFloat( pf, w->p[i][2] ); fprintf( pf,") " ); } fprintf( pf,"\n" ); } } } } /* ================ NumberLeafs_r ================ */ void NumberLeafs_r( node_t *node, int c ){ #if 0 portal_t *p; #endif if ( node->planenum != PLANENUM_LEAF ) { // decision node node->cluster = -99; if ( node->has_structural_children ) { #if 0 if ( c >= 0 ) { Sys_FPrintf( SYS_ERR,"THIS CANNOT HAPPEN\n" ); } #endif NumberLeafs_r( node->children[0], c ); NumberLeafs_r( node->children[1], c ); } else { if ( c < 0 ) { c = num_visclusters++; } NumberLeafs_r( node->children[0], c ); NumberLeafs_r( node->children[1], c ); } return; } node->area = -1; if ( node->opaque ) { // solid block, viewpoint never inside node->cluster = -1; return; } if ( c < 0 ) { c = num_visclusters++; } node->cluster = c; #if 0 // count the portals for ( p = node->portals ; p ; ) { if ( p->nodes[0] == node ) { // only write out from first leaf if ( PortalPassable( p ) ) { num_visportals++; } else{ num_solidfaces++; } p = p->next[0]; } else { if ( !PortalPassable( p ) ) { num_solidfaces++; } p = p->next[1]; } } #endif } /* ================ NumberClusters ================ */ void NumberClusters( tree_t *tree ) { num_visclusters = 0; num_visportals = 0; num_solidfaces = 0; Sys_FPrintf( SYS_VRB,"--- NumberClusters ---\n" ); // set the cluster field in every leaf and count the total number of portals NumberLeafs_r( tree->headnode, -1 ); CountVisportals_r( tree->headnode ); CountSolidFaces_r( tree->headnode ); Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters ); Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals ); Sys_FPrintf( SYS_VRB, "%9d solidfaces\n", num_solidfaces ); } /* ================ WritePortalFile ================ */ void WritePortalFile( tree_t *tree, const char *portalFilePath ){ Sys_FPrintf( SYS_VRB,"--- WritePortalFile ---\n" ); // write the file Sys_Printf( "writing %s\n", portalFilePath ); pf = fopen( portalFilePath, "w" ); if ( !pf ) { Error( "Error opening %s", portalFilePath ); } fprintf( pf, "%s\n", PORTALFILE ); fprintf( pf, "%i\n", num_visclusters ); fprintf( pf, "%i\n", num_visportals ); fprintf( pf, "%i\n", num_solidfaces ); WritePortalFile_r( tree->headnode ); WriteFaceFile_r( tree->headnode ); fclose( pf ); }