////////////////////////////////////////////////////////////////////////////////// // SPARK particle engine // // Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com // // // // This software is provided 'as-is', without any express or implied // // warranty. In no event will the authors be held liable for any damages // // arising from the use of this software. // // // // Permission is granted to anyone to use this software for any purpose, // // including commercial applications, and to alter it and redistribute it // // freely, subject to the following restrictions: // // // // 1. The origin of this software must not be misrepresented; you must not // // claim that you wrote the original software. If you use this software // // in a product, an acknowledgment in the product documentation would be // // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // ////////////////////////////////////////////////////////////////////////////////// #ifndef H_SPK_MODIFIER #define H_SPK_MODIFIER #include "Core/SPK_DEF.h" #include "Core/SPK_Vector3D.h" #include "Core/SPK_Registerable.h" #include "Core/SPK_BufferHandler.h" #include "Core/SPK_Zone.h" #include "Core/SPK_Particle.h" namespace SPK { class ModifierGroup; /** * @enum ModifierTrigger * @brief Constants defining the triggers for Modifier */ enum ModifierTrigger { ALWAYS = 1 << 0, /**< No trigger, a Particle is always modified */ INSIDE_ZONE = 1 << 1, /**< Trigger defining a Particle inside the Zone */ OUTSIDE_ZONE = 1 << 2, /**< Trigger defining a Particle outside the Zone */ INTERSECT_ZONE = 1 << 3, /**< Trigger defining a Particle intersecting the Zone (in any direction) */ ENTER_ZONE = 1 << 4, /**< Trigger defining a Particle entering the Zone */ EXIT_ZONE = 1 << 5, /**< Trigger defining a Particle exiting the Zone */ }; /** * @class Modifier * @brief A abstract class that defines a physical object acting on particles * * A Modifier is first defined by a Zone and a trigger to that Zone.
* If the Particle triggers the Modifier, the Modifier's action is applied to the Particle.
* An action can be anything that has effect on the Particle's parameters, position, velocity, life...
*
* If no Zone is attached to a Modifier the Zone is considered to be the entire universe.
*
* Like an Emitter, a Modifier can either be used automatically within a Group or manually directly by the user. */ class SPK_PREFIX Modifier : public Registerable, public Transformable, public BufferHandler { friend class ModifierGroup; friend class Group; friend class Particle; public : ///////////////// // Constructor // ///////////////// /** * @brief Constructor of Modifier * @param availableTriggers : the available triggers for this Modifier (OR-ed) * @param trigger : the default trigger of the Modifier * @param needsIntersection : true if the computation of the intersection is needed, false otherwise * @param needsNormal : true if the computation of the normal is needed, false otherwise * @param zone : the Zone of the Modifier */ Modifier(int availableTriggers = ALWAYS,ModifierTrigger trigger = ALWAYS,bool needsIntersection = false,bool needsNormal = false,Zone* zone = NULL); //////////////// // Destructor // //////////////// /** @brief Destructor of Modifier */ virtual inline ~Modifier() {} ///////////// // Setters // ///////////// /** * @brief Sets this Modifier active or not. * * An inactive Modifier will not affect its parent Group during update.
* However it can still be used manually by the user. * * @param active : true to activate this Modifier, false to deactivate it * @since 1.03.00 */ inline void setActive(bool active); /** * @brief Sets the Zone of this Modifier * * If the Zone is NULL, the Zone is considered to be the entire universe. * * @param zone : the Zone of this Modifier * @param full : true to consider the Zone as a full object so that particles are not allowed to be within */ void setZone(Zone* zone,bool full = false); /** * @brief Sets the trigger of this Modifier * * if the trigger is not one of the available triggers (see getAvailableTriggers()) for this Modifier, * nothing happens ad false is returned else the trigger is set and true is returned. * * @param trigger : the trigger of this Modifier * @return true if the trigger can be set, false otherwise */ bool setTrigger(ModifierTrigger trigger); /** * @brief Sets whether to consider this modifier local to a system or not * * A local modifier is transformed when its system is transformed, a non local one will not. * * @param local : true to consider the modifier local, false not to * @since 1.03.02 */ inline void setLocalToSystem(bool local); ///////////// // Getters // ///////////// /** * @brief Tells whether this Modifier is active or not * @return true if this Modifier is active, false if is is inactive * @since 1.03.00 */ inline bool isActive() const; /** * @brief Gets the Zone of this Modifier * @return the Zone of this Modifier */ inline Zone* getZone() const; /** * @brief Gets the trigger of this Modifier * @return the trigger of this Modifier */ inline ModifierTrigger getTrigger() const; /** * @brief Gets a flag containing all the available triggers for this Modifier * @return a flag containing all the available triggers for this Modifier */ inline int getAvailableTriggers() const; /** * @brief Tells whether the Zone of this Modifier is considerered to be full or not * @return true if the Zone of this Modifier is considerered to be full, false if not */ inline bool isFullZone() const; /** * @brief Tells whether this modifier is considered as being local to a system or not * * A local modifier is transformed when its system is transformed, a non local one will not. * * @return true if it is local, false if not * @since 1.03.02 */ inline bool isLocalToSystem() const; /////////////// // Interface // /////////////// virtual Registerable* findByName(const std::string& name); protected : /** @brief the Vector3D that holds the intersection coordinates */ static Vector3D intersection; /** @brief the Vector3D that holds the intersection coordinates */ static Vector3D normal; /** @brief true if the Modifier needs the intersection computation, false if not */ bool needsIntersection; /** @brief true if the Modifier needs the normal computation, false if not */ bool needsNormal; /** @brief the current trigger of this Modifier */ ModifierTrigger trigger; /** @brief a flag containing all the available triggers */ const int availableTriggers; virtual void registerChildren(bool registerAll); virtual void copyChildren(const Modifier& modifier,bool createBase); virtual void destroyChildren(bool keepChildren); virtual inline void propagateUpdateTransform(); private : Zone* zone; bool full; bool active; mutable bool savedActive; bool local; void beginProcess(Group& group); inline void endProcess(Group& group); inline void process(Particle& particle,float deltaTime) const; ////////////////////////// // Pure virtual methods // ////////////////////////// /** * @brief A pure virtual method that modifies the Particle * * This is a pure virtual method to be implemented by children.
* The Modifier on this Particle has already been triggered and the Particle must be modified by this method. * * @param particle : the Particle that has to be modified * @param deltaTime : the time step */ virtual void modify(Particle& particle,float deltaTime) const = 0; /** * @brief A pure virtual method that handles particles on the wrong side of this Modifier Zone. * * This is a pure virtual method to be implemented by children.
* This method can be called internally with all triggers except SPK::TRIGGER_INTERSECTS.
*
* The method isFullZone() can be called to vary the behavior whether the Zone is full or not.
* The boolean inside indicates whether the wrong side is inside (true) or outside (false) the Zone. * * @param particle : the Particle which is on the wrong side * @param inside : true if the wrong side is inside, false if it is oustside */ virtual void modifyWrongSide(Particle& particle,bool inside) const {} }; inline void Modifier::setActive(bool active) { this->active = active; } inline void Modifier::setLocalToSystem(bool local) { this->local = local; } inline bool Modifier::isActive() const { return active; } inline Zone* Modifier::getZone() const { return zone; } inline ModifierTrigger Modifier::getTrigger() const { return trigger; } inline int Modifier::getAvailableTriggers() const { return availableTriggers; } inline bool Modifier::isFullZone() const { return full; } inline bool Modifier::isLocalToSystem() const { return local; } inline void Modifier::propagateUpdateTransform() { if (zone != NULL) zone->updateTransform(this); } inline void Modifier::endProcess(Group& group) { active = savedActive; // Restores the active state of the modifier } inline void Modifier::process(Particle& particle,float deltaTime) const { switch(trigger) { case ALWAYS : modify(particle,deltaTime); break; case INSIDE_ZONE : if ((zone == NULL)||(zone->contains(particle.position()))) modify(particle,deltaTime); else modifyWrongSide(particle,true); break; case OUTSIDE_ZONE : if (zone == NULL) return; if (!zone->contains(particle.position())) modify(particle,deltaTime); else modifyWrongSide(particle,false); break; case INTERSECT_ZONE : if (zone == NULL) return; if (zone->intersects(particle.oldPosition(), particle.position(), needsIntersection ? &intersection : NULL, needsNormal ? &normal : NULL)) modify(particle,deltaTime); break; case ENTER_ZONE : if (zone == NULL) return; if (zone->contains(particle.oldPosition())) modifyWrongSide(particle,true); else if (zone->intersects(particle.oldPosition(), particle.position(), needsIntersection ? &intersection : NULL, needsNormal ? &normal : NULL)) modify(particle,deltaTime); break; case EXIT_ZONE : if (zone == NULL) return; if (!zone->contains(particle.oldPosition())) modifyWrongSide(particle,false); else if (zone->intersects(particle.oldPosition(), particle.position(), needsIntersection ? &intersection : NULL, needsNormal ? &normal : NULL)) modify(particle,deltaTime); break; } } } #endif