rev |
line source |
nuclear@0
|
1 #include "particles.h"
|
nuclear@0
|
2 #include "3deng.h"
|
nuclear@0
|
3 #include <cassert>
|
nuclear@0
|
4
|
nuclear@0
|
5 //////////////////////////////////////////////////////
|
nuclear@0
|
6 // --==( Particle class implementation )==-- //
|
nuclear@0
|
7 //////////////////////////////////////////////////////
|
nuclear@0
|
8 using namespace std;
|
nuclear@0
|
9
|
nuclear@0
|
10 Particle::Particle(int life) {
|
nuclear@0
|
11 pos = Vector3(0, 0, 0);
|
nuclear@0
|
12 vel = Vector3(0, 0, 0);
|
nuclear@0
|
13 this->life = life;
|
nuclear@0
|
14 }
|
nuclear@0
|
15
|
nuclear@0
|
16 Particle::Particle(const Vector3 &pos, int life) {
|
nuclear@0
|
17 this->pos = pos;
|
nuclear@0
|
18 vel = Vector3(0, 0, 0);
|
nuclear@0
|
19 this->life = life;
|
nuclear@0
|
20 }
|
nuclear@0
|
21
|
nuclear@0
|
22 Particle::Particle(const Vector3 &pos, const Vector3 &vel, int life) {
|
nuclear@0
|
23 this->pos = pos;
|
nuclear@0
|
24 this->vel = vel;
|
nuclear@0
|
25 this->life = life;
|
nuclear@0
|
26 }
|
nuclear@0
|
27
|
nuclear@0
|
28 void Particle::Update(const Vector3 &forces, float friction) {
|
nuclear@0
|
29 if(!life) return;
|
nuclear@0
|
30 vel *= 1.0f - friction;
|
nuclear@0
|
31 pos += vel + forces;
|
nuclear@0
|
32 life--;
|
nuclear@0
|
33 }
|
nuclear@0
|
34
|
nuclear@0
|
35 ///////////////////////////////////////////////////////
|
nuclear@0
|
36 // --==( Particle System implementation )==-- //
|
nuclear@0
|
37 ///////////////////////////////////////////////////////
|
nuclear@0
|
38
|
nuclear@0
|
39 ParticleSystem::ParticleSystem(GraphicsContext *gc) {
|
nuclear@0
|
40 this->gc = gc;
|
nuclear@0
|
41 pos = prevpos = Vector3(0, 0, 0);
|
nuclear@0
|
42 size = 1.0f;
|
nuclear@0
|
43 friction = 0.0f;
|
nuclear@0
|
44 SpawnRate = 5;
|
nuclear@0
|
45 life = 100;
|
nuclear@0
|
46 EmmiterAffectsParticleTrajectory = false;
|
nuclear@0
|
47 varray = 0;
|
nuclear@0
|
48 tarray = 0;
|
nuclear@0
|
49 texture = 0;
|
nuclear@0
|
50 obj = 0;
|
nuclear@0
|
51
|
nuclear@0
|
52 SetShootDirection(Vector3(0, 0, 0));
|
nuclear@0
|
53 SetMaxDispersionAngle(0.01f);
|
nuclear@0
|
54 SetInitialColor(1, 1, 1);
|
nuclear@0
|
55 SetDeathColor(0, 0, 0);
|
nuclear@0
|
56
|
nuclear@0
|
57 // initialize the shape of the particles
|
nuclear@0
|
58 pquad[0] = Vertex(Vector3(-0.5f, 0.5f, 0), 0, 0, 0xffffffff);
|
nuclear@0
|
59 pquad[1] = Vertex(Vector3(0.5f, 0.5f, 1), 1, 0, 0xffffffff);
|
nuclear@0
|
60 pquad[2] = Vertex(Vector3(0.5f, -0.5f, 1), 1, 1, 0xffffffff);
|
nuclear@0
|
61 pquad[3] = Vertex(Vector3(-0.5f, -0.5f, 0), 0, 1, 0xffffffff);
|
nuclear@0
|
62
|
nuclear@0
|
63 ptris[0] = Triangle(0, 1, 2);
|
nuclear@0
|
64 ptris[1] = Triangle(0, 2, 3);
|
nuclear@0
|
65
|
nuclear@0
|
66 for(int i=0; i<4; i++) {
|
nuclear@0
|
67 pquad[i].normal = Vector3(0, 0, -1);
|
nuclear@0
|
68 }
|
nuclear@0
|
69
|
nuclear@0
|
70 SetBlendingMode(BLEND_ONE, BLEND_ONE);
|
nuclear@0
|
71 SpawnDiffDispersion = 0.0f;
|
nuclear@0
|
72
|
nuclear@0
|
73 FixedUpdateRate = true;
|
nuclear@0
|
74 UpdateRate = 30.0f;
|
nuclear@0
|
75 LastUpdate = -(1.0f / UpdateRate);
|
nuclear@0
|
76
|
nuclear@0
|
77 SpawnRateChange = 0;
|
nuclear@0
|
78 }
|
nuclear@0
|
79
|
nuclear@0
|
80 ParticleSystem::~ParticleSystem() {
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 void ParticleSystem::SetGraphicsContext(GraphicsContext *gc) {
|
nuclear@0
|
84 this->gc = gc;
|
nuclear@0
|
85 }
|
nuclear@0
|
86
|
nuclear@0
|
87 void ParticleSystem::SetParticleSize(float psize) {
|
nuclear@0
|
88 size = psize;
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 void ParticleSystem::SetParticleLife(int life) {
|
nuclear@0
|
92 this->life = life;
|
nuclear@0
|
93 }
|
nuclear@0
|
94
|
nuclear@0
|
95 void ParticleSystem::SetFriction(float friction) {
|
nuclear@0
|
96 this->friction = friction;
|
nuclear@0
|
97 }
|
nuclear@0
|
98
|
nuclear@0
|
99 void ParticleSystem::SetSpawnRate(float spawnrate) {
|
nuclear@0
|
100 SpawnRate = (int)spawnrate;
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103 void ParticleSystem::SetSpawnRadius(float radius) {
|
nuclear@0
|
104 SpawnRadius = radius;
|
nuclear@0
|
105 }
|
nuclear@0
|
106
|
nuclear@0
|
107 void ParticleSystem::SetTexture(Texture *texture) {
|
nuclear@0
|
108 this->texture = texture;
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 void ParticleSystem::SetObject(Object *obj) {
|
nuclear@0
|
112 this->obj = obj;
|
nuclear@0
|
113 }
|
nuclear@0
|
114
|
nuclear@0
|
115 void ParticleSystem::SetPosition(const Vector3 &pos) {
|
nuclear@0
|
116 this->pos = pos;
|
nuclear@0
|
117 }
|
nuclear@0
|
118
|
nuclear@0
|
119 void ParticleSystem::SetShootDirection(const Vector3 &dir) {
|
nuclear@0
|
120 ShootDirection = dir;
|
nuclear@0
|
121 }
|
nuclear@0
|
122
|
nuclear@0
|
123 void ParticleSystem::SetGravitualForce(float grav) {
|
nuclear@0
|
124 GravForce = grav;
|
nuclear@0
|
125 }
|
nuclear@0
|
126
|
nuclear@0
|
127 void ParticleSystem::SetEmmiterDependence(bool dep) {
|
nuclear@0
|
128 EmmiterAffectsParticleTrajectory = dep;
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 void ParticleSystem::SetMaxDispersionAngle(float maxdisp) {
|
nuclear@0
|
132 DispRads = maxdisp;
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 void ParticleSystem::SetInitialColor(float r, float g, float b) {
|
nuclear@0
|
136 StartRed = r;
|
nuclear@0
|
137 StartGreen = g;
|
nuclear@0
|
138 StartBlue = b;
|
nuclear@0
|
139 }
|
nuclear@0
|
140
|
nuclear@0
|
141 void ParticleSystem::SetDeathColor(float r, float g, float b) {
|
nuclear@0
|
142 EndRed = r;
|
nuclear@0
|
143 EndGreen = g;
|
nuclear@0
|
144 EndBlue = b;
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@0
|
147 void ParticleSystem::SetBlendingMode(BlendingFactor src, BlendingFactor dest) {
|
nuclear@0
|
148 SourceBlend = src;
|
nuclear@0
|
149 DestBlend = dest;
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 void ParticleSystem::SetSpawningDifferenceDispersion(float val) {
|
nuclear@0
|
153 SpawnDiffDispersion = val;
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 void ParticleSystem::SetSpawnRateChange(int change) {
|
nuclear@0
|
157 SpawnRateChange = change;
|
nuclear@0
|
158 }
|
nuclear@0
|
159
|
nuclear@0
|
160 // transformation stuff
|
nuclear@0
|
161 void ParticleSystem::Translate(float x, float y, float z) {
|
nuclear@0
|
162 Translation.Translate(x, y, z);
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 void ParticleSystem::Rotate(float x, float y, float z) {
|
nuclear@0
|
166 OrbitRot.Rotate(x, y, z);
|
nuclear@0
|
167 }
|
nuclear@0
|
168
|
nuclear@0
|
169 void ParticleSystem::Rotate(const Vector3 &axis, float angle) {
|
nuclear@0
|
170 OrbitRot.Rotate(axis, angle);
|
nuclear@0
|
171 }
|
nuclear@0
|
172
|
nuclear@0
|
173 void ParticleSystem::ResetRotation() {
|
nuclear@0
|
174 OrbitRot.ResetIdentity();
|
nuclear@0
|
175 }
|
nuclear@0
|
176
|
nuclear@0
|
177 void ParticleSystem::ResetTranslation() {
|
nuclear@0
|
178 Translation.ResetIdentity();
|
nuclear@0
|
179 }
|
nuclear@0
|
180
|
nuclear@0
|
181 int ParticleSystem::CountParticles() {
|
nuclear@0
|
182 ParticleCount = (int)particles.size();
|
nuclear@0
|
183 TriCount = ParticleCount << 1;
|
nuclear@0
|
184 VertexCount = ParticleCount << 2;
|
nuclear@0
|
185 IndexCount = TriCount * 3;
|
nuclear@0
|
186
|
nuclear@0
|
187 return ParticleCount;
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 void ParticleSystem::Update(float t) {
|
nuclear@0
|
191
|
nuclear@0
|
192 if(FixedUpdateRate && t-LastUpdate < 1.0f/UpdateRate) return;
|
nuclear@0
|
193 LastUpdate = t;
|
nuclear@0
|
194
|
nuclear@0
|
195 // remove all particles that are dead
|
nuclear@0
|
196 list<Particle>::iterator iter = particles.begin();
|
nuclear@0
|
197 while(iter != particles.end()) {
|
nuclear@0
|
198 if(!iter->life) {
|
nuclear@0
|
199 iter = particles.erase(iter);
|
nuclear@0
|
200 // if we erase the iterator points to the next so no need to advance explicitly
|
nuclear@0
|
201 } else {
|
nuclear@0
|
202 iter++;
|
nuclear@0
|
203 }
|
nuclear@0
|
204 }
|
nuclear@0
|
205
|
nuclear@0
|
206
|
nuclear@0
|
207 // spawn the new particles according to spawn rate
|
nuclear@0
|
208 int LeftToSpawn = SpawnRate;
|
nuclear@0
|
209 Vector3 ShootDir = ShootDirection;
|
nuclear@0
|
210 Matrix4x4 dispxform;
|
nuclear@0
|
211
|
nuclear@0
|
212 Vector3 forces = Vector3(0.0f, -GravForce, 0.0f);
|
nuclear@0
|
213
|
nuclear@0
|
214 // find the velocity of the system by differenciating between the
|
nuclear@0
|
215 // last and the current position (time interval is considered constant)
|
nuclear@0
|
216 Vector3 velocity = (pos - prevpos) * 0.1f;
|
nuclear@0
|
217
|
nuclear@0
|
218 // adjust the shoot vector to take under consideration the velocity of the system
|
nuclear@0
|
219 if(EmmiterAffectsParticleTrajectory) ShootDir += velocity;
|
nuclear@0
|
220
|
nuclear@0
|
221
|
nuclear@0
|
222 while(LeftToSpawn--) {
|
nuclear@0
|
223 Vector3 dir = ShootDir;
|
nuclear@0
|
224 dispxform.Rotate(frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f);
|
nuclear@0
|
225 dir.Transform(dispxform);
|
nuclear@0
|
226
|
nuclear@0
|
227 Vector3 SpawnOffset(frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f);
|
nuclear@0
|
228 Vector3 SpawnDisp(0.0f, 0.0f, 0.0f);
|
nuclear@0
|
229 if(SpawnDiffDispersion > 0.0f) {
|
nuclear@0
|
230 SpawnDisp = Vector3(frand(1.0f) - 0.5f, frand(1.0f) - 0.5f, frand(1.0f) - 0.5f);
|
nuclear@0
|
231 SpawnDisp.Normalize();
|
nuclear@0
|
232 SpawnDisp *= SpawnDiffDispersion;
|
nuclear@0
|
233 }
|
nuclear@0
|
234 particles.insert(particles.end(), Particle(pos + SpawnOffset, dir + SpawnDisp, life));
|
nuclear@0
|
235 }
|
nuclear@0
|
236
|
nuclear@0
|
237
|
nuclear@0
|
238 //if(EmmiterAffectsParticleTrajectory) forces += velocity;
|
nuclear@0
|
239
|
nuclear@0
|
240 iter = particles.begin();
|
nuclear@0
|
241 while(iter != particles.end()) {
|
nuclear@0
|
242 iter->Update(forces, friction);
|
nuclear@0
|
243 iter++;
|
nuclear@0
|
244 }
|
nuclear@0
|
245
|
nuclear@0
|
246 SpawnRate += SpawnRateChange;
|
nuclear@0
|
247 if(SpawnRate < 0) SpawnRate = 0;
|
nuclear@0
|
248 }
|
nuclear@0
|
249
|
nuclear@0
|
250 inline dword FtoDW(float f) { return *((dword*)&f); }
|
nuclear@0
|
251
|
nuclear@0
|
252 void ParticleSystem::Render() {
|
nuclear@0
|
253
|
nuclear@0
|
254 CountParticles();
|
nuclear@0
|
255 if(!ParticleCount) return;
|
nuclear@0
|
256
|
nuclear@0
|
257 list<Particle>::iterator iter = particles.begin();
|
nuclear@0
|
258
|
nuclear@0
|
259 if(!obj) {
|
nuclear@0
|
260
|
nuclear@0
|
261 // ----- Render Billboarded Textured Quads -----
|
nuclear@0
|
262
|
nuclear@0
|
263 VertexBuffer *vb;
|
nuclear@0
|
264 gc->CreateVertexBuffer(ParticleCount, UsageStatic, &vb);
|
nuclear@0
|
265 Vertex *vbptr;
|
nuclear@0
|
266 Lock(vb, &vbptr);
|
nuclear@0
|
267
|
nuclear@0
|
268 for(int i=0; i<ParticleCount; i++) {
|
nuclear@0
|
269 vbptr[i].pos = iter->pos;
|
nuclear@0
|
270
|
nuclear@0
|
271 float t = 1.0f - (float)iter->life / (float)life;
|
nuclear@0
|
272 float red = StartRed + (EndRed - StartRed) * t;
|
nuclear@0
|
273 float green = StartGreen + (EndGreen - StartGreen) * t;
|
nuclear@0
|
274 float blue = StartBlue + (EndBlue - StartBlue) * t;
|
nuclear@0
|
275
|
nuclear@0
|
276 vbptr[i].color = Color(red, green, blue).GetPacked32();
|
nuclear@0
|
277
|
nuclear@0
|
278 iter++;
|
nuclear@0
|
279 }
|
nuclear@0
|
280 Unlock(vb);
|
nuclear@0
|
281
|
nuclear@0
|
282 gc->SetWorldMatrix(Matrix4x4());
|
nuclear@0
|
283 gc->SetLighting(false);
|
nuclear@0
|
284 gc->SetZWrite(false);
|
nuclear@0
|
285 gc->SetTexture(0, texture);
|
nuclear@0
|
286 gc->SetTextureStageColor(0, TexBlendModulate, TexArgCurrent, TexArgTexture);
|
nuclear@0
|
287 gc->SetAlphaBlending(true);
|
nuclear@0
|
288 gc->SetBlendFunc(SourceBlend, DestBlend);
|
nuclear@0
|
289 gc->SetVertexProgram(FixedFunction);
|
nuclear@0
|
290
|
nuclear@0
|
291 gc->SetColorVertex(true);
|
nuclear@0
|
292
|
nuclear@0
|
293 gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
|
nuclear@0
|
294 gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);
|
nuclear@0
|
295 gc->D3DDevice->SetRenderState(D3DRS_POINTSIZE, FtoDW(size));
|
nuclear@0
|
296 gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_A, FtoDW(0.0f));
|
nuclear@0
|
297 gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f));
|
nuclear@0
|
298 gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDW(1.0f));
|
nuclear@0
|
299
|
nuclear@0
|
300 gc->D3DDevice->SetStreamSource(0, vb, sizeof(Vertex));
|
nuclear@0
|
301 gc->D3DDevice->DrawPrimitive(D3DPT_POINTLIST, 0, ParticleCount);
|
nuclear@0
|
302
|
nuclear@0
|
303 gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
|
nuclear@0
|
304 gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false);
|
nuclear@0
|
305
|
nuclear@0
|
306 gc->SetColorVertex(false);
|
nuclear@0
|
307
|
nuclear@0
|
308 gc->SetLighting(true);
|
nuclear@0
|
309 gc->SetZWrite(true);
|
nuclear@0
|
310 gc->SetAlphaBlending(false);
|
nuclear@0
|
311
|
nuclear@0
|
312 vb->Release();
|
nuclear@0
|
313 } else {
|
nuclear@0
|
314
|
nuclear@0
|
315 // ---- Render Mesh Objects ----
|
nuclear@0
|
316 for(int i=0; i<ParticleCount; i++) {
|
nuclear@0
|
317 obj->ResetTranslation();
|
nuclear@0
|
318 obj->Translate(iter->pos.x, iter->pos.y, iter->pos.z);
|
nuclear@0
|
319 obj->Render();
|
nuclear@0
|
320 iter++;
|
nuclear@0
|
321 }
|
nuclear@0
|
322 }
|
nuclear@0
|
323
|
nuclear@0
|
324
|
nuclear@0
|
325 } |