MetaScene class
[laserbrain_demo] / src / metascene.cc
index aae7482..65c9d66 100644 (file)
@@ -1,7 +1,9 @@
+#include <regex>
 #include "metascene.h"
 #include "scene.h"
 #include "datamap.h"
 #include "treestore.h"
+#include "logger.h"
 
 #ifdef WIN32
 #include <malloc.h>
 #include <alloca.h>
 #endif
 
-static bool proc_node(Scene *scn, struct ts_node *node);
-static bool proc_scenefile(Scene *scn, struct ts_node *node);
+static bool proc_node(MetaScene *mscn, struct ts_node *node);
+static bool proc_scenefile(MetaScene *mscn, 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);
 
-bool load_scene(Scene *scn, const char *fname)
+
+MetaScene::MetaScene(SceneSet *sman, TextureSet *tman)
+{
+       sceneman = sman;
+       texman = tman;
+       walk_mesh = 0;
+}
+
+MetaScene::~MetaScene()
+{
+       delete walk_mesh;
+}
+
+
+bool MetaScene::load(const char *fname)
 {
        struct ts_node *root = ts_load(fname);
        if(!root || strcmp(root->name, "scene") != 0) {
                ts_free_tree(root);
-               fprintf(stderr, "failed to load scene metadata: %s\n", fname);
+               error_log("failed to load scene metadata: %s\n", fname);
                return false;
        }
 
-       bool res = proc_node(scn, root);
+       bool res = proc_node(this, root);
        ts_free_tree(root);
 
-       printf("loaded scene: %s\n", fname);
-       printf("scene graph:\n");
+       /*info_log("loaded scene: %s\n", fname);
+       info_log("scene graph:\n");
        print_scene_graph(scn->nodes, 0);
+       */
        return res;
 }
 
-static bool proc_node(Scene *scn, struct ts_node *node)
+void MetaScene::update(float dt)
+{
+       int nscn = scenes.size();
+       for(int i=0; i<nscn; i++) {
+               scenes[i]->update(dt);
+       }
+}
+
+void MetaScene::draw() const
+{
+       int nscn = scenes.size();
+       for(int i=0; i<nscn; i++) {
+               scenes[i]->draw();
+       }
+}
+
+static bool proc_node(MetaScene *mscn, struct ts_node *node)
 {
        struct ts_node *c = node->child_list;
        while(c) {
-               if(!proc_node(scn, c)) {
+               if(!proc_node(mscn, c)) {
                        return false;
                }
                c = c->next;
@@ -45,7 +79,7 @@ static bool proc_node(Scene *scn, struct ts_node *node)
 
        // do this last to allow other contents of the node to do their thing
        if(strcmp(node->name, "scenefile") == 0) {
-               return proc_scenefile(scn, node);
+               return proc_scenefile(mscn, node);
 
        } else if(strcmp(node->name, "remap") == 0) {
                const char *match = ts_get_attr_str(node, "match");
@@ -58,14 +92,14 @@ static bool proc_node(Scene *scn, struct ts_node *node)
        return true;
 }
 
-static bool proc_scenefile(Scene *scn, struct ts_node *node)
+static bool proc_scenefile(MetaScene *mscn, struct ts_node *node)
 {
        const char *fname = ts_get_attr_str(node, "file");
        if(fname) {
                // datapath
                struct ts_attr *adpath = attr_inscope(node, "datapath");
                if(adpath && adpath->val.type == TS_STRING) {
-                       printf("adding data path: %s\n", adpath->val.str);
+                       info_log("adding data path: %s\n", adpath->val.str);
                        datamap_set_path(adpath->val.str);
                }
 
@@ -82,14 +116,14 @@ static bool proc_scenefile(Scene *scn, struct ts_node *node)
                        fname = namebuf;
                }
 
-               if(!(scn->load(fname, SCNLOAD_FLIPTEX))) {
+               Scene *newscn = new Scene(mscn->texman);
+               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();
 
@@ -97,18 +131,93 @@ 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(mscn->walk_mesh) {
+                                       mscn->walk_mesh->append(*m);
                                } else {
-                                       scn->walk_mesh = m;
+                                       mscn->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;
+               }
+
+               mscn->scenes.push_back(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;
 }
@@ -128,14 +237,14 @@ static void print_scene_graph(SceneNode *n, int level)
        if(!n) return;
 
        for(int i=0; i<level; i++) {
-               fputs("  ", stdout);
+               info_log("  ");
        }
 
        int nobj = n->get_num_objects();
        if(nobj) {
-               printf("%s - %d obj\n", n->get_name(), n->get_num_objects());
+               info_log("%s - %d obj\n", n->get_name(), n->get_num_objects());
        } else {
-               printf("%s\n", n->get_name());
+               info_log("%s\n", n->get_name());
        }
 
        for(int i=0; i<n->get_num_children(); i++) {