1 //
2 // Emitter.cpp - Implementation of particle emitter classes.
3 // Copyright (C) 2006 Nick Gasson
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19
20 #include "Emitter.hpp"
21 #include "OpenGL.hpp"
22
23 #include <cmath>
24 #include <string>
25
26 //
27 // Creates a new particle emitter.
28 // x, y -> Starting position.
29 // r, g, b -> Base colour components.
30 // createnew -> New particles will be created on initialisation.
31 // deviation -> Randomness in particle colours.
32 // xg, yg -> X and Y components of acceleration.
33 // life -> Average life of each particle.
34 // max_speed -> Maximum speed of all particles.
35 // size -> Size of particles.
36 // slowdown -> Rate of speed decrease.
37 //
Emitter(int x,int y,float r,float g,float b,bool createnew,float deviation,float xg,float yg,float life,float max_speed,float size,float slowdown)38 Emitter::Emitter(int x, int y, float r, float g, float b, bool createnew,
39 float deviation, float xg, float yg, float life,
40 float max_speed, float size, float slowdown)
41 : partsize(size), r(r), g(g), b(b), deviation(deviation), xg(xg), yg(yg),
42 life(life), maxspeed(max_speed), xpos((float)x), ypos((float)y),
43 slowdown(slowdown), createrate(128.0f), xi_bias(0.0f), yi_bias(0.0f),
44 texture_(LoadTexture("images/particle.png"))
45 {
46 // Set up the particles
47 for (int i = 0; i < MAX_PARTICLES; i++) {
48 if (createnew)
49 NewParticle(i);
50 else {
51 particle[i].active = false;
52 particle[i].life = -1.0f;
53 }
54 }
55 }
56
57
58 //
59 // Resets the emitter.
60 //
Reset()61 void Emitter::Reset()
62 {
63 for (int i = 0; i < MAX_PARTICLES; i++) {
64 particle[i].active = false;
65 particle[i].life = -1.0f;
66 }
67 }
68
69
70 //
71 // Creates a new cluster of particles at (x, y).
72 //
NewCluster(int x,int y)73 void Emitter::NewCluster(int x, int y)
74 {
75 int i, created=0;
76 float oldx, oldy;
77
78 oldx = xpos;
79 oldy = ypos;
80 xpos = (float)x;
81 ypos = (float)y;
82
83 for (i = 0; i < MAX_PARTICLES; i++) {
84 if ((particle[i].life < 0.0f || !particle[i].active)
85 && created < MAX_PARTICLES/createrate) {
86 NewParticle(i);
87 created++;
88 }
89 }
90
91 xpos = oldx;
92 ypos = oldy;
93 }
94
95
96 //
97 // Draws all the particles created by this emitter.
98 //
Draw(float adjust_x,float adjust_y) const99 void Emitter::Draw(float adjust_x, float adjust_y) const
100 {
101 glEnable(GL_TEXTURE_2D);
102 glEnable(GL_BLEND);
103 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
104 glLoadIdentity();
105
106 glBindTexture(GL_TEXTURE_2D, texture_->GetGLTexture());
107
108 for (int i = 0; i < MAX_PARTICLES; i++) {
109 if (particle[i].active) {
110 float x = particle[i].x - adjust_x;
111 float y = particle[i].y - adjust_y;
112
113 glColor4f(particle[i].r, particle[i].g, particle[i].b, particle[i].life);
114 glBegin(GL_TRIANGLE_STRIP);
115 glTexCoord2d(1, 1); glVertex3f(x+partsize, y+partsize, 0);
116 glTexCoord2d(0, 1); glVertex3f(x-partsize, y+partsize, 0);
117 glTexCoord2d(1, 0); glVertex3f(x+partsize, y-partsize, 0);
118 glTexCoord2d(0, 0); glVertex3f(x-partsize, y-partsize, 0);
119 glEnd();
120
121
122 }
123 }
124
125 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
126 }
127
Process(bool createnew,bool evolve)128 void Emitter::Process(bool createnew, bool evolve)
129 {
130 int created = 0;
131 for (int i = 0; i < MAX_PARTICLES; i++) {
132 if (particle[i].active) {
133 if (evolve) {
134 // Move particle
135 particle[i].x += particle[i].xi/(slowdown*1000);
136 particle[i].y += particle[i].yi/(slowdown*1000);
137
138 // Apply gravity
139 particle[i].xi+=particle[i].xg;
140 particle[i].yi+=particle[i].yg;
141
142 // Fade particle
143 particle[i].life -= particle[i].fade;
144
145 // Apply special effect
146 ProcessEffect(i);
147
148 // See if particle died
149 if (particle[i].life < 0.0f
150 && createnew
151 && created < MAX_PARTICLES/createrate) {
152 NewParticle(i);
153 created++;
154 }
155 else if (particle[i].life < 0.0f)
156 particle[i].active = false;
157 }
158 }
159 else if (createnew && created < MAX_PARTICLES/createrate) {
160 NewParticle(i);
161 created++;
162 }
163 }
164 }
165
166 //
167 // Creates one new particle at the specified index.
168 //
NewParticle(int index)169 void Emitter::NewParticle(int index)
170 {
171 float d[3];
172 int i;
173
174 for (i = 0; i < 3; i++) {
175 d[i] = (float)(rand()%100) - 50.0f;
176 d[i] /= 100.0f;
177 d[i] *= deviation;
178 }
179
180 particle[index].active = true;
181 particle[index].life = life;
182 particle[index].fade = (float)(rand()%100)/1000.0f+0.003f;
183 particle[index].r = r + d[0] >= 1.0f ? 1.0f : r + d[0];
184 particle[index].g = g + d[1] >= 1.0f ? 1.0f : g + d[1];
185 particle[index].b = b + d[2] >= 1.0f ? 1.0f : b + d[2];
186 particle[index].x = xpos;
187 particle[index].y = ypos;
188 particle[index].xg = xg;
189 particle[index].yg = yg;
190
191 do {
192 particle[index].xi = (float)((rand()%50)-26.0f)*maxspeed;
193 particle[index].yi = (float)((rand()%50)-25.0f)*maxspeed;
194 } while (pow(particle[index].yi, 2) + pow(particle[index].xi, 2) > pow(25.0f*maxspeed, 2));
195
196 particle[index].xi += xi_bias;
197 particle[index].yi += yi_bias;
198 }
199
200
201 //
202 // Smoke trail constructor. Sets special Emitter constants.
203 //
SmokeTrail(float r,float g,float b,float dr,float dg,float db)204 SmokeTrail::SmokeTrail(float r, float g, float b,
205 float dr, float dg, float db)
206 : Emitter(0, 0, r, g, b,
207 false, 0.2f,
208 0.0f, 0.0f,
209 0.3f, 0.0f, 4.0f, 0.001f),
210 dr(dr), dg(dg), db(db)
211 {
212 createrate = 64.0f;
213 }
214
BlueSmokeTrail()215 BlueSmokeTrail::BlueSmokeTrail()
216 : SmokeTrail(0.6f, 0.6f, 0.9f, 0.03f, 0.03f, 0.02f)
217 {
218
219 }
220
OrangeSmokeTrail()221 OrangeSmokeTrail::OrangeSmokeTrail()
222 : SmokeTrail(0.9f, 0.6f, 0.6f, 0.02f, 0.03f, 0.03f)
223 {
224
225 }
226
227 //
228 // Processes the smoke trail effect for particle p.
229 //
ProcessEffect(int p)230 void SmokeTrail::ProcessEffect(int p)
231 {
232 if (particle[p].g > 0.5f)
233 particle[p].g -= 0.025f;
234 else
235 {
236 if (particle[p].r > 0.1f)
237 particle[p].r -= dr;
238 if (particle[p].b > 0.1f)
239 particle[p].b -= db;
240 if (particle[p].g > 0.1f)
241 particle[p].g -= dg;
242 }
243 }
244
245
246 //
247 // Explosion constructor. Sets Emitter constants to create a pretty explosion.
248 //
Explosion()249 Explosion::Explosion()
250 : Emitter(0, 0, 0.7f, 0.7f, 0.0f, false, 0.3f, 0.0f, 0.0f, 1.0f, 120.0f, 8.5f, 2.0f)
251 {
252 // Make a BIG explosion
253 createrate = 20.0f;
254 }
255
256
257 //
258 // Processes the explosion effect for particle p.
259 //
ProcessEffect(int p)260 void Explosion::ProcessEffect(int p)
261 {
262 if (particle[p].g > 0.5f)
263 particle[p].g -= 0.025f;
264 else {
265 if (particle[p].r > 0.1f)
266 particle[p].r -= 0.025f;
267 if (particle[p].b < 0.1f)
268 particle[p].b += 0.025f;
269 if (particle[p].g > 0.1f)
270 particle[p].g -= 0.025f;
271 }
272 }
273