material editing in scene metafile
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Tue, 29 Nov 2016 16:45:16 +0000 (18:45 +0200)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Tue, 29 Nov 2016 16:45:16 +0000 (18:45 +0200)
src/material.cc
src/material.h
src/metascene.cc
src/scene.cc
src/scene.h
src/sceneload.cc
src/texture.cc

index 0aa83cd..f893175 100644 (file)
@@ -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";
+}
index 979bbd9..5cf3533 100644 (file)
@@ -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_
index cf4d788..b92e31f 100644 (file)
@@ -1,3 +1,4 @@
+#include <regex>
 #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; i<nmeshes; i++) {
                                Mesh *m = wscn->meshes[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; i<nobj; i++) {
+               Object *obj = scn->objects[i];
+               if(std::regex_match(obj->get_name(), re)) {
+                       mtledit(&obj->mtl, scn->texset, node);
+               }
        }
-       datamap_reset();
 
        return true;
 }
index 0d23930..f116150 100644 (file)
@@ -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; i<nmeshes; i++) {
+               meshes.push_back(scn->meshes[i]);
+       }
+       scn->meshes.clear();
+
+       int nobj = scn->objects.size();
+       for(int i=0; i<nobj; i++) {
+               objects.push_back(scn->objects[i]);
+       }
+       scn->objects.clear();
+
+       if(nodes) {
+               int nchildren = scn->nodes ? scn->nodes->get_num_children() : 0;
+               for(int i=0; i<nchildren; i++) {
+                       SceneNode *n = scn->nodes->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);
index acabd10..a8c8e6a 100644 (file)
@@ -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;
index b491cf0..6e959b2 100644 (file)
@@ -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);
index cbbd11d..c556d27 100644 (file)
@@ -1,6 +1,7 @@
 #include <math.h>
 #include <assert.h>
 #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;
        }