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.

1389 lines
42 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //
  8. // This file contains code to allow us to associate client data with bsp leaves.
  9. //
  10. //=============================================================================//
  11. #include "vrad.h"
  12. #include "Bsplib.h"
  13. #include "GameBSPFile.h"
  14. #include "UtlBuffer.h"
  15. #include "UtlVector.h"
  16. #include "CModel.h"
  17. #include "studio.h"
  18. #include "pacifier.h"
  19. #include "vraddetailprops.h"
  20. #include "mathlib/halton.h"
  21. #include "messbuf.h"
  22. #include "byteswap.h"
  23. bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf );
  24. //-----------------------------------------------------------------------------
  25. //-----------------------------------------------------------------------------
  26. extern float SoftenCosineTerm( float flDot );
  27. extern float CalculateAmbientOcclusion( Vector *pPosition, Vector *pNormal );
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Writes a glview text file containing the collision surface in question
  30. // Input : *pCollide -
  31. // *pFilename -
  32. //-----------------------------------------------------------------------------
  33. void DumpRayToGlView( Ray_t const& ray, float dist, Vector* pColor, const char *pFilename )
  34. {
  35. Vector dir = ray.m_Delta;
  36. float len = VectorNormalize(dir);
  37. if (len < 1e-3)
  38. return;
  39. Vector up( 0, 0, 1 );
  40. Vector crossDir;
  41. if (fabs(DotProduct(up, dir)) - 1.0f < -1e-3 )
  42. {
  43. CrossProduct( dir, up, crossDir );
  44. VectorNormalize(crossDir);
  45. }
  46. else
  47. {
  48. up.Init( 0, 1, 0 );
  49. CrossProduct( dir, up, crossDir );
  50. VectorNormalize(crossDir);
  51. }
  52. Vector end;
  53. Vector start1, start2;
  54. VectorMA( ray.m_Start, dist, ray.m_Delta, end );
  55. VectorMA( ray.m_Start, -2, crossDir, start1 );
  56. VectorMA( ray.m_Start, 2, crossDir, start2 );
  57. FileHandle_t fp = g_pFileSystem->Open( pFilename, "a" );
  58. int vert = 0;
  59. CmdLib_FPrintf( fp, "3\n" );
  60. CmdLib_FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", start1.x, start1.y, start1.z,
  61. pColor->x, pColor->y, pColor->z );
  62. vert++;
  63. CmdLib_FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", start2.x, start2.y, start2.z,
  64. pColor->x, pColor->y, pColor->z );
  65. vert++;
  66. CmdLib_FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", end.x, end.y, end.z,
  67. pColor->x, pColor->y, pColor->z );
  68. vert++;
  69. g_pFileSystem->Close( fp );
  70. }
  71. //-----------------------------------------------------------------------------
  72. // This puppy is used to construct the game lumps
  73. //-----------------------------------------------------------------------------
  74. static CUtlVector<DetailPropLightstylesLump_t> s_DetailPropLightStyleLumpLDR;
  75. static CUtlVector<DetailPropLightstylesLump_t> s_DetailPropLightStyleLumpHDR;
  76. static CUtlVector<DetailPropLightstylesLump_t> *s_pDetailPropLightStyleLump = &s_DetailPropLightStyleLumpLDR;
  77. //-----------------------------------------------------------------------------
  78. // An amount to add to each model to get to the model center
  79. //-----------------------------------------------------------------------------
  80. CUtlVector<Vector> g_ModelCenterOffset;
  81. CUtlVector<Vector> g_SpriteCenterOffset;
  82. void VRadDetailProps_SetHDRMode( bool bHDR )
  83. {
  84. if( bHDR )
  85. {
  86. s_pDetailPropLightStyleLump = &s_DetailPropLightStyleLumpHDR;
  87. }
  88. else
  89. {
  90. s_pDetailPropLightStyleLump = &s_DetailPropLightStyleLumpLDR;
  91. }
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Finds ambient sky lights
  95. //-----------------------------------------------------------------------------
  96. static directlight_t* FindAmbientSkyLight()
  97. {
  98. static directlight_t *s_pCachedSkylight = NULL;
  99. // Don't keep searching for the same light.
  100. if ( !s_pCachedSkylight )
  101. {
  102. // find any ambient lights
  103. directlight_t* dl;
  104. for (dl = activelights; dl != 0; dl = dl->next)
  105. {
  106. if (dl->light.type == emit_skyambient)
  107. {
  108. s_pCachedSkylight = dl;
  109. break;
  110. }
  111. }
  112. }
  113. return s_pCachedSkylight;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Compute world center of a prop
  117. //-----------------------------------------------------------------------------
  118. static void ComputeWorldCenter( DetailObjectLump_t& prop, Vector& center, Vector& normal )
  119. {
  120. // Transform the offset into world space
  121. Vector forward, right;
  122. AngleVectors( prop.m_Angles, &forward, &right, &normal );
  123. VectorCopy( prop.m_Origin, center );
  124. // FIXME: Take orientation into account?
  125. switch (prop.m_Type )
  126. {
  127. case DETAIL_PROP_TYPE_MODEL:
  128. VectorMA( center, g_ModelCenterOffset[prop.m_DetailModel].x, forward, center );
  129. VectorMA( center, -g_ModelCenterOffset[prop.m_DetailModel].y, right, center );
  130. VectorMA( center, g_ModelCenterOffset[prop.m_DetailModel].z, normal, center );
  131. break;
  132. case DETAIL_PROP_TYPE_SPRITE:
  133. Vector vecOffset;
  134. VectorMultiply( g_SpriteCenterOffset[prop.m_DetailModel], prop.m_flScale, vecOffset );
  135. VectorMA( center, vecOffset.x, forward, center );
  136. VectorMA( center, -vecOffset.y, right, center );
  137. VectorMA( center, vecOffset.z, normal, center );
  138. break;
  139. }
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Computes max direct lighting for a single detal prop
  143. //-----------------------------------------------------------------------------
  144. static void ComputeMaxDirectLighting( DetailObjectLump_t& prop, Vector* maxcolor, int iThread )
  145. {
  146. // The max direct lighting must be along the direction to one
  147. // of the static lights....
  148. Vector origin, normal;
  149. ComputeWorldCenter( prop, origin, normal );
  150. if ( !origin.IsValid() || !normal.IsValid() )
  151. {
  152. static bool s_Warned = false;
  153. if ( !s_Warned )
  154. {
  155. Warning("WARNING: Bogus detail props encountered!\n" );
  156. s_Warned = true;
  157. }
  158. // fill with debug color
  159. for ( int i = 0; i < MAX_LIGHTSTYLES; ++i)
  160. {
  161. maxcolor[i].Init(1,0,0);
  162. }
  163. return;
  164. }
  165. int cluster = ClusterFromPoint(origin);
  166. Vector delta;
  167. CUtlVector< directlight_t* > lights;
  168. CUtlVector< Vector > directions;
  169. directlight_t* dl;
  170. for (dl = activelights; dl != 0; dl = dl->next)
  171. {
  172. // skyambient doesn't affect dlights..
  173. if (dl->light.type == emit_skyambient)
  174. continue;
  175. // is this lights cluster visible?
  176. if ( PVSCheck( dl->pvs, cluster ) )
  177. {
  178. lights.AddToTail(dl);
  179. VectorSubtract( dl->light.origin, origin, delta );
  180. VectorNormalize( delta );
  181. directions.AddToTail( delta );
  182. }
  183. }
  184. // Find the max illumination
  185. int i;
  186. for ( i = 0; i < MAX_LIGHTSTYLES; ++i)
  187. {
  188. maxcolor[i].Init(0,0,0);
  189. }
  190. // NOTE: See version 10 for a method where we choose a normal based on whichever
  191. // one produces the maximum possible illumination. This appeared to work better on
  192. // e3_town, so I'm trying it now; hopefully it'll be good for all cases.
  193. int j;
  194. for ( j = 0; j < lights.Count(); ++j)
  195. {
  196. dl = lights[j];
  197. SSE_sampleLightOutput_t out;
  198. FourVectors origin4;
  199. FourVectors normal4;
  200. origin4.DuplicateVector( origin );
  201. normal4.DuplicateVector( normal );
  202. GatherSampleLightSSE ( out, dl, -1, origin4, &normal4, 1, iThread, GATHERLFLAGS_STATICPROP );
  203. VectorMA( maxcolor[dl->light.style], out.m_flFalloff.m128_f32[0] * out.m_flDot[0].m128_f32[0], dl->light.intensity, maxcolor[dl->light.style] );
  204. }
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Computes the ambient term from a particular surface
  208. //-----------------------------------------------------------------------------
  209. static void ComputeAmbientFromSurface( dface_t* pFace, directlight_t* pSkylight,
  210. Vector& radcolor )
  211. {
  212. texinfo_t* pTex = &texinfo[pFace->texinfo];
  213. if (pTex)
  214. {
  215. // If we hit the sky, use the sky ambient
  216. if (pTex->flags & SURF_SKY)
  217. {
  218. if (pSkylight)
  219. {
  220. // add in sky ambient
  221. VectorDivide( pSkylight->light.intensity, 255.0f, radcolor );
  222. }
  223. }
  224. else
  225. {
  226. VectorMultiply( radcolor, dtexdata[pTex->texdata].reflectivity, radcolor );
  227. }
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Computes the lightmap color at a particular point
  232. //-----------------------------------------------------------------------------
  233. static void ComputeLightmapColorFromAverage( dface_t* pFace, directlight_t* pSkylight, float scale, Vector pColor[MAX_LIGHTSTYLES] )
  234. {
  235. texinfo_t* pTex = &texinfo[pFace->texinfo];
  236. if (pTex->flags & SURF_SKY)
  237. {
  238. if (pSkylight)
  239. {
  240. // add in sky ambient
  241. Vector amb = pSkylight->light.intensity / 255.0f;
  242. pColor[0] += amb * scale;
  243. }
  244. return;
  245. }
  246. for (int maps = 0 ; maps < MAXLIGHTMAPS && pFace->styles[maps] != 255 ; ++maps)
  247. {
  248. ColorRGBExp32* pAvgColor = dface_AvgLightColor( pFace, maps );
  249. // this code expects values from [0..1] not [0..255]
  250. Vector color;
  251. color[0] = TexLightToLinear( pAvgColor->r, pAvgColor->exponent );
  252. color[1] = TexLightToLinear( pAvgColor->g, pAvgColor->exponent );
  253. color[2] = TexLightToLinear( pAvgColor->b, pAvgColor->exponent );
  254. ComputeAmbientFromSurface( pFace, pSkylight, color );
  255. int style = pFace->styles[maps];
  256. pColor[style] += color * scale;
  257. }
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Returns true if the surface has bumped lightmaps
  261. //-----------------------------------------------------------------------------
  262. static bool SurfHasBumpedLightmaps( dface_t *pSurf )
  263. {
  264. bool hasBumpmap = false;
  265. if( ( texinfo[pSurf->texinfo].flags & SURF_BUMPLIGHT ) &&
  266. ( !( texinfo[pSurf->texinfo].flags & SURF_NOLIGHT ) ) )
  267. {
  268. hasBumpmap = true;
  269. }
  270. return hasBumpmap;
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Computes the lightmap color at a particular point
  274. //-----------------------------------------------------------------------------
  275. static void ComputeLightmapColorPointSample( dface_t* pFace, directlight_t* pSkylight, Vector2D const& luv, float scale, Vector pColor[MAX_LIGHTSTYLES] )
  276. {
  277. // face unaffected by light
  278. if (pFace->lightofs == -1 )
  279. return;
  280. int smax = ( pFace->m_LightmapTextureSizeInLuxels[0] ) + 1;
  281. int tmax = ( pFace->m_LightmapTextureSizeInLuxels[1] ) + 1;
  282. // luv is in the space of the accumulated lightmap page; we need to convert
  283. // it to be in the space of the surface
  284. int ds = clamp( (int)luv.x, 0, smax-1 );
  285. int dt = clamp( (int)luv.y, 0, tmax-1 );
  286. int offset = smax * tmax;
  287. if ( SurfHasBumpedLightmaps( pFace ) )
  288. offset *= ( NUM_BUMP_VECTS + 1 );
  289. ColorRGBExp32* pLightmap = (ColorRGBExp32*)&pdlightdata->Base()[pFace->lightofs];
  290. pLightmap += dt * smax + ds;
  291. for (int maps = 0 ; maps < MAXLIGHTMAPS && pFace->styles[maps] != 255 ; ++maps)
  292. {
  293. int style = pFace->styles[maps];
  294. Vector color;
  295. color[0] = TexLightToLinear( pLightmap->r, pLightmap->exponent );
  296. color[1] = TexLightToLinear( pLightmap->g, pLightmap->exponent );
  297. color[2] = TexLightToLinear( pLightmap->b, pLightmap->exponent );
  298. ComputeAmbientFromSurface( pFace, pSkylight, color );
  299. pColor[style] += color * scale;
  300. pLightmap += offset;
  301. }
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Tests a particular node
  305. //-----------------------------------------------------------------------------
  306. class CLightSurface : public IBSPNodeEnumerator
  307. {
  308. public:
  309. CLightSurface(int iThread) : m_pSurface(0), m_HitFrac(1.0f), m_bHasLuxel(false), m_iThread(iThread) {}
  310. // call back with a node and a context
  311. bool EnumerateNode( int node, Ray_t const& ray, float f, intp context )
  312. {
  313. dface_t* pSkySurface = 0;
  314. // Compute the actual point
  315. Vector pt;
  316. VectorMA( ray.m_Start, f, ray.m_Delta, pt );
  317. dnode_t* pNode = &dnodes[node];
  318. dface_t* pFace = &g_pFaces[pNode->firstface];
  319. for (int i=0 ; i < pNode->numfaces ; ++i, ++pFace)
  320. {
  321. // Don't take into account faces that are int a leaf
  322. if ( !pFace->onNode )
  323. continue;
  324. // Don't test displacement faces
  325. if ( pFace->dispinfo != -1 )
  326. continue;
  327. texinfo_t* pTex = &texinfo[pFace->texinfo];
  328. // Don't immediately return when we hit sky;
  329. // we may actually hit another surface
  330. if (pTex->flags & SURF_SKY)
  331. {
  332. if (TestPointAgainstSkySurface( pt, pFace ))
  333. {
  334. pSkySurface = pFace;
  335. }
  336. continue;
  337. }
  338. if (TestPointAgainstSurface( pt, pFace, pTex ))
  339. {
  340. m_HitFrac = f;
  341. m_pSurface = pFace;
  342. m_bHasLuxel = true;
  343. return false;
  344. }
  345. }
  346. // if we hit a sky surface, return it
  347. m_pSurface = pSkySurface;
  348. return (m_pSurface == 0);
  349. }
  350. // call back with a leaf and a context
  351. virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, intp context )
  352. {
  353. bool hit = false;
  354. dleaf_t* pLeaf = &dleafs[leaf];
  355. for (int i=0 ; i < pLeaf->numleaffaces ; ++i)
  356. {
  357. Assert( pLeaf->firstleafface + i < numleaffaces );
  358. Assert( dleaffaces[pLeaf->firstleafface + i] < numfaces );
  359. dface_t* pFace = &g_pFaces[dleaffaces[pLeaf->firstleafface + i]];
  360. // Don't test displacement faces; we need to check another list
  361. if ( pFace->dispinfo != -1 )
  362. continue;
  363. // Don't take into account faces that are on a node
  364. if ( pFace->onNode )
  365. continue;
  366. // Find intersection point against detail brushes
  367. texinfo_t* pTex = &texinfo[pFace->texinfo];
  368. dplane_t* pPlane = &dplanes[pFace->planenum];
  369. // Backface cull...
  370. if (DotProduct( pPlane->normal, ray.m_Delta ) > 0)
  371. continue;
  372. float startDotN = DotProduct( ray.m_Start, pPlane->normal );
  373. float deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
  374. float front = startDotN + start * deltaDotN - pPlane->dist;
  375. float back = startDotN + end * deltaDotN - pPlane->dist;
  376. int side = front < 0;
  377. // Blow it off if it doesn't split the plane...
  378. if ( (back < 0) == side )
  379. continue;
  380. // Don't test a surface that is farther away from the closest found intersection
  381. float f = front / (front-back);
  382. float mid = start * (1.0f - f) + end * f;
  383. if (mid >= m_HitFrac)
  384. continue;
  385. Vector pt;
  386. VectorMA( ray.m_Start, mid, ray.m_Delta, pt );
  387. if (TestPointAgainstSurface( pt, pFace, pTex ))
  388. {
  389. m_HitFrac = mid;
  390. m_pSurface = pFace;
  391. hit = true;
  392. m_bHasLuxel = true;
  393. }
  394. }
  395. // Now try to clip against all displacements in the leaf
  396. float dist;
  397. Vector2D luxelCoord;
  398. dface_t *pDispFace;
  399. StaticDispMgr()->ClipRayToDispInLeaf( s_DispTested[m_iThread], ray, leaf, dist, pDispFace, luxelCoord );
  400. if (dist < m_HitFrac)
  401. {
  402. m_HitFrac = dist;
  403. m_pSurface = pDispFace;
  404. Vector2DCopy( luxelCoord, m_LuxelCoord );
  405. hit = true;
  406. m_bHasLuxel = true;
  407. }
  408. return !hit;
  409. }
  410. bool FindIntersection( Ray_t const& ray )
  411. {
  412. StaticDispMgr()->StartRayTest( s_DispTested[m_iThread] );
  413. return !EnumerateNodesAlongRay( ray, this, 0 );
  414. }
  415. private:
  416. bool TestPointAgainstSurface( Vector const& pt, dface_t* pFace, texinfo_t* pTex )
  417. {
  418. // no lightmaps on this surface? punt...
  419. // FIXME: should be water surface?
  420. if (pTex->flags & SURF_NOLIGHT)
  421. return false;
  422. // See where in lightmap space our intersection point is
  423. float s, t;
  424. s = DotProduct (pt.Base(), pTex->lightmapVecsLuxelsPerWorldUnits[0]) +
  425. pTex->lightmapVecsLuxelsPerWorldUnits[0][3];
  426. t = DotProduct (pt.Base(), pTex->lightmapVecsLuxelsPerWorldUnits[1]) +
  427. pTex->lightmapVecsLuxelsPerWorldUnits[1][3];
  428. // Not in the bounds of our lightmap? punt...
  429. if( s < pFace->m_LightmapTextureMinsInLuxels[0] || t < pFace->m_LightmapTextureMinsInLuxels[1] )
  430. return false;
  431. // assuming a square lightmap (FIXME: which ain't always the case),
  432. // lets see if it lies in that rectangle. If not, punt...
  433. float ds = s - pFace->m_LightmapTextureMinsInLuxels[0];
  434. float dt = t - pFace->m_LightmapTextureMinsInLuxels[1];
  435. if( ds > pFace->m_LightmapTextureSizeInLuxels[0] || dt > pFace->m_LightmapTextureSizeInLuxels[1] )
  436. return false;
  437. m_LuxelCoord.x = ds;
  438. m_LuxelCoord.y = dt;
  439. return true;
  440. }
  441. bool TestPointAgainstSkySurface( Vector const &pt, dface_t *pFace )
  442. {
  443. // Create sky face winding.
  444. winding_t *pWinding = WindingFromFace( pFace, Vector( 0.0f, 0.0f, 0.0f ) );
  445. // Test point in winding. (Since it is at the node, it is in the plane.)
  446. bool bRet = PointInWinding( pt, pWinding );
  447. FreeWinding( pWinding );
  448. return bRet;
  449. }
  450. public:
  451. int m_iThread;
  452. dface_t* m_pSurface;
  453. float m_HitFrac;
  454. Vector2D m_LuxelCoord;
  455. bool m_bHasLuxel;
  456. };
  457. bool CastRayInLeaf( int iThread, const Vector &start, const Vector &end, int leafIndex, float *pFraction, Vector *pNormal )
  458. {
  459. pFraction[0] = 1.0f;
  460. Ray_t ray;
  461. ray.Init( start, end, vec3_origin, vec3_origin );
  462. CBaseTrace trace;
  463. if ( TraceLeafBrushes( leafIndex, start, end, trace ) != 1.0f )
  464. {
  465. pFraction[0] = trace.fraction;
  466. *pNormal = trace.plane.normal;
  467. }
  468. else
  469. {
  470. Assert(!trace.startsolid && !trace.allsolid);
  471. }
  472. StaticDispMgr()->StartRayTest( s_DispTested[iThread] );
  473. // Now try to clip against all displacements in the leaf
  474. float dist;
  475. Vector normal;
  476. StaticDispMgr()->ClipRayToDispInLeaf( s_DispTested[iThread], ray, leafIndex, dist, &normal );
  477. if ( dist < pFraction[0] )
  478. {
  479. pFraction[0] = dist;
  480. *pNormal = normal;
  481. }
  482. return pFraction[0] != 1.0f ? true : false;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Computes ambient lighting along a specified ray.
  486. // Ray represents a cone, tanTheta is the tan of the inner cone angle
  487. //-----------------------------------------------------------------------------
  488. void CalcRayAmbientLighting( int iThread, const Vector &vStart, const Vector &vEnd, float tanTheta, Vector color[MAX_LIGHTSTYLES] )
  489. {
  490. Ray_t ray;
  491. ray.Init( vStart, vEnd, vec3_origin, vec3_origin );
  492. directlight_t *pSkyLight = FindAmbientSkyLight();
  493. CLightSurface surfEnum(iThread);
  494. if (!surfEnum.FindIntersection( ray ))
  495. return;
  496. // compute the approximate radius of a circle centered around the intersection point
  497. float dist = ray.m_Delta.Length() * tanTheta * surfEnum.m_HitFrac;
  498. // until 20" we use the point sample, then blend in the average until we're covering 40"
  499. // This is attempting to model the ray as a cone - in the ideal case we'd simply sample all
  500. // luxels in the intersection of the cone with the surface. Since we don't have surface
  501. // neighbor information computed we'll just approximate that sampling with a blend between
  502. // a point sample and the face average.
  503. // This yields results that are similar in that aliasing is reduced at distance while
  504. // point samples provide accuracy for intersections with near geometry
  505. float scaleAvg = RemapValClamped( dist, 20, 40, 0.0f, 1.0f );
  506. if ( !surfEnum.m_bHasLuxel )
  507. {
  508. // don't have luxel UV, so just use average sample
  509. scaleAvg = 1.0;
  510. }
  511. float scaleSample = 1.0f - scaleAvg;
  512. if (scaleAvg != 0)
  513. {
  514. ComputeLightmapColorFromAverage( surfEnum.m_pSurface, pSkyLight, scaleAvg, color );
  515. }
  516. if (scaleSample != 0)
  517. {
  518. ComputeLightmapColorPointSample( surfEnum.m_pSurface, pSkyLight, surfEnum.m_LuxelCoord, scaleSample, color );
  519. }
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Compute ambient lighting component at specified position.
  523. //-----------------------------------------------------------------------------
  524. static void ComputeAmbientLightingAtPoint( int iThread, const Vector &origin, Vector radcolor[NUMVERTEXNORMALS], Vector color[MAX_LIGHTSTYLES] )
  525. {
  526. // NOTE: I'm not dealing with shadow-casting static props here
  527. // This is for speed, although we can add it if it turns out to
  528. // be important
  529. // sample world by casting N rays distributed across a sphere
  530. Vector upend;
  531. int j;
  532. for ( j = 0; j < MAX_LIGHTSTYLES; ++j)
  533. {
  534. color[j].Init( 0,0,0 );
  535. }
  536. float tanTheta = tan(VERTEXNORMAL_CONE_INNER_ANGLE);
  537. for (int i = 0; i < NUMVERTEXNORMALS; i++)
  538. {
  539. VectorMA( origin, COORD_EXTENT * 1.74, g_anorms[i], upend );
  540. // Now that we've got a ray, see what surface we've hit
  541. CalcRayAmbientLighting( iThread, origin, upend, tanTheta, color );
  542. // DumpRayToGlView( ray, surfEnum.m_HitFrac, &color[0], "test.out" );
  543. }
  544. for ( j = 0; j < MAX_LIGHTSTYLES; ++j)
  545. {
  546. VectorMultiply( color[j], 255.0f / (float)NUMVERTEXNORMALS, color[j] );
  547. }
  548. }
  549. //-----------------------------------------------------------------------------
  550. //
  551. // Trace a ray from position. in the specified direction to determine a positive
  552. // hit for indirect lighting.
  553. //
  554. // Fire ray out from start, with end as start + direction*MAX_TRACE_LENGTH
  555. // If hit then fire ray back to start to see if it hits a back facing surface that would natually block the incoming light ray
  556. // If still okay then test explicitly against light blockers, test only in the hit to start direction
  557. // Update surfEnum and return true if a valid intersection for indirect light.
  558. //
  559. //-----------------------------------------------------------------------------
  560. bool TraceIndirectLightingSample( Vector &position, Vector &direction, CLightSurface &surfEnum, int iThread, bool force_fast )
  561. {
  562. Ray_t ray;
  563. // trace to determine surface
  564. Vector vEnd, vStart;
  565. VectorScale( direction, MAX_TRACE_LENGTH, vEnd );
  566. VectorAdd( position, vEnd, vEnd );
  567. if ( force_fast )
  568. {
  569. vStart = position;
  570. }
  571. else
  572. {
  573. // offset ray start position to compensate for ray leakage due to coincident surfaces (we are seeing some ray tests leak in some situations - e.g. prop vertex lies on ground plane)
  574. VectorScale( direction, -EQUAL_EPSILON, vStart );
  575. VectorAdd( position, vStart, vStart );
  576. }
  577. ray.Init( vStart, vEnd, vec3_origin, vec3_origin );
  578. if ( !surfEnum.FindIntersection( ray ) )
  579. return false;
  580. // Now test explicitly against light blockers (surfaces don't exist in the bsp nodes we're checking here, and this feels a safer change than updating indirect lighting for static props to use the slower rte path for all rays)
  581. // test from hitfrac back to start only
  582. VectorScale( direction, MAX_TRACE_LENGTH * surfEnum.m_HitFrac, vEnd );
  583. VectorAdd( position, vEnd, vEnd );
  584. FourVectors rayStart, rayEnd, rayDirection;
  585. fltx4 fractionVisible = Four_Ones;
  586. rayStart.DuplicateVector( vStart );
  587. rayEnd.DuplicateVector( vEnd );
  588. // rayDirection.DuplicateVector( direction );
  589. // TestLine_LightBlockers( rayStart, rayEnd, &fractionVisible );
  590. rayDirection.DuplicateVector( -direction );
  591. TestLine_LightBlockers( rayEnd, rayStart, &fractionVisible );
  592. if ( fractionVisible.m128_f32[0] < 1.0f )
  593. {
  594. // ray hit blocker
  595. return false;
  596. }
  597. return true;
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Trace hemispherical rays from a vertex, accumulating indirect
  601. // sources at each ray termination.
  602. //
  603. // force_fast = false currently implies 'new/improved' static prop lighting is to be used.
  604. //-----------------------------------------------------------------------------
  605. void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor,
  606. int iThread, bool force_fast, bool bIgnoreNormals, int nStaticPropToSkip )
  607. {
  608. outColor.Zero();
  609. int nSamples = NUMVERTEXNORMALS;
  610. if ( do_fast || force_fast )
  611. nSamples /= 4;
  612. else
  613. nSamples *= g_flStaticPropSampleScale;
  614. float totalDot = 0;
  615. DirectionalSampler_t sampler;
  616. for (int j = 0; j < nSamples; j++)
  617. {
  618. Vector samplingNormal = sampler.NextValue();
  619. float dot;
  620. if ( bIgnoreNormals )
  621. dot = (0.7071/2);
  622. else
  623. dot = DotProduct( normal, samplingNormal );
  624. if ( dot <= EQUAL_EPSILON )
  625. {
  626. // reject angles behind our plane
  627. continue;
  628. }
  629. totalDot += dot;
  630. // trace static prop indirect
  631. Vector staticPropIndirectColor( 0.0f, 0.0f, 0.0f );
  632. float flStaticPropHitDist = FLT_MAX;
  633. if ( g_bStaticPropBounce )
  634. {
  635. FourRays myrays;
  636. myrays.origin.DuplicateVector( position );
  637. myrays.direction.DuplicateVector( samplingNormal );
  638. RayTracingResult rt_result;
  639. g_RtEnv_RadiosityPatches.Trace4Rays( myrays, ReplicateX4( 10.0f ), ReplicateX4( MAX_TRACE_LENGTH ), &rt_result );
  640. if ( rt_result.HitIds[ 0 ] != -1 )
  641. {
  642. const TriIntersectData_t &intersectData = g_RtEnv_RadiosityPatches.OptimizedTriangleList[ rt_result.HitIds[ 0 ] ].m_Data.m_IntersectData;
  643. int nId = intersectData.m_nTriangleID;
  644. if ( nId & TRACE_ID_PATCH )
  645. {
  646. int nPatchId = nId & ~TRACE_ID_PATCH;
  647. CPatch &patch = g_Patches[ nPatchId ];
  648. if ( patch.staticPropIdx != nStaticPropToSkip )
  649. {
  650. staticPropIndirectColor = dot * ( patch.totallight.light[ 0 ] + patch.directlight ) * patch.reflectivity;
  651. flStaticPropHitDist = SubFloat( rt_result.HitDistance, 0 );
  652. }
  653. }
  654. }
  655. }
  656. // important to put the constructor here to init m_hitfrac, etc
  657. CLightSurface surfEnum( iThread );
  658. // trace to determine surface
  659. if ( !TraceIndirectLightingSample( position, samplingNormal, surfEnum, iThread, force_fast ) ||
  660. flStaticPropHitDist < surfEnum.m_HitFrac * MAX_TRACE_LENGTH )
  661. {
  662. VectorAdd( outColor, staticPropIndirectColor, outColor ); // we may have hit a static prop patch
  663. continue;
  664. }
  665. // get color from surface lightmap
  666. texinfo_t* pTex = &texinfo[surfEnum.m_pSurface->texinfo];
  667. if ( !pTex || pTex->flags & SURF_SKY )
  668. {
  669. // ignore contribution from sky
  670. // sky ambient already accounted for during direct pass
  671. continue;
  672. }
  673. if ( surfEnum.m_pSurface->styles[0] == 255 || surfEnum.m_pSurface->lightofs < 0 )
  674. {
  675. // no light affects this face
  676. continue;
  677. }
  678. Vector lightmapColor;
  679. if ( !surfEnum.m_bHasLuxel )
  680. {
  681. ColorRGBExp32* pAvgLightmapColor = dface_AvgLightColor( surfEnum.m_pSurface, 0 );
  682. ColorRGBExp32ToVector( *pAvgLightmapColor, lightmapColor );
  683. }
  684. else
  685. {
  686. // get color from displacement
  687. int smax = ( surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[0] ) + 1;
  688. int tmax = ( surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[1] ) + 1;
  689. // luxelcoord is in the space of the accumulated lightmap page; we need to convert
  690. // it to be in the space of the surface
  691. int ds = clamp( (int)surfEnum.m_LuxelCoord.x, 0, smax-1 );
  692. int dt = clamp( (int)surfEnum.m_LuxelCoord.y, 0, tmax-1 );
  693. ColorRGBExp32* pLightmap = (ColorRGBExp32*)&(*pdlightdata)[surfEnum.m_pSurface->lightofs];
  694. pLightmap += dt * smax + ds;
  695. ColorRGBExp32ToVector( *pLightmap, lightmapColor );
  696. }
  697. if ( force_fast )
  698. {
  699. VectorMultiply( lightmapColor, dtexdata[pTex->texdata].reflectivity, lightmapColor );
  700. }
  701. else
  702. {
  703. // Include dot falloff on accumulating irradiance here
  704. // have tried using inv sqr falloff from TF2 changes to vrad (CL#2394791 & 2395471), but the result is very sensitive to the scale factor that is used (too dark or too bright otherwise)
  705. // this seems to give the most natural looking result (static props matching brushes)
  706. VectorMultiply( lightmapColor, dot * dtexdata[pTex->texdata].reflectivity, lightmapColor );
  707. }
  708. VectorAdd( outColor, lightmapColor, outColor );
  709. }
  710. if ( totalDot )
  711. {
  712. VectorScale( outColor, 1.0f / totalDot, outColor );
  713. }
  714. }
  715. void ComputeIndirectLightingAtPoint( Vector &position, Vector *normals, Vector *outColors, int numNormals,
  716. int iThread, bool force_fast, bool bIgnoreNormals, int nStaticPropToSkip )
  717. {
  718. const Vector vZero(0.0f, 0.0f, 0.0f);
  719. if ( numNormals != ( NUM_BUMP_VECTS + 1 ) )
  720. {
  721. for ( int k = 0; k < numNormals; ++k )
  722. {
  723. ComputeIndirectLightingAtPoint( position, normals[k], outColors[k], iThread, force_fast, bIgnoreNormals, nStaticPropToSkip );
  724. }
  725. return;
  726. }
  727. // optimize/unroll for num_bump_vects = 3
  728. outColors[0].Zero();
  729. outColors[1].Zero();
  730. outColors[2].Zero();
  731. outColors[3].Zero();
  732. int nSamples = NUMVERTEXNORMALS;
  733. if ( do_fast || force_fast )
  734. nSamples /= 4;
  735. else
  736. nSamples *= g_flStaticPropSampleScale;
  737. float totalDot[4] = {0.0f, 0.0f, 0.0f, 0.0f};
  738. DirectionalSampler_t sampler;
  739. for ( int j = 0; j < nSamples; j++ )
  740. {
  741. Vector samplingNormal = sampler.NextValue();
  742. float dot[4];
  743. if ( bIgnoreNormals )
  744. {
  745. dot[0] = dot[1] = dot[2] = dot[3] = (0.7071 / 2);
  746. }
  747. else
  748. {
  749. samplingNormal.NormalizeInPlace();
  750. dot[0] = DotProduct( normals[0], samplingNormal );
  751. dot[1] = DotProduct( normals[1], samplingNormal );
  752. dot[2] = DotProduct( normals[2], samplingNormal );
  753. dot[3] = DotProduct( normals[3], samplingNormal );
  754. }
  755. bool bDoRayTrace = false;
  756. bool bIncLighting[4] = {false, false, false, false};
  757. if ( dot[0] > EQUAL_EPSILON )
  758. {
  759. dot[0] = SoftenCosineTerm( dot[0] );
  760. totalDot[0] += dot[0];
  761. bDoRayTrace = true;
  762. bIncLighting[0] = true;
  763. }
  764. else
  765. {
  766. dot[0] = 0.0f;
  767. }
  768. if ( dot[1] > EQUAL_EPSILON )
  769. {
  770. dot[1] = SoftenCosineTerm( dot[1] );
  771. totalDot[1] += dot[1];
  772. bDoRayTrace = true;
  773. bIncLighting[1] = true;
  774. }
  775. else
  776. {
  777. dot[1] = 0.0f;
  778. }
  779. if ( dot[2] > EQUAL_EPSILON )
  780. {
  781. dot[2] = SoftenCosineTerm( dot[2] );
  782. totalDot[2] += dot[2];
  783. bDoRayTrace = true;
  784. bIncLighting[2] = true;
  785. }
  786. else
  787. {
  788. dot[2] = 0.0f;
  789. }
  790. if ( dot[3] > EQUAL_EPSILON )
  791. {
  792. dot[3] = SoftenCosineTerm( dot[3] );
  793. totalDot[3] += dot[3];
  794. bDoRayTrace = true;
  795. bIncLighting[3] = true;
  796. }
  797. else
  798. {
  799. dot[3] = 0.0f;
  800. }
  801. // important to skip
  802. if ( dot[0] <= EQUAL_EPSILON )
  803. {
  804. continue;
  805. }
  806. if ( bDoRayTrace )
  807. {
  808. Vector staticPropIndirectColor( 0.0f, 0.0f, 0.0f );
  809. float flStaticPropHitDist = FLT_MAX;
  810. if ( g_bStaticPropBounce )
  811. {
  812. FourRays myrays;
  813. myrays.origin.DuplicateVector( position );
  814. myrays.direction.DuplicateVector( samplingNormal );
  815. RayTracingResult rt_result;
  816. g_RtEnv_RadiosityPatches.Trace4Rays( myrays, ReplicateX4( 10.0f ), ReplicateX4( MAX_TRACE_LENGTH ), &rt_result );
  817. if ( rt_result.HitIds[ 0 ] != -1 )
  818. {
  819. const TriIntersectData_t &intersectData = g_RtEnv_RadiosityPatches.OptimizedTriangleList[ rt_result.HitIds[ 0 ] ].m_Data.m_IntersectData;
  820. int nId = intersectData.m_nTriangleID;
  821. if ( nId & TRACE_ID_PATCH )
  822. {
  823. int nPatchId = nId & ~TRACE_ID_PATCH;
  824. CPatch &patch = g_Patches[ nPatchId ];
  825. if ( patch.staticPropIdx != nStaticPropToSkip )
  826. {
  827. staticPropIndirectColor = ( patch.totallight.light[ 0 ] + patch.directlight ) * patch.reflectivity;
  828. flStaticPropHitDist = SubFloat( rt_result.HitDistance, 0 );
  829. }
  830. }
  831. }
  832. }
  833. // important to put the constructor here to init m_hitfrac, etc
  834. CLightSurface surfEnum( iThread );
  835. // trace to determine surface
  836. if ( !TraceIndirectLightingSample( position, samplingNormal, surfEnum, iThread, force_fast ) ||
  837. flStaticPropHitDist < surfEnum.m_HitFrac * MAX_TRACE_LENGTH )
  838. {
  839. // The dot values are 0 if bIncLighting is false so we don't actually need to branch here.
  840. VectorAdd( outColors[ 0 ], dot[ 0 ] * staticPropIndirectColor, outColors[ 0 ] ); // we may have hit a static prop patch
  841. VectorAdd( outColors[ 1 ], dot[ 1 ] * staticPropIndirectColor, outColors[ 1 ] );
  842. VectorAdd( outColors[ 2 ], dot[ 2 ] * staticPropIndirectColor, outColors[ 2 ] );
  843. VectorAdd( outColors[ 3 ], dot[ 3 ] * staticPropIndirectColor, outColors[ 3 ] );
  844. continue;
  845. }
  846. // get color from surface lightmap
  847. texinfo_t* pTex = &texinfo[surfEnum.m_pSurface->texinfo];
  848. if ( !pTex || pTex->flags & SURF_SKY )
  849. {
  850. // ignore contribution from sky
  851. // sky ambient already accounted for during direct pass
  852. continue;
  853. }
  854. if ( surfEnum.m_pSurface->styles[0] == 255 || surfEnum.m_pSurface->lightofs < 0 )
  855. {
  856. // no light affects this face
  857. continue;
  858. }
  859. Vector lightmapColor;
  860. Vector lightmapColors[4];
  861. if ( !surfEnum.m_bHasLuxel )
  862. {
  863. ColorRGBExp32* pAvgLightmapColor = dface_AvgLightColor( surfEnum.m_pSurface, 0 );
  864. ColorRGBExp32ToVector( *pAvgLightmapColor, lightmapColor );
  865. }
  866. else
  867. {
  868. // get color from displacement
  869. int smax = (surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[0]) + 1;
  870. int tmax = (surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[1]) + 1;
  871. // luxelcoord is in the space of the accumulated lightmap page; we need to convert
  872. // it to be in the space of the surface
  873. int ds = clamp( (int)surfEnum.m_LuxelCoord.x, 0, smax - 1 );
  874. int dt = clamp( (int)surfEnum.m_LuxelCoord.y, 0, tmax - 1 );
  875. ColorRGBExp32* pLightmap = (ColorRGBExp32*)&(*pdlightdata)[surfEnum.m_pSurface->lightofs];
  876. pLightmap += dt * smax + ds;
  877. ColorRGBExp32ToVector( *pLightmap, lightmapColor );
  878. }
  879. lightmapColor.Max( vZero );
  880. if ( force_fast )
  881. {
  882. VectorMultiply( lightmapColor, dtexdata[pTex->texdata].reflectivity, lightmapColors[0] );
  883. if ( bIncLighting[0] )
  884. {
  885. VectorAdd( outColors[0], lightmapColors[0], outColors[0] );
  886. }
  887. if ( bIncLighting[1] )
  888. {
  889. VectorAdd( outColors[1], lightmapColors[0], outColors[1] );
  890. }
  891. if ( bIncLighting[2] )
  892. {
  893. VectorAdd( outColors[2], lightmapColors[0], outColors[2] );
  894. }
  895. if ( bIncLighting[3] )
  896. {
  897. VectorAdd( outColors[3], lightmapColors[0], outColors[3] );
  898. }
  899. }
  900. else
  901. {
  902. // Include dot falloff on accumulating irradiance here
  903. // have tried using inv sqr falloff from TF2 changes to vrad (CL#2394791 & 2395471), but the result is very sensitive to the scale factor that is used (too dark or too bright otherwise)
  904. // this seems to give the most natural looking result (static props matching brushes)
  905. if ( bIncLighting[0] )
  906. {
  907. VectorMultiply( lightmapColor, dot[0] * dtexdata[pTex->texdata].reflectivity, lightmapColors[0] );
  908. VectorAdd( outColors[0], lightmapColors[0], outColors[0] );
  909. }
  910. if ( bIncLighting[1] )
  911. {
  912. VectorMultiply( lightmapColor, dot[1] * dtexdata[pTex->texdata].reflectivity, lightmapColors[1] );
  913. VectorAdd( outColors[1], lightmapColors[1], outColors[1] );
  914. }
  915. if ( bIncLighting[2] )
  916. {
  917. VectorMultiply( lightmapColor, dot[2] * dtexdata[pTex->texdata].reflectivity, lightmapColors[2] );
  918. VectorAdd( outColors[2], lightmapColors[2], outColors[2] );
  919. }
  920. if ( bIncLighting[3] )
  921. {
  922. VectorMultiply( lightmapColor, dot[3] * dtexdata[pTex->texdata].reflectivity, lightmapColors[3] );
  923. VectorAdd( outColors[3], lightmapColors[3], outColors[3] );
  924. }
  925. }
  926. }
  927. }
  928. if ( totalDot[0] )
  929. {
  930. VectorScale( outColors[0], 1.0f / totalDot[0], outColors[0] );
  931. }
  932. if ( totalDot[1] )
  933. {
  934. VectorScale( outColors[1], 1.0f / totalDot[1], outColors[1] );
  935. }
  936. if ( totalDot[2] )
  937. {
  938. VectorScale( outColors[2], 1.0f / totalDot[2], outColors[2] );
  939. }
  940. if ( totalDot[3] )
  941. {
  942. VectorScale( outColors[3], 1.0f / totalDot[3], outColors[3] );
  943. }
  944. }
  945. static void ComputeAmbientLighting( int iThread, DetailObjectLump_t& prop, Vector color[MAX_LIGHTSTYLES] )
  946. {
  947. Vector origin, normal;
  948. ComputeWorldCenter( prop, origin, normal );
  949. if ( !origin.IsValid() || !normal.IsValid() )
  950. {
  951. static bool s_Warned = false;
  952. if ( !s_Warned )
  953. {
  954. Warning("WARNING: Bogus detail props encountered!\n" );
  955. s_Warned = true;
  956. }
  957. // fill with debug color
  958. for ( int i = 0; i < MAX_LIGHTSTYLES; ++i)
  959. {
  960. color[i].Init(1,0,0);
  961. }
  962. return;
  963. }
  964. Vector radcolor[NUMVERTEXNORMALS];
  965. ComputeAmbientLightingAtPoint( iThread, origin, radcolor, color );
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Computes lighting for a single detal prop
  969. //-----------------------------------------------------------------------------
  970. static void ComputeLighting( DetailObjectLump_t& prop, int iThread )
  971. {
  972. // We're going to take the maximum of the ambient lighting and
  973. // the strongest directional light. This works because we're assuming
  974. // the props will have built-in faked lighting.
  975. Vector directColor[MAX_LIGHTSTYLES];
  976. Vector ambColor[MAX_LIGHTSTYLES];
  977. // Get the max influence of all direct lights
  978. ComputeMaxDirectLighting( prop, directColor, iThread );
  979. // Get the ambient lighting + lightstyles
  980. ComputeAmbientLighting( iThread, prop, ambColor );
  981. // Base lighting
  982. Vector totalColor;
  983. VectorAdd( directColor[0], ambColor[0], totalColor );
  984. VectorToColorRGBExp32( totalColor, prop.m_Lighting );
  985. bool hasLightstyles = false;
  986. prop.m_LightStyleCount = 0;
  987. // lightstyles
  988. for (int i = 1; i < MAX_LIGHTSTYLES; ++i )
  989. {
  990. VectorAdd( directColor[i], ambColor[i], totalColor );
  991. totalColor *= 0.5f;
  992. if ((totalColor[0] != 0.0f) || (totalColor[1] != 0.0f) ||
  993. (totalColor[2] != 0.0f) )
  994. {
  995. if (!hasLightstyles)
  996. {
  997. prop.m_LightStyles = s_pDetailPropLightStyleLump->Count();
  998. hasLightstyles = true;
  999. }
  1000. int j = s_pDetailPropLightStyleLump->AddToTail();
  1001. VectorToColorRGBExp32( totalColor, (*s_pDetailPropLightStyleLump)[j].m_Lighting );
  1002. (*s_pDetailPropLightStyleLump)[j].m_Style = i;
  1003. ++prop.m_LightStyleCount;
  1004. }
  1005. }
  1006. }
  1007. //-----------------------------------------------------------------------------
  1008. // Unserialization
  1009. //-----------------------------------------------------------------------------
  1010. static void UnserializeModelDict( CUtlBuffer& buf )
  1011. {
  1012. // Get origin offset for each model...
  1013. int count = buf.GetInt();
  1014. while ( --count >= 0 )
  1015. {
  1016. DetailObjectDictLump_t lump;
  1017. buf.Get( &lump, sizeof(DetailObjectDictLump_t) );
  1018. int i = g_ModelCenterOffset.AddToTail();
  1019. CUtlBuffer mdlbuf;
  1020. if (LoadStudioModel( lump.m_Name, mdlbuf ))
  1021. {
  1022. studiohdr_t* pHdr = (studiohdr_t*)mdlbuf.Base();
  1023. VectorAdd( pHdr->hull_min, pHdr->hull_max, g_ModelCenterOffset[i] );
  1024. g_ModelCenterOffset[i] *= 0.5f;
  1025. }
  1026. else
  1027. {
  1028. g_ModelCenterOffset[i].Init(0,0,0);
  1029. }
  1030. }
  1031. }
  1032. static void UnserializeSpriteDict( CUtlBuffer& buf )
  1033. {
  1034. // Get origin offset for each model...
  1035. int count = buf.GetInt();
  1036. while ( --count >= 0 )
  1037. {
  1038. DetailSpriteDictLump_t lump;
  1039. buf.Get( &lump, sizeof(DetailSpriteDictLump_t) );
  1040. // For these sprites, x goes out the front, y right, z up
  1041. int i = g_SpriteCenterOffset.AddToTail();
  1042. g_SpriteCenterOffset[i].x = 0.0f;
  1043. g_SpriteCenterOffset[i].y = lump.m_LR.x + lump.m_UL.x;
  1044. g_SpriteCenterOffset[i].z = lump.m_LR.y + lump.m_UL.y;
  1045. g_SpriteCenterOffset[i] *= 0.5f;
  1046. }
  1047. }
  1048. //-----------------------------------------------------------------------------
  1049. // Unserializes the detail props
  1050. //-----------------------------------------------------------------------------
  1051. static int UnserializeDetailProps( DetailObjectLump_t*& pProps )
  1052. {
  1053. GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
  1054. if (g_GameLumps.GetGameLumpVersion(handle) != GAMELUMP_DETAIL_PROPS_VERSION)
  1055. return 0;
  1056. // Unserialize
  1057. CUtlBuffer buf( g_GameLumps.GetGameLump(handle), g_GameLumps.GameLumpSize( handle ), CUtlBuffer::READ_ONLY );
  1058. UnserializeModelDict( buf );
  1059. UnserializeSpriteDict( buf );
  1060. // Now we're pointing to the detail prop data
  1061. // This actually works because the scope of the game lump data
  1062. // is global and the buf was just pointing to it.
  1063. int count = buf.GetInt();
  1064. if (count)
  1065. {
  1066. pProps = (DetailObjectLump_t*)buf.PeekGet();
  1067. }
  1068. else
  1069. {
  1070. pProps = 0;
  1071. }
  1072. return count;
  1073. }
  1074. //-----------------------------------------------------------------------------
  1075. // Writes the detail lighting lump
  1076. //-----------------------------------------------------------------------------
  1077. static void WriteDetailLightingLump( int lumpID, int lumpVersion, CUtlVector<DetailPropLightstylesLump_t> &lumpData )
  1078. {
  1079. GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle(lumpID);
  1080. if (handle != g_GameLumps.InvalidGameLump())
  1081. g_GameLumps.DestroyGameLump(handle);
  1082. int lightsize = lumpData.Count() * sizeof(DetailPropLightstylesLump_t);
  1083. int lumpsize = lightsize + sizeof(int);
  1084. handle = g_GameLumps.CreateGameLump( lumpID, lumpsize, 0, lumpVersion );
  1085. // Serialize the data
  1086. CUtlBuffer buf( g_GameLumps.GetGameLump(handle), lumpsize );
  1087. buf.PutInt( lumpData.Count() );
  1088. if (lightsize)
  1089. buf.Put( lumpData.Base(), lightsize );
  1090. }
  1091. static void WriteDetailLightingLumps( void )
  1092. {
  1093. WriteDetailLightingLump( GAMELUMP_DETAIL_PROP_LIGHTING, GAMELUMP_DETAIL_PROP_LIGHTING_VERSION, s_DetailPropLightStyleLumpLDR );
  1094. WriteDetailLightingLump( GAMELUMP_DETAIL_PROP_LIGHTING_HDR, GAMELUMP_DETAIL_PROP_LIGHTING_HDR_VERSION, s_DetailPropLightStyleLumpHDR );
  1095. }
  1096. // need to do this so that if we are building HDR data, the LDR data is intact, and vice versa.s
  1097. void UnserializeDetailPropLighting( int lumpID, int lumpVersion, CUtlVector<DetailPropLightstylesLump_t> &lumpData )
  1098. {
  1099. GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( lumpID );
  1100. if( handle == g_GameLumps.InvalidGameLump() )
  1101. {
  1102. return;
  1103. }
  1104. if (g_GameLumps.GetGameLumpVersion(handle) != lumpVersion)
  1105. return;
  1106. // Unserialize
  1107. CUtlBuffer buf( g_GameLumps.GetGameLump(handle), g_GameLumps.GameLumpSize( handle ), CUtlBuffer::READ_ONLY );
  1108. int count = buf.GetInt();
  1109. if( !count )
  1110. {
  1111. return;
  1112. }
  1113. lumpData.SetCount( count );
  1114. int lightsize = lumpData.Count() * sizeof(DetailPropLightstylesLump_t);
  1115. buf.Get( lumpData.Base(), lightsize );
  1116. }
  1117. DetailObjectLump_t *g_pMPIDetailProps = NULL;
  1118. void VMPI_ProcessDetailPropWU( int iThread, int iWorkUnit, MessageBuffer *pBuf )
  1119. {
  1120. CUtlVector<DetailPropLightstylesLump_t> *pDetailPropLump = s_pDetailPropLightStyleLump;
  1121. DetailObjectLump_t& prop = g_pMPIDetailProps[iWorkUnit];
  1122. ComputeLighting( prop, iThread );
  1123. // Send the results back...
  1124. pBuf->write( &prop.m_Lighting, sizeof( prop.m_Lighting ) );
  1125. pBuf->write( &prop.m_LightStyleCount, sizeof( prop.m_LightStyleCount ) );
  1126. pBuf->write( &prop.m_LightStyles, sizeof( prop.m_LightStyles ) );
  1127. for ( int i=0; i < prop.m_LightStyleCount; i++ )
  1128. {
  1129. DetailPropLightstylesLump_t *l = &pDetailPropLump->Element( i + prop.m_LightStyles );
  1130. pBuf->write( &l->m_Lighting, sizeof( l->m_Lighting ) );
  1131. pBuf->write( &l->m_Style, sizeof( l->m_Style ) );
  1132. }
  1133. }
  1134. void VMPI_ReceiveDetailPropWU( int iWorkUnit, MessageBuffer *pBuf, int iWorker )
  1135. {
  1136. CUtlVector<DetailPropLightstylesLump_t> *pDetailPropLump = s_pDetailPropLightStyleLump;
  1137. DetailObjectLump_t& prop = g_pMPIDetailProps[iWorkUnit];
  1138. pBuf->read( &prop.m_Lighting, sizeof( prop.m_Lighting ) );
  1139. pBuf->read( &prop.m_LightStyleCount, sizeof( prop.m_LightStyleCount ) );
  1140. pBuf->read( &prop.m_LightStyles, sizeof( prop.m_LightStyles ) );
  1141. pDetailPropLump->EnsureCount( prop.m_LightStyles + prop.m_LightStyleCount );
  1142. for ( int i=0; i < prop.m_LightStyleCount; i++ )
  1143. {
  1144. DetailPropLightstylesLump_t *l = &pDetailPropLump->Element( i + prop.m_LightStyles );
  1145. pBuf->read( &l->m_Lighting, sizeof( l->m_Lighting ) );
  1146. pBuf->read( &l->m_Style, sizeof( l->m_Style ) );
  1147. }
  1148. }
  1149. //-----------------------------------------------------------------------------
  1150. // Computes lighting for the detail props
  1151. //-----------------------------------------------------------------------------
  1152. void ComputeDetailPropLighting( int iThread )
  1153. {
  1154. // illuminate them all
  1155. DetailObjectLump_t* pProps;
  1156. int count = UnserializeDetailProps( pProps );
  1157. if (!count)
  1158. return;
  1159. // unserialize the lump that we aren't computing.
  1160. if( g_bHDR )
  1161. {
  1162. UnserializeDetailPropLighting( GAMELUMP_DETAIL_PROP_LIGHTING, GAMELUMP_DETAIL_PROP_LIGHTING_VERSION, s_DetailPropLightStyleLumpLDR );
  1163. }
  1164. else
  1165. {
  1166. UnserializeDetailPropLighting( GAMELUMP_DETAIL_PROP_LIGHTING_HDR, GAMELUMP_DETAIL_PROP_LIGHTING_HDR_VERSION, s_DetailPropLightStyleLumpHDR );
  1167. }
  1168. StartPacifier("Computing detail prop lighting : ");
  1169. for (int i = 0; i < count; ++i)
  1170. {
  1171. UpdatePacifier( (float)i / (float)count );
  1172. ComputeLighting( pProps[i], iThread );
  1173. }
  1174. // Write detail prop lightstyle lump...
  1175. WriteDetailLightingLumps();
  1176. EndPacifier( true );
  1177. }