1026 lines
No EOL
50 KiB
C++
1026 lines
No EOL
50 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program 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 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : WW3D *
|
|
* *
|
|
* $Archive:: /Commando/Code/ww3d2/animobj.cpp $*
|
|
* *
|
|
* Author:: Greg_h *
|
|
* *
|
|
* $Modtime:: 12/13/01 6:56p $*
|
|
* *
|
|
* $Revision:: 10 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* Animatable3DObjClass::Animatable3DObjClass -- constructor *
|
|
* Animatable3DObjClass::Animatable3DObjClass -- copy constructor *
|
|
* Animatable3DObjClass::~Animatable3DObjClass -- destructor *
|
|
* Animatable3DObjClass::operator = -- assignment operator *
|
|
* Animatable3DObjClass::Release -- Releases any anims being held by this object *
|
|
* Animatable3DObjClass::Render -- Update this object for rendering *
|
|
* Animatable3DObjClass::Special_Render -- "special render" function for animatables *
|
|
* Animatable3DObjClass::Set_Transform -- sets the transform and marks sub-objects as dirty *
|
|
* Animatable3DObjClass::Set_Position -- Sets the position and marks sub-objects as dirty *
|
|
* Animatable3DObjClass::Get_Num_Bones -- returns number of bones in this object *
|
|
* Animatable3DObjClass::Get_Bone_Name -- returns the name of the given bone *
|
|
* Animatable3DObjClass::Get_Bone_Index -- returns the index of the given bone *
|
|
* Animatable3DObjClass::Set_Animation -- set the animation state to "none" (base pose) *
|
|
* Animatable3DObjClass::Set_Animation -- Set the animation state to the given anim/frame *
|
|
* Animatable3DObjClass::Set_Animation -- set the animation state to a blend of two anims *
|
|
* Animatable3DObjClass::Set_Animation -- Set animation state with an anim combo *
|
|
* Animatable3DObjClass::Get_Bone_Transform -- return the transform for the given bone *
|
|
* Animatable3DObjClass::Get_Bone_Transform -- return the transform for the given bone *
|
|
* Animatable3DObjClass::Capture_Bone -- capture the specified bone (override animation) *
|
|
* Animatable3DObjClass::Release_Bone -- release the specified bone (allow animation) *
|
|
* Animatable3DObjClass::Is_Bone_Captured -- returns whether the specified bone is captured *
|
|
* Animatable3DObjClass::Control_Bone -- sets the transform for the bone *
|
|
* Animatable3DObjClass::Update_Sub_Object_Transforms -- recalculate the transforms for our *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
|
#include "animobj.h"
|
|
#include "htree.h"
|
|
#include "assetmgr.h"
|
|
#include "hanim.h"
|
|
#include "hcanim.h"
|
|
#include "ww3d.h"
|
|
#include "wwmemlog.h"
|
|
#include "animatedsoundmgr.h"
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Animatable3DObjClass -- constructor *
|
|
* *
|
|
* INPUT: *
|
|
* htree_name -- name of the hierarchy tree which defines the "bone" structure for this object *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) :
|
|
IsTreeValid(0),
|
|
CurMotionMode(BASE_POSE)
|
|
{
|
|
// Inline struct members can't be initialized in init list for some reason...
|
|
ModeAnim.Motion=NULL;
|
|
ModeAnim.Frame=0.0f;
|
|
ModeAnim.PrevFrame=0.0f;
|
|
ModeAnim.LastSyncTime=WW3D::Get_Sync_Time();
|
|
ModeInterp.Motion0=NULL;
|
|
ModeInterp.Motion1=NULL;
|
|
ModeInterp.Frame0=0.0f;
|
|
ModeInterp.PrevFrame0=0.0f;
|
|
ModeInterp.PrevFrame1=0.0f;
|
|
ModeInterp.Frame1=0.0f;
|
|
ModeInterp.Percentage=0.0f;
|
|
ModeCombo.AnimCombo=NULL;
|
|
|
|
/*
|
|
** Store a pointer to the htree
|
|
*/
|
|
if (htree_name == NULL) {
|
|
HTree = NULL;
|
|
} else if (htree_name[0] == 0) {
|
|
HTree = new HTreeClass;
|
|
HTree->Init_Default ();
|
|
} else {
|
|
HTreeClass * source = WW3DAssetManager::Get_Instance()->Get_HTree(htree_name);
|
|
if (source != NULL) {
|
|
HTree = new HTreeClass(*source);
|
|
} else {
|
|
WWDEBUG_SAY(("Unable to find HTree: %s\r\n",htree_name));
|
|
HTree = new HTreeClass;
|
|
HTree->Init_Default();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Animatable3DObjClass -- copy constructor *
|
|
* *
|
|
* INPUT: *
|
|
* src -- animatable object to copy. *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) :
|
|
CompositeRenderObjClass(src),
|
|
IsTreeValid(0),
|
|
CurMotionMode(BASE_POSE),
|
|
HTree(NULL)
|
|
{
|
|
// Inline struct members can't be initialized in init list for some reason...
|
|
ModeAnim.Motion=NULL;
|
|
ModeAnim.Frame=0.0f;
|
|
ModeAnim.PrevFrame=0.0f;
|
|
ModeAnim.LastSyncTime=WW3D::Get_Sync_Time();
|
|
ModeInterp.Motion0=NULL;
|
|
ModeInterp.Motion1=NULL;
|
|
ModeInterp.Frame0=0.0f;
|
|
ModeInterp.PrevFrame0=0.0f;
|
|
ModeInterp.PrevFrame1=0.0f;
|
|
ModeInterp.Frame1=0.0f;
|
|
ModeInterp.Percentage=0.0f;
|
|
ModeCombo.AnimCombo=NULL;
|
|
|
|
*this = src;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::~Animatable3DObjClass -- destructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
Animatable3DObjClass::~Animatable3DObjClass(void)
|
|
{
|
|
Release();
|
|
|
|
if (HTree) {
|
|
delete HTree;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::operator = -- assignment operator *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjClass & that)
|
|
{
|
|
if (&that != this) {
|
|
Release();
|
|
if (HTree) {
|
|
delete HTree;
|
|
}
|
|
|
|
CompositeRenderObjClass::operator = (that);
|
|
|
|
IsTreeValid = 0;
|
|
CurMotionMode = BASE_POSE;
|
|
ModeAnim.Motion = NULL;
|
|
ModeAnim.Frame = 0.0f;
|
|
ModeAnim.PrevFrame = 0.0f;
|
|
ModeAnim.LastSyncTime = WW3D::Get_Sync_Time();
|
|
ModeInterp.Motion0 = NULL;
|
|
ModeInterp.Motion1 = NULL;
|
|
ModeInterp.Frame0 = 0.0f;
|
|
ModeInterp.PrevFrame0 = 0.0f;
|
|
ModeInterp.PrevFrame1 = 0.0f;
|
|
ModeInterp.Frame1 = 0.0f;
|
|
ModeInterp.Percentage = 0.0f;
|
|
ModeCombo.AnimCombo = NULL;
|
|
|
|
HTree = new HTreeClass(*that.HTree);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Release -- Releases any anims being held by this object *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Release( void )
|
|
{
|
|
switch (CurMotionMode) {
|
|
|
|
case BASE_POSE:
|
|
break;
|
|
|
|
case SINGLE_ANIM:
|
|
if ( ModeAnim.Motion != NULL ) {
|
|
ModeAnim.Motion->Release_Ref();
|
|
ModeAnim.Motion = NULL;
|
|
}
|
|
break;
|
|
|
|
case DOUBLE_ANIM:
|
|
if ( ModeInterp.Motion0 != NULL ) {
|
|
ModeInterp.Motion0->Release_Ref();
|
|
ModeInterp.Motion0 = NULL;
|
|
}
|
|
|
|
if ( ModeInterp.Motion1 != NULL ) {
|
|
ModeInterp.Motion1->Release_Ref();
|
|
ModeInterp.Motion1 = NULL;
|
|
}
|
|
break;
|
|
|
|
case MULTIPLE_ANIM:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Render -- Update this object for rendering *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Render(RenderInfoClass & rinfo)
|
|
{
|
|
if (HTree == NULL) return;
|
|
|
|
if (Is_Not_Hidden_At_All() == false) {
|
|
return;
|
|
}
|
|
|
|
if ( CurMotionMode == SINGLE_ANIM ) {
|
|
if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) {
|
|
Single_Anim_Progress();
|
|
}
|
|
}
|
|
|
|
if (!Is_Hierarchy_Valid() || Are_Sub_Object_Transforms_Dirty()) {
|
|
Update_Sub_Object_Transforms();
|
|
}
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Special_Render -- "special render" function for animatables *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/10/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Special_Render(SpecialRenderInfoClass & rinfo)
|
|
{
|
|
if (HTree == NULL) return;
|
|
|
|
if ( CurMotionMode == SINGLE_ANIM ) {
|
|
if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) {
|
|
Single_Anim_Progress();
|
|
}
|
|
}
|
|
|
|
if (!Is_Hierarchy_Valid()) {
|
|
Update_Sub_Object_Transforms();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Transform -- sets the transform and marks sub-objects as dirty *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Transform(const Matrix3D &m)
|
|
{
|
|
CompositeRenderObjClass::Set_Transform(m);
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Position -- Sets the position and marks sub-objects as dirty *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Position(const Vector3 &v)
|
|
{
|
|
CompositeRenderObjClass::Set_Position(v);
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Get_Num_Bones -- returns number of bones in this object *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
int Animatable3DObjClass::Get_Num_Bones(void)
|
|
{
|
|
if (HTree) {
|
|
return HTree->Num_Pivots();
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Get_Bone_Name -- returns the name of the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
const char * Animatable3DObjClass::Get_Bone_Name(int bone_index)
|
|
{
|
|
if (HTree) {
|
|
return HTree->Get_Bone_Name(bone_index);
|
|
} else {
|
|
return "RootTransform";
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Get_Bone_Index -- returns the index of the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
int Animatable3DObjClass::Get_Bone_Index(const char * bonename)
|
|
{
|
|
if (HTree) {
|
|
return HTree->Get_Bone_Index(bonename);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Animation -- set the animation state to "none" (base pose) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Animation(void)
|
|
{
|
|
Release();
|
|
CurMotionMode = BASE_POSE;
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Animation -- Set the animation state to the given anim/frame *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int mode)
|
|
{
|
|
|
|
if ( motion ) {
|
|
// Add_Ref before we remove, in case it is the same one.
|
|
motion->Add_Ref();
|
|
Release();
|
|
CurMotionMode = SINGLE_ANIM;
|
|
ModeAnim.Motion = motion;
|
|
ModeAnim.PrevFrame = ModeAnim.Frame;
|
|
ModeAnim.Frame = frame;
|
|
ModeAnim.LastSyncTime = WW3D::Get_Sync_Time();
|
|
ModeAnim.AnimMode = mode;
|
|
} else {
|
|
CurMotionMode = BASE_POSE;
|
|
Release();
|
|
}
|
|
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Animation -- set the animation state to a blend of two anims *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Animation
|
|
(
|
|
HAnimClass * motion0,
|
|
float frame0,
|
|
HAnimClass * motion1,
|
|
float frame1,
|
|
float percentage
|
|
)
|
|
{
|
|
Release();
|
|
|
|
CurMotionMode = DOUBLE_ANIM;
|
|
ModeInterp.Motion0 = motion0;
|
|
ModeInterp.Motion1 = motion1;
|
|
ModeInterp.PrevFrame0 = ModeInterp.Frame0;
|
|
ModeInterp.PrevFrame1 = ModeInterp.Frame1;
|
|
ModeInterp.Frame0 = frame0;
|
|
ModeInterp.Frame1 = frame1;
|
|
ModeInterp.Percentage = percentage;
|
|
Set_Hierarchy_Valid(false);
|
|
|
|
if ( ModeInterp.Motion0 != NULL ) {
|
|
ModeInterp.Motion0->Add_Ref();
|
|
}
|
|
|
|
if ( ModeInterp.Motion1 != NULL ) {
|
|
ModeInterp.Motion1->Add_Ref();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Set_Animation -- Set animation state with an anim combo *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Set_Animation
|
|
(
|
|
HAnimComboClass * anim_combo
|
|
)
|
|
{
|
|
Release();
|
|
|
|
CurMotionMode = MULTIPLE_ANIM;
|
|
ModeCombo.AnimCombo = anim_combo;
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Peek_Animation *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
HAnimClass * Animatable3DObjClass::Peek_Animation( void )
|
|
{
|
|
if ( CurMotionMode == SINGLE_ANIM ) {
|
|
return ModeAnim.Motion;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Get_Bone_Transform -- return the transform for the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
const Matrix3D & Animatable3DObjClass::Get_Bone_Transform(const char * bonename)
|
|
{
|
|
if (HTree) {
|
|
WWASSERT(HTree);
|
|
WWASSERT(bonename);
|
|
|
|
int idx = HTree->Get_Bone_Index(bonename);
|
|
return Get_Bone_Transform(idx);
|
|
} else {
|
|
return Get_Transform();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Get_Bone_Transform -- return the transform for the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
const Matrix3D & Animatable3DObjClass::Get_Bone_Transform(int boneindex)
|
|
{
|
|
Validate_Transform();
|
|
|
|
if (HTree) {
|
|
/*
|
|
** If our hierarchy isn't valid, we just need to evaluate our animation
|
|
** state.
|
|
*/
|
|
if (!Is_Hierarchy_Valid()) {
|
|
Update_Sub_Object_Transforms();
|
|
}
|
|
|
|
return HTree->Get_Transform(boneindex);
|
|
} else {
|
|
return Transform;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Capture_Bone -- capture the specified bone (override animation) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Capture_Bone(int boneindex)
|
|
{
|
|
if (HTree) {
|
|
HTree->Capture_Bone(boneindex);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Release_Bone -- release the specified bone (allow animation) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Release_Bone(int boneindex)
|
|
{
|
|
if (HTree) {
|
|
HTree->Release_Bone(boneindex);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Is_Bone_Captured -- returns whether the specified bone is captured *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
bool Animatable3DObjClass::Is_Bone_Captured(int boneindex) const
|
|
{
|
|
if (HTree) {
|
|
return HTree->Is_Bone_Captured(boneindex);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Control_Bone -- sets the transform for the bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/2/99 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Control_Bone(int bindex,const Matrix3D & objtm,bool world_space_translation)
|
|
{
|
|
#ifdef WWDEBUG
|
|
for (int j=0; j<3; j++) {
|
|
for (int i=0; i<4; i++) {
|
|
WWASSERT(WWMath::Is_Valid_Float(objtm[j][i]));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (HTree) {
|
|
HTree->Control_Bone(bindex,objtm,world_space_translation);
|
|
Set_Hierarchy_Valid(false);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Update_Sub_Object_Transforms -- recalculate the transforms for our su *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/8/98 GTH : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Update_Sub_Object_Transforms(void)
|
|
{
|
|
/*
|
|
** The RenderObj impementation will cause our 'container'
|
|
** to update if we are not valid yet
|
|
*/
|
|
CompositeRenderObjClass::Update_Sub_Object_Transforms();
|
|
|
|
/*
|
|
** Update the transforms
|
|
*/
|
|
switch (CurMotionMode) {
|
|
|
|
case BASE_POSE:
|
|
Base_Update(Transform);
|
|
break;
|
|
|
|
case SINGLE_ANIM:
|
|
if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) {
|
|
Single_Anim_Progress();
|
|
}
|
|
Anim_Update(Transform,ModeAnim.Motion,ModeAnim.Frame);
|
|
|
|
/*
|
|
** Play any sounds that are triggered by this frame of animation
|
|
*/
|
|
if ( ModeAnim.Motion->Has_Embedded_Sounds() ) {
|
|
ModeAnim.PrevFrame = AnimatedSoundMgrClass::Trigger_Sound(ModeAnim.Motion, ModeAnim.PrevFrame, ModeAnim.Frame, Get_Transform ());
|
|
}
|
|
break;
|
|
|
|
case DOUBLE_ANIM:
|
|
Blend_Update(Transform,ModeInterp.Motion0,ModeInterp.Frame0,
|
|
ModeInterp.Motion1,ModeInterp.Frame1,ModeInterp.Percentage);
|
|
|
|
/*
|
|
** Play any sounds that are triggered by this frame of animation
|
|
*/
|
|
if ( ModeInterp.Motion0->Has_Embedded_Sounds() ) {
|
|
ModeInterp.PrevFrame0 = AnimatedSoundMgrClass::Trigger_Sound(ModeInterp.Motion0, ModeInterp.PrevFrame0, ModeInterp.Frame0, Get_Transform ());
|
|
}
|
|
|
|
if ( ModeInterp.Motion1->Has_Embedded_Sounds() ) {
|
|
ModeInterp.PrevFrame1 = AnimatedSoundMgrClass::Trigger_Sound(ModeInterp.Motion1, ModeInterp.PrevFrame1, ModeInterp.Frame1, Get_Transform ());
|
|
}
|
|
|
|
break;
|
|
|
|
case MULTIPLE_ANIM:
|
|
{
|
|
Combo_Update(Transform,ModeCombo.AnimCombo);
|
|
|
|
/*
|
|
** Play any sounds that are triggered by this frame of animation
|
|
*/
|
|
int count = ModeCombo.AnimCombo->Get_Num_Anims();
|
|
for (int index = 0; index < count; index ++) {
|
|
HAnimClass *motion = ModeCombo.AnimCombo->Peek_Motion(index);
|
|
|
|
if ( motion != NULL && motion->Has_Embedded_Sounds() ) {
|
|
float prev_frame = AnimatedSoundMgrClass::Trigger_Sound(motion, ModeCombo.AnimCombo->Get_Prev_Frame(index),
|
|
ModeCombo.AnimCombo->Get_Frame(index), Get_Transform ());
|
|
ModeCombo.AnimCombo->Set_Prev_Frame(index, prev_frame);
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
Set_Hierarchy_Valid(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Simple_Evaluate_Bone -- If the animation is 'single', evaluate the *
|
|
* given pivot and return its transform. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/13/2000 PDS : Created. *
|
|
*=============================================================================================*/
|
|
bool Animatable3DObjClass::Simple_Evaluate_Bone(int boneindex, Matrix3D *tm) const
|
|
{
|
|
bool retval = false;
|
|
|
|
//
|
|
// Only do this for simple animations
|
|
//
|
|
if ( CurMotionMode == NONE ||
|
|
CurMotionMode == BASE_POSE ||
|
|
CurMotionMode == SINGLE_ANIM)
|
|
{
|
|
//
|
|
// Determine which frame we should be on, then use this
|
|
// information to determine the bone's transform.
|
|
//
|
|
float curr_frame = Compute_Current_Frame ();
|
|
retval = Simple_Evaluate_Bone (boneindex, curr_frame, tm);
|
|
|
|
} else {
|
|
|
|
const_cast <Animatable3DObjClass *>(this)->Update_Sub_Object_Transforms();
|
|
*tm = HTree->Get_Transform(boneindex);
|
|
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Simple_Evaluate_Bone -- If the animation is 'single', evaluate the *
|
|
* given pivot and return its transform. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/13/2000 PDS : Created. *
|
|
*=============================================================================================*/
|
|
bool Animatable3DObjClass::Simple_Evaluate_Bone(int boneindex, float frame, Matrix3D *tm) const
|
|
{
|
|
bool retval = false;
|
|
|
|
//
|
|
// Only do this for simple animations
|
|
//
|
|
if (HTree != NULL) {
|
|
|
|
if (CurMotionMode == SINGLE_ANIM) {
|
|
retval = HTree->Simple_Evaluate_Pivot (ModeAnim.Motion, boneindex, frame, Get_Transform (), tm);
|
|
} else if (CurMotionMode == NONE || CurMotionMode == BASE_POSE) {
|
|
retval = HTree->Simple_Evaluate_Pivot (boneindex, Get_Transform (), tm);
|
|
} else {
|
|
*tm = Transform;
|
|
}
|
|
|
|
} else {
|
|
*tm = Transform;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Compute_Current_Frame -- Returns the animation frame for the next rend*
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: Only works for Single and CSingle! *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/13/2000 PDS : Created. *
|
|
*=============================================================================================*/
|
|
float Animatable3DObjClass::Compute_Current_Frame() const
|
|
{
|
|
float frame = 0;
|
|
|
|
switch (CurMotionMode)
|
|
{
|
|
case SINGLE_ANIM:
|
|
{
|
|
frame = ModeAnim.Frame;
|
|
|
|
//
|
|
// Compute the current frame based on elapsed time.
|
|
//
|
|
if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) {
|
|
float sync_time_diff = WW3D::Get_Sync_Time() - ModeAnim.LastSyncTime;
|
|
frame += ModeAnim.Motion->Get_Frame_Rate() * sync_time_diff * 0.001f;
|
|
|
|
//
|
|
// Wrap the frame
|
|
//
|
|
switch (ModeAnim.AnimMode)
|
|
{
|
|
case ANIM_MODE_ONCE:
|
|
if (frame >= ModeAnim.Motion->Get_Num_Frames() - 1) {
|
|
frame = ModeAnim.Motion->Get_Num_Frames() - 1;
|
|
}
|
|
break;
|
|
|
|
case ANIM_MODE_LOOP:
|
|
if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) {
|
|
frame -= ModeAnim.Motion->Get_Num_Frames() - 1;
|
|
}
|
|
// If it is still too far out, reset
|
|
if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) {
|
|
frame = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Single_Anim_Progress -- progess anims for loop and once *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: Only works for Single and CSingle *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/26/99 BMG : Created. *
|
|
*=============================================================================================*/
|
|
void Animatable3DObjClass::Single_Anim_Progress (void)
|
|
{
|
|
//
|
|
// Update the current frame (only works in "SINGLE_ANIM" mode!)
|
|
//
|
|
if (CurMotionMode == SINGLE_ANIM) {
|
|
|
|
//
|
|
// Update the frame number and sync time
|
|
//
|
|
ModeAnim.PrevFrame = ModeAnim.Frame;
|
|
ModeAnim.Frame = Compute_Current_Frame();
|
|
ModeAnim.LastSyncTime = WW3D::Get_Sync_Time();
|
|
|
|
//
|
|
// Force the heirarchy to be recalculated
|
|
//
|
|
Set_Hierarchy_Valid (false);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Animatable3DObjClass::Is_Animation_Complete -- is the current animation on the last frame? *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: Only works for Single, ONCE anims *
|
|
* *
|
|
* HISTORY: *
|
|
* 4/13/99 BMG : Created. *
|
|
*=============================================================================================*/
|
|
bool Animatable3DObjClass::Is_Animation_Complete( void ) const
|
|
{
|
|
if (CurMotionMode == SINGLE_ANIM) {
|
|
|
|
if ( ModeAnim.AnimMode == ANIM_MODE_ONCE ) {
|
|
return ( ModeAnim.Frame == ModeAnim.Motion->Get_Num_Frames() - 1 );
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// (gth) TESTING DYNAMICALLY SWAPPING SKELETONS!
|
|
|
|
void Animatable3DObjClass::Set_HTree(HTreeClass * new_htree)
|
|
{
|
|
WWMEMLOG(MEM_ANIMATION);
|
|
// try to ensure that the htree we're using has the same structure...
|
|
WWASSERT(new_htree->Num_Pivots() == HTree->Num_Pivots());
|
|
|
|
// just assign it...
|
|
if (HTree != NULL) {
|
|
delete HTree;
|
|
}
|
|
HTree = new HTreeClass(*new_htree);
|
|
}
|
|
|
|
|
|
// EOF - animobj.cpp
|