#include #include #include #include #include /* * Another World graphics convertor * Only DOS version are supported */ #define MAX_POLYGONS 4096 #define MAX_GROUPS 2048 #define MSG_USAGE "usage: spr INPUT\n" #define MSG_OPENERR "can't open file %s.\n" #define MSG_WRITEERR "can't create file %s.\n" struct polygoninfo { uint16_t offset; uint8_t color, w, h, num; struct { uint8_t x, y; } point[256]; }; struct groupinfo { uint16_t offset; uint8_t x, y, num; struct { uint16_t offset; uint8_t x, y; uint16_t color; bool group; int id; } child[256]; }; FILE *fp; uint8_t *data; uint16_t datalen, datapc; struct polygoninfo poly[MAX_POLYGONS]; int polycount; struct groupinfo group[MAX_GROUPS]; int groupcount; uint8_t vbyte() { return data[datapc++]; } uint16_t vword() { return (vbyte() << 8) | vbyte(); } int findpoly(uint16_t offset) { for(int i = 0; i < polycount; i++) { if(poly[i].offset == offset) return i; } return -1; } int findgroup(uint16_t offset) { for(int i = 0; i < groupcount; i++) { if(group[i].offset == offset) return i; } return -1; } void process(bool readgroup) { uint16_t adr = datapc; uint8_t type = vbyte(); if(type >= 0xC0) { uint8_t color = (type & 0x80) ? (type & 0x3F) : 0x0; uint8_t w = vbyte(); uint8_t h = vbyte(); uint8_t num = vbyte(); if(!readgroup) { poly[polycount].offset = adr; poly[polycount].color = color; poly[polycount].w = w; poly[polycount].h = h; poly[polycount].num = num; } for(int i = 0; i < num; i++) { uint8_t x = vbyte(); uint8_t y = vbyte(); if(!readgroup) { poly[polycount].point[i].x = x; poly[polycount].point[i].y = y; } } if(!readgroup) ++polycount; } else { type &= 0x3F; if(type == 2) { uint8_t x = vbyte(); uint8_t y = vbyte(); uint8_t childs = vbyte(); if(readgroup) { group[groupcount].offset = adr; group[groupcount].x = x; group[groupcount].y = y; group[groupcount].num = childs; } for(int i = 0; i <= childs; i++) { uint16_t offset = vword(); uint8_t xx = vbyte(); uint8_t yy = vbyte(); uint16_t color = 0xF; if(offset & 0x8000) color = vword() & 0x7F; offset = (offset & 0x7FFF) << 1; if(readgroup) { group[groupcount].child[i].offset = offset; group[groupcount].child[i].x = xx; group[groupcount].child[i].y = yy; group[groupcount].child[i].color = color; } } if(readgroup) ++groupcount; } else { printf("invalid type %u\n", type); exit(1); } } } void linkgroups() { for(int i = 0; i < groupcount; i++) { for(int j = 0; j < group[i].num; i++) { uint16_t offset = group[i].child[j].offset; group[i].child[j].group = false; int id = findpoly(offset); if(id == -1) { group[i].child[j].group = true; id = findgroup(offset); if(id == -1) { printf("grouped polygon 0x%X not found\n", offset); exit(1); } } group[i].child[j].id = id; } } } uint8_t *loadfile(const char *name, uint16_t *size) { FILE *fp; if((fp = fopen(name, "r")) == NULL) { printf(MSG_OPENERR, name); exit(1); } fseek(fp, 0, SEEK_END); int s = ftell(fp); fseek(fp, 0, SEEK_SET); uint8_t *ptr = malloc(s); fread(ptr, s, 1, fp); fclose(fp); *size = s; return ptr; } void svg_poly(char *prefix, int id) { char name[256]; snprintf(name, 256, "%s_p%i.svg", prefix, id); if((fp = fopen(name, "w")) == NULL) { printf(MSG_WRITEERR, name); exit(1); } int w = poly[id].w; int h = poly[id].h; if(w == 0) w = 1; if(h == 0) h = 1; printf("1px is p%i\n", id); fprintf(fp, "\n"); fprintf(fp, "\n", w, h); fprintf(fp, " poly[id].point[i].x) { fprintf(fp, "%u,%u ", poly[id].point[i].x, poly[id].point[i].y); fprintf(fp, "%u,%u ", poly[id].point[j].x + 1, poly[id].point[j].y); } else { fprintf(fp, "%u,%u ", poly[id].point[j].x, poly[id].point[j].y); fprintf(fp, "%u,%u ", poly[id].point[i].x + 1, poly[id].point[i].y); } } else { for(int i = 0; i < poly[id].num / 2; i++) { int j = poly[id].num - 1 - i; if (poly[id].point[j].x > poly[id].point[i].x) { fprintf(fp, "%u,%u ", poly[id].point[i].x, poly[id].point[i].y); fprintf(fp, "%u,%u ", poly[id].point[j].x + 1, poly[id].point[j].y); } else { fprintf(fp, "%u,%u ", poly[id].point[j].x, poly[id].point[j].y); fprintf(fp, "%u,%u ", poly[id].point[i].x + 1, poly[id].point[i].y); } } } fprintf(fp, "\"/>\n"); fprintf(fp, ""); fclose(fp); } void svg_group(char *prefix, int id) { char name[256]; snprintf(name, 256, "%s_g%i.svg", prefix, id); if((fp = fopen(name, "w")) == NULL) { printf(MSG_WRITEERR, name); exit(1); } fprintf(fp, "\n"); fprintf(fp, "\n"); for(int i = 0; i < group[id].num; i++) { char c = group[id].child[i].group ? 'g' : 'p'; fprintf(fp, "", prefix, c, group[id].child[i].id, group[id].child[i].x, group[id].child[i].y); } fprintf(fp, ""); fclose(fp); } int main(int argc, char **argv) { if(argc != 2) { printf(MSG_USAGE); exit(1); } data = loadfile(argv[1], &datalen); while(datapc < datalen) process(false); datapc = 0; while(datapc < datalen) process(true); linkgroups(); free(data); for(int i = 0; i < polycount; i++) svg_poly(argv[1], i); for(int i = 0; i < groupcount; i++) svg_group(argv[1], i); return 0; }