1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 /** ***************************************************************************
12 *** \file    particle_effect.h
13 *** \author  Raj Sharma, roos@allacrost.org
14 *** \author  Yohann Ferreira, yohann ferreira orange fr
15 *** \brief   Header file for particle effects
16 ***
17 *** Particle effects are basically nothing more than a collection of particle
18 *** systems. Many effects are just one system. However, for example, if you think
19 *** about a campfire effect, that might actually consist of fire + smoke + embers.
20 *** So, that's an example of an effect that consists of 3 systems.
21 ***
22 *** This file contains two classes: ParticleEffectDef, and ParticleEffect.
23 ***
24 *** ParticleEffectDef is a "definition" class, which holds a list of
25 ***    ParticleSystemDefs.
26 ***
27 *** ParticleEffect is an "instance" class, which holds a list of
28 ***    ParticleSystems.
29 ***
30 ***
31 *** This way, if you have 100 explosions, the properties of the
32 *** effect are stored only once in a ParticleEffectDef, and the only thing that
33 *** gets repeated 100 times is the ParticleEffect, which holds instance-specific stuff.
34 *** **************************************************************************/
35 
36 #ifndef __PARTICLE_EFFECT_HEADER__
37 #define __PARTICLE_EFFECT_HEADER__
38 
39 #include "engine/video/particle_system.h"
40 
41 namespace vt_script {
42 class ReadScriptDescriptor;
43 }
44 
45 namespace vt_map
46 {
47 namespace private_map
48 {
49 class ParticleObject;
50 }
51 }
52 
53 namespace vt_mode_manager
54 {
55 
56 /*!***************************************************************************
57  *  \brief particle effect definition, just consists of each of its subsystems'
58  *         definitions.
59  *****************************************************************************/
60 
61 class ParticleEffectDef
62 {
63 public:
ParticleEffectDef()64     ParticleEffectDef():
65         effect_width(0.0f),
66         effect_height(0.0f),
67         effect_collision_width(0.0f),
68         effect_collision_height(0.0f)
69     {}
70 
Clear()71     void Clear() {
72         effect_width = 0.0f;
73         effect_height = 0.0f;
74         effect_collision_width = 0.0f;
75         effect_collision_height = 0.0f;
76         _systems.clear();
77     }
78 
79     /** The effect size in pixels, used to know when to display it when it used as
80     *** a map object for instance. It is used to compute the image rectangle.
81     *** \note Not used if equal to 0.
82     **/
83     float effect_width;
84     float effect_height;
85 
86     /** The effect collision size in pixels.
87     *** \note Not used if equal to 0.
88     **/
89     float effect_collision_width;
90     float effect_collision_height;
91 
92     //! list of system definitions
93     std::vector<ParticleSystemDef> _systems;
94 };
95 
96 
97 /*!***************************************************************************
98  *  \brief particle effect, basically one coherent "effect" like an explosion,
99  *         or snow falling from the sky. Consists of one or more ParticleSystems.
100  *         An example of using multiple systems to create one effect would be
101  *         a campfire where you have fire + smoke + glowing embers.
102  *****************************************************************************/
103 
104 class ParticleEffect
105 {
106 public:
107     /*!
108      *  \brief Constructor
109      */
ParticleEffect()110     ParticleEffect() {
111         _Destroy();
112     }
113 
ParticleEffect(const std::string & effect_filename)114     ParticleEffect(const std::string &effect_filename) {
115         _Destroy();
116         LoadEffect(effect_filename);
117     }
118 
119     /** Create a particle effect without registering it to the particle manager.
120     *** It is useful managing a particle effect as a map object, for instance,
121     *** as one can control the drawing order.
122     *** \param filename The particle effect filename to load
123     *** \return whether the effect is valid.
124     **/
125     bool LoadEffect(const std::string &effect_filename);
126 
127     /*!
128      *  \brief moves the effect to the specified position on the screen,
129      *         This can be used if you want to move a particle system around
130      *         on some flight path, or if you want to attach the system to an
131      *         object. (e.g. smoke to a jet)
132      * \param x movement of system in x direction
133      * \param y movement of system in y direction
134      */
135     void Move(float x, float y);
136 
137     /*!
138      *  \brief moves the effect dx and dy units relative to its current position
139      * \param dx x offset to move to from current x position
140      * \param dy y offset to move to from current y position
141      */
142     void MoveRelative(float dx, float dy);
143 
144     /*!
145      *  \brief set the orientation of the effect (including all systems contained
146      *         within the effect). This is essentially added to the emitter orientation
147      *         for each system. For example, if you want to create a particle system for
148      *         smoke coming out of a jet, set the emitter orientation to zero degrees (right)
149      *         when you create the effect. Then, at runtime just call SetOrientation() every
150      *         frame with the angle the jet is facing.
151      * \param angle rotation of particle system
152      */
SetOrientation(float angle)153     void SetOrientation(float angle) {
154         _orientation = angle;
155     }
156 
157     /*!
158      *  \brief set the position of an "attractor point". Any particle systems which use
159      *         radial acceleration and have user-defined attractor points enabled will
160      *         have particles move towards this point
161      *
162      *  \note  a positive radial acceleration will move a particle away from the attractor,
163      *         and negative will move it towards it.
164      * \param x x coordiante of gravitation point
165      * \param y y coordiante of gravitation point
166      */
167     void SetAttractorPoint(float x, float y);
168 
169     /*!
170      *  \brief returns true if the system is alive, i.e. the number of active
171      *         particles is more than zero. This is used by the particle manager
172      *         so it knows when to destroy an effect when registered to it.
173      * \return true if system is alive, false if dead
174      */
IsAlive()175     bool IsAlive() const {
176         return _alive;
177     }
178 
179     /*!
180      *  \brief stops this effect
181      *
182      *  \param kill_immediate If this is true, the effect is immediately killed. If
183      *                        it isn't true, then we stop the effect from emitting
184      *                        new particles, and allow it to live until all the active
185      *                        particles fizzle out.
186      *  \note When registered in the particle Manager, the effect will be destroyed
187      *        at its end of life.
188      */
189     void Stop(bool kill_immediate = false);
190 
191     /*!
192      *  \brief starts this effect
193      *  \return whether the effect was started.
194      */
195     bool Start();
196 
197     /*!
198      *  \brief return the number of active particles in this effect
199      * \return number of particles in the system
200      */
GetNumParticles()201     int32_t GetNumParticles() const {
202         return _num_particles;
203     }
204 
205     //! \brief return the position of the effect into x and y
206     const vt_common::Position2D& GetPosition() const;
207 
208     /*!
209      *  \brief return the age of the system, i.e. how many seconds it has been since
210      *         it was created
211      * \return age of the system
212      */
GetAge()213     float GetAge() const {
214         return _age;
215     }
216 
217     //! \brief Get the overall effect collision width/height in pixels.
GetEffectCollisionWidth()218     float GetEffectCollisionWidth() const {
219         return _effect_def.effect_collision_width;
220     }
GetEffectCollisionHeight()221     float GetEffectCollisionHeight() const {
222         return _effect_def.effect_collision_height;
223     }
224 
225     //! \brief Get the overall effect image width/height in pixels.
GetEffectWidth()226     float GetEffectWidth() const {
227         return _effect_def.effect_width;
228     }
GetEffectHeight()229     float GetEffectHeight() const {
230         return _effect_def.effect_height;
231     }
232 
233 
IsLoaded()234     bool IsLoaded() const {
235         return _loaded;
236     }
237 
238     //! \brief draws the effect.
239     void Draw();
240 
241     /*!
242      * \brief updates the effect.
243      * \param the new frame time
244      */
245     void Update(float frame_time);
246     void Update();
247 private:
248     /*!
249      * \brief destroys the effect. This is private so that only the ParticleManager class
250      *         can destroy effects.
251      */
252     void _Destroy();
253 
254     /*!
255      * \brief loads an effect definition from a particle file
256      * \param filename file to load the effect from
257      * \return Whether the effect def is valid
258      */
259     bool _LoadEffectDef(const std::string &filename);
260 
261     /** Creates the effect based on the particle effect definition.
262     *** _LoadEffectDef() must be called before this one.
263     **/
264     bool _CreateEffect();
265 
266     //! \brief Helper function used to read a color subtable.
267     vt_video::Color _ReadColor(vt_script::ReadScriptDescriptor &particle_script,
268                                 const std::string &param_name);
269 
270     //! The effect definition
271     ParticleEffectDef _effect_def;
272 
273     //! list of subsystems that make up the effect. (for example, a fire effect might consist
274     //! of a flame + smoke + embers)
275     std::vector<ParticleSystem> _systems;
276 
277     //! Tells whether the effect definition and systems arewere successfully loaded
278     bool _loaded;
279 
280     //! position of the effect
281     vt_common::Position2D _pos;
282 
283     //! position of attractor point
284     vt_common::Position2D _attractor;
285 
286     //! orientation of the effect (angle in radians)
287     float _orientation;
288 
289     //! is the effect is alive or not
290     bool  _alive;
291 
292     //! age of the effect (seconds since it was created)
293     float _age;
294 
295     //! number of active particles (this is updated on each call to Update())
296     int32_t _num_particles;
297 }; // class ParticleEffect
298 
299 }  // namespace vt_mode_manager
300 
301 #endif  //! __PARTICLE_EFFECT_HEADER__
302