PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/quake3/q3map2/bsp.c

https://gitlab.com/illwieckz/netradiant
C | 1107 lines | 756 code | 167 blank | 184 comment | 235 complexity | 65b47ea81c0cd389899dc2fdb90676d4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /* -------------------------------------------------------------------------------
  2. Copyright (C) 1999-2007 id Software, Inc. and contributors.
  3. For a list of contributors, see the accompanying CONTRIBUTORS file.
  4. This file is part of GtkRadiant.
  5. GtkRadiant is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. GtkRadiant is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GtkRadiant; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ----------------------------------------------------------------------------------
  17. This code has been altered significantly from its original form, to support
  18. several games based on the Quake III Arena engine, in the form of "Q3Map2."
  19. ------------------------------------------------------------------------------- */
  20. /* marker */
  21. #define BSP_C
  22. /* dependencies */
  23. #include "q3map2.h"
  24. /* -------------------------------------------------------------------------------
  25. functions
  26. ------------------------------------------------------------------------------- */
  27. /*
  28. ProcessAdvertisements()
  29. copies advertisement info into the BSP structures
  30. */
  31. static void ProcessAdvertisements( void ) {
  32. int i;
  33. const char* className;
  34. const char* modelKey;
  35. int modelNum;
  36. bspModel_t* adModel;
  37. bspDrawSurface_t* adSurface;
  38. Sys_FPrintf( SYS_VRB, "--- ProcessAdvertisements ---\n" );
  39. for ( i = 0; i < numEntities; i++ ) {
  40. /* is an advertisement? */
  41. className = ValueForKey( &entities[ i ], "classname" );
  42. if ( !Q_stricmp( "advertisement", className ) ) {
  43. modelKey = ValueForKey( &entities[ i ], "model" );
  44. if ( strlen( modelKey ) > MAX_QPATH - 1 ) {
  45. Error( "Model Key for entity exceeds ad struct string length." );
  46. }
  47. else {
  48. if ( numBSPAds < MAX_MAP_ADVERTISEMENTS ) {
  49. bspAds[numBSPAds].cellId = IntForKey( &entities[ i ], "cellId" );
  50. strncpy( bspAds[numBSPAds].model, modelKey, sizeof( bspAds[numBSPAds].model ) );
  51. modelKey++;
  52. modelNum = atoi( modelKey );
  53. adModel = &bspModels[modelNum];
  54. if ( adModel->numBSPSurfaces != 1 ) {
  55. Error( "Ad cell id %d has more than one surface.", bspAds[numBSPAds].cellId );
  56. }
  57. adSurface = &bspDrawSurfaces[adModel->firstBSPSurface];
  58. // store the normal for use at run time.. all ad verts are assumed to
  59. // have identical normals (because they should be a simple rectangle)
  60. // so just use the first vert's normal
  61. VectorCopy( bspDrawVerts[adSurface->firstVert].normal, bspAds[numBSPAds].normal );
  62. // store the ad quad for quick use at run time
  63. if ( adSurface->surfaceType == MST_PATCH ) {
  64. int v0 = adSurface->firstVert + adSurface->patchHeight - 1;
  65. int v1 = adSurface->firstVert + adSurface->numVerts - 1;
  66. int v2 = adSurface->firstVert + adSurface->numVerts - adSurface->patchWidth;
  67. int v3 = adSurface->firstVert;
  68. VectorCopy( bspDrawVerts[v0].xyz, bspAds[numBSPAds].rect[0] );
  69. VectorCopy( bspDrawVerts[v1].xyz, bspAds[numBSPAds].rect[1] );
  70. VectorCopy( bspDrawVerts[v2].xyz, bspAds[numBSPAds].rect[2] );
  71. VectorCopy( bspDrawVerts[v3].xyz, bspAds[numBSPAds].rect[3] );
  72. }
  73. else {
  74. Error( "Ad cell %d has an unsupported Ad Surface type.", bspAds[numBSPAds].cellId );
  75. }
  76. numBSPAds++;
  77. }
  78. else {
  79. Error( "Maximum number of map advertisements exceeded." );
  80. }
  81. }
  82. }
  83. }
  84. Sys_FPrintf( SYS_VRB, "%9d in-game advertisements\n", numBSPAds );
  85. }
  86. /*
  87. SetCloneModelNumbers() - ydnar
  88. sets the model numbers for brush entities
  89. */
  90. static void SetCloneModelNumbers( void ){
  91. int i, j;
  92. int models;
  93. char modelValue[ 10 ];
  94. const char *value, *value2, *value3;
  95. /* start with 1 (worldspawn is model 0) */
  96. models = 1;
  97. for ( i = 1; i < numEntities; i++ )
  98. {
  99. /* only entities with brushes or patches get a model number */
  100. if ( entities[ i ].brushes == NULL && entities[ i ].patches == NULL ) {
  101. continue;
  102. }
  103. /* is this a clone? */
  104. value = ValueForKey( &entities[ i ], "_ins" );
  105. if ( value[ 0 ] == '\0' ) {
  106. value = ValueForKey( &entities[ i ], "_instance" );
  107. }
  108. if ( value[ 0 ] == '\0' ) {
  109. value = ValueForKey( &entities[ i ], "_clone" );
  110. }
  111. if ( value[ 0 ] != '\0' ) {
  112. continue;
  113. }
  114. /* add the model key */
  115. sprintf( modelValue, "*%d", models );
  116. SetKeyValue( &entities[ i ], "model", modelValue );
  117. /* increment model count */
  118. models++;
  119. }
  120. /* fix up clones */
  121. for ( i = 1; i < numEntities; i++ )
  122. {
  123. /* only entities with brushes or patches get a model number */
  124. if ( entities[ i ].brushes == NULL && entities[ i ].patches == NULL ) {
  125. continue;
  126. }
  127. /* is this a clone? */
  128. value = ValueForKey( &entities[ i ], "_ins" );
  129. if ( value[ 0 ] == '\0' ) {
  130. value = ValueForKey( &entities[ i ], "_instance" );
  131. }
  132. if ( value[ 0 ] == '\0' ) {
  133. value = ValueForKey( &entities[ i ], "_clone" );
  134. }
  135. if ( value[ 0 ] == '\0' ) {
  136. continue;
  137. }
  138. /* find an entity with matching clone name */
  139. for ( j = 0; j < numEntities; j++ )
  140. {
  141. /* is this a clone parent? */
  142. value2 = ValueForKey( &entities[ j ], "_clonename" );
  143. if ( value2[ 0 ] == '\0' ) {
  144. continue;
  145. }
  146. /* do they match? */
  147. if ( strcmp( value, value2 ) == 0 ) {
  148. /* get the model num */
  149. value3 = ValueForKey( &entities[ j ], "model" );
  150. if ( value3[ 0 ] == '\0' ) {
  151. Sys_FPrintf( SYS_WRN, "WARNING: Cloned entity %s referenced entity without model\n", value2 );
  152. continue;
  153. }
  154. models = atoi( &value2[ 1 ] );
  155. /* add the model key */
  156. sprintf( modelValue, "*%d", models );
  157. SetKeyValue( &entities[ i ], "model", modelValue );
  158. /* nuke the brushes/patches for this entity (fixme: leak!) */
  159. entities[ i ].brushes = NULL;
  160. entities[ i ].patches = NULL;
  161. }
  162. }
  163. }
  164. }
  165. /*
  166. FixBrushSides() - ydnar
  167. matches brushsides back to their appropriate drawsurface and shader
  168. */
  169. static void FixBrushSides( entity_t *e ){
  170. int i;
  171. mapDrawSurface_t *ds;
  172. sideRef_t *sideRef;
  173. bspBrushSide_t *side;
  174. /* note it */
  175. Sys_FPrintf( SYS_VRB, "--- FixBrushSides ---\n" );
  176. /* walk list of drawsurfaces */
  177. for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
  178. {
  179. /* get surface and try to early out */
  180. ds = &mapDrawSurfs[ i ];
  181. if ( ds->outputNum < 0 ) {
  182. continue;
  183. }
  184. /* walk sideref list */
  185. for ( sideRef = ds->sideRef; sideRef != NULL; sideRef = sideRef->next )
  186. {
  187. /* get bsp brush side */
  188. if ( sideRef->side == NULL || sideRef->side->outputNum < 0 ) {
  189. continue;
  190. }
  191. side = &bspBrushSides[ sideRef->side->outputNum ];
  192. /* set drawsurface */
  193. side->surfaceNum = ds->outputNum;
  194. //% Sys_FPrintf( SYS_VRB, "DS: %7d Side: %7d ", ds->outputNum, sideRef->side->outputNum );
  195. /* set shader */
  196. if ( strcmp( bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader ) ) {
  197. //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", bspShaders[ side->shaderNum ].shader, ds->shaderInfo->shader );
  198. side->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
  199. }
  200. }
  201. }
  202. }
  203. /*
  204. ProcessWorldModel()
  205. creates a full bsp + surfaces for the worldspawn entity
  206. */
  207. void ProcessWorldModel( const char *portalFilePath, const char *lineFilePath ){
  208. int i, s;
  209. entity_t *e;
  210. tree_t *tree;
  211. face_t *faces;
  212. qboolean ignoreLeaks, leaked;
  213. xmlNodePtr polyline, leaknode;
  214. char level[ 2 ], shader[ 1024 ];
  215. const char *value;
  216. int leakStatus;
  217. /* sets integer blockSize from worldspawn "_blocksize" key if it exists */
  218. value = ValueForKey( &entities[ 0 ], "_blocksize" );
  219. if ( value[ 0 ] == '\0' ) {
  220. value = ValueForKey( &entities[ 0 ], "blocksize" );
  221. }
  222. if ( value[ 0 ] == '\0' ) {
  223. value = ValueForKey( &entities[ 0 ], "chopsize" ); /* sof2 */
  224. }
  225. if ( value[ 0 ] != '\0' ) {
  226. /* scan 3 numbers */
  227. s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] );
  228. /* handle legacy case */
  229. if ( s == 1 ) {
  230. blockSize[ 1 ] = blockSize[ 0 ];
  231. blockSize[ 2 ] = blockSize[ 0 ];
  232. }
  233. }
  234. Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] );
  235. /* sof2: ignore leaks? */
  236. value = ValueForKey( &entities[ 0 ], "_ignoreleaks" ); /* ydnar */
  237. if ( value[ 0 ] == '\0' ) {
  238. value = ValueForKey( &entities[ 0 ], "ignoreleaks" );
  239. }
  240. if ( value[ 0 ] == '1' ) {
  241. ignoreLeaks = qtrue;
  242. }
  243. else{
  244. ignoreLeaks = qfalse;
  245. }
  246. /* begin worldspawn model */
  247. BeginModel();
  248. e = &entities[ 0 ];
  249. e->firstDrawSurf = 0;
  250. /* ydnar: gs mods */
  251. ClearMetaTriangles();
  252. /* check for patches with adjacent edges that need to lod together */
  253. PatchMapDrawSurfs( e );
  254. /* build an initial bsp tree using all of the sides of all of the structural brushes */
  255. faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes );
  256. tree = FaceBSP( faces );
  257. MakeTreePortals( tree );
  258. FilterStructuralBrushesIntoTree( e, tree );
  259. /* see if the bsp is completely enclosed */
  260. leakStatus = FloodEntities( tree );
  261. if ( ignoreLeaks ) {
  262. if ( leakStatus == FLOODENTITIES_LEAKED ) {
  263. leakStatus = FLOODENTITIES_GOOD;
  264. }
  265. }
  266. if ( leakStatus == FLOODENTITIES_GOOD ) {
  267. leaked = qfalse;
  268. }
  269. else
  270. {
  271. leaked = qtrue;
  272. Sys_FPrintf( SYS_NOXML, "**********************\n" );
  273. Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
  274. Sys_FPrintf( SYS_NOXML, "**********************\n" );
  275. polyline = LeakFile( tree, lineFilePath );
  276. leaknode = xmlNewNode( NULL, (xmlChar*)"message" );
  277. xmlNodeAddContent( leaknode, (xmlChar*)"MAP LEAKED\n" );
  278. xmlAddChild( leaknode, polyline );
  279. level[0] = (int) '0' + SYS_ERR;
  280. level[1] = 0;
  281. xmlSetProp( leaknode, (xmlChar*)"level", (xmlChar*) &level );
  282. xml_SendNode( leaknode );
  283. if ( leaktest ) {
  284. Sys_Printf( "--- MAP LEAKED, ABORTING LEAKTEST ---\n" );
  285. exit( 0 );
  286. }
  287. }
  288. if ( leakStatus != FLOODENTITIES_EMPTY ) { /* if no entities exist, this would accidentally the whole map, and that IS bad */
  289. /* rebuild a better bsp tree using only the sides that are visible from the inside */
  290. FillOutside( tree->headnode );
  291. /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
  292. ClipSidesIntoTree( e, tree );
  293. /* build a visible face tree (same thing as the initial bsp tree but after reducing the faces) */
  294. faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes );
  295. FreeTree( tree );
  296. tree = FaceBSP( faces );
  297. MakeTreePortals( tree );
  298. FilterStructuralBrushesIntoTree( e, tree );
  299. /* ydnar: flood again for skybox */
  300. if ( skyboxPresent ) {
  301. FloodEntities( tree );
  302. }
  303. }
  304. /* save out information for visibility processing */
  305. NumberClusters( tree );
  306. if ( !leaked ) {
  307. WritePortalFile( tree, portalFilePath );
  308. }
  309. /* flood from entities */
  310. FloodAreas( tree );
  311. /* create drawsurfs for triangle models */
  312. AddTriangleModels( e );
  313. /* create drawsurfs for surface models */
  314. AddEntitySurfaceModels( e );
  315. /* generate bsp brushes from map brushes */
  316. EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
  317. /* add references to the detail brushes */
  318. FilterDetailBrushesIntoTree( e, tree );
  319. /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */
  320. if ( !nofog ) {
  321. FogDrawSurfaces( e );
  322. }
  323. /* subdivide each drawsurf as required by shader tesselation */
  324. if ( !nosubdivide ) {
  325. SubdivideFaceSurfaces( e, tree );
  326. }
  327. /* add in any vertexes required to fix t-junctions */
  328. if ( !notjunc ) {
  329. FixTJunctions( e );
  330. }
  331. /* ydnar: classify the surfaces */
  332. ClassifyEntitySurfaces( e );
  333. /* ydnar: project decals */
  334. MakeEntityDecals( e );
  335. /* ydnar: meta surfaces */
  336. MakeEntityMetaTriangles( e );
  337. SmoothMetaTriangles();
  338. FixMetaTJunctions();
  339. MergeMetaTriangles();
  340. /* ydnar: debug portals */
  341. if ( debugPortals ) {
  342. MakeDebugPortalSurfs( tree );
  343. }
  344. /* ydnar: fog hull */
  345. value = ValueForKey( &entities[ 0 ], "_foghull" );
  346. if ( value[ 0 ] != '\0' ) {
  347. sprintf( shader, "textures/%s", value );
  348. MakeFogHullSurfs( e, tree, shader );
  349. }
  350. /* ydnar: bug 645: do flares for lights */
  351. for ( i = 0; i < numEntities && emitFlares; i++ )
  352. {
  353. entity_t *light, *target;
  354. const char *value, *flareShader;
  355. vec3_t origin, targetOrigin, normal, color;
  356. int lightStyle;
  357. /* get light */
  358. light = &entities[ i ];
  359. value = ValueForKey( light, "classname" );
  360. if ( !strcmp( value, "light" ) ) {
  361. /* get flare shader */
  362. flareShader = ValueForKey( light, "_flareshader" );
  363. value = ValueForKey( light, "_flare" );
  364. if ( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' ) {
  365. /* get specifics */
  366. GetVectorForKey( light, "origin", origin );
  367. GetVectorForKey( light, "_color", color );
  368. lightStyle = IntForKey( light, "_style" );
  369. if ( lightStyle == 0 ) {
  370. lightStyle = IntForKey( light, "style" );
  371. }
  372. /* handle directional spotlights */
  373. value = ValueForKey( light, "target" );
  374. if ( value[ 0 ] != '\0' ) {
  375. /* get target light */
  376. target = FindTargetEntity( value );
  377. if ( target != NULL ) {
  378. GetVectorForKey( target, "origin", targetOrigin );
  379. VectorSubtract( targetOrigin, origin, normal );
  380. VectorNormalize( normal, normal );
  381. }
  382. }
  383. else{
  384. //% VectorClear( normal );
  385. VectorSet( normal, 0, 0, -1 );
  386. }
  387. if ( colorsRGB ) {
  388. color[0] = Image_LinearFloatFromsRGBFloat( color[0] );
  389. color[1] = Image_LinearFloatFromsRGBFloat( color[1] );
  390. color[2] = Image_LinearFloatFromsRGBFloat( color[2] );
  391. }
  392. /* create the flare surface (note shader defaults automatically) */
  393. DrawSurfaceForFlare( mapEntityNum, origin, normal, color, flareShader, lightStyle );
  394. }
  395. }
  396. }
  397. /* add references to the final drawsurfs in the apropriate clusters */
  398. FilterDrawsurfsIntoTree( e, tree );
  399. /* match drawsurfaces back to original brushsides (sof2) */
  400. FixBrushSides( e );
  401. /* finish */
  402. EndModel( e, tree->headnode );
  403. FreeTree( tree );
  404. }
  405. /*
  406. ProcessSubModel()
  407. creates bsp + surfaces for other brush models
  408. */
  409. void ProcessSubModel( void ){
  410. entity_t *e;
  411. tree_t *tree;
  412. brush_t *b, *bc;
  413. node_t *node;
  414. /* start a brush model */
  415. BeginModel();
  416. e = &entities[ mapEntityNum ];
  417. e->firstDrawSurf = numMapDrawSurfs;
  418. /* ydnar: gs mods */
  419. ClearMetaTriangles();
  420. /* check for patches with adjacent edges that need to lod together */
  421. PatchMapDrawSurfs( e );
  422. /* allocate a tree */
  423. node = AllocNode();
  424. node->planenum = PLANENUM_LEAF;
  425. tree = AllocTree();
  426. tree->headnode = node;
  427. /* add the sides to the tree */
  428. ClipSidesIntoTree( e, tree );
  429. /* ydnar: create drawsurfs for triangle models */
  430. AddTriangleModels( e );
  431. /* create drawsurfs for surface models */
  432. AddEntitySurfaceModels( e );
  433. /* generate bsp brushes from map brushes */
  434. EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
  435. /* just put all the brushes in headnode */
  436. for ( b = e->brushes; b; b = b->next )
  437. {
  438. bc = CopyBrush( b );
  439. bc->next = node->brushlist;
  440. node->brushlist = bc;
  441. }
  442. /* subdivide each drawsurf as required by shader tesselation */
  443. if ( !nosubdivide ) {
  444. SubdivideFaceSurfaces( e, tree );
  445. }
  446. /* add in any vertexes required to fix t-junctions */
  447. if ( !notjunc ) {
  448. FixTJunctions( e );
  449. }
  450. /* ydnar: classify the surfaces and project lightmaps */
  451. ClassifyEntitySurfaces( e );
  452. /* ydnar: project decals */
  453. MakeEntityDecals( e );
  454. /* ydnar: meta surfaces */
  455. MakeEntityMetaTriangles( e );
  456. SmoothMetaTriangles();
  457. FixMetaTJunctions();
  458. MergeMetaTriangles();
  459. /* add references to the final drawsurfs in the apropriate clusters */
  460. FilterDrawsurfsIntoTree( e, tree );
  461. /* match drawsurfaces back to original brushsides (sof2) */
  462. FixBrushSides( e );
  463. /* finish */
  464. EndModel( e, node );
  465. FreeTree( tree );
  466. }
  467. /*
  468. ProcessModels()
  469. process world + other models into the bsp
  470. */
  471. void ProcessModels( const char *portalFilePath, const char *lineFilePath ){
  472. qboolean oldVerbose;
  473. entity_t *entity;
  474. /* preserve -v setting */
  475. oldVerbose = verbose;
  476. /* start a new bsp */
  477. BeginBSPFile();
  478. /* create map fogs */
  479. CreateMapFogs();
  480. /* walk entity list */
  481. for ( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
  482. {
  483. /* get entity */
  484. entity = &entities[ mapEntityNum ];
  485. if ( entity->brushes == NULL && entity->patches == NULL ) {
  486. continue;
  487. }
  488. /* process the model */
  489. Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
  490. if ( mapEntityNum == 0 ) {
  491. ProcessWorldModel(portalFilePath, lineFilePath);
  492. }
  493. else{
  494. ProcessSubModel();
  495. }
  496. /* potentially turn off the deluge of text */
  497. verbose = verboseEntities;
  498. }
  499. /* restore -v setting */
  500. verbose = oldVerbose;
  501. /* write fogs */
  502. EmitFogs();
  503. /* vortex: emit meta stats */
  504. EmitMetaStats();
  505. }
  506. /*
  507. OnlyEnts()
  508. this is probably broken unless teamed with a radiant version that preserves entity order
  509. */
  510. void OnlyEnts( const char *BSPFilePath ){
  511. char save_cmdline[1024], save_version[1024], save_gridsize[1024];
  512. const char *p;
  513. /* note it */
  514. Sys_Printf( "--- OnlyEnts ---\n" );
  515. LoadBSPFile( BSPFilePath );
  516. ParseEntities();
  517. p = ValueForKey( &entities[0], "_q3map2_cmdline" );
  518. strncpy( save_cmdline, p, sizeof( save_cmdline ) );
  519. save_cmdline[sizeof( save_cmdline ) - 1] = 0;
  520. p = ValueForKey( &entities[0], "_q3map2_version" );
  521. strncpy( save_version, p, sizeof( save_version ) );
  522. save_version[sizeof( save_version ) - 1] = 0;
  523. p = ValueForKey( &entities[0], "gridsize" );
  524. strncpy( save_gridsize, p, sizeof( save_gridsize ) );
  525. save_gridsize[sizeof( save_gridsize ) - 1] = 0;
  526. numEntities = 0;
  527. LoadShaderInfo();
  528. LoadMapFile( name, qfalse, qfalse );
  529. SetModelNumbers();
  530. SetLightStyles();
  531. if ( *save_cmdline ) {
  532. SetKeyValue( &entities[0], "_q3map2_cmdline", save_cmdline );
  533. }
  534. if ( *save_version ) {
  535. SetKeyValue( &entities[0], "_q3map2_version", save_version );
  536. }
  537. if ( *save_gridsize ) {
  538. SetKeyValue( &entities[0], "gridsize", save_gridsize );
  539. }
  540. numBSPEntities = numEntities;
  541. UnparseEntities();
  542. WriteBSPFile( BSPFilePath );
  543. }
  544. /*
  545. BSPMain() - ydnar
  546. handles creation of a bsp from a map file
  547. */
  548. int BSPMain( int argc, char **argv ){
  549. int i;
  550. char path[ 1024 ], tempSource[ 1024 ];
  551. qboolean onlyents = qfalse;
  552. char BSPFilePath [ 1024 ];
  553. char lineFilePath [ 1024 ];
  554. char portalFilePath [ 1024 ];
  555. char surfaceFilePath [ 1024 ];
  556. BSPFilePath[0] = 0;
  557. lineFilePath[0] = 0;
  558. portalFilePath[0] = 0;
  559. surfaceFilePath[0] = 0;
  560. if ( argc >= 2 && !strcmp( argv[ 1 ], "-bsp" ) ) {
  561. Sys_Printf( "-bsp argument unnecessary\n" );
  562. argv++;
  563. argc--;
  564. }
  565. /* note it */
  566. Sys_Printf( "--- BSP ---\n" );
  567. SetDrawSurfacesBuffer();
  568. mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
  569. memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
  570. numMapDrawSurfs = 0;
  571. tempSource[ 0 ] = '\0';
  572. globalCelShader[0] = 0;
  573. /* set standard game flags */
  574. maxSurfaceVerts = game->maxSurfaceVerts;
  575. maxSurfaceIndexes = game->maxSurfaceIndexes;
  576. emitFlares = game->emitFlares;
  577. texturesRGB = game->texturesRGB;
  578. colorsRGB = game->colorsRGB;
  579. /* process arguments */
  580. for ( i = 1; i < ( argc - 1 ); i++ )
  581. {
  582. if ( !strcmp( argv[ i ], "-onlyents" ) ) {
  583. Sys_Printf( "Running entity-only compile\n" );
  584. onlyents = qtrue;
  585. }
  586. else if ( !strcmp( argv[ i ], "-tempname" ) ) {
  587. strcpy( tempSource, argv[ ++i ] );
  588. }
  589. else if ( !strcmp( argv[ i ], "-tmpout" ) ) {
  590. strcpy( outbase, "/tmp" );
  591. }
  592. else if ( !strcmp( argv[ i ], "-nowater" ) ) {
  593. Sys_Printf( "Disabling water\n" );
  594. nowater = qtrue;
  595. }
  596. else if ( !strcmp( argv[ i ], "-keeplights" ) ) {
  597. keepLights = qtrue;
  598. Sys_Printf( "Leaving light entities on map after compile\n" );
  599. }
  600. else if ( !strcmp( argv[ i ], "-nodetail" ) ) {
  601. Sys_Printf( "Ignoring detail brushes\n" ) ;
  602. nodetail = qtrue;
  603. }
  604. else if ( !strcmp( argv[ i ], "-fulldetail" ) ) {
  605. Sys_Printf( "Turning detail brushes into structural brushes\n" );
  606. fulldetail = qtrue;
  607. }
  608. else if ( !strcmp( argv[ i ], "-nofog" ) ) {
  609. Sys_Printf( "Fog volumes disabled\n" );
  610. nofog = qtrue;
  611. }
  612. else if ( !strcmp( argv[ i ], "-nosubdivide" ) ) {
  613. Sys_Printf( "Disabling brush face subdivision\n" );
  614. nosubdivide = qtrue;
  615. }
  616. else if ( !strcmp( argv[ i ], "-leaktest" ) ) {
  617. Sys_Printf( "Leaktest enabled\n" );
  618. leaktest = qtrue;
  619. }
  620. else if ( !strcmp( argv[ i ], "-verboseentities" ) ) {
  621. Sys_Printf( "Verbose entities enabled\n" );
  622. verboseEntities = qtrue;
  623. }
  624. else if ( !strcmp( argv[ i ], "-nocurves" ) ) {
  625. Sys_Printf( "Ignoring curved surfaces (patches)\n" );
  626. noCurveBrushes = qtrue;
  627. }
  628. else if ( !strcmp( argv[ i ], "-notjunc" ) ) {
  629. Sys_Printf( "T-junction fixing disabled\n" );
  630. notjunc = qtrue;
  631. }
  632. else if ( !strcmp( argv[ i ], "-fakemap" ) ) {
  633. Sys_Printf( "Generating fakemap.map\n" );
  634. fakemap = qtrue;
  635. }
  636. else if ( !strcmp( argv[ i ], "-samplesize" ) ) {
  637. sampleSize = atoi( argv[ i + 1 ] );
  638. if ( sampleSize < 1 ) {
  639. sampleSize = 1;
  640. }
  641. i++;
  642. Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
  643. }
  644. else if ( !strcmp( argv[ i ], "-minsamplesize" ) ) {
  645. minSampleSize = atoi( argv[ i + 1 ] );
  646. if ( minSampleSize < 1 ) {
  647. minSampleSize = 1;
  648. }
  649. i++;
  650. Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
  651. }
  652. else if ( !strcmp( argv[ i ], "-custinfoparms" ) ) {
  653. Sys_Printf( "Custom info parms enabled\n" );
  654. useCustomInfoParms = qtrue;
  655. }
  656. /* sof2 args */
  657. else if ( !strcmp( argv[ i ], "-rename" ) ) {
  658. Sys_Printf( "Appending _bsp suffix to misc_model shaders (SOF2)\n" );
  659. renameModelShaders = qtrue;
  660. }
  661. /* ydnar args */
  662. else if ( !strcmp( argv[ i ], "-ne" ) ) {
  663. normalEpsilon = atof( argv[ i + 1 ] );
  664. i++;
  665. Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
  666. }
  667. else if ( !strcmp( argv[ i ], "-de" ) ) {
  668. distanceEpsilon = atof( argv[ i + 1 ] );
  669. i++;
  670. Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
  671. }
  672. else if ( !strcmp( argv[ i ], "-mv" ) ) {
  673. maxLMSurfaceVerts = atoi( argv[ i + 1 ] );
  674. if ( maxLMSurfaceVerts < 3 ) {
  675. maxLMSurfaceVerts = 3;
  676. }
  677. if ( maxLMSurfaceVerts > maxSurfaceVerts ) {
  678. maxSurfaceVerts = maxLMSurfaceVerts;
  679. }
  680. i++;
  681. Sys_Printf( "Maximum lightmapped surface vertex count set to %d\n", maxLMSurfaceVerts );
  682. }
  683. else if ( !strcmp( argv[ i ], "-mi" ) ) {
  684. maxSurfaceIndexes = atoi( argv[ i + 1 ] );
  685. if ( maxSurfaceIndexes < 3 ) {
  686. maxSurfaceIndexes = 3;
  687. }
  688. i++;
  689. Sys_Printf( "Maximum per-surface index count set to %d\n", maxSurfaceIndexes );
  690. }
  691. else if ( !strcmp( argv[ i ], "-np" ) ) {
  692. npDegrees = atof( argv[ i + 1 ] );
  693. if ( npDegrees < 0.0f ) {
  694. npDegrees = 0.0f;
  695. }
  696. else if ( npDegrees > 0.0f ) {
  697. Sys_Printf( "Forcing nonplanar surfaces with a breaking angle of %f degrees\n", npDegrees );
  698. }
  699. i++;
  700. }
  701. else if ( !strcmp( argv[ i ], "-snap" ) ) {
  702. bevelSnap = atoi( argv[ i + 1 ] );
  703. if ( bevelSnap < 0 ) {
  704. bevelSnap = 0;
  705. }
  706. i++;
  707. if ( bevelSnap > 0 ) {
  708. Sys_Printf( "Snapping brush bevel planes to %d units\n", bevelSnap );
  709. }
  710. }
  711. else if ( !strcmp( argv[ i ], "-texrange" ) ) {
  712. texRange = atoi( argv[ i + 1 ] );
  713. if ( texRange < 0 ) {
  714. texRange = 0;
  715. }
  716. i++;
  717. Sys_Printf( "Limiting per-surface texture range to %d texels\n", texRange );
  718. }
  719. else if ( !strcmp( argv[ i ], "-nohint" ) ) {
  720. Sys_Printf( "Hint brushes disabled\n" );
  721. noHint = qtrue;
  722. }
  723. else if ( !strcmp( argv[ i ], "-flat" ) ) {
  724. Sys_Printf( "Flatshading enabled\n" );
  725. flat = qtrue;
  726. }
  727. else if ( !strcmp( argv[ i ], "-celshader" ) ) {
  728. ++i;
  729. if ( argv[i][0] ) {
  730. sprintf( globalCelShader, "textures/%s", argv[ i ] );
  731. }
  732. else{
  733. *globalCelShader = 0;
  734. }
  735. Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader );
  736. }
  737. else if ( !strcmp( argv[ i ], "-meta" ) ) {
  738. Sys_Printf( "Creating meta surfaces from brush faces\n" );
  739. meta = qtrue;
  740. }
  741. else if ( !strcmp( argv[ i ], "-metaadequatescore" ) ) {
  742. metaAdequateScore = atoi( argv[ i + 1 ] );
  743. if ( metaAdequateScore < 0 ) {
  744. metaAdequateScore = -1;
  745. }
  746. i++;
  747. if ( metaAdequateScore >= 0 ) {
  748. Sys_Printf( "Setting ADEQUATE meta score to %d (see surface_meta.c)\n", metaAdequateScore );
  749. }
  750. }
  751. else if ( !strcmp( argv[ i ], "-metagoodscore" ) ) {
  752. metaGoodScore = atoi( argv[ i + 1 ] );
  753. if ( metaGoodScore < 0 ) {
  754. metaGoodScore = -1;
  755. }
  756. i++;
  757. if ( metaGoodScore >= 0 ) {
  758. Sys_Printf( "Setting GOOD meta score to %d (see surface_meta.c)\n", metaGoodScore );
  759. }
  760. }
  761. else if ( !strcmp( argv[ i ], "-metamaxbboxdistance" ) ) {
  762. metaMaxBBoxDistance = atof( argv[ i + 1 ] );
  763. if ( metaMaxBBoxDistance < 0 ) {
  764. metaMaxBBoxDistance = -1;
  765. }
  766. i++;
  767. if ( metaMaxBBoxDistance >= 0 ) {
  768. Sys_Printf( "Setting meta maximum bounding box distance to %f\n", metaMaxBBoxDistance );
  769. }
  770. }
  771. else if ( !strcmp( argv[ i ], "-patchmeta" ) ) {
  772. Sys_Printf( "Creating meta surfaces from patches\n" );
  773. patchMeta = qtrue;
  774. }
  775. else if ( !strcmp( argv[ i ], "-flares" ) ) {
  776. Sys_Printf( "Flare surfaces enabled\n" );
  777. emitFlares = qtrue;
  778. }
  779. else if ( !strcmp( argv[ i ], "-noflares" ) ) {
  780. Sys_Printf( "Flare surfaces disabled\n" );
  781. emitFlares = qfalse;
  782. }
  783. else if ( !strcmp( argv[ i ], "-skyfix" ) ) {
  784. Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" );
  785. skyFixHack = qtrue;
  786. }
  787. else if ( !strcmp( argv[ i ], "-debugsurfaces" ) ) {
  788. Sys_Printf( "emitting debug surfaces\n" );
  789. debugSurfaces = qtrue;
  790. }
  791. else if ( !strcmp( argv[ i ], "-debuginset" ) ) {
  792. Sys_Printf( "Debug surface triangle insetting enabled\n" );
  793. debugInset = qtrue;
  794. }
  795. else if ( !strcmp( argv[ i ], "-debugportals" ) ) {
  796. Sys_Printf( "Debug portal surfaces enabled\n" );
  797. debugPortals = qtrue;
  798. }
  799. else if ( !strcmp( argv[ i ], "-sRGBtex" ) ) {
  800. texturesRGB = qtrue;
  801. Sys_Printf( "Textures are in sRGB\n" );
  802. }
  803. else if ( !strcmp( argv[ i ], "-nosRGBtex" ) ) {
  804. texturesRGB = qfalse;
  805. Sys_Printf( "Textures are linear\n" );
  806. }
  807. else if ( !strcmp( argv[ i ], "-sRGBcolor" ) ) {
  808. colorsRGB = qtrue;
  809. Sys_Printf( "Colors are in sRGB\n" );
  810. }
  811. else if ( !strcmp( argv[ i ], "-nosRGBcolor" ) ) {
  812. colorsRGB = qfalse;
  813. Sys_Printf( "Colors are linear\n" );
  814. }
  815. else if ( !strcmp( argv[ i ], "-nosRGB" ) ) {
  816. texturesRGB = qfalse;
  817. Sys_Printf( "Textures are linear\n" );
  818. colorsRGB = qfalse;
  819. Sys_Printf( "Colors are linear\n" );
  820. }
  821. else if ( !strcmp( argv[ i ], "-altsplit" ) )
  822. {
  823. Sys_Printf( "Alternate BSP splitting (by 27) enabled\n" );
  824. bspAlternateSplitWeights = qtrue;
  825. }
  826. else if ( !strcmp( argv[ i ], "-deep" ) )
  827. {
  828. Sys_Printf( "Deep BSP tree generation enabled\n" );
  829. deepBSP = qtrue;
  830. }
  831. else if ( !strcmp( argv[ i ], "-maxarea" ) ) {
  832. Sys_Printf( "Max Area face surface generation enabled\n" );
  833. maxAreaFaceSurface = qtrue;
  834. }
  835. else if ( !strcmp( argv[ i ], "-bspfile" ) )
  836. {
  837. strcpy( BSPFilePath, argv[i + 1] );
  838. i++;
  839. Sys_Printf( "Use %s as bsp file\n", BSPFilePath );
  840. }
  841. else if ( !strcmp( argv[ i ], "-linfile" ) )
  842. {
  843. strcpy( lineFilePath, argv[i + 1] );
  844. i++;
  845. Sys_Printf( "Use %s as line file\n", lineFilePath );
  846. }
  847. else if ( !strcmp( argv[ i ], "-prtfile" ) )
  848. {
  849. strcpy( portalFilePath, argv[i + 1] );
  850. i++;
  851. Sys_Printf( "Use %s as portal file\n", portalFilePath );
  852. }
  853. else if ( !strcmp( argv[ i ], "-srffile" ) )
  854. {
  855. strcpy( surfaceFilePath, argv[i + 1] );
  856. i++;
  857. Sys_Printf( "Use %s as surface file\n", surfaceFilePath );
  858. }
  859. else{
  860. Sys_FPrintf( SYS_WRN, "WARNING: Unknown option \"%s\"\n", argv[ i ] );
  861. }
  862. }
  863. /* fixme: print more useful usage here */
  864. if ( i != ( argc - 1 ) ) {
  865. Error( "usage: q3map [options] mapfile" );
  866. }
  867. /* copy source name */
  868. strcpy( source, ExpandArg( argv[ i ] ) );
  869. StripExtension( source );
  870. /* ydnar: set default sample size */
  871. SetDefaultSampleSize( sampleSize );
  872. if (!BSPFilePath[0]) {
  873. sprintf( BSPFilePath, "%s.bsp", source );
  874. }
  875. if (!lineFilePath[0]) {
  876. sprintf( lineFilePath, "%s.lin", source );
  877. }
  878. if (!portalFilePath[0]) {
  879. sprintf( portalFilePath, "%s.prt", source );
  880. }
  881. if (!surfaceFilePath[0]) {
  882. sprintf( surfaceFilePath, "%s.srf", source );
  883. }
  884. /* delete portal, line and surface files */
  885. remove( portalFilePath );
  886. remove( lineFilePath );
  887. //% remove( surfaceFilePath ) /* ydnar */
  888. /* expand mapname */
  889. strcpy( name, ExpandArg( argv[ i ] ) );
  890. if ( strcmp( name + strlen( name ) - 4, ".reg" ) ) {
  891. /* if we are doing a full map, delete the last saved region map */
  892. sprintf( path, "%s.reg", source );
  893. remove( path );
  894. DefaultExtension( name, ".map" ); /* might be .reg */
  895. }
  896. /* if onlyents, just grab the entites and resave */
  897. if ( onlyents ) {
  898. OnlyEnts( BSPFilePath );
  899. return 0;
  900. }
  901. /* load shaders */
  902. LoadShaderInfo();
  903. /* load original file from temp spot in case it was renamed by the editor on the way in */
  904. if ( strlen( tempSource ) > 0 ) {
  905. LoadMapFile( tempSource, qfalse, qfalse );
  906. }
  907. else{
  908. LoadMapFile( name, qfalse, qfalse );
  909. }
  910. /* div0: inject command line parameters */
  911. InjectCommandLine( argv, 1, argc - 1 );
  912. /* ydnar: decal setup */
  913. ProcessDecals();
  914. /* ydnar: cloned brush model entities */
  915. SetCloneModelNumbers();
  916. /* process world and submodels */
  917. ProcessModels( portalFilePath, lineFilePath );
  918. /* set light styles from targetted light entities */
  919. SetLightStyles();
  920. /* process in game advertisements */
  921. ProcessAdvertisements();
  922. /* finish and write bsp */
  923. EndBSPFile( qtrue, BSPFilePath, surfaceFilePath );
  924. /* remove temp map source file if appropriate */
  925. if ( strlen( tempSource ) > 0 ) {
  926. remove( tempSource );
  927. }
  928. /* return to sender */
  929. return 0;
  930. }