void CAI_Spotlight::UpdateSpotlightDirection( void ) { if ( !m_hSpotlight ) { CreateSpotlightEntities(); } // Compute the current beam direction Vector vTargetDir; VectorSubtract( m_vSpotlightTargetPos, m_hSpotlight->GetAbsStartPos(), vTargetDir ); VectorNormalize(vTargetDir); ConstrainToCone( &vTargetDir ); // Compute the amount to rotate float flDot = DotProduct( vTargetDir, m_vSpotlightDir ); flDot = clamp( flDot, -1.0f, 1.0f ); float flAngle = AngleNormalize( RAD2DEG( acos( flDot ) ) ); float flClampedAngle = clamp( flAngle, 0.0f, 45.0f ); float flBeamTurnRate = SimpleSplineRemapVal( flClampedAngle, 0.0f, 45.0f, 10.0f, 45.0f ); if ( fabs(flAngle) > flBeamTurnRate * gpGlobals->frametime ) { flAngle = flBeamTurnRate * gpGlobals->frametime; } // Compute the rotation axis Vector vecRotationAxis; CrossProduct( m_vSpotlightDir, vTargetDir, vecRotationAxis ); if ( VectorNormalize( vecRotationAxis ) < 1e-3 ) { vecRotationAxis.Init( 0, 0, 1 ); } // Compute the actual rotation amount, using quat slerp blending Quaternion desiredQuat, resultQuat; AxisAngleQuaternion( vecRotationAxis, flAngle, desiredQuat ); QuaternionSlerp( m_vAngularVelocity, desiredQuat, QUAT_BLEND_FACTOR, resultQuat ); m_vAngularVelocity = resultQuat; // If we're really close, and we're not moving very quickly, slam. float flActualRotation = AngleNormalize( RAD2DEG(2 * acos(m_vAngularVelocity.w)) ); if (( flActualRotation < 1e-3 ) && (flAngle < 1e-3 )) { m_vSpotlightDir = vTargetDir; m_vAngularVelocity.Init( 0, 0, 0, 1 ); return; } // Update the desired direction matrix3x4_t rot; Vector vecNewDir; QuaternionMatrix( m_vAngularVelocity, rot ); VectorRotate( m_vSpotlightDir, rot, vecNewDir ); m_vSpotlightDir = vecNewDir; VectorNormalize(m_vSpotlightDir); }
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: Builds the animation transformation matrix for the entity if it's animating //----------------------------------------------------------------------------- void CMapAnimator::UpdateAnimation( float animTime ) { // only animate if the doc is animating and we're selected if ( !CMapDoc::GetActiveMapDoc()->IsAnimating() || !Parent->IsSelected() ) { // we're not animating m_bCurrentlyAnimating = false; return; } m_bCurrentlyAnimating = true; Vector newOrigin; Quaternion newAngles; GetAnimationAtTime( animTime, newOrigin, newAngles ); matrix4_t mat, tmpMat; Vector ourOrigin; GetOrigin( ourOrigin ); IdentityMatrix( mat ); // build us a matrix // T(newOrigin)R(angle)T(-ourOrigin) IdentityMatrix( m_CoordFrame ) ; // transform back to the origin for ( int i = 0; i < 3; i++ ) { m_CoordFrame[i][3] = -ourOrigin[i]; } // Apply interpolated Rotation QuaternionMatrix( newAngles, mat ); ConcatTransforms( mat, m_CoordFrame, tmpMat ); // transform back to our new position IdentityMatrix( mat ); for ( i = 0; i < 3; i++ ) { mat[i][3] = newOrigin[i]; } ConcatTransforms( mat, tmpMat, m_CoordFrame ); }
SOPAngle *SOPAngle::RotateAroundAxis(SOPVector *vec, lua_Number degrees) { matrix3x4_t m_rgflCoordinateFrame; Vector rotationAxisLs; Quaternion q; matrix3x4_t xform; matrix3x4_t localToWorldMatrix; Vector axisvector = vec->ToVector(); QAngle rotatedAngles; QAngle angOurAngs = ToQAngle(); AngleMatrix( angOurAngs, m_rgflCoordinateFrame ); VectorIRotate( axisvector, m_rgflCoordinateFrame, rotationAxisLs ); AxisAngleQuaternion( rotationAxisLs, degrees, q ); QuaternionMatrix( q, vec3_origin, xform ); ConcatTransforms( m_rgflCoordinateFrame, xform, localToWorldMatrix ); MatrixAngles( localToWorldMatrix, rotatedAngles ); return new SOPAngle(rotatedAngles.x, rotatedAngles.y, rotatedAngles.z); }
//------------------------------------------------------------------------------ // Constrain to cone //------------------------------------------------------------------------------ bool CAI_Spotlight::ConstrainToCone( Vector *pDirection ) { Vector vecOrigin, vecForward; if ( m_nSpotlightAttachment == 0 ) { QAngle vecAngles; vecAngles = GetOuter()->GetAbsAngles(); AngleVectors( vecAngles, &vecForward ); } else { GetOuter()->GetAttachment( m_nSpotlightAttachment, vecOrigin, &vecForward ); } if ( m_flConstraintAngle == 0.0f ) { *pDirection = vecForward; return true; } float flDot = DotProduct( vecForward, *pDirection ); if ( flDot >= cos( DEG2RAD( m_flConstraintAngle ) ) ) return false; Vector vecAxis; CrossProduct( *pDirection, vecForward, vecAxis ); VectorNormalize( vecAxis ); Quaternion q; AxisAngleQuaternion( vecAxis, -m_flConstraintAngle, q ); Vector vecResult; matrix3x4_t rot; QuaternionMatrix( q, rot ); VectorRotate( vecForward, rot, vecResult ); VectorNormalize( vecResult ); *pDirection = vecResult; return true; }
/* ==================== StudioMergeBones ==================== */ void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) { int i, j; double f; int do_hunt = true; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; float bonematrix[3][4]; static vec4_t q[MAXSTUDIOBONES]; if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) { m_pCurrentEntity->curstate.sequence = 0; } pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame( pseqdesc ); if (m_pCurrentEntity->latched.prevframe > f) { //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); } panim = StudioGetAnim( m_pSubModel, pseqdesc ); StudioCalcRotations( pos, q, pseqdesc, panim, f ); pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); for (i = 0; i < m_pStudioHeader->numbones; i++) { for (j = 0; j < m_nCachedBones; j++) { if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) { MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); break; } } if (j >= m_nCachedBones) { QuaternionMatrix( q[i], bonematrix ); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { if ( IEngineStudio.IsHardware() ) { ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); // MatrixCopy should be faster... //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); } else { ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } // Apply client-side effects to the transformation matrix StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); } else { ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } } }
/* ==================== StudioSetupBones ==================== */ void CStudioModelRenderer::StudioSetupBones ( void ) { int i; double f; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; float bonematrix[3][4]; static float pos2[MAXSTUDIOBONES][3]; static vec4_t q2[MAXSTUDIOBONES]; static float pos3[MAXSTUDIOBONES][3]; static vec4_t q3[MAXSTUDIOBONES]; static float pos4[MAXSTUDIOBONES][3]; static vec4_t q4[MAXSTUDIOBONES]; if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) { m_pCurrentEntity->curstate.sequence = 0; } pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame( pseqdesc ); if (m_pCurrentEntity->latched.prevframe > f) { //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); } panim = StudioGetAnim( m_pRenderModel, pseqdesc ); StudioCalcRotations( pos, q, pseqdesc, panim, f ); if (pseqdesc->numblends > 1) { float s; float dadt; panim += m_pStudioHeader->numbones; StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); dadt = StudioEstimateInterpolant(); s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; StudioSlerpBones( q, pos, q2, pos2, s ); if (pseqdesc->numblends == 4) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); panim += m_pStudioHeader->numbones; StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; StudioSlerpBones( q3, pos3, q4, pos4, s ); s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; StudioSlerpBones( q, pos, q3, pos3, s ); } } if (m_fDoInterp && m_pCurrentEntity->latched.sequencetime && ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) { // blend from last sequence static float pos1b[MAXSTUDIOBONES][3]; static vec4_t q1b[MAXSTUDIOBONES]; float s; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; panim = StudioGetAnim( m_pRenderModel, pseqdesc ); // clip prevframe StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); if (pseqdesc->numblends > 1) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; StudioSlerpBones( q1b, pos1b, q2, pos2, s ); if (pseqdesc->numblends == 4) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); panim += m_pStudioHeader->numbones; StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; StudioSlerpBones( q3, pos3, q4, pos4, s ); s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; StudioSlerpBones( q1b, pos1b, q3, pos3, s ); } } s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; StudioSlerpBones( q, pos, q1b, pos1b, s ); } else { //Con_DPrintf("prevframe = %4.2f\n", f); m_pCurrentEntity->latched.prevframe = f; } pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); // calc gait animation if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) { if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) { m_pPlayerInfo->gaitsequence = 0; } pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; panim = StudioGetAnim( m_pRenderModel, pseqdesc ); StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); for (i = 0; i < m_pStudioHeader->numbones; i++) { if (strcmp( pbones[i].name, "Bip01 Spine") == 0) break; memcpy( pos[i], pos2[i], sizeof( pos[i] )); memcpy( q[i], q2[i], sizeof( q[i] )); } } for (i = 0; i < m_pStudioHeader->numbones; i++) { QuaternionMatrix( q[i], bonematrix ); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { if ( IEngineStudio.IsHardware() ) { ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); // MatrixCopy should be faster... //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); } else { ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } // Apply client-side effects to the transformation matrix StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); } else { ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } }
void C_ServerRagdoll::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed ) { if ( !hdr ) return; matrix3x4_t bonematrix; bool boneSimulated[MAXSTUDIOBONES]; // no bones have been simulated memset( boneSimulated, 0, sizeof(boneSimulated) ); mstudiobone_t *pbones = hdr->pBone( 0 ); mstudioseqdesc_t *pSeqDesc = NULL; if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < hdr->GetNumSeq() ) { pSeqDesc = &hdr->pSeqdesc( m_nOverlaySequence ); } int i; for ( i = 0; i < m_elementCount; i++ ) { int index = m_boneIndex[i]; if ( index >= 0 ) { if ( hdr->boneFlags(index) & boneMask ) { boneSimulated[index] = true; matrix3x4_t &matrix = GetBoneForWrite( index ); if ( m_flBlendWeightCurrent != 0.0f && pSeqDesc && // FIXME: this bone access is illegal pSeqDesc->weight( index ) != 0.0f ) { // Use the animated bone position instead boneSimulated[index] = false; } else { AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix ); } } } } for ( i = 0; i < hdr->numbones(); i++ ) { if ( !( hdr->boneFlags( i ) & boneMask ) ) continue; // BUGBUG: Merge this code with the code in c_baseanimating somehow!!! // animate all non-simulated bones if ( boneSimulated[i] || CalcProceduralBone( hdr, i, m_BoneAccessor ) ) { continue; } else { QuaternionMatrix( q[i], pos[i], bonematrix ); if (pbones[i].parent == -1) { ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) ); } else { ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, GetBoneForWrite( i ) ); } } if ( pbones[i].parent == -1 ) { // Apply client-side effects to the transformation matrix // ApplyBoneMatrixTransform( GetBoneForWrite( i ) ); } } }
/* <16247> ../cstrike/dlls/animation.cpp:1115 */ void SV_StudioSetupBones(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict) { int i, j; float_precision f; float subframe; float adj[MAXSTUDIOCONTROLLERS]; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; float bonematrix[3][4]; int chain[MAXSTUDIOBONES]; int chainlength; vec3_t temp_angles; static float pos[MAXSTUDIOBONES][3], pos2[MAXSTUDIOBONES][3]; static float q[MAXSTUDIOBONES][4], q2[MAXSTUDIOBONES][4]; g_pstudiohdr = (studiohdr_t *)IEngineStudio.Mod_Extradata(pModel); // Bound sequence number if (sequence < 0 || sequence >= g_pstudiohdr->numseq) sequence = 0; pbones = (mstudiobone_t *)((byte *)g_pstudiohdr + g_pstudiohdr->boneindex); pseqdesc = (mstudioseqdesc_t *)((byte *)g_pstudiohdr + g_pstudiohdr->seqindex) + sequence; panim = StudioGetAnim(pModel, pseqdesc); if (iBone < -1 || iBone >= g_pstudiohdr->numbones) iBone = 0; if (iBone == -1) { chainlength = g_pstudiohdr->numbones; for (i = 0; i < chainlength; i++) chain[(chainlength - i) - 1] = i; } else { chainlength = 0; for (i = iBone; i != -1; i = pbones[i].parent) chain[chainlength++] = i; } f = StudioEstimateFrame(frame, pseqdesc); subframe = (int)f; f -= subframe; StudioCalcBoneAdj(0, adj, pcontroller, pcontroller, 0); StudioCalcRotations(pbones, chain, chainlength, adj, pos, q, pseqdesc, panim, subframe, f); if (pseqdesc->numblends != 9) { if (pseqdesc->numblends > 1) { float b = (float_precision)pblending[0] / 255.0f; pseqdesc = (mstudioseqdesc_t *)((byte *)g_pstudiohdr + g_pstudiohdr->seqindex) + sequence; panim = StudioGetAnim(pModel, pseqdesc); panim += g_pstudiohdr->numbones; StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, subframe, f); StudioSlerpBones(q, pos, q2, pos2, b); } } // This game knows how to do nine way blending else { static float pos3[MAXSTUDIOBONES][3], pos4[MAXSTUDIOBONES][3]; static float q3[MAXSTUDIOBONES][4], q4[MAXSTUDIOBONES][4]; float_precision s, t; s = GetPlayerYaw(pEdict); t = GetPlayerPitch(pEdict); // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right if (s <= 127.0f) { // Scale 0-127 blending up to 0-255 s = (s * 2.0f); if (t <= 127.0f) { t = (t * 2.0f); StudioCalcRotations(pbones, chain, chainlength, adj, pos, q, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 1); StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 3); StudioCalcRotations(pbones, chain, chainlength, adj, pos3, q3, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 4); StudioCalcRotations(pbones, chain, chainlength, adj, pos4, q4, pseqdesc, panim, subframe, f); } else { t = 2.0f * (t - 127.0f); panim = LookupAnimation(pModel, pseqdesc, 3); StudioCalcRotations(pbones, chain, chainlength, adj, pos, q, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 4); StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 6); StudioCalcRotations(pbones, chain, chainlength, adj, pos3, q3, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 7); StudioCalcRotations(pbones, chain, chainlength, adj, pos4, q4, pseqdesc, panim, subframe, f); } } else { // Scale 127-255 blending up to 0-255 s = 2.0f * (s - 127.0f); if (t <= 127.0f) { t = (t * 2.0f); panim = LookupAnimation(pModel, pseqdesc, 1); StudioCalcRotations(pbones, chain, chainlength, adj, pos, q, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 2); StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 4); StudioCalcRotations(pbones, chain, chainlength, adj, pos3, q3, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 5); StudioCalcRotations(pbones, chain, chainlength, adj, pos4, q4, pseqdesc, panim, subframe, f); } else { t = 2.0f * (t - 127.0f); panim = LookupAnimation(pModel, pseqdesc, 4); StudioCalcRotations(pbones, chain, chainlength, adj, pos, q, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 5); StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 7); StudioCalcRotations(pbones, chain, chainlength, adj, pos3, q3, pseqdesc, panim, subframe, f); panim = LookupAnimation(pModel, pseqdesc, 8); StudioCalcRotations(pbones, chain, chainlength, adj, pos4, q4, pseqdesc, panim, subframe, f); } } // Normalize interpolant s /= 255.0f; t /= 255.0f; // Spherically interpolate the bones StudioSlerpBones(q, pos, q2, pos2, s); StudioSlerpBones(q3, pos3, q4, pos4, s); StudioSlerpBones(q, pos, q3, pos3, t); } if (pseqdesc->numblends == 9 && sequence < ANIM_FIRST_DEATH_SEQUENCE && sequence != ANIM_SWIM_1 && sequence != ANIM_SWIM_2) { int copy = 1; int gaitsequence = GetPlayerGaitsequence(pEdict); // calc gait animation if (gaitsequence < 0 || gaitsequence >= g_pstudiohdr->numseq) gaitsequence = 0; pseqdesc = (mstudioseqdesc_t *)((byte *)g_pstudiohdr + g_pstudiohdr->seqindex) + gaitsequence; panim = StudioGetAnim(pModel, pseqdesc); StudioCalcRotations(pbones, chain, chainlength, adj, pos2, q2, pseqdesc, panim, 0, 0); for (i = 0; i < g_pstudiohdr->numbones; i++) { if (!Q_strcmp(pbones[i].name, "Bip01 Spine")) { copy = 0; } else if (!Q_strcmp(pbones[pbones[i].parent].name, "Bip01 Pelvis")) { copy = 1; } if (copy) { Q_memcpy(pos[i], pos2[i], sizeof(pos[i])); Q_memcpy(q[i], q2[i], sizeof(q[i])); } } } VectorCopy(angles, temp_angles); if (pEdict != NULL) { temp_angles[1] = UTIL_GetPlayerGaitYaw(ENTINDEX(pEdict)); if (temp_angles[1] < 0) temp_angles[1] += 360.0f; } AngleMatrix(temp_angles, (*g_pRotationMatrix)); (*g_pRotationMatrix)[0][3] = origin[0]; (*g_pRotationMatrix)[1][3] = origin[1]; (*g_pRotationMatrix)[2][3] = origin[2]; for (i = chainlength - 1; i >= 0; i--) { j = chain[i]; QuaternionMatrix(q[j], bonematrix); bonematrix[0][3] = pos[j][0]; bonematrix[1][3] = pos[j][1]; bonematrix[2][3] = pos[j][2]; if (pbones[j].parent == -1) ConcatTransforms((*g_pRotationMatrix), bonematrix, (*g_pBoneTransform)[j]); else ConcatTransforms((*g_pBoneTransform)[pbones[j].parent], bonematrix, (*g_pBoneTransform)[j]); } }
void StudioModel::SetUpBones ( void ) { int i; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static vec3_t pos[MAXSTUDIOBONES]; float bonematrix[3][4]; static vec4_t q[MAXSTUDIOBONES]; static vec3_t pos2[MAXSTUDIOBONES]; static vec4_t q2[MAXSTUDIOBONES]; static vec3_t pos3[MAXSTUDIOBONES]; static vec4_t q3[MAXSTUDIOBONES]; static vec3_t pos4[MAXSTUDIOBONES]; static vec4_t q4[MAXSTUDIOBONES]; if (m_sequence >= m_pstudiohdr->numseq) { m_sequence = 0; } pseqdesc = (mstudioseqdesc_t *)((byte *)m_pstudiohdr + m_pstudiohdr->seqindex) + m_sequence; panim = GetAnim( pseqdesc ); CalcRotations( pos, q, pseqdesc, panim, m_frame ); if (pseqdesc->numblends > 1) { float s; panim += m_pstudiohdr->numbones; CalcRotations( pos2, q2, pseqdesc, panim, m_frame ); s = m_blending[0] / 255.0; SlerpBones( q, pos, q2, pos2, s ); if (pseqdesc->numblends == 4) { panim += m_pstudiohdr->numbones; CalcRotations( pos3, q3, pseqdesc, panim, m_frame ); panim += m_pstudiohdr->numbones; CalcRotations( pos4, q4, pseqdesc, panim, m_frame ); s = m_blending[0] / 255.0; SlerpBones( q3, pos3, q4, pos4, s ); s = m_blending[1] / 255.0; SlerpBones( q, pos, q3, pos3, s ); } } pbones = (mstudiobone_t *)((byte *)m_pstudiohdr + m_pstudiohdr->boneindex); for (i = 0; i < m_pstudiohdr->numbones; i++) { QuaternionMatrix( q[i], bonematrix ); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { memcpy(g_bonetransform[i], bonematrix, sizeof(float) * 12); } else { R_ConcatTransforms (g_bonetransform[pbones[i].parent], bonematrix, g_bonetransform[i]); } } }
/* ==================== StudioSetupBones ==================== */ void CGameStudioModelRenderer::StudioSetupBones(void) { int i; double f; mstudiobone_t * pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t * panim; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; float bonematrix[3][4]; static float pos2[MAXSTUDIOBONES][3]; static vec4_t q2[MAXSTUDIOBONES]; static float pos3[MAXSTUDIOBONES][3]; static vec4_t q3[MAXSTUDIOBONES]; static float pos4[MAXSTUDIOBONES][3]; static vec4_t q4[MAXSTUDIOBONES]; // Use default bone setup for nonplayers if(!m_pCurrentEntity->player) { CStudioModelRenderer::StudioSetupBones(); return; } // Bound sequence number. if(m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) { m_pCurrentEntity->curstate.sequence = 0; } pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; if(m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) { f = m_pPlayerInfo->gaitframe; } else { f = StudioEstimateFrame(pseqdesc); } // This game knows how to do three way blending if(pseqdesc->numblends == 3) { float s; // Get left anim panim = StudioGetAnim(m_pRenderModel, pseqdesc); // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right if(m_pCurrentEntity->curstate.blending[0] <= 127) { StudioCalcRotations(pos, q, pseqdesc, panim, f); // Scale 0-127 blending up to 0-255 s = m_pCurrentEntity->curstate.blending[0]; s = (s * 2.0); } else { // Skip ahead to middle panim += m_pStudioHeader->numbones; StudioCalcRotations(pos, q, pseqdesc, panim, f); // Scale 127-255 blending up to 0-255 s = m_pCurrentEntity->curstate.blending[0]; s = 2.0 * (s - 127.0); } // Normalize interpolant s /= 255.0; // Go to middle or right panim += m_pStudioHeader->numbones; StudioCalcRotations(pos2, q2, pseqdesc, panim, f); // Spherically interpolate the bones StudioSlerpBones(q, pos, q2, pos2, s); } else { panim = StudioGetAnim(m_pRenderModel, pseqdesc); StudioCalcRotations(pos, q, pseqdesc, panim, f); } // Are we in the process of transitioning from one sequence to another. if(m_fDoInterp && m_pCurrentEntity->latched.sequencetime && (m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime) && (m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq)) { // blend from last sequence static float pos1b[MAXSTUDIOBONES][3]; static vec4_t q1b[MAXSTUDIOBONES]; float s; // Blending value into last sequence unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[0]; // Point at previous sequenece pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; // Know how to do three way blends if(pseqdesc->numblends == 3) { float s; // Get left animation panim = StudioGetAnim(m_pRenderModel, pseqdesc); if(prevseqblending <= 127) { // Set up bones based on final frame of previous sequence StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); s = prevseqblending; s = (s * 2.0); } else { // Skip to middle blend panim += m_pStudioHeader->numbones; StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); s = prevseqblending; s = 2.0 * (s - 127.0); } // Normalize s /= 255.0; panim += m_pStudioHeader->numbones; StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); // Interpolate bones StudioSlerpBones(q1b, pos1b, q2, pos2, s); } else { panim = StudioGetAnim(m_pRenderModel, pseqdesc); // clip prevframe StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } // Now blend last frame of previous sequence with current sequence. s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; StudioSlerpBones(q, pos, q1b, pos1b, s); } else { m_pCurrentEntity->latched.prevframe = f; } // Now convert quaternions and bone positions into matrices pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); for(i = 0; i < m_pStudioHeader->numbones; i++) { QuaternionMatrix(q[i], bonematrix); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if(pbones[i].parent == -1) { if(IEngineStudio.IsHardware()) { ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } else { ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } // Apply client-side effects to the transformation matrix StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]); } else { ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } }
void CGameStudioModelRenderer::StudioSetupBones(void) { int i; double f; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; float bonematrix[3][4]; static float pos2[MAXSTUDIOBONES][3]; static vec4_t q2[MAXSTUDIOBONES]; static float pos3[MAXSTUDIOBONES][3]; static vec4_t q3[MAXSTUDIOBONES]; static float pos4[MAXSTUDIOBONES][3]; static vec4_t q4[MAXSTUDIOBONES]; if (!m_pCurrentEntity->player) { CStudioModelRenderer::StudioSetupBones(); return; } if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) m_pCurrentEntity->curstate.sequence = 0; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; panim = StudioGetAnim(m_pRenderModel, pseqdesc); f = StudioEstimateFrame(pseqdesc); if (m_pPlayerInfo->gaitsequence == ANIM_WALK_SEQUENCE) { if (m_pCurrentEntity->curstate.blending[0] <= 26) { m_pCurrentEntity->curstate.blending[0] = 0; m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; } else { m_pCurrentEntity->curstate.blending[0] -= 26; m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; } } if (pseqdesc->numblends == 9) { float s = m_pCurrentEntity->curstate.blending[0]; float t = m_pCurrentEntity->curstate.blending[1]; if (s <= 127.0) { s = (s * 2.0); if (t <= 127.0) { t = (t * 2.0); StudioCalcRotations(pos, q, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 1); StudioCalcRotations(pos2, q2, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 3); StudioCalcRotations(pos3, q3, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos4, q4, pseqdesc, panim, f); } else { t = 2.0 * (t - 127.0); panim = LookupAnimation(pseqdesc, 3); StudioCalcRotations(pos, q, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos2, q2, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 6); StudioCalcRotations(pos3, q3, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 7); StudioCalcRotations(pos4, q4, pseqdesc, panim, f); } } else { s = 2.0 * (s - 127.0); if (t <= 127.0) { t = (t * 2.0); panim = LookupAnimation(pseqdesc, 1); StudioCalcRotations(pos, q, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 2); StudioCalcRotations(pos2, q2, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos3, q3, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 5); StudioCalcRotations(pos4, q4, pseqdesc, panim, f); } else { t = 2.0 * (t - 127.0); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos, q, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 5); StudioCalcRotations(pos2, q2, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 7); StudioCalcRotations(pos3, q3, pseqdesc, panim, f); panim = LookupAnimation(pseqdesc, 8); StudioCalcRotations(pos4, q4, pseqdesc, panim, f); } } s /= 255.0; t /= 255.0; StudioSlerpBones(q, pos, q2, pos2, s); StudioSlerpBones(q3, pos3, q4, pos4, s); StudioSlerpBones(q, pos, q3, pos3, t); } else { StudioCalcRotations(pos, q, pseqdesc, panim, f); } if (m_fDoInterp && m_pCurrentEntity->latched.sequencetime && (m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime) && (m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq)) { static float pos1b[MAXSTUDIOBONES][3]; static vec4_t q1b[MAXSTUDIOBONES]; float s = m_pCurrentEntity->latched.prevseqblending[0]; float t = m_pCurrentEntity->latched.prevseqblending[1]; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; panim = StudioGetAnim(m_pRenderModel, pseqdesc); if (pseqdesc->numblends == 9) { if (s <= 127.0) { s = (s * 2.0); if (t <= 127.0) { t = (t * 2.0); StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 1); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 3); StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } else { t = 2.0 * (t - 127.0); panim = LookupAnimation(pseqdesc, 3); StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 6); StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 7); StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } } else { s = 2.0 * (s - 127.0); if (t <= 127.0) { t = (t * 2.0); panim = LookupAnimation(pseqdesc, 1); StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 2); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 5); StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } else { t = 2.0 * (t - 127.0); panim = LookupAnimation(pseqdesc, 4); StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 5); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 7); StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim = LookupAnimation(pseqdesc, 8); StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } } s /= 255.0; t /= 255.0; StudioSlerpBones(q1b, pos1b, q2, pos2, s); StudioSlerpBones(q3, pos3, q4, pos4, s); StudioSlerpBones(q1b, pos1b, q3, pos3, t); } else { StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); } s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; StudioSlerpBones(q, pos, q1b, pos1b, s); } else { m_pCurrentEntity->latched.prevframe = f; } pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); if (m_pPlayerInfo && (m_pCurrentEntity->curstate.sequence < ANIM_FIRST_DEATH_SEQUENCE || m_pCurrentEntity->curstate.sequence > ANIM_LAST_DEATH_SEQUENCE) && (m_pCurrentEntity->curstate.sequence < ANIM_FIRST_EMOTION_SEQUENCE || m_pCurrentEntity->curstate.sequence > ANIM_LAST_EMOTION_SEQUENCE) && m_pCurrentEntity->curstate.sequence != ANIM_SWIM_1 && m_pCurrentEntity->curstate.sequence != ANIM_SWIM_2) { int copy = 1; if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) m_pPlayerInfo->gaitsequence = 0; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pPlayerInfo->gaitsequence; panim = StudioGetAnim(m_pRenderModel, pseqdesc); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe); for (i = 0; i < m_pStudioHeader->numbones; i++) { if (!strcmp(pbones[i].name, "Bip01 Spine")) copy = 0; else if (!strcmp(pbones[pbones[i].parent].name, "Bip01 Pelvis")) copy = 1; if (copy) { memcpy(pos[i], pos2[i], sizeof(pos[i])); memcpy(q[i], q2[i], sizeof(q[i])); } } } for (i = 0; i < m_pStudioHeader->numbones; i++) { QuaternionMatrix(q[i], bonematrix); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { if (IEngineStudio.IsHardware()) { ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); MatrixCopy((*m_pbonetransform)[i], (*m_plighttransform)[i]); } else { ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]); } else { ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } }
void C_GStringPlayerRagdoll::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion *q, const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed ) { if ( !hdr ) return; matrix3x4_t bonematrix; bool boneSimulated[MAXSTUDIOBONES]; // no bones have been simulated memset( boneSimulated, 0, sizeof(boneSimulated) ); mstudiobone_t *pbones = hdr->pBone( 0 ); if ( m_pRagdoll ) { // simulate bones and update flags int oldWritableBones = m_BoneAccessor.GetWritableBones(); int oldReadableBones = m_BoneAccessor.GetReadableBones(); m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); #if defined( REPLAY_ENABLED ) // If we're playing back a demo, override the ragdoll bones with cached version if available - otherwise, simulate. if ( ( !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() ) || !CReplayRagdollCache::Instance().IsInitialized() || !CReplayRagdollCache::Instance().GetFrame( this, engine->GetDemoPlaybackTick(), boneSimulated, &m_BoneAccessor ) ) #endif { m_pRagdoll->RagdollBone( this, pbones, hdr->numbones(), boneSimulated, m_BoneAccessor ); } m_BoneAccessor.SetWritableBones( oldWritableBones ); m_BoneAccessor.SetReadableBones( oldReadableBones ); } // For EF_BONEMERGE entities, copy the bone matrices for any bones that have matching names. bool boneMerge = IsEffectActive(EF_BONEMERGE); if ( boneMerge || m_pBoneMergeCache ) { if ( boneMerge ) { if ( !m_pBoneMergeCache ) { m_pBoneMergeCache = new CBoneMergeCache; m_pBoneMergeCache->Init( this ); } m_pBoneMergeCache->MergeMatchingBones( boneMask ); } else { delete m_pBoneMergeCache; m_pBoneMergeCache = NULL; } } for (int i = 0; i < hdr->numbones(); i++) { if ( i == m_iBoneHead ) { MatrixScaleBy( 0.01f, GetBoneForWrite( i ) ); } // Only update bones reference by the bone mask. if ( !( hdr->boneFlags( i ) & boneMask ) ) { continue; } if ( m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged( i ) ) continue; // animate all non-simulated bones if ( boneSimulated[i] || CalcProceduralBone( hdr, i, m_BoneAccessor )) { continue; } // skip bones that the IK has already setup else if (boneComputed.IsBoneMarked( i )) { // dummy operation, just used to verify in debug that this should have happened GetBoneForWrite( i ); } else { QuaternionMatrix( q[i], pos[i], bonematrix ); Assert( fabs( pos[i].x ) < 100000 ); Assert( fabs( pos[i].y ) < 100000 ); Assert( fabs( pos[i].z ) < 100000 ); if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) && (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) ) { // // Physics-based "jiggle" bone // Bone is assumed to be along the Z axis // Pitch around X, yaw around Y // // compute desired bone orientation matrix3x4_t goalMX; if (pbones[i].parent == -1) { ConcatTransforms( cameraTransform, bonematrix, goalMX ); } else { ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, goalMX ); } // get jiggle properties from QC data mstudiojigglebone_t *jiggleInfo = (mstudiojigglebone_t *)pbones[i].pProcedure( ); if (!m_pJiggleBones) { m_pJiggleBones = new CJiggleBones; } // do jiggle physics m_pJiggleBones->BuildJiggleTransformations( i, gpGlobals->realtime, jiggleInfo, goalMX, GetBoneForWrite( i ) ); } else if (hdr->boneParent(i) == -1) { ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) ); } else { ConcatTransforms( GetBone( hdr->boneParent(i) ), bonematrix, GetBoneForWrite( i ) ); } } } }
/* <836d8> ../engine/r_studio.c:696 */ void EXT_FUNC SV_StudioSetupBones(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const unsigned char *pcontroller, const unsigned char *pblending, int iBone, const edict_t *edict) { static vec4_t q1[128]; static vec3_t pos1[128]; static vec4_t q2[128]; static vec3_t pos2[128]; int chainlength; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; int chain[128]; float bonematrix[3][4]; mstudioanim_t *panim; float f; float adj[8]; float s; chainlength = 0; if (sequence < 0 || sequence >= pstudiohdr->numseq) { Con_DPrintf("SV_StudioSetupBones: sequence %i/%i out of range for model %s\n", sequence, pstudiohdr->numseq, pstudiohdr->name); sequence = 0; } pbones = (mstudiobone_t *)((char *)pstudiohdr + pstudiohdr->boneindex); pseqdesc = (mstudioseqdesc_t *)((char *)pstudiohdr + pstudiohdr->seqindex); pseqdesc += sequence; panim = R_GetAnim(pModel, pseqdesc); if (iBone < -1 || iBone >= pstudiohdr->numbones) iBone = 0; if (iBone != -1) { do { chain[chainlength++] = iBone; iBone = pbones[iBone].parent; } while (iBone != -1); } else { chainlength = pstudiohdr->numbones; for (int i = 0; i < pstudiohdr->numbones; i++) { chain[pstudiohdr->numbones - 1 - i] = i; } } f = (pseqdesc->numframes > 1) ? (pseqdesc->numframes - 1) * frame / 256.0f : 0.0f; R_StudioCalcBoneAdj(0.0, adj, pcontroller, pcontroller, 0); s = f - (float)(int)f; for (int i = chainlength - 1; i >= 0; i--) { int bone = chain[i]; R_StudioCalcBoneQuaterion((int)f, s, &pbones[bone], &panim[bone], adj, q1[bone]); R_StudioCalcBonePosition((int)f, s, &pbones[bone], &panim[bone], adj, pos1[bone]); } if (pseqdesc->numblends > 1) { panim = R_GetAnim(pModel, pseqdesc); panim += pstudiohdr->numbones; for (int i = chainlength - 1; i >= 0; i--) { int bone = chain[i]; R_StudioCalcBoneQuaterion((int)f, s, &pbones[bone], &panim[bone], adj, q2[bone]); R_StudioCalcBonePosition((int)f, s, &pbones[bone], &panim[bone], adj, pos2[bone]); } R_StudioSlerpBones(q1, pos1, q2, pos2, *pblending / 255.0f); } AngleMatrix(angles, rotationmatrix); rotationmatrix[0][3] = origin[0]; rotationmatrix[1][3] = origin[1]; rotationmatrix[2][3] = origin[2]; for (int i = chainlength - 1; i >= 0; i--) { int bone = chain[i]; int parent = pbones[bone].parent; QuaternionMatrix(q1[bone], bonematrix); bonematrix[0][3] = pos1[bone][0]; bonematrix[1][3] = pos1[bone][1]; bonematrix[2][3] = pos1[bone][2]; R_ConcatTransforms((parent == -1) ? rotationmatrix : bonetransform[parent], bonematrix, bonetransform[bone]); } }
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 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] ); } } }
//----------------------------------------------------------------------------- // 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; }