absence_thelab
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/3deng/particles.cpp Thu Oct 23 01:46:07 2014 +0300 1.3 @@ -0,0 +1,325 @@ 1.4 +#include "particles.h" 1.5 +#include "3deng.h" 1.6 +#include <cassert> 1.7 + 1.8 +////////////////////////////////////////////////////// 1.9 +// --==( Particle class implementation )==-- // 1.10 +////////////////////////////////////////////////////// 1.11 +using namespace std; 1.12 + 1.13 +Particle::Particle(int life) { 1.14 + pos = Vector3(0, 0, 0); 1.15 + vel = Vector3(0, 0, 0); 1.16 + this->life = life; 1.17 +} 1.18 + 1.19 +Particle::Particle(const Vector3 &pos, int life) { 1.20 + this->pos = pos; 1.21 + vel = Vector3(0, 0, 0); 1.22 + this->life = life; 1.23 +} 1.24 + 1.25 +Particle::Particle(const Vector3 &pos, const Vector3 &vel, int life) { 1.26 + this->pos = pos; 1.27 + this->vel = vel; 1.28 + this->life = life; 1.29 +} 1.30 + 1.31 +void Particle::Update(const Vector3 &forces, float friction) { 1.32 + if(!life) return; 1.33 + vel *= 1.0f - friction; 1.34 + pos += vel + forces; 1.35 + life--; 1.36 +} 1.37 + 1.38 +/////////////////////////////////////////////////////// 1.39 +// --==( Particle System implementation )==-- // 1.40 +/////////////////////////////////////////////////////// 1.41 + 1.42 +ParticleSystem::ParticleSystem(GraphicsContext *gc) { 1.43 + this->gc = gc; 1.44 + pos = prevpos = Vector3(0, 0, 0); 1.45 + size = 1.0f; 1.46 + friction = 0.0f; 1.47 + SpawnRate = 5; 1.48 + life = 100; 1.49 + EmmiterAffectsParticleTrajectory = false; 1.50 + varray = 0; 1.51 + tarray = 0; 1.52 + texture = 0; 1.53 + obj = 0; 1.54 + 1.55 + SetShootDirection(Vector3(0, 0, 0)); 1.56 + SetMaxDispersionAngle(0.01f); 1.57 + SetInitialColor(1, 1, 1); 1.58 + SetDeathColor(0, 0, 0); 1.59 + 1.60 + // initialize the shape of the particles 1.61 + pquad[0] = Vertex(Vector3(-0.5f, 0.5f, 0), 0, 0, 0xffffffff); 1.62 + pquad[1] = Vertex(Vector3(0.5f, 0.5f, 1), 1, 0, 0xffffffff); 1.63 + pquad[2] = Vertex(Vector3(0.5f, -0.5f, 1), 1, 1, 0xffffffff); 1.64 + pquad[3] = Vertex(Vector3(-0.5f, -0.5f, 0), 0, 1, 0xffffffff); 1.65 + 1.66 + ptris[0] = Triangle(0, 1, 2); 1.67 + ptris[1] = Triangle(0, 2, 3); 1.68 + 1.69 + for(int i=0; i<4; i++) { 1.70 + pquad[i].normal = Vector3(0, 0, -1); 1.71 + } 1.72 + 1.73 + SetBlendingMode(BLEND_ONE, BLEND_ONE); 1.74 + SpawnDiffDispersion = 0.0f; 1.75 + 1.76 + FixedUpdateRate = true; 1.77 + UpdateRate = 30.0f; 1.78 + LastUpdate = -(1.0f / UpdateRate); 1.79 + 1.80 + SpawnRateChange = 0; 1.81 +} 1.82 + 1.83 +ParticleSystem::~ParticleSystem() { 1.84 +} 1.85 + 1.86 +void ParticleSystem::SetGraphicsContext(GraphicsContext *gc) { 1.87 + this->gc = gc; 1.88 +} 1.89 + 1.90 +void ParticleSystem::SetParticleSize(float psize) { 1.91 + size = psize; 1.92 +} 1.93 + 1.94 +void ParticleSystem::SetParticleLife(int life) { 1.95 + this->life = life; 1.96 +} 1.97 + 1.98 +void ParticleSystem::SetFriction(float friction) { 1.99 + this->friction = friction; 1.100 +} 1.101 + 1.102 +void ParticleSystem::SetSpawnRate(float spawnrate) { 1.103 + SpawnRate = (int)spawnrate; 1.104 +} 1.105 + 1.106 +void ParticleSystem::SetSpawnRadius(float radius) { 1.107 + SpawnRadius = radius; 1.108 +} 1.109 + 1.110 +void ParticleSystem::SetTexture(Texture *texture) { 1.111 + this->texture = texture; 1.112 +} 1.113 + 1.114 +void ParticleSystem::SetObject(Object *obj) { 1.115 + this->obj = obj; 1.116 +} 1.117 + 1.118 +void ParticleSystem::SetPosition(const Vector3 &pos) { 1.119 + this->pos = pos; 1.120 +} 1.121 + 1.122 +void ParticleSystem::SetShootDirection(const Vector3 &dir) { 1.123 + ShootDirection = dir; 1.124 +} 1.125 + 1.126 +void ParticleSystem::SetGravitualForce(float grav) { 1.127 + GravForce = grav; 1.128 +} 1.129 + 1.130 +void ParticleSystem::SetEmmiterDependence(bool dep) { 1.131 + EmmiterAffectsParticleTrajectory = dep; 1.132 +} 1.133 + 1.134 +void ParticleSystem::SetMaxDispersionAngle(float maxdisp) { 1.135 + DispRads = maxdisp; 1.136 +} 1.137 + 1.138 +void ParticleSystem::SetInitialColor(float r, float g, float b) { 1.139 + StartRed = r; 1.140 + StartGreen = g; 1.141 + StartBlue = b; 1.142 +} 1.143 + 1.144 +void ParticleSystem::SetDeathColor(float r, float g, float b) { 1.145 + EndRed = r; 1.146 + EndGreen = g; 1.147 + EndBlue = b; 1.148 +} 1.149 + 1.150 +void ParticleSystem::SetBlendingMode(BlendingFactor src, BlendingFactor dest) { 1.151 + SourceBlend = src; 1.152 + DestBlend = dest; 1.153 +} 1.154 + 1.155 +void ParticleSystem::SetSpawningDifferenceDispersion(float val) { 1.156 + SpawnDiffDispersion = val; 1.157 +} 1.158 + 1.159 +void ParticleSystem::SetSpawnRateChange(int change) { 1.160 + SpawnRateChange = change; 1.161 +} 1.162 + 1.163 +// transformation stuff 1.164 +void ParticleSystem::Translate(float x, float y, float z) { 1.165 + Translation.Translate(x, y, z); 1.166 +} 1.167 + 1.168 +void ParticleSystem::Rotate(float x, float y, float z) { 1.169 + OrbitRot.Rotate(x, y, z); 1.170 +} 1.171 + 1.172 +void ParticleSystem::Rotate(const Vector3 &axis, float angle) { 1.173 + OrbitRot.Rotate(axis, angle); 1.174 +} 1.175 + 1.176 +void ParticleSystem::ResetRotation() { 1.177 + OrbitRot.ResetIdentity(); 1.178 +} 1.179 + 1.180 +void ParticleSystem::ResetTranslation() { 1.181 + Translation.ResetIdentity(); 1.182 +} 1.183 + 1.184 +int ParticleSystem::CountParticles() { 1.185 + ParticleCount = (int)particles.size(); 1.186 + TriCount = ParticleCount << 1; 1.187 + VertexCount = ParticleCount << 2; 1.188 + IndexCount = TriCount * 3; 1.189 + 1.190 + return ParticleCount; 1.191 +} 1.192 + 1.193 +void ParticleSystem::Update(float t) { 1.194 + 1.195 + if(FixedUpdateRate && t-LastUpdate < 1.0f/UpdateRate) return; 1.196 + LastUpdate = t; 1.197 + 1.198 + // remove all particles that are dead 1.199 + list<Particle>::iterator iter = particles.begin(); 1.200 + while(iter != particles.end()) { 1.201 + if(!iter->life) { 1.202 + iter = particles.erase(iter); 1.203 + // if we erase the iterator points to the next so no need to advance explicitly 1.204 + } else { 1.205 + iter++; 1.206 + } 1.207 + } 1.208 + 1.209 + 1.210 + // spawn the new particles according to spawn rate 1.211 + int LeftToSpawn = SpawnRate; 1.212 + Vector3 ShootDir = ShootDirection; 1.213 + Matrix4x4 dispxform; 1.214 + 1.215 + Vector3 forces = Vector3(0.0f, -GravForce, 0.0f); 1.216 + 1.217 + // find the velocity of the system by differenciating between the 1.218 + // last and the current position (time interval is considered constant) 1.219 + Vector3 velocity = (pos - prevpos) * 0.1f; 1.220 + 1.221 + // adjust the shoot vector to take under consideration the velocity of the system 1.222 + if(EmmiterAffectsParticleTrajectory) ShootDir += velocity; 1.223 + 1.224 + 1.225 + while(LeftToSpawn--) { 1.226 + Vector3 dir = ShootDir; 1.227 + dispxform.Rotate(frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f); 1.228 + dir.Transform(dispxform); 1.229 + 1.230 + Vector3 SpawnOffset(frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f); 1.231 + Vector3 SpawnDisp(0.0f, 0.0f, 0.0f); 1.232 + if(SpawnDiffDispersion > 0.0f) { 1.233 + SpawnDisp = Vector3(frand(1.0f) - 0.5f, frand(1.0f) - 0.5f, frand(1.0f) - 0.5f); 1.234 + SpawnDisp.Normalize(); 1.235 + SpawnDisp *= SpawnDiffDispersion; 1.236 + } 1.237 + particles.insert(particles.end(), Particle(pos + SpawnOffset, dir + SpawnDisp, life)); 1.238 + } 1.239 + 1.240 + 1.241 + //if(EmmiterAffectsParticleTrajectory) forces += velocity; 1.242 + 1.243 + iter = particles.begin(); 1.244 + while(iter != particles.end()) { 1.245 + iter->Update(forces, friction); 1.246 + iter++; 1.247 + } 1.248 + 1.249 + SpawnRate += SpawnRateChange; 1.250 + if(SpawnRate < 0) SpawnRate = 0; 1.251 +} 1.252 + 1.253 +inline dword FtoDW(float f) { return *((dword*)&f); } 1.254 + 1.255 +void ParticleSystem::Render() { 1.256 + 1.257 + CountParticles(); 1.258 + if(!ParticleCount) return; 1.259 + 1.260 + list<Particle>::iterator iter = particles.begin(); 1.261 + 1.262 + if(!obj) { 1.263 + 1.264 + // ----- Render Billboarded Textured Quads ----- 1.265 + 1.266 + VertexBuffer *vb; 1.267 + gc->CreateVertexBuffer(ParticleCount, UsageStatic, &vb); 1.268 + Vertex *vbptr; 1.269 + Lock(vb, &vbptr); 1.270 + 1.271 + for(int i=0; i<ParticleCount; i++) { 1.272 + vbptr[i].pos = iter->pos; 1.273 + 1.274 + float t = 1.0f - (float)iter->life / (float)life; 1.275 + float red = StartRed + (EndRed - StartRed) * t; 1.276 + float green = StartGreen + (EndGreen - StartGreen) * t; 1.277 + float blue = StartBlue + (EndBlue - StartBlue) * t; 1.278 + 1.279 + vbptr[i].color = Color(red, green, blue).GetPacked32(); 1.280 + 1.281 + iter++; 1.282 + } 1.283 + Unlock(vb); 1.284 + 1.285 + gc->SetWorldMatrix(Matrix4x4()); 1.286 + gc->SetLighting(false); 1.287 + gc->SetZWrite(false); 1.288 + gc->SetTexture(0, texture); 1.289 + gc->SetTextureStageColor(0, TexBlendModulate, TexArgCurrent, TexArgTexture); 1.290 + gc->SetAlphaBlending(true); 1.291 + gc->SetBlendFunc(SourceBlend, DestBlend); 1.292 + gc->SetVertexProgram(FixedFunction); 1.293 + 1.294 + gc->SetColorVertex(true); 1.295 + 1.296 + gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true); 1.297 + gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true); 1.298 + gc->D3DDevice->SetRenderState(D3DRS_POINTSIZE, FtoDW(size)); 1.299 + gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_A, FtoDW(0.0f)); 1.300 + gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f)); 1.301 + gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDW(1.0f)); 1.302 + 1.303 + gc->D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); 1.304 + gc->D3DDevice->DrawPrimitive(D3DPT_POINTLIST, 0, ParticleCount); 1.305 + 1.306 + gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false); 1.307 + gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false); 1.308 + 1.309 + gc->SetColorVertex(false); 1.310 + 1.311 + gc->SetLighting(true); 1.312 + gc->SetZWrite(true); 1.313 + gc->SetAlphaBlending(false); 1.314 + 1.315 + vb->Release(); 1.316 + } else { 1.317 + 1.318 + // ---- Render Mesh Objects ---- 1.319 + for(int i=0; i<ParticleCount; i++) { 1.320 + obj->ResetTranslation(); 1.321 + obj->Translate(iter->pos.x, iter->pos.y, iter->pos.z); 1.322 + obj->Render(); 1.323 + iter++; 1.324 + } 1.325 + } 1.326 + 1.327 + 1.328 +} 1.329 \ No newline at end of file