From: John Tsiombikas Date: Sat, 20 Jan 2024 06:00:49 +0000 (+0200) Subject: fixed scroll and added json2tmap tool X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=commitdiff_plain;h=8bec66098f3111e4b7c87361fd4142e94dcfeebd;p=mdlife fixed scroll and added json2tmap tool --- diff --git a/.gitignore b/.gitignore index 0f77bed..09004c7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.map *.z80 tools/pngdump/pngdump +tools/json2tmap/json2tmap core disasm .cache/ diff --git a/Makefile b/Makefile index d44e573..dff14a7 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ disasm: $(elf) $(OBJDUMP) -D $< >$@ src/data-asm.o: src/data.s data/font8x8.img data/cellspr.img data/simbabg.tiles \ - data/simbafg.tiles + data/simbafg.tiles data/simbafg.tmap src/z80prog-asm.o: src/z80prog.s $(z80bin) data/cellspr.img: data/cellspr.png @@ -76,6 +76,10 @@ clean: cleandep: rm -f $(dep) +.PHONY: cleandata +cleandata: + rm -f data/*.img data/*.tiles data/*.tmap data/*.cmap + .PHONY: run run: $(bin) mednafen $< @@ -97,10 +101,20 @@ debug: $(bin) # ---- tools ---- PNGDUMP = tools/pngdump/pngdump +JSON2TMAP = tools/json2tmap/json2tmap $(PNGDUMP): tools/pngdump/main.c tools/pngdump/image.c tools/pngdump/quant.c $(MAKE) -C tools/pngdump +$(JSON2TMAP): tools/json2tmap/json2tmap.c + $(MAKE) -C tools/json2tmap + +%.tmap: %.json $(JSON2TMAP) + $(JSON2TMAP) $< $@ + +%.tiles: %-tiles.png $(PNGDUMP) + $(PNGDUMP) -o $@ -oc $(@:.tiles=.cmap) -T 8x8 $< + %.tiles: %.png $(PNGDUMP) $(PNGDUMP) -o $@ -oc $(@:.tiles=.cmap) -om $(@:.tiles=.tmap) -T 8x8 -D $< diff --git a/src/part_simba.c b/src/part_simba.c index ea6f3ae..a63834d 100644 --- a/src/part_simba.c +++ b/src/part_simba.c @@ -67,18 +67,15 @@ void simba_start(void) /* set scrolling to whole screen */ vdp_setreg(VDP_REG_MODE3, 0); - scroll = 0; - vdp_setup_addr(VDP_VRAM, 0xf000); /* hscroll table is at f000, see vdp.S */ - VDP_DATA = 0; - VDP_DATA = 0; + scroll = 256; } void simba_update(void) { if(bnstate & PAD_LEFT) { - if(scroll < 0) scroll++; + if(scroll > 256) scroll--; } else if(bnstate & PAD_RIGHT) { - if(scroll > -192) scroll--; + if(scroll < 704) scroll++; } dbgval[0] = scroll; } @@ -86,6 +83,10 @@ void simba_update(void) void simba_vblank(void) { vdp_setup_addr(VDP_VRAM, 0xf000); /* hscroll table is at f000, see vdp.S */ - VDP_DATA = scroll; - VDP_DATA = scroll >> 1; + if(scroll < 512) { + VDP_DATA = 0; + } else { + VDP_DATA = 1024 - scroll; + } + VDP_DATA = 512 - (scroll >> 1); } diff --git a/tools/json2tmap/Makefile b/tools/json2tmap/Makefile new file mode 100644 index 0000000..edcd1d1 --- /dev/null +++ b/tools/json2tmap/Makefile @@ -0,0 +1,11 @@ +obj = json2tmap.o json.o dynarr.o +bin = json2tmap + +CFLAGS = -pedantic -Wall -g + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff --git a/tools/json2tmap/dynarr.c b/tools/json2tmap/dynarr.c new file mode 100644 index 0000000..59bbf8c --- /dev/null +++ b/tools/json2tmap/dynarr.c @@ -0,0 +1,141 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#include +#include +#include +#include "dynarr.h" + +/* The array descriptor keeps auxilliary information needed to manipulate + * the dynamic array. It's allocated adjacent to the array buffer. + */ +struct arrdesc { + int nelem, szelem; + int max_elem; + int bufsz; /* not including the descriptor */ +}; + +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) + +void *dynarr_alloc(int elem, int szelem) +{ + struct arrdesc *desc; + + if(!(desc = malloc(elem * szelem + sizeof *desc))) { + return 0; + } + desc->nelem = desc->max_elem = elem; + desc->szelem = szelem; + desc->bufsz = elem * szelem; + return (char*)desc + sizeof *desc; +} + +void dynarr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *dynarr_resize(void *da, int elem) +{ + int newsz; + void *tmp; + struct arrdesc *desc; + + if(!da) return 0; + desc = DESC(da); + + newsz = desc->szelem * elem; + + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { + return 0; + } + desc = tmp; + + desc->nelem = desc->max_elem = elem; + desc->bufsz = newsz; + return (char*)desc + sizeof *desc; +} + +int dynarr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int dynarr_size(void *da) +{ + return DESC(da)->nelem; +} + + +void *dynarr_clear(void *da) +{ + return dynarr_resize(da, 0); +} + +/* stack semantics */ +void *dynarr_push(void *da, void *item) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(nelem >= desc->max_elem) { + /* need to resize */ + struct arrdesc *tmp; + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + + if(item) { + memcpy((char*)da + desc->nelem * desc->szelem, item, desc->szelem); + } + desc->nelem++; + return da; +} + +void *dynarr_pop(void *da) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(!nelem) return da; + + if(nelem <= desc->max_elem / 3) { + /* reclaim space */ + struct arrdesc *tmp; + int newsz = desc->max_elem / 2; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} + +void *dynarr_finalize(void *da) +{ + struct arrdesc *desc = DESC(da); + memmove(desc, da, desc->bufsz); + return desc; +} diff --git a/tools/json2tmap/dynarr.h b/tools/json2tmap/dynarr.h new file mode 100644 index 0000000..619feeb --- /dev/null +++ b/tools/json2tmap/dynarr.h @@ -0,0 +1,90 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#ifndef DYNARR_H_ +#define DYNARR_H_ + +#define dynarr_alloc g3dimpl_dynarr_alloc +#define dynarr_free g3dimpl_dynarr_free +#define dynarr_resize g3dimpl_dynarr_resize +#define dynarr_empty g3dimpl_dynarr_empty +#define dynarr_size g3dimpl_dynarr_size +#define dynarr_clear g3dimpl_dynarr_clear +#define dynarr_push g3dimpl_dynarr_push +#define dynarr_pop g3dimpl_dynarr_pop +#define dynarr_finalize g3dimpl_dynarr_finalize + +/* usage example: + * ------------- + * int *arr = dynarr_alloc(0, sizeof *arr); + * + * int x = 10; + * arr = dynarr_push(arr, &x); + * x = 5; + * arr = dynarr_push(arr, &x); + * x = 42; + * arr = dynarr_push(arr, &x); + * + * for(i=0; i +#include +#include +#include +#include "dynarr.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#include +#else +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) +#include +#endif +#endif + +#include "json.h" + +#ifdef _MSC_VER +#define strncasecmp strnicmp +#endif + +struct json_obj *json_alloc_obj(void) +{ + struct json_obj *obj; + + if(!(obj = malloc(sizeof *obj))) { + fprintf(stderr, "json_alloc_obj: failed to allocate object\n"); + return 0; + } + json_init_obj(obj); + return obj; +} + +void json_free_obj(struct json_obj *obj) +{ + json_destroy_obj(obj); + free(obj); +} + +void json_init_obj(struct json_obj *obj) +{ + memset(obj, 0, sizeof *obj); +} + +void json_destroy_obj(struct json_obj *obj) +{ + int i; + + for(i=0; inum_items; i++) { + json_destroy_item(obj->items + i); + } + free(obj->items); +} + +struct json_arr *json_alloc_arr(void) +{ + struct json_arr *arr; + + if(!(arr = malloc(sizeof *arr))) { + fprintf(stderr, "json_alloc_arr: failed to allocate array\n"); + return 0; + } + json_init_arr(arr); + return arr; +} + +void json_free_arr(struct json_arr *arr) +{ + json_destroy_arr(arr); + free(arr); +} + +void json_init_arr(struct json_arr *arr) +{ + memset(arr, 0, sizeof *arr); +} + +void json_destroy_arr(struct json_arr *arr) +{ + int i; + + for(i=0; isize; i++) { + json_destroy_value(arr->val + i); + } + free(arr->val); +} + + +int json_item(struct json_item *item, const char *name) +{ + memset(item, 0, sizeof *item); + + if(!(item->name = strdup(name))) { + fprintf(stderr, "json_item: failed to allocate name\n"); + return -1; + } + return 0; +} + +void json_destroy_item(struct json_item *item) +{ + free(item->name); + json_destroy_value(&item->val); +} + +int json_value_str(struct json_value *jv, const char *str) +{ + jv->type = JSON_STR; + + jv->str = 0; + if(str && !(jv->str = strdup(str))) { + fprintf(stderr, "json_value_str: failed to duplicate string\n"); + return -1; + } + return 0; +} + +void json_value_num(struct json_value *jv, double num) +{ + jv->type = JSON_NUM; + jv->num = num; +} + +void json_value_bool(struct json_value *jv, int bval) +{ + jv->type = JSON_BOOL; + jv->boolean = bval; +} + +void json_value_obj(struct json_value *jv, struct json_obj *obj) +{ + jv->type = JSON_OBJ; + if(obj) { + jv->obj = *obj; + } else { + json_init_obj(&jv->obj); + } +} + +void json_value_arr(struct json_value *jv, struct json_arr *arr) +{ + jv->type = JSON_ARR; + if(arr) { + jv->arr = *arr; + } else { + json_init_arr(&jv->arr); + } +} + +void json_destroy_value(struct json_value *jv) +{ + switch(jv->type) { + case JSON_STR: + free(jv->str); + break; + + case JSON_OBJ: + json_destroy_obj(&jv->obj); + break; + + case JSON_ARR: + json_destroy_arr(&jv->arr); + break; + + default: + break; + } +} + +int json_obj_append(struct json_obj *obj, const struct json_item *item) +{ + if(obj->num_items >= obj->max_items) { + int newsz = obj->max_items ? (obj->max_items << 1) : 8; + void *tmp = realloc(obj->items, newsz * sizeof *obj->items); + if(!tmp) { + fprintf(stderr, "json_obj_append: failed to grow items array (%d)\n", newsz); + return -1; + } + obj->items = tmp; + obj->max_items = newsz; + } + + obj->items[obj->num_items++] = *item; + return 0; +} + +int json_arr_append(struct json_arr *arr, const struct json_value *val) +{ + if(arr->size >= arr->maxsize) { + int newsz = arr->maxsize ? (arr->maxsize << 1) : 8; + void *tmp = realloc(arr->val, newsz * sizeof *arr->val); + if(!tmp) { + fprintf(stderr, "json_arr_append: failed to grow array (%d)\n", newsz); + return -1; + } + arr->val = tmp; + arr->maxsize = newsz; + } + + arr->val[arr->size++] = *val; + return 0; +} + +struct json_item *json_find_item(const struct json_obj *obj, const char *name) +{ + int i; + for(i=0; inum_items; i++) { + if(strcmp(obj->items[i].name, name) == 0) { + return obj->items + i; + } + } + return 0; +} + +/* lookup functions */ + +struct json_value *json_lookup(struct json_obj *obj, const char *path) +{ + int len; + char *pelem; + const char *endp; + struct json_item *it = 0; + + pelem = alloca(strlen(path) + 1); + while(*path) { + endp = path; + while(*endp && *endp != '.') endp++; + if(!(len = endp - path)) break; + + memcpy(pelem, path, len); + pelem[len] = 0; + + /* continue after the . or point at the terminator */ + path = endp; + if(*path == '.') path++; + + if(!(it = json_find_item(obj, pelem))) { + return 0; + } + + if(it->val.type != JSON_OBJ) { + /* we hit a leaf. If the path continues we failed */ + if(*path) return 0; + } + + /* item is an object, we can continue the lookup if necessary */ + obj = &it->val.obj; + } + + return it ? &it->val : 0; +} + +const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_STR) { + return def; + } + return val->str; +} + +double json_lookup_num(struct json_obj *obj, const char *path, double def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_NUM) { + return def; + } + return val->num; +} + +int json_lookup_bool(struct json_obj *obj, const char *path, int def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_BOOL) { + return def; + } + return val->boolean; +} + +struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_OBJ) { + return def; + } + return &val->obj; +} + +struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_ARR) { + return def; + } + return &val->arr; +} + + +/* ---- parser ---- */ + +#define MAX_TOKEN_SIZE 512 +struct parser { + char *text; + char nextc; + char *token; +}; + +enum { TOKEN_NUM, TOKEN_STR, TOKEN_BOOL }; /* plus all the single-char tokens */ + + +static int item(struct parser *p, struct json_item *it); +static int array(struct parser *p, struct json_arr *arr); +static int object(struct parser *p, struct json_obj *obj); + + +static int next_char(struct parser *p) +{ + while(*p->text) { + p->nextc = *p->text++; + if(!isspace(p->nextc)) break; + } + return p->nextc; +} + +#define SET_TOKEN(token, str, len) \ + do { \ + DYNARR_RESIZE(token, (len) + 1); \ + memcpy(token, str, len); \ + token[len] = 0; \ + } while(0) + +static int next_token(struct parser *p) +{ + int len; + char *ptr, *s; + + if(!p->nextc) return -1; + + switch(p->nextc) { + case '{': + case '}': + case ',': + case '[': + case ']': + case ':': + SET_TOKEN(p->token, &p->nextc, 1); + next_char(p); + return p->token[0]; + + case '"': + DYNARR_CLEAR(p->token); + next_char(p); + while(p->nextc && p->nextc != '"') { + DYNARR_STRPUSH(p->token, p->nextc); + next_char(p); + } + next_char(p); + return TOKEN_STR; + + default: + break; + } + + s = p->text - 1; + + strtod(s, &ptr); + if(ptr != s) { + len = ptr - s; + SET_TOKEN(p->token, s, len); + p->text = ptr; + next_char(p); + return TOKEN_NUM; + } + + if(strncasecmp(s, "true", 4) == 0) { + SET_TOKEN(p->token, "true", 4); + p->text += 3; + next_char(p); + return TOKEN_BOOL; + } + if(strncasecmp(s, "false", 5) == 0) { + SET_TOKEN(p->token, "false", 5); + p->text += 4; + next_char(p); + return TOKEN_BOOL; + } + + SET_TOKEN(p->token, &p->nextc, 1); + fprintf(stderr, "json_parse: unexpected character: %c\n", p->nextc); + return -1; +} + +static int expect(struct parser *p, int tok) +{ + return next_token(p) == tok ? 1 : 0; +} + +static const char *toktypestr(int tok) +{ + static char buf[] = "' '"; + switch(tok) { + case TOKEN_NUM: return "number"; + case TOKEN_STR: return "string"; + case TOKEN_BOOL: return "boolean"; + default: + break; + } + buf[1] = tok; + return buf; +} + +#define EXPECT(p, x) \ + do { \ + if(!expect(p, x)) { \ + fprintf(stderr, "json_parse: expected: %s, found: %s\n", toktypestr(x), (p)->token); \ + return -1; \ + } \ + } while(0) + +static int value(struct parser *p, struct json_value *val) +{ + int toktype; + struct json_obj obj; + struct json_arr arr; + + toktype = next_token(p); + switch(toktype) { + case TOKEN_STR: + if(json_value_str(val, p->token) == -1) { + return -1; + } + break; + + case TOKEN_NUM: + json_value_num(val, atof(p->token)); + break; + + case TOKEN_BOOL: + json_value_bool(val, *p->token == 't' ? 1 : 0); + break; + + case '{': /* object */ + if(object(p, &obj) == -1) { + return -1; + } + json_value_obj(val, &obj); + break; + + case '[': /* array */ + if(array(p, &arr) == -1) { + return -1; + } + json_value_arr(val, &arr); + break; + + default: + fprintf(stderr, "json_parse: unexpected token %s while parsing item\n", p->text); + return -1; + } + return 0; +} + +static int item(struct parser *p, struct json_item *it) +{ + EXPECT(p, TOKEN_STR); + if(json_item(it, p->token) == -1) { + return -1; + } + EXPECT(p, ':'); + if(value(p, &it->val) == -1) { + free(it->name); + return -1; + } + return 0; +} + +static int array(struct parser *p, struct json_arr *arr) +{ + struct json_value val; + + json_init_arr(arr); + + while(p->nextc != -1 && p->nextc != ']') { + if(value(p, &val) == -1) { + fprintf(stderr, "json_parse: expected value in array\n"); + json_destroy_arr(arr); + return -1; + } + + if(json_arr_append(arr, &val) == -1) { + json_destroy_value(&val); + json_destroy_arr(arr); + return -1; + } + + if(p->nextc == ',') expect(p, ','); /* eat up comma separator */ + } + EXPECT(p, ']'); + return 0; +} + +static int object(struct parser *p, struct json_obj *obj) +{ + struct json_item it; + + json_init_obj(obj); + + while(p->nextc != -1 && p->nextc != '}') { + if(item(p, &it) == -1) { + fprintf(stderr, "json_parse: expected item in object\n"); + json_destroy_obj(obj); + return -1; + } + + if(json_obj_append(obj, &it) == -1) { + json_destroy_item(&it); + json_destroy_obj(obj); + return -1; + } + + if(p->nextc == ',') expect(p, ','); /* eat up comma separator */ + } + EXPECT(p, '}'); + return 0; +} + +int json_parse(struct json_obj *root, const char *text) +{ + struct parser p; + + if(!text || !*text) return -1; + + p.nextc = *text; + p.text = (char*)(text + 1); + if(!(p.token = dynarr_alloc(0, 1))) { + fprintf(stderr, "json_parse: failed to allocate token dynamic array\n"); + return -1; + } + + EXPECT(&p, '{'); + if(object(&p, root) == -1) { + dynarr_free(p.token); + return -1; + } + dynarr_free(p.token); + return 0; +} + + +static void putind(FILE *fp, int ind) +{ + int i; + for(i=0; inum_items; i++) { + putind(fp, ind + 1); + json_print_item(fp, obj->items + i, ind + 1); + if(i < obj->num_items - 1) { + fputs(",\n", fp); + } else { + fputc('\n', fp); + } + } + + putind(fp, ind); + fputs("}", fp); +} + +void json_print_arr(FILE *fp, struct json_arr *arr, int ind) +{ + int i; + + fputs("[\n", fp); + + for(i=0; isize; i++) { + putind(fp, ind + 1); + json_print_value(fp, arr->val + i, ind + 1); + if(i < arr->size - 1) { + fputs(",\n", fp); + } else { + fputc('\n', fp); + } + } + + putind(fp, ind); + fputs("]", fp); +} + +void json_print_item(FILE *fp, struct json_item *item, int ind) +{ + fprintf(fp, "\"%s\": ", item->name); + json_print_value(fp, &item->val, ind); +} + +void json_print_value(FILE *fp, struct json_value *val, int ind) +{ + switch(val->type) { + case JSON_STR: + fprintf(fp, "\"%s\"", val->str); + break; + case JSON_NUM: + fprintf(fp, "%g", val->num); + break; + case JSON_BOOL: + fprintf(fp, "%s", val->boolean ? "true" : "false"); + break; + case JSON_OBJ: + json_print_obj(fp, &val->obj, ind); + break; + case JSON_ARR: + json_print_arr(fp, &val->arr, ind); + break; + default: + fputs("", fp); + } +} diff --git a/tools/json2tmap/json.h b/tools/json2tmap/json.h new file mode 100644 index 0000000..705a82c --- /dev/null +++ b/tools/json2tmap/json.h @@ -0,0 +1,105 @@ +#ifndef JSON_H_ +#define JSON_H_ + +enum { + JSON_NULL, + JSON_STR, /* "foo" */ + JSON_NUM, /* 3.141 */ + JSON_BOOL, /* true */ + JSON_OBJ, /* { ... } */ + JSON_ARR /* [ ... ] */ +}; + +struct json_value; + +/* objects are collections of items { "foo": 1, "bar": 2 } */ +struct json_obj { + struct json_item *items; + int num_items, max_items; +}; + +/* arrays are collections of values [ "foo", "bar", 3.14, false, "xyzzy" ] */ +struct json_arr { + struct json_value *val; + int size, maxsize; +}; + +struct json_value { + int type; + + char *str; /* JSON_STR */ + double num; /* JSON_NUM */ + int boolean; /* JSON_BOOL */ + struct json_obj obj; /* JSON_OBJ */ + struct json_arr arr; /* JSON_ARR */ +}; + +/* items are key-value pairs "foo": "xyzzy" */ +struct json_item { + char *name; + struct json_value val; + + struct json_item *next; +}; + + +struct json_obj *json_alloc_obj(void); /* malloc + json_init_obj */ +void json_free_obj(struct json_obj *obj); /* json_destroy_obj + free */ +void json_init_obj(struct json_obj *obj); +void json_destroy_obj(struct json_obj *obj); + +struct json_arr *json_alloc_arr(void); /* malloc + json_init_arr */ +void json_free_arr(struct json_arr *arr); /* json_destroy_arr + free */ +void json_init_arr(struct json_arr *arr); +void json_destroy_arr(struct json_arr *arr); + +/* initialize item */ +int json_item(struct json_item *item, const char *name); +void json_destroy_item(struct json_item *item); + +/* pointer values for str, obj, arr can be null */ +int json_value_str(struct json_value *jv, const char *str); +void json_value_num(struct json_value *jv, double num); +void json_value_bool(struct json_value *jv, int bval); +void json_value_obj(struct json_value *jv, struct json_obj *obj); /* shallow copy obj */ +void json_value_arr(struct json_value *jv, struct json_arr *arr); /* shallow copy arr */ + +void json_destroy_value(struct json_value *jv); + +/* item can be null, in which case only space is allocated + * if not null, contents are shallow-copied (moved), do not destroy or use + */ +int json_obj_append(struct json_obj *obj, const struct json_item *item); + +/* val can be null in which case only space is allocated + * if not null, contents are shallow-copied (moved), do not destroy or use + */ +int json_arr_append(struct json_arr *arr, const struct json_value *val); + +/* find named item in an object (direct descendant name only, not a path) */ +struct json_item *json_find_item(const struct json_obj *obj, const char *name); + +/* json_lookup returns 0 if the requested value is not found */ +struct json_value *json_lookup(struct json_obj *root, const char *path); + +/* typed lookup functions return their default argument if the requested value + * is not found, or if it has the wrong type. + */ +const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def); +double json_lookup_num(struct json_obj *obj, const char *path, double def); +int json_lookup_bool(struct json_obj *obj, const char *path, int def); +/* these next two are probably not very useful */ +struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def); +struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def); + + +int json_parse(struct json_obj *root, const char *text); + +/* mostly useful for debugging */ +void json_print(FILE *fp, struct json_obj *root); +void json_print_obj(FILE *fp, struct json_obj *obj, int ind); +void json_print_arr(FILE *fp, struct json_arr *arr, int ind); +void json_print_item(FILE *fp, struct json_item *item, int ind); +void json_print_value(FILE *fp, struct json_value *val, int ind); + +#endif /* JSON_H_ */ diff --git a/tools/json2tmap/json2tmap.c b/tools/json2tmap/json2tmap.c new file mode 100644 index 0000000..a7f2a8e --- /dev/null +++ b/tools/json2tmap/json2tmap.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include "json.h" + +int ispow2(unsigned int x); + +int main(int argc, char **argv) +{ + int i, x, y, xtiles, ytiles, idx, tileno; + long filesz; + FILE *fp; + struct json_obj json, *jtileobj; + struct json_item *jitem; + struct json_arr *jtiles; + char *buf; + uint16_t *tmap; + + if(!argv[1] || !argv[2]) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + if(!(fp = fopen(argv[1], "rb"))) { + fprintf(stderr, "failed to open input file: %s\n", argv[1]); + return 1; + } + fseek(fp, 0, SEEK_END); + filesz = ftell(fp); + rewind(fp); + + if(!(buf = malloc(filesz + 1))) { + fprintf(stderr, "failed to load file: %s\n", argv[1]); + return 1; + } + if(fread(buf, 1, filesz, fp) != filesz) { + fprintf(stderr, "unexpected EOF while reading %s\n", argv[1]); + return 1; + } + buf[filesz] = 0; + fclose(fp); + + if(json_parse(&json, buf) == -1) { + return 1; + } + + xtiles = (int)json_lookup_num(&json, "tileswide", -1); + ytiles = (int)json_lookup_num(&json, "tileshigh", -1); + x = (int)json_lookup_num(&json, "tilewidth", 8); + y = (int)json_lookup_num(&json, "tileheight", 8); + if(x != 8 || y != 8) { + fprintf(stderr, "invalid tile size: %dx%d\n", x, y); + return 1; + } + if(!ispow2(xtiles) || xtiles < 32 || xtiles > 128 || !ispow2(ytiles) || + ytiles < 32 || ytiles > 128) { + fprintf(stderr, "invalid tilemap size: %dx%d\n", xtiles, ytiles); + return 1; + } + if(!(jitem = json_find_item(&json, "layers")) || jitem->val.type != JSON_ARR) { + fprintf(stderr, "layers array missing\n"); + return 1; + } + if(jitem->val.arr.size > 1) { + printf("multiple layers found, ignoring all but the first\n"); + return 1; + } + if(!(jitem = json_find_item(&jitem->val.arr.val[0].obj, "tiles")) || jitem->val.type != JSON_ARR) { + fprintf(stderr, "tiles array missing\n"); + return 1; + } + jtiles = &jitem->val.arr; + + if(!(tmap = calloc(xtiles * ytiles, sizeof *tmap))) { + fprintf(stderr, "failed to allocate %dx%d tilemap\n", xtiles, ytiles); + return 1; + } + + for(i=0; isize; i++) { + if(jtiles->val[i].type != JSON_OBJ) { + fprintf(stderr, "invalid tiles array\n"); + return 1; + } + jtileobj = &jtiles->val[i].obj; + + if((idx = json_lookup_num(jtileobj, "index", -1)) == -1) { + continue; + } + x = json_lookup_num(jtileobj, "x", -1); + y = json_lookup_num(jtileobj, "y", -1); + if(x < 0 || y < 0) continue; + tileno = json_lookup_num(jtileobj, "tile", -1); + + tmap[i] = (tileno << 8) | (tileno >> 8); + /* TODO flips */ + } + + if(!(fp = fopen(argv[2], "wb"))) { + fprintf(stderr, "failed to open output file: %s\n", argv[2]); + return 1; + } + fwrite(tmap, xtiles * ytiles, sizeof *tmap, fp); + fclose(fp); + return 0; +} + +int ispow2(unsigned int x) +{ + int i, count = 0; + + for(i=0; i<32; i++) { + if(x & 1) { + if(++count > 1) return 0; + } + x >>= 1; + } + return 1; +}