X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmetascene.cc;h=21e9093c56eb90db56a8a4786882f79a7219c083;hb=21f74bf587d9b7a76bc1ee83db02cb8c243dc567;hp=b92e31ff8820775fee430ea7d66757d95cd5ac95;hpb=d4d7f73284783d2a50d71014789d196bef7d0e0e;p=laserbrain_demo diff --git a/src/metascene.cc b/src/metascene.cc index b92e31f..21e9093 100644 --- a/src/metascene.cc +++ b/src/metascene.cc @@ -1,3 +1,4 @@ +#include #include #include "metascene.h" #include "scene.h" @@ -11,14 +12,36 @@ #include #endif -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); +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(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); -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) { @@ -27,20 +50,37 @@ bool load_scene(Scene *scn, const char *fname) return false; } - bool res = proc_node(scn, root); + bool res = proc_node(this, root); ts_free_tree(root); - info_log("loaded scene: %s\n", fname); + /*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; iupdate(dt); + } +} + +void MetaScene::draw() const +{ + int nscn = scenes.size(); + for(int i=0; idraw(); + } +} + +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; @@ -48,7 +88,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"); @@ -61,10 +101,19 @@ static bool proc_node(Scene *scn, struct ts_node *node) return true; } -static bool proc_scenefile(Scene *scn, struct ts_node *node) + + +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) { @@ -73,10 +122,9 @@ static bool proc_scenefile(Scene *scn, 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); @@ -85,49 +133,80 @@ static bool proc_scenefile(Scene *scn, struct ts_node *node) fname = namebuf; } - Scene *newscn = new Scene(scn->texset); - 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; +} - int nmeshes = wscn->meshes.size(); - for(int i=0; imeshes[i]; +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; + } - if(newscn->walk_mesh) { - newscn->walk_mesh->append(*m); - } else { - newscn->walk_mesh = m; - wscn->remove_mesh(m); // to save it from destruction - } - } + // 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(); - delete wscn; - } + int nmeshes = wscn->meshes.size(); + for(int i=0; imeshes[i]; - // 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; + if(walk_mesh) { + walk_mesh->append(*m); + } else { + walk_mesh = m; + wscn->remove_mesh(m); // to save it from destruction + } } - scn->merge(newscn); - delete newscn; + delete wscn; } - //datamap_reset(); // TODO this should be push/pop instead of hard reset + int num_medits = sdat->mtledit.size(); + for(int i=0; imtledit[i]); + } + + 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; @@ -154,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)