mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1267 lines
38 KiB
C++
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);
|
|
}
|