absence_thelab

annotate src/3deng/particles.cpp @ 0:1cffe3409164

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 23 Oct 2014 01:46:07 +0300
parents
children
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 }