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
416 lines
12 KiB
//========= 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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|