You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1419 lines
38 KiB
1419 lines
38 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Implementation of IEditorTexture interface for materials. |
|
// |
|
// Materials are kept in a directory tree containing pairs of VMT |
|
// and VTF files. Each pair of files represents a material. |
|
// |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include <process.h> |
|
#include <afxtempl.h> |
|
#include <io.h> |
|
#include <sys\stat.h> |
|
#include <fcntl.h> |
|
#include "hammer.h" |
|
#include "MapDoc.h" |
|
#include "Material.h" |
|
#include "Options.h" |
|
#include "MainFrm.h" |
|
#include "GlobalFunctions.h" |
|
#include "WADTypes.h" |
|
#include "BSPFile.h" |
|
#include "materialsystem/imaterialsystem.h" |
|
#include "materialsystem/IMaterialSystemHardwareConfig.h" |
|
#include "materialsystem/MaterialSystem_Config.h" |
|
#include "materialsystem/MaterialSystemUtil.h" |
|
#include "materialsystem/itexture.h" |
|
#include "materialsystem/imaterial.h" |
|
#include "bitmap/imageformat.h" // hack : don't want to include this just for ImageFormat |
|
#include "filesystem.h" |
|
#include "StudioModel.h" |
|
#include "tier1/strtools.h" |
|
#include "tier0/dbg.h" |
|
#include "TextureSystem.h" |
|
#include "materialproxyfactory_wc.h" |
|
#include "vstdlib/cvar.h" |
|
#include "interface.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
|
|
#pragma warning(disable:4244) |
|
|
|
#define _GraphicCacheAllocate(n) malloc(n) |
|
|
|
|
|
MaterialSystem_Config_t g_materialSystemConfig; |
|
static MaterialHandle_t g_CurrMaterial; |
|
|
|
extern void ScaleBitmap(CSize sizeSrc, CSize sizeDest, char *src, char *dest); |
|
|
|
|
|
struct MaterialCacheEntry_t |
|
{ |
|
char szName[MAX_PATH]; // |
|
CMaterial *pMaterial; // |
|
int nRefCount; // |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// This class speeds up the call to IMaterial::GetPreviewImageProperties because |
|
// we call it thousands of times per level load when there are detail props. |
|
//----------------------------------------------------------------------------- |
|
class CPreviewImagePropertiesCache |
|
{ |
|
public: |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Anyone can call this instead of IMaterial::GetPreviewImageProperties |
|
// and it'll be a lot faster if there are redundant calls to it. |
|
//----------------------------------------------------------------------------- |
|
static PreviewImageRetVal_t GetPreviewImageProperties( IMaterial *pMaterial, int *width, int *height, ImageFormat *imageFormat, bool* isTranslucent ) |
|
{ |
|
int i = s_PreviewImagePropertiesCache.Find( pMaterial ); |
|
if ( i == s_PreviewImagePropertiesCache.InvalidIndex() ) |
|
{ |
|
// Add an entry to the cache. |
|
CPreviewImagePropertiesCache::CEntry entry; |
|
entry.m_RetVal = pMaterial->GetPreviewImageProperties( &entry.m_Width, &entry.m_Height, &entry.m_ImageFormat, &entry.m_bIsTranslucent ); |
|
i = s_PreviewImagePropertiesCache.Insert( pMaterial, entry ); |
|
} |
|
|
|
CPreviewImagePropertiesCache::CEntry &entry = s_PreviewImagePropertiesCache[i]; |
|
*width = entry.m_Width; |
|
*height = entry.m_Height; |
|
*imageFormat = entry.m_ImageFormat; |
|
*isTranslucent = entry.m_bIsTranslucent; |
|
|
|
return entry.m_RetVal; |
|
} |
|
|
|
private: |
|
|
|
class CEntry |
|
{ |
|
public: |
|
int m_Width; |
|
int m_Height; |
|
ImageFormat m_ImageFormat; |
|
bool m_bIsTranslucent; |
|
PreviewImageRetVal_t m_RetVal; |
|
}; |
|
|
|
static bool PreviewImageLessFunc( IMaterial* const &a, IMaterial* const &b ) |
|
{ |
|
return a < b; |
|
} |
|
|
|
static CUtlMap<IMaterial*, CPreviewImagePropertiesCache::CEntry> s_PreviewImagePropertiesCache; |
|
}; |
|
CUtlMap<IMaterial*, CPreviewImagePropertiesCache::CEntry> CPreviewImagePropertiesCache::s_PreviewImagePropertiesCache( 64, 64, &CPreviewImagePropertiesCache::PreviewImageLessFunc ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: stuff for caching textures in memory. |
|
//----------------------------------------------------------------------------- |
|
class CMaterialImageCache |
|
{ |
|
public: |
|
|
|
CMaterialImageCache(int maxNumGraphicsLoaded); |
|
~CMaterialImageCache(void); |
|
void EnCache( CMaterial *pMaterial ); |
|
|
|
protected: |
|
|
|
CMaterial **pool; |
|
int cacheSize; |
|
int currentID; // next one to get killed. |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. Allocates a pool of material pointers. |
|
// Input : maxNumGraphicsLoaded - |
|
//----------------------------------------------------------------------------- |
|
CMaterialImageCache::CMaterialImageCache(int maxNumGraphicsLoaded) |
|
{ |
|
cacheSize = maxNumGraphicsLoaded; |
|
pool = new CMaterialPtr[cacheSize]; |
|
if (pool != NULL) |
|
{ |
|
memset(pool, 0, sizeof(CMaterialPtr) * cacheSize); |
|
} |
|
currentID = 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor. Frees the pool memory. |
|
//----------------------------------------------------------------------------- |
|
CMaterialImageCache::~CMaterialImageCache(void) |
|
{ |
|
if (pool != NULL) |
|
{ |
|
delete [] pool; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pMaterial - |
|
//----------------------------------------------------------------------------- |
|
void CMaterialImageCache::EnCache( CMaterial *pMaterial ) |
|
{ |
|
if (pMaterial->m_pData != NULL) |
|
{ |
|
// Already cached. |
|
return; |
|
} |
|
|
|
// kill currentID |
|
if ((pool[currentID]) && (pool[currentID]->HasData())) |
|
{ |
|
pool[currentID]->FreeData(); |
|
} |
|
|
|
pool[currentID] = pMaterial; |
|
pMaterial->LoadMaterialImage(); |
|
currentID = ( currentID + 1 ) % cacheSize; |
|
|
|
#if 0 |
|
OutputDebugString( "CMaterialCache::Encache: " ); |
|
OutputDebugString( pMaterial->m_szName ); |
|
OutputDebugString( "\n" ); |
|
#endif |
|
} |
|
|
|
|
|
static CMaterialImageCache *g_pMaterialImageCache = NULL; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CMaterialCache::CMaterialCache(void) |
|
{ |
|
m_pCache = NULL; |
|
m_nMaxEntries = 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CMaterialCache::~CMaterialCache(void) |
|
{ |
|
if (m_pCache != NULL) |
|
{ |
|
delete m_pCache; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Allocates cache memory for a given number of materials. |
|
// Input : nMaxEntries - Maximum number of materials in the cache. |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterialCache::Create(int nMaxEntries) |
|
{ |
|
Assert((m_pCache == NULL) && (m_nMaxEntries == 0)); |
|
|
|
if (m_pCache != NULL) |
|
{ |
|
delete m_pCache; |
|
m_pCache = NULL; |
|
m_nMaxEntries = 0; |
|
} |
|
|
|
if (nMaxEntries <= 0) |
|
{ |
|
nMaxEntries = 500; |
|
} |
|
|
|
m_pCache = new MaterialCacheEntry_t[nMaxEntries]; |
|
|
|
if (m_pCache != NULL) |
|
{ |
|
memset(m_pCache, 0, sizeof(m_pCache[0]) * nMaxEntries); |
|
m_nMaxEntries = nMaxEntries; |
|
} |
|
|
|
return(m_pCache != NULL); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Factory. Creates a material by name, first looking in the cache. |
|
// Input : pszMaterialName - Name of material, ie "brick/brickfloor01". |
|
// Output : Returns a pointer to the new material object, NULL if the given |
|
// material did not exist. |
|
//----------------------------------------------------------------------------- |
|
CMaterial *CMaterialCache::CreateMaterial(const char *pszMaterialName) |
|
{ |
|
CMaterial *pMaterial = NULL; |
|
|
|
if (pszMaterialName != NULL) |
|
{ |
|
// |
|
// Find this material in the cache. If it is here, return it. |
|
// |
|
pMaterial = FindMaterial(pszMaterialName); |
|
if (pMaterial == NULL) |
|
{ |
|
// |
|
// Not found in the cache, try to create it. |
|
// |
|
pMaterial = CMaterial::CreateMaterial(pszMaterialName, true); |
|
if (pMaterial != NULL) |
|
{ |
|
// |
|
// Success. Add the newly created material to the cache. |
|
// |
|
AddMaterial(pMaterial); |
|
return(pMaterial); |
|
} |
|
} |
|
else |
|
{ |
|
// |
|
// Found in the cache, bump the reference count. |
|
// |
|
AddRef(pMaterial); |
|
} |
|
} |
|
|
|
return(pMaterial); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Finds a material in the cache. |
|
// Input : char *pszMaterialName - |
|
// Output : CMaterial |
|
//----------------------------------------------------------------------------- |
|
void CMaterialCache::AddMaterial(CMaterial *pMaterial) |
|
{ |
|
if (pMaterial != NULL) |
|
{ |
|
Assert(m_nEntries < m_nMaxEntries); |
|
|
|
if (m_nEntries < m_nMaxEntries) |
|
{ |
|
m_pCache[m_nEntries].pMaterial = pMaterial; |
|
m_pCache[m_nEntries].nRefCount = 1; |
|
m_nEntries++; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Increments the reference count on a material in the cache. Called by |
|
// client code when a pointer to the model is copied, making that |
|
// reference independent. |
|
// Input : pModel - Model for which to increment the reference count. |
|
//----------------------------------------------------------------------------- |
|
void CMaterialCache::AddRef(CMaterial *pMaterial) |
|
{ |
|
for (int i = 0; i < m_nEntries; i++) |
|
{ |
|
if (m_pCache[i].pMaterial == pMaterial) |
|
{ |
|
m_pCache[i].nRefCount++; |
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Finds a material in the cache by name. |
|
// Input : char *pszMaterialName - |
|
// Output : CMaterial |
|
//----------------------------------------------------------------------------- |
|
CMaterial *CMaterialCache::FindMaterial(const char *pszMaterialName) |
|
{ |
|
if (pszMaterialName != NULL) |
|
{ |
|
for (int i = 0; i < m_nEntries; i++) |
|
{ |
|
if (!stricmp(m_pCache[i].pMaterial->GetName(), pszMaterialName)) |
|
{ |
|
return(m_pCache[i].pMaterial); |
|
} |
|
} |
|
} |
|
|
|
return(NULL); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Decrements the reference count of a material, deleting it and |
|
// removing it from the cache if its reference count becomes zero. |
|
// Input : pMaterial - Material to release. |
|
//----------------------------------------------------------------------------- |
|
void CMaterialCache::Release(CMaterial *pMaterial) |
|
{ |
|
if (pMaterial != NULL) |
|
{ |
|
for (int i = 0; i < m_nEntries; i++) |
|
{ |
|
if (m_pCache[i].pMaterial == pMaterial) |
|
{ |
|
m_pCache[i].nRefCount--; |
|
if (m_pCache[i].nRefCount == 0) |
|
{ |
|
delete m_pCache[i].pMaterial; |
|
|
|
m_nEntries--; |
|
m_pCache[i] = m_pCache[m_nEntries]; |
|
|
|
memset(&m_pCache[m_nEntries], 0, sizeof(m_pCache[0])); |
|
} |
|
|
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. Initializes data members. |
|
//----------------------------------------------------------------------------- |
|
CMaterial::CMaterial(void) |
|
{ |
|
memset(m_szName, 0, sizeof(m_szName)); |
|
memset(m_szFileName, 0, sizeof(m_szFileName)); |
|
memset(m_szKeywords, 0, sizeof(m_szKeywords)); |
|
|
|
m_nWidth = 0; |
|
m_nHeight = 0; |
|
m_nTextureID = 0; |
|
m_pData = NULL; |
|
m_bLoaded = false; |
|
m_pMaterial = NULL; |
|
m_TranslucentBaseTexture = false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor. Frees texture image data and palette. |
|
//----------------------------------------------------------------------------- |
|
CMaterial::~CMaterial(void) |
|
{ |
|
// |
|
// Free image data. |
|
// |
|
if (m_pData != NULL) |
|
{ |
|
free(m_pData); |
|
m_pData = NULL; |
|
} |
|
|
|
/* FIXME: Texture manager shuts down after the material system |
|
if (m_pMaterial) |
|
{ |
|
m_pMaterial->DecrementReferenceCount(); |
|
m_pMaterial = NULL; |
|
} |
|
*/ |
|
} |
|
|
|
|
|
#define MATERIAL_PREFIX_LEN 10 |
|
//----------------------------------------------------------------------------- |
|
// Finds all .VMT files in a particular directory |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::LoadMaterialsInDirectory( char const* pDirectoryName, int nDirectoryNameLen, |
|
IMaterialEnumerator *pEnum, int nContext, int nFlags ) |
|
{ |
|
//Assert( Q_strnicmp( pDirectoryName, "materials", 9 ) == 0 ); |
|
|
|
char *pWildCard; |
|
pWildCard = ( char * )stackalloc( nDirectoryNameLen + 7 ); |
|
Q_snprintf( pWildCard, nDirectoryNameLen + 7, "%s/*.vmt", pDirectoryName ); |
|
|
|
if ( !g_pFileSystem ) |
|
{ |
|
return false; |
|
} |
|
|
|
FileFindHandle_t findHandle; |
|
const char *pFileName = g_pFullFileSystem->FindFirstEx( pWildCard, "GAME", &findHandle ); |
|
while( pFileName ) |
|
{ |
|
if (IsIgnoredMaterial(pFileName)) |
|
{ |
|
pFileName = g_pFullFileSystem->FindNext( findHandle ); |
|
continue; |
|
} |
|
|
|
if( !g_pFullFileSystem->FindIsDirectory( findHandle ) ) |
|
{ |
|
// Strip off the 'materials/' part of the material name. |
|
char *pFileNameWithPath; |
|
int nAllocSize = nDirectoryNameLen + Q_strlen(pFileName) + 2; |
|
pFileNameWithPath = (char *)stackalloc( nAllocSize ); |
|
Q_snprintf( pFileNameWithPath, nAllocSize, "%s/%s", &pDirectoryName[MATERIAL_PREFIX_LEN], pFileName ); |
|
Q_strnlwr( pFileNameWithPath, nAllocSize ); |
|
|
|
// Strip off the extension... |
|
char *pExt = Q_strrchr( pFileNameWithPath, '.'); |
|
if (pExt) |
|
*pExt = 0; |
|
|
|
if (!pEnum->EnumMaterial( pFileNameWithPath, nContext )) |
|
{ |
|
return false; |
|
} |
|
} |
|
pFileName = g_pFullFileSystem->FindNext( findHandle ); |
|
} |
|
g_pFullFileSystem->FindClose( findHandle ); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Discovers all .VMT files lying under a particular directory |
|
// It only finds their names so we can generate shell materials for them |
|
// that we can load up at a later time |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::InitDirectoryRecursive( char const* pDirectoryName, |
|
IMaterialEnumerator *pEnum, int nContext, int nFlags ) |
|
{ |
|
// Make sure this is an ok directory, otherwise don't bother |
|
if (ShouldSkipMaterial( pDirectoryName + MATERIAL_PREFIX_LEN, nFlags )) |
|
return true; |
|
|
|
// Compute directory name length |
|
int nDirectoryNameLen = Q_strlen( pDirectoryName ); |
|
|
|
if (!LoadMaterialsInDirectory( pDirectoryName, nDirectoryNameLen, pEnum, nContext, nFlags )) |
|
return false; |
|
|
|
char *pWildCard = ( char * )stackalloc( nDirectoryNameLen + 5 ); |
|
strcpy(pWildCard, pDirectoryName); |
|
strcat(pWildCard, "/*.*"); |
|
int nPathStrLen = nDirectoryNameLen + 1; |
|
|
|
FileFindHandle_t findHandle; |
|
const char *pFileName = g_pFullFileSystem->FindFirstEx( pWildCard, "GAME", &findHandle ); |
|
while( pFileName ) |
|
{ |
|
if (!IsIgnoredMaterial(pFileName)) |
|
{ |
|
if ((pFileName[0] != '.') || (pFileName[1] != '.' && pFileName[1] != 0)) |
|
{ |
|
if( g_pFullFileSystem->FindIsDirectory( findHandle ) ) |
|
{ |
|
int fileNameStrLen = Q_strlen( pFileName ); |
|
char *pFileNameWithPath = ( char * )stackalloc( nPathStrLen + fileNameStrLen + 1 ); |
|
memcpy( pFileNameWithPath, pWildCard, nPathStrLen ); |
|
pFileNameWithPath[nPathStrLen] = '\0'; |
|
Q_strncat( pFileNameWithPath, pFileName, nPathStrLen + fileNameStrLen + 1 ); |
|
|
|
if (!InitDirectoryRecursive( pFileNameWithPath, pEnum, nContext, nFlags )) |
|
return false; |
|
} |
|
} |
|
} |
|
pFileName = g_pFullFileSystem->FindNext( findHandle ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Discovers all .VMT files lying under a particular directory |
|
// It only finds their names so we can generate shell materials for them |
|
// that we can load up at a later time |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::EnumerateMaterials( IMaterialEnumerator *pEnum, const char *szRoot, int nContext, int nFlags ) |
|
{ |
|
InitDirectoryRecursive( szRoot, pEnum, nContext, nFlags ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called from GetFirst/GetNextMaterialName to skip unwanted materials. |
|
// Input : pszName - Name of material to evaluate. |
|
// nFlags - One or more of the following: |
|
// INCLUDE_ALL_MATERIALS |
|
// INCLUDE_WORLD_MATERIALS |
|
// INCLUDE_MODEL_MATERIALS |
|
// Output : Returns true to skip, false to not skip this material. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::ShouldSkipMaterial(const char *pszName, int nFlags) |
|
{ |
|
static char szStrippedName[MAX_PATH]; |
|
|
|
// if NULL skip it |
|
if( !pszName ) |
|
return true; |
|
|
|
// |
|
// check against the list of user-defined exclusion directories |
|
// |
|
for( int i = 0; i < g_pGameConfig->m_MaterialExcludeCount; i++ ) |
|
{ |
|
// This will guarantee the match is at the start of the string |
|
const char *pMatchFound = Q_stristr( pszName, g_pGameConfig->m_MaterialExclusions[i].szDirectory ); |
|
if( pMatchFound == pszName ) |
|
return true; |
|
} |
|
// also check against any FGD-defined exclusions |
|
if (pGD != NULL) |
|
{ |
|
for( int i = 0; i < pGD->m_FGDMaterialExclusions.Count(); i++ ) |
|
{ |
|
const char *pMatchFound = Q_stristr( pszName, pGD->m_FGDMaterialExclusions[i].szDirectory ); |
|
if( pMatchFound == pszName ) |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
|
|
#if 0 |
|
bool bSkip = false; |
|
|
|
if (pszName != NULL) |
|
{ |
|
if (!(nFlags & INCLUDE_MODEL_MATERIALS)) |
|
{ |
|
if (_strnicmp(pszName, "models/", 7) == 0) |
|
{ |
|
bSkip = true; |
|
} |
|
} |
|
|
|
if (!(nFlags & INCLUDE_WORLD_MATERIALS)) |
|
{ |
|
if (_strnicmp(pszName, "models/", 7) != 0) |
|
{ |
|
bSkip = true; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
bSkip = true; |
|
} |
|
|
|
return(bSkip); |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Factory. Creates a material by name. |
|
// Input : pszMaterialName - Name of material, ie "brick/brickfloor01". |
|
// Output : Returns a pointer to the new material object, NULL if the given |
|
// material did not exist. |
|
//----------------------------------------------------------------------------- |
|
CMaterial *CMaterial::CreateMaterial(const char *pszMaterialName, bool bLoadImmediately, bool* pFound) |
|
{ |
|
Assert (pszMaterialName); |
|
|
|
CMaterial *pMaterial = new CMaterial; |
|
Assert( pMaterial ); |
|
|
|
// Store off the material name so we can load it later if we need to |
|
Q_snprintf( pMaterial->m_szFileName, MAX_PATH, pszMaterialName ); |
|
Q_snprintf( pMaterial->m_szName, MAX_PATH, pszMaterialName ); |
|
|
|
// |
|
// Find the material by name and load it. |
|
// |
|
if (bLoadImmediately) |
|
{ |
|
bool bFound = pMaterial->LoadMaterial(); |
|
|
|
// Returns if the material was found or not |
|
if (pFound) |
|
*pFound = bFound; |
|
} |
|
|
|
return pMaterial; |
|
} |
|
|
|
bool CMaterial::IsIgnoredMaterial( const char *pName ) |
|
{ |
|
//TODO: make this a customizable user option? |
|
if ( !Q_strnicmp(pName, ".svn", 4) || strstr (pName, ".svn") || |
|
!Q_strnicmp(pName, "models", 6) || strstr (pName, "models") ) |
|
return true; |
|
|
|
return false; |
|
} |
|
//----------------------------------------------------------------------------- |
|
// Will actually load the material bits |
|
// We don't want to load them all at once because it takes way too long |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::LoadMaterial() |
|
{ |
|
bool bFound = true; |
|
if (!m_bLoaded) |
|
{ |
|
if (IsIgnoredMaterial(m_szFileName)) |
|
{ |
|
return false; |
|
} |
|
|
|
m_bLoaded = true; |
|
|
|
IMaterial *pMat = materials->FindMaterial(m_szFileName, TEXTURE_GROUP_OTHER); |
|
if ( IsErrorMaterial( pMat ) ) |
|
bFound = false; |
|
|
|
Assert( pMat ); |
|
|
|
if (!pMat) |
|
{ |
|
return false; |
|
} |
|
|
|
if (!LoadMaterialHeader(pMat)) |
|
{ |
|
// dvs: yeaaaaaaaaah, we're gonna disable this until the spew can be reduced |
|
//Msg( mwError,"Load material header failed: %s", m_szFileName ); |
|
|
|
bFound = false; |
|
pMat = materials->FindMaterial("debug/debugempty", TEXTURE_GROUP_OTHER); |
|
|
|
if (pMat) |
|
{ |
|
LoadMaterialHeader(pMat); |
|
} |
|
} |
|
} |
|
|
|
return bFound; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Reloads owing to a material change |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::Reload( bool bFullReload ) |
|
{ |
|
// Don't bother if we're not loaded yet |
|
if (!m_bLoaded) |
|
return; |
|
|
|
FreeData(); |
|
|
|
if ( m_pMaterial ) |
|
{ |
|
m_pMaterial->DecrementReferenceCount(); |
|
} |
|
m_pMaterial = materials->FindMaterial(m_szFileName, TEXTURE_GROUP_OTHER); |
|
Assert( m_pMaterial ); |
|
|
|
if ( bFullReload ) |
|
m_pMaterial->Refresh(); |
|
|
|
PreviewImageRetVal_t retVal; |
|
bool translucentBaseTexture; |
|
ImageFormat eImageFormat; |
|
int width, height; |
|
retVal = m_pMaterial->GetPreviewImageProperties(&width, &height, &eImageFormat, &translucentBaseTexture); |
|
if (retVal == MATERIAL_PREVIEW_IMAGE_BAD) |
|
return; |
|
|
|
m_nWidth = width; |
|
m_nHeight = height; |
|
m_TranslucentBaseTexture = translucentBaseTexture; |
|
|
|
// Find the keywords for this material from the vmt file. |
|
bool bFound; |
|
IMaterialVar *pVar = m_pMaterial->FindVar("%keywords", &bFound, false); |
|
if (bFound) |
|
{ |
|
V_strcpy_safe( m_szKeywords, pVar->GetStringValue() ); |
|
|
|
// Register the keywords |
|
g_Textures.RegisterTextureKeywords( this ); |
|
} |
|
|
|
// Make sure to bump the refcount again. Not sure why this wasn't always done (check for leaks). |
|
if (m_pMaterial) |
|
{ |
|
m_pMaterial->IncrementReferenceCount(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the material |
|
//----------------------------------------------------------------------------- |
|
IMaterial* CMaterial::GetMaterial( bool bForceLoad ) |
|
{ |
|
if ( bForceLoad ) |
|
LoadMaterial(); |
|
|
|
return m_pMaterial; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::DrawIcon( CDC *pDC, CMaterial* pIcon, RECT& dstRect ) |
|
{ |
|
if (!pIcon) |
|
return; |
|
|
|
g_pMaterialImageCache->EnCache(pIcon); |
|
|
|
RECT rect, dst; |
|
rect.left = 0; rect.right = pIcon->GetWidth(); |
|
|
|
// FIXME: Workaround the fact that materials must be power of 2, I want 12 bite |
|
rect.top = 2; rect.bottom = pIcon->GetHeight() - 2; |
|
|
|
dst = dstRect; |
|
float dstHeight = dstRect.bottom - dstRect.top; |
|
float srcAspect = (float)(rect.right - rect.left) / (float)(rect.bottom - rect.top); |
|
dst.right = dst.left + (dstHeight * srcAspect); |
|
pIcon->DrawBitmap( pDC, rect, dst ); |
|
|
|
dstRect.left += dst.right - dst.left; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pDC - |
|
// dstRect - |
|
// detectErrors - |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::DrawBrowserIcons( CDC *pDC, RECT& dstRect, bool detectErrors ) |
|
{ |
|
static CMaterial* pTranslucentIcon = 0; |
|
static CMaterial* pOpaqueIcon = 0; |
|
static CMaterial* pSelfIllumIcon = 0; |
|
static CMaterial* pBaseAlphaEnvMapMaskIcon = 0; |
|
static CMaterial* pErrorIcon = 0; |
|
|
|
if (!pTranslucentIcon) |
|
{ |
|
pTranslucentIcon = CreateMaterial("editor/translucenticon", true); |
|
pOpaqueIcon = CreateMaterial("editor/opaqueicon", true); |
|
pSelfIllumIcon = CreateMaterial("editor/selfillumicon", true); |
|
pBaseAlphaEnvMapMaskIcon = CreateMaterial("editor/basealphaenvmapmaskicon", true); |
|
pErrorIcon = CreateMaterial("editor/erroricon", true); |
|
|
|
Assert( pTranslucentIcon && pOpaqueIcon && pSelfIllumIcon && pBaseAlphaEnvMapMaskIcon && pErrorIcon ); |
|
} |
|
|
|
bool error = false; |
|
|
|
IMaterial* pMaterial = GetMaterial(); |
|
if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_TRANSLUCENT ) ) |
|
{ |
|
DrawIcon( pDC, pTranslucentIcon, dstRect ); |
|
if (detectErrors) |
|
{ |
|
error = error || !m_TranslucentBaseTexture; |
|
} |
|
} |
|
else |
|
{ |
|
DrawIcon( pDC, pOpaqueIcon, dstRect ); |
|
} |
|
|
|
if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_SELFILLUM )) |
|
{ |
|
DrawIcon( pDC, pSelfIllumIcon, dstRect ); |
|
if (detectErrors) |
|
{ |
|
error = error || !m_TranslucentBaseTexture; |
|
} |
|
} |
|
|
|
if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_BASEALPHAENVMAPMASK )) |
|
{ |
|
DrawIcon( pDC, pBaseAlphaEnvMapMaskIcon, dstRect ); |
|
if (detectErrors) |
|
{ |
|
error = error || !m_TranslucentBaseTexture; |
|
} |
|
} |
|
|
|
if (error) |
|
{ |
|
DrawIcon( pDC, pErrorIcon, dstRect ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pDC - |
|
// srcRect - |
|
// dstRect - |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::DrawBitmap( CDC *pDC, RECT& srcRect, RECT& dstRect ) |
|
{ |
|
static struct |
|
{ |
|
BITMAPINFOHEADER bmih; |
|
unsigned short colorindex[256]; |
|
} bmi; |
|
|
|
int srcWidth = srcRect.right - srcRect.left; |
|
int srcHeight = srcRect.bottom - srcRect.top; |
|
|
|
BITMAPINFOHEADER &bmih = bmi.bmih; |
|
memset(&bmih, 0, sizeof(bmih)); |
|
bmih.biSize = sizeof(bmih); |
|
bmih.biWidth = srcWidth; |
|
bmih.biHeight = -srcHeight; |
|
bmih.biCompression = BI_RGB; |
|
|
|
bmih.biBitCount = 24; |
|
bmih.biPlanes = 1; |
|
|
|
static BOOL bInit = false; |
|
if (!bInit) |
|
{ |
|
bInit = true; |
|
for (int i = 0; i < 256; i++) |
|
{ |
|
bmi.colorindex[i] = i; |
|
} |
|
} |
|
|
|
int dest_width = dstRect.right - dstRect.left; |
|
int dest_height = dstRect.bottom - dstRect.top; |
|
|
|
// ** bits ** |
|
SetStretchBltMode(pDC->m_hDC, COLORONCOLOR); |
|
if (StretchDIBits(pDC->m_hDC, dstRect.left, dstRect.top, dest_width, dest_height, |
|
srcRect.left, -srcRect.top, srcWidth, srcHeight, m_pData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR) |
|
{ |
|
Msg(mwError, "CMaterial::Draw(): StretchDIBits failed."); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pDC - |
|
// rect - |
|
// iFontHeight - |
|
// dwFlags - |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::Draw(CDC *pDC, RECT& rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData)//, BrowserData_t *pBrowserData) |
|
{ |
|
g_pMaterialImageCache->EnCache(this); |
|
if (!this->HasData()) |
|
{ |
|
return; |
|
} |
|
|
|
if (m_nWidth <= 0) |
|
{ |
|
NoData: |
|
// draw "no data" |
|
CFont *pOldFont = (CFont*) pDC->SelectStockObject(ANSI_VAR_FONT); |
|
COLORREF cr = pDC->SetTextColor(RGB(0xff, 0xff, 0xff)); |
|
COLORREF cr2 = pDC->SetBkColor(RGB(0, 0, 0)); |
|
|
|
// draw black rect first |
|
pDC->FillRect(&rect, CBrush::FromHandle(HBRUSH(GetStockObject(BLACK_BRUSH)))); |
|
|
|
// then text |
|
pDC->TextOut(rect.left+2, rect.top+2, "No Image", 8); |
|
pDC->SelectObject(pOldFont); |
|
pDC->SetTextColor(cr); |
|
pDC->SetBkColor(cr2); |
|
return; |
|
} |
|
|
|
// no data - |
|
if (!m_pData) |
|
{ |
|
// try to load - |
|
if (!Load()) |
|
{ |
|
// can't load - |
|
goto NoData; |
|
} |
|
} |
|
|
|
// Draw the material image |
|
RECT srcRect, dstRect; |
|
srcRect.left = 0; |
|
srcRect.top = 0; |
|
srcRect.right = m_nWidth; |
|
srcRect.bottom = m_nHeight; |
|
dstRect = rect; |
|
|
|
if (DrawTexData.nFlags & drawCaption) |
|
{ |
|
dstRect.bottom -= iFontHeight + 4; |
|
} |
|
if (DrawTexData.nFlags & drawIcons) |
|
{ |
|
dstRect.bottom -= iIconHeight; |
|
} |
|
|
|
if (!(DrawTexData.nFlags & drawResizeAlways)) |
|
{ |
|
if (m_nWidth < dstRect.right - dstRect.left ) |
|
{ |
|
dstRect.right = dstRect.left + m_nWidth; |
|
} |
|
|
|
if (m_nHeight < dstRect.bottom - dstRect.top ) |
|
{ |
|
dstRect.bottom = dstRect.top + m_nHeight; |
|
} |
|
} |
|
DrawBitmap( pDC, srcRect, dstRect ); |
|
|
|
// Draw the icons |
|
if (DrawTexData.nFlags & drawIcons) |
|
{ |
|
dstRect = rect; |
|
if (DrawTexData.nFlags & drawCaption) |
|
{ |
|
dstRect.bottom -= iFontHeight + 5; |
|
} |
|
dstRect.top = dstRect.bottom - iIconHeight; |
|
DrawBrowserIcons(pDC, dstRect, (DrawTexData.nFlags & drawErrors) != 0 ); |
|
} |
|
|
|
// ** caption ** |
|
if (DrawTexData.nFlags & drawCaption) |
|
{ |
|
// draw background for name |
|
CBrush brCaption(RGB(0, 0, 255)); |
|
CRect rcCaption(rect); |
|
|
|
rcCaption.top = rcCaption.bottom - (iFontHeight + 5); |
|
pDC->FillRect(rcCaption, &brCaption); |
|
|
|
// draw name |
|
char szShortName[MAX_PATH]; |
|
int iLen = GetShortName(szShortName); |
|
pDC->TextOut(rect.left, rect.bottom - (iFontHeight + 4), szShortName, iLen); |
|
|
|
// draw usage count |
|
if (DrawTexData.nFlags & drawUsageCount) |
|
{ |
|
CString str; |
|
str.Format("%d", DrawTexData.nUsageCount); |
|
CSize size = pDC->GetTextExtent(str); |
|
pDC->TextOut(rect.right - size.cx, rect.bottom - (iFontHeight + 4), str); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::FreeData( void ) |
|
{ |
|
free( m_pData ); |
|
m_pData = NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns a string of comma delimited keywords associated with this |
|
// material. |
|
// Input : pszKeywords - Buffer to receive keywords, NULL to query string length. |
|
// Output : Returns the number of characters in the keyword string. |
|
//----------------------------------------------------------------------------- |
|
int CMaterial::GetKeywords(char *pszKeywords) const |
|
{ |
|
// To access keywords, we have to have the header loaded |
|
const_cast<CMaterial*>(this)->Load(); |
|
if (pszKeywords != NULL) |
|
{ |
|
strcpy(pszKeywords, m_szKeywords); |
|
} |
|
|
|
return(strlen(m_szKeywords)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pszName - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CMaterial::GetShortName(char *pszName) const |
|
{ |
|
if (pszName != NULL) |
|
{ |
|
strcpy(pszName, m_szName); |
|
} |
|
|
|
return(strlen(m_szName)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : material - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::LoadMaterialHeader( IMaterial *pMat ) |
|
{ |
|
|
|
PreviewImageRetVal_t retVal; |
|
bool translucentBaseTexture; |
|
ImageFormat eImageFormat; |
|
int width, height; |
|
retVal = CPreviewImagePropertiesCache::GetPreviewImageProperties( pMat, &width, &height, &eImageFormat, &translucentBaseTexture); |
|
if (retVal == MATERIAL_PREVIEW_IMAGE_BAD) |
|
return false; |
|
|
|
m_pMaterial = pMat; |
|
m_pMaterial->IncrementReferenceCount(); |
|
|
|
m_nWidth = width; |
|
m_nHeight = height; |
|
m_TranslucentBaseTexture = translucentBaseTexture; |
|
|
|
// Find the keywords for this material from the vmt file. |
|
bool bFound; |
|
IMaterialVar *pVar = pMat->FindVar("%keywords", &bFound, false); |
|
if (bFound) |
|
{ |
|
V_strcpy_safe( m_szKeywords, pVar->GetStringValue() ); |
|
|
|
// Register the keywords |
|
g_Textures.RegisterTextureKeywords( this ); |
|
} |
|
|
|
return(true); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the full path of the file from which this material was loaded. |
|
//----------------------------------------------------------------------------- |
|
const char *CMaterial::GetFileName( void ) const |
|
{ |
|
return(m_szFileName); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::IsWater( void ) const |
|
{ |
|
bool bFound; |
|
IMaterialVar *pVar = m_pMaterial->FindVar( "$surfaceprop", &bFound, false ); |
|
if ( bFound ) |
|
{ |
|
if ( !strcmp( "water", pVar->GetStringValue() ) ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: If the buffer pointer passed in is not NULL, copies the image data |
|
// in RGB format to the buffer |
|
// Input : pImageRGB - Pointer to buffer that receives the image data. If the |
|
// pointer is NULL, no data is copied, only the data size is returned. |
|
// Output : Returns a the size of the RGB image in bytes. |
|
//----------------------------------------------------------------------------- |
|
int CMaterial::GetImageDataRGB( void *pImageRGB ) |
|
{ |
|
Assert( m_nWidth > 0 ); |
|
|
|
if ( pImageRGB != NULL ) |
|
{ |
|
Load(); |
|
|
|
g_pMaterialImageCache->EnCache( this ); |
|
if (!this->HasData()) |
|
{ |
|
return(NULL); |
|
} |
|
|
|
unsigned char *src, *dst; |
|
src = ( unsigned char * )m_pData; |
|
dst = (unsigned char *)pImageRGB; |
|
for( ; src < ( unsigned char * )m_pData + m_nWidth * m_nHeight * 3; src += 3, dst += 3 ) |
|
{ |
|
dst[0] = src[2]; |
|
dst[1] = src[1]; |
|
dst[2] = src[0]; |
|
} |
|
|
|
return( m_nWidth * m_nHeight * 3 ); |
|
} |
|
|
|
return( m_nWidth * m_nHeight * 3 ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: If the buffer pointer passed in is not NULL, copies the image data |
|
// in RGBA format to the buffer |
|
// Input : pImageRGBA - Pointer to buffer that receives the image data. If the |
|
// pointer is NULL, no data is copied, only the data size is returned. |
|
// Output : Returns a the size of the RGBA image in bytes. |
|
//----------------------------------------------------------------------------- |
|
int CMaterial::GetImageDataRGBA(void *pImageRGBA) |
|
{ |
|
Assert( m_nWidth > 0 ); |
|
|
|
if (pImageRGBA != NULL) |
|
{ |
|
Load(); |
|
|
|
g_pMaterialImageCache->EnCache(this); |
|
if (!this->HasData()) |
|
{ |
|
return(NULL); |
|
} |
|
|
|
unsigned char *src, *dst; |
|
src = (unsigned char *)m_pData; |
|
dst = (unsigned char *)pImageRGBA; |
|
|
|
while (src < (unsigned char *)m_pData + m_nWidth * m_nHeight * 4); |
|
{ |
|
dst[0] = src[2]; |
|
dst[1] = src[1]; |
|
dst[2] = src[0]; |
|
dst[3] = 0; |
|
|
|
src += 4; |
|
dst += 4; |
|
} |
|
} |
|
|
|
return(m_nWidth * m_nHeight * 4); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : size - |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::GetSize(SIZE &size) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
Assert( m_nWidth >= 0 ); |
|
|
|
size.cx = m_nWidth; |
|
size.cy = m_nHeight; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Loads this material's image from disk if it is not already loaded. |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::Load( void ) |
|
{ |
|
LoadMaterial(); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// cache in the image size only when we need to |
|
//----------------------------------------------------------------------------- |
|
int CMaterial::GetImageWidth(void) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
return(m_nWidth); |
|
} |
|
|
|
int CMaterial::GetImageHeight(void) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
return(m_nHeight); |
|
} |
|
|
|
int CMaterial::GetWidth(void) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
return(m_nWidth); |
|
} |
|
|
|
int CMaterial::GetHeight(void) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
return(m_nHeight); |
|
} |
|
|
|
float CMaterial::GetDecalScale(void) const |
|
{ |
|
const_cast<CMaterial*>(this)->Load(); |
|
|
|
IMaterialVar *decalScaleVar; |
|
bool found; |
|
|
|
decalScaleVar = m_pMaterial->FindVar( "$decalScale", &found, false ); |
|
if( !found ) |
|
{ |
|
return 1.0f; |
|
} |
|
else |
|
{ |
|
return decalScaleVar->GetFloatValue(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::LoadMaterialImage( void ) |
|
{ |
|
Load(); |
|
|
|
if ((!m_nWidth) || (!m_nHeight)) |
|
return(false); |
|
|
|
m_pData = malloc(m_nWidth * m_nHeight * 3); |
|
Assert(m_pData); |
|
|
|
ImageFormat imageFormat; |
|
|
|
// if( _strnicmp( m_pMaterial->GetName(), "decals", 6 ) == 0 ) |
|
// { |
|
// imageFormat = IMAGE_FORMAT_BGR888_BLUESCREEN; |
|
// } |
|
// else |
|
{ |
|
imageFormat = IMAGE_FORMAT_BGR888; |
|
} |
|
|
|
PreviewImageRetVal_t retVal; |
|
retVal = m_pMaterial->GetPreviewImage( (unsigned char *)m_pData, m_nWidth, m_nHeight, imageFormat ); |
|
return (retVal != MATERIAL_PREVIEW_IMAGE_BAD); |
|
} |
|
|
|
|
|
static void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig) |
|
{ |
|
pConfig->bEditMode = true; |
|
pConfig->m_nAASamples = 0; |
|
pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP, true); |
|
// When I do this the model browser layout is horked... |
|
// pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, true ); |
|
} |
|
|
|
|
|
static char const *s_rt_names[]={"_rt_albedo","_rt_normal","_rt_position","_rt_flags", |
|
"_rt_accbuf_0","_rt_accbuf_1"}; |
|
ImageFormat s_rt_formats[]={ IMAGE_FORMAT_RGBA32323232F, IMAGE_FORMAT_RGBA32323232F, |
|
IMAGE_FORMAT_RGBA32323232F, IMAGE_FORMAT_RGBA32323232F, |
|
IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F }; |
|
|
|
// ImageFormat s_rt_formats[]={ |
|
// IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F, |
|
// IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F, |
|
// IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F, |
|
// IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F }; |
|
|
|
static CTextureReference sg_ExtraFP16Targets[NELEMS(s_rt_names)]; |
|
|
|
|
|
void AllocateLightingPreviewtextures(void) |
|
{ |
|
static bool bHaveAllocated=false; |
|
if (! bHaveAllocated ) |
|
{ |
|
bHaveAllocated = true; |
|
MaterialSystemInterface()->BeginRenderTargetAllocation(); |
|
for(int idx=0;idx<NELEMS(sg_ExtraFP16Targets);idx++) |
|
sg_ExtraFP16Targets[idx].Init( |
|
materials->CreateNamedRenderTargetTextureEx2( |
|
s_rt_names[idx], |
|
512, 512, RT_SIZE_DEFAULT, s_rt_formats[idx], |
|
MATERIAL_RT_DEPTH_SHARED, |
|
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, |
|
CREATERENDERTARGETFLAGS_HDR ) |
|
); |
|
|
|
// End block in which all render targets should be allocated (kicking off an Alt-Tab type |
|
// behavior) |
|
MaterialSystemInterface()->EndRenderTargetAllocation(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMaterial::Initialize( HWND hwnd ) |
|
{ |
|
// NOTE: This gets set to true later upon creating a 3d view. |
|
g_materialSystemConfig = materials->GetCurrentConfigForVideoCard(); |
|
InitMaterialSystemConfig( &g_materialSystemConfig ); |
|
|
|
// Create a cache for material images (for browsing and uploading to the driver). |
|
if (g_pMaterialImageCache == NULL) |
|
{ |
|
g_pMaterialImageCache = new CMaterialImageCache(500); |
|
if (g_pMaterialImageCache == NULL) |
|
return false ; |
|
} |
|
|
|
materials->OverrideConfig( g_materialSystemConfig, false ); |
|
|
|
// Set the mode |
|
// When setting the mode, we need to grab the parent window |
|
// since that's going to enclose all our little render windows |
|
g_materialSystemConfig.m_VideoMode.m_Width = g_materialSystemConfig.m_VideoMode.m_Height = 0; |
|
g_materialSystemConfig.m_VideoMode.m_Format = IMAGE_FORMAT_BGRA8888; |
|
g_materialSystemConfig.m_VideoMode.m_RefreshRate = 0; |
|
g_materialSystemConfig.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); |
|
g_materialSystemConfig.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true ); |
|
|
|
|
|
if (!MaterialSystemInterface()->SetMode( hwnd, g_materialSystemConfig ) ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Restores the material system to an uninitialized state. |
|
//----------------------------------------------------------------------------- |
|
void CMaterial::ShutDown(void) |
|
{ |
|
for ( int i = 0; i < NELEMS(sg_ExtraFP16Targets); ++i ) |
|
{ |
|
sg_ExtraFP16Targets[i].Shutdown(); |
|
} |
|
|
|
if (materials != NULL) |
|
{ |
|
materials->UncacheAllMaterials(); |
|
} |
|
|
|
delete g_pMaterialImageCache; |
|
g_pMaterialImageCache = NULL; |
|
} |
|
|
|
|
|
|