openmohaa/code/skeletor/skeletor.cpp

1267 lines
38 KiB
C++

/*
===========================================================================
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
===========================================================================
*/
// skeletor.cpp : Skeletor
#include "q_shared.h"
#include "qcommon.h"
#include "skeletor.h"
#include <tiki.h>
#define EPSILON 0.000000000001f
ChannelNameTable* skeletor_c::ChannelNames()
{
return &m_channelNames;
}
int skelAnimDataGameHeader_s::GetFrameNums(
float timeSeconds, float timeTolerance, int *beforeFrame, int *afterFrame, float *beforeWeight, float *afterWeight
)
{
int frameNum1;
int frameNum2;
frameNum1 = (int)(timeSeconds / frameTime);
frameNum2 = frameNum1 + 1;
*afterWeight = (timeSeconds / frameTime) - (float)frameNum1;
if ((1.0 - *afterWeight) * frameTime < timeTolerance || *afterWeight * frameTime < timeTolerance) {
if (*afterWeight > 0.5) {
frameNum1++;
}
if (frameNum1 >= numFrames) {
if ((flags & TAF_DELTADRIVEN)) {
frameNum1 %= numFrames;
} else {
frameNum1 = numFrames - 1;
}
}
*beforeFrame = frameNum1;
*beforeWeight = 1.0;
*afterFrame = 0;
*afterWeight = 0.0;
return 1;
} else if (frameNum2 >= numFrames) {
if ((flags & TAF_DELTADRIVEN)) {
frameNum2 %= numFrames;
} else {
frameNum2 = numFrames - 1;
}
if (frameNum1 >= numFrames) {
if ((flags & TAF_DELTADRIVEN)) {
frameNum1 %= numFrames;
} else {
*beforeFrame = numFrames - 1;
*beforeWeight = 1.0;
return 1;
}
}
}
*beforeFrame = frameNum1;
*afterFrame = frameNum2;
*beforeWeight = 1.0 - *afterWeight;
return 2;
}
SkelVec3 skelAnimDataGameHeader_s::GetDeltaOverTime(float time1, float time2)
{
float deltaWeight1;
int frameNum1;
float deltaWeight2;
int frameNum2;
SkelVec3 delta;
int currFrame;
float s, d;
deltaWeight1 = time1 / frameTime;
deltaWeight2 = time2 / frameTime;
frameNum1 = ceil(deltaWeight1);
frameNum2 = ceil(deltaWeight2);
d = frameNum1 - deltaWeight1;
s = 1.0 - (frameNum2 - deltaWeight2);
if (frameNum1 < frameNum2) {
delta = m_frame[frameNum1 % numFrames].delta;
VectorScale(delta, d, delta);
for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) {
delta += m_frame[currFrame % numFrames].delta;
}
delta.x += m_frame[frameNum2 % numFrames].delta.x * s;
delta.y += m_frame[frameNum2 % numFrames].delta.y * s;
delta.z += m_frame[frameNum2 % numFrames].delta.z * s;
} else {
s = s - (1.0 - d);
delta.x = m_frame[frameNum2 % numFrames].delta.x * s;
delta.y = m_frame[frameNum2 % numFrames].delta.y * s;
delta.z = m_frame[frameNum2 % numFrames].delta.z * s;
}
if (delta.x > -0.001f && delta.x < 0.001f) {
delta.x = 0;
}
if (delta.y > -0.001f && delta.y < 0.001f) {
delta.y = 0;
}
if (delta.z > -0.001f && delta.z < 0.001f) {
delta.z = 0;
}
return delta;
}
float skelAnimDataGameHeader_s::GetAngularDeltaOverTime(float time1, float time2)
{
float deltaWeight1;
int frameNum1;
float deltaWeight2;
int frameNum2;
float delta;
int currFrame;
float s, d;
deltaWeight1 = time1 / frameTime;
deltaWeight2 = time2 / frameTime;
frameNum1 = ceil(deltaWeight1);
frameNum2 = ceil(deltaWeight2);
d = frameNum1 - deltaWeight1;
s = 1.0 - (frameNum2 - deltaWeight2);
delta = 0;
if (frameNum1 < frameNum2) {
delta = m_frame[frameNum1 % numFrames].angleDelta * d;
for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) {
delta += m_frame[currFrame % numFrames].angleDelta;
}
delta += m_frame[frameNum2 % numFrames].angleDelta * s;
} else {
s = s - (1.0 - d);
delta = m_frame[frameNum2 % numFrames].angleDelta;
}
if (delta > -0.001f && delta < 0.001f) {
delta = 0;
}
return delta;
}
skelAnimDataGameHeader_t *skelAnimDataGameHeader_s::AllocAnimData(size_t numFrames, size_t numChannels)
{
skelAnimDataGameHeader_t *data;
const size_t animSize =
sizeof(skelAnimDataGameHeader_t) + (16 * (3 * numFrames - 3)) + 16 * numChannels * numFrames;
data = (skelAnimDataGameHeader_t *)Skel_Alloc(animSize);
data->flags = 0;
data->channelList.InitChannels();
data->nBytesUsed = animSize;
data->numFrames = numFrames;
return data;
}
skelAnimDataGameHeader_s *skelAnimDataGameHeader_s::AllocRLEChannelData(size_t numChannels)
{
int animSize;
skelAnimDataGameHeader_t *data;
animSize = sizeof(skelAnimDataGameHeader_t) + (numChannels - 1) * sizeof(skanChannelHdr);
data = (skelAnimDataGameHeader_t *)Skel_Alloc(animSize);
data->flags = 0;
data->nTotalChannels = numChannels;
data->channelList.InitChannels();
data->nBytesUsed = animSize;
return data;
}
skeletor_c::skeletor_c(dtiki_t *tiki)
{
int numBones;
int mesh;
skelHeaderGame_t *skelmodel;
m_Tiki = tiki;
m_morphTargetList.InitChannels();
m_morphTargetList.ZeroChannels();
m_frameBounds[0].set(-32, -32, 0);
m_frameBounds[1].set(32, 32, 28);
m_frameRadius = 64;
m_frameList.numActionFrames = 0;
m_frameList.numMovementFrames = 0;
m_targetLookLeft = 0;
m_targetLookRight = 0;
m_targetLookUp = 0;
m_targetLookDown = 0;
m_targetLookCrossed = 0;
m_targetBlink = 0;
VectorClear(m_eyeTargetPos);
VectorClear(m_eyePrevTargetPos);
m_timeNextBlink = Sys_Milliseconds();
numBones = m_Tiki->m_boneList.NumChannels();
m_bone = (skelBone_Base **)Skel_Alloc(numBones * sizeof(skelBone_Base *));
memset(m_bone, 0, numBones * sizeof(skelBone_Base *));
for (mesh = 0; mesh < m_Tiki->numMeshes; mesh++) {
skelmodel = TIKI_GetSkel(m_Tiki->mesh[mesh]);
SkeletorLoadBonesFromBuffer(&m_Tiki->m_boneList, skelmodel, m_bone);
LoadMorphTargetNames(skelmodel);
}
m_morphTargetList.PackChannels();
m_headBoneIndex = m_Tiki->GetBoneNumFromName("Bip01 Head");
}
skeletor_c::~skeletor_c()
{
int i;
for (i = 0; i < m_Tiki->m_boneList.m_numChannels; i++) {
delete m_bone[i];
}
m_morphTargetList.CleanUpChannels();
Skel_Free(m_bone);
m_bone = NULL;
}
void skelAnimDataGameHeader_s::DeallocAnimData(skelAnimDataGameHeader_t *data)
{
skanChannelHdr *pChannel;
int i;
int channelType;
if (!data) {
return;
}
for (i = 0; i < data->nTotalChannels; i++) {
pChannel = &data->ary_channels[i];
channelType = GetBoneChannelType(data->channelList.ChannelName(skeletor_c::ChannelNames(), i));
if (channelType != 2) {
Skel_Free(pChannel->ary_frames);
}
}
data->channelList.CleanUpChannels();
if (data->m_frame) {
Skel_Free(data->m_frame);
}
Skel_Free(data);
}
void ConvertToRotationName(const char *boneName, char *rotChannelName)
{
strcpy(rotChannelName, boneName);
strcat(rotChannelName, " rot");
}
void ConvertToPositionName(const char *boneName, char *posChannelName)
{
strcpy(posChannelName, boneName);
strcat(posChannelName, " rot");
}
void ConvertToFKRotationName(const char *boneName, char *rotChannelName)
{
strcpy(rotChannelName, boneName);
strcat(rotChannelName, " rot");
strcat(rotChannelName, "FK");
}
void ConvertToFKPositionName(const char *boneName, char *rotChannelName)
{
strcpy(rotChannelName, boneName);
strcat(rotChannelName, " pos");
strcat(rotChannelName, "FK");
}
int GetHighestFloat(float *selection)
{
float currentHighest;
int currentHighestIndex;
int i;
currentHighest = selection[0];
currentHighestIndex = 0;
for (i = 0; i < 8; i++) {
if (selection[i] > currentHighest) {
currentHighest = selection[i];
currentHighestIndex = i;
}
}
return currentHighestIndex;
}
void AddToBounds(SkelVec3 *bounds, SkelVec3 *newBounds)
{
int i;
for (i = 0; i < 3; i++) {
if (bounds[0][i] > newBounds[0][i]) {
bounds[0][i] = newBounds[0][i];
}
if (bounds[1][i] < newBounds[1][i]) {
bounds[1][i] = newBounds[1][i];
}
}
}
void skeletor_c::SetPose(
const frameInfo_t *frameInfo, const int *contIndices, const vec4_t *contValues, float actionWeight
)
{
skelAnimDataGameHeader_t *animData;
short int *aliases;
int boneNum;
int blendNum;
int i;
int blendFrame;
int movementBlendFrame;
int actionBlendFrame;
int realAnimIndex;
int beforeFrame;
int afterFrame;
float beforeWeight;
float afterWeight;
int numFramesAdded;
float cutoff_weight;
int contNum;
float animWeight;
skanBlendInfo *frame1, *frame2;
for (i = 0; i < m_Tiki->m_boneList.NumChannels(); i++) {
m_bone[i]->m_controller = NULL;
m_bone[i]->m_isDirty = true;
}
if (contIndices && contValues) {
for (contNum = 0; contNum < 5; contNum++) {
boneNum = contIndices[contNum];
// Added in 2.0.
// Make sure the bone is a valid channel
if (boneNum < 0 || boneNum >= m_Tiki->m_boneList.NumChannels()) {
continue;
}
cutoff_weight = (contValues[contNum][3] - 1.0) * (contValues[contNum][3] - 1.0);
if (cutoff_weight >= EPSILON) {
m_bone[boneNum]->m_controller = (float *)contValues[contNum];
}
}
}
for (i = 0; i < 3; i++) {
m_frameBounds[0][i] = -2.0f;
m_frameBounds[1][i] = 2.0f;
}
m_frameRadius = 2.0f;
animWeight = 0.0f;
movementBlendFrame = 0;
actionBlendFrame = MAX_SKEL_BLEND_MOVEMENT_FRAMES;
aliases = m_Tiki->a->m_aliases;
for (blendNum = 0; blendNum < MAX_FRAMEINFOS; blendNum++) {
const frameInfo_t& currentFrame = frameInfo[blendNum];
if (animWeight < currentFrame.weight) {
animWeight = currentFrame.weight;
}
}
cutoff_weight = animWeight * 0.01f;
for (blendNum = 0; blendNum < MAX_FRAMEINFOS; blendNum++) {
const frameInfo_t& currentFrame = frameInfo[blendNum];
if (currentFrame.weight <= cutoff_weight) {
continue;
}
// Added in 2.0.
// Validate the index number
if (currentFrame.index < 0 || currentFrame.index > m_Tiki->a->num_anims) {
continue;
}
realAnimIndex = aliases[currentFrame.index];
// Added in 2.0.
// Check if the alias is within bounds
if (realAnimIndex < 0 || realAnimIndex >= MAX_TIKI_ALIASES) {
continue;
}
animData = SkeletorCacheGetData(realAnimIndex);
// Added in 2.0.
// Make sure the anim data is valid
if (!animData) {
continue;
}
if (animData->bHasDelta) {
blendFrame = movementBlendFrame;
} else {
blendFrame = actionBlendFrame;
}
beforeWeight = 0.0;
afterWeight = 0.0;
beforeFrame = 0.0;
afterFrame = 0.0;
numFramesAdded =
animData->GetFrameNums(currentFrame.time, 0.001f, &beforeFrame, &afterFrame, &beforeWeight, &afterWeight);
frame1 = &m_frameList.m_blendInfo[blendFrame];
frame1->frame = beforeFrame;
frame1->pAnimationData = animData;
frame1->weight = beforeWeight * currentFrame.weight;
AddToBounds(m_frameBounds, animData->bounds);
if (frame1->pAnimationData->m_frame[frame1->frame].radius > m_frameRadius) {
m_frameRadius = frame1->pAnimationData->m_frame[frame1->frame].radius;
}
if (numFramesAdded == 2) {
frame2 = &m_frameList.m_blendInfo[blendFrame + 1];
frame2->frame = afterFrame;
frame2->pAnimationData = animData;
frame2->weight = afterWeight * currentFrame.weight;
AddToBounds(m_frameBounds, animData->bounds);
if (frame2->pAnimationData->m_frame[frame2->frame].radius > m_frameRadius) {
m_frameRadius = frame2->pAnimationData->m_frame[frame2->frame].radius;
}
}
if (animData->bHasDelta) {
movementBlendFrame = blendFrame + numFramesAdded;
} else {
actionBlendFrame = blendFrame + numFramesAdded;
}
}
for (i = 0; i < 3; i++) {
m_frameBounds[0][i] += -7.0f;
m_frameBounds[1][i] += 7.0f;
}
m_frameList.numMovementFrames = movementBlendFrame;
m_frameList.numActionFrames = actionBlendFrame - MAX_SKEL_BLEND_MOVEMENT_FRAMES;
m_frameList.actionWeight = actionWeight;
assert(m_frameList.numMovementFrames < MAX_SKEL_BLEND_MOVEMENT_FRAMES);
assert(m_frameList.numActionFrames < MAX_SKEL_BLEND_ACTION_FRAMES);
}
static SkelMat4 GetGlobalDefaultPosition(skelBone_Base *bone)
{
SkelMat4 lLocalPosition;
SkelMat4 lGlobalPosition;
SkelMat4 lParentGlobalPosition;
lLocalPosition = bone->GetTransform(NULL);
if (bone->Parent()) {
//lParentGlobalPosition = GetGlobalDefaultPosition( bone->Parent() );
//lGlobalPosition.Multiply( lParentGlobalPosition, lLocalPosition );
lGlobalPosition = lLocalPosition;
} else {
lGlobalPosition = lLocalPosition;
}
return lGlobalPosition;
}
SkelMat4 GlobalToLocal(skelBone_Base *bone, SkelMat4 pGlobalPosition)
{
SkelMat4 lLocalPosition;
SkelMat4 lParentGlobalPosition;
if (bone->Parent()) {
lParentGlobalPosition = GetGlobalDefaultPosition(bone->Parent());
lParentGlobalPosition.Inverse();
lLocalPosition.Multiply(lParentGlobalPosition, pGlobalPosition);
} else {
lLocalPosition = pGlobalPosition;
}
return lLocalPosition;
}
void BoneGetFrames(
skelHeaderGame_t *skelmodel,
skelAnimDataGameHeader_t *animData,
skelChannelList_c *boneList,
int boneNum,
Container<skanAnimFrame>& outFrames
)
{
int numBones;
skelBone_Base **bone;
int i;
skanAnimFrame frame;
int localChannelNum;
outFrames.FreeObjectList();
numBones = boneList->NumChannels();
bone = (skelBone_Base **)Skel_Alloc(sizeof(skelBone_Base *) * numBones);
memset(bone, 0, sizeof(skelBone_Base *) * numBones);
SkeletorLoadBonesFromBuffer(boneList, skelmodel, bone);
for (i = 0; i < numBones; i++) {
bone[i]->m_controller = NULL;
bone[i]->m_isDirty = true;
}
// process the rot channel
localChannelNum = animData->channelList.GetLocalFromGlobal(bone[boneNum]->GetChannelIndex(1));
if (localChannelNum >= 0) {
skanChannelHdr *channel = &animData->ary_channels[localChannelNum];
for (i = 0; i < channel->nFramesInChannel; i++) {
skanGameFrame *pFrame = &channel->ary_frames[i];
frame.nFrameNum = pFrame->nFrameNum;
VectorClear(frame.pos);
QuatToAngles(pFrame->pChannelData, frame.rot);
outFrames.AddObject(frame);
}
}
if (bone[i]->GetChannelIndex(0) != bone[i]->GetChannelIndex(1)) {
// process the pos channel
localChannelNum = animData->channelList.GetLocalFromGlobal(bone[boneNum]->GetChannelIndex(0));
if (localChannelNum >= 0) {
skanChannelHdr *channel = &animData->ary_channels[localChannelNum];
for (i = 0; i < channel->nFramesInChannel; i++) {
skanGameFrame *pFrame = &channel->ary_frames[i];
skanAnimFrame *pOutFrame = &outFrames[i];
VectorCopy(pFrame->pChannelData, pOutFrame->pos);
}
}
}
}
void SkeletorGetAnimFrame2(
skelHeaderGame_t *skelmodel,
skelChannelList_c *boneList,
skelBoneCache_t *bones,
skelAnimStoreFrameList_c *frameList,
float *radius,
vec3_t *mins,
vec3_t *maxes
)
{
int numBones;
skelBone_Base **bone;
int i;
skelAnimFrame_t *newFrame;
numBones = skelmodel->numBones;
bone = (skelBone_Base **)Skel_Alloc(sizeof(skelBone_Base *) * numBones);
memset(bone, 0, sizeof(skelBone_Base *) * numBones);
SkeletorLoadBonesFromBuffer(boneList, skelmodel, bone);
for (i = 0; i < numBones; i++) {
bone[i]->m_controller = NULL;
bone[i]->m_isDirty = true;
}
newFrame = (skelAnimFrame_t *)Skel_Alloc(sizeof(skelAnimFrame_t) + sizeof(SkelMat4) * numBones);
newFrame->radius = 0;
newFrame->bounds[0] = SkelVec3();
newFrame->bounds[1] = SkelVec3();
for (i = 0; i < numBones; i++) {
//skelBone_Base *Parent = bone[ i ]->Parent();
//bone[ i ]->SetParent( &skeletor_c::m_worldBone );
newFrame->bones[i] = bone[i]->GetTransform(frameList);
//bone[ i ]->SetParent( Parent );
}
for (i = 0; i < numBones; i++) {
VectorCopy(newFrame->bones[i][3], bones[i].offset);
bones[i].matrix[0][0] = newFrame->bones[i][0][0];
bones[i].matrix[0][1] = newFrame->bones[i][0][1];
bones[i].matrix[0][2] = newFrame->bones[i][0][2];
bones[i].matrix[0][3] = 0;
bones[i].matrix[1][0] = newFrame->bones[i][1][0];
bones[i].matrix[1][1] = newFrame->bones[i][1][1];
bones[i].matrix[1][2] = newFrame->bones[i][1][2];
bones[i].matrix[1][3] = 0;
bones[i].matrix[2][0] = newFrame->bones[i][2][0];
bones[i].matrix[2][1] = newFrame->bones[i][2][1];
bones[i].matrix[2][2] = newFrame->bones[i][2][2];
bones[i].matrix[2][3] = 0;
}
for (i = 0; i < numBones; i++) {
delete bone[i];
}
Skel_Free(bone);
if (radius) {
*radius = newFrame->radius;
}
if (mins || maxes) {
for (i = 0; i < 3; i++) {
if (mins) {
(*mins)[i] = newFrame->bounds[0][i];
}
if (maxes) {
(*maxes)[i] = newFrame->bounds[1][i];
}
}
}
Skel_Free(newFrame);
}
void SkeletorGetAnimFrame(
skelHeaderGame_t *skelmodel,
skelAnimDataGameHeader_t *animData,
skelChannelList_c *boneList,
skelBoneCache_t *bones,
int frame,
float *radius,
vec3_t *mins,
vec3_t *maxes
)
{
int numBones;
skelBone_Base **bone;
int i;
skelAnimStoreFrameList_c frameList;
skelAnimFrame_t *newFrame;
frameList.actionWeight = animData ? 1.0 : 0;
if (animData) {
if (!animData->bHasDelta) {
frameList.numMovementFrames = 0;
frameList.numActionFrames = 1;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].weight = 1.0;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].pAnimationData = animData;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].frame = frame;
} else {
frameList.numMovementFrames = 1;
frameList.numActionFrames = 0;
frameList.m_blendInfo[0].weight = 1.0;
frameList.m_blendInfo[0].pAnimationData = animData;
frameList.m_blendInfo[0].frame = frame;
}
}
numBones = skelmodel->numBones;
bone = (skelBone_Base **)Skel_Alloc(sizeof(skelBone_Base *) * numBones);
memset(bone, 0, sizeof(skelBone_Base *) * numBones);
SkeletorLoadBonesFromBuffer(boneList, skelmodel, bone);
for (i = 0; i < numBones; i++) {
bone[i]->m_controller = NULL;
bone[i]->m_isDirty = true;
}
newFrame = (skelAnimFrame_t *)Skel_Alloc(sizeof(skelAnimFrame_t) + sizeof(SkelMat4) * numBones);
if (animData) {
if (animData->m_frame) {
newFrame->radius = animData->m_frame->radius;
} else {
newFrame->radius = 0;
}
newFrame->bounds[0] = animData->bounds[0];
newFrame->bounds[1] = animData->bounds[1];
} else {
newFrame->radius = 0;
newFrame->bounds[0] = SkelVec3();
newFrame->bounds[1] = SkelVec3();
}
if (animData) {
for (i = 0; i < numBones; i++) {
//skelBone_Base *Parent = bone[ i ]->Parent();
//bone[ i ]->SetParent( &skeletor_c::m_worldBone );
newFrame->bones[i] = bone[i]->GetTransform(&frameList);
//bone[ i ]->SetParent( Parent );
}
} else {
for (i = 0; i < numBones; i++) {
newFrame->bones[i] = SkelMat4();
}
}
for (i = 0; i < numBones; i++) {
VectorCopy(newFrame->bones[i][3], bones[i].offset);
bones[i].matrix[0][0] = newFrame->bones[i][0][0];
bones[i].matrix[0][1] = newFrame->bones[i][0][1];
bones[i].matrix[0][2] = newFrame->bones[i][0][2];
bones[i].matrix[0][3] = 0;
bones[i].matrix[1][0] = newFrame->bones[i][1][0];
bones[i].matrix[1][1] = newFrame->bones[i][1][1];
bones[i].matrix[1][2] = newFrame->bones[i][1][2];
bones[i].matrix[1][3] = 0;
bones[i].matrix[2][0] = newFrame->bones[i][2][0];
bones[i].matrix[2][1] = newFrame->bones[i][2][1];
bones[i].matrix[2][2] = newFrame->bones[i][2][2];
bones[i].matrix[2][3] = 0;
}
for (i = 0; i < numBones; i++) {
delete bone[i];
}
Skel_Free(bone);
if (radius) {
*radius = newFrame->radius;
}
if (mins || maxes) {
for (i = 0; i < 3; i++) {
if (mins) {
(*mins)[i] = newFrame->bounds[0][i];
}
if (maxes) {
(*maxes)[i] = newFrame->bounds[1][i];
}
}
}
Skel_Free(newFrame);
}
void TIKI_GetSkelAnimFrameInternal2(
dtiki_t *tiki,
skelBoneCache_t *bones,
skelAnimStoreFrameList_c *frameList,
float *radius,
vec3_t *mins,
vec3_t *maxes
)
{
//int boneNum;
int numBones;
skelBone_Base **bone;
int i;
skelAnimFrame_t *newFrame;
//int realAnimIndex;
//skanBlendInfo *frame;
skelHeaderGame_t *skelmodel;
numBones = tiki->m_boneList.NumChannels();
bone = (skelBone_Base **)Skel_Alloc(sizeof(skelBone_Base *) * numBones);
memset(bone, 0, sizeof(skelBone_Base *) * numBones);
for (i = 0; i < tiki->numMeshes; i++) {
skelmodel = TIKI_GetSkel(tiki->mesh[i]);
SkeletorLoadBonesFromBuffer(&tiki->m_boneList, skelmodel, bone);
}
for (i = 0; i < numBones; i++) {
bone[i]->m_controller = NULL;
bone[i]->m_isDirty = true;
}
newFrame = (skelAnimFrame_t *)Skel_Alloc(sizeof(skelAnimFrame_t) + sizeof(SkelMat4) * numBones);
/*
if (animData)
{
if (animData->m_frame)
{
newFrame->radius = animData->m_frame->radius;
}
else
{
newFrame->radius = 0;
}
newFrame->bounds[0] = animData->bounds[0];
newFrame->bounds[1] = animData->bounds[1];
}
else
*/
{
newFrame->radius = 0;
newFrame->bounds[0] = SkelVec3();
newFrame->bounds[1] = SkelVec3();
}
for (i = 0; i < numBones; i++) {
newFrame->bones[i] = bone[i]->GetTransform(frameList);
}
for (i = 0; i < numBones; i++) {
delete bone[i];
}
Skel_Free(bone);
for (i = 0; i < numBones; i++) {
VectorCopy(newFrame->bones[i][3], bones[i].offset);
bones[i].matrix[0][0] = newFrame->bones[i][0][0];
bones[i].matrix[0][1] = newFrame->bones[i][0][1];
bones[i].matrix[0][2] = newFrame->bones[i][0][2];
bones[i].matrix[0][3] = 0;
bones[i].matrix[1][0] = newFrame->bones[i][1][0];
bones[i].matrix[1][1] = newFrame->bones[i][1][1];
bones[i].matrix[1][2] = newFrame->bones[i][1][2];
bones[i].matrix[1][3] = 0;
bones[i].matrix[2][0] = newFrame->bones[i][2][0];
bones[i].matrix[2][1] = newFrame->bones[i][2][1];
bones[i].matrix[2][2] = newFrame->bones[i][2][2];
bones[i].matrix[2][3] = 0;
}
if (radius) {
*radius = newFrame->radius;
}
if (mins && maxes) {
for (i = 0; i < 3; i++) {
(*mins)[i] = newFrame->bounds[0][i];
(*maxes)[i] = newFrame->bounds[1][i];
}
}
Skel_Free(newFrame);
}
void TIKI_GetSkelAnimFrameInternal(
dtiki_t *tiki,
skelBoneCache_t *bones,
skelAnimDataGameHeader_t *animData,
int frame,
float *radius,
vec3_t *mins,
vec3_t *maxes
)
{
//int boneNum;
int numBones;
skelBone_Base **bone;
int i;
skelAnimStoreFrameList_c frameList;
skelAnimFrame_t *newFrame;
//int realAnimIndex;
//skanBlendInfo *frame;
skelHeaderGame_t *skelmodel;
frameList.actionWeight = animData ? 1.0 : 0;
if (!animData || !animData->bHasDelta) {
frameList.numMovementFrames = 0;
frameList.numActionFrames = 1;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].weight = 1.0;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].pAnimationData = animData;
frameList.m_blendInfo[MAX_SKEL_BLEND_MOVEMENT_FRAMES].frame = frame;
} else {
frameList.numMovementFrames = 1;
frameList.numActionFrames = 0;
frameList.m_blendInfo[0].weight = 1.0;
frameList.m_blendInfo[0].pAnimationData = animData;
frameList.m_blendInfo[0].frame = frame;
}
numBones = tiki->m_boneList.NumChannels();
bone = (skelBone_Base **)Skel_Alloc(sizeof(skelBone_Base *) * numBones);
memset(bone, 0, sizeof(skelBone_Base *) * numBones);
for (i = 0; i < tiki->numMeshes; i++) {
skelmodel = TIKI_GetSkel(tiki->mesh[i]);
SkeletorLoadBonesFromBuffer(&tiki->m_boneList, skelmodel, bone);
}
for (i = 0; i < numBones; i++) {
bone[i]->m_controller = NULL;
bone[i]->m_isDirty = true;
}
newFrame = (skelAnimFrame_t *)Skel_Alloc(sizeof(skelAnimFrame_t) + sizeof(SkelMat4) * numBones);
if (animData) {
if (animData->m_frame) {
newFrame->radius = animData->m_frame->radius;
} else {
newFrame->radius = 0;
}
newFrame->bounds[0] = animData->bounds[0];
newFrame->bounds[1] = animData->bounds[1];
} else {
newFrame->radius = 0;
newFrame->bounds[0] = SkelVec3();
newFrame->bounds[1] = SkelVec3();
}
for (i = 0; i < numBones; i++) {
newFrame->bones[i] = bone[i]->GetTransform(&frameList);
}
for (i = 0; i < numBones; i++) {
delete bone[i];
}
Skel_Free(bone);
for (i = 0; i < numBones; i++) {
VectorCopy(newFrame->bones[i][3], bones[i].offset);
bones[i].matrix[0][0] = newFrame->bones[i][0][0];
bones[i].matrix[0][1] = newFrame->bones[i][0][1];
bones[i].matrix[0][2] = newFrame->bones[i][0][2];
bones[i].matrix[0][3] = 0;
bones[i].matrix[1][0] = newFrame->bones[i][1][0];
bones[i].matrix[1][1] = newFrame->bones[i][1][1];
bones[i].matrix[1][2] = newFrame->bones[i][1][2];
bones[i].matrix[1][3] = 0;
bones[i].matrix[2][0] = newFrame->bones[i][2][0];
bones[i].matrix[2][1] = newFrame->bones[i][2][1];
bones[i].matrix[2][2] = newFrame->bones[i][2][2];
bones[i].matrix[2][3] = 0;
}
if (radius) {
*radius = newFrame->radius;
}
if (mins && maxes) {
for (i = 0; i < 3; i++) {
(*mins)[i] = newFrame->bounds[0][i];
(*maxes)[i] = newFrame->bounds[1][i];
}
}
Skel_Free(newFrame);
}
void TIKI_GetSkelAnimFrame2(
dtiki_t *tiki, skelBoneCache_t *bones, int anim, int frame, float *radius, vec3_t *mins, vec3_t *maxes
)
{
short *aliases;
skelAnimDataGameHeader_t *animData;
aliases = tiki->a->m_aliases;
if (*aliases == -1) {
SKEL_Warning(
"TIKI_GetSkelAnimFrame: Bad anim in static model %s, couldn't generate pose properly.\n", tiki->name
);
return;
}
animData = SkeletorCacheGetData(aliases[anim]);
TIKI_GetSkelAnimFrameInternal(tiki, bones, animData, frame, radius, mins, maxes);
}
void TIKI_GetSkelAnimFrame(dtiki_t *tiki, skelBoneCache_t *bones, float *radius, vec3_t *mins, vec3_t *maxes)
{
TIKI_GetSkelAnimFrame2(tiki, bones, 0, 0, radius, mins, maxes);
}
void skeletor_c::GetFrame(skelAnimFrame_t *newFrame)
{
int boneNum;
int numBones;
numBones = m_Tiki->m_boneList.NumChannels();
for (boneNum = 0; boneNum < numBones; boneNum++) {
newFrame->bones[boneNum] = GetBoneFrame(boneNum);
}
newFrame->bounds[0] = m_frameBounds[0];
newFrame->bounds[1] = m_frameBounds[1];
newFrame->radius = m_frameRadius;
}
SkelMat4& skeletor_c::GetBoneFrame(int boneIndex) const
{
return m_bone[boneIndex]->GetTransform(&m_frameList);
}
bool skeletor_c::IsBoneOnGround(int boneIndex, float threshold)
{
return GetBoneFrame(boneIndex).val[3][2] < threshold;
}
float skeletor_c::GetRadius()
{
return m_frameRadius;
}
float skeletor_c::GetCentroidRadius(float *centroid)
{
centroid[0] = (m_frameBounds[0][0] + m_frameBounds[1][0]) * 0.5f;
centroid[1] = (m_frameBounds[0][1] + m_frameBounds[1][1]) * 0.5f;
centroid[2] = (m_frameBounds[0][2] + m_frameBounds[1][2]) * 0.5f;
return m_frameRadius;
}
int skeletor_c::GetMorphWeightFrame(int index, float time, int *data)
{
return GetMorphWeightFrame(data);
}
float DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum)
{
skanGameFrame *foundFrame;
size_t frameSize;
int i;
frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float));
foundFrame = channelFrames->ary_frames;
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[0];
}
int skeletor_c::GetMorphWeightFrame(int *data)
{
int numTargets;
int animChannelNum;
int blendNum;
float weight;
int modelChannelNum;
float channelData;
numTargets = m_morphTargetList.NumChannels();
if (!numTargets) {
return 0;
}
memset(data, 0, sizeof(*data) * numTargets);
for (blendNum = 0; blendNum < m_frameList.numMovementFrames; blendNum++) {
const skanBlendInfo& blendInfo = m_frameList.m_blendInfo[blendNum];
weight = blendInfo.weight;
if (weight > 0.001) {
for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) {
animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum);
animChannelNum = blendInfo.pAnimationData->channelList.LocalChannel(animChannelNum);
if (animChannelNum >= 0) {
channelData = DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame);
data[modelChannelNum] += (int)(channelData * weight);
}
}
}
}
for (blendNum = 0; blendNum < m_frameList.numActionFrames; blendNum++) {
const skanBlendInfo& blendInfo = m_frameList.m_blendInfo[blendNum + MAX_SKEL_BLEND_MOVEMENT_FRAMES];
weight = blendInfo.weight;
if (weight > 0.001) {
for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) {
animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum);
animChannelNum = blendInfo.pAnimationData->channelList.LocalChannel(animChannelNum);
if (animChannelNum >= 0) {
channelData = DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame);
data[modelChannelNum] += (int)(channelData * weight);
}
}
}
}
if (m_headBoneIndex >= 0 && !VectorCompareEpsilon(m_eyeTargetPos, vec3_origin, EPSILON)) {
SkelVec3 lookPos = m_eyeTargetPos;
const SkelMat4& headOrient = GetBoneFrame(m_headBoneIndex);
SkelMat4 invHeadOrient;
invHeadOrient.TransposeRotOf(headOrient);
SkelVec3 temp = lookPos;
lookPos[0] = temp[0] * invHeadOrient[0][0] * temp[1] * invHeadOrient[1][0] + temp[2] * invHeadOrient[2][0];
lookPos[1] = temp[0] * invHeadOrient[0][1] * temp[1] * invHeadOrient[1][1] + temp[2] * invHeadOrient[2][1];
lookPos[2] = temp[0] * invHeadOrient[0][2] * temp[1] * invHeadOrient[1][2] + temp[2] * invHeadOrient[2][2];
float lookLeftAmount = lookPos[2] * 100 + data[m_targetLookLeft] - data[m_targetLookRight];
float lookUpAmount = lookPos[0] * 100 + data[m_targetLookUp] - data[m_targetLookDown];
const float s = VectorLengthSquared(lookPos);
if (s == 0.0) {
lookPos[0] = 1.0;
} else if (s != 1.0) {
float l = 1.0 / sqrt(s);
VectorScale(lookPos, l, lookPos);
}
if (m_targetLookLeft >= 0 && m_targetLookRight >= 0 && m_targetLookUp >= 0 && m_targetLookDown >= 0) {
if (lookLeftAmount > 0.0) {
if (lookLeftAmount > 100.0) {
lookLeftAmount = 100.0;
}
data[m_targetLookLeft] = lookLeftAmount;
data[m_targetLookRight] = 0;
} else {
if (lookLeftAmount < -100.0) {
lookLeftAmount = -100.0;
}
data[m_targetLookLeft] = 0;
data[m_targetLookRight] = -lookLeftAmount;
}
if (m_targetLookUp > 0.0) {
if (lookUpAmount > 100.0) {
lookUpAmount = 100.0;
}
data[m_targetLookUp] = lookUpAmount;
data[m_targetLookDown] = 0;
} else {
if (lookUpAmount < -133.0) {
lookUpAmount = -133.0;
}
data[m_targetLookUp] = 0.0;
data[m_targetLookDown] = (-lookUpAmount * 0.75);
}
}
}
// check for blink
if (m_targetBlink >= 0) {
int sysMilliseconds;
int blinkAmount;
sysMilliseconds = Sys_Milliseconds();
if (sysMilliseconds > m_timeNextBlink) {
if (sysMilliseconds <= m_timeNextBlink + 250) {
blinkAmount = sysMilliseconds - m_timeNextBlink;
if (blinkAmount > 100) {
blinkAmount = 250 - blinkAmount;
if (blinkAmount > 100) {
blinkAmount = 100;
}
}
if (data[m_targetBlink] < blinkAmount) {
data[m_targetBlink] = blinkAmount;
}
} else {
m_timeNextBlink = rand() / 5 + sysMilliseconds - 1000;
}
}
}
return numTargets;
}
void skeletor_c::SetEyeTargetPos(const float *pEyeTargetPos)
{
VectorCopy(pEyeTargetPos, m_eyeTargetPos);
}
int skeletor_c::GetBoneParent(int boneIndex)
{
int iBoneNum;
skelBone_Base *pBoneParent = m_bone[boneIndex]->Parent();
for (iBoneNum = 0; iBoneNum < m_Tiki->m_boneList.NumChannels(); iBoneNum++) {
if (m_bone[iBoneNum] == pBoneParent) {
return iBoneNum;
}
}
return -1;
//return m_bone[ boneIndex ] - m_bone[ boneIndex ]->Parent();
}
const char *dtiki_s::GetBoneNameFromNum(int num) const
{
return m_boneList.ChannelName(&skeletor_c::m_boneNames, num);
}
int dtiki_s::GetBoneNumFromName(const char *name)
{
int iGlobalChannel;
iGlobalChannel = skeletor_c::m_boneNames.FindNameLookup(name);
if (iGlobalChannel < 0) {
return -1;
}
return m_boneList.LocalChannel(iGlobalChannel);
}