Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1168 lines
34 KiB

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