mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
1420 lines
38 KiB
C++
1420 lines
38 KiB
C++
|
//========= 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;
|
||
|
}
|
||
|
|
||
|
|