/*==LICENSE==*
CyanWorlds . com Engine - MMOG client , server and tools
Copyright ( C ) 2011 Cyan Worlds , 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/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program , or any covered work , by linking or
combining it with any of RAD Game Tools Bink SDK , Autodesk 3 ds Max SDK ,
NVIDIA PhysX SDK , Microsoft DirectX SDK , OpenSSL library , Independent
JPEG Group JPEG library , Microsoft Windows Media SDK , or Apple QuickTime SDK
( or a modified version of those libraries ) ,
containing parts covered by the terms of the Bink SDK EULA , 3 ds Max EULA ,
PhysX SDK EULA , DirectX SDK EULA , OpenSSL and SSLeay licenses , IJG
JPEG Library README , Windows Media SDK EULA , or QuickTime SDK EULA , the
licensors of this Program grant you additional
permission to convey the resulting work . Corresponding Source for a
non - source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work .
You can contact Cyan Worlds , Inc . by email legal @ cyan . com
or by snail mail at :
Cyan Worlds , Inc .
14617 N Newport Hwy
Mead , WA 99021
* = = LICENSE = = */
# include <functional>
# include <math.h>
# include <memory>
# include "HeadSpin.h"
# include "hsExceptionStack.h"
# include "hsTemplates.h"
# include "hsWindows.h"
# include <commdlg.h>
# include <cmath>
# include <stdmat.h>
# include <bmmlib.h>
# include <istdplug.h>
# include <iparamb2.h>
# include <modstack.h>
# include <keyreduc.h>
# pragma hdrstop
# include "MaxMain/plMaxNode.h"
# include "hsMaxLayerBase.h"
# include "plInterp/plAnimEaseTypes.h"
# include "plInterp/plController.h"
# include "plInterp/hsInterp.h"
# include "MaxExport/plErrorMsg.h"
# include "UserPropMgr.h"
# include "hsConverterUtils.h"
# include "hsControlConverter.h"
# include "hsMaterialConverter.h"
# include "MaxExport/plErrorMsg.h"
# include "MaxComponent/plNoteTrackAnim.h"
# include "MaxComponent/plCameraComponents.h"
# include "MaxComponent/plAnimComponent.h"
# include "pnSceneObject/plSceneObject.h"
# include "pnSceneObject/plCoordinateInterface.h"
typedef std : : unique_ptr < IKey , std : : function < void ( IKey * ) > > ikey_ptr ;
/** Allocates a managed buffer to store derivatives of IKey */
static ikey_ptr IAllocKey ( size_t size )
{
return ikey_ptr (
reinterpret_cast < IKey * > ( new uint8_t [ size ] ) ,
[ ] ( IKey * ptr ) { delete [ ] reinterpret_cast < uint8_t * > ( ptr ) ; } ) ;
}
//////////////////////////////////////////////////////////////////////////
extern UserPropMgr gUserPropMgr ;
hsControlConverter & hsControlConverter : : Instance ( )
{
static hsControlConverter the_instance ;
return the_instance ;
}
hsControlConverter : : hsControlConverter ( ) : fConverterUtils ( hsConverterUtils : : Instance ( ) )
{
}
void hsControlConverter : : Init ( plErrorMsg * msg )
{
hsGuardBegin ( " hsControlConverter::Init " ) ;
fInterface = GetCOREInterface ( ) ;
fErrorMsg = msg ;
fTicksPerFrame = : : GetTicksPerFrame ( ) ; /*160*/
fFrameRate = : : GetFrameRate ( ) ; /*30*/
fTicksPerSec = fTicksPerFrame * fFrameRate ;
Interval interval = fInterface - > GetAnimRange ( ) ;
fStartFrame = interval . Start ( ) / fTicksPerFrame ;
fEndFrame = interval . End ( ) / fTicksPerFrame ;
fNumFrames = fEndFrame - fStartFrame + 1 ;
fAnimLength = ( float ) ( fNumFrames - 1 ) / fFrameRate ;
fWarned = false ;
fForceLocal = false ;
fSegStart = fSegEnd = - 1 ;
hsGuardEnd ;
}
void hsControlConverter : : DeInit ( )
{
}
// dummy class that ApplyKeyReduction needs
class KRStatus : public KeyReduceStatus
{
void Init ( int total ) { }
int Progress ( int p ) { return KEYREDUCE_CONTINUE ; }
} ;
void hsControlConverter : : ReduceKeys ( Control * control , float threshold )
{
if ( control = = nil | | threshold < = 0 )
return ;
KRStatus status ;
if ( control - > IsLeaf ( ) )
{
if ( control - > IsKeyable ( ) )
{
IKeyControl * keyCont = GetKeyControlInterface ( control ) ;
if ( keyCont - > GetNumKeys ( ) > 2 )
{
IKey * key1 = ( IKey * ) new uint8_t [ keyCont - > GetKeySize ( ) ] ;
IKey * key2 = ( IKey * ) new uint8_t [ keyCont - > GetKeySize ( ) ] ;
keyCont - > GetKey ( 0 , key1 ) ;
keyCont - > GetKey ( keyCont - > GetNumKeys ( ) - 1 , key2 ) ;
// We want the interval to be one frame past the start and one frame
// before the end, to guarantee we leave the first and last keys
// alone. This will make sure a looping anim still lines up, and
// also prevents us from removing the controller entirely and thinking
// this channel just isn't animated at all.
//
// Also, I think this is a Max bug (since we're using Max's key reduce
// function, and the same error happens without our plugins), but if
// your range is only one frame short of the end of the anim, some
// bones get flipped on that 2nd-to-last frame. So you get a single
// frame with something like your arm pointing in the opposite
// direction at the elbow.
TimeValue start = key1 - > time + GetTicksPerFrame ( ) ;
TimeValue end = key2 - > time - 2 * GetTicksPerFrame ( ) ;
if ( start < end )
{
Interval interval ( start , end ) ;
ApplyKeyReduction ( control , interval , threshold , GetTicksPerFrame ( ) , & status ) ;
}
delete [ ] ( uint8_t * ) key1 ;
delete [ ] ( uint8_t * ) key2 ;
}
}
}
else
{
int i ;
for ( i = 0 ; i < control - > NumSubs ( ) ; i + + )
ReduceKeys ( ( Control * ) control - > SubAnim ( i ) , threshold ) ;
}
}
plController * hsControlConverter : : ConvertTMAnim ( plSceneObject * obj , plMaxNode * node , hsAffineParts * parts ,
float start /* = -1 */ , float end /* = -1 */ )
{
Control * maxTm = node - > GetTMController ( ) ;
plController * tmc = hsControlConverter : : Instance ( ) . MakeTransformController ( maxTm , node , start , end ) ;
if ( tmc )
{
const plCoordinateInterface * ci = obj - > GetCoordinateInterface ( ) ;
if ( ci )
{
const hsMatrix44 & loc2Par = ci - > GetLocalToParent ( ) ;
gemAffineParts ap ;
decomp_affine ( loc2Par . fMap , & ap ) ;
AP_SET ( ( * parts ) , ap ) ;
}
}
return tmc ;
}
bool hsControlConverter : : HasKeyTimes ( Control * ctl )
{
hsGuardBegin ( " hsControlConverter::HasKeyTimes " ) ;
if ( ! ctl )
{
return false ;
}
return ( ctl - > NumKeys ( ) > 1 ) ;
hsGuardEnd ;
}
plLeafController * hsControlConverter : : MakeMatrix44Controller ( StdUVGen * uvGen , const char * nodeName )
{
hsGuardBegin ( " hsControlConverter::MakeMatrix44Controller " ) ;
if ( ! uvGen )
return nil ;
ISetSegRange ( - 1 , - 1 ) ;
Tab < TimeValue > kTimes ;
kTimes . ZeroCount ( ) ;
Control * uScaleCtl = nil ;
Control * vScaleCtl = nil ;
Control * uOffCtl = nil ;
Control * vOffCtl = nil ;
Control * rotCtl = nil ;
GetControllerByName ( uvGen , TSTR ( " U Offset " ) , uOffCtl ) ;
GetControllerByName ( uvGen , TSTR ( " V Offset " ) , vOffCtl ) ;
GetControllerByName ( uvGen , TSTR ( " U Tiling " ) , uScaleCtl ) ;
GetControllerByName ( uvGen , TSTR ( " V Tiling " ) , vScaleCtl ) ;
GetControllerByName ( uvGen , TSTR ( " Angle " ) , rotCtl ) ;
// new with Max R2, replacing "Angle", but it doesn't hurt to look...
Control * uAngCtl = nil ;
Control * vAngCtl = nil ;
Control * wAngCtl = nil ;
GetControllerByName ( uvGen , TSTR ( " U Angle " ) , uAngCtl ) ;
GetControllerByName ( uvGen , TSTR ( " V Angle " ) , vAngCtl ) ;
GetControllerByName ( uvGen , TSTR ( " W Angle " ) , wAngCtl ) ;
int i ;
CompositeKeyTimes ( uOffCtl , kTimes ) ;
CompositeKeyTimes ( vOffCtl , kTimes ) ;
CompositeKeyTimes ( uScaleCtl , kTimes ) ;
CompositeKeyTimes ( vScaleCtl , kTimes ) ;
CompositeKeyTimes ( rotCtl , kTimes ) ;
CompositeKeyTimes ( uAngCtl , kTimes ) ;
CompositeKeyTimes ( vAngCtl , kTimes ) ;
CompositeKeyTimes ( wAngCtl , kTimes ) ;
const float kMaxRads = 30.f * M_PI / 180.f ;
MaxSampleAngles ( nodeName , uAngCtl , kTimes , kMaxRads ) ;
MaxSampleAngles ( nodeName , vAngCtl , kTimes , kMaxRads ) ;
MaxSampleAngles ( nodeName , wAngCtl , kTimes , kMaxRads ) ;
if ( kTimes . Count ( ) < 2 )
{
return nil ;
}
plLeafController * ctrl = new plLeafController ;
ctrl - > AllocKeys ( kTimes . Count ( ) , hsKeyFrame : : kMatrix44KeyFrame ) ;
TimeValue resetTime = fConverterUtils . GetTime ( fInterface ) ;
for ( i = 0 ; i < kTimes . Count ( ) ; i + + )
{
Interval v ;
uvGen - > Update ( kTimes [ i ] , v ) ;
// Get key
float secs = ( float ) kTimes [ i ] / fTicksPerSec ;
int frameNum = kTimes [ i ] / fTicksPerFrame ;
hsAssert ( frameNum < = hsKeyFrame : : kMaxFrameNumber , " Anim is too long. " ) ;
fErrorMsg - > Set ( ( frameNum < fStartFrame | | frameNum > fEndFrame ) , nodeName ,
" Warning: Skipping keyframes outside of animation interval " ) . CheckAndAsk ( ) ;
hsMatrix44Key * key = ctrl - > GetMatrix44Key ( i ) ;
StdUVGenToHsMatrix44 ( & key - > fValue , uvGen , true ) ;
key - > fFrame = frameNum ;
}
return ctrl ;
hsGuardEnd ;
}
plLeafController * hsControlConverter : : MakeMatrix44Controller ( Control * prsControl )
{
hsGuardBegin ( " hsControlConverter::MakeMatrix44Controller " ) ;
ISetSegRange ( - 1 , - 1 ) ;
Tab < TimeValue > kTimes ;
kTimes . ZeroCount ( ) ;
Control * posCtl = nil ;
Control * scaleCtl = nil ;
Control * rotCtl = nil ;
posCtl = prsControl - > GetPositionController ( ) ;
rotCtl = prsControl - > GetRotationController ( ) ;
scaleCtl = prsControl - > GetScaleController ( ) ;
int i ;
CompositeKeyTimes ( posCtl , kTimes ) ;
CompositeKeyTimes ( scaleCtl , kTimes ) ;
CompositeKeyTimes ( rotCtl , kTimes ) ;
if ( kTimes . Count ( ) < 2 )
{
return nil ;
}
plLeafController * ctrl = new plLeafController ;
ctrl - > AllocKeys ( kTimes . Count ( ) , hsKeyFrame : : kMatrix44KeyFrame ) ;
TimeValue resetTime = fConverterUtils . GetTime ( fInterface ) ; ;
for ( i = 0 ; i < kTimes . Count ( ) ; i + + )
{
// Get key
float secs = ( float ) kTimes [ i ] / fTicksPerSec ;
int frameNum = kTimes [ i ] / fTicksPerFrame ;
hsAssert ( frameNum < = hsKeyFrame : : kMaxFrameNumber , " Anim is too long. " ) ;
Matrix3 maxXform ;
maxXform . IdentityMatrix ( ) ;
Interval valid = FOREVER ;
prsControl - > GetValue ( fConverterUtils . GetTime ( fInterface ) , & maxXform , valid , CTRL_RELATIVE ) ;
hsMatrix44Key * key = ctrl - > GetMatrix44Key ( i ) ;
Matrix3ToHsMatrix44 ( & maxXform , & key - > fValue ) ;
key - > fFrame = frameNum ;
}
return ctrl ;
hsGuardEnd ;
}
//
// Create a plScalarController and store the nodes parm behavior in it.
//
plLeafController * hsControlConverter : : MakeScalarController ( Control * control , plMaxNode * node ,
float start /* = -1 */ , float end /* = -1 */ )
{
hsGuardBegin ( " hsControlConverter::MakeScalarController " ) ;
if ( control = = NULL )
return NULL ;
ISetSegRange ( start , end ) ;
return ICreateScalarController ( node , control ) ;
hsGuardEnd ;
}
plController * hsControlConverter : : MakeColorController ( Control * control , plMaxNode * node ,
float start /* = -1 */ , float end /* = -1 */ )
{
return MakePosController ( control , node , start , end ) ;
}
//
// Create a plPosController and store the nodes parm behavior in it.
//
plController * hsControlConverter : : MakePosController ( Control * control , plMaxNode * node ,
float start /* = -1 */ , float end /* = -1 */ )
{
hsGuardBegin ( " hsControlConverter::MakePosController " ) ;
if ( control = = NULL )
return NULL ;
ISetSegRange ( start , end ) ;
plController * hsCont ;
if ( control - > IsLeaf ( ) )
{
hsCont = ICreateSimplePosController ( node , control ) ;
}
else
{
hsCont = new plCompoundController ;
fErrorMsg - > Set ( control - > NumSubs ( ) ! = 3 , node - > GetName ( ) , " compound should have 3 subs " ) . Check ( ) ;
if ( control - > ClassID ( ) = = Class_ID ( POSITIONNOISE_CONTROL_CLASS_ID , 0 ) )
{
MessageBox ( GetActiveWindow ( ) , node - > GetName ( ) ,
" Warning: Noise position controller not supported. Ignoring. " , MB_OK ) ;
return hsCont ;
}
bool keep = false ;
for ( int i = 0 ; i < 3 ; i + + )
{
Control * sub = ( Control * ) control - > SubAnim ( i ) ;
plLeafController * sc = ICreateScalarController ( node , sub ) ;
( ( plCompoundController * ) hsCont ) - > SetController ( i , sc ) ;
if ( sc )
{
keep = true ;
}
}
if ( ! keep )
{
delete hsCont ;
hsCont = nil ;
}
}
return hsCont ;
hsGuardEnd ;
}
plController * hsControlConverter : : MakeScaleController ( Control * control , plMaxNode * node ,
float start /* = -1 */ , float end /* = -1 */ )
{
ISetSegRange ( start , end ) ;
if ( control - > IsLeaf ( ) )
{
// Simple scale: linear, bezier, tcb
plLeafController * sc = ICreateSimpleScaleController ( node , control ) ;
return sc ;
}
else
{
// compound scale: noise
if ( control - > ClassID ( ) = = Class_ID ( SCALENOISE_CONTROL_CLASS_ID , 0 ) )
{
MessageBox ( GetActiveWindow ( ) , node - > GetName ( ) ,
" Warning: Noise scale controller not supported. Ignoring. " , MB_OK ) ;
}
}
return NULL ;
}
plController * hsControlConverter : : MakeRotController ( Control * control , plMaxNode * node , bool camRot /* = false */ ,
float start /* = -1 */ , float end /* = -1 */ )
{
ISetSegRange ( start , end ) ;
if ( control - > IsLeaf ( ) )
{
// simple rot: linear, smooth, tcb
plLeafController * rc = ICreateSimpleRotController ( node , control , camRot ) ;
return rc ;
}
else
{
// compound rot: euler or noise
if ( control - > NumSubs ( ) )
{
if ( control - > ClassID ( ) = = Class_ID ( ROTATIONNOISE_CONTROL_CLASS_ID , 0 ) )
{
MessageBox ( GetActiveWindow ( ) , node - > GetName ( ) ,
" Warning: Noise rotation controller not supported. Ignoring. " , MB_OK ) ;
return nil ;
}
if ( fErrorMsg - > Set ( control - > ClassID ( ) ! = Class_ID ( EULER_CONTROL_CLASS_ID , 0 ) ,
node - > GetName ( ) , " Expecting euler rot ctrler " ) . CheckAndAsk ( ) )
return nil ;
if ( fErrorMsg - > Set ( control - > NumSubs ( ) ! = 3 , node - > GetName ( ) , " Rot compound controller should have 3 subcontrollers " ) . CheckAndAsk ( ) )
return nil ;
plCompoundController * rc = new plCompoundController ;
int i ;
for ( i = 0 ; i < 3 ; i + + )
{
Control * sub = ( Control * ) control - > SubAnim ( i ) ;
plLeafController * sc = ICreateScalarController ( node , sub ) ;
rc - > SetController ( i , sc ) ;
}
//
// Check if we need to fixup euler due to missing subcontrollers
//
int numRotConts ;
for ( numRotConts = 0 , i = 0 ; i < 3 ; i + + )
if ( rc - > GetController ( i ) )
numRotConts + + ;
if ( numRotConts > 0 & & numRotConts < 3 )
{
// Someone has deleted 1 or 2 of the subcontrollers
// Add a key at the start and end of the missing tracks
Interval interval = fInterface - > GetAnimRange ( ) ;
TimeValue startTime = interval . Start ( ) ; // in ticks
TimeValue endTime = interval . End ( ) ; // in ticks
hsStatusMessage ( " Fixing up euler controller due to missing subcontrollers \n " ) ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( ! rc - > GetController ( i ) )
{
Control * sub = ( Control * ) control - > SubAnim ( i ) ;
if ( ! sub )
continue ;
sub - > AddNewKey ( startTime , ADDKEY_INTERP ) ;
sub - > AddNewKey ( endTime , ADDKEY_INTERP ) ;
plLeafController * sc = ICreateScalarController ( node , sub ) ;
if ( sc )
rc - > SetController ( i , sc ) ;
else
{
fErrorMsg - > Set ( true , " Scalar Controller Error " , " nil plScalar controller " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return rc ;
}
}
}
for ( numRotConts = 0 , i = 0 ; i < 3 ; i + + )
if ( rc - > GetController ( i ) )
numRotConts + + ;
if ( numRotConts ! = 3 )
{
fErrorMsg - > Set ( true , " Euler Fixup Error " , " Euler fixup failed. " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return rc ;
}
}
else if ( numRotConts = = 0 ) // No sub controllers, no point in having the compound controller then
{
delete rc ;
rc = nil ;
}
return rc ;
}
}
return NULL ;
}
void hsControlConverter : : ScalePositionController ( plController * ctl , float scale )
{
plLeafController * simp = plLeafController : : ConvertNoRef ( ctl ) ;
plCompoundController * comp ;
int i ;
if ( simp )
{
for ( i = 0 ; i < simp - > GetNumKeys ( ) ; i + + )
{
hsPoint3Key * key = simp - > GetPoint3Key ( i ) ;
if ( key )
{
key - > fValue * = scale ;
}
hsBezPoint3Key * bezKey = simp - > GetBezPoint3Key ( i ) ;
if ( bezKey )
{
bezKey - > fInTan * = scale ;
bezKey - > fOutTan * = scale ;
bezKey - > fValue * = scale ;
}
}
}
else if ( comp = plCompoundController : : ConvertNoRef ( ctl ) )
{
for ( i = 0 ; i < 3 ; i + + )
{
ScalePositionController ( comp - > GetController ( i ) , scale ) ;
}
}
}
void hsControlConverter : : MaxSampleAngles ( const char * nodeName , Control * ctl , Tab < TimeValue > & kTimes , float maxRads )
{
hsGuardBegin ( " hsControlConverter::MaxSampleAngles " ) ;
if ( ! ctl )
{
return ;
}
Tab < TimeValue > rTimes ;
Tab < TimeValue > sTimes ;
rTimes . ZeroCount ( ) ;
IGetControlSampleTimes ( ctl , 0 , ctl - > NumKeys ( ) , rTimes , maxRads ) ;
int iR ;
for ( iR = 0 ; iR < rTimes . Count ( ) ; iR + + )
{
int iK ;
for ( iK = 0 ; iK < kTimes . Count ( ) ; iK + + )
{
if ( kTimes [ iK ] > = rTimes [ iR ] )
break ;
}
if ( kTimes [ iK ] ! = rTimes [ iR ] )
kTimes . Insert ( iK , 1 , rTimes . Addr ( iR ) ) ;
}
hsGuardEnd ;
}
plCompoundController * hsControlConverter : : MakeTransformController ( Control * control , plMaxNode * node ,
float start /* = -1 */ , float end /* = -1 */ )
{
hsGuardBegin ( " hsControlConverter::MakeTransformController " ) ;
if ( ! control )
return NULL ;
ISetSegRange ( start , end ) ;
Class_ID cid = control - > ClassID ( ) ;
if ( cid = = Class_ID ( PRS_CONTROL_CLASS_ID , 0 ) | |
cid = = Class_ID ( LOOKAT_CONTROL_CLASS_ID , 0 ) )
{
int n = control - > NumSubs ( ) ;
if ( n ! = 3 )
{
fErrorMsg - > Set ( true , " Transform Controller Error " , " Transform controller doesn't have 3 sub controllers " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return NULL ;
}
plCompoundController * tmc = new plCompoundController ;
for ( int i = 0 ; i < n ; i + + )
{
Control * sub = ( Control * ) control - > SubAnim ( i ) ;
if ( sub )
{
IConvertSubTransform ( sub , control - > SubAnimName ( i ) , node , tmc , start , end ) ;
}
}
if ( cid = = Class_ID ( LOOKAT_CONTROL_CLASS_ID , 0 ) )
{
hsTArray < hsG3DSMaxKeyFrame > kfArray ;
IAddPartsKeys ( control , & kfArray , node ) ;
bool ignoreFOV = false ;
for ( int i = 0 ; i < node - > NumAttachedComponents ( ) ; i + + )
{
if ( node - > GetAttachedComponent ( i ) - > ClassID ( ) = = ANIMCAM_CMD_CID )
{
plCameraAnimCmdComponent * pAnimComp = ( plCameraAnimCmdComponent * ) node - > GetAttachedComponent ( i ) ;
ignoreFOV = pAnimComp - > IgnoreFOV ( ) ;
break ;
}
}
if ( ! ignoreFOV )
IExportAnimatedCameraFOV ( node , & kfArray ) ;
}
if ( tmc - > GetPosController ( ) | | tmc - > GetRotController ( ) | | tmc - > GetScaleController ( ) )
return tmc ;
else
{
delete tmc ;
return NULL ;
}
}
return NULL ;
hsGuardEnd ;
}
void hsControlConverter : : ISetSegRange ( float start , float end )
{
fSegStart = ( start > = 0 ? fTicksPerSec * start : fInterface - > GetAnimRange ( ) . Start ( ) ) ;
fSegEnd = ( end > = 0 ? fTicksPerSec * end : fInterface - > GetAnimRange ( ) . End ( ) ) ;
}
void hsControlConverter : : IConvertSubTransform ( Control * control , char * ctlName , plMaxNode * node , plCompoundController * tmc ,
float start , float end )
{
if ( control )
{
ControllerType ct = IGetControlType ( ctlName ) ;
switch ( ct )
{
case ctrlTypePosition :
{
if ( tmc - > GetPosController ( ) ! = nil )
{
fErrorMsg - > Set ( true , " Position Controller Error " , " Non-nil position controller " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return ;
}
tmc - > SetPosController ( MakePosController ( control , node , start , end ) ) ;
}
break ;
case ctrlTypeRollAngle :
case ctrlTypeRotation :
{
if ( tmc - > GetRotController ( ) ! = nil )
{
fErrorMsg - > Set ( true , " Position Controller Error " , " Non-nil Rotation controller " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return ;
}
bool camRot = ( ct = = ctrlTypeRollAngle ) ;
tmc - > SetRotController ( MakeRotController ( control , node , camRot , start , end ) ) ;
}
break ;
case ctrlTypeScale :
{
if ( tmc - > GetScaleController ( ) ! = nil )
{
fErrorMsg - > Set ( true , " Scale Controller Error " , " Non-nil Scale Controller " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return ;
}
tmc - > SetScaleController ( MakeScaleController ( control , node , start , end ) ) ;
}
break ;
default :
/*
if ( plExp . GetLogFile ( ) )
fprintf ( plExp . GetLogFile ( ) , " %s unknown ctrl type=%d \n " , node - > GetName ( ) , ( int ) ct ) ;
*/
break ;
}
}
}
//
//
//
plLeafController * hsControlConverter : : ICreateSimpleRotController ( plMaxNode * node , Control * control , bool camRot )
{
hsGuardBegin ( " hsControlConverter::ICreateSimpleRotController " ) ;
return ICreateQuatController ( node , control , true , camRot ) ;
hsGuardEnd ;
}
plLeafController * hsControlConverter : : ICreateSimpleScaleController ( plMaxNode * node , Control * control )
{
hsGuardBegin ( " hsControlConverter::ICreateSimpleScaleController " ) ;
return ICreateScaleValueController ( node , control ) ;
hsGuardEnd ;
}
//
//
//
plLeafController * hsControlConverter : : ICreateQuatController ( plMaxNode * node , Control * control , bool rotation , bool camRot )
{
hsGuardBegin ( " hsControlConverter::ICreateQuatController " ) ;
int32_t startIdx , endIdx ;
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
if ( ikeys & & IGetRangeCoverKeyIndices ( node ? node - > GetName ( ) : nil , control , startIdx , endIdx ) > 1 )
{
if ( ! ( control - > IsKeyable ( ) ) )
{
fErrorMsg - > Set ( true , " Quat Controller Creation Error " , " Control is not keyable. " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return NULL ;
}
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
plLeafController * pc = new plLeafController ;
uint8_t compressLevel = node - > GetAnimCompress ( ) ;
uint8_t keyType ;
if ( compressLevel = = plAnimCompressComp : : kCompressionHigh )
keyType = hsKeyFrame : : kCompressedQuatKeyFrame32 ;
else if ( compressLevel = = plAnimCompressComp : : kCompressionLow )
keyType = hsKeyFrame : : kCompressedQuatKeyFrame64 ;
else
keyType = hsKeyFrame : : kQuatKeyFrame ;
pc - > AllocKeys ( endIdx - startIdx + 1 , keyType ) ;
for ( int i = startIdx ; i < = endIdx ; i + + )
{
// Get key
ikeys - > GetKey ( i , key . get ( ) ) ;
const float kMaxRads = M_PI * 0.5f ;
Tab < TimeValue > kTimes ;
kTimes . ZeroCount ( ) ;
if ( rotation )
IGetControlSampleTimes ( control , i , i , kTimes , kMaxRads ) ;
else
kTimes . Append ( 1 , & key - > time ) ;
int k ;
for ( k = 0 ; k < kTimes . Count ( ) ; k + + )
{
if ( keyType = = hsKeyFrame : : kQuatKeyFrame )
{
hsQuatKey * hsKey = pc - > GetQuatKey ( i - startIdx ) ;
ICreateHSInterpKey ( control , key . get ( ) , kTimes [ k ] , hsKey , node , camRot ) ;
}
else if ( keyType = = hsKeyFrame : : kCompressedQuatKeyFrame64 )
{
hsQuatKey tempKey ;
ICreateHSInterpKey ( control , key . get ( ) , kTimes [ k ] , & tempKey , node , camRot ) ;
hsCompressedQuatKey64 * compKey = pc - > GetCompressedQuatKey64 ( i - startIdx ) ;
compKey - > fFrame = tempKey . fFrame ;
compKey - > SetQuat ( tempKey . fValue ) ;
}
else
{
hsQuatKey tempKey ;
ICreateHSInterpKey ( control , key . get ( ) , kTimes [ k ] , & tempKey , node , camRot ) ;
hsCompressedQuatKey32 * compKey = pc - > GetCompressedQuatKey32 ( i - startIdx ) ;
compKey - > fFrame = tempKey . fFrame ;
compKey - > SetQuat ( tempKey . fValue ) ;
}
}
}
return pc ;
}
return nil ;
hsGuardEnd ;
}
//
//
//
plLeafController * hsControlConverter : : ICreateScaleValueController ( plMaxNode * node , Control * control )
{
hsGuardBegin ( " hsControlConverter::ICreateScaleValueController " ) ;
//plMaxNode* xformParent = GetXformParent(node);
int32_t startIdx , endIdx ;
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
if ( ikeys & & IGetRangeCoverKeyIndices ( node ? node - > GetName ( ) : nil , control , startIdx , endIdx ) > 1 )
{
if ( ! ( control - > IsKeyable ( ) ) )
{
fErrorMsg - > Set ( true , " Scale Value Controller Creation Error " , " Control is not keyable " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return NULL ;
}
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
plLeafController * pc = new plLeafController ;
pc - > AllocKeys ( endIdx - startIdx + 1 , GetKeyType ( control ) ) ;
for ( int i = startIdx ; i < = endIdx ; i + + )
{
// Get key
ikeys - > GetKey ( i , key . get ( ) ) ;
hsScaleKey * hsKey = pc - > GetScaleKey ( i - startIdx ) ;
if ( hsKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , hsKey , node ) ;
hsBezScaleKey * bezKey = pc - > GetBezScaleKey ( i - startIdx ) ;
if ( bezKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , bezKey , node ) ;
}
return pc ;
}
return nil ;
hsGuardEnd ;
}
//
//
//
plLeafController * hsControlConverter : : ICreateScalarController ( plMaxNode * node , Control * control )
{
hsGuardBegin ( " hsControlConverter::ICreateScalarController " ) ;
int32_t startIdx , endIdx ;
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
if ( ikeys & & IGetRangeCoverKeyIndices ( node ? node - > GetName ( ) : nil , control , startIdx , endIdx ) > 1 )
{
if ( ! ( control - > IsKeyable ( ) ) )
{
fErrorMsg - > Set ( true , " Scale Value Controller Creation Error " , " Control is not keyable " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return NULL ;
}
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
plLeafController * pc = new plLeafController ;
pc - > AllocKeys ( endIdx - startIdx + 1 , GetKeyType ( control ) ) ;
for ( int i = startIdx ; i < = endIdx ; i + + )
{
// Get key
ikeys - > GetKey ( i , key . get ( ) ) ;
hsScalarKey * hsKey = pc - > GetScalarKey ( i - startIdx ) ;
if ( hsKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , hsKey ) ;
hsBezScalarKey * bezKey = pc - > GetBezScalarKey ( i - startIdx ) ;
if ( bezKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , bezKey ) ;
}
return pc ;
}
return nil ;
hsGuardEnd ;
}
//
//
//
plLeafController * hsControlConverter : : ICreateSimplePosController ( plMaxNode * node , Control * control )
{
hsGuardBegin ( " hsControlConverter::ICreateSimplePosController " ) ;
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
int32_t startIdx , endIdx ;
if ( ikeys & & IGetRangeCoverKeyIndices ( node ? node - > GetName ( ) : nil , control , startIdx , endIdx ) > 1 )
{
if ( ! ( control - > IsKeyable ( ) ) )
{
fErrorMsg - > Set ( true , " Simple Position Controller Creation Error " , " Control is not keyable " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return NULL ;
}
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
plLeafController * pc = new plLeafController ;
pc - > AllocKeys ( endIdx - startIdx + 1 , GetKeyType ( control ) ) ;
for ( int i = startIdx ; i < = endIdx ; i + + )
{
// Get key
ikeys - > GetKey ( i , key . get ( ) ) ;
hsPoint3Key * hsKey = pc - > GetPoint3Key ( i - startIdx ) ;
if ( hsKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , hsKey ) ;
hsBezPoint3Key * bezKey = pc - > GetBezPoint3Key ( i - startIdx ) ;
if ( bezKey )
ICreateHSInterpKey ( control , key . get ( ) , key - > time , bezKey ) ;
}
return pc ;
}
return nil ;
hsGuardEnd ;
}
//
// Create a hsKey and store the nodes LTM in it.
// Recurses along all subcontrollers.
//
int hsControlConverter : : IAddPartsKeys ( Control * control ,
hsTArray < hsG3DSMaxKeyFrame > * kfArray ,
plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::IAddPartsKeys " ) ;
int32_t startIdx , endIdx ;
if ( control - > IsLeaf ( ) )
{
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
int num = ikeys ? IGetRangeCoverKeyIndices ( node ? node - > GetName ( ) : nil , control , startIdx , endIdx ) : 0 ;
if ( num < 2 )
{
return 0 ;
}
if ( ! control - > IsKeyable ( ) )
{
fErrorMsg - > Set ( true , " Add Parts Keys Creation Error " , " Control is not keyable " ) . Show ( ) ;
fErrorMsg - > Set ( ) ;
return 0 ;
}
int i , j ;
//
// Traverse all keys of controller
//
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
bool mb = false ;
plMaxNode * xformParent = GetXformParent ( node ) ;
for ( i = startIdx ; i < = endIdx ; i + + )
{
// Get key
ikeys - > GetKey ( i , key . get ( ) ) ;
float frameTime = key - > time / GetTicksPerSec ( ) ;
int frameNum = key - > time / GetTicksPerFrame ( ) ;
hsAssert ( frameNum < = hsKeyFrame : : kMaxFrameNumber , " Anim is too long. " ) ;
// Check if we already have a hsG3dsMaxKey at this frameNum
int found = FALSE ;
for ( j = 0 ; j < kfArray - > GetCount ( ) ; j + + )
{
hsG3DSMaxKeyFrame * k = & ( * kfArray ) [ j ] ;
if ( k - > fFrame = = frameNum )
{
found = TRUE ;
break ;
}
}
if ( found = = TRUE )
// Skip this key, there's one already there
continue ;
//
// Compute AffineParts
//
hsMatrix44 tXform = node - > GetLocalToParent44 ( key - > time ) ;
gemAffineParts ap ;
decomp_affine ( tXform . fMap , & ap ) ;
hsAffineParts parts ;
AP_SET ( parts , ap ) ;
// Init new keyframe
hsG3DSMaxKeyFrame hKey ;
hKey . fParts = parts ;
hKey . fFrame = frameNum ;
// Add key to list
kfArray - > Append ( hKey ) ;
}
}
else
{
int i ;
for ( i = 0 ; i < control - > NumSubs ( ) ; i + + )
IAddPartsKeys ( ( Control * ) control - > SubAnim ( i ) , kfArray , node ) ;
}
return kfArray - > GetCount ( ) ;
hsGuardEnd ;
}
Matrix3 hsControlConverter : : StdUVGenToMatrix3 ( StdUVGen * uvGen )
{
Matrix3 retVal ( true ) ;
if ( uvGen )
uvGen - > GetUVTransform ( retVal ) ;
retVal = Inverse ( IFlipY ( ) ) * retVal * IFlipY ( ) ;
return retVal ;
}
//
//
// returns 0 if identity, 1 otherwise
// takes into account the implicit transform of v -> 1-v in meshconvert:setuvs()
//
bool hsControlConverter : : StdUVGenToHsMatrix44 ( hsMatrix44 * hsMat , StdUVGen * uvGen , bool preserveOffset )
{
hsGuardBegin ( " hsControlConverter::StdUVGenToHsMatrix44 " ) ;
Matrix3 uvXform ;
uvGen - > GetUVTransform ( uvXform ) ;
uvXform = Inverse ( IFlipY ( ) ) * uvXform * IFlipY ( ) ;
Matrix3ToHsMatrix44 ( & uvXform , hsMat ) ;
if ( ! preserveOffset )
{
int i ;
for ( i = 0 ; i < 2 ; i + + )
{
if ( fabsf ( hsMat - > fMap [ i ] [ 3 ] ) > 1.f )
hsMat - > fMap [ i ] [ 3 ] - = float ( int ( hsMat - > fMap [ i ] [ 3 ] ) ) ;
}
}
return ( ! hsMat - > IsIdentity ( ) ) ;
hsGuardEnd ;
}
void hsControlConverter : : IGetControlSampleTimes ( Control * control , int iLo , int iHi , Tab < TimeValue > & kTimes , float maxRads )
{
hsGuardBegin ( " hsControlConverter::IGetControlSampleTimes " ) ;
kTimes . ZeroCount ( ) ;
if ( ! control )
{
return ;
}
Class_ID cID = control - > ClassID ( ) ;
SClass_ID sID = control - > SuperClassID ( ) ;
if ( iLo < 0 )
iLo = 0 ;
int num = control - > NumKeys ( ) ;
iHi + + ;
if ( iHi > num )
iHi = num ;
IKeyControl * ikeys = GetKeyControlInterface ( control ) ;
ikey_ptr key = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
ikey_ptr lastKey = IAllocKey ( ikeys - > GetKeySize ( ) ) ;
int i ;
for ( i = iLo ; i < iHi ; i + + )
{
TimeValue t = control - > GetKeyTime ( i ) ;
if ( ! i )
{
kTimes . Append ( 1 , & t ) ;
continue ;
}
int nSamp = 1 ;
float rads = 0 ;
// following code will work, except that rotations are stored
// relative to previous key, so we'd need to end off with something
// like for i = 1; i < n; i++ )
// key[i] = key[i-1] * key[i]
// or pass in the previous key and do it here.
///////////////////////////////////////
ikeys - > GetKey ( i - 1 , lastKey . get ( ) ) ;
ikeys - > GetKey ( i , key . get ( ) ) ;
if ( cID = = Class_ID ( TCBINTERP_ROTATION_CLASS_ID , 0 ) )
{
ITCBRotKey * tcbRotKey = ( ITCBRotKey * ) key . get ( ) ;
rads = tcbRotKey - > val . angle ;
}
else
if ( cID = = Class_ID ( LININTERP_ROTATION_CLASS_ID , 0 ) )
{
ILinRotKey * linRotKey = ( ILinRotKey * ) key . get ( ) ;
Point3 axis ;
AngAxisFromQ ( linRotKey - > val , & rads , axis ) ;
}
else
if ( cID = = Class_ID ( HYBRIDINTERP_ROTATION_CLASS_ID , 0 ) )
{
IBezQuatKey * bezRotKey = ( IBezQuatKey * ) key . get ( ) ;
Point3 axis ;
AngAxisFromQ ( bezRotKey - > val , & rads , axis ) ;
}
else
if ( cID = = Class_ID ( TCBINTERP_FLOAT_CLASS_ID , 0 ) )
{
ITCBFloatKey * fKey = ( ITCBFloatKey * ) key . get ( ) ;
rads = fKey - > val ;
fKey = ( ITCBFloatKey * ) lastKey . get ( ) ;
rads - = fKey - > val ;
}
else
if ( cID = = Class_ID ( LININTERP_FLOAT_CLASS_ID , 0 ) )
{
ILinFloatKey * fKey = ( ILinFloatKey * ) key . get ( ) ;
rads = fKey - > val ;
fKey = ( ILinFloatKey * ) lastKey . get ( ) ;
rads - = fKey - > val ;
}
else
if ( cID = = Class_ID ( HYBRIDINTERP_FLOAT_CLASS_ID , 0 ) )
{
IBezFloatKey * fKey = ( IBezFloatKey * ) key . get ( ) ;
rads = fKey - > val ;
fKey = ( IBezFloatKey * ) lastKey . get ( ) ;
rads - = fKey - > val ;
}
nSamp = int ( fabs ( rads / maxRads ) + 0.9f ) ;
if ( nSamp < 2 )
{
kTimes . Append ( 1 , & t ) ;
continue ;
}
TimeValue t0 = control - > GetKeyTime ( i - 1 ) ;
int j ;
for ( j = 0 ; j < nSamp ; j + + )
{
float p = float ( j + 1 ) / float ( nSamp ) ;
TimeValue ti = t0 + TimeValue ( p * ( t - t0 ) ) ;
kTimes . Append ( 1 , & ti ) ;
}
///////////////////////////////////////
}
hsGuardEnd ;
}
#if 0
// following code will work, except that TCB (but not Euler) rotations are stored
// relative to previous key, so we'd need to end off with something
// like for i = 1; i < n; i++ )
// key[i] = key[i-1]* key[i]
// or pass in the previous key and do it here.
Quat quat ;
///////////////////////////////////////
if ( cID = = Class_ID ( TCBINTERP_ROTATION_CLASS_ID , 0 ) )
{
ITCBRotKey * tcbRotKey = ( ITCBRotKey * ) mKey ;
quat = QFromAngAxis ( tcbRotKey - > val . angle , tcbRotKey - > val . axis ) ;
}
else if ( cID = = Class_ID ( HYBRIDINTERP_ROTATION_CLASS_ID , 0 ) )
{
IBezQuatKey * bezRotKey = ( IBezQuatKey * ) mKey ;
quat = bezRotKey - > val ;
}
else if ( cID = = Class_ID ( LININTERP_ROTATION_CLASS_ID , 0 ) )
{
ILinRotKey * linRotKey = ( ILinRotKey * ) mKey ;
quat = linRotKey - > val ;
}
else if ( cID = = Class_ID ( EULER_CONTROL_CLASS_ID , 0 ) )
{
float eul [ 3 ] ;
int i ;
for ( i = 0 ; i < 3 ; i + + )
{
Control * subCntl = ( Control * ) control - > SubAnim ( i ) ;
if ( fErrorMsg - > Set ( ! ( subCntl & & ( subCntl - > ClassID ( ) = = Class_ID ( TCBINTERP_FLOAT_CLASS_ID , 0 ) ) ) , node - > GetName ( ) , " Bad sub-controller type for animation " ) . CheckAndAsk ( ) )
{
eul [ i ] = 0.f ;
continue ;
}
ITCBFloatKey * fKey = ( ITCBFloatKey * ) mKey ;
eul [ i ] = fKey - > val ;
}
EulerToQuat ( eul , quat ) ;
}
hbKey - > fValue . Set ( - quat . x , - quat . y , - quat . z , quat . w ) ;
///////////////////////////////////////
# endif // try getting from key
//
// Create an hsKeyFrame from a 3DSMax key
//
int32_t hsControlConverter : : ICreateHSInterpKey ( Control * control , IKey * mKey , TimeValue keyTime , hsKeyFrame * baseKey , plMaxNode * node , bool rotQuat )
{
hsGuardBegin ( " hsControlConverter::ICreateHSInterpKey " ) ;
Class_ID cID = control - > ClassID ( ) ;
SClass_ID sID = control - > SuperClassID ( ) ;
char * nodeName = node ? node - > GetName ( ) : nil ;
// BEZ
if ( cID = = Class_ID ( HYBRIDINTERP_POSITION_CLASS_ID , 0 ) | |
cID = = Class_ID ( HYBRIDINTERP_COLOR_CLASS_ID , 0 ) | |
cID = = Class_ID ( HYBRIDINTERP_POINT3_CLASS_ID , 0 ) )
{
IBezPoint3Key * bKey = ( IBezPoint3Key * ) mKey ;
hsBezPoint3Key * hbKey = ( hsBezPoint3Key * ) baseKey ;
hbKey - > fValue . Set ( bKey - > val . x , bKey - > val . y , bKey - > val . z ) ; // color should be 0 to 1
hbKey - > fInTan . Set ( bKey - > intan . x , bKey - > intan . y , bKey - > intan . z ) ;
hbKey - > fOutTan . Set ( bKey - > outtan . x , bKey - > outtan . y , bKey - > outtan . z ) ;
}
else if ( cID = = Class_ID ( HYBRIDINTERP_SCALE_CLASS_ID , 0 ) )
{
IBezScaleKey * bKey = ( IBezScaleKey * ) mKey ;
hsBezScaleKey * hbKey = ( hsBezScaleKey * ) baseKey ;
hsMatrix44 tXform ;
IGetUnEasedLocalTM ( node , control , & tXform , keyTime ) ;
gemAffineParts ap ;
decomp_affine ( tXform . fMap , & ap ) ;
hbKey - > fValue . fS . Set ( ap . k . x , ap . k . y , ap . k . z ) ;
hbKey - > fValue . fQ . Set ( ap . u . x , ap . u . y , ap . u . z , ap . u . w ) ;
hbKey - > fInTan . Set ( bKey - > intan . x , bKey - > intan . y , bKey - > intan . z ) ;
hbKey - > fOutTan . Set ( bKey - > outtan . x , bKey - > outtan . y , bKey - > outtan . z ) ;
}
else if ( cID = = Class_ID ( HYBRIDINTERP_FLOAT_CLASS_ID , 0 ) & & ! rotQuat )
{
IBezFloatKey * bKey = ( IBezFloatKey * ) mKey ;
hsBezScalarKey * hbKey = ( hsBezScalarKey * ) baseKey ;
hbKey - > fValue = bKey - > val ;
hbKey - > fInTan = bKey - > intan ;
hbKey - > fOutTan = bKey - > outtan ;
}
else
// LIN
if ( cID = = Class_ID ( LININTERP_POSITION_CLASS_ID , 0 ) )
{
ILinPoint3Key * bKey = ( ILinPoint3Key * ) mKey ;
hsPoint3Key * hbKey = ( hsPoint3Key * ) baseKey ;
hbKey - > fValue . Set ( bKey - > val . x , bKey - > val . y , bKey - > val . z ) ;
}
else if ( sID = = SClass_ID ( CTRL_ROTATION_CLASS_ID ) | | ( cID = = Class_ID ( HYBRIDINTERP_FLOAT_CLASS_ID , 0 ) & & rotQuat ) ) // all rotations
{
hsQuatKey * hbKey = ( hsQuatKey * ) baseKey ;
// get rot values from Matrix and use quat slerp.
// could try getting rot values from key
hsMatrix44 tXform ;
IGetUnEasedLocalTM ( node , control , & tXform , keyTime ) ;
gemAffineParts ap ;
decomp_affine ( tXform . fMap , & ap ) ;
hbKey - > fValue . Set ( ap . q . x , ap . q . y , ap . q . z , ap . q . w ) ;
IEnableEaseCurves ( control , true ) ; // re-enable
}
else if ( cID = = Class_ID ( LININTERP_SCALE_CLASS_ID , 0 ) )
{
ILinScaleKey * bKey = ( ILinScaleKey * ) mKey ;
hsScaleKey * hbKey = ( hsScaleKey * ) baseKey ;
hsMatrix44 tXform ;
IGetUnEasedLocalTM ( node , control , & tXform , keyTime ) ;
gemAffineParts ap ;
decomp_affine ( tXform . fMap , & ap ) ;
hbKey - > fValue . fS . Set ( ap . k . x , ap . k . y , ap . k . z ) ;
hbKey - > fValue . fQ . Set ( ap . u . x , ap . u . y , ap . u . z , ap . u . w ) ;
}
else
if ( cID = = Class_ID ( LININTERP_FLOAT_CLASS_ID , 0 ) )
{
ILinFloatKey * bKey = ( ILinFloatKey * ) mKey ;
hsScalarKey * hbKey = ( hsScalarKey * ) baseKey ;
hbKey - > fValue = bKey - > val ;
}
else
// TCB
if ( cID = = Class_ID ( TCBINTERP_POSITION_CLASS_ID , 0 ) | |
cID = = Class_ID ( TCBINTERP_POINT3_CLASS_ID , 0 ) )
{
ITCBPoint3Key * bKey = ( ITCBPoint3Key * ) mKey ;
hsPoint3Key * hbKey = ( hsPoint3Key * ) baseKey ;
hbKey - > fValue . Set ( bKey - > val . x , bKey - > val . y , bKey - > val . z ) ;
}
else
if ( cID = = Class_ID ( TCBINTERP_FLOAT_CLASS_ID , 0 ) )
{
ITCBFloatKey * bKey = ( ITCBFloatKey * ) mKey ;
hsScalarKey * hbKey = ( hsScalarKey * ) baseKey ;
hbKey - > fValue = bKey - > val ;
}
else if ( cID = = Class_ID ( TCBINTERP_SCALE_CLASS_ID , 0 ) )
{
ITCBScaleKey * bKey = ( ITCBScaleKey * ) mKey ;
hsScaleKey * hbKey = ( hsScaleKey * ) baseKey ;
hsMatrix44 tXform ;
IGetUnEasedLocalTM ( node , control , & tXform , keyTime ) ;
gemAffineParts ap ;
decomp_affine ( tXform . fMap , & ap ) ;
hbKey - > fValue . fS . Set ( ap . k . x , ap . k . y , ap . k . z ) ;
hbKey - > fValue . fQ . Set ( ap . u . x , ap . u . y , ap . u . z , ap . u . w ) ;
}
else
{
fErrorMsg - > Set ( true , nodeName , " unknown controller type? " ) . Check ( ) ;
return 0 ; // failed
}
int frameNum = keyTime / GetTicksPerFrame ( ) ;
hsAssert ( frameNum < = hsKeyFrame : : kMaxFrameNumber , " Anim is too long. " ) ;
baseKey - > fFrame = frameNum ;
return 1 ; // did it
hsGuardEnd ;
}
uint8_t hsControlConverter : : GetKeyType ( Control * control , bool rotQuat )
{
Class_ID cID = control - > ClassID ( ) ;
SClass_ID sID = control - > SuperClassID ( ) ;
if ( cID = = Class_ID ( HYBRIDINTERP_POSITION_CLASS_ID , 0 ) | |
cID = = Class_ID ( HYBRIDINTERP_COLOR_CLASS_ID , 0 ) | |
cID = = Class_ID ( HYBRIDINTERP_POINT3_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kBezPoint3KeyFrame ;
}
else if ( cID = = Class_ID ( HYBRIDINTERP_SCALE_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kBezScaleKeyFrame ;
}
else if ( cID = = Class_ID ( HYBRIDINTERP_FLOAT_CLASS_ID , 0 ) & & ! rotQuat )
{
return hsKeyFrame : : kBezScalarKeyFrame ;
}
else if ( cID = = Class_ID ( LININTERP_POSITION_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kPoint3KeyFrame ;
}
else if ( sID = = SClass_ID ( CTRL_ROTATION_CLASS_ID ) | | ( cID = = Class_ID ( HYBRIDINTERP_FLOAT_CLASS_ID , 0 ) & & rotQuat ) ) // all rotations
{
return hsKeyFrame : : kQuatKeyFrame ;
}
else if ( cID = = Class_ID ( LININTERP_SCALE_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kScaleKeyFrame ;
}
else if ( cID = = Class_ID ( LININTERP_FLOAT_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kScalarKeyFrame ;
}
else if ( cID = = Class_ID ( TCBINTERP_POSITION_CLASS_ID , 0 ) | |
cID = = Class_ID ( TCBINTERP_POINT3_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kPoint3KeyFrame ;
}
else if ( cID = = Class_ID ( TCBINTERP_FLOAT_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kScalarKeyFrame ;
}
else if ( cID = = Class_ID ( TCBINTERP_SCALE_CLASS_ID , 0 ) )
{
return hsKeyFrame : : kScaleKeyFrame ;
}
else
{
return hsKeyFrame : : kUnknownKeyFrame ;
}
}
//
//
//
int32_t hsControlConverter : : IGetRangeCoverKeyIndices ( char * nodeName , Control * cont , int32_t & start , int32_t & end )
{
hsGuardBegin ( " hsControlConverter::IGetRangeCoverKeyIndices " ) ;
if ( ! cont )
{
return 0 ;
}
IKeyControl * keys = GetKeyControlInterface ( cont ) ;
int numKeys = keys - > GetNumKeys ( ) ;
if ( numKeys = = 0 )
return 0 ;
ikey_ptr key = IAllocKey ( keys - > GetKeySize ( ) ) ;
start = numKeys ;
for ( int i = 0 ; i < numKeys ; i + + )
{
keys - > GetKey ( i , key . get ( ) ) ;
if ( IIsKeyInRange ( key . get ( ) ) )
{
if ( start > i )
start = i ;
end = i ;
}
}
// If the keys aren't on the exact endpoints of our range, we need to include the next or previous
// one so that we have data for any time within our range.
if ( start = = numKeys ) // No keys inside the range
{
for ( int i = 0 ; i < numKeys ; i + + )
{
keys - > GetKey ( i , key . get ( ) ) ;
if ( key - > time < fSegStart )
start = i ;
}
if ( ( start = = numKeys ) | | // no keys before the start time
( start = = numKeys - 1 ) ) // no keys after end (since the latest key is before start)
{
return 0 ;
}
end = start + 1 ;
}
else
{
keys - > GetKey ( start , key . get ( ) ) ;
if ( key - > time > fSegStart & & start > 0 )
start - = 1 ;
keys - > GetKey ( end , key . get ( ) ) ;
if ( key - > time < fSegEnd & & end < numKeys - 1 )
end + = 1 ;
}
//fErrorMsg->Set(numInRange>1 && numInRange!=numKeys, nodeName ? nodeName : "?",
// "Warning: Object has controller with keyframes outside of animation interval").CheckAndAsk();
return end - start + 1 ;
hsGuardEnd ;
}
//
// find the closest ancestor (if any) that is animated.
// this node's space will be our local space.
//
plMaxNode * hsControlConverter : : GetXformParent ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::GetXformParent " ) ;
while ( node & & ( node = ( plMaxNode * ) node - > GetParentNode ( ) ) & &
! ( ForceOrigin ( node ) | | ForceLocal ( node ) | | IsAnimated ( node ) ) ) ;
return node ;
hsGuardEnd ;
}
// ###########################################################################
// Note that ForceWorldSpace Overrides ForceOrigin which Overrides ForceLocal
// ###########################################################################
bool hsControlConverter : : ForceWorldSpace ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::ForceWorldSpace " ) ;
return false ;
hsGuardEnd ;
}
// ###########################################################################
// Note that ForceWorldSpace Overrides ForceOrigin which Overrides ForceLocal
// ###########################################################################
bool hsControlConverter : : ForceOrigin ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::ForceOrigin " ) ;
char * nn = node - > GetName ( ) ;
if ( node - > IsRootNode ( ) )
{
return false ;
}
if ( ForceWorldSpace ( node ) )
{
return false ;
}
return false ;
hsGuardEnd ;
}
// ###########################################################################
// Note that ForceWorldSpace Overrides ForceOrigin which Overrides ForceLocal
// This is significant because things that require ForceLocal because they are
// animated or what-not, are still okay with ForceOrigin, but not v.v.
// ###########################################################################
bool hsControlConverter : : ForceLocal ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::ForceLocal " ) ;
const char * nn = node - > GetName ( ) ;
if ( ! node - > CanConvert ( ) )
return false ;
if ( node - > IsRootNode ( ) )
{
return false ;
}
if ( node - > GetForceLocal ( ) )
return true ;
if ( ISkinNode ( ( plMaxNode * ) node - > GetParentNode ( ) ) )
{
node - > SetForceLocal ( true ) ;
return true ;
}
Object * objectRef = node - > GetObjectRef ( ) ;
if ( fConverterUtils . IsInstanced ( objectRef ) & &
gUserPropMgr . UserPropExists ( node , " AllowInstancing " ) )
{
node - > SetForceLocal ( true ) ;
return true ;
}
return false ;
hsGuardEnd ;
}
bool hsControlConverter : : IsAnimated ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::IsAnimated " ) ;
return node - > IsAnimated ( ) ;
hsGuardEnd ;
}
bool hsControlConverter : : OwnsMaterialCopy ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::OwnsMaterialCopy " ) ;
return false ;
hsGuardEnd ;
}
bool hsControlConverter : : HasFrameEvents ( plMaxNode * node )
{
hsGuardBegin ( " hsSceneConverter::HasFrameEvents " ) ;
if ( ! node )
{
return false ;
}
TSTR sdata ;
if ( gUserPropMgr . GetUserPropString ( node , " FESound " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FESoundEmitter " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEGrab " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEDrop " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEEventOn " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEEventOnPermanent " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEEventOff " , sdata ) | |
gUserPropMgr . GetUserPropString ( node , " FEActor " , sdata ) )
{
return false ;
}
return false ;
hsGuardEnd ;
}
bool hsControlConverter : : GetControllerByName ( Animatable * anim , TSTR & name , Control * & ctl )
{
hsGuardBegin ( " hsControlConverter::GetControllerByName " ) ;
if ( anim )
{
int nSub = anim - > NumSubs ( ) ;
int i ;
for ( i = 0 ; i < nSub ; i + + )
{
if ( anim - > SubAnim ( i ) = = nil )
continue ;
TSTR subName = anim - > SubAnimName ( i ) ;
if ( subName = = name )
{
fErrorMsg - > Set ( ! anim - > SubAnim ( i ) , name , " Found controller by name, but nobody home " ) . Check ( ) ;
ctl = GetControlInterface ( anim - > SubAnim ( i ) ) ;
return true ;
}
else if ( GetControllerByName ( anim - > SubAnim ( i ) , name , ctl ) )
{
return true ;
}
}
}
ctl = nil ;
return false ;
hsGuardEnd ;
}
Control * hsControlConverter : : GetControllerByID ( IParamBlock2 * pblock , int paramID )
{
hsGuardBegin ( " hsControlConverter::GetControllerByID " ) ;
if ( pblock )
{
int animIdx = pblock - > GetAnimNum ( paramID ) ;
if ( animIdx ! = - 1 )
{
Animatable * anim = pblock - > SubAnim ( animIdx ) ;
if ( anim )
return GetControlInterface ( anim ) ;
}
}
return NULL ;
hsGuardEnd ;
}
void hsControlConverter : : CompositeKeyTimes ( Control * ctl , Tab < TimeValue > & time )
{
hsGuardBegin ( " hsControlConverter::CompositeKeyTimes " ) ;
if ( ! ctl )
{
return ;
}
int curTime = 0 ;
int i ;
for ( i = 0 ; i < ctl - > NumKeys ( ) ; i + + )
{
TimeValue t = ctl - > GetKeyTime ( i ) ;
// advance times
while ( ( curTime < time . Count ( ) ) & & ( t > time [ curTime ] ) )
curTime + + ;
// if past end, append it
if ( curTime > = time . Count ( ) )
time . Append ( 1 , & t ) ;
else // if less
if ( t < time [ curTime ] )
time . Insert ( curTime + + , 1 , & t ) ;
// already there, skip
}
hsGuardEnd ;
}
//
//
//
ControllerType hsControlConverter : : IGetControlType ( TSTR ctrlName )
{
hsGuardBegin ( " hsControlConverter::IGetControlType " ) ;
ControllerType ct = ctrlTypeUnknown ;
if ( ctrlName & & ! strcmp ( ctrlName , " Ease Curve " ) )
{
ct = ctrlTypeEase ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Mult Curve " ) )
{
ct = ctrlTypeMult ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Position " ) )
{
ct = ctrlTypePosition ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Rotation " ) )
{
ct = ctrlTypeRotation ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Scale " ) )
{
ct = ctrlTypeScale ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Transform " ) )
{
ct = ctrlTypeTransform ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Roll Angle " ) )
{
ct = ctrlTypeRollAngle ;
}
#if 0
// biped controllers are good for nothing
else if ( ctrlName & & ! strcmp ( ctrlName , " Vertical " ) )
{
ct = ctrlTypeVert ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Horizontal " ) )
{
ct = ctrlTypeHoriz ;
}
else if ( ctrlName & & ! strcmp ( ctrlName , " Turning " ) )
{
ct = ctrlTypeTurn ;
}
# endif
return ct ;
hsGuardEnd ;
}
bool hsControlConverter : : IIsKeyTimeInRange ( TimeValue time )
{
hsGuardBegin ( " hsControlConverter::IIsKeyTimeInRange " ) ;
Interval interval = fInterface - > GetAnimRange ( ) ;
TimeValue startTime = interval . Start ( ) ; // in ticks
TimeValue endTime = interval . End ( ) ; // in ticks
return ( time > = startTime & & time < = endTime ) & & // Max's range
( time > = fSegStart & & time < = fSegEnd ) ;
hsGuardEnd ;
}
bool hsControlConverter : : IIsKeyInRange ( IKey * key )
{
hsGuardBegin ( " hsControlConverter::IIsKeyInRange " ) ;
return IIsKeyTimeInRange ( key - > time ) ;
hsGuardEnd ;
}
void hsControlConverter : : IGetUnEasedLocalTM ( plMaxNode * node , Control * control , hsMatrix44 * out , TimeValue time )
{
hsGuardBegin ( " hsControlConverter::IGetUnEasedLocalTM " ) ;
// disable easing so that GetTM won't give us an eased answer.
// we want the uneased "key" value, so that we can do the easing ourselves
IEnableEaseCurves ( control , false ) ;
// Make scale key match nodeTM
fErrorMsg - > Set ( ! node , " ICreateHSInterpKey " , " nil node " ) . Check ( ) ;
* out = node - > GetLocalToParent44 ( time ) ;
IEnableEaseCurves ( control , true ) ; // re-enable
hsGuardEnd ;
}
//
//
//
void hsControlConverter : : IEnableEaseCurves ( Animatable * control , bool enable )
{
hsGuardBegin ( " hsControlConverter::IEnableEaseCurves " ) ;
if ( control )
{
int n = control - > NumSubs ( ) ;
for ( int i = 0 ; i < n ; i + + )
IEnableEaseCurves ( control - > SubAnim ( i ) , enable ) ;
EaseCurveList * el = GetEaseListInterface ( control ) ;
if ( el )
{
for ( int i = 0 ; i < el - > NumEaseCurves ( ) ; i + + )
{
if ( enable )
el - > EnableEaseCurve ( i ) ;
else
el - > DisableEaseCurve ( i ) ;
}
}
}
hsGuardEnd ;
}
// We don't actually use this ID for a plugin, just to keep track of our AppData chunks
# define CONTROL_CONVERTER_CID Class_ID(0xae807d2, 0x523808c7)
Matrix3 hsControlConverter : : IFlipY ( )
{
hsGuardBegin ( " hsControlConverter::IFlipY " ) ;
Matrix3 xfm = ScaleMatrix ( Point3 ( 1.0 , - 1.0 , 1.0 ) ) * TransMatrix ( Point3 ( 0.0 , 1.0 , 0.0 ) ) ;
return xfm ;
hsGuardEnd ;
}
bool hsControlConverter : : ISkinNode ( plMaxNode * node )
{
hsGuardBegin ( " hsControlConverter::ISkinNode " ) ;
/*
if ( fForceSkinning )
return true ;
if ( fForceNoSkinning )
return false ;
*/
if ( gUserPropMgr . UserPropExists ( node , " MATSkin " ) )
{
return true ;
}
if ( gUserPropMgr . UserPropExists ( node , " MATSkinColor " ) )
{
return true ;
}
if ( node & & node - > GetName ( ) & & strstr ( node - > GetName ( ) , " %skin " ) )
{
return true ;
}
return false ;
hsGuardEnd ;
}
void hsControlConverter : : Matrix3ToHsMatrix44 ( Matrix3 * m3 , hsMatrix44 * hsM )
{
hsGuardBegin ( " hsControlConverter::Matrix3ToHsMatrix44 " ) ;
MRow * m = m3 - > GetAddr ( ) ;
hsM - > Reset ( ) ;
hsM - > fMap [ 0 ] [ 0 ] = m [ 0 ] [ 0 ] ;
hsM - > fMap [ 0 ] [ 1 ] = m [ 1 ] [ 0 ] ;
hsM - > fMap [ 0 ] [ 2 ] = m [ 2 ] [ 0 ] ;
hsM - > fMap [ 0 ] [ 3 ] = m [ 3 ] [ 0 ] ;
hsM - > fMap [ 1 ] [ 0 ] = m [ 0 ] [ 1 ] ;
hsM - > fMap [ 1 ] [ 1 ] = m [ 1 ] [ 1 ] ;
hsM - > fMap [ 1 ] [ 2 ] = m [ 2 ] [ 1 ] ;
hsM - > fMap [ 1 ] [ 3 ] = m [ 3 ] [ 1 ] ;
hsM - > fMap [ 2 ] [ 0 ] = m [ 0 ] [ 2 ] ;
hsM - > fMap [ 2 ] [ 1 ] = m [ 1 ] [ 2 ] ;
hsM - > fMap [ 2 ] [ 2 ] = m [ 2 ] [ 2 ] ;
hsM - > fMap [ 2 ] [ 3 ] = m [ 3 ] [ 2 ] ;
hsM - > NotIdentity ( ) ;
hsGuardEnd ;
}
//// IGetEditableMeshKeyTimes ////////////////////////////////////////////////
// Moved here after hsMeshConverter was obliterated. Only used in this class
// anyway...
bool hsControlConverter : : IGetEditableMeshKeyTimes ( plMaxNode * node , Tab < TimeValue > & times )
{
hsGuardBegin ( " hsControlConverter::GetEditableMeshKeyTimes " ) ;
Animatable * anim ;
if ( IGetSubAnimByName ( node , TSTR ( " Object (Editable Mesh) " ) , anim ) )
{
fErrorMsg - > Set ( ! anim , node - > GetName ( ) , " First she says yes, then she says no. " ) . Check ( ) ;
int i ;
int nSub = anim - > NumSubs ( ) ;
for ( i = 0 ; i < nSub ; i + + )
{
if ( anim - > SubAnim ( i ) )
{
Control * ctl = GetControlInterface ( anim - > SubAnim ( i ) ) ;
hsControlConverter : : Instance ( ) . CompositeKeyTimes ( ctl , times ) ;
}
}
}
return times . Count ( ) > 0 ;
hsGuardEnd ;
}
//// IGetGeomKeyTimes ////////////////////////////////////////////////////////
// Moved here after hsMeshConverter was obliterated. Only used in this class
// anyway...
bool hsControlConverter : : IGetGeomKeyTimes ( plMaxNode * node , Tab < TimeValue > & times )
{
hsGuardBegin ( " hsControlConverter::GetGeomKeyTimes " ) ;
char * dgbNodeName = node - > GetName ( ) ;
Object * obj = node - > GetObjectRef ( ) ;
if ( ! obj )
return false ;
IDerivedObject * derObj = nil ;
if ( obj - > CanConvertToType ( derivObjClassID ) )
{
derObj = ( IDerivedObject * ) obj - > ConvertToType ( fConverterUtils . GetTime ( fInterface ) , derivObjClassID ) ;
}
else
{
SClass_ID objID = obj - > SuperClassID ( ) ;
SClass_ID genID ( GEN_DERIVOB_CLASS_ID ) ;
if ( ! ( obj - > SuperClassID ( ) = = SClass_ID ( GEN_DERIVOB_CLASS_ID ) ) )
return false ;
if ( objID ! = genID )
return false ;
derObj = ( IDerivedObject * ) obj ;
}
int i ;
int nKeys = 0 ;
for ( i = 0 ; i < derObj - > NumModifiers ( ) ; i + + )
{
Modifier * mod = derObj - > GetModifier ( i ) ;
char * dbgModName = mod - > GetName ( ) ;
if ( mod )
{
ChannelMask mask = mod - > ChannelsChanged ( ) ;
if ( mask & GEOM_CHANNEL )
{
IGetGeomKeyTimesRecur ( mod , times ) ;
}
}
}
return ( times . Count ( ) > 0 ) ;
hsGuardEnd ;
}
//// IGetGeomKeyTimesRecur ///////////////////////////////////////////////////
// Moved here after hsMeshConverter was obliterated. Only used in this class
// anyway...
void hsControlConverter : : IGetGeomKeyTimesRecur ( Animatable * anim , Tab < TimeValue > & times )
{
hsGuardBegin ( " hsControlConverter::IGetGeomKeyTimesRecur " ) ;
Control * ctl = GetControlInterface ( anim ) ;
hsControlConverter : : Instance ( ) . CompositeKeyTimes ( ctl , times ) ;
int iSub ;
int nSub = anim - > NumSubs ( ) ;
for ( iSub = 0 ; iSub < nSub ; iSub + + )
{
if ( anim - > SubAnim ( iSub ) )
IGetGeomKeyTimesRecur ( anim - > SubAnim ( iSub ) , times ) ;
}
hsGuardEnd ;
}
//// IGetGeomKeyTimesRecur ///////////////////////////////////////////////////
// Moved here after hsMeshConverter was obliterated. Only used in this class
// anyway...
bool hsControlConverter : : IGetSubAnimByName ( Animatable * anim , TSTR & name , Animatable * & subAnim )
{
hsGuardBegin ( " hsControlConverter::IGetSubAnimByName " ) ;
if ( anim )
{
int nSub = anim - > NumSubs ( ) ;
int i ;
for ( i = 0 ; i < nSub ; i + + )
{
if ( anim - > SubAnim ( i ) = = nil )
continue ;
TSTR subName = anim - > SubAnimName ( i ) ;
if ( subName = = name )
{
fErrorMsg - > Set ( ! anim - > SubAnim ( i ) , name , " Found controller by name, but nobody home " ) . Check ( ) ;
subAnim = anim - > SubAnim ( i ) ;
return true ;
}
else if ( IGetSubAnimByName ( anim - > SubAnim ( i ) , name , subAnim ) )
{
return true ;
}
}
}
subAnim = nil ;
return false ;
hsGuardEnd ;
}
// bad craziness, isolated here.
# include "plConvert.h"
# include "plgDispatch.h"
# include "MaxComponent/plAnimComponent.h"
# include "MaxComponent/plCameraComponents.h"
# include "pnMessage/plCameraMsg.h"
# include "plMessage/plAnimCmdMsg.h"
# include "pfCamera/plCameraModifier.h"
# include "pnSceneObject/plSceneObject.h"
void hsControlConverter : : IExportAnimatedCameraFOV ( plMaxNode * node , hsTArray < hsG3DSMaxKeyFrame > * kfArray )
{
// grab the FOV settings at each keyframe here
// create callback messages for the animation to send to the camera
// to interpolate to the correct FOV at each keyframe
plAnimComponentBase * pAnim = nil ;
int count = node - > NumAttachedComponents ( ) ;
int i ;
for ( i = 0 ; i < count ; i + + )
{
plComponentBase * comp = node - > GetAttachedComponent ( i ) ;
if ( comp - > ClassID ( ) = = ANIM_COMP_CID | | comp - > ClassID ( ) = = ANIM_GROUP_COMP_CID )
{
pAnim = ( plAnimComponentBase * ) comp ;
break ;
}
}
plCamera1Component * pCamComp = nil ;
for ( i = 0 ; i < count ; i + + )
{
plComponentBase * comp = node - > GetAttachedComponent ( i ) ;
if ( comp - > ClassID ( ) = = FIXEDCAM_CID )
{
pCamComp = ( plCamera1Component * ) comp ;
break ;
}
}
const plCameraModifier1 * pCamMod = nil ;
count = node - > GetSceneObject ( ) - > GetNumModifiers ( ) ;
for ( i = 0 ; i < count ; i + + )
{
pCamMod = plCameraModifier1 : : ConvertNoRef ( node - > GetSceneObject ( ) - > GetModifier ( i ) ) ;
if ( pCamMod )
break ;
}
plCameraMsg * pCamMsg = new plCameraMsg ;
pCamMsg - > SetCmd ( plCameraMsg : : kSetAnimated ) ;
pCamMsg - > AddReceiver ( pCamMod - > GetKey ( ) ) ;
plConvert : : Instance ( ) . AddMessageToQueue ( pCamMsg ) ;
Object * obj = node - > EvalWorldState ( hsConverterUtils : : Instance ( ) . GetTime ( node - > GetInterface ( ) ) ) . obj ;
GenCamera * theCam ;
hsTArray < float > fovW ;
hsTArray < float > fovH ;
for ( i = 0 ; i < kfArray - > Count ( ) ; i + + )
{
TimeValue t = TimeValue ( GetTicksPerFrame ( ) * ( kfArray [ 0 ] [ i ] . fFrame ) ) ;
theCam = ( GenCamera * ) obj - > ConvertToType ( t , Class_ID ( LOOKAT_CAM_CLASS_ID , 0 ) ) ;
float FOVvalue = theCam - > GetFOV ( t ) ; // in radians
FOVvalue * = ( float ) ( 180.f / M_PI ) ; // to degrees
int FOVType = theCam - > GetFOVType ( ) ;
float wDeg , hDeg ;
switch ( FOVType )
{
case 0 : // FOV_W
{
wDeg = FOVvalue ;
hDeg = ( wDeg * 3 ) / 4 ;
}
break ;
case 1 : // FOV_H
{
hDeg = FOVvalue ;
wDeg = ( hDeg * 4 ) / 3 ;
}
break ;
}
fovW . Append ( wDeg ) ;
fovH . Append ( hDeg ) ;
}
for ( i = 0 ; i < kfArray - > Count ( ) ; i + + )
{
plCameraMsg * pFOVMsg = new plCameraMsg ;
plCameraConfig * pCfg = pFOVMsg - > GetConfig ( ) ;
if ( i = = kfArray - > Count ( ) - 1 )
{
pCfg - > fFOVh = fovH [ 0 ] ;
pCfg - > fFOVw = fovW [ 0 ] ;
pCfg - > fAccel = kfArray [ 0 ] [ 0 ] . fFrame / MAX_FRAMES_PER_SEC ;
}
else
{
pCfg - > fFOVh = fovH [ i + 1 ] ;
pCfg - > fFOVw = fovW [ i + 1 ] ;
pCfg - > fAccel = kfArray [ 0 ] [ i + 1 ] . fFrame / MAX_FRAMES_PER_SEC ;
}
pFOVMsg - > SetCmd ( plCameraMsg : : kAddFOVKeyframe ) ;
pFOVMsg - > AddReceiver ( pCamMod - > GetKey ( ) ) ;
plEventCallbackMsg * pCall = new plEventCallbackMsg ;
pCall - > fEvent = kTime ;
pCall - > fEventTime = kfArray [ 0 ] [ i ] . fFrame / MAX_FRAMES_PER_SEC ;
pCall - > fIndex = i ;
pCall - > AddReceiver ( pCamMod - > GetKey ( ) ) ;
plAnimCmdMsg * pMsg = new plAnimCmdMsg ;
pMsg - > AddReceiver ( pCamMod - > GetKey ( ) ) ;
pMsg - > SetSender ( pAnim - > GetModKey ( node ) ) ;
pMsg - > SetCmd ( plAnimCmdMsg : : kAddCallbacks ) ;
pMsg - > SetAnimName ( ENTIRE_ANIMATION_NAME ) ;
pMsg - > fTime = kfArray [ 0 ] [ i ] . fFrame / MAX_FRAMES_PER_SEC ;
pMsg - > AddCallback ( pCall ) ;
hsRefCnt_SafeUnRef ( pCall ) ;
plConvert : : Instance ( ) . AddMessageToQueue ( pFOVMsg ) ;
plConvert : : Instance ( ) . AddMessageToQueue ( pMsg ) ;
}
}