14 static bool proc_node(MetaScene *mscn, struct ts_node *node);
15 static bool proc_scenefile(MetaScene *mscn, struct ts_node *node);
16 static bool proc_mtledit(Scene *scn, struct ts_node *node);
17 static struct ts_attr *attr_inscope(struct ts_node *node, const char *name);
19 static void print_scene_graph(SceneNode *n, int level);
22 MetaScene::MetaScene(SceneSet *sman, TextureSet *tman)
29 MetaScene::~MetaScene()
35 bool MetaScene::load(const char *fname)
37 struct ts_node *root = ts_load(fname);
38 if(!root || strcmp(root->name, "scene") != 0) {
40 error_log("failed to load scene metadata: %s\n", fname);
44 bool res = proc_node(this, root);
47 /*info_log("loaded scene: %s\n", fname);
48 info_log("scene graph:\n");
49 print_scene_graph(scn->nodes, 0);
54 void MetaScene::update(float dt)
56 int nscn = scenes.size();
57 for(int i=0; i<nscn; i++) {
58 scenes[i]->update(dt);
62 void MetaScene::draw() const
64 int nscn = scenes.size();
65 for(int i=0; i<nscn; i++) {
70 static bool proc_node(MetaScene *mscn, struct ts_node *node)
72 struct ts_node *c = node->child_list;
74 if(!proc_node(mscn, c)) {
80 // do this last to allow other contents of the node to do their thing
81 if(strcmp(node->name, "scenefile") == 0) {
82 return proc_scenefile(mscn, node);
84 } else if(strcmp(node->name, "remap") == 0) {
85 const char *match = ts_get_attr_str(node, "match");
86 const char *replace = ts_get_attr_str(node, "replace");
87 if(match && replace) {
88 datamap_map(match, replace);
95 static bool proc_scenefile(MetaScene *mscn, struct ts_node *node)
97 const char *fname = ts_get_attr_str(node, "file");
100 struct ts_attr *adpath = attr_inscope(node, "datapath");
101 if(adpath && adpath->val.type == TS_STRING) {
102 info_log("adding data path: %s\n", adpath->val.str);
103 datamap_set_path(adpath->val.str);
107 char *walkmesh_regexp = 0;
108 struct ts_attr *awmesh = attr_inscope(node, "walkmesh");
109 if(awmesh && awmesh->val.type == TS_STRING) {
110 walkmesh_regexp = awmesh->val.str;
113 int namesz = datamap_lookup(fname, 0, 0);
114 char *namebuf = (char*)alloca(namesz + 1);
115 if(datamap_lookup(fname, namebuf, namesz + 1)) {
119 Scene *newscn = new Scene(mscn->texman);
120 if(!(newscn->load(fname, SCNLOAD_FLIPTEX))) { // TODO unhardcode FLIPTEX
124 // extract the walk mesh if necessary
126 if(walkmesh_regexp && (wscn = newscn->extract_nodes(walkmesh_regexp))) {
127 // apply all transformations to the meshes
130 int nmeshes = wscn->meshes.size();
131 for(int i=0; i<nmeshes; i++) {
132 Mesh *m = wscn->meshes[i];
134 if(mscn->walk_mesh) {
135 mscn->walk_mesh->append(*m);
138 wscn->remove_mesh(m); // to save it from destruction
145 // perform material edits
146 struct ts_node *child = node->child_list;
148 proc_mtledit(newscn, child); // ignores any non-mtledit nodes, no need to check
152 mscn->scenes.push_back(newscn);
154 //datamap_reset(); // TODO this should be push/pop instead of hard reset
159 static void mtledit(Material *mtl, TextureSet *texset, struct ts_node *node)
161 node = node->child_list;
163 struct ts_node *cn = node;
166 if(strcmp(cn->name, "texture") == 0) {
167 // add/change/remove a texture
168 struct ts_attr *atype = ts_get_attr(cn, "type");
169 struct ts_attr *afile = ts_get_attr(cn, "file");
171 int textype = MTL_TEX_DIFFUSE;
173 if(atype->val.type == TS_STRING) {
174 textype = mtl_parse_type(atype->val.str);
175 } else if(atype->val.type == TS_NUMBER) {
176 textype = atype->val.inum;
177 if(textype < 0 || textype >= NUM_MTL_TEXTURES) {
178 error_log("invalid texture in mtledit: %d\n", textype);
182 error_log("unexpected texture type in mtledit: %s\n", atype->val.str);
187 if(!afile || !afile->val.str || !*afile->val.str) {
189 mtl->textures[textype] = 0;
191 Texture *tex = texset->get_texture(afile->val.str, TEX_2D);
192 mtl->add_texture(tex, textype);
195 // TODO add more edit modes
199 static bool proc_mtledit(Scene *scn, struct ts_node *node)
201 if(strcmp(node->name, "mtledit") != 0) {
205 const char *mtl_regexp = ".*";
206 struct ts_attr *amtl = ts_get_attr(node, "material");
207 if(amtl && amtl->val.type == TS_STRING) {
208 mtl_regexp = amtl->val.str;
211 // search all the objects to find matching material names
212 std::regex re{mtl_regexp};
214 int nobj = scn->objects.size();
215 for(int i=0; i<nobj; i++) {
216 Object *obj = scn->objects[i];
217 if(std::regex_match(obj->get_name(), re)) {
218 mtledit(&obj->mtl, scn->texset, node);
225 static struct ts_attr *attr_inscope(struct ts_node *node, const char *name)
227 struct ts_attr *attr = 0;
229 while(node && !(attr = ts_get_attr(node, name))) {
235 static void print_scene_graph(SceneNode *n, int level)
239 for(int i=0; i<level; i++) {
243 int nobj = n->get_num_objects();
245 info_log("%s - %d obj\n", n->get_name(), n->get_num_objects());
247 info_log("%s\n", n->get_name());
250 for(int i=0; i<n->get_num_children(); i++) {
251 print_scene_graph(n->get_child(i), level + 1);