metadata, walk polygons, stuff...
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 14 Nov 2016 10:56:40 +0000 (12:56 +0200)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 14 Nov 2016 10:56:40 +0000 (12:56 +0200)
src/app.cc
src/app.h
src/main.cc
src/metascene.cc
src/scene.cc
src/scene.h
src/sceneload.cc
src/snode.cc
src/snode.h

index 2501415..6020947 100644 (file)
@@ -15,6 +15,7 @@ static void draw_scene();
 long time_msec;
 int win_width, win_height;
 bool opt_gear_wireframe;
+bool show_walk_mesh;
 
 static float cam_dist = 0.0;
 static float cam_theta, cam_phi = 20;
@@ -50,20 +51,6 @@ bool app_init()
                return false;
        }
 
-       /*
-       datamap_set_path("data");
-       if(!datamap_load_map("data.map")) {
-               fprintf(stderr, "failed to load datafile mappings\n");
-       }
-
-       unsigned int sflags = SCNLOAD_FLIPTEX;
-       if(!(scn->load("data/testscene/patoma.fbx", sflags)) ||
-                       !(scn->load("data/testscene/kolones.fbx", sflags))) {
-               fprintf(stderr, "failed to load test scene\n");
-               return false;
-       }
-       */
-
        if(!(sdr = create_program_load("sdr/test.v.glsl", "sdr/test.p.glsl"))) {
                fprintf(stderr, "failed to load test shaders\n");
                return false;
@@ -170,6 +157,18 @@ static void draw_scene()
        glUseProgram(sdr);
        scn->draw();
        glUseProgram(0);
+
+       if(show_walk_mesh && scn->walk_mesh) {
+               glPushAttrib(GL_ENABLE_BIT);
+               glEnable(GL_BLEND);
+               glBlendFunc(GL_ONE, GL_ONE);
+               glDisable(GL_LIGHTING);
+
+               glColor3f(0.5, 0.4, 0.05);
+               scn->walk_mesh->draw();
+
+               glPopAttrib();
+       }
 }
 
 
@@ -185,10 +184,17 @@ void app_reshape(int x, int y)
 void app_keyboard(int key, bool pressed)
 {
        if(pressed) {
+               printf("key: %d (mod: %x)\n", key, app_get_modifiers());
                switch(key) {
                case 27:
                        app_quit();
                        break;
+
+               case 'w':
+                       if(app_get_modifiers() & MOD_CTRL) {
+                               show_walk_mesh = !show_walk_mesh;
+                       }
+                       break;
                }
        }
 
index 0532be1..12b3072 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -5,6 +5,12 @@ extern long time_msec;
 extern int win_width, win_height;
 extern bool opt_gear_wireframe;
 
+enum {
+       MOD_SHIFT       = 1,
+       MOD_ALT         = 2,
+       MOD_CTRL        = 4
+};
+
 bool app_init();
 void app_cleanup();
 
@@ -18,5 +24,6 @@ void app_mouse_motion(int x, int y);
 // the following functions are implemented by the backend (main.cc)
 void app_quit();
 void app_swap_buffers();
+unsigned int app_get_modifiers();
 
 #endif // APP_H_
index f0ac037..f9c9f3a 100644 (file)
@@ -16,8 +16,10 @@ static void reshape(int x, int y);
 static void key_press(unsigned char key, int x, int y);
 static void key_release(unsigned char key, int x, int y);
 static void mouse(int bn, int st, int x, int y);
+static void proc_modkeys();
 
 static unsigned int start_time;
+static unsigned int modkeys;
 
 int main(int argc, char **argv)
 {
@@ -54,6 +56,11 @@ void app_quit()
        exit(0);
 }
 
+unsigned int app_get_modifiers()
+{
+       return modkeys;
+}
+
 static bool init()
 {
        glewInit();
@@ -87,11 +94,13 @@ static void reshape(int x, int y)
 
 static void key_press(unsigned char key, int x, int y)
 {
+       proc_modkeys();
        app_keyboard(key, true);
 }
 
 static void key_release(unsigned char key, int x, int y)
 {
+       proc_modkeys();
        app_keyboard(key, false);
 }
 
@@ -100,5 +109,22 @@ static void mouse(int bn, int st, int x, int y)
        int bidx = bn - GLUT_LEFT_BUTTON;
        bool down = st == GLUT_DOWN;
 
+       proc_modkeys();
        app_mouse_button(bidx, down, x, y);
 }
+
+static void proc_modkeys()
+{
+       int glutmod = glutGetModifiers();
+
+       modkeys = 0;
+       if(glutmod & GLUT_ACTIVE_SHIFT) {
+               modkeys |= MOD_SHIFT;
+       }
+       if(glutmod & GLUT_ACTIVE_CTRL) {
+               modkeys |= MOD_CTRL;
+       }
+       if(glutmod & GLUT_ACTIVE_ALT) {
+               modkeys |= MOD_ALT;
+       }
+}
index 99a9daf..aae7482 100644 (file)
 #endif
 
 static bool proc_node(Scene *scn, struct ts_node *node);
+static bool proc_scenefile(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)
 {
        struct ts_node *root = ts_load(fname);
@@ -23,6 +26,10 @@ bool load_scene(Scene *scn, const char *fname)
 
        bool res = proc_node(scn, root);
        ts_free_tree(root);
+
+       printf("loaded scene: %s\n", fname);
+       printf("scene graph:\n");
+       print_scene_graph(scn->nodes, 0);
        return res;
 }
 
@@ -38,25 +45,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) {
-               const char *fname = ts_get_attr_str(node, "file");
-               if(fname) {
-                       struct ts_attr *adpath = attr_inscope(node, "datapath");
-                       if(adpath && adpath->val.type == TS_STRING) {
-                               printf("adding data path: %s\n", adpath->val.str);
-                               datamap_set_path(adpath->val.str);
-                       }
-
-                       int namesz = datamap_lookup(fname, 0, 0);
-                       char *namebuf = (char*)alloca(namesz + 1);
-                       if(datamap_lookup(fname, namebuf, namesz + 1)) {
-                               fname = namebuf;
-                       }
-
-                       if(!(scn->load(fname, SCNLOAD_FLIPTEX))) {
-                               return false;
-                       }
-               }
-               datamap_reset();
+               return proc_scenefile(scn, node);
 
        } else if(strcmp(node->name, "remap") == 0) {
                const char *match = ts_get_attr_str(node, "match");
@@ -69,6 +58,61 @@ static bool proc_node(Scene *scn, struct ts_node *node)
        return true;
 }
 
+static bool proc_scenefile(Scene *scn, 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);
+                       datamap_set_path(adpath->val.str);
+               }
+
+               // walkmesh
+               char *walkmesh_regexp = 0;
+               struct ts_attr *awmesh = attr_inscope(node, "walkmesh");
+               if(awmesh && awmesh->val.type == TS_STRING) {
+                       walkmesh_regexp = awmesh->val.str;
+               }
+
+               int namesz = datamap_lookup(fname, 0, 0);
+               char *namebuf = (char*)alloca(namesz + 1);
+               if(datamap_lookup(fname, namebuf, namesz + 1)) {
+                       fname = namebuf;
+               }
+
+               if(!(scn->load(fname, SCNLOAD_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))) {
+                       // apply all transformations to the meshes
+                       wscn->apply_xform();
+
+                       int nmeshes = wscn->meshes.size();
+                       for(int i=0; i<nmeshes; i++) {
+                               Mesh *m = wscn->meshes[i];
+
+                               if(scn->walk_mesh) {
+                                       scn->walk_mesh->append(*m);
+                               } else {
+                                       scn->walk_mesh = m;
+                                       wscn->remove_mesh(m);   // to save it from destruction
+                               }
+                       }
+
+                       delete wscn;
+               }
+       }
+       datamap_reset();
+
+       return true;
+}
+
 static struct ts_attr *attr_inscope(struct ts_node *node, const char *name)
 {
        struct ts_attr *attr = 0;
@@ -78,3 +122,23 @@ static struct ts_attr *attr_inscope(struct ts_node *node, const char *name)
        }
        return attr;
 }
+
+static void print_scene_graph(SceneNode *n, int level)
+{
+       if(!n) return;
+
+       for(int i=0; i<level; i++) {
+               fputs("  ", stdout);
+       }
+
+       int nobj = n->get_num_objects();
+       if(nobj) {
+               printf("%s - %d obj\n", n->get_name(), n->get_num_objects());
+       } else {
+               printf("%s\n", n->get_name());
+       }
+
+       for(int i=0; i<n->get_num_children(); i++) {
+               print_scene_graph(n->get_child(i), level + 1);
+       }
+}
index 8132fe9..0d23930 100644 (file)
@@ -1,4 +1,6 @@
+#include <regex>
 #include "scene.h"
+#include "objmesh.h"
 
 static void destroy_node_tree(SceneNode *n);
 
@@ -6,6 +8,8 @@ Scene::Scene(TextureSet *tset)
 {
        nodes = 0;
 
+       walk_mesh = 0;
+
        if(tset) {
                texset = tset;
                own_texset = false;
@@ -25,14 +29,164 @@ void Scene::destroy()
        destroy_node_tree(nodes);
        nodes = 0;
 
+       for(int i=0; i<(int)meshes.size(); i++) {
+               delete meshes[i];
+       }
+       meshes.clear();
+
+       delete walk_mesh;
+       walk_mesh = 0;
+
+       for(int i=0; i<(int)objects.size(); i++) {
+               delete objects[i];
+       }
+       objects.clear();
+
        if(own_texset) {
                delete texset;
        }
        texset = 0;
 }
 
+static void destroy_node_tree(SceneNode *n)
+{
+       if(!n) return;
+
+       int nsub = n->get_num_children();
+       for(int i=0; i<nsub; i++) {
+               destroy_node_tree(n->get_child(i));
+       }
+       delete n;
+}
+
 // Scene::load defined in sceneload.cc
 
+void Scene::add_object(Object *obj)
+{
+       objects.push_back(obj);
+}
+
+bool Scene::remove_object(Object *obj)
+{
+       std::vector<Object*>::iterator it = std::find(objects.begin(), objects.end(), obj);
+       if(it != objects.end()) {
+               objects.erase(it);
+               return true;
+       }
+       return false;
+}
+
+bool Scene::have_object(Object *obj) const
+{
+       return std::find(objects.begin(), objects.end(), obj) != objects.end();
+}
+
+void Scene::add_mesh(Mesh *m)
+{
+       meshes.push_back(m);
+}
+
+bool Scene::remove_mesh(Mesh *m)
+{
+       std::vector<Mesh*>::iterator it = std::find(meshes.begin(), meshes.end(), m);
+       if(it != meshes.end()) {
+               meshes.erase(it);
+               return true;
+       }
+       return false;
+}
+
+bool Scene::have_mesh(Mesh *m) const
+{
+       return std::find(meshes.begin(), meshes.end(), m) != meshes.end();
+}
+
+void Scene::add_node(SceneNode *n)
+{
+       // we always want to have a dedicated root node
+       if(!nodes) {
+               nodes = new SceneNode;
+               nodes->scene = this;
+               nodes->set_name("root");
+       }
+
+       nodes->add_child(n);
+}
+
+bool Scene::remove_node(SceneNode *n)
+{
+       SceneNode *par;
+       if(!n || !(par = n->get_parent())) {
+               return false;
+       }
+
+       int nsub = n->get_num_children();
+       for(int i=0; i<nsub; i++) {
+               SceneNode *c = n->get_child(i);
+               n->remove_child(c);
+               par->add_child(c);
+       }
+
+       return par->remove_child(n);
+}
+
+bool Scene::have_node(SceneNode *n) const
+{
+       return n->scene == this;
+}
+
+static void find_nodes_rec(std::list<SceneNode*> *res, SceneNode *tree, const std::regex &re)
+{
+       if(std::regex_match(tree->get_name(), re)) {
+               res->push_back(tree);
+       }
+
+       int num = tree->get_num_children();
+       for(int i=0; i<num; i++) {
+               find_nodes_rec(res, tree->get_child(i), re);
+       }
+}
+
+Scene *Scene::extract_nodes(const char *qstr)
+{
+       std::regex re{qstr};
+
+       std::list<SceneNode*> nodelist;
+       find_nodes_rec(&nodelist, nodes, re);
+       if(nodelist.empty()) {
+               return 0;
+       }
+
+       Scene *res = new Scene(texset);
+
+       for(SceneNode *n : nodelist) {
+
+               int nobj = n->get_num_objects();
+               for(int i=0; i<nobj; i++) {
+                       Object *obj = n->get_object(i);
+                       if(obj->get_type() == OBJ_MESH) {
+                               // XXX this assumes that meshes aren't shared between objects.
+                               // maybe we'll have to refcount them at some point, and copy if nref>1
+                               ObjMesh *om = (ObjMesh*)obj;
+                               remove_mesh(om->mesh);
+                               res->add_mesh(om->mesh);
+                       }
+
+                       remove_object(obj);
+                       res->add_object(obj);
+               }
+
+               remove_node(n);
+               res->add_node(n);
+       }
+       return res;
+}
+
+void Scene::apply_xform()
+{
+       nodes->apply_xform();
+}
+
 void Scene::update(float dt)
 {
        if(nodes) {
@@ -63,14 +217,3 @@ void Scene::draw() const
                }
        }
 }
-
-static void destroy_node_tree(SceneNode *n)
-{
-       if(!n) return;
-
-       int nsub = n->get_num_children();
-       for(int i=0; i<nsub; i++) {
-               destroy_node_tree(n->get_child(i));
-       }
-       delete n;
-}
index 808b3e6..acabd10 100644 (file)
@@ -2,6 +2,7 @@
 #define SCENE_H_
 
 #include <vector>
+#include <list>
 #include "mesh.h"
 #include "snode.h"
 #include "texture.h"
@@ -16,11 +17,14 @@ private:
        bool own_texset;
 
 public:
+       // meshes objects and nodes are owned by Scene
        std::vector<Mesh*> meshes;
        std::vector<Object*> objects;
        SceneNode *nodes;
 
-       TextureSet *texset;
+       Mesh *walk_mesh;
+
+       TextureSet *texset;     // only owned by Scene if own_texset is true
 
        explicit Scene(TextureSet *tset = 0);
        ~Scene();
@@ -32,6 +36,31 @@ public:
 
        bool load(const char *fname, unsigned int flags = 0);
 
+       void add_object(Object *obj);
+       bool remove_object(Object *obj);
+       bool have_object(Object *obj) const;
+
+       void add_mesh(Mesh *m);
+       bool remove_mesh(Mesh *m);
+       bool have_mesh(Mesh *m) const;
+
+       void add_node(SceneNode *n);
+       bool remove_node(SceneNode *n);
+       bool have_node(SceneNode *n) const;
+
+       /* find and remove all nodes whose names match the regexp
+        * XXX at the moment this has the effect of flattening the hierarchy in the
+        * result scene. If we ever need verbatim extraction of whole subtrees we'll
+        * need to change the algorithm.
+        */
+       Scene *extract_nodes(const char *qstr);
+
+       /* bake all node transformations to their respective meshes and make the
+        * node transformations identity.
+        * XXX this assumes no mesh is shared by two nodes.
+        */
+       void apply_xform();
+
        void update(float dt);
        void draw() const;
 };
index d173538..6fb17d4 100644 (file)
@@ -19,7 +19,6 @@
 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat);
 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode);
 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh);
-static void print_nodes(SceneNode *node, int lvl = 0);
 /*static const char *mprop_semantic(int x);
 static int count_textures(const aiMaterial *aimat);*/
 static int assimp_textype(aiTextureType type);
@@ -68,11 +67,6 @@ bool Scene::load(const char *fname, unsigned int flags)
                root_pos = root_matrix.get_translation();
                root_rot = root_matrix.get_rotation();
                root_scaling = root_matrix.get_scaling();
-
-               printf("assimp root node: %s\n", aiscn->mRootNode->mName.data);
-               printf("  pos: %f %f %f\n", root_pos.x, root_pos.y, root_pos.z);
-               printf("  rot: %f %+f %+f %+f\n", root_rot.w, root_rot.x, root_rot.y, root_rot.z);
-               printf("  scaling: %f %f %f\n", root_scaling.x, root_scaling.y, root_scaling.z);
        }
 
        // load all meshes
@@ -96,6 +90,7 @@ bool Scene::load(const char *fname, unsigned int flags)
 
        if(!nodes) {
                nodes = new SceneNode;
+               nodes->scene = this;
                nodes->set_name("root");
                nodes->set_position(root_pos);
                nodes->set_rotation(root_rot);
@@ -116,7 +111,6 @@ bool Scene::load(const char *fname, unsigned int flags)
        aiReleaseImport(aiscn);
        printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
        nodes->update(0);
-       print_nodes(nodes);
        return true;
 }
 
@@ -131,7 +125,7 @@ static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
        } else {
                mat->name = "unknown";
        }
-       printf("load_material: %s\n", mat->name.c_str());
+       //printf("load_material: %s\n", mat->name.c_str());
 
        if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
                mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
@@ -183,8 +177,6 @@ static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
                        assert(tex);
                        mat->textures.push_back(tex);
 
-                       printf("   DBG(%p)\n", (void*)tex);
-
                        if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) {
                                mat->stdtex[textype] = tex;
                        }
@@ -217,6 +209,7 @@ static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags
                Mesh *mesh = mesh_by_aimesh[aimesh];
                if(mesh) {
                        ObjMesh *obj = new ObjMesh;
+                       obj->set_name(mesh->get_name());
                        obj->mesh = mesh;
                        // also grab the material of this mesh
                        load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
@@ -241,6 +234,7 @@ static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags
 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
 {
        Mesh *mesh = new Mesh;
+       mesh->set_name(aimesh->mName.data);
 
        int num_verts = aimesh->mNumVertices;
        int num_faces = aimesh->mNumFaces;
@@ -287,39 +281,9 @@ static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, con
                iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
                iptr += 3;
        }
-
-       AABox bbox = mesh->get_aabbox();
-       printf("mesh bounding box: %f %f %f -> %f %f %f\n", bbox.min.x, bbox.min.y, bbox.min.z,
-                       bbox.max.x, bbox.max.y, bbox.max.z);
-
        return mesh;
 }
 
-static void print_nodes(SceneNode *node, int lvl)
-{
-       Vec3 pos = node->get_node_position();
-       Quat rot = node->get_node_rotation();
-       Vec3 scale = node->get_node_scaling();
-
-       const char *type = node->get_num_objects() > 0 ? "mesh node" : "null node";
-
-       for(int i=0; i<lvl; i++) {
-               fputs("  ", stdout);
-       }
-       printf("%s[%s] p(%g %g %g) rq(%g %+gi %+gj %+gk) s(%g %g %g)\n", type, node->get_name(),
-                       pos.x, pos.y, pos.z, rot.w, rot.x, rot.y, rot.z, scale.x, scale.y, scale.z);
-
-       if(node->get_num_objects()) {
-               Mat4 xform = node->get_matrix();
-               xform.print(stdout);
-       }
-
-       int nchld = node->get_num_children();
-       for(int i=0; i<nchld; i++) {
-               print_nodes(node->get_child(i), lvl + 1);
-       }
-}
-
 static int assimp_textype(aiTextureType type)
 {
        switch(type) {
index 101fe62..ffb1d08 100644 (file)
@@ -2,10 +2,12 @@
 #include <assert.h>
 #include <algorithm>
 #include "snode.h"
+#include "objmesh.h"
 
 SceneNode::SceneNode()
        : scale(1, 1, 1)
 {
+       scene = 0;
        parent = 0;
        name = 0;
 }
@@ -13,6 +15,7 @@ SceneNode::SceneNode()
 SceneNode::SceneNode(Object *obj)
        : scale(1, 1, 1)
 {
+       scene = 0;
        parent = 0;
        name = 0;
        add_object(obj);
@@ -48,6 +51,7 @@ void SceneNode::add_child(SceneNode *node)
 
        children.push_back(node);
        node->parent = this;
+       node->scene = scene;
 }
 
 bool SceneNode::remove_child(SceneNode *node)
@@ -58,6 +62,8 @@ bool SceneNode::remove_child(SceneNode *node)
        if(it != children.end()) {
                assert(node->parent == this);
                node->parent = 0;
+               node->scene = 0;
+               children.erase(it);
                return true;
        }
        return false;
@@ -190,11 +196,37 @@ void SceneNode::update(float dt)
 {
        update_node(dt);
 
-       for(size_t i=0; i<children.size(); i++) {
+       int num = children.size();
+       for(int i=0; i<num; i++) {
                children[i]->update(dt);
        }
 }
 
+void SceneNode::apply_xform()
+{
+       update_node();
+
+       // apply post-order to make sure we don't affect the children xform by our reset
+
+       int nchild = children.size();
+       for(int i=0; i<nchild; i++) {
+               children[i]->apply_xform();
+       }
+
+       int nobj = obj.size();
+       for(int i=0; i<nobj; i++) {
+               if(obj[i]->get_type() == OBJ_MESH) {
+                       ObjMesh *om = (ObjMesh*)obj[i];
+                       if(om->mesh) {
+                               om->mesh->apply_xform(xform);
+                       }
+               }
+       }
+
+       pos = Vec3(0, 0, 0);
+       rot = Quat::identity;
+       scale = Vec3(1, 1, 1);
+}
 
 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
 {
index 11651c6..5af02f4 100644 (file)
@@ -5,6 +5,8 @@
 #include "object.h"
 #include "gmath/gmath.h"
 
+class Scene;
+
 class SceneNode {
 private:
        char *name;
@@ -22,6 +24,7 @@ private:
        Mat4 inv_xform;
 
 public:
+       Scene *scene;   // scene to which this node belongs
        Mat4 dbg_xform;
 
        SceneNode();
@@ -63,6 +66,8 @@ public:
        void update_node(float dt = 0.0f);
        void update(float dt = 0.0f);
 
+       void apply_xform();
+
        bool intersect(const Ray &ray, HitPoint *hit) const;
 };