openmohaa/code/skeletor/skeletor.cpp

1255 lines
30 KiB
C++

/*
===========================================================================
Copyright (C) 2015 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
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 = ( int )( deltaWeight1 + 1.0 );
frameNum2 = ( int )( deltaWeight2 + 1.0 );
d = frameNum1 - ( time1 / frameTime );
s = 1.0 - ( frameNum2 - ( time2 / frameTime ) );
if( frameNum1 < frameNum2 )
{
delta = m_frame[ frameNum1 % numFrames ].delta;
for( currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++ )
{
delta += m_frame[ currFrame % numFrames ].delta;
}
}
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;
}
skelAnimDataGameHeader_t *skelAnimDataGameHeader_s::AllocAnimData( int numFrames, int numChannels )
{
skelAnimDataGameHeader_t *data;
int animSize;
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( int 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;
if( !data || data == ( skelAnimDataGameHeader_t * )-476 )
{
return;
}
for( i = 0; i < data->nTotalChannels; i++ )
{
pChannel = &data->ary_channels[ i ];
if( pChannel->ary_frames )
{
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( i = 0; i < 5; i++ )
{
contNum = contIndices[ i ];
if( contNum != -1 )
{
cutoff_weight = ( contValues[ i ][ 3 ] - 1.0 ) * ( contValues[ i ][ 3 ] - 1.0 );
if( cutoff_weight >= EPSILON )
{
m_bone[ contNum ]->m_controller = ( float * )contValues[ i ];
}
}
}
}
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 = 32;
aliases = m_Tiki->a->m_aliases;
for( i = 0; i < MAX_FRAMEINFOS; i++ )
{
if( animWeight < frameInfo[ i ].weight ) {
animWeight = frameInfo[ i ].weight;
}
}
cutoff_weight = animWeight * 0.01f;
for( i = 0; i < MAX_FRAMEINFOS; i++ )
{
if( frameInfo[ i ].weight > cutoff_weight )
{
animData = SkeletorCacheGetData( aliases[ frameInfo[ i ].index ] );
if( animData->bHasDelta ) {
blendFrame = movementBlendFrame;
} else {
blendFrame = actionBlendFrame;
}
beforeWeight = 0.0;
afterWeight = 0.0;
beforeFrame = 0.0;
afterFrame = 0.0;
numFramesAdded = animData->GetFrameNums( frameInfo[ i ].time, 0.01f, &beforeFrame, &afterFrame, &beforeWeight, &afterWeight );
frame1 = &m_frameList.m_blendInfo[ blendFrame ];
frame1->frame = beforeFrame;
frame1->pAnimationData = animData;
frame1->weight = beforeWeight * frameInfo[ i ].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 * frameInfo[ i ].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;
}
blendNum = blendFrame + numFramesAdded;
if( animData->bHasDelta ) {
movementBlendFrame = blendNum;
} else {
actionBlendFrame = blendNum;
}
}
}
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 - 32;
m_frameList.actionWeight = actionWeight;
}
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[32].weight = 1.0;
frameList.m_blendInfo[32].pAnimationData = animData;
frameList.m_blendInfo[32].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[32].weight = 1.0;
frameList.m_blendInfo[32].pAnimationData = animData;
frameList.m_blendInfo[32].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, NULL, NULL, NULL );
}
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 );
}
vec4_t *DecodeFrameValue( skanChannelHdr *channelFrames, int desiredFrameNum )
{
skanGameFrame *foundFrame;
int i;
foundFrame = channelFrames->ary_frames;
for( i = 0; i < channelFrames->nFramesInChannel; i++ )
{
if( channelFrames->ary_frames[ i ].nFrameNum >= desiredFrameNum )
{
foundFrame = &channelFrames->ary_frames[ i ];
break;
}
}
return &foundFrame->pChannelData;
}
int skeletor_c::GetMorphWeightFrame( int *data )
{
int numTargets;
int animChannelNum;
int blendNum;
float weight;
int modelChannelNum;
vec4_t *channelData;
numTargets = m_morphTargetList.NumChannels();
if( !numTargets ) {
return 0;
}
memset( data, 0, sizeof( *data ) * numTargets );
for( blendNum = 0; blendNum < m_frameList.numMovementFrames; blendNum++ )
{
weight = m_frameList.m_blendInfo[ blendNum ].weight;
if( weight > 0.001 )
{
for( modelChannelNum = 0; modelChannelNum < m_morphTargetList.NumChannels(); modelChannelNum++ )
{
animChannelNum = m_morphTargetList.m_chanGlobalFromLocal[ modelChannelNum ];
animChannelNum = m_morphTargetList.GetLocalFromGlobal( animChannelNum );
if( animChannelNum >= 0 )
{
channelData = DecodeFrameValue( &m_frameList.m_blendInfo[ blendNum ].pAnimationData->ary_channels[ animChannelNum ], m_frameList.m_blendInfo[ blendNum ].frame );
data[ modelChannelNum ] += ( int )( ( *channelData )[ 0 ] * weight );
}
}
}
}
for( blendNum = 32; blendNum < m_frameList.numActionFrames + 32; blendNum++ )
{
weight = m_frameList.m_blendInfo[ blendNum ].weight;
if( weight > 0.001 )
{
for( modelChannelNum = 0; modelChannelNum < m_morphTargetList.NumChannels(); modelChannelNum++ )
{
animChannelNum = m_morphTargetList.m_chanGlobalFromLocal[ modelChannelNum ];
animChannelNum = m_morphTargetList.GetLocalFromGlobal( animChannelNum );
if( animChannelNum >= 0 )
{
channelData = DecodeFrameValue( &m_frameList.m_blendInfo[ blendNum ].pAnimationData->ary_channels[ animChannelNum ], m_frameList.m_blendInfo[ blendNum ].frame );
data[ modelChannelNum ] += ( int )( ( *channelData )[ 0 ] * 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.GetLocalFromGlobal( iGlobalChannel );
}