Advertisement
Guest User

Untitled

a guest
May 28th, 2021
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.35 KB | None | 0 0
  1. "use strict";
  2.  
  3. // Imports
  4.  
  5. const fs = require('fs')
  6. const PNG = require("pngjs").PNG;
  7.  
  8. // Declare Paths
  9.  
  10. const DAT_PATH = '/home/pi/Documents/mml2data/DAT';
  11. const COMMON_PATH = '/home/pi/Documents/mml2data/COMMON';
  12. const OUT_PATH = '/home/pi/Documents/out';
  13.  
  14. // Constants
  15.  
  16. const PAL_TYPE = 0x02;
  17. const TIM_TYPE = 0x03;
  18. const EBD_TYPE = 0x0A;
  19.  
  20. // Characters (EBD)
  21.  
  22. console.log('Scanning for Actor Models');
  23.  
  24. fs.readdirSync(DAT_PATH).forEach(name => {
  25.  
  26. let file = fs.readFileSync(`${DAT_PATH}/${name}`);
  27. let type = file.readUInt32LE(0x00);
  28. if(type !== EBD_TYPE) {
  29. return;
  30. }
  31.  
  32. let len = file.readUInt32LE(0x04);
  33. let ebd = file.subarray(0x30, len + 0x30);
  34. let stub = name.substr(0, 4);
  35.  
  36. let dir = `${OUT_PATH}/${stub}`;
  37. if(!fs.existsSync(dir)) {
  38. fs.mkdirSync(dir);
  39. }
  40.  
  41. fs.writeFileSync(`${dir}/entities.ebd`, ebd);
  42.  
  43. });
  44.  
  45. // Textures (TIM)
  46.  
  47. console.log('Scanning for Textures');
  48.  
  49. fs.readdirSync(DAT_PATH).forEach(name => {
  50.  
  51. let file = fs.readFileSync(`${DAT_PATH}/${name}`);
  52.  
  53. for(let ofs = 0; ofs < file.length; ofs += 0x400) {
  54. let type = file.readUInt32LE(ofs);
  55. if(type !== TIM_TYPE) {
  56. continue;
  57. }
  58.  
  59. let str = ofs.toString(16);
  60. while(str.length < 6) {
  61. str = '0' + str;
  62. }
  63.  
  64. const header = {
  65. name : '0x' + str,
  66. stub : name.substr(0, 4),
  67. decompressed_size : file.readUInt16LE(ofs + 0x04),
  68. palette_x : file.readUInt16LE(ofs + 0x0c),
  69. palette_y : file.readUInt16LE(ofs + 0x0e),
  70. palette_size : file.readUInt16LE(ofs + 0x10),
  71. palette_count : file.readUInt16LE(ofs + 0x12),
  72. image_x : file.readUInt16LE(ofs + 0x14),
  73. image_y : file.readUInt16LE(ofs + 0x16),
  74. width : file.readUInt16LE(ofs + 0x18) * 2,
  75. height : file.readUInt16LE(ofs + 0x1a),
  76. bitfield_size : file.readUInt16LE(ofs + 0x24),
  77. bits_per_pixel : 8
  78. }
  79.  
  80. if(header.width > 256) {
  81. continue;
  82. }
  83.  
  84. if(header.height > 256) {
  85. continue;
  86. }
  87.  
  88. if(header.palette_size > 256) {
  89. continue;
  90. }
  91.  
  92. console.log('Found TIM file at offset: 0x%s', str);
  93.  
  94. if(header.palette_size < 256) {
  95. let count = header.palette_size / 16;
  96. header.palette_size = 16;
  97. header.palette_count = count;
  98. }
  99.  
  100. if(header.palette_size === 16) {
  101. header.width *= 2;
  102. header.bits_per_pixel = 4;
  103. }
  104.  
  105. // Copy the bitfield
  106.  
  107. let tmp = ofs + 0x30;
  108. const bitfield = file.subarray(tmp, tmp + header.bitfield_size);
  109. tmp += header.bitfield_size;
  110.  
  111. // Decompress
  112.  
  113. let bits = readBits(bitfield);
  114. let payload = decompress(file, tmp, bits, header)
  115.  
  116. // Render the texture
  117.  
  118. renderImage(header, payload);
  119.  
  120. }
  121.  
  122. });
  123.  
  124.  
  125. // Scan for Palettes
  126.  
  127. console.log('Scanning for palettes');
  128.  
  129. let found = false;
  130. fs.readdirSync(DAT_PATH).forEach(name => {
  131.  
  132. if(found) {
  133. return;
  134. }
  135.  
  136. let file = fs.readFileSync(`${DAT_PATH}/${name}`);
  137.  
  138. for(let ofs = 0; ofs < file.length; ofs += 0x400) {
  139. let type = file.readUInt32LE(ofs);
  140. if(type !== PAL_TYPE) {
  141. continue;
  142. }
  143.  
  144. found = true;
  145.  
  146. let str = ofs.toString(16);
  147. while(str.length < 6) {
  148. str = '0' + str;
  149. }
  150.  
  151. const header = {
  152. name : '0x' + str,
  153. stub : name.substr(0, 4),
  154. palette_size : file.readUInt16LE(ofs + 0x04),
  155. palette_x : file.readUInt16LE(ofs + 0x0c),
  156. palette_y : file.readUInt16LE(ofs + 0x0e),
  157. palette_size : file.readUInt16LE(ofs + 0x10),
  158. palette_count : file.readUInt16LE(ofs + 0x12)
  159. }
  160.  
  161. if(header.palette_size < 256) {
  162. let count = header.palette_size / 16;
  163. header.palette_size = 16;
  164. header.palette_count = count;
  165. }
  166.  
  167. let tmp = ofs + 0x30;
  168. for(let i = 0; i < header.palette_count; i++) {
  169.  
  170. let pal = [];
  171. let bits = 0;
  172.  
  173. for(let i = 0; i < header.palette_size; i++) {
  174. let color = file.readUInt16LE(tmp);
  175. tmp += 2;
  176. bits |= color;
  177.  
  178. pal[i] = {
  179. r : ((color >> 0x00) & 0x1f) << 3,
  180. g : ((color >> 0x05) & 0x1f) << 3,
  181. b : ((color >> 0x0a) & 0x1f) << 3,
  182. a : color > 0 ? 255 : 0
  183. };
  184.  
  185. }
  186.  
  187. if(!bits) {
  188. continue;
  189. }
  190.  
  191. let png = new PNG({
  192. width : 256,
  193. height : 256
  194. });
  195.  
  196. for(let y = 0; y < 256; y++) {
  197. for(let x = 0; x < 256; x++) {
  198.  
  199. let a = Math.floor(y / 64);
  200. let b = Math.floor(x / 64);
  201.  
  202. let clr = a*4 + b;
  203. let color = pal[a*4 + b];
  204.  
  205. let i = 256 * y + x;
  206. let idx = i * 4;
  207.  
  208. png.data[idx + 0] = color.r;
  209. png.data[idx + 1] = color.g;
  210. png.data[idx + 2] = color.b;
  211. png.data[idx + 3] = color.a;
  212. }
  213. }
  214.  
  215. let dir = `${OUT_PATH}/${header.stub}`;
  216. if(!fs.existsSync(dir)) {
  217. fs.mkdirSync(dir);
  218. }
  219.  
  220. let buffer = PNG.sync.write(png);
  221. console.log(`Writing: ${dir}/${header.name}_${i}.png`);
  222. fs.writeFileSync(`${dir}/${header.name}_${i}.png`, buffer);
  223.  
  224. }
  225.  
  226. }
  227.  
  228. });
  229.  
  230. // Helper Functions
  231.  
  232. function readBits(buffer) {
  233.  
  234. let bits = [];
  235. for(let ofs = 0; ofs < buffer.length; ofs += 4) {
  236. let val = buffer.readUInt32LE(ofs);
  237. for(let i = 31; i >= 0; i--) {
  238. let bit = 1 << i;
  239. bits.push(val & bit ? 1 : 0);
  240. }
  241. }
  242. return bits;
  243.  
  244. }
  245.  
  246.  
  247. function decompress(file, ofs, bits, header) {
  248.  
  249. let out_ofs = 0;
  250. let window_ofs = 0;
  251. let buffer = Buffer.alloc(header.decompressed_size);
  252.  
  253. for(let i = 0; i < bits.length; i++) {
  254.  
  255. let bit = bits[i];
  256. let word = file.readUInt16LE(ofs);
  257. ofs += 2;
  258.  
  259. if(bit === 0) {
  260. buffer.writeUInt16LE(word, out_ofs);
  261. out_ofs += 2;
  262. } else if(word === 0xffff) {
  263. window_ofs += 0x2000;
  264. } else {
  265. let val = ((word >> 3) & 0x1fff);
  266. let copy_from = window_ofs + val;
  267. let copy_len = (word & 0x07) + 2;
  268. while(copy_len--) {
  269. let w = buffer.readUInt16LE(copy_from);
  270. copy_from += 2;
  271. buffer.writeUInt16LE(w, out_ofs);
  272. out_ofs += 2;
  273. }
  274. }
  275.  
  276. if(out_ofs >= buffer.length) {
  277. break;
  278. }
  279.  
  280. if(window_ofs > buffer.length) {
  281. break;
  282. }
  283.  
  284. }
  285.  
  286. return buffer;
  287. }
  288.  
  289. function renderImage(header, payload) {
  290.  
  291. let png = new PNG({
  292. width : header.width,
  293. height : header.height
  294. });
  295.  
  296. // First we read the palette
  297.  
  298. let palette = [];
  299.  
  300. let ofs = 0;
  301.  
  302. for(let p = 0; p < header.palette_count; p++) {
  303.  
  304. let pal = [];
  305. let bits = 0;
  306.  
  307. for(let i = 0; i < header.palette_size; i++) {
  308. let color = payload.readUInt16LE(ofs);
  309. ofs += 2;
  310. bits |= color;
  311.  
  312. pal[i] = {
  313. r : ((color >> 0x00) & 0x1f) << 3,
  314. g : ((color >> 0x05) & 0x1f) << 3,
  315. b : ((color >> 0x0a) & 0x1f) << 3,
  316. a : color > 0 ? 255 : 0
  317. };
  318.  
  319. }
  320.  
  321. if(!bits) {
  322. continue;
  323. }
  324.  
  325. palette.push(pal);
  326.  
  327. }
  328.  
  329. let image_body = [];
  330. while(ofs < payload.length) {
  331. let byte = payload.readUInt8(ofs++);
  332.  
  333. switch(header.bits_per_pixel) {
  334. case 4:
  335. image_body.push(byte & 0xf);
  336. image_body.push(byte >> 4);
  337. break;
  338. case 8:
  339. image_body.push(byte);
  340. break;
  341. }
  342. }
  343.  
  344. for(let p = 0; p < palette.length; p++) {
  345.  
  346. let pal = palette[p];
  347.  
  348. for(let y = 0; y < header.height; y++) {
  349. for(let x = 0; x < header.width; x++) {
  350. let i = header.width * y + x;
  351. let color = pal[image_body[i]]
  352. let idx = i * 4;
  353.  
  354. png.data[idx + 0] = color.r;
  355. png.data[idx + 1] = color.g;
  356. png.data[idx + 2] = color.b;
  357. png.data[idx + 3] = color.a;
  358. }
  359. }
  360.  
  361. let dir = `${OUT_PATH}/${header.stub}`;
  362. if(!fs.existsSync(dir)) {
  363. fs.mkdirSync(dir);
  364. }
  365.  
  366. let buffer = PNG.sync.write(png);
  367. fs.writeFileSync(`${dir}/${header.name}_${p}.png`, buffer);
  368.  
  369. }
  370.  
  371.  
  372. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement