DEADSOFTWARE

Add graphics convertor
[awtools.git] / spr.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <stdbool.h>
7 /*
8 * Another World graphics convertor
9 * Only DOS version are supported
10 */
12 #define MAX_POLYGONS 4096
13 #define MAX_GROUPS 2048
14 #define MSG_USAGE "usage: spr INPUT\n"
15 #define MSG_OPENERR "can't open file %s.\n"
16 #define MSG_WRITEERR "can't create file %s.\n"
18 struct polygoninfo {
19 uint16_t offset;
20 uint8_t color, w, h, num;
21 struct {
22 uint8_t x, y;
23 } point[256];
24 };
26 struct groupinfo {
27 uint16_t offset;
28 uint8_t x, y, num;
29 struct {
30 uint16_t offset;
31 uint8_t x, y;
32 uint16_t color;
33 bool group;
34 int id;
35 } child[256];
36 };
38 FILE *fp;
40 uint8_t *data;
41 uint16_t datalen, datapc;
43 struct polygoninfo poly[MAX_POLYGONS];
44 int polycount;
45 struct groupinfo group[MAX_GROUPS];
46 int groupcount;
48 uint8_t vbyte() {
49 return data[datapc++];
50 }
52 uint16_t vword() {
53 return (vbyte() << 8) | vbyte();
54 }
56 int findpoly(uint16_t offset) {
57 for(int i = 0; i < polycount; i++) {
58 if(poly[i].offset == offset)
59 return i;
60 }
62 return -1;
63 }
65 int findgroup(uint16_t offset) {
66 for(int i = 0; i < groupcount; i++) {
67 if(group[i].offset == offset)
68 return i;
69 }
71 return -1;
72 }
74 void process(bool readgroup) {
75 uint16_t adr = datapc;
76 uint8_t type = vbyte();
78 if(type >= 0xC0) {
79 uint8_t color = (type & 0x80) ? (type & 0x3F) : 0x0;
80 uint8_t w = vbyte();
81 uint8_t h = vbyte();
82 uint8_t num = vbyte();
84 if(!readgroup) {
85 poly[polycount].offset = adr;
86 poly[polycount].color = color;
87 poly[polycount].w = w;
88 poly[polycount].h = h;
89 poly[polycount].num = num;
90 }
92 for(int i = 0; i < num; i++) {
93 uint8_t x = vbyte();
94 uint8_t y = vbyte();
96 if(!readgroup) {
97 poly[polycount].point[i].x = x;
98 poly[polycount].point[i].y = y;
99 }
102 if(!readgroup)
103 ++polycount;
104 } else {
105 type &= 0x3F;
106 if(type == 2) {
107 uint8_t x = vbyte();
108 uint8_t y = vbyte();
109 uint8_t childs = vbyte();
111 if(readgroup) {
112 group[groupcount].offset = adr;
113 group[groupcount].x = x;
114 group[groupcount].y = y;
115 group[groupcount].num = childs;
118 for(int i = 0; i <= childs; i++) {
119 uint16_t offset = vword();
120 uint8_t xx = vbyte();
121 uint8_t yy = vbyte();
122 uint16_t color = 0xF;
124 if(offset & 0x8000)
125 color = vword() & 0x7F;
127 offset = (offset & 0x7FFF) << 1;
129 if(readgroup) {
130 group[groupcount].child[i].offset = offset;
131 group[groupcount].child[i].x = xx;
132 group[groupcount].child[i].y = yy;
133 group[groupcount].child[i].color = color;
137 if(readgroup)
138 ++groupcount;
139 } else {
140 printf("invalid type %u\n", type);
141 exit(1);
146 void linkgroups() {
147 for(int i = 0; i < groupcount; i++) {
148 for(int j = 0; j < group[i].num; i++) {
149 uint16_t offset = group[i].child[j].offset;
151 group[i].child[j].group = false;
152 int id = findpoly(offset);
153 if(id == -1) {
154 group[i].child[j].group = true;
155 id = findgroup(offset);
156 if(id == -1) {
157 printf("grouped polygon 0x%X not found\n", offset);
158 exit(1);
162 group[i].child[j].id = id;
167 uint8_t *loadfile(const char *name, uint16_t *size) {
168 FILE *fp;
169 if((fp = fopen(name, "r")) == NULL) {
170 printf(MSG_OPENERR, name);
171 exit(1);
174 fseek(fp, 0, SEEK_END);
175 int s = ftell(fp);
176 fseek(fp, 0, SEEK_SET);
178 uint8_t *ptr = malloc(s);
179 fread(ptr, s, 1, fp);
180 fclose(fp);
182 *size = s;
183 return ptr;
186 void svg_poly(char *prefix, int id) {
187 char name[256];
188 snprintf(name, 256, "%s_p%i.svg", prefix, id);
189 if((fp = fopen(name, "w")) == NULL) {
190 printf(MSG_WRITEERR, name);
191 exit(1);
194 int w = poly[id].w;
195 int h = poly[id].h;
197 if(w == 0)
198 w = 1;
199 if(h == 0)
200 h = 1;
202 printf("1px is p%i\n", id);
204 fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
205 fprintf(fp, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"%upx\" height=\"%upx\">\n", w, h);
207 fprintf(fp, "<polygon fill=\"black\" points=\"");
208 if(poly[id].num == 1) {
209 fprintf(fp, "%u,%u ", poly[id].point[0].x, poly[id].point[0].y);
210 } else if(poly[id].num == 2) {
211 int i = 0;
212 int j = 1;
213 if (poly[id].point[j].x > poly[id].point[i].x) {
214 fprintf(fp, "%u,%u ", poly[id].point[i].x, poly[id].point[i].y);
215 fprintf(fp, "%u,%u ", poly[id].point[j].x + 1, poly[id].point[j].y);
216 } else {
217 fprintf(fp, "%u,%u ", poly[id].point[j].x, poly[id].point[j].y);
218 fprintf(fp, "%u,%u ", poly[id].point[i].x + 1, poly[id].point[i].y);
220 } else {
221 for(int i = 0; i < poly[id].num / 2; i++) {
222 int j = poly[id].num - 1 - i;
223 if (poly[id].point[j].x > poly[id].point[i].x) {
224 fprintf(fp, "%u,%u ", poly[id].point[i].x, poly[id].point[i].y);
225 fprintf(fp, "%u,%u ", poly[id].point[j].x + 1, poly[id].point[j].y);
226 } else {
227 fprintf(fp, "%u,%u ", poly[id].point[j].x, poly[id].point[j].y);
228 fprintf(fp, "%u,%u ", poly[id].point[i].x + 1, poly[id].point[i].y);
232 fprintf(fp, "\"/>\n");
234 fprintf(fp, "</svg>");
236 fclose(fp);
239 void svg_group(char *prefix, int id) {
240 char name[256];
241 snprintf(name, 256, "%s_g%i.svg", prefix, id);
242 if((fp = fopen(name, "w")) == NULL) {
243 printf(MSG_WRITEERR, name);
244 exit(1);
247 fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
248 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");
250 for(int i = 0; i < group[id].num; i++) {
251 char c = group[id].child[i].group ? 'g' : 'p';
253 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);
256 fprintf(fp, "</svg>");
258 fclose(fp);
261 int main(int argc, char **argv) {
262 if(argc != 2) {
263 printf(MSG_USAGE);
264 exit(1);
267 data = loadfile(argv[1], &datalen);
269 while(datapc < datalen)
270 process(false);
272 datapc = 0;
273 while(datapc < datalen)
274 process(true);
276 linkgroups();
278 free(data);
280 for(int i = 0; i < polycount; i++)
281 svg_poly(argv[1], i);
283 for(int i = 0; i < groupcount; i++)
284 svg_group(argv[1], i);
286 return 0;