X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=libs%2Fgoat3d%2Fsrc%2Freadgltf.c;fp=libs%2Fgoat3d%2Fsrc%2Freadgltf.c;h=8b605d6a1c36c0c078293c149049d4de869413a8;hb=6370997ad9f4d424b05bcb7dc85fa2423bd1186a;hp=0000000000000000000000000000000000000000;hpb=4c42122003b1e2e859e63013aaf15e270d47b082;p=deeprace 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; +}