//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPointCommentaryNode::UpdateViewPostThink( void ) { CBasePlayer *pPlayer = GetCommentaryPlayer(); if ( !pPlayer ) return; if ( m_hViewPosition.Get() && m_hViewPositionMover ) { // Blend back to the player's position over time. float flCurTime = (gpGlobals->curtime - m_flFinishedTime); float flTimeToBlend = min( 2.0, m_flFinishedTime - m_flStartTime ); float flBlendPerc = 1.0 - clamp( flCurTime / flTimeToBlend, 0, 1 ); //Msg("OUT: CurTime %.2f, BlendTime: %.2f, Blend: %.3f\n", flCurTime, flTimeToBlend, flBlendPerc ); // Only do this while we're still moving if ( flBlendPerc > 0 ) { // Figure out the current view position Vector vecPlayerPos = pPlayer->EyePosition(); Vector vecToPosition = (m_vecFinishOrigin - vecPlayerPos); Vector vecCurEye = pPlayer->EyePosition() + (vecToPosition * flBlendPerc); m_hViewPositionMover->SetAbsOrigin( vecCurEye ); if ( m_hViewTarget ) { Quaternion quatFinish; Quaternion quatOriginal; Quaternion quatCurrent; AngleQuaternion( m_vecOriginalAngles, quatOriginal ); AngleQuaternion( m_vecFinishAngles, quatFinish ); QuaternionSlerp( quatFinish, quatOriginal, 1.0 - flBlendPerc, quatCurrent ); QAngle angCurrent; QuaternionAngles( quatCurrent, angCurrent ); m_hViewPositionMover->SetAbsAngles( angCurrent ); } SetNextThink( gpGlobals->curtime, s_pCommentaryUpdateViewThink ); return; } pPlayer->SnapEyeAngles( m_hViewPositionMover->GetAbsAngles() ); } // We're done CleanupPostCommentary(); m_bPreventChangesWhileMoving = false; }
//----------------------------------------------------------------------------- // Purpose: Interpolate Euler angles using quaternions to avoid singularities // Input : start - // end - // output - // frac - //----------------------------------------------------------------------------- void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac ) { Quaternion src, dest; // Convert to quaternions AngleQuaternion( start, src ); AngleQuaternion( end, dest ); Quaternion result; // Slerp QuaternionSlerp( src, dest, frac, result ); // Convert to euler QuaternionAngles( result, output ); }
//----------------------------------------------------------------------------- // Purpose: Notifies that the entity this is attached to has had a key change // Input : key - // value - //----------------------------------------------------------------------------- void CMapKeyFrame::OnParentKeyChanged( const char* key, const char* value ) { if ( !stricmp(key, "NextKey") ) { m_bRebuildPath = true; } else if ( !stricmp(key, "NextTime") ) { m_flMoveTime = atof( value ); } else if ( !stricmp(key, "MoveSpeed") ) { m_flSpeed = atof( value ); m_bRebuildPath = true; } else if (!stricmp(key, "angles")) { sscanf(value, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]); AngleQuaternion(m_Angles, m_qAngles); } if( m_pPositionInterpolator ) { if( m_pPositionInterpolator->ProcessKey( key, value ) ) m_bRebuildPath = true; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFViewModel::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) { BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); CTFWeaponBase *pWeapon = ( CTFWeaponBase * )GetOwningWeapon(); if ( !pWeapon ) return; if ( pWeapon->GetWeaponID() == TF_WEAPON_MINIGUN ) { CTFMinigun *pMinigun = ( CTFMinigun * )pWeapon; int iBarrelBone = Studio_BoneIndexByName( hdr, "v_minigun_barrel" ); Assert( iBarrelBone != -1 ); if ( iBarrelBone != -1 ) { RadianEuler a; QuaternionAngles( q[iBarrelBone], a ); a.x = pMinigun->GetBarrelRotation(); AngleQuaternion( a, q[iBarrelBone] ); } } }
void CDmeRotationInput::SetRotation( const QAngle& qangle ) { Quaternion quat; AngleQuaternion( qangle, quat ); m_orientation = quat; m_angles = qangle; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CNPC_Combine_Cannon::GetPaintAim( const Vector &vecStart, const Vector &vecGoal, float flParameter, Vector *pProgress ) { // Quaternions Vector vecIdealDir; QAngle vecIdealAngles; QAngle vecCurrentAngles; Vector vecCurrentDir; Vector vecBulletOrigin = GetBulletOrigin(); // vecIdealDir is where the gun should be aimed when the painting // time is up. This can be approximate. This is only for drawing the // laser, not actually aiming the weapon. A large discrepancy will look // bad, though. vecIdealDir = vecGoal - vecBulletOrigin; VectorNormalize(vecIdealDir); // Now turn vecIdealDir into angles! VectorAngles( vecIdealDir, vecIdealAngles ); // This is the vector of the beam's current aim. vecCurrentDir = m_vecPaintStart - vecBulletOrigin; VectorNormalize(vecCurrentDir); // Turn this to angles, too. VectorAngles( vecCurrentDir, vecCurrentAngles ); Quaternion idealQuat; Quaternion currentQuat; Quaternion aimQuat; AngleQuaternion( vecIdealAngles, idealQuat ); AngleQuaternion( vecCurrentAngles, currentQuat ); QuaternionSlerp( currentQuat, idealQuat, flParameter, aimQuat ); QuaternionAngles( aimQuat, vecCurrentAngles ); // Rebuild the current aim vector. AngleVectors( vecCurrentAngles, &vecCurrentDir ); *pProgress = vecCurrentDir; }
void MakeDifferent( void ) { m_CharValue = 'd'; m_ShortValue = (short)400; m_IntValue = (int)400; m_FloatValue = 4.0f; Q_strncpy( m_szValue, "secondarydata", sizeof( m_szValue ) ); m_Vector = Vector( 400, 400, 400 ); AngleQuaternion( QAngle( 60, 0, 0 ), m_Quaternion ); m_Bool = true; m_Clr.r = m_Clr.g = m_Clr.b = m_Clr.a = 1; m_Ptr = (void *)0x00000001; // m_hEHandle = (C_BaseEntity *)0x00000001; }
CCopyTesterData() { m_CharValue = 'a'; m_ShortValue = (short)100; m_IntValue = (int)100; m_FloatValue = 1.0f; Q_strncpy( m_szValue, "primarydata", sizeof( m_szValue ) ); m_Vector = Vector( 100, 100, 100 ); AngleQuaternion( QAngle( 0, 45, 0 ), m_Quaternion ); m_Bool = false; m_Clr.r = m_Clr.g = m_Clr.b = m_Clr.a = 255; m_Ptr = (void *)0xfedcba98; // m_hEHandle = NULL; }
void C_NPC_Hydra::CalcBoneAngles( const Vector pos[], Quaternion q[] ) { int i; matrix3x4_t bonematrix; for (i = m_numHydraBones - 1; i >= 0; i--) { Vector forward; Vector left2; if (i != m_numHydraBones - 1) { QuaternionMatrix( q[i+1], bonematrix ); MatrixGetColumn( bonematrix, 1, left2 ); forward = (pos[i+1] - pos[i]) /* + (pos[i] - pos[i-1])*/; float length = VectorNormalize( forward ); if (length == 0.0) { q[i] = q[i+1]; continue; } } else { forward = m_vecHeadDir; VectorNormalize( forward ); VectorMatrix( forward, bonematrix ); MatrixGetColumn( bonematrix, 1, left2 ); } Vector up = CrossProduct( forward, left2 ); VectorNormalize( up ); Vector left = CrossProduct( up, forward ); MatrixSetColumn( forward, 0, bonematrix ); MatrixSetColumn( left, 1, bonematrix ); MatrixSetColumn( up, 2, bonematrix ); // MatrixQuaternion( bonematrix, q[i] ); QAngle angles; MatrixAngles( bonematrix, angles ); AngleQuaternion( angles, q[i] ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_NPC_Barnacle::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) { BaseClass::StandardBlendingRules( pos, q, currentTime, boneMask ); // Don't do anything while dead if ( !IsAlive() ) return; studiohdr_t *hdr = GetModelPtr(); if ( !hdr ) return; int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" ); Vector vecPrev = pos[firstBone-1]; Vector vecCurr = vec3_origin; for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ ) { // We double up the bones at the last node. Vector vecCurr; if ( i == BARNACLE_TONGUE_POINTS ) { vecCurr = m_TonguePhysics.GetLastNode()->m_vPos; } else { vecCurr = m_TonguePhysics.GetNode(i)->m_vPos; } //debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 ); // Fill out the positions in local space VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] ); vecCurr = pos[firstBone+i]; // Fill out the angles Vector vecForward = (vecCurr - vecPrev); VectorNormalize( vecForward ); QAngle vecAngle; VectorAngles( vecForward, vecAngle ); AngleQuaternion( vecAngle, q[firstBone+i] ); vecPrev = vecCurr; } }
void CNewParticleEffect::RecordControlPointOrientation( int nWhichPoint ) { if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) { // FIXME: Make a more direct way of getting QAngle angles; VectorAngles( m_ControlPoints[nWhichPoint].m_ForwardVector, m_ControlPoints[nWhichPoint].m_UpVector, angles ); static ParticleSystemSetControlPointOrientationState_t state; state.m_nParticleSystemId = GetToolParticleEffectId(); state.m_flTime = gpGlobals->curtime; state.m_nControlPoint = nWhichPoint; AngleQuaternion( angles, state.m_qOrientation ); KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointOrientation" ); msg->SetPtr( "state", &state ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFMinigun::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) { BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); if (m_iBarrelBone != -1) { UpdateBarrelMovement(); // Weapon happens to be aligned to (0,0,0) // If that changes, use this code block instead to // modify the angles /* RadianEuler a; QuaternionAngles( q[iBarrelBone], a ); a.x = m_flBarrelAngle; AngleQuaternion( a, q[iBarrelBone] ); */ AngleQuaternion( RadianEuler( 0, 0, m_flBarrelAngle ), q[m_iBarrelBone] ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : angles - //----------------------------------------------------------------------------- void CPathKeyFrame::SetKeyAngles( QAngle angles ) { m_Angles = angles; AngleQuaternion( m_Angles, m_qAngle ); }
/* ==================== StudioCalcBoneQuaterion ==================== */ void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) { int j, k; vec4_t q1, q2; vec3_t angle1, angle2; mstudioanimvalue_t *panimvalue; for (j = 0; j < 3; j++) { if (panim->offset[j+3] == 0) { angle2[j] = angle1[j] = pbone->value[j+3]; // default; } else { panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); k = frame; // DEBUG if (panimvalue->num.total < panimvalue->num.valid) k = 0; while (panimvalue->num.total <= k) { k -= panimvalue->num.total; panimvalue += panimvalue->num.valid + 1; // DEBUG if (panimvalue->num.total < panimvalue->num.valid) k = 0; } // Bah, missing blend! if (panimvalue->num.valid > k) { angle1[j] = panimvalue[k+1].value; if (panimvalue->num.valid > k + 1) { angle2[j] = panimvalue[k+2].value; } else { if (panimvalue->num.total > k + 1) angle2[j] = angle1[j]; else angle2[j] = panimvalue[panimvalue->num.valid+2].value; } } else { angle1[j] = panimvalue[panimvalue->num.valid].value; if (panimvalue->num.total > k + 1) { angle2[j] = angle1[j]; } else { angle2[j] = panimvalue[panimvalue->num.valid + 2].value; } } angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; } if (pbone->bonecontroller[j+3] != -1) { angle1[j] += adj[pbone->bonecontroller[j+3]]; angle2[j] += adj[pbone->bonecontroller[j+3]]; } } if (!VectorCompare( angle1, angle2 )) { AngleQuaternion( angle1, q1 ); AngleQuaternion( angle2, q2 ); QuaternionSlerp( q1, q2, s, q ); } else { AngleQuaternion( angle1, q ); } }
void msModel::EvaluateJoint(int index, float frame) { ms3d_joint_t *joint = &m_joints[index]; // // calculate joint animation matrix, this matrix will animate matLocalSkeleton // vec3_t pos = { 0.0f, 0.0f, 0.0f }; int numPositionKeys = (int) joint->positionKeys.size(); if (numPositionKeys > 0) { int i1 = -1; int i2 = -1; // find the two keys, where "frame" is in between for the position channel for (int i = 0; i < (numPositionKeys - 1); i++) { if (frame >= joint->positionKeys[i].time && frame < joint->positionKeys[i + 1].time) { i1 = i; i2 = i + 1; break; } } // if there are no such keys if (i1 == -1 || i2 == -1) { // either take the first if (frame < joint->positionKeys[0].time) { pos[0] = joint->positionKeys[0].key[0]; pos[1] = joint->positionKeys[0].key[1]; pos[2] = joint->positionKeys[0].key[2]; } // or the last key else if (frame >= joint->positionKeys[numPositionKeys - 1].time) { pos[0] = joint->positionKeys[numPositionKeys - 1].key[0]; pos[1] = joint->positionKeys[numPositionKeys - 1].key[1]; pos[2] = joint->positionKeys[numPositionKeys - 1].key[2]; } } // there are such keys, so interpolate using hermite interpolation else { ms3d_keyframe_t *p0 = &joint->positionKeys[i1]; ms3d_keyframe_t *p1 = &joint->positionKeys[i2]; ms3d_tangent_t *m0 = &joint->tangents[i1]; ms3d_tangent_t *m1 = &joint->tangents[i2]; // normalize the time between the keys into [0..1] float t = (frame - joint->positionKeys[i1].time) / (joint->positionKeys[i2].time - joint->positionKeys[i1].time); float t2 = t * t; float t3 = t2 * t; // calculate hermite basis float h1 = 2.0f * t3 - 3.0f * t2 + 1.0f; float h2 = -2.0f * t3 + 3.0f * t2; float h3 = t3 - 2.0f * t2 + t; float h4 = t3 - t2; // do hermite interpolation pos[0] = h1 * p0->key[0] + h3 * m0->tangentOut[0] + h2 * p1->key[0] + h4 * m1->tangentIn[0]; pos[1] = h1 * p0->key[1] + h3 * m0->tangentOut[1] + h2 * p1->key[1] + h4 * m1->tangentIn[1]; pos[2] = h1 * p0->key[2] + h3 * m0->tangentOut[2] + h2 * p1->key[2] + h4 * m1->tangentIn[2]; } } vec4_t quat = { 0.0f, 0.0f, 0.0f, 1.0f }; int numRotationKeys = (int) joint->rotationKeys.size(); if (numRotationKeys > 0) { int i1 = -1; int i2 = -1; // find the two keys, where "frame" is in between for the rotation channel for (int i = 0; i < (numRotationKeys - 1); i++) { if (frame >= joint->rotationKeys[i].time && frame < joint->rotationKeys[i + 1].time) { i1 = i; i2 = i + 1; break; } } // if there are no such keys if (i1 == -1 || i2 == -1) { // either take the first key if (frame < joint->rotationKeys[0].time) { AngleQuaternion(joint->rotationKeys[0].key, quat); } // or the last key else if (frame >= joint->rotationKeys[numRotationKeys - 1].time) { AngleQuaternion(joint->rotationKeys[numRotationKeys - 1].key, quat); } } // there are such keys, so do the quaternion slerp interpolation else { float t = (frame - joint->rotationKeys[i1].time) / (joint->rotationKeys[i2].time - joint->rotationKeys[i1].time); vec4_t q1; AngleQuaternion(joint->rotationKeys[i1].key, q1); vec4_t q2; AngleQuaternion(joint->rotationKeys[i2].key, q2); QuaternionSlerp(q1, q2, t, quat); } } // make a matrix from pos/quat float matAnimate[3][4]; QuaternionMatrix(quat, matAnimate); matAnimate[0][3] = pos[0]; matAnimate[1][3] = pos[1]; matAnimate[2][3] = pos[2]; // animate the local joint matrix using: matLocal = matLocalSkeleton * matAnimate R_ConcatTransforms(joint->matLocalSkeleton, matAnimate, joint->matLocal); // build up the hierarchy if joints // matGlobal = matGlobal(parent) * matLocal if (joint->parentIndex == -1) { memcpy(joint->matGlobal, joint->matLocal, sizeof(joint->matGlobal)); } else { ms3d_joint_t *parentJoint = &m_joints[joint->parentIndex]; R_ConcatTransforms(parentJoint->matGlobal, joint->matLocal, joint->matGlobal); } }
void C_NPC_Hydra::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) { VPROF( "C_NPC_Hydra::StandardBlendingRules" ); studiohdr_t *hdr = GetModelPtr(); if ( !hdr ) { return; } int i; // check for changing model memory requirements bool bNewlyInited = false; if (m_numHydraBones != hdr->numbones) { m_numHydraBones = hdr->numbones; // build root animation float poseparam[MAXSTUDIOPOSEPARAM]; for (i = 0; i < hdr->numposeparameters; i++) { poseparam[i] = 0; } CalcPose( hdr, NULL, pos, q, 0.0f, 0.0f, poseparam, BONE_USED_BY_ANYTHING ); // allocate arrays if (m_boneLength) { delete[] m_boneLength; } m_boneLength = new float [m_numHydraBones]; if (m_vecPos) { delete[] m_vecPos; } m_vecPos = new Vector [m_numHydraBones]; if (m_iv_vecPos) { delete m_iv_vecPos; } m_iv_vecPos = new CInterpolatedVar< Vector >[m_numHydraBones]; for ( i = 0; i < m_numHydraBones; i++ ) { m_iv_vecPos[ i ].Setup( &m_vecPos[ i ], LATCH_SIMULATION_VAR | EXCLUDE_AUTO_LATCH | EXCLUDE_AUTO_INTERPOLATE ); } // calc models bone lengths m_maxPossibleLength = 0; for (i = 0; i < m_numHydraBones-1; i++) { m_boneLength[i] = (pos[i+1] - pos[i]).Length(); m_maxPossibleLength += m_boneLength[i]; } m_boneLength[i] = 0.0f; bNewlyInited = true; } // calc new bone setup if networked. if (m_bNewChain) { CalcBoneChain( m_vecPos, m_vecChain ); for (i = 0; i < m_numHydraBones; i++) { // debugoverlay->AddLineOverlay( m_vecPos[i], m_vecPos[i<m_numHydraBones-1?i+1:m_numHydraBones-1], 0, 255, 0, false, 0.1 ); m_vecPos[i] = m_vecPos[i] - GetAbsOrigin(); m_iv_vecPos[i].NoteChanged( this, m_fLatchFlags, currentTime ); } m_bNewChain = false; } // if just allocated, initialize bones if (bNewlyInited) { for (i = 0; i < m_numHydraBones; i++) { m_iv_vecPos[i].Reset(); } } for (i = 0; i < m_numHydraBones; i++) { m_iv_vecPos[i].Interpolate( this, currentTime ); pos[ i ] = m_vecPos[ i ]; } // calculate bone angles CalcBoneAngles( pos, q ); // rotate the last bone of the hydra 90 degrees since it's oriented differently than the others Quaternion qTmp; AngleQuaternion( QAngle( 0, -90, 0) , qTmp ); QuaternionMult( q[m_numHydraBones - 1], qTmp, q[m_numHydraBones - 1] ); }