All courses now render properly. WIP items (shell, banana, fake item)
This commit is contained in:
1 parent
e010627b5d
commit
ff21142744
45 files changed
+3400
-1193
No files matched your search
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// ncer.js
|
||||
//--------------------
|
||||
// Loads ncer files and provides a variety of functions for accessing and using the data.
|
||||
// Cell data for nitro 2d graphics. Multiple images made out of multiple cells, sharing an input palette and ncgr.
|
||||
// by RHY3756547
|
||||
//
|
||||
|
||||
window.ncer = function(input) {
|
||||
var dimensions = [ //indexed by width, then height
|
||||
[[8,8], [16,8], [8,16]],
|
||||
[[16,16], [32,8], [8,32]],
|
||||
[[32,32], [32,16], [16,32]],
|
||||
[[64,64], [64,32], [32,64]],
|
||||
]
|
||||
|
||||
var mainOff;
|
||||
var t = this;
|
||||
if (input != null) {
|
||||
load(input);
|
||||
}
|
||||
this.load = load;
|
||||
|
||||
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 != "RECN") throw "NCER invalid. Expected RECN, found "+header.stamp;
|
||||
if (header.numSections < 1 || header.numSections > 3) throw "NCER invalid. Too many sections - should have 1-3.";
|
||||
//end nitro
|
||||
t.sectionOffsets = header.sectionOffsets;
|
||||
t.sectionOffsets[0] = 0x18;
|
||||
|
||||
mainOff = offset;
|
||||
|
||||
t.cebk = loadCEBK(view);
|
||||
/* ignore for now
|
||||
t.labl = loadLABL(view);
|
||||
t.uext = loadUEXT(view); //external data?
|
||||
*/
|
||||
}
|
||||
|
||||
function getSize(shape, size, double) {
|
||||
var dim = dimensions[size][shape];
|
||||
if (double) return [dim[0]*2, dim[1]*2];
|
||||
return [dim[0], dim[1]];
|
||||
}
|
||||
|
||||
function readOAM(view, offset) {
|
||||
//see ds docs. really, any of them?
|
||||
var obj0 = view.getUint16(offset, true);
|
||||
var obj1 = view.getUint16(offset + 2, true);
|
||||
var obj2 = view.getUint16(offset + 4, true);
|
||||
|
||||
var rsFlag = (obj0 & 0x100) > 0;
|
||||
var x = obj1 & 0x01FF;
|
||||
var y = obj0 & 0xFF;
|
||||
var result = {
|
||||
y: (y > 0x80) ? y-0x100 : y,
|
||||
rsFlag: rsFlag,
|
||||
disable: (!rsFlag && (obj0 & 0x200) > 0),
|
||||
doubleSize: (rsFlag && (obj0 & 0x200) > 0),
|
||||
objMode: (obj0 >> 10) & 0x3,
|
||||
mosaic: (obj0 & 0x1000) > 0,
|
||||
depth: (obj0 & 0x2000) > 0,
|
||||
shape: (obj0 >> 14) & 0x3, //used in combination with size to determine final x+y tile size.
|
||||
|
||||
x: (x > 0x100) ? x-0x200 : x,
|
||||
|
||||
xFlip: (!rsFlag && (obj1 & 0x1000) > 0),
|
||||
yFlip: (!rsFlag && (obj1 & 0x2000) > 0),
|
||||
|
||||
selectParam: rsFlag ? ((obj1 >> 9) & 0x1F) : 0,
|
||||
|
||||
size: (obj1 >> 14) & 0x3,
|
||||
|
||||
tileOffset: obj2 & 0x03FF,
|
||||
priority: (obj2 >> 10) & 3,
|
||||
pal: (obj2 >> 12) & 0xF,
|
||||
}
|
||||
result.size = getSize(result.shape, result.size, result.doubleSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
function loadCEBK(view) { //cell bank
|
||||
var offset = t.sectionOffsets[0] - 8;
|
||||
|
||||
var cebk = {};
|
||||
cebk.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (cebk.type != "KBEC") throw "NCER invalid. Expected KBEC, found "+cebk.type;
|
||||
cebk.blockSize = view.getUint32(offset+0x4, true);
|
||||
cebk.imageCount = view.getUint16(offset+0x8, true);
|
||||
cebk.bankType = view.getUint16(offset+0xA, true); //type 1 has additional fields
|
||||
cebk.unknown = view.getUint32(offset+0xC, true); //always 0x12
|
||||
cebk.boundarySize = view.getUint32(offset+0x10, true) * 64; //area in which the image can be drawn (pixel height AND width)
|
||||
cebk.partitionDataOffset = view.getUint32(offset+0x14, true);
|
||||
//pad 0x18
|
||||
//pad 0x1C
|
||||
|
||||
cebk.images = [];
|
||||
|
||||
offset += 0x20;
|
||||
var tableEnd = offset + cebk.imageCount * (8 + cebk.bankType * 8);
|
||||
for (var i=0; i<cebk.imageCount; i++) {
|
||||
var image = {};
|
||||
image.numCells = view.getUint16(offset, true);
|
||||
image.readOnlyInfo = view.getUint16(offset + 0x2, true);
|
||||
image.offset = view.getInt32(offset + 0x4, true);
|
||||
offset += 0x8;
|
||||
if (cebk.bankType == 1) {
|
||||
image.xMax = view.getInt16(offset, true);
|
||||
image.yMax = view.getInt16(offset+2, true);
|
||||
image.xMin = view.getInt16(offset+4, true);
|
||||
image.yMin = view.getInt16(offset+6, true);
|
||||
offset += 0x8;
|
||||
}
|
||||
|
||||
var offset2 = tableEnd + image.offset;
|
||||
image.cells = [];
|
||||
for (var j=0; j<image.numCells; j++) {
|
||||
var cell = readOAM(view, offset2);
|
||||
offset2 += 6;
|
||||
image.cells.push(cell);
|
||||
}
|
||||
cebk.images.push(image);
|
||||
}
|
||||
|
||||
if (cebk.partitionDataOffset != 0) { //not sure what this does, just that it's here
|
||||
var pOff = t.sectionOffsets[0] + cebk.partitionDataOffset;
|
||||
cebk.maxPartitionSize = view.getUint32(pOff, true);
|
||||
cebk.firstOffset = view.getUint32(pOff+4, true);
|
||||
pOff += cebk.firstOffset;
|
||||
for (var i=0; i<cebk.imageCount; i++) {
|
||||
cebk.images[i].partitionOffset = view.getUint32(pOff, true);
|
||||
cebk.images[i].partitionSize = view.getUint32(pOff+4, true);
|
||||
pOff += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return cebk;
|
||||
}
|
||||
|
||||
function readPalColour(view, ind) {
|
||||
var col = view.getUint16(ind, true);
|
||||
var f = 255/31;
|
||||
return [Math.round((col&31)*f), Math.round(((col>>5)&31)*f), Math.round(((col>>10)&31)*f), 255];
|
||||
}
|
||||
|
||||
function readChar(view, offset) {
|
||||
return String.fromCharCode(view.getUint8(offset));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// ncgr.js
|
||||
//--------------------
|
||||
// Loads ncgr files and provides a variety of functions for accessing and using the data.
|
||||
// "Graphics Resource", as in tile data. Usually rendered in conjunction with Palette (nclr) and Cell (ncer) / screen (nscr) data.
|
||||
// by RHY3756547
|
||||
//
|
||||
|
||||
window.ncgr = function(input) {
|
||||
|
||||
var mainOff;
|
||||
var t = this;
|
||||
if (input != null) {
|
||||
load(input);
|
||||
}
|
||||
this.load = load;
|
||||
|
||||
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 != "RGCN") throw "NCGR invalid. Expected RGCN, found "+header.stamp;
|
||||
if (header.numSections < 1 || header.numSections > 2) throw "NCGR invalid. Too many sections - should have 2.";
|
||||
offset = header.sectionOffsets[0];
|
||||
//end nitro
|
||||
t.sectionOffsets = header.sectionOffsets;
|
||||
t.sectionOffsets[0] = 0x18;
|
||||
|
||||
mainOff = offset;
|
||||
|
||||
t.char = loadCHAR(view);
|
||||
if (header.numSections > 1) t.cpos = loadCPOS(view);
|
||||
}
|
||||
|
||||
function loadCHAR(view) {
|
||||
var offset = t.sectionOffsets[0] - 8;
|
||||
|
||||
var char = {};
|
||||
char.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (char.type != "RAHC") throw "NCGR invalid. Expected RAHC, found "+char.type;
|
||||
char.blockSize = view.getUint32(offset+0x4, true);
|
||||
t.sectionOffsets[1] = t.sectionOffsets[0] + char.blockSize;
|
||||
char.tilesY = view.getUint16(offset+0x8, true); //(tiles y)
|
||||
char.tilesX = view.getUint16(offset+0xA, true); //(tiles x)
|
||||
char.bitDepth = view.getUint32(offset+0xC, true); //3 - 4bits, 4 - 8bits
|
||||
//pad 0x10
|
||||
char.tiledFlag = view.getUint32(offset+0x14, true);
|
||||
char.tileDataSize = view.getUint32(offset+0x18, true);
|
||||
char.unknown = view.getUint32(offset+0x1C, true); //usually 24
|
||||
offset += 0x20;
|
||||
|
||||
//tiles are 8 or 4 bit index to pal data
|
||||
//64 pixels per tile (8*8)
|
||||
var tileCount = (char.blockSize-0x20) / ((char.bitDepth == 4) ? 64 : 32);
|
||||
char.tiles = [];
|
||||
for (var i=0; i<tileCount; i++) {
|
||||
var tile = [];
|
||||
if (char.bitDepth == 4) {
|
||||
//easy, just read 1024 bytes
|
||||
for (var j=0; j<64; j++) tile.push(view.getUint8(offset++));
|
||||
} else {
|
||||
for (var j=0; j<32; j++) {
|
||||
var dat = view.getUint8(offset++);
|
||||
tile.push(dat&0xF);
|
||||
tile.push(dat>>4);
|
||||
}
|
||||
}
|
||||
char.tiles.push(tile);
|
||||
}
|
||||
return char;
|
||||
}
|
||||
|
||||
function loadCPOS(view) { //palette count map, supposedly. maps each palette to an ID
|
||||
var offset = t.sectionOffsets[1] - 8;
|
||||
|
||||
var cpos = {};
|
||||
cpos.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (cpos.type != "SOPC") throw "NCLR invalid. Expected SOPC, found "+stamp;
|
||||
cpos.blockSize = view.getUint32(offset+0x4, true);
|
||||
//padding 0x8
|
||||
|
||||
cpos.tileSize = view.getUint16(offset+0xC, true); //always 32
|
||||
cpos.tileCount = view.getUint16(offset+0xE, true);
|
||||
return cpos;
|
||||
}
|
||||
|
||||
function readPalColour(view, ind) {
|
||||
var col = view.getUint16(ind, true);
|
||||
var f = 255/31;
|
||||
return [Math.round((col&31)*f), Math.round(((col>>5)&31)*f), Math.round(((col>>10)&31)*f), 255];
|
||||
}
|
||||
|
||||
function readChar(view, offset) {
|
||||
return String.fromCharCode(view.getUint8(offset));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// nclr.js
|
||||
//--------------------
|
||||
// Loads nclr files and provides a variety of functions for accessing and using the data.
|
||||
// Palette information for nitro 2d graphics.
|
||||
// by RHY3756547
|
||||
//
|
||||
|
||||
window.nclr = function(input) {
|
||||
|
||||
var mainOff;
|
||||
var t = this;
|
||||
if (input != null) {
|
||||
load(input);
|
||||
}
|
||||
this.load = load;
|
||||
|
||||
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 != "RLCN") throw "NCLR invalid. Expected RLCN, found "+header.stamp;
|
||||
if (header.numSections < 1 || header.numSections > 2) throw "NCLR invalid. Too many sections - should have 2.";
|
||||
offset = header.sectionOffsets[0];
|
||||
//end nitro
|
||||
t.sectionOffsets = header.sectionOffsets;
|
||||
t.sectionOffsets[0] = 0x18;
|
||||
|
||||
mainOff = offset;
|
||||
|
||||
t.pltt = loadPLTT(view);
|
||||
if (header.numSections > 1) t.pcmp = loadPCMP(view);
|
||||
}
|
||||
|
||||
function loadPLTT(view) {
|
||||
var offset = t.sectionOffsets[0] - 8;
|
||||
|
||||
var pltt = {};
|
||||
pltt.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (pltt.type != "TTLP") throw "NCLR invalid. Expected TTLP, found "+pltt.type;
|
||||
pltt.blockSize = view.getUint32(offset+0x4, true);
|
||||
t.sectionOffsets[1] = t.sectionOffsets[0] + pltt.blockSize;
|
||||
pltt.bitDepth = view.getUint32(offset+0x8, true); //3 -> 4bit, 4 -> 8bit
|
||||
pltt.padding = view.getUint32(offset+0xC, true);
|
||||
pltt.palEntries = view.getUint32(offset+0x10, true) / 2; //stored in bytes, 2 bytes per col. seems to be wrong sometimes? (8bit mode, padding as 1)
|
||||
pltt.colorsPerPal = view.getUint32(offset+0x14, true); //usually 16
|
||||
|
||||
//16-bit pallete data
|
||||
//XBBBBBGGGGGRRRRR
|
||||
|
||||
var colsPerPal = (pltt.bitDepth == 4)?256:16;
|
||||
var realPalCount = (pltt.blockSize - 0x18) / 2;
|
||||
|
||||
offset += 0x18;
|
||||
pltt.palettes = [];
|
||||
var curPal = [];
|
||||
for (var i=0; i<realPalCount; i++) {
|
||||
curPal.push(readPalColour(view, offset));
|
||||
if (curPal.length >= colsPerPal) {
|
||||
pltt.palettes.push(curPal);
|
||||
curPal = [];
|
||||
}
|
||||
offset += 2;
|
||||
}
|
||||
if (curPal.length > 0) pltt.palettes.push(curPal);
|
||||
return pltt;
|
||||
}
|
||||
|
||||
function loadPCMP(view) { //palette count map, supposedly. maps each palette to an ID
|
||||
var offset = t.sectionOffsets[1] - 8;
|
||||
|
||||
var pcmp = {};
|
||||
pcmp.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (pcmp.type != "PMCP") throw "NCLR invalid. Expected PMCP, found "+stamp;
|
||||
pcmp.blockSize = view.getUint32(offset+0x4, true);
|
||||
pcmp.palCount = view.getUint16(offset+0x8, true);
|
||||
//unknown 16: 0?
|
||||
pcmp.unknown = view.getUint32(offset+0xC, true);
|
||||
|
||||
offset += 0x10;
|
||||
var palIDs = [];
|
||||
for (var i=0; i<pcmp.palCount; i++) {
|
||||
palIDs.push(view.getUint16(offset, true));
|
||||
offset += 2;
|
||||
}
|
||||
return pcmp;
|
||||
}
|
||||
|
||||
function readPalColour(view, ind) {
|
||||
var col = view.getUint16(ind, true);
|
||||
var f = 255/31;
|
||||
return [Math.round((col&31)*f), Math.round(((col>>5)&31)*f), Math.round(((col>>10)&31)*f), 255];
|
||||
}
|
||||
|
||||
function readChar(view, offset) {
|
||||
return String.fromCharCode(view.getUint8(offset));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// nscr.js
|
||||
//--------------------
|
||||
// Loads nscr files and provides a variety of functions for accessing and using the data.
|
||||
// Screen data for nitro 2d graphics. Each cell references a graphic (ncgr) and palette (nclr).
|
||||
// by RHY3756547
|
||||
//
|
||||
|
||||
window.nscr = function(input) {
|
||||
|
||||
var mainOff;
|
||||
var t = this;
|
||||
if (input != null) {
|
||||
load(input);
|
||||
}
|
||||
this.load = load;
|
||||
|
||||
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 != "RCSN") throw "NSCR invalid. Expected RCSN, found "+header.stamp;
|
||||
if (header.numSections != 1) throw "NSCR invalid. Too many sections - should have 1.";
|
||||
offset = header.sectionOffsets[0];
|
||||
//end nitro
|
||||
t.sectionOffsets = header.sectionOffsets;
|
||||
t.sectionOffsets[0] = 0x18;
|
||||
|
||||
mainOff = offset;
|
||||
|
||||
t.scrn = loadSCRN(view);
|
||||
}
|
||||
|
||||
function loadSCRN(view) {
|
||||
var offset = t.sectionOffsets[0] - 8;
|
||||
|
||||
var scrn = {};
|
||||
scrn.type = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3);
|
||||
if (scrn.type != "NRCS") throw "SCRN invalid. Expected NRCS, found "+scrn.type;
|
||||
scrn.blockSize = view.getUint32(offset+0x4, true);
|
||||
t.sectionOffsets[1] = t.sectionOffsets[0] + scrn.blockSize;
|
||||
scrn.screenWidth = view.getUint16(offset+0x8, true); //in pixels
|
||||
scrn.screenHeight = view.getUint16(offset+0xA, true);
|
||||
scrn.padding = view.getUint32(offset+0xC, true); //always 0
|
||||
scrn.screenDataSize = view.getUint32(offset+0x10, true);
|
||||
offset += 0x14;
|
||||
|
||||
var entries = (scrn.blockSize - 0x14)/2;
|
||||
scrn.data = [];
|
||||
|
||||
for (var i=0; i<entries; i++) {
|
||||
scrn.data.push(view.getUint16(offset, true));
|
||||
offset += 2;
|
||||
}
|
||||
return scrn;
|
||||
|
||||
/*
|
||||
Format is (YYYYXXNNNNNNNNNN)
|
||||
Y4 Palette Number
|
||||
X2 Transformation (YFlip/XFlip)
|
||||
N10 Tile Number
|
||||
*/
|
||||
}
|
||||
|
||||
function readPalColour(view, ind) {
|
||||
var col = view.getUint16(ind, true);
|
||||
var f = 255/31;
|
||||
return [Math.round((col&31)*f), Math.round(((col>>5)&31)*f), Math.round(((col>>10)&31)*f), 255];
|
||||
}
|
||||
|
||||
function readChar(view, offset) {
|
||||
return String.fromCharCode(view.getUint8(offset));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user