From dbcb9345c23c5c027d808915962843e7db2d14aa Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 14 Nov 2016 12:56:40 +0200 Subject: [PATCH 1/1] metadata, walk polygons, stuff... --- src/app.cc | 34 ++++++----- src/app.h | 7 +++ src/main.cc | 26 +++++++++ src/metascene.cc | 102 ++++++++++++++++++++++++++------- src/scene.cc | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/scene.h | 31 +++++++++- src/sceneload.cc | 44 ++------------- src/snode.cc | 34 ++++++++++- src/snode.h | 5 ++ 9 files changed, 362 insertions(+), 86 deletions(-) diff --git a/src/app.cc b/src/app.cc index 2501415..6020947 100644 --- a/src/app.cc +++ b/src/app.cc @@ -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; } } diff --git a/src/app.h b/src/app.h index 0532be1..12b3072 100644 --- 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_ diff --git a/src/main.cc b/src/main.cc index f0ac037..f9c9f3a 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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; + } +} diff --git a/src/metascene.cc b/src/metascene.cc index 99a9daf..aae7482 100644 --- a/src/metascene.cc +++ b/src/metascene.cc @@ -10,8 +10,11 @@ #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; imeshes[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; iget_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; iget_num_children(); i++) { + print_scene_graph(n->get_child(i), level + 1); + } +} diff --git a/src/scene.cc b/src/scene.cc index 8132fe9..0d23930 100644 --- a/src/scene.cc +++ b/src/scene.cc @@ -1,4 +1,6 @@ +#include #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; iget_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::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::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; iget_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 *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; iget_child(i), re); + } +} + +Scene *Scene::extract_nodes(const char *qstr) +{ + std::regex re{qstr}; + + std::list 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; iget_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; iget_child(i)); - } - delete n; -} diff --git a/src/scene.h b/src/scene.h index 808b3e6..acabd10 100644 --- a/src/scene.h +++ b/src/scene.h @@ -2,6 +2,7 @@ #define SCENE_H_ #include +#include #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 meshes; std::vector 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; }; diff --git a/src/sceneload.cc b/src/sceneload.cc index d173538..6fb17d4 100644 --- a/src/sceneload.cc +++ b/src/sceneload.cc @@ -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; iget_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; iget_child(i), lvl + 1); - } -} - static int assimp_textype(aiTextureType type) { switch(type) { diff --git a/src/snode.cc b/src/snode.cc index 101fe62..ffb1d08 100644 --- a/src/snode.cc +++ b/src/snode.cc @@ -2,10 +2,12 @@ #include #include #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; iupdate(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; iapply_xform(); + } + + int nobj = obj.size(); + for(int i=0; iget_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 { diff --git a/src/snode.h b/src/snode.h index 11651c6..5af02f4 100644 --- a/src/snode.h +++ b/src/snode.h @@ -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; }; -- 1.7.10.4