From: John Tsiombikas Date: Tue, 29 Nov 2016 16:45:16 +0000 (+0200) Subject: material editing in scene metafile X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=commitdiff_plain;h=d4d7f73284783d2a50d71014789d196bef7d0e0e material editing in scene metafile --- diff --git a/src/material.cc b/src/material.cc index 0aa83cd..f893175 100644 --- a/src/material.cc +++ b/src/material.cc @@ -40,3 +40,38 @@ void Material::add_texture(Texture *tex, int type) stdtex[type] = tex; } } + +int mtl_parse_type(const char *str) +{ + if(strcmp(str, "diffuse") == 0) { + return MTL_TEX_DIFFUSE; + } else if(strcmp(str, "specular") == 0) { + return MTL_TEX_SPECULAR; + } else if(strcmp(str, "normalmap") == 0) { + return MTL_TEX_NORMALMAP; + } else if(strcmp(str, "lightmap") == 0) { + return MTL_TEX_LIGHTMAP; + } else if(strcmp(str, "envmap") == 0) { + return MTL_TEX_ENVMAP; + } + return MTL_TEX_UNKNOWN; +} + +const char *mtl_type_string(int type) +{ + switch(type) { + case MTL_TEX_DIFFUSE: + return "diffuse"; + case MTL_TEX_SPECULAR: + return "specular"; + case MTL_TEX_NORMALMAP: + return "normalmap"; + case MTL_TEX_LIGHTMAP: + return "lightmap"; + case MTL_TEX_ENVMAP: + return "envmap"; + default: + break; + } + return "unknown"; +} diff --git a/src/material.h b/src/material.h index 979bbd9..5cf3533 100644 --- a/src/material.h +++ b/src/material.h @@ -34,4 +34,9 @@ public: void add_texture(Texture *tex, int type = MTL_TEX_UNKNOWN); }; +// returns MTL_TEX_whatever by name +int mtl_parse_type(const char *str); +// returns the name of a material type +const char *mtl_type_string(int type); + #endif // MATERIAL_H_ diff --git a/src/metascene.cc b/src/metascene.cc index cf4d788..b92e31f 100644 --- a/src/metascene.cc +++ b/src/metascene.cc @@ -1,3 +1,4 @@ +#include #include "metascene.h" #include "scene.h" #include "datamap.h" @@ -12,6 +13,7 @@ static bool proc_node(Scene *scn, struct ts_node *node); static bool proc_scenefile(Scene *scn, struct ts_node *node); +static bool proc_mtledit(Scene *scn, struct ts_node *node); static struct ts_attr *attr_inscope(struct ts_node *node, const char *name); static void print_scene_graph(SceneNode *n, int level); @@ -83,14 +85,14 @@ static bool proc_scenefile(Scene *scn, struct ts_node *node) fname = namebuf; } - if(!(scn->load(fname, SCNLOAD_FLIPTEX))) { + Scene *newscn = new Scene(scn->texset); + if(!(newscn->load(fname, SCNLOAD_FLIPTEX))) { // TODO unhardcode FLIPTEX return false; } // extract the walk mesh if necessary - // XXX as written, this will match even objects loaded by previous scenefile blocks Scene *wscn; - if(walkmesh_regexp && (wscn = scn->extract_nodes(walkmesh_regexp))) { + if(walkmesh_regexp && (wscn = newscn->extract_nodes(walkmesh_regexp))) { // apply all transformations to the meshes wscn->apply_xform(); @@ -98,18 +100,94 @@ static bool proc_scenefile(Scene *scn, struct ts_node *node) for(int i=0; imeshes[i]; - if(scn->walk_mesh) { - scn->walk_mesh->append(*m); + if(newscn->walk_mesh) { + newscn->walk_mesh->append(*m); } else { - scn->walk_mesh = m; + newscn->walk_mesh = m; wscn->remove_mesh(m); // to save it from destruction } } delete wscn; } + + // perform material edits + struct ts_node *child = node->child_list; + while(child) { + proc_mtledit(newscn, child); // ignores any non-mtledit nodes, no need to check + child = child->next; + } + + scn->merge(newscn); + delete newscn; + } + //datamap_reset(); // TODO this should be push/pop instead of hard reset + + return true; +} + +static void mtledit(Material *mtl, TextureSet *texset, struct ts_node *node) +{ + node = node->child_list; + while(node) { + struct ts_node *cn = node; + node = node->next; + + if(strcmp(cn->name, "texture") == 0) { + // add/change/remove a texture + struct ts_attr *atype = ts_get_attr(cn, "type"); + struct ts_attr *afile = ts_get_attr(cn, "file"); + + int textype = MTL_TEX_DIFFUSE; + if(atype) { + if(atype->val.type == TS_STRING) { + textype = mtl_parse_type(atype->val.str); + } else if(atype->val.type == TS_NUMBER) { + textype = atype->val.inum; + if(textype < 0 || textype >= NUM_MTL_TEXTURES) { + error_log("invalid texture in mtledit: %d\n", textype); + continue; + } + } else { + error_log("unexpected texture type in mtledit: %s\n", atype->val.str); + continue; + } + } + + if(!afile || !afile->val.str || !*afile->val.str) { + // remove + mtl->textures[textype] = 0; + } else { + Texture *tex = texset->get_texture(afile->val.str, TEX_2D); + mtl->add_texture(tex, textype); + } + } + // TODO add more edit modes + } +} + +static bool proc_mtledit(Scene *scn, struct ts_node *node) +{ + if(strcmp(node->name, "mtledit") != 0) { + return false; + } + + const char *mtl_regexp = ".*"; + struct ts_attr *amtl = ts_get_attr(node, "material"); + if(amtl && amtl->val.type == TS_STRING) { + mtl_regexp = amtl->val.str; + } + + // search all the objects to find matching material names + std::regex re{mtl_regexp}; + + int nobj = scn->objects.size(); + for(int i=0; iobjects[i]; + if(std::regex_match(obj->get_name(), re)) { + mtledit(&obj->mtl, scn->texset, node); + } } - datamap_reset(); return true; } diff --git a/src/scene.cc b/src/scene.cc index 0d23930..f116150 100644 --- a/src/scene.cc +++ b/src/scene.cc @@ -61,6 +61,56 @@ static void destroy_node_tree(SceneNode *n) // Scene::load defined in sceneload.cc +bool Scene::merge(Scene *scn) +{ + if(texset != scn->texset) { + // TODO handle this properly + error_log("for now only able to merge scenes using the same texture set\n"); + return false; + } + + if(walk_mesh) { + if(scn->walk_mesh) { + walk_mesh->append(*scn->walk_mesh); + delete scn->walk_mesh; + scn->walk_mesh = 0; + } + } else { + walk_mesh = scn->walk_mesh; + scn->walk_mesh = 0; + } + + int nmeshes = scn->meshes.size(); + for(int i=0; imeshes[i]); + } + scn->meshes.clear(); + + int nobj = scn->objects.size(); + for(int i=0; iobjects[i]); + } + scn->objects.clear(); + + if(nodes) { + int nchildren = scn->nodes ? scn->nodes->get_num_children() : 0; + for(int i=0; inodes->get_child(i); + scn->nodes->remove_child(n); + nodes->add_child(n); + } + if(scn->nodes && scn->nodes->get_num_objects() > 0) { + warning_log("merging with scene which has objects in its root node. these objects will not be merged!\n"); + } + delete scn->nodes; + } else { + nodes = scn->nodes; + } + scn->nodes = 0; + + return true; +} + void Scene::add_object(Object *obj) { objects.push_back(obj); diff --git a/src/scene.h b/src/scene.h index acabd10..a8c8e6a 100644 --- a/src/scene.h +++ b/src/scene.h @@ -36,6 +36,9 @@ public: bool load(const char *fname, unsigned int flags = 0); + // merge scn into this scene, leaving scn empty and safe to destroy + bool merge(Scene *scn); + void add_object(Object *obj); bool remove_object(Object *obj); bool have_object(Object *obj) const; diff --git a/src/sceneload.cc b/src/sceneload.cc index b491cf0..6e959b2 100644 --- a/src/sceneload.cc +++ b/src/sceneload.cc @@ -157,19 +157,12 @@ static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat) continue; } - char *fname; - int nsize = datamap_path_size(aipath.data); - if(nsize) { - fname = new char[nsize]; - datamap_lookup(aipath.data, fname, nsize); - } else { - fname = new char[strlen(aipath.data) + 1]; - char *dptr = fname; - char *sptr = aipath.data; - do { - *dptr++ = *sptr == '\\' ? '/' : *sptr; - } while(*sptr++); - } + char *fname = (char*)alloca(strlen(aipath.data) + 1); + char *dptr = fname; + char *sptr = aipath.data; + do { + *dptr++ = *sptr == '\\' ? '/' : *sptr; + } while(*sptr++); int textype = assimp_textype(aitype); info_log("loading %s texture: %s\n", assimp_textypestr(aitype), fname); diff --git a/src/texture.cc b/src/texture.cc index cbbd11d..c556d27 100644 --- a/src/texture.cc +++ b/src/texture.cc @@ -1,6 +1,7 @@ #include #include #include "texture.h" +#include "datamap.h" #include "image.h" #include "opengl.h" #include "imago2.h" @@ -201,7 +202,6 @@ void Texture::create_default(TextureType type) pixels += 4; } } - default_img->save("/tmp/foo.png"); } switch(type) { @@ -491,8 +491,17 @@ Texture *TextureSet::create_tex() bool TextureSet::load_tex(Texture *tex, const char *fname) { + char *pathbuf; + int nsize = datamap_path_size(fname); + if(nsize) { + pathbuf = (char*)alloca(nsize); + datamap_lookup(fname, pathbuf, nsize); + } else { + pathbuf = (char*)fname; + } + Image *img = new Image; - if(!img->load(fname)) { + if(!img->load(pathbuf)) { delete img; return false; }