Initial implementation of Nitro Particles

- Drifting particles and mini turbo (sans extra spark particles)
- Slowdown particles (grass/sand/water)
- Itembox collect particle
- Wall collide particle (this is really extreme and there should
probably be others)
- Shader improvements, such as dithered shadows for alpha and reduction
of artifacts. The best way to remove all artifacts would be generating
normals for courses and using the diffuse direction as a more reliable
indication of shadowed/not.
- Fixed checkpoints not resetting on new laps.
- Fixed me not being able to count to 3. (now 3 laps instead of 4)
- Fixed battle mode courses crashing on load and during due to AI being
funny (above 31, eg 36 for block fort)
This commit is contained in:
RHY3756547 committed 2018-03-24 23:50:10 +00:00
1 parent 870bef6689
commit 4af42625a0
18 files changed
+6338 -3119

No files matched your search

+88 -19
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 = [];
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),