From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/c_func_breakablesurf.cpp | 2672 +++++++++++++-------------- 1 file changed, 1336 insertions(+), 1336 deletions(-) (limited to 'mp/src/game/client/c_func_breakablesurf.cpp') 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;wGetModelMaterialCount( const_cast(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(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;wInstallBrushSurfaceRenderer( 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 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;wGetModelMaterialCount( const_cast(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(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;wInstallBrushSurfaceRenderer( 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 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 ); -- cgit v1.2.3