Super Mario 64s source code (from a leak on 4chan so be careful)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

788 lines
22 KiB

5 years ago
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <strings.h>
  4. #define STBI_NO_LINEAR
  5. #define STBI_NO_HDR
  6. #define STBI_NO_TGA
  7. #define STB_IMAGE_IMPLEMENTATION
  8. #include <stb/stb_image.h>
  9. #define STB_IMAGE_WRITE_IMPLEMENTATION
  10. #include <stb/stb_image_write.h>
  11. #include "n64graphics.h"
  12. #include "utils.h"
  13. // SCALE_M_N: upscale/downscale M-bit integer to N-bit
  14. #define SCALE_5_8(VAL_) (((VAL_) * 0xFF) / 0x1F)
  15. #define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF)
  16. #define SCALE_4_8(VAL_) ((VAL_) * 0x11)
  17. #define SCALE_8_4(VAL_) ((VAL_) / 0x11)
  18. #define SCALE_3_8(VAL_) ((VAL_) * 0x24)
  19. #define SCALE_8_3(VAL_) ((VAL_) / 0x24)
  20. typedef enum
  21. {
  22. IMG_FORMAT_RGBA,
  23. IMG_FORMAT_IA,
  24. IMG_FORMAT_I,
  25. IMG_FORMAT_CI,
  26. } img_format;
  27. //---------------------------------------------------------
  28. // N64 RGBA/IA/I/CI -> internal RGBA/IA
  29. //---------------------------------------------------------
  30. rgba *raw2rgba(const uint8_t *raw, int width, int height, int depth)
  31. {
  32. rgba *img;
  33. int img_size;
  34. img_size = width * height * sizeof(*img);
  35. img = malloc(img_size);
  36. if (!img) {
  37. ERROR("Error allocating %d bytes\n", img_size);
  38. return NULL;
  39. }
  40. if (depth == 16) {
  41. for (int i = 0; i < width * height; i++) {
  42. img[i].red = SCALE_5_8((raw[i*2] & 0xF8) >> 3);
  43. img[i].green = SCALE_5_8(((raw[i*2] & 0x07) << 2) | ((raw[i*2+1] & 0xC0) >> 6));
  44. img[i].blue = SCALE_5_8((raw[i*2+1] & 0x3E) >> 1);
  45. img[i].alpha = (raw[i*2+1] & 0x01) ? 0xFF : 0x00;
  46. }
  47. } else if (depth == 32) {
  48. for (int i = 0; i < width * height; i++) {
  49. img[i].red = raw[i*4];
  50. img[i].green = raw[i*4+1];
  51. img[i].blue = raw[i*4+2];
  52. img[i].alpha = raw[i*4+3];
  53. }
  54. }
  55. return img;
  56. }
  57. ia *raw2ia(const uint8_t *raw, int width, int height, int depth)
  58. {
  59. ia *img;
  60. int img_size;
  61. img_size = width * height * sizeof(*img);
  62. img = malloc(img_size);
  63. if (!img) {
  64. ERROR("Error allocating %u bytes\n", img_size);
  65. return NULL;
  66. }
  67. switch (depth) {
  68. case 16:
  69. for (int i = 0; i < width * height; i++) {
  70. img[i].intensity = raw[i*2];
  71. img[i].alpha = raw[i*2+1];
  72. }
  73. break;
  74. case 8:
  75. for (int i = 0; i < width * height; i++) {
  76. img[i].intensity = SCALE_4_8((raw[i] & 0xF0) >> 4);
  77. img[i].alpha = SCALE_4_8(raw[i] & 0x0F);
  78. }
  79. break;
  80. case 4:
  81. for (int i = 0; i < width * height; i++) {
  82. uint8_t bits;
  83. bits = raw[i/2];
  84. if (i % 2) {
  85. bits &= 0xF;
  86. } else {
  87. bits >>= 4;
  88. }
  89. img[i].intensity = SCALE_3_8((bits >> 1) & 0x07);
  90. img[i].alpha = (bits & 0x01) ? 0xFF : 0x00;
  91. }
  92. break;
  93. case 1:
  94. for (int i = 0; i < width * height; i++) {
  95. uint8_t bits;
  96. uint8_t mask;
  97. bits = raw[i/8];
  98. mask = 1 << (7 - (i % 8)); // MSb->LSb
  99. bits = (bits & mask) ? 0xFF : 0x00;
  100. img[i].intensity = bits;
  101. img[i].alpha = bits;
  102. }
  103. break;
  104. default:
  105. ERROR("Error invalid depth %d\n", depth);
  106. break;
  107. }
  108. return img;
  109. }
  110. ia *raw2i(const uint8_t *raw, int width, int height, int depth)
  111. {
  112. ia *img = NULL;
  113. int img_size;
  114. img_size = width * height * sizeof(*img);
  115. img = malloc(img_size);
  116. if (!img) {
  117. ERROR("Error allocating %u bytes\n", img_size);
  118. return NULL;
  119. }
  120. switch (depth) {
  121. case 8:
  122. for (int i = 0; i < width * height; i++) {
  123. img[i].intensity = raw[i];
  124. img[i].alpha = 0xFF;
  125. }
  126. break;
  127. case 4:
  128. for (int i = 0; i < width * height; i++) {
  129. uint8_t bits;
  130. bits = raw[i/2];
  131. if (i % 2) {
  132. bits &= 0xF;
  133. } else {
  134. bits >>= 4;
  135. }
  136. img[i].intensity = SCALE_4_8(bits);
  137. img[i].alpha = 0xFF;
  138. }
  139. break;
  140. default:
  141. ERROR("Error invalid depth %d\n", depth);
  142. break;
  143. }
  144. return img;
  145. }
  146. // extract RGBA from CI raw data and palette
  147. // TODO: different palette depths
  148. rgba *rawci2rgba(const uint8_t *rawci, const uint8_t *palette, int width, int height, int depth)
  149. {
  150. uint8_t *raw_rgba;
  151. rgba *img = NULL;
  152. int raw_size;
  153. // first convert to raw RGBA
  154. raw_size = 2 * width * height;
  155. raw_rgba = malloc(raw_size);
  156. if (!raw_rgba) {
  157. ERROR("Error allocating %u bytes\n", raw_size);
  158. return NULL;
  159. }
  160. for (int i = 0; i < width * height; i++) {
  161. raw_rgba[2*i] = palette[2*rawci[i]];
  162. raw_rgba[2*i+1] = palette[2*rawci[i]+1];
  163. }
  164. // then convert to RGBA image data
  165. img = raw2rgba(raw_rgba, width, height, depth);
  166. free(raw_rgba);
  167. return img;
  168. }
  169. //---------------------------------------------------------
  170. // internal RGBA/IA -> N64 RGBA/IA/I/CI
  171. // returns length written to 'raw' used or -1 on error
  172. //---------------------------------------------------------
  173. int rgba2raw(uint8_t *raw, const rgba *img, int width, int height, int depth)
  174. {
  175. int size = width * height * depth / 8;
  176. INFO("Converting RGBA%d %dx%d to raw\n", depth, width, height);
  177. if (depth == 16) {
  178. for (int i = 0; i < width * height; i++) {
  179. uint8_t r, g, b, a;
  180. r = SCALE_8_5(img[i].red);
  181. g = SCALE_8_5(img[i].green);
  182. b = SCALE_8_5(img[i].blue);
  183. a = img[i].alpha ? 0x1 : 0x0;
  184. raw[i*2] = (r << 3) | (g >> 2);
  185. raw[i*2+1] = ((g & 0x3) << 6) | (b << 1) | a;
  186. }
  187. } else if (depth == 32) {
  188. for (int i = 0; i < width * height; i++) {
  189. raw[i*4] = img[i].red;
  190. raw[i*4+1] = img[i].green;
  191. raw[i*4+2] = img[i].blue;
  192. raw[i*4+3] = img[i].alpha;
  193. }
  194. } else {
  195. ERROR("Error invalid depth %d\n", depth);
  196. size = -1;
  197. }
  198. return size;
  199. }
  200. int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
  201. {
  202. int size = width * height * depth / 8;
  203. INFO("Converting IA%d %dx%d to raw\n", depth, width, height);
  204. switch (depth) {
  205. case 16:
  206. for (int i = 0; i < width * height; i++) {
  207. raw[i*2] = img[i].intensity;
  208. raw[i*2+1] = img[i].alpha;
  209. }
  210. break;
  211. case 8:
  212. for (int i = 0; i < width * height; i++) {
  213. uint8_t val = SCALE_8_4(img[i].intensity);
  214. uint8_t alpha = SCALE_8_4(img[i].alpha);
  215. raw[i] = (val << 4) | alpha;
  216. }
  217. break;
  218. case 4:
  219. for (int i = 0; i < width * height; i++) {
  220. uint8_t val = SCALE_8_3(img[i].intensity);
  221. uint8_t alpha = img[i].alpha ? 0x01 : 0x00;
  222. uint8_t old = raw[i/2];
  223. if (i % 2) {
  224. raw[i/2] = (old & 0xF0) | (val << 1) | alpha;
  225. } else {
  226. raw[i/2] = (old & 0x0F) | (((val << 1) | alpha) << 4);
  227. }
  228. }
  229. break;
  230. case 1:
  231. for (int i = 0; i < width * height; i++) {
  232. uint8_t val = img[i].intensity;
  233. uint8_t old = raw[i/8];
  234. uint8_t bit = 1 << (7 - (i % 8));
  235. if (val) {
  236. raw[i/8] = old | bit;
  237. } else {
  238. raw[i/8] = old & (~bit);
  239. }
  240. }
  241. break;
  242. default:
  243. ERROR("Error invalid depth %d\n", depth);
  244. size = -1;
  245. break;
  246. }
  247. return size;
  248. }
  249. int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
  250. {
  251. int size = width * height * depth / 8;
  252. INFO("Converting I%d %dx%d to raw\n", depth, width, height);
  253. switch (depth) {
  254. case 8:
  255. for (int i = 0; i < width * height; i++) {
  256. raw[i] = img[i].intensity;
  257. }
  258. break;
  259. case 4:
  260. for (int i = 0; i < width * height; i++) {
  261. uint8_t val = SCALE_8_4(img[i].intensity);
  262. uint8_t old = raw[i/2];
  263. if (i % 2) {
  264. raw[i/2] = (old & 0xF0) | val;
  265. } else {
  266. raw[i/2] = (old & 0x0F) | (val << 4);
  267. }
  268. }
  269. break;
  270. default:
  271. ERROR("Error invalid depth %d\n", depth);
  272. size = -1;
  273. break;
  274. }
  275. return size;
  276. }
  277. //---------------------------------------------------------
  278. // internal RGBA/IA -> PNG
  279. //---------------------------------------------------------
  280. int rgba2png(const char *png_filename, const rgba *img, int width, int height)
  281. {
  282. int ret = 0;
  283. INFO("Saving RGBA %dx%d to \"%s\"\n", width, height, png_filename);
  284. // convert to format stb_image_write expects
  285. uint8_t *data = malloc(4*width*height);
  286. if (data) {
  287. for (int j = 0; j < height; j++) {
  288. for (int i = 0; i < width; i++) {
  289. int idx = j*width + i;
  290. data[4*idx] = img[idx].red;
  291. data[4*idx + 1] = img[idx].green;
  292. data[4*idx + 2] = img[idx].blue;
  293. data[4*idx + 3] = img[idx].alpha;
  294. }
  295. }
  296. ret = stbi_write_png(png_filename, width, height, 4, data, 0);
  297. free(data);
  298. }
  299. return ret;
  300. }
  301. int ia2png(const char *png_filename, const ia *img, int width, int height)
  302. {
  303. int ret = 0;
  304. INFO("Saving IA %dx%d to \"%s\"\n", width, height, png_filename);
  305. // convert to format stb_image_write expects
  306. uint8_t *data = malloc(2*width*height);
  307. if (data) {
  308. for (int j = 0; j < height; j++) {
  309. for (int i = 0; i < width; i++) {
  310. int idx = j*width + i;
  311. data[2*idx] = img[idx].intensity;
  312. data[2*idx + 1] = img[idx].alpha;
  313. }
  314. }
  315. ret = stbi_write_png(png_filename, width, height, 2, data, 0);
  316. free(data);
  317. }
  318. return ret;
  319. }
  320. //---------------------------------------------------------
  321. // PNG -> internal RGBA/IA
  322. //---------------------------------------------------------
  323. rgba *png2rgba(const char *png_filename, int *width, int *height)
  324. {
  325. rgba *img = NULL;
  326. int w = 0;
  327. int h = 0;
  328. int channels = 0;
  329. int img_size;
  330. stbi_uc *data = stbi_load(png_filename, &w, &h, &channels, STBI_default);
  331. if (!data || w <= 0 || h <= 0) {
  332. ERROR("Error loading \"%s\"\n", png_filename);
  333. return NULL;
  334. }
  335. INFO("Read \"%s\" %dx%d channels: %d\n", png_filename, w, h, channels);
  336. img_size = w * h * sizeof(*img);
  337. img = malloc(img_size);
  338. if (!img) {
  339. ERROR("Error allocating %u bytes\n", img_size);
  340. return NULL;
  341. }
  342. switch (channels) {
  343. case 3: // red, green, blue
  344. case 4: // red, green, blue, alpha
  345. for (int j = 0; j < h; j++) {
  346. for (int i = 0; i < w; i++) {
  347. int idx = j*w + i;
  348. img[idx].red = data[channels*idx];
  349. img[idx].green = data[channels*idx + 1];
  350. img[idx].blue = data[channels*idx + 2];
  351. if (channels == 4) {
  352. img[idx].alpha = data[channels*idx + 3];
  353. } else {
  354. img[idx].alpha = 0xFF;
  355. }
  356. }
  357. }
  358. break;
  359. case 2: // grey, alpha
  360. for (int j = 0; j < h; j++) {
  361. for (int i = 0; i < w; i++) {
  362. int idx = j*w + i;
  363. img[idx].red = data[2*idx];
  364. img[idx].green = data[2*idx];
  365. img[idx].blue = data[2*idx];
  366. img[idx].alpha = data[2*idx + 1];
  367. }
  368. }
  369. break;
  370. default:
  371. ERROR("Don't know how to read channels: %d\n", channels);
  372. free(img);
  373. img = NULL;
  374. }
  375. // cleanup
  376. stbi_image_free(data);
  377. *width = w;
  378. *height = h;
  379. return img;
  380. }
  381. ia *png2ia(const char *png_filename, int *width, int *height)
  382. {
  383. ia *img = NULL;
  384. int w = 0, h = 0;
  385. int channels = 0;
  386. int img_size;
  387. stbi_uc *data = stbi_load(png_filename, &w, &h, &channels, STBI_default);
  388. if (!data || w <= 0 || h <= 0) {
  389. ERROR("Error loading \"%s\"\n", png_filename);
  390. return NULL;
  391. }
  392. INFO("Read \"%s\" %dx%d channels: %d\n", png_filename, w, h, channels);
  393. img_size = w * h * sizeof(*img);
  394. img = malloc(img_size);
  395. if (!img) {
  396. ERROR("Error allocating %d bytes\n", img_size);
  397. return NULL;
  398. }
  399. switch (channels) {
  400. case 3: // red, green, blue
  401. case 4: // red, green, blue, alpha
  402. ERROR("Warning: averaging RGB PNG to create IA\n");
  403. for (int j = 0; j < h; j++) {
  404. for (int i = 0; i < w; i++) {
  405. int idx = j*w + i;
  406. int sum = data[channels*idx] + data[channels*idx + 1] + data[channels*idx + 2];
  407. img[idx].intensity = (sum + 1) / 3; // add 1 to round up where appropriate
  408. if (channels == 4) {
  409. img[idx].alpha = data[channels*idx + 3];
  410. } else {
  411. img[idx].alpha = 0xFF;
  412. }
  413. }
  414. }
  415. break;
  416. case 2: // grey, alpha
  417. for (int j = 0; j < h; j++) {
  418. for (int i = 0; i < w; i++) {
  419. int idx = j*w + i;
  420. img[idx].intensity = data[2*idx];
  421. img[idx].alpha = data[2*idx + 1];
  422. }
  423. }
  424. break;
  425. default:
  426. ERROR("Don't know how to read channels: %d\n", channels);
  427. free(img);
  428. img = NULL;
  429. }
  430. // cleanup
  431. stbi_image_free(data);
  432. *width = w;
  433. *height = h;
  434. return img;
  435. }
  436. const char *n64graphics_get_read_version(void)
  437. {
  438. return "stb_image 2.19";
  439. }
  440. const char *n64graphics_get_write_version(void)
  441. {
  442. return "stb_image_write 1.09";
  443. }
  444. #ifdef N64GRAPHICS_STANDALONE
  445. #define N64GRAPHICS_VERSION "0.3"
  446. #include <string.h>
  447. typedef enum
  448. {
  449. MODE_EXPORT,
  450. MODE_IMPORT,
  451. } tool_mode;
  452. typedef struct
  453. {
  454. char *img_filename;
  455. char *bin_filename;
  456. tool_mode mode;
  457. unsigned int offset;
  458. img_format format;
  459. int depth;
  460. int width;
  461. int height;
  462. int truncate;
  463. } graphics_config;
  464. static const graphics_config default_config =
  465. {
  466. .img_filename = NULL,
  467. .bin_filename = NULL,
  468. .mode = MODE_EXPORT,
  469. .offset = 0,
  470. .format = IMG_FORMAT_RGBA,
  471. .depth = 16,
  472. .width = 32,
  473. .height = 32,
  474. .truncate = 1,
  475. };
  476. typedef struct
  477. {
  478. const char *name;
  479. img_format format;
  480. int depth;
  481. } format_entry;
  482. static const format_entry format_table[] =
  483. {
  484. {"rgba16", IMG_FORMAT_RGBA, 16},
  485. {"rgba32", IMG_FORMAT_RGBA, 32},
  486. {"ia1", IMG_FORMAT_IA, 1},
  487. {"ia4", IMG_FORMAT_IA, 4},
  488. {"ia8", IMG_FORMAT_IA, 8},
  489. {"ia16", IMG_FORMAT_IA, 16},
  490. {"i4", IMG_FORMAT_I, 4},
  491. {"i8", IMG_FORMAT_I, 8},
  492. {"ci8", IMG_FORMAT_CI, 8},
  493. {"ci16", IMG_FORMAT_CI, 16},
  494. };
  495. static const char *format2str(img_format format, int depth)
  496. {
  497. for (unsigned i = 0; i < DIM(format_table); i++) {
  498. if (format == format_table[i].format && depth == format_table[i].depth) {
  499. return format_table[i].name;
  500. }
  501. }
  502. return "unknown";
  503. }
  504. static int parse_format(graphics_config *config, const char *str)
  505. {
  506. for (unsigned i = 0; i < DIM(format_table); i++) {
  507. if (!strcasecmp(str, format_table[i].name)) {
  508. config->format = format_table[i].format;
  509. config->depth = format_table[i].depth;
  510. return 1;
  511. }
  512. }
  513. return 0;
  514. }
  515. static void print_usage(void)
  516. {
  517. ERROR("Usage: n64graphics -e/-i BIN_FILE -g PNG_FILE [-o offset] [-f FORMAT] [-w WIDTH] [-h HEIGHT] [-V]\n"
  518. "\n"
  519. "n64graphics v" N64GRAPHICS_VERSION ": N64 graphics manipulator\n"
  520. "\n"
  521. "Required arguments:\n"
  522. " -e BIN_FILE export from BIN_FILE to PNG_FILE\n"
  523. " -i BIN_FILE import from PNG_FILE to BIN_FILE\n"
  524. " -g PNG_FILE graphics file to import/export (.png)\n"
  525. "Optional arguments:\n"
  526. " -o OFFSET starting offset in BIN_FILE (prevents truncation during import)\n"
  527. " -f FORMAT texture format: rgba16, rgba32, ia1, ia4, ia8, ia16, i4, i8, ci8, ci16 (default: %s)\n"
  528. " -w WIDTH export texture width (default: %d)\n"
  529. " -h HEIGHT export texture height (default: %d)\n"
  530. " -v verbose logging\n"
  531. " -V print version information\n",
  532. format2str(default_config.format, default_config.depth),
  533. default_config.width,
  534. default_config.height);
  535. }
  536. static void print_version(void)
  537. {
  538. ERROR("n64graphics v" N64GRAPHICS_VERSION ", using:\n"
  539. " %s\n"
  540. " %s\n",
  541. n64graphics_get_read_version(), n64graphics_get_write_version());
  542. }
  543. // parse command line arguments
  544. static int parse_arguments(int argc, char *argv[], graphics_config *config)
  545. {
  546. for (int i = 1; i < argc; i++) {
  547. if (argv[i][0] == '-') {
  548. switch (argv[i][1]) {
  549. case 'e':
  550. if (++i >= argc) return 0;
  551. config->bin_filename = argv[i];
  552. config->mode = MODE_EXPORT;
  553. break;
  554. case 'f':
  555. if (++i >= argc) return 0;
  556. if (!parse_format(config, argv[i])) {
  557. return 0;
  558. }
  559. break;
  560. case 'i':
  561. if (++i >= argc) return 0;
  562. config->bin_filename = argv[i];
  563. config->mode = MODE_IMPORT;
  564. break;
  565. case 'g':
  566. if (++i >= argc) return 0;
  567. config->img_filename = argv[i];
  568. break;
  569. case 'h':
  570. if (++i >= argc) return 0;
  571. config->height = strtoul(argv[i], NULL, 0);
  572. break;
  573. case 'o':
  574. if (++i >= argc) return 0;
  575. config->offset = strtoul(argv[i], NULL, 0);
  576. config->truncate = 0;
  577. break;
  578. case 'w':
  579. if (++i >= argc) return 0;
  580. config->width = strtoul(argv[i], NULL, 0);
  581. break;
  582. case 'v':
  583. g_verbosity = 1;
  584. break;
  585. case 'V':
  586. print_version();
  587. exit(0);
  588. break;
  589. default:
  590. return 0;
  591. break;
  592. }
  593. } else {
  594. return 0;
  595. }
  596. }
  597. return 1;
  598. }
  599. int main(int argc, char *argv[])
  600. {
  601. graphics_config config = default_config;
  602. rgba *imgr;
  603. ia *imgi;
  604. FILE *fp;
  605. uint8_t *raw;
  606. int raw_size;
  607. int length = 0;
  608. int flength;
  609. int res;
  610. int valid = parse_arguments(argc, argv, &config);
  611. if (!valid || !config.bin_filename || !config.bin_filename) {
  612. print_usage();
  613. exit(EXIT_FAILURE);
  614. }
  615. if (config.mode == MODE_IMPORT) {
  616. if (config.truncate) {
  617. fp = fopen(config.bin_filename, "w");
  618. } else {
  619. fp = fopen(config.bin_filename, "r+");
  620. }
  621. if (!fp) {
  622. ERROR("Error opening \"%s\"\n", config.bin_filename);
  623. return -1;
  624. }
  625. if (!config.truncate) {
  626. fseek(fp, config.offset, SEEK_SET);
  627. }
  628. switch (config.format) {
  629. case IMG_FORMAT_RGBA:
  630. imgr = png2rgba(config.img_filename, &config.width, &config.height);
  631. raw_size = config.width * config.height * config.depth / 8;
  632. raw = malloc(raw_size);
  633. if (!raw) {
  634. ERROR("Error allocating %u bytes\n", raw_size);
  635. }
  636. length = rgba2raw(raw, imgr, config.width, config.height, config.depth);
  637. break;
  638. case IMG_FORMAT_IA:
  639. imgi = png2ia(config.img_filename, &config.width, &config.height);
  640. raw_size = config.width * config.height * config.depth / 8;
  641. raw = malloc(raw_size);
  642. if (!raw) {
  643. ERROR("Error allocating %u bytes\n", raw_size);
  644. }
  645. length = ia2raw(raw, imgi, config.width, config.height, config.depth);
  646. break;
  647. case IMG_FORMAT_I:
  648. imgi = png2ia(config.img_filename, &config.width, &config.height);
  649. raw_size = config.width * config.height * config.depth / 8;
  650. raw = malloc(raw_size);
  651. if (!raw) {
  652. ERROR("Error allocating %u bytes\n", raw_size);
  653. }
  654. length = i2raw(raw, imgi, config.width, config.height, config.depth);
  655. break;
  656. default:
  657. return EXIT_FAILURE;
  658. }
  659. if (length <= 0) {
  660. ERROR("Error converting to raw format\n");
  661. return EXIT_FAILURE;
  662. }
  663. INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", length, config.offset, config.bin_filename);
  664. flength = fwrite(raw, 1, length, fp);
  665. if (flength != length) {
  666. ERROR("Error writing %d bytes to \"%s\"\n", length, config.bin_filename);
  667. }
  668. fclose(fp);
  669. } else {
  670. if (config.width <= 0 || config.height <= 0 || config.depth <= 0) {
  671. ERROR("Error: must set position width and height for export\n");
  672. return EXIT_FAILURE;
  673. }
  674. fp = fopen(config.bin_filename, "r");
  675. if (!fp) {
  676. ERROR("Error opening \"%s\"\n", config.bin_filename);
  677. return -1;
  678. }
  679. raw_size = config.width * config.height * config.depth / 8;
  680. raw = malloc(raw_size);
  681. if (config.offset > 0) {
  682. fseek(fp, config.offset, SEEK_SET);
  683. }
  684. flength = fread(raw, 1, raw_size, fp);
  685. if (flength != raw_size) {
  686. ERROR("Error reading %d bytes from \"%s\"\n", raw_size, config.bin_filename);
  687. }
  688. switch (config.format) {
  689. case IMG_FORMAT_RGBA:
  690. imgr = raw2rgba(raw, config.width, config.height, config.depth);
  691. res = rgba2png(config.img_filename, imgr, config.width, config.height);
  692. break;
  693. case IMG_FORMAT_IA:
  694. imgi = raw2ia(raw, config.width, config.height, config.depth);
  695. res = ia2png(config.img_filename, imgi, config.width, config.height);
  696. break;
  697. case IMG_FORMAT_I:
  698. imgi = raw2i(raw, config.width, config.height, config.depth);
  699. res = ia2png(config.img_filename, imgi, config.width, config.height);
  700. break;
  701. default:
  702. return EXIT_FAILURE;
  703. }
  704. if (!res) {
  705. ERROR("Error writing to \"%s\"\n", config.img_filename);
  706. }
  707. }
  708. return EXIT_SUCCESS;
  709. }
  710. #endif // N64GRAPHICS_STANDALONE