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.
166 lines
4.9 KiB
166 lines
4.9 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "tier1/strtools.h" |
|
#include "macro_texture.h" |
|
#include "bsplib.h" |
|
#include "cmdlib.h" |
|
#include "vtf/vtf.h" |
|
#include "tier1/utldict.h" |
|
#include "tier1/utlbuffer.h" |
|
#include "bitmap/imageformat.h" |
|
|
|
|
|
class CMacroTextureData |
|
{ |
|
public: |
|
int m_Width, m_Height; |
|
CUtlMemory<unsigned char> m_ImageData; |
|
}; |
|
|
|
|
|
CMacroTextureData *g_pGlobalMacroTextureData = NULL; |
|
|
|
// Which macro texture each map face uses. |
|
static CUtlDict<CMacroTextureData*, int> g_MacroTextureLookup; // Stores a list of unique macro textures. |
|
static CUtlVector<CMacroTextureData*> g_FaceMacroTextures; // Which macro texture each face wants to use. |
|
static Vector g_MacroWorldMins, g_MacroWorldMaxs; |
|
|
|
|
|
CMacroTextureData* FindMacroTexture( const char *pFilename ) |
|
{ |
|
int index = g_MacroTextureLookup.Find( pFilename ); |
|
if ( g_MacroTextureLookup.IsValidIndex( index ) ) |
|
return g_MacroTextureLookup[index]; |
|
else |
|
return NULL; |
|
} |
|
|
|
|
|
CMacroTextureData* LoadMacroTextureFile( const char *pFilename ) |
|
{ |
|
FileHandle_t hFile = g_pFileSystem->Open( pFilename, "rb" ); |
|
if ( hFile == FILESYSTEM_INVALID_HANDLE ) |
|
return NULL; |
|
|
|
// Read the file in. |
|
CUtlVector<char> tempData; |
|
tempData.SetSize( g_pFileSystem->Size( hFile ) ); |
|
g_pFileSystem->Read( tempData.Base(), tempData.Count(), hFile ); |
|
g_pFileSystem->Close( hFile ); |
|
|
|
|
|
// Now feed the data into a CUtlBuffer (great...) |
|
CUtlBuffer buf; |
|
buf.Put( tempData.Base(), tempData.Count() ); |
|
|
|
|
|
// Now make a texture out of it. |
|
IVTFTexture *pTex = CreateVTFTexture(); |
|
if ( !pTex->Unserialize( buf ) ) |
|
Error( "IVTFTexture::Unserialize( %s ) failed.", pFilename ); |
|
|
|
pTex->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false ); // Get it in a format we like. |
|
|
|
|
|
// Now convert to a CMacroTextureData. |
|
CMacroTextureData *pData = new CMacroTextureData; |
|
pData->m_Width = pTex->Width(); |
|
pData->m_Height = pTex->Height(); |
|
pData->m_ImageData.EnsureCapacity( pData->m_Width * pData->m_Height * 4 ); |
|
memcpy( pData->m_ImageData.Base(), pTex->ImageData(), pData->m_Width * pData->m_Height * 4 ); |
|
|
|
DestroyVTFTexture( pTex ); |
|
|
|
Msg( "-- LoadMacroTextureFile: %s\n", pFilename ); |
|
return pData; |
|
} |
|
|
|
|
|
void InitMacroTexture( const char *pBSPFilename ) |
|
{ |
|
// Get the world bounds (same ones used by minimaps and level designers know how to use). |
|
int i = 0; |
|
for (i; i < num_entities; ++i) |
|
{ |
|
char* pEntity = ValueForKey(&entities[i], "classname"); |
|
if( !strcmp(pEntity, "worldspawn") ) |
|
{ |
|
GetVectorForKey( &entities[i], "world_mins", g_MacroWorldMins ); |
|
GetVectorForKey( &entities[i], "world_maxs", g_MacroWorldMaxs ); |
|
break; |
|
} |
|
} |
|
|
|
if ( i == num_entities ) |
|
{ |
|
Warning( "MaskOnMacroTexture: can't find worldspawn" ); |
|
return; |
|
} |
|
|
|
|
|
// Load the macro texture that is mapped onto everything. |
|
char mapName[512], vtfFilename[512]; |
|
Q_FileBase( pBSPFilename, mapName, sizeof( mapName ) ); |
|
Q_snprintf( vtfFilename, sizeof( vtfFilename ), "materials/macro/%s/base.vtf", mapName ); |
|
g_pGlobalMacroTextureData = LoadMacroTextureFile( vtfFilename ); |
|
|
|
|
|
// Now load the macro texture for each face. |
|
g_FaceMacroTextures.SetSize( numfaces ); |
|
for ( int iFace=0; iFace < numfaces; iFace++ ) |
|
{ |
|
g_FaceMacroTextures[iFace] = NULL; |
|
|
|
if ( iFace < g_FaceMacroTextureInfos.Count() ) |
|
{ |
|
unsigned short stringID = g_FaceMacroTextureInfos[iFace].m_MacroTextureNameID; |
|
if ( stringID != 0xFFFF ) |
|
{ |
|
const char *pMacroTextureName = &g_TexDataStringData[ g_TexDataStringTable[stringID] ]; |
|
Q_snprintf( vtfFilename, sizeof( vtfFilename ), "%smaterials/%s.vtf", gamedir, pMacroTextureName ); |
|
|
|
g_FaceMacroTextures[iFace] = FindMacroTexture( vtfFilename ); |
|
if ( !g_FaceMacroTextures[iFace] ) |
|
{ |
|
g_FaceMacroTextures[iFace] = LoadMacroTextureFile( vtfFilename ); |
|
if ( g_FaceMacroTextures[iFace] ) |
|
{ |
|
g_MacroTextureLookup.Insert( vtfFilename, g_FaceMacroTextures[iFace] ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
inline Vector SampleMacroTexture( const CMacroTextureData *t, const Vector &vWorldPos ) |
|
{ |
|
int ix = (int)RemapVal( vWorldPos.x, g_MacroWorldMins.x, g_MacroWorldMaxs.x, 0, t->m_Width-0.00001 ); |
|
int iy = (int)RemapVal( vWorldPos.y, g_MacroWorldMins.y, g_MacroWorldMaxs.y, 0, t->m_Height-0.00001 ); |
|
ix = clamp( ix, 0, t->m_Width-1 ); |
|
iy = t->m_Height - 1 - clamp( iy, 0, t->m_Height-1 ); |
|
|
|
const unsigned char *pInputColor = &t->m_ImageData[(iy*t->m_Width + ix) * 4]; |
|
return Vector( pInputColor[0] / 255.0, pInputColor[1] / 255.0, pInputColor[2] / 255.0 ); |
|
} |
|
|
|
|
|
void ApplyMacroTextures( int iFace, const Vector &vWorldPos, Vector &outLuxel ) |
|
{ |
|
// Add the global macro texture. |
|
Vector vGlobal; |
|
if ( g_pGlobalMacroTextureData ) |
|
outLuxel *= SampleMacroTexture( g_pGlobalMacroTextureData, vWorldPos ); |
|
|
|
// Now add the per-material macro texture. |
|
if ( g_FaceMacroTextures[iFace] ) |
|
outLuxel *= SampleMacroTexture( g_FaceMacroTextures[iFace], vWorldPos ); |
|
} |
|
|
|
|
|
|
|
|