/* =========================================================================== 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 #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 - deltaWeight1; s = 1.0 - (frameNum2 - deltaWeight2); 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; } 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 = (int)(deltaWeight1 + 1.0); frameNum2 = (int)(deltaWeight2 + 1.0); d = frameNum1 - deltaWeight1; s = 1.0 - (frameNum2 - deltaWeight2); delta = 0; if (frameNum2 > frameNum1) { delta = m_frame[frameNum1 % numFrames].angleDelta; for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) { delta += m_frame[currFrame % numFrames].angleDelta; } } else { s = s - (1.0 - d); } delta += m_frame[frameNum2 % numFrames].angleDelta * s; 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; 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, 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 ); } 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 ); }