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