//-----------------------------------------------------------------------------
// Purpose: Rotates a matrix by 90 degrees in the plane of axis0/axis1
// Input  : &matrix - 
//			axis0 - 
//			axis1 - 
// Output : static void
//-----------------------------------------------------------------------------
static void MatrixRot90( matrix3x4_t &matrix, int axis0, int axis1 )
{
	Vector col0, col1;
	MatrixGetColumn( matrix, axis0, col0 );
	MatrixGetColumn( matrix, axis1, col1 );
	MatrixSetColumn( col1, axis0, matrix );
	MatrixSetColumn( -col0, axis1, matrix );
}
Esempio n. 2
0
//-----------------------------------------------------------------------------
// Updates the relative orientation of the camera, spring mode
//-----------------------------------------------------------------------------
void CWeaponIFMSteadyCam::UpdateDirectRelativeOrientation()
{
	// Compute a player to steadycam matrix
	VMatrix steadyCamToPlayer;
	MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer );
	MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition );

	// Compute a forward direction
	Vector vecCurrentForward;
	MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward );

	// Before any updating occurs, sample the current 
	// world-space direction of the mouse
	Vector vecDesiredDirection;
	ComputeMouseRay( steadyCamToPlayer, vecDesiredDirection );

	// rebuild a roll-less orientation based on that direction vector
	matrix3x4_t mat;
	MatrixFromForwardDirection( vecDesiredDirection, mat );
	MatrixAngles( mat, m_angRelativeAngles );
	Assert( m_angRelativeAngles.IsValid() );

	m_vecActualViewOffset -= m_vecViewOffset;
	m_vecViewOffset.Init();
}
static QAngle AlignAngles( const QAngle &angles, float cosineAlignAngle )
{
	matrix3x4_t alignMatrix;
	AngleMatrix( angles, alignMatrix );

	// NOTE: Must align z first
	for ( int j = 3; --j >= 0; )
	{
		Vector vec;
		MatrixGetColumn( alignMatrix, j, vec );
		for ( int i = 0; i < 3; i++ )
		{
			if ( fabs(vec[i]) > cosineAlignAngle )
			{
				vec[i] = SIGN(vec[i]);
				vec[(i+1)%3] = 0;
				vec[(i+2)%3] = 0;
				MatrixSetColumn( vec, j, alignMatrix );
				MatrixOrthogonalize( alignMatrix, j );
				break;
			}
		}
	}

	QAngle out;
	MatrixAngles( alignMatrix, out );
	return out;
}
//-----------------------------------------------------------------------------
// Returns the unperterbed view position for a particular role
//-----------------------------------------------------------------------------
bool CBaseTFVehicle::GetRoleViewPosition( int nRole, Vector *pVehicleEyeOrigin, QAngle *pVehicleEyeAngles )
{
	// Generate the view position in world space.
	Vector vAbsOrigin;
	QAngle vAbsAngle;
	bool bUsingThirdPersonCamera = GetRoleAbsViewPosition( nRole, &vAbsOrigin, &vAbsAngle );

	
	// Make a matrix for it.
	matrix3x4_t absMatrix;
	AngleMatrix( vAbsAngle, absMatrix );
	MatrixSetColumn( vAbsOrigin, 3, absMatrix );


	// Transform the matrix into local space.
	matrix3x4_t worldToEntity, local;
	MatrixInvert( EntityToWorldTransform(), worldToEntity );
	ConcatTransforms( worldToEntity, absMatrix, local ); 


	// Suck out the origin and angles.
	pVehicleEyeOrigin->Init( local[0][3], local[1][3], local[2][3] );
	MatrixAngles( local, *pVehicleEyeAngles );

	return bUsingThirdPersonCamera;
}
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] );
	}
}
void CRagdollPropAttached::InitRagdollAttached( IPhysicsObject *pAttached, const Vector &forceVector, int forceBone, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, CBaseAnimating *pFollow, int boneIndexRoot, const Vector &boneLocalOrigin, int parentBoneAttach, const Vector &worldAttachOrigin )
{
	int ragdollAttachedIndex = 0;
	if ( parentBoneAttach > 0 )
	{
		studiohdr_t *pStudioHdr = GetModelPtr();
		mstudiobone_t *pBone = pStudioHdr->pBone( parentBoneAttach );
		ragdollAttachedIndex = pBone->physicsbone;
	}

	InitRagdoll( forceVector, forceBone, vec3_origin, pPrevBones, pBoneToWorld, dt, collisionGroup, false );
	
	IPhysicsObject *pRefObject = m_ragdoll.list[ragdollAttachedIndex].pObject;

	Vector attachmentPointRagdollSpace;
	pRefObject->WorldToLocal( attachmentPointRagdollSpace, worldAttachOrigin );

	constraint_ragdollparams_t constraint;
	constraint.Defaults();
	matrix3x4_t tmp, worldToAttached, worldToReference, constraintToWorld;

	Vector offsetWS;
	pAttached->LocalToWorld( offsetWS, boneLocalOrigin );

	AngleMatrix( QAngle(0, pFollow->GetAbsAngles().y, 0 ), offsetWS, constraintToWorld );

	constraint.axes[0].SetAxisFriction( -2, 2, 20 );
	constraint.axes[1].SetAxisFriction( 0, 0, 0 );
	constraint.axes[2].SetAxisFriction( -15, 15, 20 );
	
	pAttached->GetPositionMatrix( tmp );
	MatrixInvert( tmp, worldToAttached );

	pRefObject->GetPositionMatrix( tmp );
	MatrixInvert( tmp, worldToReference );

	ConcatTransforms( worldToReference, constraintToWorld, constraint.constraintToReference );
	ConcatTransforms( worldToAttached, constraintToWorld, constraint.constraintToAttached );

	// for now, just slam this to be the passed in value
	MatrixSetColumn( attachmentPointRagdollSpace, 3, constraint.constraintToReference );

	DisableCollisions( pAttached );
	m_pAttachConstraint = physenv->CreateRagdollConstraint( pRefObject, pAttached, m_ragdoll.pGroup, constraint );

	FollowEntity( pFollow );
	SetOwnerEntity( pFollow );
	RagdollActivate( m_ragdoll );

	Relink();
	m_boneIndexAttached = boneIndexRoot;
	m_ragdollAttachedObjectIndex = ragdollAttachedIndex;
	m_attachmentPointBoneSpace = boneLocalOrigin;
	
	Vector vTemp;
	MatrixGetColumn( constraint.constraintToReference, 3, vTemp );
	m_attachmentPointRagdollSpace = vTemp;
}
Esempio n. 7
0
//-----------------------------------------------------------------------------------
void Matrix4x4::MatrixInvertOrthogonal(Matrix4x4* matrix)
{
	Vector3 translation = MatrixGetOffset(matrix);
	MatrixTranspose(matrix);
	MatrixSetColumn(matrix, 3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
	Matrix4x4 translationMatrix;
	MatrixMakeTranslation(&translationMatrix, translation);
	MatrixInvert(&translationMatrix);
	MatrixMultiply(matrix, &translationMatrix, matrix);
}
static void MatrixOrthogonalize( matrix3x4_t &matrix, int column )
{
	Vector columns[3];
	int i;

	for ( i = 0; i < 3; i++ )
	{
		MatrixGetColumn( matrix, i, columns[i] );
	}

	int index0 = column;
	int index1 = (column+1)%3;
	int index2 = (column+2)%3;

	columns[index2] = CrossProduct( columns[index0], columns[index1] );
	columns[index1] = CrossProduct( columns[index2], columns[index0] );
	VectorNormalize( columns[index2] );
	VectorNormalize( columns[index1] );
	MatrixSetColumn( columns[index1], index1, matrix );
	MatrixSetColumn( columns[index2], index2, matrix );
}
//-----------------------------------------------------------------------------
// Apply movement
//-----------------------------------------------------------------------------
void CLogicMeasureMovement::MeasureThink( )
{
    // FIXME: This is a hack to make measuring !player simpler. The player isn't
    // created at Activate time, so m_hMeasureTarget may be NULL because of that.
    if ( !m_hMeasureTarget.Get() && !Q_strnicmp( STRING(m_strMeasureTarget), "!player", 8 ) )
    {
        SetMeasureTarget( STRING(m_strMeasureTarget) );
    }

    // Make sure all entities are valid
    if ( m_hMeasureTarget.Get() && m_hMeasureReference.Get() && m_hTarget.Get() && m_hTargetReference.Get() )
    {
        matrix3x4_t matRefToMeasure, matWorldToMeasure;
        switch( m_nMeasureType )
        {
        case MEASURE_POSITION:
            MatrixInvert( m_hMeasureTarget->EntityToWorldTransform(), matWorldToMeasure );
            break;

        case MEASURE_EYE_POSITION:
            AngleIMatrix( m_hMeasureTarget->EyeAngles(), m_hMeasureTarget->EyePosition(), matWorldToMeasure );
            break;

            // FIXME: Could add attachment point measurement here easily
        }

        ConcatTransforms( matWorldToMeasure, m_hMeasureReference->EntityToWorldTransform(), matRefToMeasure );

        // Apply the scale factor
        if ( ( m_flScale != 0.0f ) && ( m_flScale != 1.0f ) )
        {
            Vector vecTranslation;
            MatrixGetColumn( matRefToMeasure, 3, vecTranslation );
            vecTranslation /= m_flScale;
            MatrixSetColumn( vecTranslation, 3, matRefToMeasure );
        }

        // Now apply the new matrix to the new reference point
        matrix3x4_t matMeasureToRef, matNewTargetToWorld;
        MatrixInvert( matRefToMeasure, matMeasureToRef );

        ConcatTransforms( m_hTargetReference->EntityToWorldTransform(), matMeasureToRef, matNewTargetToWorld );

        Vector vecNewOrigin;
        QAngle vecNewAngles;
        MatrixAngles( matNewTargetToWorld, vecNewAngles, vecNewOrigin );
        m_hTarget->SetAbsOrigin( vecNewOrigin );
        m_hTarget->SetAbsAngles( vecNewAngles );
    }

    SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
Esempio n. 10
0
    virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
    {
        VPROF_BUDGET( "C_ServerRagdollAttached::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );

        if ( !hdr )
            return;

        float frac = RemapVal( gpGlobals->curtime, m_parentTime, m_parentTime+ATTACH_INTERP_TIME, 0, 1 );
        frac = clamp( frac, 0.f, 1.f );
        // interpolate offset over some time
        Vector offset = m_vecOffset * (1-frac);

        C_BaseAnimating *parent = assert_cast< C_BaseAnimating* >( GetMoveParent() );
        Vector worldOrigin;
        worldOrigin.Init();


        if ( parent )
        {
            Assert( parent != this );
            parent->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );

            matrix3x4_t boneToWorld;
            parent->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld );
            VectorTransform( m_attachmentPointBoneSpace, boneToWorld, worldOrigin );
        }
        BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );

        if ( parent )
        {
            int index = m_boneIndex[m_ragdollAttachedObjectIndex];
            const matrix3x4_t &matrix = GetBone( index );
            Vector ragOrigin;
            VectorTransform( m_attachmentPointRagdollSpace, matrix, ragOrigin );
            offset = worldOrigin - ragOrigin;
            // fixes culling
            SetAbsOrigin( worldOrigin );
            m_vecOffset = offset;
        }

        for ( int i = 0; i < hdr->numbones(); i++ )
        {
            if ( !( hdr->boneFlags( i ) & boneMask ) )
                continue;

            Vector pos;
            matrix3x4_t &matrix = GetBoneForWrite( i );
            MatrixGetColumn( matrix, 3, pos );
            pos += offset;
            MatrixSetColumn( pos, 3, matrix );
        }
    }
Esempio n. 11
0
const matrix3x4_t& CCollisionProperty::CollisionToWorldTransform() const
{
	static matrix3x4_t s_matTemp[4];
	static int s_nIndex = 0;

	matrix3x4_t &matResult = s_matTemp[s_nIndex];
	s_nIndex = (s_nIndex+1) & 0x3;

	if ( IsBoundsDefinedInEntitySpace() )
	{
		return m_pOuter->EntityToWorldTransform();
	}

	SetIdentityMatrix( matResult );
	MatrixSetColumn( GetCollisionOrigin(), 3, matResult );
	return matResult;
}
Esempio n. 12
0
//-----------------------------------------------------------------------------
// Does a fast inverse, assuming the matrix only contains translation and rotation.
//-----------------------------------------------------------------------------
void MatrixInverseTR( const VMatrix& src, VMatrix &dst )
{
	Vector vTrans, vNewTrans;

	// Transpose the upper 3x3.
	dst.m[0][0] = src.m[0][0];  dst.m[0][1] = src.m[1][0]; dst.m[0][2] = src.m[2][0];
	dst.m[1][0] = src.m[0][1];  dst.m[1][1] = src.m[1][1]; dst.m[1][2] = src.m[2][1];
	dst.m[2][0] = src.m[0][2];  dst.m[2][1] = src.m[1][2]; dst.m[2][2] = src.m[2][2];

	// Transform the translation.
	vTrans.Init( -src.m[0][3], -src.m[1][3], -src.m[2][3] );
	Vector3DMultiply( dst, vTrans, vNewTrans );
	MatrixSetColumn( dst, 3, vNewTrans );

	// Fill in the bottom row.
	dst.m[3][0] = dst.m[3][1] = dst.m[3][2] = 0.0f;
	dst.m[3][3] = 1.0f;
}
Esempio n. 13
0
static void RagdollAddSolids( IPhysicsEnvironment *pPhysEnv, ragdoll_t &ragdoll, const ragdollparams_t &params, cache_ragdollsolid_t *pSolids, int solidCount, const cache_ragdollconstraint_t *pConstraints, int constraintCount )
{
	const char *pszName = params.pStudioHdr->pszName();
	Vector position;
	matrix3x4_t xform;
	// init parent index
	for ( int i = 0; i < solidCount; i++ )
	{
		ragdoll.list[i].parentIndex = -1;
	}
	// now set from constraints
	for ( int i = 0; i < constraintCount; i++ )
	{
		// save parent index
		ragdoll.list[pConstraints[i].childIndex].parentIndex = pConstraints[i].parentIndex;
		MatrixGetColumn( pConstraints[i].constraintToAttached, 3, ragdoll.list[pConstraints[i].childIndex].originParentSpace );
	}

	// now setup the solids, using parent indices
	for ( int i = 0; i < solidCount; i++ )
	{	
		ragdoll.boneIndex[i] = pSolids[i].boneIndex;
		pSolids[i].params.pName = pszName;
		pSolids[i].params.pGameData = params.pGameData;
		ragdoll.list[i].pObject = pPhysEnv->CreatePolyObject( params.pCollide->solids[pSolids[i].collideIndex], pSolids[i].surfacePropIndex, vec3_origin, vec3_angle, &pSolids[i].params );
		ragdoll.list[i].pObject->SetGameIndex( i );
		int parentIndex = ragdoll.list[i].parentIndex;
		MatrixCopy( params.pCurrentBones[ragdoll.boneIndex[i]], xform );
		if ( parentIndex >= 0 )
		{
			Assert(parentIndex<i);
			ragdoll.list[parentIndex].pObject->LocalToWorld( &position, ragdoll.list[i].originParentSpace );
			MatrixSetColumn( position, 3, xform );
		}
		ragdoll.list[i].pObject->SetPositionMatrix( xform, true );

		PhysSetGameFlags( ragdoll.list[i].pObject, FVPHYSICS_PART_OF_RAGDOLL );

	}
	ragdoll.listCount = solidCount;
}
bool RagdollGetBoneMatrix( const ragdoll_t &ragdoll, matrix3x4_t *pBoneToWorld, int objectIndex )
{
	int boneIndex = ragdoll.boneIndex[objectIndex];
	if ( boneIndex < 0 )
		return false;

	const ragdollelement_t &element = ragdoll.list[objectIndex];

	element.pObject->GetPositionMatrix( pBoneToWorld[boneIndex] );
	if ( element.parentIndex >= 0 )
	{
		// overwrite the position from physics to force rigid attachment
		// UNDONE: If we support other types of constraints (or multiple constraints per object)
		// make sure these don't fight !
		int parentBoneIndex = ragdoll.boneIndex[element.parentIndex];
		Vector out;
		VectorTransform( element.originParentSpace, pBoneToWorld[parentBoneIndex], out );
		MatrixSetColumn( out, 3, pBoneToWorld[boneIndex] );
	}

	return true;
}
Esempio n. 15
0
bool RagdollGetBoneMatrix( const ragdoll_t &ragdoll, CBoneAccessor &pBoneToWorld, int objectIndex )
{
	int boneIndex = ragdoll.boneIndex[objectIndex];
	if ( boneIndex < 0 )
		return false;

	const ragdollelement_t &element = ragdoll.list[objectIndex];

	// during restore if a model has changed since the file was saved, this could be NULL
	if ( !element.pObject )
		return false;
	element.pObject->GetPositionMatrix( &pBoneToWorld.GetBoneForWrite( boneIndex ) );
	if ( element.parentIndex >= 0 && !ragdoll.allowStretch )
	{
		// overwrite the position from physics to force rigid attachment
		// NOTE: On the client we actually override this with the proper parent bone in each LOD
		int parentBoneIndex = ragdoll.boneIndex[element.parentIndex];
		Vector out;
		VectorTransform( element.originParentSpace, pBoneToWorld.GetBone( parentBoneIndex ), out );
		MatrixSetColumn( out, 3, pBoneToWorld.GetBoneForWrite( boneIndex ) );
	}
	return true;
}
Esempio n. 16
0
bool RagdollGetBoneMatrix( const ragdoll_t &ragdoll, CBoneAccessor &pBoneToWorld, int objectIndex )
{
	int boneIndex = ragdoll.boneIndex[objectIndex];
	if ( boneIndex < 0 )
		return false;

	const ragdollelement_t &element = ragdoll.list[objectIndex];

	// during restore if a model has changed since the file was saved, this could be NULL
	if ( !element.pObject )
		return false;
	element.pObject->GetPositionMatrix( &pBoneToWorld.GetBoneForWrite( boneIndex ) );
	if ( element.parentIndex >= 0 && !ragdoll.allowStretch )
	{
		// overwrite the position from physics to force rigid attachment
		// UNDONE: If we support other types of constraints (or multiple constraints per object)
		// make sure these don't fight !
		int parentBoneIndex = ragdoll.boneIndex[element.parentIndex];
		Vector out;
		VectorTransform( element.originParentSpace, pBoneToWorld.GetBone( parentBoneIndex ), out );
		MatrixSetColumn( out, 3, pBoneToWorld.GetBoneForWrite( boneIndex ) );
	}
	return true;
}
Esempio n. 17
0
void RagdollSolveSeparation( ragdoll_t &ragdoll, CBaseEntity *pEntity )
{
	byte needsFix[256];
	int fixCount = 0;
	Assert(ragdoll.listCount<=ARRAYSIZE(needsFix));
	for ( int i = 0; i < ragdoll.listCount; i++ )
	{
		needsFix[i] = 0;
		const ragdollelement_t &element = ragdoll.list[i];
		if ( element.pConstraint && element.parentIndex >= 0 )
		{
			Vector start, target;
			element.pObject->GetPosition( &start, NULL );
			ragdoll.list[element.parentIndex].pObject->LocalToWorld( &target, element.originParentSpace );
			if ( needsFix[element.parentIndex] )
			{
				needsFix[i] = 1;
				++fixCount;
				continue;
			}
			Vector dir = target-start;
			if ( dir.LengthSqr() > 1.0f )
			{
				// this fixes a bug in ep2 with antlion grubs, but causes problems in TF2 - revisit, but disable for TF now
#if !defined(TF_CLIENT_DLL)
				// heuristic: guess that anything separated and small mass ratio is in some state that's 
				// keeping the solver from fixing it
				float mass = element.pObject->GetMass();
				float massParent = ragdoll.list[element.parentIndex].pObject->GetMass();

				if ( mass*2.0f < massParent )
				{
					// if this is <0.5 mass of parent and still separated it's attached to something heavy or 
					// in a bad state
					needsFix[i] = 1;
					++fixCount;
					continue;
				}
#endif

				if ( PhysHasContactWithOtherInDirection(element.pObject, dir) )
				{
					Ray_t ray;
					trace_t tr;
					ray.Init( target, start );
					UTIL_TraceRay( ray, MASK_SOLID, pEntity, COLLISION_GROUP_NONE, &tr );
					if ( tr.DidHit() )
					{
						needsFix[i] = 1;
						++fixCount;
					}
				}
			}
		}
	}

	if ( fixCount )
	{
		for ( int i = 0; i < ragdoll.listCount; i++ )
		{
			if ( !needsFix[i] )
				continue;

			const ragdollelement_t &element = ragdoll.list[i];
			Vector target, velocity;
			ragdoll.list[element.parentIndex].pObject->LocalToWorld( &target, element.originParentSpace );
			ragdoll.list[element.parentIndex].pObject->GetVelocityAtPoint( target, &velocity );
			matrix3x4_t xform;
			element.pObject->GetPositionMatrix( &xform );
			MatrixSetColumn( target, 3, xform );
			element.pObject->SetPositionMatrix( xform, true );
			element.pObject->SetVelocity( &velocity, &vec3_origin );
		}
		DevMsg(2, "TICK:%5d:Ragdoll separation count: %d\n", gpGlobals->tickcount, fixCount );
	}
	else
	{
		ragdoll.pGroup->ClearErrorState();
	}
}
Esempio n. 18
0
// apply custom pitch to bone merge
void CASW_Bone_Merge_Cache::MergeMatchingBones( int boneMask, CBoneBitList &boneComputed, bool bOverrideDirection, const Vector &vecDir )
{
	UpdateCache();

	// If this is set, then all the other cache data is set.
	if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
		return;

	// Have the entity we're following setup its bones.
	m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );

	matrix3x4_t matPitchUp;
	AngleMatrix( QAngle( asw_weapon_pitch.GetFloat(), 0, 0 ), matPitchUp );

	// Now copy the bone matrices.
	for ( int i=0; i < m_MergedBones.Count(); i++ )
	{
		int iOwnerBone = m_MergedBones[i].m_iMyBone;
		int iParentBone = m_MergedBones[i].m_iParentBone;

		// Only update bones reference by the bone mask.
		if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
			continue;

		if ( bOverrideDirection && m_nRightHandBoneID == -1 )		// only want to change direction of the right hand bone, cache its index here
		{
			mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 );
			for ( int k = 0; k < m_pOwnerHdr->numbones(); k++ )
			{
				if ( !Q_stricmp( pOwnerBones[k].pszName(), "ValveBiped.Bip01_R_Hand" ) )
				{
					m_nRightHandBoneID = k;
					break;
				}
			}
		}
		
		if ( bOverrideDirection && i == m_nRightHandBoneID )
		{
			matrix3x4_t matParentBoneToWorld;
			m_pFollow->GetBoneTransform( iParentBone, matParentBoneToWorld );
			MatrixSetColumn( vec3_origin, 3, matParentBoneToWorld );		// remove translation

			matrix3x4_t matParentBoneToWorldInv;
			MatrixInvert( matParentBoneToWorld, matParentBoneToWorldInv );

			QAngle angAiming;
			VectorAngles( vecDir, Vector( 0, 0, -1 ), angAiming );
			matrix3x4_t matAimDirection;
			AngleMatrix( angAiming, matAimDirection );
			MatrixSetColumn( vec3_origin, 3, matAimDirection );		// remove translation

			matrix3x4_t matCorrection;
			ConcatTransforms( matParentBoneToWorldInv, matAimDirection, matCorrection );

			ConcatTransforms( m_pFollow->GetBone( iParentBone ), matCorrection, m_pOwner->GetBoneForWrite( iOwnerBone ) );
		}
		else
		{
			ConcatTransforms( m_pFollow->GetBone( iParentBone ), matPitchUp, m_pOwner->GetBoneForWrite( iOwnerBone ) );
		}

		boneComputed.Set( i );
	}
}
Esempio n. 19
0
CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, const CTakeDamageInfo &info, int collisionGroup, bool bUseLRURetirement )
{
	SyncAnimatingWithPhysics( pAnimating );

	CRagdollProp *pRagdoll = (CRagdollProp *)CBaseEntity::CreateNoSpawn( "prop_ragdoll", pAnimating->GetAbsOrigin(), vec3_angle, NULL );
	pRagdoll->CopyAnimationDataFrom( pAnimating );
	pRagdoll->SetOwnerEntity( pAnimating );

	pRagdoll->InitRagdollAnimation();
	matrix3x4_t pBoneToWorld[MAXSTUDIOBONES], pBoneToWorldNext[MAXSTUDIOBONES];
	
	const float dt = 0.1f;

	// Copy over dissolve state...
	if ( pAnimating->IsEFlagSet( EFL_NO_DISSOLVE ) )
	{
		pRagdoll->AddEFlags( EFL_NO_DISSOLVE );
	}

	// NOTE: This currently is only necessary to prevent manhacks from
	// colliding with server ragdolls they kill
	pRagdoll->SetKiller( info.GetInflictor() );
	pRagdoll->SetSourceClassName( pAnimating->GetClassname() );

	// NPC_STATE_DEAD npc's will have their COND_IN_PVS cleared, so this needs to force SetupBones to happen
	unsigned short fPrevFlags = pAnimating->GetBoneCacheFlags();
	pAnimating->SetBoneCacheFlags( BCF_NO_ANIMATION_SKIP );

	// UNDONE: Extract velocity from bones via animation (like we do on the client)
	// UNDONE: For now, just move each bone by the total entity velocity if set.
	pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING );

	// Reset previous bone flags
	pAnimating->ClearBoneCacheFlags( BCF_NO_ANIMATION_SKIP );
	pAnimating->SetBoneCacheFlags( fPrevFlags );

	memcpy( pBoneToWorldNext, pBoneToWorld, sizeof(pBoneToWorld) );
	Vector vel = pAnimating->GetAbsVelocity();
	if ( vel.LengthSqr() > 0 )
	{
		int numbones = pAnimating->GetModelPtr()->numbones();
		for ( int i = 0; i < numbones; i++ )
		{
			Vector pos;
			MatrixGetColumn( pBoneToWorldNext[i], 3, pos );
			pos += vel * dt;
			MatrixSetColumn( pos, 3, pBoneToWorldNext[i] );
		}
	}

	// Is this a vehicle / NPC collision?
	if ( (info.GetDamageType() & DMG_VEHICLE) && pAnimating->MyNPCPointer() )
	{
		// init the ragdoll with no forces
		pRagdoll->InitRagdoll( vec3_origin, -1, vec3_origin, pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true );

		// apply vehicle forces
		// Get a list of bones with hitboxes below the plane of impact
		int boxList[128];
		Vector normal(0,0,-1);
		int count = pAnimating->GetHitboxesFrontside( boxList, ARRAYSIZE(boxList), normal, DotProduct( normal, info.GetDamagePosition() ) );
		
		// distribute force over mass of entire character
		float massScale = Studio_GetMass(pAnimating->GetModelPtr());
		massScale = clamp( massScale, 1, 1e4 );
		massScale = 1 / massScale;

		// distribute the force
		// BUGBUG: This will hit the same bone twice if it has two hitboxes!!!!
		ragdoll_t *pRagInfo = pRagdoll->GetRagdoll();
		for ( int i = 0; i < count; i++ )
		{
			int physBone = pAnimating->GetPhysicsBone( pAnimating->GetHitboxBone( boxList[i] ) );
			IPhysicsObject *pPhysics = pRagInfo->list[physBone].pObject;
			pPhysics->ApplyForceCenter( info.GetDamageForce() * pPhysics->GetMass() * massScale );
		}
	}
	else
	{
		pRagdoll->InitRagdoll( info.GetDamageForce(), forceBone, info.GetDamagePosition(), pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true );
	}

	// Are we dissolving?
	if ( pAnimating->IsDissolving() )
	{
		pRagdoll->TransferDissolveFrom( pAnimating );
	}
	else if ( bUseLRURetirement )
	{
		pRagdoll->AddSpawnFlags( SF_RAGDOLLPROP_USE_LRU_RETIREMENT );
		s_RagdollLRU.MoveToTopOfLRU( pRagdoll );
	}

	// Tracker 22598:  If we don't set the OBB mins/maxs to something valid here, then the client will have a zero sized hull
	//  for the ragdoll for one frame until Vphysics updates the real obb bounds after the first simulation frame.  Having
	//  a zero sized hull makes the ragdoll think it should be faded/alpha'd to zero for a frame, so you get a blink where
	//  the ragdoll doesn't draw initially.
	Vector mins, maxs;
	mins = pAnimating->CollisionProp()->OBBMins();
	maxs = pAnimating->CollisionProp()->OBBMaxs();
	pRagdoll->CollisionProp()->SetCollisionBounds( mins, maxs );

	return pRagdoll;
}
Esempio n. 20
0
void CRagdollPropAttached::InitRagdollAttached( 
	IPhysicsObject *pAttached, 
	const Vector &forceVector, 
	int forceBone, 
	matrix3x4_t *pPrevBones, 
	matrix3x4_t *pBoneToWorld, 
	float dt, 
	int collisionGroup, 
	CBaseAnimating *pFollow, 
	int boneIndexRoot, 
	const Vector &boneLocalOrigin, 
	int parentBoneAttach, 
	const Vector &worldAttachOrigin )
{
	int ragdollAttachedIndex = 0;
	if ( parentBoneAttach > 0 )
	{
		CStudioHdr *pStudioHdr = GetModelPtr();
		mstudiobone_t *pBone = pStudioHdr->pBone( parentBoneAttach );
		ragdollAttachedIndex = pBone->physicsbone;
	}

	InitRagdoll( forceVector, forceBone, vec3_origin, pPrevBones, pBoneToWorld, dt, collisionGroup, false );
	
	IPhysicsObject *pRefObject = m_ragdoll.list[ragdollAttachedIndex].pObject;

	Vector attachmentPointRagdollSpace;
	pRefObject->WorldToLocal( &attachmentPointRagdollSpace, worldAttachOrigin );

	constraint_ragdollparams_t constraint;
	constraint.Defaults();
	matrix3x4_t tmp, worldToAttached, worldToReference, constraintToWorld;

	Vector offsetWS;
	pAttached->LocalToWorld( &offsetWS, boneLocalOrigin );

	AngleMatrix( QAngle(0, pFollow->GetAbsAngles().y, 0 ), offsetWS, constraintToWorld );

	constraint.axes[0].SetAxisFriction( -2, 2, 20 );
	constraint.axes[1].SetAxisFriction( 0, 0, 0 );
	constraint.axes[2].SetAxisFriction( -15, 15, 20 );

	// Exaggerate the bone's ability to pull the mass of the ragdoll around
	constraint.constraint.bodyMassScale[1] = 50.0f;

	pAttached->GetPositionMatrix( &tmp );
	MatrixInvert( tmp, worldToAttached );

	pRefObject->GetPositionMatrix( &tmp );
	MatrixInvert( tmp, worldToReference );

	ConcatTransforms( worldToReference, constraintToWorld, constraint.constraintToReference );
	ConcatTransforms( worldToAttached, constraintToWorld, constraint.constraintToAttached );

	// for now, just slam this to be the passed in value
	MatrixSetColumn( attachmentPointRagdollSpace, 3, constraint.constraintToReference );

	PhysDisableEntityCollisions( pAttached, m_ragdoll.list[0].pObject );
	m_pAttachConstraint = physenv->CreateRagdollConstraint( pRefObject, pAttached, m_ragdoll.pGroup, constraint );

	SetParent( pFollow );
	SetOwnerEntity( pFollow );

	RagdollActivate( m_ragdoll, modelinfo->GetVCollide( GetModelIndex() ), GetModelIndex() );

	// add a bunch of dampening to the ragdoll
	for ( int i = 0; i < m_ragdoll.listCount; i++ )
	{
		float damping, rotdamping;
		m_ragdoll.list[i].pObject->GetDamping( &damping, &rotdamping );
		damping *= ATTACHED_DAMPING_SCALE;
		rotdamping *= ATTACHED_DAMPING_SCALE;
		m_ragdoll.list[i].pObject->SetDamping( &damping, &rotdamping );
	}

	m_boneIndexAttached = boneIndexRoot;
	m_ragdollAttachedObjectIndex = ragdollAttachedIndex;
	m_attachmentPointBoneSpace = boneLocalOrigin;
	
	Vector vTemp;
	MatrixGetColumn( constraint.constraintToReference, 3, vTemp );
	m_attachmentPointRagdollSpace = vTemp;
}
Esempio n. 21
0
void CWeaponIFMSteadyCam::UpdateRelativeOrientation()
{
	if ( m_bIsLocked )
		return;

	if ( m_bInDirectMode )
	{
		UpdateDirectRelativeOrientation();
		return;
	}

	if ( ( m_vecViewOffset.x == 0.0f ) && ( m_vecViewOffset.y == 0.0f ) )
		return;

	// Compute a player to steadycam matrix
	VMatrix steadyCamToPlayer;
	MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer );
	MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition );

	Vector vecCurrentForward;
	MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward );

	// Create a ray in steadycam space
	float flMaxD = 1.0f / tan( M_PI * m_flFOV / 360.0f );

	// Remap offsets into normalized space
	float flViewX = m_vecViewOffset.x / ( 384 / 2 );
	float flViewY = m_vecViewOffset.y / ( 288 / 2 );

	flViewX *= flMaxD * ifm_steadycam_mousefactor.GetFloat();
	flViewY *= flMaxD * ifm_steadycam_mousefactor.GetFloat();
				    
	Vector vecSelectionDir( 1.0f, -flViewX, -flViewY );
	VectorNormalize( vecSelectionDir );

	// Rotate the ray into player coordinates
	Vector vecDesiredDirection;
	Vector3DMultiply( steadyCamToPlayer, vecSelectionDir, vecDesiredDirection );

	float flDot = DotProduct( vecDesiredDirection, vecCurrentForward );
	flDot = clamp( flDot, -1.0f, 1.0f );
	float flAngle = 180.0f * acos( flDot ) / M_PI;
	if ( flAngle < 1e-3 )
	{
		matrix3x4_t mat;
		MatrixFromForwardDirection( vecDesiredDirection, mat );
		MatrixAngles( mat, m_angRelativeAngles );
		return;
	}

	Vector vecAxis;
	CrossProduct( vecCurrentForward, vecDesiredDirection, vecAxis );
	VectorNormalize( vecAxis );
	
	float flRotateRate = ifm_steadycam_rotaterate.GetFloat();
	if ( flRotateRate < 1.0f )
	{
		flRotateRate = 1.0f;
	}

	float flRateFactor = flAngle / flRotateRate;
	flRateFactor *= flRateFactor * flRateFactor;
	float flRate = flRateFactor * 30.0f;
	float flMaxAngle = gpGlobals->frametime * flRate;
	flAngle = clamp( flAngle, 0.0f, flMaxAngle );

	Vector vecNewForard;
	VMatrix rotation;
	MatrixBuildRotationAboutAxis( rotation, vecAxis, flAngle ); 
	Vector3DMultiply( rotation, vecCurrentForward, vecNewForard );

	matrix3x4_t mat;
	MatrixFromForwardDirection( vecNewForard, mat );
	MatrixAngles( mat, m_angRelativeAngles );

	Assert( m_angRelativeAngles.IsValid() );
}
Esempio n. 22
0
void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll )
{
	SetCollisionGroup( collisionGroup );

	// Make sure it's interactive debris for at most 5 seconds
	if ( collisionGroup == COLLISION_GROUP_INTERACTIVE_DEBRIS )
	{
		SetContextThink( &CRagdollProp::SetDebrisThink, gpGlobals->curtime + 5, s_pDebrisContext );
	}

	SetMoveType( MOVETYPE_VPHYSICS );
	SetSolid( SOLID_VPHYSICS );
	AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );
	m_takedamage = DAMAGE_EVENTS_ONLY;

	ragdollparams_t params;
	params.pGameData = static_cast<void *>( static_cast<CBaseEntity *>(this) );
	params.modelIndex = GetModelIndex();
	params.pCollide = modelinfo->GetVCollide( params.modelIndex );
	params.pStudioHdr = GetModelPtr();
	params.forceVector = forceVector;
	params.forceBoneIndex = forceBone;
	params.forcePosition = forcePos;
	params.pPrevBones = pPrevBones;
	params.pCurrentBones = pBoneToWorld;
	params.boneDt = dt;
	params.jointFrictionScale = 1.0;
	RagdollCreate( m_ragdoll, params, physenv );
	if ( m_anglesOverrideString != NULL_STRING && Q_strlen(m_anglesOverrideString.ToCStr()) > 0 )
	{
		char szToken[2048];
		const char *pStr = nexttoken(szToken, STRING(m_anglesOverrideString), ',');
		// anglesOverride is index,angles,index,angles (e.g. "1, 22.5 123.0 0.0, 2, 0 0 0, 3, 0 0 180.0")
		while ( szToken[0] != 0 )
		{
			int objectIndex = atoi(szToken);
			// sanity check to make sure this token is an integer
			Assert( atof(szToken) == ((float)objectIndex) );
			pStr = nexttoken(szToken, pStr, ',');
			Assert( szToken[0] );
			if ( objectIndex >= m_ragdoll.listCount )
			{
				Warning("Bad ragdoll pose in entity %s, model (%s) at %s, model changed?\n", GetDebugName(), GetModelName().ToCStr(), VecToString(GetAbsOrigin()) );
			}
			else if ( szToken[0] != 0 )
			{
				QAngle angles;
				Assert( objectIndex >= 0 && objectIndex < RAGDOLL_MAX_ELEMENTS );
				UTIL_StringToVector( angles.Base(), szToken );
				int boneIndex = m_ragdoll.boneIndex[objectIndex];
				AngleMatrix( angles, pBoneToWorld[boneIndex] );
				const ragdollelement_t &element = m_ragdoll.list[objectIndex];
				Vector out;
				if ( element.parentIndex >= 0 )
				{
					int parentBoneIndex = m_ragdoll.boneIndex[element.parentIndex];
					VectorTransform( element.originParentSpace, pBoneToWorld[parentBoneIndex], out );
				}
				else
				{
					out = GetAbsOrigin();
				}
				MatrixSetColumn( out, 3, pBoneToWorld[boneIndex] );
				element.pObject->SetPositionMatrix( pBoneToWorld[boneIndex], true );
			}
			pStr = nexttoken(szToken, pStr, ',');
		}
	}

	if ( activateRagdoll )
	{
		MEM_ALLOC_CREDIT();
		RagdollActivate( m_ragdoll, params.pCollide, GetModelIndex() );
	}

	for ( int i = 0; i < m_ragdoll.listCount; i++ )
	{
		UpdateNetworkDataFromVPhysics( m_ragdoll.list[i].pObject, i );
		g_pPhysSaveRestoreManager->AssociateModel( m_ragdoll.list[i].pObject, GetModelIndex() );
		physcollision->CollideGetAABB( m_ragdollMins[i], m_ragdollMaxs[i], m_ragdoll.list[i].pObject->GetCollide(), vec3_origin, vec3_angle );
	}
	VPhysicsSetObject( m_ragdoll.list[0].pObject );

	CalcRagdollSize();
}
Esempio n. 23
0
//-----------------------------------------------------------------------------
// Set up the bones for a frame
//-----------------------------------------------------------------------------
matrix3x4_t* CIHVTestApp::SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld, int iRun, int model, int boneMask )
{
	// Default to middle of the pose parameter range
	float pPoseParameter[MAXSTUDIOPOSEPARAM];
	for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
	{
		pPoseParameter[i] = 0.5f;
	}

	CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );

	int nFrameCount = Studio_MaxFrame( &studioHdr, g_BenchRuns[iRun].sequence1[model], pPoseParameter );
	if ( nFrameCount == 0 )
	{
		nFrameCount = 1;
	}

	Vector		pos[MAXSTUDIOBONES];
	Quaternion	q[MAXSTUDIOBONES];

	InitPose( &studioHdr, pos, q, boneMask );
	AccumulatePose( &studioHdr, NULL, pos, q, g_BenchRuns[iRun].sequence1[model], s_Cycle[model], pPoseParameter, boneMask, 1.0f, 0.0 );

	// FIXME: Try enabling this?
//	CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BoneMask( ), flTime );

	// Root transform
	matrix3x4_t rootToWorld, temp;

	MatrixCopy( shapeToWorld, rootToWorld );

	matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() );
	for ( int i = 0; i < studioHdr.numbones(); i++ ) 
	{
		// If it's not being used, fill with NAN for errors
		if ( !(studioHdr.pBone( i )->flags & boneMask) )
		{
			int j, k;
			for (j = 0; j < 3; j++)
			{
				for (k = 0; k < 4; k++)
				{
					pBoneToWorld[i][j][k] = VEC_T_NAN;
				}
			}
			continue;
		}

		matrix3x4_t boneMatrix;
		QuaternionMatrix( q[i], boneMatrix );
		MatrixSetColumn( pos[i], 3, boneMatrix );

		if (studioHdr.pBone(i)->parent == -1) 
		{
			ConcatTransforms (rootToWorld, boneMatrix, pBoneToWorld[i]);
		} 
		else 
		{
			ConcatTransforms (pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] );
		}
	}
	g_pStudioRender->UnlockBoneMatrices();
	return pBoneToWorld;
}
static int vmatrix_MatrixSetColumn (lua_State *L) {
  MatrixSetColumn(luaL_checkvmatrix(L, 1), luaL_checkint(L, 2), luaL_checkvector(L, 3));
  return 0;
}
Esempio n. 25
0
bool _ComputeRagdollBones( const ragdoll_t *pRagdoll, matrix3x4_t &parentTransform, matrix3x4_t *pBones, Vector *pPositions, QAngle *pAngles )
{
	matrix3x4_t inverted, output;

#ifdef _DEBUG
	CBitVec<MAXSTUDIOBONES> vBonesComputed;
	vBonesComputed.ClearAll();
#endif

	for ( int i = 0; i < pRagdoll->listCount; ++i )
	{
		const ragdollelement_t& element = pRagdoll->list[ i ];

		// during restore if a model has changed since the file was saved, this could be NULL
		if ( !element.pObject )
			return false;

		int const boneIndex = pRagdoll->boneIndex[ i ];
		if ( boneIndex < 0 )
		{
			AssertMsg( 0, "Replay: No mapping for ragdoll bone\n" );
			return false;
		}

		// Get global transform and put it into the bone cache
		element.pObject->GetPositionMatrix( &pBones[ boneIndex ] );

		// Ensure a fixed translation from the parent (no stretching)
		if ( element.parentIndex >= 0 && !pRagdoll->allowStretch )
		{
			int parentIndex = pRagdoll->boneIndex[ element.parentIndex ];

#ifdef _DEBUG
			// Make sure we computed the parent already
			Assert( vBonesComputed.IsBitSet(parentIndex) );
#endif

			// overwrite the position from physics to force rigid attachment
			// NOTE: On the client we actually override this with the proper parent bone in each LOD
			Vector out;
			VectorTransform( element.originParentSpace, pBones[ parentIndex ], out );
			MatrixSetColumn( out, 3, pBones[ boneIndex ] );

			MatrixInvert( pBones[ parentIndex ], inverted );
		}
		else if ( element.parentIndex == - 1 )
		{
			// Decompose into parent space
			MatrixInvert( parentTransform, inverted );
		}

#ifdef _DEBUG
		vBonesComputed.Set( boneIndex, true );
#endif

		// Compute local transform and put into 'output'
 		ConcatTransforms( inverted, pBones[ boneIndex ], output );

		// Cache as Euler/position
 		MatrixAngles( output, pAngles[ i ], pPositions[ i ] );
	}
	return true;
}
Esempio n. 26
0
void CDmeMDL::SetUpBones( CStudioHdr &studioHdr, const matrix3x4_t& shapeToWorld, int nMaxBoneCount, matrix3x4_t *pBoneToWorld )
{
	// Default to middle of the pose parameter range
	float pPoseParameter[MAXSTUDIOPOSEPARAM];
	for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
	{
		pPoseParameter[i] = 0.5f;
	}

	int nFrameCount = Studio_MaxFrame( &studioHdr, m_nSequence, pPoseParameter );
	if ( nFrameCount == 0 )
	{
		nFrameCount = 1;
	}
	float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount;

	// FIXME: We're always wrapping; may want to determing if we should clamp
	flCycle -= (int)(flCycle);

	Vector		pos[MAXSTUDIOBONES];
	Quaternion	q[MAXSTUDIOBONES];

	InitPose( &studioHdr, pos, q, BoneMask( ) );
	AccumulatePose( &studioHdr, NULL, pos, q, m_nSequence, flCycle, pPoseParameter, BoneMask( ), 1.0f, m_flTime );

	// FIXME: Try enabling this?
//	CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BoneMask( ), flTime );

	// Root transform
	matrix3x4_t rootToWorld, temp;

	// Rotate the root transform to make it align with DMEs
	// DMEs up vector is the y axis
	if ( !m_bDrawInEngine )
	{
		matrix3x4_t engineToDme;
		EngineToDmeMatrix( engineToDme );
		ConcatTransforms( engineToDme, shapeToWorld, rootToWorld );
	}
	else
	{
		MatrixCopy( shapeToWorld, rootToWorld );
	}

	if ( nMaxBoneCount > studioHdr.numbones() )
	{
		nMaxBoneCount = studioHdr.numbones();
	}

	for ( int i = 0; i < nMaxBoneCount; i++ ) 
	{
		// If it's not being used, fill with NAN for errors
#ifdef _DEBUG
		if ( !(studioHdr.pBone( i )->flags & BoneMask()))
		{
			int j, k;
			for (j = 0; j < 3; j++)
			{
				for (k = 0; k < 4; k++)
				{
					pBoneToWorld[i][j][k] = VEC_T_NAN;
				}
			}
			continue;
		}
#endif

		matrix3x4_t boneMatrix;
		QuaternionMatrix( q[i], boneMatrix );
		MatrixSetColumn( pos[i], 3, boneMatrix );

		if (studioHdr.pBone(i)->parent == -1) 
		{
			ConcatTransforms( rootToWorld, boneMatrix, pBoneToWorld[i] );
		} 
		else 
		{
			ConcatTransforms( pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] );
		}
	}
}