/**************************************************************************** Copyright (c) 2002, Radon Labs GmbH Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #ifndef __actor_H__ #define __actor_H__ #include "app/appframework/app_fwd_decl.h" #include "core/refcounted.h" #include "core/ptr.h" #include "foundation/messaging/message.h" #include "messaging/dispatcher.h" #include "app/appframework/component.h" #include "util/dictionary.h" #include "util/guid.h" #include "debug/debugtimer.h" #include "app/appframework/serialization.h" #include "math/matrix44.h" #include "math/vector.h" #include "math/quaternion.h" #include "math/bbox.h" #ifndef __SCRIPT_COMMIT__ #include "foundation/util/scriptbind.h" #include "app/scriptfeature/inc/script_message.h" #include "app/scriptfeature/inc/script_utility.h" #endif #include "addons/resource/resourcemanager.h" #include "addons/resource/resourcepriority.h" #include "addons/resource/templateresloader.h" #include "addons/resource/templateressaver.h" //------------------------------------------------------------------------------ namespace Graphic { class RenderScene; } namespace App { class Actor; class ActorManager; class ScriptComponent; class RenderComponent; class PhysicsEntity; class SkinnedMeshRenderComponent; class SkeletonComponent; class AnimationComponent; enum SysLayerID { eSL_Defualt = 0,//RenderLayer::eRLDefault eSL_Assist = 31,//RenderLayer::eSL_Assist }; typedef uint LayerID; typedef uint TagID; class ActorSerializationArgs : public Serialization::SerializationArgs { public: inline ActorSerializationArgs(Actor* parent) { this->parent = parent; } Actor* parent; }; class ActorPropertySet { public: enum FlagProperty { logic_exclusive_pos_rot = 1 << 0, logic_exclusive_RootActorName = 1 << 1 }; const static ActorPropertySet s_defaultVal; ActorPropertySet():m_Flags(0) { } ~ActorPropertySet(){}; bool TestFlag(FlagProperty eFlag) const { return (eFlag & m_Flags) != 0; } void SetFlag(FlagProperty eFlag,bool bVal) { if ( bVal ) { m_Flags |= eFlag; } else { m_Flags &= (~eFlag); } } private: uint m_Flags; }; // Modified From Nebula3's Entity(Actor) and Property(Component). MayBe It's Good for Radon Labs. // But I think It's too Difficult to Understand Nebula3's Design for Newer. For Example: Property in DB Storage , So Many Thread, So Many Details Hidden in Addon... // Actor: Manage RelationShip And Component. TODO: Add TinyActor For Object With No Game Logic. // Addons: I Hope There are only Libs Which Can Be Replace By Other Libs Or ReUse By Other Engine. Idealism, But Can Be More Easier. // Component: First: Make Addons-Lib's Function Corresponded With Actor-Component Model // Second: Corresponded With Other Components With Message. class Actor : public Core::RefCounted, App::ISerialization { __DeclareClass(Actor); __ScriptBind public: /// an Id type, used to identify entities typedef unsigned int FastId; const static GPtr NullActor; /// destructor. but use Actor::destory virtual ~Actor(); virtual Graphic::RenderScene* GetRenderScene() const; //--------------------------------basic---------------------------------------- void SetName(const Util::String& name); const Util::String& GetName(void) const; /// get the Actor's category const Util::StringAtom& GetTemplateName() const; // store activeState for templatedActors void SetTmpActiveState(bool tmpActiveState); // get activeState for templatedActors bool GetTmpActiveState(); // set activeState for templatedActors void SetActiveStateForTemplate(); bool IsLinkTemplate(void) const; void SetLinkTemplate(bool bLink); LayerID GetLayerID(void) const; void SetLayerID(LayerID id); uint GetCullMark() const; TagID GetTagID(void) const; void SetTagID(TagID); /// get unique id of Actor FastId GetFastId() const; /// if the actor is active bool IsActive() const;//bool checkParent = true /// if the actor is active bool IsDestory() const; // active the actor and it's component. add in active actor list in ActorManger // if includeChild is true, all child actor will be active too void Active(bool forceActiveControlofChild = false); // Deactive the actor and it's component. remove from active actor list in ActorManger // if includeChild is true, all child actor will be deactive void Deactive(bool forceActiveControlofChild = false); bool GetActiveControl() const; /// actor's it's component and all child actor /// obsolete fuction. the same as Deactive(true). void Destory(bool forceChild = false); //--------------------------------Parent---------------------------------------- // return parent. May be Null Actor* GetParent(void) const; // set parent. will remove from old parent void SetParent( Actor* parent ); void SetParent( const GPtr& parent ); // return child count. May be 0 SizeT GetChildCount(void) const; // return child by index const GPtr& GetChild(IndexT i) const; // find actor by FastID const GPtr& FindChild(FastId id, bool includeGrandson = true) const; const GPtr& FindChildByTag(App::TagID id, bool includeGrandson = true) const; void FindChildrenByTag(const App::TagID tagID,Util::Array< GPtr >& actors, bool includeGrandson = true) const; const GPtr& FindChild(const Util::Guid& guid, bool includeGrandson = true) const; const GPtr& FindChild(const Util::String& name, bool includeGrandson = true) const; // find child actor index in child list IndexT FindChildIndex(FastId id) const; // add child. If childActor Has Parent, Failed, Need Remove Form Other Parent First. Please Use SetParent void AddChild(GPtr& childActor ); // Remove Child By Ptr or Index. if Null or Not Exist, Failed. After Removed, the Index of other Child Actor May Change void RemoveChild( const GPtr& childActor ); void RemoveChild( IndexT i ); // remove all child void RemoveAllChild(void); //----------------------------Transform ---------------------------------------- void SetPosition(const Math::vector& pos); void SetRotation(const Math::quaternion& rot); void SetScale(const Math::vector& scale); const Math::vector& GetPosition(void) const; const Math::quaternion& GetRotation(void) const; const Math::vector& GetScale(void) const; /** move around z axis(radian). */ void Roll(Math::scalar angle ); /** move around x axis(radian). */ void Pitch(Math::scalar angle ); /** move around y axis(radian). */ void Yaw(Math::scalar angle ); // roll first, then pitch, then yaw.radian. void Rotate(Math::scalar roll , Math::scalar pitch , Math::scalar yaw ); void SetTransform(const Math::vector& pos, const Math::quaternion& rot, const Math::vector& scale); void SetTransform( const Math::matrix44& m ); void SetWorldTransform( const Math::matrix44& m ); const Math::matrix44& GetTransform(void) const; const Util::Guid& GetGUID() const; void SetWorldPosition(const Math::vector& pos); void SetWorldRotation(const Math::quaternion& rot); void SetWorldScale(const Math::vector& scale); const Math::quaternion& GetWorldRotation(void) const; const Math::vector& GetWorldPosition(void) const; const Math::vector& GetWorldScale(void) const; const Math::matrix44& GetWorldTransform(void) const; const Math::matrix44 GetWorldTranslateRotation(void) const; // remove the scales of all parent actors const Math::matrix44 GetWorldTranslateNoScale(void) const; const Math::quaternion GetWorldRotationNoScale(void) const; //-------------------------------boundingbox----------------------------------------- // get world boundingbox. Just The Actor, No child actor const Math::bbox& GetWorldBoundingBox(void) const; // get world boundingbox. Include the Actor and it's child actor. Slow !!!!!!! Math::bbox GetWorldBoundingBoxWithChild(void) const; // get local boundingbox. default is [-0.5,-0.5,-0.5]~[0.5,0.5,0.5] const Math::bbox& GetLocalBoundingBox(void) const; // set Local boundingbox. void SetLocalBoundingBox(const Math::bbox& bb); //-------------------------------component----------------------------------------- /// return true if any Component accepts/processes message bool AcceptsMessage(const Messaging::Id& msgId) const; /// send a synchronous message to the Actor void SendSync(const GPtr& msg); /// throw a message to the script template void ThrowMessageToScript(const Util::String& name,T& pair); /// find Component by RTTI (performs IsA() check), returns invalid pointer if not exists, slow! const GPtr& FindComponent(const Core::Rtti& rtti) const; template GPtr FindComponent() const; /// find Component by RTTI (perform RTTI's operator == check),returns invalid pointer if not exists, /// now only used in script sys to get the exactly component in order to show correct debug imformation. const GPtr& FindComponentExactly(const Core::Rtti& rtti) const; /// find Components by RTTI (performs IsA() check), returns empty size if not exists, slow! const Util::Array< GPtr > FindComponents(const Core::Rtti& rtti) const; /// attach a Component to the Actor void AttachComponent(const GPtr& prop); /// remove a Component from the Actor void RemoveComponent(const GPtr& prop); /// destroy a Component from the Actor void DestroyComponent(const GPtr& prop); const bool IsAllResourcePrepared() const; void SaveTerrainFile(void) const; //----------------------------- callbacks ------------------------------------------- /// register a Component callback, called by ComponentSetupCallback() method void RegisterComponentCallback(const GPtr& prop, Component::CallbackType callback); /// called at the beginning of the frame void OnBeginFrame(); /// called before movement void OnMoveBefore(); /// called after movement void OnMoveAfter(); /// called before rendering void OnFrame(); /// called at the ending of the frame void OnEndFrame(); /// debug rendering called before rendering void OnRenderDebug(); //----------------------------------ISerialization-------------------------------------- // @ISerialization::GetVersion. when change storage, must add SerializeVersion count virtual Version GetVersion() const ; // @ISerialization::Load virtual void Load( Version ver, AppReader* pReader, const Serialization::SerializationArgs* args ) ; // @ISerialization::Save virtual void Save( AppWriter* pWriter ) const ; // copy from source Actor. after copy, all old components and the child actor in this actor will destroy // if includeSelfProperty is false, only the components and child actor will copy // if includePrivateProperty is true, the actor's property( like transform, layerID,...) , components and child actor will copy // if needRecurVFL is false, the actor's visible,frozen,lock states will affect its children. // after copy, the actor is deactive. should manu active if need virtual void CopyFrom( const GPtr& pSource,const ActorPropertySet& actorPropertySet, bool includePrivateProperty , bool isTemplate = false , bool needRecurVFL = true); //virtual void CopyFromTemplateRes(Resources::ResourceId resID);' //resource loading priority: if -1,use component's setup void SetPriority( const Resources::Priority priority ); Resources::Priority GetPriority() const; bool PriorityDefinition() const; bool PriorityUndefinition() const; //----------------------------------- between components ----------------------------- #ifndef __SCRIPT_COMMIT__ void Check_OnRenderPostEffect_Bind(); void Check_OnRenderPostEffect_Unbind(); void Check_OnWillRenderObject_Bind(); void Check_OnWillRenderObject_Unbind(); #endif static void Check_Skeleton(SkeletonComponent* skeleton); static void Check_Animation(AnimationComponent* animation); static void Check_Skin(SkinnedMeshRenderComponent* skin); void OpenComponentsCommSign(ComponetsCommSign sign); void CloseComponentsCommSign(ComponetsCommSign sign); bool IsComponentsCommSignOpen(ComponetsCommSign sign); void _UpdateLocalBBox(); protected: typedef Util::Array Children; // recompute world transform if need void _UpdateWolrdTransform() const; void _UpdateLocalTransform() const; void _CopyFrom_MustProperty( const GPtr& pSource, bool needRecurVFL); void _CopyFrom_IncludeProperty( const GPtr& pSource,const ActorPropertySet& actorPropertySet); void _CopyFrom_TemplateProperty( const GPtr& pSource,const ActorPropertySet& actorPropertySet); void _CopyFrom_CommonProperty( const GPtr& pSource,const ActorPropertySet& actorPropertySet); void _CheckActive(); void _CheckDeactive(); void _Active(bool forceActiveControlofChild = false); void _Deactive(bool forceActiveControlofChild = false); void _OnRenderSceneChanged(); void _OnActorParentChanged(); /// set Actor category void SetTemplateName(const Util::StringAtom& tepName); /// cleanup the Actor Components, called from OnDeactivate() void _CleanupAllComponents(); /// call OnActivate() on all Components void _ActivateAllComponents(); /// call OnDeactivate() on all Components void _DeactivateAllComponents(); void _ActiveComponent( const GPtr& pComponent ); void _DeactiveComponent( const GPtr& pComponent ); void _SetParentImpl(Actor* p); void _DirtyWorldTransform(); /// called when attached to world. Just called by ActorManger void OnActivate(); /// called when removed from world. Just called by ActorManger void OnDeactivate(); #ifdef __GENESIS_EDITOR__ public: void SetQueryMask(uint mask); uint GetQueryMask() const; const Math::vector& GetEulerRotation() const; void SetEulerRotation(const Math::vector & rot); void SetFrozen( bool bFrozen , bool needRecursive = true ); bool GetFrozen() { return mFrozen; } protected: Math::vector mEulerAngle; uint mQueryMask; bool mFrozen; #endif public: enum EditorFlag { RenderLightMap = 1, }; void SetEditorFlag(EditorFlag flags); EditorFlag GetEditorFlag() const; bool CheckEditorFlag (EditorFlag flags); void SetVisible( bool bVisible , bool needRecursive = true); bool GetVisible() const; //return true if this actor is a child of one actor that has a animation component bool IsChildOfAnimationActor(); void SetModelName(const Util::String& name) { mModelName = name; } const Util::String& GetModelName(void) const { return mModelName; } protected:// date uint mEditorFlag; FastId mFastId; static FastId s_fastIdCounter; Util::Guid mGuid; Util::String mName; bool mActivated; //when true, actor will be actived when it is parent is been actived. bool mActiveControl; bool mTmpActiveState; Util::StringAtom mTemplateName; bool mIsLinkTemplate; LayerID mLayerID; TagID mTagID; //flag config of components. //used for bit flag.see, enum ComponetsCommSign TagID mComponentsCommSign; //local transform and bound Math::quaternion mLocalRotation; Math::vector mLocalPosition; Math::vector mLocalScale; Math::bbox mLocalBB; // cache transform and bound mutable Math::matrix44 mLocaTrans; mutable bool mDirtyLocaTrans; mutable Math::quaternion mWorldRotation; mutable Math::vector mWorldPosition; mutable Math::vector mWorldScale; mutable Math::matrix44 mWorldTrans; mutable bool mDirtyWorldTrans; mutable Math::bbox mWorldBB; mutable bool mDirtyWorldBB; GPtr mDispatcher; Util::Array > mComponents; Util::FixedArray > > mCallbackComponents; Actor* mParent; Children mChildren; bool mVisible; Resources::Priority mPriority; Util::String mModelName; //GPtr mTemplateResInfo; friend class ActorManager; friend class ActorSerialization; friend class Scene; #if NEBULA3_ENABLE_PROFILING Util::Dictionary > mComponentActivateDebugTimer; Util::Dictionary > mComponentDeactivateDebugTimer; Util::Dictionary > mComponentOnBeginFrameDebugTimer; Util::Dictionary > mComponentOnMoveBeforeDebugTimer; Util::Dictionary > mComponentOnMoveAfterDebugTimer; Util::Dictionary > mComponentOnRenderDebugTimer; void _AttachComponentTimer( const Core::Rtti* pRtti ); void _RemoveComponentTimer( const Core::Rtti* pRtti ); void _ResetComponentTimer(); #endif /// constructor. but use Actor::Create() Actor(); private: //internal call. /// actor's it's component and all child actor. void _Destory(bool forceShutDown = false); }; //------------------------------------------------------------------------ inline void Actor::SetName(const Util::String& name) { mName = name; } //------------------------------------------------------------------------ inline const Util::String& Actor::GetName(void) const { return mName; } //------------------------------------------------------------------------------ /** */ inline void Actor::SetTemplateName(const Util::StringAtom& tepName) { if (tepName.IsValid()) { Util::String str = tepName.AsString(); str.ToLower(); if (str == "empty") { this->mTemplateName = ""; return; } } this->mTemplateName = tepName; } //------------------------------------------------------------------------------ /** */ inline const Util::StringAtom& Actor::GetTemplateName() const { return this->mTemplateName; } //------------------------------------------------------------------------ inline bool Actor::IsLinkTemplate(void) const { return mIsLinkTemplate; } //------------------------------------------------------------------------ inline void Actor::SetLinkTemplate(bool bLink) { mIsLinkTemplate = bLink; } //------------------------------------------------------------------------ inline LayerID Actor::GetLayerID(void) const { return mLayerID; } //------------------------------------------------------------------------ inline uint Actor::GetCullMark(void) const { return 1 << mLayerID; } //------------------------------------------------------------------------ inline TagID Actor::GetTagID(void) const { return mTagID; } //------------------------------------------------------------------------ inline void Actor::SetTagID(TagID id) { mTagID = id; } //------------------------------------------------------------------------------ /** */ inline bool Actor::IsActive() const//bool checkParent/* = true*/ { return mActivated; //if (checkParent) //{ // return mActivated && IsParentActive(true); //} //else //{ // return mActivated; //} } //------------------------------------------------------------------------------ inline bool Actor::GetActiveControl() const { return mActiveControl; } //------------------------------------------------------------------------------ inline void Actor::SetTmpActiveState(bool tmpActiveState) { mTmpActiveState = tmpActiveState; } inline bool Actor::GetTmpActiveState() { return mTmpActiveState; } //------------------------------------------------------------------------------ /** */ inline uint Actor::GetFastId() const { return this->mFastId; } //------------------------------------------------------------------------------ /** */ inline const Math::vector& Actor::GetPosition() const { return this->mLocalPosition; } //------------------------------------------------------------------------------ /** */ inline const Util::Guid& Actor::GetGUID() const { return this->mGuid; } //------------------------------------------------------------------------------ /** */ inline const Math::quaternion& Actor::GetRotation() const { return this->mLocalRotation; } //------------------------------------------------------------------------------ /** */ inline const Math::vector& Actor::GetScale() const { return this->mLocalScale; } //------------------------------------------------------------------------------ /** */ inline bool Actor::AcceptsMessage(const Messaging::Id& msgId) const { return this->mDispatcher->AcceptsMessage(msgId); } //------------------------------------------------------------------------------ /** */ inline void Actor::SendSync(const GPtr& msg) { this->mDispatcher->HandleMessage(msg); } //------------------------------------------------------------------------ inline const Math::bbox& Actor::GetLocalBoundingBox(void) const { return mLocalBB; } //------------------------------------------------------------------------ inline Actor* Actor::GetParent(void) const { return mParent; } //------------------------------------------------------------------------ inline SizeT Actor::GetChildCount(void) const { return mChildren.Size(); } //------------------------------------------------------------------------ inline void Actor::Roll(Math::scalar angle ) { Rotate(angle, 0, 0); } //------------------------------------------------------------------------ inline void Actor::Pitch(Math::scalar angle ) { Rotate(0, angle, 0); } //------------------------------------------------------------------------ inline void Actor::Yaw(Math::scalar angle ) { Rotate(0, 0, angle); } //------------------------------------------------------------------------ inline void Actor::Rotate(Math::scalar roll , Math::scalar pitch , Math::scalar yaw ) { Math::quaternion q = Math::quaternion::rotationyawpitchroll(yaw, pitch, roll); SetRotation(q); } //------------------------------------------------------------------------ inline void Actor::OpenComponentsCommSign(ComponetsCommSign sign) { mComponentsCommSign |= sign; } //------------------------------------------------------------------------ inline void Actor::CloseComponentsCommSign(ComponetsCommSign sign) { mComponentsCommSign &= (~sign); } //------------------------------------------------------------------------ inline bool Actor::IsComponentsCommSignOpen(ComponetsCommSign sign) { return (mComponentsCommSign & sign) != 0; } //------------------------------------------------------------------------ #ifdef __GENESIS_EDITOR__ //------------------------------------------------------------------------ inline void Actor::SetQueryMask(uint mask) { if (mask > 31 || mask < 0) { n_assert(0); return; } mQueryMask = mask; } //------------------------------------------------------------------------ inline uint Actor::GetQueryMask() const { return mQueryMask; } //------------------------------------------------------------------------ inline const Math::vector& Actor::GetEulerRotation() const { return mEulerAngle; } //------------------------------------------------------------------------ inline void Actor::SetEulerRotation(const Math::vector & rot) { mEulerAngle = rot; } //------------------------------------------------------------------------ #endif inline bool Actor::CheckEditorFlag (EditorFlag flags) { return (mEditorFlag & (uint)flags) != 0; } //------------------------------------------------------------------------ inline App::Actor::EditorFlag Actor::GetEditorFlag () const { return (EditorFlag)mEditorFlag; } //------------------------------------------------------------------------ inline void Actor::SetEditorFlag (EditorFlag flags) { mEditorFlag = (uint)flags; } inline Resources::Priority Actor::GetPriority() const { return mPriority; } inline bool Actor::PriorityDefinition() const { return (Resources::ResourcePriority::Undefinition != mPriority); } inline bool Actor::PriorityUndefinition() const { return (Resources::ResourcePriority::Undefinition == mPriority); } template GPtr Actor::FindComponent() const { const GPtr& obj = this->FindComponent( T::RTTI ); if ( obj ) { return obj.downcast(); } else { return GPtr(0); } } #ifndef __SCRIPT_COMMIT__ //------------------------------------------------------------------------- template void Actor::ThrowMessageToScript( const Util::String& name,T& pair ) { TScriptMessagePtr msg = ScriptMessageCreator::Instance()->CreateMessage(name,pair); SendSync( msg.upcast() ); } #endif } // namespace Game //------------------------------------------------------------------------------ #endif // __actor_H__