/* =========================================================================== Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // skeletorbones.cpp : Skeletor bones #include "q_shared.h" #include "qcommon.h" #include "skeletor.h" char *skelBone_Names[8]; ChannelNameTable skeletor_c::m_channelNames; ChannelNameTable skeletor_c::m_boneNames; skelBone_World skeletor_c::m_worldBone; skelBone_World::skelBone_World() { m_isDirty = false; } void SkeletorLoadBoneFromBuffer(skelChannelList_c *boneList, boneData_t *boneData, skelBone_Base **bone) { int newBoneIndex; const char *boneName; int newBoneParent; skelBone_Base *parentBone; newBoneIndex = boneList->GetLocalFromGlobal(boneData->channel); if (!bone[newBoneIndex]) { boneName = skeletor_c::m_boneNames.FindName(boneData->channel); if (boneData->parent < 0) { newBoneParent = -1; } else { newBoneParent = boneList->GetLocalFromGlobal(boneData->parent); } switch (boneData->boneType) { case SKELBONE_ZERO: { skelBone_Zero *newBone = new skelBone_Zero; bone[newBoneIndex] = newBone; break; } case SKELBONE_ROTATION: { skelBone_Rotation *newBone = new skelBone_Rotation; bone[newBoneIndex] = newBone; newBone->SetChannels(boneData->channelIndex[0]); break; } case SKELBONE_POSROT: { skelBone_PosRot *newBone; if (!strncmp(boneName, "Bip01", 5)) { newBone = new skelBone_Root; bone[newBoneIndex] = newBone; } else { newBone = new skelBone_PosRot; bone[newBoneIndex] = newBone; } newBone->SetChannels(boneData->channelIndex[0], boneData->channelIndex[1]); break; } case SKELBONE_IKSHOULDER: { skelBone_IKshoulder *newBone = new skelBone_IKshoulder; bone[newBoneIndex] = newBone; break; } case SKELBONE_IKELBOW: { skelBone_IKelbow *newBone = new skelBone_IKelbow; bone[newBoneIndex] = newBone; newBone->SetBoneRefs((skelBone_IKshoulder *)bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]); break; } case SKELBONE_IKWRIST: { skelBone_IKwrist *newBone = new skelBone_IKwrist; skelBone_IKshoulder *shoulder; bone[newBoneIndex] = newBone; shoulder = (skelBone_IKshoulder *)bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]; newBone->SetChannels(boneData->channelIndex[0], boneData->channelIndex[1]); newBone->SetBoneRefs(shoulder); shoulder->SetWristBone(newBone); break; } case SKELBONE_AVROT: { skelBone_AvRot *newBone = new skelBone_AvRot; skelBone_AvRot *ref1, *ref2; bone[newBoneIndex] = newBone; ref1 = (skelBone_AvRot *)bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]; ref2 = (skelBone_AvRot *)bone[boneList->GetLocalFromGlobal(boneData->refIndex[1])]; newBone->SetBoneRefs(ref1, ref2); break; } case SKELBONE_HOSEROT: { skelBone_HoseRot *newBone = new skelBone_HoseRot; bone[newBoneIndex] = newBone; newBone->SetBoneRefs(bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]); break; } case SKELBONE_HOSEROTBOTH: { skelBone_HoseRotBoth *newBone = new skelBone_HoseRotBoth; bone[newBoneIndex] = newBone; newBone->SetBoneRefs(bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]); break; } case SKELBONE_HOSEROTPARENT: { skelBone_HoseRotParent *newBone = new skelBone_HoseRotParent; bone[newBoneIndex] = newBone; newBone->SetBoneRefs(bone[boneList->GetLocalFromGlobal(boneData->refIndex[0])]); break; } default: break; } bone[newBoneIndex]->SetBaseValue(boneData); if (newBoneParent < 0) { parentBone = &skeletor_c::m_worldBone; } else { parentBone = bone[newBoneParent]; } bone[newBoneIndex]->SetParent(parentBone); } } void SkeletorLoadBonesFromBuffer(skelChannelList_c *boneList, skelHeaderGame_t *buffer, skelBone_Base **bone) { int boneNum; for (boneNum = 0; boneNum < buffer->numBones; boneNum++) { SkeletorLoadBoneFromBuffer(boneList, &buffer->pBones[boneNum], bone); } } float *DecodeRLEPosValue(skanChannelHdr *channelFrames, int desiredFrameNum) { skanGameFrame *foundFrame = channelFrames->ary_frames; size_t frameSize; int i; frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); for (i = 0; i < channelFrames->nFramesInChannel; i++) { if (foundFrame->nFrameNum >= desiredFrameNum) { break; } foundFrame = (skanGameFrame *)((byte *)foundFrame + frameSize); } if (foundFrame->nFrameNum > desiredFrameNum) { foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); } return foundFrame->pChannelData; } float *DecodeRLERotValue(skanChannelHdr *channelFrames, int desiredFrameNum) { skanGameFrame *foundFrame = channelFrames->ary_frames; size_t frameSize; int i; frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); for (i = 0; i < channelFrames->nFramesInChannel; i++) { if (foundFrame->nFrameNum >= desiredFrameNum) { break; } foundFrame = (skanGameFrame *)((byte *)foundFrame + frameSize); } if (foundFrame->nFrameNum > desiredFrameNum) { foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); } return foundFrame->pChannelData; } SkelQuat skelAnimStoreFrameList_c::GetSlerpValue(int globalChannelNum) const { SkelQuat actionQuat, movementQuat; SkelQuat outQuat; float totalWeight; SkelQuat *pIncomingQuat; float incomingWeight; int localChannelNum; float channelActionWeight; //float movementWeight; int nTotal; int i; const skanBlendInfo *pFrame; float t; actionQuat.Set(0, 0, 0, 0); movementQuat.Set(0, 0, 0, 0); nTotal = 0; totalWeight = 0.0; if (actionWeight > 0.001) { for (i = 0; i < numActionFrames; i++) { pFrame = &m_blendInfo[i + MAX_SKEL_BLEND_MOVEMENT_FRAMES]; localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; if (incomingWeight == 0.0) { continue; } pIncomingQuat = (SkelQuat *)DecodeRLERotValue( &pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame ); totalWeight += incomingWeight; nTotal++; if (DotProduct4(*pIncomingQuat, actionQuat) >= 0.0) { actionQuat.x += pIncomingQuat->x * incomingWeight; actionQuat.y += pIncomingQuat->y * incomingWeight; actionQuat.z += pIncomingQuat->z * incomingWeight; actionQuat.w += pIncomingQuat->w * incomingWeight; } else { actionQuat.x -= pIncomingQuat->x * incomingWeight; actionQuat.y -= pIncomingQuat->y * incomingWeight; actionQuat.z -= pIncomingQuat->z * incomingWeight; actionQuat.w -= pIncomingQuat->w * incomingWeight; } } } } if (nTotal) { channelActionWeight = actionWeight; if (nTotal > 1) { t = 1.0 / actionQuat.Length(); } else { t = 1.0 / totalWeight; } actionQuat.x = actionQuat.x * t; actionQuat.y = actionQuat.y * t; actionQuat.z = actionQuat.z * t; actionQuat.w = actionQuat.w * t; } else { channelActionWeight = 0.0; } nTotal = 0; totalWeight = 0.0; if (channelActionWeight < 0.999) { for (i = 0; i < numMovementFrames; i++) { pFrame = &m_blendInfo[i]; localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; if (incomingWeight == 0.0) { continue; } pIncomingQuat = (SkelQuat *)DecodeRLERotValue( &pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame ); totalWeight += incomingWeight; nTotal++; if (DotProduct4(*pIncomingQuat, movementQuat) >= 0.0) { movementQuat.x += pIncomingQuat->x * incomingWeight; movementQuat.y += pIncomingQuat->y * incomingWeight; movementQuat.z += pIncomingQuat->z * incomingWeight; movementQuat.w += pIncomingQuat->w * incomingWeight; } else { movementQuat.x -= pIncomingQuat->x * incomingWeight; movementQuat.y -= pIncomingQuat->y * incomingWeight; movementQuat.z -= pIncomingQuat->z * incomingWeight; movementQuat.w -= pIncomingQuat->w * incomingWeight; } } } } if (nTotal) { if (nTotal > 1) { t = 1.0 / movementQuat.Length(); } else { t = 1.0 / totalWeight; } movementQuat.x = movementQuat.x * t; movementQuat.y = movementQuat.y * t; movementQuat.z = movementQuat.z * t; movementQuat.w = movementQuat.w * t; } else { movementQuat.w = 1.0; } if (channelActionWeight < 0.001) { outQuat.x = movementQuat.x; outQuat.y = movementQuat.y; outQuat.z = movementQuat.z; outQuat.w = movementQuat.w; return outQuat; } else if (channelActionWeight >= 0.999) { outQuat.x = actionQuat.x; outQuat.y = actionQuat.y; outQuat.z = actionQuat.z; outQuat.w = actionQuat.w; return outQuat; } t = 1.0 - channelActionWeight; if (DotProduct4(actionQuat, movementQuat) >= 0.0) { outQuat.x = movementQuat.x * t + actionQuat.x * channelActionWeight; outQuat.y = movementQuat.y * t + actionQuat.y * channelActionWeight; outQuat.z = movementQuat.z * t + actionQuat.z * channelActionWeight; outQuat.w = movementQuat.w * t + actionQuat.w * channelActionWeight; } else { outQuat.x = movementQuat.x * t - actionQuat.x * channelActionWeight; outQuat.y = movementQuat.y * t - actionQuat.y * channelActionWeight; outQuat.z = movementQuat.z * t - actionQuat.z * channelActionWeight; outQuat.w = movementQuat.w * t - actionQuat.w * channelActionWeight; } t = 1.0 / outQuat.Length(); outQuat.x = outQuat.x * t; outQuat.y = outQuat.y * t; outQuat.z = outQuat.z * t; outQuat.w = outQuat.w * t; return outQuat; } void skelAnimStoreFrameList_c::GetLerpValue3(int globalChannelNum, SkelVec3 *outVec) const { float totalWeight; SkelVec3 incomingVec; float incomingWeight; int localChannelNum; vec3_t result; float t; float channelActionWeight; int i; const skanBlendInfo *pFrame; totalWeight = 0.0; if (actionWeight > 0.001) { VectorClear(result); for (i = 0; i < numActionFrames; i++) { pFrame = &m_blendInfo[i + MAX_SKEL_BLEND_MOVEMENT_FRAMES]; localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; incomingVec = DecodeRLEPosValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); totalWeight += incomingWeight; result[0] += incomingVec[0] * incomingWeight; result[1] += incomingVec[1] * incomingWeight; result[2] += incomingVec[2] * incomingWeight; } } } if (totalWeight != 0.0) { t = 1.0 / totalWeight; VectorScale(result, t, *outVec); channelActionWeight = actionWeight; } else { VectorClear(*outVec); channelActionWeight = 0.0; } if (channelActionWeight >= 0.999 || !numMovementFrames) { return; } totalWeight = 0.0; VectorClear(result); for (i = 0; i < numMovementFrames; i++) { pFrame = &m_blendInfo[i]; localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; incomingVec = DecodeRLEPosValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); totalWeight += incomingWeight; result[0] += incomingVec[0] * incomingWeight; result[1] += incomingVec[1] * incomingWeight; result[2] += incomingVec[2] * incomingWeight; } } if (totalWeight != 0.0) { t = 1.0 / totalWeight * (1.0 - channelActionWeight); outVec->x = outVec->x * channelActionWeight + result[0] * t; outVec->y = outVec->y * channelActionWeight + result[1] * t; outVec->z = outVec->z * channelActionWeight + result[2] * t; } } skelBone_Base::skelBone_Base() { m_parent = NULL; m_isDirty = true; m_controller = NULL; } skelBone_Base::~skelBone_Base() {} int skelBone_Base::GetNumChannels(boneType_t boneType) { switch (boneType) { case SKELBONE_ROTATION: return 1; case SKELBONE_POSROT: case SKELBONE_IKWRIST: return 2; default: return 0; } } int skelBone_Base::GetNumBoneRefs(boneType_t boneType) { switch (boneType) { case SKELBONE_AVROT: return 2; case SKELBONE_IKELBOW: case SKELBONE_IKWRIST: case SKELBONE_HOSEROT: case SKELBONE_HOSEROTBOTH: case SKELBONE_HOSEROTPARENT: return 1; default: return 0; } } SkelMat4& skelBone_Base::GetTransform(const skelAnimStoreFrameList_c *frames) { if (m_isDirty) { return GetDirtyTransform(frames); } else { return m_cachedValue; } } void skelBone_Base::SetParent(skelBone_Base *parent) { m_parent = parent; } void skelBone_Base::SetBaseValue(boneData_t *boneData) {} int skelBone_Base::GetChannelIndex(int num) { return 0; } skelBone_Base *skelBone_Base::GetBoneRef(int num) { return NULL; } skelBone_Base *skelBone_Base::Parent() const { return m_parent; } SkelMat4& skelBone_Zero::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { if (m_parent) { m_cachedValue = m_parent->GetTransform(frames); } m_isDirty = false; return m_cachedValue; } void skelBone_Zero::SetBaseValue(boneData_t *boneData) {} int skelBone_Zero::GetChannelIndex(int num) { return 0; } skelBone_Base *skelBone_Zero::GetBoneRef(int num) { return NULL; } SkelMat4& skelBone_Rotation::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelMat4 incomingValue; SkelQuat incomingQuat; incomingQuat = frames->GetSlerpValue(m_quatChannel); incomingQuat.GetMat4(incomingValue); VectorCopy(m_baseValue, incomingValue[3]); if (m_parent) { m_cachedValue.Multiply(incomingValue, m_parent->GetTransform(frames)); } else { m_cachedValue = incomingValue; } if (m_controller) { SkelMat3 m; incomingQuat.Set(m_controller); incomingQuat.GetMat3(m); m_cachedValue.RotateBy(m); } m_isDirty = false; return m_cachedValue; } void skelBone_Rotation::SetChannels(int num) { m_quatChannel = num; } void skelBone_Rotation::SetBaseValue(boneData_t *data) { m_baseValue = data->offset; } int skelBone_Rotation::GetChannelIndex(int num) { return m_quatChannel; } skelBone_Base *skelBone_Rotation::GetBoneRef(int bone) { return 0; } SkelMat4& skelBone_PosRot::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelVec3 incomingOffset; SkelMat4 incomingValue; SkelQuat incomingQuat; incomingQuat = frames->GetSlerpValue(m_quatChannel); frames->GetLerpValue3(m_offsetChannel, &incomingOffset); incomingQuat.GetMat4(incomingValue); VectorCopy(incomingOffset, incomingValue[3]); if (m_parent) { m_cachedValue.Multiply(incomingValue, m_parent->GetTransform(frames)); } else { m_cachedValue = incomingValue; } if (m_controller) { SkelMat3 m; incomingQuat.Set(m_controller); incomingQuat.GetMat3(m); m_cachedValue.RotateBy(m); } m_isDirty = false; return m_cachedValue; } void skelBone_PosRot::SetChannels(int quatChannel, int offsetChannel) { m_quatChannel = quatChannel; m_offsetChannel = offsetChannel; } void skelBone_PosRot::SetBaseValue(boneData_t *boneData) {} int skelBone_PosRot::GetChannelIndex(int num) { if (num) { return m_quatChannel; } else { return m_offsetChannel; } } skelBone_Base *skelBone_PosRot::GetBoneRef(int num) { return NULL; } SkelMat4& skelBone_Root::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelVec3 incomingOffset; SkelMat4 incomingValue; SkelQuat incomingQuat; incomingQuat = frames->GetSlerpValue(m_quatChannel); frames->GetLerpValue3(m_offsetChannel, &incomingOffset); incomingQuat.GetMat4(incomingValue); VectorCopy(incomingOffset, incomingValue[3]); if (m_parent) { m_cachedValue.Multiply(incomingValue, m_parent->GetTransform(frames)); } else { m_cachedValue = incomingValue; } if (m_controller) { SkelMat3 m; incomingQuat.Set(m_controller); incomingQuat.GetMat3(m); m_cachedValue.RotateBy(m); } m_isDirty = false; return m_cachedValue; } skelBone_IKshoulder::skelBone_IKshoulder() { m_wrist = NULL; } SkelMat4& skelBone_IKshoulder::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelMat4 baseMatrix, targetMatrix; float desiredLength; SkelVec3 newBaseY; SkelVec3 newBaseZ; SkelVec3 cross; float cosUpperAngle; float sinUpperAngle; float maxLength; float length; float cosA; float sinA; if (!m_wrist) { m_cachedValue.MakeIdentity(); return m_cachedValue; } if (m_parent) { baseMatrix = m_parent->GetTransform(frames); } baseMatrix[3][0] += m_baseValue[0] * baseMatrix[0][0] + m_baseValue[1] * baseMatrix[1][0] + m_baseValue[2] * baseMatrix[2][0]; baseMatrix[3][1] += m_baseValue[0] * baseMatrix[0][1] + m_baseValue[1] * baseMatrix[1][1] + m_baseValue[2] * baseMatrix[2][1]; baseMatrix[3][2] += m_baseValue[0] * baseMatrix[0][2] + m_baseValue[1] * baseMatrix[1][2] + m_baseValue[2] * baseMatrix[2][2]; baseMatrix.InvertAxis(0); baseMatrix.InvertAxis(2); m_wristAngle = frames->GetSlerpValue(m_wrist->m_quatChannel); m_wristAngle.GetMat4(targetMatrix); frames->GetLerpValue3(m_wrist->m_offsetChannel, &m_wristPos); m_cachedValue = baseMatrix; VectorCopy(m_wristPos, targetMatrix[3]); VectorSubtract(targetMatrix[3], baseMatrix[3], m_cachedValue[0]); sinUpperAngle = VectorNormalize(m_cachedValue[0]); newBaseY = baseMatrix[2]; newBaseZ = m_cachedValue[0]; CrossProduct(newBaseY, newBaseZ, cross); VectorCopy(cross, m_cachedValue[1]); newBaseY = targetMatrix[2]; newBaseZ = m_cachedValue[0]; CrossProduct(newBaseY, newBaseZ, cross); VectorAdd(m_cachedValue[1], cross, m_cachedValue[1]); desiredLength = VectorNormalize(m_cachedValue[1]); if (!desiredLength) { m_cachedValue[1][1] = 1.0; } newBaseY = m_cachedValue[0]; newBaseZ = m_cachedValue[1]; CrossProduct(newBaseY, newBaseZ, cross); VectorCopy(cross, m_cachedValue[2]); cosUpperAngle = m_upperLength + m_lowerLength - 0.001; if (sinUpperAngle > cosUpperAngle) { sinUpperAngle = cosUpperAngle; m_wristPos = m_cachedValue[3]; m_wristPos[0] += m_cachedValue[0][0] * cosUpperAngle; m_wristPos[1] += m_cachedValue[0][1] * cosUpperAngle; m_wristPos[2] += m_cachedValue[0][2] * cosUpperAngle; } maxLength = (sinUpperAngle * sinUpperAngle + m_upperLength * m_upperLength - m_lowerLength * m_lowerLength) / (sinUpperAngle * m_upperLength + sinUpperAngle * m_upperLength); if (maxLength > 1.0) { maxLength = 1.0; } m_cosElbowAngle = -((m_lowerLength * m_lowerLength + m_upperLength * m_upperLength - sinUpperAngle * sinUpperAngle) / (m_upperLength * m_lowerLength + m_upperLength * m_lowerLength)); length = -sqrt(1.0 - maxLength * maxLength); cosA = m_cachedValue[0][0]; sinA = m_cachedValue[1][0]; m_cachedValue[0][0] = cosA * maxLength - sinA * length; m_cachedValue[1][0] = sinA * maxLength + cosA * length; cosA = m_cachedValue[0][1]; sinA = m_cachedValue[1][1]; m_cachedValue[0][1] = cosA * maxLength - sinA * length; m_cachedValue[1][1] = sinA * maxLength + cosA * length; cosA = m_cachedValue[0][2]; sinA = m_cachedValue[1][2]; m_cachedValue[0][2] = cosA * maxLength - sinA * length; m_cachedValue[1][2] = sinA * maxLength + cosA * length; m_isDirty = false; return m_cachedValue; } void skelBone_IKshoulder::SetBaseValue(boneData_t *boneData) { m_baseValue = boneData->offset; } int skelBone_IKshoulder::GetChannelIndex(int num) { return -1; } skelBone_Base *skelBone_IKshoulder::GetBoneRef(int num) { return m_wrist; } void skelBone_IKshoulder::SetElbowValue(float elbowOffset) { m_upperLength = elbowOffset; } void skelBone_IKshoulder::SetWristValue(float wristOffset) { m_lowerLength = wristOffset; } void skelBone_IKshoulder::SetWristBone(skelBone_IKwrist *wrist) { this->m_wrist = wrist; } float skelBone_IKshoulder::GetUpperLength() { return m_upperLength; } float skelBone_IKshoulder::GetLowerLength() { return m_lowerLength; } SkelMat4& skelBone_IKwrist::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { if (m_shoulder->m_isDirty) { m_shoulder->GetDirtyTransform(frames); } m_shoulder->m_wristAngle.GetMat4(m_cachedValue); VectorCopy(m_shoulder->m_wristPos, m_cachedValue[3]); m_isDirty = false; return m_cachedValue; } void skelBone_IKwrist::SetChannels(int quatChannel, int offsetChannel) { m_quatChannel = quatChannel; m_offsetChannel = offsetChannel; } void skelBone_IKwrist::SetBoneRefs(skelBone_IKshoulder *shoulder) { m_shoulder = shoulder; } void skelBone_IKwrist::SetBaseValue(boneData_t *boneData) { m_shoulder->SetWristValue(boneData->length); } int skelBone_IKwrist::GetChannelIndex(int num) { return -1; } skelBone_Base *skelBone_IKwrist::GetBoneRef(int num) { return m_shoulder; } SkelMat4& skelBone_IKelbow::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { float fLength; float cosA, sinA; m_cachedValue = m_shoulder->GetTransform(frames); m_cachedValue[3][0] += m_cachedValue[0][0] * m_shoulder->m_upperLength; m_cachedValue[3][1] += m_cachedValue[0][1] * m_shoulder->m_upperLength; m_cachedValue[3][2] += m_cachedValue[0][2] * m_shoulder->m_upperLength; fLength = sqrt(1.0 - m_shoulder->m_cosElbowAngle * m_shoulder->m_cosElbowAngle); cosA = m_cachedValue[0][0]; sinA = m_cachedValue[1][0]; m_cachedValue[0][0] = cosA * m_shoulder->m_cosElbowAngle - sinA * fLength; m_cachedValue[1][0] = sinA * m_shoulder->m_cosElbowAngle + cosA * fLength; cosA = m_cachedValue[0][1]; sinA = m_cachedValue[1][1]; m_cachedValue[0][1] = cosA * m_shoulder->m_cosElbowAngle - sinA * fLength; m_cachedValue[1][1] = sinA * m_shoulder->m_cosElbowAngle + cosA * fLength; cosA = m_cachedValue[0][2]; sinA = m_cachedValue[1][2]; m_cachedValue[0][2] = cosA * m_shoulder->m_cosElbowAngle - sinA * fLength; m_cachedValue[1][2] = sinA * m_shoulder->m_cosElbowAngle + cosA * fLength; m_isDirty = false; return m_cachedValue; } void skelBone_IKelbow::SetBoneRefs(skelBone_IKshoulder *shoulder) { m_shoulder = shoulder; } void skelBone_IKelbow::SetBaseValue(boneData_t *boneData) { m_shoulder->SetElbowValue(boneData->length); } int skelBone_IKelbow::GetChannelIndex(int num) { return -1; } skelBone_Base *skelBone_IKelbow::GetBoneRef(int num) { return m_shoulder; } skelBone_AvRot::skelBone_AvRot() { m_reference1 = NULL; m_reference2 = NULL; } SkelMat4& skelBone_AvRot::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelQuat temp1, temp2; SkelMat4 temp; temp1 = m_reference1->GetTransform(frames); temp2 = m_reference2->GetTransform(frames); // lerp values Slerp(temp1, temp2, m_bone2weight, &m_cachedQuat); VectorCopy(m_basePos, m_cachedValue[3]); if (m_parent) { temp.Multiply(m_cachedValue, m_parent->GetTransform(frames)); m_cachedValue = temp; } m_cachedQuat.GetMat4(m_cachedValue); m_isDirty = false; return m_cachedValue; } void skelBone_AvRot::SetBoneRefs(skelBone_Base *ref1, skelBone_Base *ref2) { m_reference1 = ref1; m_reference2 = ref2; } void skelBone_AvRot::SetBaseValue(boneData_t *boneData) { m_basePos = boneData->offset; m_bone2weight = boneData->weight; } int skelBone_AvRot::GetChannelIndex(int num) { return -1; } skelBone_Base *skelBone_AvRot::GetBoneRef(int num) { if (num) { return m_reference2; } else { return m_reference1; } } SkelMat4& skelBone_HoseRot::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelMat4 mat; if (m_parent) { mat = m_parent->GetTransform(frames); } return GetDirtyTransform(mat, m_target->GetTransform(frames)); } SkelMat4& skelBone_HoseRot::GetDirtyTransform(SkelMat4& myParentTM, SkelMat4& targetTM) { SkelMat4 m; SkelMat4 invParentTM; SkelMat4 temp; SkelVec3 rotaxis; SkelVec3 targetup, targetaim; SkelVec3 upaxis, aimaxis; SkelVec3 tmp; SkelQuat targetQuat; float l, s, c; float angle, vScale; aimaxis = myParentTM[0]; targetaim = targetTM[0]; CrossProduct(targetaim, aimaxis, rotaxis); s = VectorLengthSquared(rotaxis); if (s == 0.0) { rotaxis.x = 1.0; } else if (s != 1.0) { l = 1.0 / sqrt(s); VectorScale(rotaxis, l, rotaxis); } s = DotProduct(aimaxis, targetaim); if (s < 1.0) { if (s > -0.999) { angle = acos(s); } else { angle = 6.2831855f; } } else { angle = 0.0; } vScale = angle * m_bendRatio; if (vScale > m_bendMax) { vScale = m_bendMax; } temp[0][0] = myParentTM[0][0]; temp[0][1] = myParentTM[1][0]; temp[0][2] = myParentTM[2][0]; temp[1][0] = myParentTM[0][1]; temp[1][1] = myParentTM[1][1]; temp[1][2] = myParentTM[2][1]; temp[2][0] = myParentTM[0][2]; temp[2][1] = myParentTM[1][2]; temp[2][2] = myParentTM[2][2]; temp[3][0] = -(myParentTM[0][0] * myParentTM[3][0] + myParentTM[0][1] * myParentTM[3][1] + myParentTM[0][2] * myParentTM[3][2]); temp[3][1] = -(myParentTM[1][0] * myParentTM[3][0] + myParentTM[1][1] * myParentTM[3][1] + myParentTM[1][2] * myParentTM[3][2]); temp[3][2] = -(myParentTM[2][0] * myParentTM[3][0] + myParentTM[2][1] * myParentTM[3][1] + myParentTM[2][2] * myParentTM[3][2]); m.Multiply(temp, myParentTM); VectorCopy(rotaxis, tmp); rotaxis[0] = tmp[0] * temp[0][0] + tmp[1] * temp[1][0] + tmp[2] * temp[2][0]; rotaxis[1] = tmp[0] * temp[0][1] + tmp[1] * temp[1][1] + tmp[2] * temp[2][1]; rotaxis[2] = tmp[0] * temp[0][2] + tmp[1] * temp[1][2] + tmp[2] * temp[2][2]; targetaim.y = cos(vScale * 0.5); targetup.y = rotaxis.x * targetaim.y; targetup.z = rotaxis.y * targetaim.y; targetaim.x = rotaxis.z * targetaim.y; c = cos(vScale * 0.5); l = sqrt(1.0 - c * c); m_cachedQuat[0] = rotaxis[0] * l; m_cachedQuat[1] = rotaxis[1] * l; m_cachedQuat[2] = rotaxis[2] * l; m_cachedQuat[3] = c; if (m_spinRatio < 1.0) { m.Multiply(targetTM, temp); MatToQuat(m.val, targetQuat.val); Slerp(targetQuat, m_cachedQuat, m_spinRatio, &m_cachedQuat); } m_cachedQuat.GetMat4(m_cachedValue); VectorCopy(m_basePos, m_cachedValue[3]); m.Multiply(m_cachedValue, myParentTM); m_cachedValue = m; m_isDirty = false; return m_cachedValue; } void skelBone_HoseRot::SetBoneRefs(skelBone_Base *ref) { m_target = ref; } void skelBone_HoseRot::SetBaseValue(boneData_t *boneData) { m_bendRatio = boneData->bendRatio; m_bendMax = boneData->bendMax; m_spinRatio = boneData->spinRatio; m_basePos = boneData->offset; } int skelBone_HoseRot::GetChannelIndex(int num) { return -1; } skelBone_Base *skelBone_HoseRot::GetBoneRef(int num) { return m_target; } SkelMat4& skelBone_HoseRotBoth::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelMat4 myParentTM; SkelMat4 targetTM; if (m_parent) { myParentTM = m_parent->GetTransform(frames); targetTM = m_target->GetTransform(frames); } VectorInverse(targetTM[0]); VectorInverse(targetTM[2]); VectorInverse(myParentTM[0]); VectorInverse(myParentTM[2]); return skelBone_HoseRot::GetDirtyTransform(myParentTM, targetTM); } void skelBone_HoseRotBoth::SetBaseValue(boneData_t *boneData) { skelBone_HoseRot::SetBaseValue(boneData); m_basePos.x = -m_basePos.x; m_basePos.z = -m_basePos.z; } SkelMat4& skelBone_HoseRotParent::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { SkelMat4 myParentTM; SkelMat4 targetTM; if (m_parent) { myParentTM = m_parent->GetTransform(frames); targetTM = m_target->GetTransform(frames); } VectorInverse(myParentTM[0]); VectorInverse(myParentTM[2]); return skelBone_HoseRot::GetDirtyTransform(myParentTM, targetTM); } void skelBone_HoseRotParent::SetBaseValue(boneData_t *boneData) { skelBone_HoseRot::SetBaseValue(boneData); m_basePos.x = -m_basePos.x; m_basePos.z = -m_basePos.z; } SkelMat4& skelBone_World::GetDirtyTransform(const skelAnimStoreFrameList_c *frames) { m_cachedValue.MakeIdentity(); m_isDirty = false; return m_cachedValue; } void skelBone_World::SetBaseValue(boneData_t *boneData) {} int skelBone_World::GetChannelIndex(int num) { return 0; } skelBone_Base *skelBone_World::GetBoneRef(int num) { return NULL; }