5 #include "blob_exhibit.h"
8 static Exhibit *create_exhibit(const char *type);
11 ExhibitSlot::ExhibitSlot(Exhibit *ex)
18 ExhibitSlot::~ExhibitSlot()
22 SceneNode *par = node.get_parent();
24 par->remove_child(&node);
26 while(node.get_num_children()) {
27 par->add_child(node.get_child(0));
33 void ExhibitSlot::init(Exhibit *ex)
35 std::string node_name = "ExhibitSlot";
38 node_name += std::string(":") + std::string(ex->get_name());
42 if(ex->node->get_parent()) {
43 ex->node->get_parent()->add_child(&node);
45 node.set_position(ex->node->get_node_position());
46 node.set_rotation(ex->node->get_node_rotation());
47 ex->node->set_position(Vec3(0, 0, 0));
48 ex->node->set_rotation(Quat::identity);
55 node.set_name(node_name.c_str());
58 bool ExhibitSlot::empty() const
63 Exhibit *ExhibitSlot::get_exhibit() const
68 /* In the process of attaching the exhibit, we also steal the exhibit's node
69 * from its previous parent, and reparent it to the slot's node. As the slot's
70 * node itself should have been made a child of the original parent of the
71 * exhibit during init(), the initial state is we're interjecting a null node in
72 * the scene graph between the exhibit and its original parent.
74 * Attaching to a slot, implicitly detaches from the previous slot.
76 bool ExhibitSlot::attach_exhibit(Exhibit *ex, ExSlotAttachMode mode)
78 if(!ex || this->ex) return false;
80 if(ex->prev_slot && ex->prev_slot->ex == ex) {
81 ex->prev_slot->detach_exhibit();
84 if(mode != EXSLOT_ATTACH_TRANSIENT) {
88 node.add_child(ex->node);
93 bool ExhibitSlot::detach_exhibit()
97 node.remove_child(ex->node);
103 // ---- exhibit manager implementation ----
105 ExhibitManager::ExhibitManager()
109 ExhibitManager::~ExhibitManager()
114 void ExhibitManager::clear()
116 int num = (int)items.size();
117 for(int i=0; i<num; i++) {
122 num = (int)exslots.size();
123 for(int i=0; i<num; i++) {
129 void ExhibitManager::add(Exhibit *ex)
131 std::vector<Exhibit*>::iterator it = std::find(items.begin(), items.end(), ex);
132 if(it == items.end()) {
137 bool ExhibitManager::remove(Exhibit *ex)
139 std::vector<Exhibit*>::iterator it = std::find(items.begin(), items.end(), ex);
140 if(it != items.end()) {
147 bool ExhibitManager::load(MetaScene *mscn, const char *fname)
149 struct ts_node *root = ts_load(fname);
150 if(!root || strcmp(root->name, "exhibits") != 0) {
152 error_log("failed to load exhibits\n");
156 struct ts_node *iter = root->child_list;
158 struct ts_node *node = iter;
161 if(strcmp(node->name, "item") == 0) {
164 const char *amatch = ts_get_attr_str(node, "match_node");
165 if(!amatch || !(snode = mscn->match_node(amatch))) {
166 error_log("ExhibitManager::load: regexp \"%s\" didn't match any nodes\n",
167 amatch ? amatch : "");
172 const char *atype = ts_get_attr_str(node, "type");
173 if(!atype || !(ex = create_exhibit(atype))) {
174 error_log("failed to create exhibit of type: %s\n", atype);
180 const char *alabel = ts_get_attr_str(node, "label");
182 ex->set_name(alabel);
185 // create a new slot and attach the exhibit to it
186 ExhibitSlot *slot = new ExhibitSlot(ex);
187 exslots.push_back(slot);
189 // grab any extra exhibit data
190 const char *desc = ts_get_attr_str(node, "description");
191 const char *voice = ts_get_attr_str(node, "voiceover");
196 exd.text = std::string(desc);
199 exd.voice = new OggVorbisStream;
200 if(!exd.voice->open(voice)) {
201 error_log("failed to open voiceover: %s\n", voice);
206 ex->data.push_back(exd);
215 ExSelection ExhibitManager::select(const Ray &ray) const
218 nearest.dist = FLT_MAX;
220 int nitems = items.size();
221 for(int i=0; i<nitems; i++) {
222 ExSelection sel = items[i]->select(ray);
223 if(sel && sel.dist < nearest.dist) {
231 ExSelection ExhibitManager::select(const Sphere &sph) const
237 sel.validmask = EXSEL_SPHERE;
243 ExhibitSlot *ExhibitManager::nearest_empty_slot(const Vec3 &pos, float max_dist) const
245 ExhibitSlot *nearest = 0;
246 float nearest_sqdist = max_dist * max_dist;
248 int nslots = exslots.size();
249 for(int i=0; i<nslots; i++) {
250 ExhibitSlot *slot = exslots[i];
251 if(!slot->empty()) continue;
253 Vec3 slotpos = slot->node.get_position();
254 float dsq = length_sq(pos - slotpos);
255 if(dsq < nearest_sqdist) {
257 nearest_sqdist = dsq;
264 void ExhibitManager::stash_exhibit(Exhibit *ex)
266 // make sure it's not already stashed
267 if(std::find(stashed.begin(), stashed.end(), ex) != stashed.end()) {
270 stashed.push_back(ex);
273 if(ex->node->get_parent()) {
274 ex->node->get_parent()->remove_child(ex->node);
278 void ExhibitManager::update(float dt)
280 int num = items.size();
281 for(int i=0; i<num; i++) {
282 // if the exhibit is not part of a scene graph, first call its
283 // node's update function (otherwise it'll have been called recursively earlier)
284 if(!items[i]->node->get_parent()) {
285 items[i]->node->update(dt);
287 items[i]->update(dt);
291 void ExhibitManager::draw() const
293 int num = items.size();
294 for(int i=0; i<num; i++) {
295 items[i]->pre_draw();
297 items[i]->post_draw();
301 static Exhibit *create_exhibit(const char *type)
303 if(strcmp(type, "static") == 0) {
304 debug_log("creating static exhibit\n");
306 } else if(strcmp(type, "blobs") == 0) {
307 debug_log("creating blobs exhibit\n");
308 return new BlobExhibit;
310 error_log("unknown exhibit type: %s\n", type);