From: John Tsiombikas Date: Tue, 28 Dec 2021 16:29:16 +0000 (+0200) Subject: working on the demosystem, added libtreestore X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=andemo;a=commitdiff_plain;h=313480bbe9994a200ed9a4355d97a033bf0d6151 working on the demosystem, added libtreestore --- diff --git a/Makefile b/Makefile index e133269..163f01f 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ warn = -pedantic -Wall dbg = -g #opt = -O3 -ffast-math -fno-strict-aliasing def = -DMINIGLUT_USE_LIBC -DGLEW_STATIC -incdir = -Isrc -Ilibs -Ilibs/imago/src -Ilibs/glew +incdir = -Isrc -Ilibs -Ilibs/imago/src -Ilibs/treestore -Ilibs/glew libdir = -Llibs/unix CFLAGS = $(warn) $(dbg) $(opt) $(def) $(incdir) -fcommon -MMD -LDFLAGS = $(libdir) $(libsys) $(libgl) -limago -lpsys -lanim $(libc) +LDFLAGS = $(libdir) $(libsys) $(libgl) -limago -lpsys -lanim -ltreestore $(libc) sys ?= $(shell uname -s | sed 's/MINGW.*/mingw/') ifeq ($(sys), mingw) diff --git a/Makefile.android b/Makefile.android index d613b47..4a77672 100644 --- a/Makefile.android +++ b/Makefile.android @@ -20,12 +20,12 @@ warn = -pedantic -Wall dbg = -g opt = -O3 -ffast-math -fno-strict-aliasing def = -DGLDEF -incdir = -Isrc -Ilibs -Ilibs/imago/src +incdir = -Isrc -Ilibs -Ilibs/imago/src -Ilibs/treestore libdir = -Llibs/android CC = $(TC)clang CFLAGS = $(CCSYSROOT) $(ISYS) $(warn) $(dbg) $(opt) $(def) $(incdir) -fPIC -fcommon -MMD -LDFLAGS = $(LDSYSROOT) $(libdir) -lm -landroid -llog -lEGL -lGLESv2 -limago -lpsys -lanim +LDFLAGS = $(LDSYSROOT) $(libdir) -lm -landroid -llog -lEGL -lGLESv2 -limago -lpsys -lanim -ltreestore $(name).apk: $(name).aligned.apk keystore.jks apksigner sign --ks keystore.jks --ks-key-alias androidkey --ks-pass pass:android --key-pass pass:android --out $@ $< diff --git a/libs/Makefile b/libs/Makefile index 0800384..26536a9 100644 --- a/libs/Makefile +++ b/libs/Makefile @@ -1,8 +1,8 @@ .PHONY: all -all: imago anim psys +all: imago anim psys treestore .PHONY: clean -clean: clean-imago clean-anim clean-psys +clean: clean-imago clean-anim clean-psys clean-treestore .PHONY: imago @@ -28,3 +28,11 @@ psys: .PHONY: clean-psys clean-psys: $(MAKE) -C psys clean + +.PHONY: treestore +treestore: + $(MAKE) -C treestore + +.PHONY: clean-treestore +clean-treestore: + $(MAKE) -C treestore clean diff --git a/libs/treestore/LICENSE b/libs/treestore/LICENSE new file mode 100644 index 0000000..536e666 --- /dev/null +++ b/libs/treestore/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2016 John Tsiombikas + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libs/treestore/Makefile b/libs/treestore/Makefile new file mode 100644 index 0000000..cb9f7b3 --- /dev/null +++ b/libs/treestore/Makefile @@ -0,0 +1,27 @@ +obj = treestore.o text.o dynarr.o +lib = ../unix/libtreestore.a + +sys ?= $(shell uname -s | sed 's/MINGW.*/mingw/') +ifeq ($(sys), mingw) + obj = treestore.w32.o text.w32.o dynarr.w32.o + lib = ../w32/libtreestore.a +endif +ifeq ($(sys), android-arm64) + obj = treestore.arm64.o text.arm64.o dynarr.arm64.o + lib = ../android/libtreestore.a +endif + +CFLAGS = -O3 + +$(lib): $(obj) + $(AR) rcs $@ $(obj) + +%.arm64.o: %.c + $(CC) -o $@ $(CFLAGS) -c $< + +%.w32.o: %.c + $(CC) -o $@ $(CFLAGS) -c $< + +.PHONY: clean +clean: + rm -f $(obj) $(lib) diff --git a/libs/treestore/README.md b/libs/treestore/README.md new file mode 100644 index 0000000..f75efa9 --- /dev/null +++ b/libs/treestore/README.md @@ -0,0 +1,38 @@ +libtreestore +============ + +Libtreestore is a simple C library for reading/writing hierarchical data in a +json-like text format, or a chunk-based binary format. + +A better way to describe the text format is like XML without the CDATA, and with +curly braces instead of tags: + +``` +rootnode { + some_attribute = "some_string_value" + some_numeric_attrib = 10 + vector_attrib = [255, 128, 0] + array_attrib = ["tom", "dick", "harry"] + + # you can have multiple nodes with the same name + childnode { + childattr = "whatever" + } + childnode { + another_childattr = "xyzzy" + } +} +``` + +License +------- +Copyright (C) 2016-2019 John Tsiombikas + +Libtreestore is free software. Feel free to use, modify, and/or redistribute +it, under the terms of the MIT/X11 license. See LICENSE for detauls. + +Issues +------ +At the moment only the text format has been implemented. + +More info soon... diff --git a/libs/treestore/dynarr.c b/libs/treestore/dynarr.c new file mode 100644 index 0000000..2d3f611 --- /dev/null +++ b/libs/treestore/dynarr.c @@ -0,0 +1,133 @@ +/* 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 *ts_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 ts_dynarr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *ts_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 ts_dynarr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int ts_dynarr_size(void *da) +{ + return DESC(da)->nelem; +} + + +void *ts_dynarr_clear(void *da) +{ + return ts_dynarr_resize(da, 0); +} + +/* stack semantics */ +void *ts_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 = ts_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); + } + return da; +} + +void *ts_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 = ts_dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} diff --git a/libs/treestore/dynarr.h b/libs/treestore/dynarr.h new file mode 100644 index 0000000..513a431 --- /dev/null +++ b/libs/treestore/dynarr.h @@ -0,0 +1,69 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#ifndef DYNARR_H_ +#define DYNARR_H_ + +/* usage example: + * ------------- + * int *arr = ts_dynarr_alloc(0, sizeof *arr); + * + * int x = 10; + * arr = ts_dynarr_push(arr, &x); + * x = 5; + * arr = ts_dynarr_push(arr, &x); + * x = 42; + * arr = ts_dynarr_push(arr, &x); + * + * for(i=0; i +#include +#include +#include +#include +#include "treestore.h" +#include "dynarr.h" + +struct parser { + struct ts_io *io; + int nline; + char *token; + int nextc; +}; + +enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR }; + +static struct ts_node *read_node(struct parser *pstate); +static int read_array(struct parser *pstate, struct ts_value *tsv, char endsym); +static int next_token(struct parser *pstate); + +static int print_attr(struct ts_attr *attr, struct ts_io *io, int level); +static char *value_to_str(struct ts_value *value); +static int tree_level(struct ts_node *n); +static const char *indent(int x); +static const char *toktypestr(int type); + +#define EXPECT(type) \ + do { \ + if(next_token(pst) != (type)) { \ + fprintf(stderr, "expected %s token\n", toktypestr(type)); \ + goto err; \ + } \ + } while(0) + +#define EXPECT_SYM(c) \ + do { \ + if(next_token(pst) != TOK_SYM || pst->token[0] != (c)) { \ + fprintf(stderr, "expected symbol: %c\n", c); \ + goto err; \ + } \ + } while(0) + + +struct ts_node *ts_text_load(struct ts_io *io) +{ + char *root_name; + struct parser pstate, *pst = &pstate; + struct ts_node *node = 0; + + pstate.io = io; + pstate.nline = 0; + pstate.nextc = -1; + if(!(pstate.token = ts_dynarr_alloc(0, 1))) { + perror("failed to allocate token string"); + return 0; + } + + EXPECT(TOK_ID); + if(!(root_name = strdup(pst->token))) { + perror("failed to allocate root node name"); + ts_dynarr_free(pst->token); + return 0; + } + EXPECT_SYM('{'); + if(!(node = read_node(pst))) { + ts_dynarr_free(pst->token); + return 0; + } + node->name = root_name; + +err: + ts_dynarr_free(pst->token); + return node; +} + +static int read_value(struct parser *pst, int toktype, struct ts_value *val) +{ + switch(toktype) { + case TOK_NUM: + ts_set_valuef(val, atof(pst->token)); + break; + + case TOK_SYM: + if(pst->token[0] == '[' || pst->token[0] == '{') { + char endsym = pst->token[0] + 2; /* end symbol is dist 2 from either '[' or '{' */ + if(read_array(pst, val, endsym) == -1) { + return -1; + } + } else { + fprintf(stderr, "read_node: unexpected rhs symbol: %c\n", pst->token[0]); + } + break; + + case TOK_ID: + case TOK_STR: + default: + ts_set_value_str(val, pst->token); + } + + return 0; +} + +static struct ts_node *read_node(struct parser *pst) +{ + int type; + struct ts_node *node; + + if(!(node = ts_alloc_node())) { + perror("failed to allocate treestore node"); + return 0; + } + + while((type = next_token(pst)) == TOK_ID) { + char *id; + + if(!(id = strdup(pst->token))) { + goto err; + } + + EXPECT(TOK_SYM); + + if(pst->token[0] == '=') { + /* attribute */ + struct ts_attr *attr; + int type; + + if(!(attr = ts_alloc_attr())) { + goto err; + } + + if((type = next_token(pst)) == -1) { + ts_free_attr(attr); + fprintf(stderr, "read_node: unexpected EOF\n"); + goto err; + } + + if(read_value(pst, type, &attr->val) == -1) { + ts_free_attr(attr); + fprintf(stderr, "failed to read value\n"); + goto err; + } + attr->name = id; + ts_add_attr(node, attr); + + } else if(pst->token[0] == '{') { + /* child */ + struct ts_node *child; + + if(!(child = read_node(pst))) { + ts_free_node(node); + return 0; + } + + child->name = id; + ts_add_child(node, child); + + } else { + fprintf(stderr, "unexpected token: %s\n", pst->token); + goto err; + } + } + + if(type != TOK_SYM || pst->token[0] != '}') { + fprintf(stderr, "expected closing brace\n"); + goto err; + } + return node; + +err: + fprintf(stderr, "treestore read_node failed\n"); + ts_free_node(node); + return 0; +} + +static int read_array(struct parser *pst, struct ts_value *tsv, char endsym) +{ + int type; + struct ts_value values[32]; + int i, nval = 0; + int res; + + while((type = next_token(pst)) != -1) { + ts_init_value(values + nval); + if(read_value(pst, type, values + nval) == -1) { + return -1; + } + if(nval < 31) { + ++nval; + } else { + ts_destroy_value(values + nval); + } + + type = next_token(pst); + if(!(type == TOK_SYM && (pst->token[0] == ',' || pst->token[0] == endsym))) { + fprintf(stderr, "read_array: expected comma or end symbol ('%c')\n", endsym); + return -1; + } + if(pst->token[0] == endsym) { + break; /* we're done */ + } + } + + if(!nval) { + return -1; + } + + res = ts_set_value_arr(tsv, nval, values); + + for(i=0; inextc >= 0) { + c = pst->nextc; + pst->nextc = -1; + } else { + if(pst->io->read(&c, 1, pst->io->data) < 1) { + return -1; + } + } + return c; +} + +static void ungetchar(char c, struct parser *pst) +{ + assert(pst->nextc == -1); + pst->nextc = c; +} + +static int next_token(struct parser *pst) +{ + int c; + + DYNARR_CLEAR(pst->token); + + /* skip whitespace */ + while((c = nextchar(pst)) != -1) { + if(c == '#') { /* skip to end of line */ + while((c = nextchar(pst)) != -1 && c != '\n'); + if(c == -1) return -1; + } + if(!isspace(c)) break; + if(c == '\n') ++pst->nline; + } + if(c == -1) return -1; + + DYNARR_STRPUSH(pst->token, c); + + if(isdigit(c) || c == '-' || c == '+') { + /* token is a number */ + int found_dot = 0; + while((c = nextchar(pst)) != -1 && + (isdigit(c) || (c == '.' && !found_dot))) { + DYNARR_STRPUSH(pst->token, c); + if(c == '.') found_dot = 1; + } + if(c != -1) ungetchar(c, pst); + return TOK_NUM; + } + if(isalpha(c)) { + /* token is an identifier */ + while((c = nextchar(pst)) != -1 && (isalnum(c) || c == '_')) { + DYNARR_STRPUSH(pst->token, c); + } + if(c != -1) ungetchar(c, pst); + return TOK_ID; + } + if(c == '"') { + /* token is a string constant, remove the opening quote */ + DYNARR_STRPOP(pst->token); + while((c = nextchar(pst)) != -1 && c != '"') { + DYNARR_STRPUSH(pst->token, c); + if(c == '\n') ++pst->nline; + } + if(c != '"') { + return -1; + } + return TOK_STR; + } + return TOK_SYM; +} + +int ts_text_save(struct ts_node *tree, struct ts_io *io) +{ + char *buf; + struct ts_node *c; + struct ts_attr *attr; + int lvl = tree_level(tree); + int sz, inline_attr, res = -1; + + if(!(buf = malloc(lvl + strlen(tree->name) + 4))) { + perror("ts_text_save failed to allocate buffer"); + goto end; + } + + if(tree->child_list || (tree->attr_list && tree->attr_list->next)) { + inline_attr = 0; + } else { + inline_attr = 1; + } + + sz = sprintf(buf, "%s%s {", indent(lvl), tree->name); + if(!inline_attr) { + strcat(buf, "\n"); + sz++; + } + if(io->write(buf, sz, io->data) < sz) { + goto end; + } + + attr = tree->attr_list; + while(attr) { + if(print_attr(attr, io, inline_attr ? -1 : lvl) == -1) { + goto end; + } + attr = attr->next; + } + + c = tree->child_list; + while(c) { + if(ts_text_save(c, io) == -1) { + goto end; + } + c = c->next; + } + + if(inline_attr) { + sz = sprintf(buf, "}\n"); + } else { + sz = sprintf(buf, "%s}\n", indent(lvl)); + } + if(io->write(buf, sz, io->data) < sz) { + goto end; + } + res = 0; +end: + free(buf); + return res; +} + +static int print_attr(struct ts_attr *attr, struct ts_io *io, int level) +{ + char *buf, *val; + int sz; + + if(!(val = value_to_str(&attr->val))) { + return -1; + } + + sz = (level >= 0 ? level : 0) + strlen(attr->name) + ts_dynarr_size(val) + 5; + if(!(buf = malloc(sz))) { + perror("print_attr: failed to allocate name buffer"); + ts_dynarr_free(val); + return -1; + } + + if(level >= 0) { + sz = sprintf(buf, "%s%s = %s\n", indent(level + 1), attr->name, val); + } else { + sz = sprintf(buf, " %s = %s ", attr->name, val); + } + if(io->write(buf, sz, io->data) < sz) { + ts_dynarr_free(val); + free(buf); + return -1; + } + ts_dynarr_free(val); + free(buf); + return 0; +} + +static char *append_dynstr(char *dest, char *s) +{ + while(*s) { + DYNARR_STRPUSH(dest, *s++); + } + return dest; +} + +static char *value_to_str(struct ts_value *value) +{ + int i; + char buf[128]; + char *str, *valstr; + + if(!(str = ts_dynarr_alloc(0, 1))) { + return 0; + } + + switch(value->type) { + case TS_NUMBER: + sprintf(buf, "%g", value->fnum); + str = append_dynstr(str, buf); + break; + + case TS_VECTOR: + DYNARR_STRPUSH(str, '['); + for(i=0; ivec_size; i++) { + if(i == 0) { + sprintf(buf, "%g", value->vec[i]); + } else { + sprintf(buf, ", %g", value->vec[i]); + } + str = append_dynstr(str, buf); + } + DYNARR_STRPUSH(str, ']'); + break; + + case TS_ARRAY: + DYNARR_STRPUSH(str, '['); + for(i=0; iarray_size; i++) { + if(i > 0) { + str = append_dynstr(str, ", "); + } + if(!(valstr = value_to_str(value->array + i))) { + ts_dynarr_free(str); + return 0; + } + str = append_dynstr(str, valstr); + ts_dynarr_free(valstr); + } + DYNARR_STRPUSH(str, ']'); + break; + + default: + sprintf(buf, "\"%s\"", value->str); + str = append_dynstr(str, buf); + } + + return str; +} + +static int tree_level(struct ts_node *n) +{ + if(!n->parent) return 0; + return tree_level(n->parent) + 1; +} + +static const char *indent(int x) +{ + static const char buf[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + const char *end = buf + sizeof buf - 1; + return x > sizeof buf - 1 ? buf : end - x; +} + +static const char *toktypestr(int type) +{ + switch(type) { + case TOK_ID: + return "identifier"; + case TOK_NUM: + return "number"; + case TOK_STR: + return "string"; + case TOK_SYM: + return "symbol"; + } + return "unknown"; +} diff --git a/libs/treestore/treestore.c b/libs/treestore/treestore.c new file mode 100644 index 0000000..899cfa0 --- /dev/null +++ b/libs/treestore/treestore.c @@ -0,0 +1,809 @@ +#include +#include +#include +#include +#include +#include "treestore.h" + +#ifdef WIN32 +#include +#else +#include +#endif + +struct ts_node *ts_text_load(struct ts_io *io); +int ts_text_save(struct ts_node *tree, struct ts_io *io); + +static long io_read(void *buf, size_t bytes, void *uptr); +static long io_write(const void *buf, size_t bytes, void *uptr); + + +/* ---- ts_value implementation ---- */ + +int ts_init_value(struct ts_value *tsv) +{ + memset(tsv, 0, sizeof *tsv); + return 0; +} + +void ts_destroy_value(struct ts_value *tsv) +{ + int i; + + free(tsv->str); + free(tsv->vec); + + for(i=0; iarray_size; i++) { + ts_destroy_value(tsv->array + i); + } + free(tsv->array); +} + + +struct ts_value *ts_alloc_value(void) +{ + struct ts_value *v = malloc(sizeof *v); + if(!v || ts_init_value(v) == -1) { + free(v); + return 0; + } + return v; +} + +void ts_free_value(struct ts_value *tsv) +{ + ts_destroy_value(tsv); + free(tsv); +} + + +int ts_copy_value(struct ts_value *dest, struct ts_value *src) +{ + int i; + + if(dest == src) return 0; + + *dest = *src; + + dest->str = 0; + dest->vec = 0; + dest->array = 0; + + if(src->str) { + if(!(dest->str = malloc(strlen(src->str) + 1))) { + goto fail; + } + strcpy(dest->str, src->str); + } + if(src->vec && src->vec_size > 0) { + if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) { + goto fail; + } + memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec); + } + if(src->array && src->array_size > 0) { + if(!(dest->array = calloc(src->array_size, sizeof *src->array))) { + goto fail; + } + for(i=0; iarray_size; i++) { + if(ts_copy_value(dest->array + i, src->array + i) == -1) { + goto fail; + } + } + } + return 0; + +fail: + free(dest->str); + free(dest->vec); + if(dest->array) { + for(i=0; iarray_size; i++) { + ts_destroy_value(dest->array + i); + } + free(dest->array); + } + return -1; +} + +#define MAKE_NUMSTR_FUNC(type, fmt) \ + static char *make_##type##str(type x) \ + { \ + static char scrap[128]; \ + char *str; \ + int sz = snprintf(scrap, sizeof scrap, fmt, x); \ + if(!(str = malloc(sz + 1))) return 0; \ + sprintf(str, fmt, x); \ + return str; \ + } + +MAKE_NUMSTR_FUNC(int, "%d") +MAKE_NUMSTR_FUNC(float, "%g") + + +struct val_list_node { + struct ts_value val; + struct val_list_node *next; +}; + +int ts_set_value_str(struct ts_value *tsv, const char *str) +{ + if(tsv->str) { + ts_destroy_value(tsv); + if(ts_init_value(tsv) == -1) { + return -1; + } + } + + tsv->type = TS_STRING; + if(!(tsv->str = malloc(strlen(str) + 1))) { + return -1; + } + strcpy(tsv->str, str); + +#if 0 + /* try to parse the string and see if it fits any of the value types */ + if(*str == '[' || *str == '{') { + /* try to parse as a vector */ + struct val_list_node *list = 0, *tail = 0, *node; + int nelem = 0; + char endsym = *str++ + 2; /* ']' is '[' + 2 and '}' is '{' + 2 */ + + while(*str && *str != endsym) { + float val = strtod(str, &endp); + if(endp == str || !(node = malloc(sizeof *node))) { + break; + } + ts_init_value(&node->val); + ts_set_valuef(&node->val, val); + node->next = 0; + + if(list) { + tail->next = node; + tail = node; + } else { + list = tail = node; + } + ++nelem; + str = endp; + } + + if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) && + (tsv->vec = malloc(nelem * sizeof *tsv->vec))) { + int idx = 0; + while(list) { + node = list; + list = list->next; + + tsv->array[idx] = node->val; + tsv->vec[idx] = node->val.fnum; + ++idx; + free(node); + } + tsv->type = TS_VECTOR; + } + + } else if((tsv->fnum = strtod(str, &endp)), endp != str) { + /* it's a number I guess... */ + tsv->type = TS_NUMBER; + } +#endif + + return 0; +} + +int ts_set_valuei_arr(struct ts_value *tsv, int count, const int *arr) +{ + int i; + + if(count < 1) return -1; + if(count == 1) { + if(!(tsv->str = make_intstr(*arr))) { + return -1; + } + + tsv->type = TS_NUMBER; + tsv->fnum = (float)*arr; + tsv->inum = *arr; + return 0; + } + + /* otherwise it's an array, we need to create the ts_value array, and + * the simplified vector + */ + if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) { + return -1; + } + tsv->vec_size = count; + + for(i=0; ivec[i] = arr[i]; + } + + if(!(tsv->array = malloc(count * sizeof *tsv->array))) { + free(tsv->vec); + } + tsv->array_size = count; + + for(i=0; iarray + i); + ts_set_valuef(tsv->array + i, arr[i]); + } + + tsv->type = TS_VECTOR; + return 0; +} + +int ts_set_valueiv(struct ts_value *tsv, int count, ...) +{ + int res; + va_list ap; + va_start(ap, count); + res = ts_set_valueiv_va(tsv, count, ap); + va_end(ap); + return res; +} + +int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap) +{ + int i, *vec; + + if(count < 1) return -1; + if(count == 1) { + int num = va_arg(ap, int); + ts_set_valuei(tsv, num); + return 0; + } + + vec = alloca(count * sizeof *vec); + for(i=0; istr = make_floatstr(*arr))) { + return -1; + } + + tsv->type = TS_NUMBER; + tsv->fnum = *arr; + tsv->inum = (int)*arr; + return 0; + } + + /* otherwise it's an array, we need to create the ts_value array, and + * the simplified vector + */ + if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) { + return -1; + } + tsv->vec_size = count; + + for(i=0; ivec[i] = arr[i]; + } + + if(!(tsv->array = malloc(count * sizeof *tsv->array))) { + free(tsv->vec); + } + tsv->array_size = count; + + for(i=0; iarray + i); + ts_set_valuef(tsv->array + i, arr[i]); + } + + tsv->type = TS_VECTOR; + return 0; +} + +int ts_set_valuefv(struct ts_value *tsv, int count, ...) +{ + int res; + va_list ap; + va_start(ap, count); + res = ts_set_valuefv_va(tsv, count, ap); + va_end(ap); + return res; +} + +int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap) +{ + int i; + float *vec; + + if(count < 1) return -1; + if(count == 1) { + float num = va_arg(ap, double); + ts_set_valuef(tsv, num); + return 0; + } + + vec = alloca(count * sizeof *vec); + for(i=0; iarray = malloc(count * sizeof *tsv->array))) { + return -1; + } + tsv->array_size = count; + + for(i=0; iarray + i, (struct ts_value*)arr + i) == -1) { + while(--i >= 0) { + ts_destroy_value(tsv->array + i); + } + free(tsv->array); + tsv->array = 0; + return -1; + } + } + + if(allnum) { + if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) { + ts_destroy_value(tsv); + return -1; + } + tsv->type = TS_VECTOR; + tsv->vec_size = count; + + for(i=0; ivec[i] = tsv->array[i].fnum; + } + } else { + tsv->type = TS_ARRAY; + } + return 0; +} + +int ts_set_valuev(struct ts_value *tsv, int count, ...) +{ + int res; + va_list ap; + va_start(ap, count); + res = ts_set_valuev_va(tsv, count, ap); + va_end(ap); + return res; +} + +int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap) +{ + int i; + + if(count <= 1) return -1; + + if(!(tsv->array = malloc(count * sizeof *tsv->array))) { + return -1; + } + tsv->array_size = count; + + for(i=0; iarray + i, src) == -1) { + while(--i >= 0) { + ts_destroy_value(tsv->array + i); + } + free(tsv->array); + tsv->array = 0; + return -1; + } + } + return 0; +} + + +/* ---- ts_attr implementation ---- */ + +int ts_init_attr(struct ts_attr *attr) +{ + memset(attr, 0, sizeof *attr); + return ts_init_value(&attr->val); +} + +void ts_destroy_attr(struct ts_attr *attr) +{ + free(attr->name); + ts_destroy_value(&attr->val); +} + +struct ts_attr *ts_alloc_attr(void) +{ + struct ts_attr *attr = malloc(sizeof *attr); + if(!attr || ts_init_attr(attr) == -1) { + free(attr); + return 0; + } + return attr; +} + +void ts_free_attr(struct ts_attr *attr) +{ + ts_destroy_attr(attr); + free(attr); +} + +int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src) +{ + if(dest == src) return 0; + + if(ts_set_attr_name(dest, src->name) == -1) { + return -1; + } + + if(ts_copy_value(&dest->val, &src->val) == -1) { + ts_destroy_attr(dest); + return -1; + } + return 0; +} + +int ts_set_attr_name(struct ts_attr *attr, const char *name) +{ + char *n = malloc(strlen(name) + 1); + if(!n) return -1; + strcpy(n, name); + + free(attr->name); + attr->name = n; + return 0; +} + + +/* ---- ts_node implementation ---- */ + +int ts_init_node(struct ts_node *node) +{ + memset(node, 0, sizeof *node); + return 0; +} + +void ts_destroy_node(struct ts_node *node) +{ + if(!node) return; + + free(node->name); + + while(node->attr_list) { + struct ts_attr *attr = node->attr_list; + node->attr_list = node->attr_list->next; + ts_free_attr(attr); + } +} + +struct ts_node *ts_alloc_node(void) +{ + struct ts_node *node = malloc(sizeof *node); + if(!node || ts_init_node(node) == -1) { + free(node); + return 0; + } + return node; +} + +void ts_free_node(struct ts_node *node) +{ + ts_destroy_node(node); + free(node); +} + +void ts_free_tree(struct ts_node *tree) +{ + if(!tree) return; + + while(tree->child_list) { + struct ts_node *child = tree->child_list; + tree->child_list = tree->child_list->next; + ts_free_tree(child); + } + + ts_free_node(tree); +} + +int ts_set_node_name(struct ts_node *node, const char *name) +{ + char *n = malloc(strlen(name) + 1); + if(!n) return -1; + strcpy(n, name); + + free(node->name); + node->name = n; + return 0; +} + +void ts_add_attr(struct ts_node *node, struct ts_attr *attr) +{ + attr->next = 0; + if(node->attr_list) { + node->attr_tail->next = attr; + node->attr_tail = attr; + } else { + node->attr_list = node->attr_tail = attr; + } + node->attr_count++; +} + +struct ts_attr *ts_get_attr(struct ts_node *node, const char *name) +{ + struct ts_attr *attr = node->attr_list; + while(attr) { + if(strcmp(attr->name, name) == 0) { + return attr; + } + attr = attr->next; + } + return 0; +} + +const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val) +{ + struct ts_attr *attr = ts_get_attr(node, aname); + if(!attr || !attr->val.str) { + return def_val; + } + return attr->val.str; +} + +float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val) +{ + struct ts_attr *attr = ts_get_attr(node, aname); + if(!attr || attr->val.type != TS_NUMBER) { + return def_val; + } + return attr->val.fnum; +} + +int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val) +{ + struct ts_attr *attr = ts_get_attr(node, aname); + if(!attr || attr->val.type != TS_NUMBER) { + return def_val; + } + return attr->val.inum; +} + +float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val) +{ + struct ts_attr *attr = ts_get_attr(node, aname); + if(!attr || !attr->val.vec) { + return def_val; + } + return attr->val.vec; +} + +struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val) +{ + struct ts_attr *attr = ts_get_attr(node, aname); + if(!attr || !attr->val.array) { + return def_val; + } + return attr->val.array; +} + +void ts_add_child(struct ts_node *node, struct ts_node *child) +{ + if(child->parent) { + if(child->parent == node) return; + ts_remove_child(child->parent, child); + } + child->parent = node; + child->next = 0; + + if(node->child_list) { + node->child_tail->next = child; + node->child_tail = child; + } else { + node->child_list = node->child_tail = child; + } + node->child_count++; +} + +int ts_remove_child(struct ts_node *node, struct ts_node *child) +{ + struct ts_node dummy, *iter = &dummy; + dummy.next = node->child_list; + + while(iter->next && iter->next != child) { + iter = iter->next; + } + if(!iter->next) { + return -1; + } + + child->parent = 0; + + iter->next = child->next; + if(!iter->next) { + node->child_tail = iter; + } + node->child_list = dummy.next; + node->child_count--; + assert(node->child_count >= 0); + return 0; +} + +struct ts_node *ts_get_child(struct ts_node *node, const char *name) +{ + struct ts_node *res = node->child_list; + while(res) { + if(strcmp(res->name, name) == 0) { + return res; + } + res = res->next; + } + return 0; +} + +struct ts_node *ts_load(const char *fname) +{ + FILE *fp; + struct ts_node *root; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno)); + return 0; + } + + root = ts_load_file(fp); + fclose(fp); + return root; +} + +struct ts_node *ts_load_file(FILE *fp) +{ + struct ts_io io = {0}; + io.data = fp; + io.read = io_read; + + return ts_load_io(&io); +} + +struct ts_node *ts_load_io(struct ts_io *io) +{ + return ts_text_load(io); +} + +int ts_save(struct ts_node *tree, const char *fname) +{ + FILE *fp; + int res; + + if(!(fp = fopen(fname, "wb"))) { + fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno)); + return 0; + } + res = ts_save_file(tree, fp); + fclose(fp); + return res; +} + +int ts_save_file(struct ts_node *tree, FILE *fp) +{ + struct ts_io io = {0}; + io.data = fp; + io.write = io_write; + + return ts_save_io(tree, &io); +} + +int ts_save_io(struct ts_node *tree, struct ts_io *io) +{ + return ts_text_save(tree, io); +} + +static const char *pathtok(const char *path, char *tok) +{ + int len; + const char *dot = strchr(path, '.'); + if(!dot) { + strcpy(tok, path); + return 0; + } + + len = dot - path; + memcpy(tok, path, len); + tok[len] = 0; + return dot + 1; +} + +struct ts_attr *ts_lookup(struct ts_node *node, const char *path) +{ + char *name = alloca(strlen(path) + 1); + + if(!node) return 0; + + if(!(path = pathtok(path, name)) || strcmp(name, node->name) != 0) { + return 0; + } + + while((path = pathtok(path, name)) && (node = ts_get_child(node, name))); + + if(path || !node) return 0; + return ts_get_attr(node, name); +} + +const char *ts_lookup_str(struct ts_node *root, const char *path, const char *def_val) +{ + struct ts_attr *attr = ts_lookup(root, path); + if(!attr || !attr->val.str) { + return def_val; + } + return attr->val.str; +} + +float ts_lookup_num(struct ts_node *root, const char *path, float def_val) +{ + struct ts_attr *attr = ts_lookup(root, path); + if(!attr || attr->val.type != TS_NUMBER) { + return def_val; + } + return attr->val.fnum; +} + +int ts_lookup_int(struct ts_node *root, const char *path, int def_val) +{ + struct ts_attr *attr = ts_lookup(root, path); + if(!attr || attr->val.type != TS_NUMBER) { + return def_val; + } + return attr->val.inum; +} + +float *ts_lookup_vec(struct ts_node *root, const char *path, float *def_val) +{ + struct ts_attr *attr = ts_lookup(root, path); + if(!attr || !attr->val.vec) { + return def_val; + } + return attr->val.vec; +} + +struct ts_value *ts_lookup_array(struct ts_node *node, const char *path, struct ts_value *def_val) +{ + struct ts_attr *attr = ts_lookup(node, path); + if(!attr || !attr->val.array) { + return def_val; + } + return attr->val.array; +} + +static long io_read(void *buf, size_t bytes, void *uptr) +{ + size_t sz = fread(buf, 1, bytes, uptr); + if(sz < bytes && errno) return -1; + return sz; +} + +static long io_write(const void *buf, size_t bytes, void *uptr) +{ + size_t sz = fwrite(buf, 1, bytes, uptr); + if(sz < bytes && errno) return -1; + return sz; +} diff --git a/libs/treestore/treestore.h b/libs/treestore/treestore.h new file mode 100644 index 0000000..842a489 --- /dev/null +++ b/libs/treestore/treestore.h @@ -0,0 +1,167 @@ +#ifndef TREESTORE_H_ +#define TREESTORE_H_ + +#include +#include +#include + +#ifdef __cplusplus +#define TS_DEFVAL(x) =(x) +extern "C" { +#else +#define TS_DEFVAL(x) +#endif + +/** set of user-supplied I/O functions, for ts_load_io/ts_save_io */ +struct ts_io { + void *data; + + long (*read)(void *buf, size_t bytes, void *uptr); + long (*write)(const void *buf, size_t bytes, void *uptr); +}; + +enum ts_value_type { TS_STRING, TS_NUMBER, TS_VECTOR, TS_ARRAY }; + +/** treestore node attribute value */ +struct ts_value { + enum ts_value_type type; + + char *str; /**< string values will have this set */ + int inum; /**< numeric values will have this set */ + float fnum; /**< numeric values will have this set */ + + /** vector values (arrays containing ONLY numbers) will have this set */ + float *vec; /**< elements of the vector */ + int vec_size; /**< size of the vector (in elements), same as array_size */ + + /** array values (including vectors) will have this set */ + struct ts_value *array; /**< elements of the array */ + int array_size; /**< size of the array (in elements) */ +}; + +int ts_init_value(struct ts_value *tsv); +void ts_destroy_value(struct ts_value *tsv); + +struct ts_value *ts_alloc_value(void); /**< also calls ts_init_value */ +void ts_free_value(struct ts_value *tsv); /**< also calls ts_destroy_value */ + +/** perform a deep-copy of a ts_value */ +int ts_copy_value(struct ts_value *dest, struct ts_value *src); + +/** set a ts_value as a string */ +int ts_set_value_str(struct ts_value *tsv, const char *str); + +/** set a ts_value from a list of integers */ +int ts_set_valuei_arr(struct ts_value *tsv, int count, const int *arr); +int ts_set_valueiv(struct ts_value *tsv, int count, ...); +int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap); +int ts_set_valuei(struct ts_value *tsv, int inum); /**< equiv: ts_set_valueiv(val, 1, inum) */ + +/** set a ts_value from a list of floats */ +int ts_set_valuef_arr(struct ts_value *tsv, int count, const float *arr); +int ts_set_valuefv(struct ts_value *tsv, int count, ...); +int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap); +int ts_set_valuef(struct ts_value *tsv, float fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ + +/** set a ts_value from a list of ts_value pointers. they are deep-copied as per ts_copy_value */ +int ts_set_value_arr(struct ts_value *tsv, int count, const struct ts_value *arr); +int ts_set_valuev(struct ts_value *tsv, int count, ...); +int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap); + + +/** treestore node attribute */ +struct ts_attr { + char *name; + struct ts_value val; + + struct ts_attr *next; +}; + +int ts_init_attr(struct ts_attr *attr); +void ts_destroy_attr(struct ts_attr *attr); + +struct ts_attr *ts_alloc_attr(void); /**< also calls ts_init_attr */ +void ts_free_attr(struct ts_attr *attr); /**< also calls ts_destroy_attr */ + +/** perform a deep-copy of a ts_attr */ +int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src); + +int ts_set_attr_name(struct ts_attr *attr, const char *name); + + + +/** treestore node */ +struct ts_node { + char *name; + + int attr_count; + struct ts_attr *attr_list, *attr_tail; + + int child_count; + struct ts_node *child_list, *child_tail; + struct ts_node *parent; + + struct ts_node *next; /* next sibling */ +}; + +int ts_init_node(struct ts_node *node); +void ts_destroy_node(struct ts_node *node); + +struct ts_node *ts_alloc_node(void); /**< also calls ts_init_node */ +void ts_free_node(struct ts_node *n); /**< also calls ts_destroy_node */ + +/** recursively destroy all the nodes of the tree */ +void ts_free_tree(struct ts_node *tree); + +int ts_set_node_name(struct ts_node *node, const char *name); + +void ts_add_attr(struct ts_node *node, struct ts_attr *attr); +struct ts_attr *ts_get_attr(struct ts_node *node, const char *name); + +const char *ts_get_attr_str(struct ts_node *node, const char *aname, + const char *def_val TS_DEFVAL(0)); +float ts_get_attr_num(struct ts_node *node, const char *aname, + float def_val TS_DEFVAL(0.0f)); +int ts_get_attr_int(struct ts_node *node, const char *aname, + int def_val TS_DEFVAL(0.0f)); +float *ts_get_attr_vec(struct ts_node *node, const char *aname, + float *def_val TS_DEFVAL(0)); +struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, + struct ts_value *def_val TS_DEFVAL(0)); + + +void ts_add_child(struct ts_node *node, struct ts_node *child); +int ts_remove_child(struct ts_node *node, struct ts_node *child); +struct ts_node *ts_get_child(struct ts_node *node, const char *name); + +/* load/save by opening the specified file */ +struct ts_node *ts_load(const char *fname); +int ts_save(struct ts_node *tree, const char *fname); + +/* load/save using the supplied FILE pointer */ +struct ts_node *ts_load_file(FILE *fp); +int ts_save_file(struct ts_node *tree, FILE *fp); + +/* load/save using custom I/O functions */ +struct ts_node *ts_load_io(struct ts_io *io); +int ts_save_io(struct ts_node *tree, struct ts_io *io); + + +struct ts_attr *ts_lookup(struct ts_node *root, const char *path); +const char *ts_lookup_str(struct ts_node *root, const char *path, + const char *def_val TS_DEFVAL(0)); +float ts_lookup_num(struct ts_node *root, const char *path, + float def_val TS_DEFVAL(0.0f)); +int ts_lookup_int(struct ts_node *root, const char *path, + int def_val TS_DEFVAL(0)); +float *ts_lookup_vec(struct ts_node *root, const char *path, + float *def_val TS_DEFVAL(0)); +struct ts_value *ts_lookup_array(struct ts_node *root, const char *path, + struct ts_value *def_val TS_DEFVAL(0)); + + +#ifdef __cplusplus +} +#endif + +#endif /* TREESTORE_H_ */ diff --git a/sdr/foo-notex.p.glsl b/sdr/foo-notex.p.glsl new file mode 100644 index 0000000..8bd9162 --- /dev/null +++ b/sdr/foo-notex.p.glsl @@ -0,0 +1,4 @@ +void main() +{ + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} diff --git a/src/assman.c b/src/assman.c index 809cc05..373c9f5 100644 --- a/src/assman.c +++ b/src/assman.c @@ -87,6 +87,8 @@ unsigned int get_vsdr(const char *fname) buf[sz] = 0; ass_fclose(fp); + printf("vertex shader %s ", fname); + fflush(stdout); sdr = create_vertex_shader(buf); free(buf); @@ -123,6 +125,8 @@ unsigned int get_psdr(const char *fname) buf[sz] = 0; ass_fclose(fp); + printf("pixel shader %s ", fname); + fflush(stdout); sdr = create_pixel_shader(buf); free(buf); diff --git a/src/demo.c b/src/demo.c index 5023275..77c33d2 100644 --- a/src/demo.c +++ b/src/demo.c @@ -20,6 +20,7 @@ int demo_init(void) if(!(tex_logo = get_tex2d("data/ml_logo_old.png"))) { return -1; } + glBindTexture(GL_TEXTURE_2D, tex_logo); glUseProgram(sdr_foo); gl_begin(GL_QUADS); gl_texcoord2f(0, 1); @@ -47,18 +48,10 @@ void demo_cleanup(void) void demo_display(void) { - struct demoscreen *scr; + dsys_update(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - scr = dsys_act_scr; - while(scr) { - if(scr->update) { - scr->update(dsys_time); - } - scr->draw(); - scr = scr->next; - } + dsys_draw(); } void demo_reshape(int x, int y) @@ -102,12 +95,10 @@ void demo_keyboard(int key, int pressed) } } else { - struct demoscreen *scr = dsys_act_scr; - while(scr) { - if(scr->keyboard) { - scr->keyboard(key, pressed); - } - scr = scr->next; + int i; + for(i=0; ikeyboard) scr->keyboard(key, pressed); } } } @@ -115,22 +106,18 @@ void demo_keyboard(int key, int pressed) void demo_mouse(int bn, int pressed, int x, int y) { - struct demoscreen *scr = dsys_act_scr; - while(scr) { - if(scr->mouse) { - scr->mouse(bn, pressed, x, y); - } - scr = scr->next; + int i; + for(i=0; imouse) scr->mouse(bn, pressed, x, y); } } void demo_motion(int x, int y) { - struct demoscreen *scr = dsys_act_scr; - while(scr) { - if(scr->motion) { - scr->motion(x, y); - } - scr = scr->next; + int i; + for(i=0; imotion) scr->motion(x, y); } } diff --git a/src/demo.h b/src/demo.h index 275c552..e58f071 100644 --- a/src/demo.h +++ b/src/demo.h @@ -1,6 +1,12 @@ #ifndef DEMO_H_ #define DEMO_H_ +#include "opengl.h" +#include "sanegl.h" +#include "demosys.h" +#include "assman.h" +#include "util.h" + enum { KEY_F1 = 128, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, diff --git a/src/demosys.c b/src/demosys.c index 7cefce5..41bfda1 100644 --- a/src/demosys.c +++ b/src/demosys.c @@ -1,15 +1,23 @@ #include #include +#include "demo.h" #include "demosys.h" - -static struct demoscreen *act_tail; +#include "treestore.h" +#include "assfile.h" void regscr_testa(void); void regscr_testb(void); +static void proc_screen_script(struct demoscreen *scr, struct ts_node *node); +static long io_read(void *buf, size_t bytes, void *uptr); + + int dsys_init(const char *fname) { int i; + struct ts_io io = {0}; + struct ts_node *ts, *tsnode; + struct demoscreen *scr; regscr_testa(); regscr_testb(); @@ -21,14 +29,57 @@ int dsys_init(const char *fname) } } + if(!fname || !(io.data = ass_fopen(fname, "rb"))) { + dsys_run_screen(dsys_screens[0]); + return 0; + } + io.read = io_read; + + if(!(ts = ts_load_io(&io)) || strcmp(ts->name, "demo") != 0) { + ass_fclose(io.data); + fprintf(stderr, "failed to read demoscript\n"); + return -1; + } + + tsnode = ts->child_list; + while(tsnode) { + if(strcmp(tsnode->name, "screen") == 0 && + (scr = dsys_find_screen(ts_get_attr_str(tsnode, "name", 0)))) { + proc_screen_script(scr, tsnode); + } + tsnode = tsnode->next; + } + + ass_fclose(io.data); return 0; } +static void proc_screen_script(struct demoscreen *scr, struct ts_node *node) +{ + struct ts_attr *attr; + long tm; + + attr = node->attr_list; + while(attr) { + if(sscanf(attr->name, "key_%ld", &tm) == 1 && attr->val.type == TS_NUMBER) { + anm_set_value(&scr->track, tm, attr->val.fnum); + } + attr = attr->next; + } +} + +static long io_read(void *buf, size_t bytes, void *uptr) +{ + return ass_fread(buf, 1, bytes, uptr); +} + + void dsys_destroy(void) { int i; for(i=0; itrack); if(dsys_screens[i]->destroy) { dsys_screens[i]->destroy(); } @@ -36,32 +87,57 @@ void dsys_destroy(void) dsys_num_screens = 0; } -struct demoscreen *dsys_find_screen(const char *name) +void dsys_update(void) { - int i; + int i, j, sort_needed = 0; + struct demoscreen *scr; + dsys_time = time_msec; + + dsys_num_act = 0; for(i=0; iname, name) == 0) { - return dsys_screens[i]; + scr = dsys_screens[i]; + scr->vis = anm_get_value(&scr->track, dsys_time); + + if(scr->vis > 0.0f) { + if(!scr->active) { + if(scr->start) scr->start(); + scr->active = 1; + } + if(scr->update) scr->update(dsys_time); + + if(dsys_num_act && scr->prio != dsys_act[dsys_num_act - 1]->prio) { + sort_needed = 1; + } + dsys_act[dsys_num_act++] = scr; + } else { + if(scr->active) { + if(scr->stop) scr->stop(); + scr->active = 0; + } + } + } + + if(sort_needed) { + for(i=0; iprio > dsys_act[j - 1]->prio) { + void *tmp = dsys_act[j]; + dsys_act[j] = dsys_act[j - 1]; + dsys_act[j - 1] = tmp; + } + } } } - return 0; } -void dsys_run_screen(struct demoscreen *scr) +/* TODO: do something about draw ordering of the active screens */ +void dsys_draw(void) { - struct demoscreen *act; - - if(!scr) return; - if(dsys_act_scr == scr && act_tail == scr) return; - - act = dsys_act_scr; - while(act) { - if(act->stop) act->stop(); - act = act->next; + int i; + for(i=0; idraw(); } - dsys_act_scr = act_tail = scr; - if(scr->start) scr->start(); } void dsys_run(void) @@ -84,12 +160,55 @@ void dsys_seek_norm(float t) { } + +struct demoscreen *dsys_find_screen(const char *name) +{ + int i; + + if(!name) return 0; + + for(i=0; iname, name) == 0) { + return dsys_screens[i]; + } + } + return 0; +} + +void dsys_run_screen(struct demoscreen *scr) +{ + int i; + + if(!scr) return; + if(dsys_num_act == 1 && dsys_act[0] == scr) return; + + for(i=0; istop) dsys_act[i]->stop(); + dsys_act[i]->active = 0; + } + + dsys_act[0] = scr; + dsys_num_act = 1; + + if(scr->start) scr->start(); + scr->active = 1; +} + + int dsys_add_screen(struct demoscreen *scr) { if(!scr->name || !scr->init || !scr->draw) { fprintf(stderr, "dsys_add_screen: invalid screen\n"); return -1; } + if(anm_init_track(&scr->track) == -1) { + fprintf(stderr, "dsys_add_screen: failed to initialize keyframe track\n"); + return -1; + } + anm_set_track_interpolator(&scr->track, ANM_INTERP_LINEAR); + anm_set_track_extrapolator(&scr->track, ANM_EXTRAP_EXTEND); + anm_set_track_default(&scr->track, 0); + dsys_screens[dsys_num_screens++] = scr; return 0; } diff --git a/src/demosys.h b/src/demosys.h index e369771..abbc154 100644 --- a/src/demosys.h +++ b/src/demosys.h @@ -6,8 +6,6 @@ struct demoscreen { char *name; - struct anm_track track; - int (*init)(void); void (*destroy)(void); void (*reshape)(int x, int y); @@ -22,7 +20,9 @@ struct demoscreen { void (*mouse)(int bn, int pressed, int x, int y); void (*motion)(int x, int y); - struct demoscreen *next; + struct anm_track track; + int active, prio; + float vis; }; /* global demo state */ @@ -33,15 +33,15 @@ long dsys_time; /* demo time in milliseconds */ #define MAX_DSYS_SCREENS 64 struct demoscreen *dsys_screens[MAX_DSYS_SCREENS]; int dsys_num_screens; -struct demoscreen *dsys_act_scr; /* linked list of active screens */ +struct demoscreen *dsys_act[MAX_DSYS_SCREENS]; +int dsys_num_act; int dsys_init(const char *fname); void dsys_destroy(void); -/* overrides the demo sequence, and runs a single screen */ -struct demoscreen *dsys_find_screen(const char *name); -void dsys_run_screen(struct demoscreen *scr); +void dsys_update(void); +void dsys_draw(void); void dsys_run(void); void dsys_stop(void); @@ -49,6 +49,10 @@ void dsys_seek_abs(long tm); void dsys_seek_rel(long dt); void dsys_seek_norm(float t); +/* overrides the demo sequence, and runs a single screen */ +struct demoscreen *dsys_find_screen(const char *name); +void dsys_run_screen(struct demoscreen *scr); + int dsys_add_screen(struct demoscreen *scr); #endif /* DEMOSYS_H_ */ diff --git a/src/noise.c b/src/noise.c new file mode 100644 index 0000000..4401e5a --- /dev/null +++ b/src/noise.c @@ -0,0 +1,521 @@ +#include +#include +#include "noise.h" + +/* ---- Ken Perlin's implementation of noise ---- */ +#define B 0x100 +#define BM 0xff +#define N 0x1000 +#define NP 12 /* 2^N */ +#define NM 0xfff + +#define s_curve(t) (t * t * (3.0f - 2.0f * t)) + +#define setup(elem, b0, b1, r0, r1) \ + do { \ + float t = elem + N; \ + b0 = ((int)t) & BM; \ + b1 = (b0 + 1) & BM; \ + r0 = t - (int)t; \ + r1 = r0 - 1.0f; \ + } while(0) + +#define setup_p(elem, b0, b1, r0, r1, p) \ + do { \ + float t = elem + N; \ + b0 = (((int)t) & BM) % p; \ + b1 = ((b0 + 1) & BM) % p; \ + r0 = t - (int)t; \ + r1 = r0 - 1.0f; \ + } while(0) + + +static int perm[B + B + 2]; /* permuted index from g_n onto themselves */ +static float grad3[B + B + 2][3]; /* 3D random gradients */ +static float grad2[B + B + 2][2]; /* 2D random gradients */ +static float grad1[B + B + 2]; /* 1D random ... slopes */ +static int tables_valid; + +#define init_once() if(!tables_valid) init_noise() + +static void init_noise() +{ + int i; + float len; + + /* calculate random gradients */ + for(i=0; i 1.0f) sz = 1.0f; + xr = sz / NX; + yr = sz / NY; + + gl_vertex2f(x - xr, y - yr); + gl_vertex2f(x + xr, y - yr); + gl_vertex2f(x + xr, y + yr); + gl_vertex2f(x - xr, y + yr); + } + } + gl_end(); } diff --git a/src/util.c b/src/util.c index dc86d10..7be1859 100644 --- a/src/util.c +++ b/src/util.c @@ -41,3 +41,14 @@ char *strdup_nf_impl(const char *s, const char *file, int line) } return res; } + + +int match_prefix(const char *str, const char *prefix) +{ + while(*str && *prefix) { + if(*str++ != *prefix++) { + return 0; + } + } + return *prefix ? 0 : 1; +} diff --git a/src/util.h b/src/util.h index 61ae532..69b8f53 100644 --- a/src/util.h +++ b/src/util.h @@ -18,14 +18,13 @@ #define malloc_nf(sz) malloc_nf_impl(sz, __FILE__, __LINE__) void *malloc_nf_impl(size_t sz, const char *file, int line); - #define calloc_nf(num, sz) calloc_nf_impl(num, sz, __FILE__, __LINE__) void *calloc_nf_impl(size_t num, size_t sz, const char *file, int line); - #define realloc_nf(p, sz) realloc_nf_impl(p, sz, __FILE__, __LINE__) void *realloc_nf_impl(void *p, size_t sz, const char *file, int line); - #define strdup_nf(s) strdup_nf_impl(s, __FILE__, __LINE__) char *strdup_nf_impl(const char *s, const char *file, int line); +int match_prefix(const char *str, const char *prefix); + #endif /* UTIL_H_ */