Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1336 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "particles_simple.h"
  10. #include "iviewrender.h"
  11. #include "proxyentity.h"
  12. #include "materialsystem/imaterialvar.h"
  13. #include "model_types.h"
  14. #include "engine/ivmodelinfo.h"
  15. #include "clienteffectprecachesystem.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #define MAX_NUM_PANELS 16
  19. extern IVDebugOverlay *debugoverlay;
  20. enum WinSide_t
  21. {
  22. WIN_SIDE_BOTTOM,
  23. WIN_SIDE_RIGHT,
  24. WIN_SIDE_TOP,
  25. WIN_SIDE_LEFT,
  26. };
  27. enum WinEdge_t
  28. {
  29. EDGE_NOT = -1, // No edge
  30. EDGE_NONE, /* No edge on both sides /##\ */
  31. EDGE_FULL, // Edge on both sides |##|
  32. EDGE_LEFT, /* Edge is on left only |##\ */
  33. EDGE_RIGHT, // Edge is on right only /##|
  34. };
  35. #define STYLE_HIGHLIGHT = -1;
  36. #define NUM_EDGE_TYPES 4
  37. #define NUM_EDGE_STYLES 3
  38. //==================================================
  39. // C_BreakableSurface
  40. //==================================================
  41. //-----------------------------------------------------------------------------
  42. // All the information associated with a particular handle
  43. //-----------------------------------------------------------------------------
  44. struct Panel_t
  45. {
  46. char m_nWidth;
  47. char m_nHeight;
  48. char m_nSide;
  49. char m_nEdgeType;
  50. char m_nStyle;
  51. };
  52. struct EdgeTexture_t
  53. {
  54. int m_nRenderIndex;
  55. int m_nStyle;
  56. CMaterialReference m_pMaterialEdge;
  57. CTextureReference m_pMaterialEdgeTexture;
  58. };
  59. // Bits for m_nPanelBits
  60. #define BITS_PANEL_IS_SOLID (1<<0)
  61. #define BITS_PANEL_IS_STALE (1<<1)
  62. class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer
  63. {
  64. public:
  65. DECLARE_CLIENTCLASS();
  66. DECLARE_CLASS( C_BreakableSurface, C_BaseEntity );
  67. DECLARE_DATADESC();
  68. int m_nNumWide;
  69. int m_nNumHigh;
  70. float m_flPanelWidth;
  71. float m_flPanelHeight;
  72. Vector m_vNormal;
  73. Vector m_vCorner;
  74. bool m_bIsBroken;
  75. int m_nSurfaceType;
  76. // This is the texture we're going to use to multiply by the cracked base texture
  77. ITexture* m_pCurrentDetailTexture;
  78. // Stores linked list of edges to render
  79. CUtlLinkedList< Panel_t, unsigned short > m_RenderList;
  80. C_BreakableSurface();
  81. ~C_BreakableSurface();
  82. public:
  83. void InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName);
  84. virtual void OnDataChanged( DataUpdateType_t updateType );
  85. virtual void OnPreDataChanged( DataUpdateType_t updateType );
  86. bool IsTransparent( void );
  87. bool HavePanel(int nWidth, int nHeight);
  88. bool RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface );
  89. int DrawModel( int flags );
  90. void DrawSolidBlocks( IBrushSurface* pBrushSurface );
  91. virtual void OnRestore();
  92. virtual bool ShouldReceiveProjectedTextures( int flags );
  93. private:
  94. // One bit per pane
  95. CNetworkArray( bool, m_RawPanelBitVec, MAX_NUM_PANELS * MAX_NUM_PANELS );
  96. bool m_PrevRawPanelBitVec[ MAX_NUM_PANELS * MAX_NUM_PANELS ];
  97. // 2 bits of flags and 2 bits of edge type
  98. byte m_nPanelBits[MAX_NUM_PANELS][MAX_NUM_PANELS]; //UNDONE: allocate this dynamically?
  99. CMaterialReference m_pMaterialBox;
  100. EdgeTexture_t m_pSolid;
  101. EdgeTexture_t m_pEdge[NUM_EDGE_TYPES][NUM_EDGE_STYLES];
  102. inline bool InLegalRange(int nWidth, int nHeight);
  103. inline bool IsPanelSolid(int nWidth, int nHeight);
  104. inline bool IsPanelStale(int nWidth, int nHeight);
  105. inline void SetPanelSolid(int nWidth, int nHeight, bool value);
  106. inline void SetPanelStale(int nWidth, int nHeight, bool value);
  107. void DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
  108. CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
  109. const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
  110. void DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
  111. CMeshBuilder *pMeshBuilder, const Vector &vStartPos,
  112. const Vector &vWStep, const Vector &vHstep, WinSide_t nEdge);
  113. void DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
  114. CMeshBuilder *pMeshBuilder, const Vector &vPosition,
  115. const Vector &vWidth, const Vector &vHeight);
  116. void DrawRenderList( IBrushSurface* pBrushSurface);
  117. void DrawRenderListHighlights( IBrushSurface* pBrushSurface );
  118. int FindRenderPanel(int nWidth, int nHeight, WinSide_t nSide);
  119. void AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle);
  120. int FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle);
  121. inline void SetStyleType( int w, int h, int type )
  122. {
  123. Assert( type < NUM_EDGE_STYLES );
  124. Assert( type >= 0 );
  125. // Clear old value
  126. m_nPanelBits[ w ][ h ] &= 0xF0; // ( ~0x03 << 2 ); Left shifting a negative value has undefined behavior. Use the constant 0xF0 instead.
  127. // Insert new value
  128. m_nPanelBits[ w ][ h ] |= ( type << 2 );
  129. }
  130. inline int GetStyleType( int w, int h )
  131. {
  132. int value = m_nPanelBits[ w ][ h ];
  133. value = ( value >> 2 ) & 0x03;
  134. Assert( value < NUM_EDGE_STYLES );
  135. return value;
  136. }
  137. // Gets at the cracked version of the material
  138. void FindCrackedMaterial();
  139. CMaterialReference m_pCrackedMaterial;
  140. CTextureReference m_pMaterialBoxTexture;
  141. void UpdateEdgeType(int nWidth, int nHeight, int forceStyle = -1 );
  142. };
  143. BEGIN_DATADESC( C_BreakableSurface )
  144. DEFINE_ARRAY( m_nPanelBits, FIELD_CHARACTER, MAX_NUM_PANELS * MAX_NUM_PANELS ),
  145. // DEFINE_FIELD( m_nNumWide, FIELD_INTEGER ),
  146. // DEFINE_FIELD( m_nNumHigh, FIELD_INTEGER ),
  147. // DEFINE_FIELD( m_flPanelWidth, FIELD_FLOAT ),
  148. // DEFINE_FIELD( m_flPanelHeight, FIELD_FLOAT ),
  149. // DEFINE_FIELD( m_vNormal, FIELD_VECTOR ),
  150. // DEFINE_FIELD( m_vCorner, FIELD_VECTOR ),
  151. // DEFINE_FIELD( m_bIsBroken, FIELD_BOOLEAN ),
  152. // DEFINE_FIELD( m_nSurfaceType, FIELD_INTEGER ),
  153. // DEFINE_FIELD( m_pCurrentDetailTexture, ITexture* ),
  154. // DEFINE_FIELD( m_RenderList, CUtlLinkedList < Panel_t , unsigned short > ),
  155. // DEFINE_FIELD( m_pMaterialBox, CMaterialReference ),
  156. // DEFINE_FIELD( m_pSolid, EdgeTexture_t ),
  157. // DEFINE_ARRAY( m_pEdge, EdgeTexture_t, NUM_EDGE_TYPES][NUM_EDGE_STYLES ),
  158. // DEFINE_FIELD( m_pCrackedMaterial, CMaterialReference ),
  159. // DEFINE_FIELD( m_pMaterialBoxTexture, CTextureReference ),
  160. END_DATADESC()
  161. bool C_BreakableSurface::InLegalRange(int nWidth, int nHeight)
  162. {
  163. return (nWidth < m_nNumWide && nHeight < m_nNumHigh &&
  164. nWidth >=0 && nHeight >= 0 );
  165. }
  166. bool C_BreakableSurface::IsPanelSolid(int nWidth, int nHeight)
  167. {
  168. return ( BITS_PANEL_IS_SOLID & m_nPanelBits[nWidth][nHeight] )!=0 ;
  169. }
  170. bool C_BreakableSurface::IsPanelStale(int nWidth, int nHeight)
  171. {
  172. return ( BITS_PANEL_IS_STALE & m_nPanelBits[nWidth][nHeight] )!=0 ;
  173. }
  174. void C_BreakableSurface::SetPanelSolid(int nWidth, int nHeight, bool value)
  175. {
  176. if ( !InLegalRange( nWidth, nHeight ) )
  177. return;
  178. if ( value )
  179. {
  180. m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_SOLID;
  181. }
  182. else
  183. {
  184. m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_SOLID;
  185. }
  186. }
  187. void C_BreakableSurface::SetPanelStale(int nWidth, int nHeight, bool value)
  188. {
  189. if ( !InLegalRange( nWidth, nHeight) )
  190. return;
  191. if ( value )
  192. {
  193. m_nPanelBits[nWidth][nHeight] |= BITS_PANEL_IS_STALE;
  194. }
  195. else
  196. {
  197. m_nPanelBits[nWidth][nHeight] &= ~BITS_PANEL_IS_STALE;
  198. }
  199. }
  200. void C_BreakableSurface::OnRestore()
  201. {
  202. BaseClass::OnRestore();
  203. // FIXME: This restores the general state, but not the random edge bits
  204. // those would need to be serialized separately...
  205. // traverse everthing and restore bits
  206. // Initialize panels
  207. for (int w=0;w<m_nNumWide;w++)
  208. {
  209. for (int h=0;h<m_nNumHigh;h++)
  210. {
  211. // Force recomputation
  212. SetPanelSolid(w,h,IsPanelSolid(w,h));
  213. SetPanelStale(w,h,true);
  214. UpdateEdgeType( w, h, GetStyleType(w,h ) );
  215. }
  216. }
  217. }
  218. //Receive datatable
  219. IMPLEMENT_CLIENTCLASS_DT( C_BreakableSurface, DT_BreakableSurface, CBreakableSurface )
  220. RecvPropInt( RECVINFO( m_nNumWide ) ),
  221. RecvPropInt( RECVINFO( m_nNumHigh ) ),
  222. RecvPropFloat( RECVINFO( m_flPanelWidth) ),
  223. RecvPropFloat( RECVINFO( m_flPanelHeight) ),
  224. RecvPropVector( RECVINFO( m_vNormal ) ),
  225. RecvPropVector( RECVINFO( m_vCorner ) ),
  226. RecvPropInt( RECVINFO( m_bIsBroken )),
  227. RecvPropInt( RECVINFO( m_nSurfaceType )),
  228. RecvPropArray3( RECVINFO_ARRAY(m_RawPanelBitVec), RecvPropInt( RECVINFO( m_RawPanelBitVec[ 0 ] ))),
  229. END_RECV_TABLE()
  230. //-----------------------------------------------------------------------------
  231. // Gets at the cracked version of the material
  232. //-----------------------------------------------------------------------------
  233. void C_BreakableSurface::FindCrackedMaterial()
  234. {
  235. m_pCrackedMaterial = 0;
  236. // First time we've seen it, get the material on the brush model
  237. int materialCount = modelinfo->GetModelMaterialCount( const_cast<model_t*>(GetModel()) );
  238. if( materialCount != 1 )
  239. {
  240. Warning( "Encountered func_breakablesurf that has a material applied to more than one surface!\n" );
  241. m_pCrackedMaterial.Init( "debug/debugempty", TEXTURE_GROUP_OTHER );
  242. return;
  243. }
  244. // Get at the first material; even if there are more than one.
  245. IMaterial* pMaterial;
  246. modelinfo->GetModelMaterials( const_cast<model_t*>(GetModel()), 1, &pMaterial );
  247. // The material should point to a cracked version of itself
  248. bool foundVar;
  249. IMaterialVar* pCrackName = pMaterial->FindVar( "$crackmaterial", &foundVar, false );
  250. if (foundVar)
  251. {
  252. m_pCrackedMaterial.Init( pCrackName->GetStringValue(), TEXTURE_GROUP_CLIENT_EFFECTS );
  253. }
  254. else
  255. {
  256. m_pCrackedMaterial.Init( pMaterial );
  257. }
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Gets at the base texture
  261. //-----------------------------------------------------------------------------
  262. static ITexture* GetBaseTexture( IMaterial* pMaterial )
  263. {
  264. bool foundVar;
  265. IMaterialVar* pTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  266. if (!foundVar)
  267. return 0;
  268. return pTextureVar->GetTextureValue();
  269. }
  270. //------------------------------------------------------------------------------
  271. // Purpose :
  272. // Input :
  273. // Output :
  274. //------------------------------------------------------------------------------
  275. void C_BreakableSurface::InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName)
  276. {
  277. m_pEdge[nEdgeType][nEdgeStyle].m_nRenderIndex = m_RenderList.InvalidIndex();
  278. m_pEdge[nEdgeType][nEdgeStyle].m_nStyle = nEdgeStyle;
  279. m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge.Init(pMaterialName, TEXTURE_GROUP_CLIENT_EFFECTS);
  280. m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdgeTexture.Init( GetBaseTexture( m_pEdge[nEdgeType][nEdgeStyle].m_pMaterialEdge ) );
  281. }
  282. //-----------------------------------------------------------------------------
  283. // constructor, destructor
  284. //-----------------------------------------------------------------------------
  285. C_BreakableSurface::C_BreakableSurface()
  286. {
  287. m_vNormal.Init();
  288. m_vCorner.Init();
  289. m_bIsBroken = false;
  290. m_pCurrentDetailTexture = NULL;
  291. Q_memset( m_PrevRawPanelBitVec, 0xff, sizeof( m_PrevRawPanelBitVec ) );
  292. }
  293. C_BreakableSurface::~C_BreakableSurface()
  294. {
  295. }
  296. void C_BreakableSurface::OnPreDataChanged( DataUpdateType_t updateType )
  297. {
  298. BaseClass::OnPreDataChanged( updateType );
  299. if ( updateType == DATA_UPDATE_CREATED )
  300. {
  301. // Initialize panels
  302. m_nNumWide = MAX_NUM_PANELS;
  303. m_nNumHigh = MAX_NUM_PANELS;
  304. for (int w=0;w<MAX_NUM_PANELS;w++)
  305. {
  306. for (int h=0;h<MAX_NUM_PANELS;h++)
  307. {
  308. SetPanelSolid(w,h,true);
  309. SetPanelStale(w,h,false);
  310. m_RawPanelBitVec.Set( w + h * MAX_NUM_PANELS, true );
  311. }
  312. }
  313. }
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Purpose:
  317. // Input : bnewentity -
  318. //-----------------------------------------------------------------------------
  319. void C_BreakableSurface::OnDataChanged( DataUpdateType_t updateType )
  320. {
  321. C_BaseEntity::OnDataChanged( updateType );
  322. if ( updateType == DATA_UPDATE_CREATED )
  323. {
  324. // Get at the cracked material
  325. FindCrackedMaterial();
  326. // Use same solid box for all breakable surfaces
  327. m_pMaterialBox.Init( "models/brokenglass/glassbroken_solid", TEXTURE_GROUP_MODEL );
  328. m_pMaterialBoxTexture.Init( GetBaseTexture( m_pMaterialBox ) );
  329. // NOTE: If you add or change this list of materials, change
  330. // the precache list on func_breakablesurf.cpp on the server.
  331. // Load the edge types and styles for the specific surface type
  332. if (m_nSurfaceType == SHATTERSURFACE_TILE)
  333. {
  334. InitMaterial(EDGE_NONE, 0,"models/brokentile/tilebroken_03a");
  335. InitMaterial(EDGE_FULL, 0,"models/brokentile/tilebroken_03b");
  336. InitMaterial(EDGE_LEFT, 0,"models/brokentile/tilebroken_03c");
  337. InitMaterial(EDGE_RIGHT,0,"models/brokentile/tilebroken_03d");
  338. InitMaterial(EDGE_NONE, 1,"models/brokentile/tilebroken_02a");
  339. InitMaterial(EDGE_FULL, 1,"models/brokentile/tilebroken_02b");
  340. InitMaterial(EDGE_LEFT, 1,"models/brokentile/tilebroken_02c");
  341. InitMaterial(EDGE_RIGHT,1,"models/brokentile/tilebroken_02d");
  342. InitMaterial(EDGE_NONE, 2,"models/brokentile/tilebroken_01a");
  343. InitMaterial(EDGE_FULL, 2,"models/brokentile/tilebroken_01b");
  344. InitMaterial(EDGE_LEFT, 2,"models/brokentile/tilebroken_01c");
  345. InitMaterial(EDGE_RIGHT,2,"models/brokentile/tilebroken_01d");
  346. }
  347. else
  348. {
  349. InitMaterial(EDGE_NONE, 0,"models/brokenglass/glassbroken_03a");
  350. InitMaterial(EDGE_FULL, 0,"models/brokenglass/glassbroken_03b");
  351. InitMaterial(EDGE_LEFT, 0,"models/brokenglass/glassbroken_03c");
  352. InitMaterial(EDGE_RIGHT,0,"models/brokenglass/glassbroken_03d");
  353. InitMaterial(EDGE_NONE, 1,"models/brokenglass/glassbroken_02a");
  354. InitMaterial(EDGE_FULL, 1,"models/brokenglass/glassbroken_02b");
  355. InitMaterial(EDGE_LEFT, 1,"models/brokenglass/glassbroken_02c");
  356. InitMaterial(EDGE_RIGHT,1,"models/brokenglass/glassbroken_02d");
  357. InitMaterial(EDGE_NONE, 2,"models/brokenglass/glassbroken_01a");
  358. InitMaterial(EDGE_FULL, 2,"models/brokenglass/glassbroken_01b");
  359. InitMaterial(EDGE_LEFT, 2,"models/brokenglass/glassbroken_01c");
  360. InitMaterial(EDGE_RIGHT,2,"models/brokenglass/glassbroken_01d");
  361. }
  362. }
  363. bool changed = false;
  364. for ( int j = 0; j < m_nNumHigh; j++ )
  365. {
  366. for ( int i = 0; i < m_nNumWide; i++ )
  367. {
  368. int offset = i + j * m_nNumWide;
  369. bool newVal = m_RawPanelBitVec[ offset ];
  370. bool oldVal = m_PrevRawPanelBitVec[ offset ];
  371. if ( newVal != oldVal )
  372. {
  373. changed = true;
  374. }
  375. SetPanelSolid(i,j,newVal);
  376. if ( !newVal && changed )
  377. {
  378. // Mark these panels and being stale (need edge type updated)
  379. // We update them in one fell swoop rather than as each panel
  380. // is updated, so we don't have to do duplicate operations
  381. SetPanelStale(i, j ,true);
  382. SetPanelStale(i, j+1,true);
  383. SetPanelStale(i, j-1,true);
  384. SetPanelStale(i-1, j ,true);
  385. SetPanelStale(i+1, j ,true);
  386. SetPanelStale(i+1, j+1,true);
  387. SetPanelStale(i-1, j+1,true);
  388. SetPanelStale(i+1, j-1,true);
  389. SetPanelStale(i-1, j-1,true);
  390. }
  391. }
  392. }
  393. if ( changed )
  394. {
  395. for (int width=0;width<m_nNumWide;width++)
  396. {
  397. for (int height=0;height<m_nNumHigh;height++)
  398. {
  399. if ( IsPanelStale(width,height) )
  400. {
  401. UpdateEdgeType( width, height );
  402. }
  403. }
  404. }
  405. }
  406. Q_memcpy( m_PrevRawPanelBitVec, m_RawPanelBitVec.Base(), sizeof( m_PrevRawPanelBitVec ) );
  407. }
  408. bool C_BreakableSurface::IsTransparent( void )
  409. {
  410. // Not an identity brush if it's broken
  411. if (m_bIsBroken)
  412. return true;
  413. return C_BaseEntity::IsTransparent();
  414. }
  415. //------------------------------------------------------------------------------
  416. // Purpose :
  417. // Input :
  418. // Output :
  419. //------------------------------------------------------------------------------
  420. int C_BreakableSurface::DrawModel( int flags )
  421. {
  422. if ( !m_bReadyToDraw )
  423. return 0;
  424. // If I'm not broken draw normally
  425. if (m_bIsBroken)
  426. render->InstallBrushSurfaceRenderer( this );
  427. // If it's broken, always draw it translucent
  428. BaseClass::DrawModel( m_bIsBroken ? flags | STUDIO_TRANSPARENCY : flags );
  429. // Remove our nonstandard brush surface renderer...
  430. render->InstallBrushSurfaceRenderer( 0 );
  431. return 0;
  432. }
  433. bool C_BreakableSurface::RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface )
  434. {
  435. // If tile draw highlight for grout
  436. if (m_nSurfaceType == SHATTERSURFACE_TILE)
  437. {
  438. DrawRenderListHighlights(pBrushSurface);
  439. }
  440. DrawSolidBlocks(pBrushSurface);
  441. DrawRenderList(pBrushSurface);
  442. // Don't draw decals
  443. return false;
  444. }
  445. //------------------------------------------------------------------------------
  446. // Purpose :
  447. // Input :
  448. // Output :
  449. //------------------------------------------------------------------------------
  450. void C_BreakableSurface::DrawRenderList(IBrushSurface* pBrushSurface)
  451. {
  452. // Get width and height steps
  453. QAngle vAngles;
  454. VectorAngles(-1*m_vNormal,vAngles);
  455. Vector vWidthStep,vHeightStep;
  456. AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
  457. vWidthStep *= m_flPanelWidth;
  458. vHeightStep *= m_flPanelHeight;
  459. CMeshBuilder pMeshBuilder;
  460. IMesh* pMesh = NULL;
  461. int nCurStyle = -1;
  462. int nCurEdgeType = -1;
  463. CMatRenderContextPtr pRenderContext( materials );
  464. for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
  465. {
  466. if (nCurStyle != m_RenderList[i].m_nStyle ||
  467. nCurEdgeType != m_RenderList[i].m_nEdgeType )
  468. {
  469. nCurStyle = m_RenderList[i].m_nStyle;
  470. nCurEdgeType = m_RenderList[i].m_nEdgeType;
  471. m_pCurrentDetailTexture = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdgeTexture;
  472. pRenderContext->Flush(false);
  473. pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
  474. pMesh = pRenderContext->GetDynamicMesh( );
  475. }
  476. Vector vRenderPos = m_vCorner +
  477. (m_RenderList[i].m_nWidth*vWidthStep) +
  478. (m_RenderList[i].m_nHeight*vHeightStep);
  479. DrawOneEdge(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
  480. }
  481. }
  482. //------------------------------------------------------------------------------
  483. // Purpose :
  484. // Input :
  485. // Output :
  486. //------------------------------------------------------------------------------
  487. void C_BreakableSurface::DrawRenderListHighlights(IBrushSurface* pBrushSurface)
  488. {
  489. // Get width and height steps
  490. QAngle vAngles;
  491. VectorAngles(-1*m_vNormal,vAngles);
  492. Vector vWidthStep,vHeightStep;
  493. AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
  494. vWidthStep *= m_flPanelWidth;
  495. vHeightStep *= m_flPanelHeight;
  496. CMeshBuilder pMeshBuilder;
  497. IMesh* pMesh = NULL;
  498. int nCurStyle = -1;
  499. int nCurEdgeType = -1;
  500. CMatRenderContextPtr pRenderContext( materials );
  501. for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
  502. {
  503. if (nCurStyle != m_RenderList[i].m_nStyle ||
  504. nCurEdgeType != m_RenderList[i].m_nEdgeType )
  505. {
  506. nCurStyle = m_RenderList[i].m_nStyle;
  507. nCurEdgeType = m_RenderList[i].m_nEdgeType;
  508. IMaterial *pMat = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdge;
  509. pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat );
  510. }
  511. Vector vRenderPos = m_vCorner +
  512. (m_RenderList[i].m_nWidth*vWidthStep) +
  513. (m_RenderList[i].m_nHeight*vHeightStep) +
  514. (0.30*m_vNormal);
  515. DrawOneHighlight(pBrushSurface, pMesh,&pMeshBuilder,vRenderPos,vWidthStep,vHeightStep,(WinSide_t)m_RenderList[i].m_nSide);
  516. }
  517. }
  518. //------------------------------------------------------------------------------
  519. // Purpose :
  520. // Input :
  521. // Output :
  522. //------------------------------------------------------------------------------
  523. bool C_BreakableSurface::HavePanel(int nWidth, int nHeight)
  524. {
  525. // If I'm off the edge, always give support
  526. if (!InLegalRange(nWidth,nHeight))
  527. {
  528. return true;
  529. }
  530. return (IsPanelSolid(nWidth,nHeight));
  531. }
  532. //------------------------------------------------------------------------------
  533. // Purpose :
  534. // Input :
  535. // Output :
  536. //------------------------------------------------------------------------------
  537. void C_BreakableSurface::UpdateEdgeType(int nWidth, int nHeight, int forceStyle /*=-1*/ )
  538. {
  539. Assert( forceStyle < NUM_EDGE_STYLES );
  540. // -----------------------------------
  541. // Check edge conditions
  542. // -----------------------------------
  543. if (!InLegalRange(nWidth,nHeight))
  544. {
  545. return;
  546. }
  547. // ----------------------------------
  548. // If solid has no edges
  549. // ----------------------------------
  550. if (IsPanelSolid(nWidth,nHeight))
  551. {
  552. return;
  553. }
  554. // Panel is no longer stale
  555. SetPanelStale(nWidth, nHeight,false);
  556. // ----------------------------------
  557. // Set edge type base on neighbors
  558. // ----------------------------------
  559. bool bUp = HavePanel(nWidth, nHeight+1);
  560. bool bDown = HavePanel(nWidth, nHeight-1);
  561. bool bLeft = HavePanel(nWidth-1, nHeight );
  562. bool bRight = HavePanel(nWidth+1, nHeight );
  563. bool bUpLeft = HavePanel(nWidth-1, nHeight+1);
  564. bool bUpRight = HavePanel(nWidth+1, nHeight+1);
  565. bool bDownLeft = HavePanel(nWidth-1, nHeight-1);
  566. bool bDownRight = HavePanel(nWidth+1, nHeight-1);
  567. //-------------
  568. // Top
  569. //-------------
  570. if (bUp)
  571. {
  572. bool bLeftEdge = !bLeft && bUpLeft;
  573. bool bRightEdge = !bRight && bUpRight;
  574. if (bLeftEdge && bRightEdge)
  575. {
  576. AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_FULL, forceStyle );
  577. }
  578. else if (bLeftEdge)
  579. {
  580. AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_LEFT, forceStyle );
  581. }
  582. else if (bRightEdge)
  583. {
  584. AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_RIGHT, forceStyle );
  585. }
  586. else
  587. {
  588. AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NONE, forceStyle );
  589. }
  590. }
  591. else
  592. {
  593. AddToRenderList(nWidth, nHeight, WIN_SIDE_TOP, EDGE_NOT, forceStyle );
  594. }
  595. //-------------
  596. // Bottom
  597. //-------------
  598. if (bDown)
  599. {
  600. bool bLeftEdge = !bLeft && bDownLeft;
  601. bool bRightEdge = !bRight && bDownRight;
  602. if (bLeftEdge && bRightEdge)
  603. {
  604. AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_FULL, forceStyle );
  605. }
  606. else if (bLeftEdge)
  607. {
  608. AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_RIGHT, forceStyle );
  609. }
  610. else if (bRightEdge)
  611. {
  612. AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_LEFT, forceStyle );
  613. }
  614. else
  615. {
  616. AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NONE, forceStyle );
  617. }
  618. }
  619. else
  620. {
  621. AddToRenderList(nWidth, nHeight, WIN_SIDE_BOTTOM, EDGE_NOT, forceStyle );
  622. }
  623. //-------------
  624. // Left
  625. //-------------
  626. if (bLeft)
  627. {
  628. bool bTop = !bUp && bUpLeft;
  629. bool bBottom = !bDown && bDownLeft;
  630. if (bTop && bBottom)
  631. {
  632. AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_FULL, forceStyle );
  633. }
  634. else if (bTop)
  635. {
  636. AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_RIGHT, forceStyle );
  637. }
  638. else if (bBottom)
  639. {
  640. AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_LEFT, forceStyle );
  641. }
  642. else
  643. {
  644. AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NONE, forceStyle );
  645. }
  646. }
  647. else
  648. {
  649. AddToRenderList(nWidth, nHeight, WIN_SIDE_LEFT, EDGE_NOT, forceStyle );
  650. }
  651. //-------------
  652. // Right
  653. //-------------
  654. if (bRight)
  655. {
  656. bool bTop = !bUp && bUpRight;
  657. bool bBottom = !bDown && bDownRight;
  658. if (bTop && bBottom)
  659. {
  660. AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_FULL, forceStyle );
  661. }
  662. else if (bTop)
  663. {
  664. AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_LEFT, forceStyle );
  665. }
  666. else if (bBottom)
  667. {
  668. AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_RIGHT, forceStyle );
  669. }
  670. else
  671. {
  672. AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NONE, forceStyle );
  673. }
  674. }
  675. else
  676. {
  677. AddToRenderList(nWidth, nHeight, WIN_SIDE_RIGHT, EDGE_NOT, forceStyle );
  678. }
  679. }
  680. //--------------------------------------------------------------------------------
  681. // Purpose : Return index to panel in render list that meets these qualifications
  682. // Input :
  683. // Output :
  684. //--------------------------------------------------------------------------------
  685. int C_BreakableSurface::FindRenderPanel(int nWidth, int nHeight, WinSide_t nWinSide)
  686. {
  687. for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
  688. {
  689. if (m_RenderList[i].m_nSide == nWinSide &&
  690. m_RenderList[i].m_nWidth == nWidth &&
  691. m_RenderList[i].m_nHeight == nHeight)
  692. {
  693. return i;
  694. }
  695. }
  696. return m_RenderList.InvalidIndex();
  697. }
  698. //----------------------------------------------------------------------------------
  699. // Purpose : Returns first element in render list with the same edge type and style
  700. // Input :
  701. // Output :
  702. //----------------------------------------------------------------------------------
  703. int C_BreakableSurface::FindFirstRenderTexture(WinEdge_t nEdgeType, int nStyle)
  704. {
  705. for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) )
  706. {
  707. if (m_RenderList[i].m_nStyle == nStyle &&
  708. m_RenderList[i].m_nEdgeType == nEdgeType )
  709. {
  710. return i;
  711. }
  712. }
  713. return m_RenderList.InvalidIndex();
  714. }
  715. //------------------------------------------------------------------------------
  716. // Purpose : Add a edge to be rendered to the render list
  717. // Input :
  718. // Output :
  719. //------------------------------------------------------------------------------
  720. void C_BreakableSurface::AddToRenderList(int nWidth, int nHeight, WinSide_t nSide, WinEdge_t nEdgeType, int forceStyle )
  721. {
  722. // -----------------------------------------------------
  723. // Try to find old panel
  724. int nOldPanelIndex = FindRenderPanel(nWidth,nHeight,nSide);
  725. // -----------------------------------------------------
  726. // If I have an old panel, get it's style and remove it
  727. // otherwise randomly chose a style
  728. int nStyle;
  729. if (m_RenderList.IsValidIndex(nOldPanelIndex) )
  730. {
  731. nStyle = m_RenderList[nOldPanelIndex].m_nStyle;
  732. m_RenderList.Remove(nOldPanelIndex);
  733. }
  734. else
  735. {
  736. nStyle = random->RandomInt(0,NUM_EDGE_STYLES-1);
  737. }
  738. if ( forceStyle != -1 )
  739. {
  740. nStyle = forceStyle;
  741. }
  742. // -----------------------------------------------------
  743. // If my new panel has an edge, add it to render list
  744. if (nEdgeType != EDGE_NOT)
  745. {
  746. // Renderlist is sorted by texture type. Find first element
  747. // that shares the same texture as the new panel
  748. unsigned short nTexIndex = FindFirstRenderTexture(nEdgeType, nStyle);
  749. // If texture was already in list, add after last use
  750. unsigned short nNewIndex;
  751. if (m_RenderList.IsValidIndex(nTexIndex))
  752. {
  753. nNewIndex = m_RenderList.InsertAfter(nTexIndex);
  754. }
  755. // Otherwise add to send of render list
  756. else
  757. {
  758. nNewIndex = m_RenderList.AddToTail();
  759. }
  760. // Now fill out my data
  761. m_RenderList[nNewIndex].m_nHeight = nHeight;
  762. m_RenderList[nNewIndex].m_nWidth = nWidth;
  763. m_RenderList[nNewIndex].m_nEdgeType = nEdgeType;
  764. m_RenderList[nNewIndex].m_nSide = nSide;
  765. m_RenderList[nNewIndex].m_nStyle = nStyle;
  766. Assert( nStyle < NUM_EDGE_STYLES );
  767. SetStyleType( nWidth, nHeight, nStyle );
  768. }
  769. }
  770. //------------------------------------------------------------------------------
  771. // Purpose :
  772. // Input :
  773. // Output :
  774. //------------------------------------------------------------------------------
  775. void C_BreakableSurface::DrawSolidBlocks(IBrushSurface* pBrushSurface)
  776. {
  777. CMatRenderContextPtr pRenderContext( materials );
  778. m_pCurrentDetailTexture = m_pMaterialBoxTexture;
  779. // Gotta flush (in a non-stalling way) because we effectively
  780. // have a new material due to the new base texture
  781. pRenderContext->Flush(false);
  782. pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this);
  783. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  784. CMeshBuilder pMeshBuilder;
  785. // ---------------
  786. // Create panels
  787. // ---------------
  788. QAngle vAngles;
  789. VectorAngles(-1*m_vNormal,vAngles);
  790. Vector vWidthStep,vHeightStep;
  791. AngleVectors(vAngles,NULL,&vWidthStep,&vHeightStep);
  792. vWidthStep *= m_flPanelWidth;
  793. vHeightStep *= m_flPanelHeight;
  794. Vector vCurPos = m_vCorner;
  795. for (int width=0;width<m_nNumWide;width++)
  796. {
  797. int height;
  798. int nHCount = 0;
  799. for (height=0;height<m_nNumHigh;height++)
  800. {
  801. // Keep count of how many panes there are in a row
  802. if (IsPanelSolid(width,height))
  803. {
  804. nHCount++;
  805. }
  806. // Drow the strip and start counting again
  807. else if (nHCount > 0)
  808. {
  809. vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
  810. DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
  811. nHCount = 0;
  812. }
  813. }
  814. if (nHCount)
  815. {
  816. vCurPos = m_vCorner + vWidthStep*width + vHeightStep*(height-nHCount);
  817. DrawOneBlock(pBrushSurface, pMesh, &pMeshBuilder, vCurPos,vWidthStep,vHeightStep*nHCount);
  818. }
  819. }
  820. }
  821. //------------------------------------------------------------------------------
  822. // Purpose :
  823. // Input :
  824. // Output :
  825. //------------------------------------------------------------------------------
  826. void C_BreakableSurface::DrawOneBlock(IBrushSurface* pBrushSurface, IMesh* pMesh,
  827. CMeshBuilder *pMeshBuilder, const Vector &vCurPos, const Vector &vWidthStep,
  828. const Vector &vHeightStep)
  829. {
  830. pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
  831. Vector2D texCoord, lightCoord;
  832. pBrushSurface->ComputeTextureCoordinate( vCurPos, texCoord );
  833. pBrushSurface->ComputeLightmapCoordinate( vCurPos, lightCoord );
  834. pMeshBuilder->Position3f( vCurPos.x, vCurPos.y, vCurPos.z );
  835. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  836. pMeshBuilder->TexCoord2f( 0, 0, 1 );
  837. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  838. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  839. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  840. pMeshBuilder->AdvanceVertex();
  841. Vector vNextPos = vCurPos + vWidthStep;
  842. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  843. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  844. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
  845. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  846. pMeshBuilder->TexCoord2f( 0, 0, 0 );
  847. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  848. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  849. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  850. pMeshBuilder->AdvanceVertex();
  851. vNextPos = vNextPos + vHeightStep;
  852. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  853. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  854. pMeshBuilder->Position3f( vNextPos.x , vNextPos.y, vNextPos.z );
  855. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  856. pMeshBuilder->TexCoord2f( 0, 1, 0 );
  857. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  858. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  859. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  860. pMeshBuilder->AdvanceVertex();
  861. vNextPos = vNextPos - vWidthStep;
  862. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  863. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  864. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y , vNextPos.z);
  865. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  866. pMeshBuilder->TexCoord2f( 0, 1, 1 );
  867. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  868. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  869. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  870. pMeshBuilder->AdvanceVertex();
  871. pMeshBuilder->End();
  872. pMesh->Draw();
  873. }
  874. //------------------------------------------------------------------------------
  875. // Purpose :
  876. // Input :
  877. // Output :
  878. //------------------------------------------------------------------------------
  879. void C_BreakableSurface::DrawOneEdge( IBrushSurface* pBrushSurface, IMesh* pMesh,
  880. CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
  881. const Vector &vHStep, WinSide_t nEdge )
  882. {
  883. pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
  884. Vector2D texCoord, lightCoord;
  885. pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
  886. pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
  887. pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
  888. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  889. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  890. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  891. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  892. switch (nEdge)
  893. {
  894. case WIN_SIDE_RIGHT:
  895. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  896. break;
  897. case WIN_SIDE_BOTTOM:
  898. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  899. break;
  900. case WIN_SIDE_LEFT:
  901. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  902. break;
  903. case WIN_SIDE_TOP:
  904. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  905. break;
  906. }
  907. pMeshBuilder->AdvanceVertex();
  908. Vector vNextPos = vStartPos + vWStep;
  909. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  910. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  911. pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
  912. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  913. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  914. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  915. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  916. switch (nEdge)
  917. {
  918. case WIN_SIDE_RIGHT:
  919. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  920. break;
  921. case WIN_SIDE_BOTTOM:
  922. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  923. break;
  924. case WIN_SIDE_LEFT:
  925. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  926. break;
  927. case WIN_SIDE_TOP:
  928. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  929. break;
  930. }
  931. pMeshBuilder->AdvanceVertex();
  932. vNextPos = vNextPos + vHStep;
  933. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  934. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  935. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
  936. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  937. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  938. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  939. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  940. switch (nEdge)
  941. {
  942. case WIN_SIDE_RIGHT:
  943. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  944. break;
  945. case WIN_SIDE_BOTTOM:
  946. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  947. break;
  948. case WIN_SIDE_LEFT:
  949. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  950. break;
  951. case WIN_SIDE_TOP:
  952. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  953. break;
  954. }
  955. pMeshBuilder->AdvanceVertex();
  956. vNextPos = vNextPos - vWStep;
  957. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  958. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  959. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
  960. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  961. pMeshBuilder->Color4ub( 255, 255, 255, 255 );
  962. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  963. pMeshBuilder->TexCoord2fv( 2, texCoord.Base() );
  964. switch (nEdge)
  965. {
  966. case WIN_SIDE_RIGHT:
  967. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  968. break;
  969. case WIN_SIDE_BOTTOM:
  970. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  971. break;
  972. case WIN_SIDE_LEFT:
  973. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  974. break;
  975. case WIN_SIDE_TOP:
  976. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  977. break;
  978. }
  979. pMeshBuilder->AdvanceVertex();
  980. pMeshBuilder->End();
  981. pMesh->Draw();
  982. }
  983. //------------------------------------------------------------------------------
  984. // Purpose :
  985. // Input :
  986. // Output :
  987. //------------------------------------------------------------------------------
  988. void C_BreakableSurface::DrawOneHighlight( IBrushSurface* pBrushSurface, IMesh* pMesh,
  989. CMeshBuilder *pMeshBuilder, const Vector &vStartPos, const Vector &vWStep,
  990. const Vector &vHStep, WinSide_t nEdge )
  991. {
  992. Vector vColor = Vector(0.41,0.35,0.24);
  993. pMeshBuilder->Begin( pMesh, MATERIAL_QUADS, 1 );
  994. Vector2D texCoord, lightCoord;
  995. pBrushSurface->ComputeTextureCoordinate( vStartPos, texCoord );
  996. pBrushSurface->ComputeLightmapCoordinate( vStartPos, lightCoord );
  997. pMeshBuilder->Position3f( vStartPos.x, vStartPos.y, vStartPos.z);
  998. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  999. pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
  1000. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  1001. switch (nEdge)
  1002. {
  1003. case WIN_SIDE_RIGHT:
  1004. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  1005. break;
  1006. case WIN_SIDE_BOTTOM:
  1007. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  1008. break;
  1009. case WIN_SIDE_LEFT:
  1010. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  1011. break;
  1012. case WIN_SIDE_TOP:
  1013. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  1014. break;
  1015. }
  1016. pMeshBuilder->AdvanceVertex();
  1017. Vector vNextPos = vStartPos + vWStep;
  1018. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  1019. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  1020. pMeshBuilder->Position3f( vNextPos.x , vNextPos.y , vNextPos.z);
  1021. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  1022. pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
  1023. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  1024. switch (nEdge)
  1025. {
  1026. case WIN_SIDE_RIGHT:
  1027. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  1028. break;
  1029. case WIN_SIDE_BOTTOM:
  1030. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  1031. break;
  1032. case WIN_SIDE_LEFT:
  1033. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  1034. break;
  1035. case WIN_SIDE_TOP:
  1036. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  1037. break;
  1038. }
  1039. pMeshBuilder->AdvanceVertex();
  1040. vNextPos = vNextPos + vHStep;
  1041. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  1042. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  1043. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
  1044. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  1045. pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
  1046. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  1047. switch (nEdge)
  1048. {
  1049. case WIN_SIDE_RIGHT:
  1050. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  1051. break;
  1052. case WIN_SIDE_BOTTOM:
  1053. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  1054. break;
  1055. case WIN_SIDE_LEFT:
  1056. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  1057. break;
  1058. case WIN_SIDE_TOP:
  1059. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  1060. break;
  1061. }
  1062. pMeshBuilder->AdvanceVertex();
  1063. vNextPos = vNextPos - vWStep;
  1064. pBrushSurface->ComputeTextureCoordinate( vNextPos, texCoord );
  1065. pBrushSurface->ComputeLightmapCoordinate( vNextPos, lightCoord );
  1066. pMeshBuilder->Position3f( vNextPos.x, vNextPos.y, vNextPos.z );
  1067. pMeshBuilder->Normal3fv( m_vNormal.Base() );
  1068. pMeshBuilder->Color4f( vColor[0], vColor[1], vColor[2], 1.0);
  1069. pMeshBuilder->TexCoord2fv( 1, lightCoord.Base() );
  1070. switch (nEdge)
  1071. {
  1072. case WIN_SIDE_RIGHT:
  1073. pMeshBuilder->TexCoord2f( 0, 0.0f, 0.0f );
  1074. break;
  1075. case WIN_SIDE_BOTTOM:
  1076. pMeshBuilder->TexCoord2f( 0, 1.0f, 0.0f );
  1077. break;
  1078. case WIN_SIDE_LEFT:
  1079. pMeshBuilder->TexCoord2f( 0, 1.0f, 1.0f );
  1080. break;
  1081. case WIN_SIDE_TOP:
  1082. pMeshBuilder->TexCoord2f( 0, 0.0f, 1.0f );
  1083. break;
  1084. }
  1085. pMeshBuilder->AdvanceVertex();
  1086. pMeshBuilder->End();
  1087. pMesh->Draw();
  1088. }
  1089. bool C_BreakableSurface::ShouldReceiveProjectedTextures( int flags )
  1090. {
  1091. return false;
  1092. }
  1093. //------------------------------------------------------------------------------
  1094. // A material proxy that resets the texture to use the original surface texture
  1095. //------------------------------------------------------------------------------
  1096. class CBreakableSurfaceProxy : public CEntityMaterialProxy
  1097. {
  1098. public:
  1099. CBreakableSurfaceProxy();
  1100. virtual ~CBreakableSurfaceProxy();
  1101. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  1102. virtual void OnBind( C_BaseEntity *pC_BaseEntity );
  1103. virtual IMaterial *GetMaterial();
  1104. private:
  1105. // get at the material whose texture we're going to steal
  1106. void AcquireSourceMaterial( C_BaseEntity* pEnt );
  1107. IMaterialVar* m_BaseTextureVar;
  1108. };
  1109. CBreakableSurfaceProxy::CBreakableSurfaceProxy()
  1110. {
  1111. m_BaseTextureVar = NULL;
  1112. }
  1113. CBreakableSurfaceProxy::~CBreakableSurfaceProxy()
  1114. {
  1115. }
  1116. bool CBreakableSurfaceProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  1117. {
  1118. bool foundVar;
  1119. m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  1120. return foundVar;
  1121. }
  1122. void CBreakableSurfaceProxy::OnBind( C_BaseEntity *pC_BaseEntity )
  1123. {
  1124. C_BreakableSurface *pEnt = dynamic_cast< C_BreakableSurface * >(pC_BaseEntity);
  1125. if( !pEnt )
  1126. {
  1127. return;
  1128. }
  1129. // Use the current base texture specified by the suface
  1130. m_BaseTextureVar->SetTextureValue( pEnt->m_pCurrentDetailTexture );
  1131. }
  1132. IMaterial *CBreakableSurfaceProxy::GetMaterial()
  1133. {
  1134. if ( !m_BaseTextureVar )
  1135. return NULL;
  1136. return m_BaseTextureVar->GetOwningMaterial();
  1137. }
  1138. EXPOSE_INTERFACE( CBreakableSurfaceProxy, IMaterialProxy, "BreakableSurface" IMATERIAL_PROXY_INTERFACE_VERSION );