📄 c_shield.cpp
字号:
void C_Shield::DrawShieldPoints(Vector* pt, Vector* normal, float* opacity)
{
SetCurrentDecal( -1 );
if (mat_wireframe.GetInt() == 0)
materials->Bind( m_pShield, (IClientRenderable*)this );
else
materials->Bind( m_pWireframe, (IClientRenderable*)this );
IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL );
int numTriangles = (m_SubdivisionCount - 1) * (m_SubdivisionCount - 1) * 2;
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
float du = 1.0f * m_InvSubdivisionCount;
float dv = du;
unsigned char color[3];
color[0] = 255;
color[1] = 255;
color[2] = 255;
for ( int i = 0; i < m_SubdivisionCount - 1; ++i)
{
float v = i * dv;
for (int j = 0; j < m_SubdivisionCount - 1; ++j)
{
int idx = i * m_SubdivisionCount + 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 + m_SubdivisionCount].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] );
meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].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 + m_SubdivisionCount].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] );
meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].Base() );
meshBuilder.TexCoord2f( 0, u, v + dv );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount+1] );
meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount + 1].Base() );
meshBuilder.TexCoord2f( 0, u + du, v + dv );
meshBuilder.AdvanceVertex();
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Draws shield decals
//-----------------------------------------------------------------------------
void C_Shield::DrawShieldDecals( Vector* pt, bool hitDecals )
{
if (m_Decals.Size() == 0)
return;
// Compute ripples:
for ( int r = m_Decals.Size(); --r >= 0; )
{
// At the moment, nothing passes!
bool passDecal = false;
if ((!hitDecals) && (passDecal == hitDecals))
continue;
SetCurrentDecal( r );
// We have to force a flush here because we're changing the proxy state
if (!hitDecals)
materials->Bind( m_pPassDecal, (IClientRenderable*)this );
else
materials->Bind( passDecal ? m_pPassDecal2 : m_pHitDecal, (IClientRenderable*)this );
float dtime = gpGlobals->curtime - m_Decals[r].m_StartTime;
float decay = exp( -( 2 * dtime) );
// Retire the animation if it wraps
// This gets set by TextureAnimatedWrapped above
if ((m_Decals[r].m_StartTime < 0.0f) || (decay < 1e-3))
{
m_Decals.Remove(r);
continue;
}
IMesh* pMesh = materials->GetDynamicMesh();
// Figure out the quads we must mod2x....
float u0 = m_Decals[r].m_RippleU - m_Decals[r].m_Radius;
float u1 = m_Decals[r].m_RippleU + m_Decals[r].m_Radius;
float v0 = m_Decals[r].m_RippleV - m_Decals[r].m_Radius;
float v1 = m_Decals[r].m_RippleV + m_Decals[r].m_Radius;
float du = u1 - u0;
float dv = v1 - v0;
int i0 = Floor2Int( v0 * (m_SubdivisionCount - 1) );
int i1 = Ceil2Int( v1 * (m_SubdivisionCount - 1) );
int j0 = Floor2Int( u0 * (m_SubdivisionCount - 1) );
int j1 = Ceil2Int( u1 * (m_SubdivisionCount - 1) );
if (i0 < 0)
i0 = 0;
if (i1 >= m_SubdivisionCount)
i1 = m_SubdivisionCount - 1;
if (j0 < 0)
j0 = 0;
if (j1 >= m_SubdivisionCount)
j1 = m_SubdivisionCount - 1;
int numTriangles = (i1 - i0) * (j1 - j0) * 2;
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
float decalDu = m_InvSubdivisionCount / du;
float decalDv = m_InvSubdivisionCount / dv;
unsigned char color[3];
color[0] = s_ImpactDecalColor[0] * decay;
color[1] = s_ImpactDecalColor[1] * decay;
color[2] = s_ImpactDecalColor[2] * decay;
for ( int i = i0; i < i1; ++i)
{
float t = (float)i * m_InvSubdivisionCount;
for (int j = j0; j < j1; ++j)
{
float s = (float)j * m_InvSubdivisionCount;
int idx = i * m_SubdivisionCount + j;
// Compute (u,v) into the decal
float decalU = (s - u0) / du;
float decalV = (t - v0) / dv;
meshBuilder.Position3fv( pt[idx].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU, decalV );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + 1].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + 1].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() );
meshBuilder.Color3ubv( color );
meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV + decalDv );
meshBuilder.AdvanceVertex();
}
}
meshBuilder.End();
pMesh->Draw();
}
}
//-----------------------------------------------------------------------------
// Computes a single point
//-----------------------------------------------------------------------------
void C_Shield::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
{
// Precache some computations for the point on the spline at (s, t).
m_SplinePatch.SetupPatchQuery( s, t );
// Get the position + normal
m_SplinePatch.GetPointAndNormal( pt, normal );
// From here on down is all futzing with opacity
// Check neighbors for activity...
bool active = IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it);
if (m_SplinePatch.m_fs == 0.0f)
active = active || IsPanelActive(m_SplinePatch.m_is - 1, m_SplinePatch.m_it);
if (m_SplinePatch.m_ft == 0.0f)
active = active || IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it - 1);
if (!active)
{
// If the panel's not active, it's transparent.
opacity = 0.0f;
}
else
{
if ((s == 0.0f) || (t == 0.0f) ||
(s == (Width() - 1.0f)) || (t == (Height() - 1.0f)) )
{
// If it's on the edge, it's max opacity
opacity = 192.0f;
}
else
{
// Channel zero is the opacity data
opacity = m_SplinePatch.GetChannel( 0 );
// Make the shield translucent if the owner is the local player...
// Also don't mess with the edges..
if (m_ShieldOwnedByLocalPlayer)
{
// Channel 1 is the opacity blend
float blendFactor = m_SplinePatch.GetChannel( 1 );
blendFactor = clamp( blendFactor, 0.0f, 1.0f );
float blendValue = 1.0f;
Vector delta;
VectorSubtract( pt, GetAbsOrigin(), delta );
float dist = VectorLength( delta );
if (dist != 0.0f)
{
delta *= 1.0f / dist;
float dot = DotProduct( m_ViewDir, delta );
float angle = acos( dot );
float fov = M_PI * render->GetFieldOfView() / 180.0f;
if (angle < fov * .2f)
blendValue = 0.1f;
else if (angle < fov * 0.4f)
{
// Want a cos falloff between .2 and .4
// 0.1 at .2 and 1.0 at .4
angle -= fov * 0.2f;
blendValue = 1.0f - 0.9f * 0.5f * (cos ( M_PI * angle / (fov * 0.2f) ) + 1.0f);
}
}
// Interpolate between 1 and the blend value based on the blend factor...
opacity *= (1.0f - blendFactor) + blendFactor * blendValue;
}
opacity = clamp( opacity, 0.0f, 192.0f );
}
}
opacity *= m_FadeValue;
}
//-----------------------------------------------------------------------------
// Compute the shield points using catmull-rom
//-----------------------------------------------------------------------------
void C_Shield::ComputeShieldPoints( Vector* pt, Vector* normal, float* opacity )
{
int i;
for ( i = 0; i < m_SubdivisionCount; ++i)
{
float t = (Height() - 1) * (float)i * m_InvSubdivisionCount;
for (int j = 0; j < m_SubdivisionCount; ++j)
{
float s = (Width() - 1) * (float)j * m_InvSubdivisionCount;
int idx = i * m_SubdivisionCount + j;
ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] );
}
}
}
//-----------------------------------------------------------------------------
// Compute the shield ripples from being hit
//-----------------------------------------------------------------------------
void C_Shield::RippleShieldPoints( Vector* pt, float* opacity )
{
// Compute ripples:
for ( int r = m_Ripples.Size(); --r >= 0; )
{
float dtime = gpGlobals->curtime - m_Ripples[r].m_StartTime;
float decay = exp( -( 2 * dtime) );
float amplitude = m_Ripples[r].m_Amplitude * decay;
for ( int i = 0; i < m_SubdivisionCount; ++i)
{
float t = i * m_InvSubdivisionCount;
for (int j = 0; j < m_SubdivisionCount; ++j)
{
float s = j * m_InvSubdivisionCount;
int idx = i * m_SubdivisionCount + j;
float ds = s - m_Ripples[r].m_RippleU;
float dt = t - m_Ripples[r].m_RippleV;
float dr = sqrt( ds * ds + dt * dt );
if (dr < m_Ripples[r].m_Radius)
{
// need to apply ripple
float diff = amplitude * cos( 0.5f * M_PI * dr / m_Ripples[r].m_Radius );
VectorMA( pt[idx], diff, m_Ripples[r].m_Direction, pt[idx] );
// Compute opacity at this point...
float impactopacity = 192.0f * decay * dr / m_Ripples[r].m_Radius;
if (impactopacity > opacity[idx])
opacity[idx] = impactopacity;
}
}
}
if (amplitude < 0.1)
m_Ripples.Remove(r);
}
}
//-----------------------------------------------------------------------------
// Main draw entry point
//-----------------------------------------------------------------------------
int C_Shield::DrawModel( int flags )
{
if ( !m_bReadyToDraw )
return 0;
if (m_FadeValue == 0.0f)
return 1;
// If I have no power, don't draw
if ( m_flPowerLevel <= 0 )
return 1;
// Make it curvy or not!!
m_SplinePatch.SetLinearBlend( m_CurveValue );
// Set up the patch with all the data it's going to need
int count = Width() * Height();
Vector const** pControlPoints = (Vector const**)stackalloc(count * sizeof(Vector*));
float* pControlOpacity = (float*)stackalloc(count * sizeof(float));
float* pControlBlend = (float*)stackalloc(count * sizeof(float));
GetShieldData( pControlPoints, pControlOpacity, pControlBlend );
m_SplinePatch.SetControlPositions( pControlPoints );
m_SplinePatch.SetChannelData( 0, pControlOpacity );
m_SplinePatch.SetChannelData( 1, pControlBlend );
// DrawWireframeModel( pControlPoints );
// Allocate space for temporary data
int numSubdivisions = m_SubdivisionCount * m_SubdivisionCount;
Vector* pt = (Vector*)stackalloc(numSubdivisions * sizeof(Vector));
Vector* normal = (Vector*)stackalloc(numSubdivisions * sizeof(Vector));
float* opacity = (float*)stackalloc(numSubdivisions * sizeof(float));
// Do something a little special if this shield is owned by the local player
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
m_ShieldOwnedByLocalPlayer = (player->entindex() == m_nOwningPlayerIndex);
if (m_ShieldOwnedByLocalPlayer)
{
QAngle viewAngles;
engine->GetViewAngles(viewAngles);
AngleVectors( viewAngles, &m_ViewDir );
}
ComputeShieldPoints( pt, normal, opacity );
RippleShieldPoints( pt, opacity );
// Commented out because it causes things to not be drawn behind it
// DrawShieldDecals( pt, false );
DrawShieldPoints( pt, normal, opacity );
DrawShieldDecals( pt, true );
return 1;
}
//============================================================================================================
// SHIELD POWERLEVEL PROXY
//============================================================================================================
class CShieldPowerLevelProxy : public CResultProxy
{
public:
void OnBind( void *pC_BaseEntity );
};
void CShieldPowerLevelProxy::OnBind( void *pRenderable )
{
IClientRenderable *pRend = (IClientRenderable *)pRenderable;
C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
C_Shield *pShield = dynamic_cast<C_Shield*>(pEntity);
if (!pShield)
return;
SetFloatResult( pShield->GetPowerLevel() );
}
EXPOSE_INTERFACE( CShieldPowerLevelProxy, IMaterialProxy, "ShieldPowerLevel" IMATERIAL_PROXY_INTERFACE_VERSION );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -