aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/hl2/c_energy_wave.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mp/src/game/client/hl2/c_energy_wave.cpp')
-rw-r--r--mp/src/game/client/hl2/c_energy_wave.cpp416
1 files changed, 416 insertions, 0 deletions
diff --git a/mp/src/game/client/hl2/c_energy_wave.cpp b/mp/src/game/client/hl2/c_energy_wave.cpp
new file mode 100644
index 00000000..97655f53
--- /dev/null
+++ b/mp/src/game/client/hl2/c_energy_wave.cpp
@@ -0,0 +1,416 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's energy wave
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imesh.h"
+#include "energy_wave_effect.h"
+#include "mathlib/vmatrix.h"
+#include "clienteffectprecachesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEnergyWave )
+CLIENTEFFECT_MATERIAL( "effects/energywave/energywave" )
+CLIENTEFFECT_REGISTER_END()
+
+//-----------------------------------------------------------------------------
+// Energy Wave:
+//-----------------------------------------------------------------------------
+
+class C_EnergyWave : public C_BaseEntity
+{
+public:
+ DECLARE_CLASS( C_EnergyWave, C_BaseEntity );
+ DECLARE_CLIENTCLASS();
+
+ C_EnergyWave();
+ ~C_EnergyWave();
+
+ void PostDataUpdate( DataUpdateType_t updateType );
+ int DrawModel( int flags );
+ void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity );
+ void DrawWireframeModel( );
+
+ CEnergyWaveEffect m_EWaveEffect;
+
+ IMaterial* m_pWireframe;
+ IMaterial* m_pEWaveMat;
+
+private:
+ C_EnergyWave( const C_EnergyWave & ); // not defined, not accessible
+
+ void ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity );
+ void DrawEWavePoints(Vector* pt, Vector* normal, float* opacity);
+
+};
+
+
+EXTERN_RECV_TABLE(DT_BaseEntity);
+
+IMPLEMENT_CLIENTCLASS_DT(C_EnergyWave, DT_EWaveEffect, CEnergyWave)
+END_RECV_TABLE()
+
+
+// ----------------------------------------------------------------------------
+// Functions.
+// ----------------------------------------------------------------------------
+
+C_EnergyWave::C_EnergyWave() : m_EWaveEffect(NULL, NULL)
+{
+ m_pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
+ m_pEWaveMat = materials->FindMaterial("effects/energywave/energywave", TEXTURE_GROUP_CLIENT_EFFECTS);
+ m_EWaveEffect.Spawn();
+}
+
+C_EnergyWave::~C_EnergyWave()
+{
+}
+
+void C_EnergyWave::PostDataUpdate( DataUpdateType_t updateType )
+{
+ MarkMessageReceived();
+
+ // Make sure that origin points to current origin, at least
+ MoveToLastReceivedPosition();
+}
+
+
+
+enum
+{
+ NUM_SUBDIVISIONS = 21,
+};
+
+
+static void ComputeIndices( int is, int it, int* idx )
+{
+ int is0 = (is > 0) ? (is - 1) : is;
+ int it0 = (it > 0) ? (it - 1) : it;
+ int is1 = (is < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? is + 1 : is;
+ int it1 = (it < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? it + 1 : it;
+ int is2 = is + 2;
+ int it2 = it + 2;
+ if (is2 >= EWAVE_NUM_HORIZONTAL_POINTS)
+ is2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
+ if (it2 >= EWAVE_NUM_HORIZONTAL_POINTS)
+ it2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
+
+ idx[0] = is0 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[1] = is + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[2] = is1 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[3] = is2 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
+
+ idx[4] = is0 + it * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[5] = is + it * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[6] = is1 + it * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[7] = is2 + it * EWAVE_NUM_HORIZONTAL_POINTS;
+
+ idx[8] = is0 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[9] = is + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[10] = is1 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[11] = is2 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
+
+ idx[12] = is0 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[13] = is + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[14] = is1 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
+ idx[15] = is2 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
+}
+
+void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
+{
+ int is = (int)s;
+ int it = (int)t;
+ if( is >= EWAVE_NUM_HORIZONTAL_POINTS )
+ is -= 1;
+
+ if( it >= EWAVE_NUM_VERTICAL_POINTS )
+ it -= 1;
+
+ int idx[16];
+ ComputeIndices( is, it, idx );
+
+ // The patch equation is:
+ // px = S * M * Gx * M^T * T^T
+ // py = S * M * Gy * M^T * T^T
+ // pz = S * M * Gz * M^T * T^T
+ // where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1]
+ // M is the patch type matrix, in my case I'm using a catmull-rom
+ // G is the array of control points. rows have constant t
+ static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5,
+ 1, -2.5, 2, -0.5,
+ -0.5, 0, 0.5, 0,
+ 0, 1, 0, 0 );
+
+ VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO;
+
+ Vector pos;
+ for (int i = 0; i < 4; ++i)
+ {
+ for (int j = 0; j < 4; ++j)
+ {
+ const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] );
+
+ controlPointsX[j][i] = v.x;
+ controlPointsY[j][i] = v.y;
+ controlPointsZ[j][i] = v.z;
+
+ controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() );
+ }
+ }
+
+ float fs = s - is;
+ float ft = t - it;
+
+ VMatrix temp, mgm[4];
+ MatrixTranspose( catmullRom, temp );
+ MatrixMultiply( controlPointsX, temp, mgm[0] );
+ MatrixMultiply( controlPointsY, temp, mgm[1] );
+ MatrixMultiply( controlPointsZ, temp, mgm[2] );
+ MatrixMultiply( controlPointsO, temp, mgm[3] );
+
+ MatrixMultiply( catmullRom, mgm[0], mgm[0] );
+ MatrixMultiply( catmullRom, mgm[1], mgm[1] );
+ MatrixMultiply( catmullRom, mgm[2], mgm[2] );
+ MatrixMultiply( catmullRom, mgm[3], mgm[3] );
+
+ Vector4D svec, tvec;
+ float ft2 = ft * ft;
+ tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f;
+
+ float fs2 = fs * fs;
+ svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f;
+
+ Vector4D tmp;
+ Vector4DMultiply( mgm[0], tvec, tmp );
+ pt[0] = DotProduct4D( tmp, svec );
+ Vector4DMultiply( mgm[1], tvec, tmp );
+ pt[1] = DotProduct4D( tmp, svec );
+ Vector4DMultiply( mgm[2], tvec, tmp );
+ pt[2] = DotProduct4D( tmp, svec );
+
+ Vector4DMultiply( mgm[3], tvec, tmp );
+ opacity = DotProduct4D( tmp, svec );
+
+ if ((s == 0.0f) || (t == 0.0f) ||
+ (s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) )
+ {
+ opacity = 0.0f;
+ }
+
+ if ((s <= 0.3) || (t < 0.3))
+ {
+ opacity *= 0.35f;
+ }
+ if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) )
+ {
+ opacity *= 0.35f;
+ }
+
+ if (opacity < 0.0f)
+ opacity = 0.0f;
+ else if (opacity > 255.0f)
+ opacity = 255.0f;
+
+ // Normal computation
+ Vector4D dsvec, dtvec;
+ dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f;
+ dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f;
+
+ Vector ds, dt;
+ Vector4DMultiply( mgm[0], tvec, tmp );
+ ds[0] = DotProduct4D( tmp, dsvec );
+ Vector4DMultiply( mgm[1], tvec, tmp );
+ ds[1] = DotProduct4D( tmp, dsvec );
+ Vector4DMultiply( mgm[2], tvec, tmp );
+ ds[2] = DotProduct4D( tmp, dsvec );
+
+ Vector4DMultiply( mgm[0], dtvec, tmp );
+ dt[0] = DotProduct4D( tmp, svec );
+ Vector4DMultiply( mgm[1], dtvec, tmp );
+ dt[1] = DotProduct4D( tmp, svec );
+ Vector4DMultiply( mgm[2], dtvec, tmp );
+ dt[2] = DotProduct4D( tmp, svec );
+
+ CrossProduct( ds, dt, normal );
+ VectorNormalize( normal );
+}
+
+void C_EnergyWave::DrawWireframeModel( )
+{
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
+
+ int numLines = (EWAVE_NUM_VERTICAL_POINTS - 1) * EWAVE_NUM_HORIZONTAL_POINTS +
+ EWAVE_NUM_VERTICAL_POINTS * (EWAVE_NUM_HORIZONTAL_POINTS - 1);
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines );
+
+ Vector tmp;
+ for (int i = 0; i < EWAVE_NUM_VERTICAL_POINTS; ++i)
+ {
+ for (int j = 0; j < EWAVE_NUM_HORIZONTAL_POINTS; ++j)
+ {
+ if ( i > 0 )
+ {
+ meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i - 1 ).Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+ }
+
+ if (j > 0)
+ {
+ meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j - 1, i ).Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Compute the ewave points using catmull-rom
+//-----------------------------------------------------------------------------
+
+void C_EnergyWave::ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity )
+{
+ int i;
+ for ( i = 0; i < NUM_SUBDIVISIONS; ++i)
+ {
+ float t = (EWAVE_NUM_VERTICAL_POINTS -1 ) * (float)i / (float)(NUM_SUBDIVISIONS - 1);
+ for (int j = 0; j < NUM_SUBDIVISIONS; ++j)
+ {
+ float s = (EWAVE_NUM_HORIZONTAL_POINTS-1) * (float)j / (float)(NUM_SUBDIVISIONS - 1);
+ int idx = i * NUM_SUBDIVISIONS + j;
+
+ ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Draws the base ewave
+//-----------------------------------------------------------------------------
+
+#define TRANSITION_REGION_WIDTH 0.5f
+
+void C_EnergyWave::DrawEWavePoints(Vector* pt, Vector* normal, float* opacity)
+{
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEWaveMat );
+
+ int numTriangles = (NUM_SUBDIVISIONS - 1) * (NUM_SUBDIVISIONS - 1) * 2;
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
+
+ float du = 1.0f / (float)(NUM_SUBDIVISIONS - 1);
+ float dv = du;
+
+ unsigned char color[3];
+ color[0] = 255;
+ color[1] = 255;
+ color[2] = 255;
+
+ for ( int i = 0; i < NUM_SUBDIVISIONS - 1; ++i)
+ {
+ float v = i * dv;
+ for (int j = 0; j < NUM_SUBDIVISIONS - 1; ++j)
+ {
+ int idx = i * NUM_SUBDIVISIONS + j;
+ float u = j * du;
+
+ meshBuilder.Position3fv( pt[idx].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] );
+ meshBuilder.Normal3fv( normal[idx].Base() );
+ meshBuilder.TexCoord2f( 0, u, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
+ meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
+ meshBuilder.TexCoord2f( 0, u, v + dv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
+ meshBuilder.Normal3fv( normal[idx+1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
+ meshBuilder.Normal3fv( normal[idx+1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
+ meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
+ meshBuilder.TexCoord2f( 0, u, v + dv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS+1] );
+ meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS + 1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v + dv );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Main draw entry point
+//-----------------------------------------------------------------------------
+
+int C_EnergyWave::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ // NOTE: We've got a stiff spring case here, we need to simulate at
+ // a fairly fast timestep. A better solution would be to use an
+ // implicit method, which I'm going to not implement for the moment
+
+ float dt = gpGlobals->frametime;
+ m_EWaveEffect.SetPosition( GetAbsOrigin(), GetAbsAngles() );
+ m_EWaveEffect.Simulate(dt);
+
+ Vector pt[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
+ Vector normal[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
+ float opacity[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
+
+ ComputeEWavePoints( pt, normal, opacity );
+
+ DrawEWavePoints( pt, normal, opacity );
+
+ return 1;
+}
+
+
+
+
+