From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/helper-classes/RDGE/src/core/script/particle.js | 842 +++++++++++++++++++++ 1 file changed, 842 insertions(+) create mode 100644 js/helper-classes/RDGE/src/core/script/particle.js (limited to 'js/helper-classes/RDGE/src/core/script/particle.js') diff --git a/js/helper-classes/RDGE/src/core/script/particle.js b/js/helper-classes/RDGE/src/core/script/particle.js new file mode 100644 index 00000000..dd83433e --- /dev/null +++ b/js/helper-classes/RDGE/src/core/script/particle.js @@ -0,0 +1,842 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +particleStats = function() { + this.numParticles = new stat("particles", "numParticles", 0); + this.numDrawCalls = new stat("particles", "numDrawCalls", 0); + this.numVerts = new stat("particles", "numVerts", 0); + this.numTris = new stat("particles", "numTris", 0); + + this.report = function(psys) { + for (em in psys.emitters) { + var pbuffer = psys.emitters[em].pbuffer; + var idxBuffer = pbuffer.indexBuffer.front(); + var posBuffer = pbuffer.posBuffer.front(); + this.numParticles.value += idxBuffer.numIndices / 6; + this.numTris.value += idxBuffer.numIndices / 3; + this.numVerts.value += this.numParticles.value * 4; + if(this.numParticles.value > 0) { + this.numDrawCalls.value++; + } + } + } +}; + +g_particleStats = null; +//if( g_enableBenchmarks ) { +// g_particleStats = new particleStats; +//} + +particle = function(def, id) { + this.id = id; + this.def = def; + if( this.def.numFrames == undefined ) { + if( this.def.textureSize && this.def.frameSize ) { + this.def.numFrames = ( this.def.textureSize[0] / this.def.frameSize[0] ) * ( this.def.textureSize[1] / this.def.frameSize[1] ); + } else { + this.def.numFrames = 0; + } + } + + this.pos = vec3.zero(); + this.delta = vec3.zero(); + this.rotate = 0.0; + this.age = 0.0; + this.lifespan = 0.0; + this.velocity = vec3.zero(); + this.gravity = vec3.zero(); + this.frame = 0; + this.frameCount = 0; + this.lastPos = vec3.zero(); + this.state = 0; + this.hide = false; + this.color = vec4.zero(); + + this.randomize = function(min, max) { + return min + (max - min) * Math.random(); + } + this.rate = this.randomize( -1.0, 1.0 ); + + this.randomize3 = function(min, max) { + return [this.randomize(min[0], max[0]), + this.randomize(min[1], max[1]), + this.randomize(min[2], max[2])]; + } + + this.spawn = function(spawnMatrix) { + if( this.def.initialframe == undefined ) { + this.frame = this.id % this.def.numFrames; + } else { + this.frame = this.randomize( this.def.initialframe[0], this.def.initialframe[1] ); + } + this.pos = this.randomize3(this.def.initialpos[0], this.def.initialpos[1]); + if (this.def.worldSpace) { + // calculate the initial position in world space. + this.pos = mat4.transformPoint( spawnMatrix, this.pos ); + } + // all other values are assumed to be defined in local or world space depending on + // the particles worldSpace designation. + var toRadians = Math.PI/180.0; + if( this.def.initialsize ) { + this.size = this.randomize(this.def.initialsize[0], this.def.initialsize[1]); + } else { + this.size = 1.0; + } + this.velocity = this.randomize3(this.def.initialvel[0], this.def.initialvel[1]); + this.gravity = [this.def.gravity[0], this.def.gravity[1], this.def.gravity[2]]; + this.rotate = this.randomize(this.def.initialrot[0] * toRadians, this.def.initialrot[1] * toRadians); + this.lifespan = this.randomize(this.def.lifespan[0], this.def.lifespan[1]); + this.age = 0.0; + this.delta = [0.0, 0.0, 0.0]; + this.lastPos = vec3.add(this.pos, vec3.scale(this.velocity, -1.0 / 30.0)); + this.color = [1,1,1,1];//vec4.random( [0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 1.0] ); + } +} + +// double buffered array utility class +DoubleBuffer = function(arrType, size) { + this.buffer = {}; + this.buffer[0] = new arrType(size); + this.buffer[1] = new arrType(size); + this.bufferIndex = 0; + + this.flip = function() { + this.bufferIndex = 1 - this.bufferIndex; + } + this.front = function() { + return this.buffer[this.bufferIndex]; + } + this.back = function() { + return this.buffer[1 - this.bufferIndex]; + } +} + + +// cycling buffer +particleBuffer = function(pdef, emitter, size) +{ + var renderer = g_Engine.getContext().renderer; + var ctx = renderer.ctx; + + s_particleShader = new jshader(); + s_particleShader.def = { + 'shaders': { + 'defaultVShader': "assets/shaders/particle_vshader.glsl", + 'defaultFShader': "assets/shaders/particle_fshader.glsl" + }, + 'techniques': { + 'defaultTechnique': [{ + 'vshader' : 'defaultVShader', + 'fshader' : 'defaultFShader', + 'attributes' : { + 'a_pos' : { 'type' : 'vec4' }, + 'a_posId' : { 'type' : 'float' }, + 'a_rotation' : { 'type' : 'float' }, + 'a_size' : { 'type' : 'float' }, + 'a_color' : { 'type' : 'vec4' } + }, + 'params' : { + 'u_projMatrix' : { 'type' : 'mat4' }, + 'u_viewMatrix' : { 'type' : 'mat4' }, + 'u_worldMatrix' : { 'type' : 'mat4' }, + 'u_particleSizeX' : { 'type' : 'vec4' }, + 'u_particleSizeY' : { 'type' : 'vec4' }, + 'u_particleRot' : { 'type' : 'vec4' }, + 'u_particleColors' : { 'type' : 'mat4' }, + 'u_textureSize' : { 'type' : 'vec2' }, + 'u_frameSize' : { 'type' : 'vec2' }, + 's_texture0' : { 'type' : 'tex2d' } +// 's_texture1' : { 'type' : 'tex2d' } + } + }] + } + } + s_particleShader.init(); + s_particleTextures = {}; + + this.shader = s_particleShader; + this.owner = emitter; + if( pdef.texture && s_particleTextures[pdef.texture] == undefined ) { + s_particleTextures[pdef.texture] = renderer.createTexture(pdef.texture); + if( !pdef.textureSize || !pdef.frameSize ) { + pdef.textureSize = []; + pdef.textureSize[0] = s_particleTextures[pdef.texture].image.width; + pdef.textureSize[1] = s_particleTextures[pdef.texture].image.height; + + } + + if( !pdef.frameSize ) { + pdef.frameSize = []; + pdef.frameSize[0] = s_particleTextures[pdef.texture].image.width; + pdef.frameSize[1] = s_particleTextures[pdef.texture].image.height; + } + } + if( pdef.texture2 && s_particleTextures[pdef.texture2] == undefined ) { + s_particleTextures[pdef.texture2] = renderer.createTexture(pdef.texture2); + } + this.texture = s_particleTextures[pdef.texture]; + this.texture2 = s_particleTextures[pdef.texture2]; + this.bounds = {}; + this.bounds.min = vec3.zero(); + this.bounds.max = vec3.zero(); + + this.srcBlend = pdef.srcBlend; + this.dstBlend = pdef.dstBlend; + + this.particles = new Array(); + + this.posBuffer = new DoubleBuffer(Float32Array, 16 * size); // 4 positions per particle, 4 components per position (particle age in w) + this.posIdBuffer = new Float32Array(4 * size); + this.sizeBuffer = new DoubleBuffer(Float32Array, 4 * size); + this.rotBuffer = new DoubleBuffer(Float32Array, 4 * size); + this.colorBuffer = new DoubleBuffer(Float32Array, 16 * size); + this.indexBuffer = new DoubleBuffer(Uint16Array, 6 * size); + this.indexBuffer.front().numIndices = 0; + this.indexBuffer.back().numIndices = 0; + + for ( i = 0; i < size; ++i ) { + this.particles.push(new particle(pdef, i)); + + // initialize double buffers. + // the first pass will init the front buffers. + // the second pass will init the back buffers. + for ( j = 0; j < 2; ++j ) { + // init position buffer + var pfb = this.posBuffer.front(); + var i16 = i * 16; + for ( j = 0; j < 4; ++j ) { + var cmpBaseIndex = i16 + j * 4; + pfb[cmpBaseIndex + 0] = 0; + pfb[cmpBaseIndex + 1] = 0; + pfb[cmpBaseIndex + 2] = 0; + pfb[cmpBaseIndex + 3] = 1; + } + + // init rotation buffer + var i4 = i * 4; + var rfb = this.rotBuffer.front(); + rfb[i4 + 0] = 0; + rfb[i4 + 1] = 0; + rfb[i4 + 2] = 0; + rfb[i4 + 3] = 0; + + // init rotation buffer + var i4 = i * 4; + var sfb = this.sizeBuffer.front(); + rfb[i4 + 0] = 1; + rfb[i4 + 1] = 1; + rfb[i4 + 2] = 1; + rfb[i4 + 3] = 1; + + // init color buffer + var i4 = i * 4; + var cfb = this.colorBuffer.front(); + cfb[i4] = 0xFFFFFF; + + // init index buffer + var ifb = this.indexBuffer.front(); + var i6 = i * 6; + ifb[i6 + 0] = i4 + 1; + ifb[i6 + 1] = i4 + 0; + ifb[i6 + 2] = i4 + 3; + ifb[i6 + 3] = i4 + 1; + ifb[i6 + 4] = i4 + 3; + ifb[i6 + 5] = i4 + 2; + + // flip buffers + this.posBuffer.flip(); + this.rotBuffer.flip(); + this.indexBuffer.flip(); + } + + var i4 = i * 4; + this.posIdBuffer[i4 + 0] = 0; + this.posIdBuffer[i4 + 1] = 1; + this.posIdBuffer[i4 + 2] = 2; + this.posIdBuffer[i4 + 3] = 3; + } + + this.posBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.posBufferObject); + ctx.bufferData(ctx.ARRAY_BUFFER, this.posBuffer.front(), ctx.DYNAMIC_DRAW); + + this.posIdBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.posIdBufferObject); + ctx.bufferData(ctx.ARRAY_BUFFER, this.posIdBuffer, ctx.DYNAMIC_DRAW); + + this.rotBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.rotBufferObject); + ctx.bufferData(ctx.ARRAY_BUFFER, this.rotBuffer.front(), ctx.DYNAMIC_DRAW); + + this.sizeBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.sizeBufferObject); + ctx.bufferData(ctx.ARRAY_BUFFER, this.sizeBuffer.front(), ctx.DYNAMIC_DRAW); + + this.colorBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.colorBufferObject); + ctx.bufferData(ctx.ARRAY_BUFFER, this.colorBuffer.front(), ctx.DYNAMIC_DRAW); + + this.indexBufferObject = ctx.createBuffer(); + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBufferObject); + ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer.front(), ctx.DYNAMIC_DRAW); + + this.start = 0; + this.end = 0; + this.cap = size; + + this.kill = function() { + this.start++; + if (this.start > (this.cap - 1)) + this.start = 0; + } + + this.emit = function(parent) { + this.end++; + if (this.end >= this.cap) { + this.end = 0; + } + if (this.end == this.start) { + this.kill(); + } + this.particles[this.end].spawn(this.owner.world); + } + + this.sync = function() { + this.posBuffer.flip(); + this.rotBuffer.flip(); + this.sizeBuffer.flip(); + this.colorBuffer.flip(); + this.indexBuffer.flip(); + + // update the back buffer. + var dstPosBuffer = this.posBuffer.back(); + var dstRotBuffer = this.rotBuffer.back(); + var dstSizeBuffer = this.sizeBuffer.back(); + var dstColorBuffer = this.colorBuffer.back(); + var dstIdxBuffer = this.indexBuffer.back(); + + var bmin = this.bounds.min; + var bmax = this.bounds.max; + + bmin[0] = 1e10; + bmin[1] = 1e10; + bmin[2] = 1e10; + + bmax[0] = -1e10; + bmax[1] = -1e10; + bmax[2] = -1e10; + + var numIndices = 0; + var i = this.start; + while(1) { + var x, y, z, w; + var p = this.particles[i]; + var age = (p.age / p.lifespan); // normalized age + // combine frame number and age and store in w. + // to decode : + // frame = floor( w ); + // age = fract( w ); + var pw = Math.min(age, 0.999) + Math.floor(p.frame); + if (age < 1.0) { // || (pdef.persist != undefined && pdef.persist == true)) { + var px = p.pos[0]; + var py = p.pos[1]; + var pz = p.pos[2]; + + if (px > bmax[0]) { bmax[0] = px; } + if (px > bmax[1]) { bmax[1] = py; } + if (px > bmax[2]) { bmax[2] = pz; } + + if (px < bmin[0]) { bmin[0] = px; } + if (px < bmin[1]) { bmin[1] = py; } + if (px < bmin[2]) { bmin[2] = pz; } + + var i16 = i * 16; + for (j = 0; j < 4; ++j) { + var cmpBaseIndex = i16 + j * 4; + dstPosBuffer[cmpBaseIndex + 0] = px; + dstPosBuffer[cmpBaseIndex + 1] = py; + dstPosBuffer[cmpBaseIndex + 2] = pz; + dstPosBuffer[cmpBaseIndex + 3] = pw; + } + + var i4 = i * 4; + var r = 0.0; + if (pdef.velocityAligned) { + r = Math.atan2(p.delta[0], p.delta[1]); + } + dstRotBuffer[i4 + 0] = p.rotate + r; + dstRotBuffer[i4 + 1] = p.rotate + r; + dstRotBuffer[i4 + 2] = p.rotate + r; + dstRotBuffer[i4 + 3] = p.rotate + r; + + dstSizeBuffer[i4 + 0] = p.size; + dstSizeBuffer[i4 + 1] = p.size; + dstSizeBuffer[i4 + 2] = p.size; + dstSizeBuffer[i4 + 3] = p.size; + + var i16 = i * 16; + for (j = 0; j < 4; ++j) { + var cmpBaseIndex = i16 + j * 4; + dstColorBuffer[cmpBaseIndex + 0] = p.color[0]; + dstColorBuffer[cmpBaseIndex + 1] = p.color[1]; + dstColorBuffer[cmpBaseIndex + 2] = p.color[2]; + dstColorBuffer[cmpBaseIndex + 3] = p.color[3]; + } + + dstIdxBuffer[numIndices + 0] = i4 + 1; + dstIdxBuffer[numIndices + 1] = i4 + 0; + dstIdxBuffer[numIndices + 2] = i4 + 3; + dstIdxBuffer[numIndices + 3] = i4 + 1; + dstIdxBuffer[numIndices + 4] = i4 + 2; + dstIdxBuffer[numIndices + 5] = i4 + 3; + + numIndices += 6; + } + + if( i == this.end ) { + break; + } + i++; + if (i == this.cap && this.end != this.cap) { + i = 0; + } + } + dstIdxBuffer.numIndices = numIndices; + + if (!pdef.worldSpace) { + // calculate the world space bounds from local space. + // first transform our local space min-max coordinates to world space. + var bminW = mat4.mul(bmin, this.owner.world); + var bmaxW = mat4.mul(bmax, this.owner.world); + + // now calculate axis aligned bounds based on the world space coordinates. + if (bmaxW[0] > bmax[0]) { bmax[0] = bmaxW[0]; } + if (bmaxW[1] > bmax[1]) { bmax[1] = bmaxW[1]; } + if (bmaxW[2] > bmax[2]) { bmax[2] = bmaxW[2]; } + if (bminW[0] < bmin[0]) { bmin[0] = bminW[0]; } + if (bminW[1] < bmin[1]) { bmin[1] = bminW[1]; } + if (bminW[2] < bmin[2]) { bmin[2] = bminW[2]; } + } + } + + this.update = function(dt, movers) { + var i = this.start; + if( pdef.persist != undefined && pdef.persist == false ) { + while (1) { + var p = this.particles[i]; + if( p.age < p.lifespan ) + break; + this.kill(); + if( i == this.end ) { + break; + } + i++; + if (i == this.cap && this.end != this.cap) { + i = 0; + } + } + } + + i = this.start; + while (1) { + var p = this.particles[i]; + var j = movers.length; + while (j) { + movers[--j].move(p, dt); + } + if( i == this.end ) { + break; + } + i++; + if (i == this.cap && this.end != this.cap) { + i = 0; + } + } + + this.sync(); + } + + this.render = function() { + + var renderer = g_Engine.getContext().renderer; + var ctx = g_Engine.getContext().renderer.ctx; + + // draw using the front buffer. + var srcPosBuffer = this.posBuffer.front(); + var srcRotBuffer = this.rotBuffer.front(); + var srcSizeBuffer = this.sizeBuffer.front(); + var srcColBuffer = this.colorBuffer.front(); + var srcIdxBuffer = this.indexBuffer.front(); + + if (srcIdxBuffer.numIndices > 0) + { + // set modelview matrix + var shaderparms = this.shader.defaultTechnique; + var activeCam = renderer.cameraManager().getActiveCamera(); + if (pdef.worldSpace) + { + shaderparms.u_viewMatrix.set(activeCam.view); + shaderparms.u_worldMatrix.set(mat4.identity()); + } + else + { + shaderparms.u_viewMatrix.set(activeCam.view); + shaderparms.u_worldMatrix.set(this.owner.world); +// shaderparms.u_mvMatrix.set(mat4.mul(this.owner.world, activeCam.view)); + } + shaderparms.u_projMatrix.set( activeCam.proj ); + + shaderparms.u_particleSizeX.set( pdef.sizeX ); + shaderparms.u_particleSizeY.set( pdef.sizeY ); + shaderparms.u_particleRot.set( vec4.scale( pdef.rotation, Math.PI / 180.0 ) ); + shaderparms.u_particleColors.set( mat4.transpose( pdef.colors ) ); + shaderparms.u_textureSize.set(pdef.textureSize); + shaderparms.u_frameSize.set(pdef.frameSize); + shaderparms.s_texture0.set(this.texture); +// shaderparms.s_texture1.set(null); + + var passCount = this.shader.begin(); + for(passIdx = 0; passIdx < passCount; ++passIdx ) + { + this.shader.beginPass(passIdx); + + // setup render states + if (!pdef.depthTest) + { + ctx.disable(ctx.DEPTH_TEST); + } + + ctx.enable(ctx.BLEND); + ctx.blendFunc(ctx[pdef.srcBlend], ctx[pdef.dstBlend]); + + ctx.enableVertexAttribArray(0); + ctx.enableVertexAttribArray(1); + ctx.enableVertexAttribArray(2); + ctx.enableVertexAttribArray(3); + ctx.enableVertexAttribArray(4); + + // update position buffer + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.posBufferObject); + ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, srcPosBuffer); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.posBufferObject); + ctx.vertexAttribPointer(0, 4, ctx.FLOAT, false, 0, 0); + + // position id buffer + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.posIdBufferObject); + ctx.vertexAttribPointer(1, 1, ctx.FLOAT, false, 0, 0); + + // update rotation buffer + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.rotBufferObject); + ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, srcRotBuffer); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.rotBufferObject); + ctx.vertexAttribPointer(2, 1, ctx.FLOAT, false, 0, 0); + + // update size buffer + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.sizeBufferObject); + ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, srcSizeBuffer); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.sizeBufferObject); + ctx.vertexAttribPointer(3, 1, ctx.FLOAT, false, 0, 0); + + // update color buffer + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.colorBufferObject); + ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, srcColBuffer); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.colorBufferObject); + ctx.vertexAttribPointer(4, 4, ctx.FLOAT, false, 0, 0); + + // update index buffer + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBufferObject); + ctx.bufferSubData(ctx.ELEMENT_ARRAY_BUFFER, 0, srcIdxBuffer); + + // draw + ctx.drawElements(ctx.TRIANGLES, srcIdxBuffer.numIndices, ctx.UNSIGNED_SHORT, 0); + + // restore render states + ctx.disable(ctx.BLEND); + if (!pdef.depthTest) + { + ctx.enable(ctx.DEPTH_TEST); + } + ctx.blendFunc(ctx.ONE, ctx.ZERO); + + this.shader.endPass(); + } + this.shader.end(); + } + } +} + +particleMoverDefault = function() { + this.move = function(particle, dt) + { + particle.age += dt; + + if( particle.def.persist ) { + if( particle.def.cycle && particle.age > particle.lifespan * 0.99 ) { + particle.age -= particle.lifespan * 0.99; + } else { + particle.age = Math.min( particle.age, particle.lifespan * 0.99 ); + } + + } else { + particle.age = Math.min(particle.age, particle.lifespan); + } + + if( particle.def.frameRate > 0.0 ) + { + particle.frame += particle.def.frameRate * dt;//Math.min( particle.def.numFrames - 1, particle.frame + particle.def.frameRate * dt ); + if( particle.def.frameLoop ) + { + particle.frame = particle.frame % particle.def.numFrames; + } + else + { + particle.frame = Math.min( particle.def.numFrames - 1, particle.frame ) + } + } + + var oldPos = particle.pos; + var pg = particle.gravity; + var pv = particle.velocity; + var pp = particle.pos; + var pd = particle.delta; + + pv[0] += pg[0] * dt; + pv[1] += pg[1] * dt; + pv[2] += pg[2] * dt; + pp[0] = pp[0] + pv[0] * dt; + pp[1] = pp[1] + pv[1] * dt; + pp[2] = pp[2] + pv[2] * dt; + pd[0] = pp[0] - oldPos[0]; + pd[1] = pp[1] - oldPos[1]; + pd[2] = pp[2] - oldPos[2]; + + // particle turbulence + if (particle.def.turbulence) + { + var tMin = particle.def.turbulence[0]; + var tMax = particle.def.turbulence[1]; + var tx = Math.random() * (tMax[0] - tMin[0]) + tMin[0]; + var ty = Math.random() * (tMax[1] - tMin[1]) + tMin[1]; + var tz = Math.random() * (tMax[2] - tMin[2]) + tMin[2]; + pv[0] += tx; + pv[1] += ty; + pv[2] += tz; + } + + // particle jitter + if (particle.def.jitter) + { + var jMin = particle.def.jitter[0]; + var jMax = particle.def.jitter[1]; + var jx = Math.random() * (jMax[0] - jMin[0]) + jMin[0]; + var jy = Math.random() * (jMax[1] - jMin[1]) + jMin[1]; + var jz = Math.random() * (jMax[2] - jMin[2]) + jMin[2]; + pp[0] += jx; + pp[1] += jy; + pp[2] += jz; + } + } +} + +particleEmitter = function(def) +{ + this.def = def; + this.world = mat4.identity(); + this.pbuffer = new particleBuffer(this.def.particle, this, this.def.maxParticles); + + this.movers = new Array(); + var creatorFunc = particleMoverDefault; + if( def.particle.moverFunc ) + { + creatorFunc = eval(def.particle.moverFunc); + } + this.movers.push(new creatorFunc()); + + this.localTime = 0.0; + this.lastEmitTime = 0.0; + this.emitCounter = 0; + this.firstUpdate = true; + + this.attachToNode = function( node ) + { + this.controller = node; + } + + this.update = function(dt) + { + this.localTime += dt; + if( this.firstUpdate ) + { + this.lastEmitTime = this.localTime; + this.firstUpdate = false; + } + + if( this.def.emit != undefined && this.def.emit == false ) + { + this.lastEmitTime = this.localTime - 1.0/this.def.emitRate; + } + + // this needs to be handled differently.. + var maxParticles = this.def.maxParticles; + var emitOnce = this.def.emitOnce; + var emitCount = ( this.def.emit == undefined || this.def.emit == true ) ? Math.floor((this.localTime - this.lastEmitTime) * this.def.emitRate) : 0; + while (emitCount--) + { + if(emitOnce && this.emitCounter++ >= maxParticles) + { + break; + } + this.pbuffer.emit(this.world); + this.lastEmitTime = this.localTime; + } + + this.pbuffer.update(dt, this.movers); + } +} + + + +particleSys = function(addr) +{ + loaded = ( typeof loaded == 'undefined' ) ? {} : loaded; + + this.def = null; + this.node = null; + this.world = mat4.identity(); + this.emitters = {}; + + // load particle system definition at addr + this.init = function() + { + if (this.def == null) + { + return; + } + for (e in this.def.emitters) + { + this.emitters[e] = new particleEmitter(this.def.emitters[e]); + } + + this.bounds = {}; + this.bounds.min = vec3.zero(); + this.bounds.max = vec3.zero(); + } + + if( !loaded[addr] ) { + var request = new XMLHttpRequest(); + request.sender = this; + + request.onreadystatechange = function() + { + if (request.readyState == 4) + { + if (request.status == 200 || window.location.href.indexOf("http") == -1) + { + request.sender.def = eval("(" + request.responseText + ")"); //retrieve result as an JavaScript object + loaded[addr] = request.sender.def; + request.sender.init(); + } + else + { + alert("An error has occured loading particle system."); + } + } + } + + request.open("GET", addr, true); + request.send(null); + } else { + this.def = loaded[addr]; + this.init(); + } + // + + this.update = function(dt) + { + if (this.def == null) + { + return; + } + + var bmin = this.bounds.min; + var bmax = this.bounds.max; + + bmin[0] = 1e10; + bmin[1] = 1e10; + bmin[2] = 1e10; + + bmax[0] = -1e10; + bmax[1] = -1e10; + bmax[2] = -1e10; + + var parent = this.node ? this.node.world : this.world; + for (em in this.emitters) { + var emitter = this.emitters[em]; + emitter.world = parent; + emitter.update(dt); + + var emin = emitter.pbuffer.bounds.min; + var emax = emitter.pbuffer.bounds.max; + + // calculate a bounds that fits all particles. + if (emin[0] < bmin[0]) { bmin[0] = emin[0]; } + if (emin[1] < bmin[1]) { bmin[1] = emin[1]; } + if (emin[2] < bmin[2]) { bmin[2] = emin[2]; } + if (emax[0] > bmax[0]) { bmax[0] = emax[0]; } + if (emax[1] > bmax[1]) { bmax[1] = emax[1]; } + if (emax[2] > bmax[2]) { bmax[2] = emax[2]; } + } + } + + this.render = function() + { + if (this.def == null) + { + return; + } + for (em in this.emitters) + { + var pbuffer = this.emitters[em].pbuffer; + pbuffer.render(); + } + if(g_particleStats) { + g_particleStats.report(this); + } + } + + this.attachToNode = function(node) + { + this.node = node; + } +} + +g_particleSystemManager = new objectManager(); +g_particleSystemManager.update = function( dt ) +{ + var i = this.objects.length - 1; + while( i >= 0 ) + { + var psys = this.objects[i]; + if( psys ) { + psys.update(dt); + } + i--; + } +} + +g_particleSystemManager.render = function( dt ) +{ + var i = 0; + while( i < this.objects.length ) + { + var psys = this.objects[i]; + if( psys ) { + psys.render(); + } + i++; + } +} + -- cgit v1.2.3