Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

416 lines
10 KiB

//========== Copyright © 2005, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "pch_materialsystem.h"
#ifndef _PS3
#define MATSYS_INTERNAL
#endif
#include "cmaterialsystem.h"
#include "IHardwareConfigInternal.h"
#include "cmatpaintmaps.h"
#include "cmatlightmaps.h"
#include "materialsystem_global.h"
#include "materialsystem/materialsystem_config.h"
#include "itextureinternal.h"
// src/public/
#include "game/shared/portal2/paint_enum.h"
static Color g_PaintColors[PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER];
static void RegisterPaintColors()
{
#if defined ( PORTAL2 )
// These ConVar are defined in src/game/shared/portal/paint_color_manager.cpp
static ConVarRef speed_paint_color( "speed_paint_color" );
static ConVarRef bounce_paint_color( "bounce_paint_color" );
static ConVarRef reflect_paint_color( "reflect_paint_color" );
static ConVarRef portal_paint_color( "portal_paint_color" );
static ConVarRef erase_color( "erase_color" );
g_PaintColors[SPEED_POWER] = speed_paint_color.GetColor();
g_PaintColors[BOUNCE_POWER] = bounce_paint_color.GetColor();
g_PaintColors[PORTAL_POWER] = portal_paint_color.GetColor();
g_PaintColors[REFLECT_POWER] = reflect_paint_color.GetColor();
g_PaintColors[NO_POWER] = erase_color.GetColor();
#endif
}
static const BYTE NUM_ALPHA_BITS = 5;
static const BYTE PAINT_COLOR_BITS = 7 << NUM_ALPHA_BITS; // 224
static const BYTE PAINT_ALPHA_BITS = PAINT_COLOR_BITS ^ 0xFF; // 31
BYTE GetColorIndex( BYTE byte )
{
return ( PAINT_COLOR_BITS & byte ) >> NUM_ALPHA_BITS;
}
inline const Color &GetColor( BYTE byte )
{
BYTE colorIndex = GetColorIndex( byte );
return g_PaintColors[ colorIndex ];
}
inline float GetAlpha( BYTE byte )
{
double alpha = ( PAINT_ALPHA_BITS & byte ); // leave as double to postpone the frsp...
alpha /= PAINT_ALPHA_BITS;
alpha = clamp( alpha, 0.0, 1.0 );
return alpha; // ...to here
}
CMatPaintmaps::CMatPaintmaps( void )
{
m_pDataManager = NULL;
m_nUpdatingPaintmapsStackDepth = 0;
m_nLockedPaintmap = -1;
}
bool CMatPaintmaps::IsEnabled( void )
{
return (m_pDataManager != NULL);
}
void CMatPaintmaps::RegisterPaintmapDataManager( IPaintmapDataManager *pDataManager )
{
m_pDataManager = pDataManager;
RegisterPaintColors();
}
void CMatPaintmaps::BeginPaintTextureAllocation( int iPaintmapCount )
{
CleanupPaintmaps();
m_pDataManager->BeginPaintmapsDataAllocation( iPaintmapCount );
}
void CMatPaintmaps::EndPaintTextureAllocation( void )
{
//do we need to do anything?
}
void CMatPaintmaps::ReleasePaintmaps( void )
{
// clean up paint textures, leave the paint data alone
for( int i = 0; i < m_PaintmapTextureHandles.Count(); i++ )
{
g_pShaderAPI->DeleteTexture( m_PaintmapTextureHandles[i] );
}
m_PaintmapTextureHandles.RemoveAll();
}
void CMatPaintmaps::RestorePaintmaps( int nNumLightmaps )
{
Assert( m_PaintmapTextureHandles.Count() == 0 );
// reallocate + update paint textures
for ( int i=0; i<nNumLightmaps; ++i )
{
int width, height;
m_pDataManager->GetPaintmapSize( i, width, height );
AllocatePaintmapTexture( i, width, height );
}
m_pDataManager->OnRestorePaintmaps();
}
void CMatPaintmaps::CleanupPaintmaps( void )
{
for( int i = 0; i < m_PaintmapTextureHandles.Count(); i++ )
{
g_pShaderAPI->DeleteTexture( m_PaintmapTextureHandles[i] );
}
m_PaintmapTextureHandles.RemoveAll();
if( m_pDataManager )
{
m_pDataManager->DestroyPaintmapsData();
}
}
ShaderAPITextureHandle_t CMatPaintmaps::GetPaintmapPageTextureHandle( int paintmap )
{
//test new texture
if( paintmap >= 0 && paintmap < m_PaintmapTextureHandles.Count() )
{
return m_PaintmapTextureHandles[paintmap];
}
return INVALID_SHADERAPI_TEXTURE_HANDLE;
}
void CMatPaintmaps::BeginUpdatePaintmaps()
{
CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
if ( pCallQueue )
{
pCallQueue->QueueCall( this, &CMatPaintmaps::BeginUpdatePaintmaps );
return;
}
m_nUpdatingPaintmapsStackDepth++;
}
void CMatPaintmaps::FillRect( int paintmap, Rect_t* RESTRICT pRect, BYTE* RESTRICT pPaintData, Rect_t* RESTRICT pSubRect /*= NULL*/ ) RESTRICT
{
VPROF("CMatPaintmaps::FillRect");
int width, height;
m_pDataManager->GetPaintmapSize( paintmap, width, height );
// trap corrupted paint rect
// TODO: Server writing to and Client reading from rect list in paint.cpp in the engine is not threadsafe
if ( pRect->x < 0 || pRect->y < 0 || pRect->x >= width || pRect->y >= height ||
pRect->width < 0 || pRect->height < 0 || pRect->width > width || pRect->height > height ||
pRect->x + pRect->width > width || pRect->y + pRect->height > height )
{
DevWarning( "Corrupted paint rect\n" );
return;
}
int rectOffset[2] = { pRect->x, pRect->y };
if ( pSubRect )
{
rectOffset[0] -= pSubRect->x;
rectOffset[1] -= pSubRect->y;
}
int index;
for( int t = 0; t < pRect->height; ++t )
{
m_PaintmapPixelWriter.Seek( rectOffset[0], rectOffset[1] + t );
index = ( t + pRect->y ) * width;
for( int s = 0; s < pRect->width; ++s )
{
BYTE paintData = pPaintData[index + s + pRect->x];
const Color &color = GetColor( paintData );
float alpha = GetAlpha( paintData );
#ifndef _PS3
m_PaintmapPixelWriter.WritePixel( color.r(), color.g(), color.b(), alpha * 255 );
#else // is PS3
Assert( m_PaintmapPixelWriter.IsUsing16BitFloatFormat() );
m_PaintmapPixelWriter.WritePixelNoAdvance16F(
(float)color.r() / 255.0f,
(float)color.g() / 255.0f,
(float)color.b() / 255.0f,
alpha );
m_PaintmapPixelWriter.SkipPixels(1);
#endif
}
}
}
void CMatPaintmaps::UpdatePaintmap( int paintmap, BYTE* pPaintData, int numRects, Rect_t* pRects )
{
VPROF("CMatPaintmaps::UpdatePaintmap");
if ( paintmap >= GetMaterialSystem()->GetNumLightmapPages() || paintmap < 0 )
{
Error( "CMatPaintmaps::UpdatePaintmap paintmap=%d out of range\n", paintmap );
return;
}
bool bLockSubRect = pRects != NULL;
Rect_t rect;
if ( bLockSubRect )
{
int minX = 512;
int minY = 512;
int maxX = 0;
int maxY = 0;
// find min/max rect
for ( int i=0; i<numRects; ++i )
{
Rect_t* pCurrentRect = &pRects[i];
minX = MIN( pCurrentRect->x, minX );
minY = MIN( pCurrentRect->y, minY );
maxX = MAX( pCurrentRect->x + pCurrentRect->width, maxX );
maxY = MAX( pCurrentRect->y + pCurrentRect->height, maxY );
}
rect.x = minX;
rect.y = minY;
rect.width = maxX - minX;
rect.height = maxY - minY;
}
else
{
rect.x = rect.y = 0;
m_pDataManager->GetPaintmapSize( paintmap, rect.width, rect.height );
}
if ( bLockSubRect )
{
g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
if ( !g_pShaderAPI->TexLock( 0, 0, rect.x, rect.y, rect.width, rect.height, m_PaintmapPixelWriter ) )
{
Assert("Failed to lock paint texture!");
return;
}
}
else
{
if ( !LockPaintmap( paintmap ) )
{
Assert("Failed to lock paint texture!");
return;
}
}
// modify texture!
if ( pRects )
{
for ( int i=0; i<numRects; ++i )
{
FillRect( paintmap, &pRects[i], pPaintData, &rect );
}
}
else
{
FillRect( paintmap, &rect, pPaintData );
}
if ( bLockSubRect )
{
g_pShaderAPI->TexUnlock();
}
}
void CMatPaintmaps::EndUpdatePaintmaps()
{
CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
if ( pCallQueue )
{
pCallQueue->QueueCall( this, &CMatPaintmaps::EndUpdatePaintmaps );
return;
}
m_nUpdatingPaintmapsStackDepth--;
Assert( m_nUpdatingPaintmapsStackDepth >= 0 );
if( m_nUpdatingPaintmapsStackDepth <= 0 && m_nLockedPaintmap != -1 )
{
g_pShaderAPI->TexUnlock();
m_nLockedPaintmap = -1;
}
}
ConVar mat_dynamicPaintmaps( "mat_dynamicPaintmaps", "0", FCVAR_CHEAT );
void CMatPaintmaps::AllocatePaintmapTexture( int paintmap, int iWidth, int iHeight )
{
// allocate paint texture
int flags = 0;
bool bUseDynamicTextures = HardwareConfig()->PreferDynamicTextures() && mat_dynamicPaintmaps.GetBool();
if ( bUseDynamicTextures || IsPS3() ) // On PS3, we need the dynamic flag as a hint that we're going to update this texture incrementally in the future
{
flags |= TEXTURE_CREATE_DYNAMIC;
}
else
{
flags |= TEXTURE_CREATE_MANAGED;
}
//flags |= TEXTUREFLAGS_PROCEDURAL;
m_PaintmapTextureHandles.EnsureCount( paintmap + 1 );
char debugName[256];
Q_snprintf( debugName, sizeof( debugName ), "[paintmap %d]", paintmap );
ImageFormat imageFormat;
#if !defined( _X360 )
imageFormat = IMAGE_FORMAT_RGBA8888;
#else
imageFormat = IMAGE_FORMAT_LINEAR_RGBA8888;
#endif
#ifdef _PS3
// PS3 needs 16F textures...but the HDR_TYPE_FLOAT codepath has a lot of other baggage with it. Just lie here.
imageFormat = IMAGE_FORMAT_RGBA16161616F;
#endif // _PS3
m_PaintmapTextureHandles[paintmap] = g_pShaderAPI->CreateTexture(
iWidth, iHeight, 1,
imageFormat,
1, 1, flags, debugName, TEXTURE_GROUP_LIGHTMAP ); // don't mipmap Paintmaps
Assert( m_PaintmapTextureHandles[paintmap] != INVALID_SHADERAPI_TEXTURE_HANDLE );
// Load up the texture data
g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
// Blat out the paintmap bits
InitPaintmapBits( paintmap );
}
void CMatPaintmaps::AllocatePaintmap( int paintmap, int iWidth, int iHeight )
{
if( !IsEnabled() )
return;
// allocate paint data
m_pDataManager->AllocatePaintmapData( paintmap, iWidth, iHeight );
// allocate paint texture
AllocatePaintmapTexture( paintmap, iWidth, iHeight );
}
void CMatPaintmaps::InitPaintmapBits( int paintmap )
{
CPixelWriter writer;
int width, height;
m_pDataManager->GetPaintmapSize( paintmap, width, height );
g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, width, height, writer ) )
return;
// This always needs to be initialized fully to black
void *pBits = writer.GetPixelMemory();
memset( pBits, 0, width * height * writer.GetPixelSize() );
g_pShaderAPI->TexUnlock();
}
bool CMatPaintmaps::LockPaintmap( int paintmap )
{
if( m_nLockedPaintmap != -1 )
{
g_pShaderAPI->TexUnlock();
}
g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
int width, height;
m_pDataManager->GetPaintmapSize( paintmap, width, height );
if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, width, height, m_PaintmapPixelWriter ) )
{
Assert( 0 );
return false;
}
m_nLockedPaintmap = paintmap;
return true;
}