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.

1241 lines
38 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. // HDRFIXME: reduce the number of include files here.
  10. #include "render_pch.h"
  11. #include "client.h"
  12. #include "cdll_int.h"
  13. #include "lightcache.h"
  14. #include "client_class.h"
  15. #include "icliententitylist.h"
  16. #include "traceinit.h"
  17. #include "server.h"
  18. #include "ispatialpartitioninternal.h"
  19. #include "cdll_engine_int.h"
  20. #include "filesystem.h"
  21. #include "filesystem_engine.h"
  22. #include "ivtex.h"
  23. #include "materialsystem/itexture.h"
  24. #include "view.h"
  25. #include "tier0/dbg.h"
  26. #include "tier2/fileutils.h"
  27. #include "staticpropmgr.h"
  28. #include "icliententity.h"
  29. #include "gl_drawlights.h"
  30. #include "Overlay.h"
  31. #include "vmodes.h"
  32. #include "gl_cvars.h"
  33. #include "utlbuffer.h"
  34. #include "vtf/vtf.h"
  35. #include "bitmap/imageformat.h"
  36. #include "cbenchmark.h"
  37. #include "r_decal.h"
  38. #include "ivideomode.h"
  39. #include "tier0/icommandline.h"
  40. #include "dmxloader/dmxelement.h"
  41. #include "dmxloader/dmxloader.h"
  42. #include "bitmap/floatbitmap.h"
  43. #include "tier2/tier2.h"
  44. #include "../utils/common/bsplib.h"
  45. #include "ibsppack.h"
  46. // memdbgon must be the last include file in a .cpp file!!!
  47. #include "tier0/memdbgon.h"
  48. // putting this here so that it is replicated to the client.dll and materialsystem.dll
  49. ConVar dynamic_tonemap( "mat_dynamic_tonemapping", "1", FCVAR_CHEAT );
  50. ConVar reload_materials( "reload_materials", "0" );
  51. ConVar r_DrawBeams( "r_DrawBeams", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" );
  52. static ConVar mat_force_tonemap_scale( "mat_force_tonemap_scale", "0.0", FCVAR_CHEAT );
  53. static const char *facingName[6] = { "rt", "lf", "bk", "ft", "up", "dn" };
  54. //-----------------------------------------------------------------------------
  55. // Load, unload vtex
  56. //-----------------------------------------------------------------------------
  57. static IVTex* VTex_Load( CSysModule** pModule )
  58. {
  59. // load the vtex dll
  60. IVTex *pIVTex = NULL;
  61. *pModule = FileSystem_LoadModule( "vtex_dll" );
  62. if ( *pModule )
  63. {
  64. CreateInterfaceFn factory = Sys_GetFactory( *pModule );
  65. if ( factory )
  66. {
  67. pIVTex = ( IVTex * )factory( IVTEX_VERSION_STRING, NULL );
  68. }
  69. }
  70. if ( !pIVTex )
  71. {
  72. ConMsg( "Can't load vtex_dll.dll\n" );
  73. }
  74. return pIVTex;
  75. }
  76. static void VTex_Unload( CSysModule *pModule )
  77. {
  78. FileSystem_UnloadModule( pModule );
  79. }
  80. //-----------------------------------------------------------------------------
  81. // Main entry point for taking cubemap snapshots
  82. //-----------------------------------------------------------------------------
  83. static void TakeCubemapSnapshot( const Vector &origin, const char *pFileNameBase, int screenBufSize,
  84. int tgaSize, bool bPFM )
  85. {
  86. if ( IsGameConsole() )
  87. return;
  88. if ( g_LostVideoMemory )
  89. return;
  90. ITexture *pSaveRenderTarget = NULL;
  91. CMatRenderContextPtr pRenderContext( materials );
  92. // HDRFIXME: push/pop
  93. if( bPFM )
  94. {
  95. pSaveRenderTarget = pRenderContext->GetRenderTarget();
  96. pRenderContext->SetRenderTarget( NULL );
  97. }
  98. // HACK HACK HACK!!!!
  99. // If this is lower than the size of the render target (I think) we don't get water.
  100. screenBufSize = 512;
  101. char name[1024];
  102. CViewSetup view;
  103. memset( &view, 0, sizeof(view) );
  104. view.origin = origin;
  105. view.m_flAspectRatio = 1.0f;
  106. view.m_bRenderToSubrectOfLargerScreen = true;
  107. // garymcthack
  108. view.zNear = 8.0f;
  109. view.zFar = 28400.0f;
  110. view.x = 0;
  111. view.y = 0;
  112. view.width = ( float )screenBufSize;
  113. view.height = ( float )screenBufSize;
  114. const char *pExtension = ".tga";
  115. if( bPFM )
  116. {
  117. pExtension = ".pfm";
  118. }
  119. Shader_BeginRendering();
  120. if( bPFM )
  121. {
  122. int backbufferWidth, backbufferHeight;
  123. materials->GetBackBufferDimensions( backbufferWidth, backbufferHeight );
  124. pRenderContext->Viewport( 0, 0, backbufferWidth, backbufferHeight );
  125. pRenderContext->ClearColor3ub( 128, 128, 128 );
  126. pRenderContext->ClearBuffers( true, true );
  127. }
  128. int nFlags = VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH;
  129. // NOTE: This is for a workaround on ATI with building cubemaps.
  130. // Clearing just the viewport doesn't seem to work properly.
  131. nFlags |= VIEW_CLEAR_FULL_TARGET;
  132. static float angle0[6]={0, 0, 0, 0, - 90, 90};
  133. static float angle1[6]={0, 180, 90, 270, 0, 0};
  134. static CubeMapFaceIndex_t face_idx[6]={CUBEMAP_FACE_RIGHT, CUBEMAP_FACE_LEFT,
  135. CUBEMAP_FACE_BACK, CUBEMAP_FACE_FRONT,
  136. CUBEMAP_FACE_UP, CUBEMAP_FACE_DOWN};
  137. static int engine_cubemap_idx_to_fbm_idx[6]={4, 3, 0, 2, 5, 1};
  138. if (bPFM)
  139. {
  140. FloatCubeMap_t Envmap(tgaSize, tgaSize);
  141. for( int side = 0; side < 6; side++ )
  142. {
  143. view.angles[0] = angle0[side];
  144. view.angles[1] = angle1[side];
  145. view.angles[2] = 0;
  146. view.fov = 90;
  147. view.fovViewmodel = 90;
  148. view.origin = origin;
  149. if (g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER)
  150. {
  151. FloatBitMap_t &hdr_map = Envmap.face_maps[engine_cubemap_idx_to_fbm_idx[side]];
  152. hdr_map.Clear( 0, 0, 0, 1 );
  153. // we are going to need to render multiple exposures
  154. float exposure = 16.0;
  155. bool bOverExposedTexels = true;
  156. while( bOverExposedTexels && ( exposure > 0.05 ))
  157. {
  158. mat_force_tonemap_scale.SetValue( exposure );
  159. g_ClientDLL->RenderView( view, nFlags, 0 );
  160. uint8 * pImage = new uint8[ screenBufSize * screenBufSize * 4 ];
  161. uint8 * pImage1 = new uint8[ tgaSize * tgaSize * 4 ];
  162. // Get Bits from the material system
  163. pRenderContext->ReadPixels( 0, 0, screenBufSize, screenBufSize,
  164. pImage, IMAGE_FORMAT_RGBA8888 );
  165. ImageLoader::ResampleInfo_t info;
  166. info.m_pSrc = pImage;
  167. info.m_pDest = pImage1;
  168. info.m_nSrcWidth = screenBufSize;
  169. info.m_nSrcHeight = screenBufSize;
  170. info.m_nDestWidth = tgaSize;
  171. info.m_nDestHeight = tgaSize;
  172. info.m_flSrcGamma = 1.0f;
  173. info.m_flDestGamma = 1.0f;
  174. if( ! ImageLoader::ResampleRGBA8888( info ) )
  175. {
  176. Sys_Error( "Can't resample\n" );
  177. }
  178. FloatBitMap_t ldr_map( tgaSize, tgaSize );
  179. for( int x1 = 0; x1 < tgaSize; x1++ )
  180. for( int y1 = 0; y1 < tgaSize; y1++ )
  181. for( int c = 0; c < 3; c++ )
  182. ldr_map.Pixel( x1, y1, 0, c ) = pImage1[c + 4 * ( x1 + tgaSize * y1 )]* ( 1 / 255.0 );
  183. delete[] pImage;
  184. delete[] pImage1;
  185. ldr_map.RaiseToPower( 2.2 ); // gamma to linear
  186. float scale = 1.0 / exposure;
  187. bOverExposedTexels = false;
  188. for( int x = 0; x < hdr_map.NumCols(); x++ )
  189. for( int y = 0; y < hdr_map.NumRows(); y++ )
  190. for( int c = 0; c < 3; c++ )
  191. {
  192. float texel = ldr_map.Pixel( x, y, 0, c );
  193. if ( texel > 0.98 )
  194. bOverExposedTexels = true;
  195. texel *= scale;
  196. hdr_map.Pixel( x, y, 0, c ) = MAX( hdr_map.Pixel( x, y, 0, c ), texel );
  197. }
  198. exposure *= 0.75;
  199. materials->SwapBuffers();
  200. }
  201. mat_force_tonemap_scale.SetValue( 0.0f );
  202. Q_snprintf( name, sizeof( name ), "%s%s%s", pFileNameBase, facingName[side],pExtension );
  203. // hdr_map.WritePFM(name);
  204. }
  205. else
  206. {
  207. g_ClientDLL->RenderView( view, nFlags, 0 );
  208. Q_snprintf( name, sizeof( name ), "%s%s%s", pFileNameBase, facingName[side],pExtension );
  209. Assert( strlen( name ) < 1023 );
  210. videomode->TakeSnapshotTGARect( name, 0, 0, screenBufSize, screenBufSize, tgaSize, tgaSize, bPFM, face_idx[side]);
  211. }
  212. }
  213. if (g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER)
  214. {
  215. // FloatCubeMap_t OutEnvmap(tgaSize, tgaSize);
  216. // for(int f=0;f<6;f++)
  217. // OutEnvmap.face_maps[f].Clear(0,0,0,1);
  218. // Envmap.Resample(OutEnvmap,15.0);
  219. Q_snprintf( name, sizeof( name ), "%s", pFileNameBase);
  220. Envmap.WritePFMs( name );
  221. // Q_snprintf( name, sizeof( name ), "%s_filtered", pFileNameBase);
  222. // OutEnvmap.WritePFMs( name );
  223. }
  224. }
  225. else
  226. {
  227. for(int side=0;side<6;side++)
  228. {
  229. view.angles[0] = angle0[side];
  230. view.angles[1] = angle1[side];
  231. view.angles[2] = 0;
  232. view.fov = 90;
  233. view.fovViewmodel = 90;
  234. view.origin = origin;
  235. g_ClientDLL->RenderView( view, nFlags, 0 );
  236. Q_snprintf( name, sizeof( name ), "%s%s%s", pFileNameBase, facingName[side],pExtension );
  237. Assert( strlen( name ) < 1023 );
  238. videomode->TakeSnapshotTGARect( name, 0, 0, screenBufSize, screenBufSize, tgaSize, tgaSize, bPFM, face_idx[side]);
  239. }
  240. }
  241. if( bPFM )
  242. {
  243. materials->SwapBuffers();
  244. }
  245. // HDRFIXME: push/pop
  246. if( bPFM )
  247. {
  248. pRenderContext->SetRenderTarget( pSaveRenderTarget );
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Interface factory for VTex
  253. //-----------------------------------------------------------------------------
  254. void* CubemapsFSFactory( const char *pName, int *pReturnCode )
  255. {
  256. if ( IsGameConsole() )
  257. return NULL;
  258. if ( Q_stricmp( pName, FILESYSTEM_INTERFACE_VERSION ) == 0 )
  259. return g_pFileSystem;
  260. return NULL;
  261. }
  262. class CCubemapCollection
  263. {
  264. public:
  265. bool Add( char const *szCubemapFile );
  266. void Purge() { m_arrEntries.RemoveAll(); }
  267. protected:
  268. CUtlSymbolTable m_arrEntries;
  269. };
  270. //
  271. // Adds a cubemap to the unique list of cubemaps,
  272. // returns true when added a new unique cubemap,
  273. // or false if the cubemap has already been added before.
  274. //
  275. bool CCubemapCollection::Add( char const *szCubemapFile )
  276. {
  277. if ( m_arrEntries.Find( szCubemapFile ) != CUtlSymbol() )
  278. {
  279. return false;
  280. }
  281. else
  282. {
  283. m_arrEntries.AddString( szCubemapFile );
  284. return true;
  285. }
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Generates a cubemap .vtf from .TGA snapshots
  289. //-----------------------------------------------------------------------------
  290. static void BuildSingleCubemap( const char *pVTFName, const Vector &vecOrigin,
  291. int nSize, bool bHDR, const char *pGameDir, IVTex *ivt, CCubemapCollection *pCC )
  292. {
  293. if ( IsGameConsole() )
  294. return;
  295. if ( pCC && !pCC->Add( pVTFName ) )
  296. return; // Already compiled
  297. int nScreenBufSize = 4 * nSize;
  298. TakeCubemapSnapshot( vecOrigin, pVTFName, nScreenBufSize, nSize, bHDR );
  299. char pTXTName[ MAX_PATH ];
  300. Q_strncpy( pTXTName, pVTFName, sizeof(pTXTName) );
  301. Q_SetExtension( pTXTName, ".txt", sizeof(pTXTName) );
  302. // HDRFIXME: Make this go to a buffer instead.
  303. FileHandle_t fp = g_pFileSystem->Open( pTXTName, "w" );
  304. if( bHDR )
  305. {
  306. g_pFileSystem->FPrintf( fp, "\"pfm\" \"1\"\n" );
  307. // HDRFIXME: Make sure that we can mip and lod and get rid of this.
  308. }
  309. // don't let any dest alpha creep into the image
  310. g_pFileSystem->FPrintf( fp, "\"stripalphachannel\" \"1\"\n" );
  311. g_pFileSystem->Close( fp );
  312. if ( ivt )
  313. {
  314. char *argv[64];
  315. int iArg = 0;
  316. argv[iArg++] = "";
  317. argv[iArg++] = "-oldcubepath"; // Process one file per face (new authoring path uses one file per cubemap)
  318. argv[iArg++] = "-quiet";
  319. argv[iArg++] = "-UseStandardError"; // These are only here for the -currently released- version of vtex.dll.
  320. argv[iArg++] = "-WarningsAsErrors";
  321. argv[iArg++] = pTXTName;
  322. ivt->VTex( CubemapsFSFactory, pGameDir, iArg, argv );
  323. }
  324. g_pFileSystem->RemoveFile( pTXTName, NULL );
  325. const char *pSrcExtension = bHDR ? ".pfm" : ".tga";
  326. for( int i = 0; i < 6; i++ )
  327. {
  328. char pTempName[MAX_PATH];
  329. Q_snprintf( pTempName, sizeof( pTempName ), "%s%s", pVTFName, facingName[i] );
  330. Q_SetExtension( pTempName, pSrcExtension, sizeof(pTempName) );
  331. g_pFileSystem->RemoveFile( pTempName, NULL );
  332. }
  333. }
  334. #if !defined( DEDICATED )
  335. //-----------------------------------------------------------------------------
  336. // Grab six views for environment mapping tests
  337. //-----------------------------------------------------------------------------
  338. CON_COMMAND( envmap, "" )
  339. {
  340. if ( IsGameConsole() )
  341. return;
  342. char base[ 256 ];
  343. IClientEntity *world = entitylist->GetClientEntity( 0 );
  344. if( world && world->GetModel() )
  345. {
  346. Q_FileBase( modelloader->GetName( ( model_t *)world->GetModel() ), base, sizeof( base ) );
  347. }
  348. else
  349. {
  350. Q_strncpy( base, "Env", sizeof( base ) );
  351. }
  352. int strLen = strlen( base ) + strlen( "cubemap_screenshots/" ) + 1;
  353. char *str = ( char * )stackalloc( strLen );
  354. Q_snprintf( str, strLen, "cubemap_screenshots/%s", base );
  355. g_pFileSystem->CreateDirHierarchy( "cubemap_screenshots", "DEFAULT_WRITE_PATH" );
  356. TakeCubemapSnapshot( MainViewOrigin(), str, mat_envmapsize.GetInt(), mat_envmaptgasize.GetInt(),
  357. g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE );
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Write lighting information to a DMX file
  361. //-----------------------------------------------------------------------------
  362. static void WriteLightProbe( const char *pBasePath, const LightingState_t& state, bool bHDR )
  363. {
  364. char pFullPath[MAX_PATH];
  365. Q_strncpy( pFullPath, pBasePath, sizeof(pFullPath) );
  366. Q_SetExtension( pFullPath, ".prb", sizeof(pFullPath) );
  367. DECLARE_DMX_CONTEXT();
  368. CDmxElement *pLightProbe = CreateDmxElement( "DmeElement" );
  369. const char *pCubemap = pBasePath + Q_strlen( "materials/" );
  370. CDmxElementModifyScope modify( pLightProbe );
  371. pLightProbe->SetValue( "name", "lightprobe" );
  372. pLightProbe->SetValue( "cubemap", pCubemap );
  373. if ( bHDR )
  374. {
  375. char pTemp[MAX_PATH];
  376. Q_snprintf( pTemp, sizeof(pTemp), "%s_hdr", pCubemap );
  377. pLightProbe->SetValue( "cubemapHdr", pTemp );
  378. }
  379. CDmxAttribute *pAmbientCube = pLightProbe->AddAttribute( "ambientCube" );
  380. CUtlVector< Vector >& vec = pAmbientCube->GetArrayForEdit<Vector>();
  381. for ( int i = 0; i < 6 ; ++i )
  382. {
  383. vec.AddToTail( state.r_boxcolor[i] );
  384. }
  385. CDmxAttribute *pLocalLightList = pLightProbe->AddAttribute( "localLights" );
  386. CUtlVector< CDmxElement* >& lights = pLocalLightList->GetArrayForEdit<CDmxElement*>();
  387. modify.Release();
  388. for ( int i = 0; i < state.numlights; ++i )
  389. {
  390. CDmxElement* pLight = CreateDmxElement( "DmeElement" );
  391. lights.AddToTail( pLight );
  392. CDmxElementModifyScope modify( pLight );
  393. const dworldlight_t &wl = *state.locallight[i];
  394. pLight->SetValue( "color", wl.intensity );
  395. switch( wl.type )
  396. {
  397. case emit_point:
  398. pLight->SetValue( "name", "Point" );
  399. pLight->SetValue( "origin", wl.origin );
  400. pLight->SetValue( "attenuation", Vector( wl.constant_attn, wl.linear_attn, wl.quadratic_attn ) );
  401. pLight->SetValue( "maxDistance", wl.radius );
  402. break;
  403. case emit_spotlight:
  404. pLight->SetValue( "name", "Spot" );
  405. pLight->SetValue( "origin", wl.origin );
  406. pLight->SetValue( "direction", wl.normal );
  407. pLight->SetValue( "attenuation", Vector( wl.constant_attn, wl.linear_attn, wl.quadratic_attn ) );
  408. pLight->SetValue( "theta", 2.0f * acos( wl.stopdot ) );
  409. pLight->SetValue( "phi", 2.0f * acos( wl.stopdot2 ) );
  410. pLight->SetValue( "exponent", wl.exponent ? wl.exponent : 1.0f );
  411. pLight->SetValue( "maxDistance", wl.radius );
  412. break;
  413. case emit_surface:
  414. pLight->SetValue( "name", "Spot" );
  415. pLight->SetValue( "origin", wl.origin );
  416. pLight->SetValue( "direction", wl.normal );
  417. pLight->SetValue( "attenuation", Vector( 0.0f, 0.0f, 1.0f ) );
  418. pLight->SetValue( "theta", 0.0f );
  419. pLight->SetValue( "phi", 0.0f );
  420. pLight->SetValue( "exponent", 1.0f );
  421. pLight->SetValue( "maxDistance", wl.radius );
  422. break;
  423. case emit_skylight:
  424. pLight->SetValue( "name", "Directional" );
  425. pLight->SetValue( "direction", wl.normal );
  426. break;
  427. }
  428. }
  429. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  430. if ( SerializeDMX( buf, pLightProbe, pFullPath ) )
  431. {
  432. g_pFullFileSystem->WriteFile( pFullPath, "MOD", buf );
  433. }
  434. CleanupDMX( pLightProbe );
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Grab an envmap @ the view position + write lighting information
  438. //-----------------------------------------------------------------------------
  439. CON_COMMAND( lightprobe,
  440. "Samples the lighting environment.\n"
  441. "Creates a cubemap and a file indicating the local lighting in a subdirectory called 'materials/lightprobes'\n."
  442. "The lightprobe command requires you specify a base file name.\n" )
  443. {
  444. if ( IsGameConsole() )
  445. return;
  446. if ( args.ArgC() < 2 )
  447. {
  448. ConMsg( "sample_lighting usage: lightprobe <base file name> [cubemap dimension]\n" );
  449. return;
  450. }
  451. int nTGASize = mat_envmaptgasize.GetInt();
  452. if ( args.ArgC() >= 3 )
  453. {
  454. nTGASize = atoi( args[2] );
  455. }
  456. CSysModule *pModule;
  457. IVTex *pIVTex = VTex_Load( &pModule );
  458. if ( !pIVTex )
  459. return;
  460. char pBasePath[MAX_PATH];
  461. Q_snprintf( pBasePath, sizeof(pBasePath), "materials/lightprobes/%s", args[1] );
  462. Q_StripFilename( pBasePath );
  463. g_pFileSystem->CreateDirHierarchy( pBasePath, "DEFAULT_WRITE_PATH" );
  464. char pTemp[MAX_PATH];
  465. char pMaterialSrcPath[MAX_PATH];
  466. Q_snprintf( pTemp, sizeof(pTemp), "materialsrc/lightprobes/%s", args[1] );
  467. GetModContentSubdirectory( pTemp, pMaterialSrcPath, sizeof(pMaterialSrcPath) );
  468. Q_StripFilename( pMaterialSrcPath );
  469. g_pFileSystem->CreateDirHierarchy( pMaterialSrcPath, NULL );
  470. char pGameDir[MAX_OSPATH];
  471. COM_GetGameDir( pGameDir, sizeof( pGameDir ) );
  472. bool bHDR = g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE;
  473. if ( bHDR )
  474. {
  475. char pTemp2[MAX_PATH];
  476. Q_snprintf( pTemp2, sizeof(pTemp2), "materialsrc/lightprobes/%s_hdr", args[1] );
  477. GetModContentSubdirectory( pTemp2, pMaterialSrcPath, sizeof(pMaterialSrcPath) );
  478. BuildSingleCubemap( pMaterialSrcPath, MainViewOrigin(), nTGASize, true, pGameDir, pIVTex, NULL );
  479. }
  480. GetModContentSubdirectory( pTemp, pMaterialSrcPath, sizeof(pMaterialSrcPath) );
  481. BuildSingleCubemap( pMaterialSrcPath, MainViewOrigin(), nTGASize, false, pGameDir, pIVTex, NULL );
  482. VTex_Unload( pModule );
  483. // Get the lighting at the point
  484. LightingState_t lightingState;
  485. LightcacheGetDynamic_Stats stats;
  486. LightcacheGetDynamic( MainViewOrigin(), lightingState, stats, NULL );
  487. Q_snprintf( pBasePath, sizeof(pBasePath), "materials/lightprobes/%s", args[1] );
  488. WriteLightProbe( pBasePath, lightingState, bHDR );
  489. }
  490. static bool LoadSrcVTFFiles( IVTFTexture *pSrcVTFTextures[6], const char *pSkyboxBaseName )
  491. {
  492. if ( IsGameConsole() )
  493. {
  494. return false;
  495. }
  496. else
  497. {
  498. int i;
  499. for( i = 0; i < 6; i++ )
  500. {
  501. // !!! FIXME: This needs to open the vmt (or some other method) to find the correct LDR or HDR set of skybox textures! Look in vbsp\cubemap.cpp!
  502. char srcVTFFileName[1024];
  503. Q_snprintf( srcVTFFileName, sizeof( srcVTFFileName ), "materials/skybox/%s%s.vtf", pSkyboxBaseName, facingName[i] );
  504. CUtlBuffer buf;
  505. if ( !g_pFileSystem->ReadFile( srcVTFFileName, NULL, buf ) )
  506. return false;
  507. pSrcVTFTextures[i] = CreateVTFTexture();
  508. if (!pSrcVTFTextures[i]->Unserialize(buf))
  509. {
  510. Warning("*** Error unserializing skybox texture: %s\n", pSkyboxBaseName );
  511. return false;
  512. }
  513. // NOTE: texture[0] is a side texture that could be 1/2 height, so allow this and also allow 4x4 faces
  514. if ( ( ( pSrcVTFTextures[i]->Width() != pSrcVTFTextures[0]->Width() ) && ( pSrcVTFTextures[i]->Width() != 4 ) ) ||
  515. ( ( pSrcVTFTextures[i]->Height() != pSrcVTFTextures[0]->Height() ) && ( pSrcVTFTextures[i]->Height() != pSrcVTFTextures[0]->Height()*2 ) && ( pSrcVTFTextures[i]->Height() != 4 ) ) ||
  516. ( pSrcVTFTextures[i]->Flags() != pSrcVTFTextures[0]->Flags() ) )
  517. {
  518. Warning("*** Error: Skybox vtf files for %s weren't compiled with the same size texture and/or same flags!\n", pSkyboxBaseName );
  519. return false;
  520. }
  521. }
  522. return true;
  523. }
  524. }
  525. #define DEFAULT_CUBEMAP_SIZE 32
  526. void Cubemap_CreateDefaultCubemap( const char *pMapName, IBSPPack *iBSPPack )
  527. {
  528. if ( IsGameConsole() )
  529. return;
  530. #ifndef _GAMECONSOLE
  531. // NOTE: This implementation depends on the fact that all VTF files contain
  532. // all mipmap levels
  533. ConVarRef skyboxBaseNameConVar( "sv_skyname" );
  534. IVTFTexture *pSrcVTFTextures[6];
  535. if ( !skyboxBaseNameConVar.IsValid() || !skyboxBaseNameConVar.GetString() )
  536. {
  537. Warning( "Couldn't create default cubemap\n" );
  538. return;
  539. }
  540. const char *pSkyboxBaseName = skyboxBaseNameConVar.GetString();
  541. if( !LoadSrcVTFFiles( pSrcVTFTextures, pSkyboxBaseName ) )
  542. {
  543. Warning( "Can't load skybox file %s to build the default cubemap!\n", pSkyboxBaseName );
  544. return;
  545. }
  546. Msg( "Creating default cubemaps for env_cubemap using skybox %s...\n", pSkyboxBaseName );
  547. // Figure out the mip differences between the two textures
  548. int iMipLevelOffset = 0;
  549. int tmp = pSrcVTFTextures[0]->Width();
  550. while( tmp > DEFAULT_CUBEMAP_SIZE )
  551. {
  552. iMipLevelOffset++;
  553. tmp >>= 1;
  554. }
  555. // Create the destination cubemap
  556. IVTFTexture *pDstCubemap = CreateVTFTexture();
  557. pDstCubemap->Init( DEFAULT_CUBEMAP_SIZE, DEFAULT_CUBEMAP_SIZE, 1,
  558. pSrcVTFTextures[0]->Format(), pSrcVTFTextures[0]->Flags() | TEXTUREFLAGS_ENVMAP,
  559. pSrcVTFTextures[0]->FrameCount() );
  560. // First iterate over all frames
  561. for (int iFrame = 0; iFrame < pDstCubemap->FrameCount(); ++iFrame)
  562. {
  563. // Next iterate over all normal cube faces (we know there's 6 cause it's an envmap)
  564. for (int iFace = 0; iFace < 6; ++iFace )
  565. {
  566. // Finally, iterate over all mip levels in the *destination*
  567. for (int iMip = 0; iMip < pDstCubemap->MipCount(); ++iMip )
  568. {
  569. // Copy the bits from the source images into the cube faces
  570. unsigned char *pSrcBits = pSrcVTFTextures[iFace]->ImageData( iFrame, 0, iMip + iMipLevelOffset );
  571. unsigned char *pDstBits = pDstCubemap->ImageData( iFrame, iFace, iMip );
  572. int iSize = pDstCubemap->ComputeMipSize( iMip );
  573. int iSrcMipSize = pSrcVTFTextures[iFace]->ComputeMipSize( iMip + iMipLevelOffset );
  574. // !!! FIXME: Set this to black until the LDR/HDR issues are fixed on line ~563 in this file
  575. memset( pDstBits, 0, iSize );
  576. continue;
  577. if ( ( pSrcVTFTextures[iFace]->Width() == 4 ) && ( pSrcVTFTextures[iFace]->Height() == 4 ) ) // If texture is 4x4 square
  578. {
  579. // Force mip level 2 to get the 1x1 face
  580. unsigned char *pSrcBits = pSrcVTFTextures[iFace]->ImageData( iFrame, 0, 2 );
  581. int iSrcMipSize = pSrcVTFTextures[iFace]->ComputeMipSize( 2 );
  582. // Replicate 1x1 mip level across entire face
  583. //memset( pDstBits, 0, iSize );
  584. for ( int i = 0; i < ( iSize / iSrcMipSize ); i++ )
  585. {
  586. memcpy( pDstBits + ( i * iSrcMipSize ), pSrcBits, iSrcMipSize );
  587. }
  588. }
  589. else if ( pSrcVTFTextures[iFace]->Width() == pSrcVTFTextures[iFace]->Height() ) // If texture is square
  590. {
  591. if ( iSrcMipSize != iSize )
  592. {
  593. Warning( "%s - ERROR! Cannot copy square face for default cubemap! iSrcMipSize(%d) != iSize(%d)\n", pSkyboxBaseName, iSrcMipSize, iSize );
  594. memset( pDstBits, 0, iSize );
  595. }
  596. else
  597. {
  598. // Just copy the mip level
  599. memcpy( pDstBits, pSrcBits, iSize );
  600. }
  601. }
  602. else if ( pSrcVTFTextures[iFace]->Width() == pSrcVTFTextures[iFace]->Height()*2 ) // If texture is rectangle 2x wide
  603. {
  604. int iMipWidth, iMipHeight, iMipDepth;
  605. pDstCubemap->ComputeMipLevelDimensions( iMip, &iMipWidth, &iMipHeight, &iMipDepth );
  606. if ( ( iMipHeight > 1 ) && ( iSrcMipSize*2 != iSize ) )
  607. {
  608. Warning( "%s - ERROR building default cube map! %d*2 != %d\n", pSkyboxBaseName, iSrcMipSize, iSize );
  609. memset( pDstBits, 0, iSize );
  610. }
  611. else
  612. {
  613. // Copy row at a time and repeat last row
  614. memcpy( pDstBits, pSrcBits, iSize/2 );
  615. //memcpy( pDstBits + iSize/2, pSrcBits, iSize/2 );
  616. int nSrcRowSize = pSrcVTFTextures[iFace]->RowSizeInBytes( iMip + iMipLevelOffset );
  617. int nDstRowSize = pDstCubemap->RowSizeInBytes( iMip );
  618. if ( nSrcRowSize != nDstRowSize )
  619. {
  620. Warning( "%s - ERROR building default cube map! nSrcRowSize(%d) != nDstRowSize(%d)!\n", pSkyboxBaseName, nSrcRowSize, nDstRowSize );
  621. memset( pDstBits, 0, iSize );
  622. }
  623. else
  624. {
  625. for ( int i = 0; i < ( iSize/2 / nSrcRowSize ); i++ )
  626. {
  627. memcpy( pDstBits + iSize/2 + i*nSrcRowSize, pSrcBits + iSrcMipSize - nSrcRowSize, nSrcRowSize );
  628. }
  629. }
  630. }
  631. }
  632. else
  633. {
  634. // ERROR! This code only supports square and rectangluar 2x wide
  635. Warning( "%s - Couldn't create default cubemap because texture res is %dx%d\n", pSkyboxBaseName, pSrcVTFTextures[iFace]->Width(), pSrcVTFTextures[iFace]->Height() );
  636. memset( pDstBits, 0, iSize );
  637. return;
  638. }
  639. }
  640. }
  641. }
  642. int flagUnion = 0;
  643. int i;
  644. for( i = 0; i < 6; i++ )
  645. {
  646. flagUnion |= pSrcVTFTextures[i]->Flags();
  647. }
  648. bool bHasAlpha =
  649. ( ( flagUnion & ( TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA ) ) != 0 );
  650. // Convert the cube to format that we can apply tools to it...
  651. // ImageFormat originalFormat = pDstCubemap->Format();
  652. pDstCubemap->ConvertImageFormat( IMAGE_FORMAT_DEFAULT, false );
  653. if( !bHasAlpha )
  654. {
  655. // set alpha to zero since the source doesn't have any alpha in it
  656. unsigned char *pImageData = pDstCubemap->ImageData();
  657. int size = pDstCubemap->ComputeTotalSize(); // in bytes!
  658. unsigned char *pEnd = pImageData + size;
  659. for( ; pImageData < pEnd; pImageData += 4 )
  660. {
  661. pImageData[3] = ( unsigned char )0;
  662. }
  663. }
  664. // Fixup the cubemap facing
  665. pDstCubemap->FixCubemapFaceOrientation();
  666. // Now that the bits are in place, compute the spheremaps...
  667. pDstCubemap->GenerateSpheremap();
  668. // Convert the cubemap to the final format
  669. pDstCubemap->ConvertImageFormat( IMAGE_FORMAT_DXT5, false );
  670. // Write the puppy out!
  671. char dstVTFFileName[1024];
  672. Q_snprintf( dstVTFFileName, sizeof( dstVTFFileName ), "materials/maps/%s/cubemapdefault.vtf", pMapName );
  673. CUtlBuffer outputBuf;
  674. if (!pDstCubemap->Serialize( outputBuf ))
  675. {
  676. Warning( "Error serializing default cubemap %s\n", dstVTFFileName );
  677. return;
  678. }
  679. // spit out the default one.
  680. iBSPPack->AddBufferToPack( dstVTFFileName, outputBuf.Base(), outputBuf.TellPut(), false );
  681. // Clean up the textures
  682. for( i = 0; i < 6; i++ )
  683. {
  684. DestroyVTFTexture( pSrcVTFTextures[i] );
  685. }
  686. DestroyVTFTexture( pDstCubemap );
  687. #endif
  688. }
  689. static void AddSampleToBSPFile( bool bHDR, mcubemapsample_t *pSample, const char *matDir, IBSPPack *iBSPPack, CCubemapCollection *pCC )
  690. {
  691. if ( IsGameConsole() )
  692. return;
  693. char inputTextureName[512] = {};
  694. const char *pHDRSuffix = bHDR ? "_hdr" : "";
  695. Q_snprintf( inputTextureName, sizeof( inputTextureName ), "%s/c%d_%d_%d%s.vtf", matDir, ( int )pSample->origin[0],
  696. ( int )pSample->origin[1], ( int )pSample->origin[2], pHDRSuffix );
  697. if ( pCC && !pCC->Add( inputTextureName ) )
  698. return; // Already added earlier
  699. char localPath[1024] = {};
  700. if ( !g_pFileSystem->RelativePathToFullPath( inputTextureName, "DEFAULT_WRITE_PATH", localPath, sizeof( localPath ) ) || !*localPath )
  701. {
  702. Warning( "vtex failed to compile cubemap '%s'!\n", inputTextureName );
  703. }
  704. else
  705. {
  706. // Rename the cubemap for storage in the BPS ( "blah_hdr.vtf" -> "blah.hdr.vtf" )
  707. char outputTextureName[512];
  708. const char *pHDRExtension = bHDR ? ".hdr" : "";
  709. Q_snprintf( outputTextureName, sizeof( outputTextureName ), "%s/c%d_%d_%d%s.vtf", matDir, ( int )pSample->origin[0],
  710. ( int )pSample->origin[1], ( int )pSample->origin[2], pHDRExtension );
  711. Q_FixSlashes( localPath );
  712. iBSPPack->AddFileToPack( outputTextureName, localPath );
  713. }
  714. g_pFileSystem->RemoveFile( inputTextureName, "DEFAULT_WRITE_PATH" );
  715. }
  716. /*
  717. ===============
  718. R_BuildCubemapSamples
  719. Take a cubemap at each "cubemap" entity in the current map.
  720. ===============
  721. */
  722. // HOLY CRAP THIS NEEDS TO BE CLEANED UP
  723. //Added these to seperate from R_BuildCubemapSamples to a) clean it up abit and b) fix the issue where if it fails, mouse is disabled.
  724. static bool saveShadows = true;
  725. static bool bDrawWater = true;
  726. static int nSaveLightStyle = -1;
  727. static int bSaveDrawBeams = true;
  728. static bool bSaveMatSpecular = true;
  729. static int nOldOcclusionVal = 1;
  730. static int nOldBloomDisable = 0;
  731. static int originaldrawMRMModelsVal = 1;
  732. void R_BuildCubemapSamples_PreBuild()
  733. {
  734. if ( IsGameConsole() )
  735. return;
  736. FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
  737. // Make sure that the file is writable before building cubemaps.
  738. Assert( g_pFileSystem->FileExists( GetBaseLocalClient().m_szLevelName, "GAME" ) );
  739. if( !g_pFileSystem->IsFileWritable( GetBaseLocalClient().m_szLevelName, "GAME" ) )
  740. {
  741. Warning( "%s is not writable!!! Check it out before running buildcubemaps.\n", GetBaseLocalClient().m_szLevelName );
  742. return;
  743. }
  744. // disable the mouse so that it won't be recentered all the bloody time.
  745. ConVarRef cl_mouseenable( "cl_mouseenable" );
  746. if( cl_mouseenable.IsValid() )
  747. {
  748. cl_mouseenable.SetValue( 0 );
  749. }
  750. ConVarRef r_shadows( "r_shadows" );
  751. saveShadows = true;
  752. if ( r_shadows.IsValid() )
  753. {
  754. saveShadows = r_shadows.GetBool();
  755. r_shadows.SetValue( 0 );
  756. }
  757. // Clear the water surface.
  758. ConVarRef mat_drawwater( "mat_drawwater" );
  759. bDrawWater = true;
  760. if ( mat_drawwater.IsValid() )
  761. {
  762. bDrawWater = mat_drawwater.GetBool();
  763. mat_drawwater.SetValue( 0 );
  764. }
  765. nSaveLightStyle = -1;
  766. ConVarRef r_lightstyle( "r_lightstyle" );
  767. if ( r_lightstyle.IsValid() )
  768. {
  769. nSaveLightStyle = r_lightstyle.GetInt();
  770. r_lightstyle.SetValue( 0 );
  771. R_RedownloadAllLightmaps();
  772. }
  773. bSaveDrawBeams = r_DrawBeams.GetInt();
  774. r_DrawBeams.SetValue( 0 );
  775. bSaveMatSpecular = mat_fastspecular.GetBool();
  776. // ConVar *r_drawtranslucentworld = ( ConVar * )cv->FindVar( "r_drawtranslucentworld" );
  777. // ConVar *r_drawtranslucentrenderables = ( ConVar * )cv->FindVar( "r_drawtranslucentrenderables" );
  778. // bool bSaveDrawTranslucentWorld = true;
  779. // bool bSaveDrawTranslucentRenderables = true;
  780. // if( r_drawtranslucentworld )
  781. // {
  782. // bSaveDrawTranslucentWorld = r_drawtranslucentworld->GetBool();
  783. // NOTE! : We use to set this to 0 for HDR.
  784. // r_drawtranslucentworld->SetValue( 0 );
  785. // }
  786. // if( r_drawtranslucentrenderables )
  787. // {
  788. // bSaveDrawTranslucentRenderables = r_drawtranslucentrenderables->GetBool();
  789. // NOTE! : We use to set this to 0 for HDR.
  790. // r_drawtranslucentrenderables->SetValue( 0 );
  791. // }
  792. static ConVarRef building_cubemaps( "building_cubemaps" );
  793. if ( building_cubemaps.IsValid() )
  794. {
  795. building_cubemaps.SetValue( 1 );
  796. }
  797. ConVarRef r_portalsopenall( "r_portalsopenall" );
  798. if( r_portalsopenall.IsValid() )
  799. {
  800. r_portalsopenall.SetValue( 1 );
  801. }
  802. nOldOcclusionVal = 1;
  803. ConVarRef r_occlusion( "r_occlusion" );
  804. if( r_occlusion.IsValid() )
  805. {
  806. nOldOcclusionVal = r_occlusion.GetInt();
  807. r_occlusion.SetValue( 0 );
  808. }
  809. ConVarRef mat_disable_bloom( "mat_disable_bloom" );
  810. nOldBloomDisable = 0;
  811. if ( mat_disable_bloom.IsValid() )
  812. {
  813. nOldBloomDisable = mat_disable_bloom.GetInt();
  814. mat_disable_bloom.SetValue( 1 );
  815. }
  816. ConVarRef drawMRMModelsCVar( "r_drawothermodels" );
  817. if( drawMRMModelsCVar.IsValid() )
  818. originaldrawMRMModelsVal = drawMRMModelsCVar.GetInt();
  819. }
  820. void R_BuildCubemapSamples_PostBuild()
  821. {
  822. // re-enable the mouse.
  823. ConVarRef cl_mouseenable( "cl_mouseenable" );
  824. if( cl_mouseenable.IsValid() )
  825. {
  826. cl_mouseenable.SetValue( 1 );
  827. }
  828. ConVarRef r_shadows( "r_shadows" );
  829. if( r_shadows.IsValid() )
  830. {
  831. r_shadows.SetValue( saveShadows );
  832. }
  833. ConVarRef mat_drawwater( "mat_drawwater" );
  834. if ( mat_drawwater.IsValid() )
  835. {
  836. mat_drawwater.SetValue( bDrawWater );
  837. }
  838. if( bSaveMatSpecular )
  839. {
  840. mat_fastspecular.SetValue( "1" );
  841. }
  842. else
  843. {
  844. mat_fastspecular.SetValue( "0" );
  845. }
  846. ConVarRef r_lightstyle( "r_lightstyle" );
  847. if( r_lightstyle.IsValid() )
  848. {
  849. r_lightstyle.SetValue( nSaveLightStyle );
  850. R_RedownloadAllLightmaps();
  851. }
  852. ConVarRef r_portalsopenall( "r_portalsopenall" );
  853. if( r_portalsopenall.IsValid() )
  854. {
  855. r_portalsopenall.SetValue( 0 );
  856. }
  857. ConVarRef r_occlusion( "r_occlusion" );
  858. if( r_occlusion.IsValid() )
  859. {
  860. r_occlusion.SetValue( nOldOcclusionVal );
  861. }
  862. ConVarRef mat_disable_bloom( "mat_disable_bloom" );
  863. if ( mat_disable_bloom.IsValid() )
  864. {
  865. mat_disable_bloom.SetValue( nOldBloomDisable);
  866. }
  867. r_DrawBeams.SetValue( bSaveDrawBeams );
  868. ConVarRef drawMRMModelsCVar( "r_drawothermodels" );
  869. if( drawMRMModelsCVar.IsValid() )
  870. {
  871. drawMRMModelsCVar.SetValue( originaldrawMRMModelsVal );
  872. }
  873. static ConVarRef building_cubemaps( "building_cubemaps" );
  874. if ( building_cubemaps.IsValid() )
  875. {
  876. building_cubemaps.SetValue( 0 );
  877. }
  878. }
  879. void R_BuildCubemapSamples( int numIterations )
  880. {
  881. if ( IsGameConsole() )
  882. return;
  883. // Make sure that the file is writable before building cubemaps.
  884. Assert( g_pFileSystem->FileExists( GetBaseLocalClient().m_szLevelName, "GAME" ) );
  885. if( !g_pFileSystem->IsFileWritable( GetBaseLocalClient().m_szLevelName, "GAME" ) )
  886. {
  887. Warning( "%s is not writable!!! Check it out before running buildcubemaps.\n", GetBaseLocalClient().m_szLevelName );
  888. return;
  889. }
  890. R_BuildCubemapSamples_PreBuild();
  891. int bounce;
  892. for( bounce = 0; bounce < numIterations; bounce++ )
  893. {
  894. if( bounce == 0 )
  895. {
  896. mat_fastspecular.SetValue( "0" );
  897. }
  898. else
  899. {
  900. mat_fastspecular.SetValue( "1" );
  901. }
  902. UpdateMaterialSystemConfig();
  903. char mapName[ 256 ];
  904. IClientEntity *world = entitylist->GetClientEntity( 0 );
  905. if( world && world->GetModel() )
  906. {
  907. const model_t *pModel = world->GetModel();
  908. const char *pModelName = modelloader->GetName( pModel );
  909. // This handles the case where you have a map in a directory under maps.
  910. // We need to keep everything after "maps/" so it looks for the BSP file in the right place.
  911. if ( Q_stristr( pModelName, "maps/" ) == pModelName ||
  912. Q_stristr( pModelName, "maps\\" ) == pModelName )
  913. {
  914. Q_strncpy( mapName, &pModelName[5], sizeof( mapName ) );
  915. Q_StripExtension( mapName, mapName, sizeof( mapName ) );
  916. }
  917. else
  918. {
  919. Q_FileBase( pModelName, mapName, sizeof( mapName ) );
  920. }
  921. }
  922. else
  923. {
  924. ConDMsg( "R_BuildCubemapSamples: No map loaded!\n" );
  925. R_BuildCubemapSamples_PostBuild();
  926. return;
  927. }
  928. int oldDrawMRMModelsVal = 1;
  929. ConVarRef drawMRMModelsCVar( "r_drawothermodels" );
  930. if( drawMRMModelsCVar.IsValid() )
  931. {
  932. oldDrawMRMModelsVal = drawMRMModelsCVar.GetInt();
  933. drawMRMModelsCVar.SetValue( 0 );
  934. }
  935. bool bOldLightSpritesActive = ActivateLightSprites( true );
  936. // load the vtex dll
  937. CSysModule *pModule;
  938. IVTex *ivt = VTex_Load( &pModule );
  939. if ( !ivt )
  940. return;
  941. char matDir[MAX_PATH];
  942. Q_snprintf( matDir, sizeof(matDir), "materials/maps/%s", mapName );
  943. g_pFileSystem->CreateDirHierarchy( matDir, "DEFAULT_WRITE_PATH" );
  944. char pTemp[MAX_PATH];
  945. Q_snprintf( pTemp, sizeof(pTemp), "materialsrc/maps/%s", mapName );
  946. char pMaterialSrcDir[MAX_PATH];
  947. GetModContentSubdirectory( pTemp, pMaterialSrcDir, sizeof(pMaterialSrcDir) );
  948. g_pFileSystem->CreateDirHierarchy( pMaterialSrcDir, NULL );
  949. char gameDir[MAX_OSPATH];
  950. COM_GetGameDir( gameDir, sizeof( gameDir ) );
  951. model_t *pWorldModel = ( model_t *)world->GetModel();
  952. int i;
  953. for( i = 0; i < pWorldModel->brush.pShared->m_nCubemapSamples; i++ )
  954. {
  955. mcubemapsample_t *pCubemapSample = &pWorldModel->brush.pShared->m_pCubemapSamples[i];
  956. int tgaSize = ( pCubemapSample->size == 0 ) ? mat_envmaptgasize.GetInt() : 1 << ( pCubemapSample->size-1 );
  957. int screenBufSize = 4 * tgaSize;
  958. if ( (screenBufSize > videomode->GetModeWidth()) || (screenBufSize > videomode->GetModeHeight()) )
  959. {
  960. Warning( "Cube map buffer size %d x %d is bigger than screen!\nRun at a higher resolution! or reduce your cubemap resolution (needs 4X)\n", screenBufSize, screenBufSize );
  961. // BUGBUG: We'll leak DLLs/handles if we break out here, but this should be infrequent.
  962. R_BuildCubemapSamples_PostBuild();
  963. return;
  964. }
  965. }
  966. bool bSupportsHDR = g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE;
  967. CCubemapCollection uniqueCubemaps;
  968. for( i = 0; i < pWorldModel->brush.pShared->m_nCubemapSamples; i++ )
  969. {
  970. Warning( "bounce: %d/%d sample: %d/%d\n", bounce+1, numIterations, i+1, pWorldModel->brush.pShared->m_nCubemapSamples );
  971. mcubemapsample_t *pCubemapSample = &pWorldModel->brush.pShared->m_pCubemapSamples[i];
  972. char pVTFName[ MAX_PATH ];
  973. const char *pHDRSuffix = bSupportsHDR ? "_hdr" : "";
  974. Q_snprintf( pVTFName, sizeof( pVTFName ), "%s/c%d_%d_%d%s", pMaterialSrcDir,
  975. ( int )pCubemapSample->origin[0], ( int )pCubemapSample->origin[1],
  976. ( int )pCubemapSample->origin[2], pHDRSuffix );
  977. int nTgaSize = ( pCubemapSample->size == 0 ) ? mat_envmaptgasize.GetInt() : 1 << ( pCubemapSample->size-1 );
  978. BuildSingleCubemap( pVTFName, pCubemapSample->origin, nTgaSize, bSupportsHDR, gameDir, ivt, &uniqueCubemaps );
  979. }
  980. uniqueCubemaps.Purge(); // Finished compiling cubemaps
  981. ActivateLightSprites( bOldLightSpritesActive );
  982. VTex_Unload( pModule );
  983. // load the bsppack dll
  984. IBSPPack *iBSPPack = NULL;
  985. pModule = FileSystem_LoadModule( "bsppack" );
  986. if ( pModule )
  987. {
  988. CreateInterfaceFn factory = Sys_GetFactory( pModule );
  989. if ( factory )
  990. {
  991. iBSPPack = ( IBSPPack * )factory( IBSPPACK_VERSION_STRING, NULL );
  992. }
  993. }
  994. if( !iBSPPack )
  995. {
  996. ConMsg( "Can't load bsppack.dll\n" );
  997. R_BuildCubemapSamples_PostBuild();
  998. return;
  999. }
  1000. iBSPPack->SetHDRMode( bSupportsHDR );
  1001. char mapPath[1024];
  1002. Q_snprintf( mapPath, sizeof( mapPath ), "maps/%s.bsp", mapName );
  1003. iBSPPack->LoadBSPFile( g_pFileSystem, mapPath );
  1004. // Cram the textures into the bsp.
  1005. Q_snprintf( matDir, sizeof(matDir), "materials/maps/%s", mapName );
  1006. for ( i=0 ; i < pWorldModel->brush.pShared->m_nCubemapSamples ; i++ )
  1007. {
  1008. mcubemapsample_t *pSample = &pWorldModel->brush.pShared->m_pCubemapSamples[i];
  1009. AddSampleToBSPFile( bSupportsHDR, pSample, matDir, iBSPPack, &uniqueCubemaps );
  1010. }
  1011. uniqueCubemaps.Purge(); // Finished adding cubemaps to BSP file
  1012. Cubemap_CreateDefaultCubemap( mapName, iBSPPack );
  1013. iBSPPack->WriteBSPFile( mapPath );
  1014. iBSPPack->ClearPackFile();
  1015. FileSystem_UnloadModule( pModule );
  1016. if ( Host_IsSinglePlayerGame() )
  1017. {
  1018. // use restart setpos to back to the same point in the same map
  1019. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "restart setpos\n" );
  1020. }
  1021. else
  1022. {
  1023. // can't use restart in a multiplayer game, so just load the map in listen server mode.
  1024. // FIXME: Could add a setpos x y z setang a b c to end of the map command to reset the location, but l4d stomps it with a spawn point.
  1025. Cbuf_AddText( Cbuf_GetCurrentPlayer(), va( "map %s\n", mapName ) );
  1026. }
  1027. }
  1028. R_BuildCubemapSamples_PostBuild();
  1029. UpdateMaterialSystemConfig();
  1030. // after map reloads, run any state that had to wait for map to reload
  1031. reload_materials.SetValue( 1 );
  1032. }
  1033. #if !defined( DEDICATED ) && !defined( _GAMECONSOLE )
  1034. CON_COMMAND( buildcubemaps, "Rebuild cubemaps." )
  1035. {
  1036. extern void V_RenderVGuiOnly();
  1037. bool bAllow = Host_AllowQueuedMaterialSystem(false);
  1038. // do this to force a frame to render so the material system syncs up to single thread mode
  1039. V_RenderVGuiOnly();
  1040. if ( args.ArgC() == 1 )
  1041. {
  1042. R_BuildCubemapSamples( 1 );
  1043. }
  1044. else if( args.ArgC() == 2 )
  1045. {
  1046. R_BuildCubemapSamples( atoi( args[ 1 ] ) );
  1047. }
  1048. else
  1049. {
  1050. ConMsg( "Usage: buildcubemaps [numBounces]\n" );
  1051. }
  1052. Host_AllowQueuedMaterialSystem(bAllow);
  1053. }
  1054. #endif // DEDICATED
  1055. #endif