From 33ab189334bfa6bbb9e1af6e1de849c636b81a15 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Sun, 16 Apr 2017 14:25:38 +0300 Subject: [PATCH] Add graphics convertor --- .gitignore | 2 + Makefile | 10 +- README | 5 +- spr.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 .gitignore create mode 100644 spr.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..acb4590 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +BANK* +MEMLIST.BIN diff --git a/Makefile b/Makefile index 2fa0e39..4e2c79d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: unpk dis +all: unpk dis spr unpk: cc -o unpk unpk.c @@ -6,11 +6,11 @@ unpk: dis: cc -o dis dis.c dis_aw.c dis_intel.c dis_att.c -#view: -# cc -lSDL2 -o view view.c view_vid.c +spr: + cc -o spr spr.c distclean: - rm -f unpk dis view + rm -f unpk dis spr workclean: - rm -f file*.snd file*.mus file*.bmp file*.pal file*.obj file*.spr file*.unk + rm -f file*.snd file*.mus file*.bmp file*.pal file*.obj file*.spr file*.unk file*.spr_*.svg diff --git a/README b/README index 5e3ab35..7e3116e 100644 --- a/README +++ b/README @@ -12,8 +12,11 @@ dis [-a | -i | -u] [-p] OBJECT OUTFILE -a | -i | -u - Generate with AnotherWorld/Intel/AT&T syntax -p - print opcode address +spr INPUT + Convert game graphics into SVG. + Licence: GPLv3 Links: https://www.anotherworld.fr/anotherworld_uk/another_world.htm - https://github.com/cyxx/rawgl \ No newline at end of file + https://github.com/cyxx/rawgl diff --git a/spr.c b/spr.c new file mode 100644 index 0000000..b983eb7 --- /dev/null +++ b/spr.c @@ -0,0 +1,287 @@ +#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; +} -- 2.29.2