mkjs/code/formats/nsbtp.js

180 lines
4.6 KiB
JavaScript
Raw Permalink Normal View History

2017-09-08 09:24:16 -07:00
//
// nsbtp.js
//--------------------
// Reads NSBTP files (texture info animation) for use in combination with an NSBMD (model) file
// by RHY3756547
//
// includes: gl-matrix.js (glMatrix 2.0)
// /formats/nitro.js
//
window.nsbtp = function(input) {
var mainOff, matOff;
var animData;
//anim data structure:
// {
// objectData: [
// {
// obj: { }
// }
// ]
// }
var mainObj = this;
var prop = [
"scaleS",
"scaleT",
"rotation",
"translateS",
"translateT"
]
if (input != null) {
load(input);
}
this.load = load;
var texTotal;
var palTotal;
var texNamesOff;
var palNamesOff;
var texNames;
var palNames;
2017-09-08 09:24:16 -07:00
function load(input) {
var view = new DataView(input);
var header = null;
var offset = 0;
var tex;
//nitro 3d header
header = nitro.readHeader(view);
if (header.stamp != "BTP0") throw "NSBTP invalid. Expected BTP0, found "+header.stamp;
if (header.numSections > 1) throw "NSBTP invalid. Too many sections - should have 1 maximum.";
offset = header.sectionOffsets[0];
//end nitro
mainOff = offset;
var stamp = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
if (stamp != "PAT0") throw "NSBTP invalid. Expected PAT0, found "+stamp;
animData = nitro.read3dInfo(view, mainOff+8, animInfoHandler);
mainObj.animData = animData;
}
function animInfoHandler(view, offset) {
var animOff = view.getUint32(offset, true);
var off = mainOff+animOff;
var obj = readAnimData(view, off);
obj.nextoff = offset+4;
return obj;
}
function readAnimData(view, offset) {
matOff = offset;
var stamp = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3); //should be M_PT, where _ is a 0 character
offset += 4;
//b400 0303 4400 7400 - countdown (3..2..1.. then start is another model, duration 180 frames, 3 frames of anim)
//1400 0404 4800 8800 - kuribo (4 frames, shorter animation duration)
//1e00 0202 4000 6000 - pinball stage (2 frames)
//0200 0202 4000 6000 - fish, cow and crab (duration and total 2 frames, unusually short animation)
//0d00 0404 5000 9000 - bat (duration 13, 6 frames, uneven pacing)
//16bit duration (60fps frames, total)
//8bit tex start
//8bit pal start
//16bit unknown (flags? kuribo repeats by playing backwards)
//16bit unknown
//example data, for 3 mat 3 pal data
//var tinfo = texInfoHandler(view, offset+4);
//8 bytes here? looks like texinfo
var duration = view.getUint16(offset, true);
texTotal = view.getUint8(offset+2);
palTotal = view.getUint8(offset+3);
texNamesOff = view.getUint16(offset+4, true);
palNamesOff = view.getUint16(offset+6, true);
var nameOffset = matOff + texNamesOff;
texNames = [];
//read 16char tex names
for (var i=0; i<texTotal; i++) {
var name = "";
for (var j=0; j<16; j++) {
name += readChar(view, nameOffset++)
}
texNames[i] = name;
}
nameOffset = matOff + palNamesOff;
palNames = [];
//read 16char pal names
for (var i=0; i<palTotal; i++) {
var name = "";
for (var j=0; j<16; j++) {
name += readChar(view, nameOffset++)
}
palNames[i] = name;
}
2017-09-08 09:24:16 -07:00
//...then another nitro
var data = nitro.read3dInfo(view, offset+8, matInfoHandler);
return {data: data, nextoff: data.nextoff, texTotal:texTotal, palTotal:palTotal, duration:duration, texNames: texNames, palNames: palNames};
2017-09-08 09:24:16 -07:00
}
function matInfoHandler(view, offset, base) {
var obj = {}
obj.frames = [];
// in here...
// 16bit frames
// 16bit maybe material number (probably? mostly 0) to replace
// 16bit unknown (flags? 0x4400 count, 0x1101 waluigi, 0x3303 goomba, 0x0010 fish)
// 16bit offset from M_PT (always 0x38)
//at offset (frame of these)
// 16bit happenAt
// 8bit tex
// 8bit pal
//then (frame of these)
// 16char texname
//then (frame of these)
// 16char palname
// texture animations are bound to the material via the name of this block.
2017-09-08 09:24:16 -07:00
var frames = view.getUint32(offset, true);
2017-09-08 09:24:16 -07:00
obj.flags = view.getUint16(offset+4, true);
var offset2 = view.getUint16(offset+6, true);
offset += 8;
obj.nextoff = offset;
offset = matOff + offset2;
//info and timing for each frame
for (var i=0; i<frames; i++) {
var entry = {
2017-09-08 09:24:16 -07:00
time: view.getUint16(offset, true),
tex: view.getUint8(offset+2), //index into names?
pal: view.getUint8(offset+3), //index into pal names?
2017-09-08 09:24:16 -07:00
}
entry.texName = texNames[entry.tex];
entry.palName = palNames[entry.pal];
obj.frames.push(entry);
2017-09-08 09:24:16 -07:00
offset += 4;
}
return obj;
}
function readChar(view, offset) {
return String.fromCharCode(view.getUint8(offset));
}
}