2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
// HDRFIXME: reduce the number of include files here.
# include "render_pch.h"
# include "client.h"
# include "cdll_int.h"
# include "lightcache.h"
# include "client_class.h"
# include "icliententitylist.h"
# include "traceinit.h"
# include "server.h"
# include "ispatialpartitioninternal.h"
# include "cdll_engine_int.h"
# include "filesystem.h"
# include "filesystem_engine.h"
# include "ivtex.h"
# include "materialsystem/itexture.h"
# include "view.h"
# include "tier0/dbg.h"
# include "tier2/fileutils.h"
# include "staticpropmgr.h"
# include "icliententity.h"
# include "gl_drawlights.h"
# include "Overlay.h"
# include "vmodes.h"
# include "gl_cvars.h"
# include "utlbuffer.h"
# include "vtf/vtf.h"
# include "bitmap/imageformat.h"
# include "cbenchmark.h"
# include "r_decal.h"
# include "ivideomode.h"
# include "tier0/icommandline.h"
# include "dmxloader/dmxelement.h"
# include "dmxloader/dmxloader.h"
# include "bitmap/float_bm.h"
# include "tier2/tier2.h"
# include "../utils/common/bsplib.h"
# include "ibsppack.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
// putting this here so that it is replicated to the client.dll and materialsystem.dll
ConVar dynamic_tonemap ( " mat_dynamic_tonemapping " , " 1 " , FCVAR_CHEAT ) ;
ConVar building_cubemaps ( " building_cubemaps " , " 0 " ) ;
ConVar reload_materials ( " reload_materials " , " 0 " ) ;
ConVar r_DrawBeams ( " r_DrawBeams " , " 1 " , FCVAR_CHEAT , " 0=Off, 1=Normal, 2=Wireframe " ) ;
static ConVar mat_force_tonemap_scale ( " mat_force_tonemap_scale " , " 0.0 " , FCVAR_CHEAT ) ;
static const char * facingName [ 6 ] = { " rt " , " lf " , " bk " , " ft " , " up " , " dn " } ;
//-----------------------------------------------------------------------------
// Load, unload vtex
//-----------------------------------------------------------------------------
IVTex * VTex_Load ( CSysModule * * pModule )
{
// load the vtex dll
IVTex * pIVTex = NULL ;
* pModule = FileSystem_LoadModule ( " vtex_dll " ) ;
if ( * pModule )
{
CreateInterfaceFn factory = Sys_GetFactory ( * pModule ) ;
if ( factory )
{
pIVTex = ( IVTex * ) factory ( IVTEX_VERSION_STRING , NULL ) ;
}
}
if ( ! pIVTex )
{
ConMsg ( " Can't load vtex_dll.dll \n " ) ;
}
return pIVTex ;
}
void VTex_Unload ( CSysModule * pModule )
{
FileSystem_UnloadModule ( pModule ) ;
}
//-----------------------------------------------------------------------------
// Main entry point for taking cubemap snapshots
//-----------------------------------------------------------------------------
static void TakeCubemapSnapshot ( const Vector & origin , const char * pFileNameBase , int screenBufSize ,
int tgaSize , bool bPFM )
{
if ( IsX360 ( ) )
return ;
if ( g_LostVideoMemory )
return ;
ITexture * pSaveRenderTarget = NULL ;
CMatRenderContextPtr pRenderContext ( materials ) ;
// HDRFIXME: push/pop
if ( bPFM )
{
pSaveRenderTarget = pRenderContext - > GetRenderTarget ( ) ;
pRenderContext - > SetRenderTarget ( NULL ) ;
}
// HACK HACK HACK!!!!
// If this is lower than the size of the render target (I think) we don't get water.
screenBufSize = 512 ;
char name [ 1024 ] ;
CViewSetup view ;
memset ( & view , 0 , sizeof ( view ) ) ;
view . origin = origin ;
view . m_flAspectRatio = 1.0f ;
view . m_bRenderToSubrectOfLargerScreen = true ;
// garymcthack
view . zNear = 8.0f ;
view . zFar = 28400.0f ;
view . x = 0 ;
view . y = 0 ;
view . width = ( float ) screenBufSize ;
view . height = ( float ) screenBufSize ;
const char * pExtension = " .tga " ;
if ( bPFM )
{
pExtension = " .pfm " ;
}
Shader_BeginRendering ( ) ;
if ( bPFM )
{
int backbufferWidth , backbufferHeight ;
materials - > GetBackBufferDimensions ( backbufferWidth , backbufferHeight ) ;
pRenderContext - > Viewport ( 0 , 0 , backbufferWidth , backbufferHeight ) ;
pRenderContext - > ClearColor3ub ( 128 , 128 , 128 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
}
int nFlags = VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ;
// NOTE: This is for a workaround on ATI with building cubemaps.
// Clearing just the viewport doesn't seem to work properly.
nFlags | = VIEW_CLEAR_FULL_TARGET ;
static float angle0 [ 6 ] = { 0 , 0 , 0 , 0 , - 90 , 90 } ;
static float angle1 [ 6 ] = { 0 , 180 , 90 , 270 , 0 , 0 } ;
static CubeMapFaceIndex_t face_idx [ 6 ] = { CUBEMAP_FACE_RIGHT , CUBEMAP_FACE_LEFT ,
CUBEMAP_FACE_BACK , CUBEMAP_FACE_FRONT ,
CUBEMAP_FACE_UP , CUBEMAP_FACE_DOWN } ;
static int engine_cubemap_idx_to_fbm_idx [ 6 ] = { 4 , 3 , 0 , 2 , 5 , 1 } ;
if ( bPFM )
{
FloatCubeMap_t Envmap ( tgaSize , tgaSize ) ;
for ( int side = 0 ; side < 6 ; side + + )
{
view . angles [ 0 ] = angle0 [ side ] ;
view . angles [ 1 ] = angle1 [ side ] ;
view . angles [ 2 ] = 0 ;
view . fov = 90 ;
view . fovViewmodel = 90 ;
view . origin = origin ;
if ( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) = = HDR_TYPE_INTEGER )
{
FloatBitMap_t & hdr_map = Envmap . face_maps [ engine_cubemap_idx_to_fbm_idx [ side ] ] ;
hdr_map . Clear ( 0 , 0 , 0 , 1 ) ;
// we are going to need to render multiple exposures
float exposure = 16.0 ;
bool bOverExposedTexels = true ;
while ( bOverExposedTexels & & ( exposure > 0.05 ) )
{
mat_force_tonemap_scale . SetValue ( 0.0f ) ;
pRenderContext - > ResetToneMappingScale ( exposure ) ;
g_ClientDLL - > RenderView ( view , nFlags , 0 ) ;
uint8 * pImage = new uint8 [ screenBufSize * screenBufSize * 4 ] ;
uint8 * pImage1 = new uint8 [ tgaSize * tgaSize * 4 ] ;
// Get Bits from the material system
pRenderContext - > ReadPixels ( 0 , 0 , screenBufSize , screenBufSize ,
pImage , IMAGE_FORMAT_RGBA8888 ) ;
ImageLoader : : ResampleInfo_t info ;
info . m_pSrc = pImage ;
info . m_pDest = pImage1 ;
info . m_nSrcWidth = screenBufSize ;
info . m_nSrcHeight = screenBufSize ;
info . m_nDestWidth = tgaSize ;
info . m_nDestHeight = tgaSize ;
info . m_flSrcGamma = 1.0f ;
info . m_flDestGamma = 1.0f ;
if ( ! ImageLoader : : ResampleRGBA8888 ( info ) )
{
Sys_Error ( " Can't resample \n " ) ;
}
FloatBitMap_t ldr_map ( tgaSize , tgaSize ) ;
for ( int x1 = 0 ; x1 < tgaSize ; x1 + + )
for ( int y1 = 0 ; y1 < tgaSize ; y1 + + )
for ( int c = 0 ; c < 3 ; c + + )
ldr_map . Pixel ( x1 , y1 , c ) = pImage1 [ c + 4 * ( x1 + tgaSize * y1 ) ] * ( 1 / 255.0 ) ;
delete [ ] pImage ;
delete [ ] pImage1 ;
ldr_map . RaiseToPower ( 2.2 ) ; // gamma to linear
float scale = 1.0 / exposure ;
bOverExposedTexels = false ;
for ( int x = 0 ; x < hdr_map . Width ; x + + )
for ( int y = 0 ; y < hdr_map . Height ; y + + )
for ( int c = 0 ; c < 3 ; c + + )
{
float texel = ldr_map . Pixel ( x , y , c ) ;
if ( texel > 0.98 )
bOverExposedTexels = true ;
texel * = scale ;
hdr_map . Pixel ( x , y , c ) = max ( hdr_map . Pixel ( x , y , c ) , texel ) ;
}
exposure * = 0.75 ;
materials - > SwapBuffers ( ) ;
}
Q_snprintf ( name , sizeof ( name ) , " %s%s%s " , pFileNameBase , facingName [ side ] , pExtension ) ;
// hdr_map.WritePFM(name);
}
else
{
g_ClientDLL - > RenderView ( view , nFlags , 0 ) ;
Q_snprintf ( name , sizeof ( name ) , " %s%s%s " , pFileNameBase , facingName [ side ] , pExtension ) ;
Assert ( strlen ( name ) < 1023 ) ;
videomode - > TakeSnapshotTGARect ( name , 0 , 0 , screenBufSize , screenBufSize , tgaSize , tgaSize , bPFM , face_idx [ side ] ) ;
}
}
if ( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) = = HDR_TYPE_INTEGER )
{
// FloatCubeMap_t OutEnvmap(tgaSize, tgaSize);
// for(int f=0;f<6;f++)
// OutEnvmap.face_maps[f].Clear(0,0,0,1);
// Envmap.Resample(OutEnvmap,15.0);
Q_snprintf ( name , sizeof ( name ) , " %s " , pFileNameBase ) ;
Envmap . WritePFMs ( name ) ;
// Q_snprintf( name, sizeof( name ), "%s_filtered", pFileNameBase);
// OutEnvmap.WritePFMs( name );
}
}
else
{
for ( int side = 0 ; side < 6 ; side + + )
{
view . angles [ 0 ] = angle0 [ side ] ;
view . angles [ 1 ] = angle1 [ side ] ;
view . angles [ 2 ] = 0 ;
view . fov = 90 ;
view . fovViewmodel = 90 ;
view . origin = origin ;
g_ClientDLL - > RenderView ( view , nFlags , 0 ) ;
Q_snprintf ( name , sizeof ( name ) , " %s%s%s " , pFileNameBase , facingName [ side ] , pExtension ) ;
Assert ( strlen ( name ) < 1023 ) ;
videomode - > TakeSnapshotTGARect ( name , 0 , 0 , screenBufSize , screenBufSize , tgaSize , tgaSize , bPFM , face_idx [ side ] ) ;
}
}
if ( bPFM )
{
materials - > SwapBuffers ( ) ;
}
// HDRFIXME: push/pop
if ( bPFM )
{
pRenderContext - > SetRenderTarget ( pSaveRenderTarget ) ;
}
}
//-----------------------------------------------------------------------------
// Interface factory for VTex
//-----------------------------------------------------------------------------
void * CubemapsFSFactory ( const char * pName , int * pReturnCode )
{
if ( IsX360 ( ) )
return NULL ;
if ( Q_stricmp ( pName , FILESYSTEM_INTERFACE_VERSION ) = = 0 )
return g_pFileSystem ;
return NULL ;
}
//-----------------------------------------------------------------------------
// Generates a cubemap .vtf from .TGA snapshots
//-----------------------------------------------------------------------------
static void BuildSingleCubemap ( const char * pVTFName , const Vector & vecOrigin ,
int nSize , bool bHDR , const char * pGameDir , IVTex * ivt )
{
if ( IsX360 ( ) )
return ;
int nScreenBufSize = 4 * nSize ;
TakeCubemapSnapshot ( vecOrigin , pVTFName , nScreenBufSize , nSize , bHDR ) ;
char pTXTName [ MAX_PATH ] ;
Q_strncpy ( pTXTName , pVTFName , sizeof ( pTXTName ) ) ;
Q_SetExtension ( pTXTName , " .txt " , sizeof ( pTXTName ) ) ;
// HDRFIXME: Make this go to a buffer instead.
FileHandle_t fp = g_pFileSystem - > Open ( pTXTName , " w " ) ;
if ( bHDR )
{
g_pFileSystem - > FPrintf ( fp , " \" pfm \" \" 1 \" \n " ) ;
// HDRFIXME: Make sure that we can mip and lod and get rid of this.
}
// don't let any dest alpha creep into the image
g_pFileSystem - > FPrintf ( fp , " \" stripalphachannel \" \" 1 \" \n " ) ;
g_pFileSystem - > Close ( fp ) ;
if ( ivt )
{
char * argv [ 64 ] ;
int iArg = 0 ;
argv [ iArg + + ] = " " ;
argv [ iArg + + ] = " -quiet " ;
argv [ iArg + + ] = " -UseStandardError " ; // These are only here for the -currently released- version of vtex.dll.
argv [ iArg + + ] = " -WarningsAsErrors " ;
argv [ iArg + + ] = pTXTName ;
ivt - > VTex ( CubemapsFSFactory , pGameDir , iArg , argv ) ;
}
g_pFileSystem - > RemoveFile ( pTXTName , NULL ) ;
const char * pSrcExtension = bHDR ? " .pfm " : " .tga " ;
for ( int i = 0 ; i < 6 ; i + + )
{
char pTempName [ MAX_PATH ] ;
Q_snprintf ( pTempName , sizeof ( pTempName ) , " %s%s " , pVTFName , facingName [ i ] ) ;
Q_SetExtension ( pTempName , pSrcExtension , sizeof ( pTempName ) ) ;
g_pFileSystem - > RemoveFile ( pTempName , NULL ) ;
}
}
# if !defined( SWDS )
//-----------------------------------------------------------------------------
// Grab six views for environment mapping tests
//-----------------------------------------------------------------------------
CON_COMMAND ( envmap , " " )
{
if ( IsX360 ( ) )
return ;
char base [ 256 ] ;
IClientEntity * world = entitylist - > GetClientEntity ( 0 ) ;
if ( world & & world - > GetModel ( ) )
{
Q_FileBase ( modelloader - > GetName ( ( model_t * ) world - > GetModel ( ) ) , base , sizeof ( base ) ) ;
}
else
{
Q_strncpy ( base , " Env " , sizeof ( base ) ) ;
}
int strLen = strlen ( base ) + strlen ( " cubemap_screenshots/ " ) + 1 ;
char * str = ( char * ) _alloca ( strLen ) ;
Q_snprintf ( str , strLen , " cubemap_screenshots/%s " , base ) ;
g_pFileSystem - > CreateDirHierarchy ( " cubemap_screenshots " , " DEFAULT_WRITE_PATH " ) ;
TakeCubemapSnapshot ( MainViewOrigin ( ) , str , mat_envmapsize . GetInt ( ) , mat_envmaptgasize . GetInt ( ) ,
g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ! = HDR_TYPE_NONE ) ;
}
//-----------------------------------------------------------------------------
// Write lighting information to a DMX file
//-----------------------------------------------------------------------------
static void WriteLightProbe ( const char * pBasePath , const LightingState_t & state , bool bHDR )
{
char pFullPath [ MAX_PATH ] ;
Q_strncpy ( pFullPath , pBasePath , sizeof ( pFullPath ) ) ;
Q_SetExtension ( pFullPath , " .prb " , sizeof ( pFullPath ) ) ;
DECLARE_DMX_CONTEXT ( ) ;
CDmxElement * pLightProbe = CreateDmxElement ( " DmeElement " ) ;
const char * pCubemap = pBasePath + Q_strlen ( " materials/ " ) ;
CDmxElementModifyScope modify ( pLightProbe ) ;
pLightProbe - > SetValue ( " name " , " lightprobe " ) ;
pLightProbe - > SetValue ( " cubemap " , pCubemap ) ;
if ( bHDR )
{
char pTemp [ MAX_PATH ] ;
Q_snprintf ( pTemp , sizeof ( pTemp ) , " %s_hdr " , pCubemap ) ;
pLightProbe - > SetValue ( " cubemapHdr " , pTemp ) ;
}
CDmxAttribute * pAmbientCube = pLightProbe - > AddAttribute ( " ambientCube " ) ;
CUtlVector < Vector > & vec = pAmbientCube - > GetArrayForEdit < Vector > ( ) ;
for ( int i = 0 ; i < 6 ; + + i )
{
vec . AddToTail ( state . r_boxcolor [ i ] ) ;
}
CDmxAttribute * pLocalLightList = pLightProbe - > AddAttribute ( " localLights " ) ;
CUtlVector < CDmxElement * > & lights = pLocalLightList - > GetArrayForEdit < CDmxElement * > ( ) ;
modify . Release ( ) ;
for ( int i = 0 ; i < state . numlights ; + + i )
{
CDmxElement * pLight = CreateDmxElement ( " DmeElement " ) ;
lights . AddToTail ( pLight ) ;
const dworldlight_t & wl = * state . locallight [ i ] ;
pLight - > SetValue ( " color " , wl . intensity ) ;
switch ( wl . type )
{
case emit_point :
pLight - > SetValue ( " name " , " Point " ) ;
pLight - > SetValue ( " origin " , wl . origin ) ;
pLight - > SetValue ( " attenuation " , Vector ( wl . constant_attn , wl . linear_attn , wl . quadratic_attn ) ) ;
pLight - > SetValue ( " maxDistance " , wl . radius ) ;
break ;
case emit_spotlight :
pLight - > SetValue ( " name " , " Spot " ) ;
pLight - > SetValue ( " origin " , wl . origin ) ;
pLight - > SetValue ( " direction " , wl . normal ) ;
pLight - > SetValue ( " attenuation " , Vector ( wl . constant_attn , wl . linear_attn , wl . quadratic_attn ) ) ;
pLight - > SetValue ( " theta " , 2.0f * acos ( wl . stopdot ) ) ;
pLight - > SetValue ( " phi " , 2.0f * acos ( wl . stopdot2 ) ) ;
pLight - > SetValue ( " exponent " , wl . exponent ? wl . exponent : 1.0f ) ;
pLight - > SetValue ( " maxDistance " , wl . radius ) ;
break ;
case emit_surface :
pLight - > SetValue ( " name " , " Spot " ) ;
pLight - > SetValue ( " origin " , wl . origin ) ;
pLight - > SetValue ( " direction " , wl . normal ) ;
pLight - > SetValue ( " attenuation " , Vector ( 0.0f , 0.0f , 1.0f ) ) ;
pLight - > SetValue ( " theta " , 0.0f ) ;
pLight - > SetValue ( " phi " , 0.0f ) ;
pLight - > SetValue ( " exponent " , 1.0f ) ;
pLight - > SetValue ( " maxDistance " , wl . radius ) ;
break ;
case emit_skylight :
pLight - > SetValue ( " name " , " Directional " ) ;
pLight - > SetValue ( " direction " , wl . normal ) ;
break ;
}
}
CUtlBuffer buf ( 0 , 0 , CUtlBuffer : : TEXT_BUFFER ) ;
if ( SerializeDMX ( buf , pLightProbe , pFullPath ) )
{
g_pFullFileSystem - > WriteFile ( pFullPath , " MOD " , buf ) ;
}
CleanupDMX ( pLightProbe ) ;
}
//-----------------------------------------------------------------------------
// Grab an envmap @ the view position + write lighting information
//-----------------------------------------------------------------------------
CON_COMMAND ( lightprobe ,
" Samples the lighting environment. \n "
" Creates a cubemap and a file indicating the local lighting in a subdirectory called 'materials/lightprobes' \n . "
" The lightprobe command requires you specify a base file name. \n " )
{
if ( IsX360 ( ) )
return ;
if ( args . ArgC ( ) < 2 )
{
ConMsg ( " sample_lighting usage: lightprobe <base file name> [cubemap dimension] \n " ) ;
return ;
}
int nTGASize = mat_envmaptgasize . GetInt ( ) ;
if ( args . ArgC ( ) > = 3 )
{
nTGASize = atoi ( args [ 2 ] ) ;
}
CSysModule * pModule ;
IVTex * pIVTex = VTex_Load ( & pModule ) ;
if ( ! pIVTex )
return ;
char pBasePath [ MAX_PATH ] ;
Q_snprintf ( pBasePath , sizeof ( pBasePath ) , " materials/lightprobes/%s " , args [ 1 ] ) ;
Q_StripFilename ( pBasePath ) ;
g_pFileSystem - > CreateDirHierarchy ( pBasePath , " DEFAULT_WRITE_PATH " ) ;
char pTemp [ MAX_PATH ] ;
char pMaterialSrcPath [ MAX_PATH ] ;
Q_snprintf ( pTemp , sizeof ( pTemp ) , " materialsrc/lightprobes/%s " , args [ 1 ] ) ;
GetModContentSubdirectory ( pTemp , pMaterialSrcPath , sizeof ( pMaterialSrcPath ) ) ;
Q_StripFilename ( pMaterialSrcPath ) ;
g_pFileSystem - > CreateDirHierarchy ( pMaterialSrcPath , NULL ) ;
char pGameDir [ MAX_OSPATH ] ;
COM_GetGameDir ( pGameDir , sizeof ( pGameDir ) ) ;
bool bHDR = g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ! = HDR_TYPE_NONE ;
if ( bHDR )
{
char pTemp2 [ MAX_PATH ] ;
Q_snprintf ( pTemp2 , sizeof ( pTemp2 ) , " materialsrc/lightprobes/%s_hdr " , args [ 1 ] ) ;
GetModContentSubdirectory ( pTemp2 , pMaterialSrcPath , sizeof ( pMaterialSrcPath ) ) ;
BuildSingleCubemap ( pMaterialSrcPath , MainViewOrigin ( ) , nTGASize , true , pGameDir , pIVTex ) ;
}
GetModContentSubdirectory ( pTemp , pMaterialSrcPath , sizeof ( pMaterialSrcPath ) ) ;
BuildSingleCubemap ( pMaterialSrcPath , MainViewOrigin ( ) , nTGASize , false , pGameDir , pIVTex ) ;
VTex_Unload ( pModule ) ;
// Get the lighting at the point
LightingState_t lightingState ;
LightcacheGetDynamic_Stats stats ;
LightcacheGetDynamic ( MainViewOrigin ( ) , lightingState , stats ) ;
Q_snprintf ( pBasePath , sizeof ( pBasePath ) , " materials/lightprobes/%s " , args [ 1 ] ) ;
WriteLightProbe ( pBasePath , lightingState , bHDR ) ;
}
static bool LoadSrcVTFFiles ( IVTFTexture * pSrcVTFTextures [ 6 ] , const char * pSkyboxBaseName )
{
if ( IsX360 ( ) )
return false ;
int i ;
for ( i = 0 ; i < 6 ; i + + )
{
// !!! 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!
char srcVTFFileName [ 1024 ] ;
Q_snprintf ( srcVTFFileName , sizeof ( srcVTFFileName ) , " materials/skybox/%s%s.vtf " , pSkyboxBaseName , facingName [ i ] ) ;
CUtlBuffer buf ;
if ( ! g_pFileSystem - > ReadFile ( srcVTFFileName , NULL , buf ) )
return false ;
pSrcVTFTextures [ i ] = CreateVTFTexture ( ) ;
if ( ! pSrcVTFTextures [ i ] - > Unserialize ( buf ) )
{
Warning ( " *** Error unserializing skybox texture: %s \n " , pSkyboxBaseName ) ;
return false ;
}
// NOTE: texture[0] is a side texture that could be 1/2 height, so allow this and also allow 4x4 faces
if ( ( ( pSrcVTFTextures [ i ] - > Width ( ) ! = pSrcVTFTextures [ 0 ] - > Width ( ) ) & & ( pSrcVTFTextures [ i ] - > Width ( ) ! = 4 ) ) | |
( ( pSrcVTFTextures [ i ] - > Height ( ) ! = pSrcVTFTextures [ 0 ] - > Height ( ) ) & & ( pSrcVTFTextures [ i ] - > Height ( ) ! = pSrcVTFTextures [ 0 ] - > Height ( ) * 2 ) & & ( pSrcVTFTextures [ i ] - > Height ( ) ! = 4 ) ) | |
( pSrcVTFTextures [ i ] - > Flags ( ) ! = pSrcVTFTextures [ 0 ] - > Flags ( ) ) )
{
Warning ( " *** Error: Skybox vtf files for %s weren't compiled with the same size texture and/or same flags! \n " , pSkyboxBaseName ) ;
return false ;
}
}
return true ;
}
# define DEFAULT_CUBEMAP_SIZE 32
void Cubemap_CreateDefaultCubemap ( const char * pMapName , IBSPPack * iBSPPack )
{
if ( IsX360 ( ) )
return ;
// NOTE: This implementation depends on the fact that all VTF files contain
// all mipmap levels
ConVarRef skyboxBaseNameConVar ( " sv_skyname " ) ;
IVTFTexture * pSrcVTFTextures [ 6 ] ;
if ( ! skyboxBaseNameConVar . IsValid ( ) | | ! skyboxBaseNameConVar . GetString ( ) )
{
Warning ( " Couldn't create default cubemap \n " ) ;
return ;
}
const char * pSkyboxBaseName = skyboxBaseNameConVar . GetString ( ) ;
if ( ! LoadSrcVTFFiles ( pSrcVTFTextures , pSkyboxBaseName ) )
{
Warning ( " Can't load skybox file %s to build the default cubemap! \n " , pSkyboxBaseName ) ;
return ;
}
Msg ( " Creating default cubemaps for env_cubemap using skybox %s... \n " , pSkyboxBaseName ) ;
// Figure out the mip differences between the two textures
int iMipLevelOffset = 0 ;
int tmp = pSrcVTFTextures [ 0 ] - > Width ( ) ;
while ( tmp > DEFAULT_CUBEMAP_SIZE )
{
iMipLevelOffset + + ;
tmp > > = 1 ;
}
// Create the destination cubemap
IVTFTexture * pDstCubemap = CreateVTFTexture ( ) ;
pDstCubemap - > Init ( DEFAULT_CUBEMAP_SIZE , DEFAULT_CUBEMAP_SIZE , 1 ,
pSrcVTFTextures [ 0 ] - > Format ( ) , pSrcVTFTextures [ 0 ] - > Flags ( ) | TEXTUREFLAGS_ENVMAP ,
pSrcVTFTextures [ 0 ] - > FrameCount ( ) ) ;
// First iterate over all frames
for ( int iFrame = 0 ; iFrame < pDstCubemap - > FrameCount ( ) ; + + iFrame )
{
// Next iterate over all normal cube faces (we know there's 6 cause it's an envmap)
for ( int iFace = 0 ; iFace < 6 ; + + iFace )
{
// Finally, iterate over all mip levels in the *destination*
for ( int iMip = 0 ; iMip < pDstCubemap - > MipCount ( ) ; + + iMip )
{
// Copy the bits from the source images into the cube faces
unsigned char * pSrcBits = pSrcVTFTextures [ iFace ] - > ImageData ( iFrame , 0 , iMip + iMipLevelOffset ) ;
unsigned char * pDstBits = pDstCubemap - > ImageData ( iFrame , iFace , iMip ) ;
int iSize = pDstCubemap - > ComputeMipSize ( iMip ) ;
int iSrcMipSize = pSrcVTFTextures [ iFace ] - > ComputeMipSize ( iMip + iMipLevelOffset ) ;
// !!! FIXME: Set this to black until the LDR/HDR issues are fixed on line ~563 in this file
memset ( pDstBits , 0 , iSize ) ;
continue ;
if ( ( pSrcVTFTextures [ iFace ] - > Width ( ) = = 4 ) & & ( pSrcVTFTextures [ iFace ] - > Height ( ) = = 4 ) ) // If texture is 4x4 square
{
// Force mip level 2 to get the 1x1 face
pSrcBits = pSrcVTFTextures [ iFace ] - > ImageData ( iFrame , 0 , 2 ) ;
iSrcMipSize = pSrcVTFTextures [ iFace ] - > ComputeMipSize ( 2 ) ;
// Replicate 1x1 mip level across entire face
//memset( pDstBits, 0, iSize );
for ( int i = 0 ; i < ( iSize / iSrcMipSize ) ; i + + )
{
memcpy ( pDstBits + ( i * iSrcMipSize ) , pSrcBits , iSrcMipSize ) ;
}
}
else if ( pSrcVTFTextures [ iFace ] - > Width ( ) = = pSrcVTFTextures [ iFace ] - > Height ( ) ) // If texture is square
{
if ( iSrcMipSize ! = iSize )
{
Warning ( " %s - ERROR! Cannot copy square face for default cubemap! iSrcMipSize(%d) != iSize(%d) \n " , pSkyboxBaseName , iSrcMipSize , iSize ) ;
memset ( pDstBits , 0 , iSize ) ;
}
else
{
// Just copy the mip level
memcpy ( pDstBits , pSrcBits , iSize ) ;
}
}
else if ( pSrcVTFTextures [ iFace ] - > Width ( ) = = pSrcVTFTextures [ iFace ] - > Height ( ) * 2 ) // If texture is rectangle 2x wide
{
int iMipWidth , iMipHeight , iMipDepth ;
pDstCubemap - > ComputeMipLevelDimensions ( iMip , & iMipWidth , & iMipHeight , & iMipDepth ) ;
if ( ( iMipHeight > 1 ) & & ( iSrcMipSize * 2 ! = iSize ) )
{
Warning ( " %s - ERROR building default cube map! %d*2 != %d \n " , pSkyboxBaseName , iSrcMipSize , iSize ) ;
memset ( pDstBits , 0 , iSize ) ;
}
else
{
// Copy row at a time and repeat last row
memcpy ( pDstBits , pSrcBits , iSize / 2 ) ;
//memcpy( pDstBits + iSize/2, pSrcBits, iSize/2 );
int nSrcRowSize = pSrcVTFTextures [ iFace ] - > RowSizeInBytes ( iMip + iMipLevelOffset ) ;
int nDstRowSize = pDstCubemap - > RowSizeInBytes ( iMip ) ;
if ( nSrcRowSize ! = nDstRowSize )
{
Warning ( " %s - ERROR building default cube map! nSrcRowSize(%d) != nDstRowSize(%d)! \n " , pSkyboxBaseName , nSrcRowSize , nDstRowSize ) ;
memset ( pDstBits , 0 , iSize ) ;
}
else
{
for ( int i = 0 ; i < ( iSize / 2 / nSrcRowSize ) ; i + + )
{
memcpy ( pDstBits + iSize / 2 + i * nSrcRowSize , pSrcBits + iSrcMipSize - nSrcRowSize , nSrcRowSize ) ;
}
}
}
}
else
{
// ERROR! This code only supports square and rectangluar 2x wide
Warning ( " %s - Couldn't create default cubemap because texture res is %dx%d \n " , pSkyboxBaseName , pSrcVTFTextures [ iFace ] - > Width ( ) , pSrcVTFTextures [ iFace ] - > Height ( ) ) ;
memset ( pDstBits , 0 , iSize ) ;
return ;
}
}
}
}
int flagUnion = 0 ;
int i ;
for ( i = 0 ; i < 6 ; i + + )
{
flagUnion | = pSrcVTFTextures [ i ] - > Flags ( ) ;
}
bool bHasAlpha =
( ( flagUnion & ( TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA ) ) ! = 0 ) ;
// Convert the cube to format that we can apply tools to it...
// ImageFormat originalFormat = pDstCubemap->Format();
pDstCubemap - > ConvertImageFormat ( IMAGE_FORMAT_DEFAULT , false ) ;
if ( ! bHasAlpha )
{
// set alpha to zero since the source doesn't have any alpha in it
unsigned char * pImageData = pDstCubemap - > ImageData ( ) ;
int size = pDstCubemap - > ComputeTotalSize ( ) ; // in bytes!
unsigned char * pEnd = pImageData + size ;
for ( ; pImageData < pEnd ; pImageData + = 4 )
{
pImageData [ 3 ] = ( unsigned char ) 0 ;
}
}
// Fixup the cubemap facing
pDstCubemap - > FixCubemapFaceOrientation ( ) ;
// Now that the bits are in place, compute the spheremaps...
pDstCubemap - > GenerateSpheremap ( ) ;
// Convert the cubemap to the final format
pDstCubemap - > ConvertImageFormat ( IMAGE_FORMAT_DXT5 , false ) ;
// Write the puppy out!
char dstVTFFileName [ 1024 ] ;
Q_snprintf ( dstVTFFileName , sizeof ( dstVTFFileName ) , " materials/maps/%s/cubemapdefault.vtf " , pMapName ) ;
CUtlBuffer outputBuf ;
if ( ! pDstCubemap - > Serialize ( outputBuf ) )
{
Warning ( " Error serializing default cubemap %s \n " , dstVTFFileName ) ;
return ;
}
// spit out the default one.
iBSPPack - > AddBufferToPack ( dstVTFFileName , outputBuf . Base ( ) , outputBuf . TellPut ( ) , false ) ;
// Clean up the textures
for ( i = 0 ; i < 6 ; i + + )
{
DestroyVTFTexture ( pSrcVTFTextures [ i ] ) ;
}
DestroyVTFTexture ( pDstCubemap ) ;
}
static void AddSampleToBSPFile ( bool bHDR , mcubemapsample_t * pSample , const char * matDir , IBSPPack * iBSPPack )
{
if ( IsX360 ( ) )
return ;
char textureName [ MAX_PATH ] = { 0 } ;
const char * pHDRExtension = " " ;
if ( bHDR )
{
pHDRExtension = " .hdr " ;
}
Q_snprintf ( textureName , sizeof ( textureName ) , " %s/c%d_%d_%d%s.vtf " , matDir , ( int ) pSample - > origin [ 0 ] ,
( int ) pSample - > origin [ 1 ] , ( int ) pSample - > origin [ 2 ] , pHDRExtension ) ;
char localPath [ MAX_PATH ] = { 0 } ;
if ( ! g_pFileSystem - > RelativePathToFullPath_safe ( textureName , " DEFAULT_WRITE_PATH " , localPath ) | | ! * localPath )
{
Warning ( " vtex failed to compile cubemap! \n " ) ;
}
else
{
Q_FixSlashes ( localPath ) ;
iBSPPack - > AddFileToPack ( textureName , localPath ) ;
}
g_pFileSystem - > RemoveFile ( textureName , " DEFAULT_WRITE_PATH " ) ;
}
/*
= = = = = = = = = = = = = = =
R_BuildCubemapSamples
Take a cubemap at each " cubemap " entity in the current map .
= = = = = = = = = = = = = = =
*/
// HOLY CRAP THIS NEEDS TO BE CLEANED UP
//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.
static bool saveShadows = true ;
static bool bDrawWater = true ;
static int nSaveLightStyle = - 1 ;
static int bSaveDrawBeams = true ;
static bool bSaveMatSpecular = true ;
static int nOldOcclusionVal = 1 ;
static int nOldBloomDisable = 0 ;
static int originaldrawMRMModelsVal = 1 ;
void R_BuildCubemapSamples_PreBuild ( )
{
// disable the mouse so that it won't be recentered all the bloody time.
ConVarRef cl_mouseenable ( " cl_mouseenable " ) ;
if ( cl_mouseenable . IsValid ( ) )
{
cl_mouseenable . SetValue ( 0 ) ;
}
ConVarRef r_shadows ( " r_shadows " ) ;
saveShadows = true ;
if ( r_shadows . IsValid ( ) )
{
saveShadows = r_shadows . GetBool ( ) ;
r_shadows . SetValue ( 0 ) ;
}
// Clear the water surface.
ConVarRef mat_drawwater ( " mat_drawwater " ) ;
bDrawWater = true ;
if ( mat_drawwater . IsValid ( ) )
{
bDrawWater = mat_drawwater . GetBool ( ) ;
mat_drawwater . SetValue ( 0 ) ;
}
nSaveLightStyle = - 1 ;
ConVarRef r_lightstyleRef ( " r_lightstyle " ) ;
if ( r_lightstyleRef . IsValid ( ) )
{
nSaveLightStyle = r_lightstyleRef . GetInt ( ) ;
r_lightstyleRef . SetValue ( 0 ) ;
R_RedownloadAllLightmaps ( ) ;
}
bSaveDrawBeams = r_DrawBeams . GetInt ( ) ;
r_DrawBeams . SetValue ( 0 ) ;
bSaveMatSpecular = mat_fastspecular . GetBool ( ) ;
// ConVar *r_drawtranslucentworld = ( ConVar * )cv->FindVar( "r_drawtranslucentworld" );
// ConVar *r_drawtranslucentrenderables = ( ConVar * )cv->FindVar( "r_drawtranslucentrenderables" );
// bool bSaveDrawTranslucentWorld = true;
// bool bSaveDrawTranslucentRenderables = true;
// if( r_drawtranslucentworld )
// {
// bSaveDrawTranslucentWorld = r_drawtranslucentworld->GetBool();
// NOTE! : We use to set this to 0 for HDR.
// r_drawtranslucentworld->SetValue( 0 );
// }
// if( r_drawtranslucentrenderables )
// {
// bSaveDrawTranslucentRenderables = r_drawtranslucentrenderables->GetBool();
// NOTE! : We use to set this to 0 for HDR.
// r_drawtranslucentrenderables->SetValue( 0 );
// }
building_cubemaps . SetValue ( 1 ) ;
ConVarRef r_portalsopenall ( " r_portalsopenall " ) ;
if ( r_portalsopenall . IsValid ( ) )
{
r_portalsopenall . SetValue ( 1 ) ;
}
nOldOcclusionVal = 1 ;
ConVarRef r_occlusion ( " r_occlusion " ) ;
if ( r_occlusion . IsValid ( ) )
{
nOldOcclusionVal = r_occlusion . GetInt ( ) ;
r_occlusion . SetValue ( 0 ) ;
}
ConVarRef mat_disable_bloom ( " mat_disable_bloom " ) ;
nOldBloomDisable = 0 ;
if ( mat_disable_bloom . IsValid ( ) )
{
nOldBloomDisable = mat_disable_bloom . GetInt ( ) ;
mat_disable_bloom . SetValue ( 1 ) ;
}
ConVarRef drawMRMModelsCVar ( " r_drawothermodels " ) ;
if ( drawMRMModelsCVar . IsValid ( ) )
originaldrawMRMModelsVal = drawMRMModelsCVar . GetInt ( ) ;
}
void R_BuildCubemapSamples_PostBuild ( )
{
// re-enable the mouse.
ConVarRef cl_mouseenable ( " cl_mouseenable " ) ;
if ( cl_mouseenable . IsValid ( ) )
{
cl_mouseenable . SetValue ( 1 ) ;
}
ConVarRef r_shadows ( " r_shadows " ) ;
if ( r_shadows . IsValid ( ) )
{
r_shadows . SetValue ( saveShadows ) ;
}
ConVarRef mat_drawwater ( " mat_drawwater " ) ;
if ( mat_drawwater . IsValid ( ) )
{
mat_drawwater . SetValue ( bDrawWater ) ;
}
if ( bSaveMatSpecular )
{
mat_fastspecular . SetValue ( " 1 " ) ;
}
else
{
mat_fastspecular . SetValue ( " 0 " ) ;
}
ConVarRef r_lightstyleRef ( " r_lightstyle " ) ;
if ( r_lightstyleRef . IsValid ( ) )
{
r_lightstyleRef . SetValue ( nSaveLightStyle ) ;
R_RedownloadAllLightmaps ( ) ;
}
ConVarRef r_portalsopenall ( " r_portalsopenall " ) ;
if ( r_portalsopenall . IsValid ( ) )
{
r_portalsopenall . SetValue ( 0 ) ;
}
ConVarRef r_occlusion ( " r_occlusion " ) ;
if ( r_occlusion . IsValid ( ) )
{
r_occlusion . SetValue ( nOldOcclusionVal ) ;
}
ConVarRef mat_disable_bloom ( " mat_disable_bloom " ) ;
if ( mat_disable_bloom . IsValid ( ) )
{
mat_disable_bloom . SetValue ( nOldBloomDisable ) ;
}
r_DrawBeams . SetValue ( bSaveDrawBeams ) ;
ConVarRef drawMRMModelsCVar ( " r_drawothermodels " ) ;
if ( drawMRMModelsCVar . IsValid ( ) )
{
drawMRMModelsCVar . SetValue ( originaldrawMRMModelsVal ) ;
}
building_cubemaps . SetValue ( 0 ) ;
}
void R_BuildCubemapSamples ( int numIterations )
{
if ( IsX360 ( ) )
return ;
// Make sure that the file is writable before building cubemaps.
Assert ( g_pFileSystem - > FileExists ( cl . m_szLevelFileName , " GAME " ) ) ;
if ( ! g_pFileSystem - > IsFileWritable ( cl . m_szLevelFileName , " GAME " ) )
{
Warning ( " %s is not writable!!! Check it out before running buildcubemaps. \n " , cl . m_szLevelFileName ) ;
return ;
}
R_BuildCubemapSamples_PreBuild ( ) ;
int bounce ;
for ( bounce = 0 ; bounce < numIterations ; bounce + + )
{
if ( bounce = = 0 )
{
mat_fastspecular . SetValue ( " 0 " ) ;
}
else
{
mat_fastspecular . SetValue ( " 1 " ) ;
}
UpdateMaterialSystemConfig ( ) ;
IClientEntity * world = entitylist - > GetClientEntity ( 0 ) ;
if ( ! world | | ! world - > GetModel ( ) )
{
ConDMsg ( " R_BuildCubemapSamples: No map loaded! \n " ) ;
R_BuildCubemapSamples_PostBuild ( ) ;
return ;
}
int oldDrawMRMModelsVal = 1 ;
ConVarRef drawMRMModelsCVar ( " r_drawothermodels " ) ;
if ( drawMRMModelsCVar . IsValid ( ) )
{
oldDrawMRMModelsVal = drawMRMModelsCVar . GetInt ( ) ;
drawMRMModelsCVar . SetValue ( 0 ) ;
}
bool bOldLightSpritesActive = ActivateLightSprites ( true ) ;
// load the vtex dll
CSysModule * pModule ;
IVTex * ivt = VTex_Load ( & pModule ) ;
if ( ! ivt )
return ;
char matDir [ MAX_PATH ] ;
Q_snprintf ( matDir , sizeof ( matDir ) , " materials/maps/%s " , cl . m_szLevelBaseName ) ;
g_pFileSystem - > CreateDirHierarchy ( matDir , " DEFAULT_WRITE_PATH " ) ;
char pTemp [ MAX_PATH ] ;
Q_snprintf ( pTemp , sizeof ( pTemp ) , " materialsrc/maps/%s " , cl . m_szLevelBaseName ) ;
char pMaterialSrcDir [ MAX_PATH ] ;
GetModContentSubdirectory ( pTemp , pMaterialSrcDir , sizeof ( pMaterialSrcDir ) ) ;
g_pFileSystem - > CreateDirHierarchy ( pMaterialSrcDir , NULL ) ;
char gameDir [ MAX_OSPATH ] ;
COM_GetGameDir ( gameDir , sizeof ( gameDir ) ) ;
model_t * pWorldModel = ( model_t * ) world - > GetModel ( ) ;
int i ;
for ( i = 0 ; i < pWorldModel - > brush . pShared - > m_nCubemapSamples ; i + + )
{
mcubemapsample_t * pCubemapSample = & pWorldModel - > brush . pShared - > m_pCubemapSamples [ i ] ;
int tgaSize = ( pCubemapSample - > size = = 0 ) ? mat_envmaptgasize . GetInt ( ) : 1 < < ( pCubemapSample - > size - 1 ) ;
int screenBufSize = 4 * tgaSize ;
if ( ( screenBufSize > videomode - > GetModeWidth ( ) ) | | ( screenBufSize > videomode - > GetModeHeight ( ) ) )
{
Warning ( " Cube map buffer size %d x %d is bigger than screen! \n Run at a higher resolution! or reduce your cubemap resolution (needs 4X) \n " , screenBufSize , screenBufSize ) ;
// BUGBUG: We'll leak DLLs/handles if we break out here, but this should be infrequent.
R_BuildCubemapSamples_PostBuild ( ) ;
return ;
}
}
2022-03-26 00:24:41 +00:00
bool bSupportsHDR = true ; //g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE;
2020-04-22 16:56:21 +00:00
for ( i = 0 ; i < pWorldModel - > brush . pShared - > m_nCubemapSamples ; i + + )
{
Warning ( " bounce: %d/%d sample: %d/%d \n " , bounce + 1 , numIterations , i + 1 , pWorldModel - > brush . pShared - > m_nCubemapSamples ) ;
mcubemapsample_t * pCubemapSample = & pWorldModel - > brush . pShared - > m_pCubemapSamples [ i ] ;
char pVTFName [ MAX_PATH ] ;
Q_snprintf ( pVTFName , sizeof ( pVTFName ) , " %s/c%d_%d_%d " , pMaterialSrcDir ,
( int ) pCubemapSample - > origin [ 0 ] , ( int ) pCubemapSample - > origin [ 1 ] ,
( int ) pCubemapSample - > origin [ 2 ] ) ;
int nTgaSize = ( pCubemapSample - > size = = 0 ) ? mat_envmaptgasize . GetInt ( ) : 1 < < ( pCubemapSample - > size - 1 ) ;
BuildSingleCubemap ( pVTFName , pCubemapSample - > origin , nTgaSize , bSupportsHDR , gameDir , ivt ) ;
}
ActivateLightSprites ( bOldLightSpritesActive ) ;
VTex_Unload ( pModule ) ;
// load the bsppack dll
IBSPPack * iBSPPack = NULL ;
pModule = FileSystem_LoadModule ( " bsppack " ) ;
if ( pModule )
{
CreateInterfaceFn factory = Sys_GetFactory ( pModule ) ;
if ( factory )
{
iBSPPack = ( IBSPPack * ) factory ( IBSPPACK_VERSION_STRING , NULL ) ;
}
}
if ( ! iBSPPack )
{
ConMsg ( " Can't load bsppack.dll \n " ) ;
R_BuildCubemapSamples_PostBuild ( ) ;
return ;
}
2022-03-26 00:24:41 +00:00
iBSPPack - > SetHDRMode ( true /*g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE*/ ) ;
2020-04-22 16:56:21 +00:00
iBSPPack - > LoadBSPFile ( g_pFileSystem , cl . m_szLevelFileName ) ;
// Cram the textures into the bsp.
Q_snprintf ( matDir , sizeof ( matDir ) , " materials/maps/%s " , cl . m_szLevelBaseName ) ;
for ( i = 0 ; i < pWorldModel - > brush . pShared - > m_nCubemapSamples ; i + + )
{
mcubemapsample_t * pSample = & pWorldModel - > brush . pShared - > m_pCubemapSamples [ i ] ;
AddSampleToBSPFile ( bSupportsHDR , pSample , matDir , iBSPPack ) ;
}
Cubemap_CreateDefaultCubemap ( cl . m_szLevelBaseName , iBSPPack ) ;
// Resolve levelfilename to absolute to ensure we are writing the exact file we loaded and not preferentially to
// DEFAULT_WRITE_PATH
char szAbsFile [ MAX_PATH ] = { 0 } ;
g_pFullFileSystem - > RelativePathToFullPath ( cl . m_szLevelFileName , NULL , szAbsFile , sizeof ( szAbsFile ) ) ;
if ( ! * szAbsFile )
{
ConMsg ( " Failed to resolve absolute path of map: %s \n " , cl . m_szLevelFileName ) ;
R_BuildCubemapSamples_PostBuild ( ) ;
return ;
}
iBSPPack - > WriteBSPFile ( szAbsFile ) ;
iBSPPack - > ClearPackFile ( ) ;
FileSystem_UnloadModule ( pModule ) ;
Cbuf_AddText ( " restart setpos \n " ) ;
}
R_BuildCubemapSamples_PostBuild ( ) ;
UpdateMaterialSystemConfig ( ) ;
// after map reloads, run any state that had to wait for map to reload
reload_materials . SetValue ( 1 ) ;
}
# if !defined( _X360 )
CON_COMMAND ( buildcubemaps , " Rebuild cubemaps. " )
{
extern void V_RenderVGuiOnly ( ) ;
bool bAllow = Host_AllowQueuedMaterialSystem ( false ) ;
// do this to force a frame to render so the material system syncs up to single thread mode
V_RenderVGuiOnly ( ) ;
if ( args . ArgC ( ) = = 1 )
{
R_BuildCubemapSamples ( 1 ) ;
}
else if ( args . ArgC ( ) = = 2 )
{
R_BuildCubemapSamples ( atoi ( args [ 1 ] ) ) ;
}
else
{
ConMsg ( " Usage: buildcubemaps [numBounces] \n " ) ;
}
Host_AllowQueuedMaterialSystem ( bAllow ) ;
}
# endif // SWDS
# endif