// // nitroParticle.js //-------------------- // Implements a generic nitro particle. Currently positioned and updated in software for debug // simplicity - but should be moved to vertex shader in future. // by riperiperi // window.NitroParticle = function(scene, emitter, pos, vel, dir, dirVel, duration, scale, attached) { var t = this; t.update = update; t.draw = draw; t.time = 0; t.duration = duration | 0; t.pos = vec3.add(pos, pos, [0, 0, 0]); t.vel = vel; t.dirVel = dirVel; //float t.dir = dir; //float t.attached = attached; t.scale = scale; //vec2 t.emitter = emitter; t.aScale = 1; //decode 16 bit color into float t.baseColor = convertCol(emitter.color); t.baseColor[3] = emitter.opacity / 0x1F; t.aColor = vec4.clone(t.baseColor); t.frame = emitter.textureId; if (t.emitter.texAnim) t.frame = t.emitter.texAnim.textures[0]; function convertCol(col) { return [ ((col&31)/31), (((col>>5)&31)/31), (((col>>10)&31)/31), 1 //Math.round((col>>15)*255); ]; } function update(scene) { var particlePct = t.time / t.duration; t.pos[0] += t.vel[0] * 16; t.pos[1] += t.vel[1] * (t.emitter.yOffIntensity/128) * 16; t.pos[2] += t.vel[2] * 16; if (t.emitter.gravity) { vec3.add(t.vel, t.vel, t.emitter.gravity); } if (t.emitter.colorAnim) { var ca = t.emitter.colorAnim; var from = convertCol(ca.colorFrom); var to = convertCol(ca.colorTo); var pctFloat = (ca.framePct/0xFFFF); vec4.lerp(t.aColor, from, to, Math.max(0, (particlePct - pctFloat)/(1 - pctFloat))); t.aColor[3] = t.emitter.opacity/0x1F; } else { t.aColor = vec4.clone(t.baseColor); } if (t.emitter.opacityAnim) { var oa = t.emitter.opacityAnim; var pctFade = oa.startFade / 0xFFFF; var opaMul = 1-Math.max(0, (particlePct - pctFade)/(1 - pctFade)); t.aColor[3] = opaMul;// * oa.intensity/0x0FFF; //vec4.scale(t.aColor, t.aColor, opaMul); } if (t.emitter.texAnim) { var ta = t.emitter.texAnim; var frame = 0; if ((ta.unknown1 & 128) > 0) { //select frame based on particle duration var frame = ta.textures[Math.min((particlePct * ta.frames) | 0, ta.frames-1)]; } else { //repeating anim with framerate //not sure what framerate is, but its likely in the unknowns. var frame = ta.textures[(t.time % ta.frames)]; } t.frame = frame; } t.dir += t.dirVel; if (t.time++ >= t.duration) scene.removeParticle(t); } function draw(view, pMatrix, gl) { var particlePct = t.time / t.duration; var pos = t.pos; var vel = t.vel; if (t.attached != null) { pos = vec3.transformMat4([], pos, t.attached.mat); //tranform our vector by the target matrix var mat = t.attached.mat; var org = []; mat4.getTranslation(org, mat); mat[12] = 0; mat[13] = 0; mat[14] = 0; vel = vec3.transformMat4([], vel, mat); mat[12] = org[0]; mat[13] = org[1]; mat[14] = org[2]; } var mat = mat4.translate(mat4.create(), view, pos); var bbMode = t.emitter.flag & 0xF0; if (bbMode == 0x10) { //spark, billboards towards camera var camPos = scene.camera.view.pos; camPos = vec3.sub([], camPos, pos); vec3.normalize(camPos, camPos); var n = vec3.sub([], vel, t.ovel); vec3.normalize(n,n); mat4.multiply(mat, mat, mat4.invert([], mat4.lookAt([], [0,0,0], camPos, n))); } else if (bbMode == 0x20) { //no billboard mat4.rotateY(mat, mat, t.dir); } else if (bbMode == 0x30) { //spark, no billboard var camPos = scene.camera.view.pos; camPos = vec3.sub([], camPos, pos); vec3.normalize(camPos, camPos); var n = vec3.sub([], vel, t.ovel); vec3.normalize(n,n); mat4.multiply(mat, mat, mat4.invert([], mat4.lookAt([], [0,0,0], camPos, n))); mat4.rotateY(mat, mat, t.dir); } else { //billboard mat4.multiply(mat, mat, nitroRender.billboardMat); mat4.rotateZ(mat, mat, t.dir); } var finalScale = 1; if (t.emitter.scaleAnim) { var sa = t.emitter.scaleAnim; if (particlePct < sa.fromZeroTime) { var fzPct = particlePct / sa.fromZeroTime; finalScale = sa.scaleFrom * fzPct; } else { var rescaledPct = Math.min(1, (particlePct - sa.fromZeroTime) / (1-(sa.fromZeroTime + sa.holdTime*(1-sa.fromZeroTime)))); finalScale = sa.scaleFrom * (1-rescaledPct) + sa.scaleTo * rescaledPct; } } mat4.scale(mat, mat, vec3.scale([], [t.scale[0], t.scale[1], 1], 12*finalScale)); mat4.translate(mat, mat, [t.emitter.xScaleDelta, t.emitter.yScaleDelta, 0]); drawGeneric(mat, pMatrix, gl); } var MAT3I = mat3.create(); var MAT4I = mat4.create(); function drawGeneric(mv, project, gl) { var shader = nitroRender.nitroShader; if (!nitroRender.flagShadow) { gl.uniform1f(shader.shadOffUniform, 0.001); gl.uniform1f(shader.lightIntensityUniform, 0); } if (window.VTX_PARTICLE == null) genGlobalVtx(gl); var obj = window.VTX_PARTICLE; nitroRender.setColMult(t.aColor); gl.uniformMatrix4fv(shader.mvMatrixUniform, false, mv); gl.uniformMatrix4fv(shader.pMatrixUniform, false, project); //matrix stack unused, just put an identity in slot 0 gl.uniformMatrix4fv(shader.matStackUniform, false, MAT4I); var frame = t.emitter.parent.getTexture(t.frame, gl); gl.bindTexture(gl.TEXTURE_2D, frame); //texture matrix not used gl.uniformMatrix3fv(shader.texMatrixUniform, false, MAT3I); if (obj != nitroRender.last.obj) { gl.bindBuffer(gl.ARRAY_BUFFER, obj.vPos); gl.vertexAttribPointer(shader.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, obj.vTx); gl.vertexAttribPointer(shader.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, obj.vCol); gl.vertexAttribPointer(shader.colorAttribute, 4, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, obj.vMat); gl.vertexAttribPointer(shader.matAttribute, 1, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, obj.vNorm); gl.vertexAttribPointer(shader.normAttribute, 3, gl.FLOAT, false, 0, 0); nitroRender.last.obj = obj; } gl.disable(gl.CULL_FACE); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); nitroRender.setColMult([1, 1, 1, 1]); if (!nitroRender.flagShadow) { nitroRender.resetShadOff(); gl.uniform1f(shader.lightIntensityUniform, 0.3); } } function genGlobalVtx(gl) { var vecPos = [-1,-1,0, 1,-1,0, -1,1,0, 1,1,0]; var vecTx = [1,1, 0,1, 1,0, 0,0]; var vecCol = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; var vecMat = [0,0,0,0]; var vecNorm = [0,1,0, 0,1,0, 0,1,0, 0,1,0]; var pos = gl.createBuffer(); var col = gl.createBuffer(); var tx = gl.createBuffer(); var mat = gl.createBuffer(); var norm = gl.createBuffer(); var posArray = new Float32Array(vecPos); gl.bindBuffer(gl.ARRAY_BUFFER, pos); gl.bufferData(gl.ARRAY_BUFFER, posArray, gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, tx); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vecTx), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, col); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vecCol), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, mat); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vecMat), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, norm); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vecNorm), gl.STATIC_DRAW); window.VTX_PARTICLE = { posArray: posArray, vPos: pos, vTx: tx, vCol: col, vMat: mat, vNorm: norm, verts: vecPos.length/3, }; } }