//-----------------------------------------------------------------------------
// 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;
}
Exemple #2
0
//-----------------------------------------------------------------------------
// 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 );
	}
}
Exemple #15
0
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] );
}