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.
583 lines
15 KiB
583 lines
15 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
|
|
#include "cbase.h" |
|
// identifier was truncated to '255' characters in the debug information |
|
#pragma warning(disable: 4786) |
|
|
|
#include "ProxyEntity.h" |
|
#include "materialsystem/IMaterialVar.h" |
|
#include "materialsystem/ITexture.h" |
|
#include "bitmap/TGALoader.h" |
|
#include "view.h" |
|
#include "datacache/idatacache.h" |
|
#include "materialsystem/IMaterial.h" |
|
#include "vtf/vtf.h" |
|
|
|
#include "imaterialproxydict.h" |
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
class CCamoMaterialProxy; |
|
|
|
class CCamoTextureRegen : public ITextureRegenerator |
|
{ |
|
public: |
|
CCamoTextureRegen( CCamoMaterialProxy *pProxy ) : m_pProxy(pProxy) {} |
|
virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect ); |
|
virtual void Release() {} |
|
|
|
private: |
|
CCamoMaterialProxy *m_pProxy; |
|
}; |
|
|
|
class CCamoMaterialProxy : public CEntityMaterialProxy |
|
{ |
|
public: |
|
CCamoMaterialProxy(); |
|
virtual ~CCamoMaterialProxy(); |
|
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); |
|
virtual void OnBind(C_BaseEntity *pC_BaseEntity ); |
|
virtual IMaterial *GetMaterial(); |
|
|
|
// Procedurally generates the camo texture... |
|
void GenerateCamoTexture( ITexture* pTexture, IVTFTexture *pVTFTexture ); |
|
|
|
protected: |
|
#if 0 |
|
virtual void SetInstanceDataSize( int size ); |
|
virtual void *FindInstanceData( C_BaseEntity *pEntity ); |
|
virtual void *AllocateInstanceData( C_BaseEntity *pEntity ); |
|
#endif |
|
|
|
private: |
|
void LoadCamoPattern( void ); |
|
void GenerateRandomPointsInNormalizedCube( void ); |
|
void GetColors( Vector &lighting, Vector &base, int index, |
|
const Vector &boxMin, const Vector &boxExtents, |
|
const Vector &forward, const Vector &right, const Vector &up, |
|
const Vector& entityPosition ); |
|
// this needs to go in a base class |
|
|
|
private: |
|
#if 0 |
|
// stuff that needs to be in a base class. |
|
struct InstanceData_t |
|
{ |
|
C_BaseEntity *pEntity; |
|
void *data; |
|
struct InstanceData_s *next; |
|
}; |
|
|
|
struct CamoInstanceData_t |
|
{ |
|
int dummy; |
|
}; |
|
#endif |
|
|
|
unsigned char *m_pCamoPatternImage; |
|
|
|
#if 0 |
|
int m_InstanceDataSize; |
|
InstanceData_t *m_InstanceDataListHead; |
|
#endif |
|
|
|
IMaterial *m_pMaterial; |
|
IMaterialVar *m_pCamoTextureVar; |
|
IMaterialVar *m_pCamoPatternTextureVar; |
|
Vector *m_pointsInNormalizedBox; // [m_CamoPatternNumColors] |
|
|
|
int m_CamoPatternNumColors; |
|
int m_CamoPatternWidth; |
|
int m_CamoPatternHeight; |
|
#if 0 |
|
cache_user_t m_camoImageDataCache; |
|
#endif |
|
unsigned char m_CamoPalette[256][3]; |
|
// these represent that part of the entitiy's bounding box that we |
|
// want to cast rays through to get colors for the camo |
|
Vector m_SubBoundingBoxMin; // normalized |
|
Vector m_SubBoundingBoxMax; // normalized |
|
|
|
CCamoTextureRegen m_TextureRegen; |
|
C_BaseEntity *m_pEnt; |
|
}; |
|
|
|
|
|
void CCamoTextureRegen::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect ) |
|
{ |
|
m_pProxy->GenerateCamoTexture( pTexture, pVTFTexture ); |
|
} |
|
|
|
|
|
#pragma warning (disable:4355) |
|
|
|
CCamoMaterialProxy::CCamoMaterialProxy() : m_TextureRegen(this) |
|
{ |
|
#if 0 |
|
m_InstanceDataSize = 0; |
|
#endif |
|
#if 0 |
|
memset( &m_camoImageDataCache, 0,sizeof( m_camoImageDataCache ) ); |
|
#endif |
|
m_pointsInNormalizedBox = NULL; |
|
#if 0 |
|
m_InstanceDataListHead = NULL; |
|
#endif |
|
m_pCamoPatternImage = NULL; |
|
m_pMaterial = NULL; |
|
m_pCamoTextureVar = NULL; |
|
m_pCamoPatternTextureVar = NULL; |
|
m_pointsInNormalizedBox = NULL; |
|
m_pEnt = NULL; |
|
} |
|
|
|
#pragma warning (default:4355) |
|
|
|
CCamoMaterialProxy::~CCamoMaterialProxy() |
|
{ |
|
#if 0 |
|
InstanceData_t *curr = m_InstanceDataListHead; |
|
while( curr ) |
|
{ |
|
InstanceData_t *next; |
|
next = curr->next; |
|
delete curr; |
|
curr = next; |
|
} |
|
m_InstanceDataListHead = NULL; |
|
#endif |
|
|
|
// Disconnect the texture regenerator... |
|
if (m_pCamoTextureVar) |
|
{ |
|
ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue(); |
|
if (pCamoTexture) |
|
pCamoTexture->SetTextureRegenerator( NULL ); |
|
} |
|
|
|
delete m_pCamoPatternImage; |
|
delete m_pointsInNormalizedBox; |
|
} |
|
|
|
|
|
#if 0 |
|
void CCamoMaterialProxy::SetInstanceDataSize( int size ) |
|
{ |
|
m_InstanceDataSize = size; |
|
} |
|
#endif |
|
|
|
#if 0 |
|
void *CCamoMaterialProxy::FindInstanceData( C_BaseEntity *pEntity ) |
|
{ |
|
InstanceData_t *curr = m_InstanceDataListHead; |
|
while( curr ) |
|
{ |
|
if( pEntity == curr->pEntity ) |
|
{ |
|
return curr->data; |
|
} |
|
curr = curr->next; |
|
} |
|
return NULL; |
|
} |
|
#endif |
|
|
|
#if 0 |
|
void *CCamoMaterialProxy::AllocateInstanceData( C_BaseEntity *pEntity ) |
|
{ |
|
InstanceData_t *newData = new InstanceData_t; |
|
newData->pEntity = pEntity; |
|
newData->next = m_InstanceDataListHead; |
|
m_InstanceDataListHead = newData; |
|
newData->data = new unsigned char[m_InstanceDataSize]; |
|
return newData->data; |
|
} |
|
#endif |
|
|
|
bool CCamoMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) |
|
{ |
|
return false; // hack! Need to make sure that the TGA loader has a valid filesystem before trying |
|
// to load the camo pattern. |
|
|
|
#if 0 |
|
// set how big our instance data is. |
|
SetInstanceDataSize( sizeof( CamoInstanceData_t ) ); |
|
#endif |
|
// remember what material we belong to. |
|
m_pMaterial = pMaterial; |
|
// get pointers to material vars. |
|
bool found; |
|
m_pCamoTextureVar = m_pMaterial->FindVar( "$baseTexture", &found ); |
|
if( !found ) |
|
{ |
|
m_pCamoTextureVar = NULL; |
|
return false; |
|
} |
|
ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue(); |
|
if (pCamoTexture) |
|
pCamoTexture->SetTextureRegenerator( &m_TextureRegen ); |
|
|
|
// Need to get the palettized texture to create the procedural texture from |
|
// somewhere. |
|
m_pCamoPatternTextureVar = m_pMaterial->FindVar( "$camoPatternTexture", &found ); |
|
if( !found ) |
|
{ |
|
m_pCamoTextureVar = NULL; |
|
return false; |
|
} |
|
|
|
IMaterialVar *subBoundingBoxMinVar, *subBoundingBoxMaxVar; |
|
|
|
subBoundingBoxMinVar = m_pMaterial->FindVar( "$camoBoundingBoxMin", &found, false ); |
|
if( !found ) |
|
{ |
|
m_SubBoundingBoxMin = Vector( 0.0f, 0.0f, 0.0f ); |
|
} |
|
else |
|
{ |
|
subBoundingBoxMinVar->GetVecValue( m_SubBoundingBoxMin.Base(), 3 ); |
|
} |
|
|
|
subBoundingBoxMaxVar = m_pMaterial->FindVar( "$camoBoundingBoxMax", &found, false ); |
|
if( !found ) |
|
{ |
|
m_SubBoundingBoxMax = Vector( 1.0f, 1.0f, 1.0f ); |
|
} |
|
else |
|
{ |
|
subBoundingBoxMaxVar->GetVecValue( m_SubBoundingBoxMax.Base(), 3 ); |
|
} |
|
|
|
LoadCamoPattern(); |
|
GenerateRandomPointsInNormalizedCube(); |
|
|
|
return true; |
|
} |
|
|
|
void CCamoMaterialProxy::GetColors( Vector &diffuseColor, Vector &baseColor, int index, |
|
const Vector &boxMin, const Vector &boxExtents, |
|
const Vector &forward, const Vector &right, const Vector &up, |
|
const Vector& entityPosition ) |
|
{ |
|
Vector position, transformedPosition; |
|
|
|
// hack |
|
// m_pointsInNormalizedBox[index] = Vector( 0.5f, 0.5f, 1.0f ); |
|
|
|
position[0] = m_pointsInNormalizedBox[index][0] * boxExtents[0] + boxMin[0]; |
|
position[1] = m_pointsInNormalizedBox[index][1] * boxExtents[1] + boxMin[1]; |
|
position[2] = m_pointsInNormalizedBox[index][2] * boxExtents[2] + boxMin[2]; |
|
transformedPosition[0] = right[0] * position[0] + forward[0] * position[1] + up[0] * position[2]; |
|
transformedPosition[1] = right[1] * position[0] + forward[1] * position[1] + up[1] * position[2]; |
|
transformedPosition[2] = right[2] * position[0] + forward[2] * position[1] + up[2] * position[2]; |
|
transformedPosition = transformedPosition + entityPosition; |
|
Vector direction = transformedPosition - CurrentViewOrigin(); |
|
VectorNormalize( direction ); |
|
direction = direction * ( COORD_EXTENT * 1.74f ); |
|
Vector endPoint = position + direction; |
|
|
|
// baseColor is already in gamma space |
|
// engine->TraceLineMaterialAndLighting( g_vecInstantaneousRenderOrigin, endPoint, diffuseColor, baseColor ); |
|
engine->TraceLineMaterialAndLighting( transformedPosition, endPoint, diffuseColor, baseColor ); |
|
|
|
// hack - optimize! - convert from linear to gamma space - this should be hidden |
|
diffuseColor[0] = pow( diffuseColor[0], 1.0f / 2.2f ); |
|
diffuseColor[1] = pow( diffuseColor[1], 1.0f / 2.2f ); |
|
diffuseColor[2] = pow( diffuseColor[2], 1.0f / 2.2f ); |
|
|
|
#if 0 |
|
Msg( "%f %f %f\n", |
|
diffuseColor[0], |
|
diffuseColor[1], |
|
diffuseColor[2] ); |
|
#endif |
|
|
|
#if 0 |
|
float MAX; |
|
MAX = diffuseColor[0]; |
|
if( diffuseColor[1] > MAX ) |
|
{ |
|
MAX = diffuseColor[1]; |
|
} |
|
if( diffuseColor[2] > MAX ) |
|
{ |
|
MAX = diffuseColor[2]; |
|
} |
|
if( MAX > 1.0f ) |
|
{ |
|
MAX = 1.0f / MAX; |
|
diffuseColor = diffuseColor * MAX; |
|
} |
|
#else |
|
if( diffuseColor[0] > 1.0f ) |
|
{ |
|
diffuseColor[0] = 1.0f; |
|
} |
|
if( diffuseColor[1] > 1.0f ) |
|
{ |
|
diffuseColor[1] = 1.0f; |
|
} |
|
if( diffuseColor[2] > 1.0f ) |
|
{ |
|
diffuseColor[2] = 1.0f; |
|
} |
|
#endif |
|
// hack |
|
//baseColor = Vector( 1.0f, 1.0f, 1.0f ); |
|
//diffuseColor = Vector( 1.0f, 1.0f, 1.0f ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Procedurally generates the camo texture... |
|
//----------------------------------------------------------------------------- |
|
void CCamoMaterialProxy::GenerateCamoTexture( ITexture* pTexture, IVTFTexture *pVTFTexture ) |
|
{ |
|
if (!m_pEnt) |
|
return; |
|
|
|
#if 0 |
|
CamoInstanceData_t *pInstanceData; |
|
pInstanceData = ( CamoInstanceData_t * )FindInstanceData( pEnt ); |
|
if( !pInstanceData ) |
|
{ |
|
pInstanceData = ( CamoInstanceData_t * )AllocateInstanceData( pEnt ); |
|
if( !pInstanceData ) |
|
{ |
|
return; |
|
} |
|
// init the instance data |
|
} |
|
#endif |
|
|
|
Vector entityPosition; |
|
entityPosition = m_pEnt->GetAbsOrigin(); |
|
|
|
QAngle entityAngles; |
|
entityAngles = m_pEnt->GetAbsAngles(); |
|
|
|
// Get the bounding box for the entity |
|
Vector mins, maxs; |
|
mins = m_pEnt->WorldAlignMins(); |
|
maxs = m_pEnt->WorldAlignMaxs(); |
|
|
|
Vector traceDirection; |
|
Vector traceEnd; |
|
trace_t traceResult; |
|
|
|
Vector forward, right, up; |
|
AngleVectors( entityAngles, &forward, &right, &up ); |
|
|
|
Vector position, transformedPosition; |
|
Vector maxsMinusMins = maxs - mins; |
|
|
|
Vector diffuseColor[256]; |
|
Vector baseColor; |
|
|
|
unsigned char camoPalette[256][3]; |
|
// Calculate the camo palette |
|
//Msg( "start of loop\n" ); |
|
int i; |
|
for( i = 0; i < m_CamoPatternNumColors; i++ ) |
|
{ |
|
GetColors( diffuseColor[i], baseColor, i, |
|
mins, maxsMinusMins, forward, right, up, entityPosition ); |
|
#if 1 |
|
camoPalette[i][0] = diffuseColor[i][0] * baseColor[0] * 255.0f; |
|
camoPalette[i][1] = diffuseColor[i][1] * baseColor[1] * 255.0f; |
|
camoPalette[i][2] = diffuseColor[i][2] * baseColor[2] * 255.0f; |
|
#endif |
|
#if 0 |
|
camoPalette[i][0] = baseColor[0] * 255.0f; |
|
camoPalette[i][1] = baseColor[1] * 255.0f; |
|
camoPalette[i][2] = baseColor[2] * 255.0f; |
|
#endif |
|
#if 0 |
|
camoPalette[i][0] = diffuseColor[i][0] * 255.0f; |
|
camoPalette[i][1] = diffuseColor[i][1] * 255.0f; |
|
camoPalette[i][2] = diffuseColor[i][2] * 255.0f; |
|
#endif |
|
} |
|
|
|
int width = pVTFTexture->Width(); |
|
int height = pVTFTexture->Height(); |
|
if( width != m_CamoPatternWidth || height != m_CamoPatternHeight ) |
|
{ |
|
return; |
|
} |
|
|
|
unsigned char *imageData = pVTFTexture->ImageData( 0, 0, 0 ); |
|
enum ImageFormat imageFormat = pVTFTexture->Format(); |
|
if( imageFormat != IMAGE_FORMAT_RGB888 ) |
|
{ |
|
return; |
|
} |
|
// optimize |
|
#if 1 |
|
int x, y; |
|
for( y = 0; y < height; y++ ) |
|
{ |
|
for( x = 0; x < width; x++ ) |
|
{ |
|
int offset = 3 * ( x + y * width ); |
|
assert( offset < width * height * 3 ); |
|
int paletteID = m_pCamoPatternImage[x + y * width]; |
|
assert( paletteID < 256 ); |
|
#if 1 |
|
imageData[offset + 0] = camoPalette[paletteID][0]; |
|
imageData[offset + 1] = camoPalette[paletteID][1]; |
|
imageData[offset + 2] = camoPalette[paletteID][2]; |
|
#else |
|
imageData[offset] = 255; |
|
imageData[offset + 1] = 0; |
|
imageData[offset + 2] = 0; |
|
#endif |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Called when the texture is bound... |
|
//----------------------------------------------------------------------------- |
|
void CCamoMaterialProxy::OnBind( C_BaseEntity *pEntity ) |
|
{ |
|
if( !m_pCamoTextureVar ) |
|
{ |
|
return; |
|
} |
|
|
|
m_pEnt = pEntity; |
|
ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue(); |
|
pCamoTexture->Download(); |
|
|
|
// Mark it so it doesn't get regenerated on task switch |
|
m_pEnt = NULL; |
|
} |
|
|
|
void CCamoMaterialProxy::LoadCamoPattern( void ) |
|
{ |
|
#if 0 |
|
// hack - need to figure out a name to attach that isn't too long. |
|
m_pCamoPatternImage = |
|
( unsigned char * )datacache->FindByName( &m_camoImageDataCache, "camopattern" ); |
|
|
|
if( m_pCamoPatternImage ) |
|
{ |
|
// is already in the cache. |
|
return m_pCamoPatternImage; |
|
} |
|
#endif |
|
|
|
enum ImageFormat indexImageFormat; |
|
int indexImageSize; |
|
#ifndef _XBOX |
|
float dummyGamma; |
|
if( !TGALoader::GetInfo( m_pCamoPatternTextureVar->GetStringValue(), |
|
&m_CamoPatternWidth, &m_CamoPatternHeight, &indexImageFormat, &dummyGamma ) ) |
|
{ |
|
//Warning( "Can't get tga info for hl2/materials/models/combine_elite/camo7paletted.tga for camo material\n" ); |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
} |
|
#else |
|
// xboxissue - no tga support, why implemented this way |
|
Assert( 0 ); |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
#endif |
|
|
|
if( indexImageFormat != IMAGE_FORMAT_I8 ) |
|
{ |
|
// Warning( "Camo material texture hl2/materials/models/combine_elite/camo7paletted.tga must be 8-bit greyscale\n" ); |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
} |
|
|
|
indexImageSize = ImageLoader::GetMemRequired( m_CamoPatternWidth, m_CamoPatternHeight, 1, indexImageFormat, false ); |
|
#if 0 |
|
m_pCamoPatternImage = ( unsigned char * ) |
|
datacache->Alloc( &m_camoImageDataCache, indexImageSize, "camopattern" ); |
|
#endif |
|
m_pCamoPatternImage = ( unsigned char * )new unsigned char[indexImageSize]; |
|
if( !m_pCamoPatternImage ) |
|
{ |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
} |
|
|
|
#ifndef _XBOX |
|
if( !TGALoader::Load( m_pCamoPatternImage, m_pCamoPatternTextureVar->GetStringValue(), |
|
m_CamoPatternWidth, m_CamoPatternHeight, IMAGE_FORMAT_I8, dummyGamma, false ) ) |
|
{ |
|
// Warning( "camo texture hl2/materials/models/combine_elite/camo7paletted.tga must be grey-scale" ); |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
} |
|
#else |
|
// xboxissue - no tga support, why is the camo done this way? |
|
Assert( 0 ); |
|
#endif |
|
|
|
bool colorUsed[256]; |
|
int colorRemap[256]; |
|
// count the number of colors used in the image. |
|
int i; |
|
for( i = 0; i < 256; i++ ) |
|
{ |
|
colorUsed[i] = false; |
|
} |
|
for( i = 0; i < indexImageSize; i++ ) |
|
{ |
|
colorUsed[m_pCamoPatternImage[i]] = true; |
|
} |
|
m_CamoPatternNumColors = 0; |
|
for( i = 0; i < 256; i++ ) |
|
{ |
|
if( colorUsed[i] ) |
|
{ |
|
colorRemap[i] = m_CamoPatternNumColors; |
|
m_CamoPatternNumColors++; |
|
} |
|
} |
|
// remap the color to the beginning of the palette. |
|
for( i = 0; i < indexImageSize; i++ ) |
|
{ |
|
m_pCamoPatternImage[i] = colorRemap[m_pCamoPatternImage[i]]; |
|
// hack |
|
// m_pCamoPatternImage[i] = 0; |
|
} |
|
} |
|
|
|
void CCamoMaterialProxy::GenerateRandomPointsInNormalizedCube( void ) |
|
{ |
|
m_pointsInNormalizedBox = new Vector[m_CamoPatternNumColors]; |
|
if( !m_pointsInNormalizedBox ) |
|
{ |
|
m_pCamoTextureVar = NULL; |
|
return; |
|
} |
|
|
|
int i; |
|
for( i = 0; i < m_CamoPatternNumColors; i++ ) |
|
{ |
|
m_pointsInNormalizedBox[i][0] = random->RandomFloat( m_SubBoundingBoxMin[0], m_SubBoundingBoxMax[0] ); |
|
m_pointsInNormalizedBox[i][1] = random->RandomFloat( m_SubBoundingBoxMin[1], m_SubBoundingBoxMax[1] ); |
|
m_pointsInNormalizedBox[i][2] = random->RandomFloat( m_SubBoundingBoxMin[2], m_SubBoundingBoxMax[2] ); |
|
} |
|
} |
|
|
|
IMaterial *CCamoMaterialProxy::GetMaterial() |
|
{ |
|
return m_pMaterial; |
|
} |
|
|
|
EXPOSE_MATERIAL_PROXY( CCamoMaterialProxy, Camo );
|
|
|