Team Fortress 2 Source Code as on 22/4/2020
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.

1759 lines
53 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "vrad.h"
  8. #include "utlvector.h"
  9. #include "cmodel.h"
  10. #include "BSPTreeData.h"
  11. #include "VRAD_DispColl.h"
  12. #include "CollisionUtils.h"
  13. #include "lightmap.h"
  14. #include "Radial.h"
  15. #include "CollisionUtils.h"
  16. #include "mathlib/bumpvects.h"
  17. #include "utlrbtree.h"
  18. #include "tier0/fasttimer.h"
  19. #include "disp_vrad.h"
  20. class CBSPDispRayDistanceEnumerator;
  21. //=============================================================================
  22. //
  23. // Displacement/Face List
  24. //
  25. class CBSPDispFaceListEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
  26. {
  27. public:
  28. //=========================================================================
  29. //
  30. // Construction/Deconstruction
  31. //
  32. CBSPDispFaceListEnumerator() {};
  33. virtual ~CBSPDispFaceListEnumerator()
  34. {
  35. m_DispList.Purge();
  36. m_FaceList.Purge();
  37. }
  38. // ISpatialLeafEnumerator
  39. bool EnumerateLeaf( int ndxLeaf, int context );
  40. // IBSPTreeDataEnumerator
  41. bool FASTCALL EnumerateElement( int userId, int context );
  42. public:
  43. CUtlVector<CVRADDispColl*> m_DispList;
  44. CUtlVector<int> m_FaceList;
  45. };
  46. //=============================================================================
  47. //
  48. // RayEnumerator
  49. //
  50. class CBSPDispRayEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
  51. {
  52. public:
  53. // ISpatialLeafEnumerator
  54. bool EnumerateLeaf( int ndxLeaf, int context );
  55. // IBSPTreeDataEnumerator
  56. bool FASTCALL EnumerateElement( int userId, int context );
  57. };
  58. //=============================================================================
  59. //
  60. // VRad Displacement Manager
  61. //
  62. class CVRadDispMgr : public IVRadDispMgr
  63. {
  64. public:
  65. //=========================================================================
  66. //
  67. // Construction/Deconstruction
  68. //
  69. CVRadDispMgr();
  70. virtual ~CVRadDispMgr();
  71. // creation/destruction
  72. void Init( void );
  73. void Shutdown( void );
  74. // "CalcPoints"
  75. bool BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
  76. bool BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
  77. bool BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
  78. // patching functions
  79. void MakePatches( void );
  80. void SubdividePatch( int iPatch );
  81. // pre "FinalLightFace"
  82. void InsertSamplesDataIntoHashTable( void );
  83. void InsertPatchSampleDataIntoHashTable( void );
  84. // "FinalLightFace"
  85. radial_t *BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump );
  86. bool SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl, LightingValue_t *pLightSample, int sampleCount, bool bPatch );
  87. radial_t *BuildPatchRadial( int ndxFace, bool bBump );
  88. // utility
  89. void GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, bool bInside );
  90. void GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree );
  91. // bsp tree functions
  92. bool ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray );
  93. bool ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf );
  94. void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf,
  95. float& dist, dface_t*& pFace, Vector2D& luxelCoord );
  96. void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
  97. int ndxLeaf, float& dist, Vector *pNormal );
  98. void StartRayTest( DispTested_t &dispTested );
  99. void AddPolysForRayTrace( void );
  100. // general timing -- should be moved!!
  101. void StartTimer( const char *name );
  102. void EndTimer( void );
  103. //=========================================================================
  104. //
  105. // Enumeration Methods
  106. //
  107. bool DispRay_EnumerateLeaf( int ndxLeaf, int context );
  108. bool DispRay_EnumerateElement( int userId, int context );
  109. bool DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pEnum );
  110. bool DispFaceList_EnumerateLeaf( int ndxLeaf, int context );
  111. bool DispFaceList_EnumerateElement( int userId, int context );
  112. private:
  113. //=========================================================================
  114. //
  115. // BSP Tree Helpers
  116. //
  117. void InsertDispIntoTree( int ndxDisp );
  118. void RemoveDispFromTree( int ndxDisp );
  119. //=========================================================================
  120. //
  121. // Displacement Data Loader (from .bsp)
  122. //
  123. void UnserializeDisps( void );
  124. void DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace );
  125. //=========================================================================
  126. //
  127. // Sampling Helpers
  128. //
  129. void RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial, int ndxStyle, bool bBump );
  130. void RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
  131. radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle );
  132. void RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial, bool bBump );
  133. void RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
  134. Vector const &luxelNormal, float radius,
  135. radial_t *pRadial, int ndxRadial, bool bBump,
  136. CUtlVector<CPatch*> &interestingPatches );
  137. bool IsNeighbor( int iDispFace, int iNeighborFace );
  138. void GetInterestingPatchesForLuxels(
  139. int ndxFace,
  140. CUtlVector<CPatch*> &interestingPatches,
  141. float patchSampleRadius );
  142. private:
  143. struct DispCollTree_t
  144. {
  145. CVRADDispColl *m_pDispTree;
  146. BSPTreeDataHandle_t m_Handle;
  147. };
  148. struct EnumContext_t
  149. {
  150. DispTested_t *m_pDispTested;
  151. Ray_t const *m_pRay;
  152. };
  153. CUtlVector<DispCollTree_t> m_DispTrees;
  154. IBSPTreeData *m_pBSPTreeData;
  155. CBSPDispRayEnumerator m_EnumDispRay;
  156. CBSPDispFaceListEnumerator m_EnumDispFaceList;
  157. int sampleCount;
  158. Vector *m_pSamplePos;
  159. CFastTimer m_Timer;
  160. };
  161. //-----------------------------------------------------------------------------
  162. // Purpose: expose IVRadDispMgr to vrad
  163. //-----------------------------------------------------------------------------
  164. static CVRadDispMgr s_DispMgr;
  165. IVRadDispMgr *StaticDispMgr( void )
  166. {
  167. return &s_DispMgr;
  168. }
  169. //=============================================================================
  170. //
  171. // Displacement/Face List
  172. //
  173. // ISpatialLeafEnumerator
  174. bool CBSPDispFaceListEnumerator::EnumerateLeaf( int ndxLeaf, int context )
  175. {
  176. return s_DispMgr.DispFaceList_EnumerateLeaf( ndxLeaf, context );
  177. }
  178. // IBSPTreeDataEnumerator
  179. bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, int context )
  180. {
  181. return s_DispMgr.DispFaceList_EnumerateElement( userId, context );
  182. }
  183. //=============================================================================
  184. //
  185. // RayEnumerator
  186. //
  187. bool CBSPDispRayEnumerator::EnumerateLeaf( int ndxLeaf, int context )
  188. {
  189. return s_DispMgr.DispRay_EnumerateLeaf( ndxLeaf, context );
  190. }
  191. bool FASTCALL CBSPDispRayEnumerator::EnumerateElement( int userId, int context )
  192. {
  193. return s_DispMgr.DispRay_EnumerateElement( userId, context );
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Here's an enumerator that we use for testing against disps in a leaf...
  197. //-----------------------------------------------------------------------------
  198. class CBSPDispRayDistanceEnumerator : public IBSPTreeDataEnumerator
  199. {
  200. public:
  201. CBSPDispRayDistanceEnumerator() : m_Distance(1.0f), m_pSurface(0) {}
  202. // IBSPTreeDataEnumerator
  203. bool FASTCALL EnumerateElement( int userId, int context )
  204. {
  205. return s_DispMgr.DispRayDistance_EnumerateElement( userId, this );
  206. }
  207. float m_Distance;
  208. dface_t* m_pSurface;
  209. DispTested_t *m_pDispTested;
  210. Ray_t const *m_pRay;
  211. Vector2D m_LuxelCoord;
  212. Vector m_Normal;
  213. };
  214. //-----------------------------------------------------------------------------
  215. //-----------------------------------------------------------------------------
  216. CVRadDispMgr::CVRadDispMgr()
  217. {
  218. m_pBSPTreeData = CreateBSPTreeData();
  219. }
  220. //-----------------------------------------------------------------------------
  221. //-----------------------------------------------------------------------------
  222. CVRadDispMgr::~CVRadDispMgr()
  223. {
  224. DestroyBSPTreeData( m_pBSPTreeData );
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Insert a displacement into the tree for collision
  228. //-----------------------------------------------------------------------------
  229. void CVRadDispMgr::InsertDispIntoTree( int ndxDisp )
  230. {
  231. DispCollTree_t &dispTree = m_DispTrees[ndxDisp];
  232. CDispCollTree *pDispTree = dispTree.m_pDispTree;
  233. // get the bounding box of the tree
  234. Vector boxMin, boxMax;
  235. pDispTree->GetBounds( boxMin, boxMax );
  236. // add the displacement to the tree so we will collide against it
  237. dispTree.m_Handle = m_pBSPTreeData->Insert( ndxDisp, boxMin, boxMax );
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Remove a displacement from the tree for collision
  241. //-----------------------------------------------------------------------------
  242. void CVRadDispMgr::RemoveDispFromTree( int ndxDisp )
  243. {
  244. // release the tree handle
  245. if( m_DispTrees[ndxDisp].m_Handle != TREEDATA_INVALID_HANDLE )
  246. {
  247. m_pBSPTreeData->Remove( m_DispTrees[ndxDisp].m_Handle );
  248. m_DispTrees[ndxDisp].m_Handle = TREEDATA_INVALID_HANDLE;
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. //-----------------------------------------------------------------------------
  253. void CVRadDispMgr::Init( void )
  254. {
  255. // initialize the bsp tree
  256. m_pBSPTreeData->Init( ToolBSPTree() );
  257. // read in displacements that have been compiled into the bsp file
  258. UnserializeDisps();
  259. }
  260. //-----------------------------------------------------------------------------
  261. //-----------------------------------------------------------------------------
  262. void CVRadDispMgr::Shutdown( void )
  263. {
  264. // remove all displacements from the tree
  265. for( int ndxDisp = m_DispTrees.Size(); ndxDisp >= 0; ndxDisp-- )
  266. {
  267. RemoveDispFromTree( ndxDisp );
  268. }
  269. // shutdown the bsp tree
  270. m_pBSPTreeData->Shutdown();
  271. // purge the displacement collision tree list
  272. m_DispTrees.Purge();
  273. }
  274. //-----------------------------------------------------------------------------
  275. //-----------------------------------------------------------------------------
  276. void CVRadDispMgr::DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace )
  277. {
  278. // get the .bsp displacement
  279. ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo];
  280. if( !pDisp )
  281. return;
  282. //
  283. // initlialize the displacement base surface
  284. //
  285. CCoreDispSurface *pSurf = pBuilderDisp->GetSurface();
  286. pSurf->SetPointCount( 4 );
  287. pSurf->SetHandle( ndxFace );
  288. pSurf->SetContents( pDisp->contents );
  289. Vector pt[4];
  290. int ndxPt;
  291. for( ndxPt = 0; ndxPt < 4; ndxPt++ )
  292. {
  293. int eIndex = dsurfedges[pFace->firstedge+ndxPt];
  294. if( eIndex < 0 )
  295. {
  296. pSurf->SetPoint( ndxPt, dvertexes[dedges[-eIndex].v[1]].point );
  297. }
  298. else
  299. {
  300. pSurf->SetPoint( ndxPt, dvertexes[dedges[eIndex].v[0]].point );
  301. }
  302. VectorCopy( pSurf->GetPoint(ndxPt), pt[ndxPt] );
  303. }
  304. //
  305. // calculate the displacement surface normal
  306. //
  307. Vector vFaceNormal;
  308. pSurf->GetNormal( vFaceNormal );
  309. for( ndxPt = 0; ndxPt < 4; ndxPt++ )
  310. {
  311. pSurf->SetPointNormal( ndxPt, vFaceNormal );
  312. }
  313. // set the surface initial point info
  314. pSurf->SetPointStart( pDisp->startPosition );
  315. pSurf->FindSurfPointStartIndex();
  316. pSurf->AdjustSurfPointData();
  317. Vector vecTmp( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
  318. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
  319. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
  320. int nLuxelsPerWorldUnit = static_cast<int>( 1.0f / VectorLength( vecTmp ) );
  321. Vector vecU( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
  322. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
  323. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
  324. Vector vecV( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][0],
  325. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][1],
  326. texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][2] );
  327. pSurf->CalcLuxelCoords( nLuxelsPerWorldUnit, false, vecU, vecV );
  328. pBuilderDisp->SetNeighborData( pDisp->m_EdgeNeighbors, pDisp->m_CornerNeighbors );
  329. CDispVert *pVerts = &g_DispVerts[ pDisp->m_iDispVertStart ];
  330. CDispTri *pTris = &g_DispTris[pDisp->m_iDispTriStart];
  331. //
  332. // initialize the displacement data
  333. //
  334. pBuilderDisp->InitDispInfo(
  335. pDisp->power,
  336. pDisp->minTess,
  337. pDisp->smoothingAngle,
  338. pVerts,
  339. pTris );
  340. }
  341. //-----------------------------------------------------------------------------
  342. //-----------------------------------------------------------------------------
  343. void CVRadDispMgr::UnserializeDisps( void )
  344. {
  345. // temporarily create the "builder" displacements
  346. CUtlVector<CCoreDispInfo*> builderDisps;
  347. for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
  348. {
  349. CCoreDispInfo *pDisp = new CCoreDispInfo;
  350. if ( !pDisp )
  351. {
  352. builderDisps.Purge();
  353. return;
  354. }
  355. int nIndex = builderDisps.AddToTail();
  356. pDisp->SetListIndex( nIndex );
  357. builderDisps[nIndex] = pDisp;
  358. }
  359. // Set them up as CDispUtilsHelpers.
  360. for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
  361. {
  362. builderDisps[iDisp]->SetDispUtilsHelperInfo( builderDisps.Base(), g_dispinfo.Count() );
  363. }
  364. //
  365. // find all faces with displacement data and initialize
  366. //
  367. for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
  368. {
  369. dface_t *pFace = &g_pFaces[ndxFace];
  370. if( ValidDispFace( pFace ) )
  371. {
  372. DispBuilderInit( builderDisps[pFace->dispinfo], pFace, ndxFace );
  373. }
  374. }
  375. // generate the displacement surfaces
  376. for( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
  377. {
  378. builderDisps[iDisp]->Create();
  379. }
  380. // smooth edge normals
  381. SmoothNeighboringDispSurfNormals( builderDisps.Base(), g_dispinfo.Count() );
  382. //
  383. // create the displacement collision tree and add it to the bsp tree
  384. //
  385. CVRADDispColl *pDispTrees = new CVRADDispColl[g_dispinfo.Count()];
  386. if( !pDispTrees )
  387. return;
  388. m_DispTrees.AddMultipleToTail( g_dispinfo.Count() );
  389. for( int iDisp = 0; iDisp < g_dispinfo.Count(); iDisp++ )
  390. {
  391. pDispTrees[iDisp].Create( builderDisps[iDisp] );
  392. m_DispTrees[iDisp].m_pDispTree = &pDispTrees[iDisp];
  393. m_DispTrees[iDisp].m_Handle = TREEDATA_INVALID_HANDLE;
  394. InsertDispIntoTree( iDisp );
  395. }
  396. // free "builder" disps
  397. builderDisps.Purge();
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose: create a set of patches for each displacement surface to transfer
  401. // bounced light around with
  402. //-----------------------------------------------------------------------------
  403. void CVRadDispMgr::MakePatches( void )
  404. {
  405. // Collect stats - keep track of the total displacement surface area.
  406. float flTotalArea = 0.0f;
  407. // Create patches for all of the displacements.
  408. int nTreeCount = m_DispTrees.Size();
  409. for( int iTree = 0; iTree < nTreeCount; ++iTree )
  410. {
  411. // Get the current displacement collision tree.
  412. CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
  413. if( !pDispTree )
  414. continue;
  415. flTotalArea += pDispTree->CreateParentPatches();
  416. }
  417. // Print stats.
  418. qprintf( "%i Displacements\n", nTreeCount );
  419. qprintf( "%i Square Feet [%.2f Square Inches]\n", ( int )( flTotalArea / 144.0f ), flTotalArea );
  420. }
  421. //-----------------------------------------------------------------------------
  422. //-----------------------------------------------------------------------------
  423. void CVRadDispMgr::SubdividePatch( int iPatch )
  424. {
  425. // Get the current patch to subdivide.
  426. CPatch *pPatch = &g_Patches[iPatch];
  427. if ( !pPatch )
  428. return;
  429. // Create children patches.
  430. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[pPatch->faceNumber].dispinfo];
  431. CVRADDispColl *pTree = dispTree.m_pDispTree;
  432. if( pTree )
  433. {
  434. pTree->CreateChildPatches( iPatch, 0 );
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. //-----------------------------------------------------------------------------
  439. void CVRadDispMgr::StartRayTest( DispTested_t &dispTested )
  440. {
  441. if( m_DispTrees.Size() > 0 )
  442. {
  443. if( dispTested.m_pTested == 0 )
  444. {
  445. dispTested.m_pTested = new int[m_DispTrees.Size()];
  446. memset( dispTested.m_pTested, 0, m_DispTrees.Size() * sizeof( int ) );
  447. dispTested.m_Enum = 0;
  448. }
  449. ++dispTested.m_Enum;
  450. }
  451. }
  452. //-----------------------------------------------------------------------------
  453. //-----------------------------------------------------------------------------
  454. bool CVRadDispMgr::ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray )
  455. {
  456. StartRayTest( dispTested );
  457. EnumContext_t ctx;
  458. ctx.m_pRay = &ray;
  459. ctx.m_pDispTested = &dispTested;
  460. // If it got through without a hit, it returns true
  461. return !m_pBSPTreeData->EnumerateLeavesAlongRay( ray, &m_EnumDispRay, ( int )&ctx );
  462. }
  463. //-----------------------------------------------------------------------------
  464. //-----------------------------------------------------------------------------
  465. bool CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
  466. int ndxLeaf )
  467. {
  468. EnumContext_t ctx;
  469. ctx.m_pRay = &ray;
  470. ctx.m_pDispTested = &dispTested;
  471. return !m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, ( int )&ctx );
  472. }
  473. //-----------------------------------------------------------------------------
  474. //-----------------------------------------------------------------------------
  475. void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
  476. int ndxLeaf, float& dist, dface_t*& pFace, Vector2D& luxelCoord )
  477. {
  478. CBSPDispRayDistanceEnumerator rayTestEnum;
  479. rayTestEnum.m_pRay = &ray;
  480. rayTestEnum.m_pDispTested = &dispTested;
  481. m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
  482. dist = rayTestEnum.m_Distance;
  483. pFace = rayTestEnum.m_pSurface;
  484. if (pFace)
  485. {
  486. Vector2DCopy( rayTestEnum.m_LuxelCoord, luxelCoord );
  487. }
  488. }
  489. void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
  490. int ndxLeaf, float& dist, Vector *pNormal )
  491. {
  492. CBSPDispRayDistanceEnumerator rayTestEnum;
  493. rayTestEnum.m_pRay = &ray;
  494. rayTestEnum.m_pDispTested = &dispTested;
  495. m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
  496. dist = rayTestEnum.m_Distance;
  497. if ( rayTestEnum.m_pSurface )
  498. {
  499. *pNormal = rayTestEnum.m_Normal;
  500. }
  501. }
  502. void CVRadDispMgr::AddPolysForRayTrace( void )
  503. {
  504. int nTreeCount = m_DispTrees.Size();
  505. for( int iTree = 0; iTree < nTreeCount; ++iTree )
  506. {
  507. // Get the current displacement collision tree.
  508. CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
  509. // Add the triangles of the tree to the RT environment
  510. pDispTree->AddPolysForRayTrace();
  511. }
  512. }
  513. //-----------------------------------------------------------------------------
  514. //-----------------------------------------------------------------------------
  515. void CVRadDispMgr::GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal,
  516. bool bInside )
  517. {
  518. // get the displacement surface data
  519. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  520. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  521. // find the parameterized displacement indices
  522. Vector2D uv;
  523. pDispTree->BaseFacePlaneToDispUV( pt, uv );
  524. if( bInside )
  525. {
  526. if( uv[0] < 0.0f || uv[0] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[0] ); }
  527. if( uv[1] < 0.0f || uv[1] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[1] ); }
  528. }
  529. if( uv[0] < 0.0f ) { uv[0] = 0.0f; }
  530. if( uv[0] > 1.0f ) { uv[0] = 1.0f; }
  531. if( uv[1] < 0.0f ) { uv[1] = 0.0f; }
  532. if( uv[1] > 1.0f ) { uv[1] = 1.0f; }
  533. // get the normal at "pt"
  534. pDispTree->DispUVToSurfNormal( uv, ptNormal );
  535. // get the new "pt"
  536. pDispTree->DispUVToSurfPoint( uv, pt, 1.0f );
  537. }
  538. //-----------------------------------------------------------------------------
  539. //-----------------------------------------------------------------------------
  540. void CVRadDispMgr::GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree )
  541. {
  542. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  543. *ppDispTree = dispTree.m_pDispTree;
  544. }
  545. //-----------------------------------------------------------------------------
  546. //-----------------------------------------------------------------------------
  547. bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, int context )
  548. {
  549. return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, context );
  550. }
  551. //-----------------------------------------------------------------------------
  552. //-----------------------------------------------------------------------------
  553. bool CVRadDispMgr::DispRay_EnumerateElement( int userId, int context )
  554. {
  555. DispCollTree_t &dispTree = m_DispTrees[userId];
  556. EnumContext_t *pCtx = ( EnumContext_t* )context;
  557. // don't test twice (check tested value)
  558. if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
  559. return true;
  560. // set the tested value
  561. pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
  562. // false mean stop iterating -- return false if we hit! (NOTE: opposite return
  563. // result of the collision tree's ray test, thus the !)
  564. CBaseTrace trace;
  565. trace.fraction = 1.0f;
  566. return ( !dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, pCtx->m_pRay->InvDelta(), &trace, true ) );
  567. }
  568. //-----------------------------------------------------------------------------
  569. //-----------------------------------------------------------------------------
  570. bool CVRadDispMgr::DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pCtx )
  571. {
  572. DispCollTree_t &dispTree = m_DispTrees[userId];
  573. // don't test twice (check tested value)
  574. if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
  575. return true;
  576. // set the tested value
  577. pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
  578. // Test the ray, if it's closer than previous tests, use it!
  579. RayDispOutput_t output;
  580. output.ndxVerts[0] = -1;
  581. output.ndxVerts[1] = -1;
  582. output.ndxVerts[2] = -1;
  583. output.ndxVerts[3] = -1;
  584. output.u = -1.0f;
  585. output.v = -1.0f;
  586. output.dist = FLT_MAX;
  587. if (dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, output ))
  588. {
  589. if (output.dist < pCtx->m_Distance)
  590. {
  591. pCtx->m_Distance = output.dist;
  592. pCtx->m_pSurface = &g_pFaces[dispTree.m_pDispTree->GetParentIndex()];
  593. // Get the luxel coordinate
  594. ComputePointFromBarycentric(
  595. dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[0]),
  596. dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[1]),
  597. dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[2]),
  598. output.u, output.v, pCtx->m_LuxelCoord );
  599. Vector v0,v1,v2;
  600. dispTree.m_pDispTree->GetVert( output.ndxVerts[0], v0 );
  601. dispTree.m_pDispTree->GetVert( output.ndxVerts[1], v1 );
  602. dispTree.m_pDispTree->GetVert( output.ndxVerts[2], v2 );
  603. Vector e0 = v1-v0;
  604. Vector e1 = v2-v0;
  605. pCtx->m_Normal = CrossProduct( e0, e1 );
  606. VectorNormalize(pCtx->m_Normal);
  607. }
  608. }
  609. return true;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Test a ray against a particular dispinfo
  613. //-----------------------------------------------------------------------------
  614. /*
  615. float CVRadDispMgr::ClipRayToDisp( Ray_t const &ray, int dispinfo )
  616. {
  617. assert( m_DispTrees.IsValidIndex(dispinfo) );
  618. RayDispOutput_t output;
  619. if (!m_DispTrees[dispinfo].m_pDispTree->AABBTree_Ray( ray, output ))
  620. return 1.0f;
  621. return output.dist;
  622. }
  623. */
  624. //-----------------------------------------------------------------------------
  625. //-----------------------------------------------------------------------------
  626. bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, int context )
  627. {
  628. //
  629. // add the faces found in this leaf to the face list
  630. //
  631. dleaf_t *pLeaf = &dleafs[ndxLeaf];
  632. for( int ndxFace = 0; ndxFace < pLeaf->numleaffaces; ndxFace++ )
  633. {
  634. // get the current face index
  635. int ndxLeafFace = pLeaf->firstleafface + ndxFace;
  636. // check to see if the face already lives in the list
  637. int ndx;
  638. int size = m_EnumDispFaceList.m_FaceList.Size();
  639. for( ndx = 0; ndx < size; ndx++ )
  640. {
  641. if( m_EnumDispFaceList.m_FaceList[ndx] == ndxLeafFace )
  642. break;
  643. }
  644. if( ndx == size )
  645. {
  646. int ndxList = m_EnumDispFaceList.m_FaceList.AddToTail();
  647. m_EnumDispFaceList.m_FaceList[ndxList] = ndxLeafFace;
  648. }
  649. }
  650. return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispFaceList, context );
  651. }
  652. //-----------------------------------------------------------------------------
  653. //-----------------------------------------------------------------------------
  654. bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, int context )
  655. {
  656. DispCollTree_t &dispTree = m_DispTrees[userId];
  657. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  658. if( !pDispTree )
  659. return false;
  660. // check to see if the displacement already lives in the list
  661. int ndx;
  662. int size = m_EnumDispFaceList.m_DispList.Size();
  663. for( ndx = 0; ndx < size; ndx++ )
  664. {
  665. if( m_EnumDispFaceList.m_DispList[ndx] == pDispTree )
  666. break;
  667. }
  668. if( ndx == size )
  669. {
  670. int ndxList = m_EnumDispFaceList.m_DispList.AddToTail();
  671. m_EnumDispFaceList.m_DispList[ndxList] = pDispTree;
  672. }
  673. return true;
  674. }
  675. //-----------------------------------------------------------------------------
  676. //-----------------------------------------------------------------------------
  677. inline void GetSampleLight( facelight_t *pFaceLight, int ndxStyle, bool bBumped,
  678. int ndxSample, LightingValue_t *pSampleLight )
  679. {
  680. // SampleLight[0].Init( 20.0f, 10.0f, 10.0f );
  681. // return;
  682. // get sample from bumped lighting data
  683. if( bBumped )
  684. {
  685. for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
  686. {
  687. pSampleLight[ndxBump] = pFaceLight->light[ndxStyle][ndxBump][ndxSample];
  688. }
  689. }
  690. // just a generally lit surface
  691. else
  692. {
  693. pSampleLight[0] = pFaceLight->light[ndxStyle][0][ndxSample];
  694. }
  695. }
  696. //-----------------------------------------------------------------------------
  697. //-----------------------------------------------------------------------------
  698. void AddSampleLightToRadial( Vector const &samplePos, Vector const &sampleNormal,
  699. LightingValue_t *pSampleLight, float sampleRadius2,
  700. Vector const &luxelPos, Vector const &luxelNormal,
  701. radial_t *pRadial, int ndxRadial, bool bBumped,
  702. bool bNeighborBumped )
  703. {
  704. // check normals to see if sample contributes any light at all
  705. float angle = sampleNormal.Dot( luxelNormal );
  706. if ( angle < 0.15f )
  707. return;
  708. // calculate the light vector
  709. Vector vSegment = samplePos - luxelPos;
  710. // get the distance to the light
  711. float dist = vSegment.Length();
  712. float dist2 = dist * dist;
  713. // Check to see if the light is within the influence.
  714. float influence = 1.0f - ( dist2 / ( sampleRadius2 ) );
  715. if( influence <= 0.0f )
  716. return;
  717. influence *= angle;
  718. if( bBumped )
  719. {
  720. if( bNeighborBumped )
  721. {
  722. for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
  723. {
  724. pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[ndxBump], influence );
  725. }
  726. pRadial->weight[ndxRadial] += influence;
  727. }
  728. else
  729. {
  730. influence *= 0.05f;
  731. for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
  732. {
  733. pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[0], influence );
  734. }
  735. pRadial->weight[ndxRadial] += influence;
  736. }
  737. }
  738. else
  739. {
  740. pRadial->light[0][ndxRadial].AddWeighted( pSampleLight[0], influence );
  741. pRadial->weight[ndxRadial] += influence;
  742. }
  743. }
  744. //-----------------------------------------------------------------------------
  745. //-----------------------------------------------------------------------------
  746. bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace )
  747. {
  748. if ( iFace == iNeighborFace )
  749. return true;
  750. faceneighbor_t *pFaceNeighbor = &faceneighbor[iFace];
  751. for ( int iNeighbor = 0; iNeighbor < pFaceNeighbor->numneighbors; iNeighbor++ )
  752. {
  753. if ( pFaceNeighbor->neighbor[iNeighbor] == iNeighborFace )
  754. return true;
  755. }
  756. return false;
  757. }
  758. //-----------------------------------------------------------------------------
  759. //-----------------------------------------------------------------------------
  760. void CVRadDispMgr::RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
  761. radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle )
  762. {
  763. // calculate one over the voxel size
  764. float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
  765. //
  766. // find voxel info
  767. //
  768. int voxelMin[3], voxelMax[3];
  769. for( int axis = 0; axis < 3; axis++ )
  770. {
  771. voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
  772. voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
  773. }
  774. SampleData_t sampleData;
  775. for( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
  776. {
  777. for( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
  778. {
  779. for( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
  780. {
  781. sampleData.x = ndxX * 100;
  782. sampleData.y = ndxY * 10;
  783. sampleData.z = ndxZ;
  784. UtlHashHandle_t handle = g_SampleHashTable.Find( sampleData );
  785. if( handle != g_SampleHashTable.InvalidHandle() )
  786. {
  787. SampleData_t *pSampleData = &g_SampleHashTable.Element( handle );
  788. int count = pSampleData->m_Samples.Count();
  789. for( int ndx = 0; ndx < count; ndx++ )
  790. {
  791. SampleHandle_t sampleHandle = pSampleData->m_Samples.Element( ndx );
  792. int ndxSample = ( sampleHandle & 0x0000ffff );
  793. int ndxFaceLight = ( ( sampleHandle >> 16 ) & 0x0000ffff );
  794. facelight_t *pFaceLight = &facelight[ndxFaceLight];
  795. if( pFaceLight && IsNeighbor( ndxFace, ndxFaceLight ) )
  796. {
  797. //
  798. // check for similar lightstyles
  799. //
  800. dface_t *pFace = &g_pFaces[ndxFaceLight];
  801. if( pFace )
  802. {
  803. int ndxNeighborStyle = -1;
  804. for( int ndxLightStyle = 0; ndxLightStyle < MAXLIGHTMAPS; ndxLightStyle++ )
  805. {
  806. if( pFace->styles[ndxLightStyle] == lightStyle )
  807. {
  808. ndxNeighborStyle = ndxLightStyle;
  809. break;
  810. }
  811. }
  812. if( ndxNeighborStyle == -1 )
  813. continue;
  814. // is this surface bumped???
  815. bool bNeighborBump = texinfo[pFace->texinfo].flags & SURF_BUMPLIGHT ? true : false;
  816. LightingValue_t sampleLight[NUM_BUMP_VECTS+1];
  817. GetSampleLight( pFaceLight, ndxNeighborStyle, bNeighborBump, ndxSample, sampleLight );
  818. AddSampleLightToRadial( pFaceLight->sample[ndxSample].pos, pFaceLight->sample[ndxSample].normal,
  819. sampleLight, radius*radius, luxelPt, luxelNormal, pRadial, ndxRadial,
  820. bBump, bNeighborBump );
  821. }
  822. }
  823. }
  824. }
  825. }
  826. }
  827. }
  828. }
  829. //-----------------------------------------------------------------------------
  830. //-----------------------------------------------------------------------------
  831. void CVRadDispMgr::RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
  832. int ndxStyle, bool bBump )
  833. {
  834. //
  835. // get data lighting data
  836. //
  837. int ndxFace = pDispTree->GetParentIndex();
  838. dface_t *pFace = &g_pFaces[ndxFace];
  839. facelight_t *pFaceLight = &facelight[ndxFace];
  840. // get the influence radius
  841. float radius2 = pDispTree->GetSampleRadius2();
  842. float radius = ( float )sqrt( radius2 );
  843. int radialSize = pRadial->w * pRadial->h;
  844. for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
  845. {
  846. RadialLuxelAddSamples( ndxFace, pFaceLight->luxel[ndxRadial], pFaceLight->luxelNormals[ndxRadial],
  847. radius, pRadial, ndxRadial, bBump, pFace->styles[ndxStyle] );
  848. }
  849. }
  850. //-----------------------------------------------------------------------------
  851. //-----------------------------------------------------------------------------
  852. radial_t *CVRadDispMgr::BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump )
  853. {
  854. // allocate the radial
  855. radial_t *pRadial = AllocateRadial( ndxFace );
  856. if( !pRadial )
  857. return NULL;
  858. //
  859. // step 1: get the displacement surface to be lit
  860. //
  861. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  862. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  863. if( !pDispTree )
  864. return NULL;
  865. // step 2: build radial luxels
  866. RadialLuxelBuild( pDispTree, pRadial, ndxStyle, bBump );
  867. // step 3: return the built radial
  868. return pRadial;
  869. }
  870. //-----------------------------------------------------------------------------
  871. //-----------------------------------------------------------------------------
  872. bool CVRadDispMgr::SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl,
  873. LightingValue_t *pLightSample, int sampleCount, bool bPatch )
  874. {
  875. bool bGoodSample = true;
  876. for ( int count = 0; count < sampleCount; count++ )
  877. {
  878. pLightSample[count].Zero();
  879. if ( pRadial->weight[ndxLxl] > 0.0f )
  880. {
  881. pLightSample[count].AddWeighted( pRadial->light[count][ndxLxl], ( 1.0f / pRadial->weight[ndxLxl] ) );
  882. }
  883. else
  884. {
  885. // error, luxel has no samples (not for patches)
  886. if ( !bPatch )
  887. {
  888. // Yes, 2550 is correct!
  889. // pLightSample[count].Init( 2550.0f, 0.0f, 2550.0f );
  890. if( count == 0 )
  891. bGoodSample = false;
  892. }
  893. }
  894. }
  895. return bGoodSample;
  896. }
  897. //-----------------------------------------------------------------------------
  898. //-----------------------------------------------------------------------------
  899. void GetPatchLight( CPatch *pPatch, bool bBump, Vector *pPatchLight )
  900. {
  901. VectorCopy( pPatch->totallight.light[0], pPatchLight[0] );
  902. if( bBump )
  903. {
  904. for( int ndxBump = 1; ndxBump < ( NUM_BUMP_VECTS + 1 ); ndxBump++ )
  905. {
  906. VectorCopy( pPatch->totallight.light[ndxBump], pPatchLight[ndxBump] );
  907. }
  908. }
  909. }
  910. extern void GetBumpNormals( const float* sVect, const float* tVect, const Vector& flatNormal,
  911. const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] );
  912. extern void PreGetBumpNormalsForDisp( texinfo_t *pTexinfo, Vector &vecU, Vector &vecV, Vector &vecNormal );
  913. //-----------------------------------------------------------------------------
  914. //-----------------------------------------------------------------------------
  915. void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal,
  916. Vector *pPatchLight, float patchRadius2,
  917. Vector const &luxelPos, Vector const &luxelNormal,
  918. radial_t *pRadial, int ndxRadial, bool bBump,
  919. bool bNeighborBump )
  920. {
  921. // calculate the light vector
  922. Vector vSegment = patchOrigin - luxelPos;
  923. // get the distance to the light
  924. float dist = vSegment.Length();
  925. float dist2 = dist * dist;
  926. // Check to see if the light is within the sample influence.
  927. float influence = 1.0f - ( dist2 / ( patchRadius2 ) );
  928. if ( influence <= 0.0f )
  929. return;
  930. if( bBump )
  931. {
  932. Vector normals[NUM_BUMP_VECTS+1];
  933. normals[0] = luxelNormal;
  934. texinfo_t *pTexinfo = &texinfo[g_pFaces[pRadial->facenum].texinfo];
  935. Vector vecTexU, vecTexV;
  936. PreGetBumpNormalsForDisp( pTexinfo, vecTexU, vecTexV, normals[0] );
  937. GetBumpNormals( vecTexU, vecTexV, normals[0], normals[0], &normals[1] );
  938. if( bNeighborBump )
  939. {
  940. float flScale = patchNormal.Dot( normals[0] );
  941. flScale = max( 0.0f, flScale );
  942. float flBumpInfluence = influence * flScale;
  943. for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
  944. {
  945. pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[ndxBump], flBumpInfluence );
  946. }
  947. pRadial->weight[ndxRadial] += flBumpInfluence;
  948. }
  949. else
  950. {
  951. float flScale = patchNormal.Dot( normals[0] );
  952. flScale = max( 0.0f, flScale );
  953. float flBumpInfluence = influence * flScale * 0.05f;
  954. for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
  955. {
  956. pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[0], flBumpInfluence );
  957. }
  958. pRadial->weight[ndxRadial] += flBumpInfluence;
  959. }
  960. }
  961. else
  962. {
  963. float flScale = patchNormal.Dot( luxelNormal );
  964. flScale = max( 0.0f, flScale );
  965. influence *= flScale;
  966. pRadial->light[0][ndxRadial].AddWeighted( pPatchLight[0], influence );
  967. // add the weight value
  968. pRadial->weight[ndxRadial] += influence;
  969. }
  970. }
  971. //-----------------------------------------------------------------------------
  972. //-----------------------------------------------------------------------------
  973. void CVRadDispMgr::RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
  974. Vector const &luxelNormal, float radius,
  975. radial_t *pRadial, int ndxRadial, bool bBump,
  976. CUtlVector<CPatch*> &interestingPatches )
  977. {
  978. #ifdef SAMPLEHASH_QUERY_ONCE
  979. for ( int i=0; i < interestingPatches.Count(); i++ )
  980. {
  981. CPatch *pPatch = interestingPatches[i];
  982. bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
  983. Vector patchLight[NUM_BUMP_VECTS+1];
  984. GetPatchLight( pPatch, bBump, patchLight );
  985. AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
  986. luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
  987. }
  988. #else
  989. // calculate one over the voxel size
  990. float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
  991. //
  992. // find voxel info
  993. //
  994. int voxelMin[3], voxelMax[3];
  995. for ( int axis = 0; axis < 3; axis++ )
  996. {
  997. voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
  998. voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
  999. }
  1000. unsigned short curIterationKey = IncrementPatchIterationKey();
  1001. PatchSampleData_t patchData;
  1002. for ( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
  1003. {
  1004. for ( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
  1005. {
  1006. for ( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
  1007. {
  1008. patchData.x = ndxX * 100;
  1009. patchData.y = ndxY * 10;
  1010. patchData.z = ndxZ;
  1011. UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
  1012. if ( handle != g_PatchSampleHashTable.InvalidHandle() )
  1013. {
  1014. PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
  1015. int count = pPatchData->m_ndxPatches.Count();
  1016. for ( int ndx = 0; ndx < count; ndx++ )
  1017. {
  1018. int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
  1019. CPatch *pPatch = &g_Patches.Element( ndxPatch );
  1020. if ( pPatch && pPatch->m_IterationKey != curIterationKey )
  1021. {
  1022. pPatch->m_IterationKey = curIterationKey;
  1023. if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
  1024. {
  1025. bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
  1026. Vector patchLight[NUM_BUMP_VECTS+1];
  1027. GetPatchLight( pPatch, bBump, patchLight );
  1028. AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
  1029. luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
  1030. }
  1031. }
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. #endif
  1038. }
  1039. void CVRadDispMgr::GetInterestingPatchesForLuxels(
  1040. int ndxFace,
  1041. CUtlVector<CPatch*> &interestingPatches,
  1042. float patchSampleRadius )
  1043. {
  1044. facelight_t *pFaceLight = &facelight[ndxFace];
  1045. // Get the max bounds of all voxels that these luxels touch.
  1046. Vector vLuxelMin( FLT_MAX, FLT_MAX, FLT_MAX );
  1047. Vector vLuxelMax( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  1048. for ( int i=0; i < pFaceLight->numluxels; i++ )
  1049. {
  1050. VectorMin( pFaceLight->luxel[i], vLuxelMin, vLuxelMin );
  1051. VectorMax( pFaceLight->luxel[i], vLuxelMax, vLuxelMax );
  1052. }
  1053. int allVoxelMin[3], allVoxelMax[3];
  1054. for ( int axis = 0; axis < 3; axis++ )
  1055. {
  1056. allVoxelMin[axis] = ( int )( ( vLuxelMin[axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
  1057. allVoxelMax[axis] = ( int )( ( vLuxelMax[axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
  1058. }
  1059. int allVoxelSize[3] = { allVoxelMax[0] - allVoxelMin[0], allVoxelMax[1] - allVoxelMin[1], allVoxelMax[2] - allVoxelMin[2] };
  1060. // Now figure out exactly which voxels these luxels touch.
  1061. CUtlVector<unsigned char> voxelBits;
  1062. voxelBits.SetSize( ((allVoxelSize[0] * allVoxelSize[1] * allVoxelSize[2]) + 7) / 8 );
  1063. memset( voxelBits.Base(), 0, voxelBits.Count() );
  1064. for ( int i=0; i < pFaceLight->numluxels; i++ )
  1065. {
  1066. int voxelMin[3], voxelMax[3];
  1067. for ( int axis=0; axis < 3; axis++ )
  1068. {
  1069. voxelMin[axis] = ( int )( ( pFaceLight->luxel[i][axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
  1070. voxelMax[axis] = ( int )( ( pFaceLight->luxel[i][axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
  1071. }
  1072. for ( int x=voxelMin[0]; x < voxelMax[0]; x++ )
  1073. {
  1074. for ( int y=voxelMin[1]; y < voxelMax[1]; y++ )
  1075. {
  1076. for ( int z=voxelMin[2]; z < voxelMax[2]; z++ )
  1077. {
  1078. int iBit = (z - allVoxelMin[2])*(allVoxelSize[0]*allVoxelSize[1]) +
  1079. (y-allVoxelMin[1])*allVoxelSize[0] +
  1080. (x-allVoxelMin[0]);
  1081. voxelBits[iBit>>3] |= (1 << (iBit & 7));
  1082. }
  1083. }
  1084. }
  1085. }
  1086. // Now get the list of patches that touch those voxels.
  1087. unsigned short curIterationKey = IncrementPatchIterationKey();
  1088. for ( int x=0; x < allVoxelSize[0]; x++ )
  1089. {
  1090. for ( int y=0; y < allVoxelSize[1]; y++ )
  1091. {
  1092. for ( int z=0; z < allVoxelSize[2]; z++ )
  1093. {
  1094. // Make sure this voxel has any luxels that care about it.
  1095. int iBit = z*(allVoxelSize[0]*allVoxelSize[1]) + y*allVoxelSize[0] + x;
  1096. unsigned char val = voxelBits[iBit>>3] & (1 << (iBit & 7));
  1097. if ( !val )
  1098. continue;
  1099. PatchSampleData_t patchData;
  1100. patchData.x = (x + allVoxelMin[0]) * 100;
  1101. patchData.y = (y + allVoxelMin[1]) * 10;
  1102. patchData.z = (z + allVoxelMin[2]);
  1103. UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
  1104. if ( handle != g_PatchSampleHashTable.InvalidHandle() )
  1105. {
  1106. PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
  1107. // For all patches that touch this hash table element..
  1108. for ( int ndx = 0; ndx < pPatchData->m_ndxPatches.Count(); ndx++ )
  1109. {
  1110. int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
  1111. CPatch *pPatch = &g_Patches.Element( ndxPatch );
  1112. // If we haven't touched the patch already and it's a valid neighbor, then we want to use it.
  1113. if ( pPatch && pPatch->m_IterationKey != curIterationKey )
  1114. {
  1115. pPatch->m_IterationKey = curIterationKey;
  1116. if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
  1117. {
  1118. interestingPatches.AddToTail( pPatch );
  1119. }
  1120. }
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. //-----------------------------------------------------------------------------
  1129. void CVRadDispMgr::RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
  1130. bool bBump )
  1131. {
  1132. //
  1133. // get data lighting data
  1134. //
  1135. int ndxFace = pDispTree->GetParentIndex();
  1136. facelight_t *pFaceLight = &facelight[ndxFace];
  1137. // get the influence radius
  1138. float radius2 = pDispTree->GetPatchSampleRadius2();
  1139. float radius = ( float )sqrt( radius2 );
  1140. CUtlVector<CPatch*> interestingPatches;
  1141. #ifdef SAMPLEHASH_QUERY_ONCE
  1142. GetInterestingPatchesForLuxels( ndxFace, interestingPatches, radius );
  1143. #endif
  1144. int radialSize = pRadial->w * pRadial->h;
  1145. for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
  1146. {
  1147. RadialLuxelAddPatch(
  1148. ndxFace,
  1149. pFaceLight->luxel[ndxRadial],
  1150. pFaceLight->luxelNormals[ndxRadial],
  1151. radius,
  1152. pRadial,
  1153. ndxRadial,
  1154. bBump,
  1155. interestingPatches );
  1156. }
  1157. }
  1158. //-----------------------------------------------------------------------------
  1159. //-----------------------------------------------------------------------------
  1160. radial_t *CVRadDispMgr::BuildPatchRadial( int ndxFace, bool bBump )
  1161. {
  1162. // allocate the radial
  1163. radial_t *pRadial = AllocateRadial( ndxFace );
  1164. if( !pRadial )
  1165. return NULL;
  1166. //
  1167. // step 1: get the displacement surface to be lit
  1168. //
  1169. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  1170. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  1171. if( !pDispTree )
  1172. return NULL;
  1173. // step 2: build radial of patch light
  1174. RadialPatchBuild( pDispTree, pRadial, bBump );
  1175. // step 3: return the built radial
  1176. return pRadial;
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. //-----------------------------------------------------------------------------
  1180. bool SampleInSolid( sample_t *pSample )
  1181. {
  1182. int ndxLeaf = PointLeafnum( pSample->pos );
  1183. return ( dleafs[ndxLeaf].contents == CONTENTS_SOLID );
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. //-----------------------------------------------------------------------------
  1187. void CVRadDispMgr::InsertSamplesDataIntoHashTable( void )
  1188. {
  1189. int totalSamples = 0;
  1190. #if 0
  1191. int totalSamplesInSolid = 0;
  1192. #endif
  1193. for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
  1194. {
  1195. dface_t *pFace = &g_pFaces[ndxFace];
  1196. facelight_t *pFaceLight = &facelight[ndxFace];
  1197. if( !pFace || !pFaceLight )
  1198. continue;
  1199. if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
  1200. continue;
  1201. #if 0
  1202. bool bDisp = ( pFace->dispinfo != -1 );
  1203. #endif
  1204. //
  1205. // for each sample
  1206. //
  1207. for( int ndxSample = 0; ndxSample < pFaceLight->numsamples; ndxSample++ )
  1208. {
  1209. sample_t *pSample = &pFaceLight->sample[ndxSample];
  1210. if( pSample )
  1211. {
  1212. #if 0
  1213. if( bDisp )
  1214. {
  1215. // test sample to see if the displacement samples resides in solid
  1216. if( SampleInSolid( pSample ) )
  1217. {
  1218. totalSamplesInSolid++;
  1219. continue;
  1220. }
  1221. }
  1222. #endif
  1223. // create the sample handle
  1224. SampleHandle_t sampleHandle = ndxSample;
  1225. sampleHandle |= ( ndxFace << 16 );
  1226. SampleData_AddSample( pSample, sampleHandle );
  1227. }
  1228. }
  1229. totalSamples += pFaceLight->numsamples;
  1230. }
  1231. #if 0
  1232. // not implemented yet!!!
  1233. Msg( "%d samples in solid\n", totalSamplesInSolid );
  1234. #endif
  1235. // log the distribution
  1236. SampleData_Log();
  1237. }
  1238. //-----------------------------------------------------------------------------
  1239. //-----------------------------------------------------------------------------
  1240. void CVRadDispMgr::InsertPatchSampleDataIntoHashTable( void )
  1241. {
  1242. // don't insert patch samples if we are not bouncing light
  1243. if( numbounce <= 0 )
  1244. return;
  1245. int totalPatchSamples = 0;
  1246. for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
  1247. {
  1248. dface_t *pFace = &g_pFaces[ndxFace];
  1249. facelight_t *pFaceLight = &facelight[ndxFace];
  1250. if( !pFace || !pFaceLight )
  1251. continue;
  1252. if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
  1253. continue;
  1254. //
  1255. // for each patch
  1256. //
  1257. CPatch *pNextPatch = NULL;
  1258. if( g_FacePatches.Element( ndxFace ) != g_FacePatches.InvalidIndex() )
  1259. {
  1260. for( CPatch *pPatch = &g_Patches.Element( g_FacePatches.Element( ndxFace ) ); pPatch; pPatch = pNextPatch )
  1261. {
  1262. // next patch
  1263. pNextPatch = NULL;
  1264. if( pPatch->ndxNext != g_Patches.InvalidIndex() )
  1265. {
  1266. pNextPatch = &g_Patches.Element( pPatch->ndxNext );
  1267. }
  1268. // skip patches with children
  1269. if( pPatch->child1 != g_Patches.InvalidIndex() )
  1270. continue;
  1271. int ndxPatch = pPatch - g_Patches.Base();
  1272. PatchSampleData_AddSample( pPatch, ndxPatch );
  1273. totalPatchSamples++;
  1274. }
  1275. }
  1276. }
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. //-----------------------------------------------------------------------------
  1280. void CVRadDispMgr::StartTimer( const char *name )
  1281. {
  1282. Msg( name );
  1283. m_Timer.Start();
  1284. }
  1285. //-----------------------------------------------------------------------------
  1286. //-----------------------------------------------------------------------------
  1287. void CVRadDispMgr::EndTimer( void )
  1288. {
  1289. m_Timer.End();
  1290. CCycleCount duration = m_Timer.GetDuration();
  1291. double seconds = duration.GetSeconds();
  1292. Msg( "Done<%1.4lf sec>\n", seconds );
  1293. }
  1294. //-----------------------------------------------------------------------------
  1295. //-----------------------------------------------------------------------------
  1296. bool CVRadDispMgr::BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  1297. {
  1298. // get the tree assosciated with the face
  1299. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  1300. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  1301. if( !pDispTree )
  1302. return false;
  1303. // lightmap size
  1304. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  1305. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  1306. // calculate the steps in uv space
  1307. float stepU = 1.0f / ( float )width;
  1308. float stepV = 1.0f / ( float )height;
  1309. float halfStepU = stepU * 0.5f;
  1310. float halfStepV = stepV * 0.5f;
  1311. //
  1312. // build the winding points (used to generate world space winding and
  1313. // calculate the area of the "sample")
  1314. //
  1315. int ndxU, ndxV;
  1316. CUtlVector<sample_t> samples;
  1317. samples.SetCount( SINGLEMAP );
  1318. sample_t *pSamples = samples.Base();
  1319. CUtlVector<Vector> worldPoints;
  1320. worldPoints.SetCount( SINGLEMAP );
  1321. Vector *pWorldPoints = worldPoints.Base();
  1322. for( ndxV = 0; ndxV < ( height + 1 ); ndxV++ )
  1323. {
  1324. for( ndxU = 0; ndxU < ( width + 1 ); ndxU++ )
  1325. {
  1326. int ndx = ( ndxV * ( width + 1 ) ) + ndxU;
  1327. Vector2D uv( ndxU * stepU, ndxV * stepV );
  1328. pDispTree->DispUVToSurfPoint( uv, pWorldPoints[ndx], 0.0f );
  1329. }
  1330. }
  1331. for( ndxV = 0; ndxV < height; ndxV++ )
  1332. {
  1333. for( ndxU = 0; ndxU < width; ndxU++ )
  1334. {
  1335. // build the winding
  1336. winding_t *pWinding = AllocWinding( 4 );
  1337. if( pWinding )
  1338. {
  1339. pWinding->numpoints = 4;
  1340. pWinding->p[0] = pWorldPoints[(ndxV*(width+1))+ndxU];
  1341. pWinding->p[1] = pWorldPoints[((ndxV+1)*(width+1))+ndxU];
  1342. pWinding->p[2] = pWorldPoints[((ndxV+1)*(width+1))+(ndxU+1)];
  1343. pWinding->p[3] = pWorldPoints[(ndxV*(width+1))+(ndxU+1)];
  1344. // calculate the area
  1345. float area = WindingArea( pWinding );
  1346. int ndxSample = ( ndxV * width ) + ndxU;
  1347. pSamples[ndxSample].w = pWinding;
  1348. pSamples[ndxSample].area = area;
  1349. }
  1350. else
  1351. {
  1352. Msg( "BuildDispSamples: WARNING - failed winding allocation\n" );
  1353. }
  1354. }
  1355. }
  1356. //
  1357. // build the samples points (based on s, t and sampleoffset (center of samples);
  1358. // generates world space position and normal)
  1359. //
  1360. for( ndxV = 0; ndxV < height; ndxV++ )
  1361. {
  1362. for( ndxU = 0; ndxU < width; ndxU++ )
  1363. {
  1364. int ndxSample = ( ndxV * width ) + ndxU;
  1365. pSamples[ndxSample].s = ndxU;
  1366. pSamples[ndxSample].t = ndxV;
  1367. pSamples[ndxSample].coord[0] = ( ndxU * stepU ) + halfStepU;
  1368. pSamples[ndxSample].coord[1] = ( ndxV * stepV ) + halfStepV;
  1369. pDispTree->DispUVToSurfPoint( pSamples[ndxSample].coord, pSamples[ndxSample].pos, 1.0f );
  1370. pDispTree->DispUVToSurfNormal( pSamples[ndxSample].coord, pSamples[ndxSample].normal );
  1371. }
  1372. }
  1373. //
  1374. // copy over samples
  1375. //
  1376. pFaceLight->numsamples = width * height;
  1377. pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
  1378. if( !pFaceLight->sample )
  1379. return false;
  1380. memcpy( pFaceLight->sample, pSamples, pFaceLight->numsamples * sizeof( *pFaceLight->sample ) );
  1381. // statistics - warning?!
  1382. if( pFaceLight->numsamples == 0 )
  1383. {
  1384. Msg( "BuildDispSamples: WARNING - no samples %d\n", pLightInfo->face - g_pFaces );
  1385. }
  1386. return true;
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. //-----------------------------------------------------------------------------
  1390. bool CVRadDispMgr::BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  1391. {
  1392. // get the tree assosciated with the face
  1393. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  1394. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  1395. if( !pDispTree )
  1396. return false;
  1397. // lightmap size
  1398. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  1399. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  1400. // calcuate actual luxel points
  1401. pFaceLight->numluxels = width * height;
  1402. pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
  1403. pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
  1404. if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
  1405. return false;
  1406. float stepU = 1.0f / ( float )( width - 1 );
  1407. float stepV = 1.0f / ( float )( height - 1 );
  1408. for( int ndxV = 0; ndxV < height; ndxV++ )
  1409. {
  1410. for( int ndxU = 0; ndxU < width; ndxU++ )
  1411. {
  1412. int ndxLuxel = ( ndxV * width ) + ndxU;
  1413. Vector2D uv( ndxU * stepU, ndxV * stepV );
  1414. pDispTree->DispUVToSurfPoint( uv, pFaceLight->luxel[ndxLuxel], 1.0f );
  1415. pDispTree->DispUVToSurfNormal( uv, pFaceLight->luxelNormals[ndxLuxel] );
  1416. }
  1417. }
  1418. return true;
  1419. }
  1420. //-----------------------------------------------------------------------------
  1421. //-----------------------------------------------------------------------------
  1422. bool CVRadDispMgr::BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  1423. {
  1424. // get the tree assosciated with the face
  1425. DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
  1426. CVRADDispColl *pDispTree = dispTree.m_pDispTree;
  1427. if( !pDispTree )
  1428. return false;
  1429. // lightmap size
  1430. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  1431. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  1432. // calcuate actual luxel points
  1433. pFaceLight->numsamples = width * height;
  1434. pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
  1435. if( !pFaceLight->sample )
  1436. return false;
  1437. pFaceLight->numluxels = width * height;
  1438. pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
  1439. pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
  1440. if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
  1441. return false;
  1442. float stepU = 1.0f / ( float )( width - 1 );
  1443. float stepV = 1.0f / ( float )( height - 1 );
  1444. float halfStepU = stepU * 0.5f;
  1445. float halfStepV = stepV * 0.5f;
  1446. for( int ndxV = 0; ndxV < height; ndxV++ )
  1447. {
  1448. for( int ndxU = 0; ndxU < width; ndxU++ )
  1449. {
  1450. int ndx = ( ndxV * width ) + ndxU;
  1451. pFaceLight->sample[ndx].s = ndxU;
  1452. pFaceLight->sample[ndx].t = ndxV;
  1453. pFaceLight->sample[ndx].coord[0] = ( ndxU * stepU ) + halfStepU;
  1454. pFaceLight->sample[ndx].coord[1] = ( ndxV * stepV ) + halfStepV;
  1455. pDispTree->DispUVToSurfPoint( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].pos, 1.0f );
  1456. pDispTree->DispUVToSurfNormal( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].normal );
  1457. pFaceLight->luxel[ndx] = pFaceLight->sample[ndx].pos;
  1458. pFaceLight->luxelNormals[ndx] = pFaceLight->sample[ndx].normal;
  1459. }
  1460. }
  1461. return true;
  1462. }