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.

1009 lines
30 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "render_pch.h"
  10. #include "modelloader.h"
  11. #include "gl_model_private.h"
  12. #include "gl_lightmap.h"
  13. #include "disp.h"
  14. #include "mathlib/mathlib.h"
  15. #include "gl_rsurf.h"
  16. #include "gl_matsysiface.h"
  17. #include "zone.h"
  18. #include "materialsystem/imesh.h"
  19. #include "materialsystem/ivballoctracker.h"
  20. #include "mathlib/vector.h"
  21. #include "iscratchpad3d.h"
  22. #include "tier0/fasttimer.h"
  23. #include "lowpassstream.h"
  24. #include "con_nprint.h"
  25. #include "tier2/tier2.h"
  26. #include "tier0/dbg.h"
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. void BuildTagData( CCoreDispInfo *pCoreDisp, CDispInfo *pDisp );
  30. void SmoothDispSurfNormals( CCoreDispInfo **ppListBase, int nListSize );
  31. // This makes sure that whoever is creating and deleting CDispInfos frees them all
  32. // (and calls their destructors) before the module is gone.
  33. class CConstructorChecker
  34. {
  35. public:
  36. CConstructorChecker() {m_nConstructedObjects = 0;}
  37. ~CConstructorChecker() {Assert(m_nConstructedObjects == 0);}
  38. int m_nConstructedObjects;
  39. } g_ConstructorChecker;
  40. //-----------------------------------------------------------------------------
  41. // Static helpers.
  42. //-----------------------------------------------------------------------------
  43. static void BuildDispGetSurfNormals( Vector points[4], Vector normals[4] )
  44. {
  45. //
  46. // calculate the displacement surface normal
  47. //
  48. Vector tmp[2];
  49. Vector normal;
  50. tmp[0] = points[1] - points[0];
  51. tmp[1] = points[3] - points[0];
  52. normal = tmp[1].Cross( tmp[0] );
  53. VectorNormalize( normal );
  54. for( int i = 0; i < 4; i++ )
  55. {
  56. normals[i] = normal;
  57. }
  58. }
  59. static bool FindExtraDependency( unsigned short *pDependencies, int nDependencies, int iDisp )
  60. {
  61. for( int i=0; i < nDependencies; i++ )
  62. {
  63. if ( pDependencies[i] == iDisp )
  64. return true;
  65. }
  66. return false;
  67. }
  68. static CDispGroup* FindCombo( CUtlVector<CDispGroup*> &combos, int idLMPage, IMaterial *pMaterial )
  69. {
  70. for( int i=0; i < combos.Count(); i++ )
  71. {
  72. if( combos[i]->m_LightmapPageID == idLMPage && combos[i]->m_pMaterial == pMaterial )
  73. return combos[i];
  74. }
  75. return NULL;
  76. }
  77. static CDispGroup* AddCombo( CUtlVector<CDispGroup*> &combos, int idLMPage, IMaterial *pMaterial )
  78. {
  79. CDispGroup *pCombo = new CDispGroup;
  80. pCombo->m_LightmapPageID = idLMPage;
  81. pCombo->m_pMaterial = pMaterial;
  82. pCombo->m_nVisible = 0;
  83. combos.AddToTail( pCombo );
  84. return pCombo;
  85. }
  86. static inline CDispInfo* GetModelDisp( model_t const *pWorld, int i )
  87. {
  88. return static_cast< CDispInfo* >(
  89. DispInfo_IndexArray( pWorld->brush.pShared->hDispInfos, i ) );
  90. }
  91. static void BuildDispSurfInit(
  92. model_t *pWorld,
  93. CCoreDispInfo *pBuildDisp,
  94. SurfaceHandle_t worldSurfID )
  95. {
  96. if( !IS_SURF_VALID( worldSurfID ) )
  97. return;
  98. ASSERT_SURF_VALID( worldSurfID );
  99. Vector surfPoints[4];
  100. Vector surfNormals[4];
  101. Vector2D surfTexCoords[4];
  102. Vector2D surfLightCoords[4][4];
  103. if ( MSurf_VertCount( worldSurfID ) != 4 )
  104. return;
  105. #ifndef DEDICATED
  106. BuildMSurfaceVerts( pWorld->brush.pShared, worldSurfID, surfPoints, surfTexCoords, surfLightCoords );
  107. #endif
  108. BuildDispGetSurfNormals( surfPoints, surfNormals );
  109. CCoreDispSurface *pDispSurf = pBuildDisp->GetSurface();
  110. int surfFlag = pDispSurf->GetFlags();
  111. int nLMVects = 1;
  112. if( MSurf_Flags( worldSurfID ) & SURFDRAW_BUMPLIGHT )
  113. {
  114. surfFlag |= CCoreDispInfo::SURF_BUMPED;
  115. nLMVects = NUM_BUMP_VECTS + 1;
  116. }
  117. pDispSurf->SetPointCount( 4 );
  118. for( int i = 0; i < 4; i++ )
  119. {
  120. pDispSurf->SetPoint( i, surfPoints[i] );
  121. pDispSurf->SetPointNormal( i, surfNormals[i] );
  122. pDispSurf->SetTexCoord( i, surfTexCoords[i] );
  123. for( int j = 0; j < nLMVects; j++ )
  124. {
  125. pDispSurf->SetLuxelCoord( j, i, surfLightCoords[i][j] );
  126. }
  127. }
  128. Vector vecS = MSurf_TexInfo( worldSurfID )->textureVecsTexelsPerWorldUnits[0].AsVector3D();
  129. Vector vecT = MSurf_TexInfo( worldSurfID )->textureVecsTexelsPerWorldUnits[1].AsVector3D();
  130. VectorNormalize( vecS );
  131. VectorNormalize( vecT );
  132. pDispSurf->SetSAxis( vecS );
  133. pDispSurf->SetTAxis( vecT );
  134. pDispSurf->SetFlags( surfFlag );
  135. pDispSurf->FindSurfPointStartIndex();
  136. pDispSurf->AdjustSurfPointData();
  137. #ifndef DEDICATED
  138. //
  139. // adjust the lightmap coordinates -- this is currently done redundantly!
  140. // the will be fixed correctly when the displacement common code is written.
  141. // This is here to get things running for (GDC, E3)
  142. //
  143. SurfaceCtx_t ctx;
  144. SurfSetupSurfaceContext( ctx, worldSurfID );
  145. int lightmapWidth = MSurf_LightmapExtents( worldSurfID )[0];
  146. int lightmapHeight = MSurf_LightmapExtents( worldSurfID )[1];
  147. Vector2D uv( 0.0f, 0.0f );
  148. for ( int ndxLuxel = 0; ndxLuxel < 4; ndxLuxel++ )
  149. {
  150. switch( ndxLuxel )
  151. {
  152. case 0: { uv.Init( 0.0f, 0.0f ); break; }
  153. case 1: { uv.Init( 0.0f, ( float )lightmapHeight ); break; }
  154. case 2: { uv.Init( ( float )lightmapWidth, ( float )lightmapHeight ); break; }
  155. case 3: { uv.Init( ( float )lightmapWidth, 0.0f ); break; }
  156. }
  157. uv.x += 0.5f;
  158. uv.y += 0.5f;
  159. uv *= ctx.m_Scale;
  160. uv += ctx.m_Offset;
  161. pDispSurf->SetLuxelCoord( 0, ndxLuxel, uv );
  162. }
  163. #endif
  164. }
  165. VertexFormat_t ComputeDisplacementStaticMeshVertexFormat( const IMaterial * pMaterial, const CDispGroup *pCombo, const ddispinfo_t *pMapDisps )
  166. {
  167. VertexFormat_t vertexFormat = pMaterial->GetVertexFormat();
  168. // FIXME: set VERTEX_FORMAT_COMPRESSED if there are no artifacts and if it saves enough memory (use 'mem_dumpvballocs')
  169. vertexFormat &= ~VERTEX_FORMAT_COMPRESSED;
  170. // FIXME: check for and strip unused vertex elements (TANGENT_S/T?)
  171. return vertexFormat;
  172. }
  173. void AddEmptyMesh(
  174. model_t *pWorld,
  175. CDispGroup *pCombo,
  176. const ddispinfo_t *pMapDisps,
  177. int *pDispInfos,
  178. int nDisps,
  179. int nTotalVerts,
  180. int nTotalIndices )
  181. {
  182. CMatRenderContextPtr pRenderContext( materials );
  183. CGroupMesh *pMesh = new CGroupMesh;
  184. pCombo->m_Meshes.AddToTail( pMesh );
  185. VertexFormat_t vertexFormat = ComputeDisplacementStaticMeshVertexFormat( pCombo->m_pMaterial, pCombo, pMapDisps );
  186. pMesh->m_pMesh = pRenderContext->CreateStaticMesh( vertexFormat, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_DISP );
  187. pMesh->m_pGroup = pCombo;
  188. pMesh->m_nVisible = 0;
  189. CMeshBuilder builder;
  190. builder.Begin( pMesh->m_pMesh, MATERIAL_TRIANGLES, nTotalVerts, nTotalIndices );
  191. // Just advance the verts and indices and leave the data blank for now.
  192. builder.AdvanceIndices( nTotalIndices );
  193. builder.AdvanceVertices( nTotalVerts );
  194. builder.End();
  195. pMesh->m_DispInfos.SetSize( nDisps );
  196. pMesh->m_Visible.SetSize( nDisps );
  197. pMesh->m_VisibleDisps.SetSize( nDisps );
  198. int iVertOffset = 0;
  199. int iIndexOffset = 0;
  200. for( int iDisp=0; iDisp < nDisps; iDisp++ )
  201. {
  202. CDispInfo *pDisp = GetModelDisp( pWorld, pDispInfos[iDisp] );
  203. const ddispinfo_t *pMapDisp = &pMapDisps[ pDispInfos[iDisp] ];
  204. pDisp->m_pMesh = pMesh;
  205. pDisp->m_iVertOffset = iVertOffset;
  206. pDisp->m_iIndexOffset = iIndexOffset;
  207. int nVerts, nIndices;
  208. CalcMaxNumVertsAndIndices( pMapDisp->power, &nVerts, &nIndices );
  209. iVertOffset += nVerts;
  210. iIndexOffset += nIndices;
  211. pMesh->m_DispInfos[iDisp] = pDisp;
  212. }
  213. Assert( iVertOffset == nTotalVerts );
  214. Assert( iIndexOffset == nTotalIndices );
  215. }
  216. void FillStaticBuffer(
  217. CGroupMesh *pMesh,
  218. CDispInfo *pDisp,
  219. const CCoreDispInfo *pCoreDisp,
  220. const CDispVert *pVerts,
  221. int nLightmaps )
  222. {
  223. #ifndef DEDICATED
  224. // Put the verts into the buffer.
  225. int nVerts, nIndices;
  226. CalcMaxNumVertsAndIndices( pDisp->GetPower(), &nVerts, &nIndices );
  227. CMeshBuilder builder;
  228. builder.BeginModify( pMesh->m_pMesh, pDisp->m_iVertOffset, nVerts, 0, 0 );
  229. SurfaceCtx_t ctx;
  230. SurfSetupSurfaceContext( ctx, pDisp->GetParent() );
  231. for( int i=0; i < nVerts; i++ )
  232. {
  233. // NOTE: position comes from our system-memory buffer so when you're restoring
  234. // static buffers (from alt+tab), it includes changes from terrain mods.
  235. const Vector &vPos = pCoreDisp->GetVert( i );
  236. builder.Position3f( vPos.x, vPos.y, vPos.z );
  237. const Vector &vNormal = pCoreDisp->GetNormal( i );
  238. builder.Normal3f( vNormal.x, vNormal.y, vNormal.z );
  239. Vector vec;
  240. pCoreDisp->GetTangentS( i, vec );
  241. builder.TangentS3f( VectorExpand( vec ) );
  242. pCoreDisp->GetTangentT( i, vec );
  243. builder.TangentT3f( VectorExpand( vec ) );
  244. Vector2D texCoord;
  245. pCoreDisp->GetTexCoord( i, texCoord );
  246. builder.TexCoord2f( 0, texCoord.x, texCoord.y );
  247. Vector2D lightCoord;
  248. {
  249. pCoreDisp->GetLuxelCoord( 0, i, lightCoord );
  250. builder.TexCoord2f( DISP_LMCOORDS_STAGE, lightCoord.x, lightCoord.y );
  251. }
  252. if ( ( pCoreDisp->GetFlags() & DISP_INFO_FLAG_HAS_MULTIBLEND ) != 0 )
  253. {
  254. Vector4D vMultiBlend, vAlphaBlend;
  255. Vector vMultiBlendColor[ MAX_MULTIBLEND_CHANNELS ];
  256. pCoreDisp->GetMultiBlend( i, vMultiBlend, vAlphaBlend, vMultiBlendColor[ 0 ], vMultiBlendColor[ 1 ], vMultiBlendColor[ 2 ], vMultiBlendColor[ 3 ] );
  257. builder.TexCoord4fv( DISP_MULTIBLEND_STAGE, vAlphaBlend.Base() );
  258. for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
  259. {
  260. builder.TexCoord4f( DISP_MULTIBLEND_STAGE + i + 1, vMultiBlendColor[ i ].x, vMultiBlendColor[ i ].y, vMultiBlendColor[ i ].z, vMultiBlend.Base()[ i ] );
  261. }
  262. builder.Specular4fv( vMultiBlend.Base() );
  263. }
  264. float flAlpha = ( ( CCoreDispInfo * )pCoreDisp )->GetAlpha( i );
  265. flAlpha *= ( 1.0f / 255.0f );
  266. flAlpha = clamp( flAlpha, 0.0f, 1.0f );
  267. builder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
  268. if( nLightmaps > 1 )
  269. {
  270. SurfComputeLightmapCoordinate( ctx, pDisp->GetParent(), pDisp->m_Verts[i].m_vPos, lightCoord );
  271. builder.TexCoord2f( 2, ctx.m_BumpSTexCoordOffset, 0.0f );
  272. }
  273. builder.AdvanceVertex();
  274. }
  275. builder.EndModify();
  276. #endif
  277. }
  278. void CDispInfo::CopyMapDispData( const ddispinfo_t *pBuildDisp )
  279. {
  280. m_iLightmapAlphaStart = pBuildDisp->m_iLightmapAlphaStart;
  281. m_Power = pBuildDisp->power;
  282. Assert( m_Power >= 2 && m_Power <= NUM_POWERINFOS );
  283. m_pPowerInfo = ::GetPowerInfo( m_Power );
  284. // Max # of indices:
  285. // Take the number of triangles (2 * (size-1) * (size-1))
  286. // and multiply by 3!
  287. // These can be non-null in the case of task switch restore
  288. int size = GetSideLength();
  289. m_Indices.SetSize( 6 * (size-1) * (size-1) );
  290. // Per-node information
  291. if (m_pNodeInfo)
  292. delete[] m_pNodeInfo;
  293. m_pNodeInfo = new DispNodeInfo_t[m_pPowerInfo->m_NodeCount];
  294. }
  295. void DispInfo_CreateMaterialGroups( model_t *pWorld, const MaterialSystem_SortInfo_t *pSortInfos )
  296. {
  297. for ( int iDisp=0; iDisp < pWorld->brush.pShared->numDispInfos; iDisp++ )
  298. {
  299. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  300. int idLMPage = pSortInfos[MSurf_MaterialSortID( pDisp->m_ParentSurfID )].lightmapPageID;
  301. CDispGroup *pCombo = FindCombo( g_DispGroups, idLMPage, MSurf_TexInfo( pDisp->m_ParentSurfID )->material );
  302. if( !pCombo )
  303. pCombo = AddCombo( g_DispGroups, idLMPage, MSurf_TexInfo( pDisp->m_ParentSurfID )->material );
  304. MEM_ALLOC_CREDIT();
  305. pCombo->m_DispInfos.AddToTail( iDisp );
  306. }
  307. }
  308. void DispInfo_LinkToParentFaces( model_t *pWorld, const ddispinfo_t *pMapDisps, int nDisplacements )
  309. {
  310. for ( int iDisp=0; iDisp < nDisplacements; iDisp++ )
  311. {
  312. const ddispinfo_t *pMapDisp = &pMapDisps[iDisp];
  313. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  314. // Set its parent.
  315. SurfaceHandle_t surfID = SurfaceHandleFromIndex( pMapDisp->m_iMapFace );
  316. Assert( pMapDisp->m_iMapFace < pWorld->brush.pShared->numsurfaces );
  317. Assert( MSurf_Flags( surfID ) & SURFDRAW_HAS_DISP );
  318. surfID->pDispInfo = pDisp;
  319. pDisp->SetParent( surfID );
  320. }
  321. }
  322. void DispInfo_CreateEmptyStaticBuffers( model_t *pWorld, const ddispinfo_t *pMapDisps )
  323. {
  324. // For each combo, create empty buffers.
  325. for( int i=0; i < g_DispGroups.Count(); i++ )
  326. {
  327. CDispGroup *pCombo = g_DispGroups[i];
  328. int nTotalVerts=0, nTotalIndices=0;
  329. int iStart = 0;
  330. for( int iDisp=0; iDisp < pCombo->m_DispInfos.Count(); iDisp++ )
  331. {
  332. const ddispinfo_t *pMapDisp = &pMapDisps[pCombo->m_DispInfos[iDisp]];
  333. int nVerts, nIndices;
  334. CalcMaxNumVertsAndIndices( pMapDisp->power, &nVerts, &nIndices );
  335. // If we're going to pass our vertex buffer limit, or we're at the last one,
  336. // make a static buffer and fill it up.
  337. if( (nTotalVerts + nVerts) > MAX_STATIC_BUFFER_VERTS ||
  338. (nTotalIndices + nIndices) > MAX_STATIC_BUFFER_INDICES )
  339. {
  340. AddEmptyMesh( pWorld, pCombo, pMapDisps, &pCombo->m_DispInfos[iStart], iDisp-iStart, nTotalVerts, nTotalIndices );
  341. Assert( nTotalVerts > 0 && nTotalIndices > 0 );
  342. nTotalVerts = nTotalIndices = 0;
  343. iStart = iDisp;
  344. --iDisp;
  345. }
  346. else if( iDisp == pCombo->m_DispInfos.Count()-1 )
  347. {
  348. AddEmptyMesh( pWorld, pCombo, pMapDisps, &pCombo->m_DispInfos[iStart], iDisp-iStart+1, nTotalVerts+nVerts, nTotalIndices+nIndices );
  349. break;
  350. }
  351. else
  352. {
  353. nTotalVerts += nVerts;
  354. nTotalIndices += nIndices;
  355. }
  356. }
  357. }
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Purpose:
  361. // Input : *pWorld -
  362. // iDisp -
  363. // *pMapDisp -
  364. // *pCoreDisp -
  365. // *pVerts -
  366. // pWorld -
  367. // iDisp -
  368. // Output : Returns true on success, false on failure.
  369. // Information: Setup the CCoreDispInfo using the ddispinfo_t and have it translate the data
  370. // into a format we'll copy into the rendering structures. This roundaboutness is because
  371. // of legacy code. It should all just be stored in the map file, but it's not a high priority right now.
  372. //-----------------------------------------------------------------------------
  373. bool DispInfo_CreateFromMapDisp( model_t *pWorld, int iDisp, const ddispinfo_t *pMapDisp, CCoreDispInfo *pCoreDisp, const CDispVert *pVerts,
  374. const CDispTri *pTris, const CDispMultiBlend *pMultiBlend, const MaterialSystem_SortInfo_t *pSortInfos, bool bRestoring )
  375. {
  376. // Get the matching CDispInfo to fill in.
  377. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  378. // Initialize the core disp info with data from the map displacement.
  379. pCoreDisp->GetSurface()->SetPointStart( pMapDisp->startPosition );
  380. pCoreDisp->InitDispInfo( pMapDisp->power, pMapDisp->minTess, pMapDisp->smoothingAngle, pVerts, pTris, pMapDisp->minTess, pMultiBlend );
  381. pCoreDisp->SetNeighborData( pMapDisp->m_EdgeNeighbors, pMapDisp->m_CornerNeighbors );
  382. // Copy the allowed verts list.
  383. ErrorIfNot( pCoreDisp->GetAllowedVerts().GetNumDWords() == sizeof( pMapDisp->m_AllowedVerts ) / 4, ( "DispInfo_StoreMapData: size mismatch in 'allowed verts' list" ) );
  384. for ( int iVert = 0; iVert < pCoreDisp->GetAllowedVerts().GetNumDWords(); ++iVert )
  385. {
  386. pCoreDisp->GetAllowedVerts().SetDWord( iVert, pMapDisp->m_AllowedVerts[iVert] );
  387. }
  388. // Build the reset of the intermediate data from the initial map displacement data.
  389. BuildDispSurfInit( pWorld, pCoreDisp, pDisp->GetParent() );
  390. if ( !pCoreDisp->Create() )
  391. return false;
  392. // Save the point start index - needed for overlays.
  393. pDisp->m_iPointStart = pCoreDisp->GetSurface()->GetPointStartIndex();
  394. // Now setup the CDispInfo.
  395. pDisp->m_Index = static_cast<unsigned short>( iDisp );
  396. // Store ddispinfo_t data.
  397. pDisp->CopyMapDispData( pMapDisp );
  398. // Store CCoreDispInfo data.
  399. if( !pDisp->CopyCoreDispData( pWorld, pSortInfos, pCoreDisp, bRestoring ) )
  400. return false;
  401. // Initialize all the active and other verts after setting up neighbors.
  402. pDisp->InitializeActiveVerts();
  403. pDisp->m_iLightmapSamplePositionStart = pMapDisp->m_iLightmapSamplePositionStart;
  404. return true;
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose:
  408. // Input : *pWorld -
  409. // iDisp -
  410. // *pCoreDisp -
  411. // *pVerts -
  412. // Output : Returns true on success, false on failure.
  413. //-----------------------------------------------------------------------------
  414. void DispInfo_CreateStaticBuffersAndTags( model_t *pWorld, int iDisp, CCoreDispInfo *pCoreDisp, const CDispVert *pVerts )
  415. {
  416. // Get the matching CDispInfo to fill in.
  417. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  418. // Now copy the CCoreDisp's data into the static buffer.
  419. FillStaticBuffer( pDisp->m_pMesh, pDisp, pCoreDisp, pVerts, pDisp->NumLightMaps() );
  420. // Now build the tagged data for visualization.
  421. BuildTagData( pCoreDisp, pDisp );
  422. }
  423. // On the xbox, we lock the meshes ahead of time.
  424. void SetupMeshReaders( model_t *pWorld, int nDisplacements )
  425. {
  426. for ( int iDisp=0; iDisp < nDisplacements; iDisp++ )
  427. {
  428. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  429. MeshDesc_t desc;
  430. memset( &desc, 0, sizeof( desc ) );
  431. desc.m_VertexSize_Position = sizeof( CDispRenderVert );
  432. desc.m_VertexSize_TexCoord[0] = sizeof( CDispRenderVert );
  433. desc.m_VertexSize_TexCoord[DISP_LMCOORDS_STAGE] = sizeof( CDispRenderVert );
  434. desc.m_VertexSize_Normal = sizeof( CDispRenderVert );
  435. desc.m_VertexSize_TangentS = sizeof( CDispRenderVert );
  436. desc.m_VertexSize_TangentT = sizeof( CDispRenderVert );
  437. CDispRenderVert *pBaseVert = pDisp->m_Verts.Base();
  438. desc.m_pPosition = (float*)&pBaseVert->m_vPos;
  439. desc.m_pTexCoord[0] = (float*)&pBaseVert->m_vTexCoord;
  440. desc.m_pTexCoord[DISP_LMCOORDS_STAGE] = (float*)&pBaseVert->m_LMCoords;
  441. desc.m_pNormal = (float*)&pBaseVert->m_vNormal;
  442. desc.m_pTangentS = (float*)&pBaseVert->m_vSVector;
  443. desc.m_pTangentT = (float*)&pBaseVert->m_vTVector;
  444. desc.m_nIndexSize = 1;
  445. desc.m_pIndices = pDisp->m_Indices.Base();
  446. pDisp->m_MeshReader.BeginRead_Direct( desc, pDisp->NumVerts(), pDisp->m_nIndices );
  447. }
  448. }
  449. void UpdateDispBBoxes( model_t *pWorld, int nDisplacements )
  450. {
  451. for ( int iDisp=0; iDisp < nDisplacements; iDisp++ )
  452. {
  453. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  454. pDisp->UpdateBoundingBox();
  455. }
  456. }
  457. #include "tier0/memdbgoff.h"
  458. bool DispInfo_LoadDisplacements( model_t *pWorld, bool bRestoring )
  459. {
  460. MEM_ALLOC_CREDIT_( "DispInfo_LoadDisplacements" );
  461. const MaterialSystem_SortInfo_t *pSortInfos = materialSortInfoArray;
  462. int nDisplacements = CMapLoadHelper::LumpSize( LUMP_DISPINFO ) / sizeof( ddispinfo_t );
  463. int nSamplePositionBytes = CMapLoadHelper::LumpSize( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
  464. // Setup the world's list of displacements.
  465. if ( bRestoring )
  466. {
  467. /* Breakpoint-able: */
  468. if (pWorld->brush.pShared->numDispInfos != nDisplacements)
  469. {
  470. volatile int a = 0; a = a + 1;
  471. }
  472. if ( !pWorld->brush.pShared->numDispInfos && nDisplacements )
  473. {
  474. // Attempting to restore displacements before displacements got loaded
  475. return false;
  476. }
  477. ErrorIfNot(
  478. pWorld->brush.pShared->numDispInfos == nDisplacements,
  479. ("DispInfo_LoadDisplacments: dispcounts (%d and %d) don't match.", pWorld->brush.pShared->numDispInfos, nDisplacements)
  480. );
  481. }
  482. else
  483. {
  484. // Create the displacements.
  485. pWorld->brush.pShared->numDispInfos = nDisplacements;
  486. pWorld->brush.pShared->hDispInfos = DispInfo_CreateArray( pWorld->brush.pShared->numDispInfos );
  487. static ConVarRef r_dlightsenable( "r_dlightsenable" );
  488. if ( r_dlightsenable.GetBool() )
  489. {
  490. // Load lightmap sample positions (only needed to support dlights).
  491. HUNK_ALLOC_CREDIT_( "g_DispLightmapSamplePositions" );
  492. g_DispLightmapSamplePositions.SetSize( nSamplePositionBytes );
  493. CMapLoadHelper lhDispLMPositions( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
  494. lhDispLMPositions.LoadLumpData( 0, nSamplePositionBytes, g_DispLightmapSamplePositions.Base() );
  495. }
  496. }
  497. // Free old data.
  498. DispInfo_ReleaseMaterialSystemObjects( pWorld );
  499. // load the displacement info structures into temporary space
  500. // using temporary storage that is not the stack for compatibility with console stack
  501. #if 0 //#ifndef _GAMECONSOLE // With large MAX_MAP_DISPINFO we always want to use heap to avoid a stack overflow on PC as well.
  502. ddispinfo_t tempDisps[MAX_MAP_DISPINFO];
  503. #else
  504. CUtlMemory< ddispinfo_t > m_DispInfoBuf( 0, MAX_MAP_DISPINFO );
  505. ddispinfo_t *tempDisps = m_DispInfoBuf.Base();
  506. #endif
  507. ErrorIfNot(
  508. nDisplacements <= MAX_MAP_DISPINFO,
  509. ("DispInfo_LoadDisplacements: nDisplacements (%d) > MAX_MAP_DISPINFO (%d)", nDisplacements, MAX_MAP_DISPINFO)
  510. );
  511. CMapLoadHelper lhDispInfo( LUMP_DISPINFO );
  512. lhDispInfo.LoadLumpData( 0, nDisplacements * sizeof( ddispinfo_t ), tempDisps );
  513. // Now hook up the displacements to their parents.
  514. DispInfo_LinkToParentFaces( pWorld, tempDisps, nDisplacements );
  515. // First, create "groups" (or "combos") which contain all the displacements that
  516. // use the same material and lightmap.
  517. DispInfo_CreateMaterialGroups( pWorld, pSortInfos );
  518. // Now make the static buffers for each material/lightmap combo.
  519. if ( g_VBAllocTracker )
  520. g_VBAllocTracker->TrackMeshAllocations( "DispInfo_LoadDisplacements" );
  521. DispInfo_CreateEmptyStaticBuffers( pWorld, tempDisps );
  522. if ( g_VBAllocTracker )
  523. g_VBAllocTracker->TrackMeshAllocations( NULL );
  524. // Now setup each displacement one at a time.
  525. // using temporary storage that is not the stack for compatibility with console stack
  526. #ifndef _GAMECONSOLE
  527. CDispVert tempVerts[MAX_DISPVERTS];
  528. #else
  529. CUtlMemory< CDispVert > m_DispVertsBuf( 0, MAX_DISPVERTS );
  530. CDispVert *tempVerts = m_DispVertsBuf.Base();
  531. #endif
  532. #ifndef _GAMECONSOLE
  533. CDispTri tempTris[MAX_DISPTRIS];
  534. #else
  535. // using temporary storage that is not the stack for compatibility with console stack
  536. CUtlMemory< CDispTri > m_DispTrisBuf( 0, MAX_DISPTRIS );
  537. CDispTri *tempTris = m_DispTrisBuf.Base();
  538. #endif
  539. #ifndef _GAMECONSOLE
  540. CDispMultiBlend tempMultiBlend[MAX_DISPVERTS];
  541. #else
  542. CUtlMemory< CDispMultiBlend > m_DispMultiBlendBuf( 0, MAX_DISPVERTS );
  543. CDispMultiBlend *tempMultiBlend = m_DispMultiBlendBuf.Base();
  544. #endif
  545. int iCurVert = 0;
  546. int iCurTri = 0;
  547. int iCurMultiBlend = 0;
  548. // Core displacement list.
  549. CUtlVector<CCoreDispInfo*> aCoreDisps;
  550. int iDisp = 0;
  551. for ( iDisp = 0; iDisp < nDisplacements; ++iDisp )
  552. {
  553. CCoreDispInfo *pCoreDisp = new CCoreDispInfo;
  554. aCoreDisps.AddToTail( pCoreDisp );
  555. }
  556. CMapLoadHelper lhDispVerts( LUMP_DISP_VERTS );
  557. CMapLoadHelper lhDispTris( LUMP_DISP_TRIS );
  558. CMapLoadHelper lhDispMultiBLend( LUMP_DISP_MULTIBLEND );
  559. for ( iDisp = 0; iDisp < nDisplacements; ++iDisp )
  560. {
  561. // Get the current map displacement.
  562. ddispinfo_t *pMapDisp = &tempDisps[iDisp];
  563. if ( !pMapDisp )
  564. continue;
  565. // Load the vertices from the file.
  566. int nVerts = NUM_DISP_POWER_VERTS( pMapDisp->power );
  567. ErrorIfNot( nVerts <= MAX_DISPVERTS, ( "DispInfo_LoadDisplacements: invalid vertex count (%d)", nVerts ) );
  568. lhDispVerts.LoadLumpData( iCurVert * sizeof(CDispVert), nVerts*sizeof(CDispVert), tempVerts );
  569. if ( ( pMapDisp->minTess & DISP_INFO_FLAG_HAS_MULTIBLEND ) != 0 )
  570. {
  571. lhDispMultiBLend.LoadLumpData( iCurMultiBlend * sizeof( CDispMultiBlend ), nVerts * sizeof( CDispMultiBlend ), tempMultiBlend );
  572. iCurMultiBlend += nVerts;
  573. }
  574. iCurVert += nVerts;
  575. // Load the triangle indices from the file.
  576. int nTris = NUM_DISP_POWER_TRIS( pMapDisp->power );
  577. ErrorIfNot( nTris <= MAX_DISPTRIS, ( "DispInfo_LoadDisplacements: invalid tri count (%d)", nTris ) );
  578. lhDispTris.LoadLumpData( iCurTri * sizeof(CDispTri), nTris*sizeof(CDispTri), tempTris );
  579. iCurTri += nTris;
  580. // Now create the CoreDispInfo and the base CDispInfo.
  581. if ( !DispInfo_CreateFromMapDisp( pWorld, iDisp, pMapDisp, aCoreDisps[iDisp], tempVerts, tempTris, tempMultiBlend, pSortInfos, bRestoring ) )
  582. return false;
  583. }
  584. // Smooth Normals.
  585. SmoothDispSurfNormals( aCoreDisps.Base(), nDisplacements );
  586. // Fill in the static buffers.
  587. for ( iDisp = 0; iDisp < nDisplacements; ++iDisp )
  588. {
  589. DispInfo_CreateStaticBuffersAndTags( pWorld, iDisp, aCoreDisps[iDisp], tempVerts );
  590. // Copy over the now blended normals
  591. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  592. pDisp->CopyCoreDispVertData( aCoreDisps[iDisp], pDisp->m_BumpSTexCoordOffset );
  593. }
  594. // Destroy core displacement list.
  595. aCoreDisps.PurgeAndDeleteElements();
  596. // If we're not using LOD, then maximally tesselate all the displacements and
  597. // make sure they never change.
  598. for ( iDisp=0; iDisp < nDisplacements; iDisp++ )
  599. {
  600. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  601. pDisp->m_ActiveVerts = pDisp->m_AllowedVerts;
  602. }
  603. for ( iDisp=0; iDisp < nDisplacements; iDisp++ )
  604. {
  605. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  606. pDisp->TesselateDisplacement();
  607. }
  608. SetupMeshReaders( pWorld, nDisplacements );
  609. UpdateDispBBoxes( pWorld, nDisplacements );
  610. return true;
  611. }
  612. #include "tier0/memdbgon.h"
  613. void DispInfo_ReleaseMaterialSystemObjects( model_t *pWorld )
  614. {
  615. CMatRenderContextPtr pRenderContext( materials );
  616. // Free all the static meshes.
  617. for( int iGroup=0; iGroup < g_DispGroups.Count(); iGroup++ )
  618. {
  619. CDispGroup *pGroup = g_DispGroups[iGroup];
  620. for( int iMesh=0; iMesh < pGroup->m_Meshes.Count(); iMesh++ )
  621. {
  622. CGroupMesh *pMesh = pGroup->m_Meshes[iMesh];
  623. pRenderContext->DestroyStaticMesh( pMesh->m_pMesh );
  624. }
  625. pGroup->m_Meshes.PurgeAndDeleteElements();
  626. }
  627. g_DispGroups.PurgeAndDeleteElements();
  628. // Clear pointers in the dispinfos.
  629. if( pWorld )
  630. {
  631. for( int iDisp=0; iDisp < pWorld->brush.pShared->numDispInfos; iDisp++ )
  632. {
  633. CDispInfo *pDisp = GetModelDisp( pWorld, iDisp );
  634. if ( !pDisp )
  635. {
  636. AssertOnce( 0 );
  637. continue;
  638. }
  639. pDisp->m_pMesh = NULL;
  640. pDisp->m_iVertOffset = pDisp->m_iIndexOffset = 0;
  641. }
  642. }
  643. }
  644. //-----------------------------------------------------------------------------
  645. // CDispInfo implementation.
  646. //-----------------------------------------------------------------------------
  647. CDispInfo::CDispInfo()
  648. {
  649. m_ParentSurfID = SURFACE_HANDLE_INVALID;
  650. m_bTouched = false;
  651. ++g_ConstructorChecker.m_nConstructedObjects;
  652. m_BBoxMin.Init();
  653. m_BBoxMax.Init();
  654. m_idLMPage = -1;
  655. m_pPowerInfo = NULL;
  656. m_ViewerSphereCenter.Init( 1e24, 1e24, 1e24 );
  657. m_bInUse = false;
  658. m_pNodeInfo = 0;
  659. m_pMesh = NULL;
  660. m_Tag = NULL;
  661. m_pDispArray = NULL;
  662. m_FirstDecal = DISP_DECAL_HANDLE_INVALID;
  663. m_FirstShadowDecal = DISP_SHADOW_HANDLE_INVALID;
  664. for ( int i=0; i < 4; i++ )
  665. {
  666. m_EdgeNeighbors[i].SetInvalid();
  667. m_CornerNeighbors[i].SetInvalid();
  668. }
  669. }
  670. CDispInfo::~CDispInfo()
  671. {
  672. if (m_pNodeInfo)
  673. delete[] m_pNodeInfo;
  674. delete[] m_pWalkIndices;
  675. delete[] m_pBuildIndices;
  676. --g_ConstructorChecker.m_nConstructedObjects;
  677. // All the decals should have been freed through
  678. // CModelLoader::Map_UnloadModel -> R_DecalTerm
  679. Assert( m_FirstDecal == DISP_DECAL_HANDLE_INVALID );
  680. Assert( m_FirstShadowDecal == DISP_SHADOW_HANDLE_INVALID );
  681. }
  682. void CDispInfo::CopyCoreDispVertData( const CCoreDispInfo *pCoreDisp, float bumpSTexCoordOffset )
  683. {
  684. #ifndef DEDICATED
  685. if( NumLightMaps() <= 1 )
  686. {
  687. bumpSTexCoordOffset = 0.0f;
  688. }
  689. // Copy vertex positions (for backfacing tests).
  690. HUNK_ALLOC_CREDIT_( "CopyCoreDispVertData" );
  691. m_Verts.SetSize( m_pPowerInfo->m_MaxVerts );
  692. m_BumpSTexCoordOffset = bumpSTexCoordOffset;
  693. for( int i=0; i < NumVerts(); i++ )
  694. {
  695. pCoreDisp->GetVert( i, m_Verts[i].m_vPos );
  696. pCoreDisp->GetTexCoord( i, m_Verts[i].m_vTexCoord );
  697. pCoreDisp->GetLuxelCoord( 0, i, m_Verts[i].m_LMCoords );
  698. // mat_normals needs this as well as the dynamic lighting code
  699. pCoreDisp->GetNormal( i, m_Verts[i].m_vNormal );
  700. pCoreDisp->GetTangentS( i, m_Verts[i].m_vSVector );
  701. pCoreDisp->GetTangentT( i, m_Verts[i].m_vTVector );
  702. }
  703. #endif
  704. }
  705. bool CDispInfo::CopyCoreDispData(
  706. model_t *pWorld,
  707. const MaterialSystem_SortInfo_t *pSortInfos,
  708. const CCoreDispInfo *pCoreDisp,
  709. bool bRestoring )
  710. {
  711. m_idLMPage = pSortInfos[MSurf_MaterialSortID( GetParent() )].lightmapPageID;
  712. #ifndef DEDICATED
  713. SurfaceCtx_t ctx;
  714. SurfSetupSurfaceContext( ctx, GetParent() );
  715. #endif
  716. // Restoring is only for alt+tabbing, which can't happen on consoles
  717. if ( IsPC() && bRestoring )
  718. {
  719. #ifndef DEDICATED
  720. // When restoring, have to recompute lightmap coords
  721. if( NumLightMaps() > 1 )
  722. {
  723. m_BumpSTexCoordOffset = ctx.m_BumpSTexCoordOffset;
  724. }
  725. else
  726. {
  727. m_BumpSTexCoordOffset = 0.0f;
  728. }
  729. for( int i=0; i < NumVerts(); i++ )
  730. {
  731. pCoreDisp->GetLuxelCoord( 0, i, m_Verts[i].m_LMCoords );
  732. }
  733. #endif // DEDICATED
  734. return true;
  735. }
  736. // When restoring, leave all this data the same.
  737. const CCoreDispSurface *pSurface = pCoreDisp->GetSurface();
  738. for( int index=0; index < 4; index++ )
  739. {
  740. pSurface->GetTexCoord( index, m_BaseSurfaceTexCoords[index] );
  741. m_BaseSurfacePositions[index] = pSurface->GetPoint( index );
  742. }
  743. #ifndef DEDICATED
  744. CopyCoreDispVertData( pCoreDisp, ctx.m_BumpSTexCoordOffset );
  745. #endif
  746. // Copy neighbor info.
  747. for ( int iEdge=0; iEdge < 4; iEdge++ )
  748. {
  749. m_EdgeNeighbors[iEdge] = *pCoreDisp->GetEdgeNeighbor( iEdge );
  750. m_CornerNeighbors[iEdge] = *pCoreDisp->GetCornerNeighbors( iEdge );
  751. }
  752. // Copy allowed verts.
  753. m_AllowedVerts = pCoreDisp->GetAllowedVerts();
  754. m_nIndices = 0;
  755. return true;
  756. }
  757. int CDispInfo::NumLightMaps()
  758. {
  759. return (MSurf_Flags( m_ParentSurfID ) & SURFDRAW_BUMPLIGHT) ? NUM_BUMP_VECTS+1 : 1;
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose:
  763. // NOTE: You cannot use the builddisp.cpp IsTriWalkable, IsTriBuildable functions
  764. // because the flags are different having been collapsed in vbsp
  765. //-----------------------------------------------------------------------------
  766. void BuildTagData( CCoreDispInfo *pCoreDisp, CDispInfo *pDisp )
  767. {
  768. int nWalkTest = 0;
  769. int nBuildTest = 0;
  770. int iTri;
  771. for ( iTri = 0; iTri < pCoreDisp->GetTriCount(); ++iTri )
  772. {
  773. if ( pCoreDisp->IsTriTag( iTri, DISPTRI_TAG_WALKABLE ) )
  774. {
  775. nWalkTest++;
  776. }
  777. if ( pCoreDisp->IsTriTag( iTri, DISPTRI_TAG_BUILDABLE ) )
  778. {
  779. nBuildTest++;
  780. }
  781. }
  782. nWalkTest *= 3;
  783. nBuildTest *= 3;
  784. pDisp->m_pWalkIndices = new unsigned short[nWalkTest];
  785. pDisp->m_pBuildIndices = new unsigned short[nBuildTest];
  786. int nWalkCount = 0;
  787. int nBuildCount = 0;
  788. for ( iTri = 0; iTri < pCoreDisp->GetTriCount(); ++iTri )
  789. {
  790. if ( pCoreDisp->IsTriTag( iTri, DISPTRI_TAG_WALKABLE ) )
  791. {
  792. pCoreDisp->GetTriIndices( iTri,
  793. pDisp->m_pWalkIndices[nWalkCount],
  794. pDisp->m_pWalkIndices[nWalkCount+1],
  795. pDisp->m_pWalkIndices[nWalkCount+2] );
  796. nWalkCount += 3;
  797. }
  798. if ( pCoreDisp->IsTriTag( iTri, DISPTRI_TAG_BUILDABLE ) )
  799. {
  800. pCoreDisp->GetTriIndices( iTri,
  801. pDisp->m_pBuildIndices[nBuildCount],
  802. pDisp->m_pBuildIndices[nBuildCount+1],
  803. pDisp->m_pBuildIndices[nBuildCount+2] );
  804. nBuildCount += 3;
  805. }
  806. }
  807. Assert( nWalkCount == nWalkTest );
  808. Assert( nBuildCount == nBuildTest );
  809. pDisp->m_nWalkIndexCount = nWalkCount;
  810. pDisp->m_nBuildIndexCount = nBuildCount;
  811. }