1 /** @file generator.h  World map (particle) generator.
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2006-2015 Daniel Swanson <danij@dengine.net>
5  *
6  * @par License
7  * GPL: http://www.gnu.org/licenses/gpl.html
8  *
9  * <small>This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version. This program is distributed in the hope that it
13  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details. You should have received a copy of the GNU
16  * General Public License along with this program; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA</small>
19  */
20 
21 #ifndef CLIENT_WORLD_GENERATOR_H
22 #define CLIENT_WORLD_GENERATOR_H
23 
24 #include <de/Vector>
25 #include <doomsday/defs/dedtypes.h>
26 #include "map.h"
27 
28 class Line;
29 class Plane;
30 struct mobj_s;
31 
32 namespace world {
33 
34 class BspLeaf;
35 
36 /**
37  * POD structure used when querying the current state of a particle.
38  */
39 struct ParticleInfo
40 {
41     de::dint stage;           ///< -1 => particle doesn't exist
42     de::dshort tics;
43     fixed_t origin[3];        ///< Coordinates.
44     fixed_t mov[3];           ///< Momentum.
45     world::BspLeaf *bspLeaf;  ///< Updated when needed.
46     Line *contact;            ///< Updated when lines hit/avoided.
47     de::dushort yaw, pitch;   ///< Rotation angles (0-65536 => 0-360).
48 };
49 
50 /**
51  * Particle generator.
52  */
53 struct Generator
54 {
55     /**
56      * Particle animation is defined as a sequence of (perhaps interpolated)
57      * property value stages.
58      */
59     struct ParticleStage
60     {
61         enum Flag
62         {
63             StageTouch     = 0x1,   ///< Touching ends current stage.
64             DieTouch       = 0x2,   ///< Dies from first touch.
65             Bright         = 0x4,   ///< Fullbright.
66             Shading        = 0x8,   ///< Pseudo-3D.
67             PlaneFlat      = 0x10,  ///< Touches a plane => render as flat.
68             StageWallTouch = 0x20,  ///< Touch a wall => end stage.
69             StageFlatTouch = 0x40,  ///< Touch a flat => end stage.
70             WallFlat       = 0x80,  ///< Touches a wall => render as flat.
71             SphereForce    = 0x100,
72             ZeroYaw        = 0x200, ///< Set particle yaw to zero.
73             ZeroPitch      = 0x400, ///< Set particle pitch to zero.
74             RandomYaw      = 0x800,
75             RandomPitch    = 0x1000
76         };
77         Q_DECLARE_FLAGS(Flags, Flag)
78 
79         de::dshort type;
80         Flags flags;
81         fixed_t resistance;
82         fixed_t bounce;
83         fixed_t radius;
84         fixed_t gravity;
85     };
86 
87     enum Flag
88     {
89         Static               = 0x1,     ///< Can't be replaced by anything.
90         RelativeVelocity     = 0x2,     ///< Particles inherit source's velocity.
91         SpawnOnly            = 0x4,     ///< Generator is spawned only when source is being spawned.
92         RelativeVector       = 0x8,     ///< Rotate spawn vector w/mobj angle.
93         BlendAdditive        = 0x10,    ///< Render using additive blending.
94         SpawnFloor           = 0x20,    ///< Flat-trig: spawn on floor.
95         SpawnCeiling         = 0x40,    ///< Flat-trig: spawn on ceiling.
96         SpawnSpace           = 0x80,    ///< Flat-trig: spawn in air.
97         Density              = 0x100,   ///< Definition specifies a density.
98         ModelOnly            = 0x200,   ///< Only spawn if source is a 3D model.
99         ScaledRate           = 0x400,   ///< Spawn rate affected by a factor.
100         Group                = 0x800,   ///< Triggered by all in anim group.
101         BlendSubtract        = 0x1000,  ///< Subtractive blending.
102         BlendReverseSubtract = 0x2000,  ///< Reverse subtractive blending.
103         BlendMultiply        = 0x4000,  ///< Multiplicative blending.
104         BlendInverseMultiply = 0x8000,  ///< Inverse multiplicative blending.
105         StateChain           = 0x10000  ///< Chain after existing state gen(s).
106     };
107     Q_DECLARE_FLAGS(Flags, Flag)
108 
109     /// Unique identifier associated with each generator (1-based).
110     typedef de::dshort Id;
111 
112 public: /// @todo make private:
113     thinker_t thinker;               ///< Func = P_PtcGenThinker
114     Plane *plane;                    ///< Flat-triggered.
115     ded_ptcgen_t const *def;         ///< The definition of this generator.
116     struct mobj_s *source;           ///< If mobj-triggered.
117     de::dint srcid;                  ///< Source mobj ID.
118     de::dint type;                   ///< Type-triggered; mobj type number (-1=none).
119     de::dint type2;                  ///< Type-triggered; alternate type.
120     fixed_t originAtSpawn[3];        ///< Used by untriggered/damage gens.
121     fixed_t vector[3];               ///< Converted from the definition.
122     de::dfloat spawnRateMultiplier;
123     de::dint count;                  ///< Number of particles generated thus far.
124     ParticleStage *stages;
125 
126 public:
127     /**
128      * Returns the map in which the generator exists.
129      *
130      * @see Thinker_Map()
131      */
132     world::Map &map() const;
133 
134     /**
135      * Returns the unique identifier of the generator. The identifier is 1-based.
136      */
137     Id id() const;
138 
139     /**
140      * Change the unique identifier of the generator. The identifier is 1-based.
141      *
142      * @param newId  New identifier to apply.
143      */
144     void setId(Id newId);
145 
146     /**
147      * Set gen->count prior to calling this function.
148      */
149     void configureFromDef(ded_ptcgen_t const *def);
150 
151     /**
152      * Generate and/or move the particles.
153      */
154     void runTick();
155 
156     /**
157      * Run the generator's thinker for the given number of @a tics.
158      */
159     void presimulate(de::dint tics);
160 
161     /**
162      * Returns the age of the generator (time since spawn), in tics.
163      */
164     de::dint age() const;
165 
166     /**
167      * Determine the @em approximate origin of the generator in map space.
168      *
169      * @note In the case of generator attached to a mobj this is the @em current,
170      * unsmoothed origin of the mobj offset by the @em initial origin at generator
171      * spawn time. For all other types of generator the initial origin at generator
172      * spawn time is returned.
173      */
174     de::Vector3d origin() const;
175 
176     /**
177      * Returns @c true iff the generator is @em static, meaning it will not be
178      * replaced under any circumstances.
179      */
180     bool isStatic() const;
181 
182     /**
183      * Returns @c true iff the generator is @em untriggered.
184      */
185     bool isUntriggered() const;
186 
187     /**
188      * Change the @em untriggered state of the generator.
189      */
190     void setUntriggered(bool yes = true);
191 
192     /**
193      * Returns the currently configured blending mode for the generator.
194      */
195     blendmode_t blendmode() const;
196 
197     /**
198      * Returns the total number of @em active particles for the generator.
199      */
200     de::dint activeParticleCount() const;
201 
202     /**
203      * Provides readonly access to the generator particle info data.
204      */
205     ParticleInfo const *particleInfo() const;
206 
207 public: /// @todo make private:
208     /**
209      * Clears all memory used for manipulating the generated particles.
210      */
211     void clearParticles();
212 
213     /**
214      * Attempt to spawn a new particle.
215      *
216      * @return  Index of the newly spawned particle; otherwise @c -1.
217      */
218     de::dint newParticle();
219 
220     /**
221      * The movement is done in two steps:
222      * Z movement is done first. Skyflat kills the particle.
223      * XY movement checks for hits with solid walls (no backsector).
224      * This is supposed to be fast and simple (but not too simple).
225      */
226     void moveParticle(de::dint index);
227 
228     void spinParticle(ParticleInfo &pt);
229 
230     de::dfloat particleZ(ParticleInfo const &pt) const;
231 
232     de::Vector3f particleOrigin(ParticleInfo const &pt) const;
233     de::Vector3f particleMomentum(ParticleInfo const &pt) const;
234 
235 public:
236     /**
237      * Register the console commands, variables, etc..., of this module.
238      */
239     static void consoleRegister();
240 
241 private:
242     Id _id;                  ///< Unique in the map.
243     Flags _flags;
244     de::dint _age;           ///< Time since spawn, in tics.
245     de::dfloat _spawnCount;
246     bool _untriggered;       ///< @c true= consider this as not yet triggered.
247     de::dint _spawnCP;       ///< Particle spawn cursor.
248     ParticleInfo *_pinfo;    ///< Info about each generated particle.
249 };
250 
251 Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Flags)
252 Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::ParticleStage::Flags)
253 
254 typedef Generator::ParticleStage GeneratorParticleStage;
255 
256 void Generator_Delete(Generator *gen);
257 void Generator_Thinker(Generator *gen);
258 
259 }  // namespace world
260 
261 #endif  // CLIENT_WORLD_GENERATOR_H
262