working on the demosystem, added libtreestore
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 28 Dec 2021 16:29:16 +0000 (18:29 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 28 Dec 2021 16:29:16 +0000 (18:29 +0200)
23 files changed:
Makefile
Makefile.android
libs/Makefile
libs/treestore/LICENSE [new file with mode: 0644]
libs/treestore/Makefile [new file with mode: 0644]
libs/treestore/README.md [new file with mode: 0644]
libs/treestore/dynarr.c [new file with mode: 0644]
libs/treestore/dynarr.h [new file with mode: 0644]
libs/treestore/text.c [new file with mode: 0644]
libs/treestore/treestore.c [new file with mode: 0644]
libs/treestore/treestore.h [new file with mode: 0644]
sdr/foo-notex.p.glsl [new file with mode: 0644]
src/assman.c
src/demo.c
src/demo.h
src/demosys.c
src/demosys.h
src/noise.c [new file with mode: 0644]
src/noise.h [new file with mode: 0644]
src/scr/testa.c
src/scr/testb.c
src/util.c
src/util.h

index e133269..163f01f 100644 (file)
--- 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)
index d613b47..4a77672 100644 (file)
@@ -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 $@ $<
index 0800384..26536a9 100644 (file)
@@ -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 (file)
index 0000000..536e666
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
+
+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 (file)
index 0000000..cb9f7b3
--- /dev/null
@@ -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 (file)
index 0000000..f75efa9
--- /dev/null
@@ -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 <nuclear@member.fsf.org>
+
+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 (file)
index 0000000..2d3f611
--- /dev/null
@@ -0,0 +1,133 @@
+/* dynarr - dynamic resizable C array data structure
+ * author: John Tsiombikas <nuclear@member.fsf.org>
+ * license: public domain
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 (file)
index 0000000..513a431
--- /dev/null
@@ -0,0 +1,69 @@
+/* dynarr - dynamic resizable C array data structure
+ * author: John Tsiombikas <nuclear@member.fsf.org>
+ * 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<ts_dynarr_size(arr); i++) {
+ *     printf("%d\n", arr[i]);
+ *  }
+ *  ts_dynarr_free(arr);
+ */
+
+void *ts_dynarr_alloc(int elem, int szelem);
+void ts_dynarr_free(void *da);
+void *ts_dynarr_resize(void *da, int elem);
+
+int ts_dynarr_empty(void *da);
+int ts_dynarr_size(void *da);
+
+void *ts_dynarr_clear(void *da);
+
+/* stack semantics */
+void *ts_dynarr_push(void *da, void *item);
+void *ts_dynarr_pop(void *da);
+
+
+/* helper macros */
+#define DYNARR_RESIZE(da, n) \
+       do { (da) = ts_dynarr_resize((da), (n)); } while(0)
+#define DYNARR_CLEAR(da) \
+       do { (da) = ts_dynarr_clear(da); } while(0)
+#define DYNARR_PUSH(da, item) \
+       do { (da) = ts_dynarr_push((da), (item)); } while(0)
+#define DYNARR_POP(da) \
+       do { (da) = ts_dynarr_pop(da); } while(0)
+
+/* utility macros to push characters to a string. assumes and maintains
+ * the invariant that the last element is always a zero
+ */
+#define DYNARR_STRPUSH(da, c) \
+       do { \
+               char cnull = 0, ch = (char)(c); \
+               (da) = ts_dynarr_pop(da); \
+               (da) = ts_dynarr_push((da), &ch); \
+               (da) = ts_dynarr_push((da), &cnull); \
+       } while(0)
+
+#define DYNARR_STRPOP(da) \
+       do { \
+               char cnull = 0; \
+               (da) = ts_dynarr_pop(da); \
+               (da) = ts_dynarr_pop(da); \
+               (da) = ts_dynarr_push((da), &cnull); \
+       } while(0)
+
+
+#endif /* DYNARR_H_ */
diff --git a/libs/treestore/text.c b/libs/treestore/text.c
new file mode 100644 (file)
index 0000000..38bfd0f
--- /dev/null
@@ -0,0 +1,466 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#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; i<nval; i++) {
+               ts_destroy_value(values + i);
+       }
+       return res;
+}
+
+static int nextchar(struct parser *pst)
+{
+       char c;
+
+       if(pst->nextc >= 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; i<value->vec_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; i<value->array_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 (file)
index 0000000..899cfa0
--- /dev/null
@@ -0,0 +1,809 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "treestore.h"
+
+#ifdef WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#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; i<tsv->array_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; i<src->array_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; i<dest->array_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; i<count; i++) {
+               tsv->vec[i] = arr[i];
+       }
+
+       if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
+               free(tsv->vec);
+       }
+       tsv->array_size = count;
+
+       for(i=0; i<count; i++) {
+               ts_init_value(tsv->array + 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; i<count; i++) {
+               vec[i] = va_arg(ap, int);
+       }
+       return ts_set_valuei_arr(tsv, count, vec);
+}
+
+int ts_set_valuei(struct ts_value *tsv, int inum)
+{
+       return ts_set_valuei_arr(tsv, 1, &inum);
+}
+
+int ts_set_valuef_arr(struct ts_value *tsv, int count, const float *arr)
+{
+       int i;
+
+       if(count < 1) return -1;
+       if(count == 1) {
+               if(!(tsv->str = 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; i<count; i++) {
+               tsv->vec[i] = arr[i];
+       }
+
+       if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
+               free(tsv->vec);
+       }
+       tsv->array_size = count;
+
+       for(i=0; i<count; i++) {
+               ts_init_value(tsv->array + 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; i<count; i++) {
+               vec[i] = va_arg(ap, double);
+       }
+       return ts_set_valuef_arr(tsv, count, vec);
+}
+
+int ts_set_valuef(struct ts_value *tsv, float fnum)
+{
+       return ts_set_valuef_arr(tsv, 1, &fnum);
+}
+
+int ts_set_value_arr(struct ts_value *tsv, int count, const struct ts_value *arr)
+{
+       int i, allnum = 1;
+
+       if(count <= 1) return -1;
+
+       if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
+               return -1;
+       }
+       tsv->array_size = count;
+
+       for(i=0; i<count; i++) {
+               if(arr[i].type != TS_NUMBER) {
+                       allnum = 0;
+               }
+               if(ts_copy_value(tsv->array + 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; i<count; i++) {
+                       tsv->vec[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; i<count; i++) {
+               struct ts_value *src = va_arg(ap, struct ts_value*);
+               if(ts_copy_value(tsv->array + 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 (file)
index 0000000..842a489
--- /dev/null
@@ -0,0 +1,167 @@
+#ifndef TREESTORE_H_
+#define TREESTORE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#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 (file)
index 0000000..8bd9162
--- /dev/null
@@ -0,0 +1,4 @@
+void main()
+{
+       gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+}
index 809cc05..373c9f5 100644 (file)
@@ -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);
 
index 5023275..77c33d2 100644 (file)
@@ -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; i<dsys_num_act; i++) {
+                               struct demoscreen *scr = dsys_act[i];
+                               if(scr->keyboard) 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; i<dsys_num_act; i++) {
+               struct demoscreen *scr = dsys_act[i];
+               if(scr->mouse) 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; i<dsys_num_act; i++) {
+               struct demoscreen *scr = dsys_act[i];
+               if(scr->motion) scr->motion(x, y);
        }
 }
index 275c552..e58f071 100644 (file)
@@ -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,
index 7cefce5..41bfda1 100644 (file)
@@ -1,15 +1,23 @@
 #include <stdio.h>
 #include <string.h>
+#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; i<dsys_num_screens; i++) {
+               anm_destroy_track(&dsys_screens[i]->track);
                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; i<dsys_num_screens; i++) {
-               if(strcmp(dsys_screens[i]->name, 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; i<dsys_num_act; i++) {
+                       for(j=i+1; j<dsys_num_act; j++) {
+                               if(dsys_act[j]->prio > 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; i<dsys_num_act; i++) {
+               dsys_act[i]->draw();
        }
-       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; i<dsys_num_screens; i++) {
+               if(strcmp(dsys_screens[i]->name, 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; i<dsys_num_act; i++) {
+               if(dsys_act[i]->stop) 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;
 }
index e369771..abbc154 100644 (file)
@@ -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 (file)
index 0000000..4401e5a
--- /dev/null
@@ -0,0 +1,521 @@
+#include <stdlib.h>
+#include <math.h>
+#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<B; i++) {
+               perm[i] = i;    /* .. and initialize permutation mapping to identity */
+
+               grad1[i] = (float)((rand() % (B + B)) - B) / B;
+
+               grad2[i][0] = (float)((rand() % (B + B)) - B) / B;
+               grad2[i][1] = (float)((rand() % (B + B)) - B) / B;
+               if((len = sqrt(grad2[i][0] * grad2[i][0] + grad2[i][1] * grad2[i][1])) != 0.0f) {
+                       grad2[i][0] /= len;
+                       grad2[i][1] /= len;
+               }
+
+               grad3[i][0] = (float)((rand() % (B + B)) - B) / B;
+               grad3[i][1] = (float)((rand() % (B + B)) - B) / B;
+               grad3[i][2] = (float)((rand() % (B + B)) - B) / B;
+               if((len = sqrt(grad3[i][0] * grad3[i][0] + grad3[i][1] * grad3[i][1]) + grad3[i][2] * grad3[i][2]) != 0.0f) {
+                       grad3[i][0] /= len;
+                       grad3[i][1] /= len;
+                       grad3[i][2] /= len;
+               }
+       }
+
+       /* permute indices by swapping them randomly */
+       for(i=0; i<B; i++) {
+               int rand_idx = rand() % B;
+
+               int tmp = perm[i];
+               perm[i] = perm[rand_idx];
+               perm[rand_idx] = tmp;
+       }
+
+       /* fill up the rest of the arrays by duplicating the existing gradients */
+       /* and permutations */
+       for(i=0; i<B+2; i++) {
+               perm[B + i] = perm[i];
+               grad1[B + i] = grad1[i];
+               grad2[B + i][0] = grad2[i][0];
+               grad2[B + i][1] = grad2[i][1];
+               grad3[B + i][0] = grad3[i][0];
+               grad3[B + i][1] = grad3[i][1];
+               grad3[B + i][2] = grad3[i][2];
+       }
+
+       tables_valid = 1;
+}
+
+#define lerp(a, b, t) ((a) + ((b) - (a)) * (t))
+#define dotgrad2(g, x, y) ((g)[0] * (x) + (g)[1] * (y))
+#define dotgrad3(g, x, y, z) ((g)[0] * (x) + (g)[1] * (y) + (g)[2] * (z))
+
+float noise1(float x)
+{
+       int bx0, bx1;
+       float rx0, rx1, sx, u, v;
+
+       init_once();
+
+       setup(x, bx0, bx1, rx0, rx1);
+       sx = s_curve(rx0);
+       u = rx0 * grad1[perm[bx0]];
+       v = rx1 * grad1[perm[bx1]];
+       return lerp(u, v, sx);
+}
+
+float noise2(float x, float y)
+{
+       int i, j, b00, b10, b01, b11;
+       int bx0, bx1, by0, by1;
+       float rx0, rx1, ry0, ry1;
+       float sx, sy, u, v, a, b;
+
+       init_once();
+
+       setup(x, bx0, bx1, rx0, rx1);
+       setup(y, by0, by1, ry0, ry1);
+
+       i = perm[bx0];
+       j = perm[bx1];
+
+       b00 = perm[i + by0];
+       b10 = perm[j + by0];
+       b01 = perm[i + by1];
+       b11 = perm[j + by1];
+
+       /* calculate hermite inteprolating factors */
+       sx = s_curve(rx0);
+       sy = s_curve(ry0);
+
+       /* interpolate along the left edge */
+       u = dotgrad2(grad2[b00], rx0, ry0);
+       v = dotgrad2(grad2[b10], rx1, ry0);
+       a = lerp(u, v, sx);
+
+       /* interpolate along the right edge */
+       u = dotgrad2(grad2[b01], rx0, ry1);
+       v = dotgrad2(grad2[b11], rx1, ry1);
+       b = lerp(u, v, sx);
+
+       /* interpolate between them */
+       return lerp(a, b, sy);
+}
+
+float noise3(float x, float y, float z)
+{
+       int i, j;
+       int bx0, bx1, by0, by1, bz0, bz1;
+       int b00, b10, b01, b11;
+       float rx0, rx1, ry0, ry1, rz0, rz1;
+       float sx, sy, sz;
+       float u, v, a, b, c, d;
+
+       init_once();
+
+       setup(x, bx0, bx1, rx0, rx1);
+       setup(y, by0, by1, ry0, ry1);
+       setup(z, bz0, bz1, rz0, rz1);
+
+       i = perm[bx0];
+       j = perm[bx1];
+
+       b00 = perm[i + by0];
+       b10 = perm[j + by0];
+       b01 = perm[i + by1];
+       b11 = perm[j + by1];
+
+       /* calculate hermite interpolating factors */
+       sx = s_curve(rx0);
+       sy = s_curve(ry0);
+       sz = s_curve(rz0);
+
+       /* interpolate along the top slice of the cell */
+       u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz0);
+       v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz0);
+       a = lerp(u, v, sx);
+
+       u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz0);
+       v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz0);
+       b = lerp(u, v, sx);
+
+       c = lerp(a, b, sy);
+
+       /* interpolate along the bottom slice of the cell */
+       u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz1);
+       v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz1);
+       a = lerp(u, v, sx);
+
+       u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz1);
+       v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz1);
+       b = lerp(u, v, sx);
+
+       d = lerp(a, b, sy);
+
+       /* interpolate between slices */
+       return lerp(c, d, sz);
+}
+
+float noise4(float x, float y, float z, float w)
+{
+       return 0;       /* TODO */
+}
+
+
+float pnoise1(float x, int period)
+{
+       int bx0, bx1;
+       float rx0, rx1, sx, u, v;
+
+       init_once();
+
+       setup_p(x, bx0, bx1, rx0, rx1, period);
+       sx = s_curve(rx0);
+       u = rx0 * grad1[perm[bx0]];
+       v = rx1 * grad1[perm[bx1]];
+       return lerp(u, v, sx);
+}
+
+float pnoise2(float x, float y, int per_x, int per_y)
+{
+       int i, j, b00, b10, b01, b11;
+       int bx0, bx1, by0, by1;
+       float rx0, rx1, ry0, ry1;
+       float sx, sy, u, v, a, b;
+
+       init_once();
+
+       setup_p(x, bx0, bx1, rx0, rx1, per_x);
+       setup_p(y, by0, by1, ry0, ry1, per_y);
+
+       i = perm[bx0];
+       j = perm[bx1];
+
+       b00 = perm[i + by0];
+       b10 = perm[j + by0];
+       b01 = perm[i + by1];
+       b11 = perm[j + by1];
+
+       /* calculate hermite inteprolating factors */
+       sx = s_curve(rx0);
+       sy = s_curve(ry0);
+
+       /* interpolate along the left edge */
+       u = dotgrad2(grad2[b00], rx0, ry0);
+       v = dotgrad2(grad2[b10], rx1, ry0);
+       a = lerp(u, v, sx);
+
+       /* interpolate along the right edge */
+       u = dotgrad2(grad2[b01], rx0, ry1);
+       v = dotgrad2(grad2[b11], rx1, ry1);
+       b = lerp(u, v, sx);
+
+       /* interpolate between them */
+       return lerp(a, b, sy);
+}
+
+float pnoise3(float x, float y, float z, int per_x, int per_y, int per_z)
+{
+       int i, j;
+       int bx0, bx1, by0, by1, bz0, bz1;
+       int b00, b10, b01, b11;
+       float rx0, rx1, ry0, ry1, rz0, rz1;
+       float sx, sy, sz;
+       float u, v, a, b, c, d;
+
+       init_once();
+
+       setup_p(x, bx0, bx1, rx0, rx1, per_x);
+       setup_p(y, by0, by1, ry0, ry1, per_y);
+       setup_p(z, bz0, bz1, rz0, rz1, per_z);
+
+       i = perm[bx0];
+       j = perm[bx1];
+
+       b00 = perm[i + by0];
+       b10 = perm[j + by0];
+       b01 = perm[i + by1];
+       b11 = perm[j + by1];
+
+       /* calculate hermite interpolating factors */
+       sx = s_curve(rx0);
+       sy = s_curve(ry0);
+       sz = s_curve(rz0);
+
+       /* interpolate along the top slice of the cell */
+       u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz0);
+       v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz0);
+       a = lerp(u, v, sx);
+
+       u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz0);
+       v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz0);
+       b = lerp(u, v, sx);
+
+       c = lerp(a, b, sy);
+
+       /* interpolate along the bottom slice of the cell */
+       u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz1);
+       v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz1);
+       a = lerp(u, v, sx);
+
+       u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz1);
+       v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz1);
+       b = lerp(u, v, sx);
+
+       d = lerp(a, b, sy);
+
+       /* interpolate between slices */
+       return lerp(c, d, sz);
+}
+
+float pnoise4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w)
+{
+       return 0;
+}
+
+
+float fbm1(float x, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += noise1(x * freq) / freq;
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+float fbm2(float x, float y, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += noise2(x * freq, y * freq) / freq;
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+float fbm3(float x, float y, float z, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += noise3(x * freq, y * freq, z * freq) / freq;
+               freq *= 2.0f;
+       }
+       return res;
+
+}
+
+float fbm4(float x, float y, float z, float w, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += noise4(x * freq, y * freq, z * freq, w * freq) / freq;
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+
+float pfbm1(float x, int per, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += pnoise1(x * freq, per) / freq;
+               freq *= 2.0f;
+               per *= 2;
+       }
+       return res;
+}
+
+float pfbm2(float x, float y, int per_x, int per_y, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += pnoise2(x * freq, y * freq, per_x, per_y) / freq;
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+       }
+       return res;
+}
+
+float pfbm3(float x, float y, float z, int per_x, int per_y, int per_z, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += pnoise3(x * freq, y * freq, z * freq, per_x, per_y, per_z) / freq;
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+               per_z *= 2;
+       }
+       return res;
+}
+
+float pfbm4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += pnoise4(x * freq, y * freq, z * freq, w * freq,
+                               per_x, per_y, per_z, per_w) / freq;
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+               per_z *= 2;
+               per_w *= 2;
+       }
+       return res;
+}
+
+
+float turbulence1(float x, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(noise1(x * freq) / freq);
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+float turbulence2(float x, float y, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(noise2(x * freq, y * freq) / freq);
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+float turbulence3(float x, float y, float z, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(noise3(x * freq, y * freq, z * freq) / freq);
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+float turbulence4(float x, float y, float z, float w, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(noise4(x * freq, y * freq, z * freq, w * freq) / freq);
+               freq *= 2.0f;
+       }
+       return res;
+}
+
+
+float pturbulence1(float x, int per, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(pnoise1(x * freq, per) / freq);
+               freq *= 2.0f;
+               per *= 2;
+       }
+       return res;
+}
+
+float pturbulence2(float x, float y, int per_x, int per_y, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(pnoise2(x * freq, y * freq, per_x, per_y) / freq);
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+       }
+       return res;
+}
+
+float pturbulence3(float x, float y, float z, int per_x, int per_y, int per_z, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(pnoise3(x * freq, y * freq, z * freq, per_x, per_y, per_z) / freq);
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+               per_z *= 2;
+       }
+       return res;
+}
+
+float pturbulence4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w, int octaves)
+{
+       int i;
+       float res = 0.0f, freq = 1.0f;
+       for(i=0; i<octaves; i++) {
+               res += fabs(pnoise4(x * freq, y * freq, z * freq, w * freq,
+                               per_x, per_y, per_z, per_w) / freq);
+               freq *= 2.0f;
+               per_x *= 2;
+               per_y *= 2;
+               per_z *= 2;
+               per_w *= 2;
+       }
+       return res;
+}
diff --git a/src/noise.h b/src/noise.h
new file mode 100644 (file)
index 0000000..7c9eaaa
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef NOISE_H_
+#define NOISE_H_
+
+float noise1(float x);
+float noise2(float x, float y);
+float noise3(float x, float y, float z);
+/*float noise4(float x, float y, float z, float w);*/
+
+float pnoise1(float x, int period);
+float pnoise2(float x, float y, int per_x, int per_y);
+float pnoise3(float x, float y, float z, int per_x, int per_y, int per_z);
+/*float pnoise4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w);*/
+
+float fbm1(float x, int octaves);
+float fbm2(float x, float y, int octaves);
+float fbm3(float x, float y, float z, int octaves);
+/*float fbm4(float x, float y, float z, float w, int octaves);*/
+
+float pfbm1(float x, int per, int octaves);
+float pfbm2(float x, float y, int per_x, int per_y, int octaves);
+float pfbm3(float x, float y, float z, int per_x, int per_y, int per_z, int octaves);
+/*float pfbm4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w, int octaves);*/
+
+float turbulence1(float x, int octaves);
+float turbulence2(float x, float y, int octaves);
+float turbulence3(float x, float y, float z, int octaves);
+/*float turbulence4(float x, float y, float z, float w, int octaves);*/
+
+float pturbulence1(float x, int per, int octaves);
+float pturbulence2(float x, float y, int per_x, int per_y, int octaves);
+float pturbulence3(float x, float y, float z, int per_x, int per_y, int per_z, int octaves);
+/*float pturbulence4(float x, float y, float z, float w, int per_x, int per_y, int per_z, int per_w, int octaves);*/
+
+
+#endif /* NOISE_H_ */
index 876ea51..e5f1bb3 100644 (file)
@@ -1,6 +1,46 @@
-#include "demosys.h"
-#include "opengl.h"
+#include "demo.h"
+#include "noise.h"
+
+static int init(void);
+static void destroy(void);
+static void draw(void);
+
+static unsigned int sdr_foo;
+
+static struct demoscreen scr = { "testa", init, destroy, 0, 0, 0, 0, draw };
 
 void regscr_testa(void)
 {
+       dsys_add_screen(&scr);
+}
+
+static int init(void)
+{
+       if(!(sdr_foo = get_sdrprog("sdr/foo.v.glsl", "sdr/foo-notex.p.glsl"))) {
+               return -1;
+       }
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+static void draw(void)
+{
+       int i;
+       float t = dsys_time / 1000.0f;
+
+       glUseProgram(sdr_foo);
+       gl_begin(GL_QUADS);
+       for(i=0; i<16; i++) {
+               float x0 = i / 8.0f - 1.0f + 0.01;
+               float x1 = (i + 1) / 8.0f - 1.0f - 0.01;
+               float y = noise2((float)i * 1.24f, t);
+               gl_vertex2f(x0, -1);
+               gl_vertex2f(x1, -1);
+               gl_vertex2f(x1, y);
+               gl_vertex2f(x0, y);
+       }
+       gl_end();
 }
index b65de8a..548fa0b 100644 (file)
@@ -1,6 +1,56 @@
-#include "demosys.h"
-#include "opengl.h"
+#include "demo.h"
+#include "noise.h"
+
+static int init(void);
+static void destroy(void);
+static void draw(void);
+
+static unsigned int sdr_foo;
 
 void regscr_testb(void)
 {
+       static struct demoscreen scr = { "testb", init, destroy, 0, 0, 0, 0, draw };
+       dsys_add_screen(&scr);
+}
+
+static int init(void)
+{
+       if(!(sdr_foo = get_sdrprog("sdr/foo.v.glsl", "sdr/foo-notex.p.glsl"))) {
+               return -1;
+       }
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+#define NX     16
+#define NY     10
+
+static void draw(void)
+{
+       int i, j;
+       float x, y, xr, yr, sz;
+       float t = dsys_time / 700.0f;
+
+       glUseProgram(sdr_foo);
+       gl_begin(GL_QUADS);
+       for(i=0; i<NY; i++) {
+               y = (i + 0.5f) / (NY/2.0f) - 1.0f;
+               for(j=0; j<NX; j++) {
+                       x = (j + 0.5f) / (NX/2.0f) - 1.0f;
+                       sz = noise2(x * 5.0f, t) * noise2(y * 5.0f, t) * 2.5f;
+                       if(sz < 0.0f) sz = 0.0f;
+                       if(sz > 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();
 }
index dc86d10..7be1859 100644 (file)
@@ -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;
+}
index 61ae532..69b8f53 100644 (file)
 
 #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_ */