void CLocalSpaceEmitter::RenderParticles( CParticleRenderIterator *pIterator ) { const matrix3x4_t &mLocalToWorld = GetTransformMatrix(); const VMatrix &mModelView = ParticleMgr()->GetModelView(); const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst(); while ( pParticle ) { // Transform it Vector screenPos, worldPos; VectorTransform( pParticle->m_Pos, mLocalToWorld, worldPos ); // Correct viewmodel squashing if ( m_fFlags & FLE_VIEWMODEL ) { FormatViewModelAttachment( NULL, worldPos, false ); } TransformParticle( mModelView, worldPos, screenPos ); float sortKey = (int) screenPos.z; // Render it RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), screenPos, UpdateColor( pParticle ), UpdateAlpha( pParticle ) * GetAlphaDistanceFade( screenPos, m_flNearClipMin, m_flNearClipMax ), UpdateScale( pParticle ), pParticle->m_flRoll ); pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Returns the attachment render origin + origin //----------------------------------------------------------------------------- void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ) { C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity(); if (pEnt && (m_nAttachmentIndex > 0)) { pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles ); if ( IsAttachedToViewModel() ) { FormatViewModelAttachment( *pOrigin, true ); } } else { BaseClass::GetAimEntOrigin( pAttachedTo, pOrigin, pAngles ); } }
//----------------------------------------------------------------------------- // Returns the attachment render origin + origin //----------------------------------------------------------------------------- void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ) { C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity(); const char* panelName = PanelName(); vgui::Panel panel = m_PanelWrapper.GetPanel(); if ( Q_strcmp(panelName, "health_screen") == 0 ) { QAngle weapAngles = pEnt->GetAbsAngles(); Vector weapForward, weapRight, weapUp; AngleVectors(weapAngles, &weapForward, &weapRight, &weapUp); VMatrix worldFromPanel; AngleMatrix(weapAngles, worldFromPanel.As3x4()); MatrixRotate(worldFromPanel, Vector(0, 0, 1), 180.f); MatrixRotate(worldFromPanel, Vector(1, 0, 0), -90.f); MatrixAngles(worldFromPanel.As3x4(), *pAngles); // move it right and over *pOrigin = pEnt->GetAbsOrigin() + weapRight*1.75 + weapUp*2.3 + weapForward*5; return; } //todo: set alpha per view ... m_PanelWrapper.GetPanel()->SetAlpha(200); if (pEnt && (m_nAttachmentIndex > 0)) { { C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles ); } if ( IsAttachedToViewModel() ) { FormatViewModelAttachment( *pOrigin, true ); } } else { BaseClass::GetAimEntOrigin( pAttachedTo, pOrigin, pAngles ); } // Msg("%s origin %.1f %.1f %.1f angles %.1f %.1f %.1f \n", PanelName(), pOrigin->x, pOrigin->y, pOrigin->z, pAngles->x, pAngles->y, pAngles->z); }
//----------------------------------------------------------------------------- // Purpose: Get the attachment point on a viewmodel that a base weapon is using //----------------------------------------------------------------------------- bool UTIL_GetWeaponAttachment( C_BaseCombatWeapon *pWeapon, int attachmentID, Vector &absOrigin, QAngle &absAngles ) { // This is already correct in third-person if ( pWeapon && pWeapon->ShouldDrawUsingViewModel() == false ) { return pWeapon->GetAttachment( attachmentID, absOrigin, absAngles ); } // Otherwise we need to translate the attachment to the viewmodel's version and reformat it CBasePlayer *pOwner = ToBasePlayer( pWeapon->GetOwner() ); if ( pOwner != NULL ) { int ret = pOwner->GetViewModel()->GetAttachment( attachmentID, absOrigin, absAngles ); FormatViewModelAttachment( absOrigin, true ); return ret; } // Wasn't found return false; }
//----------------------------------------------------------------------------- // Purpose: Get the attachment point on a viewmodel that a base weapon is using //----------------------------------------------------------------------------- bool UTIL_GetWeaponAttachment( C_BaseCombatWeapon *pWeapon, int attachmentID, Vector &absOrigin, QAngle &absAngles ) { // Other players & third person if ( pWeapon && (!pWeapon->IsCarriedByLocalPlayer() || ::input->CAM_IsThirdPerson())) { return pWeapon->GetAttachment( attachmentID, absOrigin, absAngles ); } // Otherwise we need to translate the attachment to the viewmodel's version and reformat it CBasePlayer *pOwner = ToBasePlayer( pWeapon->GetOwner() ); if ( pOwner != NULL ) { int ret = pOwner->GetViewModel()->GetAttachment( attachmentID, absOrigin, absAngles ); FormatViewModelAttachment( absOrigin, true ); return ret; } // Wasn't found return false; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int iPoint, bool bInitializing ) { ParticleControlPoint_t *pPoint = &pEffect->pControlPoints[iPoint]; if ( !pPoint->hEntity.Get() ) { if ( pPoint->iAttachType == PATTACH_WORLDORIGIN && bInitializing ) { pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, Vector(1,0,0), Vector(0,1,0), Vector(0,0,1) ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, pPoint->vecOriginOffset ); pEffect->pParticleEffect->SetSortOrigin( pPoint->vecOriginOffset ); } pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, NULL ); return; } // Only update non-follow particles when we're initializing, // unless we're parented to something, in which case we should always update if ( !bInitializing && !pPoint->hEntity->GetMoveParent() && (pPoint->iAttachType == PATTACH_ABSORIGIN || pPoint->iAttachType == PATTACH_POINT ) ) return; if ( pPoint->iAttachType == PATTACH_CUSTOMORIGIN ) return; Vector vecOrigin, vecForward, vecRight, vecUp; float flOffset = 0.0f; bool bUsingHeadOrigin = false; #ifdef TF_CLIENT_DLL CBaseEntity *pWearable = (CBaseEntity*) pPoint->hEntity.Get(); if ( pWearable && dynamic_cast<IHasAttributes*>( pWearable ) && !pWearable->IsPlayer() ) { C_BaseAnimating *pAnimating = pPoint->hEntity->GetBaseAnimating(); if ( pAnimating ) { int bUseHeadOrigin = 0; CALL_ATTRIB_HOOK_INT_ON_OTHER( pPoint->hEntity.Get(), bUseHeadOrigin, particle_effect_use_head_origin ); if ( bUseHeadOrigin > 0 ) { int iBone = Studio_BoneIndexByName( pAnimating->GetModelPtr(), "bip_head" ); if ( iBone < 0 ) { iBone = Studio_BoneIndexByName( pAnimating->GetModelPtr(), "prp_helmet" ); if ( iBone < 0 ) { iBone = Studio_BoneIndexByName( pAnimating->GetModelPtr(), "prp_hat" ); } } if ( iBone >= 0 ) { bUsingHeadOrigin = true; const matrix3x4_t headBone = pAnimating->GetBone( iBone ); MatrixVectors( headBone, &vecForward, &vecRight, &vecUp ); MatrixPosition( headBone, vecOrigin ); CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pPoint->hEntity.Get(), flOffset, particle_effect_vertical_offset ); } } } } #endif if ( !bUsingHeadOrigin ) { switch ( pPoint->iAttachType ) { case PATTACH_POINT: case PATTACH_POINT_FOLLOW: { C_BaseAnimating *pAnimating = pPoint->hEntity->GetBaseAnimating(); Assert( pAnimating ); if ( pAnimating ) { matrix3x4_t attachmentToWorld; if ( !pAnimating->GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) { // try C_BaseAnimating if attach point is not on the weapon if ( !pAnimating->C_BaseAnimating::GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) { Warning( "Cannot update control point %d for effect '%s'.\n", pPoint->iAttachmentPoint, pEffect->pParticleEffect->GetEffectName() ); attachmentToWorld = pAnimating->RenderableToWorldTransform(); } } VMatrix vMat(attachmentToWorld); MatrixTranslate( vMat, pPoint->vecOriginOffset ); MatrixVectors( vMat.As3x4(), &vecForward, &vecRight, &vecUp ); MatrixPosition( vMat.As3x4(), vecOrigin ); if ( pEffect->pParticleEffect->m_pDef->IsViewModelEffect() ) { FormatViewModelAttachment( vecOrigin, true ); } } } break; case PATTACH_ABSORIGIN: case PATTACH_ABSORIGIN_FOLLOW: default: { vecOrigin = pPoint->hEntity->GetAbsOrigin() + pPoint->vecOriginOffset; pPoint->hEntity->GetVectors( &vecForward, &vecRight, &vecUp ); } break; case PATTACH_ROOTBONE_FOLLOW: { C_BaseAnimating *pAnimating = pPoint->hEntity->GetBaseAnimating(); Assert( pAnimating ); if ( pAnimating ) { matrix3x4_t rootBone; if ( pAnimating->GetRootBone( rootBone ) ) { MatrixVectors( rootBone, &vecForward, &vecRight, &vecUp ); MatrixPosition( rootBone, vecOrigin ); } } } break; } } Vector vecForcedOriginOffset( 0, 0, flOffset ); pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, vecForward, vecRight, vecUp ); pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, pPoint->hEntity ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, vecOrigin + vecForcedOriginOffset ); pEffect->pParticleEffect->SetSortOrigin( vecOrigin + vecForcedOriginOffset); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int iPoint, bool bInitializing ) { ParticleControlPoint_t *pPoint = &pEffect->pControlPoints[iPoint]; if ( !pPoint->hEntity.Get() ) { if ( pPoint->iAttachType == PATTACH_WORLDORIGIN && bInitializing ) { pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, Vector(1,0,0), Vector(0,1,0), Vector(0,0,1) ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, pPoint->vecOriginOffset ); pEffect->pParticleEffect->SetSortOrigin( pPoint->vecOriginOffset ); } pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, NULL ); return; } // Only update non-follow particles when we're initializing, // unless we're parented to something, in which case we should always update if ( !bInitializing && !pPoint->hEntity->GetMoveParent() && (pPoint->iAttachType == PATTACH_ABSORIGIN || pPoint->iAttachType == PATTACH_POINT ) ) return; if ( pPoint->iAttachType == PATTACH_CUSTOMORIGIN ) return; Vector vecOrigin, vecForward, vecRight, vecUp; switch ( pPoint->iAttachType ) { case PATTACH_POINT: case PATTACH_POINT_FOLLOW: { C_BaseAnimating *pAnimating = pPoint->hEntity->GetBaseAnimating(); Assert( pAnimating ); if ( pAnimating ) { matrix3x4_t attachmentToWorld; pAnimating->GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ); MatrixVectors( attachmentToWorld, &vecForward, &vecRight, &vecUp ); MatrixPosition( attachmentToWorld, vecOrigin ); if ( pEffect->pParticleEffect->m_pDef->IsViewModelEffect() ) { FormatViewModelAttachment( vecOrigin, true ); } } } break; case PATTACH_ABSORIGIN: case PATTACH_ABSORIGIN_FOLLOW: default: { vecOrigin = pPoint->hEntity->GetAbsOrigin() + pPoint->vecOriginOffset; pPoint->hEntity->GetVectors( &vecForward, &vecRight, &vecUp ); } break; } pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, vecForward, vecRight, vecUp ); pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, pPoint->hEntity ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, vecOrigin ); pEffect->pParticleEffect->SetSortOrigin( vecOrigin ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int iPoint, bool bInitializing ) { ParticleControlPoint_t *pPoint = &pEffect->pControlPoints[iPoint]; if ( pEffect->pParticleEffect->m_pDef->IsScreenSpaceEffect() && iPoint == 0 ) { pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, Vector(1,0,0), Vector(0,1,0), Vector(0,0,1) ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, vec3_origin ); return; } if ( !pPoint->hEntity.Get() ) { if ( pPoint->iAttachType == PATTACH_WORLDORIGIN && bInitializing ) { pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, Vector(1,0,0), Vector(0,1,0), Vector(0,0,1) ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, pPoint->vecOriginOffset ); pEffect->pParticleEffect->SetSortOrigin( pPoint->vecOriginOffset ); } pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, NULL ); return; } // Only update non-follow particles when we're initializing, if ( !bInitializing && (pPoint->iAttachType == PATTACH_ABSORIGIN || pPoint->iAttachType == PATTACH_POINT ) ) return; if ( pPoint->iAttachType == PATTACH_CUSTOMORIGIN ) return; Vector vecOrigin, vecForward, vecRight, vecUp; switch ( pPoint->iAttachType ) { case PATTACH_POINT: case PATTACH_POINT_FOLLOW: { C_BaseAnimating *pAnimating = pPoint->hEntity->GetBaseAnimating(); bool bValid = false; Assert( pAnimating ); if ( pAnimating ) { matrix3x4_t attachmentToWorld; if ( pAnimating->IsViewModel() ) { C_BasePlayer *pPlayer = ToBasePlayer( ((C_BaseViewModel *)pAnimating)->GetOwner() ); ACTIVE_SPLITSCREEN_PLAYER_GUARD( C_BasePlayer::GetSplitScreenSlotForPlayer( pPlayer ) ); if ( pAnimating->GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) { bValid = true; MatrixVectors( attachmentToWorld, &vecForward, &vecRight, &vecUp ); MatrixPosition( attachmentToWorld, vecOrigin ); if ( pEffect->pParticleEffect->m_pDef->IsViewModelEffect() ) { FormatViewModelAttachment( pPlayer, vecOrigin, true ); } } } else { // HACK_GETLOCALPLAYER_GUARD( "CParticleProperty::UpdateControlPoint" ); if ( pAnimating->GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) { bValid = true; MatrixVectors( attachmentToWorld, &vecForward, &vecRight, &vecUp ); #ifdef _DEBUG float flTests[3] = {vecForward.Dot( vecRight ), vecRight.Dot( vecUp ), vecUp.Dot( vecForward )}; static float s_flMaxTest = 0.001f; Assert( fabs( flTests[0] ) + fabs( flTests[1] ) + fabs( flTests[2] ) < s_flMaxTest ); #endif MatrixPosition( attachmentToWorld, vecOrigin ); if ( pEffect->pParticleEffect->m_pDef->IsViewModelEffect() ) { HACK_GETLOCALPLAYER_GUARD( "CParticleProperty::UpdateControlPoint" ); FormatViewModelAttachment( NULL, vecOrigin, true ); } } } } if ( !bValid ) { static bool bWarned = false; if ( !bWarned ) { bWarned = true; DevWarning( "Attempted to attach particle effect %s to an unknown attachment on entity %s\n", pEffect->pParticleEffect->m_pDef->GetName(), pAnimating->GetClassname() ); } } if ( !bValid ) { AssertOnce( 0 ); return; } } break; case PATTACH_ABSORIGIN: case PATTACH_ABSORIGIN_FOLLOW: default: { vecOrigin = pPoint->hEntity->GetAbsOrigin() + pPoint->vecOriginOffset; pPoint->hEntity->GetVectors( &vecForward, &vecRight, &vecUp ); } break; case PATTACH_EYES_FOLLOW: { C_BaseEntity *pEnt = pPoint->hEntity; if ( !pEnt->IsPlayer() ) return; C_BasePlayer *pPlayer = assert_cast< C_BasePlayer* >( pEnt ); bool bValid = false; Assert( pPlayer ); if ( pPlayer ) { bValid = true; vecOrigin = pPlayer->EyePosition() + pPoint->vecOriginOffset; pPlayer->EyeVectors( &vecForward, &vecRight, &vecUp ); } if ( !bValid ) { AssertOnce( 0 ); return; } } break; case PATTACH_CUSTOMORIGIN_FOLLOW: { matrix3x4_t mat; MatrixMultiply( pPoint->hEntity->RenderableToWorldTransform(), pPoint->matOffset, mat ); MatrixVectors( mat, &vecForward, &vecRight, &vecUp ); vecOrigin = pPoint->hEntity->GetAbsOrigin() + pPoint->vecOriginOffset; } break; } pEffect->pParticleEffect->SetControlPointOrientation( pPoint->iControlPoint, vecForward, vecRight, vecUp ); pEffect->pParticleEffect->SetControlPointEntity( pPoint->iControlPoint, pPoint->hEntity ); pEffect->pParticleEffect->SetControlPoint( pPoint->iControlPoint, vecOrigin ); pEffect->pParticleEffect->SetSortOrigin( vecOrigin ); }