Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- // Imports
- const fs = require('fs')
- const PNG = require("pngjs").PNG;
- // Declare Paths
- const DAT_PATH = '/home/pi/Documents/mml2data/DAT';
- const COMMON_PATH = '/home/pi/Documents/mml2data/COMMON';
- const OUT_PATH = '/home/pi/Documents/out';
- // Constants
- const PAL_TYPE = 0x02;
- const TIM_TYPE = 0x03;
- const EBD_TYPE = 0x0A;
- // Characters (EBD)
- console.log('Scanning for Actor Models');
- fs.readdirSync(DAT_PATH).forEach(name => {
- let file = fs.readFileSync(`${DAT_PATH}/${name}`);
- let type = file.readUInt32LE(0x00);
- if(type !== EBD_TYPE) {
- return;
- }
- let len = file.readUInt32LE(0x04);
- let ebd = file.subarray(0x30, len + 0x30);
- let stub = name.substr(0, 4);
- let dir = `${OUT_PATH}/${stub}`;
- if(!fs.existsSync(dir)) {
- fs.mkdirSync(dir);
- }
- fs.writeFileSync(`${dir}/entities.ebd`, ebd);
- });
- // Textures (TIM)
- console.log('Scanning for Textures');
- fs.readdirSync(DAT_PATH).forEach(name => {
- let file = fs.readFileSync(`${DAT_PATH}/${name}`);
- for(let ofs = 0; ofs < file.length; ofs += 0x400) {
- let type = file.readUInt32LE(ofs);
- if(type !== TIM_TYPE) {
- continue;
- }
- let str = ofs.toString(16);
- while(str.length < 6) {
- str = '0' + str;
- }
- const header = {
- name : '0x' + str,
- stub : name.substr(0, 4),
- decompressed_size : file.readUInt16LE(ofs + 0x04),
- palette_x : file.readUInt16LE(ofs + 0x0c),
- palette_y : file.readUInt16LE(ofs + 0x0e),
- palette_size : file.readUInt16LE(ofs + 0x10),
- palette_count : file.readUInt16LE(ofs + 0x12),
- image_x : file.readUInt16LE(ofs + 0x14),
- image_y : file.readUInt16LE(ofs + 0x16),
- width : file.readUInt16LE(ofs + 0x18) * 2,
- height : file.readUInt16LE(ofs + 0x1a),
- bitfield_size : file.readUInt16LE(ofs + 0x24),
- bits_per_pixel : 8
- }
- if(header.width > 256) {
- continue;
- }
- if(header.height > 256) {
- continue;
- }
- if(header.palette_size > 256) {
- continue;
- }
- console.log('Found TIM file at offset: 0x%s', str);
- if(header.palette_size < 256) {
- let count = header.palette_size / 16;
- header.palette_size = 16;
- header.palette_count = count;
- }
- if(header.palette_size === 16) {
- header.width *= 2;
- header.bits_per_pixel = 4;
- }
- // Copy the bitfield
- let tmp = ofs + 0x30;
- const bitfield = file.subarray(tmp, tmp + header.bitfield_size);
- tmp += header.bitfield_size;
- // Decompress
- let bits = readBits(bitfield);
- let payload = decompress(file, tmp, bits, header)
- // Render the texture
- renderImage(header, payload);
- }
- });
- // Scan for Palettes
- console.log('Scanning for palettes');
- let found = false;
- fs.readdirSync(DAT_PATH).forEach(name => {
- if(found) {
- return;
- }
- let file = fs.readFileSync(`${DAT_PATH}/${name}`);
- for(let ofs = 0; ofs < file.length; ofs += 0x400) {
- let type = file.readUInt32LE(ofs);
- if(type !== PAL_TYPE) {
- continue;
- }
- found = true;
- let str = ofs.toString(16);
- while(str.length < 6) {
- str = '0' + str;
- }
- const header = {
- name : '0x' + str,
- stub : name.substr(0, 4),
- palette_size : file.readUInt16LE(ofs + 0x04),
- palette_x : file.readUInt16LE(ofs + 0x0c),
- palette_y : file.readUInt16LE(ofs + 0x0e),
- palette_size : file.readUInt16LE(ofs + 0x10),
- palette_count : file.readUInt16LE(ofs + 0x12)
- }
- if(header.palette_size < 256) {
- let count = header.palette_size / 16;
- header.palette_size = 16;
- header.palette_count = count;
- }
- let tmp = ofs + 0x30;
- for(let i = 0; i < header.palette_count; i++) {
- let pal = [];
- let bits = 0;
- for(let i = 0; i < header.palette_size; i++) {
- let color = file.readUInt16LE(tmp);
- tmp += 2;
- bits |= color;
- pal[i] = {
- r : ((color >> 0x00) & 0x1f) << 3,
- g : ((color >> 0x05) & 0x1f) << 3,
- b : ((color >> 0x0a) & 0x1f) << 3,
- a : color > 0 ? 255 : 0
- };
- }
- if(!bits) {
- continue;
- }
- let png = new PNG({
- width : 256,
- height : 256
- });
- for(let y = 0; y < 256; y++) {
- for(let x = 0; x < 256; x++) {
- let a = Math.floor(y / 64);
- let b = Math.floor(x / 64);
- let clr = a*4 + b;
- let color = pal[a*4 + b];
- let i = 256 * y + x;
- let idx = i * 4;
- png.data[idx + 0] = color.r;
- png.data[idx + 1] = color.g;
- png.data[idx + 2] = color.b;
- png.data[idx + 3] = color.a;
- }
- }
- let dir = `${OUT_PATH}/${header.stub}`;
- if(!fs.existsSync(dir)) {
- fs.mkdirSync(dir);
- }
- let buffer = PNG.sync.write(png);
- console.log(`Writing: ${dir}/${header.name}_${i}.png`);
- fs.writeFileSync(`${dir}/${header.name}_${i}.png`, buffer);
- }
- }
- });
- // Helper Functions
- function readBits(buffer) {
- let bits = [];
- for(let ofs = 0; ofs < buffer.length; ofs += 4) {
- let val = buffer.readUInt32LE(ofs);
- for(let i = 31; i >= 0; i--) {
- let bit = 1 << i;
- bits.push(val & bit ? 1 : 0);
- }
- }
- return bits;
- }
- function decompress(file, ofs, bits, header) {
- let out_ofs = 0;
- let window_ofs = 0;
- let buffer = Buffer.alloc(header.decompressed_size);
- for(let i = 0; i < bits.length; i++) {
- let bit = bits[i];
- let word = file.readUInt16LE(ofs);
- ofs += 2;
- if(bit === 0) {
- buffer.writeUInt16LE(word, out_ofs);
- out_ofs += 2;
- } else if(word === 0xffff) {
- window_ofs += 0x2000;
- } else {
- let val = ((word >> 3) & 0x1fff);
- let copy_from = window_ofs + val;
- let copy_len = (word & 0x07) + 2;
- while(copy_len--) {
- let w = buffer.readUInt16LE(copy_from);
- copy_from += 2;
- buffer.writeUInt16LE(w, out_ofs);
- out_ofs += 2;
- }
- }
- if(out_ofs >= buffer.length) {
- break;
- }
- if(window_ofs > buffer.length) {
- break;
- }
- }
- return buffer;
- }
- function renderImage(header, payload) {
- let png = new PNG({
- width : header.width,
- height : header.height
- });
- // First we read the palette
- let palette = [];
- let ofs = 0;
- for(let p = 0; p < header.palette_count; p++) {
- let pal = [];
- let bits = 0;
- for(let i = 0; i < header.palette_size; i++) {
- let color = payload.readUInt16LE(ofs);
- ofs += 2;
- bits |= color;
- pal[i] = {
- r : ((color >> 0x00) & 0x1f) << 3,
- g : ((color >> 0x05) & 0x1f) << 3,
- b : ((color >> 0x0a) & 0x1f) << 3,
- a : color > 0 ? 255 : 0
- };
- }
- if(!bits) {
- continue;
- }
- palette.push(pal);
- }
- let image_body = [];
- while(ofs < payload.length) {
- let byte = payload.readUInt8(ofs++);
- switch(header.bits_per_pixel) {
- case 4:
- image_body.push(byte & 0xf);
- image_body.push(byte >> 4);
- break;
- case 8:
- image_body.push(byte);
- break;
- }
- }
- for(let p = 0; p < palette.length; p++) {
- let pal = palette[p];
- for(let y = 0; y < header.height; y++) {
- for(let x = 0; x < header.width; x++) {
- let i = header.width * y + x;
- let color = pal[image_body[i]]
- let idx = i * 4;
- png.data[idx + 0] = color.r;
- png.data[idx + 1] = color.g;
- png.data[idx + 2] = color.b;
- png.data[idx + 3] = color.a;
- }
- }
- let dir = `${OUT_PATH}/${header.stub}`;
- if(!fs.existsSync(dir)) {
- fs.mkdirSync(dir);
- }
- let buffer = PNG.sync.write(png);
- fs.writeFileSync(`${dir}/${header.name}_${p}.png`, buffer);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement