video.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "display.h"
  5. enum CHUNK_TYPE {
  6. CHUNK_INIT_AUDIO = 0,
  7. CHUNK_AUDIO = 1,
  8. CHUNK_INIT_VIDEO = 2,
  9. CHUNK_VIDEO = 3,
  10. CHUNK_SHUTDOWN = 4,
  11. CHUNK_END = 5,
  12. };
  13. enum OP_TYPE {
  14. OP_EOS = 0x0,
  15. OP_EOC = 0x1,
  16. OP_CREATE_TIMER = 0x02,
  17. OP_INIT_AUDIO_BUFFER = 0x03,
  18. OP_START_STOP_AUDIO = 0x04,
  19. OP_INIT_VIDEO_BUFFERS = 0x05,
  20. OP_VIDEO_UNCOMPRESSED = 0x06,
  21. OP_DISPLAY = 0x07,
  22. OP_AUDIO_FRAME = 0x08,
  23. OP_AUDIO_FRAME_SILENCE = 0x09,
  24. OP_INIT_VIDEO_MODE = 0xa,
  25. OP_CREATE_GRADIENT = 0xb,
  26. OP_SET_PALETTE = 0xc,
  27. OP_SET_PALETTE_COMPRESSED = 0xd,
  28. OP_SET_UNK_MAP = 0xe,
  29. OP_SET_DECODE_MAP = 0xf,
  30. OP_UNK3 = 0x10,
  31. OP_VIDEO_DATA = 0x11,
  32. OP_UNK4 = 0x12,
  33. OP_UNK5 = 0x13,
  34. OP_UNK6 = 0x14,
  35. OP_UNK7 = 0x15
  36. };
  37. typedef struct {
  38. unsigned int size;
  39. short unk1;
  40. short unk2;
  41. short unk3;
  42. char* data;
  43. unsigned int loc;
  44. } video_data;
  45. video_data data;
  46. char *video_buffer;
  47. char *video_buffer_cur;
  48. char *video_buffer_prev;
  49. char *video_buffer_debug;
  50. char *video_buffer_debug2;
  51. char *changed_blocks;
  52. int movie_width;
  53. int movie_height;
  54. int delay;
  55. int video_init = 0;
  56. short pixel_width = 8;
  57. short* unk_map;
  58. int unk_map_size;
  59. short* decode_map;
  60. int decode_map_size;
  61. int total_frames = 0;
  62. char read_char() {
  63. char ret;
  64. memcpy(&ret, data.data + data.loc, 1);
  65. data.loc += 1;
  66. return ret;
  67. }
  68. short read_int16() {
  69. short ret;
  70. memcpy(&ret, data.data + data.loc, 2);
  71. data.loc += 2;
  72. return ret;
  73. }
  74. int read_int32() {
  75. int ret;
  76. memcpy(&ret, data.data + data.loc, 4);
  77. data.loc += 4;
  78. return ret;
  79. }
  80. void swap_buffers() {
  81. printf("Swap buffers\n");
  82. char* c = video_buffer_cur;
  83. video_buffer_cur = video_buffer_prev;
  84. video_buffer_prev = c;
  85. //memset(video_buffer_cur, 0x33, movie_width * movie_height);
  86. //memcpy(video_buffer_cur, video_buffer_prev, movie_width * movie_height);
  87. }
  88. void check_header() {
  89. char magic[] = { 'I', 'n', 't', 'e', 'r', 'p', 'l', 'a', 'y', ' ', 'M', 'V', 'E', ' ', 'F', 'i', 'l', 'e', 0x1A, 0 };
  90. if (data.size < sizeof(magic)) {
  91. fprintf(stderr, "Wrong size, not an MVE file\n");
  92. exit(1);
  93. }
  94. if (memcmp(data.data, magic, sizeof(magic))) {
  95. fprintf(stderr, "Unknown file magic\n");
  96. exit(1);
  97. }
  98. data.loc = sizeof(magic);
  99. // And now we just assume we have data. This could be better
  100. data.unk1 = read_int16();
  101. data.unk2 = read_int16();
  102. data.unk3 = read_int16();
  103. printf("Found Interplay MVE file: Vermagic: 0x%04X 0x%04X 0x%04X\n", data.unk1, data.unk2, data.unk3);
  104. }
  105. void parse_chunk() {
  106. while(1) {
  107. int opsize = read_int16();
  108. char op = read_char();
  109. char ver = read_char();
  110. int data_loc = data.loc;
  111. printf("Opsize: %i, code: 0x%04X, version: %i\n\t", opsize, op, ver);
  112. switch(op) {
  113. case OP_EOS: {
  114. printf("OP_EOS\n");
  115. return;
  116. }
  117. case OP_EOC: {
  118. printf("OP_EOC\n\n");
  119. return;
  120. }
  121. case OP_CREATE_TIMER: {
  122. int rate = read_int32();
  123. short subdiv = read_int16();
  124. delay = (rate * subdiv + 500) / 1000;
  125. printf("OP_CREATE_TIMER: rate %i, subdiv %i, setting delay to %i\n", rate, subdiv, delay);
  126. break;
  127. }
  128. case OP_INIT_AUDIO_BUFFER: {
  129. short unknown = read_int16();
  130. short flags = read_int16();
  131. short rate = read_int16();
  132. int buflen;
  133. if (ver == 0)
  134. buflen = read_int16();
  135. if (ver == 1)
  136. buflen = read_int32();
  137. printf("OP_INIT_AUDIO_BUFFER v%i: unk 0x%04X, flags 0x%04X, rate %i, buflen %i\n", ver, unknown, flags, rate, buflen);
  138. break;
  139. }
  140. case OP_START_STOP_AUDIO: {
  141. printf("OP_START_STOP_AUDIO\n");
  142. break;
  143. }
  144. case OP_INIT_VIDEO_BUFFERS: {
  145. short width = read_int16();
  146. short height = read_int16();
  147. short count = 1;
  148. short true_color = 0;
  149. if (ver < 0 || ver > 2) {
  150. fprintf(stderr, "OP_INIT_VIDEO_BUFFERS: Unknown version\n");
  151. exit(1);
  152. }
  153. if (ver >=1)
  154. count = read_int16();
  155. if (ver == 2)
  156. true_color = read_int16();
  157. printf("OP_INIT_VIDEO_BUFFERS v%i: width %i, height %i, count %i, true_color %i\n", ver, width, height, count, true_color);
  158. movie_width = width * 8;
  159. movie_height = height * 8;
  160. video_buffer = calloc(movie_width * movie_height * 2, 1);
  161. video_buffer_cur = video_buffer;
  162. video_buffer_prev = video_buffer + movie_width * movie_height;
  163. video_buffer_debug = calloc(movie_width * movie_height, 1);
  164. video_buffer_debug2 = calloc(movie_width * movie_height, 1);
  165. // TODO
  166. memset(video_buffer_cur, 0xee, movie_width * movie_height);
  167. memset(video_buffer_prev, 0x33, movie_width * movie_height);
  168. memset(video_buffer_debug, 0xee, movie_width * movie_height);
  169. memset(video_buffer_debug2, 0x22, movie_width * movie_height);
  170. changed_blocks = calloc(width * height, 1);
  171. if (true_color)
  172. pixel_width = 16;
  173. break;
  174. }
  175. case OP_VIDEO_UNCOMPRESSED: {
  176. short frameno = read_int16(); // Seems to increase every frame anyway, starts at 1?
  177. short frameno2 = read_int16(); // Also increases every frame, starts at 0?
  178. short scale_width = read_int16(); // +4
  179. short scale_height = read_int16(); // +6
  180. short blocks_wide = read_int16(); // +8
  181. short blocks_high = read_int16(); // +10
  182. short unk1 = read_int16(); // +12
  183. printf("OP_VIDEO_UNCOMPRESSED: frameno %02i, frameno2 %02i, scale_width 0x%04X, scale_height 0x%04X, blocks wide %i, blocks high %i, bytes data %i, unk1: %04X\n", frameno, frameno2, scale_width, scale_height, blocks_wide, blocks_high, opsize - 12, unk1);;
  184. if(unk1 & 1) swap_buffers();
  185. short* metadata = (short*)(data.data + data.loc);
  186. char* pixeldata = data.data + data.loc + (blocks_wide * blocks_high * 2);
  187. char* out = video_buffer_cur;
  188. for (int block_y = 0; block_y < blocks_high; ++block_y) {
  189. for (int block_x = 0; block_x < blocks_wide; ++block_x) {
  190. if(! *metadata) {
  191. for (int i = 0; i < 8; ++i) {
  192. memcpy(out + (i * (blocks_wide * 8)), pixeldata, 8);
  193. pixeldata += 8;
  194. }
  195. }
  196. out += 8;
  197. metadata++;
  198. }
  199. out += (blocks_wide * 8) * 7;
  200. }
  201. out = video_buffer_cur;
  202. metadata = (short*)(data.data + data.loc);
  203. for (int block_y = 0; block_y < blocks_high; ++block_y) {
  204. for (int block_x = 0; block_x < blocks_wide; ++block_x) {
  205. short op = *metadata;
  206. if (op) {
  207. if(op < 0) {
  208. pixeldata = video_buffer_prev + (out - video_buffer_cur) + (unsigned short)op - 0xC000;
  209. } else {
  210. pixeldata = out + (unsigned short) op - 0x4000;
  211. }
  212. for (int i = 0; i < 8; ++i) {
  213. memcpy(out + (i * (blocks_wide * 8)), pixeldata + (i * (blocks_wide * 8)), 8);
  214. }
  215. }
  216. out += 8;
  217. ++metadata;
  218. }
  219. out += (blocks_wide * 8) * 7;
  220. }
  221. break;
  222. }
  223. case OP_DISPLAY: {
  224. short pal_start = read_int16(); // +0
  225. short pal_count = read_int16(); // +2
  226. if (ver == 0)
  227. printf("OP_DISPLAY v0: pal_start %i, pal_count %i\n", pal_start, pal_count);
  228. if (ver == 1) {
  229. short unk1 = read_int16(); // +4
  230. printf("OP_DISPLAY v1: pal_start %i, pal_count %i, unk1 0x%04X\n", pal_start, pal_count, unk1);
  231. }
  232. display_buffer(movie_width, movie_height, video_buffer_cur, video_buffer_prev, delay, changed_blocks);
  233. //display_buffer(movie_width * 2, movie_height, video_buffer, delay);
  234. //display_buffer(movie_width * 2, movie_height, video_buffer, 0);
  235. ++total_frames;
  236. break;
  237. }
  238. case OP_AUDIO_FRAME: {
  239. short seq_index = read_int16();
  240. short stream_mask = read_int16();
  241. short stream_len = read_int16();
  242. printf("OP_AUDIO_FRAME: seq_index %i, stream_mask 0x%04X, stream_len %i\n", seq_index, stream_mask, stream_len);
  243. break;
  244. }
  245. case OP_AUDIO_FRAME_SILENCE: {
  246. short seq_index = read_int16();
  247. short stream_mask = read_int16();
  248. short stream_len = read_int16();
  249. printf("OP_AUDIO_FRAME_SILENCE: seq_index %i, stream_mask 0x%04X, stream_len %i\n", seq_index, stream_mask, stream_len);
  250. break;
  251. }
  252. case OP_INIT_VIDEO_MODE: {
  253. short width = read_int16();
  254. short height = read_int16();
  255. short flags = read_int16();
  256. printf("OP_INIT_VIDEO_MODE: width %i, height %i, flags 0x%04X\n", width, height, flags);
  257. if(!video_init) {
  258. create_window(width * 2, height * 2);
  259. wait_for_keypress();
  260. video_init = 1;
  261. }
  262. break;
  263. }
  264. case OP_CREATE_GRADIENT: {
  265. printf("OP_CREATE_GRADIENT\n");
  266. break;
  267. }
  268. case OP_SET_PALETTE: {
  269. unsigned char pal_start = read_int16();
  270. unsigned char pal_count = read_int16();
  271. /* 6-bit palette, convert to 8 bit */
  272. for (int i = 0; i < pal_count; ++i) {
  273. short r = read_char();
  274. short g = read_char();
  275. short b = read_char();
  276. colors[pal_start + i].r = (r << 2) | (r >> 4);
  277. colors[pal_start + i].g = (g << 2) | (g >> 4);
  278. colors[pal_start + i].b = (b << 2) | (b >> 4);
  279. }
  280. printf("OP_SET_PALETTE: pal_start %i, pal_count %i\n", pal_start, pal_count);
  281. break;
  282. }
  283. case OP_SET_PALETTE_COMPRESSED: {
  284. printf("OP_SET_PALETTE_COMPRESSED\n");
  285. break;
  286. }
  287. case OP_SET_UNK_MAP: {
  288. unk_map = (short*)(data.data + data.loc);
  289. unk_map_size = opsize / 2;
  290. printf("OP_SET_UNK_MAP: entries %i\n", unk_map_size);
  291. break;
  292. }
  293. case OP_SET_DECODE_MAP: {
  294. decode_map = (short*)(data.data + data.loc);
  295. decode_map_size = opsize / 2;
  296. printf("OP_SET_DECODE_MAP: entries %i\n", decode_map_size);
  297. break;
  298. }
  299. case OP_UNK3: {
  300. short frameno = read_int16(); // Seems to increase every frame anyway, starts at 1?
  301. short frameno2 = read_int16(); // Also increases every frame, starts at 0?
  302. short scale_width = read_int16(); // +4
  303. short scale_height = read_int16(); // +6
  304. short blocks_wide = read_int16(); // +8
  305. short blocks_high = read_int16(); // +10
  306. unsigned short unk1 = read_int16(); // +12
  307. printf("OP_UNK3: frameno %02i, frameno2 %02i, scale_width 0x%04X, scale_height 0x%04X, blocks wide %i, blocks high %i, unk1 %04X, bytes data %i\n", frameno, frameno2, scale_width, scale_height, blocks_wide, blocks_high, unk1, opsize - 14);
  308. if(unk1 & 1) swap_buffers();
  309. int source_blocks = 0;
  310. char* pixeldata = data.data + data.loc;
  311. char* out = video_buffer_cur;
  312. short* unk_map_l = unk_map;
  313. short* decode_map_l = decode_map;
  314. short cur_unk = *unk_map;
  315. char* changed_blocks_p = changed_blocks;
  316. memset(changed_blocks, 0, blocks_high * blocks_wide);
  317. for (int i = 0; i < unk_map_size; ++i) {
  318. printf("%hi, ", unk_map[i]);
  319. }
  320. printf("\n");
  321. for (int block_y = 0; block_y < blocks_high; ++block_y) {
  322. for (int block_x = 0; block_x < blocks_wide; ++block_x) {
  323. while (cur_unk <= 0) {
  324. if (cur_unk != -0x8000 && cur_unk != 0) {
  325. if(! *decode_map_l) {
  326. for (int i = 0; i < 8; ++i) {
  327. memcpy(out + (i * (blocks_wide * 8)), pixeldata, 8);
  328. pixeldata += 8;
  329. }
  330. ++source_blocks;
  331. }
  332. *changed_blocks_p = 1;
  333. ++decode_map_l;
  334. break;
  335. }
  336. cur_unk = *(++unk_map_l);
  337. }
  338. cur_unk *= 2;
  339. out += 8;
  340. ++changed_blocks_p;
  341. }
  342. out += (blocks_wide * 8) * 7;
  343. }
  344. printf("Consumed %li out of %i unk_map entries, %i blocks copied\n", unk_map_l - unk_map + 1, unk_map_size, source_blocks);
  345. int cur_blocks = 0;
  346. int prev_blocks = 0;
  347. out = video_buffer_cur;
  348. unk_map_l = unk_map;
  349. decode_map_l = decode_map;
  350. cur_unk = *unk_map;
  351. for (int block_y = 0; block_y < blocks_high; ++block_y) {
  352. for (int block_x = 0; block_x < blocks_wide; ++block_x) {
  353. while (cur_unk <= 0) {
  354. if (cur_unk != -0x8000 && cur_unk != 0) {
  355. short op = *decode_map_l;
  356. if(op) {
  357. if(op < 0) {
  358. pixeldata = video_buffer_prev + (out - video_buffer_cur) + (unsigned short)op - 0xC000;
  359. ++prev_blocks;
  360. } else {
  361. pixeldata = out + (op - 0x4000);
  362. ++cur_blocks;
  363. }
  364. for (int i = 0; i < 8; ++i) {
  365. memcpy(out + (i * (blocks_wide * 8)), pixeldata + (i * (blocks_wide * 8)), 8);
  366. }
  367. }
  368. ++decode_map_l;
  369. break;
  370. }
  371. cur_unk = *(++unk_map_l);
  372. }
  373. cur_unk *= 2;
  374. out += 8;
  375. }
  376. out += (blocks_wide * 8) * 7;
  377. }
  378. printf("Consumed %li out of %i unk_map entries, %i prev blocks, %i cur blocks\n", unk_map_l - unk_map + 1, unk_map_size, prev_blocks, cur_blocks);
  379. break;
  380. }
  381. case OP_VIDEO_DATA: {
  382. printf("OP_VIDEO_DATA\n");
  383. break;
  384. }
  385. case OP_UNK4: {
  386. printf("OP_UNK4\n");
  387. break;
  388. }
  389. case OP_UNK5: {
  390. printf("OP_UNK5\n");
  391. break;
  392. }
  393. case OP_UNK6: {
  394. printf("OP_UNK6\n");
  395. break;
  396. }
  397. case OP_UNK7: {
  398. printf("OP_UNK7\n");
  399. break;
  400. }
  401. default:
  402. fprintf(stderr, "Unkown opcode 0x%04X\n", op);
  403. }
  404. data.loc = data_loc + opsize;
  405. }
  406. }
  407. short read_chunk() {
  408. short size = read_int16();
  409. short type = read_int16();
  410. printf("Found chunk type: ");
  411. switch(type) {
  412. case CHUNK_INIT_AUDIO:
  413. printf("INIT AUDIO ");
  414. break;
  415. case CHUNK_AUDIO:
  416. printf("AUDIO ");
  417. break;
  418. case CHUNK_INIT_VIDEO:
  419. printf("INIT VIDEO ");
  420. break;
  421. case CHUNK_VIDEO:
  422. printf("VIDEO ");
  423. break;
  424. case CHUNK_SHUTDOWN:
  425. printf("SHUTDOWN ");
  426. break;
  427. case CHUNK_END:
  428. printf("END ");
  429. break;
  430. default:
  431. printf("UNKNOWN! ");
  432. break;
  433. }
  434. printf("(0x%04X) of size %i\n", type, size);
  435. parse_chunk(size);
  436. return type;
  437. }
  438. void read_all_chunks() {
  439. while (1) {
  440. short t = read_chunk();
  441. if (t < 0 || t > CHUNK_VIDEO) {
  442. printf("End parsing\n");
  443. break;
  444. }
  445. }
  446. }
  447. int main(int argc, char *argv[]) {
  448. if(argc != 2) {
  449. fprintf(stderr, "Usage: %s [FILE]\n", argv[0]);
  450. exit(1);
  451. }
  452. init_sdl();
  453. FILE *f = fopen(argv[1], "rb");
  454. if (!f) {
  455. perror("Failed to open file");
  456. exit(1);
  457. }
  458. fseek(f, 0L, SEEK_END);
  459. data.size = ftell(f);
  460. rewind(f);
  461. data.data = malloc(data.size);
  462. fread(data.data, data.size, 1, f);
  463. fclose(f);
  464. data.loc = 0;
  465. check_header();
  466. read_all_chunks();
  467. wait_for_keypress();
  468. free(data.data);
  469. printf("Played %i frames\n", total_frames);
  470. }