summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a5b49eb)
raw | patch | inline | side by side (parent: a5b49eb)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 16 Apr 2017 11:25:38 +0000 (14:25 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 16 Apr 2017 11:25:38 +0000 (14:25 +0300) |
.gitignore | [new file with mode: 0644] | patch | blob |
Makefile | patch | blob | history | |
README | patch | blob | history | |
spr.c | [new file with mode: 0644] | patch | blob |
diff --git a/.gitignore b/.gitignore
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+BANK*
+MEMLIST.BIN
diff --git a/Makefile b/Makefile
index 2fa0e39e51ad63b51a48686168fe426728164e09..4e2c79d44201c6a9e7780ff5a3c48157c12ba569 100644 (file)
--- a/Makefile
+++ b/Makefile
-all: unpk dis
+all: unpk dis spr
unpk:
cc -o unpk unpk.c
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
index 5e3ab353fdd4a16f881fc842d0c389bfea7ccc90..7e3116e028d5afbe0a9bb50e1971a4093555220a 100644 (file)
--- a/README
+++ b/README
-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
--- /dev/null
+++ b/spr.c
@@ -0,0 +1,287 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+/*
+ * 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, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
+ fprintf(fp, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"%upx\" height=\"%upx\">\n", w, h);
+
+ fprintf(fp, "<polygon fill=\"black\" points=\"");
+ if(poly[id].num == 1) {
+ fprintf(fp, "%u,%u ", poly[id].point[0].x, poly[id].point[0].y);
+ } else if(poly[id].num == 2) {
+ int i = 0;
+ int j = 1;
+ 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);
+ }
+ } 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, "</svg>");
+
+ 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, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
+ fprintf(fp, "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"320px\" height=\"200px\">\n");
+
+ for(int i = 0; i < group[id].num; i++) {
+ char c = group[id].child[i].group ? 'g' : 'p';
+
+ fprintf(fp, "<image xlink:href=\"%s_%c%i.svg\" x=\"%i\" y=\"%i\"/>", prefix, c, group[id].child[i].id, group[id].child[i].x, group[id].child[i].y);
+ }
+
+ fprintf(fp, "</svg>");
+
+ 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;
+}