absence_thelab

view src/3deng/particles.cpp @ 1:4d5933c261c3

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