Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3109 lines
77 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // vrad.c
  9. #include "vrad.h"
  10. #include "physdll.h"
  11. #include "lightmap.h"
  12. #include "tier1/strtools.h"
  13. #include "vmpi.h"
  14. #include "macro_texture.h"
  15. #include "vmpi_tools_shared.h"
  16. #include "leaf_ambient_lighting.h"
  17. #include "tools_minidump.h"
  18. #include "loadcmdline.h"
  19. #include "byteswap.h"
  20. #include "iscratchpad3d.h"
  21. #define ALLOWDEBUGOPTIONS (0 || _DEBUG)
  22. static FileHandle_t pFpTrans = NULL;
  23. /*
  24. NOTES
  25. -----
  26. every surface must be divided into at least two patches each axis
  27. */
  28. CUtlVector<CPatch> g_Patches;
  29. CUtlVector<int> g_FacePatches; // constains all patches, children first
  30. CUtlVector<int> faceParents; // contains only root patches, use next parent to iterate
  31. CUtlVector<int> clusterChildren;
  32. CUtlVector<Vector> emitlight;
  33. CUtlVector<bumplights_t> addlight;
  34. int num_sky_cameras;
  35. sky_camera_t sky_cameras[MAX_MAP_AREAS];
  36. int area_sky_cameras[MAX_MAP_AREAS];
  37. entity_t *face_entity[MAX_MAP_FACES];
  38. Vector face_offset[MAX_MAP_FACES]; // for rotating bmodels
  39. int fakeplanes;
  40. unsigned numbounce = 100; // 25; /* Originally this was 8 */
  41. float maxchop = 4; // coarsest allowed number of luxel widths for a patch
  42. float minchop = 4; // "-chop" tightest number of luxel widths for a patch, used on edges
  43. float dispchop = 8.0f; // number of luxel widths for a patch
  44. float g_MaxDispPatchRadius = 1500.0f; // Maximum radius allowed for displacement patches
  45. qboolean g_bDumpPatches;
  46. bool bDumpNormals = false;
  47. bool g_bDumpRtEnv = false;
  48. bool bRed2Black = true;
  49. bool g_bFastAmbient = false;
  50. bool g_bNoSkyRecurse = false;
  51. bool g_bFiniteFalloffModel = false; // whether to use 1/xxx or not
  52. int junk;
  53. Vector ambient( 0, 0, 0 );
  54. float lightscale = 1.0;
  55. float dlight_threshold = 0.1; // was DIRECT_LIGHT constant
  56. char source[MAX_PATH] = "";
  57. char platformPath[MAX_PATH] = "";
  58. char level_name[MAX_PATH] = ""; // map filename, without extension or path info
  59. char global_lights[MAX_PATH] = "";
  60. char designer_lights[MAX_PATH] = "";
  61. char level_lights[MAX_PATH] = "";
  62. char vismatfile[_MAX_PATH] = "";
  63. char incrementfile[_MAX_PATH] = "";
  64. IIncremental *g_pIncremental = 0;
  65. bool g_bInterrupt = false; // Wsed with background lighting in WC. Tells VRAD
  66. // to stop lighting.
  67. float g_SunAngularExtent=0.0;
  68. float g_flSkySampleScale = 1.0;
  69. float g_flStaticPropSampleScale = 4.0;
  70. bool g_bLargeDispSampleRadius = false;
  71. bool g_bOnlyStaticProps = false;
  72. bool g_bShowStaticPropNormals = false;
  73. bool g_bStaticPropBounce = false;
  74. float g_flStaticPropBounceBoost = 1.0f;
  75. float gamma = 0.5;
  76. float indirect_sun = 1.0;
  77. float reflectivityScale = 1.0;
  78. qboolean do_extra = true;
  79. bool debug_extra = false;
  80. qboolean do_fast = false;
  81. qboolean do_centersamples = false;
  82. int extrapasses = 4;
  83. float smoothing_threshold = 0.7071067; // cos(45.0*(M_PI/180))
  84. // Cosine of smoothing angle(in radians)
  85. float coring = 1.0; // Light threshold to force to blackness(minimizes lightmaps)
  86. qboolean texscale = true;
  87. int dlight_map = 0; // Setting to 1 forces direct lighting into different lightmap than radiosity
  88. float luxeldensity = 1.0;
  89. unsigned num_degenerate_faces;
  90. qboolean g_bLowPriority = false;
  91. qboolean g_bLogHashData = false;
  92. bool g_bNoDetailLighting = false;
  93. double g_flStartTime;
  94. bool g_bStaticPropLighting = false;
  95. bool g_bStaticPropPolys = false;
  96. bool g_bTextureShadows = false;
  97. bool g_bDisablePropSelfShadowing = false;
  98. bool g_bFastStaticProps = false;
  99. bool g_bDumpBumpStaticProps = false;
  100. bool g_bDisableStaticPropVertexInSolidTest = false;
  101. CUtlVector<byte> g_FacesVisibleToLights;
  102. RayTracingEnvironment g_RtEnv;
  103. RayTracingEnvironment g_RtEnv_LightBlockers; // ray tracing environment consisting solely of light blockers - used in conjunction with bsp to solve indirect lighting for static props (as opposed to using the full RTE).
  104. RayTracingEnvironment g_RtEnv_RadiosityPatches;
  105. dface_t *g_pFaces=0;
  106. // this is a list of material names used on static props which shouldn't cast shadows. a
  107. // sequential search is used since we allow substring matches. its not time critical, and this
  108. // functionality is a stopgap until vrad starts reading .vmt files.
  109. CUtlVector<char const *> g_NonShadowCastingMaterialStrings;
  110. /*
  111. ===================================================================
  112. MISC
  113. ===================================================================
  114. */
  115. int leafparents[MAX_MAP_LEAFS];
  116. int nodeparents[MAX_MAP_NODES];
  117. void MakeParents (int nodenum, int parent)
  118. {
  119. int i, j;
  120. dnode_t *node;
  121. nodeparents[nodenum] = parent;
  122. node = &dnodes[nodenum];
  123. for (i=0 ; i<2 ; i++)
  124. {
  125. j = node->children[i];
  126. if (j < 0)
  127. leafparents[-j - 1] = nodenum;
  128. else
  129. MakeParents (j, nodenum);
  130. }
  131. }
  132. /*
  133. ===================================================================
  134. TEXTURE LIGHT VALUES
  135. ===================================================================
  136. */
  137. typedef struct
  138. {
  139. char name[256];
  140. Vector value;
  141. char *filename;
  142. } texlight_t;
  143. #define MAX_TEXLIGHTS 128
  144. texlight_t texlights[MAX_TEXLIGHTS];
  145. int num_texlights;
  146. /*
  147. ============
  148. ReadLightFile
  149. ============
  150. */
  151. void ReadLightFile (char *filename)
  152. {
  153. char buf[1024];
  154. int file_texlights = 0;
  155. FileHandle_t f = g_pFileSystem->Open( filename, "r" );
  156. if (!f)
  157. {
  158. Warning("Warning: Couldn't open texlight file %s.\n", filename);
  159. return;
  160. }
  161. Msg("[Reading texlights from '%s']\n", filename);
  162. while ( CmdLib_FGets( buf, sizeof( buf ), f ) )
  163. {
  164. // check ldr/hdr
  165. char * scan = buf;
  166. if ( !strnicmp( "hdr:", scan, 4) )
  167. {
  168. scan += 4;
  169. if ( ! g_bHDR )
  170. {
  171. continue;
  172. }
  173. }
  174. if ( !strnicmp( "ldr:", scan, 4) )
  175. {
  176. scan += 4;
  177. if ( g_bHDR )
  178. {
  179. continue;
  180. }
  181. }
  182. scan += strspn( scan, " \t" );
  183. char NoShadName[1024];
  184. if ( sscanf(scan,"noshadow %s",NoShadName)==1)
  185. {
  186. char * dot = strchr( NoShadName, '.' );
  187. if ( dot ) // if they specify .vmt, kill it
  188. * dot = 0;
  189. //printf("add %s as a non shadow casting material\n",NoShadName);
  190. g_NonShadowCastingMaterialStrings.AddToTail( strdup( NoShadName ));
  191. }
  192. else if ( sscanf( scan, "forcetextureshadow %s", NoShadName ) == 1 )
  193. {
  194. //printf("add %s as a non shadow casting material\n",NoShadName);
  195. ForceTextureShadowsOnModel( NoShadName );
  196. }
  197. else
  198. {
  199. char szTexlight[256];
  200. Vector value;
  201. if ( num_texlights == MAX_TEXLIGHTS )
  202. Error ("Too many texlights, max = %d", MAX_TEXLIGHTS);
  203. int argCnt = sscanf (scan, "%s ",szTexlight );
  204. if( argCnt != 1 )
  205. {
  206. if ( strlen( scan ) > 4 )
  207. Msg( "ignoring bad texlight '%s' in %s", scan, filename );
  208. continue;
  209. }
  210. LightForString( scan + strlen( szTexlight ) + 1, value );
  211. int j = 0;
  212. for( j; j < num_texlights; j ++ )
  213. {
  214. if ( strcmp( texlights[j].name, szTexlight ) == 0 )
  215. {
  216. if ( strcmp( texlights[j].filename, filename ) == 0 )
  217. {
  218. Msg( "ERROR\a: Duplication of '%s' in file '%s'!\n",
  219. texlights[j].name, texlights[j].filename );
  220. }
  221. else if ( texlights[j].value[0] != value[0]
  222. || texlights[j].value[1] != value[1]
  223. || texlights[j].value[2] != value[2] )
  224. {
  225. Warning( "Warning: Overriding '%s' from '%s' with '%s'!\n",
  226. texlights[j].name, texlights[j].filename, filename );
  227. }
  228. else
  229. {
  230. Warning( "Warning: Redundant '%s' def in '%s' AND '%s'!\n",
  231. texlights[j].name, texlights[j].filename, filename );
  232. }
  233. break;
  234. }
  235. }
  236. strcpy( texlights[j].name, szTexlight );
  237. VectorCopy( value, texlights[j].value );
  238. texlights[j].filename = filename;
  239. file_texlights ++;
  240. num_texlights = max( num_texlights, j + 1 );
  241. }
  242. }
  243. qprintf ( "[%i texlights parsed from '%s']\n\n", file_texlights, filename);
  244. g_pFileSystem->Close( f );
  245. }
  246. /*
  247. ============
  248. LightForTexture
  249. ============
  250. */
  251. void LightForTexture( const char *name, Vector& result )
  252. {
  253. result[ 0 ] = result[ 1 ] = result[ 2 ] = 0;
  254. char baseFilename[ MAX_PATH ];
  255. if ( Q_strncmp( "maps/", name, 5 ) == 0 )
  256. {
  257. // this might be a patch texture for cubemaps. try to parse out the original filename.
  258. if ( Q_strncmp( level_name, name + 5, Q_strlen( level_name ) ) == 0 )
  259. {
  260. const char *base = name + 5 + Q_strlen( level_name );
  261. if ( *base == '/' )
  262. {
  263. ++base; // step past the path separator
  264. // now we've gotten rid of the 'maps/level_name/' part, so we're left with
  265. // 'originalName_%d_%d_%d'.
  266. strcpy( baseFilename, base );
  267. bool foundSeparators = true;
  268. for ( int i=0; i<3; ++i )
  269. {
  270. char *underscore = Q_strrchr( baseFilename, '_' );
  271. if ( underscore && *underscore )
  272. {
  273. *underscore = '\0';
  274. }
  275. else
  276. {
  277. foundSeparators = false;
  278. }
  279. }
  280. if ( foundSeparators )
  281. {
  282. name = baseFilename;
  283. }
  284. }
  285. }
  286. }
  287. for (int i=0 ; i<num_texlights ; i++)
  288. {
  289. if (!Q_strcasecmp (name, texlights[i].name))
  290. {
  291. VectorCopy( texlights[i].value, result );
  292. return;
  293. }
  294. }
  295. }
  296. /*
  297. =======================================================================
  298. MAKE FACES
  299. =======================================================================
  300. */
  301. /*
  302. =============
  303. WindingFromFace
  304. =============
  305. */
  306. winding_t *WindingFromFace (dface_t *f, Vector& origin )
  307. {
  308. int i;
  309. int se;
  310. dvertex_t *dv;
  311. int v;
  312. winding_t *w;
  313. w = AllocWinding (f->numedges);
  314. w->numpoints = f->numedges;
  315. for (i=0 ; i<f->numedges ; i++)
  316. {
  317. se = dsurfedges[f->firstedge + i];
  318. if (se < 0)
  319. v = dedges[-se].v[1];
  320. else
  321. v = dedges[se].v[0];
  322. dv = &dvertexes[v];
  323. VectorAdd (dv->point, origin, w->p[i]);
  324. }
  325. RemoveColinearPoints (w);
  326. return w;
  327. }
  328. /*
  329. =============
  330. BaseLightForFace
  331. =============
  332. */
  333. void BaseLightForFace( dface_t *f, Vector& light, float *parea, Vector& reflectivity )
  334. {
  335. texinfo_t *tx;
  336. dtexdata_t *texdata;
  337. //
  338. // check for light emited by texture
  339. //
  340. tx = &texinfo[f->texinfo];
  341. texdata = &dtexdata[tx->texdata];
  342. LightForTexture (TexDataStringTable_GetString( texdata->nameStringTableID ), light);
  343. *parea = texdata->height * texdata->width;
  344. VectorScale( texdata->reflectivity, reflectivityScale, reflectivity );
  345. // always keep this less than 1 or the solution will not converge
  346. for ( int i = 0; i < 3; i++ )
  347. {
  348. if ( reflectivity[i] > 0.99 )
  349. reflectivity[i] = 0.99;
  350. }
  351. }
  352. qboolean IsSky (dface_t *f)
  353. {
  354. texinfo_t *tx;
  355. tx = &texinfo[f->texinfo];
  356. if (tx->flags & SURF_SKY)
  357. return true;
  358. return false;
  359. }
  360. #ifdef STATIC_FOG
  361. /*=============
  362. IsFog
  363. =============*/
  364. qboolean IsFog( dface_t *f )
  365. {
  366. texinfo_t *tx;
  367. tx = &texinfo[f->texinfo];
  368. // % denotes a fog texture
  369. if( tx->texture[0] == '%' )
  370. return true;
  371. return false;
  372. }
  373. #endif
  374. void ProcessSkyCameras()
  375. {
  376. int i;
  377. num_sky_cameras = 0;
  378. for (i = 0; i < numareas; ++i)
  379. {
  380. area_sky_cameras[i] = -1;
  381. }
  382. for (i = 0; i < num_entities; ++i)
  383. {
  384. entity_t *e = &entities[i];
  385. const char *name = ValueForKey (e, "classname");
  386. if (stricmp (name, "sky_camera"))
  387. continue;
  388. Vector origin;
  389. GetVectorForKey( e, "origin", origin );
  390. int node = PointLeafnum( origin );
  391. int area = -1;
  392. if (node >= 0 && node < numleafs) area = dleafs[node].area;
  393. float scale = FloatForKey( e, "scale" );
  394. if (scale > 0.0f)
  395. {
  396. sky_cameras[num_sky_cameras].origin = origin;
  397. sky_cameras[num_sky_cameras].sky_to_world = scale;
  398. sky_cameras[num_sky_cameras].world_to_sky = 1.0f / scale;
  399. sky_cameras[num_sky_cameras].area = area;
  400. if (area >= 0 && area < numareas)
  401. {
  402. area_sky_cameras[area] = num_sky_cameras;
  403. }
  404. ++num_sky_cameras;
  405. }
  406. }
  407. }
  408. /*
  409. =============
  410. MakePatchForFace
  411. =============
  412. */
  413. float totalarea;
  414. void MakePatchForFace (int fn, winding_t *w)
  415. {
  416. dface_t *f = g_pFaces + fn;
  417. float area;
  418. CPatch *patch;
  419. Vector centroid(0,0,0);
  420. int i, j;
  421. texinfo_t *tx;
  422. // get texture info
  423. tx = &texinfo[f->texinfo];
  424. // No patches at all for fog!
  425. #ifdef STATIC_FOG
  426. if ( IsFog( f ) )
  427. return;
  428. #endif
  429. // the sky needs patches or the form factors don't work out correctly
  430. // if (IsSky( f ) )
  431. // return;
  432. area = WindingArea (w);
  433. if (area <= 0)
  434. {
  435. num_degenerate_faces++;
  436. // Msg("degenerate face\n");
  437. return;
  438. }
  439. totalarea += area;
  440. // get a patch
  441. int ndxPatch = g_Patches.AddToTail();
  442. patch = &g_Patches[ndxPatch];
  443. memset( patch, 0, sizeof( CPatch ) );
  444. patch->ndxNext = g_Patches.InvalidIndex();
  445. patch->ndxNextParent = g_Patches.InvalidIndex();
  446. patch->ndxNextClusterChild = g_Patches.InvalidIndex();
  447. patch->child1 = g_Patches.InvalidIndex();
  448. patch->child2 = g_Patches.InvalidIndex();
  449. patch->parent = g_Patches.InvalidIndex();
  450. patch->needsBumpmap = tx->flags & SURF_BUMPLIGHT ? true : false;
  451. patch->staticPropIdx = -1;
  452. // link and save patch data
  453. patch->ndxNext = g_FacePatches.Element( fn );
  454. g_FacePatches[fn] = ndxPatch;
  455. // patch->next = face_g_Patches[fn];
  456. // face_g_Patches[fn] = patch;
  457. // compute a separate scale for chop - since the patch "scale" is the texture scale
  458. // we want textures with higher resolution lighting to be chopped up more
  459. float chopscale[2];
  460. chopscale[0] = chopscale[1] = 16.0f;
  461. if ( texscale )
  462. {
  463. // Compute the texture "scale" in s,t
  464. for( i=0; i<2; i++ )
  465. {
  466. patch->scale[i] = 0.0f;
  467. chopscale[i] = 0.0f;
  468. for( j=0; j<3; j++ )
  469. {
  470. patch->scale[i] +=
  471. tx->textureVecsTexelsPerWorldUnits[i][j] *
  472. tx->textureVecsTexelsPerWorldUnits[i][j];
  473. chopscale[i] +=
  474. tx->lightmapVecsLuxelsPerWorldUnits[i][j] *
  475. tx->lightmapVecsLuxelsPerWorldUnits[i][j];
  476. }
  477. patch->scale[i] = sqrt( patch->scale[i] );
  478. chopscale[i] = sqrt( chopscale[i] );
  479. }
  480. }
  481. else
  482. {
  483. patch->scale[0] = patch->scale[1] = 1.0f;
  484. }
  485. patch->area = area;
  486. patch->sky = IsSky( f );
  487. // chop scaled up lightmaps coarser
  488. patch->luxscale = ((chopscale[0]+chopscale[1])/2);
  489. patch->chop = maxchop;
  490. #ifdef STATIC_FOG
  491. patch->fog = FALSE;
  492. #endif
  493. patch->winding = w;
  494. patch->plane = &dplanes[f->planenum];
  495. // make a new plane to adjust for origined bmodels
  496. if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] )
  497. {
  498. dplane_t *pl;
  499. // origin offset faces must create new planes
  500. if (numplanes + fakeplanes >= MAX_MAP_PLANES)
  501. {
  502. Error ("numplanes + fakeplanes >= MAX_MAP_PLANES");
  503. }
  504. pl = &dplanes[numplanes + fakeplanes];
  505. fakeplanes++;
  506. *pl = *(patch->plane);
  507. pl->dist += DotProduct (face_offset[fn], pl->normal);
  508. patch->plane = pl;
  509. }
  510. patch->faceNumber = fn;
  511. WindingCenter (w, patch->origin);
  512. // Save "center" for generating the face normals later.
  513. VectorSubtract( patch->origin, face_offset[fn], face_centroids[fn] );
  514. VectorCopy( patch->plane->normal, patch->normal );
  515. WindingBounds (w, patch->face_mins, patch->face_maxs);
  516. VectorCopy( patch->face_mins, patch->mins );
  517. VectorCopy( patch->face_maxs, patch->maxs );
  518. BaseLightForFace( f, patch->baselight, &patch->basearea, patch->reflectivity );
  519. // Chop all texlights very fine.
  520. if ( !VectorCompare( patch->baselight, vec3_origin ) )
  521. {
  522. // patch->chop = do_extra ? maxchop / 2 : maxchop;
  523. tx->flags |= SURF_LIGHT;
  524. }
  525. // get rid of do extra functionality on displacement surfaces
  526. if( ValidDispFace( f ) )
  527. {
  528. patch->chop = maxchop;
  529. }
  530. // FIXME: If we wanted to add a dependency from vrad to the material system,
  531. // we could do this. It would add a bunch of file accesses, though:
  532. /*
  533. // Check for a material var which would override the patch chop
  534. bool bFound;
  535. const char *pMaterialName = TexDataStringTable_GetString( dtexdata[ tx->texdata ].nameStringTableID );
  536. MaterialSystemMaterial_t hMaterial = FindMaterial( pMaterialName, &bFound, false );
  537. if ( bFound )
  538. {
  539. const char *pChopValue = GetMaterialVar( hMaterial, "%chop" );
  540. if ( pChopValue )
  541. {
  542. float flChopValue;
  543. if ( sscanf( pChopValue, "%f", &flChopValue ) > 0 )
  544. {
  545. patch->chop = flChopValue;
  546. }
  547. }
  548. }
  549. */
  550. }
  551. entity_t *EntityForModel (int modnum)
  552. {
  553. int i;
  554. char *s;
  555. char name[16];
  556. sprintf (name, "*%i", modnum);
  557. // search the entities for one using modnum
  558. for (i=0 ; i<num_entities ; i++)
  559. {
  560. s = ValueForKey (&entities[i], "model");
  561. if (!strcmp (s, name))
  562. return &entities[i];
  563. }
  564. return &entities[0];
  565. }
  566. /*
  567. =============
  568. MakePatches
  569. =============
  570. */
  571. void MakePatches (void)
  572. {
  573. int i, j;
  574. dface_t *f;
  575. int fn;
  576. winding_t *w;
  577. dmodel_t *mod;
  578. Vector origin;
  579. entity_t *ent;
  580. ParseEntities ();
  581. qprintf ("%i faces\n", numfaces);
  582. for (i=0 ; i<nummodels ; i++)
  583. {
  584. mod = dmodels+i;
  585. ent = EntityForModel (i);
  586. VectorCopy (vec3_origin, origin);
  587. // bmodels with origin brushes need to be offset into their
  588. // in-use position
  589. GetVectorForKey (ent, "origin", origin);
  590. for (j=0 ; j<mod->numfaces ; j++)
  591. {
  592. fn = mod->firstface + j;
  593. face_entity[fn] = ent;
  594. VectorCopy (origin, face_offset[fn]);
  595. f = &g_pFaces[fn];
  596. if( f->dispinfo == -1 )
  597. {
  598. w = WindingFromFace (f, origin );
  599. MakePatchForFace( fn, w );
  600. }
  601. }
  602. }
  603. if (num_degenerate_faces > 0)
  604. {
  605. qprintf("%d degenerate faces\n", num_degenerate_faces );
  606. }
  607. qprintf ("%i square feet [%.2f square inches]\n", (int)(totalarea/144), totalarea );
  608. // make the displacement surface patches
  609. StaticDispMgr()->MakePatches();
  610. if ( g_bStaticPropBounce )
  611. {
  612. StaticPropMgr()->MakePatches();
  613. }
  614. }
  615. /*
  616. =======================================================================
  617. SUBDIVIDE
  618. =======================================================================
  619. */
  620. //-----------------------------------------------------------------------------
  621. // Purpose: does this surface take/emit light
  622. //-----------------------------------------------------------------------------
  623. bool PreventSubdivision( CPatch *patch )
  624. {
  625. if ( patch->faceNumber < 0 )
  626. {
  627. // static prop patch
  628. return true;
  629. }
  630. dface_t *f = g_pFaces + patch->faceNumber;
  631. texinfo_t *tx = &texinfo[f->texinfo];
  632. if (tx->flags & SURF_NOCHOP)
  633. return true;
  634. if (tx->flags & SURF_NOLIGHT && !(tx->flags & SURF_LIGHT))
  635. return true;
  636. return false;
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Purpose: subdivide the "parent" patch
  640. //-----------------------------------------------------------------------------
  641. int CreateChildPatch( int nParentIndex, winding_t *pWinding, float flArea, const Vector &vecCenter )
  642. {
  643. int nChildIndex = g_Patches.AddToTail();
  644. CPatch *child = &g_Patches[nChildIndex];
  645. CPatch *parent = &g_Patches[nParentIndex];
  646. // copy all elements of parent patch to children
  647. *child = *parent;
  648. // Set up links
  649. child->ndxNext = g_Patches.InvalidIndex();
  650. child->ndxNextParent = g_Patches.InvalidIndex();
  651. child->ndxNextClusterChild = g_Patches.InvalidIndex();
  652. child->child1 = g_Patches.InvalidIndex();
  653. child->child2 = g_Patches.InvalidIndex();
  654. child->parent = nParentIndex;
  655. child->m_IterationKey = 0;
  656. child->winding = pWinding;
  657. child->area = flArea;
  658. VectorCopy( vecCenter, child->origin );
  659. if ( ValidDispFace( g_pFaces + child->faceNumber ) )
  660. {
  661. // shouldn't get here anymore!!
  662. Msg( "SubdividePatch: Error - Should not be here!\n" );
  663. StaticDispMgr()->GetDispSurfNormal( child->faceNumber, child->origin, child->normal, true );
  664. }
  665. else
  666. {
  667. GetPhongNormal( child->faceNumber, child->origin, child->normal );
  668. }
  669. child->planeDist = child->plane->dist;
  670. WindingBounds(child->winding, child->mins, child->maxs);
  671. if ( !VectorCompare( child->baselight, vec3_origin ) )
  672. {
  673. // don't check edges on surf lights
  674. return nChildIndex;
  675. }
  676. // Subdivide patch towards minchop if on the edge of the face
  677. Vector total;
  678. VectorSubtract( child->maxs, child->mins, total );
  679. VectorScale( total, child->luxscale, total );
  680. if ( child->chop > minchop && (total[0] < child->chop) && (total[1] < child->chop) && (total[2] < child->chop) )
  681. {
  682. for ( int i=0; i<3; ++i )
  683. {
  684. if ( (child->face_maxs[i] == child->maxs[i] || child->face_mins[i] == child->mins[i] )
  685. && total[i] > minchop )
  686. {
  687. child->chop = max( minchop, child->chop / 2 );
  688. break;
  689. }
  690. }
  691. }
  692. return nChildIndex;
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose: subdivide the "parent" patch
  696. //-----------------------------------------------------------------------------
  697. void SubdividePatch( int ndxPatch )
  698. {
  699. winding_t *w, *o1, *o2;
  700. Vector total;
  701. Vector split;
  702. vec_t dist;
  703. vec_t widest = -1;
  704. int i, widest_axis = -1;
  705. bool bSubdivide = false;
  706. // get the current patch
  707. CPatch *patch = &g_Patches.Element( ndxPatch );
  708. if ( !patch )
  709. return;
  710. // never subdivide sky patches
  711. if ( patch->sky )
  712. return;
  713. // get the patch winding
  714. w = patch->winding;
  715. // subdivide along the widest axis
  716. VectorSubtract (patch->maxs, patch->mins, total);
  717. VectorScale( total, patch->luxscale, total );
  718. for (i=0 ; i<3 ; i++)
  719. {
  720. if ( total[i] > widest )
  721. {
  722. widest_axis = i;
  723. widest = total[i];
  724. }
  725. if ( (total[i] >= patch->chop) && (total[i] >= minchop) )
  726. {
  727. bSubdivide = true;
  728. }
  729. }
  730. if ((!bSubdivide) && widest_axis != -1)
  731. {
  732. // make more square
  733. if (total[widest_axis] > total[(widest_axis + 1) % 3] * 2 && total[widest_axis] > total[(widest_axis + 2) % 3] * 2)
  734. {
  735. if (patch->chop > minchop)
  736. {
  737. bSubdivide = true;
  738. patch->chop = max( minchop, patch->chop / 2 );
  739. }
  740. }
  741. }
  742. if ( !bSubdivide )
  743. return;
  744. // split the winding
  745. VectorCopy (vec3_origin, split);
  746. split[widest_axis] = 1;
  747. dist = (patch->mins[widest_axis] + patch->maxs[widest_axis])*0.5f;
  748. ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
  749. // calculate the area of the patches to see if they are "significant"
  750. Vector center1, center2;
  751. float area1 = WindingAreaAndBalancePoint( o1, center1 );
  752. float area2 = WindingAreaAndBalancePoint( o2, center2 );
  753. if( area1 == 0 || area2 == 0 )
  754. {
  755. Msg( "zero area child patch\n" );
  756. return;
  757. }
  758. // create new child patches
  759. int ndxChild1Patch = CreateChildPatch( ndxPatch, o1, area1, center1 );
  760. int ndxChild2Patch = CreateChildPatch( ndxPatch, o2, area2, center2 );
  761. // FIXME: This could go into CreateChildPatch if child1, child2 were stored in the patch as child[0], child[1]
  762. patch = &g_Patches.Element( ndxPatch );
  763. patch->child1 = ndxChild1Patch;
  764. patch->child2 = ndxChild2Patch;
  765. SubdividePatch( ndxChild1Patch );
  766. SubdividePatch( ndxChild2Patch );
  767. }
  768. /*
  769. =============
  770. SubdividePatches
  771. =============
  772. */
  773. void SubdividePatches (void)
  774. {
  775. unsigned i, num;
  776. if (numbounce == 0)
  777. return;
  778. unsigned int uiPatchCount = g_Patches.Count();
  779. qprintf ("%i patches before subdivision\n", uiPatchCount);
  780. for (i = 0; i < uiPatchCount; i++)
  781. {
  782. CPatch *pCur = &g_Patches.Element( i );
  783. pCur->planeDist = pCur->plane->dist;
  784. if ( pCur->faceNumber < 0 )
  785. {
  786. // This and all following patches are "fake" staticprop patches. Set up parent data structure for them.
  787. break;
  788. }
  789. pCur->ndxNextParent = faceParents.Element( pCur->faceNumber );
  790. faceParents[pCur->faceNumber] = pCur - g_Patches.Base();
  791. }
  792. for (i=0 ; i< uiPatchCount; i++)
  793. {
  794. CPatch *patch = &g_Patches.Element( i );
  795. patch->parent = -1;
  796. if ( PreventSubdivision(patch) )
  797. continue;
  798. if (!do_fast)
  799. {
  800. if( g_pFaces[patch->faceNumber].dispinfo == -1 )
  801. {
  802. SubdividePatch( i );
  803. }
  804. else
  805. {
  806. StaticDispMgr()->SubdividePatch( i );
  807. }
  808. }
  809. }
  810. // fixup next pointers
  811. for (i = 0; i < (unsigned)numfaces; i++)
  812. {
  813. g_FacePatches[i] = g_FacePatches.InvalidIndex();
  814. }
  815. uiPatchCount = g_Patches.Count();
  816. for (i = 0; i < uiPatchCount; i++)
  817. {
  818. CPatch *pCur = &g_Patches.Element( i );
  819. if ( pCur->faceNumber < 0)
  820. {
  821. // Static prop patches don't have an associated face
  822. continue;
  823. }
  824. pCur->ndxNext = g_FacePatches.Element( pCur->faceNumber );
  825. g_FacePatches[pCur->faceNumber] = pCur - g_Patches.Base();
  826. #if 0
  827. CPatch *prev;
  828. prev = face_g_Patches[g_Patches[i].faceNumber];
  829. g_Patches[i].next = prev;
  830. face_g_Patches[g_Patches[i].faceNumber] = &g_Patches[i];
  831. #endif
  832. }
  833. // Cache off the leaf number:
  834. // We have to do this after subdivision because some patches span leaves.
  835. // (only the faces for model #0 are split by it's BSP which is what governs the PVS, and the leaves we're interested in)
  836. // Sub models (1-255) are only split for the BSP that their model forms.
  837. // When those patches are subdivided their origins can end up in a different leaf.
  838. // The engine will split (clip) those faces at run time to the world BSP because the models
  839. // are dynamic and can be moved. In the software renderer, they must be split exactly in order
  840. // to sort per polygon.
  841. for ( i = 0; i < uiPatchCount; i++ )
  842. {
  843. g_Patches[i].clusterNumber = ClusterFromPoint( g_Patches[i].origin );
  844. //
  845. // test for point in solid space (can happen with detail and displacement surfaces)
  846. //
  847. if( g_Patches[i].clusterNumber == -1 )
  848. {
  849. for( int j = 0; j < g_Patches[i].winding->numpoints; j++ )
  850. {
  851. int clusterNumber = ClusterFromPoint( g_Patches[i].winding->p[j] );
  852. if( clusterNumber != -1 )
  853. {
  854. g_Patches[i].clusterNumber = clusterNumber;
  855. break;
  856. }
  857. }
  858. }
  859. }
  860. // build the list of patches that need to be lit
  861. for ( num = 0; num < uiPatchCount; num++ )
  862. {
  863. // do them in reverse order
  864. i = uiPatchCount - num - 1;
  865. // skip patches with children
  866. CPatch *pCur = &g_Patches.Element( i );
  867. if( pCur->child1 == g_Patches.InvalidIndex() )
  868. {
  869. if( pCur->clusterNumber != - 1 )
  870. {
  871. pCur->ndxNextClusterChild = clusterChildren.Element( pCur->clusterNumber );
  872. clusterChildren[pCur->clusterNumber] = pCur - g_Patches.Base();
  873. }
  874. }
  875. #if 0
  876. if (g_Patches[i].child1 == g_Patches.InvalidIndex() )
  877. {
  878. if( g_Patches[i].clusterNumber != -1 )
  879. {
  880. g_Patches[i].nextclusterchild = cluster_children[g_Patches[i].clusterNumber];
  881. cluster_children[g_Patches[i].clusterNumber] = &g_Patches[i];
  882. }
  883. }
  884. #endif
  885. }
  886. qprintf ("%i patches after subdivision\n", uiPatchCount);
  887. }
  888. //=====================================================================
  889. /*
  890. =============
  891. MakeScales
  892. This is the primary time sink.
  893. It can be run multi threaded.
  894. =============
  895. */
  896. int total_transfer;
  897. int max_transfer;
  898. //-----------------------------------------------------------------------------
  899. // Purpose: Computes the form factor from a polygon patch to a differential patch
  900. // using formula 81 of Philip Dutre's Global Illumination Compendium,
  901. // [email protected], http://www.graphics.cornell.edu/~phil/GI/
  902. //-----------------------------------------------------------------------------
  903. float FormFactorPolyToDiff ( CPatch *pPolygon, CPatch* pDifferential )
  904. {
  905. winding_t *pWinding = pPolygon->winding;
  906. float flFormFactor = 0.0f;
  907. for ( int iPoint = 0; iPoint < pWinding->numpoints; iPoint++ )
  908. {
  909. int iNextPoint = ( iPoint < pWinding->numpoints - 1 ) ? iPoint + 1 : 0;
  910. Vector vGammaVector, vVector1, vVector2;
  911. VectorSubtract( pWinding->p[ iPoint ], pDifferential->origin, vVector1 );
  912. VectorSubtract( pWinding->p[ iNextPoint ], pDifferential->origin, vVector2 );
  913. VectorNormalize( vVector1 );
  914. VectorNormalize( vVector2 );
  915. CrossProduct( vVector1, vVector2, vGammaVector );
  916. float flSinAlpha = VectorNormalize( vGammaVector );
  917. if (flSinAlpha < -1.0f || flSinAlpha > 1.0f)
  918. return 0.0f;
  919. vGammaVector *= asin( flSinAlpha );
  920. flFormFactor += DotProduct( vGammaVector, pDifferential->normal );
  921. }
  922. flFormFactor *= ( 0.5f / pPolygon->area ); // divide by pi later, multiply by area later
  923. return flFormFactor;
  924. }
  925. //-----------------------------------------------------------------------------
  926. // Purpose: Computes the form factor from a differential element to a differential
  927. // element. This is okay when the distance between patches is 5 times
  928. // greater than patch size. Lecture slides by Pat Hanrahan,
  929. // http://graphics.stanford.edu/courses/cs348b-00/lectures/lecture17/radiosity.2.pdf
  930. //-----------------------------------------------------------------------------
  931. float FormFactorDiffToDiff ( CPatch *pDiff1, CPatch* pDiff2 )
  932. {
  933. Vector vDelta;
  934. VectorSubtract( pDiff1->origin, pDiff2->origin, vDelta );
  935. float flLength = VectorNormalize( vDelta );
  936. return -DotProduct( vDelta, pDiff1->normal ) * DotProduct( vDelta, pDiff2->normal ) / ( flLength * flLength );
  937. }
  938. void MakeTransfer( int ndxPatch1, int ndxPatch2, transfer_t *all_transfers )
  939. //void MakeTransfer (CPatch *patch, CPatch *patch2, transfer_t *all_transfers )
  940. {
  941. Vector delta;
  942. vec_t scale;
  943. float trans;
  944. transfer_t *transfer;
  945. //
  946. // get patches
  947. //
  948. if( ndxPatch1 == g_Patches.InvalidIndex() || ndxPatch2 == g_Patches.InvalidIndex() )
  949. return;
  950. CPatch *pPatch1 = &g_Patches.Element( ndxPatch1 );
  951. CPatch *pPatch2 = &g_Patches.Element( ndxPatch2 );
  952. if (IsSky( &g_pFaces[ pPatch2->faceNumber ] ) )
  953. return;
  954. // overflow check!
  955. if ( pPatch1->numtransfers >= MAX_PATCHES)
  956. {
  957. return;
  958. }
  959. // hack for patch areas that area <= 0 (degenerate)
  960. if ( pPatch2->area <= 0)
  961. {
  962. return;
  963. }
  964. transfer = &all_transfers[pPatch1->numtransfers];
  965. scale = FormFactorDiffToDiff( pPatch2, pPatch1 );
  966. // patch normals may be > 90 due to smoothing groups
  967. if (scale <= 0)
  968. {
  969. //Msg("scale <= 0\n");
  970. return;
  971. }
  972. // Test 5 times rule
  973. Vector vDelta;
  974. VectorSubtract( pPatch1->origin, pPatch2->origin, vDelta );
  975. float flThreshold = ( M_PI * 0.04 ) * DotProduct( vDelta, vDelta );
  976. if (flThreshold < pPatch2->area)
  977. {
  978. scale = FormFactorPolyToDiff( pPatch2, pPatch1 );
  979. if (scale <= 0.0)
  980. return;
  981. }
  982. trans = (pPatch2->area*scale);
  983. if (trans <= TRANSFER_EPSILON)
  984. {
  985. return;
  986. }
  987. transfer->patch = pPatch2 - g_Patches.Base();
  988. // FIXME: why is this not trans?
  989. transfer->transfer = trans;
  990. #if 0
  991. // DEBUG! Dump patches and transfer connection for displacements. This creates a lot of data, so only
  992. // use it when you really want it - that is why it is #if-ed out.
  993. if ( g_bDumpPatches )
  994. {
  995. if ( !pFpTrans )
  996. {
  997. pFpTrans = g_pFileSystem->Open( "trans.txt", "w" );
  998. }
  999. Vector light = pPatch1->totallight.light[0] + pPatch1->directlight;
  1000. WriteWinding( pFpTrans, pPatch1->winding, light );
  1001. light = pPatch2->totallight.light[0] + pPatch2->directlight;
  1002. WriteWinding( pFpTrans, pPatch2->winding, light );
  1003. WriteLine( pFpTrans, pPatch1->origin, pPatch2->origin, Vector( 255, 0, 255 ) );
  1004. }
  1005. #endif
  1006. pPatch1->numtransfers++;
  1007. }
  1008. void MakeScales ( int ndxPatch, transfer_t *all_transfers )
  1009. {
  1010. int j;
  1011. float total;
  1012. transfer_t *t, *t2;
  1013. total = 0;
  1014. if( ndxPatch == g_Patches.InvalidIndex() )
  1015. return;
  1016. CPatch *patch = &g_Patches.Element( ndxPatch );
  1017. // copy the transfers out
  1018. if (patch->numtransfers)
  1019. {
  1020. if (patch->numtransfers > max_transfer)
  1021. {
  1022. max_transfer = patch->numtransfers;
  1023. }
  1024. patch->transfers = ( transfer_t* )calloc (1, patch->numtransfers * sizeof(transfer_t));
  1025. if (!patch->transfers)
  1026. Error ("Memory allocation failure");
  1027. // get total transfer energy
  1028. t2 = all_transfers;
  1029. // overflow check!
  1030. for (j=0 ; j<patch->numtransfers ; j++, t2++)
  1031. {
  1032. total += t2->transfer;
  1033. }
  1034. // the total transfer should be PI, but we need to correct errors due to overlaping surfaces
  1035. if (total > M_PI)
  1036. total = 1.0f/total;
  1037. else
  1038. total = 1.0f/M_PI;
  1039. t = patch->transfers;
  1040. t2 = all_transfers;
  1041. for (j=0 ; j<patch->numtransfers ; j++, t++, t2++)
  1042. {
  1043. t->transfer = t2->transfer*total;
  1044. t->patch = t2->patch;
  1045. }
  1046. if (patch->numtransfers > max_transfer)
  1047. {
  1048. max_transfer = patch->numtransfers;
  1049. }
  1050. }
  1051. else
  1052. {
  1053. // Error - patch has no transfers
  1054. // patch->totallight[2] = 255;
  1055. }
  1056. ThreadLock ();
  1057. total_transfer += patch->numtransfers;
  1058. ThreadUnlock ();
  1059. }
  1060. /*
  1061. =============
  1062. WriteWorld
  1063. =============
  1064. */
  1065. void WriteWorld (char *name, int iBump)
  1066. {
  1067. unsigned j;
  1068. FileHandle_t out;
  1069. CPatch *patch;
  1070. out = g_pFileSystem->Open( name, "w" );
  1071. if (!out)
  1072. Error ("Couldn't open %s", name);
  1073. unsigned int uiPatchCount = g_Patches.Count();
  1074. for (j=0; j<uiPatchCount; j++)
  1075. {
  1076. patch = &g_Patches.Element( j );
  1077. // skip parent patches
  1078. if (patch->child1 != g_Patches.InvalidIndex() )
  1079. continue;
  1080. if( patch->clusterNumber == -1 )
  1081. {
  1082. Vector vGreen;
  1083. VectorClear( vGreen );
  1084. vGreen[1] = 256.0f;
  1085. WriteWinding( out, patch->winding, vGreen );
  1086. }
  1087. else
  1088. {
  1089. Vector light = patch->totallight.light[iBump] + patch->directlight;
  1090. WriteWinding( out, patch->winding, light );
  1091. if( bDumpNormals )
  1092. {
  1093. WriteNormal( out, patch->origin, patch->plane->normal, 15.0f, patch->plane->normal * 255.0f );
  1094. }
  1095. }
  1096. }
  1097. g_pFileSystem->Close( out );
  1098. }
  1099. void WriteRTEnv (char *name)
  1100. {
  1101. FileHandle_t out;
  1102. out = g_pFileSystem->Open( name, "w" );
  1103. if (!out)
  1104. Error ("Couldn't open %s", name);
  1105. winding_t *triw = AllocWinding( 3 );
  1106. triw->numpoints = 3;
  1107. for( int i = 0; i < g_RtEnv.OptimizedTriangleList.Count(); i++ )
  1108. {
  1109. triw->p[0] = g_RtEnv.OptimizedTriangleList[i].Vertex( 0);
  1110. triw->p[1] = g_RtEnv.OptimizedTriangleList[i].Vertex( 1);
  1111. triw->p[2] = g_RtEnv.OptimizedTriangleList[i].Vertex( 2);
  1112. int id = g_RtEnv.OptimizedTriangleList[i].m_Data.m_GeometryData.m_nTriangleID;
  1113. Vector color(0, 0, 0);
  1114. if (id & TRACE_ID_OPAQUE) color.Init(0, 255, 0);
  1115. if (id & TRACE_ID_SKY) color.Init(0, 0, 255);
  1116. if (id & TRACE_ID_STATICPROP) color.Init(255, 0, 0);
  1117. WriteWinding(out, triw, color);
  1118. }
  1119. FreeWinding(triw);
  1120. g_pFileSystem->Close( out );
  1121. }
  1122. void WriteWinding (FileHandle_t out, winding_t *w, Vector& color )
  1123. {
  1124. int i;
  1125. CmdLib_FPrintf (out, "%i\n", w->numpoints);
  1126. for (i=0 ; i<w->numpoints ; i++)
  1127. {
  1128. CmdLib_FPrintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  1129. w->p[i][0],
  1130. w->p[i][1],
  1131. w->p[i][2],
  1132. color[ 0 ] / 256,
  1133. color[ 1 ] / 256,
  1134. color[ 2 ] / 256 );
  1135. }
  1136. }
  1137. void WriteNormal( FileHandle_t out, Vector const &nPos, Vector const &nDir,
  1138. float length, Vector const &color )
  1139. {
  1140. CmdLib_FPrintf( out, "2\n" );
  1141. CmdLib_FPrintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  1142. nPos.x, nPos.y, nPos.z,
  1143. color.x / 256, color.y / 256, color.z / 256 );
  1144. CmdLib_FPrintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  1145. nPos.x + ( nDir.x * length ),
  1146. nPos.y + ( nDir.y * length ),
  1147. nPos.z + ( nDir.z * length ),
  1148. color.x / 256, color.y / 256, color.z / 256 );
  1149. }
  1150. void WriteLine( FileHandle_t out, const Vector &vecPos1, const Vector &vecPos2, const Vector &color )
  1151. {
  1152. CmdLib_FPrintf( out, "2\n" );
  1153. CmdLib_FPrintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  1154. vecPos1.x, vecPos1.y, vecPos1.z,
  1155. color.x / 256, color.y / 256, color.z / 256 );
  1156. CmdLib_FPrintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  1157. vecPos2.x, vecPos2.y, vecPos2.z,
  1158. color.x / 256, color.y / 256, color.z / 256 );
  1159. }
  1160. void WriteTrace( const char *pFileName, const FourRays &rays, const RayTracingResult& result )
  1161. {
  1162. FileHandle_t out;
  1163. out = g_pFileSystem->Open( pFileName, "a" );
  1164. if (!out)
  1165. Error ("Couldn't open %s", pFileName);
  1166. // Draws rays
  1167. for ( int i = 0; i < 4; ++i )
  1168. {
  1169. Vector vecOrigin = rays.origin.Vec(i);
  1170. Vector vecEnd = rays.direction.Vec(i);
  1171. VectorNormalize( vecEnd );
  1172. vecEnd *= SubFloat( result.HitDistance, i );
  1173. vecEnd += vecOrigin;
  1174. WriteLine( out, vecOrigin, vecEnd, Vector( 256, 0, 0 ) );
  1175. WriteNormal( out, vecEnd, result.surface_normal.Vec(i), 10.0f, Vector( 256, 265, 0 ) );
  1176. }
  1177. g_pFileSystem->Close( out );
  1178. }
  1179. /*
  1180. =============
  1181. CollectLight
  1182. =============
  1183. */
  1184. // patch's totallight += new light received to each patch
  1185. // patch's emitlight = addlight (newly received light from GatherLight)
  1186. // patch's addlight = 0
  1187. // pull received light from children.
  1188. void CollectLight( Vector& total )
  1189. {
  1190. int i, j;
  1191. CPatch *patch;
  1192. VectorFill( total, 0 );
  1193. // process patches in reverse order so that children are processed before their parents
  1194. unsigned int uiPatchCount = g_Patches.Count();
  1195. for( i = uiPatchCount - 1; i >= 0; i-- )
  1196. {
  1197. patch = &g_Patches.Element( i );
  1198. int normalCount = patch->needsBumpmap ? NUM_BUMP_VECTS+1 : 1;
  1199. // sky's never collect light, it is just dropped
  1200. if (patch->sky)
  1201. {
  1202. VectorFill( emitlight[ i ], 0 );
  1203. }
  1204. else if ( patch->child1 == g_Patches.InvalidIndex() )
  1205. {
  1206. // This is a leaf node.
  1207. for ( j = 0; j < normalCount; j++ )
  1208. {
  1209. VectorAdd( patch->totallight.light[j], addlight[i].light[j], patch->totallight.light[j] );
  1210. }
  1211. VectorCopy( addlight[i].light[0], emitlight[i] );
  1212. VectorAdd( total, emitlight[i], total );
  1213. }
  1214. else
  1215. {
  1216. // This is an interior node.
  1217. // Pull received light from children.
  1218. float s1, s2;
  1219. CPatch *child1;
  1220. CPatch *child2;
  1221. child1 = &g_Patches[patch->child1];
  1222. child2 = &g_Patches[patch->child2];
  1223. // BUG: This doesn't do anything?
  1224. if ((int)patch->area != (int)(child1->area + child2->area))
  1225. s1 = 0;
  1226. s1 = child1->area / (child1->area + child2->area);
  1227. s2 = child2->area / (child1->area + child2->area);
  1228. // patch->totallight = s1 * child1->totallight + s2 * child2->totallight
  1229. for ( j = 0; j < normalCount; j++ )
  1230. {
  1231. VectorScale( child1->totallight.light[j], s1, patch->totallight.light[j] );
  1232. VectorMA( patch->totallight.light[j], s2, child2->totallight.light[j], patch->totallight.light[j] );
  1233. }
  1234. // patch->emitlight = s1 * child1->emitlight + s2 * child2->emitlight
  1235. VectorScale( emitlight[patch->child1], s1, emitlight[i] );
  1236. VectorMA( emitlight[i], s2, emitlight[patch->child2], emitlight[i] );
  1237. }
  1238. for ( j = 0; j < NUM_BUMP_VECTS+1; j++ )
  1239. {
  1240. VectorFill( addlight[ i ].light[j], 0 );
  1241. }
  1242. }
  1243. }
  1244. /*
  1245. =============
  1246. GatherLight
  1247. Get light from other patches
  1248. Run multi-threaded
  1249. =============
  1250. */
  1251. #ifdef _WIN32
  1252. #pragma warning (disable:4701)
  1253. #endif
  1254. extern void GetBumpNormals( const float* sVect, const float* tVect, const Vector& flatNormal,
  1255. const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] );
  1256. void PreGetBumpNormalsForDisp( texinfo_t *pTexinfo, Vector &vecU, Vector &vecV, Vector &vecNormal )
  1257. {
  1258. Vector vecTexU( pTexinfo->textureVecsTexelsPerWorldUnits[0][0], pTexinfo->textureVecsTexelsPerWorldUnits[0][1], pTexinfo->textureVecsTexelsPerWorldUnits[0][2] );
  1259. Vector vecTexV( pTexinfo->textureVecsTexelsPerWorldUnits[1][0], pTexinfo->textureVecsTexelsPerWorldUnits[1][1], pTexinfo->textureVecsTexelsPerWorldUnits[1][2] );
  1260. Vector vecLightU( pTexinfo->lightmapVecsLuxelsPerWorldUnits[0][0], pTexinfo->lightmapVecsLuxelsPerWorldUnits[0][1], pTexinfo->lightmapVecsLuxelsPerWorldUnits[0][2] );
  1261. Vector vecLightV( pTexinfo->lightmapVecsLuxelsPerWorldUnits[1][0], pTexinfo->lightmapVecsLuxelsPerWorldUnits[1][1], pTexinfo->lightmapVecsLuxelsPerWorldUnits[1][2] );
  1262. VectorNormalize( vecTexU );
  1263. VectorNormalize( vecTexV );
  1264. VectorNormalize( vecLightU );
  1265. VectorNormalize( vecLightV );
  1266. bool bDoConversion = false;
  1267. if ( fabs( vecTexU.Dot( vecLightU ) ) < 0.999f )
  1268. {
  1269. bDoConversion = true;
  1270. }
  1271. if ( fabs( vecTexV.Dot( vecLightV ) ) < 0.999f )
  1272. {
  1273. bDoConversion = true;
  1274. }
  1275. if ( bDoConversion )
  1276. {
  1277. matrix3x4_t matTex( vecTexU, vecTexV, vecNormal, vec3_origin );
  1278. matrix3x4_t matLight( vecLightU, vecLightV, vecNormal, vec3_origin );
  1279. matrix3x4_t matTmp;
  1280. ConcatTransforms ( matLight, matTex, matTmp );
  1281. MatrixGetColumn( matTmp, 0, vecU );
  1282. MatrixGetColumn( matTmp, 1, vecV );
  1283. MatrixGetColumn( matTmp, 2, vecNormal );
  1284. Assert( fabs( vecTexU.Dot( vecTexV ) ) <= 0.001f );
  1285. return;
  1286. }
  1287. vecU = vecTexU;
  1288. vecV = vecTexV;
  1289. }
  1290. void GatherLight (int threadnum, void *pUserData)
  1291. {
  1292. int i, j, k;
  1293. transfer_t *trans;
  1294. int num;
  1295. CPatch *patch;
  1296. Vector sum, v;
  1297. while (1)
  1298. {
  1299. j = GetThreadWork ();
  1300. if (j == -1)
  1301. break;
  1302. patch = &g_Patches[j];
  1303. trans = patch->transfers;
  1304. num = patch->numtransfers;
  1305. if ( patch->needsBumpmap )
  1306. {
  1307. Vector delta;
  1308. Vector bumpSum[NUM_BUMP_VECTS+1];
  1309. Vector normals[NUM_BUMP_VECTS+1];
  1310. // Disps
  1311. bool bDisp = ( patch->faceNumber >= 0 ) && ( g_pFaces[ patch->faceNumber ].dispinfo != -1 );
  1312. if ( bDisp )
  1313. {
  1314. normals[0] = patch->normal;
  1315. texinfo_t *pTexinfo = &texinfo[g_pFaces[patch->faceNumber].texinfo];
  1316. Vector vecTexU, vecTexV;
  1317. PreGetBumpNormalsForDisp( pTexinfo, vecTexU, vecTexV, normals[0] );
  1318. // use facenormal along with the smooth normal to build the three bump map vectors
  1319. GetBumpNormals( vecTexU, vecTexV, normals[0], normals[0], &normals[1] );
  1320. }
  1321. else
  1322. {
  1323. GetPhongNormal( patch->faceNumber, patch->origin, normals[0] );
  1324. texinfo_t *pTexinfo = &texinfo[g_pFaces[patch->faceNumber].texinfo];
  1325. // use facenormal along with the smooth normal to build the three bump map vectors
  1326. GetBumpNormals( pTexinfo->textureVecsTexelsPerWorldUnits[0],
  1327. pTexinfo->textureVecsTexelsPerWorldUnits[1], patch->normal,
  1328. normals[0], &normals[1] );
  1329. }
  1330. // force the base lightmap to use the flat normal instead of the phong normal
  1331. // FIXME: why does the patch not use the phong normal?
  1332. normals[0] = patch->normal;
  1333. for ( i = 0; i < NUM_BUMP_VECTS+1; i++ )
  1334. {
  1335. VectorFill( bumpSum[i], 0 );
  1336. }
  1337. float dot;
  1338. for (k=0 ; k<num ; k++, trans++)
  1339. {
  1340. CPatch *patch2 = &g_Patches[trans->patch];
  1341. // get vector to other patch
  1342. VectorSubtract (patch2->origin, patch->origin, delta);
  1343. VectorNormalize (delta);
  1344. // find light emitted from other patch
  1345. for(i=0; i<3; i++)
  1346. {
  1347. v[i] = emitlight[trans->patch][i] * patch2->reflectivity[i];
  1348. }
  1349. // remove normal already factored into transfer steradian
  1350. float scale = 1.0f / DotProduct (delta, patch->normal);
  1351. VectorScale( v, trans->transfer * scale, v );
  1352. Vector bumpTransfer;
  1353. for ( i = 0; i < NUM_BUMP_VECTS+1; i++ )
  1354. {
  1355. dot = DotProduct( delta, normals[i] );
  1356. if ( dot <= 0 )
  1357. {
  1358. // Assert( i > 0 ); // if this hits, then the transfer shouldn't be here. It doesn't face the flat normal of this face!
  1359. continue;
  1360. }
  1361. bumpTransfer = v * dot;
  1362. VectorAdd( bumpSum[i], bumpTransfer, bumpSum[i] );
  1363. }
  1364. }
  1365. for ( i = 0; i < NUM_BUMP_VECTS+1; i++ )
  1366. {
  1367. VectorCopy( bumpSum[i], addlight[j].light[i] );
  1368. }
  1369. }
  1370. else
  1371. {
  1372. VectorFill( sum, 0 );
  1373. for (k=0 ; k<num ; k++, trans++)
  1374. {
  1375. for(i=0; i<3; i++)
  1376. {
  1377. v[i] = emitlight[trans->patch][i] * g_Patches[trans->patch].reflectivity[i];
  1378. }
  1379. VectorScale( v, trans->transfer, v );
  1380. VectorAdd( sum, v, sum );
  1381. }
  1382. VectorCopy( sum, addlight[j].light[0] );
  1383. }
  1384. }
  1385. }
  1386. #ifdef _WIN32
  1387. #pragma warning (default:4701)
  1388. #endif
  1389. /*
  1390. =============
  1391. BounceLight
  1392. =============
  1393. */
  1394. void BounceLight (void)
  1395. {
  1396. unsigned i;
  1397. Vector added;
  1398. char name[64];
  1399. qboolean bouncing = numbounce > 0;
  1400. unsigned int uiPatchCount = g_Patches.Count();
  1401. for (i=0 ; i<uiPatchCount; i++)
  1402. {
  1403. // totallight has a copy of the direct lighting. Move it to the emitted light and zero it out (to integrate bounces only)
  1404. VectorCopy( g_Patches[i].totallight.light[0], emitlight[i] );
  1405. // NOTE: This means that only the bounced light is integrated into totallight!
  1406. VectorFill( g_Patches[i].totallight.light[0], 0 );
  1407. }
  1408. #if 0
  1409. FileHandle_t dFp = g_pFileSystem->Open( "lightemit.txt", "w" );
  1410. unsigned int uiPatchCount = g_Patches.Size();
  1411. for (i=0 ; i<uiPatchCount; i++)
  1412. {
  1413. CmdLib_FPrintf( dFp, "Emit %d: %f %f %f\n", i, emitlight[i].x, emitlight[i].y, emitlight[i].z );
  1414. }
  1415. g_pFileSystem->Close( dFp );
  1416. for (i=0; i<num_patches ; i++)
  1417. {
  1418. Vector total;
  1419. VectorSubtract (g_Patches[i].maxs, g_Patches[i].mins, total);
  1420. Msg("%4d %4d %4d %4d (%d) %.0f", i, g_Patches[i].parent, g_Patches[i].child1, g_Patches[i].child2, g_Patches[i].samples, g_Patches[i].area );
  1421. Msg(" [%.0f %.0f %.0f]", total[0], total[1], total[2] );
  1422. if (g_Patches[i].child1 != g_Patches.InvalidIndex() )
  1423. {
  1424. Vector tmp;
  1425. VectorScale( g_Patches[i].totallight.light[0], g_Patches[i].area, tmp );
  1426. VectorMA( tmp, -g_Patches[g_Patches[i].child1].area, g_Patches[g_Patches[i].child1].totallight.light[0], tmp );
  1427. VectorMA( tmp, -g_Patches[g_Patches[i].child2].area, g_Patches[g_Patches[i].child2].totallight.light[0], tmp );
  1428. // Msg("%.0f ", VectorLength( tmp ) );
  1429. // Msg("%d ", g_Patches[i].samples - g_Patches[g_Patches[i].child1].samples - g_Patches[g_Patches[i].child2].samples );
  1430. // Msg("%d ", g_Patches[i].samples );
  1431. }
  1432. Msg("\n");
  1433. }
  1434. #endif
  1435. i = 0;
  1436. while ( bouncing )
  1437. {
  1438. // transfer light from to the leaf patches from other patches via transfers
  1439. // this moves shooter->emitlight to receiver->addlight
  1440. uiPatchCount = g_Patches.Count();
  1441. RunThreadsOn (uiPatchCount, true, GatherLight);
  1442. // move newly received light (addlight) to light to be sent out (emitlight)
  1443. // start at children and pull light up to parents
  1444. // light is always received to leaf patches
  1445. CollectLight( added );
  1446. qprintf ("\tBounce #%i added RGB(%.0f, %.0f, %.0f)\n", i+1, added[0], added[1], added[2] );
  1447. if ( i+1 == numbounce || (added[0] < 1.0 && added[1] < 1.0 && added[2] < 1.0) )
  1448. bouncing = false;
  1449. i++;
  1450. if ( g_bDumpPatches && !bouncing && i != 1)
  1451. {
  1452. sprintf (name, "bounce%i.txt", i);
  1453. WriteWorld (name, 0);
  1454. }
  1455. }
  1456. }
  1457. //-----------------------------------------------------------------------------
  1458. // Purpose: Counts the number of clusters in a map with no visibility
  1459. // Output : int
  1460. //-----------------------------------------------------------------------------
  1461. int CountClusters( void )
  1462. {
  1463. int clusterCount = 0;
  1464. for ( int i = 0; i < numleafs; i++ )
  1465. {
  1466. if ( dleafs[i].cluster > clusterCount )
  1467. clusterCount = dleafs[i].cluster;
  1468. }
  1469. return clusterCount + 1;
  1470. }
  1471. /*
  1472. =============
  1473. RadWorld
  1474. =============
  1475. */
  1476. void RadWorld_Start()
  1477. {
  1478. unsigned i;
  1479. if (luxeldensity < 1.0)
  1480. {
  1481. // Remember the old lightmap vectors.
  1482. float oldLightmapVecs[MAX_MAP_TEXINFO][2][4];
  1483. for (i = 0; i < texinfo.Count(); i++)
  1484. {
  1485. for( int j=0; j < 2; j++ )
  1486. {
  1487. for( int k=0; k < 3; k++ )
  1488. {
  1489. oldLightmapVecs[i][j][k] = texinfo[i].lightmapVecsLuxelsPerWorldUnits[j][k];
  1490. }
  1491. }
  1492. }
  1493. // rescale luxels to be no denser than "luxeldensity"
  1494. for (i = 0; i < texinfo.Count(); i++)
  1495. {
  1496. texinfo_t *tx = &texinfo[i];
  1497. for (int j = 0; j < 2; j++ )
  1498. {
  1499. Vector tmp( tx->lightmapVecsLuxelsPerWorldUnits[j][0], tx->lightmapVecsLuxelsPerWorldUnits[j][1], tx->lightmapVecsLuxelsPerWorldUnits[j][2] );
  1500. float scale = VectorNormalize( tmp );
  1501. // only rescale them if the current scale is "tighter" than the desired scale
  1502. // FIXME: since this writes out to the BSP file every run, once it's set high it can't be reset
  1503. // to a lower value.
  1504. if (fabs( scale ) > luxeldensity)
  1505. {
  1506. if (scale < 0)
  1507. {
  1508. scale = -luxeldensity;
  1509. }
  1510. else
  1511. {
  1512. scale = luxeldensity;
  1513. }
  1514. VectorScale( tmp, scale, tmp );
  1515. tx->lightmapVecsLuxelsPerWorldUnits[j][0] = tmp.x;
  1516. tx->lightmapVecsLuxelsPerWorldUnits[j][1] = tmp.y;
  1517. tx->lightmapVecsLuxelsPerWorldUnits[j][2] = tmp.z;
  1518. }
  1519. }
  1520. }
  1521. UpdateAllFaceLightmapExtents();
  1522. }
  1523. MakeParents (0, -1);
  1524. BuildClusterTable();
  1525. // turn each face into a single patch
  1526. MakePatches ();
  1527. PairEdges ();
  1528. // store the vertex normals calculated in PairEdges
  1529. // so that the can be written to the bsp file for
  1530. // use in the engine
  1531. SaveVertexNormals();
  1532. // subdivide patches to a maximum dimension
  1533. SubdividePatches ();
  1534. // add displacement faces to cluster table
  1535. AddDispsToClusterTable();
  1536. if ( g_bStaticPropBounce )
  1537. {
  1538. AddStaticPropPatchesToClusterTable();
  1539. }
  1540. // create directlights out of patches and lights
  1541. CreateDirectLights ();
  1542. // set up sky cameras
  1543. ProcessSkyCameras();
  1544. }
  1545. // This function should fill in the indices into g_pFaces[] for the faces
  1546. // with displacements that touch the specified leaf.
  1547. void STUB_GetDisplacementsTouchingLeaf( int iLeaf, CUtlVector<int> &dispFaces )
  1548. {
  1549. }
  1550. void BuildFacesVisibleToLights( bool bAllVisible )
  1551. {
  1552. g_FacesVisibleToLights.SetSize( numfaces/8 + 1 );
  1553. if( bAllVisible )
  1554. {
  1555. memset( g_FacesVisibleToLights.Base(), 0xFF, g_FacesVisibleToLights.Count() );
  1556. return;
  1557. }
  1558. // First merge all the light PVSes.
  1559. CUtlVector<byte> aggregate;
  1560. aggregate.SetSize( (dvis->numclusters/8) + 1 );
  1561. memset( aggregate.Base(), 0, aggregate.Count() );
  1562. int nDWords = aggregate.Count() / 4;
  1563. int nBytes = aggregate.Count() - nDWords*4;
  1564. for( directlight_t *dl = activelights; dl != NULL; dl = dl->next )
  1565. {
  1566. byte *pIn = dl->pvs;
  1567. byte *pOut = aggregate.Base();
  1568. for( int iDWord=0; iDWord < nDWords; iDWord++ )
  1569. {
  1570. *((unsigned long*)pOut) |= *((unsigned long*)pIn);
  1571. pIn += 4;
  1572. pOut += 4;
  1573. }
  1574. for( int iByte=0; iByte < nBytes; iByte++ )
  1575. {
  1576. *pOut |= *pIn;
  1577. ++pOut;
  1578. ++pIn;
  1579. }
  1580. }
  1581. // Now tag any faces that are visible to this monster PVS.
  1582. for( int iCluster=0; iCluster < dvis->numclusters; iCluster++ )
  1583. {
  1584. if( g_ClusterLeaves[iCluster].leafCount )
  1585. {
  1586. if( aggregate[iCluster>>3] & (1 << (iCluster & 7)) )
  1587. {
  1588. for ( int i = 0; i < g_ClusterLeaves[iCluster].leafCount; i++ )
  1589. {
  1590. int iLeaf = g_ClusterLeaves[iCluster].leafs[i];
  1591. // Tag all the faces.
  1592. int iFace;
  1593. for( iFace=0; iFace < dleafs[iLeaf].numleaffaces; iFace++ )
  1594. {
  1595. int index = dleafs[iLeaf].firstleafface + iFace;
  1596. index = dleaffaces[index];
  1597. assert( index < numfaces );
  1598. g_FacesVisibleToLights[index >> 3] |= (1 << (index & 7));
  1599. }
  1600. // Fill in STUB_GetDisplacementsTouchingLeaf when it's available
  1601. // so displacements get relit.
  1602. CUtlVector<int> dispFaces;
  1603. STUB_GetDisplacementsTouchingLeaf( iLeaf, dispFaces );
  1604. for( iFace=0; iFace < dispFaces.Count(); iFace++ )
  1605. {
  1606. int index = dispFaces[iFace];
  1607. g_FacesVisibleToLights[index >> 3] |= (1 << (index & 7));
  1608. }
  1609. }
  1610. }
  1611. }
  1612. }
  1613. // For stats.. figure out how many faces it's going to touch.
  1614. int nFacesToProcess = 0;
  1615. for( int i=0; i < numfaces; i++ )
  1616. {
  1617. if( g_FacesVisibleToLights[i>>3] & (1 << (i & 7)) )
  1618. ++nFacesToProcess;
  1619. }
  1620. }
  1621. void MakeAllScales (void)
  1622. {
  1623. // determine visibility between patches
  1624. BuildVisMatrix ();
  1625. // release visibility matrix
  1626. FreeVisMatrix ();
  1627. Msg("transfers %d, max %d\n", total_transfer, max_transfer );
  1628. qprintf ("transfer lists: %5.1f megs\n"
  1629. , (float)total_transfer * sizeof(transfer_t) / (1024*1024));
  1630. if ( g_bStaticPropBounce )
  1631. {
  1632. int nTransfers = 0;
  1633. for ( int i = 0; i < g_Patches.Count(); i++ )
  1634. {
  1635. CPatch *pCur = &g_Patches.Element( i );
  1636. if ( pCur->faceNumber >= 0 )
  1637. {
  1638. continue;
  1639. }
  1640. nTransfers += pCur->numtransfers;
  1641. }
  1642. Msg( "static prop patch transfers %d\n", nTransfers );
  1643. }
  1644. }
  1645. // Helper function. This can be useful to visualize the world and faces and see which face
  1646. // corresponds to which dface.
  1647. #if 0
  1648. #include "iscratchpad3d.h"
  1649. void ScratchPad_DrawWorld()
  1650. {
  1651. IScratchPad3D *pPad = ScratchPad3D_Create();
  1652. pPad->SetAutoFlush( false );
  1653. for ( int i=0; i < numfaces; i++ )
  1654. {
  1655. dface_t *f = &g_pFaces[i];
  1656. // Draw the face's outline, then put text for its face index on it too.
  1657. CUtlVector<Vector> points;
  1658. for ( int iEdge = 0; iEdge < f->numedges; iEdge++ )
  1659. {
  1660. int v;
  1661. int se = dsurfedges[f->firstedge + iEdge];
  1662. if ( se < 0 )
  1663. v = dedges[-se].v[1];
  1664. else
  1665. v = dedges[se].v[0];
  1666. dvertex_t *dv = &dvertexes[v];
  1667. points.AddToTail( dv->point );
  1668. }
  1669. // Draw the outline.
  1670. Vector vCenter( 0, 0, 0 );
  1671. for ( iEdge=0; iEdge < points.Count(); iEdge++ )
  1672. {
  1673. pPad->DrawLine( CSPVert( points[iEdge] ), CSPVert( points[(iEdge+1)%points.Count()] ) );
  1674. vCenter += points[iEdge];
  1675. }
  1676. vCenter /= points.Count();
  1677. // Draw the text.
  1678. char str[512];
  1679. Q_snprintf( str, sizeof( str ), "%d", i );
  1680. CTextParams params;
  1681. params.m_bCentered = true;
  1682. params.m_bOutline = true;
  1683. params.m_flLetterWidth = 2;
  1684. params.m_vColor.Init( 1, 0, 0 );
  1685. VectorAngles( dplanes[f->planenum].normal, params.m_vAngles );
  1686. params.m_bTwoSided = true;
  1687. params.m_vPos = vCenter;
  1688. pPad->DrawText( str, params );
  1689. }
  1690. pPad->Release();
  1691. }
  1692. #endif
  1693. bool RadWorld_Go()
  1694. {
  1695. g_iCurFace = 0;
  1696. InitMacroTexture( source );
  1697. if( g_pIncremental )
  1698. {
  1699. g_pIncremental->PrepareForLighting();
  1700. // Cull out faces that aren't visible to any of the lights that we're updating with.
  1701. BuildFacesVisibleToLights( false );
  1702. }
  1703. else
  1704. {
  1705. // Mark all faces visible.. when not doing incremental lighting, it's highly
  1706. // likely that all faces are going to be touched by at least one light so don't
  1707. // waste time here.
  1708. BuildFacesVisibleToLights( true );
  1709. }
  1710. // build initial facelights
  1711. if (g_bUseMPI)
  1712. {
  1713. // RunThreadsOnIndividual (numfaces, true, BuildFacelights);
  1714. RunMPIBuildFacelights();
  1715. if ( g_bStaticPropBounce )
  1716. {
  1717. RunThreadsOnIndividual( g_Patches.Count(), true, BuildStaticPropPatchlights );
  1718. }
  1719. }
  1720. else
  1721. {
  1722. RunThreadsOnIndividual( numfaces, true, BuildFacelights );
  1723. if ( g_bStaticPropBounce )
  1724. {
  1725. RunThreadsOnIndividual( g_Patches.Count(), true, BuildStaticPropPatchlights );
  1726. }
  1727. #if 0
  1728. IScratchPad3D *pPad = ScratchPad3D_Create();
  1729. pPad->SetAutoFlush( false );
  1730. float flMax = 0.0f;
  1731. for ( int i = 0; i < g_Patches.Count(); i++ )
  1732. {
  1733. if ( g_Patches[ i ].child1 != g_Patches.InvalidIndex() || g_Patches[ i ].child2 != g_Patches.InvalidIndex() )
  1734. continue;
  1735. Vector vLight = g_Patches[ i ].directlight;
  1736. flMax = Max( flMax, vLight.x );
  1737. flMax = Max( flMax, vLight.y );
  1738. flMax = Max( flMax, vLight.z );
  1739. }
  1740. for ( int i = 0; i < g_Patches.Count(); i++ )
  1741. {
  1742. if ( g_Patches[ i ].child1 != g_Patches.InvalidIndex() || g_Patches[ i ].child2 != g_Patches.InvalidIndex() )
  1743. continue;
  1744. Vector vLight = g_Patches[ i ].directlight * g_Patches[i].reflectivity;
  1745. vLight /= flMax;
  1746. vLight.x = SrgbLinearToGamma( vLight.x );
  1747. vLight.y = SrgbLinearToGamma( vLight.y );
  1748. vLight.z = SrgbLinearToGamma( vLight.z );
  1749. pPad->DrawPolygon( CSPVertList( g_Patches[ i ].winding->p, g_Patches[ i ].winding->numpoints, CSPColor( vLight ) ) );
  1750. }
  1751. pPad->Release();
  1752. #endif
  1753. }
  1754. // Was the process interrupted?
  1755. if( g_pIncremental && (g_iCurFace != numfaces) )
  1756. return false;
  1757. // Figure out the offset into lightmap data for each face.
  1758. PrecompLightmapOffsets();
  1759. // If we're doing incremental lighting, stop here.
  1760. if( g_pIncremental )
  1761. {
  1762. g_pIncremental->Finalize();
  1763. }
  1764. else
  1765. {
  1766. // free up the direct lights now that we have facelights
  1767. ExportDirectLightsToWorldLights();
  1768. if ( g_bDumpPatches )
  1769. {
  1770. for( int iBump = 0; iBump < 4; ++iBump )
  1771. {
  1772. char szName[64];
  1773. sprintf ( szName, "bounce0_%d.txt", iBump );
  1774. WriteWorld( szName, iBump );
  1775. }
  1776. }
  1777. if (numbounce > 0)
  1778. {
  1779. // allocate memory for emitlight/addlight
  1780. emitlight.SetSize( g_Patches.Count() );
  1781. memset( emitlight.Base(), 0, g_Patches.Count() * sizeof( Vector ) );
  1782. addlight.SetSize( g_Patches.Count() );
  1783. memset( addlight.Base(), 0, g_Patches.Count() * sizeof( bumplights_t ) );
  1784. MakeAllScales ();
  1785. // spread light around
  1786. BounceLight ();
  1787. }
  1788. //
  1789. // displacement surface luxel accumulation (make threaded!!!)
  1790. //
  1791. StaticDispMgr()->StartTimer( "Build Patch/Sample Hash Table(s)....." );
  1792. StaticDispMgr()->InsertSamplesDataIntoHashTable();
  1793. StaticDispMgr()->InsertPatchSampleDataIntoHashTable();
  1794. StaticDispMgr()->EndTimer();
  1795. // blend bounced light into direct light and save
  1796. VMPI_SetCurrentStage( "FinalLightFace" );
  1797. if ( !g_bUseMPI || g_bMPIMaster )
  1798. RunThreadsOnIndividual (numfaces, true, FinalLightFace);
  1799. // Distribute the lighting data to workers.
  1800. VMPI_DistributeLightData();
  1801. Msg("FinalLightFace Done\n"); fflush(stdout);
  1802. }
  1803. return true;
  1804. }
  1805. // declare the sample file pointer -- the whole debug print system should
  1806. // be reworked at some point!!
  1807. FileHandle_t pFileSamples[4][4];
  1808. void LoadPhysicsDLL( void )
  1809. {
  1810. PhysicsDLLPath( "VPHYSICS.DLL" );
  1811. }
  1812. void InitDumpPatchesFiles()
  1813. {
  1814. for( int iStyle = 0; iStyle < 4; ++iStyle )
  1815. {
  1816. for ( int iBump = 0; iBump < 4; ++iBump )
  1817. {
  1818. char szFilename[MAX_PATH];
  1819. sprintf( szFilename, "samples_style%d_bump%d.txt", iStyle, iBump );
  1820. pFileSamples[iStyle][iBump] = g_pFileSystem->Open( szFilename, "w" );
  1821. if( !pFileSamples[iStyle][iBump] )
  1822. {
  1823. Error( "Can't open %s for -dump.\n", szFilename );
  1824. }
  1825. }
  1826. }
  1827. }
  1828. void VRAD_LoadBSP( char const *pFilename )
  1829. {
  1830. ThreadSetDefault ();
  1831. g_flStartTime = Plat_FloatTime();
  1832. if( g_bLowPriority )
  1833. {
  1834. SetLowPriority();
  1835. }
  1836. strcpy( level_name, source );
  1837. // This must come after InitFileSystem because the file system pointer might change.
  1838. if ( g_bDumpPatches )
  1839. InitDumpPatchesFiles();
  1840. // This part is just for VMPI. VMPI's file system needs the basedir in front of all filenames,
  1841. // so we prepend qdir here.
  1842. strcpy( source, ExpandPath( source ) );
  1843. if ( !g_bUseMPI )
  1844. {
  1845. // Setup the logfile.
  1846. char logFile[512];
  1847. _snprintf( logFile, sizeof(logFile), "%s.log", source );
  1848. g_CmdLibFileLoggingListener.Open( logFile );
  1849. }
  1850. LoadPhysicsDLL();
  1851. // Set the required global lights filename and try looking in qproject
  1852. strcpy( global_lights, "lights.rad" );
  1853. if ( !g_pFileSystem->FileExists( global_lights ) )
  1854. {
  1855. // Otherwise, try looking in the BIN directory from which we were run from
  1856. Msg( "Could not find lights.rad in %s.\nTrying VRAD BIN directory instead...\n",
  1857. global_lights );
  1858. GetModuleFileName( NULL, global_lights, sizeof( global_lights ) );
  1859. Q_ExtractFilePath( global_lights, global_lights, sizeof( global_lights ) );
  1860. strcat( global_lights, "lights.rad" );
  1861. }
  1862. // Set the optional level specific lights filename
  1863. strcpy( level_lights, source );
  1864. Q_DefaultExtension( level_lights, ".rad", sizeof( level_lights ) );
  1865. if ( !g_pFileSystem->FileExists( level_lights ) )
  1866. *level_lights = 0;
  1867. ReadLightFile(global_lights); // Required
  1868. if ( *designer_lights ) ReadLightFile(designer_lights); // Command-line
  1869. if ( *level_lights ) ReadLightFile(level_lights); // Optional & implied
  1870. strcpy(incrementfile, source);
  1871. Q_DefaultExtension(incrementfile, ".r0", sizeof(incrementfile));
  1872. Q_DefaultExtension(source, ".bsp", sizeof( source ));
  1873. GetPlatformMapPath( source, platformPath, 0, MAX_PATH );
  1874. Msg( "Loading %s\n", platformPath );
  1875. VMPI_SetCurrentStage( "LoadBSPFile" );
  1876. LoadBSPFile (platformPath);
  1877. // now, set whether or not static prop lighting is present
  1878. if (g_bStaticPropLighting)
  1879. g_LevelFlags |= g_bHDR? LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_HDR : LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_NONHDR;
  1880. else
  1881. {
  1882. g_LevelFlags &= ~( LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_HDR | LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_NONHDR );
  1883. }
  1884. extern int g_numVradStaticPropsLightingStreams;
  1885. if ( g_numVradStaticPropsLightingStreams == 3 )
  1886. {
  1887. g_LevelFlags |= LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_3;
  1888. g_LevelFlags |= LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_3_NO_SUN;
  1889. }
  1890. // Enable level flag that tells us we are packing in the additional lightmap alpha data in the lighting lump
  1891. // we're now storing slightly modified alpha data for improved CSM/lightmap blending, so update with an extra flag.
  1892. g_LevelFlags |= LVLFLAGS_LIGHTMAP_ALPHA | LVLFLAGS_LIGHTMAP_ALPHA_3;
  1893. // Lightstyles now interleaved correctly with lightmap alpha data, an old map could use lightstyles iff there was no env_cascade light in the map
  1894. g_LevelFlags |= LVLFLAGS_LIGHTSTYLES_WITH_CSM;
  1895. // now, we need to set our face ptr depending upon hdr, and if hdr, init it
  1896. if (g_bHDR)
  1897. {
  1898. g_pFaces = dfaces_hdr;
  1899. if (numfaces_hdr==0)
  1900. {
  1901. numfaces_hdr = numfaces;
  1902. memcpy( dfaces_hdr, dfaces, numfaces*sizeof(dfaces[0]) );
  1903. }
  1904. }
  1905. else
  1906. {
  1907. g_pFaces = dfaces;
  1908. }
  1909. ParseEntities ();
  1910. ExtractBrushEntityShadowCasters();
  1911. StaticPropMgr()->Init();
  1912. StaticDispMgr()->Init();
  1913. if (!visdatasize)
  1914. {
  1915. Msg("No vis information, direct lighting only.\n");
  1916. numbounce = 0;
  1917. ambient[0] = ambient[1] = ambient[2] = 0.1f;
  1918. dvis->numclusters = CountClusters();
  1919. }
  1920. //
  1921. // patches and referencing data (ensure capacity)
  1922. //
  1923. // TODO: change the maxes to the amount from the bsp!!
  1924. //
  1925. // g_Patches.EnsureCapacity( MAX_PATCHES );
  1926. g_FacePatches.SetSize( MAX_MAP_FACES );
  1927. faceParents.SetSize( MAX_MAP_FACES );
  1928. clusterChildren.SetSize( MAX_MAP_CLUSTERS );
  1929. int ndx;
  1930. for ( ndx = 0; ndx < MAX_MAP_FACES; ndx++ )
  1931. {
  1932. g_FacePatches[ndx] = g_FacePatches.InvalidIndex();
  1933. faceParents[ndx] = faceParents.InvalidIndex();
  1934. }
  1935. for ( ndx = 0; ndx < MAX_MAP_CLUSTERS; ndx++ )
  1936. {
  1937. clusterChildren[ndx] = clusterChildren.InvalidIndex();
  1938. }
  1939. // Setup ray tracer
  1940. AddBrushesForRayTrace();
  1941. StaticDispMgr()->AddPolysForRayTrace();
  1942. StaticPropMgr()->AddPolysForRayTrace();
  1943. // Dump raytracer for glview
  1944. if ( g_bDumpRtEnv )
  1945. WriteRTEnv("trace.txt");
  1946. // Build acceleration structure
  1947. printf ( "Setting up ray-trace acceleration structure... ");
  1948. float start = Plat_FloatTime();
  1949. g_RtEnv.SetupAccelerationStructure();
  1950. g_RtEnv_LightBlockers.SetupAccelerationStructure();
  1951. float end = Plat_FloatTime();
  1952. printf ( "Done (%.2f seconds)\n", end-start );
  1953. #if 0 // To test only k-d build
  1954. exit(0);
  1955. #endif
  1956. RadWorld_Start();
  1957. // Setup incremental lighting.
  1958. if( g_pIncremental )
  1959. {
  1960. if( !g_pIncremental->Init( source, incrementfile ) )
  1961. {
  1962. Error( "Unable to load incremental lighting file in %s.\n", incrementfile );
  1963. return;
  1964. }
  1965. }
  1966. }
  1967. void VRAD_ComputeOtherLighting()
  1968. {
  1969. // Compute lighting for the bsp file
  1970. if ( !g_bNoDetailLighting )
  1971. {
  1972. ComputeDetailPropLighting( THREADINDEX_MAIN );
  1973. }
  1974. ComputePerLeafAmbientLighting();
  1975. // bake the static props high quality vertex lighting into the bsp
  1976. if ( !do_fast && g_bStaticPropLighting )
  1977. {
  1978. StaticPropMgr()->ComputeLighting( THREADINDEX_MAIN );
  1979. }
  1980. }
  1981. extern void CloseDispLuxels();
  1982. void VRAD_Finish()
  1983. {
  1984. Msg( "Ready to Finish\n" );
  1985. fflush( stdout );
  1986. if ( verbose )
  1987. {
  1988. PrintBSPFileSizes();
  1989. }
  1990. Msg( "Writing %s\n", platformPath );
  1991. VMPI_SetCurrentStage( "WriteBSPFile" );
  1992. WriteBSPFile(platformPath);
  1993. if ( g_bDumpPatches )
  1994. {
  1995. for ( int iStyle = 0; iStyle < 4; ++iStyle )
  1996. {
  1997. for ( int iBump = 0; iBump < 4; ++iBump )
  1998. {
  1999. g_pFileSystem->Close( pFileSamples[iStyle][iBump] );
  2000. }
  2001. }
  2002. }
  2003. CloseDispLuxels();
  2004. StaticPropMgr()->Shutdown();
  2005. double end = Plat_FloatTime();
  2006. char str[512];
  2007. GetHourMinuteSecondsString( (int)( end - g_flStartTime ), str, sizeof( str ) );
  2008. Msg( "%s elapsed\n", str );
  2009. ReleasePakFileLumps();
  2010. }
  2011. // Run startup code like initialize mathlib (called from main() and from the
  2012. // WorldCraft interface into vrad).
  2013. void VRAD_Init()
  2014. {
  2015. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  2016. InstallAllocationFunctions();
  2017. InstallSpewFunction();
  2018. }
  2019. int ParseCommandLine( int argc, char **argv, bool *onlydetail )
  2020. {
  2021. *onlydetail = false;
  2022. // default to LDR
  2023. SetHDRMode( false );
  2024. int i;
  2025. for( i=1 ; i<argc ; i++ )
  2026. {
  2027. if ( !Q_stricmp( argv[i], "-StaticPropLighting" ) ) // use -final for higher quality
  2028. {
  2029. g_bStaticPropLighting = true;
  2030. extern int g_numVradStaticPropsLightingStreams;
  2031. g_numVradStaticPropsLightingStreams = 3;
  2032. }
  2033. else if ( !Q_stricmp( argv[i], "-StaticPropLightingFinal" ) ) // slower, higher quality - deprecated, remove soon
  2034. {
  2035. g_bStaticPropLighting = true;
  2036. extern int g_numVradStaticPropsLightingStreams;
  2037. g_numVradStaticPropsLightingStreams = 3;
  2038. }
  2039. else if ( !Q_stricmp( argv[i], "-StaticPropLighting3" ) ) // dump bump data - deprecated, remove soon
  2040. {
  2041. g_bStaticPropLighting = true;
  2042. extern int g_numVradStaticPropsLightingStreams;
  2043. g_numVradStaticPropsLightingStreams = 3;
  2044. g_bDumpBumpStaticProps = true;
  2045. }
  2046. else if ( !stricmp( argv[i], "-StaticPropNormals" ) )
  2047. {
  2048. g_bShowStaticPropNormals = true;
  2049. }
  2050. else if ( !stricmp( argv[i], "-OnlyStaticProps" ) )
  2051. {
  2052. g_bOnlyStaticProps = true;
  2053. }
  2054. else if ( !Q_stricmp( argv[i], "-StaticPropPolys" ) )
  2055. {
  2056. g_bStaticPropPolys = true;
  2057. }
  2058. else if ( !Q_stricmp( argv[i], "-nossprops" ) )
  2059. {
  2060. g_bDisablePropSelfShadowing = true;
  2061. }
  2062. else if ( !stricmp( argv[i], "-StaticPropDisableInSolidTest" ) )
  2063. {
  2064. g_bDisableStaticPropVertexInSolidTest = true;
  2065. }
  2066. else if ( !Q_stricmp( argv[i], "-textureshadows" ) )
  2067. {
  2068. g_bTextureShadows = true;
  2069. }
  2070. else if ( !strcmp( argv[i], "-dump" ) )
  2071. {
  2072. g_bDumpPatches = true;
  2073. }
  2074. else if ( !Q_stricmp( argv[i], "-nodetaillight" ) )
  2075. {
  2076. g_bNoDetailLighting = true;
  2077. }
  2078. else if ( !Q_stricmp( argv[i], "-rederrors" ) )
  2079. {
  2080. bRed2Black = false;
  2081. }
  2082. else if ( !Q_stricmp( argv[i], "-dumpnormals" ) )
  2083. {
  2084. bDumpNormals = true;
  2085. }
  2086. else if ( !Q_stricmp( argv[i], "-dumptrace" ) )
  2087. {
  2088. g_bDumpRtEnv = true;
  2089. }
  2090. else if ( !Q_stricmp( argv[i], "-LargeDispSampleRadius" ) )
  2091. {
  2092. g_bLargeDispSampleRadius = true;
  2093. }
  2094. else if (!Q_stricmp(argv[i],"-bounce"))
  2095. {
  2096. if ( ++i < argc )
  2097. {
  2098. numbounce = atoi (argv[i]);
  2099. if ( numbounce < 0 )
  2100. {
  2101. Warning("Error: expected non-negative value after '-bounce'\n" );
  2102. return 1;
  2103. }
  2104. }
  2105. else
  2106. {
  2107. Warning("Error: expected a value after '-bounce'\n" );
  2108. return 1;
  2109. }
  2110. }
  2111. else if (!Q_stricmp(argv[i],"-verbose") || !Q_stricmp(argv[i],"-v"))
  2112. {
  2113. verbose = true;
  2114. }
  2115. else if (!Q_stricmp(argv[i],"-threads"))
  2116. {
  2117. if ( ++i < argc )
  2118. {
  2119. numthreads = atoi (argv[i]);
  2120. if ( numthreads <= 0 )
  2121. {
  2122. Warning("Error: expected positive value after '-threads'\n" );
  2123. return 1;
  2124. }
  2125. }
  2126. else
  2127. {
  2128. Warning("Error: expected a value after '-threads'\n" );
  2129. return 1;
  2130. }
  2131. }
  2132. else if ( !Q_stricmp(argv[i], "-lights" ) )
  2133. {
  2134. if ( ++i < argc && *argv[i] )
  2135. {
  2136. strcpy( designer_lights, argv[i] );
  2137. }
  2138. else
  2139. {
  2140. Warning("Error: expected a filepath after '-lights'\n" );
  2141. return 1;
  2142. }
  2143. }
  2144. else if (!Q_stricmp(argv[i],"-noextra"))
  2145. {
  2146. do_extra = false;
  2147. }
  2148. else if (!Q_stricmp(argv[i],"-debugextra"))
  2149. {
  2150. debug_extra = true;
  2151. }
  2152. else if ( !Q_stricmp(argv[i], "-fastambient") )
  2153. {
  2154. g_bFastAmbient = true;
  2155. }
  2156. else if (!Q_stricmp(argv[i],"-fast"))
  2157. {
  2158. do_fast = true;
  2159. g_bFastStaticProps = true;
  2160. }
  2161. else if (!Q_stricmp(argv[i],"-noskyboxrecurse"))
  2162. {
  2163. g_bNoSkyRecurse = true;
  2164. }
  2165. else if (!Q_stricmp(argv[i],"-final"))
  2166. {
  2167. g_flSkySampleScale = 16.0;
  2168. g_flStaticPropSampleScale = 16.0;
  2169. }
  2170. else if (!Q_stricmp( argv[i], "-finitefalloff" ) )
  2171. {
  2172. g_bFiniteFalloffModel = true;
  2173. }
  2174. else if (!Q_stricmp(argv[i],"-extrasky"))
  2175. {
  2176. if ( ++i < argc && *argv[i] )
  2177. {
  2178. g_flSkySampleScale = atof( argv[i] );
  2179. }
  2180. else
  2181. {
  2182. Warning("Error: expected a scale factor after '-extrasky'\n" );
  2183. return 1;
  2184. }
  2185. }
  2186. else if ( !Q_stricmp( argv[i], "-staticpropsamplescale" ) )
  2187. {
  2188. if ( ++i < argc && *argv[i] )
  2189. {
  2190. g_flStaticPropSampleScale = atof( argv[i] );
  2191. }
  2192. else
  2193. {
  2194. Warning( "Error: expected a scale factor after '-extraskystaticprops'\n" );
  2195. return 1;
  2196. }
  2197. }
  2198. else if (!Q_stricmp(argv[i],"-centersamples"))
  2199. {
  2200. do_centersamples = true;
  2201. }
  2202. else if (!Q_stricmp(argv[i],"-smooth"))
  2203. {
  2204. if ( ++i < argc )
  2205. {
  2206. smoothing_threshold = (float)cos(atof(argv[i])*(M_PI/180.0));
  2207. }
  2208. else
  2209. {
  2210. Warning("Error: expected an angle after '-smooth'\n" );
  2211. return 1;
  2212. }
  2213. }
  2214. else if (!Q_stricmp(argv[i],"-dlightmap"))
  2215. {
  2216. dlight_map = 1;
  2217. }
  2218. else if (!Q_stricmp(argv[i],"-luxeldensity"))
  2219. {
  2220. if ( ++i < argc )
  2221. {
  2222. luxeldensity = (float)atof (argv[i]);
  2223. if (luxeldensity > 1.0)
  2224. luxeldensity = 1.0 / luxeldensity;
  2225. }
  2226. else
  2227. {
  2228. Warning("Error: expected a value after '-luxeldensity'\n" );
  2229. return 1;
  2230. }
  2231. }
  2232. else if( !Q_stricmp( argv[i], "-low" ) )
  2233. {
  2234. g_bLowPriority = true;
  2235. }
  2236. else if( !Q_stricmp( argv[i], "-loghash" ) )
  2237. {
  2238. g_bLogHashData = true;
  2239. }
  2240. else if( !Q_stricmp( argv[i], "-onlydetail" ) )
  2241. {
  2242. *onlydetail = true;
  2243. }
  2244. else if (!Q_stricmp(argv[i],"-softsun"))
  2245. {
  2246. if ( ++i < argc )
  2247. {
  2248. g_SunAngularExtent=atof(argv[i]);
  2249. g_SunAngularExtent=sin((M_PI/180.0)*g_SunAngularExtent);
  2250. printf("sun extent=%f\n",g_SunAngularExtent);
  2251. }
  2252. else
  2253. {
  2254. Warning("Error: expected an angular extent value (0..180) '-softsun'\n" );
  2255. return 1;
  2256. }
  2257. }
  2258. else if ( !Q_stricmp( argv[i], "-maxdispsamplesize" ) )
  2259. {
  2260. if ( ++i < argc )
  2261. {
  2262. g_flMaxDispSampleSize = ( float )atof( argv[i] );
  2263. }
  2264. else
  2265. {
  2266. Warning( "Error: expected a sample size after '-maxdispsamplesize'\n" );
  2267. return 1;
  2268. }
  2269. }
  2270. else if ( stricmp( argv[i], "-StopOnExit" ) == 0 )
  2271. {
  2272. g_bStopOnExit = true;
  2273. }
  2274. else if ( stricmp( argv[i], "-steam" ) == 0 )
  2275. {
  2276. }
  2277. else if ( stricmp( argv[i], "-allowdebug" ) == 0 )
  2278. {
  2279. // Don't need to do anything, just don't error out.
  2280. }
  2281. else if ( !Q_stricmp( argv[i], CMDLINEOPTION_NOVCONFIG ) )
  2282. {
  2283. }
  2284. else if ( !Q_stricmp( argv[i], "-vproject" ) || !Q_stricmp( argv[i], "-game" ) )
  2285. {
  2286. ++i;
  2287. }
  2288. else if ( !Q_stricmp( argv[i], "-FullMinidumps" ) )
  2289. {
  2290. EnableFullMinidumps( true );
  2291. }
  2292. else if ( !Q_stricmp( argv[i], "-hdr" ) )
  2293. {
  2294. SetHDRMode( true );
  2295. }
  2296. else if ( !Q_stricmp( argv[i], "-ldr" ) )
  2297. {
  2298. SetHDRMode( false );
  2299. }
  2300. else if (!Q_stricmp(argv[i],"-maxchop"))
  2301. {
  2302. if ( ++i < argc )
  2303. {
  2304. maxchop = (float)atof (argv[i]);
  2305. if ( maxchop < 1 )
  2306. {
  2307. Warning("Error: expected positive value after '-maxchop'\n" );
  2308. return 1;
  2309. }
  2310. }
  2311. else
  2312. {
  2313. Warning("Error: expected a value after '-maxchop'\n" );
  2314. return 1;
  2315. }
  2316. }
  2317. else if (!Q_stricmp(argv[i],"-chop"))
  2318. {
  2319. if ( ++i < argc )
  2320. {
  2321. minchop = (float)atof (argv[i]);
  2322. if ( minchop < 1 )
  2323. {
  2324. Warning("Error: expected positive value after '-chop'\n" );
  2325. return 1;
  2326. }
  2327. minchop = min( minchop, maxchop );
  2328. }
  2329. else
  2330. {
  2331. Warning("Error: expected a value after '-chop'\n" );
  2332. return 1;
  2333. }
  2334. }
  2335. else if ( !Q_stricmp( argv[i], "-dispchop" ) )
  2336. {
  2337. if ( ++i < argc )
  2338. {
  2339. dispchop = ( float )atof( argv[i] );
  2340. if ( dispchop < 1.0f )
  2341. {
  2342. Warning( "Error: expected positive value after '-dipschop'\n" );
  2343. return 1;
  2344. }
  2345. }
  2346. else
  2347. {
  2348. Warning( "Error: expected a value after '-dispchop'\n" );
  2349. return 1;
  2350. }
  2351. }
  2352. else if ( !Q_stricmp( argv[i], "-disppatchradius" ) )
  2353. {
  2354. if ( ++i < argc )
  2355. {
  2356. g_MaxDispPatchRadius = ( float )atof( argv[i] );
  2357. if ( g_MaxDispPatchRadius < 10.0f )
  2358. {
  2359. Warning( "Error: g_MaxDispPatchRadius < 10.0\n" );
  2360. return 1;
  2361. }
  2362. }
  2363. else
  2364. {
  2365. Warning( "Error: expected a value after '-disppatchradius'\n" );
  2366. return 1;
  2367. }
  2368. }
  2369. else if ( !Q_stricmp( argv[i], "-reflectivityscale" ) )
  2370. {
  2371. if ( ++i < argc )
  2372. {
  2373. reflectivityScale = (float)atof (argv[i]);
  2374. }
  2375. else
  2376. {
  2377. Warning("Error: expected a value after '-reflectivityscale'\n" );
  2378. return 1;
  2379. }
  2380. }
  2381. else if ( !Q_stricmp( argv[i],"-ambient" ) )
  2382. {
  2383. if ( i+3 < argc )
  2384. {
  2385. ambient[0] = (float)atof (argv[++i]) * 128;
  2386. ambient[1] = (float)atof (argv[++i]) * 128;
  2387. ambient[2] = (float)atof (argv[++i]) * 128;
  2388. }
  2389. else
  2390. {
  2391. Warning("Error: expected three color values after '-ambient'\n" );
  2392. return 1;
  2393. }
  2394. }
  2395. else if ( !Q_stricmp( argv[ i ], "-StaticPropBounce" ) )
  2396. {
  2397. if ( i + 1 < argc )
  2398. {
  2399. g_flStaticPropBounceBoost = (float)atof( argv[ ++i ] );
  2400. }
  2401. else
  2402. {
  2403. Warning("Error: expected bounce scale after '-StaticPropBounce'\n" );
  2404. return 1;
  2405. }
  2406. g_bStaticPropBounce = true;
  2407. }
  2408. #if ALLOWDEBUGOPTIONS
  2409. else if (!Q_stricmp(argv[i],"-scale"))
  2410. {
  2411. if ( ++i < argc )
  2412. {
  2413. lightscale = (float)atof (argv[i]);
  2414. }
  2415. else
  2416. {
  2417. Warning("Error: expected a value after '-scale'\n" );
  2418. return 1;
  2419. }
  2420. }
  2421. else if (!Q_stricmp(argv[i],"-dlight"))
  2422. {
  2423. if ( ++i < argc )
  2424. {
  2425. dlight_threshold = (float)atof (argv[i]);
  2426. }
  2427. else
  2428. {
  2429. Warning("Error: expected a value after '-dlight'\n" );
  2430. return 1;
  2431. }
  2432. }
  2433. else if (!Q_stricmp(argv[i],"-sky"))
  2434. {
  2435. if ( ++i < argc )
  2436. {
  2437. indirect_sun = (float)atof (argv[i]);
  2438. }
  2439. else
  2440. {
  2441. Warning("Error: expected a value after '-sky'\n" );
  2442. return 1;
  2443. }
  2444. }
  2445. else if (!Q_stricmp(argv[i],"-notexscale"))
  2446. {
  2447. texscale = false;
  2448. }
  2449. else if (!Q_stricmp(argv[i],"-coring"))
  2450. {
  2451. if ( ++i < argc )
  2452. {
  2453. coring = (float)atof( argv[i] );
  2454. }
  2455. else
  2456. {
  2457. Warning("Error: expected a light threshold after '-coring'\n" );
  2458. return 1;
  2459. }
  2460. }
  2461. #endif
  2462. else if ( !Q_stricmp( argv[i], "-tempcontent" ) )
  2463. {
  2464. // ... Do nothing, just let this pass to the filesystem
  2465. }
  2466. // NOTE: the -mpi checks must come last here because they allow the previous argument
  2467. // to be -mpi as well. If it game before something else like -game, then if the previous
  2468. // argument was -mpi and the current argument was something valid like -game, it would skip it.
  2469. else if ( !Q_strncasecmp( argv[i], "-mpi", 4 ) || !Q_strncasecmp( argv[i-1], "-mpi", 4 ) )
  2470. {
  2471. if ( stricmp( argv[i], "-mpi" ) == 0 )
  2472. g_bUseMPI = true;
  2473. // Any other args that start with -mpi are ok too.
  2474. if ( i == argc - 1 && V_stricmp( argv[i], "-mpi_ListParams" ) != 0 )
  2475. break;
  2476. }
  2477. else if ( !Q_stricmp( argv[i], "-processheap" ) )
  2478. {
  2479. // ... Do nothing, just let this pass to the mem system
  2480. }
  2481. else
  2482. {
  2483. break;
  2484. }
  2485. }
  2486. return i;
  2487. }
  2488. void PrintCommandLine( int argc, char **argv )
  2489. {
  2490. Warning( "Command line: " );
  2491. for ( int z=0; z < argc; z++ )
  2492. {
  2493. Warning( "\"%s\" ", argv[z] );
  2494. }
  2495. Warning( "\n\n" );
  2496. }
  2497. void PrintUsage( int argc, char **argv )
  2498. {
  2499. PrintCommandLine( argc, argv );
  2500. Warning(
  2501. "usage : vrad [options...] bspfile\n"
  2502. "example: vrad c:\\hl2\\hl2\\maps\\test\n"
  2503. "\n"
  2504. "Common options:\n"
  2505. "\n"
  2506. " -v (or -verbose): Turn on verbose output (also shows more command\n"
  2507. " -bounce # : Set max number of bounces (default: 100).\n"
  2508. " -fast : Quick and dirty lighting.\n"
  2509. " -fastambient : Per-leaf ambient sampling is lower quality to save compute time.\n"
  2510. " -final : High quality processing. equivalent to -extrasky 16.\n"
  2511. " -finitefalloff : use an alternative falloff model that falls off to exactly zero at the zero_percent_distance.\n"
  2512. " -extrasky n : trace N times as many rays for indirect light and sky ambient.\n"
  2513. " -low : Run as an idle-priority process.\n"
  2514. " -mpi : Use VMPI to distribute computations.\n"
  2515. " -rederror : Show errors in red.\n"
  2516. "\n"
  2517. " -vproject <directory> : Override the VPROJECT environment variable.\n"
  2518. " -game <directory> : Same as -vproject.\n"
  2519. "\n"
  2520. "Other options:\n"
  2521. " -novconfig : Don't bring up graphical UI on vproject errors.\n"
  2522. " -dump : Write debugging .txt files.\n"
  2523. " -dumpnormals : Write normals to debug files.\n"
  2524. " -dumptrace : Write ray-tracing environment to debug files.\n"
  2525. " -threads : Control the number of threads vbsp uses (defaults to the #\n"
  2526. " or processors on your machine).\n"
  2527. " -lights <file> : Load a lights file in addition to lights.rad and the\n"
  2528. " level lights file.\n"
  2529. " -noextra : Disable supersampling.\n"
  2530. " -debugextra : Places debugging data in lightmaps to visualize\n"
  2531. " supersampling.\n"
  2532. " -smooth # : Set the threshold for smoothing groups, in degrees\n"
  2533. " (default 45).\n"
  2534. );
  2535. Warning(
  2536. " -dlightmap : Force direct lighting into different lightmap than\n"
  2537. " radiosity.\n"
  2538. " -stoponexit : Wait for a keypress on exit.\n"
  2539. " -mpi_pw <pw> : Use a password to choose a specific set of VMPI workers.\n"
  2540. " -nodetaillight : Don't light detail props.\n"
  2541. " -centersamples : Move sample centers.\n"
  2542. " -luxeldensity # : Rescale all luxels by the specified amount (default: 1.0).\n"
  2543. " The number specified must be less than 1.0 or it will be\n"
  2544. " ignored.\n"
  2545. " -loghash : Log the sample hash table to samplehash.txt.\n"
  2546. " -onlydetail : Only light detail props and per-leaf lighting.\n"
  2547. " -maxdispsamplesize #: Set max displacement sample size (default: 512).\n"
  2548. " -softsun <n> : Treat the sun as an area light source of size <n> degrees."
  2549. " Produces soft shadows.\n"
  2550. " Recommended values are between 0 and 5. Default is 0.\n"
  2551. " -FullMinidumps : Write large minidumps on crash.\n"
  2552. " -chop : Smallest number of luxel widths for a bounce patch, used on edges\n"
  2553. " -maxchop : Coarsest allowed number of luxel widths for a patch, used in face interiors\n"
  2554. " -LargeDispSampleRadius: This can be used if there are splotches of bounced\n"
  2555. " light on terrain. The compile will take longer, but\n"
  2556. " it will gather light across a wider area.\n"
  2557. " -StaticPropLighting : generate baked static prop vertex lighting\n"
  2558. " -StaticPropLightingFinal : generate baked static prop vertex lighting (uses higher/final quality processing)\n"
  2559. " -StaticPropPolys : Perform shadow tests of static props at polygon precision\n"
  2560. " -OnlyStaticProps : Only perform direct static prop lighting (vrad debug option)\n"
  2561. " -StaticPropNormals : when lighting static props, just show their normal vector\n"
  2562. " -StaticPropBounce : Enable static props to bounce light. Experimental option, doesn't work with VMPI right now.\n"
  2563. " -textureshadows : Allows texture alpha channels to block light - rays intersecting alpha surfaces will sample the texture\n"
  2564. " -noskyboxrecurse : Turn off recursion into 3d skybox (skybox shadows on world)\n"
  2565. " -nossprops : Globally disable self-shadowing on static props\n"
  2566. "\n"
  2567. #if 1 // Disabled for the initial SDK release with VMPI so we can get feedback from selected users.
  2568. );
  2569. #else
  2570. " -mpi_ListParams : Show a list of VMPI parameters.\n"
  2571. "\n"
  2572. );
  2573. // Show VMPI parameters?
  2574. for ( int i=1; i < argc; i++ )
  2575. {
  2576. if ( V_stricmp( argv[i], "-mpi_ListParams" ) == 0 )
  2577. {
  2578. Warning( "VMPI-specific options:\n\n" );
  2579. bool bIsSDKMode = VMPI_IsSDKMode();
  2580. for ( int i=k_eVMPICmdLineParam_FirstParam+1; i < k_eVMPICmdLineParam_LastParam; i++ )
  2581. {
  2582. if ( (VMPI_GetParamFlags( (EVMPICmdLineParam)i ) & VMPI_PARAM_SDK_HIDDEN) && bIsSDKMode )
  2583. continue;
  2584. Warning( "[%s]\n", VMPI_GetParamString( (EVMPICmdLineParam)i ) );
  2585. Warning( VMPI_GetParamHelpString( (EVMPICmdLineParam)i ) );
  2586. Warning( "\n\n" );
  2587. }
  2588. break;
  2589. }
  2590. }
  2591. #endif
  2592. }
  2593. int RunVRAD( int argc, char **argv )
  2594. {
  2595. #if defined(_MSC_VER) && ( _MSC_VER >= 1310 )
  2596. Msg("Valve Software - vrad.exe SSE (" __DATE__ ")\n" );
  2597. #else
  2598. Msg("Valve Software - vrad.exe (" __DATE__ ")\n" );
  2599. #endif
  2600. Msg("\n Valve Radiosity Simulator \n");
  2601. verbose = true; // Originally FALSE
  2602. bool onlydetail;
  2603. int i = ParseCommandLine( argc, argv, &onlydetail );
  2604. if (i != argc - 1)
  2605. {
  2606. PrintUsage( argc, argv );
  2607. DeleteCmdLine( argc, argv );
  2608. Plat_ExitProcess( 0 );
  2609. }
  2610. VRAD_LoadBSP( argv[i] );
  2611. if ( (! onlydetail) && (! g_bOnlyStaticProps ) )
  2612. {
  2613. RadWorld_Go();
  2614. }
  2615. VRAD_ComputeOtherLighting();
  2616. VRAD_Finish();
  2617. VMPI_SetCurrentStage( "master done" );
  2618. DeleteCmdLine( argc, argv );
  2619. CmdLib_Cleanup();
  2620. return 0;
  2621. }
  2622. int VRAD_Main(int argc, char **argv)
  2623. {
  2624. g_pFileSystem = NULL; // Safeguard against using it before it's properly initialized.
  2625. VRAD_Init();
  2626. // This must come first.
  2627. VRAD_SetupMPI( argc, argv );
  2628. // Initialize the filesystem, so additional commandline options can be loaded
  2629. Q_StripExtension( argv[ argc - 1 ], source, sizeof( source ) );
  2630. CmdLib_InitFileSystem( argv[ argc - 1 ] );
  2631. Q_FileBase( source, source, sizeof( source ) );
  2632. #if !defined( _DEBUG )
  2633. if ( g_bUseMPI && !g_bMPIMaster )
  2634. {
  2635. SetupToolsMinidumpHandler( VMPI_ExceptionFilter );
  2636. }
  2637. else
  2638. #endif
  2639. {
  2640. LoadCmdLineFromFile( argc, argv, source, "vrad" ); // Don't do this if we're a VMPI worker..
  2641. SetupDefaultToolsMinidumpHandler();
  2642. }
  2643. return RunVRAD( argc, argv );
  2644. }