X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fexman.cc;h=31ee1aec95457deb536f237c25fd593133c738f6;hp=28f3700c80aad471881484467e282ce2a7bdb686;hb=37b68f014b46922b885c6344d6b069cba3c9c3c5;hpb=b75b6703809abf0dc02f2e557ba73e9efbefa4d1 diff --git a/src/exman.cc b/src/exman.cc index 28f3700..31ee1ae 100644 --- a/src/exman.cc +++ b/src/exman.cc @@ -1,13 +1,112 @@ +#include #include #include "exman.h" #include "exhibit.h" #include "blob_exhibit.h" #include "treestore.h" +#include "app.h" +#include "geomdraw.h" static Exhibit *create_exhibit(const char *type); + +ExhibitSlot::ExhibitSlot(Exhibit *ex) +{ + this->ex = 0; + + init(ex); +} + +ExhibitSlot::~ExhibitSlot() +{ + detach_exhibit(); + + SceneNode *par = node.get_parent(); + if(par) { + par->remove_child(&node); + + while(node.get_num_children()) { + par->add_child(node.get_child(0)); + } + } +} + + +void ExhibitSlot::init(Exhibit *ex) +{ + std::string node_name = "ExhibitSlot"; + if(ex) { + if(ex->get_name()) { + node_name += std::string(":") + std::string(ex->get_name()); + } + + if(ex->node) { + if(ex->node->get_parent()) { + ex->node->get_parent()->add_child(&node); + } + node.set_position(ex->node->get_node_position()); + node.set_rotation(ex->node->get_node_rotation()); + ex->node->set_position(Vec3(0, 0, 0)); + ex->node->set_rotation(Quat::identity); + } + attach_exhibit(ex); + } else { + this->ex = 0; + } + + node.set_name(node_name.c_str()); +} + +bool ExhibitSlot::empty() const +{ + return ex == 0; +} + +Exhibit *ExhibitSlot::get_exhibit() const +{ + return ex; +} + +/* In the process of attaching the exhibit, we also steal the exhibit's node + * from its previous parent, and reparent it to the slot's node. As the slot's + * node itself should have been made a child of the original parent of the + * exhibit during init(), the initial state is we're interjecting a null node in + * the scene graph between the exhibit and its original parent. + * + * Attaching to a slot, implicitly detaches from the previous slot. + */ +bool ExhibitSlot::attach_exhibit(Exhibit *ex, ExSlotAttachMode mode) +{ + if(!ex || this->ex) return false; + + if(ex->prev_slot && ex->prev_slot->ex == ex) { + ex->prev_slot->detach_exhibit(); + } + + if(mode != EXSLOT_ATTACH_TRANSIENT) { + ex->prev_slot = this; + } + + node.add_child(ex->node); + this->ex = ex; + return true; +} + +bool ExhibitSlot::detach_exhibit() +{ + if(!ex) return false; + + node.remove_child(ex->node); + ex = 0; + return true; +} + + +// ---- exhibit manager implementation ---- + ExhibitManager::ExhibitManager() { + own_scn = 0; } ExhibitManager::~ExhibitManager() @@ -17,11 +116,16 @@ ExhibitManager::~ExhibitManager() void ExhibitManager::clear() { - int num = (int)items.size(); + // not deleting exhibit objects, as they will be deleted the own_scn destructor + items.clear(); + + int num = (int)exslots.size(); for(int i=0; i::iterator it = std::find(items.begin(), items.end(), ex); if(it == items.end()) { items.push_back(ex); + own_scn->add_object(ex); + if(ex->node) own_scn->add_node(ex->node); } } @@ -37,6 +143,8 @@ bool ExhibitManager::remove(Exhibit *ex) std::vector::iterator it = std::find(items.begin(), items.end(), ex); if(it != items.end()) { items.erase(it); + own_scn->remove_object(ex); + if(ex->node) own_scn->remove_node(ex->node); return true; } return false; @@ -51,30 +159,103 @@ bool ExhibitManager::load(MetaScene *mscn, const char *fname) return false; } + /* create our own scene to manage all exhibits not already in an existing scene + * and add it to the metascene. + * Also exhibit drawing happens due to the renderer drawing the metascene + */ + if(!own_scn) { + own_scn = new Scene; + own_scn->name = "ad-hoc exhibits"; + mscn->scenes.push_back(own_scn); + } + struct ts_node *iter = root->child_list; while(iter) { struct ts_node *node = iter; iter = iter->next; - if(strcmp(node->name, "item") == 0) { - SceneNode *snode; - - const char *amatch = ts_get_attr_str(node, "match_node"); - if(!amatch || !(snode = mscn->match_node(amatch))) { - error_log("ExhibitManager::load: regexp \"%s\" didn't match any nodes\n", - amatch ? amatch : ""); - continue; - } + SceneNode *snode = 0; + if(strcmp(node->name, "item") == 0) { Exhibit *ex; const char *atype = ts_get_attr_str(node, "type"); if(!atype || !(ex = create_exhibit(atype))) { error_log("failed to create exhibit of type: %s\n", atype); continue; } + const char *alabel = ts_get_attr_str(node, "label"); + if(alabel) { + ex->set_name(alabel); + } + const char *amatch = ts_get_attr_str(node, "match_node"); + if(amatch) { + if(!(snode = mscn->match_node(amatch))) { + error_log("ExhibitManager::load: regexp \"%s\" didn't match any nodes\n", + amatch ? amatch : ""); + continue; + } + } + + // add everything to our data structures + // equivalent to add_exhibit(ex), but without all the searching + own_scn->add_object(ex); + if(!snode) { + snode = new SceneNode; + snode->set_name(ex->get_name()); + own_scn->add_node(snode); + } ex->set_node(snode); items.push_back(ex); + + float *apos = ts_get_attr_vec(node, "pos"); + if(apos) { + snode->set_position(Vec3(apos[0], apos[1], apos[2])); + } + float *arot_axis = ts_get_attr_vec(node, "rotaxis"); + if(arot_axis) { + float arot_angle = ts_get_attr_num(node, "rotangle", 0.0f); + Vec3 axis = Vec3(arot_axis[0], arot_axis[1], arot_axis[2]); + Quat q; + q.set_rotation(axis, deg_to_rad(arot_angle)); + snode->set_rotation(q); + } + struct ts_attr *ascale = ts_get_attr(node, "scale"); + if(ascale) { + switch(ascale->val.type) { + case TS_NUMBER: + snode->set_scaling(Vec3(ascale->val.fnum, ascale->val.fnum, ascale->val.fnum)); + break; + case TS_VECTOR: + snode->set_scaling(Vec3(ascale->val.vec[0], ascale->val.vec[1], ascale->val.vec[2])); + default: + break; + } + } + + // create a new slot and attach the exhibit to it + ExhibitSlot *slot = new ExhibitSlot(ex); + exslots.push_back(slot); + + // grab any extra exhibit data + const char *desc = ts_get_attr_str(node, "description"); + const char *voice = ts_get_attr_str(node, "voiceover"); + if(desc || voice) { + ExData exd; + + if(desc) { + exd.text = std::string(desc); + } + if(voice) { + exd.voice = new OggVorbisStream; + if(!exd.voice->open(voice)) { + error_log("failed to open voiceover: %s\n", voice); + delete exd.voice; + exd.voice = 0; + } + } + ex->data.push_back(exd); + } } } @@ -84,18 +265,76 @@ bool ExhibitManager::load(MetaScene *mscn, const char *fname) ExSelection ExhibitManager::select(const Ray &ray) const { - return ExSelection(); // TODO + ExSelection nearest; + nearest.dist = FLT_MAX; + + int nitems = items.size(); + for(int i=0; iselect(ray); + if(sel && sel.dist < nearest.dist) { + nearest = sel; + } + } + + return nearest; } ExSelection ExhibitManager::select(const Sphere &sph) const { - return ExSelection(); // TODO + ExSelection sel; + if(!items.empty()) { + sel.ex = items[0]; + sel.selsphere = sph; + sel.validmask = EXSEL_SPHERE; + } + return sel; // TODO +} + +// TODO optimize +ExhibitSlot *ExhibitManager::nearest_empty_slot(const Vec3 &pos, float max_dist) const +{ + ExhibitSlot *nearest = 0; + float nearest_sqdist = max_dist * max_dist; + + int nslots = exslots.size(); + for(int i=0; iempty()) continue; + + Vec3 slotpos = slot->node.get_position(); + float dsq = length_sq(pos - slotpos); + if(dsq < nearest_sqdist) { + nearest = slot; + nearest_sqdist = dsq; + } + } + + return nearest; +} + +void ExhibitManager::stash_exhibit(Exhibit *ex) +{ + // make sure it's not already stashed + if(std::find(stashed.begin(), stashed.end(), ex) != stashed.end()) { + return; + } + stashed.push_back(ex); + + ex->prev_slot = 0; + if(ex->node->get_parent()) { + ex->node->get_parent()->remove_child(ex->node); + } } void ExhibitManager::update(float dt) { int num = items.size(); for(int i=0; inode && !items[i]->node->get_parent()) { + items[i]->node->update(dt); + } items[i]->update(dt); } } @@ -104,9 +343,10 @@ void ExhibitManager::draw() const { int num = items.size(); for(int i=0; ipre_draw(); - items[i]->draw(); - items[i]->post_draw(); + if(exsel_hover.ex == items[i]) { + const AABox &bvol = items[i]->get_aabox(); + draw_geom_object(&bvol); + } } } @@ -117,7 +357,13 @@ static Exhibit *create_exhibit(const char *type) return new Exhibit; } else if(strcmp(type, "blobs") == 0) { debug_log("creating blobs exhibit\n"); - return new BlobExhibit; + BlobExhibit *b = new BlobExhibit; + if(!b->init()) { + delete b; + error_log("failed to initialize blobs exhibit\n"); + return 0; + } + return b; } error_log("unknown exhibit type: %s\n", type); return 0;