+static void apply_mtledit(Scene *scn, const MaterialEdit &med)
+{
+ // search all the objects to find matching material names
+ int nobj = scn->objects.size();
+ for(int i=0; i<nobj; i++) {
+ Object *obj = scn->objects[i];
+ if(std::regex_match(obj->mtl.name, med.name_re)) {
+ apply_mtledit(&obj->mtl, med);
+ }
+ }
+}
+
+static bool proc_music(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);
+ }
+
+ int namesz = mscn->datamap.lookup(fname, 0, 0);
+ char *namebuf = (char*)alloca(namesz + 1);
+ if(mscn->datamap.lookup(fname, namebuf, namesz + 1)) {
+ fname = namebuf;
+ }
+
+ OggVorbisStream *ovstream = new OggVorbisStream;
+ if(!ovstream->open(fname)) {
+ delete ovstream;
+ return false;
+ }
+
+ delete mscn->music;
+ mscn->music = ovstream;
+ }
+ 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);
+ }
+ }
+}
+