//----------------------------------------------------------------------------- // Purpose: Draw targeting reticle //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::DrawCrosshair( void ) { BaseClass::DrawCrosshair(); // Find enemy players in front of me C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return; trace_t tr; Vector vecStart, vecEnd; VectorMA( CurrentViewOrigin(), 1500, CurrentViewForward(), vecEnd ); VectorMA( CurrentViewOrigin(), 48, CurrentViewForward(), vecStart ); UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); if ( tr.DidHitNonWorldEntity() ) { C_BaseEntity *pEntity = tr.m_pEnt; if ( pEntity && pEntity->IsPlayer() && !pPlayer->InSameTeam( pEntity ) ) { // Draw a reticle vgui::Color clr = gHUD.m_clrYellowish; clr[3] = 128; // Calculate circle size int iRatio = 30; // Draw the circle int iDegrees = 0; Vector vecPoint, vecLastPoint(0,0,0); vecPoint.z = 0.0f; for ( int i = 0; i < 360; i++ ) { float flRadians = DEG2RAD( iDegrees ); iDegrees += (360 / 360); float ca = cos( flRadians ); float sa = sin( flRadians ); // Rotate it around the circle vecPoint.x = (int)((ScreenWidth() / 2) + (iRatio * sa)); vecPoint.y = (int)((ScreenHeight() / 2) - (iRatio * ca)); // Draw the point, if it's not on the previous point, to avoid smaller circles being brighter if ( vecLastPoint != vecPoint ) { vgui::surface()->DrawSetColor( clr ); vgui::surface()->DrawFilledRect( vecPoint.x, vecPoint.y, vecPoint.x + 1, vecPoint.y + 1 ); } vecLastPoint = vecPoint; } } } }
float GlowSightDistance( const Vector &glowOrigin, bool bShouldTrace ) { float dist = (glowOrigin - CurrentViewOrigin()).Length(); C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); if ( local ) { dist *= local->GetFOVDistanceAdjustFactor(); } if ( bShouldTrace ) { Vector end = glowOrigin; // HACKHACK: trace 4" from destination in case the glow is inside some parent object // allow a little error... if ( dist > 4 ) { end -= CurrentViewForward()*4; } int traceFlags = MASK_OPAQUE|CONTENTS_MONSTER|CONTENTS_DEBRIS; CTraceFilterGlow filter(NULL, COLLISION_GROUP_NONE); trace_t tr; UTIL_TraceLine( CurrentViewOrigin(), end, traceFlags, &filter, &tr ); if ( tr.fraction != 1.0f ) return -1; } return dist; }
//----------------------------------------------------------------------------- // Purpose: Updates and renders all effects //----------------------------------------------------------------------------- int C_HopwireExplosion::DrawModel( int flags ) { AddParticles(); #ifndef C17 CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Flush(); UpdateRefractTexture(); IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); float refract = m_FXCoreAlpha.Interp( gpGlobals->curtime ); float scale = m_FXCoreScale.Interp( gpGlobals->curtime ); IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); pVar->SetFloatValue( refract ); pRenderContext->Bind( pMat, (IClientRenderable*)this ); float sin1 = sinf( gpGlobals->curtime * 10 ); float sin2 = sinf( gpGlobals->curtime ); float scaleY = ( sin1 * sin2 ) * 32.0f; float scaleX = (sin2 * sin2) * 32.0f; // FIXME: The ball needs to sort properly at all times static color32 white = {255,255,255,255}; DrawSpriteTangentSpace( GetRenderOrigin() + ( CurrentViewForward() * 128.0f ), scale+scaleX, scale+scaleY, white ); #endif return 1; }
void CPixelVisibilityQuery::IssueCountingQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ) { if ( !m_failed ) { Assert( IsValid() ); #if 0 // this centers it on the screen. // This is nice because it makes the glows fade as they get partially clipped by the view frustum // But it introduces sub-pixel errors (off by one row/column of pixels) so the glows shimmer // UNDONE: Compute an offset center coord that matches sub-pixel coords with the real glow position // UNDONE: Or frustum clip the sphere/geometry and fade based on proxy size Vector origin = m_origin - CurrentViewOrigin(); float dot = DotProduct(CurrentViewForward(), origin); origin = CurrentViewOrigin() + dot * CurrentViewForward(); #endif PixelVisibility_DrawProxy( pRenderContext, m_queryHandleCount, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); } }
//----------------------------------------------------------------------------- // Compute vectors perpendicular to the beam //----------------------------------------------------------------------------- static void ComputeBeamPerpendicular( const Vector &vecBeamDelta, Vector *pPerp ) { // Direction in worldspace of the center of the beam Vector vecBeamCenter = vecBeamDelta; VectorNormalize( vecBeamCenter ); CrossProduct( CurrentViewForward(), vecBeamCenter, *pPerp ); VectorNormalize( *pPerp ); }
//----------------------------------------------------------------------------- // 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; }
void CSimple3DEmitter::RenderParticles( CParticleRenderIterator *pIterator ) { const Particle3D *pParticle = (const Particle3D *)pIterator->GetFirst(); while ( pParticle ) { float sortKey = CurrentViewForward().Dot( CurrentViewOrigin() - pParticle->m_Pos ); // ------------------------------------------------------- // Set color based on direction towards camera // ------------------------------------------------------- Vector color; Vector vFaceNorm; Vector vCameraToFace = (pParticle->m_Pos - CurrentViewOrigin()); AngleVectors(pParticle->m_vAngles,&vFaceNorm); float flFacing = DotProduct(vCameraToFace,vFaceNorm); if (flFacing <= 0) { color[0] = pParticle->m_uchFrontColor[0] / 255.0f; color[1] = pParticle->m_uchFrontColor[1] / 255.0f; color[2] = pParticle->m_uchFrontColor[2] / 255.0f; } else { color[0] = pParticle->m_uchBackColor[0] / 255.0f; color[1] = pParticle->m_uchBackColor[1] / 255.0f; color[2] = pParticle->m_uchBackColor[2] / 255.0f; } //Render it in world space RenderParticle_ColorSizeAngles( pIterator->GetParticleDraw(), pParticle->m_Pos, color, pParticle->GetFadeFraction(), pParticle->m_uchSize, pParticle->m_vAngles); pParticle = (const Particle3D *)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : flags - // Output : int //----------------------------------------------------------------------------- int C_WeaponPhysCannon::DrawModel( int flags ) { // If we're not ugrading, don't do anything special if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false ) return BaseClass::DrawModel( flags ); if ( gpGlobals->frametime == 0 ) return BaseClass::DrawModel( flags ); if ( !m_bReadyToDraw ) return 0; m_bWasUpgraded = true; // Create the particle emitter if it's not already if ( SetupEmitter() ) { // Add the power-up particles // See if we should draw if ( m_bReadyToDraw == false ) return 0; C_BaseAnimating *pAnimating = GetBaseAnimating(); if (!pAnimating) return 0; matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) ) return 0; studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) return false; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( !set ) return false; int i; float fadePerc = 1.0f; if ( m_bIsCurrentlyUpgrading ) { Vector vecSkew = vec3_origin; // Skew the particles in front or in back of their targets vecSkew = CurrentViewForward() * 4.0f; float spriteScale = 1.0f; spriteScale = clamp( spriteScale, 0.75f, 1.0f ); SimpleParticle *sParticle; for ( i = 0; i < set->numhitboxes; ++i ) { Vector vecAbsOrigin, xvec, yvec; mstudiobbox_t *pBox = set->pHitbox(i); ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec ); Vector offset; Vector xDir, yDir; xDir = xvec; float xScale = VectorNormalize( xDir ) * 0.75f; yDir = yvec; float yScale = VectorNormalize( yDir ) * 0.75f; int numParticles = clamp( 4.0f * fadePerc, 1, 3 ); for ( int j = 0; j < numParticles; j++ ) { offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); offset += vecSkew; sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = vec3_origin; sParticle->m_uchStartSize = 16.0f * spriteScale; sParticle->m_flDieTime = 0.2f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f ); float alpha = 40; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2; } } } } int attachment = LookupAttachment( "core" ); Vector coreOrigin; QAngle coreAngles; GetAttachment( attachment, coreOrigin, coreAngles ); SimpleParticle *sParticle; // Do the core effects for ( int i = 0; i < 4; i++ ) { sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = vec3_origin; sParticle->m_flDieTime = 0.1f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 255; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; if ( i < 2 ) { sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; } else { if ( random->RandomInt( 0, 20 ) == 0 ) { sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f; sParticle->m_flDieTime = 0.25f; } else { sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; } } } if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading ) { // Update our attractor point m_pAttractor->SetAttractorOrigin( coreOrigin ); Vector offset; for ( int i = 0; i < 4; i++ ) { offset = coreOrigin + RandomVector( -32.0f, 32.0f ); sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = Vector(0,0,8); sParticle->m_flDieTime = 0.5f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 255; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); sParticle->m_uchEndSize = 0; } } return BaseClass::DrawModel( flags ); }
float PixelVisibility_DrawProxy( IMatRenderContext *pRenderContext, OcclusionQueryObjectHandle_t queryHandle, Vector origin, float scale, float proxyAspect, IMaterial *pMaterial, bool screenspace ) { Vector point; // don't expand this with distance to fit pixels or the sprite will poke through // only expand the parts perpendicular to the view float forwardScale = scale; // draw a pyramid of points touching a sphere of radius "scale" at origin float pixelsPerUnit = pRenderContext->ComputePixelDiameterOfSphere( origin, 1.0f ); pixelsPerUnit = MAX( pixelsPerUnit, 1e-4f ); if ( screenspace ) { // Force this to be the size of a sphere of diameter "scale" at some reference distance (1.0 unit) float pixelsPerUnit2 = pRenderContext->ComputePixelDiameterOfSphere( CurrentViewOrigin() + CurrentViewForward()*1.0f, scale*0.5f ); // force drawing of "scale" pixels scale = pixelsPerUnit2 / pixelsPerUnit; } else { float pixels = scale * pixelsPerUnit; // make the radius larger to ensure a minimum screen space size of the proxy geometry if ( pixels < MIN_PROXY_PIXELS ) { scale = MIN_PROXY_PIXELS / pixelsPerUnit; } } // collapses the pyramid to a plane - so this could be a quad instead Vector dir = origin - CurrentViewOrigin(); VectorNormalize(dir); origin -= dir * forwardScale; forwardScale = 0.0f; // Vector verts[5]; const float sqrt2 = 0.707106781f; // sqrt(2) - keeps all vectors the same length from origin scale *= sqrt2; float scale45x = scale; float scale45y = scale / proxyAspect; verts[0] = origin - CurrentViewForward() * forwardScale; // the apex of the pyramid verts[1] = origin + CurrentViewUp() * scale45y - CurrentViewRight() * scale45x; // these four form the base verts[2] = origin + CurrentViewUp() * scale45y + CurrentViewRight() * scale45x; // the pyramid is a sprite with a point that verts[3] = origin - CurrentViewUp() * scale45y + CurrentViewRight() * scale45x; // pokes back toward the camera through any nearby verts[4] = origin - CurrentViewUp() * scale45y - CurrentViewRight() * scale45x; // geometry // get screen coords of edges Vector screen[4]; for ( int i = 0; i < 4; i++ ) { extern int ScreenTransform( const Vector& point, Vector& screen ); if ( ScreenTransform( verts[i+1], screen[i] ) ) return -1; } // compute area and screen-clipped area float w = screen[1].x - screen[0].x; float h = screen[0].y - screen[3].y; float ws = MIN(1.0f, screen[1].x) - MAX(-1.0f, screen[0].x); float hs = MIN(1.0f, screen[0].y) - MAX(-1.0f, screen[3].y); float area = w*h; // area can be zero when we ALT-TAB float areaClipped = ws*hs; float ratio = 0.0f; if ( area != 0 ) { // compute the ratio of the area not clipped by the frustum to total area ratio = areaClipped / area; ratio = clamp(ratio, 0.0f, 1.0f); } pRenderContext->BeginOcclusionQueryDrawing( queryHandle ); CMeshBuilder meshBuilder; IMesh* pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 4 ); // draw a pyramid for ( int i = 0; i < 4; i++ ) { int a = i+1; int b = (a%4)+1; meshBuilder.Position3fv( verts[0].Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( verts[a].Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( verts[b].Base() ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); pMesh->Draw(); // sprite/quad proxy #if 0 meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); VectorMA (origin, -scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, -scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); #endif pRenderContext->EndOcclusionQueryDrawing( queryHandle ); // fraction clipped by frustum return ratio; }
void CGlowOverlay::Draw( bool bCacheFullSceneState ) { extern ConVar r_drawsprites; if( !r_drawsprites.GetBool() ) return; // Get the vector to the sun. Vector vToGlow; if( m_bDirectional ) vToGlow = m_vDirection; else vToGlow = m_vPos - CurrentViewOrigin(); VectorNormalize( vToGlow ); float flDot = vToGlow.Dot( CurrentViewForward() ); UpdateGlowObstruction( vToGlow, bCacheFullSceneState ); if( m_flGlowObstructionScale == 0 ) return; bool bWireframe = ShouldDrawInWireFrameMode() || (r_drawsprites.GetInt() == 2); CMatRenderContextPtr pRenderContext( materials ); for( int iSprite=0; iSprite < m_nSprites; iSprite++ ) { CGlowSprite *pSprite = &m_Sprites[iSprite]; // Figure out the color and size to draw it. float flHorzSize, flVertSize; Vector vColor; CalcSpriteColorAndSize( flDot, pSprite, &flHorzSize, &flVertSize, &vColor ); // If we're alpha'd out, then don't bother if ( vColor.LengthSqr() < 0.00001f ) continue; // Setup the basis to draw the sprite. Vector vBasePt, vUp, vRight; CalcBasis( vToGlow, flHorzSize, flVertSize, vBasePt, vUp, vRight ); //Get our diagonal radius float radius = (vRight+vUp).Length(); if ( R_CullSphere( view->GetFrustum(), 5, &vBasePt, radius ) ) continue; // Get our material (deferred default load) if ( m_Sprites[iSprite].m_pMaterial == NULL ) { m_Sprites[iSprite].m_pMaterial = materials->FindMaterial( "sprites/light_glow02_add_noz", TEXTURE_GROUP_CLIENT_EFFECTS ); } Assert( m_Sprites[iSprite].m_pMaterial ); static unsigned int nHDRColorScaleCache = 0; IMaterialVar *pHDRColorScaleVar = m_Sprites[iSprite].m_pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache ); if( pHDRColorScaleVar ) { pHDRColorScaleVar->SetFloatValue( m_flHDRColorScale ); } // Draw the sprite. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, m_Sprites[iSprite].m_pMaterial ); CMeshBuilder builder; builder.Begin( pMesh, MATERIAL_QUADS, 1 ); Vector vPt; vPt = vBasePt - vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 0, 1 ); builder.AdvanceVertex(); vPt = vBasePt + vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 1, 1 ); builder.AdvanceVertex(); vPt = vBasePt + vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 1, 0 ); builder.AdvanceVertex(); vPt = vBasePt - vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 0, 0 ); builder.AdvanceVertex(); builder.End( false, true ); if( bWireframe ) { IMaterial *pWireframeMaterial = materials->FindMaterial( "debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER ); pRenderContext->Bind( pWireframeMaterial ); // Draw the sprite. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, pWireframeMaterial ); CMeshBuilder builder; builder.Begin( pMesh, MATERIAL_QUADS, 1 ); Vector vPt; vPt = vBasePt - vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color3f( 1.0f, 0.0f, 0.0f ); builder.AdvanceVertex(); vPt = vBasePt + vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color3f( 1.0f, 0.0f, 0.0f ); builder.AdvanceVertex(); vPt = vBasePt + vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color3f( 1.0f, 0.0f, 0.0f ); builder.AdvanceVertex(); vPt = vBasePt - vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color3f( 1.0f, 0.0f, 0.0f ); builder.AdvanceVertex(); builder.End( false, true ); } } }
//----------------------------------------------------------------------------- // Purpose: Simulate and render the particle in this system // Input : *pInParticle - particle to consider // *pDraw - drawing utilities // &sortKey - sorting key // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CSimple3DEmitter::SimulateAndRender( Particle *pInParticle, ParticleDraw *pDraw, float &sortKey ) { Particle3D *pParticle = (Particle3D *) pInParticle; const float timeDelta = pDraw->GetTimeDelta(); //Should this particle die? pParticle->m_flLifetime += timeDelta; if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) return false; sortKey = CurrentViewForward().Dot( CurrentViewOrigin() - pParticle->m_Pos ); // ------------------------------------------------------- // Set color based on direction towards camera // ------------------------------------------------------- Vector color; Vector vFaceNorm; Vector vCameraToFace = (pParticle->m_Pos - CurrentViewOrigin()); AngleVectors(pParticle->m_vAngles,&vFaceNorm); float flFacing = DotProduct(vCameraToFace,vFaceNorm); if (flFacing <= 0) { color[0] = pParticle->m_uchFrontColor[0] / 255.0f; color[1] = pParticle->m_uchFrontColor[1] / 255.0f; color[2] = pParticle->m_uchFrontColor[2] / 255.0f; } else { color[0] = pParticle->m_uchBackColor[0] / 255.0f; color[1] = pParticle->m_uchBackColor[1] / 255.0f; color[2] = pParticle->m_uchBackColor[2] / 255.0f; } // Angular rotation pParticle->m_vAngles.x += pParticle->m_flAngSpeed * timeDelta; pParticle->m_vAngles.y += pParticle->m_flAngSpeed * timeDelta; pParticle->m_vAngles.z += pParticle->m_flAngSpeed * timeDelta; //Render it in world space RenderParticle_ColorSizeAngles( pDraw, pParticle->m_Pos, color, 1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime), pParticle->m_uchSize, pParticle->m_vAngles); //Simulate the movement with collision trace_t trace; m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, &pParticle->m_flAngSpeed, timeDelta, &trace ); // --------------------------------------- // Decay towards flat // --------------------------------------- if (pParticle->m_flAngSpeed == 0 || trace.fraction != 1.0) { pParticle->m_vAngles.x = anglemod(pParticle->m_vAngles.x); if (pParticle->m_vAngles.x < 180) { if (fabs(pParticle->m_vAngles.x - 90) > 0.5) { pParticle->m_vAngles.x = 0.5*pParticle->m_vAngles.x + 46; } } else { if (fabs(pParticle->m_vAngles.x - 270) > 0.5) { pParticle->m_vAngles.x = 0.5*pParticle->m_vAngles.x + 135; } } pParticle->m_vAngles.y = anglemod(pParticle->m_vAngles.y); if (fabs(pParticle->m_vAngles.y) > 0.5) { pParticle->m_vAngles.y = 0.5*pParticle->m_vAngles.z; } } return true; }
//----------------------------------------------------------------------------- // Purpose: Special draw for the warped overlay //----------------------------------------------------------------------------- void CWarpOverlay::Draw( bool bCacheFullSceneState ) { // Get the vector to the sun. Vector vToGlow; if( m_bDirectional ) vToGlow = m_vDirection; else vToGlow = m_vPos - CurrentViewOrigin(); VectorNormalize( vToGlow ); float flDot = vToGlow.Dot( CurrentViewForward() ); if( flDot <= g_flOverlayRange ) return; UpdateGlowObstruction( vToGlow, bCacheFullSceneState ); if( m_flGlowObstructionScale == 0 ) return; CMatRenderContextPtr pRenderContext( materials ); //FIXME: Allow multiple? for( int iSprite=0; iSprite < m_nSprites; iSprite++ ) { CGlowSprite *pSprite = &m_Sprites[iSprite]; // Figure out the color and size to draw it. float flHorzSize, flVertSize; Vector vColor; CalcSpriteColorAndSize( flDot, pSprite, &flHorzSize, &flVertSize, &vColor ); // Setup the basis to draw the sprite. Vector vBasePt, vUp, vRight; CalcBasis( vToGlow, flHorzSize, flVertSize, vBasePt, vUp, vRight ); // Draw the sprite. IMaterial *pMaterial = materials->FindMaterial( "sun/overlay", TEXTURE_GROUP_CLIENT_EFFECTS ); IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, pMaterial ); CMeshBuilder builder; builder.Begin( pMesh, MATERIAL_QUADS, 1 ); Vector vPt; vPt = vBasePt - vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 0, 1 ); builder.AdvanceVertex(); vPt = vBasePt + vRight + vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 1, 1 ); builder.AdvanceVertex(); vPt = vBasePt + vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 1, 0 ); builder.AdvanceVertex(); vPt = vBasePt - vRight - vUp; builder.Position3fv( vPt.Base() ); builder.Color4f( VectorExpand(vColor), 1 ); builder.TexCoord2f( 0, 0, 0 ); builder.AdvanceVertex(); builder.End( false, true ); } }
//----------------------------------------------------------------------------- // Purpose: // TFTODO: Make the sniper dot get brighter the more damage it will do. //----------------------------------------------------------------------------- int CSniperDot::DrawModel( int flags ) { // Get the owning player. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() ); if ( !pPlayer ) return -1; // Get the sprite rendering position. Vector vecEndPos; float flSize = 6.0; if ( !pPlayer->IsDormant() ) { Vector vecAttachment, vecDir; QAngle angles; float flDist = MAX_TRACE_LENGTH; // Always draw the dot in front of our faces when in first-person. if ( pPlayer->IsLocalPlayer() ) { // Take our view position and orientation vecAttachment = CurrentViewOrigin(); vecDir = CurrentViewForward(); // Clamp the forward distance for the sniper's firstperson flDist = 384; flSize = 2.0; } else { // Take the owning player eye position and direction. vecAttachment = pPlayer->EyePosition(); QAngle angles = pPlayer->EyeAngles(); AngleVectors( angles, &vecDir ); } trace_t tr; UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * flDist ), MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); // Backup off the hit plane, towards the source vecEndPos = tr.endpos + vecDir * -4; } else { // Just use our position if we can't predict it otherwise. vecEndPos = GetAbsOrigin(); } // Draw our laser dot in space. CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( m_hSpriteMaterial, this ); float flLifeTime = gpGlobals->curtime - m_flChargeStartTime; float flStrength = RemapValClamped( flLifeTime, 0.0, TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX / TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC, 0.1, 1.0 ); color32 innercolor = { 255, 255, 255, 255 }; color32 outercolor = { 255, 255, 255, 128 }; DrawSprite( vecEndPos, flSize, flSize, outercolor ); DrawSprite( vecEndPos, flSize * flStrength, flSize * flStrength, innercolor ); // Successful. return 1; }
//----------------------------------------------------------------------------- // Purpose: // TFTODO: Make the sniper dot get brighter the more damage it will do. //----------------------------------------------------------------------------- int CSniperDot::DrawModel( int flags ) { // Get the owning player. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() ); if ( !pPlayer ) return -1; // Get the sprite rendering position. Vector vecEndPos; float flSize = 6.0; if ( !pPlayer->IsDormant() ) { Vector vecAttachment, vecDir; QAngle angles; float flDist = MAX_TRACE_LENGTH; // Always draw the dot in front of our faces when in first-person. if ( pPlayer->IsLocalPlayer() ) { // Take our view position and orientation vecAttachment = CurrentViewOrigin(); vecDir = CurrentViewForward(); // Clamp the forward distance for the sniper's firstperson flDist = 384; flSize = 2.0; } else { // Take the owning player eye position and direction. vecAttachment = pPlayer->EyePosition(); QAngle angles = pPlayer->EyeAngles(); AngleVectors( angles, &vecDir ); } trace_t tr; UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * flDist ), MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); // Backup off the hit plane, towards the source vecEndPos = tr.endpos + vecDir * -4; } else { // Just use our position if we can't predict it otherwise. vecEndPos = GetAbsOrigin(); } // Draw our laser dot in space. CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( m_hSpriteMaterial, this ); float flLifeTime = gpGlobals->curtime - m_flChargeStartTime; float flStrength = RemapValClamped( flLifeTime, 0.0, TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX / TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC, 0.1, 1.0 ); color32 innercolor = { 255, 255, 255, 255 }; color32 outercolor = { 255, 255, 255, 128 }; // PistonMiner: DM sniper point coloring if (TFGameRules()->IsDeathmatch()) { // Get the color of the mercenary we are drawing the dot of. C_TF_PlayerResource *tf_PR = dynamic_cast<C_TF_PlayerResource *>(g_PR); Color ownercolor = tf_PR->GetPlayerColor(pPlayer->index); // Convert to HSV so we can edit the color better. Vector hsv, rgb; RGBtoHSV(Vector(ownercolor.r() / 255.f, ownercolor.g() / 255.f, ownercolor.b() / 255.f), hsv); // Set the Value to max for constant brightness. hsv.z = 1.0; // Convert back to RGB HSVtoRGB(hsv, rgb); // Apply the color to our sprite. m_hSpriteMaterial->ColorModulate( rgb.x, rgb.y, rgb.z ); } DrawSprite( vecEndPos, flSize, flSize, outercolor ); DrawSprite( vecEndPos, flSize * flStrength, flSize * flStrength, innercolor ); // Successful. return 1; }
//----------------------------------------------------------------------------- // 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: // Input : flags - // Output : int //----------------------------------------------------------------------------- int C_EntityDissolve::DrawModel( int flags ) { // See if we should draw if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false ) return 0; C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; if ( pAnimating == NULL ) return 0; matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false ) return 0; studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr == NULL ) return false; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set == NULL ) return false; // Make sure the emitter is setup properly SetupEmitter(); // Get fade percentages for the effect float fadeInPerc = GetFadeInPercentage(); float fadeOutPerc = GetFadeOutPercentage(); float fadePerc = ( fadeInPerc >= 1.0f ) ? fadeOutPerc : fadeInPerc; Vector vecSkew = vec3_origin; // Do extra effects under certain circumstances if ( ( fadePerc < 0.99f ) && ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) ) ) { DoSparks( set, hitboxbones ); } // Skew the particles in front or in back of their targets vecSkew = CurrentViewForward() * ( 8.0f - ( ( 1.0f - fadePerc ) * 32.0f ) ); float spriteScale = ( ( gpGlobals->curtime - m_flStartTime ) / m_flFadeOutLength ); spriteScale = clamp( spriteScale, 0.75f, 1.0f ); // Cache off this material reference if ( g_Material_Spark == NULL ) { g_Material_Spark = ParticleMgr()->GetPMaterial( "effects/spark" ); } if ( g_Material_AR2Glow == NULL ) { g_Material_AR2Glow = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" ); } SimpleParticle *sParticle; for ( int i = 0; i < set->numhitboxes; ++i ) { Vector vecAbsOrigin, xvec, yvec; mstudiobbox_t *pBox = set->pHitbox(i); ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec ); Vector offset; Vector xDir, yDir; xDir = xvec; float xScale = VectorNormalize( xDir ) * 0.75f; yDir = yvec; float yScale = VectorNormalize( yDir ) * 0.75f; int numParticles = clamp( 3.0f * fadePerc, 0.f, 3.f ); int iTempParts = 2; if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { numParticles = 15; iTempParts = 20; } } for ( int j = 0; j < iTempParts; j++ ) { // Skew the origin offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); offset += vecSkew; if ( random->RandomInt( 0, 2 ) != 0 ) continue; sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, vecAbsOrigin + offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) ); if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; VectorNormalize( vDirection ); sParticle->m_vecVelocity = vDirection * m_nMagnitude; } } if ( sParticle->m_vecVelocity.z > 0 ) { sParticle->m_uchStartSize = random->RandomFloat( 4, 6 ) * spriteScale; } else { sParticle->m_uchStartSize = 2 * spriteScale; } sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.5f ); // If we're the last particles, last longer if ( numParticles == 0 ) { sParticle->m_flDieTime *= 2.0f; sParticle->m_uchStartSize = 2 * spriteScale; sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f ); if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { sParticle->m_flDieTime *= 2.0f; sParticle->m_flRollDelta = Helper_RandomFloat( -1.0f, 1.0f ); } } } else { sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f, 8.0f ); } sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); float alpha = 255; sParticle->m_uchColor[0] = m_vEffectColor.x; sParticle->m_uchColor[1] = m_vEffectColor.y; sParticle->m_uchColor[2] = m_vEffectColor.z; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; } for ( int j = 0; j < numParticles; j++ ) { offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); offset += vecSkew; sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_AR2Glow, vecAbsOrigin + offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -64.0f, 128.0f ) ); sParticle->m_uchStartSize = random->RandomFloat( 8, 12 ) * spriteScale; sParticle->m_flDieTime = 0.1f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f ); float alpha = 255; sParticle->m_uchColor[0] = m_vEffectColor.x; sParticle->m_uchColor[1] = m_vEffectColor.y; sParticle->m_uchColor[2] = m_vEffectColor.z; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; VectorNormalize( vDirection ); sParticle->m_vecVelocity = vDirection * m_nMagnitude; sParticle->m_flDieTime = 0.5f; } } } } return 1; }
void CFXDiscreetLine::Draw( double frametime ) { Vector lineDir, viewDir, cross; Vector vecEnd, vecStart; Vector tmp; // Update the effect Update( frametime ); // Calculate our distance along our path float sDistance = m_fVelocity * m_fStartTime; float eDistance = sDistance - m_fLength; //Clip to start sDistance = MAX( 0.0f, sDistance ); eDistance = MAX( 0.0f, eDistance ); if ( ( sDistance == 0.0f ) && ( eDistance == 0.0f ) ) return; // Clip it if ( m_fClipLength != 0.0f ) { sDistance = MIN( sDistance, m_fClipLength ); eDistance = MIN( eDistance, m_fClipLength ); } // Get our delta to calculate the tc offset float dDistance = fabs( sDistance - eDistance ); float dTotal = ( m_fLength != 0.0f ) ? m_fLength : 0.01f; float fOffset = ( dDistance / dTotal ); // Find our points along our path VectorMA( m_vecOrigin, sDistance, m_vecDirection, vecEnd ); VectorMA( m_vecOrigin, eDistance, m_vecDirection, vecStart ); //Setup our info for drawing the line VectorSubtract( vecEnd, vecStart, lineDir ); VectorSubtract( vecEnd, CurrentViewOrigin(), viewDir ); cross = lineDir.Cross( viewDir ); VectorNormalize( cross ); CMeshBuilder meshBuilder; IMesh *pMesh; CMatRenderContextPtr pRenderContext( materials ); // Better, more visible tracers if ( tracer_extra.GetBool() ) { float flScreenWidth = ScreenWidth(); float flHalfScreenWidth = flScreenWidth * 0.5f; float zCoord = CurrentViewForward().Dot( vecStart - CurrentViewOrigin() ); float flScreenSpaceWidth = m_fScale * flHalfScreenWidth / zCoord; float flAlpha; float flScale; if ( flScreenSpaceWidth < 0.5f ) { flAlpha = RemapVal( flScreenSpaceWidth, 0.25f, 2.0f, 0.3f, 1.0f ); flAlpha = clamp( flAlpha, 0.25f, 1.0f ); flScale = 0.5f * zCoord / flHalfScreenWidth; } else { flAlpha = 1.0f; flScale = m_fScale; } //Bind the material pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 2 ); float color = (int) 255.0f * flAlpha; //FIXME: for now no coloration VectorMA( vecStart, -flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecStart, flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, fOffset ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, -flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, fOffset ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); flScale = flScale * 2.0f; color = (int) 64.0f * flAlpha; // Soft outline VectorMA( vecStart, -flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecStart, flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, fOffset ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, -flScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, fOffset ); meshBuilder.Color4ub( color, color, color, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); } else { //Bind the material pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); //FIXME: for now no coloration VectorMA( vecStart, -m_fScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); meshBuilder.Color4ub( 255, 255, 255, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecStart, m_fScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); meshBuilder.Color4ub( 255, 255, 255, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, m_fScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 0.0f, fOffset ); meshBuilder.Color4ub( 255, 255, 255, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); VectorMA( vecEnd, -m_fScale, cross, tmp ); meshBuilder.Position3fv( tmp.Base() ); meshBuilder.TexCoord2f( 0, 1.0f, fOffset ); meshBuilder.Color4ub( 255, 255, 255, 255 ); meshBuilder.Normal3fv( cross.Base() ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); pMesh->Draw(); }