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.

1086 lines
33 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. // wrapper for the material system for the engine.
  10. #include "render_pch.h"
  11. #include "view.h"
  12. #include "zone.h"
  13. #include <float.h>
  14. #include "sys_dll.h"
  15. #include "materialsystem/imesh.h"
  16. #include "gl_water.h"
  17. #include "utlrbtree.h"
  18. #include "istudiorender.h"
  19. #include "tier0/dbg.h"
  20. #include "keyvalues.h"
  21. #include "vstdlib/random.h"
  22. #include "lightcache.h"
  23. #include "sysexternal.h"
  24. #include "cmd.h"
  25. #include "modelloader.h"
  26. #include "tier0/icommandline.h"
  27. #include "materialsystem/imaterial.h"
  28. #include "toolframework/itoolframework.h"
  29. #include "toolframework/itoolsystem.h"
  30. #include "tier2/p4helpers.h"
  31. #include "p4lib/ip4.h"
  32. #include "vgui/ISystem.h"
  33. #include <vgui_controls/Controls.h>
  34. #include "paint.h"
  35. extern ConVar developer;
  36. #ifdef _WIN32
  37. #include <crtdbg.h>
  38. #endif
  39. // memdbgon must be the last include file in a .cpp file!!!
  40. #include "tier0/memdbgon.h"
  41. #ifndef DEDICATED
  42. IMaterial* g_materialWireframe;
  43. IMaterial* g_materialTranslucentSingleColor;
  44. IMaterial* g_materialTranslucentVertexColor;
  45. IMaterial* g_materialWorldWireframe;
  46. IMaterial* g_materialWorldWireframeZBuffer;
  47. IMaterial* g_materialWorldWireframeGreen;
  48. IMaterial* g_materialBrushWireframe;
  49. IMaterial* g_materialDecalWireframe;
  50. IMaterial* g_materialDebugLightmap;
  51. IMaterial* g_materialDebugLightmapZBuffer;
  52. IMaterial* g_materialDebugLuxels;
  53. IMaterial* g_materialLeafVisWireframe;
  54. IMaterial* g_pMaterialWireframeVertexColor;
  55. IMaterial* g_pMaterialWireframeVertexColorIgnoreZ;
  56. IMaterial* g_pMaterialLightSprite;
  57. IMaterial* g_pMaterialShadowBuild;
  58. IMaterial* g_pMaterialMRMWireframe;
  59. IMaterial* g_pMaterialWriteZ;
  60. IMaterial* g_pMaterialWaterDuDv;
  61. IMaterial* g_pMaterialWaterFirstPass;
  62. IMaterial* g_pMaterialWaterSecondPass;
  63. IMaterial* g_pMaterialAmbientCube;
  64. IMaterial* g_pMaterialDebugFlat;
  65. IMaterial* g_pMaterialDepthWrite[2][2];
  66. IMaterial* g_pMaterialSSAODepthWrite[ 2 ][ 2 ];
  67. #ifdef NEWMESH
  68. CUtlVector<IVertexBuffer *> g_WorldStaticMeshes; // fixme - rename to g_WorldStaticVertexBuffers
  69. #else
  70. CUtlVector<IMesh *> g_WorldStaticMeshes;
  71. #endif
  72. void WorldStaticMeshCreate( void );
  73. void WorldStaticMeshDestroy( void );
  74. bool TangentSpaceSurfaceSetup( SurfaceHandle_t surfID, Vector &tVect );
  75. void TangentSpaceComputeBasis( Vector& tangent, Vector& binormal, const Vector& normal, const Vector& tVect, bool negateTangent );
  76. //-----------------------------------------------------------------------------
  77. // A console command edit a particular material
  78. //-----------------------------------------------------------------------------
  79. CON_COMMAND_F( mat_edit, "Bring up the material under the crosshair in the editor", FCVAR_CHEAT )
  80. {
  81. if ( !toolframework->InToolMode() )
  82. return;
  83. IMaterial* pMaterial = NULL;
  84. if ( args.ArgC() < 2 )
  85. {
  86. pMaterial = GetMaterialAtCrossHair();
  87. }
  88. else
  89. {
  90. const char *pMaterialName = args[ 1 ];
  91. pMaterial = materials->FindMaterial( pMaterialName, "edited materials", false );
  92. }
  93. if ( !pMaterial )
  94. {
  95. ConMsg( "no/bad material\n" );
  96. }
  97. else
  98. {
  99. IToolSystem *pToolSystem = toolframework->SwitchToTool( "Material Editor" );
  100. if ( pToolSystem )
  101. {
  102. ConMsg( "editing material \"%s\"\n", pMaterial->GetName() );
  103. KeyValues *pKeyValues = new KeyValues( "EditMaterial" );
  104. pKeyValues->SetString( "material", pMaterial->GetName() );
  105. pToolSystem->PostToolMessage( 0, pKeyValues );
  106. pKeyValues->deleteThis();
  107. }
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. // A console command to spew out the material under the crosshair
  112. //-----------------------------------------------------------------------------
  113. CON_COMMAND_F( mat_crosshair, "Display the name of the material under the crosshair", FCVAR_CHEAT )
  114. {
  115. IMaterial* pMaterial = GetMaterialAtCrossHair();
  116. if (!pMaterial)
  117. ConMsg ("no/bad material\n");
  118. else
  119. ConMsg ("hit material \"%s\"\n", pMaterial->GetName());
  120. }
  121. //-----------------------------------------------------------------------------
  122. // A console command to open the material under the crosshair in the associated editor.
  123. //-----------------------------------------------------------------------------
  124. CON_COMMAND_F( mat_crosshair_edit, "open the material under the crosshair in the editor defined by mat_crosshair_edit_editor", FCVAR_CHEAT )
  125. {
  126. IMaterial* pMaterial = GetMaterialAtCrossHair();
  127. if (!pMaterial)
  128. {
  129. ConMsg ("no/bad material\n");
  130. }
  131. else
  132. {
  133. char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
  134. Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vmt", pMaterial->GetName() );
  135. char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
  136. if ( p4 )
  137. {
  138. CP4AutoEditAddFile autop4( szResolvedName );
  139. }
  140. else
  141. {
  142. Warning( "run with -p4 to get p4 operations upon mat_crosshair_edit\n" );
  143. }
  144. vgui::system()->ShellExecute( "open", szResolvedName );
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. // A console command to open the material under the crosshair in the associated editor.
  149. //-----------------------------------------------------------------------------
  150. CON_COMMAND_F( mat_crosshair_explorer, "open the material under the crosshair in explorer and highlight the vmt file", FCVAR_CHEAT )
  151. {
  152. IMaterial* pMaterial = GetMaterialAtCrossHair();
  153. if (!pMaterial)
  154. {
  155. ConMsg ("no/bad material\n");
  156. }
  157. else
  158. {
  159. char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
  160. Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vmt", pMaterial->GetName() );
  161. char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
  162. char params[256];
  163. Q_snprintf( params, sizeof( params ) - 1, "/E,/SELECT,%s", szResolvedName );
  164. vgui::system()->ShellExecuteEx( "open", "explorer.exe", params );
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // A console command to open the material under the crosshair in the associated editor.
  169. //-----------------------------------------------------------------------------
  170. CON_COMMAND_F( mat_crosshair_reloadmaterial, "reload the material under the crosshair", FCVAR_CHEAT )
  171. {
  172. IMaterial* pMaterial = GetMaterialAtCrossHair();
  173. if (!pMaterial)
  174. {
  175. ConMsg ("no/bad material\n");
  176. }
  177. else
  178. {
  179. materials->ReloadMaterials( pMaterial->GetName() );
  180. }
  181. }
  182. CON_COMMAND_F( mat_crosshair_printmaterial, "print the material under the crosshair", FCVAR_CHEAT )
  183. {
  184. IMaterial* pMaterial = GetMaterialAtCrossHair();
  185. if (!pMaterial)
  186. {
  187. ConMsg ("no/bad material\n");
  188. }
  189. else
  190. {
  191. materials->DebugPrintUsedMaterials( pMaterial->GetName(), true );
  192. }
  193. }
  194. static void RegisterLightmappedSurface( SurfaceHandle_t surfID )
  195. {
  196. int lightmapSize[2];
  197. int allocationWidth, allocationHeight;
  198. bool bNeedsBumpmap;
  199. // fixme: lightmapSize needs to be in msurface_t once we
  200. // switch over to having lightmap size untied to base texture
  201. // size
  202. lightmapSize[0] = ( MSurf_LightmapExtents( surfID )[0] ) + 1;
  203. lightmapSize[1] = ( MSurf_LightmapExtents( surfID )[1] ) + 1;
  204. // Allocate all bumped lightmaps next to each other so that we can just
  205. // increment the s texcoord by pSurf->bumpSTexCoordOffset to render the next
  206. // of the three lightmaps
  207. bNeedsBumpmap = SurfNeedsBumpedLightmaps( surfID );
  208. if( bNeedsBumpmap )
  209. {
  210. MSurf_Flags( surfID ) |= SURFDRAW_BUMPLIGHT;
  211. allocationWidth = lightmapSize[0] * ( NUM_BUMP_VECTS+1 );
  212. }
  213. else
  214. {
  215. MSurf_Flags( surfID ) &= ~SURFDRAW_BUMPLIGHT;
  216. allocationWidth = lightmapSize[0];
  217. }
  218. allocationHeight = lightmapSize[1];
  219. // register this surface's lightmap
  220. int offsetIntoLightmapPage[2];
  221. MSurf_MaterialSortID( surfID ) = materials->AllocateLightmap(
  222. allocationWidth,
  223. allocationHeight,
  224. offsetIntoLightmapPage,
  225. MSurf_TexInfo( surfID )->material );
  226. MSurf_OffsetIntoLightmapPage( surfID )[0] = offsetIntoLightmapPage[0];
  227. MSurf_OffsetIntoLightmapPage( surfID )[1] = offsetIntoLightmapPage[1];
  228. }
  229. static void RegisterUnlightmappedSurface( SurfaceHandle_t surfID )
  230. {
  231. MSurf_MaterialSortID( surfID ) = materials->AllocateWhiteLightmap( MSurf_TexInfo( surfID )->material );
  232. MSurf_OffsetIntoLightmapPage( surfID )[0] = 0;
  233. MSurf_OffsetIntoLightmapPage( surfID )[1] = 0;
  234. }
  235. static bool LightmapLess( const SurfaceHandle_t& surfID1, const SurfaceHandle_t& surfID2 )
  236. {
  237. // FIXME: This really should be in the material system,
  238. // as it completely depends on the behavior of the lightmap packer
  239. bool hasLightmap1 = (MSurf_Flags( surfID1 ) & SURFDRAW_NOLIGHT) == 0;
  240. bool hasLightmap2 = (MSurf_Flags( surfID2 ) & SURFDRAW_NOLIGHT) == 0;
  241. // We want lightmapped surfaces to show up first
  242. if (hasLightmap1 != hasLightmap2)
  243. return hasLightmap1 > hasLightmap2;
  244. // The sort by enumeration ID
  245. IMaterial* pMaterial1 = MSurf_TexInfo( surfID1 )->material;
  246. IMaterial* pMaterial2 = MSurf_TexInfo( surfID2 )->material;
  247. int enum1 = pMaterial1->GetEnumerationID();
  248. int enum2 = pMaterial2->GetEnumerationID();
  249. if (enum1 != enum2)
  250. return enum1 < enum2;
  251. bool hasLightstyle1 = (MSurf_Flags( surfID1 ) & SURFDRAW_HASLIGHTSYTLES) == 0;
  252. bool hasLightstyle2 = (MSurf_Flags( surfID2 ) & SURFDRAW_HASLIGHTSYTLES) == 0;
  253. // We want Lightstyled surfaces to show up first
  254. if (hasLightstyle1 != hasLightstyle2)
  255. return hasLightstyle1 > hasLightstyle2;
  256. // Then sort by lightmap area for better packing... (big areas first)
  257. // NOTE: Don't care about bumpmap increasing area here because it is a linear factor
  258. // (all surfs with the same material have the same bumpmapping cost)
  259. #if 1
  260. int area1 = MSurf_LightmapExtents( surfID1 )[0] * MSurf_LightmapExtents( surfID1 )[1];
  261. int area2 = MSurf_LightmapExtents( surfID2 )[0] * MSurf_LightmapExtents( surfID2 )[1];
  262. return area2 < area1;
  263. #else
  264. // Previous algorithm: pack minimum height first
  265. // NOTE: In d1_trainstation_05, greatest area results in fewer material splits
  266. // so I've switched over to that heuristic
  267. return MSurf_LightmapExtents( surfID1 )[1] < MSurf_LightmapExtents( surfID2 )[1];
  268. #endif
  269. }
  270. void MaterialSystem_RegisterLightmapSurfaces( void )
  271. {
  272. SurfaceHandle_t surfID = SURFACE_HANDLE_INVALID;
  273. materials->BeginLightmapAllocation();
  274. // Add all the surfaces to a list, sorted by lightmapped
  275. // then by material enumeration then by area
  276. CUtlRBTree< SurfaceHandle_t, int > surfaces( 0, host_state.worldbrush->numsurfaces, LightmapLess );
  277. for( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ )
  278. {
  279. surfID = SurfaceHandleFromIndex( surfaceIndex );
  280. if( ( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) ||
  281. ( MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) )
  282. {
  283. MSurf_Flags( surfID ) |= SURFDRAW_NOLIGHT;
  284. }
  285. else
  286. {
  287. MSurf_Flags( surfID ) &= ~SURFDRAW_NOLIGHT;
  288. }
  289. surfaces.Insert(surfID);
  290. }
  291. // iterate sorted surfaces
  292. surfID = SURFACE_HANDLE_INVALID;
  293. for (int i = surfaces.FirstInorder(); i != surfaces.InvalidIndex(); i = surfaces.NextInorder(i) )
  294. {
  295. SurfaceHandle_t surfID = surfaces[i];
  296. bool hasLightmap = ( MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) == 0;
  297. if ( hasLightmap )
  298. {
  299. RegisterLightmappedSurface( surfID );
  300. }
  301. else
  302. {
  303. RegisterUnlightmappedSurface( surfID );
  304. }
  305. }
  306. materials->EndLightmapAllocation();
  307. }
  308. static void TestBumpSanity( SurfaceHandle_t surfID )
  309. {
  310. ASSERT_SURF_VALID( surfID );
  311. // use the last one to check if we need a bumped lightmap, but don't have it so that we can warn.
  312. bool needsBumpmap = SurfNeedsBumpedLightmaps( surfID );
  313. bool hasBumpmap = SurfHasBumpedLightmaps( surfID );
  314. if ( needsBumpmap && !hasBumpmap && MSurf_Samples( surfID ) )
  315. {
  316. Warning( "Need to rebuild map to get bumped lighting on material %s\n",
  317. materialSortInfoArray[MSurf_MaterialSortID( surfID )].material->GetName() );
  318. }
  319. }
  320. void MaterialSytsem_DoBumpWarnings( void )
  321. {
  322. int sortID;
  323. IMaterial *pPrevMaterial = NULL;
  324. for( sortID = 0; sortID < g_WorldStaticMeshes.Count(); sortID++ )
  325. {
  326. if( pPrevMaterial == materialSortInfoArray[sortID].material )
  327. {
  328. continue;
  329. }
  330. // Find one surface in each material sort info type
  331. for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ )
  332. {
  333. SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex );
  334. if( MSurf_MaterialSortID( surfID ) == sortID )
  335. {
  336. TestBumpSanity( surfID );
  337. break;
  338. }
  339. }
  340. pPrevMaterial = materialSortInfoArray[sortID].material;
  341. }
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose:
  345. //-----------------------------------------------------------------------------
  346. static void GenerateTexCoordsForPrimVerts( void )
  347. {
  348. int j, k, l;
  349. for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ )
  350. {
  351. SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex );
  352. /*
  353. if( pSurf->numPrims > 0 )
  354. {
  355. ConMsg( "pSurf %d has %d prims (normal: %f %f %f dist: %f)\n",
  356. ( int )i, ( int )pSurf->numPrims,
  357. pSurf->plane->normal[0], pSurf->plane->normal[1], pSurf->plane->normal[2],
  358. pSurf->plane->dist );
  359. ConMsg( "\tfirst primID: %d\n", ( int )pSurf->firstPrimID );
  360. }
  361. */
  362. for( j = 0; j < MSurf_NumPrims( surfID ); j++ )
  363. {
  364. mprimitive_t *pPrim;
  365. assert( MSurf_FirstPrimID( surfID ) + j < host_state.worldbrush->numprimitives );
  366. pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfID ) + j];
  367. for( k = 0; k < pPrim->vertCount; k++ )
  368. {
  369. int lightmapSize[2];
  370. int lightmapPageSize[2];
  371. float sOffset, sScale, tOffset, tScale;
  372. materials->GetLightmapPageSize(
  373. SortInfoToLightmapPage( MSurf_MaterialSortID( surfID ) ),
  374. &lightmapPageSize[0], &lightmapPageSize[1] );
  375. lightmapSize[0] = ( MSurf_LightmapExtents( surfID )[0] ) + 1;
  376. lightmapSize[1] = ( MSurf_LightmapExtents( surfID )[1] ) + 1;
  377. sScale = 1.0f / ( float )lightmapPageSize[0];
  378. sOffset = ( float )MSurf_OffsetIntoLightmapPage( surfID )[0] * sScale;
  379. sScale = MSurf_LightmapExtents( surfID )[0] * sScale;
  380. tScale = 1.0f / ( float )lightmapPageSize[1];
  381. tOffset = ( float )MSurf_OffsetIntoLightmapPage( surfID )[1] * tScale;
  382. tScale = MSurf_LightmapExtents( surfID )[1] * tScale;
  383. for ( l = 0; l < pPrim->vertCount; l++ )
  384. {
  385. // world-space vertex
  386. assert( l+pPrim->firstVert < host_state.worldbrush->numprimverts );
  387. mprimvert_t &vert = host_state.worldbrush->primverts[l+pPrim->firstVert];
  388. Vector& vec = vert.pos;
  389. // base texture coordinate
  390. vert.texCoord[0] = DotProduct (vec, MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[0].AsVector3D()) +
  391. MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[0][3];
  392. vert.texCoord[0] /= MSurf_TexInfo( surfID )->material->GetMappingWidth();
  393. vert.texCoord[1] = DotProduct (vec, MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[1].AsVector3D()) +
  394. MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[1][3];
  395. vert.texCoord[1] /= MSurf_TexInfo( surfID )->material->GetMappingHeight();
  396. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) )
  397. {
  398. vert.lightCoord[0] = 0.5f;
  399. vert.lightCoord[1] = 0.5f;
  400. }
  401. else if ( MSurf_LightmapExtents( surfID )[0] == 0 )
  402. {
  403. vert.lightCoord[0] = sOffset;
  404. vert.lightCoord[1] = tOffset;
  405. }
  406. else
  407. {
  408. vert.lightCoord[0] = DotProduct (vec, MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) +
  409. MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[0][3];
  410. vert.lightCoord[0] -= MSurf_LightmapMins( surfID )[0];
  411. vert.lightCoord[0] += 0.5f;
  412. vert.lightCoord[0] /= ( float )MSurf_LightmapExtents( surfID )[0]; //pSurf->texinfo->texture->width;
  413. vert.lightCoord[1] = DotProduct (vec, MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) +
  414. MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[1][3];
  415. vert.lightCoord[1] -= MSurf_LightmapMins( surfID )[1];
  416. vert.lightCoord[1] += 0.5f;
  417. vert.lightCoord[1] /= ( float )MSurf_LightmapExtents( surfID )[1]; //pSurf->texinfo->texture->height;
  418. vert.lightCoord[0] = sOffset + vert.lightCoord[0] * sScale;
  419. vert.lightCoord[1] = tOffset + vert.lightCoord[1] * tScale;
  420. }
  421. }
  422. }
  423. }
  424. }
  425. }
  426. struct sortmap_t
  427. {
  428. MaterialSystem_SortInfo_t info;
  429. int index;
  430. };
  431. IMatRenderContext *pSortMapRenderContext;
  432. int __cdecl SortMapCompareFunc( const void *pElem0, const void *pElem1 )
  433. {
  434. const sortmap_t *pMap0 = (const sortmap_t *)pElem0;
  435. const sortmap_t *pMap1 = (const sortmap_t *)pElem1;
  436. return pSortMapRenderContext->CompareMaterialCombos( pMap0->info.material, pMap1->info.material, pMap0->info.lightmapPageID, pMap1->info.lightmapPageID );
  437. }
  438. //-----------------------------------------------------------------------------
  439. // Purpose:
  440. //-----------------------------------------------------------------------------
  441. void MaterialSystem_CreateSortinfo( void )
  442. {
  443. Assert( !materialSortInfoArray );
  444. int nSortIDs = materials->GetNumSortIDs();
  445. materialSortInfoArray = ( MaterialSystem_SortInfo_t * )new MaterialSystem_SortInfo_t[ nSortIDs ];
  446. Assert( materialSortInfoArray );
  447. materials->GetSortInfo( materialSortInfoArray );
  448. int i = 0;
  449. sortmap_t *pMap = (sortmap_t *)stackalloc( sizeof(sortmap_t) * nSortIDs );
  450. for ( i = 0; i < nSortIDs; i++ )
  451. {
  452. pMap[i].info = materialSortInfoArray[i];
  453. pMap[i].index = i;
  454. }
  455. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  456. pSortMapRenderContext = pRenderContext;
  457. qsort( pMap, nSortIDs, sizeof( sortmap_t ), SortMapCompareFunc );
  458. int *pSortIDRemap = (int *)stackalloc( sizeof(int) * nSortIDs );
  459. for ( i = 0; i < nSortIDs; i++ )
  460. {
  461. materialSortInfoArray[i] = pMap[i].info;
  462. pSortIDRemap[pMap[i].index] = i;
  463. //Msg("Material %s, lightmap %d ", materialSortInfoArray[i].material->GetName(), materialSortInfoArray[i].lightmapPageID );
  464. }
  465. for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ )
  466. {
  467. SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex );
  468. int sortID = MSurf_MaterialSortID( surfID );
  469. #if _DEBUG
  470. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  471. Assert ( materialSortInfoArray[pSortIDRemap[sortID]].material == pMaterial );
  472. #endif
  473. MSurf_MaterialSortID( surfID ) = pSortIDRemap[sortID];
  474. }
  475. // Create texcoords for subdivided surfaces
  476. GenerateTexCoordsForPrimVerts();
  477. // Create the hardware vertex buffers for each face
  478. WorldStaticMeshCreate();
  479. if ( developer.GetInt() )
  480. {
  481. MaterialSytsem_DoBumpWarnings();
  482. }
  483. }
  484. bool SurfHasBumpedLightmaps( SurfaceHandle_t surfID )
  485. {
  486. ASSERT_SURF_VALID( surfID );
  487. bool hasBumpmap = false;
  488. if( ( MSurf_TexInfo( surfID )->flags & SURF_BUMPLIGHT ) &&
  489. ( !( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) ) &&
  490. ( host_state.worldbrush->lightdata ) &&
  491. ( MSurf_Samples( surfID ) ) )
  492. {
  493. hasBumpmap = true;
  494. }
  495. return hasBumpmap;
  496. }
  497. bool SurfNeedsBumpedLightmaps( SurfaceHandle_t surfID )
  498. {
  499. ASSERT_SURF_VALID( surfID );
  500. assert( MSurf_TexInfo( surfID ) );
  501. assert( MSurf_TexInfo( surfID )->material );
  502. return MSurf_TexInfo( surfID )->material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  503. }
  504. bool SurfHasLightmap( SurfaceHandle_t surfID )
  505. {
  506. ASSERT_SURF_VALID( surfID );
  507. bool hasLightmap = false;
  508. if( ( !( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) ) &&
  509. ( host_state.worldbrush->lightdata ) &&
  510. ( MSurf_Samples( surfID ) ) )
  511. {
  512. hasLightmap = true;
  513. }
  514. return hasLightmap;
  515. }
  516. bool SurfNeedsLightmap( SurfaceHandle_t surfID )
  517. {
  518. ASSERT_SURF_VALID( surfID );
  519. assert( MSurf_TexInfo( surfID ) );
  520. assert( MSurf_TexInfo( surfID )->material );
  521. if (MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT)
  522. return false;
  523. return MSurf_TexInfo( surfID )->material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: This registers paint surfaces
  527. //-----------------------------------------------------------------------------
  528. void MaterialSystem_RegisterPaintSurfaces( void )
  529. {
  530. IPaintmapDataManager *pPaintmapDataManager = NULL;
  531. if ( g_PaintManager.m_bShouldRegister )
  532. {
  533. pPaintmapDataManager = &g_PaintManager;
  534. }
  535. materials->RegisterPaintmapDataManager( pPaintmapDataManager );
  536. }
  537. //-----------------------------------------------------------------------------
  538. // Purpose: This builds the surface info for a terrain face
  539. //-----------------------------------------------------------------------------
  540. void BuildMSurfaceVerts( const worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, Vector *verts,
  541. Vector2D *texCoords, Vector2D lightCoords[][4] )
  542. {
  543. SurfaceCtx_t ctx;
  544. SurfSetupSurfaceContext( ctx, surfID );
  545. int vertCount = MSurf_VertCount( surfID );
  546. int vertFirstIndex = MSurf_FirstVertIndex( surfID );
  547. for ( int i = 0; i < vertCount; i++ )
  548. {
  549. int vertIndex = pBrushData->vertindices[vertFirstIndex + i];
  550. // world-space vertex
  551. Vector& vec = pBrushData->vertexes[vertIndex].position;
  552. // output to mesh
  553. if ( verts )
  554. {
  555. VectorCopy( vec, verts[i] );
  556. }
  557. if ( texCoords )
  558. {
  559. SurfComputeTextureCoordinate( surfID, vec, texCoords[i].Base() );
  560. }
  561. //
  562. // garymct: normalized (within space of surface) lightmap texture coordinates
  563. //
  564. if ( lightCoords )
  565. {
  566. SurfComputeLightmapCoordinate( ctx, surfID, vec, lightCoords[i][0] );
  567. if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT )
  568. {
  569. // bump maps appear left to right in lightmap page memory, calculate the offset for the
  570. // width of a single map
  571. for ( int bumpID = 1; bumpID <= NUM_BUMP_VECTS; bumpID++ )
  572. {
  573. lightCoords[i][bumpID][0] = lightCoords[i][0][0] + (bumpID * ctx.m_BumpSTexCoordOffset);
  574. lightCoords[i][bumpID][1] = lightCoords[i][0][1];
  575. }
  576. }
  577. }
  578. }
  579. }
  580. void BuildMSurfacePrimVerts( worldbrushdata_t *pBrushData, mprimitive_t *prim, CMeshBuilder &builder, SurfaceHandle_t surfID )
  581. {
  582. Vector tVect;
  583. bool negate = false;
  584. // FIXME: For some reason, normals are screwed up on water surfaces. Revisit this once we have normals started in primverts.
  585. if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE )
  586. {
  587. negate = TangentSpaceSurfaceSetup( surfID, tVect );
  588. }
  589. // Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )] ];
  590. for ( int i = 0; i < prim->vertCount; i++ )
  591. {
  592. mprimvert_t &primVert = pBrushData->primverts[prim->firstVert + i];
  593. builder.Position3fv( primVert.pos.Base() );
  594. builder.Normal3fv( MSurf_Plane( surfID ).normal.Base() );
  595. // builder.Normal3fv( normal.Base() );
  596. builder.TexCoord2fv( 0, primVert.texCoord );
  597. builder.TexCoord2fv( 1, primVert.lightCoord );
  598. if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE )
  599. {
  600. Vector tangentS, tangentT;
  601. TangentSpaceComputeBasis( tangentS, tangentT, MSurf_Plane( surfID ).normal, tVect, false );
  602. builder.TangentS3fv( tangentS.Base() );
  603. builder.TangentT3fv( tangentT.Base() );
  604. }
  605. builder.AdvanceVertex();
  606. }
  607. }
  608. void BuildMSurfacePrimIndices( worldbrushdata_t *pBrushData, mprimitive_t *prim, CMeshBuilder &builder )
  609. {
  610. for ( int i = 0; i < prim->indexCount; i++ )
  611. {
  612. unsigned short primIndex = pBrushData->primindices[prim->firstIndex + i];
  613. builder.Index( primIndex - prim->firstVert );
  614. builder.AdvanceIndex();
  615. }
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Here's a version of the mesh builder used to allow for client DLL to draw brush models
  619. //-----------------------------------------------------------------------------
  620. void BuildBrushModelVertexArray(worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, BrushVertex_t* pVerts )
  621. {
  622. SurfaceCtx_t ctx;
  623. SurfSetupSurfaceContext( ctx, surfID );
  624. Vector tVect;
  625. bool negate = false;
  626. if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE )
  627. {
  628. negate = TangentSpaceSurfaceSetup( surfID, tVect );
  629. }
  630. for ( int i = 0; i < MSurf_VertCount( surfID ); i++ )
  631. {
  632. int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID ) + i];
  633. // world-space vertex
  634. Vector& vec = pBrushData->vertexes[vertIndex].position;
  635. // output to mesh
  636. VectorCopy( vec, pVerts[i].m_Pos );
  637. Vector2D uv;
  638. SurfComputeTextureCoordinate( surfID, vec, pVerts[i].m_TexCoord.Base() );
  639. // garymct: normalized (within space of surface) lightmap texture coordinates
  640. SurfComputeLightmapCoordinate( ctx, surfID, vec, pVerts[i].m_LightmapCoord );
  641. // Activate this if necessary
  642. // if ( surf->flags & SURFDRAW_BUMPLIGHT )
  643. // {
  644. // // bump maps appear left to right in lightmap page memory, calculate
  645. // // the offset for the width of a single map. The pixel shader will use
  646. // // this to compute the actual texture coordinates
  647. // builder.TexCoord2f( 2, ctx.m_BumpSTexCoordOffset, 0.0f );
  648. // }
  649. Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID ) + i] ];
  650. VectorCopy( normal, pVerts[i].m_Normal );
  651. if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE )
  652. {
  653. Vector tangentS, tangentT;
  654. TangentSpaceComputeBasis( tangentS, tangentT, normal, tVect, negate );
  655. VectorCopy( tangentS, pVerts[i].m_TangentS );
  656. VectorCopy( tangentT, pVerts[i].m_TangentT );
  657. }
  658. }
  659. }
  660. #endif // DEDICATED
  661. void CMSurfaceSortList::Init( int maxSortIDs, int minMaterialLists )
  662. {
  663. m_list.RemoveAll();
  664. m_list.EnsureCapacity(minMaterialLists);
  665. m_maxSortIDs = maxSortIDs;
  666. int groupMax = maxSortIDs*MAX_MAT_SORT_GROUPS;
  667. #ifndef _PS3
  668. m_groups.RemoveAll();
  669. m_groups.EnsureCount(groupMax);
  670. int groupBytes = (groupMax+7)>>3;
  671. m_groupUsed.EnsureCount(groupBytes);
  672. Q_memset(m_groupUsed.Base(), 0, groupBytes);
  673. #else
  674. m_groupsShared.RemoveAll();
  675. m_groupsShared.EnsureCapacity(maxSortIDs * 2); // 7LTODO Tune this
  676. m_groupIndices.RemoveAll();
  677. m_groupIndices.EnsureCount(groupMax);
  678. Q_memset(m_groupIndices.Base(), 0xFF, groupMax*2);
  679. #endif
  680. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ )
  681. {
  682. m_sortGroupLists[i].RemoveAll();
  683. #if defined(_PS3)
  684. int cap = (i==0) ? 256 : 64;
  685. #else
  686. int cap = (i==0) ? 128 : 16;
  687. #endif
  688. m_sortGroupLists[i].EnsureCapacity(cap);
  689. groupOffset[i] = m_maxSortIDs * i;
  690. }
  691. InitGroup(&m_emptyGroup);
  692. }
  693. void CMSurfaceSortList::InitGroup( surfacesortgroup_t *pGroup )
  694. {
  695. pGroup->listHead = -1;
  696. pGroup->listTail = -1;
  697. pGroup->vertexCount = 0;
  698. pGroup->groupListIndex = -1;
  699. pGroup->vertexCountNoDetail = 0;
  700. pGroup->indexCountNoDetail = 0;
  701. pGroup->triangleCount = 0;
  702. pGroup->surfaceCount = 0;
  703. }
  704. void CMSurfaceSortList::Shutdown()
  705. {
  706. }
  707. void CMSurfaceSortList::Reset()
  708. {
  709. Init( m_maxSortIDs, m_list.NumAllocated() );
  710. }
  711. #if defined(_PS3)
  712. void CMSurfaceSortList::EnsureCapacityForSPU( int maxSortIDs, int minMaterialLists )
  713. {
  714. m_list.EnsureCapacity(minMaterialLists);
  715. m_groupsShared.EnsureCapacity(maxSortIDs * 2); // 7LTODO Tune this
  716. int groupMax = maxSortIDs*MAX_MAT_SORT_GROUPS;
  717. m_groupIndices.EnsureCount(groupMax);
  718. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ )
  719. {
  720. int cap = (i==0) ? 256 : 64;
  721. m_sortGroupLists[i].EnsureCapacity(cap);
  722. groupOffset[i] = m_maxSortIDs * i;
  723. }
  724. // InitGroup(&m_emptyGroup);
  725. }
  726. #endif
  727. // this resizes the groups and groupUsed arrays
  728. #if !defined(_PS3)
  729. void CMSurfaceSortList::EnsureMaxSortIDs( int newMaxSortIDs )
  730. {
  731. if ( newMaxSortIDs > m_maxSortIDs )
  732. {
  733. int oldMax = m_maxSortIDs;
  734. // compute new size, expand by minimum of 256
  735. newMaxSortIDs += 255;
  736. newMaxSortIDs -= (newMaxSortIDs&255);
  737. int groupMax = newMaxSortIDs * MAX_MAT_SORT_GROUPS;
  738. int groupBytes = (groupMax+7)>>3;
  739. // resize the arrays
  740. m_groups.EnsureCount(groupMax);
  741. m_groupUsed.EnsureCount(groupBytes);
  742. // now loop through the list backwards and move the old data over
  743. for ( int i = MAX_MAT_SORT_GROUPS; --i >= 0; )
  744. {
  745. for ( int j = newMaxSortIDs; --j >= 0; )
  746. {
  747. int newIndex = (i * newMaxSortIDs) + j;
  748. if ( j < oldMax )
  749. {
  750. // when i == 0, the group indices overlap so they don't need to be remapped
  751. if ( i != 0 )
  752. {
  753. int oldIndex = (i * oldMax) + j;
  754. MarkGroupNotUsed(newIndex);
  755. if ( IsGroupUsed(oldIndex) )
  756. {
  757. MarkGroupNotUsed(oldIndex);
  758. MarkGroupUsed(newIndex);
  759. m_groups[newIndex] = m_groups[oldIndex];
  760. InitGroup( &m_groups[oldIndex] );
  761. }
  762. }
  763. if ( IsGroupUsed(newIndex) && m_groups[newIndex].groupListIndex >= 0 )
  764. {
  765. m_sortGroupLists[i][m_groups[newIndex].groupListIndex] = &m_groups[newIndex];
  766. }
  767. }
  768. else
  769. {
  770. MarkGroupNotUsed(newIndex);
  771. }
  772. }
  773. groupOffset[i] = i*newMaxSortIDs;
  774. }
  775. m_maxSortIDs = newMaxSortIDs;
  776. }
  777. }
  778. #endif
  779. void CMSurfaceSortList::AddSurfaceToTail( msurface2_t *pSurface, int sortGroup, int sortID )
  780. {
  781. Assert(sortGroup<MAX_MAT_SORT_GROUPS);
  782. int index = groupOffset[sortGroup] + sortID;
  783. #ifndef _PS3
  784. surfacesortgroup_t * RESTRICT pGroup = &m_groups[index];
  785. if ( !IsGroupUsed(index) )
  786. {
  787. MarkGroupUsed(index);
  788. InitGroup(pGroup);
  789. }
  790. #else
  791. surfacesortgroup_t * RESTRICT pGroup;
  792. if ( !IsGroupUsed(index) )
  793. {
  794. MarkGroupUsed(index);
  795. pGroup = &m_groupsShared[m_groupIndices[index]];
  796. InitGroup(pGroup);
  797. }
  798. else
  799. {
  800. pGroup = &m_groupsShared[m_groupIndices[index]];
  801. }
  802. #endif
  803. materiallist_t *pList = NULL;
  804. short prevIndex = -1;
  805. int vertCount = MSurf_VertCount(pSurface);
  806. int triangleCount = vertCount - 2;
  807. pGroup->vertexCount += vertCount;
  808. if (MSurf_Flags(pSurface) & SURFDRAW_NODE)
  809. {
  810. pGroup->vertexCountNoDetail += vertCount;
  811. pGroup->indexCountNoDetail += triangleCount * 3;
  812. }
  813. pGroup->triangleCount += triangleCount;
  814. pGroup->surfaceCount++;
  815. if ( pGroup->listTail != m_list.InvalidIndex() )
  816. {
  817. // existing block
  818. pList = &m_list[pGroup->listTail];
  819. if ( pList->count >= ARRAYSIZE(pList->pSurfaces) )
  820. {
  821. prevIndex = pGroup->listTail;
  822. // no space in existing block
  823. pList = NULL;
  824. }
  825. }
  826. // use existing block?
  827. if ( pList )
  828. {
  829. pList->pSurfaces[pList->count] = pSurface;
  830. pList->count++;
  831. }
  832. else
  833. {
  834. // allocate a new block
  835. short nextBlock = m_list.AddToTail();
  836. if ( prevIndex >= 0 )
  837. {
  838. m_list[prevIndex].nextBlock = nextBlock;
  839. }
  840. pGroup->listTail = nextBlock;
  841. // handle the first use case
  842. if ( pGroup->listHead == m_list.InvalidIndex() )
  843. {
  844. // UNDONE: This should really be sorted by sortID would help reduce state changes
  845. // NOTE: Doesn't seem to help much in benchmarks to sort this vector
  846. int index = m_sortGroupLists[sortGroup].AddToTail( (surfacesortgroup_t *) pGroup);
  847. pGroup->groupListIndex = index;
  848. pGroup->listHead = nextBlock;
  849. }
  850. pList = &m_list[nextBlock];
  851. pList->nextBlock = m_list.InvalidIndex();
  852. pList->count = 1;
  853. pList->pSurfaces[0] = pSurface;
  854. }
  855. }
  856. msurface2_t *CMSurfaceSortList::GetSurfaceAtHead( const surfacesortgroup_t &group ) const
  857. {
  858. if ( group.listHead == m_list.InvalidIndex() )
  859. return NULL;
  860. Assert(m_list[group.listHead].count>0);
  861. return m_list[group.listHead].pSurfaces[0];
  862. }
  863. void CMSurfaceSortList::GetSurfaceListForGroup( CUtlVector<msurface2_t *> &list, const surfacesortgroup_t &group ) const
  864. {
  865. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( *this, group, surfID )
  866. {
  867. list.AddToTail(surfID);
  868. }
  869. MSL_FOREACH_SURFACE_IN_GROUP_END()
  870. }
  871. #ifndef DEDICATED
  872. IMaterial *GetMaterialAtCrossHair( void )
  873. {
  874. #ifdef _WIN32
  875. Vector endPoint;
  876. Vector lightmapColor;
  877. // max_range * sqrt(3)
  878. VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint );
  879. SurfaceHandle_t hitSurfID = R_LightVec( MainViewOrigin(), endPoint, false, lightmapColor );
  880. if( IS_SURF_VALID( hitSurfID ) )
  881. {
  882. return MSurf_TexInfo( hitSurfID )->material;
  883. }
  884. else
  885. {
  886. return NULL;
  887. }
  888. #else
  889. Assert( false ); // return value was not defined for this platform - returning NULL
  890. return NULL;
  891. #endif
  892. }
  893. // hack
  894. extern void DrawLightmapPage( int lightmapPageID );
  895. static float textureS, textureT;
  896. static SurfaceHandle_t s_CrossHairSurfID;;
  897. static Vector crossHairDiffuseLightColor;
  898. static Vector crossHairBaseColor;
  899. static float lightmapCoords[2];
  900. void SaveSurfAtCrossHair()
  901. {
  902. #ifdef _WIN32
  903. Vector endPoint;
  904. Vector lightmapColor;
  905. // max_range * sqrt(3)
  906. VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint );
  907. s_CrossHairSurfID = R_LightVec( MainViewOrigin(), endPoint, false, lightmapColor,
  908. &textureS, &textureT, &lightmapCoords[0], &lightmapCoords[1] );
  909. #endif
  910. }
  911. void DebugDrawLightmapAtCrossHair()
  912. {
  913. return;
  914. IMaterial *pMaterial;
  915. int lightmapPageSize[2];
  916. if( s_CrossHairSurfID <= 0 )
  917. {
  918. return;
  919. }
  920. materials->GetLightmapPageSize( materialSortInfoArray[MSurf_MaterialSortID( s_CrossHairSurfID )].lightmapPageID,
  921. &lightmapPageSize[0], &lightmapPageSize[1] );
  922. pMaterial = MSurf_TexInfo( s_CrossHairSurfID )->material;
  923. // pMaterial->GetLowResColorSample( textureS, textureT, baseColor );
  924. DrawLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( s_CrossHairSurfID )].lightmapPageID );
  925. #if 0
  926. int i;
  927. for( i = 0; i < 2; i++ )
  928. {
  929. xy[i] =
  930. ( ( float )pCrossHairSurf->offsetIntoLightmapPage[i] / ( float )lightmapPageSize[i] ) +
  931. lightmapCoord[i] * ( pCrossHairSurf->lightmapExtents[i] / ( float )lightmapPageSize[i] );
  932. }
  933. materials->Bind( g_materialWireframe );
  934. IMesh* pMesh = materials->GetDynamicMesh( g_materialWireframe );
  935. CMeshBuilder meshBuilder;
  936. meshBuilder.Begin( pMesh, MATERIAL_QUAD, 1 );
  937. meshBuilder.Position3f(
  938. meshBuilder.AdvanceVertex();
  939. meshBuilder.End();
  940. pMesh->Draw();
  941. #endif
  942. }
  943. void ReleaseMaterialSystemObjects( int nChangeFlags );
  944. void RestoreMaterialSystemObjects( int nChangeFlags );
  945. void ForceMatSysRestore()
  946. {
  947. ReleaseMaterialSystemObjects( 0 );
  948. RestoreMaterialSystemObjects( 0 );
  949. }
  950. #endif