From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- engine/matsys_interface.cpp | 2313 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2313 insertions(+) create mode 100644 engine/matsys_interface.cpp (limited to 'engine/matsys_interface.cpp') diff --git a/engine/matsys_interface.cpp b/engine/matsys_interface.cpp new file mode 100644 index 0000000..d3067bf --- /dev/null +++ b/engine/matsys_interface.cpp @@ -0,0 +1,2313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: loads and unloads main matsystem dll and interface +// +//===========================================================================// + +#include "render_pch.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/materialsystem_config.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/ivballoctracker.h" +#include "materialsystem/imesh.h" +#include "tier0/dbg.h" +#include "sys_dll.h" +#include "host.h" +#include "cmodel_engine.h" +#include "gl_model_private.h" +#include "view.h" +#include "gl_matsysiface.h" +#include "gl_cvars.h" +#include "gl_lightmap.h" +#include "lightcache.h" +#include "vstdlib/random.h" +#include "tier0/icommandline.h" +#include "draw.h" +#include "decal_private.h" +#include "l_studio.h" +#include "KeyValues.h" +#include "materialsystem/imaterial.h" +#include "gl_shader.h" +#include "ivideomode.h" +#include "cdll_engine_int.h" +#include "utldict.h" +#include "filesystem.h" +#include "host_saverestore.h" +#include "server.h" +#include "game/client/iclientrendertargets.h" +#include "tier2/tier2.h" +#include "LoadScreenUpdate.h" +#include "client.h" +#include "sourcevr/isourcevirtualreality.h" +#if defined( _X360 ) +#include "xbox/xbox_launch.h" +#endif + +#if defined( USE_SDL ) +#include "SDL.h" +#endif + +//X360TEMP +#include "materialsystem/itexture.h" + +extern IFileSystem *g_pFileSystem; +#ifndef SWDS +#include "iregistry.h" +#endif + +#include "igame.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Start the frame count at one so stuff gets updated the first frame +int r_framecount = 1; // used for dlight + lightstyle push checking +int d_lightstylevalue[256]; +int d_lightstylenumframes[256]; + +const MaterialSystem_Config_t *g_pMaterialSystemConfig; + +static CSysModule *g_MaterialsDLL = NULL; +bool g_LostVideoMemory = false; + +IMaterial* g_materialEmpty; // purple checkerboard for missing textures + +void ReleaseMaterialSystemObjects(); +void RestoreMaterialSystemObjects( int nChangeFlags ); + +extern ConVar mat_colorcorrection; +extern ConVar sv_allow_color_correction; + +ConVar mat_debugalttab( "mat_debugalttab", "0", FCVAR_CHEAT ); + +// Static pointers to renderable textures +static CTextureReference g_PowerOfTwoFBTexture; +static CTextureReference g_WaterReflectionTexture; +static CTextureReference g_WaterRefractionTexture; +static CTextureReference g_CameraTexture; +static CTextureReference g_BuildCubemaps16BitTexture; +static CTextureReference g_QuarterSizedFBTexture0; +static CTextureReference g_QuarterSizedFBTexture1; +static CTextureReference g_TeenyFBTexture0; +static CTextureReference g_TeenyFBTexture1; +static CTextureReference g_TeenyFBTexture2; +static CTextureReference g_FullFrameFBTexture0; +static CTextureReference g_FullFrameFBTexture1; +static CTextureReference g_FullFrameFBTexture2; +static CTextureReference g_FullFrameDepth; +static CTextureReference g_ResolvedFullFrameDepth; + +void WorldStaticMeshCreate( void ); +void WorldStaticMeshDestroy( void ); + +ConVar r_norefresh( "r_norefresh","0"); +ConVar r_decals( "r_decals", "2048" ); +ConVar mp_decals( "mp_decals","200", FCVAR_ARCHIVE); +ConVar r_lightmap( "r_lightmap", "-1", FCVAR_CHEAT | FCVAR_MATERIAL_SYSTEM_THREAD ); +ConVar r_lightstyle( "r_lightstyle","-1", FCVAR_CHEAT | FCVAR_MATERIAL_SYSTEM_THREAD ); +ConVar r_dynamic( "r_dynamic","1"); + +ConVar mat_norendering( "mat_norendering", "0", FCVAR_CHEAT ); +ConVar mat_wireframe( "mat_wireframe", "0", FCVAR_CHEAT ); +ConVar mat_luxels( "mat_luxels", "0", FCVAR_CHEAT ); +ConVar mat_normals( "mat_normals", "0", FCVAR_CHEAT ); +ConVar mat_bumpbasis( "mat_bumpbasis", "0", FCVAR_CHEAT ); +ConVar mat_envmapsize( "mat_envmapsize", "128" ); +ConVar mat_envmaptgasize( "mat_envmaptgasize", "32.0" ); +ConVar mat_levelflush( "mat_levelflush", "1" ); +ConVar mat_fastspecular( "mat_fastspecular", "1", 0, "Enable/Disable specularity for visual testing. Will not reload materials and will not affect perf." ); +ConVar mat_fullbright( "mat_fullbright","0", FCVAR_CHEAT ); + +static ConVar mat_monitorgamma( "mat_monitorgamma", "2.2", FCVAR_ARCHIVE, "monitor gamma (typically 2.2 for CRT and 1.7 for LCD)", true, 1.6f, true, 2.6f ); +static ConVar mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min", "16" ); +static ConVar mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max", "255" ); +// TV's generally have a 2.5 gamma, so we need to convert our 2.2 frame buffer into a 2.5 frame buffer for display on a TV +static ConVar mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp", "2.5", 0, "", true, 1.0f, true, 4.0f ); +#ifdef _X360 +static ConVar mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled", "1", FCVAR_ARCHIVE, "" ); +#else +static ConVar mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled", "0", FCVAR_ARCHIVE, "" ); +#endif + +ConVar r_drawbrushmodels( "r_drawbrushmodels", "1", FCVAR_CHEAT, "Render brush models. 0=Off, 1=Normal, 2=Wireframe" ); + +ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0" ); +ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" ); +#ifndef _X360 +ConVar r_waterforceexpensive( "r_waterforceexpensive", "0", FCVAR_ARCHIVE ); +#endif +ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0" ); + +// Note: this is only here so we can ship an update without changing materialsystem.dll. +// Once we ship materialsystem.dll again, we can get rid of this and make the only one exist in materialsystem.dll. +ConVar mat_depthbias_normal( "mat_depthbias_normal", "0.0f", FCVAR_CHEAT ); + +// This is here so that the client and the materialsystem can both see this. +ConVar mat_show_ab_hdr( "mat_show_ab_hdr", "0" ); + +static void NukeModeSwitchSaveGames( void ) +{ + if( g_pFileSystem->FileExists( "save\\modeswitchsave.sav" ) ) + { + g_pFileSystem->RemoveFile( "save\\modeswitchsave.sav" ); + } + if( g_pFileSystem->FileExists( "save\\modeswitchsave.tga" ) ) + { + g_pFileSystem->RemoveFile( "save\\modeswitchsave.tga" ); + } +} + +void mat_hdr_level_Callback( IConVar *var, const char *pOldString, float flOldValue ) +{ + if ( IsX360() ) + { + // can't support, expected to be static + return; + } + +#ifdef CSS_PERF_TEST + ConVarRef hdr( var ); + if ( hdr.GetInt() > 0 ) + hdr.SetValue( 0 ); + return; +#endif + // Can do any reloading that is necessary here upon change. + // FIXME: should check if there is actually going to be a change here (ie. are we able to run in HDR + // given the current map and hardware. +#ifndef SWDS + if ( g_pMaterialSystemHardwareConfig->GetHardwareHDRType() != HDR_TYPE_NONE && + saverestore->IsValidSave() && + modelloader->LastLoadedMapHasHDRLighting() && + sv.GetMaxClients() == 1 && + !sv.IsLevelMainMenuBackground() + ) + { + NukeModeSwitchSaveGames(); + Cbuf_AddText( "save modeswitchsave;wait;load modeswitchsave\n" ); + } +#endif +} + +#ifdef CSS_PERF_TEST +ConVar mat_hdr_level( "mat_hdr_level", "0", 0, + "Set to 0 for no HDR, 1 for LDR+bloom on HDR maps, and 2 for full HDR on HDR maps.", + mat_hdr_level_Callback ); +#else +ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_ARCHIVE, + "Set to 0 for no HDR, 1 for LDR+bloom on HDR maps, and 2 for full HDR on HDR maps.", + mat_hdr_level_Callback ); +#endif + +MaterialSystem_SortInfo_t *materialSortInfoArray = 0; +static bool s_bConfigLightingChanged = false; + +extern unsigned long GetRam(); + + +//----------------------------------------------------------------------------- +// return true if lightmaps need to be redownloaded +//----------------------------------------------------------------------------- +bool MaterialConfigLightingChanged() +{ + return s_bConfigLightingChanged; +} + +void ClearMaterialConfigLightingChanged() +{ + s_bConfigLightingChanged = false; +} + + +//----------------------------------------------------------------------------- +// List of all convars to store into the registry +//----------------------------------------------------------------------------- +static const char *s_pRegistryConVars[] = +{ + "mat_forceaniso", + "mat_picmip", +// "mat_dxlevel", + "mat_trilinear", + "mat_vsync", + "mat_forcehardwaresync", + "mat_parallaxmap", + "mat_reducefillrate", + "r_shadowrendertotexture", + "r_rootlod", +#ifndef _X360 + "r_waterforceexpensive", +#endif + "r_waterforcereflectentities", + "mat_antialias", + "mat_aaquality", + "mat_specular", + "mat_bumpmap", + "mat_hdr_level", + "mat_colorcorrection", + + // NOTE: Empty string must always be last! + "" +}; + +#if defined( OSX ) + #define MOD_VIDEO_CONFIG_SETTINGS "videoconfig_mac.cfg" + #define USE_VIDEOCONFIG_FILE 1 +#elif defined( POSIX ) + #define MOD_VIDEO_CONFIG_SETTINGS "videoconfig_linux.cfg" + #define USE_VIDEOCONFIG_FILE 1 +#elif defined( DX_TO_GL_ABSTRACTION ) + #define MOD_VIDEO_CONFIG_SETTINGS "videoconfig_gl.cfg" + #define USE_VIDEOCONFIG_FILE 1 +#else + #define MOD_VIDEO_CONFIG_SETTINGS "videoconfig.cfg" + #define USE_VIDEOCONFIG_FILE 0 +#endif + +#if USE_VIDEOCONFIG_FILE +static CThreadMutex g_VideoConfigMutex; +#endif + +static int ReadVideoConfigInt( const char *pName, int nDefault ) +{ +#if USE_VIDEOCONFIG_FILE + AUTO_LOCK( g_VideoConfigMutex ); + + // Try to make a keyvalues from the cfg file + KeyValues *pVideoConfig = new KeyValues( "videoconfig" ); + bool bFileExists = pVideoConfig->LoadFromFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD" ); + + // We probably didn't have one on disk yet, just bail. It'll get created soon. + if ( !bFileExists ) + return nDefault; + + int nInt = pVideoConfig->GetInt( pName, nDefault ); + pVideoConfig->deleteThis(); + return nInt; +#else + return registry->ReadInt( pName, nDefault ); +#endif +} + +static void ReadVideoConfigInt( const char *pName, int *pEntry ) +{ +#if USE_VIDEOCONFIG_FILE + AUTO_LOCK( g_VideoConfigMutex ); + + // Try to make a keyvalues from the cfg file + KeyValues *pVideoConfig = new KeyValues( "videoconfig" ); + bool bFileExists = pVideoConfig->LoadFromFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD" ); + + // We probably didn't have one on disk yet, just bail. It'll get created soon. + if ( !bFileExists ) + return; + + if ( pVideoConfig->GetInt( pName, -1 ) != -1 ) + { + *pEntry = pVideoConfig->GetInt( pName, 0 ); + } + + pVideoConfig->deleteThis(); +#else + if ( registry->ReadInt( pName, -1 ) != -1 ) + { + *pEntry = registry->ReadInt( pName, 0 ); + } +#endif +} + +static const char *ReadVideoConfigString( const char *pName, const char *pDefault ) +{ +#if USE_VIDEOCONFIG_FILE + AUTO_LOCK( g_VideoConfigMutex ); + static char szRetString[ 255 ]; + + // Try to make a keyvalues from the cfg file + KeyValues *pVideoConfig = new KeyValues( "videoconfig" ); + bool bFileExists = pVideoConfig->LoadFromFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD" ); + + // We probably didn't have one on disk yet, just bail. It'll get created soon. + if ( !bFileExists ) + return pDefault; + + const char *pString = pVideoConfig->GetString( pName, pDefault ); + Q_strncpy( szRetString, pString, sizeof(szRetString) ); + pVideoConfig->deleteThis(); + return szRetString; +#else + return registry->ReadString( pName, pDefault ); +#endif +} + + + +static void WriteVideoConfigInt( const char *pName, int nEntry ) +{ +#if USE_VIDEOCONFIG_FILE + AUTO_LOCK( g_VideoConfigMutex ); + + // Try to make a keyvalues from the cfg file + KeyValues *pVideoConfig = new KeyValues( "videoconfig" ); + pVideoConfig->LoadFromFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD" ); + + pVideoConfig->SetInt( pName, nEntry ); + + pVideoConfig->SaveToFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD", false, false, true ); + pVideoConfig->deleteThis(); +#else + registry->WriteInt( pName, nEntry ); +#endif +} + + +static void WriteVideoConfigString( const char *pName, const char *pString ) +{ +#if USE_VIDEOCONFIG_FILE + AUTO_LOCK( g_VideoConfigMutex ); + + // Try to make a keyvalues from the cfg file + KeyValues *pVideoConfig = new KeyValues( "videoconfig" ); + pVideoConfig->LoadFromFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD" ); + + pVideoConfig->SetString( pName, pString ); + + pVideoConfig->SaveToFile( g_pFullFileSystem, MOD_VIDEO_CONFIG_SETTINGS, "MOD", false, false, true ); + pVideoConfig->deleteThis(); +#else + registry->WriteString( pName, pString ); +#endif +} + +//----------------------------------------------------------------------------- +// Scan for video config convars which are overridden on the cmd line, used +// for development and automated timedemo regression testing. +// (Unfortunately, convars aren't set early enough during init from the cmd line +// for the usual machinery to work here.) +//----------------------------------------------------------------------------- +static bool s_bVideoConfigOverriddenFromCmdLine; + +template +static T OverrideVideoConfigFromCommandLine( const char *pCVarName, T curVal ) +{ + char szOption[256]; + V_snprintf( szOption, sizeof( szOption ), "+%s", pCVarName ); + if ( CommandLine()->CheckParm( szOption ) ) + { + T newVal = CommandLine()->ParmValue( szOption, curVal ); + Warning( "Video configuration ignoring %s due to command line override\n", pCVarName ); + s_bVideoConfigOverriddenFromCmdLine = true; + return newVal; + } + return curVal; +} + +//----------------------------------------------------------------------------- +// Reads convars from the registry +//----------------------------------------------------------------------------- +static void ReadMaterialSystemConfigFromRegistry( MaterialSystem_Config_t &config ) +{ +#ifndef SWDS + if ( IsX360() ) + return; + + ReadVideoConfigInt( "ScreenWidth", &config.m_VideoMode.m_Width ); + ReadVideoConfigInt( "ScreenHeight", &config.m_VideoMode.m_Height ); + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, ReadVideoConfigInt( "ScreenWindowed", 0 ) != 0 ); +#if defined( USE_SDL ) && !defined( SWDS ) + // Read the ScreenDisplayIndex and set sdl_displayindex if it's there. + ConVarRef conVar( "sdl_displayindex" ); + if ( conVar.IsValid() ) + { + int displayIndex = 0; + + ReadVideoConfigInt( "ScreenDisplayIndex", &displayIndex ); + conVar.SetValue( displayIndex ); + displayIndex = conVar.GetInt(); + + // Make sure the width / height isn't too large for this display. + SDL_Rect rect; + if ( !SDL_GetDisplayBounds( displayIndex, &rect ) ) + { + if ( ( config.m_VideoMode.m_Width > rect.w ) || ( config.m_VideoMode.m_Height > rect.h ) ) + { + config.m_VideoMode.m_Width = rect.w; + config.m_VideoMode.m_Height = rect.h; + } + } + } +#endif // USE_SDL && !SWDS + + // Special case... + const char *szMonitorGamma = ReadVideoConfigString( "ScreenMonitorGamma", "2.2" ); + if ( szMonitorGamma && strlen(szMonitorGamma) > 0 ) + { + float flMonitorGamma = atof( szMonitorGamma ); + // temp, to make sure people with gamma values saved in the old format don't max out + if (flMonitorGamma > 3.0f) + { + flMonitorGamma = 2.2f; + } + + flMonitorGamma = OverrideVideoConfigFromCommandLine( "mat_monitorgamma", flMonitorGamma ); + + mat_monitorgamma.SetValue( flMonitorGamma ); + config.m_fMonitorGamma = mat_monitorgamma.GetFloat(); + } + + for ( int i = 0; s_pRegistryConVars[i][0]; ++i ) + { + int nValue = ReadVideoConfigInt( s_pRegistryConVars[i], 0x80000000 ); + if ( nValue == 0x80000000 ) + continue; + + nValue = OverrideVideoConfigFromCommandLine( s_pRegistryConVars[i], nValue ); + + ConVarRef conVar( s_pRegistryConVars[i] ); + if ( conVar.IsValid() ) + { + conVar.SetValue( nValue ); + } + } + + int nValue = ReadVideoConfigInt( "DXLevel_V1", -1 ); + if ( nValue != -1 ) + { + nValue = OverrideVideoConfigFromCommandLine( "mat_dxlevel", nValue ); + + ConVarRef conVar( "mat_dxlevel" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( nValue ); + } + } + + nValue = ReadVideoConfigInt( "MotionBlur", -1 ); + if ( nValue != -1 ) + { + nValue = OverrideVideoConfigFromCommandLine( "mat_motion_blur_enabled", nValue ); + + ConVarRef conVar( "mat_motion_blur_enabled" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( nValue ); + config.m_bMotionBlur = ReadVideoConfigInt( "MotionBlur", 0 ) != 0; + } + } + + nValue = ReadVideoConfigInt( "ShadowDepthTexture", -1 ); + if ( nValue != -1 ) + { + nValue = OverrideVideoConfigFromCommandLine( "r_flashlightdepthtexture", nValue ); + + ConVarRef conVar( "r_flashlightdepthtexture" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( nValue ); + config.m_bShadowDepthTexture = ReadVideoConfigInt( "ShadowDepthTexture", 0 ) != 0; + } + } + + nValue = ReadVideoConfigInt( "VRModeAdapter", -1 ); + if ( nValue != -1 ) + { + nValue = OverrideVideoConfigFromCommandLine( "mat_vrmode_adapter", nValue ); + + ConVarRef conVar( "mat_vrmode_adapter" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( nValue ); + config.m_nVRModeAdapter = ReadVideoConfigInt( "VRModeAdapter", -1 ); + } + } + +#endif +} + +//----------------------------------------------------------------------------- +// Writes convars into the registry +//----------------------------------------------------------------------------- +static void WriteMaterialSystemConfigToRegistry( const MaterialSystem_Config_t &config ) +{ +#ifndef SWDS + if ( IsX360() ) + return; + +#if defined( USE_SDL ) && !defined( SWDS ) + // Save sdl_displayindex out to ScreenDisplayIndex. + ConVarRef conVar( "sdl_displayindex" ); + if ( conVar.IsValid() && !UseVR() ) + { + WriteVideoConfigInt( "ScreenDisplayIndex", conVar.GetInt() ); + } +#endif // USE_SDL && !SWDS + WriteVideoConfigInt( "ScreenWidth", config.m_VideoMode.m_Width ); + WriteVideoConfigInt( "ScreenHeight", config.m_VideoMode.m_Height ); + WriteVideoConfigInt( "ScreenWindowed", config.Windowed() ); + WriteVideoConfigInt( "ScreenMSAA", config.m_nAASamples ); + WriteVideoConfigInt( "ScreenMSAAQuality", config.m_nAAQuality ); + WriteVideoConfigInt( "MotionBlur", config.m_bMotionBlur ? 1 : 0 ); + WriteVideoConfigInt( "ShadowDepthTexture", config.m_bShadowDepthTexture ? 1 : 0 ); + WriteVideoConfigInt( "VRModeAdapter", config.m_nVRModeAdapter ); + + // Registry only stores ints, so divide/multiply by 100 when reading/writing. + WriteVideoConfigString( "ScreenMonitorGamma", mat_monitorgamma.GetString() ); + + for ( int i = 0; s_pRegistryConVars[i][0]; ++i ) + { + ConVarRef conVar( s_pRegistryConVars[i] ); + if ( !conVar.IsValid() ) + continue; + + WriteVideoConfigInt( s_pRegistryConVars[i], conVar.GetInt() ); + } +#endif +} + +//----------------------------------------------------------------------------- +// Override config with command line params +//----------------------------------------------------------------------------- +static void OverrideMaterialSystemConfigFromCommandLine( MaterialSystem_Config_t &config ) +{ + if ( IsX360() ) + { + // these overrides cannot be supported + // the console configuration is explicit + return; + } + + if ( CommandLine()->FindParm( "-dxlevel" ) ) + { + config.dxSupportLevel = CommandLine()->ParmValue( "-dxlevel", config.dxSupportLevel ); + + // hack, mat_dxlevel is a special case, since it's saved in the registry + // but has a special different command-line override + // we need to re-apply the cvar + ConVarRef conVar( "mat_dxlevel" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( config.dxSupportLevel ); + } + } + + // Check for windowed mode command line override + if ( CommandLine()->FindParm( "-sw" ) || + CommandLine()->FindParm( "-startwindowed" ) || + CommandLine()->FindParm( "-windowed" ) || + CommandLine()->FindParm( "-window" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + } + // Check for fullscreen override + else if ( CommandLine()->FindParm( "-full" ) || CommandLine()->FindParm( "-fullscreen" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, false ); + } + + // Get width and height + if ( CommandLine()->FindParm( "-width" ) || CommandLine()->FindParm( "-w" ) ) + { + config.m_VideoMode.m_Width = CommandLine()->ParmValue( "-width", config.m_VideoMode.m_Width ); + config.m_VideoMode.m_Width = CommandLine()->ParmValue( "-w", config.m_VideoMode.m_Width ); + if( !( CommandLine()->FindParm( "-height" ) || CommandLine()->FindParm( "-h" ) ) ) + { + config.m_VideoMode.m_Height = ( config.m_VideoMode.m_Width * 3 ) / 4; + } + } + if ( CommandLine()->FindParm( "-height" ) || CommandLine()->FindParm( "-h" ) ) + { + config.m_VideoMode.m_Height = CommandLine()->ParmValue( "-height", config.m_VideoMode.m_Height ); + config.m_VideoMode.m_Height = CommandLine()->ParmValue( "-h", config.m_VideoMode.m_Height ); + } + +#if defined( USE_SDL ) && !defined( SWDS ) + // If -displayindex was specified on the command line, then set sdl_displayindex. + if ( CommandLine()->FindParm( "-displayindex" ) ) + { + ConVarRef conVar( "sdl_displayindex" ); + + if ( conVar.IsValid() ) + { + int displayIndex = CommandLine()->ParmValue( "-displayindex", conVar.GetInt() ); + + conVar.SetValue( displayIndex ); + displayIndex = conVar.GetInt(); + + // Make sure the width / height isn't too large for this display. + SDL_Rect rect; + if ( !SDL_GetDisplayBounds( displayIndex, &rect ) ) + { + if ( ( config.m_VideoMode.m_Width > rect.w ) || ( config.m_VideoMode.m_Height > rect.h ) ) + { + config.m_VideoMode.m_Width = rect.w; + config.m_VideoMode.m_Height = rect.h; + } + } + } + } +#endif // USE_SDL && !SWDS + + if ( CommandLine()->FindParm( "-resizing" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, CommandLine()->CheckParm( "-resizing" ) ? true : false ); + } +#ifndef CSS_PERF_TEST + if ( CommandLine()->FindParm( "-mat_vsync" ) ) + { + int vsync = CommandLine()->ParmValue( "-mat_vsync", 1 ); + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, vsync == 0 ); + } +#endif + config.m_nAASamples = CommandLine()->ParmValue( "-mat_antialias", config.m_nAASamples ); + config.m_nAAQuality = CommandLine()->ParmValue( "-mat_aaquality", config.m_nAAQuality ); + + // Clamp the requested dimensions to the display resolution + MaterialVideoMode_t videoMode; + materials->GetDisplayMode( videoMode ); + config.m_VideoMode.m_Width = MIN( videoMode.m_Width, config.m_VideoMode.m_Width ); + config.m_VideoMode.m_Height = MIN( videoMode.m_Height, config.m_VideoMode.m_Height ); + + // safe mode + if ( CommandLine()->FindParm( "-safe" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + config.m_VideoMode.m_Width = 640; + config.m_VideoMode.m_Height = 480; + config.m_VideoMode.m_RefreshRate = 0; + config.m_nAASamples = 0; + config.m_nAAQuality = 0; + } +} + + +//----------------------------------------------------------------------------- +// Updates the material system config +//----------------------------------------------------------------------------- +void OverrideMaterialSystemConfig( MaterialSystem_Config_t &config ) +{ + // enable/disable flashlight support based on mod (user can also set this explicitly) + // FIXME: this is only here because dxsupport_override.cfg is currently broken + ConVarRef mat_supportflashlight( "mat_supportflashlight" ); + if ( mat_supportflashlight.GetInt() == -1 ) + { + const char * gameName = COM_GetModDirectory(); + if ( !V_stricmp( gameName, "portal" ) || + !V_stricmp( gameName, "tf" ) || + !V_stricmp( gameName, "tf_beta" ) ) + { + mat_supportflashlight.SetValue( false ); + } + else + { + mat_supportflashlight.SetValue( true ); + } + } + config.m_bSupportFlashlight = mat_supportflashlight.GetBool(); + + // apply the settings in the material system + bool bLightmapsNeedReloading = materials->OverrideConfig( config, false ); + if ( bLightmapsNeedReloading ) + { + s_bConfigLightingChanged = true; + } + + // if VRModeAdapter is set, don't let things come up full screen + // They will be on the HMD display and that's BAD. + if( config.m_nVRModeAdapter != -1 ) + { + WriteVideoConfigInt( "ScreenWindowed", 1 ); + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + } +} + + +void HandleServerAllowColorCorrection() +{ +#ifndef SWDS + if ( !sv_allow_color_correction.GetBool() && mat_colorcorrection.GetInt() ) + { + Warning( "mat_colorcorrection being forced to 0 due to sv_allow_color_correction=0.\n" ); + mat_colorcorrection.SetValue( 0 ); + } +#endif +} + +// auto config version to store in the registry so we can force reconfigs if needed +#define AUTOCONFIG_VERSION 1 + +//----------------------------------------------------------------------------- +// Purpose: Initializes configuration +//----------------------------------------------------------------------------- +void InitMaterialSystemConfig( bool bInEditMode ) +{ + // get the default config for the current card as a starting point. + g_pMaterialSystemConfig = &materials->GetCurrentConfigForVideoCard(); + if ( !g_pMaterialSystemConfig ) + { + Sys_Error( "Could not get the material system config record!" ); + } + if ( bInEditMode ) + return; + + MaterialSystem_Config_t config = *g_pMaterialSystemConfig; + +#if !defined(SWDS) + // see if they've changed video card, or have no settings present + MaterialAdapterInfo_t driverInfo; + materials->GetDisplayAdapterInfo( materials->GetCurrentAdapter(), driverInfo ); + + // see if the user has changed video cards or dx levels + uint currentVendorID = ReadVideoConfigInt( "VendorID", -1 ); + uint currentDeviceID = ReadVideoConfigInt( "DeviceID", -1 ); + + uint autoConfigVersion = ReadVideoConfigInt( "AutoConfigVersion", -1 ); + + if ( autoConfigVersion != AUTOCONFIG_VERSION ) + { + uint max_dxlevel, recommended_dxlevel; + materials->GetDXLevelDefaults( max_dxlevel, recommended_dxlevel ); + uint currentDXLevel = ReadVideoConfigInt( "DXLevel_V1", -1 ); + if ((max_dxlevel != recommended_dxlevel) && (currentDXLevel != recommended_dxlevel)) + { + ConVarRef conVar( "mat_dxlevel" ); + if ( conVar.IsValid() ) + { + conVar.SetValue( (int)recommended_dxlevel ); + } + } + // Update the autoconfig version. + WriteVideoConfigInt( "AutoConfigVersion", AUTOCONFIG_VERSION ); + } + + if ( driverInfo.m_VendorID == currentVendorID && + driverInfo.m_DeviceID == currentDeviceID && + !CommandLine()->FindParm( "-autoconfig" ) && + !CommandLine()->FindParm( "-dxlevel" )) + { + // the stored configuration looks like it will be valid, load it in + ReadMaterialSystemConfigFromRegistry( config ); + } +#endif + + OverrideMaterialSystemConfigFromCommandLine( config ); + OverrideMaterialSystemConfig( config ); + + // Force the convars to update -- need this due to threading + g_pCVar->ProcessQueuedMaterialThreadConVarSets(); + + // Don't smack registry if dxlevel is overridden, or if the video config was overridden from the command line. + if ( !CommandLine()->FindParm( "-dxlevel" ) && !s_bVideoConfigOverriddenFromCmdLine ) + { + WriteMaterialSystemConfigToRegistry( *g_pMaterialSystemConfig ); + } + + UpdateMaterialSystemConfig(); + +#if !defined(SWDS) + // write out the current vendor has been seen & registered + WriteVideoConfigInt( "VendorID", driverInfo.m_VendorID ); + WriteVideoConfigInt( "DeviceID", driverInfo.m_DeviceID ); + WriteVideoConfigInt( "DXLevel_V1", g_pMaterialSystemConfig->dxSupportLevel ); +#endif +} + + +//----------------------------------------------------------------------------- +// Updates the material system config +//----------------------------------------------------------------------------- +void UpdateMaterialSystemConfig( void ) +{ + if ( host_state.worldbrush && !host_state.worldbrush->lightdata ) + { + mat_fullbright.SetValue( 1 ); + } + + // apply the settings in the material system + bool bLightmapsNeedReloading = materials->UpdateConfig( false ); + if ( bLightmapsNeedReloading ) + { + s_bConfigLightingChanged = true; + } + +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets all the relevant keyvalue data to be uploaded as part of the benchmark data +// Input : *dataToUpload - keyvalue set that will be uploaded +//----------------------------------------------------------------------------- +void GetMaterialSystemConfigForBenchmarkUpload(KeyValues *dataToUpload) +{ +#if !defined(SWDS) + // hardware info + MaterialAdapterInfo_t driverInfo; + materials->GetDisplayAdapterInfo( materials->GetCurrentAdapter(), driverInfo ); + + dataToUpload->SetInt( "vendorID", driverInfo.m_VendorID ); + dataToUpload->SetInt( "deviceID", driverInfo.m_DeviceID ); + dataToUpload->SetInt( "ram", GetRam() ); + + const CPUInformation& pi = *GetCPUInformation(); + double fFrequency = pi.m_Speed / 1000000.0; + dataToUpload->SetInt( "cpu_speed", (int)fFrequency ); + dataToUpload->SetString( "cpu", pi.m_szProcessorID ); + + // material system settings + dataToUpload->SetInt( "width", g_pMaterialSystemConfig->m_VideoMode.m_Width ); + dataToUpload->SetInt( "height", g_pMaterialSystemConfig->m_VideoMode.m_Height ); + dataToUpload->SetInt( "AASamples", g_pMaterialSystemConfig->m_nAASamples ); + dataToUpload->SetInt( "AAQuality", g_pMaterialSystemConfig->m_nAAQuality ); + dataToUpload->SetInt( "AnisoLevel", g_pMaterialSystemConfig->m_nForceAnisotropicLevel ); + dataToUpload->SetInt( "SkipMipLevels", g_pMaterialSystemConfig->skipMipLevels ); + dataToUpload->SetInt( "DXLevel", g_pMaterialSystemConfig->dxSupportLevel ); + dataToUpload->SetInt( "ShadowDepthTexture", g_pMaterialSystemConfig->ShadowDepthTexture() ); + dataToUpload->SetInt( "MotionBlur", g_pMaterialSystemConfig->MotionBlur() ); + dataToUpload->SetInt( "Windowed", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_WINDOWED) ? 1 : 0 ); + dataToUpload->SetInt( "Trilinear", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR) ? 1 : 0 ); + dataToUpload->SetInt( "ForceHWSync", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC) ? 1 : 0 ); + dataToUpload->SetInt( "NoWaitForVSync", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC) ? 1 : 0 ); + dataToUpload->SetInt( "DisableSpecular", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR) ? 1 : 0 ); + dataToUpload->SetInt( "DisableBumpmapping", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP) ? 1 : 0 ); + dataToUpload->SetInt( "EnableParallaxMapping", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING) ? 1 : 0 ); + dataToUpload->SetInt( "ZPrefill", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL) ? 1 : 0 ); + dataToUpload->SetInt( "ReduceFillRate", (g_pMaterialSystemConfig->m_Flags & MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE) ? 1 : 0 ); + dataToUpload->SetInt( "RenderToTextureShadows", r_shadowrendertotexture.GetInt() ? 1 : 0 ); + dataToUpload->SetInt( "FlashlightDepthTexture", r_flashlightdepthtexture.GetInt() ? 1 : 0 ); +#ifndef _X360 + dataToUpload->SetInt( "RealtimeWaterReflection", r_waterforceexpensive.GetInt() ? 1 : 0 ); +#endif + dataToUpload->SetInt( "WaterReflectEntities", r_waterforcereflectentities.GetInt() ? 1 : 0 ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Dumps the specified config info to the console +//----------------------------------------------------------------------------- +void PrintMaterialSystemConfig( const MaterialSystem_Config_t &config ) +{ + Warning( "width: %d\n", config.m_VideoMode.m_Width ); + Warning( "height: %d\n", config.m_VideoMode.m_Height ); + Warning( "m_nForceAnisotropicLevel: %d\n", config.m_nForceAnisotropicLevel ); + Warning( "aasamples: %d\n", config.m_nAASamples ); + Warning( "aaquality: %d\n", config.m_nAAQuality ); + + Warning( "skipMipLevels: %d\n", config.skipMipLevels ); + Warning( "dxSupportLevel: %d\n", config.dxSupportLevel ); + Warning( "monitorGamma: %f\n", config.m_fMonitorGamma ); + Warning( "MATSYS_VIDCFG_FLAGS_WINDOWED: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_WINDOWED ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL ) ? "true" : "false" ); + Warning( "MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE: %s\n", ( config.m_Flags & MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE ) ? "true" : "false" ); + Warning( "r_shadowrendertotexture: %s\n", r_shadowrendertotexture.GetInt() ? "true" : "false" ); + Warning( "motionblur: %s\n", config.m_bMotionBlur ? "true" : "false" ); + Warning( "shadowdepthtexture: %s\n", config.m_bShadowDepthTexture ? "true" : "false" ); +#ifndef _X360 + Warning( "r_waterforceexpensive: %s\n", r_waterforceexpensive.GetInt() ? "true" : "false" ); +#endif + Warning( "r_waterforcereflectentities: %s\n", r_waterforcereflectentities.GetInt() ? "true" : "false" ); +} + +CON_COMMAND( mat_configcurrent, "show the current video control panel config for the material system" ) +{ + const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard(); + PrintMaterialSystemConfig( config ); +} + +#if !defined(SWDS) && !defined( _X360 ) +CON_COMMAND( mat_setvideomode, "sets the width, height, windowed state of the material system" ) +{ + if ( args.ArgC() != 4 ) + return; + + int nWidth = Q_atoi( args[1] ); + int nHeight = Q_atoi( args[2] ); + bool bWindowed = Q_atoi( args[3] ) > 0 ? true : false; + + videomode->SetMode( nWidth, nHeight, bWindowed ); +} +#endif + +CON_COMMAND( mat_enable_vrmode, "Switches the material system to VR mode (after restart)" ) +{ + if( args.ArgC() != 2 ) + return; + + if( !g_pSourceVR ) + return; + + ConVarRef mat_vrmode_adapter( "mat_vrmode_adapter" ); + bool bVRMode = Q_atoi( args[1] ) != 0; + if( bVRMode ) + { +#if defined( _WIN32 ) + int32 nVRModeAdapter = g_pSourceVR->GetVRModeAdapter(); + if( nVRModeAdapter == -1 ) + { + Warning( "Unable to get VRModeAdapter from OpenVR. VR mode will not be enabled. Try restarting and then enabling VR again.\n" ); + } + mat_vrmode_adapter.SetValue( nVRModeAdapter ); +#else + mat_vrmode_adapter.SetValue( 0 ); // This convar isn't actually used on other platforms so just use 0 to indicate that it's set +#endif + } + else + { + mat_vrmode_adapter.SetValue( -1 ); + } +} + + +CON_COMMAND( mat_savechanges, "saves current video configuration to the registry" ) +{ + // if the user has got to the point where they can adjust and apply video changes, then we can clear safe mode + CommandLine()->RemoveParm( "-safe" ); + + // write out config + UpdateMaterialSystemConfig(); + if ( !CommandLine()->FindParm( "-dxlevel" ) ) + { + WriteMaterialSystemConfigToRegistry( *g_pMaterialSystemConfig ); + } +} + +#ifdef _DEBUG +//----------------------------------------------------------------------------- +// A console command to debug materials +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_debug, "Activates debugging spew for a specific material.", FCVAR_CHEAT ) +{ + if ( args.ArgC() != 2 ) + { + ConMsg ("usage: mat_debug [ ]\n"); + return; + } + + materials->ToggleDebugMaterial( args[1] ); +} + +//----------------------------------------------------------------------------- +// A console command to suppress materials +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_suppress, "Supress a material from drawing", FCVAR_CHEAT ) +{ + if ( args.ArgC() != 2 ) + { + ConMsg ("usage: mat_suppress [ ]\n"); + return; + } + + materials->ToggleSuppressMaterial( args[1] ); +} +#endif // _DEBUG + +static ITexture *CreatePowerOfTwoFBTexture( void ) +{ + if ( IsX360() ) + return NULL; + + return materials->CreateNamedRenderTargetTextureEx2( + "_rt_PowerOfTwoFB", + 1024, 1024, RT_SIZE_DEFAULT, + // Has dest alpha for vort warp effect + IMAGE_FORMAT_RGBA8888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + CREATERENDERTARGETFLAGS_HDR ); +} + +static ITexture *CreateWaterReflectionTexture( void ) +{ + return materials->CreateNamedRenderTargetTextureEx2( + "_rt_WaterReflection", + 1024, 1024, RT_SIZE_PICMIP, + materials->GetBackBufferFormat(), + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + CREATERENDERTARGETFLAGS_HDR ); +} + +static ITexture *CreateWaterRefractionTexture( void ) +{ + return materials->CreateNamedRenderTargetTextureEx2( + "_rt_WaterRefraction", + 1024, 1024, RT_SIZE_PICMIP, + // This is different than reflection because it has to have alpha for fog factor. + IMAGE_FORMAT_RGBA8888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + CREATERENDERTARGETFLAGS_HDR ); +} + +static ITexture *CreateCameraTexture( void ) +{ + return materials->CreateNamedRenderTargetTextureEx2( + "_rt_Camera", + 256, 256, RT_SIZE_DEFAULT, + materials->GetBackBufferFormat(), + MATERIAL_RT_DEPTH_SHARED, + 0, + CREATERENDERTARGETFLAGS_HDR ); +} + +static ITexture *CreateBuildCubemaps16BitTexture( void ) +{ + return materials->CreateNamedRenderTargetTextureEx2( + "_rt_BuildCubemaps16bit", + 0, 0, + RT_SIZE_FULL_FRAME_BUFFER, + IMAGE_FORMAT_RGBA16161616, + MATERIAL_RT_DEPTH_SHARED ); +} + +static ITexture *CreateQuarterSizedFBTexture( int n, unsigned int iRenderTargetFlags ) +{ + char nbuf[20]; + sprintf(nbuf,"_rt_SmallFB%d",n); + + ImageFormat fmt=materials->GetBackBufferFormat(); + if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) + fmt = IMAGE_FORMAT_RGBA16161616F; + + return materials->CreateNamedRenderTargetTextureEx2( + nbuf, 0, 0, RT_SIZE_HDR, + fmt, MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + iRenderTargetFlags ); +} + +static ITexture *CreateTeenyFBTexture( int n ) +{ + char nbuf[20]; + sprintf(nbuf,"_rt_TeenyFB%d",n); + + ImageFormat fmt = materials->GetBackBufferFormat(); + if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) + fmt = IMAGE_FORMAT_RGBA16161616F; + + return materials->CreateNamedRenderTargetTextureEx2( + nbuf, 32, 32, RT_SIZE_DEFAULT, + fmt, MATERIAL_RT_DEPTH_SHARED ); +} + +static ITexture *CreateFullFrameFBTexture( int textureIndex, int iExtraFlags = 0 ) +{ + char textureName[256]; + if ( textureIndex > 0 ) + { + sprintf( textureName, "_rt_FullFrameFB%d", textureIndex ); + } + else + { + V_strcpy_safe( textureName, "_rt_FullFrameFB" ); + } + + int rtFlags = iExtraFlags | CREATERENDERTARGETFLAGS_HDR; + if ( IsX360() ) + { + // just make the system memory texture only + rtFlags |= CREATERENDERTARGETFLAGS_NOEDRAM; + } + return materials->CreateNamedRenderTargetTextureEx2( + textureName, + 1, 1, RT_SIZE_FULL_FRAME_BUFFER, materials->GetBackBufferFormat(), + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + rtFlags ); +} + +static ITexture *CreateFullFrameDepthTexture( void ) +{ + if ( IsX360() ) + { + return materials->CreateNamedRenderTargetTextureEx2( "_rt_FullFrameDepth", 1, 1, + RT_SIZE_FULL_FRAME_BUFFER, materials->GetShadowDepthTextureFormat(), MATERIAL_RT_DEPTH_NONE, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE, + CREATERENDERTARGETFLAGS_NOEDRAM ); + + } + else + { + materials->AddTextureAlias( "_rt_FullFrameDepth", "_rt_PowerOfTwoFB" ); + } + return NULL; +} + + +static ITexture *CreateResolvedFullFrameDepthTexture( void ) +{ + if ( IsPC() ) + { + return materials->CreateNamedRenderTargetTextureEx2( "_rt_ResolvedFullFrameDepth", 1, 1, + RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_RGBA8888, MATERIAL_RT_DEPTH_SEPARATE, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE, + CREATERENDERTARGETFLAGS_NOEDRAM ); + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Create render targets which mods rely upon to render correctly +//----------------------------------------------------------------------------- +void InitWellKnownRenderTargets( void ) +{ +#if !defined( SWDS ) + if ( mat_debugalttab.GetBool() ) + { + Warning( "mat_debugalttab: InitWellKnownRenderTargets\n" ); + } + + // Begin block in which all render targets should be allocated + materials->BeginRenderTargetAllocation(); + + // JasonM - + // Do we put logic in here to determine which of these to create, based upon DX level, HDR enable etc? + // YES! DX Level should gate these + + // before we create anything, see if VR mode wants to override the "framebuffer" size + if( UseVR() ) + { + int nWidth, nHeight; + g_pSourceVR->GetRenderTargetFrameBufferDimensions( nWidth, nHeight ); + g_pMaterialSystem->SetRenderTargetFrameBufferSizeOverrides( nWidth, nHeight ); + } + else + { + g_pMaterialSystem->SetRenderTargetFrameBufferSizeOverrides( 0, 0 ); + } + + // Create the render targets upon which mods may rely + + if ( IsPC() ) + { + // Create for all mods as vgui2 uses it for 3D painting + g_PowerOfTwoFBTexture.Init( CreatePowerOfTwoFBTexture() ); + } + + // Create these for all mods because the engine references them + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80 ) + { + if ( IsPC() && g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 && + g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) + { + // Used for building HDR Cubemaps + g_BuildCubemaps16BitTexture.Init( CreateBuildCubemaps16BitTexture() ); + } + + // Used in Bloom effects + g_QuarterSizedFBTexture0.Init( CreateQuarterSizedFBTexture( 0, 0 ) ); + if( IsX360() ) + materials->AddTextureAlias( "_rt_SmallFB1", "_rt_SmallFB0" ); //an alias is good enough on the 360 since we don't have a texture lock problem during post processing + else + g_QuarterSizedFBTexture1.Init( CreateQuarterSizedFBTexture( 1, 0 ) ); + } + + if ( IsPC() ) + { + g_TeenyFBTexture0.Init( CreateTeenyFBTexture( 0 ) ); + g_TeenyFBTexture1.Init( CreateTeenyFBTexture( 1 ) ); + g_TeenyFBTexture2.Init( CreateTeenyFBTexture( 2 ) ); + } + + g_FullFrameFBTexture0.Init( CreateFullFrameFBTexture( 0 ) ); + g_FullFrameFBTexture1.Init( CreateFullFrameFBTexture( 1 ) ); + + if ( IsX360() ) + { + g_FullFrameFBTexture2.Init( CreateFullFrameFBTexture( 2, CREATERENDERTARGETFLAGS_TEMP ) ); + } + + g_FullFrameDepth.Init( CreateFullFrameDepthTexture() ); + g_ResolvedFullFrameDepth.Init( CreateResolvedFullFrameDepthTexture() ); + + // if we're in stereo mode init a render target for VGUI + if( UseVR() ) + { + g_pSourceVR->CreateRenderTargets( materials ); + } + + // Allow the client to init their own mod-specific render targets + if ( g_pClientRenderTargets ) + { + g_pClientRenderTargets->InitClientRenderTargets( materials, g_pMaterialSystemHardwareConfig ); + } + else + { + // If this mod doesn't define the interface, fallback to initializing the standard render textures + // NOTE: these should match up with the 'Get' functions in cl_dll/rendertexture.h/cpp + g_WaterReflectionTexture.Init( CreateWaterReflectionTexture() ); + g_WaterRefractionTexture.Init( CreateWaterRefractionTexture() ); + g_CameraTexture.Init( CreateCameraTexture() ); + } + + // End block in which all render targets should be allocated (kicking off an Alt-Tab type behavior) + materials->EndRenderTargetAllocation(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->SetNonInteractiveTempFullscreenBuffer( g_FullFrameFBTexture0, MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD ); +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: Shut down the render targets which mods rely upon to render correctly +//----------------------------------------------------------------------------- +void ShutdownWellKnownRenderTargets( void ) +{ +#if !defined( SWDS ) + if ( IsX360() ) + { + // cannot allowing RT's to reconstruct, causes other fatal problems + // many other 360 systems have been coded with this expected constraint + Assert( 0 ); + return; + } + + if ( IsPC() && mat_debugalttab.GetBool() ) + { + Warning( "mat_debugalttab: ShutdownWellKnownRenderTargets\n" ); + } + + g_PowerOfTwoFBTexture.Shutdown(); + g_BuildCubemaps16BitTexture.Shutdown(); + + g_QuarterSizedFBTexture0.Shutdown(); + + if( IsX360() ) + materials->RemoveTextureAlias( "_rt_SmallFB1" ); + else + g_QuarterSizedFBTexture1.Shutdown(); + + g_TeenyFBTexture0.Shutdown(); + g_TeenyFBTexture1.Shutdown(); + g_TeenyFBTexture2.Shutdown(); + g_FullFrameFBTexture0.Shutdown(); + g_FullFrameFBTexture1.Shutdown(); + if ( IsX360() ) + { + g_FullFrameFBTexture2.Shutdown(); + } + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->SetNonInteractiveTempFullscreenBuffer( NULL, MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD ); + + g_FullFrameDepth.Shutdown(); + if( IsPC() ) + { + materials->RemoveTextureAlias( "_rt_FullFrameDepth" ); + } + + if( g_pSourceVR ) + g_pSourceVR->ShutdownRenderTargets(); + + + // Shutdown client render targets + if ( g_pClientRenderTargets ) + { + g_pClientRenderTargets->ShutdownClientRenderTargets(); + } + else + { + g_WaterReflectionTexture.Shutdown(); + g_WaterRefractionTexture.Shutdown(); + g_CameraTexture.Shutdown(); + } +#endif +} + + +//----------------------------------------------------------------------------- +// A console command to spew out driver information +//----------------------------------------------------------------------------- +CON_COMMAND( mat_reset_rendertargets, "Resets all the render targets" ) +{ + ShutdownWellKnownRenderTargets(); + InitWellKnownRenderTargets(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Make the debug system materials +//----------------------------------------------------------------------------- +static void InitDebugMaterials( void ) +{ + if ( IsPC() && mat_debugalttab.GetBool() ) + { + Warning( "mat_debugalttab: InitDebugMaterials\n" ); + } + + g_materialEmpty = GL_LoadMaterial( "debug/debugempty", TEXTURE_GROUP_OTHER ); +#ifndef SWDS + g_materialWireframe = GL_LoadMaterial( "debug/debugwireframe", TEXTURE_GROUP_OTHER ); + g_materialTranslucentSingleColor = GL_LoadMaterial( "debug/debugtranslucentsinglecolor", TEXTURE_GROUP_OTHER ); + g_materialTranslucentVertexColor = GL_LoadMaterial( "debug/debugtranslucentvertexcolor", TEXTURE_GROUP_OTHER ); + g_materialWorldWireframe = GL_LoadMaterial( "debug/debugworldwireframe", TEXTURE_GROUP_OTHER ); + g_materialWorldWireframeZBuffer = GL_LoadMaterial( "debug/debugworldwireframezbuffer", TEXTURE_GROUP_OTHER ); + + g_materialBrushWireframe = GL_LoadMaterial( "debug/debugbrushwireframe", TEXTURE_GROUP_OTHER ); + g_materialDecalWireframe = GL_LoadMaterial( "debug/debugdecalwireframe", TEXTURE_GROUP_OTHER ); + g_materialDebugLightmap = GL_LoadMaterial( "debug/debuglightmap", TEXTURE_GROUP_OTHER ); + g_materialDebugLightmapZBuffer = GL_LoadMaterial( "debug/debuglightmapzbuffer", TEXTURE_GROUP_OTHER ); + g_materialDebugLuxels = GL_LoadMaterial( "debug/debugluxels", TEXTURE_GROUP_OTHER ); + + g_materialLeafVisWireframe = GL_LoadMaterial( "debug/debugleafviswireframe", TEXTURE_GROUP_OTHER ); + g_pMaterialWireframeVertexColor = GL_LoadMaterial( "debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER ); + g_pMaterialWireframeVertexColorIgnoreZ = GL_LoadMaterial( "debug/debugwireframevertexcolorignorez", TEXTURE_GROUP_OTHER ); + g_pMaterialLightSprite = GL_LoadMaterial( "engine/lightsprite", TEXTURE_GROUP_OTHER ); + g_pMaterialShadowBuild = GL_LoadMaterial( "engine/shadowbuild", TEXTURE_GROUP_OTHER); + g_pMaterialMRMWireframe = GL_LoadMaterial( "debug/debugmrmwireframe", TEXTURE_GROUP_OTHER ); + g_pMaterialDebugFlat = GL_LoadMaterial( "debug/debugdrawflattriangles", TEXTURE_GROUP_OTHER ); + + g_pMaterialAmbientCube = GL_LoadMaterial( "debug/debugambientcube", TEXTURE_GROUP_OTHER ); + + g_pMaterialWriteZ = GL_LoadMaterial( "engine/writez", TEXTURE_GROUP_OTHER ); + + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) + { + // Materials for writing to shadow depth buffer + KeyValues *pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 0 ); + pVMTKeyValues->SetInt( "$nocull", 0 ); + g_pMaterialDepthWrite[0][0] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite00", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialDepthWrite[0][0]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 0 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + g_pMaterialDepthWrite[0][1] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialDepthWrite[0][1]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 1 ); + pVMTKeyValues->SetInt( "$nocull", 0 ); + g_pMaterialDepthWrite[1][0] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite10", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialDepthWrite[1][0]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 1 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + g_pMaterialDepthWrite[1][1] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite11", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialDepthWrite[1][1]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 0 ); + pVMTKeyValues->SetInt( "$nocull", 0 ); + pVMTKeyValues->SetInt( "$color_depth", 1 ); + g_pMaterialSSAODepthWrite[0][0] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite00", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialSSAODepthWrite[0][0]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 0 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$color_depth", 1 ); + g_pMaterialSSAODepthWrite[0][1] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialSSAODepthWrite[0][1]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 1 ); + pVMTKeyValues->SetInt( "$nocull", 0 ); + pVMTKeyValues->SetInt( "$color_depth", 1 ); + g_pMaterialSSAODepthWrite[1][0] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite10", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialSSAODepthWrite[1][0]->IncrementReferenceCount(); + + pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 1 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$color_depth", 1 ); + g_pMaterialSSAODepthWrite[1][1] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite11", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + g_pMaterialSSAODepthWrite[1][1]->IncrementReferenceCount(); + } + else + { + g_pMaterialDepthWrite[0][0] = g_pMaterialDepthWrite[0][1] = g_pMaterialDepthWrite[1][0] = g_pMaterialDepthWrite[1][1] = NULL; + g_pMaterialSSAODepthWrite[0][0] = g_pMaterialSSAODepthWrite[0][1] = g_pMaterialSSAODepthWrite[1][0] = g_pMaterialSSAODepthWrite[1][1] = NULL; + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static void ShutdownDebugMaterials( void ) +{ + if ( IsPC() && mat_debugalttab.GetBool() ) + { + Warning( "mat_debugalttab: ShutdownDebugMaterials\n" ); + } + + GL_UnloadMaterial( g_materialEmpty ); +#ifndef SWDS + GL_UnloadMaterial( g_pMaterialLightSprite ); + GL_UnloadMaterial( g_pMaterialWireframeVertexColor ); + GL_UnloadMaterial( g_pMaterialWireframeVertexColorIgnoreZ ); + GL_UnloadMaterial( g_materialLeafVisWireframe ); + + GL_UnloadMaterial( g_materialDebugLuxels ); + GL_UnloadMaterial( g_materialDebugLightmapZBuffer ); + GL_UnloadMaterial( g_materialDebugLightmap ); + GL_UnloadMaterial( g_materialDecalWireframe ); + GL_UnloadMaterial( g_materialBrushWireframe ); + + GL_UnloadMaterial( g_materialWorldWireframeZBuffer ); + GL_UnloadMaterial( g_materialWorldWireframe ); + GL_UnloadMaterial( g_materialTranslucentSingleColor ); + GL_UnloadMaterial( g_materialTranslucentVertexColor ); + GL_UnloadMaterial( g_materialWireframe ); + GL_UnloadMaterial( g_pMaterialShadowBuild ); + GL_UnloadMaterial( g_pMaterialMRMWireframe ); + GL_UnloadMaterial( g_pMaterialWriteZ ); + + GL_UnloadMaterial( g_pMaterialAmbientCube ); + GL_UnloadMaterial( g_pMaterialDebugFlat ); + + // Materials for writing to shadow depth buffer + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) + { + for (int i = 0; i<2; i++) + { + for (int j = 0; j<2; j++) + { + if( g_pMaterialDepthWrite[i][j] ) + { + g_pMaterialDepthWrite[i][j]->DecrementReferenceCount(); + } + g_pMaterialDepthWrite[i][j] = NULL; + + if( g_pMaterialSSAODepthWrite[i][j] ) + { + g_pMaterialSSAODepthWrite[i][j]->DecrementReferenceCount(); + } + g_pMaterialSSAODepthWrite[i][j] = NULL; + } + } + } + +#endif +} + + +//----------------------------------------------------------------------------- +// Used to deal with making sure Present is called often enough +//----------------------------------------------------------------------------- +void InitStartupScreen() +{ + if ( !IsX360() ) + return; + +#ifdef _X360 + XVIDEO_MODE videoMode; + XGetVideoMode( &videoMode ); + bool bIsWidescreen = videoMode.fIsWideScreen != FALSE; +#else + int width, height; + materials->GetBackBufferDimensions( width, height ); + float aspectRatio = (float)width/(float)height; + bool bIsWidescreen = aspectRatio >= 1.5999f; +#endif + + // NOTE: Brutal hackery, this code is duplicated in gameui.dll + // but I have to do this prior to gameui being loaded. + // 360 uses hi-res game specific backgrounds + char gameName[MAX_PATH]; + char filename[MAX_PATH]; + V_FileBase( com_gamedir, gameName, sizeof( gameName ) ); + V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_%s%s", gameName, ( bIsWidescreen ? "_widescreen" : "" ) ); + + ITexture *pTexture = materials->FindTexture( filename, TEXTURE_GROUP_OTHER ); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->SetNonInteractiveTempFullscreenBuffer( pTexture, MATERIAL_NON_INTERACTIVE_MODE_STARTUP ); + + pTexture = materials->FindTexture( "//platform/materials/engine/box", TEXTURE_GROUP_OTHER ); + + KeyValues *modinfo = new KeyValues("ModInfo"); + if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) ) + { + if ( V_stricmp( modinfo->GetString("type", "singleplayer_only" ), "multiplayer_only" ) == 0 ) + { + pRenderContext->SetNonInteractivePacifierTexture( pTexture, 0.5f, 0.9f, 0.1f ); + } + else + { + pRenderContext->SetNonInteractivePacifierTexture( pTexture, 0.5f, 0.86f, 0.1f ); + } + } + modinfo->deleteThis(); + + BeginLoadingUpdates( MATERIAL_NON_INTERACTIVE_MODE_STARTUP ); +} + + +//----------------------------------------------------------------------------- +// A console command to spew out driver information +//----------------------------------------------------------------------------- +CON_COMMAND( mat_info, "Shows material system info" ) +{ + materials->SpewDriverInfo(); +} + +void InitMaterialSystem( void ) +{ + materials->AddReleaseFunc( ReleaseMaterialSystemObjects ); + materials->AddRestoreFunc( RestoreMaterialSystemObjects ); + + UpdateMaterialSystemConfig(); + + InitWellKnownRenderTargets(); + + InitDebugMaterials(); + +#ifndef SWDS + DispInfo_InitMaterialSystem(); +#endif + +#ifdef BENCHMARK + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + { + Error( "dx6 and dx7 hardware not supported by this benchmark!" ); + } +#endif +} + +void ShutdownMaterialSystem( void ) +{ + ShutdownDebugMaterials(); + + ShutdownWellKnownRenderTargets(); + +#ifndef SWDS + DispInfo_ShutdownMaterialSystem(); +#endif +} + +//----------------------------------------------------------------------------- +// Methods to restore, release material system objects +//----------------------------------------------------------------------------- +void ReleaseMaterialSystemObjects() +{ +#ifndef SWDS + DispInfo_ReleaseMaterialSystemObjects( host_state.worldmodel ); + + modelrender->ReleaseAllStaticPropColorData(); +#endif + +#ifndef SWDS + WorldStaticMeshDestroy(); +#endif + g_LostVideoMemory = true; +} + +void RestoreMaterialSystemObjects( int nChangeFlags ) +{ + if ( IsX360() ) + return; + + bool bThreadingAllowed = Host_AllowQueuedMaterialSystem( false ); + g_LostVideoMemory = false; + + if ( nChangeFlags & MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED ) + { + // ensure decals have no stale references to invalid lods + modelrender->RemoveAllDecalsFromAllModels(); + } + + if (host_state.worldmodel) + { + if ( (nChangeFlags & MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED) || materials->GetNumSortIDs() == 0 ) + { +#ifndef SWDS + // Reload lightmaps, world meshes, etc. because we may have switched from bumped to unbumped + R_LoadWorldGeometry( true ); +#endif + } + else + { + modelloader->Map_LoadDisplacements( host_state.worldmodel, true ); +#ifndef SWDS + WorldStaticMeshCreate(); + // Gotta recreate the lightmaps + R_RedownloadAllLightmaps(); +#endif + } + +#ifndef SWDS + // Need to re-figure out the env_cubemaps, so blow away the lightcache. + R_StudioInitLightingCache(); + modelrender->RestoreAllStaticPropColorData(); +#endif + } + +#ifndef DEDICATED + cl.ForceFullUpdate(); +#endif + + Host_AllowQueuedMaterialSystem( bThreadingAllowed ); +} + +bool TangentSpaceSurfaceSetup( SurfaceHandle_t surfID, Vector &tVect ) +{ + Vector sVect; + VectorCopy( MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[0].AsVector3D(), sVect ); + VectorCopy( MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[1].AsVector3D(), tVect ); + VectorNormalize( sVect ); + VectorNormalize( tVect ); + Vector tmpVect; + CrossProduct( sVect, tVect, tmpVect ); + // Make sure that the tangent space works if textures are mapped "backwards". + if( DotProduct( MSurf_Plane( surfID ).normal, tmpVect ) > 0.0f ) + { + return true; + } + return false; +} + +void TangentSpaceComputeBasis( Vector& tangentS, Vector& tangentT, const Vector& normal, const Vector& tVect, bool negateTangent ) +{ + // tangent x binormal = normal + // tangent = sVect + // binormal = tVect + CrossProduct( normal, tVect, tangentS ); + VectorNormalize( tangentS ); + CrossProduct( tangentS, normal, tangentT ); + VectorNormalize( tangentT ); + + if ( negateTangent ) + { + VectorScale( tangentS, -1.0f, tangentS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MaterialSystem_DestroySortinfo( void ) +{ + if ( materialSortInfoArray ) + { +#ifndef SWDS + WorldStaticMeshDestroy(); +#endif + delete[] materialSortInfoArray; + materialSortInfoArray = NULL; + } +} + + +#ifndef SWDS + +// The amount to blend between basetexture and basetexture2 used to sit in lightmap +// alpha, so we didn't care about the vertex color or vertex alpha. But now if they're +// using it, we have to make sure the vertex has the color and alpha specified correctly +// or it will look weird. +static inline bool CheckMSurfaceBaseTexture2( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID ) +{ + if ( !SurfaceHasDispInfo( surfID ) && + (MSurf_TexInfo( surfID )->texinfoFlags & TEXINFO_USING_BASETEXTURE2) ) + { + const char *pMaterialName = MSurf_TexInfo( surfID )->material->GetName(); + if ( pMaterialName ) + { + bool bShowIt = false; + if ( developer.GetInt() <= 1 ) + { + static CUtlDict nameDict; + if ( nameDict.Find( pMaterialName ) == -1 ) + { + nameDict.Insert( pMaterialName, 0 ); + bShowIt = true; + } + } + else + { + bShowIt = true; + } + + if ( bShowIt ) + { + // Calculate the surface's centerpoint. + Vector vCenter( 0, 0, 0 ); + for ( int i = 0; i < MSurf_VertCount( surfID ); i++ ) + { + int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID ) + i]; + vCenter += pBrushData->vertexes[vertIndex].position; + } + vCenter /= (float)MSurf_VertCount( surfID ); + + // Spit out the warning. + Warning( "Warning: using WorldTwoTextureBlend on a non-displacement surface.\n" + "Support for this will go away soon.\n" + " - Material : %s\n" + " - Surface center : %d %d %d\n" + , pMaterialName, (int)vCenter.x, (int)vCenter.y, (int)vCenter.z ); + } + } + return true; + } + else + { + return false; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Build a vertex buffer for this face +// Input : *pWorld - world model base +// *surf - surf to add to the mesh +// overbright - overbright factor (for colors) +// &builder - mesh that holds the vertex buffer +//----------------------------------------------------------------------------- +#ifdef NEWMESH +void BuildMSurfaceVertexArrays( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, float overbright, + CVertexBufferBuilder &builder ) +{ + SurfaceCtx_t ctx; + SurfSetupSurfaceContext( ctx, surfID ); + + byte flatColor[4] = { 255, 255, 255, 255 }; + + Vector tVect; + bool negate = false; + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + negate = TangentSpaceSurfaceSetup( surfID, tVect ); + } + + CheckMSurfaceBaseTexture2( pBrushData, surfID ); + + for ( int i = 0; i < MSurf_VertCount( surfID ); i++ ) + { + int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID ) + i]; + + // world-space vertex + Vector& vec = pBrushData->vertexes[vertIndex].position; + + // output to mesh + builder.Position3fv( vec.Base() ); + + Vector2D uv; + SurfComputeTextureCoordinate( ctx, surfID, vec, uv ); + builder.TexCoord2fv( 0, uv.Base() ); + + // garymct: normalized (within space of surface) lightmap texture coordinates + SurfComputeLightmapCoordinate( ctx, surfID, vec, uv ); + builder.TexCoord2fv( 1, uv.Base() ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT ) + { + // bump maps appear left to right in lightmap page memory, calculate + // the offset for the width of a single map. The pixel shader will use + // this to compute the actual texture coordinates + builder.TexCoord2f( 2, ctx.m_BumpSTexCoordOffset, 0.0f ); + } + + Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID ) + i] ]; + builder.Normal3fv( normal.Base() ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + Vector tangentS, tangentT; + TangentSpaceComputeBasis( tangentS, tangentT, normal, tVect, negate ); + builder.TangentS3fv( tangentS.Base() ); + builder.TangentT3fv( tangentT.Base() ); + } + + // The amount to blend between basetexture and basetexture2 used to sit in lightmap + // alpha, so we didn't care about the vertex color or vertex alpha. But now if they're + // using it, we have to make sure the vertex has the color and alpha specified correctly + // or it will look weird. + if ( !SurfaceHasDispInfo( surfID ) && + (MSurf_TexInfo( surfID )->texinfoFlags & TEXINFO_USING_BASETEXTURE2) ) + { + static bool bWarned = false; + if ( !bWarned ) + { + const char *pMaterialName = MSurf_TexInfo( surfID )->material->GetName(); + bWarned = true; + Warning( "Warning: WorldTwoTextureBlend found on a non-displacement surface (material: %s). This wastes perf for no benefit.\n", pMaterialName ); + } + + builder.Color4ub( 255, 255, 255, 0 ); + } + else + { + builder.Color3ubv( flatColor ); + } + + builder.AdvanceVertex(); + } +} +#else +//----------------------------------------------------------------------------- +// Purpose: Build a vertex buffer for this face +// Input : *pWorld - world model base +// *surf - surf to add to the mesh +// overbright - overbright factor (for colors) +// &builder - mesh that holds the vertex buffer +//----------------------------------------------------------------------------- +void BuildMSurfaceVertexArrays( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, float overbright, + CMeshBuilder &builder ) +{ + SurfaceCtx_t ctx; + SurfSetupSurfaceContext( ctx, surfID ); + + byte flatColor[4] = { 255, 255, 255, 255 }; + + Vector tVect; + bool negate = false; + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + negate = TangentSpaceSurfaceSetup( surfID, tVect ); + } + + CheckMSurfaceBaseTexture2( pBrushData, surfID ); + + for ( int i = 0; i < MSurf_VertCount( surfID ); i++ ) + { + int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID ) + i]; + + // world-space vertex + Vector& vec = pBrushData->vertexes[vertIndex].position; + + // output to mesh + builder.Position3fv( vec.Base() ); + + Vector2D uv; + SurfComputeTextureCoordinate( ctx, surfID, vec, uv ); + builder.TexCoord2fv( 0, uv.Base() ); + + // garymct: normalized (within space of surface) lightmap texture coordinates + SurfComputeLightmapCoordinate( ctx, surfID, vec, uv ); + builder.TexCoord2fv( 1, uv.Base() ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT ) + { + // bump maps appear left to right in lightmap page memory, calculate + // the offset for the width of a single map. The pixel shader will use + // this to compute the actual texture coordinates + + if ( uv.x + ctx.m_BumpSTexCoordOffset*3 > 1.00001f ) + { + Assert(0); + + SurfComputeLightmapCoordinate( ctx, surfID, vec, uv ); + } + builder.TexCoord2f( 2, ctx.m_BumpSTexCoordOffset, 0.0f ); + } + + Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID ) + i] ]; + builder.Normal3fv( normal.Base() ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + Vector tangentS, tangentT; + TangentSpaceComputeBasis( tangentS, tangentT, normal, tVect, negate ); + builder.TangentS3fv( tangentS.Base() ); + builder.TangentT3fv( tangentT.Base() ); + } + + // The amount to blend between basetexture and basetexture2 used to sit in lightmap + // alpha, so we didn't care about the vertex color or vertex alpha. But now if they're + // using it, we have to make sure the vertex has the color and alpha specified correctly + // or it will look weird. + if ( !SurfaceHasDispInfo( surfID ) && + (MSurf_TexInfo( surfID )->texinfoFlags & TEXINFO_USING_BASETEXTURE2) ) + { + static bool bWarned = false; + if ( !bWarned ) + { + const char *pMaterialName = MSurf_TexInfo( surfID )->material->GetName(); + bWarned = true; + Warning( "Warning: WorldTwoTextureBlend found on a non-displacement surface (material: %s). This wastes perf for no benefit.\n", pMaterialName ); + } + + builder.Color4ub( 255, 255, 255, 0 ); + } + else + { + builder.Color3ubv( flatColor ); + } + + builder.AdvanceVertex(); + } +} +#endif // NEWMESH + +static int VertexCountForSurfaceList( const CMSurfaceSortList &list, const surfacesortgroup_t &group ) +{ + int vertexCount = 0; + MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(list, group, surfID) + vertexCount += MSurf_VertCount(surfID); + MSL_FOREACH_SURFACE_IN_GROUP_END(); + return vertexCount; +} + +//----------------------------------------------------------------------------- +// Builds a static mesh from a list of all surfaces with the same material +//----------------------------------------------------------------------------- + +struct meshlist_t +{ +#ifdef NEWMESH + IVertexBuffer *pVertexBuffer; +#else + IMesh *pMesh; +#endif + IMaterial *pMaterial; + int vertCount; + VertexFormat_t vertexFormat; +}; + +static CUtlVector g_Meshes; + +ConVar mat_max_worldmesh_vertices("mat_max_worldmesh_vertices", "65536"); + +static VertexFormat_t GetUncompressedFormat( const IMaterial * pMaterial ) +{ + // FIXME: IMaterial::GetVertexFormat() should do this stripping (add a separate 'SupportsCompression' accessor) + return ( pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED ); +} + +int FindOrAddMesh( IMaterial *pMaterial, int vertexCount ) +{ + VertexFormat_t format = GetUncompressedFormat( pMaterial ); + + CMatRenderContextPtr pRenderContext( materials ); + + int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial ); + int worldLimit = mat_max_worldmesh_vertices.GetInt(); + worldLimit = max(worldLimit,1024); + if ( nMaxVertices > worldLimit ) + { + nMaxVertices = mat_max_worldmesh_vertices.GetInt(); + } + + for ( int i = 0; i < g_Meshes.Count(); i++ ) + { + if ( g_Meshes[i].vertexFormat != format ) + continue; + + if ( g_Meshes[i].vertCount + vertexCount > nMaxVertices ) + continue; + + g_Meshes[i].vertCount += vertexCount; + return i; + } + + int index = g_Meshes.AddToTail(); + g_Meshes[index].vertCount = vertexCount; + g_Meshes[index].vertexFormat = format; + g_Meshes[index].pMaterial = pMaterial; + + return index; +} + +void SetTexInfoBaseTexture2Flags() +{ + for ( int i=0; i < host_state.worldbrush->numtexinfo; i++ ) + { + host_state.worldbrush->texinfo[i].texinfoFlags &= ~TEXINFO_USING_BASETEXTURE2; + } + + for ( int i=0; i < host_state.worldbrush->numtexinfo; i++ ) + { + mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[i]; + IMaterial *pMaterial = pTexInfo->material; + if ( !pMaterial ) + continue; + + IMaterialVar **pParms = pMaterial->GetShaderParams(); + int nParms = pMaterial->ShaderParamCount(); + for ( int j=0; j < nParms; j++ ) + { + if ( !pParms[j]->IsDefined() ) + continue; + + if ( Q_stricmp( pParms[j]->GetName(), "$basetexture2" ) == 0 ) + { + pTexInfo->texinfoFlags |= TEXINFO_USING_BASETEXTURE2; + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Determines vertex formats for all the world geometry +//----------------------------------------------------------------------------- +VertexFormat_t ComputeWorldStaticMeshVertexFormat( const IMaterial * pMaterial ) +{ + VertexFormat_t vertexFormat = GetUncompressedFormat( pMaterial ); + + // FIXME: set VERTEX_FORMAT_COMPRESSED if there are no artifacts and if it saves enough memory (use 'mem_dumpvballocs') + // vertexFormat |= VERTEX_FORMAT_COMPRESSED; + // FIXME: check for and strip unused vertex elements (TANGENT_S/T?) + + return vertexFormat; +} + +//----------------------------------------------------------------------------- +// Builds static meshes for all the world geometry +//----------------------------------------------------------------------------- +void WorldStaticMeshCreate( void ) +{ + r_framecount = 1; + WorldStaticMeshDestroy(); + g_Meshes.RemoveAll(); + + SetTexInfoBaseTexture2Flags(); + + int nSortIDs = materials->GetNumSortIDs(); + if ( nSortIDs == 0 ) + { + // this is probably a bug in alt-tab. It's calling this as a restore function + // but the lightmaps haven't been allocated yet + Assert(0); + return; + } + + // Setup sortbins for flashlight rendering + // FIXME!!!! Could have less bins since we don't care about the lightmap + // for projective light rendering purposes. + // Not entirely true since we need the correct lightmap page for WorldVertexTransition materials. + g_pShadowMgr->SetNumWorldMaterialBuckets( nSortIDs ); + + Assert( !g_WorldStaticMeshes.Count() ); + g_WorldStaticMeshes.SetCount( nSortIDs ); + memset( g_WorldStaticMeshes.Base(), 0, sizeof(g_WorldStaticMeshes[0]) * g_WorldStaticMeshes.Count() ); + + CMSurfaceSortList matSortArray; + matSortArray.Init( nSortIDs, 512 ); + int *sortIndex = (int *)_alloca( sizeof(int) * g_WorldStaticMeshes.Count() ); + + bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; + + int i; + // sort the surfaces into the sort arrays + for( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ ) + { + SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex ); + // set these flags here as they are determined by material data + MSurf_Flags( surfID ) &= ~(SURFDRAW_TANGENTSPACE); + + // do we need to compute tangent space here? + if ( bTools || ( MSurf_TexInfo( surfID )->material->GetVertexFormat() & VERTEX_TANGENT_SPACE ) ) + { + MSurf_Flags( surfID ) |= SURFDRAW_TANGENTSPACE; + } + + // don't create vertex buffers for nodraw faces, water faces, or faces with dynamic data +// if ( (MSurf_Flags( surfID ) & (SURFDRAW_NODRAW|SURFDRAW_WATERSURFACE|SURFDRAW_DYNAMIC)) +// || SurfaceHasDispInfo( surfID ) ) + if( SurfaceHasDispInfo( surfID ) ) + { + MSurf_VertBufferIndex( surfID ) = 0xFFFF; + continue; + } + + // attach to head of list + matSortArray.AddSurfaceToTail( surfID, 0, MSurf_MaterialSortID( surfID ) ); + } + + // iterate the arrays and create buffers + for ( i = 0; i < g_WorldStaticMeshes.Count(); i++ ) + { + const surfacesortgroup_t &group = matSortArray.GetGroupForSortID(0,i); + int vertexCount = VertexCountForSurfaceList( matSortArray, group ); + + SurfaceHandle_t surfID = matSortArray.GetSurfaceAtHead( group ); + g_WorldStaticMeshes[i] = NULL; + sortIndex[i] = surfID ? FindOrAddMesh( MSurf_TexInfo( surfID )->material, vertexCount ) : -1; + } + + CMatRenderContextPtr pRenderContext( materials ); + + PIXEVENT( pRenderContext, "WorldStaticMeshCreate" ); +#ifdef NEWMESH + for ( i = 0; i < g_Meshes.Count(); i++ ) + { + Assert( g_Meshes[i].vertCount > 0 ); + Assert( g_Meshes[i].pMaterial ); + g_Meshes[i].pVertexBuffer = pRenderContext->CreateStaticVertexBuffer( GetUncompressedFormat( g_Meshes[i].pMaterial ), g_Meshes[i].vertCount, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_WORLD ); + int vertBufferIndex = 0; + // NOTE: Index count is zero because this will be a static vertex buffer!!! + CVertexBufferBuilder vertexBufferBuilder; + vertexBufferBuilder.Begin( g_Meshes[i].pVertexBuffer, g_Meshes[i].vertCount ); + for ( int j = 0; j < g_WorldStaticMeshes.Count(); j++ ) + { + int meshId = sortIndex[j]; + if ( meshId == i ) + { + g_WorldStaticMeshes[j] = g_Meshes[i].pVertexBuffer; + const surfacesortgroup_t &group = matSortArray.GetGroupForSortID(0,j); + MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(matSortArray, group, surfID); + MSurf_VertBufferIndex( surfID ) = vertBufferIndex; + BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, OVERBRIGHT, vertexBufferBuilder ); + + vertBufferIndex += MSurf_VertCount( surfID ); + + MSL_FOREACH_SURFACE_IN_GROUP_END(); + } + } + vertexBufferBuilder.End(); + Assert(vertBufferIndex == g_Meshes[i].vertCount); + } +#else + for ( i = 0; i < g_Meshes.Count(); i++ ) + { + Assert( g_Meshes[i].vertCount > 0 ); + if ( g_VBAllocTracker ) + g_VBAllocTracker->TrackMeshAllocations( "WorldStaticMeshCreate" ); + VertexFormat_t vertexFormat = ComputeWorldStaticMeshVertexFormat( g_Meshes[i].pMaterial ); + g_Meshes[i].pMesh = pRenderContext->CreateStaticMesh( vertexFormat, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_WORLD, g_Meshes[i].pMaterial ); + int vertBufferIndex = 0; + // NOTE: Index count is zero because this will be a static vertex buffer!!! + CMeshBuilder meshBuilder; + meshBuilder.Begin( g_Meshes[i].pMesh, MATERIAL_TRIANGLES, g_Meshes[i].vertCount, 0 ); + + for ( int j = 0; j < g_WorldStaticMeshes.Count(); j++ ) + { + int meshId = sortIndex[j]; + if ( meshId == i ) + { + g_WorldStaticMeshes[j] = g_Meshes[i].pMesh; + const surfacesortgroup_t &group = matSortArray.GetGroupForSortID(0,j); + MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(matSortArray, group, surfID); + + MSurf_VertBufferIndex( surfID ) = vertBufferIndex; + BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, OVERBRIGHT, meshBuilder ); + vertBufferIndex += MSurf_VertCount( surfID ); + + MSL_FOREACH_SURFACE_IN_GROUP_END(); + } + } + meshBuilder.End(); + Assert(vertBufferIndex == g_Meshes[i].vertCount); + if ( g_VBAllocTracker ) + g_VBAllocTracker->TrackMeshAllocations( NULL ); + } +#endif + //Msg("Total %d meshes, %d before\n", g_Meshes.Count(), g_WorldStaticMeshes.Count() ); +} + +void WorldStaticMeshDestroy( void ) +{ + CMatRenderContextPtr pRenderContext( materials ); + + // Blat out the static meshes associated with each material + for ( int i = 0; i < g_Meshes.Count(); i++ ) + { +#ifdef NEWMESH + pRenderContext->DestroyVertexBuffer( g_Meshes[i].pVertexBuffer ); +#else + pRenderContext->DestroyStaticMesh( g_Meshes[i].pMesh ); +#endif + } + g_WorldStaticMeshes.Purge(); + g_Meshes.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Compute texture and lightmap coordinates +//----------------------------------------------------------------------------- + +void SurfComputeTextureCoordinate( SurfaceCtx_t const& ctx, SurfaceHandle_t surfID, + Vector const& vec, Vector2D& uv ) +{ + mtexinfo_t* pTexInfo = MSurf_TexInfo( surfID ); + + // base texture coordinate + uv.x = DotProduct (vec, pTexInfo->textureVecsTexelsPerWorldUnits[0].AsVector3D()) + + pTexInfo->textureVecsTexelsPerWorldUnits[0][3]; + uv.x /= pTexInfo->material->GetMappingWidth(); + + uv.y = DotProduct (vec, pTexInfo->textureVecsTexelsPerWorldUnits[1].AsVector3D()) + + pTexInfo->textureVecsTexelsPerWorldUnits[1][3]; + uv.y /= pTexInfo->material->GetMappingHeight(); +} + +#if _DEBUG +void CheckTexCoord( float coord ) +{ + Assert(coord <= 1.0f ); +} +#endif + +void SurfComputeLightmapCoordinate( SurfaceCtx_t const& ctx, SurfaceHandle_t surfID, + Vector const& vec, Vector2D& uv ) +{ + if ( (MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) ) + { + uv.x = uv.y = 0.5f; + } + else if ( MSurf_LightmapExtents( surfID )[0] == 0 ) + { + uv = (0.5f * ctx.m_Scale + ctx.m_Offset); + } + else + { + mtexinfo_t* pTexInfo = MSurf_TexInfo( surfID ); + + uv.x = DotProduct (vec, pTexInfo->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + + pTexInfo->lightmapVecsLuxelsPerWorldUnits[0][3]; + uv.x -= MSurf_LightmapMins( surfID )[0]; + uv.x += 0.5f; + + uv.y = DotProduct (vec, pTexInfo->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + + pTexInfo->lightmapVecsLuxelsPerWorldUnits[1][3]; + uv.y -= MSurf_LightmapMins( surfID )[1]; + uv.y += 0.5f; + + uv *= ctx.m_Scale; + uv += ctx.m_Offset; + + assert( uv.IsValid() ); + } +#if _DEBUG + // This was here for check against displacements and they actually get calculated later correctly. +// CheckTexCoord( uv.x ); +// CheckTexCoord( uv.y ); +#endif + uv.x = clamp(uv.x, 0.0f, 1.0f); + uv.y = clamp(uv.y, 0.0f, 1.0f); +} + + +//----------------------------------------------------------------------------- +// Compute a context necessary for creating vertex data +//----------------------------------------------------------------------------- + +void SurfSetupSurfaceContext( SurfaceCtx_t& ctx, SurfaceHandle_t surfID ) +{ + materials->GetLightmapPageSize( + SortInfoToLightmapPage( MSurf_MaterialSortID( surfID ) ), + &ctx.m_LightmapPageSize[0], &ctx.m_LightmapPageSize[1] ); + ctx.m_LightmapSize[0] = ( MSurf_LightmapExtents( surfID )[0] ) + 1; + ctx.m_LightmapSize[1] = ( MSurf_LightmapExtents( surfID )[1] ) + 1; + + ctx.m_Scale.x = 1.0f / ( float )ctx.m_LightmapPageSize[0]; + ctx.m_Scale.y = 1.0f / ( float )ctx.m_LightmapPageSize[1]; + + ctx.m_Offset.x = ( float )MSurf_OffsetIntoLightmapPage( surfID )[0] * ctx.m_Scale.x; + ctx.m_Offset.y = ( float )MSurf_OffsetIntoLightmapPage( surfID )[1] * ctx.m_Scale.y; + + if ( ctx.m_LightmapPageSize[0] != 0.0f ) + { + ctx.m_BumpSTexCoordOffset = ( float )ctx.m_LightmapSize[0] / ( float )ctx.m_LightmapPageSize[0]; + } + else + { + ctx.m_BumpSTexCoordOffset = 0.0f; + } +} + +#endif // SWDS -- cgit v1.2.3