/* ============== R_CalcBone ============== */ void R_CalcBone(mdsHeader_t *header, const refEntity_t *refent, int boneNum) { thisBoneInfo = &boneInfo[boneNum]; if (thisBoneInfo->torsoWeight) { cTBonePtr = &cBoneListTorso[boneNum]; isTorso = qtrue; if (thisBoneInfo->torsoWeight == 1.0f) { fullTorso = qtrue; } } else { isTorso = qfalse; fullTorso = qfalse; } cBonePtr = &cBoneList[boneNum]; bonePtr = &bones[boneNum]; // we can assume the parent has already been uncompressed for this frame + lerp if (thisBoneInfo->parent >= 0) { parentBone = &bones[thisBoneInfo->parent]; parentBoneInfo = &boneInfo[thisBoneInfo->parent]; } else { parentBone = NULL; parentBoneInfo = NULL; } #ifdef HIGH_PRECISION_BONES // rotation if (fullTorso) { VectorCopy(cTBonePtr->angles, angles); } else { VectorCopy(cBonePtr->angles, angles); if (isTorso) { VectorCopy(cTBonePtr->angles, tangles); // blend the angles together for (j = 0; j < 3; j++) { diff = tangles[j] - angles[j]; if (Q_fabs(diff) > 180) { diff = AngleNormalize180(diff); } angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff; } } } #else // rotation if (fullTorso) { sh = (short *)cTBonePtr->angles; pf = angles; ANGLES_SHORT_TO_FLOAT(pf, sh); } else { sh = (short *)cBonePtr->angles; pf = angles; ANGLES_SHORT_TO_FLOAT(pf, sh); if (isTorso) { int j; sh = (short *)cTBonePtr->angles; pf = tangles; ANGLES_SHORT_TO_FLOAT(pf, sh); // blend the angles together for (j = 0; j < 3; j++) { diff = tangles[j] - angles[j]; if (Q_fabs(diff) > 180) { diff = AngleNormalize180(diff); } angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff; } } } #endif AnglesToAxis(angles, bonePtr->matrix); // translation if (parentBone) { #ifdef HIGH_PRECISION_BONES if (fullTorso) { angles[0] = cTBonePtr->ofsAngles[0]; angles[1] = cTBonePtr->ofsAngles[1]; angles[2] = 0; LocalAngleVector(angles, vec); LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } else { angles[0] = cBonePtr->ofsAngles[0]; angles[1] = cBonePtr->ofsAngles[1]; angles[2] = 0; LocalAngleVector(angles, vec); if (isTorso) { tangles[0] = cTBonePtr->ofsAngles[0]; tangles[1] = cTBonePtr->ofsAngles[1]; tangles[2] = 0; LocalAngleVector(tangles, v2); // blend the angles together SLerp_Normal(vec, v2, thisBoneInfo->torsoWeight, vec); LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } else // legs bone { LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } } #else if (fullTorso) { sh = (short *)cTBonePtr->ofsAngles; pf = angles; *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0; LocalAngleVector(angles, vec); LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } else { sh = (short *)cBonePtr->ofsAngles; pf = angles; *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0; LocalAngleVector(angles, vec); if (isTorso) { sh = (short *)cTBonePtr->ofsAngles; pf = tangles; *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0; LocalAngleVector(tangles, v2); // blend the angles together SLerp_Normal(vec, v2, thisBoneInfo->torsoWeight, vec); LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } else // legs bone { LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation); } } #endif } else // just use the frame position { bonePtr->translation[0] = frame->parentOffset[0]; bonePtr->translation[1] = frame->parentOffset[1]; bonePtr->translation[2] = frame->parentOffset[2]; } if (boneNum == header->torsoParent) // this is the torsoParent { VectorCopy(bonePtr->translation, torsoParentOffset); } validBones[boneNum] = 1; rawBones[boneNum] = *bonePtr; newBones[boneNum] = 1; }
/* ============== R_CalcBoneLerp ============== */ void R_CalcBoneLerp(mdsHeader_t *header, const refEntity_t *refent, int boneNum) { if (!refent || !header || boneNum < 0 || boneNum >= MDS_MAX_BONES) { return; } thisBoneInfo = &boneInfo[boneNum]; if (!thisBoneInfo) { return; } if (thisBoneInfo->parent >= 0) { parentBone = &bones[thisBoneInfo->parent]; parentBoneInfo = &boneInfo[thisBoneInfo->parent]; } else { parentBone = NULL; parentBoneInfo = NULL; } if (thisBoneInfo->torsoWeight) { cTBonePtr = &cBoneListTorso[boneNum]; cOldTBonePtr = &cOldBoneListTorso[boneNum]; isTorso = qtrue; if (thisBoneInfo->torsoWeight == 1.0f) { fullTorso = qtrue; } } else { isTorso = qfalse; fullTorso = qfalse; } cBonePtr = &cBoneList[boneNum]; cOldBonePtr = &cOldBoneList[boneNum]; bonePtr = &bones[boneNum]; newBones[boneNum] = 1; // rotation (take into account 170 to -170 lerps, which need to take the shortest route) if (fullTorso) { sh = (short *)cTBonePtr->angles; sh2 = (short *)cOldTBonePtr->angles; pf = angles; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; } else { sh = (short *)cBonePtr->angles; sh2 = (short *)cOldBonePtr->angles; pf = angles; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - backlerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - backlerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - backlerp * diff; if (isTorso) { int j; sh = (short *)cTBonePtr->angles; sh2 = (short *)cOldTBonePtr->angles; pf = tangles; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; a1 = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2); *(pf++) = a1 - torsoBacklerp * diff; // blend the angles together for (j = 0; j < 3; j++) { diff = tangles[j] - angles[j]; if (Q_fabs(diff) > 180) { diff = AngleNormalize180(diff); } angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff; } } } AnglesToAxis(angles, bonePtr->matrix); if (parentBone) { if (fullTorso) { sh = (short *)cTBonePtr->ofsAngles; sh2 = (short *)cOldTBonePtr->ofsAngles; } else { sh = (short *)cBonePtr->ofsAngles; sh2 = (short *)cOldBonePtr->ofsAngles; } pf = angles; *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0; LocalAngleVector(angles, v2); // new pf = angles; *(pf++) = SHORT2ANGLE(*(sh2++)); *(pf++) = SHORT2ANGLE(*(sh2++)); *(pf++) = 0; LocalAngleVector(angles, vec); // old // blend the angles together if (fullTorso) { SLerp_Normal(vec, v2, torsoFrontlerp, dir); } else { SLerp_Normal(vec, v2, frontlerp, dir); } // translation if (!fullTorso && isTorso) // partial legs/torso, need to lerp according to torsoWeight { // calc the torso frame sh = (short *)cTBonePtr->ofsAngles; sh2 = (short *)cOldTBonePtr->ofsAngles; pf = angles; *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0; LocalAngleVector(angles, v2); // new pf = angles; *(pf++) = SHORT2ANGLE(*(sh2++)); *(pf++) = SHORT2ANGLE(*(sh2++)); *(pf++) = 0; LocalAngleVector(angles, vec); // old // blend the angles together SLerp_Normal(vec, v2, torsoFrontlerp, v2); // blend the torso/legs together SLerp_Normal(dir, v2, thisBoneInfo->torsoWeight, dir); } LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, dir, bonePtr->translation); } else // just interpolate the frame positions { bonePtr->translation[0] = frontlerp * frame->parentOffset[0] + backlerp * oldFrame->parentOffset[0]; bonePtr->translation[1] = frontlerp * frame->parentOffset[1] + backlerp * oldFrame->parentOffset[1]; bonePtr->translation[2] = frontlerp * frame->parentOffset[2] + backlerp * oldFrame->parentOffset[2]; } if (boneNum == header->torsoParent) // this is the torsoParent { VectorCopy(bonePtr->translation, torsoParentOffset); } validBones[boneNum] = 1; rawBones[boneNum] = *bonePtr; newBones[boneNum] = 1; }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones( mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones, int renderend ) { int i, j; int *boneRefs; float torsoWeight; mdsBoneFrame_t *bones, *bonePtr, *parentBone; mdsFrame_t *frame, *torsoFrame; mdsBoneInfo_t *boneInfo, *thisBoneInfo, *parentBoneInfo; mdsBoneFrameCompressed_t *cBonePtr, *cTBonePtr, *cBoneList, *cBoneListTorso; vec3_t t, torsoAxis[3], tmpAxis[3]; vec3_t torsoParentOffset = {0}; vec4_t m1[4]; vec4_t m2[4] = {{0}, {0}, {0}, {0}}; int frameSize; bones = smpbones[renderend]; frameSize = (int) ( sizeof( mdsFrame_t ) + ( header->numBones - 1 ) * sizeof( mdsBoneFrameCompressed_t ) ); frame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames + refent->frame * frameSize ); torsoFrame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames + refent->torsoFrame * frameSize ); boneInfo = ( mdsBoneInfo_t * )( (byte *)header + header->ofsBones ); boneRefs = boneList; Matrix3Transpose( refent->torsoAxis, torsoAxis ); cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; for ( i = 0; i < numBones; i++, boneRefs++ ) { // R_CalcBone( header, refent, *boneRefs ); int boneNum; short *sh; float *pf, diff; vec3_t tangles, angles, vec, v2; qboolean isTorso, fullTorso; fullTorso = qfalse; boneNum = *boneRefs; thisBoneInfo = &boneInfo[boneNum]; if ( thisBoneInfo->torsoWeight ) { isTorso = qtrue; if ( thisBoneInfo->torsoWeight == 1.0f ) { fullTorso = qtrue; } } else { isTorso = qfalse; } cTBonePtr = &cBoneListTorso[boneNum]; cBonePtr = &cBoneList[boneNum]; bonePtr = &bones[ boneNum ]; // we can assume the parent has already been uncompressed for this frame + lerp if ( thisBoneInfo->parent >= 0 ) { parentBone = &bones[ thisBoneInfo->parent ]; parentBoneInfo = &boneInfo[ thisBoneInfo->parent ]; } else { parentBone = NULL; parentBoneInfo = NULL; } // rotation if ( fullTorso ) { sh = (short *)cTBonePtr->angles; pf = angles; ANGLES_SHORT_TO_FLOAT( pf, sh ); } else { sh = (short *)cBonePtr->angles; pf = angles; ANGLES_SHORT_TO_FLOAT( pf, sh ); if ( isTorso ) { sh = (short *)cTBonePtr->angles; pf = tangles; ANGLES_SHORT_TO_FLOAT( pf, sh ); // blend the angles together for ( j = 0; j < 3; j++ ) { diff = tangles[j] - angles[j]; if ( fabs( diff ) > 180 ) { diff = AngleNormalize180( diff ); } angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff; } } } AnglesToAxis( angles, bonePtr->matrix ); // translation if ( parentBone ) { if ( fullTorso ) { sh = (short *)cTBonePtr->ofsAngles; pf = angles; *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0; LocalAngleVector( angles, vec ); } else { sh = (short *)cBonePtr->ofsAngles; pf = angles; *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0; LocalAngleVector( angles, vec ); if ( isTorso ) { sh = (short *)cTBonePtr->ofsAngles; pf = tangles; *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0; LocalAngleVector( tangles, v2 ); // blend the angles together SLerp_Normal( vec, v2, thisBoneInfo->torsoWeight, vec ); } } LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation ); } else { // just use the frame position bonePtr->translation[0] = frame->parentOffset[0]; bonePtr->translation[1] = frame->parentOffset[1]; bonePtr->translation[2] = frame->parentOffset[2]; } if ( boneNum == header->torsoParent ) { VectorCopy( bonePtr->translation, torsoParentOffset ); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for ( i = 0; i < numBones; i++, boneRefs++ ) { thisBoneInfo = &boneInfo[ *boneRefs ]; bonePtr = &bones[ *boneRefs ]; // add torso rotation if ( thisBoneInfo->torsoWeight > 0 ) { if ( !( thisBoneInfo->flags & BONEFLAG_TAG ) ) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract( bonePtr->translation, torsoParentOffset, t ); Matrix4FromAxisPlusTranslation( bonePtr->matrix, t, m1 ); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if ( torsoWeight != thisBoneInfo->torsoWeight ) { Matrix4FromScaledAxisPlusTranslation( torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2 ); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation( m2, m1, bonePtr->matrix, bonePtr->translation ); } else { // tag's require special handling // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector( bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0] ); LocalScaledMatrixTransformVector( bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1] ); LocalScaledMatrixTransformVector( bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2] ); memcpy( bonePtr->matrix, tmpAxis, sizeof( tmpAxis ) ); // rotate the translation around the torsoParent VectorSubtract( bonePtr->translation, torsoParentOffset, t ); LocalScaledMatrixTransformVector( t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation ); VectorAdd( bonePtr->translation, torsoParentOffset, bonePtr->translation ); } } } }