123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "display.h"
- enum CHUNK_TYPE {
- CHUNK_INIT_AUDIO = 0,
- CHUNK_AUDIO = 1,
- CHUNK_INIT_VIDEO = 2,
- CHUNK_VIDEO = 3,
- CHUNK_SHUTDOWN = 4,
- CHUNK_END = 5,
- };
- enum OP_TYPE {
- OP_EOS = 0x0,
- OP_EOC = 0x1,
- OP_CREATE_TIMER = 0x02,
- OP_INIT_AUDIO_BUFFER = 0x03,
- OP_START_STOP_AUDIO = 0x04,
- OP_INIT_VIDEO_BUFFERS = 0x05,
- OP_VIDEO_UNCOMPRESSED = 0x06,
- OP_DISPLAY = 0x07,
- OP_AUDIO_FRAME = 0x08,
- OP_AUDIO_FRAME_SILENCE = 0x09,
- OP_INIT_VIDEO_MODE = 0xa,
- OP_CREATE_GRADIENT = 0xb,
- OP_SET_PALETTE = 0xc,
- OP_SET_PALETTE_COMPRESSED = 0xd,
- OP_SET_UNK_MAP = 0xe,
- OP_SET_DECODE_MAP = 0xf,
- OP_UNK3 = 0x10,
- OP_VIDEO_DATA = 0x11,
- OP_UNK4 = 0x12,
- OP_UNK5 = 0x13,
- OP_UNK6 = 0x14,
- OP_UNK7 = 0x15
- };
- typedef struct {
- unsigned int size;
- short unk1;
- short unk2;
- short unk3;
- char* data;
- unsigned int loc;
- } video_data;
- video_data data;
- char *video_buffer;
- char *video_buffer_cur;
- char *video_buffer_prev;
- char *video_buffer_debug;
- char *video_buffer_debug2;
- char *changed_blocks;
- int movie_width;
- int movie_height;
- int delay;
- int video_init = 0;
- short pixel_width = 8;
- short* unk_map;
- int unk_map_size;
- short* decode_map;
- int decode_map_size;
- int total_frames = 0;
- char read_char() {
- char ret;
- memcpy(&ret, data.data + data.loc, 1);
- data.loc += 1;
- return ret;
- }
- short read_int16() {
- short ret;
- memcpy(&ret, data.data + data.loc, 2);
- data.loc += 2;
- return ret;
- }
- int read_int32() {
- int ret;
- memcpy(&ret, data.data + data.loc, 4);
- data.loc += 4;
- return ret;
- }
- void swap_buffers() {
- printf("Swap buffers\n");
- char* c = video_buffer_cur;
- video_buffer_cur = video_buffer_prev;
- video_buffer_prev = c;
- //memset(video_buffer_cur, 0x33, movie_width * movie_height);
- //memcpy(video_buffer_cur, video_buffer_prev, movie_width * movie_height);
- }
- void check_header() {
- char magic[] = { 'I', 'n', 't', 'e', 'r', 'p', 'l', 'a', 'y', ' ', 'M', 'V', 'E', ' ', 'F', 'i', 'l', 'e', 0x1A, 0 };
- if (data.size < sizeof(magic)) {
- fprintf(stderr, "Wrong size, not an MVE file\n");
- exit(1);
- }
-
- if (memcmp(data.data, magic, sizeof(magic))) {
- fprintf(stderr, "Unknown file magic\n");
- exit(1);
- }
- data.loc = sizeof(magic);
- // And now we just assume we have data. This could be better
- data.unk1 = read_int16();
- data.unk2 = read_int16();
- data.unk3 = read_int16();
- printf("Found Interplay MVE file: Vermagic: 0x%04X 0x%04X 0x%04X\n", data.unk1, data.unk2, data.unk3);
- }
- void parse_chunk() {
- while(1) {
- int opsize = read_int16();
- char op = read_char();
- char ver = read_char();
- int data_loc = data.loc;
- printf("Opsize: %i, code: 0x%04X, version: %i\n\t", opsize, op, ver);
- switch(op) {
- case OP_EOS: {
- printf("OP_EOS\n");
- return;
- }
-
- case OP_EOC: {
- printf("OP_EOC\n\n");
- return;
- }
- case OP_CREATE_TIMER: {
- int rate = read_int32();
- short subdiv = read_int16();
- delay = (rate * subdiv + 500) / 1000;
- printf("OP_CREATE_TIMER: rate %i, subdiv %i, setting delay to %i\n", rate, subdiv, delay);
- break;
- }
- case OP_INIT_AUDIO_BUFFER: {
- short unknown = read_int16();
- short flags = read_int16();
- short rate = read_int16();
- int buflen;
- if (ver == 0)
- buflen = read_int16();
- if (ver == 1)
- buflen = read_int32();
- printf("OP_INIT_AUDIO_BUFFER v%i: unk 0x%04X, flags 0x%04X, rate %i, buflen %i\n", ver, unknown, flags, rate, buflen);
- break;
- }
- case OP_START_STOP_AUDIO: {
- printf("OP_START_STOP_AUDIO\n");
- break;
- }
- case OP_INIT_VIDEO_BUFFERS: {
- short width = read_int16();
- short height = read_int16();
- short count = 1;
- short true_color = 0;
- if (ver < 0 || ver > 2) {
- fprintf(stderr, "OP_INIT_VIDEO_BUFFERS: Unknown version\n");
- exit(1);
- }
- if (ver >=1)
- count = read_int16();
- if (ver == 2)
- true_color = read_int16();
- printf("OP_INIT_VIDEO_BUFFERS v%i: width %i, height %i, count %i, true_color %i\n", ver, width, height, count, true_color);
- movie_width = width * 8;
- movie_height = height * 8;
- video_buffer = calloc(movie_width * movie_height * 2, 1);
- video_buffer_cur = video_buffer;
- video_buffer_prev = video_buffer + movie_width * movie_height;
- video_buffer_debug = calloc(movie_width * movie_height, 1);
- video_buffer_debug2 = calloc(movie_width * movie_height, 1);
- // TODO
- memset(video_buffer_cur, 0xee, movie_width * movie_height);
- memset(video_buffer_prev, 0x33, movie_width * movie_height);
- memset(video_buffer_debug, 0xee, movie_width * movie_height);
- memset(video_buffer_debug2, 0x22, movie_width * movie_height);
- changed_blocks = calloc(width * height, 1);
- if (true_color)
- pixel_width = 16;
- break;
- }
- case OP_VIDEO_UNCOMPRESSED: {
- short frameno = read_int16(); // Seems to increase every frame anyway, starts at 1?
- short frameno2 = read_int16(); // Also increases every frame, starts at 0?
-
- short scale_width = read_int16(); // +4
- short scale_height = read_int16(); // +6
- short blocks_wide = read_int16(); // +8
- short blocks_high = read_int16(); // +10
- short unk1 = read_int16(); // +12
- 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);;
- if(unk1 & 1) swap_buffers();
- short* metadata = (short*)(data.data + data.loc);
- char* pixeldata = data.data + data.loc + (blocks_wide * blocks_high * 2);
- char* out = video_buffer_cur;
- for (int block_y = 0; block_y < blocks_high; ++block_y) {
- for (int block_x = 0; block_x < blocks_wide; ++block_x) {
- if(! *metadata) {
- for (int i = 0; i < 8; ++i) {
- memcpy(out + (i * (blocks_wide * 8)), pixeldata, 8);
- pixeldata += 8;
- }
- }
- out += 8;
- metadata++;
- }
- out += (blocks_wide * 8) * 7;
- }
- out = video_buffer_cur;
- metadata = (short*)(data.data + data.loc);
- for (int block_y = 0; block_y < blocks_high; ++block_y) {
- for (int block_x = 0; block_x < blocks_wide; ++block_x) {
- short op = *metadata;
- if (op) {
- if(op < 0) {
- pixeldata = video_buffer_prev + (out - video_buffer_cur) + (unsigned short)op - 0xC000;
- } else {
- pixeldata = out + (unsigned short) op - 0x4000;
- }
- for (int i = 0; i < 8; ++i) {
- memcpy(out + (i * (blocks_wide * 8)), pixeldata + (i * (blocks_wide * 8)), 8);
- }
- }
- out += 8;
- ++metadata;
- }
- out += (blocks_wide * 8) * 7;
- }
- break;
- }
- case OP_DISPLAY: {
- short pal_start = read_int16(); // +0
- short pal_count = read_int16(); // +2
- if (ver == 0)
- printf("OP_DISPLAY v0: pal_start %i, pal_count %i\n", pal_start, pal_count);
- if (ver == 1) {
- short unk1 = read_int16(); // +4
- printf("OP_DISPLAY v1: pal_start %i, pal_count %i, unk1 0x%04X\n", pal_start, pal_count, unk1);
- }
- display_buffer(movie_width, movie_height, video_buffer_cur, video_buffer_prev, delay, changed_blocks);
- //display_buffer(movie_width * 2, movie_height, video_buffer, delay);
- //display_buffer(movie_width * 2, movie_height, video_buffer, 0);
-
- ++total_frames;
- break;
- }
- case OP_AUDIO_FRAME: {
- short seq_index = read_int16();
- short stream_mask = read_int16();
- short stream_len = read_int16();
- printf("OP_AUDIO_FRAME: seq_index %i, stream_mask 0x%04X, stream_len %i\n", seq_index, stream_mask, stream_len);
- break;
- }
- case OP_AUDIO_FRAME_SILENCE: {
- short seq_index = read_int16();
- short stream_mask = read_int16();
- short stream_len = read_int16();
- printf("OP_AUDIO_FRAME_SILENCE: seq_index %i, stream_mask 0x%04X, stream_len %i\n", seq_index, stream_mask, stream_len);
- break;
- }
- case OP_INIT_VIDEO_MODE: {
- short width = read_int16();
- short height = read_int16();
- short flags = read_int16();
-
- printf("OP_INIT_VIDEO_MODE: width %i, height %i, flags 0x%04X\n", width, height, flags);
- if(!video_init) {
- create_window(width * 2, height * 2);
- wait_for_keypress();
- video_init = 1;
- }
- break;
- }
- case OP_CREATE_GRADIENT: {
- printf("OP_CREATE_GRADIENT\n");
- break;
- }
- case OP_SET_PALETTE: {
- unsigned char pal_start = read_int16();
- unsigned char pal_count = read_int16();
- /* 6-bit palette, convert to 8 bit */
- for (int i = 0; i < pal_count; ++i) {
- short r = read_char();
- short g = read_char();
- short b = read_char();
- colors[pal_start + i].r = (r << 2) | (r >> 4);
- colors[pal_start + i].g = (g << 2) | (g >> 4);
- colors[pal_start + i].b = (b << 2) | (b >> 4);
- }
- printf("OP_SET_PALETTE: pal_start %i, pal_count %i\n", pal_start, pal_count);
- break;
- }
- case OP_SET_PALETTE_COMPRESSED: {
- printf("OP_SET_PALETTE_COMPRESSED\n");
- break;
- }
- case OP_SET_UNK_MAP: {
- unk_map = (short*)(data.data + data.loc);
- unk_map_size = opsize / 2;
- printf("OP_SET_UNK_MAP: entries %i\n", unk_map_size);
- break;
- }
- case OP_SET_DECODE_MAP: {
- decode_map = (short*)(data.data + data.loc);
- decode_map_size = opsize / 2;
- printf("OP_SET_DECODE_MAP: entries %i\n", decode_map_size);
- break;
- }
- case OP_UNK3: {
- short frameno = read_int16(); // Seems to increase every frame anyway, starts at 1?
- short frameno2 = read_int16(); // Also increases every frame, starts at 0?
-
- short scale_width = read_int16(); // +4
- short scale_height = read_int16(); // +6
- short blocks_wide = read_int16(); // +8
- short blocks_high = read_int16(); // +10
- unsigned short unk1 = read_int16(); // +12
- 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);
- if(unk1 & 1) swap_buffers();
- int source_blocks = 0;
- char* pixeldata = data.data + data.loc;
- char* out = video_buffer_cur;
- short* unk_map_l = unk_map;
- short* decode_map_l = decode_map;
- short cur_unk = *unk_map;
- char* changed_blocks_p = changed_blocks;
- memset(changed_blocks, 0, blocks_high * blocks_wide);
- for (int i = 0; i < unk_map_size; ++i) {
- printf("%hi, ", unk_map[i]);
- }
- printf("\n");
- for (int block_y = 0; block_y < blocks_high; ++block_y) {
- for (int block_x = 0; block_x < blocks_wide; ++block_x) {
- while (cur_unk <= 0) {
- if (cur_unk != -0x8000 && cur_unk != 0) {
- if(! *decode_map_l) {
- for (int i = 0; i < 8; ++i) {
- memcpy(out + (i * (blocks_wide * 8)), pixeldata, 8);
- pixeldata += 8;
- }
- ++source_blocks;
- }
- *changed_blocks_p = 1;
- ++decode_map_l;
- break;
- }
- cur_unk = *(++unk_map_l);
- }
- cur_unk *= 2;
- out += 8;
- ++changed_blocks_p;
- }
- out += (blocks_wide * 8) * 7;
- }
- printf("Consumed %li out of %i unk_map entries, %i blocks copied\n", unk_map_l - unk_map + 1, unk_map_size, source_blocks);
- int cur_blocks = 0;
- int prev_blocks = 0;
- out = video_buffer_cur;
- unk_map_l = unk_map;
- decode_map_l = decode_map;
- cur_unk = *unk_map;
- for (int block_y = 0; block_y < blocks_high; ++block_y) {
- for (int block_x = 0; block_x < blocks_wide; ++block_x) {
- while (cur_unk <= 0) {
- if (cur_unk != -0x8000 && cur_unk != 0) {
- short op = *decode_map_l;
- if(op) {
- if(op < 0) {
- pixeldata = video_buffer_prev + (out - video_buffer_cur) + (unsigned short)op - 0xC000;
- ++prev_blocks;
- } else {
- pixeldata = out + (op - 0x4000);
- ++cur_blocks;
- }
- for (int i = 0; i < 8; ++i) {
- memcpy(out + (i * (blocks_wide * 8)), pixeldata + (i * (blocks_wide * 8)), 8);
- }
- }
- ++decode_map_l;
- break;
- }
- cur_unk = *(++unk_map_l);
- }
- cur_unk *= 2;
- out += 8;
- }
- out += (blocks_wide * 8) * 7;
- }
- 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);
- break;
- }
- case OP_VIDEO_DATA: {
- printf("OP_VIDEO_DATA\n");
- break;
- }
- case OP_UNK4: {
- printf("OP_UNK4\n");
- break;
- }
- case OP_UNK5: {
- printf("OP_UNK5\n");
- break;
- }
- case OP_UNK6: {
- printf("OP_UNK6\n");
- break;
- }
- case OP_UNK7: {
- printf("OP_UNK7\n");
- break;
- }
- default:
- fprintf(stderr, "Unkown opcode 0x%04X\n", op);
- }
- data.loc = data_loc + opsize;
- }
- }
- short read_chunk() {
- short size = read_int16();
- short type = read_int16();
- printf("Found chunk type: ");
- switch(type) {
- case CHUNK_INIT_AUDIO:
- printf("INIT AUDIO ");
- break;
- case CHUNK_AUDIO:
- printf("AUDIO ");
- break;
- case CHUNK_INIT_VIDEO:
- printf("INIT VIDEO ");
- break;
- case CHUNK_VIDEO:
- printf("VIDEO ");
- break;
- case CHUNK_SHUTDOWN:
- printf("SHUTDOWN ");
- break;
- case CHUNK_END:
- printf("END ");
- break;
- default:
- printf("UNKNOWN! ");
- break;
- }
- printf("(0x%04X) of size %i\n", type, size);
- parse_chunk(size);
-
- return type;
- }
- void read_all_chunks() {
- while (1) {
- short t = read_chunk();
- if (t < 0 || t > CHUNK_VIDEO) {
- printf("End parsing\n");
- break;
- }
- }
- }
- int main(int argc, char *argv[]) {
- if(argc != 2) {
- fprintf(stderr, "Usage: %s [FILE]\n", argv[0]);
- exit(1);
- }
- init_sdl();
- FILE *f = fopen(argv[1], "rb");
- if (!f) {
- perror("Failed to open file");
- exit(1);
- }
- fseek(f, 0L, SEEK_END);
- data.size = ftell(f);
- rewind(f);
- data.data = malloc(data.size);
- fread(data.data, data.size, 1, f);
- fclose(f);
- data.loc = 0;
- check_header();
- read_all_chunks();
-
- wait_for_keypress();
- free(data.data);
- printf("Played %i frames\n", total_frames);
- }
|