1 /* $Id$ */
2
3 /******************************************************************************/
4
5 #ifndef _PARTICLES_HPP_
6 #define _PARTICLES_HPP_
7
8 /******************************************************************************/
9
10 #include <SDL.h>
11 #include "global.hpp"
12 #include "vector.hpp"
13 #include "flag.hpp"
14 #include "video.hpp"
15 #include "graphics.hpp"
16 #include "serializable.hpp"
17 #include "counter.hpp"
18
19 /******************************************************************************/
20
21 // predeclaration of World, to allow the particle class to
22 // own a pointer to the world, it lives in
23 class World;
24
25 /******************************************************************************/
26
27 /*! This class handles all kinds of particles, e.g. dirt, blood, and shots,
28 which are drawn as simple dots.
29 */
30
31 class Particles : public Serializable {
32 public:
33
34 enum { BOUNCE_EARTH = Flags::OBSTACLE_EARTH,
35 BOUNCE_OBJECT = Flags::OBSTACLE_OBJECT,
36 BOUNCE_PARTICLE = Flags::OBSTACLE_PARTICLE,
37 BOUNCE_OBSTACLE_ANY = BOUNCE_EARTH | BOUNCE_OBJECT | BOUNCE_PARTICLE,
38 EXPL_EARTH = (1 << 3) | BOUNCE_EARTH,
39 EXPL_OBJECT = (1 << 4) | BOUNCE_OBJECT,
40 EXPL_PARTICLE = (1 << 5) | BOUNCE_PARTICLE,
41 EXPL_OBSTACLE_ANY = EXPL_EARTH | EXPL_OBJECT | EXPL_PARTICLE,
42 EXPL_TTL = (1 << 6),
43 DAMAGE = (1 << 7),
44 STAIN = (1 << 8),
45 EXPL_GEN_SPARKS = (1 << 9),
46 INVISIBLE = (1 << 10),
47 REDUNDANT = (1 << 11),
48 SPARK = (1 << 12),
49 SPECIAL_BOUNCE = (1 << 13)};
50
51 struct ParticleData : public Serializable {
52 Vector pos, //!< position
53 vel; //!< velocity
54 Uint16 type; //!< type (e.g. dirt, blood, shot, spark)
55 Sint16 modifier; //!< modifies the behavior depending on particle type
56
57 Uint8 owner; //!< owner ID
58
59 bool decaying;
60 Counter ttl; //!< time to live
61 /*!< If \a ttl is larger than zero, it will be
62 decremented in each time step. When it reaches
63 zero, the particle is removed. If \a ttl is
64 initialized with a negative value, the time to
65 live is unlimited. */
66 Sint32 damage; //!< damage caused by particle
67 Uint32 color; //!< color
ParticleDataParticles::ParticleData68 ParticleData( const Vector& posInit = 0,
69 const Vector& velInit = 0,
70 const Uint16 typeInit = 0,
71 const Sint16 modifierInit = 0,
72 const Uint8 ownerInit = 0,
73 const real ttlInit = -1,
74 const Sint32 damageInit = 1,
75 const Uint32 colorInit = 0xffffff ):
76 pos( posInit ), vel( velInit ), type( typeInit ),
77 modifier( modifierInit ), owner( ownerInit ),
78 damage( damageInit ), color( colorInit ) {
79 if ( ttlInit < 0.0 ) {
80 decaying = false;
81 }
82 else {
83 decaying = true;
84 ttl.setTimeToLive( ttlInit );
85 }
86 }
getSerializeBufferSizeParticles::ParticleData87 Uint32 getSerializeBufferSize() const {
88 return 2 * Serialize<Vector>::sizeOf()
89 + Serialize<Uint16>::sizeOf()
90 + Serialize<Sint16>::sizeOf()
91 + Serialize<Uint8>::sizeOf()
92 + Serialize<bool>::sizeOf()
93 + ttl.getSerializeBufferSize()
94 + Serialize<Sint32>::sizeOf()
95 + Serialize<Uint32>::sizeOf();
96 }
serializeParticles::ParticleData97 void serialize( Uint8*& bufferPointer ) const {
98 Serialize<Vector>::serialize( pos, bufferPointer );
99 Serialize<Vector>::serialize( vel, bufferPointer );
100 Serialize<Uint16>::serialize( type, bufferPointer );
101 Serialize<Sint16>::serialize( modifier, bufferPointer );
102 Serialize<Uint8>::serialize( owner, bufferPointer );
103 Serialize<bool>::serialize( decaying, bufferPointer );
104 ttl.serialize( bufferPointer );
105 Serialize<Sint32>::serialize( damage, bufferPointer );
106 Serialize<Uint32>::serialize( color, bufferPointer );
107 }
deserializeParticles::ParticleData108 void deserialize( Uint8*& bufferPointer ) {
109 Serialize<Vector>::deserialize( bufferPointer, pos );
110 Serialize<Vector>::deserialize( bufferPointer, vel );
111 Serialize<Uint16>::deserialize( bufferPointer, type );
112 Serialize<Sint16>::deserialize( bufferPointer, modifier );
113 Serialize<Uint8>::deserialize( bufferPointer, owner );
114 Serialize<bool>::deserialize( bufferPointer, decaying );
115 ttl.deserialize( bufferPointer );
116 Serialize<Sint32>::deserialize( bufferPointer, damage );
117 Serialize<Uint32>::deserialize( bufferPointer, color );
118 }
119 };
120
121 Particles( World& world );
122
123 //! Adds a particle to the particle array. If #m_MAX_PARTICLES already
124 //! exist, the particle will not be created.
125 //! \return \arg \c true if the particle could be added.
126 //! \arg \c false if the particle could not be added, because
127 //! #m_MAX_PARTICLES is exceeded.
128 bool addParticle( const ParticleData& particleData );
129
130 //! Removes a particle from the particle array. \a index is decremented,
131 //! because it points to a different particle after deleting the old one.
132 void removeParticle( int* index );
133
134 //! Moves all particles according to velocity ParticleData::vel by using
135 //! an explicit Euler step and handles collisions.
136 void doTimestep();
137
138 //! Draws all particles with a simple dot.
139 void draw( SDL_Surface* surface, const SDL_Rect& rect ) const;
140
reset(void)141 void reset( void ) { m_nParticles = 0; }
142
143 virtual Uint32 getSerializeBufferSize() const;
144 virtual void serialize( Uint8*& bufferPointer ) const;
145 virtual void deserialize( Uint8*& bufferPointer );
146
147 static const int m_N_SPARK_COLORS = 52;
148
149 private:
150 static const int m_MAX_PARTICLES = 40000; //!< Maximum number of particles.
151 static const int m_MAX_REDUNDANT_PARTICLES = int( 0.9*m_MAX_PARTICLES );
152 Sint32 m_nParticles; //!< Current number of particles.
153 ParticleData m_particleData[m_MAX_PARTICLES]; //!< Array of particles.
154 World& m_world; //!< a reference to the world the particles live in
155
156 Uint32 m_sparkColor[m_N_SPARK_COLORS];
157 };
158
159 /******************************************************************************/
160
removeParticle(int * index)161 inline void Particles::removeParticle( int* index ) {
162 DBG( 3 ) {
163 ASSERT( *index < m_nParticles,
164 "Particles::remove: index larger than current number of particles\n" );
165 }
166
167 // If index particle is not the last particle in the list
168 if( *index < m_nParticles-1 ) {
169 // Yes, then copy data from last particle onto index particle
170 m_particleData[*index] = m_particleData[m_nParticles-1];
171 // Decrease index, since we have to work on the same index in the next
172 // loop iteration
173 (*index)--;
174 }
175 // No, then there's no need to copy anything, just decrease m_nParticles
176 m_nParticles--;
177 }
178
179 /******************************************************************************/
180
draw(SDL_Surface * surface,const SDL_Rect & rect) const181 inline void Particles::draw( SDL_Surface* surface, const SDL_Rect& rect ) const {
182 int x, y;
183
184 if ( SDL_MUSTLOCK( surface ) )
185 SDL_LockSurface( surface );
186
187 for( int p = 0; p < m_nParticles; p++) {
188 if( ! (m_particleData[p].type & INVISIBLE) ) {
189 x = ROUND( m_particleData[p].pos.x ) - rect.x;
190 y = ROUND( m_particleData[p].pos.y ) - rect.y;
191 Graphics::setPixelClip( surface, x, y, m_particleData[p].color );
192 }
193 }
194
195 if ( SDL_MUSTLOCK( surface ) )
196 SDL_UnlockSurface( surface );
197 }
198
199 /******************************************************************************/
200
201 #endif // _PARTICLES_HPP_
202