From 6370997ad9f4d424b05bcb7dc85fa2423bd1186a Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 1 Apr 2023 01:42:00 +0300 Subject: [PATCH] latest goat3d changes --- libs/goat3d/src/g3dscn.h | 3 + libs/goat3d/src/json.c | 635 ++++++++++++++++++++++++++++++++++++++++++++ libs/goat3d/src/json.h | 105 ++++++++ libs/goat3d/src/read.c | 5 + libs/goat3d/src/readgltf.c | 179 +++++++++++++ libs/goat3d/src/util.c | 1 + 6 files changed, 928 insertions(+) create mode 100644 libs/goat3d/src/json.c create mode 100644 libs/goat3d/src/json.h create mode 100644 libs/goat3d/src/readgltf.c diff --git a/libs/goat3d/src/g3dscn.h b/libs/goat3d/src/g3dscn.h index 468f9d3..e1e8f5e 100644 --- a/libs/goat3d/src/g3dscn.h +++ b/libs/goat3d/src/g3dscn.h @@ -195,4 +195,7 @@ int g3dimpl_anmsave(const struct goat3d *g, struct goat3d_io *io); /* defined in extmesh.c */ int g3dimpl_loadmesh(struct goat3d_mesh *mesh, const char *fname); +/* defined in readgltf.c */ +int g3dimpl_loadgltf(struct goat3d *g, struct goat3d_io *io); + #endif /* GOAT3D_SCENE_H_ */ diff --git a/libs/goat3d/src/json.c b/libs/goat3d/src/json.c new file mode 100644 index 0000000..e38ea15 --- /dev/null +++ b/libs/goat3d/src/json.c @@ -0,0 +1,635 @@ +#include +#include +#include +#include +#include "dynarr.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#include +#else +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) +#include +#endif +#endif + +#include "json.h" + +#ifdef _MSC_VER +#define strncasecmp strnicmp +#endif + +struct json_obj *json_alloc_obj(void) +{ + struct json_obj *obj; + + if(!(obj = malloc(sizeof *obj))) { + fprintf(stderr, "json_alloc_obj: failed to allocate object\n"); + return 0; + } + json_init_obj(obj); + return obj; +} + +void json_free_obj(struct json_obj *obj) +{ + json_destroy_obj(obj); + free(obj); +} + +void json_init_obj(struct json_obj *obj) +{ + memset(obj, 0, sizeof *obj); +} + +void json_destroy_obj(struct json_obj *obj) +{ + int i; + + for(i=0; inum_items; i++) { + json_destroy_item(obj->items + i); + } + free(obj->items); +} + +struct json_arr *json_alloc_arr(void) +{ + struct json_arr *arr; + + if(!(arr = malloc(sizeof *arr))) { + fprintf(stderr, "json_alloc_arr: failed to allocate array\n"); + return 0; + } + json_init_arr(arr); + return arr; +} + +void json_free_arr(struct json_arr *arr) +{ + json_destroy_arr(arr); + free(arr); +} + +void json_init_arr(struct json_arr *arr) +{ + memset(arr, 0, sizeof *arr); +} + +void json_destroy_arr(struct json_arr *arr) +{ + int i; + + for(i=0; isize; i++) { + json_destroy_value(arr->val + i); + } + free(arr->val); +} + + +int json_item(struct json_item *item, const char *name) +{ + memset(item, 0, sizeof *item); + + if(!(item->name = strdup(name))) { + fprintf(stderr, "json_item: failed to allocate name\n"); + return -1; + } + return 0; +} + +void json_destroy_item(struct json_item *item) +{ + free(item->name); + json_destroy_value(&item->val); +} + +int json_value_str(struct json_value *jv, const char *str) +{ + jv->type = JSON_STR; + + jv->str = 0; + if(str && !(jv->str = strdup(str))) { + fprintf(stderr, "json_value_str: failed to duplicate string\n"); + return -1; + } + return 0; +} + +void json_value_num(struct json_value *jv, double num) +{ + jv->type = JSON_NUM; + jv->num = num; +} + +void json_value_bool(struct json_value *jv, int bval) +{ + jv->type = JSON_BOOL; + jv->boolean = bval; +} + +void json_value_obj(struct json_value *jv, struct json_obj *obj) +{ + jv->type = JSON_OBJ; + if(obj) { + jv->obj = *obj; + } else { + json_init_obj(&jv->obj); + } +} + +void json_value_arr(struct json_value *jv, struct json_arr *arr) +{ + jv->type = JSON_ARR; + if(arr) { + jv->arr = *arr; + } else { + json_init_arr(&jv->arr); + } +} + +void json_destroy_value(struct json_value *jv) +{ + switch(jv->type) { + case JSON_STR: + free(jv->str); + break; + + case JSON_OBJ: + json_destroy_obj(&jv->obj); + break; + + case JSON_ARR: + json_destroy_arr(&jv->arr); + break; + + default: + break; + } +} + +int json_obj_append(struct json_obj *obj, const struct json_item *item) +{ + if(obj->num_items >= obj->max_items) { + int newsz = obj->max_items ? (obj->max_items << 1) : 8; + void *tmp = realloc(obj->items, newsz * sizeof *obj->items); + if(!tmp) { + fprintf(stderr, "json_obj_append: failed to grow items array (%d)\n", newsz); + return -1; + } + obj->items = tmp; + obj->max_items = newsz; + } + + obj->items[obj->num_items++] = *item; + return 0; +} + +int json_arr_append(struct json_arr *arr, const struct json_value *val) +{ + if(arr->size >= arr->maxsize) { + int newsz = arr->maxsize ? (arr->maxsize << 1) : 8; + void *tmp = realloc(arr->val, newsz * sizeof *arr->val); + if(!tmp) { + fprintf(stderr, "json_arr_append: failed to grow array (%d)\n", newsz); + return -1; + } + arr->val = tmp; + arr->maxsize = newsz; + } + + arr->val[arr->size++] = *val; + return 0; +} + +struct json_item *json_find_item(const struct json_obj *obj, const char *name) +{ + int i; + for(i=0; inum_items; i++) { + if(strcmp(obj->items[i].name, name) == 0) { + return obj->items + i; + } + } + return 0; +} + +/* lookup functions */ + +struct json_value *json_lookup(struct json_obj *obj, const char *path) +{ + int len; + char *pelem; + const char *endp; + struct json_item *it = 0; + + pelem = alloca(strlen(path) + 1); + while(*path) { + endp = path; + while(*endp && *endp != '.') endp++; + if(!(len = endp - path)) break; + + memcpy(pelem, path, len); + pelem[len] = 0; + + /* continue after the . or point at the terminator */ + path = endp; + if(*path == '.') path++; + + if(!(it = json_find_item(obj, pelem))) { + return 0; + } + + if(it->val.type != JSON_OBJ) { + /* we hit a leaf. If the path continues we failed */ + if(*path) return 0; + } + + /* item is an object, we can continue the lookup if necessary */ + obj = &it->val.obj; + } + + return it ? &it->val : 0; +} + +const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_STR) { + return def; + } + return val->str; +} + +double json_lookup_num(struct json_obj *obj, const char *path, double def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_NUM) { + return def; + } + return val->num; +} + +int json_lookup_bool(struct json_obj *obj, const char *path, int def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_BOOL) { + return def; + } + return val->boolean; +} + +struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_OBJ) { + return def; + } + return &val->obj; +} + +struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def) +{ + struct json_value *val; + + if(!(val = json_lookup(obj, path)) || val->type != JSON_ARR) { + return def; + } + return &val->arr; +} + + +/* ---- parser ---- */ + +#define MAX_TOKEN_SIZE 512 +struct parser { + char *text; + char nextc; + char *token; +}; + +enum { TOKEN_NUM, TOKEN_STR, TOKEN_BOOL }; /* plus all the single-char tokens */ + + +static int item(struct parser *p, struct json_item *it); +static int array(struct parser *p, struct json_arr *arr); +static int object(struct parser *p, struct json_obj *obj); + + +static int next_char(struct parser *p) +{ + while(*p->text) { + p->nextc = *p->text++; + if(!isspace(p->nextc)) break; + } + return p->nextc; +} + +#define SET_TOKEN(token, str, len) \ + do { \ + DYNARR_RESIZE(token, (len) + 1); \ + memcpy(token, str, len); \ + token[len] = 0; \ + } while(0) + +static int next_token(struct parser *p) +{ + int len; + char *ptr, *s; + + if(!p->nextc) return -1; + + switch(p->nextc) { + case '{': + case '}': + case ',': + case '[': + case ']': + case ':': + SET_TOKEN(p->token, &p->nextc, 1); + next_char(p); + return p->token[0]; + + case '"': + DYNARR_CLEAR(p->token); + next_char(p); + while(p->nextc && p->nextc != '"') { + DYNARR_STRPUSH(p->token, p->nextc); + next_char(p); + } + next_char(p); + return TOKEN_STR; + + default: + break; + } + + s = p->text - 1; + + strtod(s, &ptr); + if(ptr != s) { + len = ptr - s; + SET_TOKEN(p->token, s, len); + p->text = ptr; + next_char(p); + return TOKEN_NUM; + } + + if(strncasecmp(s, "true", 4) == 0) { + SET_TOKEN(p->token, "true", 4); + p->text += 3; + next_char(p); + return TOKEN_BOOL; + } + if(strncasecmp(s, "false", 5) == 0) { + SET_TOKEN(p->token, "false", 5); + p->text += 4; + next_char(p); + return TOKEN_BOOL; + } + + SET_TOKEN(p->token, &p->nextc, 1); + fprintf(stderr, "json_parse: unexpected character: %c\n", p->nextc); + return -1; +} + +static int expect(struct parser *p, int tok) +{ + return next_token(p) == tok ? 1 : 0; +} + +static const char *toktypestr(int tok) +{ + static char buf[] = "' '"; + switch(tok) { + case TOKEN_NUM: return "number"; + case TOKEN_STR: return "string"; + case TOKEN_BOOL: return "boolean"; + default: + break; + } + buf[1] = tok; + return buf; +} + +#define EXPECT(p, x) \ + do { \ + if(!expect(p, x)) { \ + fprintf(stderr, "json_parse: expected: %s, found: %s\n", toktypestr(x), (p)->token); \ + return -1; \ + } \ + } while(0) + +static int value(struct parser *p, struct json_value *val) +{ + int toktype; + struct json_obj obj; + struct json_arr arr; + + toktype = next_token(p); + switch(toktype) { + case TOKEN_STR: + if(json_value_str(val, p->token) == -1) { + return -1; + } + break; + + case TOKEN_NUM: + json_value_num(val, atof(p->token)); + break; + + case TOKEN_BOOL: + json_value_bool(val, *p->token == 't' ? 1 : 0); + break; + + case '{': /* object */ + if(object(p, &obj) == -1) { + return -1; + } + json_value_obj(val, &obj); + break; + + case '[': /* array */ + if(array(p, &arr) == -1) { + return -1; + } + json_value_arr(val, &arr); + break; + + default: + fprintf(stderr, "json_parse: unexpected token %s while parsing item\n", p->text); + return -1; + } + return 0; +} + +static int item(struct parser *p, struct json_item *it) +{ + EXPECT(p, TOKEN_STR); + if(json_item(it, p->token) == -1) { + return -1; + } + EXPECT(p, ':'); + if(value(p, &it->val) == -1) { + free(it->name); + return -1; + } + return 0; +} + +static int array(struct parser *p, struct json_arr *arr) +{ + struct json_value val; + + json_init_arr(arr); + + while(p->nextc != -1 && p->nextc != ']') { + if(value(p, &val) == -1) { + fprintf(stderr, "json_parse: expected value in array\n"); + json_destroy_arr(arr); + return -1; + } + + if(json_arr_append(arr, &val) == -1) { + json_destroy_value(&val); + json_destroy_arr(arr); + return -1; + } + + if(p->nextc == ',') expect(p, ','); /* eat up comma separator */ + } + EXPECT(p, ']'); + return 0; +} + +static int object(struct parser *p, struct json_obj *obj) +{ + struct json_item it; + + json_init_obj(obj); + + while(p->nextc != -1 && p->nextc != '}') { + if(item(p, &it) == -1) { + fprintf(stderr, "json_parse: expected item in object\n"); + json_destroy_obj(obj); + return -1; + } + + if(json_obj_append(obj, &it) == -1) { + json_destroy_item(&it); + json_destroy_obj(obj); + return -1; + } + + if(p->nextc == ',') expect(p, ','); /* eat up comma separator */ + } + EXPECT(p, '}'); + return 0; +} + +int json_parse(struct json_obj *root, const char *text) +{ + struct parser p; + + if(!text || !*text) return -1; + + p.nextc = *text; + p.text = (char*)(text + 1); + if(!(p.token = dynarr_alloc(0, 1))) { + fprintf(stderr, "json_parse: failed to allocate token dynamic array\n"); + return -1; + } + + EXPECT(&p, '{'); + if(object(&p, root) == -1) { + dynarr_free(p.token); + return -1; + } + dynarr_free(p.token); + return 0; +} + + +static void putind(FILE *fp, int ind) +{ + int i; + for(i=0; inum_items; i++) { + putind(fp, ind + 1); + json_print_item(fp, obj->items + i, ind + 1); + if(i < obj->num_items - 1) { + fputs(",\n", fp); + } else { + fputc('\n', fp); + } + } + + putind(fp, ind); + fputs("}", fp); +} + +void json_print_arr(FILE *fp, struct json_arr *arr, int ind) +{ + int i; + + fputs("[\n", fp); + + for(i=0; isize; i++) { + putind(fp, ind + 1); + json_print_value(fp, arr->val + i, ind + 1); + if(i < arr->size - 1) { + fputs(",\n", fp); + } else { + fputc('\n', fp); + } + } + + putind(fp, ind); + fputs("]", fp); +} + +void json_print_item(FILE *fp, struct json_item *item, int ind) +{ + fprintf(fp, "\"%s\": ", item->name); + json_print_value(fp, &item->val, ind); +} + +void json_print_value(FILE *fp, struct json_value *val, int ind) +{ + switch(val->type) { + case JSON_STR: + fprintf(fp, "\"%s\"", val->str); + break; + case JSON_NUM: + fprintf(fp, "%g", val->num); + break; + case JSON_BOOL: + fprintf(fp, "%s", val->boolean ? "true" : "false"); + break; + case JSON_OBJ: + json_print_obj(fp, &val->obj, ind); + break; + case JSON_ARR: + json_print_arr(fp, &val->arr, ind); + break; + default: + fputs("", fp); + } +} diff --git a/libs/goat3d/src/json.h b/libs/goat3d/src/json.h new file mode 100644 index 0000000..705a82c --- /dev/null +++ b/libs/goat3d/src/json.h @@ -0,0 +1,105 @@ +#ifndef JSON_H_ +#define JSON_H_ + +enum { + JSON_NULL, + JSON_STR, /* "foo" */ + JSON_NUM, /* 3.141 */ + JSON_BOOL, /* true */ + JSON_OBJ, /* { ... } */ + JSON_ARR /* [ ... ] */ +}; + +struct json_value; + +/* objects are collections of items { "foo": 1, "bar": 2 } */ +struct json_obj { + struct json_item *items; + int num_items, max_items; +}; + +/* arrays are collections of values [ "foo", "bar", 3.14, false, "xyzzy" ] */ +struct json_arr { + struct json_value *val; + int size, maxsize; +}; + +struct json_value { + int type; + + char *str; /* JSON_STR */ + double num; /* JSON_NUM */ + int boolean; /* JSON_BOOL */ + struct json_obj obj; /* JSON_OBJ */ + struct json_arr arr; /* JSON_ARR */ +}; + +/* items are key-value pairs "foo": "xyzzy" */ +struct json_item { + char *name; + struct json_value val; + + struct json_item *next; +}; + + +struct json_obj *json_alloc_obj(void); /* malloc + json_init_obj */ +void json_free_obj(struct json_obj *obj); /* json_destroy_obj + free */ +void json_init_obj(struct json_obj *obj); +void json_destroy_obj(struct json_obj *obj); + +struct json_arr *json_alloc_arr(void); /* malloc + json_init_arr */ +void json_free_arr(struct json_arr *arr); /* json_destroy_arr + free */ +void json_init_arr(struct json_arr *arr); +void json_destroy_arr(struct json_arr *arr); + +/* initialize item */ +int json_item(struct json_item *item, const char *name); +void json_destroy_item(struct json_item *item); + +/* pointer values for str, obj, arr can be null */ +int json_value_str(struct json_value *jv, const char *str); +void json_value_num(struct json_value *jv, double num); +void json_value_bool(struct json_value *jv, int bval); +void json_value_obj(struct json_value *jv, struct json_obj *obj); /* shallow copy obj */ +void json_value_arr(struct json_value *jv, struct json_arr *arr); /* shallow copy arr */ + +void json_destroy_value(struct json_value *jv); + +/* item can be null, in which case only space is allocated + * if not null, contents are shallow-copied (moved), do not destroy or use + */ +int json_obj_append(struct json_obj *obj, const struct json_item *item); + +/* val can be null in which case only space is allocated + * if not null, contents are shallow-copied (moved), do not destroy or use + */ +int json_arr_append(struct json_arr *arr, const struct json_value *val); + +/* find named item in an object (direct descendant name only, not a path) */ +struct json_item *json_find_item(const struct json_obj *obj, const char *name); + +/* json_lookup returns 0 if the requested value is not found */ +struct json_value *json_lookup(struct json_obj *root, const char *path); + +/* typed lookup functions return their default argument if the requested value + * is not found, or if it has the wrong type. + */ +const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def); +double json_lookup_num(struct json_obj *obj, const char *path, double def); +int json_lookup_bool(struct json_obj *obj, const char *path, int def); +/* these next two are probably not very useful */ +struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def); +struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def); + + +int json_parse(struct json_obj *root, const char *text); + +/* mostly useful for debugging */ +void json_print(FILE *fp, struct json_obj *root); +void json_print_obj(FILE *fp, struct json_obj *obj, int ind); +void json_print_arr(FILE *fp, struct json_arr *arr, int ind); +void json_print_item(FILE *fp, struct json_item *item, int ind); +void json_print_value(FILE *fp, struct json_value *val, int ind); + +#endif /* JSON_H_ */ diff --git a/libs/goat3d/src/read.c b/libs/goat3d/src/read.c index cad023d..285c64c 100644 --- a/libs/goat3d/src/read.c +++ b/libs/goat3d/src/read.c @@ -54,6 +54,11 @@ int g3dimpl_scnload(struct goat3d *g, struct goat3d_io *io) struct ts_node *tsroot, *c; const char *str; + /* attempt to load it as gltf first */ + if((g3dimpl_loadgltf(g, io)) == 0) { + return 0; + } + tsio.data = io->cls; tsio.read = io->read; tsio.write = io->write; diff --git a/libs/goat3d/src/readgltf.c b/libs/goat3d/src/readgltf.c new file mode 100644 index 0000000..8b605d6 --- /dev/null +++ b/libs/goat3d/src/readgltf.c @@ -0,0 +1,179 @@ +/* +goat3d - 3D scene, and animation file format library. +Copyright (C) 2013-2023 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ +#include +#include +#include "goat3d.h" +#include "g3dscn.h" +#include "log.h" +#include "json.h" + +static struct goat3d_material *read_material(struct goat3d *g, struct json_obj *jmtl); + +int g3dimpl_loadgltf(struct goat3d *g, struct goat3d_io *io) +{ + long i, filesz; + char *filebuf; + struct json_obj root; + struct json_value *jval; + struct json_item *jitem; + struct goat3d_material *mtl; + + if(!(filebuf = malloc(4096))) { + goat3d_logmsg(LOG_ERROR, "goat3d_load: failed to allocate file buffer\n"); + return -1; + } + filesz = io->read(filebuf, 4096, io->cls); + if(filesz < 2) { + free(filebuf); + return -1; + } + for(i=0; iseek(0, SEEK_END, io->cls); + io->seek(0, SEEK_SET, io->cls); + if(!(filebuf = malloc(filesz + 1))) { + goat3d_logmsg(LOG_ERROR, "goat3d_load: failed to load file into memory\n"); + return -1; + } + if(io->read(filebuf, filesz, io->cls) != filesz) { + goat3d_logmsg(LOG_ERROR, "goat3d_load: EOF while reading file\n"); + free(filebuf); + return -1; + } + filebuf[filesz] = 0; + + json_init_obj(&root); + if(json_parse(&root, filebuf) == -1) { + free(filebuf); + return -1; + } + free(filebuf); + + /* a valid gltf file needs to have an "asset" node with a version number */ + if(!(jval = json_lookup(&root, "asset.version"))) { + json_destroy_obj(&root); + return -1; + } + + /* read all materials */ + if((jitem = json_find_item(&root, "materials"))) { + if(jitem->val.type != JSON_ARR) { + goat3d_logmsg(LOG_ERROR, "goat3d_load: gltf materials value is not an array!\n"); + goto skipmtl; + } + + for(i=0; ival.arr.size; i++) { + jval = jitem->val.arr.val + i; + + if(jval->type != JSON_OBJ) { + goat3d_logmsg(LOG_ERROR, "goat3d_load: gltf material is not a json object!\n"); + continue; + } + + if((mtl = read_material(g, &jval->obj))) { + goat3d_add_mtl(g, mtl); + } + } + } +skipmtl: + + /* ... */ + + json_destroy_obj(&root); + return 0; +} + +static int jarr_to_vec(struct json_arr *jarr, float *vec) +{ + int i; + + if(jarr->size < 3 || jarr->size > 4) { + return -1; + } + + for(i=0; i<4; i++) { + if(i >= jarr->size) { + vec[i] = 0; + continue; + } + if(jarr->val[i].type != JSON_NUM) { + return -1; + } + vec[i] = jarr->val[i].num; + } + return jarr->size; +} + +static int jval_to_vec(struct json_value *jval, float *vec) +{ + if(jval->type != JSON_ARR) return -1; + return jarr_to_vec(&jval->arr, vec); +} + +static struct goat3d_material *read_material(struct goat3d *g, struct json_obj *jmtl) +{ + struct goat3d_material *mtl; + const char *str; + struct json_value *jval; + float color[4], specular[4], roughness, metal, ior; + int nelem; + + if(!(mtl = malloc(sizeof *mtl)) || g3dimpl_mtl_init(mtl) == -1) { + free(mtl); + goat3d_logmsg(LOG_ERROR, "read_material: failed to allocate material\n"); + return 0; + } + + if((str = json_lookup_str(jmtl, "name", 0))) { + goat3d_set_mtl_name(mtl, str); + } + + if((jval = json_lookup(jmtl, "pbrMetallicRoughness.baseColorFactor")) && + (nelem = jval_to_vec(jval, color)) != -1) { + goat3d_set_mtl_attrib(mtl, "diffuse", color); + } + /* TODO textures */ + + if((roughness = json_lookup_num(jmtl, "pbrMetallicRoughness.roughnessFactor", -1.0)) >= 0) { + goat3d_set_mtl_attrib1f(mtl, "roughness", roughness); + goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, (1.0f - roughness) * 100.0f + 1.0f); + } + if((metal = json_lookup_num(jmtl, "pbrMetallicRoughness.metallicFactor", -1.0)) >= 0) { + goat3d_set_mtl_attrib1f(mtl, "metal", metal); + } + if((jval = json_lookup(jmtl, "extensions.KHR_materials_specular.specularColorFactor")) && + (nelem = jval_to_vec(jval, specular)) != -1) { + goat3d_set_mtl_attrib(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular); + } + if((ior = json_lookup_num(jmtl, "extensions.KHR_materials_ior.ior", -1.0)) >= 0) { + goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_IOR, ior); + } + /* TODO more attributes */ + + return mtl; +} diff --git a/libs/goat3d/src/util.c b/libs/goat3d/src/util.c index ece922a..9344e55 100644 --- a/libs/goat3d/src/util.c +++ b/libs/goat3d/src/util.c @@ -16,6 +16,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include +#include #include "util.h" static int b64bits(int c); -- 1.7.10.4