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.

416 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Client's energy wave
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //-----------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #include "cbase.h"
  14. #include "materialsystem/imaterialsystem.h"
  15. #include "materialsystem/imesh.h"
  16. #include "energy_wave_effect.h"
  17. #include "mathlib/vmatrix.h"
  18. #include "clienteffectprecachesystem.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. CLIENTEFFECT_REGISTER_BEGIN( PrecacheEnergyWave )
  22. CLIENTEFFECT_MATERIAL( "effects/energywave/energywave" )
  23. CLIENTEFFECT_REGISTER_END()
  24. //-----------------------------------------------------------------------------
  25. // Energy Wave:
  26. //-----------------------------------------------------------------------------
  27. class C_EnergyWave : public C_BaseEntity
  28. {
  29. public:
  30. DECLARE_CLASS( C_EnergyWave, C_BaseEntity );
  31. DECLARE_CLIENTCLASS();
  32. C_EnergyWave();
  33. ~C_EnergyWave();
  34. void PostDataUpdate( DataUpdateType_t updateType );
  35. int DrawModel( int flags );
  36. void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity );
  37. void DrawWireframeModel( );
  38. CEnergyWaveEffect m_EWaveEffect;
  39. IMaterial* m_pWireframe;
  40. IMaterial* m_pEWaveMat;
  41. private:
  42. C_EnergyWave( const C_EnergyWave & ); // not defined, not accessible
  43. void ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity );
  44. void DrawEWavePoints(Vector* pt, Vector* normal, float* opacity);
  45. };
  46. EXTERN_RECV_TABLE(DT_BaseEntity);
  47. IMPLEMENT_CLIENTCLASS_DT(C_EnergyWave, DT_EWaveEffect, CEnergyWave)
  48. END_RECV_TABLE()
  49. // ----------------------------------------------------------------------------
  50. // Functions.
  51. // ----------------------------------------------------------------------------
  52. C_EnergyWave::C_EnergyWave() : m_EWaveEffect(NULL, NULL)
  53. {
  54. m_pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
  55. m_pEWaveMat = materials->FindMaterial("effects/energywave/energywave", TEXTURE_GROUP_CLIENT_EFFECTS);
  56. m_EWaveEffect.Spawn();
  57. }
  58. C_EnergyWave::~C_EnergyWave()
  59. {
  60. }
  61. void C_EnergyWave::PostDataUpdate( DataUpdateType_t updateType )
  62. {
  63. MarkMessageReceived();
  64. // Make sure that origin points to current origin, at least
  65. MoveToLastReceivedPosition();
  66. }
  67. enum
  68. {
  69. NUM_SUBDIVISIONS = 21,
  70. };
  71. static void ComputeIndices( int is, int it, int* idx )
  72. {
  73. int is0 = (is > 0) ? (is - 1) : is;
  74. int it0 = (it > 0) ? (it - 1) : it;
  75. int is1 = (is < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? is + 1 : is;
  76. int it1 = (it < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? it + 1 : it;
  77. int is2 = is + 2;
  78. int it2 = it + 2;
  79. if (is2 >= EWAVE_NUM_HORIZONTAL_POINTS)
  80. is2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
  81. if (it2 >= EWAVE_NUM_HORIZONTAL_POINTS)
  82. it2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
  83. idx[0] = is0 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
  84. idx[1] = is + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
  85. idx[2] = is1 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
  86. idx[3] = is2 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
  87. idx[4] = is0 + it * EWAVE_NUM_HORIZONTAL_POINTS;
  88. idx[5] = is + it * EWAVE_NUM_HORIZONTAL_POINTS;
  89. idx[6] = is1 + it * EWAVE_NUM_HORIZONTAL_POINTS;
  90. idx[7] = is2 + it * EWAVE_NUM_HORIZONTAL_POINTS;
  91. idx[8] = is0 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
  92. idx[9] = is + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
  93. idx[10] = is1 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
  94. idx[11] = is2 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
  95. idx[12] = is0 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
  96. idx[13] = is + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
  97. idx[14] = is1 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
  98. idx[15] = is2 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
  99. }
  100. void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
  101. {
  102. int is = (int)s;
  103. int it = (int)t;
  104. if( is >= EWAVE_NUM_HORIZONTAL_POINTS )
  105. is -= 1;
  106. if( it >= EWAVE_NUM_VERTICAL_POINTS )
  107. it -= 1;
  108. int idx[16];
  109. ComputeIndices( is, it, idx );
  110. // The patch equation is:
  111. // px = S * M * Gx * M^T * T^T
  112. // py = S * M * Gy * M^T * T^T
  113. // pz = S * M * Gz * M^T * T^T
  114. // where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1]
  115. // M is the patch type matrix, in my case I'm using a catmull-rom
  116. // G is the array of control points. rows have constant t
  117. static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5,
  118. 1, -2.5, 2, -0.5,
  119. -0.5, 0, 0.5, 0,
  120. 0, 1, 0, 0 );
  121. VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO;
  122. Vector pos;
  123. for (int i = 0; i < 4; ++i)
  124. {
  125. for (int j = 0; j < 4; ++j)
  126. {
  127. const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] );
  128. controlPointsX[j][i] = v.x;
  129. controlPointsY[j][i] = v.y;
  130. controlPointsZ[j][i] = v.z;
  131. controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() );
  132. }
  133. }
  134. float fs = s - is;
  135. float ft = t - it;
  136. VMatrix temp, mgm[4];
  137. MatrixTranspose( catmullRom, temp );
  138. MatrixMultiply( controlPointsX, temp, mgm[0] );
  139. MatrixMultiply( controlPointsY, temp, mgm[1] );
  140. MatrixMultiply( controlPointsZ, temp, mgm[2] );
  141. MatrixMultiply( controlPointsO, temp, mgm[3] );
  142. MatrixMultiply( catmullRom, mgm[0], mgm[0] );
  143. MatrixMultiply( catmullRom, mgm[1], mgm[1] );
  144. MatrixMultiply( catmullRom, mgm[2], mgm[2] );
  145. MatrixMultiply( catmullRom, mgm[3], mgm[3] );
  146. Vector4D svec, tvec;
  147. float ft2 = ft * ft;
  148. tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f;
  149. float fs2 = fs * fs;
  150. svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f;
  151. Vector4D tmp;
  152. Vector4DMultiply( mgm[0], tvec, tmp );
  153. pt[0] = DotProduct4D( tmp, svec );
  154. Vector4DMultiply( mgm[1], tvec, tmp );
  155. pt[1] = DotProduct4D( tmp, svec );
  156. Vector4DMultiply( mgm[2], tvec, tmp );
  157. pt[2] = DotProduct4D( tmp, svec );
  158. Vector4DMultiply( mgm[3], tvec, tmp );
  159. opacity = DotProduct4D( tmp, svec );
  160. if ((s == 0.0f) || (t == 0.0f) ||
  161. (s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) )
  162. {
  163. opacity = 0.0f;
  164. }
  165. if ((s <= 0.3) || (t < 0.3))
  166. {
  167. opacity *= 0.35f;
  168. }
  169. if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) )
  170. {
  171. opacity *= 0.35f;
  172. }
  173. if (opacity < 0.0f)
  174. opacity = 0.0f;
  175. else if (opacity > 255.0f)
  176. opacity = 255.0f;
  177. // Normal computation
  178. Vector4D dsvec, dtvec;
  179. dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f;
  180. dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f;
  181. Vector ds, dt;
  182. Vector4DMultiply( mgm[0], tvec, tmp );
  183. ds[0] = DotProduct4D( tmp, dsvec );
  184. Vector4DMultiply( mgm[1], tvec, tmp );
  185. ds[1] = DotProduct4D( tmp, dsvec );
  186. Vector4DMultiply( mgm[2], tvec, tmp );
  187. ds[2] = DotProduct4D( tmp, dsvec );
  188. Vector4DMultiply( mgm[0], dtvec, tmp );
  189. dt[0] = DotProduct4D( tmp, svec );
  190. Vector4DMultiply( mgm[1], dtvec, tmp );
  191. dt[1] = DotProduct4D( tmp, svec );
  192. Vector4DMultiply( mgm[2], dtvec, tmp );
  193. dt[2] = DotProduct4D( tmp, svec );
  194. CrossProduct( ds, dt, normal );
  195. VectorNormalize( normal );
  196. }
  197. void C_EnergyWave::DrawWireframeModel( )
  198. {
  199. IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
  200. int numLines = (EWAVE_NUM_VERTICAL_POINTS - 1) * EWAVE_NUM_HORIZONTAL_POINTS +
  201. EWAVE_NUM_VERTICAL_POINTS * (EWAVE_NUM_HORIZONTAL_POINTS - 1);
  202. CMeshBuilder meshBuilder;
  203. meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines );
  204. Vector tmp;
  205. for (int i = 0; i < EWAVE_NUM_VERTICAL_POINTS; ++i)
  206. {
  207. for (int j = 0; j < EWAVE_NUM_HORIZONTAL_POINTS; ++j)
  208. {
  209. if ( i > 0 )
  210. {
  211. meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
  212. meshBuilder.Color4ub( 255, 255, 255, 128 );
  213. meshBuilder.AdvanceVertex();
  214. meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i - 1 ).Base() );
  215. meshBuilder.Color4ub( 255, 255, 255, 128 );
  216. meshBuilder.AdvanceVertex();
  217. }
  218. if (j > 0)
  219. {
  220. meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
  221. meshBuilder.Color4ub( 255, 255, 255, 128 );
  222. meshBuilder.AdvanceVertex();
  223. meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j - 1, i ).Base() );
  224. meshBuilder.Color4ub( 255, 255, 255, 128 );
  225. meshBuilder.AdvanceVertex();
  226. }
  227. }
  228. }
  229. meshBuilder.End();
  230. pMesh->Draw();
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Compute the ewave points using catmull-rom
  234. //-----------------------------------------------------------------------------
  235. void C_EnergyWave::ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity )
  236. {
  237. int i;
  238. for ( i = 0; i < NUM_SUBDIVISIONS; ++i)
  239. {
  240. float t = (EWAVE_NUM_VERTICAL_POINTS -1 ) * (float)i / (float)(NUM_SUBDIVISIONS - 1);
  241. for (int j = 0; j < NUM_SUBDIVISIONS; ++j)
  242. {
  243. float s = (EWAVE_NUM_HORIZONTAL_POINTS-1) * (float)j / (float)(NUM_SUBDIVISIONS - 1);
  244. int idx = i * NUM_SUBDIVISIONS + j;
  245. ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] );
  246. }
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Draws the base ewave
  251. //-----------------------------------------------------------------------------
  252. #define TRANSITION_REGION_WIDTH 0.5f
  253. void C_EnergyWave::DrawEWavePoints(Vector* pt, Vector* normal, float* opacity)
  254. {
  255. IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEWaveMat );
  256. int numTriangles = (NUM_SUBDIVISIONS - 1) * (NUM_SUBDIVISIONS - 1) * 2;
  257. CMeshBuilder meshBuilder;
  258. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
  259. float du = 1.0f / (float)(NUM_SUBDIVISIONS - 1);
  260. float dv = du;
  261. unsigned char color[3];
  262. color[0] = 255;
  263. color[1] = 255;
  264. color[2] = 255;
  265. for ( int i = 0; i < NUM_SUBDIVISIONS - 1; ++i)
  266. {
  267. float v = i * dv;
  268. for (int j = 0; j < NUM_SUBDIVISIONS - 1; ++j)
  269. {
  270. int idx = i * NUM_SUBDIVISIONS + j;
  271. float u = j * du;
  272. meshBuilder.Position3fv( pt[idx].Base() );
  273. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] );
  274. meshBuilder.Normal3fv( normal[idx].Base() );
  275. meshBuilder.TexCoord2f( 0, u, v );
  276. meshBuilder.AdvanceVertex();
  277. meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
  278. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
  279. meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
  280. meshBuilder.TexCoord2f( 0, u, v + dv );
  281. meshBuilder.AdvanceVertex();
  282. meshBuilder.Position3fv( pt[idx + 1].Base() );
  283. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
  284. meshBuilder.Normal3fv( normal[idx+1].Base() );
  285. meshBuilder.TexCoord2f( 0, u + du, v );
  286. meshBuilder.AdvanceVertex();
  287. meshBuilder.Position3fv( pt[idx + 1].Base() );
  288. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
  289. meshBuilder.Normal3fv( normal[idx+1].Base() );
  290. meshBuilder.TexCoord2f( 0, u + du, v );
  291. meshBuilder.AdvanceVertex();
  292. meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
  293. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
  294. meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
  295. meshBuilder.TexCoord2f( 0, u, v + dv );
  296. meshBuilder.AdvanceVertex();
  297. meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS + 1].Base() );
  298. meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS+1] );
  299. meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS + 1].Base() );
  300. meshBuilder.TexCoord2f( 0, u + du, v + dv );
  301. meshBuilder.AdvanceVertex();
  302. }
  303. }
  304. meshBuilder.End();
  305. pMesh->Draw();
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Main draw entry point
  309. //-----------------------------------------------------------------------------
  310. int C_EnergyWave::DrawModel( int flags )
  311. {
  312. if ( !m_bReadyToDraw )
  313. return 0;
  314. // NOTE: We've got a stiff spring case here, we need to simulate at
  315. // a fairly fast timestep. A better solution would be to use an
  316. // implicit method, which I'm going to not implement for the moment
  317. float dt = gpGlobals->frametime;
  318. m_EWaveEffect.SetPosition( GetAbsOrigin(), GetAbsAngles() );
  319. m_EWaveEffect.Simulate(dt);
  320. Vector pt[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
  321. Vector normal[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
  322. float opacity[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
  323. ComputeEWavePoints( pt, normal, opacity );
  324. DrawEWavePoints( pt, normal, opacity );
  325. return 1;
  326. }