//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "c_prop_combine_ball.h" #include "materialsystem/imaterial.h" #include "model_types.h" #include "c_physicsprop.h" #include "c_te_effect_dispatch.h" #include "fx_quad.h" #include "fx.h" #include "clienteffectprecachesystem.h" #include "view.h" #include "view_scene.h" #include "beamdraw.h" // Precache our effects CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCombineBall ) CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" ) CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_nocull" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" ) CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" ) CLIENTEFFECT_REGISTER_END() IMPLEMENT_CLIENTCLASS_DT( C_PropCombineBall, DT_PropCombineBall, CPropCombineBall ) RecvPropBool( RECVINFO( m_bEmit ) ), RecvPropFloat( RECVINFO( m_flRadius ) ), RecvPropBool( RECVINFO( m_bHeld ) ), RecvPropBool( RECVINFO( m_bLaunched ) ), END_RECV_TABLE() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- C_PropCombineBall::C_PropCombineBall( void ) { m_pFlickerMaterial = NULL; m_pBodyMaterial = NULL; m_pBlurMaterial = NULL; } //----------------------------------------------------------------------------- // Purpose: // Input : updateType - //----------------------------------------------------------------------------- void C_PropCombineBall::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); if ( updateType == DATA_UPDATE_CREATED ) { m_vecLastOrigin = GetAbsOrigin(); InitMaterials(); } } //----------------------------------------------------------------------------- // Purpose: // Output : RenderGroup_t //----------------------------------------------------------------------------- RenderGroup_t C_PropCombineBall::GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; } //----------------------------------------------------------------------------- // Purpose: Cache the material handles // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool C_PropCombineBall::InitMaterials( void ) { // Motion blur if ( m_pBlurMaterial == NULL ) { m_pBlurMaterial = materials->FindMaterial( "effects/ar2_altfire1b", NULL, false ); if ( m_pBlurMaterial == NULL ) return false; } // Main body of the ball if ( m_pBodyMaterial == NULL ) { m_pBodyMaterial = materials->FindMaterial( "effects/ar2_altfire1", NULL, false ); if ( m_pBodyMaterial == NULL ) return false; } // Flicker material if ( m_pFlickerMaterial == NULL ) { m_pFlickerMaterial = materials->FindMaterial( "effects/combinemuzzle1", NULL, false ); if ( m_pFlickerMaterial == NULL ) return false; } return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_PropCombineBall::DrawMotionBlur( void ) { float color[3]; Vector vecDir = GetAbsOrigin() - m_vecLastOrigin; float speed = VectorNormalize( vecDir ); speed = clamp( speed, 0, 32 ); float stepSize = MIN( ( speed * 0.5f ), 4.0f ); Vector spawnPos = GetAbsOrigin(); Vector spawnStep = -vecDir * stepSize; float base = RemapValClamped( speed, 4, 32, 0.0f, 1.0f ); CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( m_pBlurMaterial ); // Draw the motion blurred trail for ( int i = 0; i < 8; i++ ) { spawnPos += spawnStep; color[0] = color[1] = color[2] = base * ( 1.0f - ( (float) i / 12.0f ) ); DrawHalo( m_pBlurMaterial, spawnPos, m_flRadius, color ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_PropCombineBall::DrawFlicker( void ) { float rand1 = random->RandomFloat( 0.2f, 0.3f ); float rand2 = random->RandomFloat( 1.5f, 2.5f ); if ( gpGlobals->frametime == 0.0f ) { rand1 = 0.2f; rand2 = 1.5f; } float color[3]; color[0] = color[1] = color[2] = rand1; // Draw the flickering glow CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( m_pFlickerMaterial ); DrawHalo( m_pFlickerMaterial, GetAbsOrigin(), m_flRadius * rand2, color ); } //----------------------------------------------------------------------------- // Purpose: // Input : pMaterial - // source - // color - //----------------------------------------------------------------------------- void DrawHaloOriented( const Vector& source, float scale, float const *color, float roll ) { Vector point, screen; CMatRenderContextPtr pRenderContext( materials ); IMesh* pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); // Transform source into screen space ScreenTransform( source, screen ); Vector right, up; float sr, cr; SinCos( roll, &sr, &cr ); for ( int i = 0; i < 3; i++ ) { right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr; up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr; } meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 1); VectorMA (source, -scale, up, point); VectorMA (point, -scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 0); VectorMA (source, scale, up, point); VectorMA (point, -scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 0); VectorMA (source, scale, up, point); VectorMA (point, scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 1); VectorMA (source, -scale, up, point); VectorMA (point, scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); } //----------------------------------------------------------------------------- // Purpose: // Input : flags - // Output : int //----------------------------------------------------------------------------- int C_PropCombineBall::DrawModel( int flags ) { if ( !m_bEmit ) return 0; // Make sure our materials are cached if ( !InitMaterials() ) { //NOTENOTE: This means that a material was not found for the combine ball, so it may not render! AssertOnce( 0 ); return 0; } // Draw the flickering overlay DrawFlicker(); // Draw the motion blur from movement if ( m_bHeld || m_bLaunched ) { DrawMotionBlur(); } // Draw the model if we're being held if ( m_bHeld ) { QAngle angles; VectorAngles( -CurrentViewForward(), angles ); // Always orient towards the camera! SetAbsAngles( angles ); BaseClass::DrawModel( flags ); } else { float color[3]; color[0] = color[1] = color[2] = 1.0f; float sinOffs = 1.0f * sin( gpGlobals->curtime * 25 ); float roll = SpawnTime(); // Draw the main ball body CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( m_pBodyMaterial, (C_BaseEntity*) this ); DrawHaloOriented( GetAbsOrigin(), m_flRadius + sinOffs, color, roll ); } m_vecLastOrigin = GetAbsOrigin(); return 1; } //----------------------------------------------------------------------------- // Purpose: // Input : &data - //----------------------------------------------------------------------------- void CombineBallImpactCallback( const CEffectData &data ) { // Quick flash FX_AddQuad( data.m_vOrigin, data.m_vNormal, data.m_flRadius * 10.0f, 0, 0.75f, 1.0f, 0.0f, 0.4f, random->RandomInt( 0, 360 ), 0, Vector( 1.0f, 1.0f, 1.0f ), 0.25f, "effects/combinemuzzle1_nocull", (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); // Lingering burn FX_AddQuad( data.m_vOrigin, data.m_vNormal, data.m_flRadius * 2.0f, data.m_flRadius * 4.0f, 0.75f, 1.0f, 0.0f, 0.4f, random->RandomInt( 0, 360 ), 0, Vector( 1.0f, 1.0f, 1.0f ), 0.5f, "effects/combinemuzzle2_nocull", (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); // Throw sparks FX_ElectricSpark( data.m_vOrigin, 2, 1, &data.m_vNormal ); } DECLARE_CLIENT_EFFECT( "cball_bounce", CombineBallImpactCallback ); //----------------------------------------------------------------------------- // Purpose: // Input : &data - //----------------------------------------------------------------------------- void CombineBallExplosionCallback( const CEffectData &data ) { Vector normal(0,0,1); // Throw sparks FX_ElectricSpark( data.m_vOrigin, 4, 1, &normal ); } DECLARE_CLIENT_EFFECT( "cball_explode", CombineBallExplosionCallback );