Merge pull request #5 from riperiperi/gh-pages

Particle Effects, Loop/Sticky collision types
This commit is contained in:
riperiperi authored and GitHub committed 2018-03-26 10:28:13 +01:00
commit 42b11dc1a7
19 files changed
+6575 -3152

No files matched your search

+19 -3
View File
@@ -42,7 +42,14 @@ window.cameraIngame = function(kart) {
camNormal[2] += (kart.kartNormal[2]-camNormal[2])*0.075;
vec3.normalize(camNormal, camNormal);
camAngle += dirDiff(kart.physicalDir+kart.driftOff/2, camAngle)*0.075;
if (kart.physBasis != null) {
var kartA = kart.physicalDir+kart.driftOff/2;
var forward = [Math.sin(kartA), 0, -Math.cos(kartA)];
vec3.transformMat4(forward, forward, kart.physBasis.mat);
camAngle += dirDiff(Math.atan2(forward[0], -forward[2]), camAngle)*0.075;
} else {
camAngle += dirDiff(kart.physicalDir+kart.driftOff/2, camAngle)*0.075;
}
camAngle = fixDir(camAngle);
boostOff += (((kart.boostNorm+kart.boostMT > 0)?5:0) - boostOff)*0.075
@@ -52,14 +59,23 @@ 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;
}
function buildBasis() {
//order y, x, z
var basis = gramShmidt(camNormal, [Math.cos(camAngle), 0, Math.sin(camAngle)], [Math.sin(camAngle), 0, -Math.cos(camAngle)]);
var kart = thisObj.kart;
var forward = [Math.sin(camAngle), 0, -Math.cos(camAngle)];
var side = [Math.cos(camAngle), 0, Math.sin(camAngle)];
/*
if (kart.physBasis != null) {
vec3.transformMat4(forward, forward, kart.physBasis.mat);
vec3.transformMat4(side, side, kart.physBasis.mat);
}
*/
var basis = gramShmidt(camNormal, side, forward);
var temp = basis[0];
basis[0] = basis[1];
basis[1] = temp; //todo: cleanup
+1 -1
View File
@@ -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) {
+1
View File
@@ -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;
}
+16 -14
View File
@@ -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},
{},
{},
{},
+33 -4
View File
@@ -19,6 +19,7 @@ window.controlRaceCPU = function(nkm) {
}
this.fetchInput = fetchInput;
this.setRouteID = setRouteID;
var battleMode = (nkm.sections["EPAT"] == null);
@@ -53,11 +54,30 @@ window.controlRaceCPU = function(nkm) {
var dist = vec3.dot(destNorm, kart.pos) + destConst;
if (dist < ePoi.pointSize) advancePoint();
if (ePath.loop) debugger;
destPoint = vec3.add([], ePoi.pos, vec3.scale([], vec3.lerp([], posOffset, destOff, offTrans), ePoi.pointSize));
var dirToPt = Math.atan2(destPoint[0]-kart.pos[0], kart.pos[2]-destPoint[2]);
var diff = dirDiff(dirToPt, kart.physicalDir);
var physDir = kart.physicalDir;
if (kart.physBasis) {
if (kart.physBasis.loop) {
return {
accel: true, //x
decel: false, //z
drift: false, //s
item: false, //a
//-1 to 1, intensity.
turn: 0,
airTurn: 0 //air excitebike turn, doesn't really have much function
};
}
var forward = [Math.sin(physDir), 0, -Math.cos(physDir)];
vec3.transformMat4(forward, forward, kart.physBasis.mat);
var physDir = Math.atan2(forward[0], -forward[2]);
}
var diff = dirDiff(dirToPt, physDir);
var turn = Math.min(Math.max(-1, (diff*3)), 1);
offTrans += 1/240;
@@ -94,6 +114,11 @@ window.controlRaceCPU = function(nkm) {
}
function setRouteID(routeID) {
ePoiInd = routeID-1
advancePoint();
}
function advancePoint() {
if (++ePoiInd < ePath.startInd+ePath.pathLen) {
//next within this path
@@ -102,10 +127,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];
+10 -3
View File
@@ -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;
@@ -30,20 +31,25 @@ window.IngameRes = function(rom) {
"koura_w" /*blue shell item rep*/, "f_box", "killer" /*bullet bill*/
]
//order
//donkey, toad, bowser?, luigi, mario, peach, wario, yoshi, daisy, waluigi, dry bones (karon), robo, heyho
var toSoundOff = [
4, 0, 1, 2, 5, 6, 7, 3, 10, 8, 9, 11, 12
];
var charNames = [
"mario", "donkey", "kinopio", "koopa", "peach", "wario", "yoshi", "luigi", "karon", "daisy", "waluigi", "robo", "heyho"
]
];
var charAbbrv = [
"MR", "DK", "KO", "KP", "PC", "WR", "YS", "LG", "KA", "DS", "WL", "RB", "HH"
]
];
var tireName = ["kart_tire_L", "kart_tire_M", "kart_tire_S"];
var characters = [];
var karts = [];
var test = new spa(r.MainEffect.getFile("RaceEffect.spa"));
loadItems();
loadTires();
@@ -75,6 +81,7 @@ window.IngameRes = function(rom) {
loseA: new nsbca(r.KartModelSub.getFile(base+"_lose.nsbca")),
spinA: new nsbca(r.KartModelSub.getFile(base+"_spin.nsbca")),
winA: new nsbca(r.KartModelSub.getFile(base+"_win.nsbca")),
sndOff: toSoundOff[ind]*14,
}
characters[ind] = obj;
return characters[ind];
+11 -5
View File
@@ -165,6 +165,11 @@ window.courseScene = function(mainNarc, texNarc, music, chars, options, gameRes)
vec3.scale(targ, targ, 1/1024);
mat4.mul(scn.shadMat, mat4.ortho(mat4.create(), targ[0]-shadres, targ[0]+shadres, targ[1]-shadres, targ[1]+shadres, -targ[2]-2.5, -targ[2]+2.5), scn.lightMat);
var places = [];
for (var i=0; i<scn.karts.length; i++) { places.push(scn.karts[i]); }
places.sort(function(a, b) {return b.getPosition() - a.getPosition()});
for (var i=0; i<places.length; i++) { places[i].placement = i+1; };
for (var i=0; i<scn.karts.length; i++) {
var ent = scn.karts[i];
if (ent.active) ent.update(scn);
@@ -291,9 +296,9 @@ window.courseScene = function(mainNarc, texNarc, music, chars, options, gameRes)
// the thresholds for different win sounds and music
// thresh, goalsound, goalmusic, goalpostmusic
var finishPercents = [
[0, 66, 46, 58],
[0.5, 66, 47, 56],
[1.1, 67, 48, 57]
[0, 66, 46, 58, 9],
[0.5, 66, 47, 56, 10],
[1.1, 67, 48, 57, 11]
]
function lapAdvance(kart) {
@@ -309,20 +314,21 @@ window.courseScene = function(mainNarc, texNarc, music, chars, options, gameRes)
else if (kart.lapNumber == 4) {
var finishTuple = [];
for (var i=0; i<finishPercents.length; i++) {
if (finishPercents[i][0] > winPercent) continue;
finishTuple = finishPercents[i];
if (finishPercents[i][0] >= winPercent) break;
}
kart.controller = new controlRaceCPU(scn.nkm, {});
kart.controller.setKart(kart);
kart.anim.setAnim(winPercent>0.5?kart.charRes.LoseA:kart.charRes.winA);
kart.anim.setAnim(winPercent>0.5?kart.charRes.loseA:kart.charRes.winA);
kart.animMode = "raceEnd";
scn.camera = (new cameraSpectator(kart, scn));
nitroAudio.playSound(finishTuple[1], {volume:2}, 0);
nitroAudio.playSound(finishTuple[2], {volume:2}, null);
nitroAudio.instaKill(scn.musicPlayer);
kart.playCharacterSound(finishTuple[4], 2);
musicRestartTimer = 0;
musicRestart = 7.5*60;
musicRestartType = 1;
+1 -1
View File
@@ -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
+1
View File
@@ -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;
+266 -31
View File
@@ -21,6 +21,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
var params = scene.gameRes.kartPhys.karts[kartN];
var offsets = scene.gameRes.kartOff.karts[kartN];
this.wheelClass = (offsets.name[10] == "L")?2:((offsets.name[10] == "M")?1:0);
this.local = controller.local;
this.active = true;
@@ -66,12 +67,20 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
this.drawWheels = drawWheels;
this.drawChar = drawChar;
this.getPosition = getPosition;
this.playCharacterSound = playCharacterSound;
this.trackAttach = null; //a normal for the kart to attach to (loop)
this.boostMT = 0;
this.boostNorm = 0;
this.kartColVel = vec3.create();
this.kartColTimer = 0;
this.kartWallTimer = 0;
this.charSoundTimer = 0;
this.placement = 0;
this.lastPlacement = 0;
var charRes = scene.gameRes.getChar(charN);
var kartRes = scene.gameRes.getKart(kartN);
@@ -95,14 +104,24 @@ 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.OOB = 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];
var checkpoints = nkm.sections["CPOI"].entries;
var respawns = nkm.sections["CPOI"].entries;
var respawns = nkm.sections["KTPJ"].entries;
var futureChecks = [1];
var hitGroundAnim = [ //length 13, on y axis
@@ -193,6 +212,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], [k.wheelClass*(i-2.5)*-2, (-params.colRadius)-k.wheelClass*2, 0]), 1/16);
}
}
var scale = 16;
@@ -262,7 +285,20 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
drawChar(view, pMatrix);
}
k.lWheelParticle = null;
function update(scene) {
if (k.placement != k.lastPlacement) {
if (k.placement < k.lastPlacement) {
if (k.charSoundTimer == 0) {
playCharacterSound(5);
k.charSoundTimer = 60;
}
}
k.lastPlacement = k.placement;
}
var lastPos = vec3.clone(k.pos);
updateMat = true;
@@ -314,7 +350,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 +374,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,25 +386,55 @@ 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
if (k.OOB > 0) {
playCharacterSound(0);
var current = checkpoints[k.checkPointNumber];
var respawn = respawns[current.respawn];
k.physicalDir = (180-respawn.angle[1])*(Math.PI/180);
k.angle = k.physicalDir;
k.speed = 0;
k.vel = vec3.create();
k.pos = vec3.clone(respawn.pos);
vec3.add(k.pos, k.pos, [0,16,0]);
if (k.controller.setRouteID != null) k.controller.setRouteID(respawn.id1);
k.OOB = 0;
}
var groundEffect = 0;
if (lastCollided != -1) {
groundEffect = MKDS_COLTYPE.PHYS_MAP[lastCollided];
@@ -402,6 +472,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 +505,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 +542,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 +563,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;
@@ -562,6 +640,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
if (!onGround) {
this.kartTargetNormal = [0, 1, 0];
if (k.physBasis != null) vec3.transformMat4(this.kartTargetNormal,this.kartTargetNormal,k.physBasis.mat);
vec3.add(k.vel, k.vel, k.gravity)
if (k.ylock >= 0) {
ylvel += k.gravity[1];
@@ -584,6 +663,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
if (k.kartColTimer > 0) k.kartColTimer--;
if (k.kartWallTimer > 0) k.kartWallTimer--;
if (k.charSoundTimer > 0) k.charSoundTimer--;
wheelTurn += k.speed/16;
wheelTurn = fixDir(wheelTurn);
@@ -602,7 +683,15 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
var steps = 0;
var remainingT = 1;
var velSeg = vec3.clone(k.vel);
var baseVel = k.vel;
if (k.physBasis != null) {
if (k.physBasis.time-- < 0) exitBasis();
else {
baseVel = vec3.transformMat4([], baseVel, k.physBasis.mat);
k.vel[1] = -1;
}
}
var velSeg = vec3.clone(baseVel);
var posSeg = vec3.clone(k.pos);
var ignoreList = [];
while (steps++ < 10 && remainingT > 0.01) {
@@ -611,7 +700,10 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
colResponse(posSeg, velSeg, result, ignoreList)
remainingT -= result.t;
if (remainingT > 0.01) {
velSeg = vec3.scale(vec3.create(), k.vel, remainingT);
if (k.physBasis != null) {
baseVel = vec3.transformMat4([], k.vel, k.physBasis.mat);
}
velSeg = vec3.scale(vec3.create(), baseVel, remainingT);
}
} else {
vec3.add(posSeg, posSeg, velSeg);
@@ -642,6 +734,43 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
positionChanged(lastPos, k.pos);
}
function playCharacterSound(sound, volume) {
//0 - hit
//1 - hit spin
//2 - hit ?? hit grnd
//3 - hit banana? race start?
//4 - hit spin?
//5 - good pass?
//6 - good OK!
//7 - use item
//8 - hit someone?
//9 = win
//10 = alright
//11 = bad
//12 = good record
//13 = bad record
if (volume == null) volume = 1;
nitroAudio.playSound(sound + charRes.sndOff, {volume: 2*volume}, 2, k);
}
function clearWheelParticles(prio) {
for (var 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 (var i=0; i<2; i++) {
k.wheelParticles[i].setEmitter(id, prio);
}
}
function genFutureChecks() {
//all future points that
var chosen = {}
@@ -661,6 +790,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,11 +815,21 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
k.lapNumber++;
k.checkPointNumber = 0;
k.passedKTP2 = 0;
futureChecks = [1];
scene.lapAdvance(k);
}
}
}
function getPosition() {
if (futureChecks.length == 0) return 0;
var check = checkpoints[futureChecks[0]];
var dist = vec2.sub([], [check.x1, check.z1], [k.pos[0], k.pos[2]]);
var dot = vec2.dot(dist, [check.sinus, check.cosinus]);
return k.checkPointNumber + (1-(Math.abs(dot)/(0xFFFF))) + k.lapNumber*checkpoints.length;
}
function forwardCrossedKTP(ktp, oldPos, pos) {
var distOld = vec2.sub([], [ktp.pos[0], ktp.pos[2]], [oldPos[0], oldPos[2]]);
var dist = vec2.sub([], [ktp.pos[0], ktp.pos[2]], [pos[0], pos[2]]);
@@ -768,7 +908,13 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
function buildBasis() {
//order y, x, z
var dir = k.physicalDir+k.driftOff+(Math.sin((COLBOUNCE_TIME-k.kartColTimer)/3)*(Math.PI/6)*(k.kartColTimer/COLBOUNCE_TIME));
var basis = gramShmidt(k.kartNormal, [Math.cos(dir), 0, Math.sin(dir)], [Math.sin(dir), 0, -Math.cos(dir)]);
var forward = [Math.sin(dir), 0, -Math.cos(dir)];
var side = [Math.cos(dir), 0, Math.sin(dir)];
if (k.physBasis != null) {
vec3.transformMat4(forward, forward, k.physBasis.mat);
vec3.transformMat4(side, side, k.physBasis.mat);
}
var basis = gramShmidt(k.kartNormal, side, forward);
var temp = basis[0];
basis[0] = basis[1];
basis[1] = temp; //todo: cleanup
@@ -781,6 +927,56 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
function enterBasis(normal) {
//establish a new basis for the kart velocity based on this normal.
//used by looping and sticky track surface types.
//first let's get the forward direction in our current basis
var dir = k.angle;
var forward, side;
if (k.physBasis != null) {
forward = vec3.transformMat4([], [- Math.sin(dir), 0, Math.cos(dir)], k.physBasis.mat);
side = vec3.transformMat4([], [Math.cos(dir), 0, Math.sin(dir)], k.physBasis.mat);
} else {
forward = [-Math.sin(dir), 0, Math.cos(dir)];
side = [Math.cos(dir), 0, Math.sin(dir)];
}
var basis = gramShmidt(normal, side, forward);
var temp = basis[0];
basis[0] = basis[1];
basis[1] = temp; //todo: cleanup
var m4 = [
basis[0][0], basis[0][1], basis[0][2], 0,
basis[1][0], basis[1][1], basis[1][2], 0,
basis[2][0], basis[2][1], basis[2][2], 0,
0, 0, 0, 1
];
k.physicalDir = dirDiff(k.physicalDir, k.angle);
k.angle = 0; //our front direction is now aligned with z.
k.vel = [Math.sin(k.angle)*k.speed, k.vel[1], -Math.cos(k.angle)*k.speed];
k.physBasis = {
mat: m4,
inv: mat4.invert([], m4),
time: 15,
loop: false
};
}
function exitBasis() {
//return to a normal y up, z forward basis.
var v = vec3.transformMat4([], k.vel, k.physBasis.mat);
k.physicalDir = dirDiff(k.physicalDir, k.angle);
k.angle = Math.atan2(v[0], -v[2]);
k.physicalDir += k.angle;
k.vel = v;
k.physBasis = null;
}
function sndUpdate(view) {
k.soundProps.pos = vec3.transformMat4([], k.pos, view);
if (k.soundProps.lastPos != null) k.soundProps.vel = vec3.sub([], k.soundProps.pos, k.soundProps.lastPos);
@@ -805,6 +1001,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,25 +1016,41 @@ 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);
var n = vec3.normalize([], dat.normal);
var an = n;
if (k.physBasis != null) {
an = vec3.transformMat4([], n, k.physBasis.inv);
}
var gravS = Math.sqrt(vec3.dot(k.gravity, k.gravity));
var angle = Math.acos(vec3.dot(vec3.scale(vec3.create(), k.gravity, -1/gravS), n));
var adjustPos = true;
if (colType == MKDS_COLTYPE.OOB || colType == MKDS_COLTYPE.FALL) {
k.OOB = 1;
}
if (MKDS_COLTYPE.GROUP_WALL.indexOf(colType) != -1) { //wall
//sliding plane, except normal is transformed to be entirely on the xz plane (cannot ride on top of wall, treated as vertical)
var xz = Math.sqrt(n[0]*n[0]+n[2]*n[2])
var adjN = [n[0]/xz, 0, n[2]/xz]
var xz = Math.sqrt(an[0]*an[0]+an[2]*an[2])
var adjN = [an[0]/xz, 0, an[2]/xz]
var proj = vec3.dot(k.vel, adjN);
if (proj < -1) {
if (lastColSounds.hit != null) nitroAudio.playSound(lastColSounds.hit, {volume:1}, 0, k)
if (k.kartWallTimer == 0) {
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));
}
k.kartWallTimer = 15;
}
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), adjN, proj));
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), adjN, proj));
//convert back to angle + speed to keep change to kart vel
@@ -846,13 +1063,31 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
k.boostNorm = BOOSTTIME;
}
var stick = (colType == MKDS_COLTYPE.STICKY || colType == MKDS_COLTYPE.LOOP);
if (k.vel[1] > 0) k.vel[1] = 0;
var proj = vec3.dot(k.vel, n);
if (proj < -4 && k.vel[1] < -2) { proj -= 1.5; }
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), n, proj));
var proj = vec3.dot(k.vel, an);
if (!stick && proj < -4 && k.vel[1] < -2) { proj -= 1.5; }
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), an, proj));
if (stick) {
enterBasis(dat.pNormal);
k.physBasis.loop = colType == MKDS_COLTYPE.LOOP;
} else {
if (k.physBasis != null)
exitBasis();
}
k.kartTargetNormal = dat.pNormal;
if (!onGround) {
console.log("ground: "+colType+", "+colBE);
if (change) {
var particle = colParticle(lastCollided, colBE);
if (particle == null)
clearWheelParticles(0);
else
setWheelParticles(particle, 0);
}
if (!onGround && !stick) {
groundAnim = 0;
if (lastColSounds.land != null) nitroAudio.playSound(lastColSounds.land, {volume:1}, 0, k)
}
+98 -29
View File
@@ -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 = [];
for (let i=0; i<particleCount; i++) {
this.particles[i] = readParticle(view, offset);
offset = this.particles[i].nextOff;
t.particles = [];
for (var i=0; i<particleCount; i++) {
t.particles[i] = readParticle(view, offset);
t.particles[i].parent = t;
offset = t.particles[i].nextOff;
}
}
offset = firstTexOffset;
this.particleTextures = [];
for (let i=0; i<particleTexCount; i++) {
this.particleTextures[i] = readParticleTexture(view, offset);
offset = this.particleTextures[i].nextOff;
t.particleTextures = [];
for (var i=0; i<particleTexCount; i++) {
t.particleTextures[i] = readParticleTexture(view, offset);
offset = t.particleTextures[i].nextOff;
}
//window.debugParticle = true;
if (window.debugParticle) {
for (let i=0; i<particleCount; i++) {
for (var 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)
@@ -203,7 +272,7 @@ window.spa = function(input) {
if ((obj.flag & ParticleFlags.TextureAnimation) != 0)
{
var textures = [];
for (let i=0; i<8; i++) textures[i] = view.getUint8(off+i);
for (var i=0; i<8; i++) textures[i] = view.getUint8(off+i);
obj.texAnim = {
textures: textures,
frames: view.getUint8(off+8),
@@ -215,7 +284,7 @@ window.spa = function(input) {
if ((obj.flag & ParticleFlags.Bit16) != 0)
{
obj.Bit16 = [];
for (let i=0; i<20; i++) obj.Bit16[i] = view.getUint8(off+i);
for (var i=0; i<20; i++) obj.Bit16[i] = view.getUint8(off+i);
off += 20;
}
if ((obj.flag & ParticleFlags.Gravity) != 0)
@@ -239,31 +308,31 @@ window.spa = function(input) {
{
//seems to be 4 int 16s typically in some kind of pattern.
obj.Bit25 = [];
for (let i=0; i<8; i++) obj.Bit25[i] = view.getUint8(off+i);
for (var i=0; i<8; i++) obj.Bit25[i] = view.getUint8(off+i);
off += 8;
}
if ((obj.flag & ParticleFlags.Bit26) != 0)
{
obj.Bit26 = [];
for (let i=0; i<16; i++) obj.Bit26[i] = view.getUint8(off+i);
for (var i=0; i<16; i++) obj.Bit26[i] = view.getUint8(off+i);
off += 16;
}
if ((obj.flag & ParticleFlags.Bit27) != 0)
{
obj.Bit27 = [];
for (let i=0; i<4; i++) obj.Bit27[i] = view.getUint8(off+i);
for (var i=0; i<4; i++) obj.Bit27[i] = view.getUint8(off+i);
off += 4;
}
if ((obj.flag & ParticleFlags.Bit28) != 0)
{
obj.Bit28 = [];
for (let i=0; i<8; i++) obj.Bit28[i] = view.getUint8(off+i);
for (var i=0; i<8; i++) obj.Bit28[i] = view.getUint8(off+i);
off += 8;
}
if ((obj.flag & ParticleFlags.Bit29) != 0)
{
obj.Bit29 = [];
for (let i=0; i<16; i++) obj.Bit29[i] = view.getUint8(off+i);
for (var i=0; i<16; i++) obj.Bit29[i] = view.getUint8(off+i);
off += 16;
}
@@ -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),
+20 -20
View File
@@ -2,27 +2,27 @@
* @fileoverview gl-matrix - High performance matrix and vector operations
* @author Brandon Jones
* @author Colin MacKenzie IV
* @version 2.2.1
* @version 2.4.0
*/
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
(function(e){"use strict";var t={};typeof exports=="undefined"?typeof define=="function"&&typeof define.amd=="object"&&define.amd?(t.exports={},define(function(){return t.exports})):t.exports=typeof window!="undefined"?window:e:t.exports=exports,function(e){if(!t)var t=1e-6;if(!n)var n=typeof Float32Array!="undefined"?Float32Array:Array;if(!r)var r=Math.random;var i={};i.setMatrixArrayType=function(e){n=e},typeof e!="undefined"&&(e.glMatrix=i);var s=Math.PI/180;i.toRadian=function(e){return e*s};var o={};o.create=function(){var e=new n(2);return e[0]=0,e[1]=0,e},o.clone=function(e){var t=new n(2);return t[0]=e[0],t[1]=e[1],t},o.fromValues=function(e,t){var r=new n(2);return r[0]=e,r[1]=t,r},o.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e},o.set=function(e,t,n){return e[0]=t,e[1]=n,e},o.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e},o.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e},o.sub=o.subtract,o.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e},o.mul=o.multiply,o.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e},o.div=o.divide,o.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e},o.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e},o.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e},o.scaleAndAdd=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e},o.distance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1];return Math.sqrt(n*n+r*r)},o.dist=o.distance,o.squaredDistance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1];return n*n+r*r},o.sqrDist=o.squaredDistance,o.length=function(e){var t=e[0],n=e[1];return Math.sqrt(t*t+n*n)},o.len=o.length,o.squaredLength=function(e){var t=e[0],n=e[1];return t*t+n*n},o.sqrLen=o.squaredLength,o.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e},o.normalize=function(e,t){var n=t[0],r=t[1],i=n*n+r*r;return i>0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},o.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},o.cross=function(e,t,n){var r=t[0]*n[1]-t[1]*n[0];return e[0]=e[1]=0,e[2]=r,e},o.lerp=function(e,t,n,r){var i=t[0],s=t[1];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e},o.random=function(e,t){t=t||1;var n=r()*2*Math.PI;return e[0]=Math.cos(n)*t,e[1]=Math.sin(n)*t,e},o.transformMat2=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i,e[1]=n[1]*r+n[3]*i,e},o.transformMat2d=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i+n[4],e[1]=n[1]*r+n[3]*i+n[5],e},o.transformMat3=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[3]*i+n[6],e[1]=n[1]*r+n[4]*i+n[7],e},o.transformMat4=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[4]*i+n[12],e[1]=n[1]*r+n[5]*i+n[13],e},o.forEach=function(){var e=o.create();return function(t,n,r,i,s,o){var u,a;n||(n=2),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u<a;u+=n)e[0]=t[u],e[1]=t[u+1],s(e,e,o),t[u]=e[0],t[u+1]=e[1];return t}}(),o.str=function(e){return"vec2("+e[0]+", "+e[1]+")"},typeof e!="undefined"&&(e.vec2=o);var u={};u.create=function(){var e=new n(3);return e[0]=0,e[1]=0,e[2]=0,e},u.clone=function(e){var t=new n(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t},u.fromValues=function(e,t,r){var i=new n(3);return i[0]=e,i[1]=t,i[2]=r,i},u.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e},u.set=function(e,t,n,r){return e[0]=t,e[1]=n,e[2]=r,e},u.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e},u.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e},u.sub=u.subtract,u.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e},u.mul=u.multiply,u.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e},u.div=u.divide,u.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e[2]=Math.min(t[2],n[2]),e},u.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e[2]=Math.max(t[2],n[2]),e},u.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e},u.scaleAndAdd=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e[2]=t[2]+n[2]*r,e},u.distance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2];return Math.sqrt(n*n+r*r+i*i)},u.dist=u.distance,u.squaredDistance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2];return n*n+r*r+i*i},u.sqrDist=u.squaredDistance,u.length=function(e){var t=e[0],n=e[1],r=e[2];return Math.sqrt(t*t+n*n+r*r)},u.len=u.length,u.squaredLength=function(e){var t=e[0],n=e[1],r=e[2];return t*t+n*n+r*r},u.sqrLen=u.squaredLength,u.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e},u.normalize=function(e,t){var n=t[0],r=t[1],i=t[2],s=n*n+r*r+i*i;return s>0&&(s=1/Math.sqrt(s),e[0]=t[0]*s,e[1]=t[1]*s,e[2]=t[2]*s),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},u.cross=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2];return e[0]=i*a-s*u,e[1]=s*o-r*a,e[2]=r*u-i*o,e},u.lerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e[2]=o+r*(n[2]-o),e},u.random=funLine truncated
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{var r=n();for(var a in r)("object"==typeof exports?exports:t)[a]=r[a]}}(this,function(){return function(t){function n(a){if(r[a])return r[a].exports;var e=r[a]={i:a,l:!1,exports:{}};return t[a].call(e.exports,e,e.exports,n),e.l=!0,e.exports}var r={};return n.m=t,n.c=r,n.d=function(t,r,a){n.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:a})},n.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(r,"a",r),r},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=4)}([function(t,n,r){"use strict";function a(t){n.ARRAY_TYPE=i=t}function e(t){return t*s}function u(t,n){return Math.abs(t-n)<=o*Math.max(1,Math.abs(t),Math.abs(n))}Object.defineProperty(n,"__esModule",{value:!0}),n.setMatrixArrayType=a,n.toRadian=e,n.equals=u;var o=n.EPSILON=1e-6,i=n.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,s=(n.RANDOM=Math.random,Math.PI/180)},function(t,n,r){"use strict";function a(){var t=new g.ARRAY_TYPE(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function e(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t}function u(t){var n=new g.ARRAY_TYPE(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n}function o(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t}function i(t,n,r,a,e,u,o,i,s){var c=new g.ARRAY_TYPE(9);return c[0]=t,c[1]=n,c[2]=r,c[3]=a,c[4]=e,c[5]=u,c[6]=o,c[7]=i,c[8]=s,c}function s(t,n,r,a,e,u,o,i,s,c){return t[0]=n,t[1]=r,t[2]=a,t[3]=e,t[4]=u,t[5]=o,t[6]=i,t[7]=s,t[8]=c,t}function c(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function f(t,n){if(t===n){var r=n[1],a=n[2],e=n[5];t[1]=n[3],t[2]=n[6],t[3]=r,t[5]=n[7],t[6]=a,t[7]=e}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t}function M(t,n){var r=n[0],a=n[1],e=n[2],u=n[3],o=n[4],i=n[5],s=n[6],c=n[7],f=n[8],M=f*o-i*c,h=-f*u+i*s,l=c*u-o*s,v=r*M+a*h+e*l;return v?(v=1/v,t[0]=M*v,t[1]=(-f*a+e*c)*v,t[2]=(i*a-e*o)*v,t[3]=h*v,t[4]=(f*r-e*s)*v,t[5]=(-i*r+e*u)*v,t[6]=l*v,t[7]=(-c*r+a*s)*v,t[8]=(o*r-a*u)*v,t):null}function h(t,n){var r=n[0],a=n[1],e=n[2],u=n[3],o=n[4],i=n[5],s=n[6],c=n[7],f=n[8];return t[0]=o*f-i*c,t[1]=e*c-a*f,t[2]=a*i-e*o,t[3]=i*s-u*f,t[4]=r*f-e*s,t[5]=e*u-r*i,t[6]=u*c-o*s,t[7]=a*s-r*c,t[8]=r*o-a*u,t}function l(t){var n=t[0],r=t[1],a=t[2],e=t[3],u=t[4],o=t[5],i=t[6],s=t[7],c=t[8];return n*(c*u-o*s)+r*(-c*e+o*i)+a*(s*e-u*i)}function v(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=n[6],f=n[7],M=n[8],h=r[0],l=r[1],v=r[2],d=r[3],b=r[4],m=r[5],p=r[6],P=r[7],E=r[8];return t[0]=h*a+l*o+v*c,t[1]=h*e+l*i+v*f,t[2]=h*u+l*s+v*M,t[3]=d*a+b*o+m*c,t[4]=d*e+b*i+m*f,t[5]=d*u+b*s+m*M,t[6]=p*a+P*o+E*c,t[7]=p*e+P*i+E*f,t[8]=p*u+P*s+E*M,t}function d(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=n[6],f=n[7],M=n[8],h=r[0],l=r[1];return t[0]=a,t[1]=e,t[2]=u,t[3]=o,t[4]=i,t[5]=s,t[6]=h*a+l*o+c,t[7]=h*e+l*i+f,t[8]=h*u+l*s+M,t}function b(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=n[6],f=n[7],M=n[8],h=Math.sin(r),l=Math.cos(r);return t[0]=l*a+h*o,t[1]=l*e+h*i,t[2]=l*u+h*s,t[3]=l*o-h*a,t[4]=l*i-h*e,t[5]=l*s-h*u,t[6]=c,t[7]=f,t[8]=M,t}function m(t,n,r){var a=r[0],e=r[1];return t[0]=a*n[0],t[1]=a*n[1],t[2]=a*n[2],t[3]=e*n[3],t[4]=e*n[4],t[5]=e*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t}function p(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t}function P(t,n){var r=Math.sin(n),a=Math.cos(n);return t[0]=a,t[1]=r,t[2]=0,t[3]=-r,t[4]=a,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function E(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function O(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t}function x(t,n){var r=n[0],a=n[1],e=n[2],u=n[3],o=r+r,i=a+a,s=e+e,c=r*o,f=a*o,M=a*i,h=e*o,l=e*i,v=e*s,d=u*o,b=u*i,m=u*s;return t[0]=1-M-v,t[3]=f-m,t[6]=h+b,t[1]=f+m,t[4]=1-c-v,t[7]=l-d,t[2]=h-b,t[5]=l+d,t[8]=1-c-M,t}function A(t,n){var r=n[0],a=n[1],e=n[2],u=n[3],o=n[4],i=n[5],s=n[6],c=n[7],f=n[8],M=n[9],h=n[10],l=n[11],v=n[12],d=n[13],b=n[14],m=n[15],p=r*i-a*o,P=r*s-e*o,E=r*c-u*o,O=a*s-e*i,x=a*c-u*i,A=e*c-u*s,q=f*d-M*v,y=f*b-h*v,w=f*m-l*v,R=M*b-h*d,L=M*m-l*d,S=h*m-l*b,_=p*S-P*L+E*R+O*w-x*y+A*q;return _?(_=1/_,t[0]=(i*S-s*L+c*R)*_,t[1]=(s*w-o*S-c*y)*_,t[2]=(o*L-i*w+c*q)*_,t[3]=(e*L-a*S-u*R)*_,t[4]=(r*S-e*w+u*y)*_,t[5]=(a*w-r*L-u*q)*_,t[6]=(d*A-b*x+m*O)*_,t[7]=(b*E-v*A-m*P)*_,t[8]=(v*x-d*E+m*p)*_,t):null}function q(t,n,r){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/r,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t}function y(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"}function w(t){return Math.sqrt(Math.pLine truncated
+5594 -2998
View File
File diff suppressed because it is too large. Load diff
+25 -25
View File
@@ -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);
}
}
+173
View File
@@ -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) {
}
}
+251
View File
@@ -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;
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.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,
};
}
}
+9 -4
View File
@@ -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) {
+45 -13
View File
@@ -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"],
+1 -1
View File
@@ -1 +1 @@
<head> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="mkjs"> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, user-scalable=no"> <!-- Client Code Includes --> <script src="code/engine/largeSphereCollider.js"></script> <script src="code/engine/collisionTypes.js"></script> <script src="code/engine/mkdsConst.js"></script> <script src="code/engine/ingameRes.js"></script> <script src="code/engine/itemController.js"></script> <script src="code/IndexedDBShim.min.js"></script> <script src="code/engine/storage/fileStore.js"></script> <script src="code/engine/controls/controlDefault.js"></script> <script src="code/engine/controls/controlRaceCPU.js"></script> <script src="code/engine/controls/controlNetwork.js"></script> <script src="code/engine/cameras/cameraIngame.js"></script> <script src="code/engine/cameras/cameraSpectator.js"></script> <script src="code/engine/cameras/cameraIntro.js"></script> <script src="code/engine/scenes/sceneDrawer.js"></script> <script src="code/engine/scenes/courseScene.js"></script> <script src="code/engine/scenes/clientScene.js"></script> <script src="code/engine/scenes/singleScene.js"></script> <script src="code/ui/race3DUI.js"></script> <script src="code/formats/net/netKart.js"></script> <script src="code/entities/objDatabase.js"></script> <script src="code/entities/trafficCar.js"></script> <script src="code/entities/water.js"></script> <script src="code/entities/itembox.js"></script> <script src="code/entities/decorations.js"></script> <script src="code/entities/rotatingGear.js"></script> <script src="code/entities/bowserPlatforms.js"></script> <script src="code/entities/soundMaker.js"></script> <script src="code/particles/itemboxShard.js"></script> <script src="code/entities/shell.js"></script> <script src="code/entities/kart.js"></script> <script src="code/formats/kcl.js"></script> <script src="code/formats/ndsFS.js"></script> <script src="code/formats/nitro.js"></script> <script src="code/formats/nsbtx.js"></script> <script src="code/formats/nsbmd.js"></script> <script src="code/formats/nsbta.js"></script> <script src="code/formats/nsbca.js"></script> <script src="code/formats/nsbtp.js"></script> <script src="code/formats/nftr.js"></script> <script src="code/formats/narc.js"></script> <script src="code/formats/lz77.js"></script> <script src="code/formats/spa.js"></script> <script src="code/formats/nkm.js"></script> <script src="code/formats/kartphysicalparam.js"></script> <script src="code/formats/kartoffsetdata.js"></script> <script src="code/render/nitroRender.js"></script> <script src="code/render/nitroShaders.js"></script> <script src="code/render/shadowRender.js"></script> <script src="code/render/nitroAnimator.js"></script> <script src="code/glmatrix/gl-matrix.js"></script> <script src="code/formats/sdat.js"></script> <script src="code/formats/swav.js"></script> <script src="code/formats/swar.js"></script> <script src="code/formats/sbnk.js"></script> <script src="code/formats/sseq.js"></script> <script src="code/formats/ssar.js"></script> <script src="code/audio/sseqPlayer.js"></script> <script src="code/audio/nitroAudio.js"></script> <!-- Inline code (because that's always a good idea) --> <script> var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; window.requestAnimationFrame = requestAnimationFrame; var files = {}; var fileQuota; var filesLoaded = 0; var mobile = (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mLine truncated
<head> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="mkjs"> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, user-scalable=no"> <!-- Client Code Includes --> <script src="code/engine/largeSphereCollider.js"></script> <script src="code/engine/collisionTypes.js"></script> <script src="code/engine/mkdsConst.js"></script> <script src="code/engine/ingameRes.js"></script> <script src="code/engine/itemController.js"></script> <script src="code/IndexedDBShim.min.js"></script> <script src="code/engine/storage/fileStore.js"></script> <script src="code/engine/controls/controlDefault.js"></script> <script src="code/engine/controls/controlRaceCPU.js"></script> <script src="code/engine/controls/controlNetwork.js"></script> <script src="code/engine/cameras/cameraIngame.js"></script> <script src="code/engine/cameras/cameraSpectator.js"></script> <script src="code/engine/cameras/cameraIntro.js"></script> <script src="code/engine/scenes/sceneDrawer.js"></script> <script src="code/engine/scenes/courseScene.js"></script> <script src="code/engine/scenes/clientScene.js"></script> <script src="code/engine/scenes/singleScene.js"></script> <script src="code/ui/race3DUI.js"></script> <script src="code/formats/net/netKart.js"></script> <script src="code/entities/objDatabase.js"></script> <script src="code/entities/trafficCar.js"></script> <script src="code/entities/water.js"></script> <script src="code/entities/itembox.js"></script> <script src="code/entities/decorations.js"></script> <script src="code/entities/rotatingGear.js"></script> <script src="code/entities/bowserPlatforms.js"></script> <script src="code/entities/soundMaker.js"></script> <script src="code/particles/itemboxShard.js"></script> <script src="code/particles/nitroParticle.js"></script> <script src="code/particles/nitroEmitter.js"></script> <script src="code/entities/shell.js"></script> <script src="code/entities/kart.js"></script> <script src="code/formats/kcl.js"></script> <script src="code/formats/ndsFS.js"></script> <script src="code/formats/nitro.js"></script> <script src="code/formats/nsbtx.js"></script> <script src="code/formats/nsbmd.js"></script> <script src="code/formats/nsbta.js"></script> <script src="code/formats/nsbca.js"></script> <script src="code/formats/nsbtp.js"></script> <script src="code/formats/nftr.js"></script> <script src="code/formats/narc.js"></script> <script src="code/formats/lz77.js"></script> <script src="code/formats/spa.js"></script> <script src="code/formats/nkm.js"></script> <script src="code/formats/kartphysicalparam.js"></script> <script src="code/formats/kartoffsetdata.js"></script> <script src="code/render/nitroRender.js"></script> <script src="code/render/nitroShaders.js"></script> <script src="code/render/shadowRender.js"></script> <script src="code/render/nitroAnimator.js"></script> <script src="code/glmatrix/gl-matrix.js"></script> <script src="code/formats/sdat.js"></script> <script src="code/formats/swav.js"></script> <script src="code/formats/swar.js"></script> <script src="code/formats/sbnk.js"></script> <script src="code/formats/sseq.js"></script> <script src="code/formats/ssar.js"></script> <script src="code/audio/sseqPlayer.js"></script> <script src="code/audio/nitroAudio.js"></script> <!-- Inline code (because that's always a good idea) --> <script> var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; window.requestAnimationFrame = requestAnimationFrame; var files = {}; var fileQuota; var filesLoaded = 0; var mobile = (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|Line truncated