Files
HL2Overcharged/game/client/overcharged/c_energy_wave.cpp
2025-05-21 21:09:22 +03:00

664 lines
18 KiB
C++

//========= Copyright © 1996-2005, 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 );
}
/*double noise2(double arg)
{
return (arg + random->RandomFloat(-1.5f, 1.5f));
}
static void RandomizeNormal1(Vector &vec)
{
vec.x = 2.0f * (noise2(vec.x) - 0.5f);
vec.y = 2.0f * (noise2(vec.y) - 0.5f);
vec.z = 2.0f * (noise2(vec.z) - 0.5f);
}*/
void C_EnergyWave::DrawWireframeModel( )
{
//IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
CMatRenderContextPtr pRenderContext( materials );
IMesh* pMesh = pRenderContext->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();
}
}
}
/*Vector origin = tmp;
int stacks = 200;
int slices = 200;
float radius = 5000.0f;
// this sucks and stuff
float x = origin.x;
float y = origin.y;
float z = origin.z;
float stackAngle, sliceAngle;
int stack, slice;
Vector v[4];
float sliced, stacked, sliced1, stacked1, stacks1;
float slicedsin, slicedcos, stackedsin, stackedcos;
float sliced1sin, sliced1cos, stacked1sin, stacked1cos;
float stacks1sin, stacks1cos;
float stacksin, stackcos;
// IMaterial *pMaterial = materials->FindMaterial("effects/splashwake4", 0);
// CMatRenderContextPtr pRenderContext(materials);
// IMesh *pMesh = pRenderContext->GetDynamicMesh(true, NULL, NULL, pMaterial);
// CMeshBuilder meshBuilder;
stackAngle = M_PI / (float)stacks;
sliceAngle = 2.0 * M_PI / (float)slices;
for (stack = 1; stack < stacks - 1; stack++)
{
for (slice = 0; slice < slices; slice++)
{
int i, j;
sliced = sliceAngle * slice;
stacked = stackAngle * stack;
sliced1 = sliceAngle * (slice + 1);
stacked1 = stackAngle * (stack + 1);
SinCos(sliced, &slicedsin, &slicedcos);
SinCos(stacked, &stackedsin, &stackedcos);
SinCos(sliced1, &sliced1sin, &sliced1cos);
SinCos(stacked1, &stacked1sin, &stacked1cos);
v[0][0] = -slicedsin * stackedsin;
v[0][1] = slicedcos * stackedsin;
v[0][2] = stackedcos;
v[1][0] = -sliced1sin * stackedsin;
v[1][1] = sliced1cos * stackedsin;
v[1][2] = stackedcos;
v[2][0] = -sliced1sin * stacked1sin;
v[2][1] = sliced1cos * stacked1sin;
v[2][2] = stacked1cos;
v[3][0] = -slicedsin * stacked1sin;
v[3][1] = slicedcos * stacked1sin;
v[3][2] = stacked1cos;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
#if 1
// if( drawWireframe.value )
if (1)
{
meshBuilder.Begin(pMesh, MATERIAL_QUADS, 1);
meshBuilder.Position3fv(v[0].Base());
Vector normal;
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[3].Base());
normal = v[3] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
else
{
// DrawIndexedQuad( v, 0, 1, 2, 3 );
}
#endif
}
}
// do the caps
for (slice = 0; slice < slices; slice++)
{
int i, j;
sliced = sliceAngle * slice;
stacked = stackAngle * stack;
sliced1 = sliceAngle * (slice + 1);
stacked1 = stackAngle * (stack + 1);
stacks1 = stackAngle * (stacks - 1);
SinCos(sliced, &slicedsin, &slicedcos);
SinCos(stacked, &stackedsin, &stackedcos);
SinCos(sliced1, &sliced1sin, &sliced1cos);
SinCos(stacked1, &stacked1sin, &stacked1cos);
SinCos(stackAngle, &stacksin, &stackcos);
SinCos(stacks1, &stacks1sin, &stacks1cos);
v[0][0] = 0.0f;
v[0][1] = 0.0f;
v[0][2] = 1.0f;
v[1][0] = -sliced1sin * stacksin;
v[1][1] = sliced1cos * stacksin;
v[1][2] = stackcos;
v[2][0] = -slicedsin * stacksin;
v[2][1] = slicedcos * stacksin;
v[2][2] = stackcos;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
meshBuilder.Begin(pMesh, MATERIAL_TRIANGLES, 1);
meshBuilder.Position3fv(v[0].Base());
Vector normal;
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
v[0][0] = 0.0f;
v[0][1] = 0.0f;
v[0][2] = -1.0f;
v[1][0] = -sliced1sin * stacks1sin;
v[1][1] = sliced1cos * stacks1sin;
v[1][2] = stacks1cos;
v[2][0] = -slicedsin * stacks1sin;
v[2][1] = slicedcos * stacks1sin;
v[2][2] = stacks1cos;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
meshBuilder.Begin(pMesh, MATERIAL_TRIANGLES, 1);
meshBuilder.Position3fv(v[0].Base());
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal1(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
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 );
CMatRenderContextPtr pRenderContext( materials );
IMesh* pMesh = pRenderContext->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;
}