+ /* 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;
+
+ 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;
+ exd.type = EXDATA_INFO;
+
+ if(desc) {
+ char *fixed_desc = new char[strlen(desc) + 1];
+ clean_desc_text(fixed_desc, desc);
+ exd.text = std::string(fixed_desc);
+ delete [] fixed_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);
+ }
+ }
+ }
+