/*==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 .
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAnimStealthNode - Stealthy hidden INode that represents a single //
// segment's worth of animation info for a material. //
// Stored as an INode so they can be "selected" //
// by components as targets of animation messages. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plAnimStealthNode_h
#define _plAnimStealthNode_h
#include "Max.h"
#include "iparamb2.h"
#include "iparamm2.h"
#include "hsTypes.h"
#include "pnKeyedObject/plKey.h"
#include "MaxComponent/plAnimObjInterface.h"
#include "MaxComponent/plMaxAnimUtils.h"
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;
#define ANIMSTEALTH_CLASSID Class_ID(0xd0272f8, 0x750349c9)
#define REFMSG_NOTETRACK_ADDED REFMSG_USER + 1
class plPassMtlBase;
class NoteTrack;
class plMaxNode;
class plErrorMsg;
class plAnimTimeConvert;
//// Class Def ///////////////////////////////////////////////////////////////
class plAnimStealthNode : public HelperObject, public plAnimObjInterface
{
protected:
ClassDesc2 *fClassDesc;
IParamBlock2 *fParamBlock;
plPassMtlBase *fParentMtl;
static ParamBlockDesc2 sAnimStealthPB;
hsBool fPreppedForConvert;
SegmentMap *fCachedSegMap;
SegmentSpec *IGetSegmentSpec( void ) const;
public:
// Some IDs
enum
{
kBlockPB = 0
};
enum Refs
{
kRefParamBlock,
kRefParentMtl
};
// ParamBlock IDs
enum ParamBlockIDs
{
kPBAutoStart, // Start the Animation on load (V2)
kPBLoop, // Start Looping at Begin Location
kPBName, // Name of the notetrack animation to play
kPBLoopName, // Name of the notetrack specified loop
kPBEaseInType,
kPBEaseOutType,
kPBEaseInLength,
kPBEaseOutLength,
kPBEaseInMin,
kPBEaseInMax,
kPBEaseOutMin,
kPBEaseOutMax
};
plAnimStealthNode( BOOL loading );
virtual ~plAnimStealthNode();
void DeleteThis() { delete this; }
INode *GetINode( void );
plPassMtlBase *GetParentMtl( void );
void SetParentMtl( plPassMtlBase *parent );
void SetNodeName( const char *parentName );
// Create the dialog for this object and place it inside the given dialog, centering it in the given control if any
bool CreateAndEmbedDlg( IParamMap2 *parentMap, IMtlParams *parentParams, HWND frameCtrl = nil );
// Release said dialog
void ReleaseDlg( void );
// Switch underlying objects in the dialog (to avoid unnecessary deletion/recreations)
void SwitchDlg( plAnimStealthNode *toSwitchTo );
// Get the actual window handle of the currently active dialog displaying us
HWND GetWinDlg( void ) const;
// Interesting functions
const char *GetSegmentName( void ) const;
void SetSegment( const char *name ); // nil for "entire animation"
// Conversion from stealth's INode to the actual object
static bool CanConvertToStealth( INode *objNode );
static plAnimStealthNode *ConvertToStealth( INode *objNode );
///////////////////////////////////////////////////////////////////////////////////////
// Required Max functions
//
TCHAR* GetObjectName() { return (TCHAR*)fClassDesc->ClassName(); }
void InitNodeName(TSTR& s) { s = fClassDesc->InternalName(); }
void GetClassName(TSTR& s) { s = fClassDesc->ClassName(); }
Class_ID ClassID() { return ANIMSTEALTH_CLASSID; }
RefTargetHandle Clone(RemapDir &remap);
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
RefResult NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget, PartID& partID, RefMessage message);
// allow retreival of our paramblock from other plug-ins
// and the max core
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// We override because we don't want to be able to animate this sucker
int NumSubs() { return 0; }
Animatable *SubAnim( int i ) { return nil; }
TSTR SubAnimName( int i ) { return fClassDesc->ClassName(); }
// plug-in mouse creation callback
CreateMouseCallBack* GetCreateMouseCallBack();
void BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev);
void EndEditParams(IObjParam *ip, ULONG flags, Animatable *next);
// void SelectionSetChanged(Interface *ip, IUtil *iu);
void BuildMesh(TimeValue t);
void FreeCaches();
void GetLocalBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box);
void GetWorldBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box);
int Display(TimeValue t, INode *node, ViewExp *vpt, int flags);
int HitTest(TimeValue t, INode *node, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt);
ObjectState Eval(TimeValue t) { return ObjectState(this); }
IOResult Save(ISave* isave);
IOResult Load(ILoad* iload);
int CanConvertToType( Class_ID obtype ) { return ( obtype == ANIMSTEALTH_CLASSID ) ? 1 : 0; }
const char *GetCategory() { return fClassDesc->Category(); }
/// Parameter access
bool GetAutoStart( void ) const;
void SetAutoStart( bool b );
bool GetLoop( void ) const;
const char *GetLoopName( void ) const;
void SetLoop( bool b, const char *name );
UInt8 GetEaseInType( void ) const;
hsScalar GetEaseInLength( void ) const;
hsScalar GetEaseInMin( void ) const;
hsScalar GetEaseInMax( void ) const;
void SetEaseIn( UInt8 type, hsScalar length, hsScalar min, hsScalar max );
UInt8 GetEaseOutType( void ) const;
hsScalar GetEaseOutLength( void ) const;
hsScalar GetEaseOutMin( void ) const;
hsScalar GetEaseOutMax( void ) const;
void SetEaseOut( UInt8 type, hsScalar length, hsScalar min, hsScalar max );
// Conversion stuff
void GetAllStopPoints( hsTArray &out );
hsScalar GetSegStart( void ) const;
hsScalar GetSegEnd( void ) const;
void GetLoopPoints( hsScalar &start, hsScalar &end ) const;
void StuffToTimeConvert( plAnimTimeConvert &convert, hsScalar maxLength );
// plAnimObjInterface functions
virtual void PickTargetNode( IParamBlock2 *destPB, ParamID destParamID, ParamID typeID );
virtual hsBool IsNodeRestricted( void ) { return true; }
virtual const char *GetIfaceSegmentName( hsBool allowNil );
virtual hsBool GetKeyList( INode *restrictedNode, hsTArray &outKeys );
virtual hsBool MightRequireSeparateMaterial( void ) { return true; }
// Convert time, called on the setupProps pass for each material applied to a node in the scene
virtual hsBool SetupProperties( plMaxNode *node, plErrorMsg *pErrMsg );
virtual hsBool ConvertDeInit( plMaxNode *node, plErrorMsg *pErrMsg );
// Returns true if the parent material is applied to any node in the scene, false otherwise
hsBool IsParentUsedInScene( void );
};
//// Accessor for Parent's ParamBlock ////////////////////////////////////////
class plStealthNodeAccessor : public PBAccessor
{
protected:
void ISetParent( ReferenceTarget *target, plPassMtlBase *parent );
void IHandleSet( PB2Value &v, ReferenceMaker *owner, ParamID id, int tabIndex, TimeValue t );
public:
plStealthNodeAccessor() { }
static plStealthNodeAccessor &GetInstance( void );
virtual void Set( PB2Value &v, ReferenceMaker *owner, ParamID id, int tabIndex, TimeValue t );
virtual void TabChanged( tab_changes changeCode, Tab *tab, ReferenceMaker *owner,
ParamID id, int tabIndex, int count );
};
#endif //_plAnimStealthNode_h