1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 /**
21  * \file graphics/engine/particle.h
22  * \brief Particle rendering - CParticle class (aka particle)
23  */
24 
25 #pragma once
26 
27 
28 #include "graphics/engine/engine.h"
29 
30 #include "object/interface/trace_drawing_object.h"
31 
32 #include "sound/sound_type.h"
33 
34 
35 class CRobotMain;
36 class CObject;
37 class CSoundInterface;
38 
39 
40 // Graphics module namespace
41 namespace Gfx
42 {
43 
44 const short MAXPARTICULE = 500;
45 const short MAXPARTITYPE = 6;
46 const short MAXTRACK = 100;
47 const short MAXTRACKLEN = 10;
48 const short MAXPARTIFOG = 100;
49 const short MAXWHEELTRACE = 1000;
50 
51 const short SH_WORLD = 0;       // particle in the world in the interface
52 const short SH_FRONT = 1;       // particle in the world on the interface
53 const short SH_INTERFACE = 2;   // particle in the interface
54 const short SH_MAX = 3;
55 
56 // type == 0    ->  triangles
57 // type == 1    ->  effect00 (black background)
58 // type == 2    ->  effect01 (black background)
59 // type == 3    ->  effect02 (black background)
60 // type == 4    ->  text     (white background)
61 
62 
63 enum ParticleType
64 {
65     PARTIEXPLOT     = 1,        //! < technology explosion
66     PARTIEXPLOO     = 2,        //! < organic explosion
67     PARTIMOTOR      = 3,        //! < the engine exhaust gas
68     PARTIGLINT      = 4,        //! < reflection
69     PARTIBLITZ      = 5,        //! < lightning recharging battery
70     PARTICRASH      = 6,        //! < dust after fall
71     PARTIGAS        = 7,        //! < gas from the reactor
72     PARTIFIRE       = 9,        //! < fireball shrinks
73     PARTIFIREZ      = 10,       //! < fireball grows
74     PARTIBLUE       = 11,       //! < blue ball
75     PARTISELY       = 12,       //! < yellow robot lights
76     PARTISELR       = 13,       //! < red robot lights
77     PARTIGUN1       = 18,       //! < bullet 1 (fireball)
78     PARTIGUN2       = 19,       //! < bullet 2 (ant)
79     PARTIGUN3       = 20,       //! < bullet 3 (spider)
80     PARTIGUN4       = 21,       //! < bullet 4 (orgaball)
81     PARTIFRAG       = 22,       //! < triangular fragment
82     PARTIQUEUE      = 23,       //! < inflamed tail (TODO: unused?)
83     PARTIORGANIC1   = 24,       //! < organic ball mother
84     PARTIORGANIC2   = 25,       //! < organic ball daughter
85     PARTISMOKE1     = 26,       //! < black smoke
86     PARTISMOKE2     = 27,       //! < black smoke
87     PARTISMOKE3     = 28,       //! < black smoke
88     PARTIBLOOD      = 30,       //! < human blood
89     PARTIBLOODM     = 31,       //! < AlienQueen blood
90     PARTIVAPOR      = 32,       //! < steam
91     PARTIVIRUS      = 33,       //! < virus (random letter)
92     PARTIRAY1       = 43,       //! < ray 1 (turn)
93     PARTIRAY2       = 44,       //! < ray 2 (electric arc)
94     PARTIRAY3       = 45,       //! < ray 3 (ExchangePost)
95     PARTIFLAME      = 47,       //! < flame
96     PARTIBUBBLE     = 48,       //! < bubble
97     PARTIFLIC       = 49,       //! < circles in the water
98     PARTIEJECT      = 50,       //! < ejection from the reactor
99     PARTISCRAPS     = 51,       //! < waste from the reactor
100     PARTITOTO       = 52,       //! < Robby's reactor
101     PARTIERROR      = 53,       //! < Robby says no
102     PARTIWARNING    = 54,       //! < Robby says blah
103     PARTIINFO       = 54,       //! < Robby says yes
104     PARTIQUARTZ     = 55,       //! < reflection crystal
105     PARTISPHERE0    = 56,       //! < explosion sphere
106     PARTISPHERE1    = 57,       //! < energy sphere
107     PARTISPHERE2    = 58,       //! < analysis sphere
108     PARTISPHERE3    = 59,       //! < shield sphere
109     PARTISPHERE4    = 60,       //! < information sphere (emit)
110     PARTISPHERE5    = 61,       //! < botanical sphere (gravity root)
111     PARTISPHERE6    = 62,       //! < information sphere (receive)
112     PARTIGUNDEL     = 66,       //! < bullet destroyed by shield
113     PARTIPART       = 67,       //! < object part
114     PARTITRACK1     = 68,       //! < drag 1
115     PARTITRACK2     = 69,       //! < drag 2
116     PARTITRACK3     = 70,       //! < drag 3
117     PARTITRACK4     = 71,       //! < drag 4
118     PARTITRACK5     = 72,       //! < drag 5
119     PARTITRACK6     = 73,       //! < drag 6
120     PARTITRACK7     = 74,       //! < drag 7
121     PARTITRACK8     = 75,       //! < drag 8
122     PARTITRACK9     = 76,       //! < drag 9
123     PARTITRACK10    = 77,       //! < drag 10
124     PARTITRACK11    = 78,       //! < drag 11
125     PARTITRACK12    = 79,       //! < drag 12 (TODO: unused?)
126     PARTIGLINTb     = 88,       //! < blue reflection
127     PARTIGLINTr     = 89,       //! < red reflection
128     PARTILENS1      = 90,       //! < brilliance 1 (orange)
129     PARTILENS2      = 91,       //! < brilliance 2 (yellow)
130     PARTILENS3      = 92,       //! < brilliance 3 (red)
131     PARTILENS4      = 93,       //! < brilliance 4 (violet)
132     PARTICONTROL    = 94,       //! < reflection on button
133     PARTISHOW       = 95,       //! < shows a place
134     PARTICHOC       = 96,       //! < shock wave
135     PARTIGFLAT      = 97,       //! < shows if the ground is flat
136     PARTIRECOVER    = 98,       //! < blue ball recycler
137     PARTIROOT       = 100,      //! < gravity root smoke
138     PARTIPLOUF0     = 101,      //! < splash
139     PARTIDROP       = 106,      //! < drop
140     PARTIFOG0       = 107,      //! < fog 0
141     PARTIFOG1       = 108,      //! < fog 1
142     PARTIFOG2       = 109,      //! < fog 2
143     PARTIFOG3       = 110,      //! < fog 3
144     PARTIFOG4       = 111,      //! < fog 4
145     PARTIFOG5       = 112,      //! < fog 5
146     PARTIFOG6       = 113,      //! < fog 6
147     PARTIFOG7       = 114,      //! < fog 7
148     PARTILIMIT1     = 117,      //! < shows the limits 1
149     PARTILIMIT2     = 118,      //! < shows the limits 2
150     PARTILIMIT3     = 119,      //! < shows the limits 3
151     PARTIWATER      = 121,      //! < drop of water
152     PARTIEXPLOG1    = 122,      //! < ball explosion 1
153     PARTIEXPLOG2    = 123,      //! < ball explosion 2
154     PARTIBASE       = 124,      //! < gases of spaceship
155 };
156 
157 enum ParticlePhase
158 {
159     PARPHSTART      = 0,
160     PARPHEND        = 1,
161 };
162 
163 struct Particle
164 {
165     bool            used = false;      // TRUE -> particle used
166     bool            ray = false;       // TRUE -> ray with goal
167     unsigned short  uniqueStamp = 0;    // unique mark
168     short           sheet = 0;      // sheet (0..n)
169     ParticleType    type = {};       // type PARTI*
170     ParticlePhase   phase = {};      // phase PARPH*
171     float           mass = 0.0f;       // mass of the particle (in rebounding)
172     float           weight = 0.0f;     // weight of the particle (for noise)
173     float           duration = 0.0f;   // length of life
174     Math::Vector    pos;        // absolute position (relative if object links)
175     Math::Vector    goal;       // goal position (if ray)
176     Math::Vector    speed;      // speed of displacement
177     float           windSensitivity = 0.0f;
178     short           bounce = 0;     // number of rebounds
179     Math::Point     dim;        // dimensions of the rectangle
180     float           zoom = 0.0f;       // zoom (0..1)
181     float           angle = 0.0f;      // angle of rotation
182     float           intensity = 0.0f;  // intensity
183     Math::Point     texSup;     // coordinated upper texture
184     Math::Point     texInf;     // coordinated lower texture
185     float           time = 0.0f;       // age of the particle (0..n)
186     float           phaseTime = 0.0f;  // age at the beginning of phase
187     float           testTime = 0.0f;   // time since last test
188     CObject*        objLink = nullptr;    // father object (for example reactor)
189     CObject*        objFather = nullptr;  // father object (for example reactor)
190     short           objRank = 0;    // rank of the object, or -1
191     short           trackRank = 0;  // rank of the drag
192     char            text = 0;
193     Color           color = Color(1.0f, 1.0f, 1.0f, 1.0f);
194 };
195 
196 struct Track
197 {
198     char            used = 0;      // TRUE -> drag used
199     char            drawParticle = 0;
200     float           step = 0.0f;       // duration of not
201     float           last = 0.0f;       // increase last not memorized
202     float           intensity = 0.0f;  // intensity at starting (0..1)
203     float           width = 0.0f;      // tail width
204     int             posUsed = 0.0f;    // number of positions in "pos"
205     int             head = 0;       // head to write index
206     Math::Vector    pos[MAXTRACKLEN];
207     float           len[MAXTRACKLEN] = {};
208 };
209 
210 struct WheelTrace
211 {
212     TraceColor      color = TraceColor::Black;
213     Math::Vector    pos[4];
214 };
215 
216 
217 /**
218  * \class CParticle
219  * \brief Particle engine
220  *
221  * TODO: documentation
222  */
223 class CParticle
224 {
225 public:
226     CParticle(CEngine* engine);
227     ~CParticle();
228 
229     //! Sets the device to use
230     void        SetDevice(CDevice* device);
231 
232     //! Removes all particles
233     void        FlushParticle();
234 
235     //! Removes all particles of a sheet
236     void        FlushParticle(int sheet);
237 
238     //! Creates a new particle
239     int         CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim,
240                                ParticleType type, float duration = 1.0f, float mass = 0.0f,
241                                float windSensitivity = 1.0f, int sheet = 0);
242 
243     //! Creates a new triangular particle (debris)
244     int         CreateFrag(Math::Vector pos, Math::Vector speed, EngineTriangle* triangle,
245                            ParticleType type, float duration = 1.0f, float mass = 0.0f,
246                            float windSensitivity = 1.0f, int sheet = 0);
247 
248     //! Creates a new particle being a part of object
249     int         CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type,
250                            float duration = 1.0f, float mass = 0.0f, float weight = 0.0f,
251                            float windSensitivity = 1.0f, int sheet = 0);
252 
253     //! Creates a new linear particle (radius)
254     int         CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim,
255                           float duration = 1.0f, int sheet = 0);
256 
257     //! Creates a particle with a trail
258     int         CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type,
259                             float duration = 1.0f, float mass = 0.0f, float length = 10.0f, float width = 1.0f);
260 
261     //! Creates a tire mark
262     void        CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3,
263                                  const Math::Vector &p4, TraceColor color);
264 
265     //! Removes all particles of a given type
266     void        DeleteParticle(ParticleType type);
267     //! Removes all particles of a given channel
268     void        DeleteParticle(int channel);
269     //! Specifies the object to which the particle is bound
270     void        SetObjectLink(int channel, CObject *object);
271     //! Specifies the parent object that created the particle
272     void        SetObjectFather(int channel, CObject *object);
273     void        SetPosition(int channel, Math::Vector pos);
274     void        SetDimension(int channel, Math::Point dim);
275     void        SetZoom(int channel, float zoom);
276     void        SetAngle(int channel, float angle);
277     void        SetIntensity(int channel, float intensity);
278     void        SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity);
279     void        SetPhase(int channel, ParticlePhase phase, float duration);
280 
281     //! Returns the position of the particle
282     bool        GetPosition(int channel, Math::Vector &pos);
283 
284     //! Returns the color if you're in the fog or black if you're not
285     Color       GetFogColor(Math::Vector pos);
286 
287     //! Indicates whether a sheet is updated or not
288     void        SetFrameUpdate(int sheet, bool update);
289     //! Updates all the particles.
290     void        FrameParticle(float rTime);
291     //! Draws all the particles
292     void        DrawParticle(int sheet);
293 
294     //! Indicates that the object binds to the particle no longer exists, without deleting it
295     void        CutObjectLink(CObject* obj);
296 
297 protected:
298     //! Removes a particle of given rank
299     void        DeleteRank(int rank);
300     /**
301      * \brief Adapts the channel so it can be used as an offset in m_particle
302      * \param channel Channel number to process, will be modified to be index of particle in m_particle
303      * \return true if success, false if particle doesn't exist anymore
304      **/
305     bool        CheckChannel(int &channel);
306     //! Draws a triangular particle
307     void        DrawParticleTriangle(int i);
308     //! Draw a normal particle
309     void        DrawParticleNorm(int i);
310     //! Draw a particle flat (horizontal)
311     void        DrawParticleFlat(int i);
312     //! Draw a particle to a flat sheet of fog
313     void        DrawParticleFog(int i);
314     //! Draw a particle in the form of radius
315     void        DrawParticleRay(int i);
316     //! Draws a spherical particle
317     void        DrawParticleSphere(int i);
318     //! Draws a cylindrical particle
319     void        DrawParticleCylinder(int i);
320     //! Draws a text particle
321     void        DrawParticleText(int i);
322     //! Draws a tire mark
323     void        DrawParticleWheel(int i);
324     //! Seeks if an object collided with a bullet
325     CObject*    SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father);
326     //! Seeks if an object collided with a ray
327     CObject*    SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father);
328     //! Sounded one
329     void        Play(SoundType sound, Math::Vector pos, float amplitude);
330     //! Moves a drag; returns true if the drag is finished
331     bool        TrackMove(int i, Math::Vector pos, float progress);
332     //! Draws a drag
333     void        TrackDraw(int i, ParticleType type);
334 
335 protected:
336     CEngine*     m_engine = nullptr;
337     CDevice*     m_device = nullptr;
338     CTerrain*    m_terrain = nullptr;
339     CWater*      m_water = nullptr;
340     CRobotMain*       m_main = nullptr;
341     CSoundInterface*  m_sound = nullptr;
342 
343     Particle       m_particle[MAXPARTICULE*MAXPARTITYPE];
344     EngineTriangle m_triangle[MAXPARTICULE];  // triangle if PartiType == 0
345     Track          m_track[MAXTRACK];
346     int           m_wheelTraceTotal = 0;
347     int           m_wheelTraceIndex = 0;
348     WheelTrace    m_wheelTrace[MAXWHEELTRACE];
349     int           m_totalInterface[MAXPARTITYPE][SH_MAX] = {};
350     bool          m_frameUpdate[SH_MAX] = {};
351     int           m_fogTotal = 0;
352     int           m_fog[MAXPARTIFOG] = {};
353     int           m_uniqueStamp = 0;
354     int           m_exploGunCounter = 0;
355     float         m_lastTimeGunDel = 0.0f;
356     float         m_absTime = 0.0f;
357 };
358 
359 
360 } // namespace Gfx
361