From 21f74bf587d9b7a76bc1ee83db02cb8c243dc567 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 2 Dec 2016 03:32:05 +0200 Subject: [PATCH] background scene file loading introduces race condition with datamaps --- src/material.cc | 18 ++++++- src/material.h | 1 + src/metascene.cc | 151 ++++++++++++++++++++++++++++++++++++------------------ src/metascene.h | 5 ++ src/scene.cc | 1 + src/scene.h | 5 +- src/sceneload.cc | 7 ++- 7 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/material.cc b/src/material.cc index f893175..6b10534 100644 --- a/src/material.cc +++ b/src/material.cc @@ -34,13 +34,29 @@ void Material::setup() const void Material::add_texture(Texture *tex, int type) { - textures.push_back(tex); + if(std::find(textures.begin(), textures.end(), tex) == textures.end()) { + textures.push_back(tex); + } if(type != MTL_TEX_UNKNOWN) { stdtex[type] = tex; } } +void Material::remove_texture(Texture *tex) +{ + std::vector::iterator it = std::find(textures.begin(), textures.end(), tex); + if(it != textures.end()) { + textures.erase(it); + } + + for(int i=0; i #include #include "metascene.h" #include "scene.h" @@ -11,9 +12,17 @@ #include #endif +struct MaterialEdit { + std::regex name_re; + int attr; + Texture *tex; +}; + 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 bool proc_mtledit(MaterialEdit *med, struct ts_node *node, TextureSet *texset); +static void apply_mtledit(Scene *scn, const MaterialEdit &med); +static void apply_mtledit(Material *mtl, const MaterialEdit &med); static struct ts_attr *attr_inscope(struct ts_node *node, const char *name); static void print_scene_graph(SceneNode *n, int level); @@ -92,10 +101,19 @@ static bool proc_node(MetaScene *mscn, struct ts_node *node) return true; } + + +struct SceneData { + std::string walkmesh_regexp; + std::vector mtledit; +}; + static bool proc_scenefile(MetaScene *mscn, struct ts_node *node) { const char *fname = ts_get_attr_str(node, "file"); if(fname) { + SceneData *sdat = new SceneData; + // datapath struct ts_attr *adpath = attr_inscope(node, "datapath"); if(adpath && adpath->val.type == TS_STRING) { @@ -104,10 +122,9 @@ static bool proc_scenefile(MetaScene *mscn, struct ts_node *node) } // 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; + sdat->walkmesh_regexp = std::string(awmesh->val.str); } int namesz = datamap_lookup(fname, 0, 0); @@ -116,48 +133,80 @@ static bool proc_scenefile(MetaScene *mscn, struct ts_node *node) fname = namebuf; } - Scene *newscn = new Scene(mscn->texman); - if(!(newscn->load(fname, SCNLOAD_FLIPTEX))) { // TODO unhardcode FLIPTEX - return false; + // material edits + struct ts_node *child = node->child_list; + while(child) { + MaterialEdit medit; + if(proc_mtledit(&medit, child, mscn->texman)) { + sdat->mtledit.push_back(medit); + } + child = child->next; } - // extract the walk mesh if necessary - Scene *wscn; - if(walkmesh_regexp && (wscn = newscn->extract_nodes(walkmesh_regexp))) { - // apply all transformations to the meshes - wscn->apply_xform(); + Scene *newscn = mscn->sceneman->get(fname); + /* NOTE: setting this after get() is not a race condition, because + * scene_loaded() which uses this, will only run in our main loop during + * SceneSet::update() on the main thread. + */ + newscn->metascn = mscn; + mscn->scndata[newscn] = sdat; + } + return true; +} + +bool MetaScene::scene_loaded(Scene *newscn) +{ + SceneData *sdat = (SceneData*)scndata[newscn]; + if(!sdat) { + error_log("MetaScene::scene_loaded called, but corresponding SceneData not found\n"); + return false; + } - int nmeshes = wscn->meshes.size(); - for(int i=0; imeshes[i]; + // extract the walk mesh if necessary + Scene *wscn; + if(!sdat->walkmesh_regexp.empty() && (wscn = newscn->extract_nodes(sdat->walkmesh_regexp.c_str()))) { + // apply all transformations to the meshes + wscn->apply_xform(); - if(mscn->walk_mesh) { - mscn->walk_mesh->append(*m); - } else { - mscn->walk_mesh = m; - wscn->remove_mesh(m); // to save it from destruction - } - } + int nmeshes = wscn->meshes.size(); + for(int i=0; imeshes[i]; - delete wscn; + if(walk_mesh) { + walk_mesh->append(*m); + } else { + walk_mesh = m; + wscn->remove_mesh(m); // to save it from destruction + } } - // 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; - } + delete wscn; + } - mscn->scenes.push_back(newscn); + int num_medits = sdat->mtledit.size(); + for(int i=0; imtledit[i]); } - //datamap_reset(); // TODO this should be push/pop instead of hard reset + scenes.push_back(newscn); return true; } -static void mtledit(Material *mtl, TextureSet *texset, struct ts_node *node) +static bool proc_mtledit(MaterialEdit *med, struct ts_node *node, TextureSet *texset) { + if(strcmp(node->name, "mtledit") != 0) { + return false; + } + + const char *restr = ".*"; + struct ts_attr *amtl = ts_get_attr(node, "material"); + if(amtl && amtl->val.type == TS_STRING) { + restr = amtl->val.str; + } + + med->name_re = std::regex(restr); + node = node->child_list; while(node) { struct ts_node *cn = node; @@ -184,42 +233,44 @@ static void mtledit(Material *mtl, TextureSet *texset, struct ts_node *node) } } + med->attr = textype; + if(!afile || !afile->val.str || !*afile->val.str) { // remove - mtl->textures[textype] = 0; + med->tex = 0; } else { - Texture *tex = texset->get_texture(afile->val.str, TEX_2D); - mtl->add_texture(tex, textype); + med->tex = texset->get_texture(afile->val.str, TEX_2D); } } // TODO add more edit modes } + + return true; } -static bool proc_mtledit(Scene *scn, struct ts_node *node) +static void apply_mtledit(Scene *scn, const MaterialEdit &med) { - 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); + if(std::regex_match(obj->get_name(), med.name_re)) { + apply_mtledit(&obj->mtl, med); } } +} - return true; +static void apply_mtledit(Material *mtl, const MaterialEdit &med) +{ + // TODO more edit modes... + if(med.tex) { + mtl->add_texture(med.tex, med.attr); + } else { + Texture *tex = mtl->stdtex[med.attr]; + if(tex) { + mtl->remove_texture(tex); + } + } } static struct ts_attr *attr_inscope(struct ts_node *node, const char *name) diff --git a/src/metascene.h b/src/metascene.h index e793a39..5d57ee0 100644 --- a/src/metascene.h +++ b/src/metascene.h @@ -1,6 +1,7 @@ #ifndef METASCENE_H_ #define METASCENE_H_ +#include #include "scene.h" #include "mesh.h" @@ -15,10 +16,14 @@ public: Vec3 start_pos; Quat start_rot; + std::map scndata; + + MetaScene(SceneSet *sman, TextureSet *tman); ~MetaScene(); bool load(const char *fname); + bool scene_loaded(Scene *scn); void update(float dt); void draw() const; diff --git a/src/scene.cc b/src/scene.cc index f116150..651e9c6 100644 --- a/src/scene.cc +++ b/src/scene.cc @@ -6,6 +6,7 @@ static void destroy_node_tree(SceneNode *n); Scene::Scene(TextureSet *tset) { + metascn = 0; nodes = 0; walk_mesh = 0; diff --git a/src/scene.h b/src/scene.h index 3712ee6..7489261 100644 --- a/src/scene.h +++ b/src/scene.h @@ -16,11 +16,15 @@ enum { SCNLOAD_STAGE_GL = 0x8000 }; +class MetaScene; + class Scene { private: bool own_texset; public: + MetaScene *metascn; + // meshes objects and nodes are owned by Scene std::vector meshes; std::vector objects; @@ -73,7 +77,6 @@ public: void draw() const; }; - class SceneSet : public DataSet { private: static Scene *create_scene(); diff --git a/src/sceneload.cc b/src/sceneload.cc index 11ce1e1..7e9cade 100644 --- a/src/sceneload.cc +++ b/src/sceneload.cc @@ -17,6 +17,7 @@ #include "objmesh.h" #include "datamap.h" #include "logger.h" +#include "metascene.h" 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); @@ -381,7 +382,11 @@ bool SceneSet::load_scene(Scene *scn, const char *fname) bool SceneSet::done_scene(Scene *scn) { - return scn->load(0, SCNLOAD_STAGE_GL); + bool res = scn->load(0, SCNLOAD_STAGE_GL); + if(scn->metascn) { + scn->metascn->scene_loaded(scn); + } + return res; } void SceneSet::free_scene(Scene *scn) -- 1.7.10.4