diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/c_sprite.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/c_sprite.cpp')
| -rw-r--r-- | mp/src/game/client/c_sprite.cpp | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/mp/src/game/client/c_sprite.cpp b/mp/src/game/client/c_sprite.cpp new file mode 100644 index 00000000..6cedec12 --- /dev/null +++ b/mp/src/game/client/c_sprite.cpp @@ -0,0 +1,500 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+#include "cbase.h"
+#include "c_sprite.h"
+#include "model_types.h"
+#include "iviewrender.h"
+#include "view.h"
+#include "enginesprite.h"
+#include "engine/ivmodelinfo.h"
+#include "util_shared.h"
+#include "tier0/vprof.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "view_shared.h"
+#include "viewrender.h"
+#include "tier1/KeyValues.h"
+#include "toolframework/itoolframework.h"
+#include "toolframework_client.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+ConVar r_drawsprites( "r_drawsprites", "1", FCVAR_CHEAT );
+
+//-----------------------------------------------------------------------------
+// Purpose: Generic sprite model renderer
+// Input : *baseentity -
+// *psprite -
+// fscale -
+// frame -
+// rendermode -
+// r -
+// g -
+// b -
+// a -
+// forward -
+// right -
+// up -
+//-----------------------------------------------------------------------------
+static unsigned int s_nHDRColorScaleCache = 0;
+void DrawSpriteModel( IClientEntity *baseentity, CEngineSprite *psprite, const Vector &origin, float fscale, float frame,
+ int rendermode, int r, int g, int b, int a, const Vector& forward, const Vector& right, const Vector& up, float flHDRColorScale )
+{
+ float scale;
+ IMaterial *material;
+
+ // don't even bother culling, because it's just a single
+ // polygon without a surface cache
+ if ( fscale > 0 )
+ scale = fscale;
+ else
+ scale = 1.0f;
+
+ if ( rendermode == kRenderNormal )
+ {
+ render->SetBlend( 1.0f );
+ }
+
+ material = psprite->GetMaterial( (RenderMode_t)rendermode, frame );
+ if ( !material )
+ return;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ if ( ShouldDrawInWireFrameMode() || r_drawsprites.GetInt() == 2 )
+ {
+ IMaterial *pMaterial = materials->FindMaterial( "debug/debugspritewireframe", TEXTURE_GROUP_OTHER );
+ pRenderContext->Bind( pMaterial, NULL );
+ }
+ else
+ {
+ pRenderContext->Bind( material, (IClientRenderable*)baseentity );
+ }
+
+ unsigned char color[4];
+ color[0] = r;
+ color[1] = g;
+ color[2] = b;
+ color[3] = a;
+
+ IMaterialVar *pHDRColorScaleVar = material->FindVarFast( "$HDRCOLORSCALE", &s_nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetVecValue( flHDRColorScale, flHDRColorScale, flHDRColorScale );
+ }
+
+ Vector point;
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ Vector vec_a;
+ Vector vec_b;
+ Vector vec_c;
+ Vector vec_d;
+
+ // isolate common terms
+ VectorMA( origin, psprite->GetDown() * scale, up, vec_a );
+ VectorScale( right, psprite->GetLeft() * scale, vec_b );
+ VectorMA( origin, psprite->GetUp() * scale, up, vec_c );
+ VectorScale( right, psprite->GetRight() * scale, vec_d );
+
+ float flMinU, flMinV, flMaxU, flMaxV;
+ psprite->GetTexCoordRange( &flMinU, &flMinV, &flMaxU, &flMaxV );
+
+ meshBuilder.Color4ubv( color );
+ meshBuilder.TexCoord2f( 0, flMinU, flMaxV );
+ VectorAdd( vec_a, vec_b, point );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv( color );
+ meshBuilder.TexCoord2f( 0, flMinU, flMinV );
+ VectorAdd( vec_c, vec_b, point );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv( color );
+ meshBuilder.TexCoord2f( 0, flMaxU, flMinV );
+ VectorAdd( vec_c, vec_d, point );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv( color );
+ meshBuilder.TexCoord2f( 0, flMaxU, flMaxV );
+ VectorAdd( vec_a, vec_d, point );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Determine glow brightness/scale based on distance to render origin and trace results
+// Input : entorigin -
+// rendermode -
+// renderfx -
+// alpha -
+// pscale - Pointer to the value for scale, will be changed based on distance and rendermode.
+//-----------------------------------------------------------------------------
+float StandardGlowBlend( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle, int rendermode, int renderfx, int alpha, float *pscale )
+{
+ float dist;
+ float brightness;
+
+ brightness = PixelVisibility_FractionVisible( params, queryHandle );
+ if ( brightness <= 0.0f )
+ {
+ return 0.0f;
+ }
+ dist = GlowSightDistance( params.position, false );
+ if ( dist <= 0.0f )
+ {
+ return 0.0f;
+ }
+
+ if ( renderfx == kRenderFxNoDissipation )
+ {
+ return (float)alpha * (1.0f/255.0f) * brightness;
+ }
+
+ // UNDONE: Tweak these magic numbers (1200 - distance at full brightness)
+ float fadeOut = (1200.0f*1200.0f) / (dist*dist);
+ fadeOut = clamp( fadeOut, 0.0f, 1.0f );
+
+ if (rendermode != kRenderWorldGlow)
+ {
+ // Make the glow fixed size in screen space, taking into consideration the scale setting.
+ if ( *pscale == 0.0f )
+ {
+ *pscale = 1.0f;
+ }
+
+ *pscale *= dist * (1.0f/200.0f);
+ }
+
+ return fadeOut * brightness;
+}
+
+static float SpriteAspect( CEngineSprite *pSprite )
+{
+ if ( pSprite )
+ {
+ float x = fabsf(pSprite->GetRight() - pSprite->GetLeft());
+ float y = fabsf(pSprite->GetDown() - pSprite->GetUp());
+ if ( y != 0 && x != 0 )
+ {
+ return x / y;
+ }
+ }
+
+ return 1.0f;
+}
+
+float C_SpriteRenderer::GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *pscale )
+{
+ pixelvis_queryparams_t params;
+ float aspect = SpriteAspect(psprite);
+ params.Init( entorigin, PIXELVIS_DEFAULT_PROXY_SIZE, aspect );
+ return StandardGlowBlend( params, &m_queryHandle, rendermode, renderfx, alpha, pscale );
+}
+
+// since sprites can network down a glow proxy size, handle that here
+float CSprite::GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *pscale )
+{
+ pixelvis_queryparams_t params;
+ float aspect = SpriteAspect(psprite);
+ params.Init( entorigin, m_flGlowProxySize, aspect );
+ return StandardGlowBlend( params, &m_queryHandle, rendermode, renderfx, alpha, pscale );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Determine sprite orientation axes
+// Input : type -
+// forward -
+// right -
+// up -
+//-----------------------------------------------------------------------------
+void C_SpriteRenderer::GetSpriteAxes( SPRITETYPE type,
+ const Vector& origin,
+ const QAngle& angles,
+ Vector& forward,
+ Vector& right,
+ Vector& up )
+{
+ int i;
+ float dot, angle, sr, cr;
+ Vector tvec;
+
+ // Automatically roll parallel sprites if requested
+ if ( angles[2] != 0 && type == SPR_VP_PARALLEL )
+ {
+ type = SPR_VP_PARALLEL_ORIENTED;
+ }
+
+ switch( type )
+ {
+ case SPR_FACING_UPRIGHT:
+ {
+ // generate the sprite's axes, with vup straight up in worldspace, and
+ // r_spritedesc.vright perpendicular to modelorg.
+ // This will not work if the view direction is very close to straight up or
+ // down, because the cross product will be between two nearly parallel
+ // vectors and starts to approach an undefined state, so we don't draw if
+ // the two vectors are less than 1 degree apart
+ tvec[0] = -origin[0];
+ tvec[1] = -origin[1];
+ tvec[2] = -origin[2];
+ VectorNormalize (tvec);
+ dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
+ // r_spritedesc.vup is 0, 0, 1
+ if ((dot > 0.999848f) || (dot < -0.999848f)) // cos(1 degree) = 0.999848
+ return;
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 1;
+ right[0] = tvec[1];
+ // CrossProduct(r_spritedesc.vup, -modelorg,
+ right[1] = -tvec[0];
+ // r_spritedesc.vright)
+ right[2] = 0;
+ VectorNormalize (right);
+ forward[0] = -right[1];
+ forward[1] = right[0];
+ forward[2] = 0;
+ // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
+ // r_spritedesc.vpn)
+ }
+ break;
+
+ case SPR_VP_PARALLEL:
+ {
+ // generate the sprite's axes, completely parallel to the viewplane. There
+ // are no problem situations, because the sprite is always in the same
+ // position relative to the viewer
+ for (i=0 ; i<3 ; i++)
+ {
+ up[i] = CurrentViewUp()[i];
+ right[i] = CurrentViewRight()[i];
+ forward[i] = CurrentViewForward()[i];
+ }
+ }
+ break;
+
+ case SPR_VP_PARALLEL_UPRIGHT:
+ {
+ // generate the sprite's axes, with g_vecVUp straight up in worldspace, and
+ // r_spritedesc.vright parallel to the viewplane.
+ // This will not work if the view direction is very close to straight up or
+ // down, because the cross product will be between two nearly parallel
+ // vectors and starts to approach an undefined state, so we don't draw if
+ // the two vectors are less than 1 degree apart
+ dot = CurrentViewForward()[2]; // same as DotProduct (vpn, r_spritedesc.g_vecVUp) because
+ // r_spritedesc.vup is 0, 0, 1
+ if ((dot > 0.999848f) || (dot < -0.999848f)) // cos(1 degree) = 0.999848
+ return;
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 1;
+ right[0] = CurrentViewForward()[1];
+ // CrossProduct (r_spritedesc.vup, vpn,
+ right[1] = -CurrentViewForward()[0]; // r_spritedesc.vright)
+ right[2] = 0;
+ VectorNormalize (right);
+ forward[0] = -right[1];
+ forward[1] = right[0];
+ forward[2] = 0;
+ // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
+ // r_spritedesc.vpn)
+ }
+ break;
+
+ case SPR_ORIENTED:
+ {
+ // generate the sprite's axes, according to the sprite's world orientation
+ AngleVectors( angles, &forward, &right, &up );
+ }
+ break;
+
+ case SPR_VP_PARALLEL_ORIENTED:
+ {
+ // generate the sprite's axes, parallel to the viewplane, but rotated in
+ // that plane around the center according to the sprite entity's roll
+ // angle. So vpn stays the same, but vright and vup rotate
+ angle = angles[ROLL] * (M_PI*2.0f/360.0f);
+ SinCos( angle, &sr, &cr );
+
+ for (i=0 ; i<3 ; i++)
+ {
+ forward[i] = CurrentViewForward()[i];
+ right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr;
+ up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr;
+ }
+ }
+ break;
+
+ default:
+ Warning( "GetSpriteAxes: Bad sprite type %d\n", type );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_SpriteRenderer::DrawSprite(
+ IClientEntity *entity,
+ const model_t *model,
+ const Vector& origin,
+ const QAngle& angles,
+ float frame,
+ IClientEntity *attachedto,
+ int attachmentindex,
+ int rendermode,
+ int renderfx,
+ int alpha,
+ int r,
+ int g,
+ int b,
+ float scale,
+ float flHDRColorScale
+ )
+{
+ VPROF_BUDGET( "C_SpriteRenderer::DrawSprite", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+
+ if ( !r_drawsprites.GetBool() || !model || modelinfo->GetModelType( model ) != mod_sprite )
+ {
+ return 0;
+ }
+
+ // Get extra data
+ CEngineSprite *psprite = (CEngineSprite *)modelinfo->GetModelExtraData( model );
+ if ( !psprite )
+ {
+ return 0;
+ }
+
+ Vector effect_origin;
+ VectorCopy( origin, effect_origin );
+
+ // Use attachment point
+ if ( attachedto )
+ {
+ C_BaseEntity *ent = attachedto->GetBaseEntity();
+ if ( ent )
+ {
+ // don't draw viewmodel effects in reflections
+ if ( CurrentViewID() == VIEW_REFLECTION )
+ {
+ int group = ent->GetRenderGroup();
+ if ( group == RENDER_GROUP_VIEW_MODEL_TRANSLUCENT || group == RENDER_GROUP_VIEW_MODEL_OPAQUE )
+ return 0;
+ }
+ QAngle temp;
+ ent->GetAttachment( attachmentindex, effect_origin, temp );
+ }
+ }
+
+ if ( rendermode != kRenderNormal )
+ {
+ float blend = render->GetBlend();
+
+ // kRenderGlow and kRenderWorldGlow have a special blending function
+ if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow ))
+ {
+ blend *= GlowBlend( psprite, effect_origin, rendermode, renderfx, alpha, &scale );
+
+ // Fade out the sprite depending on distance from the view origin.
+ r *= blend;
+ g *= blend;
+ b *= blend;
+ }
+
+ render->SetBlend( blend );
+ if ( blend <= 0.0f )
+ {
+ return 0;
+ }
+ }
+
+ // Get orthonormal basis
+ Vector forward, right, up;
+ GetSpriteAxes( (SPRITETYPE)psprite->GetOrientation(), origin, angles, forward, right, up );
+
+ // Draw
+ DrawSpriteModel(
+ entity,
+ psprite,
+ effect_origin,
+ scale,
+ frame,
+ rendermode,
+ r,
+ g,
+ b,
+ alpha,
+ forward, right, up, flHDRColorScale );
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSprite::GetToolRecordingState( KeyValues *msg )
+{
+ if ( !ToolsEnabled() )
+ return;
+
+ VPROF_BUDGET( "CSprite::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
+
+ BaseClass::GetToolRecordingState( msg );
+
+ // Use attachment point
+ if ( m_hAttachedToEntity )
+ {
+ C_BaseEntity *ent = m_hAttachedToEntity->GetBaseEntity();
+ if ( ent )
+ {
+ BaseEntityRecordingState_t *pState = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
+
+ // override position if we're driven by an attachment
+ QAngle temp;
+ pState->m_vecRenderOrigin = GetAbsOrigin();
+ ent->GetAttachment( m_nAttachment, pState->m_vecRenderOrigin, temp );
+
+ // override viewmodel if we're driven by an attachment
+ bool bViewModel = dynamic_cast< C_BaseViewModel* >( ent ) != NULL;
+ msg->SetInt( "viewmodel", bViewModel );
+ }
+ }
+
+ float renderscale = GetRenderScale();
+ if ( m_bWorldSpaceScale )
+ {
+ CEngineSprite *psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( GetModel() );
+ float flMinSize = MIN( psprite->GetWidth(), psprite->GetHeight() );
+ renderscale /= flMinSize;
+ }
+
+ // sprite params
+ static SpriteRecordingState_t state;
+ state.m_flRenderScale = renderscale;
+ state.m_flFrame = m_flFrame;
+ state.m_flProxyRadius = m_flGlowProxySize;
+ state.m_nRenderMode = GetRenderMode();
+ state.m_nRenderFX = m_nRenderFX;
+ state.m_Color.SetColor( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB(), GetRenderBrightness() );
+
+ msg->SetPtr( "sprite", &state );
+}
|