+ return proc_scenefile(mscn, node);
+
+ } else if(strcmp(node->name, "remap") == 0) {
+ const char *match = ts_get_attr_str(node, "match");
+ const char *replace = ts_get_attr_str(node, "replace");
+ if(match && replace) {
+ mscn->datamap.map(match, replace);
+ }
+
+ } else if(strcmp(node->name, "music") == 0) {
+ return proc_music(mscn, node);
+ }
+
+ return true;
+}
+
+
+
+struct SceneData {
+ MetaScene *meta;
+ std::string walkmesh_regexp, spawn_regexp;
+ std::vector<MaterialEdit> mtledit;
+};
+
+/*! Processes a `scenefile` node. And kicks off scene loading (if necessary) by
+ * calling `SceneSet::get`.
+ */
+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;
+ sdat->meta = mscn;
+
+ // datapath
+ struct ts_attr *adpath = attr_inscope(node, "datapath");
+ if(adpath && adpath->val.type == TS_STRING) {
+ mscn->datamap.set_path(adpath->val.str);
+ }
+
+ // strip path
+ struct ts_attr *aspath = attr_inscope(node, "strip_path");
+ if(aspath && aspath->val.type == TS_NUMBER) {
+ mscn->datamap.set_strip(aspath->val.inum);
+ }
+
+ // walkmesh
+ struct ts_attr *awmesh = attr_inscope(node, "walkmesh");
+ if(awmesh && awmesh->val.type == TS_STRING) {
+ sdat->walkmesh_regexp = std::string(awmesh->val.str);
+ }
+
+ // spawn node
+ struct ts_attr *awspawn = attr_inscope(node, "spawn");
+ if(awspawn) {
+ switch(awspawn->val.type) {
+ case TS_VECTOR:
+ mscn->start_pos = Vec3(awspawn->val.vec[0], awspawn->val.vec[1],
+ awspawn->val.vec[2]);
+ break;
+
+ case TS_STRING:
+ default:
+ sdat->spawn_regexp = std::string(awspawn->val.str);
+ }
+ }
+ if((awspawn = attr_inscope(node, "spawn_rot")) && awspawn->val.type == TS_VECTOR) {
+ Quat rot;
+ rot.rotate(Vec3(1, 0, 0), deg_to_rad(awspawn->val.vec[0]));
+ rot.rotate(Vec3(0, 1, 0), deg_to_rad(awspawn->val.vec[1]));
+ rot.rotate(Vec3(0, 0, 1), deg_to_rad(awspawn->val.vec[2]));
+ mscn->start_rot = rot;
+ }
+
+ int namesz = mscn->datamap.lookup(fname, 0, 0);
+ char *namebuf = (char*)alloca(namesz + 1);
+ if(mscn->datamap.lookup(fname, namebuf, namesz + 1)) {
+ fname = namebuf;
+ }
+
+ // material edits are kept in a list to be applied when the scene has been loaded
+ struct ts_node *child = node->child_list;
+ while(child) {
+ MaterialEdit medit;
+ if(proc_mtledit(mscn, &medit, child)) {
+ sdat->mtledit.push_back(medit);