⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c_shield.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
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 + -