// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef PARTICLE_NODE_H #define PARTICLE_NODE_H // STL includes #include #include // NeL includes #include "nel/misc/smart_ptr.h" #include "nel/misc/stream.h" #include #include "nel/3d/skeleton_model.h" // Projects includes #include "ps_initial_pos.h" namespace NL3D { class CParticleSystem; class CParticleSystemModel; class CShapeBank; } namespace NLQT { class CParticleWorkspace; /** @class CWorkspaceNode @author Nicolas Vizerie @author Nevrax France @date 2004 @brief A node in the workspace particles system editor. @details Contains NeL system of particles and allows them to perform the following operations: - Creating a new empty particle system (createEmptyPS()). - Loading and saving the existing system of particles. - Linking / unlinking of the system of particles to any bone of the skeleton model. - Operations with the name and directory location of the particles system file. - Has a flag indicating if the particles system changed or not (intended for the editor) */ class CWorkspaceNode : public NLMISC::CRefCount { public: void init(CParticleWorkspace *ws); void setRelativePath(const std::string &relativePath); const std::string &getRelativePath() const { return _RelativePath; } std::string getFullPath() const; std::string getFilename() const { return NLMISC::CFile::getFilename(_RelativePath); } /// Serial node information into workspace stream. This does not save the particle system shape, only a reference to its file void serial(NLMISC::IStream &f); /// Save the particle system target file void savePS() throw(NLMISC::EStream); /// Save particle system with an arbitrary filename void savePSAs(const std::string &fullPath) throw(NLMISC::EStream); /// put back in the unloaded state void unload(); /// Load the particle system target file /// @return true if loading succeed (false means that loading was ok, but this is not a particle system). Other cases throw an exception. bool loadPS() throw(NLMISC::EStream); /// Create an empty particle system void createEmptyPS(); /// Helper flag to know if a ps has been modified /// @{ bool isModified() const { return _Modified; } void setModified(bool modified); /// @} NL3D::CParticleSystem *getPSPointer() const { return _PS; } NL3D::CParticleSystemModel *getPSModel() const { return _PSM; } /// See if this node ps has been loaded bool isLoaded() const { return _PS != NULL; } /// Get the workspace in which this node is inserted CParticleWorkspace *getWorkspace() const { return _WS; } /// Memorize current position of object in the system. Useful to play the system because instances can be created / deleted void memorizeState(); /// Restore state previously memorize. Is usually called when the user stops a particle system void restoreState(); /// Test if state is currenlty memorized bool isStateMemorized() const; /// For edition : If the state of the system has been memorized, keep it on par with the system when it is modified void removeLocated(NL3D::CPSLocated *loc); /// For edition : If the state of the system has been memorized, keep it on par with the system when it is modified void removeLocatedBindable(NL3D::CPSLocatedBindable *lb); /// Returns the skeleton to which the ps is currently sticked NL3D::CSkeletonModel *getParentSkel() const { return _ParentSkel; } const std::string &getParentSkelName() const { return _ParentSkelName; } const std::string &getParentBoneName() const { return _ParentBoneName; } std::string getTriggerAnim() { return _TriggerAnim; } void setTriggerAnim(const std::string &anim); private: std::string _TriggerAnim; NL3D::CParticleSystem *_PS; NL3D::CParticleSystemModel *_PSM; // Keep a shape bank per node because we want the whole path to identify the ps, not just its filename // (shape bank keeps the filename only) NL3D::CShapeBank *_ShapeBank; // Relative path from which the ps was inserted // relative path is also a unique identifier for this ps in the workspace std::string _RelativePath; // initial pos of system. Allow to restore the initial instances of the system when doing start / stop CPSInitialPos _InitialPos; bool _Modified; CParticleWorkspace *_WS; NLMISC::CRefPtr _ParentSkel; bool _ResetAutoCount; // std::string _ParentSkelName; std::string _ParentBoneName; private: void setup(NL3D::CParticleSystemModel &psm); public: bool getResetAutoCountFlag() const { return _ResetAutoCount; } void setResetAutoCountFlag(bool reset) { _ResetAutoCount = reset; } /// Stick to a skeleton void stickPSToSkeleton(NL3D::CSkeletonModel *skel, uint bone, const std::string &parentSkelName, // for callback after loading const std::string &parentBoneName ); void unstickPSFromSkeleton(); private: friend class CParticleWorkspace; // Ctor CWorkspaceNode(); public: // DTor ~CWorkspaceNode(); }; /* class CWorkspaceNode */ typedef std::vector > TNodeVect; typedef TNodeVect::iterator TPWNodeItr; /** @class CParticleWorkspace @author Nicolas Vizerie @author Nevrax France @date 2004 @brief A container containing all the loaded particle system. @details Allows you to load \ save in xml file list of systems of particles (the path to each file as well) and additional parameters (skeleton model, and to which bone it is attached) There is a feedback mechanism showed changes are being made with the container,with a particle system or connection to the skeleton. */ class CParticleWorkspace { public: /// callback to know when a workspace node has been modified struct IModificationCallback { virtual void workspaceModifiedFlagChanged(CParticleWorkspace &pw) = 0; virtual void nodeModifiedFlagChanged(CWorkspaceNode &node) = 0; virtual void nodeSkelParentChanged(CWorkspaceNode &node) = 0; // called when fx has been linked / unlinked from a skeleton parent }; /// Сonstructor CParticleWorkspace(); /// Destructor ~CParticleWorkspace(); /// Init the workspace for the given object viewer /// must be called prior to other methods void init(const std::string &filename); /// Set a new name for the workspace (not its filename) void setName(const std::string &name); /// Set a new file name for the workspace void setFileName(const std::string &fileName); std::string getName() const { return _Name; } /// Get the path in which workpsace is located with a trailing slash std::string getPath() const; std::string getFilename() const; /// Get Number of nodes in the workspace uint getNumNode() const { return (uint)_Nodes.size(); } /// Get a node in workspace /// Can keep pointer safely as long as the node is not deleted CWorkspaceNode *getNode(uint index) const { return _Nodes[index]; } /// Get a node from a pointer on a particle system CWorkspaceNode *getNodeFromPS(NL3D::CParticleSystem *ps) const; /// Test if the workspace already contains a node with the given filename name /// NB : 2 node with the same name re not allowed, even if their path is different bool containsFile(std::string filename) const; /// Add a node in the workspace. Will succeed only if fx filename does not already exist in the workspace. /// The node is in the 'unloaded' state, so caller must load it afterward. /// NB : no lookup is done, full path must be provided. /// @return pointer to new node, or NULL if already inserted CWorkspaceNode *addNode(const std::string &filenameWithFullPath) throw( NLMISC::Exception); /// Remove a node by it's index void removeNode(uint index); /// Remove a node by it's pointer void removeNode(CWorkspaceNode *ptr); /// Get index of a node from its pointer, or -1 if not found sint getIndexFromNode(CWorkspaceNode *node) const; /// Save the workspace structure. The target file is the one given when this object was created /// NB : ps shape are not saved, only the structure is. To save the shapes, call CNode::save() void save() throw(NLMISC::EStream); /// Load the workspace structure. The target file is the one given when this object was created /// All nodes are in the 'unloaded" state, so it is to the caller to load them by calling load() on their node void load() throw(NLMISC::EStream); /// Test whether the structure of the workspace has been modified (does not test if ps inside the workspace have been modified) bool isModified() const { return _Modified; } /// Test whether the content of the workspace has ben modified bool isContentModified() const; void touch() { setModifiedFlag(true); } void clearModifiedFlag() { setModifiedFlag(false); } /// Set a callback to know when a node is modified void setModificationCallback(IModificationCallback *cb) { _ModificationCallback = cb; } IModificationCallback *getModificationCallback() const { return _ModificationCallback; } /// Restick all objects, useful after loading void restickAllObjects(); TNodeVect& getNodeList() { return _Nodes; } private: // use smart ptr to avoir prb wih resize TNodeVect _Nodes; // path + name of workspace std::string _Filename; bool _Modified; IModificationCallback *_ModificationCallback; // workspace user name std::string _Name; /// serial the object void serial(NLMISC::IStream &f) throw(NLMISC::EStream); /// set the 'modified flag' and call the callback void setModifiedFlag(bool modified); public: void nodeModified(CWorkspaceNode &node); }; /* class CParticleWorkspace */ } /* namespace NLQT */ #endif // PARTICLE_NODE_H