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)pull/5/head
parent
870bef6689
commit
4af42625a0
|
@ -52,7 +52,7 @@ window.cameraIngame = function(kart) {
|
|||
var dist = 192;
|
||||
this.targetShadowPos = vec3.add([], kart.pos, [Math.sin(kart.angle)*dist, 0, -Math.cos(kart.angle)*dist])
|
||||
|
||||
thisObj.view = {p:p, mv:mat};
|
||||
thisObj.view = {p:p, mv:mat, pos: vec3.scale([], vec3.transformMat4([], [0,0,0], mat4.invert([], mat)), 1024)};
|
||||
|
||||
return thisObj.view;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ window.cameraIntro = function() {
|
|||
|
||||
thisObj.targetShadowPos = lookAtPos;
|
||||
|
||||
return {p:p, mv:mat}
|
||||
return {p:p, mv:mat, pos: vec3.scale([], vec3.transformMat4([], [0,0,0], mat4.invert([], mat)), 1024)}
|
||||
}
|
||||
|
||||
var initCam = function(scene, came) {
|
||||
|
|
|
@ -55,6 +55,7 @@ window.cameraSpectator = function(kart) {
|
|||
if (zoomLevel > curCam.zoomEnd) zoomLevel = curCam.zoomEnd;
|
||||
|
||||
thisObj.view = camFunc[curCam.camType](scene, curCam);
|
||||
thisObj.view.pos = vec3.scale([], vec3.transformMat4([], [0,0,0], mat4.invert([], thisObj.view.mv)), 1024)
|
||||
return thisObj.view;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,8 +141,10 @@ window.MKDS_COLTYPE = new (function(){
|
|||
this.PHYS_MAP[this.LOOP] = 11;
|
||||
|
||||
//collision sound handlers
|
||||
//26 is blue water, 30 is white
|
||||
//28 and 15 might be sand/dirt
|
||||
|
||||
var waterRoad = {drift: MKDS_COLSOUNDS.DRIFT_WATER, brake: MKDS_COLSOUNDS.BRAKE_WATER, land: MKDS_COLSOUNDS.LAND_WATER, drive: MKDS_COLSOUNDS.DRIVE_WATER};
|
||||
var waterRoad = {drift: MKDS_COLSOUNDS.DRIFT_WATER, brake: MKDS_COLSOUNDS.BRAKE_WATER, land: MKDS_COLSOUNDS.LAND_WATER, drive: MKDS_COLSOUNDS.DRIVE_WATER, particle: 30};
|
||||
|
||||
this.SOUNDMAP = {
|
||||
0x00: //road
|
||||
|
@ -164,7 +166,7 @@ window.MKDS_COLTYPE = new (function(){
|
|||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_ASPHALT},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_ASPHALT},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_ASPHALT},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_WATER, brake: MKDS_COLSOUNDS.BRAKE_WATER, land: MKDS_COLSOUNDS.LAND_WATERDEEP, drive: MKDS_COLSOUNDS.DRIVE_WATER},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_WATER, brake: MKDS_COLSOUNDS.BRAKE_WATER, land: MKDS_COLSOUNDS.LAND_WATERDEEP, drive: MKDS_COLSOUNDS.DRIVE_WATER, particle: 30},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_ASPHALT},
|
||||
{},
|
||||
{},
|
||||
|
@ -187,27 +189,27 @@ window.MKDS_COLTYPE = new (function(){
|
|||
|
||||
0x03: //road 4
|
||||
[
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND , land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_DIRT, brake: MKDS_COLSOUNDS.BRAKE_DIRT, land: MKDS_COLSOUNDS.LAND_DIRT, drive: MKDS_COLSOUNDS.DRIVE_DIRT},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND , land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND, particle: 28},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_DIRT, brake: MKDS_COLSOUNDS.BRAKE_DIRT, land: MKDS_COLSOUNDS.LAND_DIRT, drive: MKDS_COLSOUNDS.DRIVE_DIRT, particle: 15},
|
||||
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS, particle: 32},
|
||||
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_SNOW}, //snow
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND, particle: 28},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND, particle: 28},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_SNOW, particle:112}, //snow
|
||||
{},
|
||||
{}
|
||||
],
|
||||
|
||||
0x05: //road 5
|
||||
[
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND , land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_DIRT, brake: MKDS_COLSOUNDS.BRAKE_DIRT, land: MKDS_COLSOUNDS.LAND_DIRT, drive: MKDS_COLSOUNDS.DRIVE_DIRT},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND , land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND, particle: 28},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_DIRT, brake: MKDS_COLSOUNDS.BRAKE_DIRT, land: MKDS_COLSOUNDS.LAND_DIRT, drive: MKDS_COLSOUNDS.DRIVE_DIRT, particle: 15},
|
||||
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS, particle: 32},
|
||||
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_SAND, brake: MKDS_COLSOUNDS.BRAKE_SAND, land: MKDS_COLSOUNDS.LAND_SAND, drive: MKDS_COLSOUNDS.DRIVE_SAND, particle: 28},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ASPHALT, brake: MKDS_COLSOUNDS.BRAKE, land: MKDS_COLSOUNDS.LAND_GRASS, drive: MKDS_COLSOUNDS.DRIVE_GRASS, particle: 32},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
|
@ -216,7 +218,7 @@ window.MKDS_COLTYPE = new (function(){
|
|||
0x06: //slippery
|
||||
[
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_ICE, brake: MKDS_COLSOUNDS.BRAKE_ICE, land:MKDS_COLSOUNDS.LAND_ICE},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_MARSH, brake: MKDS_COLSOUNDS.BRAKE_MARSH, land:MKDS_COLSOUNDS.LAND_MARSH, drive: MKDS_COLSOUNDS.DRIVE_MARSH},
|
||||
{drift: MKDS_COLSOUNDS.DRIFT_MARSH, brake: MKDS_COLSOUNDS.BRAKE_MARSH, land:MKDS_COLSOUNDS.LAND_MARSH, drive: MKDS_COLSOUNDS.DRIVE_MARSH, particle: 24},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
|
|
|
@ -102,10 +102,14 @@ window.controlRaceCPU = function(nkm) {
|
|||
//advance to one of next possible paths
|
||||
|
||||
if (battleMode) {
|
||||
var pathInd = ((Math.random()>0.5 && ePath.source.length>0)?ePath.source:ePath.dest)[Math.floor(Math.random()*ePath.dest.length)];
|
||||
var loc = (Math.random()>0.5 && ePath.source.length>0)?ePath.source:ePath.dest;
|
||||
var pathInd = loc[Math.floor(Math.random()*loc.length)];
|
||||
ePoiInd = pathInd;
|
||||
ePoi = points[ePoiInd];
|
||||
recomputePath();
|
||||
var pt = points[ePoiInd];
|
||||
if (pt != null) {
|
||||
ePoi = pt;
|
||||
recomputePath();
|
||||
}
|
||||
} else {
|
||||
var pathInd = ePath.dest[Math.floor(Math.random()*ePath.dest.length)];
|
||||
ePath = paths[pathInd];
|
||||
|
|
|
@ -18,6 +18,7 @@ window.IngameRes = function(rom) {
|
|||
|
||||
this.Race = new narc(lz77.decompress(rom.getFile("/data/Scene/Race.carc"))); //contains lakitu, count, various graphics
|
||||
this.RaceLoc = new narc(lz77.decompress(rom.getFile("/data/Scene/Race_us.carc"))); //contains lakitu lap signs, START, YOU WIN etc. some of these will be replaced by hi res graphics by default.
|
||||
this.RaceEffect = new spa(r.MainEffect.getFile("RaceEffect.spa"));
|
||||
|
||||
this.MainFont = new nftr(r.Main2D.getFile("marioFont.NFTR"));
|
||||
//debugger;
|
||||
|
@ -43,7 +44,6 @@ window.IngameRes = function(rom) {
|
|||
var characters = [];
|
||||
var karts = [];
|
||||
|
||||
var test = new spa(r.MainEffect.getFile("RaceEffect.spa"));
|
||||
loadItems();
|
||||
loadTires();
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ window.ObjDecor = function(obji, scene) {
|
|||
forceBill = false;
|
||||
return {mdl:[{nsbmd:"choropu.nsbmd"}], other:[null, null, "choropu.nsbtp"]}; //has nsbtp
|
||||
case 0x019B: //cheep cheep (bouncing)
|
||||
return {mdl:[{nsbmd:"pukupuku.nsbmd"}], other:[null, null, "pukupuku.nsbtp"]}; //has nsbtp
|
||||
return {mdl:[{nsbmd:"pukupuku.nsbmd"}]}; //has nsbtp //, other:[null, null, "pukupuku.nsbtp"]
|
||||
case 0x019D: //snowman
|
||||
return {mdl:[{nsbmd:"sman_top.nsbmd"}, {nsbmd:"sman_bottom.nsbmd"}]};
|
||||
case 0x019E: //trunk with bats
|
||||
|
|
|
@ -45,6 +45,7 @@ window.ItemBox = function(obji, scene) {
|
|||
for (var j=0; j<10; j++) {
|
||||
scene.particles.push(new ItemShard(scene, ok, res.mdl[2]));
|
||||
}
|
||||
scene.particles.push(new NitroEmitter(scene, ok, 47));
|
||||
t.mode = 1;
|
||||
t.time = 0;
|
||||
break;
|
||||
|
|
|
@ -95,9 +95,18 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
this.lastInput = null;
|
||||
|
||||
//race statistics
|
||||
this.lapNumber = 0;
|
||||
this.lapNumber = 1;
|
||||
this.passedKTP2 = false;
|
||||
this.checkPointNumber = 0;
|
||||
|
||||
this.wheelParticles = [
|
||||
new NitroEmitter(scene, k, -1, [1, 1.5, -1]),
|
||||
new NitroEmitter(scene, k, -1, [-1, 1.5, -1])
|
||||
];
|
||||
|
||||
scene.particles.push(this.wheelParticles[0]);
|
||||
scene.particles.push(this.wheelParticles[1]);
|
||||
|
||||
var nkm = scene.nkm;
|
||||
var startLine = nkm.sections["KTPS"].entries[0];
|
||||
var passLine = nkm.sections["KTP2"].entries[0];
|
||||
|
@ -193,6 +202,10 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
mat4.scale(wmat, wmat, [scale, scale, scale]);
|
||||
if (i<2) mat4.rotateY(wmat, wmat, ((k.driveAnimF-14)/14)*Math.PI/6);
|
||||
mat4.rotateX(wmat, wmat, wheelTurn);
|
||||
|
||||
if (i>1) {
|
||||
k.wheelParticles[i-2].offset = vec3.scale(k.wheelParticles[i-2].offset, vec3.add(k.wheelParticles[i-2].offset, offsets.wheels[i], [0, -params.colRadius, 0]), 1/16);
|
||||
}
|
||||
}
|
||||
|
||||
var scale = 16;
|
||||
|
@ -262,7 +275,11 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
drawChar(view, pMatrix);
|
||||
}
|
||||
|
||||
|
||||
k.lWheelParticle = null;
|
||||
|
||||
function update(scene) {
|
||||
|
||||
var lastPos = vec3.clone(k.pos);
|
||||
updateMat = true;
|
||||
|
||||
|
@ -314,7 +331,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
sounds.boost = null;
|
||||
}
|
||||
|
||||
if (onGround && k.speed > 0.5) {
|
||||
var isMoving = onGround && k.speed > 0.5;
|
||||
if (isMoving) {
|
||||
if (lastCollided != sounds.lastTerrain || lastBE != sounds.lastBE || sounds.drive == null) {
|
||||
if (sounds.drive != null) nitroAudio.kill(sounds.drive);
|
||||
if (lastColSounds.drive != null) {
|
||||
|
@ -337,7 +355,10 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
} else {
|
||||
if (sounds.drift != null) { nitroAudio.kill(sounds.drift); sounds.drift = null; }
|
||||
if (sounds.drive != null) { nitroAudio.kill(sounds.drive); sounds.drive = null; }
|
||||
|
||||
}
|
||||
k.wheelParticles[0].pause = !isMoving;
|
||||
k.wheelParticles[1].pause = !isMoving;
|
||||
|
||||
//end sound update
|
||||
|
||||
|
@ -346,23 +367,40 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
} else if (k.cannon != null) { //when cannon is active, we fly forward at max move speed until we get to the cannon point.
|
||||
var c = scene.nkm.sections["KTPC"].entries[k.cannon];
|
||||
|
||||
var mat = mat4.create();
|
||||
mat4.rotateY(mat, mat, c.angle[1]*(Math.PI/180));
|
||||
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
|
||||
if (c.id2 != 0) {
|
||||
var c2 = scene.nkm.sections["KTPC"].entries[c.id2];
|
||||
c = c2;
|
||||
|
||||
var forward = [0, 0, 1];
|
||||
var up = [0, 1, 0];
|
||||
var mat = mat4.create();
|
||||
mat4.rotateY(mat, mat, c.angle[1]*(Math.PI/180));
|
||||
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
|
||||
|
||||
k.vel = vec3.scale([], vec3.transformMat4(forward, forward, mat), MAXSPEED);
|
||||
k.speed = MAXSPEED;
|
||||
vec3.add(k.pos, k.pos, k.vel);
|
||||
k.physicalDir = (180-c.angle[1])*(Math.PI/180);
|
||||
k.angle = k.physicalDir;
|
||||
k.kartTargetNormal = vec3.transformMat4(up, up, mat);
|
||||
k.pos = vec3.clone(c2.pos);
|
||||
vec3.add(k.pos, k.pos, vec3.transformMat4([], [0,16,16], mat));
|
||||
|
||||
var planeConst = -vec3.dot(c.pos, forward);
|
||||
var cannonDist = vec3.dot(k.pos, forward) + planeConst;
|
||||
if (cannonDist > 0) k.cannon = null;
|
||||
k.physicalDir = (180-c2.angle[1])*(Math.PI/180);
|
||||
k.angle = k.physicalDir;
|
||||
k.cannon = null;
|
||||
} else {
|
||||
|
||||
var mat = mat4.create();
|
||||
mat4.rotateY(mat, mat, c.angle[1]*(Math.PI/180));
|
||||
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
|
||||
|
||||
var forward = [0, 0, 1];
|
||||
var up = [0, 1, 0];
|
||||
|
||||
k.vel = vec3.scale([], vec3.transformMat4(forward, forward, mat), MAXSPEED);
|
||||
k.speed = Math.min(k.speed+1, MAXSPEED);
|
||||
vec3.add(k.pos, k.pos, k.vel);
|
||||
k.physicalDir = (180-c.angle[1])*(Math.PI/180);
|
||||
k.angle = k.physicalDir;
|
||||
k.kartTargetNormal = vec3.transformMat4(up, up, mat);
|
||||
|
||||
var planeConst = -vec3.dot(c.pos, forward);
|
||||
var cannonDist = vec3.dot(k.pos, forward) + planeConst;
|
||||
if (cannonDist > 0) k.cannon = null;
|
||||
}
|
||||
} else { //default kart mode
|
||||
|
||||
var groundEffect = 0;
|
||||
|
@ -402,6 +440,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
if ((onGround) && !(input.accel && input.drift && (k.speed > 2 || !k.driftLanded))) {
|
||||
//end drift, execute miniturbo
|
||||
k.drifting = false;
|
||||
clearWheelParticles();
|
||||
if (sounds.powerslide != null) {
|
||||
nitroAudio.instaKill(sounds.powerslide);
|
||||
sounds.powerslide = null;
|
||||
|
@ -434,11 +473,15 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
|
||||
if (onGround) {
|
||||
if (!k.driftLanded) {
|
||||
if (k.driftMode == 0) k.drifting = false;
|
||||
if (k.driftMode == 0) {
|
||||
k.drifting = false;
|
||||
clearWheelParticles();
|
||||
}
|
||||
else {
|
||||
k.driftPSMode = 0;
|
||||
k.driftPSTick = 0;
|
||||
k.driftLanded = true;
|
||||
if (k.drifting) setWheelParticles(20, 1); //20 = smoke, 1 = drift priority
|
||||
}
|
||||
}
|
||||
if (k.drifting) {
|
||||
|
@ -467,7 +510,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
k.driftPSMode++;
|
||||
k.driftPSTick = 1;
|
||||
|
||||
//play blue spark sound
|
||||
//play blue spark sound, flare
|
||||
setWheelParticles(126, 2); //126 = blue flare, 2 = flare priority
|
||||
var blue = nitroAudio.playSound(210, {}, 0, k);
|
||||
blue.gainN.gain.value = 2;
|
||||
|
||||
|
@ -487,6 +531,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
k.driftPSMode++;
|
||||
k.driftPSTick = 1;
|
||||
//play red sparks sound, full MT!
|
||||
setWheelParticles(22, 2); //22 = red flare, 2 = flare priority
|
||||
setWheelParticles(17, 1); //17 = red mt, 1 = drift priority
|
||||
sounds.powerslide = nitroAudio.playSound(209, {}, 0, k);
|
||||
sounds.powerslide.gainN.gain.value = 2;
|
||||
} else k.driftPSTick = 0;
|
||||
|
@ -642,6 +688,24 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
positionChanged(lastPos, k.pos);
|
||||
}
|
||||
|
||||
function clearWheelParticles(prio) {
|
||||
for (let i=0; i<2; i++) {
|
||||
if (prio == null) {
|
||||
//clear all specials
|
||||
k.wheelParticles[i].clearEmitter(1); //drift mode
|
||||
//k.wheelParticles[i].clearEmitter(2); //drift flare (blue mt, red big flash)
|
||||
} else {
|
||||
k.wheelParticles[i].clearEmitter(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setWheelParticles(id, prio) {
|
||||
for (let i=0; i<2; i++) {
|
||||
k.wheelParticles[i].setEmitter(id, prio);
|
||||
}
|
||||
}
|
||||
|
||||
function genFutureChecks() {
|
||||
//all future points that
|
||||
var chosen = {}
|
||||
|
@ -661,6 +725,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
|
||||
function positionChanged(oldPos, pos) {
|
||||
//crossed into new checkpoint?
|
||||
if (checkpoints.length == 0) return;
|
||||
for (var i=0; i<futureChecks.length; i++) {
|
||||
var check = checkpoints[futureChecks[i]];
|
||||
var distOld = vec2.sub([], [check.x1, check.z1], [oldPos[0], oldPos[2]]);
|
||||
|
@ -685,6 +750,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
k.lapNumber++;
|
||||
k.checkPointNumber = 0;
|
||||
k.passedKTP2 = 0;
|
||||
futureChecks = [1];
|
||||
scene.lapAdvance(k);
|
||||
}
|
||||
}
|
||||
|
@ -805,6 +871,11 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
return MKDS_COLTYPE.SOUNDMAP[collision][effect] || {};
|
||||
}
|
||||
|
||||
function colParticle(collision, effect) {
|
||||
if (MKDS_COLTYPE.SOUNDMAP[collision] == null) return null
|
||||
return MKDS_COLTYPE.SOUNDMAP[collision][effect].particle || null;
|
||||
}
|
||||
|
||||
function project(u, v) {
|
||||
return vec3.scale([], u, (vec3.dot(u, v)/vec3.dot(u, u)))
|
||||
}
|
||||
|
@ -815,6 +886,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
var colType = (plane.CollisionType>>8)&31;
|
||||
var colBE = (plane.CollisionType>>5)&7;
|
||||
|
||||
var change = (colType != lastCollided);
|
||||
lastCollided = colType;
|
||||
lastBE = colBE;
|
||||
lastColSounds = colSound(lastCollided, colBE);
|
||||
|
@ -832,9 +904,14 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
|
||||
if (proj < -1) {
|
||||
if (lastColSounds.hit != null) nitroAudio.playSound(lastColSounds.hit, {volume:1}, 0, k)
|
||||
var colObj = {pos:pos, vel:[0,0,0], mat: mat4.fromTranslation([], pos)};
|
||||
scene.particles.push(new NitroEmitter(scene, colObj, 13));
|
||||
scene.particles.push(new NitroEmitter(scene, colObj, 14));
|
||||
}
|
||||
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), adjN, proj));
|
||||
|
||||
|
||||
|
||||
//convert back to angle + speed to keep change to kart vel
|
||||
|
||||
var v = k.vel;
|
||||
|
@ -851,6 +928,14 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
|||
if (proj < -4 && k.vel[1] < -2) { proj -= 1.5; }
|
||||
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), n, proj));
|
||||
k.kartTargetNormal = dat.pNormal;
|
||||
|
||||
if (change) {
|
||||
var particle = colParticle(lastCollided, colBE);
|
||||
if (particle == null)
|
||||
clearWheelParticles(0);
|
||||
else
|
||||
setWheelParticles(particle, 0);
|
||||
}
|
||||
if (!onGround) {
|
||||
console.log("ground: "+colType+", "+colBE);
|
||||
groundAnim = 0;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
window.spa = function(input) {
|
||||
var t = this;
|
||||
this.load = load;
|
||||
this.getTexture = getTexture;
|
||||
|
||||
var colourBuffer;
|
||||
|
||||
|
@ -36,42 +37,108 @@ window.spa = function(input) {
|
|||
|
||||
offset += 24;
|
||||
if (version == "12_1") {
|
||||
this.particles = [];
|
||||
t.particles = [];
|
||||
for (let i=0; i<particleCount; i++) {
|
||||
this.particles[i] = readParticle(view, offset);
|
||||
offset = this.particles[i].nextOff;
|
||||
t.particles[i] = readParticle(view, offset);
|
||||
t.particles[i].parent = t;
|
||||
offset = t.particles[i].nextOff;
|
||||
}
|
||||
}
|
||||
|
||||
offset = firstTexOffset;
|
||||
this.particleTextures = [];
|
||||
t.particleTextures = [];
|
||||
for (let i=0; i<particleTexCount; i++) {
|
||||
this.particleTextures[i] = readParticleTexture(view, offset);
|
||||
offset = this.particleTextures[i].nextOff;
|
||||
t.particleTextures[i] = readParticleTexture(view, offset);
|
||||
offset = t.particleTextures[i].nextOff;
|
||||
}
|
||||
|
||||
//window.debugParticle = true;
|
||||
if (window.debugParticle) {
|
||||
for (let i=0; i<particleCount; i++) {
|
||||
var text = document.createElement("textarea");
|
||||
var p = this.particles[i];
|
||||
var p = t.particles[i];
|
||||
p.parent = null;
|
||||
text.value = JSON.stringify(p, true, 4);
|
||||
p.parent = t;
|
||||
text.style.width = 500;
|
||||
text.style.height = 200;
|
||||
|
||||
|
||||
var obj = this.particleTextures[p.textureId];
|
||||
if (p.texAnim) obj = this.particleTextures[p.texAnim.textures[0]];
|
||||
var obj = t.particleTextures[p.textureId];
|
||||
if (p.texAnim) obj = t.particleTextures[p.texAnim.textures[0]];
|
||||
if (obj == null) {
|
||||
continue;
|
||||
}
|
||||
var test = readTexWithPal(obj.info, obj);
|
||||
document.body.appendChild(document.createElement("br"));
|
||||
document.body.appendChild(document.createTextNode(i+":"));
|
||||
document.body.appendChild(test);
|
||||
document.body.appendChild(text);
|
||||
document.body.appendChild(document.createElement("br"));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTexture(id, gl) {
|
||||
var t = this;
|
||||
var obj = t.particleTextures[id];
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (obj.glTex == null) {
|
||||
var canvas = readTexWithPal(obj.info, obj);
|
||||
var m = obj.info;
|
||||
if (m.flipX || m.flipY) {
|
||||
var fC = document.createElement("canvas");
|
||||
var ctx = fC.getContext("2d");
|
||||
fC.width = (m.flipX)?canvas.width*2:canvas.width;
|
||||
fC.height = (m.flipY)?canvas.height*2:canvas.height;
|
||||
ctx.drawImage(canvas, 0, 0);
|
||||
ctx.save();
|
||||
if (m.flipX) {
|
||||
ctx.translate(2*canvas.width, 0);
|
||||
ctx.scale(-1, 1);
|
||||
ctx.drawImage(canvas, 0, 0);
|
||||
ctx.restore();
|
||||
ctx.save();
|
||||
}
|
||||
if (m.flipY) {
|
||||
ctx.translate(0, 2*canvas.height);
|
||||
ctx.scale(1, -1);
|
||||
ctx.drawImage(fC, 0, 0);
|
||||
ctx.restore();
|
||||
}
|
||||
var t = loadTex(fC, gl, !m.repeatX, !m.repeatY);
|
||||
t.realWidth = canvas.width;
|
||||
t.realHeight = canvas.height;
|
||||
obj.glTex = t;
|
||||
} else {
|
||||
var t = loadTex(canvas, gl, !m.repeatX, !m.repeatY);
|
||||
t.realWidth = canvas.width;
|
||||
t.realHeight = canvas.height;
|
||||
obj.glTex = t;
|
||||
}
|
||||
}
|
||||
return obj.glTex;
|
||||
}
|
||||
|
||||
function loadTex(img, gl, clampx, clampy) { //general purpose function for loading an image into a texture.
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
if (clampx) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
if (clampy) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
|
||||
texture.width = img.width;
|
||||
texture.height = img.height;
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
return texture;
|
||||
}
|
||||
|
||||
function readParticle(view, off) {
|
||||
var obj = {};
|
||||
var ParticleFlags =
|
||||
|
@ -106,6 +173,7 @@ window.spa = function(input) {
|
|||
Bit29: 0x20000000
|
||||
}
|
||||
|
||||
obj.ParticleFlags = ParticleFlags;
|
||||
obj.flag = view.getUint32(off, true);
|
||||
obj.position = [view.getInt32(off+0x4, true)/4096, view.getInt32(off+0x8, true)/4096, view.getInt32(off+0xC, true)/4096];
|
||||
//this is just hilarious at this point
|
||||
|
@ -118,8 +186,8 @@ window.spa = function(input) {
|
|||
//not sure what this vector is for. grass it's (0, 1, 0), smoke it's (-0.706787109375, 0, -0.707275390625) billboard alignment vector? (it's a bit crazy for powerslide)
|
||||
obj.vector = [view.getInt16(off+0x1C, true)/4096, view.getInt16(off+0x1E, true)/4096, view.getInt16(off+0x20, true)/4096];
|
||||
obj.color = view.getUint16(off+0x22, true); //15 bit, usually 32767 for white.
|
||||
obj.randomxz = view.getUint32(off+0x24, true); //random xz velocity intensity
|
||||
obj.velocity = view.getUint32(off+0x28, true); //initial velocity related
|
||||
obj.randomxz = view.getUint32(off+0x24, true)/4096; //random xz velocity intensity
|
||||
obj.velocity = view.getUint32(off+0x28, true)/4096; //initial velocity related (along predefined vector)
|
||||
obj.size = view.getUint32(off+0x2C, true)/4096; //size
|
||||
obj.aspect = view.getUint16(off+0x30, true) / 4096; //aspect
|
||||
|
||||
|
@ -130,8 +198,8 @@ window.spa = function(input) {
|
|||
obj.rotVelFrom = view.getInt16(off+0x34, true);
|
||||
obj.rotVelTo = view.getInt16(off+0x36, true);
|
||||
|
||||
obj.unknown13 = view.getUint16(off+0x38, true); //??? (0)
|
||||
obj.unknown14 = view.getUint16(off+0x3A, true); //??? (4B)
|
||||
obj.scX = view.getInt16(off+0x38, true)/0x8000; //??? (0) //scale center offset?
|
||||
obj.scY = view.getInt16(off+0x3A, true)/0x8000; //??? (4B) //scale center offset?
|
||||
obj.emitterLifetime = view.getUint16(off+0x3C, true); //stop emitting particles after this many frames
|
||||
obj.duration = view.getUint16(off+0x3E, true);
|
||||
|
||||
|
@ -146,8 +214,8 @@ window.spa = function(input) {
|
|||
obj.textureId = view.getUint8(off+0x47, true);
|
||||
obj.unknown21 = view.getUint32(off+0x48, true); //negative number makes grass disappear (1 for grass, smoke)
|
||||
obj.unknown22 = view.getUint32(off+0x4C, true); //some numbers make grass disappear (0x458d00 for grass, 0x74725f60 for smoke)
|
||||
obj.xScaleDelta = view.getUint16(off+0x50, true); //x scale delta for some reason. usually 0
|
||||
obj.yScaleDelta = view.getUint16(off+0x52, true); //y scale delta for some reason. usually 0
|
||||
obj.xScaleDelta = view.getInt16(off+0x50, true)/4096; //x scale delta for some reason. usually 0
|
||||
obj.yScaleDelta = view.getInt16(off+0x52, true)/4096; //y scale delta for some reason. usually 0
|
||||
obj.unknown25 = view.getUint32(off+0x54, true); //FFFFFFFF makes run at half framerate. idk? usually 0
|
||||
off += 0x58;
|
||||
|
||||
|
@ -165,7 +233,8 @@ window.spa = function(input) {
|
|||
unkBase: view.getUint16(off, true)/4096,
|
||||
scaleFrom: view.getUint16(off+2, true)/4096,
|
||||
scaleTo: view.getUint16(off+4, true)/4096,
|
||||
param: view.getUint16(off+6, true),
|
||||
fromZeroTime: view.getUint8(off+6, true)/0xFF, //time to dedicate to an animation from zero size
|
||||
holdTime: view.getUint8(off+7, true)/0xFF, //time to dedicate to holding state at the end.
|
||||
flagParam: view.getUint16(off+8, true),
|
||||
unk4b: view.getUint16(off+10, true),
|
||||
};
|
||||
|
@ -173,7 +242,7 @@ window.spa = function(input) {
|
|||
}
|
||||
if ((obj.flag & ParticleFlags.ColorAnimation) != 0)
|
||||
{
|
||||
obj.ColorAnimation = {
|
||||
obj.colorAnim = {
|
||||
colorFrom: view.getUint16(off, true), //color from
|
||||
colorTo: view.getUint16(off+2, true), //color to (seems to be same as base color)
|
||||
framePct: view.getUint16(off+4, true), //frame pct to become color to (FFFF means always from, 8000 is about the middle)
|
||||
|
@ -278,7 +347,7 @@ window.spa = function(input) {
|
|||
|
||||
var flags = view.getUint16(off+4, true);
|
||||
obj.info = {
|
||||
pal0trans: (flags>>3)&1, //weirdly different format
|
||||
pal0trans: true,//z(flags>>3)&1, //weirdly different format
|
||||
format: ((flags)&7),
|
||||
height: 8 << ((flags>>8)&0xF),
|
||||
width: 8 << ((flags>>4)&0xF),
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
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.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,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -246,10 +246,9 @@ window.nitroRender = new function() {
|
|||
|
||||
gl.uniformMatrix4fv(shader.shadowMatUniform, false, sMat);
|
||||
gl.uniformMatrix4fv(shader.farShadowMatUniform, false, fsMat);
|
||||
gl.uniform1f(shader.lightIntensityUniform, 0.3);
|
||||
|
||||
gl.uniform1f(shader.shadOffUniform, 0.00005+((mobile)?0.0005:0));
|
||||
gl.uniform1f(shader.farShadOffUniform, 0.0005);
|
||||
|
||||
this.resetShadOff();
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, sTex);
|
||||
gl.uniform1i(shader.lightSamplerUniform, 1);
|
||||
|
@ -262,6 +261,12 @@ window.nitroRender = new function() {
|
|||
this.prepareShader();
|
||||
}
|
||||
|
||||
this.resetShadOff = function() {
|
||||
var shader = shaders[1];
|
||||
gl.uniform1f(shader.shadOffUniform, 0.00005+((mobile)?0.0005:0));
|
||||
gl.uniform1f(shader.farShadOffUniform, 0.0005);
|
||||
}
|
||||
|
||||
this.unsetShadowMode = function() {
|
||||
this.nitroShader = shaders[0];
|
||||
gl.useProgram(this.nitroShader);
|
||||
|
@ -384,7 +389,7 @@ function nitroModel(bmd, btx, remap) {
|
|||
}
|
||||
|
||||
if (remap != null) {
|
||||
setTextureRemap(remap)
|
||||
setTextureRemap(remap);
|
||||
}
|
||||
|
||||
if (btx != null) {
|
||||
|
|
|
@ -16,9 +16,39 @@ window.nitroShaders = new (function() {
|
|||
\n\
|
||||
uniform sampler2D uSampler;\n\
|
||||
\n\
|
||||
float indexValue() {\n\
|
||||
int x = int(mod(gl_FragCoord.x, 4.0));\n\
|
||||
int y = int(mod(gl_FragCoord.y, 4.0));\n\
|
||||
int i = (x + y * 4);\n\
|
||||
if (i == 0) return 0.0;\n\
|
||||
else if (i == 1) return 8.0;\n\
|
||||
else if (i == 2) return 2.0;\n\
|
||||
else if (i == 3) return 10.0;\n\
|
||||
else if (i == 4) return 12.0;\n\
|
||||
else if (i == 5) return 4.0;\n\
|
||||
else if (i == 6) return 14.0;\n\
|
||||
else if (i == 7) return 6.0;\n\
|
||||
else if (i == 8) return 3.0;\n\
|
||||
else if (i == 9) return 11.0;\n\
|
||||
else if (i == 10) return 1.0;\n\
|
||||
else if (i == 11) return 9.0;\n\
|
||||
else if (i == 12) return 15.0;\n\
|
||||
else if (i == 13) return 7.0;\n\
|
||||
else if (i == 14) return 13.0;\n\
|
||||
else if (i == 15) return 5.0;\n\
|
||||
}\n\
|
||||
\n\
|
||||
float dither(float color) {\n\
|
||||
float closestColor = (color < 0.5) ? 0.0 : 1.0;\n\
|
||||
float secondClosestColor = 1.0 - closestColor;\n\
|
||||
float d = indexValue();\n\
|
||||
float distance = abs(closestColor - color);\n\
|
||||
return (distance < d) ? closestColor : secondClosestColor;\n\
|
||||
}\n\
|
||||
\n\
|
||||
void main(void) {\n\
|
||||
gl_FragColor = texture2D(uSampler, vTextureCoord)*color;\n\
|
||||
if (gl_FragColor.a == 0.0) discard;\n\
|
||||
if (gl_FragColor.a < 1.0 && (gl_FragColor.a == 0.0 || dither(gl_FragColor.a) == 0.0)) discard;\n\
|
||||
}"
|
||||
|
||||
this.defaultVert = "attribute vec3 aVertexPosition;\n\
|
||||
|
@ -62,20 +92,20 @@ window.nitroShaders = new (function() {
|
|||
\n\
|
||||
uniform sampler2D uSampler;\n\
|
||||
\n\
|
||||
float shadowCompare(sampler2D map, vec2 pos, float compare) {\n\
|
||||
float shadowCompare(sampler2D map, vec2 pos, float compare, float so) {\n\
|
||||
float depth = texture2D(map, pos).r;\n\
|
||||
return step(compare, depth);\n\
|
||||
return smoothstep(compare-so, compare, depth);\n\
|
||||
}\n\
|
||||
\n\
|
||||
float shadowLerp(sampler2D depths, vec2 size, vec2 uv, float compare){\n\
|
||||
float shadowLerp(sampler2D depths, vec2 size, vec2 uv, float compare, float so){\n\
|
||||
vec2 texelSize = vec2(1.0)/size;\n\
|
||||
vec2 f = fract(uv*size+0.5);\n\
|
||||
vec2 centroidUV = floor(uv*size+0.5)/size;\n\
|
||||
\n\
|
||||
float lb = shadowCompare(depths, centroidUV+texelSize*vec2(0.0, 0.0), compare);\n\
|
||||
float lt = shadowCompare(depths, centroidUV+texelSize*vec2(0.0, 1.0), compare);\n\
|
||||
float rb = shadowCompare(depths, centroidUV+texelSize*vec2(1.0, 0.0), compare);\n\
|
||||
float rt = shadowCompare(depths, centroidUV+texelSize*vec2(1.0, 1.0), compare);\n\
|
||||
float lb = shadowCompare(depths, centroidUV+texelSize*vec2(0.0, 0.0), compare, so);\n\
|
||||
float lt = shadowCompare(depths, centroidUV+texelSize*vec2(0.0, 1.0), compare, so);\n\
|
||||
float rb = shadowCompare(depths, centroidUV+texelSize*vec2(1.0, 0.0), compare, so);\n\
|
||||
float rt = shadowCompare(depths, centroidUV+texelSize*vec2(1.0, 1.0), compare, so);\n\
|
||||
float a = mix(lb, lt, f.y);\n\
|
||||
float b = mix(rb, rt, f.y);\n\
|
||||
float c = mix(a, b, f.x);\n\
|
||||
|
@ -89,14 +119,14 @@ window.nitroShaders = new (function() {
|
|||
float dist = max(ldNorm.x, ldNorm.y);\n\
|
||||
\n\
|
||||
if (dist > 0.5) {\n\
|
||||
gl_FragColor = col*mix(vec4(0.5, 0.5, 0.7, 1.0), vec4(1.0, 1.0, 1.0, 1.0), shadowLerp(farLightDSampler, vec2(4096.0, 4096.0), fLightDist.xy, fLightDist.z-farShadOff));\n\
|
||||
gl_FragColor = col*mix(vec4(0.5, 0.5, 0.7, 1.0), vec4(1.0, 1.0, 1.0, 1.0), shadowLerp(farLightDSampler, vec2(4096.0, 4096.0), fLightDist.xy, fLightDist.z-farShadOff, farShadOff*2.0));\n\
|
||||
} else if (dist > 0.4) {\n\
|
||||
float lerp1 = shadowLerp(farLightDSampler, vec2(4096.0, 4096.0), fLightDist.xy, fLightDist.z-farShadOff);\n\
|
||||
float lerp2 = shadowLerp(lightDSampler, vec2(2048.0, 2048.0), lightDist.xy, lightDist.z-shadOff);\n\
|
||||
float lerp1 = shadowLerp(farLightDSampler, vec2(4096.0, 4096.0), fLightDist.xy, fLightDist.z-farShadOff, farShadOff*2.0);\n\
|
||||
float lerp2 = shadowLerp(lightDSampler, vec2(2048.0, 2048.0), lightDist.xy, lightDist.z-shadOff, shadOff*4.0);\n\
|
||||
\n\
|
||||
gl_FragColor = col*mix(vec4(0.5, 0.5, 0.7, 1.0), vec4(1.0, 1.0, 1.0, 1.0), mix(lerp2, lerp1, (dist-0.4)*10.0));\n\
|
||||
} else {\n\
|
||||
gl_FragColor = col*mix(vec4(0.5, 0.5, 0.7, 1.0), vec4(1.0, 1.0, 1.0, 1.0), shadowLerp(lightDSampler, vec2(2048.0, 2048.0), lightDist.xy, lightDist.z-shadOff));\n\
|
||||
gl_FragColor = col*mix(vec4(0.5, 0.5, 0.7, 1.0), vec4(1.0, 1.0, 1.0, 1.0), shadowLerp(lightDSampler, vec2(2048.0, 2048.0), lightDist.xy, lightDist.z-shadOff, shadOff*4.0));\n\
|
||||
}\n\
|
||||
\n\
|
||||
if (gl_FragColor.a == 0.0) discard;\n\
|
||||
|
@ -118,6 +148,7 @@ window.nitroShaders = new (function() {
|
|||
\n\
|
||||
uniform mat4 shadowMat;\n\
|
||||
uniform mat4 farShadowMat;\n\
|
||||
uniform float lightIntensity; \n\
|
||||
\n\
|
||||
varying vec2 vTextureCoord;\n\
|
||||
varying vec4 color;\n\
|
||||
|
@ -133,7 +164,7 @@ window.nitroShaders = new (function() {
|
|||
lightDist = (shadowMat*pos + vec4(1, 1, 1, 0)) / 2.0;\n\
|
||||
fLightDist = (farShadowMat*pos + vec4(1, 1, 1, 0)) / 2.0;\n\
|
||||
vec3 adjNorm = normalize(vec3(uMVMatrix * matStack[int(matrixID)] * vec4(aNormal, 0.0)));\n\
|
||||
float diffuse = 0.7-dot(adjNorm, vec3(0.0, -1.0, 0.0))*0.3;\n\
|
||||
float diffuse = (1.0-lightIntensity)-dot(adjNorm, vec3(0.0, -1.0, 0.0))*lightIntensity;\n\
|
||||
\n\
|
||||
color = aColor*colMult;\n\
|
||||
color = vec4(color.x*diffuse, color.y*diffuse, color.z*diffuse, color.w);\n\
|
||||
|
@ -270,6 +301,7 @@ window.nitroShaders = new (function() {
|
|||
var shadUnif = [
|
||||
["shadowMatUniform", "shadowMat"],
|
||||
["farShadowMatUniform", "farShadowMat"],
|
||||
["lightIntensityUniform", "lightIntensity"],
|
||||
|
||||
["shadOffUniform", "shadOff"],
|
||||
["farShadOffUniform", "farShadOff"],
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue