aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_func_breakablesurf.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_func_breakablesurf.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_func_breakablesurf.cpp')
-rw-r--r--mp/src/game/client/c_func_breakablesurf.cpp2672
1 files changed, 1336 insertions, 1336 deletions
diff --git a/mp/src/game/client/c_func_breakablesurf.cpp b/mp/src/game/client/c_func_breakablesurf.cpp
index a253ba52..03176315 100644
--- a/mp/src/game/client/c_func_breakablesurf.cpp
+++ b/mp/src/game/client/c_func_breakablesurf.cpp
@@ -1,1336 +1,1336 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-#include "cbase.h"
-#include "particles_simple.h"
-#include "iviewrender.h"
-#include "proxyentity.h"
-#include "materialsystem/imaterialvar.h"
-#include "model_types.h"
-#include "engine/ivmodelinfo.h"
-#include "clienteffectprecachesystem.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define MAX_NUM_PANELS 16
-
-extern IVDebugOverlay *debugoverlay;
-
-
-enum WinSide_t
-{
- WIN_SIDE_BOTTOM,
- WIN_SIDE_RIGHT,
- WIN_SIDE_TOP,
- WIN_SIDE_LEFT,
-};
-
-enum WinEdge_t
-{
- EDGE_NOT = -1, // No edge
- EDGE_NONE, /* No edge on both sides /##\ */
- EDGE_FULL, // Edge on both sides |##|
- EDGE_LEFT, /* Edge is on left only |##\ */
- EDGE_RIGHT, // Edge is on right only /##|
-};
-
-#define STYLE_HIGHLIGHT = -1;
-
-#define NUM_EDGE_TYPES 4
-#define NUM_EDGE_STYLES 3
-
-
-//==================================================
-// C_BreakableSurface
-//==================================================
-
-//-----------------------------------------------------------------------------
-// All the information associated with a particular handle
-//-----------------------------------------------------------------------------
-struct Panel_t
-{
- char m_nWidth;
- char m_nHeight;
- char m_nSide;
- char m_nEdgeType;
- char m_nStyle;
-};
-
-struct EdgeTexture_t
-{
- int m_nRenderIndex;
- int m_nStyle;
- CMaterialReference m_pMaterialEdge;
- CTextureReference m_pMaterialEdgeTexture;
-};
-
-// Bits for m_nPanelBits
-#define BITS_PANEL_IS_SOLID (1<<0)
-#define BITS_PANEL_IS_STALE (1<<1)
-
-
-class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer
-{
-public:
- DECLARE_CLIENTCLASS();
- DECLARE_CLASS( C_BreakableSurface, C_BaseEntity );
- DECLARE_DATADESC();
-
- int m_nNumWide;
- int m_nNumHigh;
- float m_flPanelWidth;
- float m_flPanelHeight;
- Vector m_vNormal;
- Vector m_vCorner;
- bool m_bIsBroken;
- int m_nSurfaceType;
-
-
- // This is the texture we're going to use to multiply by the cracked base texture
- ITexture* m_pCurrentDetailTexture;
-
- // Stores linked list of edges to render
- CUtlLinkedList< Panel_t, unsigned short > m_RenderList;
-
-
- C_BreakableSurface();
- ~C_BreakableSurface();
-
-public:
- void InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName);
- virtual void OnDataChanged( DataUpdateType_t updateType );
- virtual void OnPreDataChanged( DataUpdateType_t updateType );
-
- bool IsTransparent( void );
- bool HavePanel(int nWidth, int nHeight);
- bool RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface );
- int DrawModel( int flags );
- void DrawSolidBlocks( IBrushSurface* pBrushSurface );
-
- virtual void OnRestore();
-
- virtual bool ShouldReceiveProjectedTextures( int flags );
-
-private:
- // One bit per pane
- CNetworkArray( bool, m_RawPanelBitVec, MAX_NUM_PANELS * MAX_NUM_PANELS );
- bool m_PrevRawPanelBitVec[ MAX_NUM_PANELS * MAX_NUM_PANELS ];
-
- // 2 bits of flags and 2 bits of edge type
- byte m_nPanelBits[MAX_NUM_PANELS][MAX_NUM_PANELS]; //UNDONE: allocate this dynamically?
- CMaterialReference m_pMaterialBox;
- EdgeTexture_t m_pSolid;
- EdgeTexture_t m_pEdge[NUM_EDGE_TYPES][NUM_EDGE_STYLES];
-
- inline bool InLegalRange(int nWidth, int nHeight);
- inline bool IsPanelSolid(int nWidth, int nHeight);
- inline bool IsPanelStale(int nWidth, int nHeight);
- inline void SetPanelSolid(int nWidth, int nHeight, bool value);
- inline void SetPanelStale(int nWidth, int nHeight, bool value);
-
- void DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
- const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
- void DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
- const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
- void DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vPosition,
- const Vector &vWidth, const Vector &vHeight);
-
- void DrawRenderList( IBrushSurface* pBrushSurface);
- void DrawRenderListHighlights( IBrushSurface* pBrushSurface );
- int FindRenderPanel(int nWidth, int nHeight, WinSide_t nSide);
- void AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle);
- int FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle);
-
- inline void SetStyleType( int w, int h, int type )
- {
- Assert( type < NUM_EDGE_STYLES );
- Assert( type >= 0 );
- // Clear old value
- m_nPanelBits[ w ][ h ] &= ( ~0x03 << 2 );
- // Insert new value
- m_nPanelBits[ w ][ h ] |= ( type << 2 );
- }
-
- inline int GetStyleType( int w, int h )
- {
- int value = m_nPanelBits[ w ][ h ];
- value = ( value >> 2 ) & 0x03;
- Assert( value < NUM_EDGE_STYLES );
- return value;
- }
-
- // Gets at the cracked version of the material
- void FindCrackedMaterial();
-
- CMaterialReference m_pCrackedMaterial;
- CTextureReference m_pMaterialBoxTexture;
-
-
- void UpdateEdgeType(int nWidth, int nHeight, int forceStyle = -1 );
-};
-
-BEGIN_DATADESC( C_BreakableSurface )
-
- DEFINE_ARRAY( m_nPanelBits, FIELD_CHARACTER, MAX_NUM_PANELS * MAX_NUM_PANELS ),
-
-// DEFINE_FIELD( m_nNumWide, FIELD_INTEGER ),
-// DEFINE_FIELD( m_nNumHigh, FIELD_INTEGER ),
-// DEFINE_FIELD( m_flPanelWidth, FIELD_FLOAT ),
-// DEFINE_FIELD( m_flPanelHeight, FIELD_FLOAT ),
-// DEFINE_FIELD( m_vNormal, FIELD_VECTOR ),
-// DEFINE_FIELD( m_vCorner, FIELD_VECTOR ),
-// DEFINE_FIELD( m_bIsBroken, FIELD_BOOLEAN ),
-// DEFINE_FIELD( m_nSurfaceType, FIELD_INTEGER ),
- // DEFINE_FIELD( m_pCurrentDetailTexture, ITexture* ),
- // DEFINE_FIELD( m_RenderList, CUtlLinkedList < Panel_t , unsigned short > ),
- // DEFINE_FIELD( m_pMaterialBox, CMaterialReference ),
- // DEFINE_FIELD( m_pSolid, EdgeTexture_t ),
- // DEFINE_ARRAY( m_pEdge, EdgeTexture_t, NUM_EDGE_TYPES][NUM_EDGE_STYLES ),
- // DEFINE_FIELD( m_pCrackedMaterial, CMaterialReference ),
- // DEFINE_FIELD( m_pMaterialBoxTexture, CTextureReference ),
-
-END_DATADESC()
-
-bool C_BreakableSurface::InLegalRange(int nWidth, int nHeight)
-{
- return (nWidth < m_nNumWide && nHeight < m_nNumHigh &&
- nWidth >=0 && nHeight >= 0 );
-}
-
-bool C_BreakableSurface::IsPanelSolid(int nWidth, int nHeight)
-{
- return ( BITS_PANEL_IS_SOLID & m_nPanelBits[nWidth][nHeight] )!=0 ;
-}
-
-bool C_BreakableSurface::IsPanelStale(int nWidth, int nHeight)
-{
- return ( BITS_PANEL_IS_STALE & m_nPanelBits[nWidth][nHeight] )!=0 ;
-}
-
-void C_BreakableSurface::SetPanelSolid(int nWidth, int nHeight, bool value)
-{
- if ( !InLegalRange( nWidth, nHeight ) )
- return;
-
- if ( value )
- {
- m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_SOLID;
- }
- else
- {
- m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_SOLID;
- }
-}
-
-void C_BreakableSurface::SetPanelStale(int nWidth, int nHeight, bool value)
-{
- if ( !InLegalRange( nWidth, nHeight) )
- return;
-
- if ( value )
- {
- m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_STALE;
- }
- else
- {
- m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_STALE;
- }
-}
-
-void C_BreakableSurface::OnRestore()
-{
- BaseClass::OnRestore();
-
- // FIXME: This restores the general state, but not the random edge bits
- // those would need to be serialized separately...
- // traverse everthing and restore bits
- // Initialize panels
- for (int w=0;w<m_nNumWide;w++)
- {
- for (int h=0;h<m_nNumHigh;h++)
- {
- // Force recomputation
- SetPanelSolid(w,h,IsPanelSolid(w,h));
- SetPanelStale(w,h,true);
- UpdateEdgeType( w, h, GetStyleType(w,h ) );
- }
- }
-}
-
-
-//Receive datatable
-IMPLEMENT_CLIENTCLASS_DT( C_BreakableSurface, DT_BreakableSurface, CBreakableSurface )
- RecvPropInt( RECVINFO( m_nNumWide ) ),
- RecvPropInt( RECVINFO( m_nNumHigh ) ),
- RecvPropFloat( RECVINFO( m_flPanelWidth) ),
- RecvPropFloat( RECVINFO( m_flPanelHeight) ),
- RecvPropVector( RECVINFO( m_vNormal ) ),
- RecvPropVector( RECVINFO( m_vCorner ) ),
- RecvPropInt( RECVINFO( m_bIsBroken )),
- RecvPropInt( RECVINFO( m_nSurfaceType )),
- RecvPropArray3( RECVINFO_ARRAY(m_RawPanelBitVec), RecvPropInt( RECVINFO( m_RawPanelBitVec[ 0 ] ))),
-
-END_RECV_TABLE()
-
-//-----------------------------------------------------------------------------
-// Gets at the cracked version of the material
-//-----------------------------------------------------------------------------
-void C_BreakableSurface::FindCrackedMaterial()
-{
- m_pCrackedMaterial = 0;
-
- // First time we've seen it, get the material on the brush model
- int materialCount = modelinfo->GetModelMaterialCount( const_cast<model_t*>(GetModel()) );
- if( materialCount != 1 )
- {
- Warning( "Encountered func_breakablesurf that has a material applied to more than one surface!\n" );
- m_pCrackedMaterial.Init( "debug/debugempty", TEXTURE_GROUP_OTHER );
- return;
- }
-
- // Get at the first material; even if there are more than one.
- IMaterial* pMaterial;
- modelinfo->GetModelMaterials( const_cast<model_t*>(GetModel()), 1, &pMaterial );
-
- // The material should point to a cracked version of itself
- bool foundVar;
- IMaterialVar* pCrackName = pMaterial->FindVar( "$crackmaterial", &foundVar, false );
- if (foundVar)
- {
- m_pCrackedMaterial.Init( pCrackName->GetStringValue(), TEXTURE_GROUP_CLIENT_EFFECTS );
- }
- else
- {
- m_pCrackedMaterial.Init( pMaterial );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Gets at the base texture
-//-----------------------------------------------------------------------------
-
-static ITexture* GetBaseTexture( IMaterial* pMaterial )
-{
- bool foundVar;
- IMaterialVar* pTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
- if (!foundVar)
- return 0;
-
- return pTextureVar->GetTextureValue();
-}
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName)
-{
- m_pEdge[nEdgeType][nEdgeStyle].m_nRenderIndex = m_RenderList.InvalidIndex();
- m_pEdge[nEdgeType][nEdgeStyle].m_nStyle = nEdgeStyle;
- m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge.Init(pMaterialName, TEXTURE_GROUP_CLIENT_EFFECTS);
- m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdgeTexture.Init( GetBaseTexture( m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge ) );
-}
-
-//-----------------------------------------------------------------------------
-// constructor, destructor
-//-----------------------------------------------------------------------------
-
-C_BreakableSurface::C_BreakableSurface()
-{
- m_vNormal.Init();
- m_vCorner.Init();
- m_bIsBroken = false;
-
- m_pCurrentDetailTexture = NULL;
-
- Q_memset( m_PrevRawPanelBitVec, 0xff, sizeof( m_PrevRawPanelBitVec ) );
-}
-
-C_BreakableSurface::~C_BreakableSurface()
-{
-}
-
-void C_BreakableSurface::OnPreDataChanged( DataUpdateType_t updateType )
-{
- BaseClass::OnPreDataChanged( updateType );
-
- if ( updateType == DATA_UPDATE_CREATED )
- {
- // Initialize panels
- m_nNumWide = MAX_NUM_PANELS;
- m_nNumHigh = MAX_NUM_PANELS;
- for (int w=0;w<MAX_NUM_PANELS;w++)
- {
- for (int h=0;h<MAX_NUM_PANELS;h++)
- {
- SetPanelSolid(w,h,true);
- SetPanelStale(w,h,false);
-
- m_RawPanelBitVec.Set( w + h * MAX_NUM_PANELS, true );
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : bnewentity -
-//-----------------------------------------------------------------------------
-void C_BreakableSurface::OnDataChanged( DataUpdateType_t updateType )
-{
- C_BaseEntity::OnDataChanged( updateType );
-
- if ( updateType == DATA_UPDATE_CREATED )
- {
- // Get at the cracked material
- FindCrackedMaterial();
-
- // Use same solid box for all breakable surfaces
- m_pMaterialBox.Init( "models/brokenglass/glassbroken_solid", TEXTURE_GROUP_MODEL );
- m_pMaterialBoxTexture.Init( GetBaseTexture( m_pMaterialBox ) );
-
- // NOTE: If you add or change this list of materials, change
- // the precache list on func_breakablesurf.cpp on the server.
-
- // Load the edge types and styles for the specific surface type
- if (m_nSurfaceType == SHATTERSURFACE_TILE)
- {
- InitMaterial(EDGE_NONE, 0,"models/brokentile/tilebroken_03a");
- InitMaterial(EDGE_FULL, 0,"models/brokentile/tilebroken_03b");
- InitMaterial(EDGE_LEFT, 0,"models/brokentile/tilebroken_03c");
- InitMaterial(EDGE_RIGHT,0,"models/brokentile/tilebroken_03d");
-
- InitMaterial(EDGE_NONE, 1,"models/brokentile/tilebroken_02a");
- InitMaterial(EDGE_FULL, 1,"models/brokentile/tilebroken_02b");
- InitMaterial(EDGE_LEFT, 1,"models/brokentile/tilebroken_02c");
- InitMaterial(EDGE_RIGHT,1,"models/brokentile/tilebroken_02d");
-
- InitMaterial(EDGE_NONE, 2,"models/brokentile/tilebroken_01a");
- InitMaterial(EDGE_FULL, 2,"models/brokentile/tilebroken_01b");
- InitMaterial(EDGE_LEFT, 2,"models/brokentile/tilebroken_01c");
- InitMaterial(EDGE_RIGHT,2,"models/brokentile/tilebroken_01d");
- }
- else
- {
- InitMaterial(EDGE_NONE, 0,"models/brokenglass/glassbroken_03a");
- InitMaterial(EDGE_FULL, 0,"models/brokenglass/glassbroken_03b");
- InitMaterial(EDGE_LEFT, 0,"models/brokenglass/glassbroken_03c");
- InitMaterial(EDGE_RIGHT,0,"models/brokenglass/glassbroken_03d");
-
- InitMaterial(EDGE_NONE, 1,"models/brokenglass/glassbroken_02a");
- InitMaterial(EDGE_FULL, 1,"models/brokenglass/glassbroken_02b");
- InitMaterial(EDGE_LEFT, 1,"models/brokenglass/glassbroken_02c");
- InitMaterial(EDGE_RIGHT,1,"models/brokenglass/glassbroken_02d");
-
- InitMaterial(EDGE_NONE, 2,"models/brokenglass/glassbroken_01a");
- InitMaterial(EDGE_FULL, 2,"models/brokenglass/glassbroken_01b");
- InitMaterial(EDGE_LEFT, 2,"models/brokenglass/glassbroken_01c");
- InitMaterial(EDGE_RIGHT,2,"models/brokenglass/glassbroken_01d");
- }
- }
-
- bool changed = false;
-
- for ( int j = 0; j < m_nNumHigh; j++ )
- {
- for ( int i = 0; i < m_nNumWide; i++ )
- {
- int offset = i + j * m_nNumWide;
-
- bool newVal = m_RawPanelBitVec[ offset ];
- bool oldVal = m_PrevRawPanelBitVec[ offset ];
-
- if ( newVal != oldVal )
- {
- changed = true;
- }
-
- SetPanelSolid(i,j,newVal);
-
- if ( !newVal && changed )
- {
-
- // Mark these panels and being stale (need edge type updated)
- // We update them in one fell swoop rather than as each panel
- // is updated, so we don't have to do duplicate operations
- SetPanelStale(i, j ,true);
- SetPanelStale(i, j+1,true);
- SetPanelStale(i, j-1,true);
- SetPanelStale(i-1, j ,true);
- SetPanelStale(i+1, j ,true);
- SetPanelStale(i+1, j+1,true);
- SetPanelStale(i-1, j+1,true);
- SetPanelStale(i+1, j-1,true);
- SetPanelStale(i-1, j-1,true);
- }
- }
- }
-
- if ( changed )
- {
- for (int width=0;width<m_nNumWide;width++)
- {
- for (int height=0;height<m_nNumHigh;height++)
- {
- if ( IsPanelStale(width,height) )
- {
- UpdateEdgeType( width, height );
- }
- }
- }
- }
-
- Q_memcpy( m_PrevRawPanelBitVec, m_RawPanelBitVec.Base(), sizeof( m_PrevRawPanelBitVec ) );
-}
-
-bool C_BreakableSurface::IsTransparent( void )
-{
- // Not an identity brush if it's broken
- if (m_bIsBroken)
- return true;
-
- return C_BaseEntity::IsTransparent();
-}
-
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-int C_BreakableSurface::DrawModel( int flags )
-{
- if ( !m_bReadyToDraw )
- return 0;
-
- // If I'm not broken draw normally
- if (m_bIsBroken)
- render->InstallBrushSurfaceRenderer( this );
-
- // If it's broken, always draw it translucent
- BaseClass::DrawModel( m_bIsBroken ? flags | STUDIO_TRANSPARENCY : flags );
-
- // Remove our nonstandard brush surface renderer...
- render->InstallBrushSurfaceRenderer( 0 );
-
- return 0;
-}
-
-bool C_BreakableSurface::RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface )
-{
- // If tile draw highlight for grout
- if (m_nSurfaceType == SHATTERSURFACE_TILE)
- {
- DrawRenderListHighlights(pBrushSurface);
- }
- DrawSolidBlocks(pBrushSurface);
- DrawRenderList(pBrushSurface);
-
- // Don't draw decals
- return false;
-}
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawRenderList(IBrushSurface* pBrushSurface)
-{
- // Get width and height steps
- QAngle vAngles;
- VectorAngles(-1*m_vNormal,vAngles);
- Vector vWidthStep,vHeightStep;
- AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
- vWidthStep *= m_flPanelWidth;
- vHeightStep *= m_flPanelHeight;
-
- CMeshBuilder pMeshBuilder;
- IMesh* pMesh = NULL;
- int nCurStyle = -1;
- int nCurEdgeType = -1;
- CMatRenderContextPtr pRenderContext( materials );
- for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
- {
-
- if (nCurStyle != m_RenderList[i].m_nStyle ||
- nCurEdgeType != m_RenderList[i].m_nEdgeType )
- {
- nCurStyle = m_RenderList[i].m_nStyle;
- nCurEdgeType = m_RenderList[i].m_nEdgeType;
-
- m_pCurrentDetailTexture = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdgeTexture;
- pRenderContext->Flush(false);
- pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
- pMesh = pRenderContext->GetDynamicMesh( );
- }
-
- Vector vRenderPos = m_vCorner +
- (m_RenderList[i].m_nWidth*vWidthStep) +
- (m_RenderList[i].m_nHeight*vHeightStep);
-
- DrawOneEdge(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
- }
-}
-
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawRenderListHighlights(IBrushSurface* pBrushSurface)
-{
- // Get width and height steps
- QAngle vAngles;
- VectorAngles(-1*m_vNormal,vAngles);
- Vector vWidthStep,vHeightStep;
- AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
- vWidthStep *= m_flPanelWidth;
- vHeightStep *= m_flPanelHeight;
-
-
- CMeshBuilder pMeshBuilder;
- IMesh* pMesh = NULL;
- int nCurStyle = -1;
- int nCurEdgeType = -1;
- CMatRenderContextPtr pRenderContext( materials );
- for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
- {
-
- if (nCurStyle != m_RenderList[i].m_nStyle ||
- nCurEdgeType != m_RenderList[i].m_nEdgeType )
- {
- nCurStyle = m_RenderList[i].m_nStyle;
- nCurEdgeType = m_RenderList[i].m_nEdgeType;
-
- IMaterial *pMat = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdge;
- pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat );
- }
-
- Vector vRenderPos = m_vCorner +
- (m_RenderList[i].m_nWidth*vWidthStep) +
- (m_RenderList[i].m_nHeight*vHeightStep) +
- (0.30*m_vNormal);
-
- DrawOneHighlight(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
- }
-}
-
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-bool C_BreakableSurface::HavePanel(int nWidth, int nHeight)
-{
- // If I'm off the edge, always give support
- if (!InLegalRange(nWidth,nHeight))
- {
- return true;
- }
- return (IsPanelSolid(nWidth,nHeight));
-}
-
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::UpdateEdgeType(int nWidth, int nHeight, int forceStyle /*=-1*/ )
-{
- Assert( forceStyle < NUM_EDGE_STYLES );
-
- // -----------------------------------
- // Check edge conditions
- // -----------------------------------
- if (!InLegalRange(nWidth,nHeight))
- {
- return;
- }
-
- // ----------------------------------
- // If solid has no edges
- // ----------------------------------
- if (IsPanelSolid(nWidth,nHeight))
- {
- return;
- }
-
- // Panel is no longer stale
- SetPanelStale(nWidth, nHeight,false);
-
- // ----------------------------------
- // Set edge type base on neighbors
- // ----------------------------------
- bool bUp = HavePanel(nWidth, nHeight+1);
- bool bDown = HavePanel(nWidth, nHeight-1);
- bool bLeft = HavePanel(nWidth-1, nHeight );
- bool bRight = HavePanel(nWidth+1, nHeight );
-
- bool bUpLeft = HavePanel(nWidth-1, nHeight+1);
- bool bUpRight = HavePanel(nWidth+1, nHeight+1);
- bool bDownLeft = HavePanel(nWidth-1, nHeight-1);
- bool bDownRight = HavePanel(nWidth+1, nHeight-1);
-
- //-------------
- // Top
- //-------------
- if (bUp)
- {
- bool bLeftEdge = !bLeft && bUpLeft;
- bool bRightEdge = !bRight && bUpRight;
-
- if (bLeftEdge && bRightEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_FULL, forceStyle );
- }
- else if (bLeftEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_LEFT, forceStyle );
- }
- else if (bRightEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_RIGHT, forceStyle );
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NONE, forceStyle );
- }
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NOT, forceStyle );
- }
- //-------------
- // Bottom
- //-------------
- if (bDown)
- {
- bool bLeftEdge = !bLeft && bDownLeft;
- bool bRightEdge = !bRight && bDownRight;
-
- if (bLeftEdge && bRightEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_FULL, forceStyle );
- }
- else if (bLeftEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_RIGHT, forceStyle );
- }
- else if (bRightEdge)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_LEFT, forceStyle );
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NONE, forceStyle );
- }
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NOT, forceStyle );
- }
- //-------------
- // Left
- //-------------
- if (bLeft)
- {
- bool bTop = !bUp && bUpLeft;
- bool bBottom = !bDown && bDownLeft;
-
- if (bTop && bBottom)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_FULL, forceStyle );
- }
- else if (bTop)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_RIGHT, forceStyle );
- }
- else if (bBottom)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_LEFT, forceStyle );
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NONE, forceStyle );
- }
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NOT, forceStyle );
- }
- //-------------
- // Right
- //-------------
- if (bRight)
- {
- bool bTop = !bUp && bUpRight;
- bool bBottom = !bDown && bDownRight;
-
- if (bTop && bBottom)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_FULL, forceStyle );
- }
- else if (bTop)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_LEFT, forceStyle );
- }
- else if (bBottom)
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_RIGHT, forceStyle );
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NONE, forceStyle );
- }
- }
- else
- {
- AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NOT, forceStyle );
- }
-}
-
-//--------------------------------------------------------------------------------
-// Purpose : Return index to panel in render list that meets these qualifications
-// Input :
-// Output :
-//--------------------------------------------------------------------------------
-int C_BreakableSurface::FindRenderPanel(int nWidth, int nHeight, WinSide_t nWinSide)
-{
- for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
- {
- if (m_RenderList[i].m_nSide == nWinSide &&
- m_RenderList[i].m_nWidth == nWidth &&
- m_RenderList[i].m_nHeight == nHeight)
- {
- return i;
- }
- }
- return m_RenderList.InvalidIndex();
-}
-
-//----------------------------------------------------------------------------------
-// Purpose : Returns first element in render list with the same edge type and style
-// Input :
-// Output :
-//----------------------------------------------------------------------------------
-int C_BreakableSurface::FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle)
-{
- for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
- {
- if (m_RenderList[i].m_nStyle == nStyle &&
- m_RenderList[i].m_nEdgeType == nEdgeType )
- {
- return i;
- }
- }
- return m_RenderList.InvalidIndex();
-}
-
-//------------------------------------------------------------------------------
-// Purpose : Add a edge to be rendered to the render list
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle )
-{
- // -----------------------------------------------------
- // Try to find old panel
- int nOldPanelIndex = FindRenderPanel(nWidth,nHeight,nSide);
-
- // -----------------------------------------------------
- // If I have an old panel, get it's style and remove it
- // otherwise randomly chose a style
- int nStyle;
- if (m_RenderList.IsValidIndex(nOldPanelIndex) )
- {
- nStyle = m_RenderList[nOldPanelIndex].m_nStyle;
- m_RenderList.Remove(nOldPanelIndex);
- }
- else
- {
- nStyle = random->RandomInt(0,NUM_EDGE_STYLES-1);
- }
-
- if ( forceStyle != -1 )
- {
- nStyle = forceStyle;
- }
-
- // -----------------------------------------------------
- // If my new panel has an edge, add it to render list
- if (nEdgeType != EDGE_NOT)
- {
- // Renderlist is sorted by texture type. Find first element
- // that shares the same texture as the new panel
- unsigned short nTexIndex = FindFirstRenderTexture(nEdgeType, nStyle);
-
- // If texture was already in list, add after last use
- unsigned short nNewIndex;
- if (m_RenderList.IsValidIndex(nTexIndex))
- {
- nNewIndex = m_RenderList.InsertAfter(nTexIndex);
- }
- // Otherwise add to send of render list
- else
- {
- nNewIndex = m_RenderList.AddToTail();
- }
-
- // Now fill out my data
- m_RenderList[nNewIndex].m_nHeight = nHeight;
- m_RenderList[nNewIndex].m_nWidth = nWidth;
- m_RenderList[nNewIndex].m_nEdgeType = nEdgeType;
- m_RenderList[nNewIndex].m_nSide = nSide;
- m_RenderList[nNewIndex].m_nStyle = nStyle;
-
- Assert( nStyle < NUM_EDGE_STYLES );
- SetStyleType( nWidth, nHeight, nStyle );
- }
-}
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawSolidBlocks(IBrushSurface* pBrushSurface)
-{
- CMatRenderContextPtr pRenderContext( materials );
-
- m_pCurrentDetailTexture = m_pMaterialBoxTexture;
-
- // Gotta flush (in a non-stalling way) because we effectively
- // have a new material due to the new base texture
- pRenderContext->Flush(false);
- pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
- CMeshBuilder pMeshBuilder;
-
- // ---------------
- // Create panels
- // ---------------
- QAngle vAngles;
- VectorAngles(-1*m_vNormal,vAngles);
- Vector vWidthStep,vHeightStep;
- AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
- vWidthStep *= m_flPanelWidth;
- vHeightStep *= m_flPanelHeight;
-
- Vector vCurPos = m_vCorner;
- for (int width=0;width<m_nNumWide;width++)
- {
- int height;
- int nHCount = 0;
- for (height=0;height<m_nNumHigh;height++)
- {
- // Keep count of how many panes there are in a row
- if (IsPanelSolid(width,height))
- {
- nHCount++;
- }
-
- // Drow the strip and start counting again
- else if (nHCount > 0)
- {
- vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
- DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
- nHCount = 0;
- }
- }
- if (nHCount)
- {
- vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
- DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vCurPos, const Vector &vWidthStep,
- const Vector &vHeightStep)
-{
- pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
-
- Vector2D texCoord, lightCoord;
- pBrushSurface->ComputeTextureCoordinate( vCurPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vCurPos, lightCoord );
-
- pMeshBuilder->Position3f( vCurPos.x, vCurPos.y, vCurPos.z );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2f( 0, 0, 1 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->AdvanceVertex();
-
- Vector vNextPos = vCurPos + vWidthStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2f( 0, 0, 0 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos + vHeightStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x , vNextPos.y, vNextPos.z );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2f( 0, 1, 0 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos - vWidthStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y , vNextPos.z);
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2f( 0, 1, 1 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->AdvanceVertex();
-
- pMeshBuilder->End();
- pMesh->Draw();
-}
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
- const Vector &vHStep, WinSide_t nEdge )
-{
- pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
-
- Vector2D texCoord, lightCoord;
- pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
-
- pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- Vector vNextPos = vStartPos + vWStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos + vHStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos - vWStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4ub( 255, 255, 255, 255 );
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- pMeshBuilder->End();
- pMesh->Draw();
-}
-
-
-
-
-//------------------------------------------------------------------------------
-// Purpose :
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void C_BreakableSurface::DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
- CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
- const Vector &vHStep, WinSide_t nEdge )
-{
- Vector vColor = Vector(0.41,0.35,0.24);
-
- pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
-
- Vector2D texCoord, lightCoord;
- pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
-
- pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- Vector vNextPos = vStartPos + vWStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos + vHStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- vNextPos = vNextPos - vWStep;
-
- pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
- pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
-
- pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
- pMeshBuilder->Normal3fv( m_vNormal.Base() );
- pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
- pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
- switch (nEdge)
- {
- case WIN_SIDE_RIGHT:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
- break;
- case WIN_SIDE_BOTTOM:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
- break;
- case WIN_SIDE_LEFT:
- pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
- break;
- case WIN_SIDE_TOP:
- pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
- break;
- }
- pMeshBuilder->AdvanceVertex();
-
- pMeshBuilder->End();
- pMesh->Draw();
-}
-
-bool C_BreakableSurface::ShouldReceiveProjectedTextures( int flags )
-{
- return false;
-}
-
-
-//------------------------------------------------------------------------------
-// A material proxy that resets the texture to use the original surface texture
-//------------------------------------------------------------------------------
-class CBreakableSurfaceProxy : public CEntityMaterialProxy
-{
-public:
- CBreakableSurfaceProxy();
- virtual ~CBreakableSurfaceProxy();
- virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
- virtual void OnBind( C_BaseEntity *pC_BaseEntity );
- virtual IMaterial *GetMaterial();
-
-private:
- // get at the material whose texture we're going to steal
- void AcquireSourceMaterial( C_BaseEntity* pEnt );
-
- IMaterialVar* m_BaseTextureVar;
-};
-
-CBreakableSurfaceProxy::CBreakableSurfaceProxy()
-{
- m_BaseTextureVar = NULL;
-}
-
-CBreakableSurfaceProxy::~CBreakableSurfaceProxy()
-{
-}
-
-
-bool CBreakableSurfaceProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
-{
- bool foundVar;
- m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
- return foundVar;
-}
-
-void CBreakableSurfaceProxy::OnBind( C_BaseEntity *pC_BaseEntity )
-{
- C_BreakableSurface *pEnt = dynamic_cast< C_BreakableSurface * >(pC_BaseEntity);
- if( !pEnt )
- {
- return;
- }
-
- // Use the current base texture specified by the suface
- m_BaseTextureVar->SetTextureValue( pEnt->m_pCurrentDetailTexture );
-}
-
-IMaterial *CBreakableSurfaceProxy::GetMaterial()
-{
- if ( !m_BaseTextureVar )
- return NULL;
-
- return m_BaseTextureVar->GetOwningMaterial();
-}
-
-EXPOSE_INTERFACE( CBreakableSurfaceProxy, IMaterialProxy, "BreakableSurface" IMATERIAL_PROXY_INTERFACE_VERSION );
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "particles_simple.h"
+#include "iviewrender.h"
+#include "proxyentity.h"
+#include "materialsystem/imaterialvar.h"
+#include "model_types.h"
+#include "engine/ivmodelinfo.h"
+#include "clienteffectprecachesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define MAX_NUM_PANELS 16
+
+extern IVDebugOverlay *debugoverlay;
+
+
+enum WinSide_t
+{
+ WIN_SIDE_BOTTOM,
+ WIN_SIDE_RIGHT,
+ WIN_SIDE_TOP,
+ WIN_SIDE_LEFT,
+};
+
+enum WinEdge_t
+{
+ EDGE_NOT = -1, // No edge
+ EDGE_NONE, /* No edge on both sides /##\ */
+ EDGE_FULL, // Edge on both sides |##|
+ EDGE_LEFT, /* Edge is on left only |##\ */
+ EDGE_RIGHT, // Edge is on right only /##|
+};
+
+#define STYLE_HIGHLIGHT = -1;
+
+#define NUM_EDGE_TYPES 4
+#define NUM_EDGE_STYLES 3
+
+
+//==================================================
+// C_BreakableSurface
+//==================================================
+
+//-----------------------------------------------------------------------------
+// All the information associated with a particular handle
+//-----------------------------------------------------------------------------
+struct Panel_t
+{
+ char m_nWidth;
+ char m_nHeight;
+ char m_nSide;
+ char m_nEdgeType;
+ char m_nStyle;
+};
+
+struct EdgeTexture_t
+{
+ int m_nRenderIndex;
+ int m_nStyle;
+ CMaterialReference m_pMaterialEdge;
+ CTextureReference m_pMaterialEdgeTexture;
+};
+
+// Bits for m_nPanelBits
+#define BITS_PANEL_IS_SOLID (1<<0)
+#define BITS_PANEL_IS_STALE (1<<1)
+
+
+class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer
+{
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_CLASS( C_BreakableSurface, C_BaseEntity );
+ DECLARE_DATADESC();
+
+ int m_nNumWide;
+ int m_nNumHigh;
+ float m_flPanelWidth;
+ float m_flPanelHeight;
+ Vector m_vNormal;
+ Vector m_vCorner;
+ bool m_bIsBroken;
+ int m_nSurfaceType;
+
+
+ // This is the texture we're going to use to multiply by the cracked base texture
+ ITexture* m_pCurrentDetailTexture;
+
+ // Stores linked list of edges to render
+ CUtlLinkedList< Panel_t, unsigned short > m_RenderList;
+
+
+ C_BreakableSurface();
+ ~C_BreakableSurface();
+
+public:
+ void InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName);
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void OnPreDataChanged( DataUpdateType_t updateType );
+
+ bool IsTransparent( void );
+ bool HavePanel(int nWidth, int nHeight);
+ bool RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface );
+ int DrawModel( int flags );
+ void DrawSolidBlocks( IBrushSurface* pBrushSurface );
+
+ virtual void OnRestore();
+
+ virtual bool ShouldReceiveProjectedTextures( int flags );
+
+private:
+ // One bit per pane
+ CNetworkArray( bool, m_RawPanelBitVec, MAX_NUM_PANELS * MAX_NUM_PANELS );
+ bool m_PrevRawPanelBitVec[ MAX_NUM_PANELS * MAX_NUM_PANELS ];
+
+ // 2 bits of flags and 2 bits of edge type
+ byte m_nPanelBits[MAX_NUM_PANELS][MAX_NUM_PANELS]; //UNDONE: allocate this dynamically?
+ CMaterialReference m_pMaterialBox;
+ EdgeTexture_t m_pSolid;
+ EdgeTexture_t m_pEdge[NUM_EDGE_TYPES][NUM_EDGE_STYLES];
+
+ inline bool InLegalRange(int nWidth, int nHeight);
+ inline bool IsPanelSolid(int nWidth, int nHeight);
+ inline bool IsPanelStale(int nWidth, int nHeight);
+ inline void SetPanelSolid(int nWidth, int nHeight, bool value);
+ inline void SetPanelStale(int nWidth, int nHeight, bool value);
+
+ void DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
+ const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
+ void DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
+ const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
+ void DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vPosition,
+ const Vector &vWidth, const Vector &vHeight);
+
+ void DrawRenderList( IBrushSurface* pBrushSurface);
+ void DrawRenderListHighlights( IBrushSurface* pBrushSurface );
+ int FindRenderPanel(int nWidth, int nHeight, WinSide_t nSide);
+ void AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle);
+ int FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle);
+
+ inline void SetStyleType( int w, int h, int type )
+ {
+ Assert( type < NUM_EDGE_STYLES );
+ Assert( type >= 0 );
+ // Clear old value
+ m_nPanelBits[ w ][ h ] &= ( ~0x03 << 2 );
+ // Insert new value
+ m_nPanelBits[ w ][ h ] |= ( type << 2 );
+ }
+
+ inline int GetStyleType( int w, int h )
+ {
+ int value = m_nPanelBits[ w ][ h ];
+ value = ( value >> 2 ) & 0x03;
+ Assert( value < NUM_EDGE_STYLES );
+ return value;
+ }
+
+ // Gets at the cracked version of the material
+ void FindCrackedMaterial();
+
+ CMaterialReference m_pCrackedMaterial;
+ CTextureReference m_pMaterialBoxTexture;
+
+
+ void UpdateEdgeType(int nWidth, int nHeight, int forceStyle = -1 );
+};
+
+BEGIN_DATADESC( C_BreakableSurface )
+
+ DEFINE_ARRAY( m_nPanelBits, FIELD_CHARACTER, MAX_NUM_PANELS * MAX_NUM_PANELS ),
+
+// DEFINE_FIELD( m_nNumWide, FIELD_INTEGER ),
+// DEFINE_FIELD( m_nNumHigh, FIELD_INTEGER ),
+// DEFINE_FIELD( m_flPanelWidth, FIELD_FLOAT ),
+// DEFINE_FIELD( m_flPanelHeight, FIELD_FLOAT ),
+// DEFINE_FIELD( m_vNormal, FIELD_VECTOR ),
+// DEFINE_FIELD( m_vCorner, FIELD_VECTOR ),
+// DEFINE_FIELD( m_bIsBroken, FIELD_BOOLEAN ),
+// DEFINE_FIELD( m_nSurfaceType, FIELD_INTEGER ),
+ // DEFINE_FIELD( m_pCurrentDetailTexture, ITexture* ),
+ // DEFINE_FIELD( m_RenderList, CUtlLinkedList < Panel_t , unsigned short > ),
+ // DEFINE_FIELD( m_pMaterialBox, CMaterialReference ),
+ // DEFINE_FIELD( m_pSolid, EdgeTexture_t ),
+ // DEFINE_ARRAY( m_pEdge, EdgeTexture_t, NUM_EDGE_TYPES][NUM_EDGE_STYLES ),
+ // DEFINE_FIELD( m_pCrackedMaterial, CMaterialReference ),
+ // DEFINE_FIELD( m_pMaterialBoxTexture, CTextureReference ),
+
+END_DATADESC()
+
+bool C_BreakableSurface::InLegalRange(int nWidth, int nHeight)
+{
+ return (nWidth < m_nNumWide && nHeight < m_nNumHigh &&
+ nWidth >=0 && nHeight >= 0 );
+}
+
+bool C_BreakableSurface::IsPanelSolid(int nWidth, int nHeight)
+{
+ return ( BITS_PANEL_IS_SOLID & m_nPanelBits[nWidth][nHeight] )!=0 ;
+}
+
+bool C_BreakableSurface::IsPanelStale(int nWidth, int nHeight)
+{
+ return ( BITS_PANEL_IS_STALE & m_nPanelBits[nWidth][nHeight] )!=0 ;
+}
+
+void C_BreakableSurface::SetPanelSolid(int nWidth, int nHeight, bool value)
+{
+ if ( !InLegalRange( nWidth, nHeight ) )
+ return;
+
+ if ( value )
+ {
+ m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_SOLID;
+ }
+ else
+ {
+ m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_SOLID;
+ }
+}
+
+void C_BreakableSurface::SetPanelStale(int nWidth, int nHeight, bool value)
+{
+ if ( !InLegalRange( nWidth, nHeight) )
+ return;
+
+ if ( value )
+ {
+ m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_STALE;
+ }
+ else
+ {
+ m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_STALE;
+ }
+}
+
+void C_BreakableSurface::OnRestore()
+{
+ BaseClass::OnRestore();
+
+ // FIXME: This restores the general state, but not the random edge bits
+ // those would need to be serialized separately...
+ // traverse everthing and restore bits
+ // Initialize panels
+ for (int w=0;w<m_nNumWide;w++)
+ {
+ for (int h=0;h<m_nNumHigh;h++)
+ {
+ // Force recomputation
+ SetPanelSolid(w,h,IsPanelSolid(w,h));
+ SetPanelStale(w,h,true);
+ UpdateEdgeType( w, h, GetStyleType(w,h ) );
+ }
+ }
+}
+
+
+//Receive datatable
+IMPLEMENT_CLIENTCLASS_DT( C_BreakableSurface, DT_BreakableSurface, CBreakableSurface )
+ RecvPropInt( RECVINFO( m_nNumWide ) ),
+ RecvPropInt( RECVINFO( m_nNumHigh ) ),
+ RecvPropFloat( RECVINFO( m_flPanelWidth) ),
+ RecvPropFloat( RECVINFO( m_flPanelHeight) ),
+ RecvPropVector( RECVINFO( m_vNormal ) ),
+ RecvPropVector( RECVINFO( m_vCorner ) ),
+ RecvPropInt( RECVINFO( m_bIsBroken )),
+ RecvPropInt( RECVINFO( m_nSurfaceType )),
+ RecvPropArray3( RECVINFO_ARRAY(m_RawPanelBitVec), RecvPropInt( RECVINFO( m_RawPanelBitVec[ 0 ] ))),
+
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Gets at the cracked version of the material
+//-----------------------------------------------------------------------------
+void C_BreakableSurface::FindCrackedMaterial()
+{
+ m_pCrackedMaterial = 0;
+
+ // First time we've seen it, get the material on the brush model
+ int materialCount = modelinfo->GetModelMaterialCount( const_cast<model_t*>(GetModel()) );
+ if( materialCount != 1 )
+ {
+ Warning( "Encountered func_breakablesurf that has a material applied to more than one surface!\n" );
+ m_pCrackedMaterial.Init( "debug/debugempty", TEXTURE_GROUP_OTHER );
+ return;
+ }
+
+ // Get at the first material; even if there are more than one.
+ IMaterial* pMaterial;
+ modelinfo->GetModelMaterials( const_cast<model_t*>(GetModel()), 1, &pMaterial );
+
+ // The material should point to a cracked version of itself
+ bool foundVar;
+ IMaterialVar* pCrackName = pMaterial->FindVar( "$crackmaterial", &foundVar, false );
+ if (foundVar)
+ {
+ m_pCrackedMaterial.Init( pCrackName->GetStringValue(), TEXTURE_GROUP_CLIENT_EFFECTS );
+ }
+ else
+ {
+ m_pCrackedMaterial.Init( pMaterial );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at the base texture
+//-----------------------------------------------------------------------------
+
+static ITexture* GetBaseTexture( IMaterial* pMaterial )
+{
+ bool foundVar;
+ IMaterialVar* pTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
+ if (!foundVar)
+ return 0;
+
+ return pTextureVar->GetTextureValue();
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName)
+{
+ m_pEdge[nEdgeType][nEdgeStyle].m_nRenderIndex = m_RenderList.InvalidIndex();
+ m_pEdge[nEdgeType][nEdgeStyle].m_nStyle = nEdgeStyle;
+ m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge.Init(pMaterialName, TEXTURE_GROUP_CLIENT_EFFECTS);
+ m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdgeTexture.Init( GetBaseTexture( m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge ) );
+}
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+C_BreakableSurface::C_BreakableSurface()
+{
+ m_vNormal.Init();
+ m_vCorner.Init();
+ m_bIsBroken = false;
+
+ m_pCurrentDetailTexture = NULL;
+
+ Q_memset( m_PrevRawPanelBitVec, 0xff, sizeof( m_PrevRawPanelBitVec ) );
+}
+
+C_BreakableSurface::~C_BreakableSurface()
+{
+}
+
+void C_BreakableSurface::OnPreDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnPreDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ // Initialize panels
+ m_nNumWide = MAX_NUM_PANELS;
+ m_nNumHigh = MAX_NUM_PANELS;
+ for (int w=0;w<MAX_NUM_PANELS;w++)
+ {
+ for (int h=0;h<MAX_NUM_PANELS;h++)
+ {
+ SetPanelSolid(w,h,true);
+ SetPanelStale(w,h,false);
+
+ m_RawPanelBitVec.Set( w + h * MAX_NUM_PANELS, true );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_BreakableSurface::OnDataChanged( DataUpdateType_t updateType )
+{
+ C_BaseEntity::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ // Get at the cracked material
+ FindCrackedMaterial();
+
+ // Use same solid box for all breakable surfaces
+ m_pMaterialBox.Init( "models/brokenglass/glassbroken_solid", TEXTURE_GROUP_MODEL );
+ m_pMaterialBoxTexture.Init( GetBaseTexture( m_pMaterialBox ) );
+
+ // NOTE: If you add or change this list of materials, change
+ // the precache list on func_breakablesurf.cpp on the server.
+
+ // Load the edge types and styles for the specific surface type
+ if (m_nSurfaceType == SHATTERSURFACE_TILE)
+ {
+ InitMaterial(EDGE_NONE, 0,"models/brokentile/tilebroken_03a");
+ InitMaterial(EDGE_FULL, 0,"models/brokentile/tilebroken_03b");
+ InitMaterial(EDGE_LEFT, 0,"models/brokentile/tilebroken_03c");
+ InitMaterial(EDGE_RIGHT,0,"models/brokentile/tilebroken_03d");
+
+ InitMaterial(EDGE_NONE, 1,"models/brokentile/tilebroken_02a");
+ InitMaterial(EDGE_FULL, 1,"models/brokentile/tilebroken_02b");
+ InitMaterial(EDGE_LEFT, 1,"models/brokentile/tilebroken_02c");
+ InitMaterial(EDGE_RIGHT,1,"models/brokentile/tilebroken_02d");
+
+ InitMaterial(EDGE_NONE, 2,"models/brokentile/tilebroken_01a");
+ InitMaterial(EDGE_FULL, 2,"models/brokentile/tilebroken_01b");
+ InitMaterial(EDGE_LEFT, 2,"models/brokentile/tilebroken_01c");
+ InitMaterial(EDGE_RIGHT,2,"models/brokentile/tilebroken_01d");
+ }
+ else
+ {
+ InitMaterial(EDGE_NONE, 0,"models/brokenglass/glassbroken_03a");
+ InitMaterial(EDGE_FULL, 0,"models/brokenglass/glassbroken_03b");
+ InitMaterial(EDGE_LEFT, 0,"models/brokenglass/glassbroken_03c");
+ InitMaterial(EDGE_RIGHT,0,"models/brokenglass/glassbroken_03d");
+
+ InitMaterial(EDGE_NONE, 1,"models/brokenglass/glassbroken_02a");
+ InitMaterial(EDGE_FULL, 1,"models/brokenglass/glassbroken_02b");
+ InitMaterial(EDGE_LEFT, 1,"models/brokenglass/glassbroken_02c");
+ InitMaterial(EDGE_RIGHT,1,"models/brokenglass/glassbroken_02d");
+
+ InitMaterial(EDGE_NONE, 2,"models/brokenglass/glassbroken_01a");
+ InitMaterial(EDGE_FULL, 2,"models/brokenglass/glassbroken_01b");
+ InitMaterial(EDGE_LEFT, 2,"models/brokenglass/glassbroken_01c");
+ InitMaterial(EDGE_RIGHT,2,"models/brokenglass/glassbroken_01d");
+ }
+ }
+
+ bool changed = false;
+
+ for ( int j = 0; j < m_nNumHigh; j++ )
+ {
+ for ( int i = 0; i < m_nNumWide; i++ )
+ {
+ int offset = i + j * m_nNumWide;
+
+ bool newVal = m_RawPanelBitVec[ offset ];
+ bool oldVal = m_PrevRawPanelBitVec[ offset ];
+
+ if ( newVal != oldVal )
+ {
+ changed = true;
+ }
+
+ SetPanelSolid(i,j,newVal);
+
+ if ( !newVal && changed )
+ {
+
+ // Mark these panels and being stale (need edge type updated)
+ // We update them in one fell swoop rather than as each panel
+ // is updated, so we don't have to do duplicate operations
+ SetPanelStale(i, j ,true);
+ SetPanelStale(i, j+1,true);
+ SetPanelStale(i, j-1,true);
+ SetPanelStale(i-1, j ,true);
+ SetPanelStale(i+1, j ,true);
+ SetPanelStale(i+1, j+1,true);
+ SetPanelStale(i-1, j+1,true);
+ SetPanelStale(i+1, j-1,true);
+ SetPanelStale(i-1, j-1,true);
+ }
+ }
+ }
+
+ if ( changed )
+ {
+ for (int width=0;width<m_nNumWide;width++)
+ {
+ for (int height=0;height<m_nNumHigh;height++)
+ {
+ if ( IsPanelStale(width,height) )
+ {
+ UpdateEdgeType( width, height );
+ }
+ }
+ }
+ }
+
+ Q_memcpy( m_PrevRawPanelBitVec, m_RawPanelBitVec.Base(), sizeof( m_PrevRawPanelBitVec ) );
+}
+
+bool C_BreakableSurface::IsTransparent( void )
+{
+ // Not an identity brush if it's broken
+ if (m_bIsBroken)
+ return true;
+
+ return C_BaseEntity::IsTransparent();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+int C_BreakableSurface::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ // If I'm not broken draw normally
+ if (m_bIsBroken)
+ render->InstallBrushSurfaceRenderer( this );
+
+ // If it's broken, always draw it translucent
+ BaseClass::DrawModel( m_bIsBroken ? flags | STUDIO_TRANSPARENCY : flags );
+
+ // Remove our nonstandard brush surface renderer...
+ render->InstallBrushSurfaceRenderer( 0 );
+
+ return 0;
+}
+
+bool C_BreakableSurface::RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface )
+{
+ // If tile draw highlight for grout
+ if (m_nSurfaceType == SHATTERSURFACE_TILE)
+ {
+ DrawRenderListHighlights(pBrushSurface);
+ }
+ DrawSolidBlocks(pBrushSurface);
+ DrawRenderList(pBrushSurface);
+
+ // Don't draw decals
+ return false;
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawRenderList(IBrushSurface* pBrushSurface)
+{
+ // Get width and height steps
+ QAngle vAngles;
+ VectorAngles(-1*m_vNormal,vAngles);
+ Vector vWidthStep,vHeightStep;
+ AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
+ vWidthStep *= m_flPanelWidth;
+ vHeightStep *= m_flPanelHeight;
+
+ CMeshBuilder pMeshBuilder;
+ IMesh* pMesh = NULL;
+ int nCurStyle = -1;
+ int nCurEdgeType = -1;
+ CMatRenderContextPtr pRenderContext( materials );
+ for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
+ {
+
+ if (nCurStyle != m_RenderList[i].m_nStyle ||
+ nCurEdgeType != m_RenderList[i].m_nEdgeType )
+ {
+ nCurStyle = m_RenderList[i].m_nStyle;
+ nCurEdgeType = m_RenderList[i].m_nEdgeType;
+
+ m_pCurrentDetailTexture = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdgeTexture;
+ pRenderContext->Flush(false);
+ pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
+ pMesh = pRenderContext->GetDynamicMesh( );
+ }
+
+ Vector vRenderPos = m_vCorner +
+ (m_RenderList[i].m_nWidth*vWidthStep) +
+ (m_RenderList[i].m_nHeight*vHeightStep);
+
+ DrawOneEdge(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawRenderListHighlights(IBrushSurface* pBrushSurface)
+{
+ // Get width and height steps
+ QAngle vAngles;
+ VectorAngles(-1*m_vNormal,vAngles);
+ Vector vWidthStep,vHeightStep;
+ AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
+ vWidthStep *= m_flPanelWidth;
+ vHeightStep *= m_flPanelHeight;
+
+
+ CMeshBuilder pMeshBuilder;
+ IMesh* pMesh = NULL;
+ int nCurStyle = -1;
+ int nCurEdgeType = -1;
+ CMatRenderContextPtr pRenderContext( materials );
+ for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
+ {
+
+ if (nCurStyle != m_RenderList[i].m_nStyle ||
+ nCurEdgeType != m_RenderList[i].m_nEdgeType )
+ {
+ nCurStyle = m_RenderList[i].m_nStyle;
+ nCurEdgeType = m_RenderList[i].m_nEdgeType;
+
+ IMaterial *pMat = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdge;
+ pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat );
+ }
+
+ Vector vRenderPos = m_vCorner +
+ (m_RenderList[i].m_nWidth*vWidthStep) +
+ (m_RenderList[i].m_nHeight*vHeightStep) +
+ (0.30*m_vNormal);
+
+ DrawOneHighlight(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+bool C_BreakableSurface::HavePanel(int nWidth, int nHeight)
+{
+ // If I'm off the edge, always give support
+ if (!InLegalRange(nWidth,nHeight))
+ {
+ return true;
+ }
+ return (IsPanelSolid(nWidth,nHeight));
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::UpdateEdgeType(int nWidth, int nHeight, int forceStyle /*=-1*/ )
+{
+ Assert( forceStyle < NUM_EDGE_STYLES );
+
+ // -----------------------------------
+ // Check edge conditions
+ // -----------------------------------
+ if (!InLegalRange(nWidth,nHeight))
+ {
+ return;
+ }
+
+ // ----------------------------------
+ // If solid has no edges
+ // ----------------------------------
+ if (IsPanelSolid(nWidth,nHeight))
+ {
+ return;
+ }
+
+ // Panel is no longer stale
+ SetPanelStale(nWidth, nHeight,false);
+
+ // ----------------------------------
+ // Set edge type base on neighbors
+ // ----------------------------------
+ bool bUp = HavePanel(nWidth, nHeight+1);
+ bool bDown = HavePanel(nWidth, nHeight-1);
+ bool bLeft = HavePanel(nWidth-1, nHeight );
+ bool bRight = HavePanel(nWidth+1, nHeight );
+
+ bool bUpLeft = HavePanel(nWidth-1, nHeight+1);
+ bool bUpRight = HavePanel(nWidth+1, nHeight+1);
+ bool bDownLeft = HavePanel(nWidth-1, nHeight-1);
+ bool bDownRight = HavePanel(nWidth+1, nHeight-1);
+
+ //-------------
+ // Top
+ //-------------
+ if (bUp)
+ {
+ bool bLeftEdge = !bLeft && bUpLeft;
+ bool bRightEdge = !bRight && bUpRight;
+
+ if (bLeftEdge && bRightEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_FULL, forceStyle );
+ }
+ else if (bLeftEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_LEFT, forceStyle );
+ }
+ else if (bRightEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_RIGHT, forceStyle );
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NONE, forceStyle );
+ }
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NOT, forceStyle );
+ }
+ //-------------
+ // Bottom
+ //-------------
+ if (bDown)
+ {
+ bool bLeftEdge = !bLeft && bDownLeft;
+ bool bRightEdge = !bRight && bDownRight;
+
+ if (bLeftEdge && bRightEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_FULL, forceStyle );
+ }
+ else if (bLeftEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_RIGHT, forceStyle );
+ }
+ else if (bRightEdge)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_LEFT, forceStyle );
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NONE, forceStyle );
+ }
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NOT, forceStyle );
+ }
+ //-------------
+ // Left
+ //-------------
+ if (bLeft)
+ {
+ bool bTop = !bUp && bUpLeft;
+ bool bBottom = !bDown && bDownLeft;
+
+ if (bTop && bBottom)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_FULL, forceStyle );
+ }
+ else if (bTop)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_RIGHT, forceStyle );
+ }
+ else if (bBottom)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_LEFT, forceStyle );
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NONE, forceStyle );
+ }
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NOT, forceStyle );
+ }
+ //-------------
+ // Right
+ //-------------
+ if (bRight)
+ {
+ bool bTop = !bUp && bUpRight;
+ bool bBottom = !bDown && bDownRight;
+
+ if (bTop && bBottom)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_FULL, forceStyle );
+ }
+ else if (bTop)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_LEFT, forceStyle );
+ }
+ else if (bBottom)
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_RIGHT, forceStyle );
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NONE, forceStyle );
+ }
+ }
+ else
+ {
+ AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NOT, forceStyle );
+ }
+}
+
+//--------------------------------------------------------------------------------
+// Purpose : Return index to panel in render list that meets these qualifications
+// Input :
+// Output :
+//--------------------------------------------------------------------------------
+int C_BreakableSurface::FindRenderPanel(int nWidth, int nHeight, WinSide_t nWinSide)
+{
+ for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
+ {
+ if (m_RenderList[i].m_nSide == nWinSide &&
+ m_RenderList[i].m_nWidth == nWidth &&
+ m_RenderList[i].m_nHeight == nHeight)
+ {
+ return i;
+ }
+ }
+ return m_RenderList.InvalidIndex();
+}
+
+//----------------------------------------------------------------------------------
+// Purpose : Returns first element in render list with the same edge type and style
+// Input :
+// Output :
+//----------------------------------------------------------------------------------
+int C_BreakableSurface::FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle)
+{
+ for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
+ {
+ if (m_RenderList[i].m_nStyle == nStyle &&
+ m_RenderList[i].m_nEdgeType == nEdgeType )
+ {
+ return i;
+ }
+ }
+ return m_RenderList.InvalidIndex();
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Add a edge to be rendered to the render list
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle )
+{
+ // -----------------------------------------------------
+ // Try to find old panel
+ int nOldPanelIndex = FindRenderPanel(nWidth,nHeight,nSide);
+
+ // -----------------------------------------------------
+ // If I have an old panel, get it's style and remove it
+ // otherwise randomly chose a style
+ int nStyle;
+ if (m_RenderList.IsValidIndex(nOldPanelIndex) )
+ {
+ nStyle = m_RenderList[nOldPanelIndex].m_nStyle;
+ m_RenderList.Remove(nOldPanelIndex);
+ }
+ else
+ {
+ nStyle = random->RandomInt(0,NUM_EDGE_STYLES-1);
+ }
+
+ if ( forceStyle != -1 )
+ {
+ nStyle = forceStyle;
+ }
+
+ // -----------------------------------------------------
+ // If my new panel has an edge, add it to render list
+ if (nEdgeType != EDGE_NOT)
+ {
+ // Renderlist is sorted by texture type. Find first element
+ // that shares the same texture as the new panel
+ unsigned short nTexIndex = FindFirstRenderTexture(nEdgeType, nStyle);
+
+ // If texture was already in list, add after last use
+ unsigned short nNewIndex;
+ if (m_RenderList.IsValidIndex(nTexIndex))
+ {
+ nNewIndex = m_RenderList.InsertAfter(nTexIndex);
+ }
+ // Otherwise add to send of render list
+ else
+ {
+ nNewIndex = m_RenderList.AddToTail();
+ }
+
+ // Now fill out my data
+ m_RenderList[nNewIndex].m_nHeight = nHeight;
+ m_RenderList[nNewIndex].m_nWidth = nWidth;
+ m_RenderList[nNewIndex].m_nEdgeType = nEdgeType;
+ m_RenderList[nNewIndex].m_nSide = nSide;
+ m_RenderList[nNewIndex].m_nStyle = nStyle;
+
+ Assert( nStyle < NUM_EDGE_STYLES );
+ SetStyleType( nWidth, nHeight, nStyle );
+ }
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawSolidBlocks(IBrushSurface* pBrushSurface)
+{
+ CMatRenderContextPtr pRenderContext( materials );
+
+ m_pCurrentDetailTexture = m_pMaterialBoxTexture;
+
+ // Gotta flush (in a non-stalling way) because we effectively
+ // have a new material due to the new base texture
+ pRenderContext->Flush(false);
+ pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+ CMeshBuilder pMeshBuilder;
+
+ // ---------------
+ // Create panels
+ // ---------------
+ QAngle vAngles;
+ VectorAngles(-1*m_vNormal,vAngles);
+ Vector vWidthStep,vHeightStep;
+ AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
+ vWidthStep *= m_flPanelWidth;
+ vHeightStep *= m_flPanelHeight;
+
+ Vector vCurPos = m_vCorner;
+ for (int width=0;width<m_nNumWide;width++)
+ {
+ int height;
+ int nHCount = 0;
+ for (height=0;height<m_nNumHigh;height++)
+ {
+ // Keep count of how many panes there are in a row
+ if (IsPanelSolid(width,height))
+ {
+ nHCount++;
+ }
+
+ // Drow the strip and start counting again
+ else if (nHCount > 0)
+ {
+ vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
+ DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
+ nHCount = 0;
+ }
+ }
+ if (nHCount)
+ {
+ vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
+ DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vCurPos, const Vector &vWidthStep,
+ const Vector &vHeightStep)
+{
+ pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ Vector2D texCoord, lightCoord;
+ pBrushSurface->ComputeTextureCoordinate( vCurPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vCurPos, lightCoord );
+
+ pMeshBuilder->Position3f( vCurPos.x, vCurPos.y, vCurPos.z );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2f( 0, 0, 1 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ Vector vNextPos = vCurPos + vWidthStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2f( 0, 0, 0 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos + vHeightStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x , vNextPos.y, vNextPos.z );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2f( 0, 1, 0 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos - vWidthStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y , vNextPos.z);
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2f( 0, 1, 1 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->End();
+ pMesh->Draw();
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
+ const Vector &vHStep, WinSide_t nEdge )
+{
+ pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ Vector2D texCoord, lightCoord;
+ pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
+
+ pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ Vector vNextPos = vStartPos + vWStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos + vHStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos - vWStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4ub( 255, 255, 255, 255 );
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->End();
+ pMesh->Draw();
+}
+
+
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void C_BreakableSurface::DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
+ CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
+ const Vector &vHStep, WinSide_t nEdge )
+{
+ Vector vColor = Vector(0.41,0.35,0.24);
+
+ pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ Vector2D texCoord, lightCoord;
+ pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
+
+ pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ Vector vNextPos = vStartPos + vWStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos + vHStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ vNextPos = vNextPos - vWStep;
+
+ pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
+ pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
+
+ pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
+ pMeshBuilder->Normal3fv( m_vNormal.Base() );
+ pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
+ pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
+ switch (nEdge)
+ {
+ case WIN_SIDE_RIGHT:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
+ break;
+ case WIN_SIDE_BOTTOM:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
+ break;
+ case WIN_SIDE_LEFT:
+ pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
+ break;
+ case WIN_SIDE_TOP:
+ pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
+ break;
+ }
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->End();
+ pMesh->Draw();
+}
+
+bool C_BreakableSurface::ShouldReceiveProjectedTextures( int flags )
+{
+ return false;
+}
+
+
+//------------------------------------------------------------------------------
+// A material proxy that resets the texture to use the original surface texture
+//------------------------------------------------------------------------------
+class CBreakableSurfaceProxy : public CEntityMaterialProxy
+{
+public:
+ CBreakableSurfaceProxy();
+ virtual ~CBreakableSurfaceProxy();
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( C_BaseEntity *pC_BaseEntity );
+ virtual IMaterial *GetMaterial();
+
+private:
+ // get at the material whose texture we're going to steal
+ void AcquireSourceMaterial( C_BaseEntity* pEnt );
+
+ IMaterialVar* m_BaseTextureVar;
+};
+
+CBreakableSurfaceProxy::CBreakableSurfaceProxy()
+{
+ m_BaseTextureVar = NULL;
+}
+
+CBreakableSurfaceProxy::~CBreakableSurfaceProxy()
+{
+}
+
+
+bool CBreakableSurfaceProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ bool foundVar;
+ m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
+ return foundVar;
+}
+
+void CBreakableSurfaceProxy::OnBind( C_BaseEntity *pC_BaseEntity )
+{
+ C_BreakableSurface *pEnt = dynamic_cast< C_BreakableSurface * >(pC_BaseEntity);
+ if( !pEnt )
+ {
+ return;
+ }
+
+ // Use the current base texture specified by the suface
+ m_BaseTextureVar->SetTextureValue( pEnt->m_pCurrentDetailTexture );
+}
+
+IMaterial *CBreakableSurfaceProxy::GetMaterial()
+{
+ if ( !m_BaseTextureVar )
+ return NULL;
+
+ return m_BaseTextureVar->GetOwningMaterial();
+}
+
+EXPOSE_INTERFACE( CBreakableSurfaceProxy, IMaterialProxy, "BreakableSurface" IMATERIAL_PROXY_INTERFACE_VERSION );