// // nsbtx.js //-------------------- // Reads NSBTX files (or TEX0 sections) and provides canvases containing decoded texture data. // by RHY3756547 // // includes: gl-matrix.js (glMatrix 2.0) // /formats/nitro.js // window.nsbtx = function(input, tex0, autogen) { var texDataSize, texInfoOff, texOffset, compTexSize, compTexInfoOff, compTexOffset, compTexInfoDataOff /*wtf*/, palSize, palInfoOff, palOffset, mainOff var textureInfo, paletteInfo, palData, texData, colourBuffer var thisObj = this; var bitDepths = [0, 8, 2, 4, 8, 2, 8, 16] if (input != null) { load(input, tex0, autogen); } this.load = load; this.readTexWithPal = readTexWithPal; this.scopeEval = function(code) {return eval(code)} //for debug purposes function load(input, tex0, autogen) { var colourBuffer = new Uint32Array(4); var view = new DataView(input); var header = null; var offset = 0; if (!tex0) { //nitro 3d header header = nitro.readHeader(view); if (header.stamp != "BTX0") throw "NSBTX invalid. Expected BTX0, found "+header.stamp; if (header.numSections > 1) throw "NSBTX invalid. Too many sections - should only have one."; offset = header.sectionOffsets[0]; } mainOff = offset; var stamp = readChar(view, offset+0x0)+readChar(view, offset+0x1)+readChar(view, offset+0x2)+readChar(view, offset+0x3); if (stamp != "TEX0") throw "NSBTX invalid. Expected TEX0, found "+stamp; var size = view.getUint32(offset+0x04, true); var texDataSize = view.getUint16(offset+0x0C, true)<<8; var texInfoOff = view.getUint16(offset+0x0E, true); var texOffset = view.getUint16(offset+0x14, true); var compTexSize = view.getUint16(offset+0x1C, true)<<8; var compTexInfoOff = view.getUint16(offset+0x1E, true); var compTexOffset = view.getUint32(offset+0x24, true); var compTexInfoDataOff = view.getUint32(offset+0x28, true); var palSize = view.getUint32(offset+0x30, true)<<3; var palInfoOff = view.getUint32(offset+0x34, true); var palOffset = view.getUint32(offset+0x38, true); //read palletes, then textures. palData = input.slice(mainOff + palOffset, palSize); texData = input.slice(mainOff + texOffset, texDataSize); paletteInfo = nitro.read3dInfo(view, palInfoOff, palInfoHandler); textureInfo = nitro.read3dInfo(view, texInfoOff, texInfoHandler); if (autogen) { console.log(textureInfo.objectData.length) for (var i=0; i>((i%4)*2))&3) if (i%4 == 3) databuf = texView.readUint8(++off); } else if (bitDepths == 4) { if (i%2 == 0) { col = readPalColour(palView, palOff, databuf&15) } else { col = readPalColour(palView, palOff, databuf>>4) databuf = texView.readUint8(++off); } } else if (bitDepths == 8) { col = readPalColour(palView, palOff, texView.readUint8(off)) off += 1; } else if (bitDepths == 16) { col = readPalColour(palView, palOff, texView.readUint16(off, true)) off += 2; } data.data.set(col, i*4); } return canvas; } function readPalColour(view, palOff, ind) { var col = palView.getUint16(palOff+ind*2, true); colourBuffer[0] = Math.round(((col&31)/31)*255) colourBuffer[1] = Math.round((((col>>5)&31)/31)*255) colourBuffer[2] = Math.round((((col>>10)&31)/31)*255) colourBuffer[3] = Math.round((col>>15)*255) } function palInfoHandler(view, offset) { var palOffset = view.getUint16(offset, true)<<3; var unknown = view.getUint16(offset+2, true); return { palOffset: palOffset, nextoff: offset+4 } } function texInfoHandler(view, offset) { var texOffset = view.getUint16(offset, true)<<3; var flags = view.getUint16(offset+2, true); var width2 = view.getUint8(offset+4, true); var unknown = view.getUint8(offset+5, true); var height2 = view.getUint8(offset+6, true); var unknown2 = view.getUint8(offset+7, true); return { texOffset: texOffset, pal: (flags>>13), format: ((flags>>10)&7), height: ((flags>>7)&7)<<3, width: ((flags>>4)&7)<<3, nextoff: offset+8 } } function readChar(view, offset) { return String.fromCharCode(view.getUint8(offset)); } }