Initial implementation of Nitro Particles
- Drifting particles and mini turbo (sans extra spark particles) - Slowdown particles (grass/sand/water) - Itembox collect particle - Wall collide particle (this is really extreme and there should probably be others) - Shader improvements, such as dithered shadows for alpha and reduction of artifacts. The best way to remove all artifacts would be generating normals for courses and using the diffuse direction as a more reliable indication of shadowed/not. - Fixed checkpoints not resetting on new laps. - Fixed me not being able to count to 3. (now 3 laps instead of 4) - Fixed battle mode courses crashing on load and during due to AI being funny (above 31, eg 36 for block fort)
This commit is contained in:
1 parent
870bef6689
commit
4af42625a0
18 files changed
+6338
-3119
No files matched your search
@@ -5,35 +5,35 @@
|
||||
//
|
||||
|
||||
window.ItemShard = function(scene, targ, model) {
|
||||
var t = this;
|
||||
t.update = update;
|
||||
t.draw = draw;
|
||||
var t = this;
|
||||
t.update = update;
|
||||
t.draw = draw;
|
||||
|
||||
t.time = 0;
|
||||
t.pos = vec3.clone(targ.pos);
|
||||
t.vel = vec3.add([], targ.vel, [(Math.random()-0.5)*5, Math.random()*7, (Math.random()-0.5)*5]);
|
||||
t.dirVel = [(Math.random()-0.5), (Math.random()-0.5), (Math.random()-0.5)];
|
||||
t.dir = [Math.random()*2*Math.PI, Math.random()*2*Math.PI, Math.random()*2*Math.PI];
|
||||
t.scale = Math.random()+0.5;
|
||||
t.scale = [t.scale, t.scale, t.scale];
|
||||
t.time = 0;
|
||||
t.pos = vec3.clone(targ.pos);
|
||||
t.vel = vec3.add([], targ.vel, [(Math.random()-0.5)*5, Math.random()*7, (Math.random()-0.5)*5]);
|
||||
t.dirVel = [(Math.random()-0.5), (Math.random()-0.5), (Math.random()-0.5)];
|
||||
t.dir = [Math.random()*2*Math.PI, Math.random()*2*Math.PI, Math.random()*2*Math.PI];
|
||||
t.scale = Math.random()+0.5;
|
||||
t.scale = [t.scale, t.scale, t.scale];
|
||||
|
||||
function update(scene) {
|
||||
vec3.add(t.pos, t.pos, t.vel);
|
||||
vec3.add(t.vel, t.vel, [0, -0.17, 0]);
|
||||
vec3.add(t.dir, t.dir, t.dirVel);
|
||||
function update(scene) {
|
||||
vec3.add(t.pos, t.pos, t.vel);
|
||||
vec3.add(t.vel, t.vel, [0, -0.17, 0]);
|
||||
vec3.add(t.dir, t.dir, t.dirVel);
|
||||
|
||||
if (t.time++ > 30) scene.removeParticle(t);
|
||||
}
|
||||
if (t.time++ > 30) scene.removeParticle(t);
|
||||
}
|
||||
|
||||
function draw(view, pMatrix, gl) {
|
||||
var mat = mat4.translate(mat4.create(), view, t.pos);
|
||||
|
||||
mat4.rotateZ(mat, mat, t.dir[2]);
|
||||
mat4.rotateY(mat, mat, t.dir[1]);
|
||||
mat4.rotateX(mat, mat, t.dir[0]);
|
||||
function draw(view, pMatrix, gl) {
|
||||
var mat = mat4.translate(mat4.create(), view, t.pos);
|
||||
|
||||
mat4.rotateZ(mat, mat, t.dir[2]);
|
||||
mat4.rotateY(mat, mat, t.dir[1]);
|
||||
mat4.rotateX(mat, mat, t.dir[0]);
|
||||
|
||||
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
|
||||
model.draw(mat, pMatrix);
|
||||
}
|
||||
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
|
||||
model.draw(mat, pMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// nitroEmitter.js
|
||||
//--------------------
|
||||
// Implemtents the generic nitro particle emitter.
|
||||
// by riperiperi
|
||||
//
|
||||
|
||||
window.NitroEmitter = function(scene, targ, emitterID, vector, offset) {
|
||||
var t = this;
|
||||
t.update = update;
|
||||
t.draw = draw;
|
||||
|
||||
var pRes = scene.gameRes.RaceEffect;
|
||||
var emitter = (emitterID == -1)?null:pRes.particles[emitterID];
|
||||
t.attached = targ; //an entity with pos and vel.
|
||||
|
||||
if (vector == null) vector = [0, 1, 0];
|
||||
if (offset == null) offset = [0,0,0];
|
||||
t.offset = offset;
|
||||
t.vector = vector;
|
||||
t.pctParticle = 0;
|
||||
t.time = 0;
|
||||
t.dead = false;
|
||||
t.curPrio = 0;
|
||||
t.doNotDelete = (emitter == null);
|
||||
t.pause = false;
|
||||
|
||||
t.setEmitter = setEmitter;
|
||||
t.clearEmitter = clearEmitter;
|
||||
|
||||
var particleList = [emitterID, -1, -1, -1];
|
||||
|
||||
function setEmitter(emitterID, prio) {
|
||||
particleList[prio] = emitterID;
|
||||
if (t.curPrio <= prio) {
|
||||
//activate this emitter immediately.
|
||||
t.curPrio = prio;
|
||||
t.dead = false;
|
||||
emitter = pRes.particles[emitterID];
|
||||
t.time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function clearEmitter(prio) {
|
||||
//if (t.curPrio > prio) return; //this emitter cannot be unset
|
||||
if (prio == t.curPrio) {
|
||||
findNextEmitter();
|
||||
} else {
|
||||
particleList[prio] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
function findNextEmitter() {
|
||||
particleList[t.curPrio] = -1;
|
||||
var em = t.curPrio-1;
|
||||
while (em >= 0) {
|
||||
if (particleList[em] != -1) {
|
||||
t.dead = false;
|
||||
emitter = pRes.particles[particleList[em]];
|
||||
t.time = 0;
|
||||
t.curPrio = em;
|
||||
return;
|
||||
}
|
||||
em--;
|
||||
}
|
||||
if (em == -1) {
|
||||
t.curPrio = 0;
|
||||
emitter = null;
|
||||
dead = true;
|
||||
}
|
||||
t.curPrio = em;
|
||||
}
|
||||
|
||||
function update(scene) {
|
||||
if (emitter == null || t.dead || t.pause) return;
|
||||
if ((t.time % (emitter.frequency)) == 0 && t.time >= emitter.delay) {
|
||||
//should we create new particles? fractional logic for doing this
|
||||
t.pctParticle += emitter.particleChance;
|
||||
while (t.pctParticle >= 1) {
|
||||
|
||||
var attach = (emitter.flag & 0x8000) > 0;
|
||||
|
||||
t.pctParticle -= 1;
|
||||
//create a new particle
|
||||
//TODO: make these transform with the target's world matrix
|
||||
var pos = vec3.create();
|
||||
//add offset
|
||||
vec3.add(pos, pos, t.offset);
|
||||
//add emitter properties
|
||||
vec3.add(pos, pos, emitter.position);
|
||||
var spread = [Math.random()*2-1, Math.random()*2-1, Math.random()*2-1];
|
||||
var spreadMode = (emitter.flag & 0xF);
|
||||
if (spreadMode == 2) {
|
||||
spread[1] = 0; //spread is only in xz direction
|
||||
}
|
||||
vec3.normalize(spread, spread);
|
||||
if (spreadMode == 0) {
|
||||
spread = [0,0,0];
|
||||
}
|
||||
vec3.scale(spread, spread, Math.random()*emitter.areaSpread*2);
|
||||
vec3.add(pos, pos, spread);
|
||||
|
||||
vec3.scale(pos, pos, 16);
|
||||
if (!attach) {
|
||||
if (targ.mat != null) {
|
||||
vec3.transformMat4(pos, pos, targ.mat);
|
||||
} else {
|
||||
vec3.add(pos, pos, targ.pos);
|
||||
}
|
||||
}
|
||||
|
||||
//inherit velocity
|
||||
var vel = (attach)?vec3.create():vec3.clone(targ.vel);
|
||||
vec3.scale(vel, vel, 1/32);
|
||||
|
||||
var vector = vec3.clone(t.vector);
|
||||
if (!attach) {
|
||||
if (targ.mat != null) {
|
||||
//tranform our vector by the target matrix
|
||||
var mat = targ.mat;
|
||||
var org = [];
|
||||
mat4.getTranslation(org, mat);
|
||||
mat[12] = 0;
|
||||
mat[13] = 0;
|
||||
mat[14] = 0;
|
||||
|
||||
vec3.transformMat4(vector, vector, mat);
|
||||
|
||||
mat[12] = org[0];
|
||||
mat[13] = org[1];
|
||||
mat[14] = org[2];
|
||||
}
|
||||
}
|
||||
vec3.normalize(vector, vector);
|
||||
vec3.add(vel, vel, vec3.scale([], vector, emitter.velocity));
|
||||
|
||||
var xz = [Math.random()*2-1, 0, Math.random()*2-1];
|
||||
vec3.normalize(xz, xz);
|
||||
vec3.scale(xz, xz, Math.random()*emitter.randomxz);
|
||||
vec3.add(vel, vel, xz);
|
||||
|
||||
var rotVel = ((emitter.rotVelFrom + ((Math.random()*emitter.rotVelTo-emitter.rotVelFrom) | 0))/65535) * Math.PI*2;
|
||||
var dir = ((emitter.flag & 0x2000) > 0)?(Math.random()*Math.PI*2):0;
|
||||
var duration = emitter.duration + emitter.duration * emitter.varDuration/0xFF * (Math.random() * 2 - 1);
|
||||
var scaleMod = (emitter.varScale/0xFF * (Math.random() * 2 - 1)) + 1;
|
||||
|
||||
var scale = [scaleMod * emitter.size, scaleMod * emitter.size * emitter.aspect];
|
||||
|
||||
var particle = new NitroParticle(scene, emitter, pos, vel, dir, rotVel, duration, scale, (attach?t.attached:null));
|
||||
particle.ovel = (attach)?vec3.create():vec3.scale([], targ.vel, 1/32);
|
||||
|
||||
scene.particles.push(particle);
|
||||
}
|
||||
|
||||
|
||||
var pos = vec3.clone(targ.pos);
|
||||
|
||||
}
|
||||
t.time++;
|
||||
|
||||
if (t.time == emitter.emitterLifetime) {
|
||||
t.dead = true;
|
||||
if (!t.doNotDelete) scene.removeParticle(t);
|
||||
else {
|
||||
findNextEmitter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function draw(view, pMatrix, gl) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// 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;
|
||||
|
||||
let pos = t.pos;
|
||||
let 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.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,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user