PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/lpf2ani/lpf2ani.c

https://github.com/0xDEC0DE/sc2-uqm
C | 1325 lines | 1068 code | 210 blank | 47 comment | 271 complexity | f511a107b5c124d8acec0d331e1b0cbd MD5 | raw file
Possible License(s): GPL-2.0
  1. /**
  2. * DOS SC2 LPF animation files converter (.anm?)
  3. * By Alex Volkov (codepro@usa.net), 20050121
  4. * GPL applies
  5. *
  6. * The frames are dumped into separate paletted 8bpp PNGs;
  7. * .ani and presentation .txt files are created
  8. *
  9. **/
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <stdarg.h>
  13. #include <string.h>
  14. #include <malloc.h>
  15. #ifdef WIN32
  16. # include <getopt.h>
  17. #else
  18. # include <unistd.h>
  19. #endif
  20. #include <png.h>
  21. #if defined(__GNUC__)
  22. # include <alloca.h>
  23. #endif
  24. #include "lpf.h"
  25. int opt_verbose = 0;
  26. int opt_framerate = 0;
  27. char* opt_inname = 0;
  28. char* opt_outname = 0;
  29. int opt_deltamask = 0;
  30. int opt_fullrects = 0;
  31. int opt_sectorsize = 8;
  32. char* opt_actfile = 0;
  33. header hdr;
  34. framepackinfo* packs = 0;
  35. const char* outmask = 0;
  36. png_color* palette = 0;
  37. uint8_t buf[0x10000];
  38. uint8_t* fimg = 0;
  39. uint32_t fimgsize = 0;
  40. // internals
  41. int error(int errn, const char* fmt, const char* s);
  42. void verbose(const char* fmt, ...);
  43. typedef struct _file_info
  44. {
  45. int w, h;
  46. int x, y;
  47. uint8_t* image;
  48. int timestamp;
  49. int index;
  50. int identical;
  51. struct _file_info* next;
  52. } file_info;
  53. void file_infos_free();
  54. void file_info_init(file_info* ms);
  55. void file_info_cleanup(file_info* ms);
  56. int cInfos = 0;
  57. file_info* Infos = 0;
  58. int framedelay = 100; // default 10 fps
  59. int _curframe = -1;
  60. int _curdeltaframe = -1;
  61. int error(int errn, const char* fmt, const char* s)
  62. {
  63. fprintf(stderr, fmt, s);
  64. return errn;
  65. }
  66. void verbose(const char* fmt, ...)
  67. {
  68. va_list args;
  69. if (!opt_verbose)
  70. return;
  71. va_start(args, fmt);
  72. vfprintf(stderr, fmt, args);
  73. va_end(args);
  74. }
  75. int readhead(FILE* f)
  76. {
  77. if (fread(&hdr, sizeof(hdr), 1, f) != 1)
  78. return 250;
  79. verbose("Total frames %u\n", hdr.cframes);
  80. return 0;
  81. }
  82. int readpalette(FILE* f)
  83. {
  84. int i;
  85. lpfpalcolor* lpfpal;
  86. verbose("Converting palette, %d colors...\n", PAL_COLORS);
  87. lpfpal = (lpfpalcolor*) alloca(sizeof(lpfpalcolor) * PAL_COLORS);
  88. palette = (png_color*) malloc(sizeof(png_color) * PAL_COLORS);
  89. if (!lpfpal || !palette)
  90. return 240;
  91. fseek(f, hdr.opal, SEEK_SET);
  92. if (fread(lpfpal, sizeof(lpfpalcolor), PAL_COLORS, f) != PAL_COLORS)
  93. return 241;
  94. for (i = 0; i < PAL_COLORS; i++)
  95. {
  96. palette[i].red = lpfpal[i].bchan.r;
  97. palette[i].green = lpfpal[i].bchan.g;
  98. palette[i].blue = lpfpal[i].bchan.b;
  99. }
  100. return 0;
  101. }
  102. int writepalette(const char* actfile)
  103. {
  104. FILE* f;
  105. int c;
  106. f = fopen(actfile, "wb");
  107. if (!f)
  108. return 231;
  109. c = fwrite(palette, sizeof(palette[0]), PAL_COLORS, f);
  110. fclose(f);
  111. return c == PAL_COLORS ? 0 : 232;
  112. }
  113. int processpacks(FILE* f)
  114. {
  115. int i, j, k;
  116. uint32_t packofs;
  117. framepack* pack;
  118. packs = (framepackinfo*) calloc(sizeof(framepackinfo), hdr.cpacks);
  119. pack = (framepack*) alloca(sizeof(framepack) + sizeof(uint16_t) * 128);
  120. if (!packs || !pack)
  121. return 230;
  122. fseek(f, hdr.opacks, SEEK_SET);
  123. if (fread(packs, sizeof(framepackinfo), hdr.cpacks, f) != hdr.cpacks)
  124. return 231;
  125. packofs = hdr.opacks + hdr.cpackslots * sizeof(framepackinfo);
  126. // dump packs
  127. for (i = 0; i < hdr.cpacks; ++i)
  128. {
  129. verbose("pack %02d: start frame %03d, frames %03d\n", i, packs[i].frame, packs[i].cframes);
  130. fseek(f, packofs + i * 0x10000, SEEK_SET);
  131. fread(pack, FRAMEPACK_SIZE(packs[i]), 1, f);
  132. for (j = 0; j < pack->info.cframes; ++j)
  133. {
  134. verbose("\tframe %03d: size 0x%04x", pack->info.frame + j, pack->sizes[j]);
  135. if (pack->sizes[j])
  136. {
  137. fread(buf, 1, pack->sizes[j], f);
  138. verbose(" dump ");
  139. for (k = 0; k < 16 && k < pack->sizes[j]; ++k)
  140. verbose("%02x ", buf[k]);
  141. }
  142. verbose("\n");
  143. }
  144. }
  145. return 0;
  146. }
  147. int processframe(uint8_t* frame, int size, uint8_t* image)
  148. {
  149. uint8_t* fd;
  150. uint8_t* fe;
  151. uint8_t* fo;
  152. int total = 0;
  153. int i;
  154. if (size == 0)
  155. return total;
  156. size -= sizeof(frameheader);
  157. frame += sizeof(frameheader);
  158. verbose("\tpacked data: ");
  159. for (i = 0; i < 16 && i < size; i++)
  160. verbose("%02x ", frame[i]);
  161. verbose("\n");
  162. for (fd = frame, fe = frame + size, fo = image; fd < fe; )
  163. {
  164. uint8_t flags = *fd++;
  165. int count = flags & FD_COUNT_MASK;
  166. if (flags & FD_EXT_FLAG)
  167. {
  168. if (count == 0)
  169. { // ext
  170. uint16_t flags = *((uint16_t*)fd)++;
  171. if (flags & FD_EXT_FLAG1)
  172. {
  173. count = flags & FD_EXT_RCOUNT_MASK;
  174. if (flags & FD_EXT_FLAG2)
  175. { // repeat
  176. uint8_t pixel = *fd++;
  177. //verbose("\t\tlong repeat: %04x, pixel %02x, ofs %04x\n", flags, pixel, fd - frame + 4);
  178. memset(fo, pixel, count);
  179. fo += count;
  180. total += count;
  181. }
  182. else
  183. { // quote
  184. //verbose("\t\tlong quote: %04x, ofs %04x\n", flags, fd - frame + 4);
  185. memcpy(fo, fd, count);
  186. fd += count;
  187. fo += count;
  188. total += count;
  189. }
  190. }
  191. else
  192. { // skip
  193. count = flags & FD_EXT_SCOUNT_MASK;
  194. fo += count;
  195. total += count;
  196. }
  197. }
  198. else
  199. { // skip
  200. //verbose("\t\tshort skip: %02x, ofs %04x\n", fd->skip.count, (uint8_t*)fd - frame + 4);
  201. fo += count;
  202. total += count;
  203. }
  204. }
  205. else
  206. {
  207. if (count == 0)
  208. { // repeat
  209. uint8_t pixel;
  210. count = *fd++;
  211. pixel = *fd++;
  212. memset(fo, pixel, count);
  213. fo += count;
  214. total += count;
  215. }
  216. else
  217. { // quote
  218. memcpy(fo, fd, count);
  219. fd += count;
  220. fo += count;
  221. total += count;
  222. }
  223. }
  224. }
  225. verbose("\t\toutput bytes: %04x\n", total);
  226. return total;
  227. }
  228. int packfromframe(uint16_t iframe)
  229. {
  230. uint16_t i;
  231. for (i = 0; i < hdr.cpacks && (iframe < packs[i].frame || iframe >= packs[i].frame + packs[i].cframes); ++i)
  232. ;
  233. return i;
  234. }
  235. int write_png(const char* filename, uint8_t* fimg, uint32_t w, uint32_t h, png_colorp pal, uint32_t cpal)
  236. {
  237. FILE* out;
  238. png_structp png;
  239. png_infop pngi;
  240. png_bytepp rows;
  241. uint32_t i;
  242. out = fopen(filename, "wb");
  243. if (!out)
  244. return -1;
  245. png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  246. if (!png)
  247. {
  248. fclose(out);
  249. return -1;
  250. }
  251. pngi = png_create_info_struct(png);
  252. if (!pngi)
  253. {
  254. png_destroy_write_struct(&png, (png_infopp)NULL);
  255. fclose(out);
  256. return -1;
  257. }
  258. rows = malloc(sizeof(png_bytep) * h);
  259. if (!rows)
  260. {
  261. png_destroy_write_struct(&png, (png_infopp)NULL);
  262. fclose(out);
  263. return -1;
  264. }
  265. for (i = 0; i < h; ++i)
  266. rows[i] = fimg + i * w;
  267. if (setjmp(png_jmpbuf(png)))
  268. {
  269. png_destroy_write_struct(&png, &pngi);
  270. free(rows);
  271. fclose(out);
  272. return -1;
  273. }
  274. png_init_io(png, out);
  275. png_set_filter(png, 0, PNG_FILTER_NONE);
  276. png_set_compression_level(png, Z_BEST_COMPRESSION);
  277. png_set_IHDR(png, pngi, w, h, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  278. png_set_PLTE(png, pngi, pal, cpal);
  279. png_set_rows(png, pngi, rows);
  280. //png_write_png(png, pngi, PNG_TRANSFORM_IDENTITY, NULL);
  281. png_write_info(png, pngi);
  282. png_write_image(png, rows);
  283. png_write_end(png, pngi);
  284. png_destroy_write_struct(&png, &pngi);
  285. fclose(out);
  286. free(rows);
  287. return 0;
  288. }
  289. int compare_images(file_info* i1, file_info* i2)
  290. {
  291. int cnt = 0;
  292. int w, h, x, y;
  293. int dx1, dx2, dy1, dy2;
  294. if (i1->w > i2->w)
  295. {
  296. w = i2->w;
  297. dx1 = i2->x;
  298. dx2 = 0;
  299. }
  300. else if (i1->w < i2->w)
  301. {
  302. w = i1->w;
  303. dx1 = 0;
  304. dx2 = i1->x;
  305. }
  306. else
  307. {
  308. w = i1->w;
  309. dx1 = dx2 = 0;
  310. }
  311. if (i1->h > i2->h)
  312. {
  313. h = i2->h;
  314. dy1 = i2->y;
  315. dy2 = 0;
  316. }
  317. else if (i1->h < i2->h)
  318. {
  319. h = i1->h;
  320. dy1 = 0;
  321. dy2 = i1->y;
  322. }
  323. else
  324. {
  325. h = i1->h;
  326. dy1 = dy2 = 0;
  327. }
  328. for (y = 0; y < h; y++)
  329. {
  330. for (x = 0; x < w; x++)
  331. {
  332. if (i1->image[(y + dy1) * i1->w + x + dx1] != i2->image[(y + dy2) * i2->w + x + dx2])
  333. cnt++;
  334. }
  335. }
  336. return cnt;
  337. }
  338. int equal_images(int i1, int i2)
  339. {
  340. // deference identical chain
  341. while (Infos[i1].identical != -1)
  342. i1 = Infos[i1].identical;
  343. while (Infos[i2].identical != -1)
  344. i2 = Infos[i2].identical;
  345. if (i1 == i2)
  346. return 1;
  347. if (Infos[i1].x != Infos[i2].x || Infos[i1].y != Infos[i2].y
  348. || Infos[i1].w != Infos[i2].w || Infos[i1].h != Infos[i2].h)
  349. return 0;
  350. return compare_images(Infos + i1, Infos + i2) == 0;
  351. }
  352. int delta_adjust_positions(int* pos1, int* pos2)
  353. {
  354. if (*pos1 <= *pos2)
  355. return 1;
  356. else
  357. {
  358. (*pos1)--;
  359. (*pos2)--;
  360. return -1;
  361. }
  362. }
  363. void clean_expansion_horz(unsigned char* mask, int w, int x1, int y1, int x2, int y2, int threshold)
  364. {
  365. int x, y, dx, dy;
  366. // assume anything out of bounds is cleared
  367. int prevclear = threshold + 1;
  368. dy = delta_adjust_positions (&y1, &y2);
  369. dx = delta_adjust_positions (&x1, &x2);
  370. for (y = y1; y != y2; y += dy)
  371. {
  372. int dcnt, ecnt;
  373. dcnt = ecnt = 0;
  374. for (x = x1; x != x2; x += dx)
  375. {
  376. if (mask[y * w + x] == 1)
  377. dcnt++;
  378. else if (mask[y * w + x] == 2 || mask[y * w + x] == 3)
  379. ecnt++;
  380. }
  381. if (dcnt == 0 && ecnt == 0)
  382. { // line is clear
  383. prevclear++;
  384. }
  385. else if (dcnt == 0)
  386. {
  387. if (prevclear >= threshold)
  388. { // it's not clear yet, but it will be in a moment ;)
  389. int lx, ly = y;
  390. if (prevclear == threshold)
  391. { // need to clean everything we just checked
  392. ly = y - prevclear * dy;
  393. }
  394. for (ly = ly; ly != y + dy; ly += dy)
  395. for (lx = x1; lx != x2; lx += dx)
  396. mask[ly * w + lx] = 0;
  397. }
  398. prevclear++;
  399. }
  400. else
  401. { // line is dirty
  402. prevclear = 0;
  403. }
  404. }
  405. }
  406. void clean_expansion_vert(unsigned char* mask, int w, int x1, int y1, int x2, int y2, int threshold)
  407. {
  408. int x, y, dx, dy;
  409. // assume anything out of bounds is cleared
  410. int prevclear = threshold + 1;
  411. dy = delta_adjust_positions (&y1, &y2);
  412. dx = delta_adjust_positions (&x1, &x2);
  413. for (x = x1; x != x2; x += dx)
  414. {
  415. int dcnt, ecnt;
  416. dcnt = ecnt = 0;
  417. for (y = y1; y != y2; y += dy)
  418. {
  419. if (mask[y * w + x] == 1)
  420. dcnt++;
  421. else if (mask[y * w + x] == 2 || mask[y * w + x] == 3)
  422. ecnt++;
  423. }
  424. if (dcnt == 0 && ecnt == 0)
  425. { // line is clear
  426. prevclear++;
  427. }
  428. else if (dcnt == 0)
  429. {
  430. if (prevclear >= threshold)
  431. { // it's not clear yet, but it will be in a moment ;)
  432. int ly, lx = x;
  433. if (prevclear == threshold)
  434. { // need to clean everything we just checked
  435. lx = x - prevclear * dx;
  436. }
  437. for (lx = lx; lx != x + dx; lx += dx)
  438. for (ly = y1; ly != y2; ly += dy)
  439. mask[ly * w + lx] = 0;
  440. }
  441. prevclear++;
  442. }
  443. else
  444. { // line is dirty
  445. prevclear = 0;
  446. }
  447. }
  448. }
  449. struct _expand_corner
  450. {
  451. int x, y;
  452. int tx1, ty1;
  453. int tx2, ty2;
  454. }
  455. const expand_corner [] =
  456. {
  457. {0, 0, 1, 0, 0, 1}, // top-left
  458. {1, 0, 0, 0, 0, 1}, // top-mid, from left
  459. {1, 0, 2, 0, 2, 1}, // top-mid, from right
  460. {2, 0, 1, 0, 2, 1}, // top-right
  461. {0, 1, 0, 0, 1, 0}, // mid-left, from top
  462. {0, 1, 0, 2, 1, 2}, // mid-left, from bottom
  463. {2, 1, 1, 0, 2, 0}, // mid-right, from top
  464. {2, 1, 1, 2, 2, 2}, // mid-right, from bottom
  465. {0, 2, 1, 2, 0, 1}, // bot-left
  466. {1, 2, 0, 1, 0, 2}, // bot-mid, from left
  467. {1, 2, 2, 1, 2, 2}, // bot-mid, from right
  468. {2, 2, 1, 2, 2, 1}, // bot-right
  469. {-1,-1, -1,-1, -1,-1} // term
  470. };
  471. // this will recursively expand the missing corner pixels
  472. // recursion is limited so we dont overflow the stack
  473. int expand_rect(char* mask, int x, int y, int w, int h)
  474. {
  475. static int level = 0;
  476. int x1, y1, x2, y2, i, lx, ly;
  477. const struct _expand_corner* pc;
  478. signed char matrix[3][3];
  479. int cnt = 0;
  480. if (level > 99)
  481. return 1; // make sure parent knows it failed
  482. level++;
  483. if (x > 0)
  484. x1 = x - 1;
  485. else
  486. {
  487. for (i = 0; i < 3; i++)
  488. matrix[0][i] = -1;
  489. x1 = x;
  490. }
  491. if (y > 0)
  492. y1 = y - 1;
  493. else
  494. {
  495. for (i = 0; i < 3; i++)
  496. matrix[i][0] = -1;
  497. y1 = y;
  498. }
  499. if (x + 1 < w)
  500. x2 = x + 2;
  501. else
  502. {
  503. for (i = 0; i < 3; i++)
  504. matrix[2][i] = -1;
  505. x2 = x + 1;
  506. }
  507. if (y + 1 < h)
  508. y2 = y + 2;
  509. else
  510. {
  511. for (i = 0; i < 3; i++)
  512. matrix[i][2] = -1;
  513. y2 = y + 1;
  514. }
  515. for (ly = y1; ly < y2; ly++)
  516. for (lx = x1; lx < x2; lx++)
  517. matrix[lx - x + 1][ly - y + 1] = mask[ly * w + lx];
  518. // check corner pixels
  519. for (pc = expand_corner; pc->x != -1; pc++)
  520. {
  521. if (matrix[pc->x][pc->y] == 0 && matrix[pc->tx1][pc->ty1] > 0 && matrix[pc->tx2][pc->ty2] > 0)
  522. { // corner pixel missing
  523. int ofs = (y - 1 + pc->y) * w + (x - 1 + pc->x);
  524. matrix[pc->x][pc->y] = 3;
  525. // but it may already be present in the mask (recursive)
  526. if (mask[ofs] == 0)
  527. {
  528. mask[ofs] = 3;
  529. cnt += 1 + expand_rect (mask, x - 1 + pc->x, y - 1 + pc->y, w, h);
  530. }
  531. }
  532. }
  533. level--;
  534. return cnt;
  535. }
  536. file_info* file_info_add_image (file_info* fi)
  537. {
  538. file_info* ni;
  539. ni = (file_info*) malloc(sizeof(file_info));
  540. if (!ni)
  541. return 0;
  542. file_info_init(ni);
  543. while (fi->next)
  544. fi = fi->next;
  545. return fi->next = ni;
  546. }
  547. int is_multi_delta_image (file_info* fi)
  548. {
  549. return fi && fi->next;
  550. }
  551. #define MASK_COLORS 4
  552. png_color mask_pal[MASK_COLORS] =
  553. {
  554. {0x00, 0x00, 0x00},
  555. {0xff, 0xff, 0xff},
  556. {0x00, 0xff, 0x00},
  557. {0x00, 0x00, 0xff}
  558. };
  559. void create_mask_png (uint8_t* mask, int w, int h)
  560. {
  561. char fname[260];
  562. sprintf(fname, "mask_%03d_%03d.png", _curframe, _curdeltaframe);
  563. write_png(fname, mask, w, h, mask_pal, MASK_COLORS);
  564. }
  565. int build_delta(file_info* i1, file_info* i2)
  566. {
  567. int w, h, x, y;
  568. int dx1, dx2, dy1, dy2;
  569. int cnt;
  570. char* mask = 0;
  571. if (i1->w > i2->w)
  572. {
  573. w = i2->w;
  574. dx1 = i2->x;
  575. dx2 = 0;
  576. }
  577. else if (i1->w < i2->w)
  578. {
  579. w = i1->w;
  580. dx1 = 0;
  581. dx2 = i1->x;
  582. }
  583. else
  584. {
  585. w = i1->w;
  586. dx1 = dx2 = 0;
  587. }
  588. if (i1->h > i2->h)
  589. {
  590. h = i2->h;
  591. dy1 = i2->y;
  592. dy2 = 0;
  593. }
  594. else if (i1->h < i2->h)
  595. {
  596. h = i1->h;
  597. dy1 = 0;
  598. dy2 = i1->y;
  599. }
  600. else
  601. {
  602. h = i1->h;
  603. dy1 = dy2 = 0;
  604. }
  605. mask = (char*) malloc(w * h);
  606. if (!mask)
  607. return 220;
  608. memset(mask, 0, w * h);
  609. // build diff mask first
  610. for (y = 0; y < h; y++)
  611. {
  612. for (x = 0; x < w; x++)
  613. {
  614. if (i1->image[(y + dy1) * i1->w + x + dx1] != i2->image[(y + dy2) * i2->w + x + dx2])
  615. // diff pixel
  616. mask[y * w + x] = 1;
  617. }
  618. }
  619. // coarse expand the diff pixels
  620. for (y = 0; y < h; y++)
  621. {
  622. for (x = 0; x < w; x++)
  623. {
  624. if (mask[y * w + x] == 1)
  625. {
  626. int x1 = x - 2;
  627. int x2 = x + 3;
  628. int y1 = y - 2;
  629. int y2 = y + 3;
  630. int lx;
  631. if (x1 < 0)
  632. x1 = 0;
  633. if (x2 > w)
  634. x2 = w;
  635. if (y1 < 0)
  636. y1 = 0;
  637. if (y2 > h)
  638. y2 = h;
  639. for (y1 = y1; y1 < y2; y1++)
  640. for (lx = x1; lx < x2; lx++)
  641. if (mask[y1 * w + lx] == 0)
  642. mask[y1 * w + lx] = 2;
  643. }
  644. }
  645. }
  646. // scan and remove extra expansion horizontally and vertically
  647. clean_expansion_vert (mask, w, 0, 0, w, h, 1);
  648. clean_expansion_vert (mask, w, w, 0, 0, h, 1);
  649. clean_expansion_horz (mask, w, 0, 0, w, h, 1);
  650. clean_expansion_horz (mask, w, 0, h, w, 0, 1);
  651. do // coarse expand the diff pixels
  652. { // merge would-be diff rectangles in the process
  653. cnt = 0;
  654. for (y = 0; y < h; y++)
  655. {
  656. for (x = 0; x < w; x++)
  657. {
  658. if (mask[y * w + x] != 0)
  659. cnt += expand_rect (mask, x, y, w, h);
  660. }
  661. }
  662. // repeat is something was expanded
  663. } while (cnt != 0);
  664. // at this point we should have guaranteed non-overlapping
  665. // rectangles that cover all of the delta areas
  666. if (opt_sectorsize)
  667. { // final expansion cleanup
  668. for (y = 0; y < h; y += opt_sectorsize)
  669. {
  670. for (x = 0; x < w; x += opt_sectorsize)
  671. {
  672. int x2, y2;
  673. cnt = 0;
  674. for (y2 = y; y2 < y + opt_sectorsize && y2 < h; y2++)
  675. for (x2 = x; x2 < x + opt_sectorsize && x2 < w; x2++)
  676. if (mask[y2 * w + x2] == 1)
  677. cnt++;
  678. if (cnt > 0)
  679. continue; // dirty sector
  680. // clean up sector
  681. for (y2 = y; y2 < y + opt_sectorsize && y2 < h; y2++)
  682. for (x2 = x; x2 < x + opt_sectorsize && x2 < w; x2++)
  683. mask[y2 * w + x2] = 0;
  684. }
  685. }
  686. }
  687. // check how muany pixels have to be replaced
  688. for (x = 0, cnt = 0; x < w * h; x++)
  689. if (mask[x])
  690. cnt++;
  691. if (opt_deltamask)
  692. create_mask_png(mask, w, h);
  693. // generate delta images
  694. if (cnt != w * h)
  695. {
  696. int ofs;
  697. for (y = 0, ofs = 0; y < h; y++)
  698. {
  699. for (x = 0; x < w; x++, ofs++)
  700. {
  701. if (mask[ofs] != 0)
  702. { // copy masked rectangle into a new image
  703. // and clear the mask
  704. int i;
  705. int rw, rh;
  706. int x2, y2;
  707. unsigned char* src;
  708. unsigned char* dst;
  709. file_info* ni;
  710. ni = file_info_add_image (i1);
  711. if (!ni)
  712. {
  713. x = w;
  714. y = h;
  715. break;
  716. }
  717. // lookup delta rectangle
  718. for (i = x, src = mask + ofs; i < w && *src != 0; i++, src++)
  719. ;
  720. ni->w = rw = i - x;
  721. if (opt_fullrects)
  722. { // locate only complete rectangles
  723. y2 = y + 1;
  724. for (i = y + 1, src = mask + ofs; i < h && *src != 0; i++, src += w)
  725. {
  726. unsigned char* src2;
  727. y2 = i;
  728. for (x2 = x, src2 = src; x2 < x + rw && *src2 != 0; x2++, src2++)
  729. ;
  730. if (x2 < x + rw)
  731. break;
  732. }
  733. }
  734. else
  735. { // any rectangles
  736. for (y2 = y + 1, src = mask + ofs; y2 < h && *src != 0; y2++, src += w)
  737. ;
  738. }
  739. ni->h = rh = y2 - y;
  740. ni->image = (unsigned char*) malloc (rw * rh);
  741. if (!ni->image)
  742. {
  743. x = w;
  744. y = h;
  745. break;
  746. }
  747. // copy the pixels
  748. for (i = 0, src = i1->image + (dy1 + y) * i1->w + dx1 + x, dst = ni->image;
  749. i < rh;
  750. i++, src += i1->w, dst += rw
  751. )
  752. {
  753. memcpy (dst, src, rw);
  754. memset (mask + ofs + i * w, 0, rw);
  755. }
  756. ni->x = i1->x + dx1 + x;
  757. ni->y = i1->y + dy1 + y;
  758. }
  759. }
  760. }
  761. if (i1->next)
  762. { // dispose of the original
  763. file_info* ni = i1->next;
  764. free (i1->image);
  765. i1->image = ni->image;
  766. i1->x = ni->x;
  767. i1->y = ni->y;
  768. i1->w = ni->w;
  769. i1->h = ni->h;
  770. i1->next = ni->next;
  771. free (ni);
  772. }
  773. }
  774. else
  775. { // break here
  776. cnt = 1;
  777. }
  778. if (mask)
  779. free (mask);
  780. return 0;
  781. }
  782. void delta_images(void)
  783. {
  784. int i;
  785. verbose("calculating frame image deltas");
  786. // remove dupes
  787. for (i = 1; i < cInfos; i++)
  788. {
  789. int i2;
  790. // dereference identical chain
  791. for (i2 = i - 1; Infos[i2].identical != -1; i2 = Infos[i2].identical)
  792. ;
  793. if (equal_images(i, i2))
  794. {
  795. Infos[i].identical = i2;
  796. // dont need image data anymore
  797. if (Infos[i].image)
  798. {
  799. free(Infos[i].image);
  800. Infos[i].image = 0;
  801. }
  802. }
  803. verbose (".", 0);
  804. }
  805. verbose ("|", 0);
  806. // compute deltas
  807. for (i = cInfos - 1; i > 0; i--)
  808. {
  809. int i2;
  810. if (Infos[i].identical != -1)
  811. // no delta needed
  812. continue;
  813. else
  814. {
  815. // deref indentical chain
  816. for (i2 = i - 1; i2 >= 0 && Infos[i2].identical != -1; i2 = Infos[i2].identical)
  817. ;
  818. // debug info
  819. _curframe = i;
  820. _curdeltaframe = i2;
  821. build_delta (Infos + i, Infos + i2);
  822. }
  823. verbose (".", 0);
  824. }
  825. verbose ("\n", 0);
  826. }
  827. void file_info_init(file_info* ms)
  828. {
  829. memset(ms, 0, sizeof(*ms));
  830. ms->identical = -1;
  831. ms->index = -1;
  832. }
  833. void file_info_cleanup(file_info* ms)
  834. {
  835. file_info* fi = ms;
  836. while (fi)
  837. {
  838. file_info* tempi = fi;
  839. if (fi->image)
  840. {
  841. free(fi->image);
  842. fi->image = 0;
  843. }
  844. fi = fi->next;
  845. if (tempi != ms)
  846. free (tempi);
  847. }
  848. }
  849. void file_infos_free()
  850. {
  851. int i;
  852. if (Infos)
  853. {
  854. for (i = 0; i < cInfos; i++)
  855. file_info_cleanup (Infos + i);
  856. free (Infos);
  857. Infos = 0;
  858. }
  859. }
  860. int processframes(FILE* f)
  861. {
  862. uint32_t i;
  863. uint32_t packofs;
  864. framepack* pack;
  865. //char filename[250];
  866. pack = (framepack*) alloca(sizeof(framepack) + sizeof(uint16_t) * 128);
  867. packofs = hdr.opacks + hdr.cpackslots * sizeof(framepackinfo);
  868. cInfos = hdr.cframes;
  869. Infos = malloc(sizeof(file_info) * cInfos);
  870. if (!Infos)
  871. return 251;
  872. memset(Infos, 0, sizeof(file_info) * cInfos);
  873. // process frames
  874. for (i = 0; i < hdr.cframes; ++i)
  875. {
  876. int iframe;
  877. int ofs;
  878. int j;
  879. int size;
  880. int ipack = packfromframe(i);
  881. file_info* rf = Infos + i;
  882. fseek(f, packofs + ipack * 0x10000, SEEK_SET);
  883. fread(pack, FRAMEPACK_SIZE(packs[ipack]), 1, f);
  884. iframe = i - pack->info.frame;
  885. size = pack->sizes[iframe];
  886. for (j = 0, ofs = 0; j < iframe; ofs += pack->sizes[j], ++j)
  887. ;
  888. verbose("frame %03d: pack %03d, index %03d, ofs 0x%04x, size 0x%04x\n", i, ipack, iframe, ofs, size);
  889. fseek(f, ofs, SEEK_CUR);
  890. fread(buf, 1, size, f);
  891. processframe(buf, size, fimg);
  892. file_info_init(rf);
  893. rf->image = malloc(fimgsize);
  894. if (!rf->image)
  895. return 221;
  896. memcpy(rf->image, fimg, fimgsize);
  897. rf->w = hdr.w;
  898. rf->h = hdr.h;
  899. rf->x = 0;
  900. rf->y = 0;
  901. }
  902. return 0;
  903. }
  904. int write_ani_file(const char* outname)
  905. {
  906. char filename[250];
  907. FILE* fani;
  908. FILE* fscr;
  909. int i;
  910. int sync;
  911. int imgind;
  912. verbose("Writing ANI, Script and PNG files\n");
  913. sprintf(filename, "%s.ani", outname);
  914. fani = fopen(filename, "wt");
  915. if (!fani)
  916. return 211;
  917. sprintf(filename, "%s.txt", outname);
  918. fscr = fopen(filename, "wt");
  919. if (!fscr)
  920. {
  921. fclose(fani);
  922. return 211;
  923. }
  924. for (i = 0, imgind = 0, sync = 0; i < cInfos; ++i, sync += framedelay)
  925. {
  926. file_info* rf = Infos + i;
  927. int new_png;
  928. int draw_cmd;
  929. int batched;
  930. if (rf->identical == -1)
  931. { // unique frame
  932. new_png = 1;
  933. draw_cmd = 1;
  934. }
  935. else
  936. { // frame identical to another
  937. new_png = 0;
  938. if (i > 0 && (rf->identical == i - 1 || rf->identical == Infos[i - 1].identical))
  939. draw_cmd = 0; // frame has not changed since last
  940. else
  941. draw_cmd = 1; // frame changed
  942. rf = Infos + rf->identical;
  943. }
  944. if (draw_cmd)
  945. fprintf(fscr, "#(Sync frame)\n"
  946. "SYNC %d\n", sync);
  947. batched = 0;
  948. for ( ; rf && rf->image; rf = rf->next)
  949. {
  950. if (new_png)
  951. { // produce new png
  952. rf->index = imgind++;
  953. sprintf(filename, "%s.%03d.png", outname, rf->index);
  954. // produce PNG
  955. write_png(filename, rf->image, rf->w, rf->h, palette, PAL_COLORS);
  956. // add it to .ani
  957. fprintf(fani, "%s -1 -1 %d %d\n", filename, -rf->x, -rf->y);
  958. }
  959. if (draw_cmd)
  960. { // add it to script
  961. if (!batched && rf->next)
  962. { // drawing a batch
  963. batched = 1;
  964. fprintf(fscr, "#(Batch several draws)\n"
  965. "BATCH\n");
  966. }
  967. fprintf(fscr, "#(Draw frame image)\n"
  968. "DRAW %d\n", rf->index);
  969. }
  970. }
  971. if (batched && draw_cmd)
  972. { // unbatch
  973. fprintf(fscr, "#(End of batch)\n"
  974. "UNBATCH\n");
  975. }
  976. verbose(".");
  977. }
  978. // sync last frame
  979. fprintf(fscr, "#(Sync frame)\n"
  980. "SYNC %d\n", sync);
  981. verbose("\n");
  982. fclose(fscr);
  983. fclose(fani);
  984. return 0;
  985. }
  986. void usage()
  987. {
  988. fprintf(stderr, "usage: lpf2ani [-v] [-f rate] [-r] [-s size] [-o out-name] <lpf-file>\n");
  989. fprintf(stderr, "\tconverts DOS LPF animation file to .ani format and scripts the animation\n");
  990. fprintf(stderr, "\twill create <out-name>.ani, <out-name>.txt, and\n");
  991. fprintf(stderr, "\t8bpp paletted PNGs of mask <out-name>.<frameN>.png\n");
  992. fprintf(stderr, "options:\n");
  993. fprintf(stderr, " -v\t\t : be verbose, explains things no human should know\n");
  994. fprintf(stderr, " -f rate\t : override framerate; rate is 1..100 per second\n");
  995. fprintf(stderr, " -r\t\t : split delta frames into full rectangles only\n");
  996. fprintf(stderr, " -s size\t : enable sector cleanup and set sector size (8..64)\n");
  997. fprintf(stderr, " -p actname\t : produce PhotoShop palette file (.act)\n");
  998. fprintf(stderr, "diagnostical options:\n");
  999. fprintf(stderr, " -d\t\t : generate delta-mask PNGs (form: mask_FRM1_FRM2.png)\n");
  1000. }
  1001. void parse_arguments(int argc, char *argv[])
  1002. {
  1003. char ch;
  1004. while ((ch = getopt(argc, argv, "?hvdrf:s:o:p:")) != -1)
  1005. {
  1006. switch(ch)
  1007. {
  1008. case 'o':
  1009. opt_outname = optarg;
  1010. break;
  1011. case 'f':
  1012. opt_framerate = atoi(optarg);
  1013. if (opt_framerate < 1 || opt_framerate > 100)
  1014. {
  1015. fprintf(stderr, "invalid -f option value\n");
  1016. usage();
  1017. exit(EXIT_FAILURE);
  1018. }
  1019. break;
  1020. case 'd':
  1021. opt_deltamask = 1;
  1022. break;
  1023. case 'r':
  1024. opt_fullrects = 1;
  1025. break;
  1026. case 's':
  1027. opt_sectorsize = atoi(optarg);
  1028. if (opt_sectorsize < 8 || opt_sectorsize > 64)
  1029. {
  1030. fprintf(stderr, "invalid -r option value\n");
  1031. usage();
  1032. exit(EXIT_FAILURE);
  1033. }
  1034. break;
  1035. case 'v':
  1036. opt_verbose = 1;
  1037. break;
  1038. case 'p':
  1039. opt_actfile = optarg;
  1040. break;
  1041. case '?':
  1042. case 'h':
  1043. default:
  1044. usage();
  1045. exit(EXIT_FAILURE);
  1046. }
  1047. }
  1048. argc -= optind;
  1049. argv += optind;
  1050. if (argc != 1)
  1051. {
  1052. usage();
  1053. exit(EXIT_FAILURE);
  1054. }
  1055. opt_inname = argv[0];
  1056. }
  1057. int main(int argc, char* argv[])
  1058. {
  1059. FILE *f;
  1060. int ret = 0;
  1061. parse_arguments(argc, argv);
  1062. if (!opt_outname)
  1063. {
  1064. char* pch;
  1065. opt_outname = (char*) calloc (strlen(opt_inname) + 6, 1);
  1066. if (!opt_outname)
  1067. return error (EXIT_FAILURE, "No memory", 0);
  1068. pch = strrchr(opt_inname, '.');
  1069. if (!pch)
  1070. pch = opt_inname + strlen(opt_inname);
  1071. strncpy(opt_outname, opt_inname, pch - opt_inname + 1);
  1072. opt_outname[pch - opt_inname] = '\0';
  1073. verbose("Output name: %s\n", opt_outname);
  1074. }
  1075. f = fopen(opt_inname, "rb");
  1076. if (!f)
  1077. {
  1078. fprintf(stderr, "Cannot open %s\n", opt_inname);
  1079. return 1;
  1080. }
  1081. verbose("Reading file %s\n", opt_inname);
  1082. ret = readhead(f);
  1083. if (!ret)
  1084. ret = readpalette(f);
  1085. if (!ret)
  1086. {
  1087. framedelay = 1000 / hdr.fps;
  1088. if (opt_framerate)
  1089. { // override delay
  1090. framedelay = 1000 / opt_framerate;
  1091. }
  1092. verbose("using framedelay of %d, effective fps %d\n", framedelay, 1000 / framedelay);
  1093. }
  1094. if (!ret && opt_actfile)
  1095. ret = writepalette(opt_actfile);
  1096. if (!ret)
  1097. {
  1098. fimgsize = hdr.w * hdr.h;
  1099. fimg = malloc(fimgsize);
  1100. if (!fimg)
  1101. ret = 101;
  1102. }
  1103. if (!ret)
  1104. ret = processpacks(f);
  1105. if (!ret)
  1106. ret = processframes(f);
  1107. if (!ret)
  1108. {
  1109. delta_images();
  1110. ret = write_ani_file(opt_outname);
  1111. }
  1112. file_infos_free();
  1113. fclose(f);
  1114. return ret;
  1115. }