rev |
line source |
nuclear@54
|
1 /*
|
nuclear@54
|
2 goat3d - 3D scene, character, and animation file format library.
|
nuclear@54
|
3 Copyright (C) 2013-2014 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@54
|
4
|
nuclear@54
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@54
|
6 it under the terms of the GNU Lesser General Public License as published by
|
nuclear@54
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@54
|
8 (at your option) any later version.
|
nuclear@54
|
9
|
nuclear@54
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@54
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@54
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@54
|
13 GNU Lesser General Public License for more details.
|
nuclear@54
|
14
|
nuclear@54
|
15 You should have received a copy of the GNU Lesser General Public License
|
nuclear@54
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@54
|
17 */
|
nuclear@19
|
18 #include <stdio.h>
|
nuclear@75
|
19 #include <map>
|
nuclear@75
|
20 #include <string>
|
nuclear@95
|
21 #include <algorithm>
|
nuclear@19
|
22 #include "goat3d.h"
|
nuclear@19
|
23 #include "goat3d_impl.h"
|
nuclear@19
|
24 #include "tinyxml2.h"
|
nuclear@19
|
25 #include "log.h"
|
nuclear@19
|
26
|
nuclear@47
|
27 using namespace g3dimpl;
|
nuclear@19
|
28 using namespace tinyxml2;
|
nuclear@19
|
29
|
nuclear@95
|
30 struct Key {
|
nuclear@95
|
31 long tm;
|
nuclear@95
|
32 Vector4 val;
|
nuclear@95
|
33 };
|
nuclear@95
|
34
|
nuclear@95
|
35 static bool read_track(Scene *scn, XMLElement *xml_track, int *anim_idx);
|
nuclear@95
|
36 static Key read_key(XMLElement *xml_key);
|
nuclear@95
|
37
|
nuclear@19
|
38 static Material *read_material(Scene *scn, XMLElement *xml_mtl);
|
nuclear@19
|
39 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
|
nuclear@19
|
40 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
|
nuclear@75
|
41 static Node *read_node(Scene *scn, XMLElement *xml_node, std::map<Node*, std::string> &linkmap);
|
nuclear@75
|
42 static std::string get_name(XMLElement *node, int idx, const char *def_prefix);
|
nuclear@19
|
43
|
nuclear@19
|
44 bool Scene::loadxml(goat3d_io *io)
|
nuclear@19
|
45 {
|
nuclear@19
|
46 long bytes = io->seek(0, SEEK_END, io->cls);
|
nuclear@19
|
47 io->seek(0, SEEK_SET, io->cls);
|
nuclear@19
|
48
|
nuclear@19
|
49 char *buf = new char[bytes];
|
nuclear@19
|
50 if(io->read(buf, bytes, io->cls) < bytes) {
|
nuclear@19
|
51 logmsg(LOG_ERROR, "failed to read XML scene file\n");
|
nuclear@45
|
52 delete [] buf;
|
nuclear@19
|
53 return false;
|
nuclear@19
|
54 }
|
nuclear@19
|
55
|
nuclear@19
|
56 XMLDocument xml;
|
nuclear@19
|
57 XMLError err = xml.Parse(buf, bytes);
|
nuclear@19
|
58 if(err) {
|
nuclear@19
|
59 logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
|
nuclear@19
|
60 xml.GetErrorStr2());
|
nuclear@45
|
61 delete [] buf;
|
nuclear@19
|
62 return false;
|
nuclear@19
|
63 }
|
nuclear@19
|
64
|
nuclear@19
|
65 XMLElement *root = xml.RootElement();
|
nuclear@19
|
66 if(strcmp(root->Name(), "scene") != 0) {
|
nuclear@19
|
67 logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
|
nuclear@45
|
68 delete [] buf;
|
nuclear@19
|
69 return false;
|
nuclear@19
|
70 }
|
nuclear@19
|
71
|
nuclear@19
|
72 XMLElement *elem;
|
nuclear@19
|
73
|
nuclear@19
|
74 // get all materials
|
nuclear@19
|
75 elem = root->FirstChildElement("mtl");
|
nuclear@19
|
76 while(elem) {
|
nuclear@19
|
77 Material *mtl = read_material(this, elem);
|
nuclear@19
|
78 if(mtl) {
|
nuclear@19
|
79 add_material(mtl);
|
nuclear@19
|
80 }
|
nuclear@19
|
81 elem = elem->NextSiblingElement("mtl");
|
nuclear@19
|
82 }
|
nuclear@19
|
83
|
nuclear@19
|
84 // get all meshes
|
nuclear@19
|
85 elem = root->FirstChildElement("mesh");
|
nuclear@19
|
86 while(elem) {
|
nuclear@19
|
87 Mesh *mesh = read_mesh(this, elem);
|
nuclear@19
|
88 if(mesh) {
|
nuclear@19
|
89 add_mesh(mesh);
|
nuclear@19
|
90 }
|
nuclear@19
|
91 elem = elem->NextSiblingElement("mesh");
|
nuclear@19
|
92 }
|
nuclear@19
|
93
|
nuclear@75
|
94 // get all nodes
|
nuclear@75
|
95 std::map<Node*, std::string> linkmap;
|
nuclear@75
|
96
|
nuclear@75
|
97 elem = root->FirstChildElement("node");
|
nuclear@75
|
98 while(elem) {
|
nuclear@75
|
99 Node *node = read_node(this, elem, linkmap);
|
nuclear@75
|
100 if(node) {
|
nuclear@75
|
101 add_node(node);
|
nuclear@75
|
102 }
|
nuclear@75
|
103 elem = elem->NextSiblingElement("node");
|
nuclear@75
|
104 }
|
nuclear@75
|
105
|
nuclear@75
|
106 // link up all the nodes in the hierarchy
|
nuclear@75
|
107 for(size_t i=0; i<nodes.size(); i++) {
|
nuclear@75
|
108 std::string parent_name = linkmap[nodes[i]];
|
nuclear@75
|
109 if(!parent_name.empty()) {
|
nuclear@75
|
110 Node *parent = get_node(parent_name.c_str());
|
nuclear@75
|
111 if(parent) {
|
nuclear@75
|
112 parent->add_child(nodes[i]);
|
nuclear@75
|
113 }
|
nuclear@75
|
114 }
|
nuclear@75
|
115 }
|
nuclear@75
|
116
|
nuclear@45
|
117 delete [] buf;
|
nuclear@45
|
118 return true;
|
nuclear@19
|
119 }
|
nuclear@19
|
120
|
nuclear@51
|
121 bool Scene::load_anim_xml(goat3d_io *io)
|
nuclear@51
|
122 {
|
nuclear@51
|
123 long bytes = io->seek(0, SEEK_END, io->cls);
|
nuclear@51
|
124 io->seek(0, SEEK_SET, io->cls);
|
nuclear@51
|
125
|
nuclear@51
|
126 char *buf = new char[bytes];
|
nuclear@51
|
127 if(io->read(buf, bytes, io->cls) < bytes) {
|
nuclear@51
|
128 logmsg(LOG_ERROR, "failed to read XML animation file\n");
|
nuclear@51
|
129 delete [] buf;
|
nuclear@51
|
130 return false;
|
nuclear@51
|
131 }
|
nuclear@51
|
132
|
nuclear@51
|
133 XMLDocument xml;
|
nuclear@51
|
134 XMLError err = xml.Parse(buf, bytes);
|
nuclear@51
|
135 if(err) {
|
nuclear@51
|
136 logmsg(LOG_ERROR, "failed to parse XML animation file: %s\n%s\n", xml.GetErrorStr1(),
|
nuclear@51
|
137 xml.GetErrorStr2());
|
nuclear@51
|
138 delete [] buf;
|
nuclear@51
|
139 return false;
|
nuclear@51
|
140 }
|
nuclear@51
|
141
|
nuclear@51
|
142 XMLElement *root = xml.RootElement();
|
nuclear@51
|
143 if(strcmp(root->Name(), "anim") != 0) {
|
nuclear@95
|
144 logmsg(LOG_ERROR, "%s: root node is not <anim>\n", __FUNCTION__);
|
nuclear@51
|
145 delete [] buf;
|
nuclear@51
|
146 return false;
|
nuclear@51
|
147 }
|
nuclear@51
|
148
|
nuclear@95
|
149 int anim_idx = -1;
|
nuclear@95
|
150 XMLElement *elem = root->FirstChildElement();
|
nuclear@51
|
151 while(elem) {
|
nuclear@51
|
152 const char *elem_name = elem->Name();
|
nuclear@51
|
153
|
nuclear@95
|
154 if(strcmp(elem_name, "track") != 0) {
|
nuclear@95
|
155 logmsg(LOG_ERROR, "%s: only <track>s allowed in <anim>\n", __FUNCTION__);
|
nuclear@95
|
156 delete [] buf;
|
nuclear@95
|
157 return false;
|
nuclear@95
|
158 }
|
nuclear@95
|
159
|
nuclear@95
|
160 if(!read_track(this, elem, &anim_idx)) {
|
nuclear@95
|
161 delete [] buf;
|
nuclear@95
|
162 return false;
|
nuclear@51
|
163 }
|
nuclear@51
|
164 elem = elem->NextSiblingElement();
|
nuclear@51
|
165 }
|
nuclear@51
|
166
|
nuclear@95
|
167 if(anim_idx == -1) {
|
nuclear@95
|
168 logmsg(LOG_INFO, "%s: WARNING animation affected 0 nodes\n", __FUNCTION__);
|
nuclear@95
|
169 }
|
nuclear@95
|
170
|
nuclear@51
|
171 delete [] buf;
|
nuclear@51
|
172 return true;
|
nuclear@51
|
173 }
|
nuclear@19
|
174
|
nuclear@95
|
175 static bool read_track(Scene *scn, XMLElement *xml_track, int *anim_idx)
|
nuclear@95
|
176 {
|
nuclear@95
|
177 Node *node = 0;
|
nuclear@95
|
178 int type = -1;
|
nuclear@95
|
179 std::vector<Key> keys;
|
nuclear@95
|
180
|
nuclear@95
|
181 XMLElement *elem = xml_track->FirstChildElement();
|
nuclear@95
|
182 while(elem) {
|
nuclear@95
|
183 const char *elem_name = elem->Name();
|
nuclear@95
|
184
|
nuclear@95
|
185 if(strcmp(elem_name, "node") == 0) {
|
nuclear@95
|
186 const char *name = elem->Attribute("string");
|
nuclear@95
|
187 if(!name || !(node = scn->get_node(name))) {
|
nuclear@95
|
188 logmsg(LOG_ERROR, "%s: invalid track node: %s\n", __FUNCTION__, name);
|
nuclear@95
|
189 return false;
|
nuclear@95
|
190 }
|
nuclear@95
|
191
|
nuclear@95
|
192 } else if(strcmp(elem_name, "attr") == 0) {
|
nuclear@95
|
193 const char *str = elem->Attribute("string");
|
nuclear@95
|
194 if(str && strcmp(str, "position") == 0) {
|
nuclear@95
|
195 type = XFormNode::POSITION_TRACK;
|
nuclear@95
|
196 } else if(str && strcmp(str, "rotation") == 0) {
|
nuclear@95
|
197 type = XFormNode::ROTATION_TRACK;
|
nuclear@95
|
198 } else if(str && strcmp(str, "scaling") == 0) {
|
nuclear@95
|
199 type = XFormNode::SCALING_TRACK;
|
nuclear@95
|
200 } else {
|
nuclear@95
|
201 logmsg(LOG_ERROR, "%s: invalid track attribute specifier: %s\n", __FUNCTION__, str);
|
nuclear@95
|
202 return false;
|
nuclear@95
|
203 }
|
nuclear@95
|
204
|
nuclear@95
|
205 } else if(strcmp(elem_name, "key") == 0) {
|
nuclear@95
|
206 Key key = read_key(elem);
|
nuclear@95
|
207 if(key.tm == LONG_MIN) {
|
nuclear@95
|
208 return false; // logging in read_key
|
nuclear@95
|
209 }
|
nuclear@95
|
210 keys.push_back(key);
|
nuclear@95
|
211
|
nuclear@95
|
212 } else {
|
nuclear@95
|
213 logmsg(LOG_ERROR, "%s: unexpected element <%s> in <track>\n", __FUNCTION__, elem_name);
|
nuclear@95
|
214 return false;
|
nuclear@95
|
215 }
|
nuclear@95
|
216 elem = elem->NextSiblingElement();
|
nuclear@95
|
217 }
|
nuclear@95
|
218
|
nuclear@95
|
219 if(!node) {
|
nuclear@95
|
220 logmsg(LOG_ERROR, "%s: invalid track, missing node reference\n", __FUNCTION__);
|
nuclear@95
|
221 return false;
|
nuclear@95
|
222 }
|
nuclear@95
|
223 if(type == -1) {
|
nuclear@95
|
224 logmsg(LOG_ERROR, "%s: invalid track, missing attribute specifier\n", __FUNCTION__);
|
nuclear@95
|
225 return false;
|
nuclear@95
|
226 }
|
nuclear@95
|
227
|
nuclear@95
|
228 if(*anim_idx == -1) {
|
nuclear@95
|
229 // this is the first node we encounter. add a new animation and activate it
|
nuclear@95
|
230 XFormNode *root = node->get_root();
|
nuclear@95
|
231 *anim_idx = root->get_animation_count() + 1;
|
nuclear@95
|
232
|
nuclear@95
|
233 char name[64];
|
nuclear@95
|
234 sprintf(name, "anim%03d\n", *anim_idx);
|
nuclear@95
|
235 root->add_animation(name);
|
nuclear@95
|
236 root->use_animation(*anim_idx);
|
nuclear@95
|
237 } else {
|
nuclear@95
|
238 // make sure this node hierarchy already has this animation, otherwise add it
|
nuclear@95
|
239 XFormNode *root = node->get_root();
|
nuclear@95
|
240 if(root->get_active_animation_index() != *anim_idx) {
|
nuclear@95
|
241 char name[64];
|
nuclear@95
|
242 sprintf(name, "anim%03d\n", *anim_idx);
|
nuclear@95
|
243 root->add_animation(name);
|
nuclear@95
|
244 root->use_animation(*anim_idx);
|
nuclear@95
|
245 }
|
nuclear@95
|
246 }
|
nuclear@95
|
247
|
nuclear@95
|
248 for(auto key : keys) {
|
nuclear@95
|
249 switch(type) {
|
nuclear@95
|
250 case XFormNode::POSITION_TRACK:
|
nuclear@95
|
251 node->set_position(Vector3(key.val.x, key.val.y, key.val.z), key.tm);
|
nuclear@95
|
252 break;
|
nuclear@95
|
253 case XFormNode::ROTATION_TRACK:
|
nuclear@95
|
254 node->set_rotation(Quaternion(key.val.w, key.val.x, key.val.y, key.val.z), key.tm);
|
nuclear@95
|
255 break;
|
nuclear@95
|
256 case XFormNode::SCALING_TRACK:
|
nuclear@95
|
257 node->set_scaling(Vector3(key.val.x, key.val.y, key.val.z), key.tm);
|
nuclear@95
|
258 }
|
nuclear@95
|
259 }
|
nuclear@95
|
260 return true;
|
nuclear@95
|
261 }
|
nuclear@95
|
262
|
nuclear@95
|
263 static Key read_key(XMLElement *xml_key)
|
nuclear@95
|
264 {
|
nuclear@95
|
265 Key key;
|
nuclear@95
|
266 key.tm = LONG_MIN; // initialize to invalid time
|
nuclear@95
|
267
|
nuclear@95
|
268 XMLElement *xml_time = xml_key->FirstChildElement("time");
|
nuclear@95
|
269 XMLElement *xml_value = xml_key->FirstChildElement("value");
|
nuclear@95
|
270
|
nuclear@95
|
271 if(!xml_time || !xml_value) {
|
nuclear@95
|
272 logmsg(LOG_ERROR, "%s: invalid key, missing either <time> or <value> elements\n", __FUNCTION__);
|
nuclear@95
|
273 return key;
|
nuclear@95
|
274 }
|
nuclear@95
|
275
|
nuclear@95
|
276 int ival;
|
nuclear@95
|
277 if(xml_time->QueryIntAttribute("int", &ival) != XML_NO_ERROR) {
|
nuclear@95
|
278 logmsg(LOG_ERROR, "%s: invalid time element in <key>\n", __FUNCTION__);
|
nuclear@95
|
279 return key;
|
nuclear@95
|
280 }
|
nuclear@95
|
281
|
nuclear@95
|
282 const char *vstr;
|
nuclear@95
|
283 if((vstr = xml_value->Attribute("float3"))) {
|
nuclear@95
|
284 if(sscanf(vstr, "%f %f %f", &key.val.x, &key.val.y, &key.val.z) != 3) {
|
nuclear@95
|
285 logmsg(LOG_ERROR, "%s: invalid float3 value element in <key>: %s\n", __FUNCTION__, vstr);
|
nuclear@95
|
286 return key;
|
nuclear@95
|
287 }
|
nuclear@95
|
288 } else if((vstr = xml_value->Attribute("float4"))) {
|
nuclear@95
|
289 if(sscanf(vstr, "%f %f %f %f", &key.val.x, &key.val.y, &key.val.z, &key.val.w) != 4) {
|
nuclear@95
|
290 logmsg(LOG_ERROR, "%s: invalid float4 value element in <key>: %s\n", __FUNCTION__, vstr);
|
nuclear@95
|
291 return key;
|
nuclear@95
|
292 }
|
nuclear@95
|
293 } else {
|
nuclear@95
|
294 logmsg(LOG_ERROR, "%s: invalid value element in <key>: missing float3 or float4 attributes\n", __FUNCTION__);
|
nuclear@95
|
295 return key;
|
nuclear@95
|
296 }
|
nuclear@95
|
297
|
nuclear@95
|
298 key.tm = ival;
|
nuclear@95
|
299 return key;
|
nuclear@95
|
300 }
|
nuclear@95
|
301
|
nuclear@19
|
302 static Material *read_material(Scene *scn, XMLElement *xml_mtl)
|
nuclear@19
|
303 {
|
nuclear@19
|
304 Material *mtl = new Material;
|
nuclear@75
|
305 mtl->name = get_name(xml_mtl, scn->get_material_count(), "material");
|
nuclear@19
|
306
|
nuclear@19
|
307 // get all the material attributes in turn
|
nuclear@19
|
308 XMLElement *elem = xml_mtl->FirstChildElement("attr");
|
nuclear@19
|
309 while(elem) {
|
nuclear@19
|
310 MaterialAttrib attr;
|
nuclear@19
|
311 const char *name = read_material_attrib(&attr, elem);
|
nuclear@19
|
312 if(name) {
|
nuclear@19
|
313 (*mtl)[name] = attr;
|
nuclear@19
|
314 }
|
nuclear@19
|
315
|
nuclear@19
|
316 elem = elem->NextSiblingElement("attr");
|
nuclear@19
|
317 }
|
nuclear@19
|
318
|
nuclear@19
|
319 return mtl;
|
nuclear@19
|
320 }
|
nuclear@19
|
321
|
nuclear@19
|
322 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
|
nuclear@19
|
323 {
|
nuclear@94
|
324 const char *name = 0;
|
nuclear@19
|
325
|
nuclear@19
|
326 XMLElement *elem;
|
nuclear@19
|
327 if((elem = xml_attr->FirstChildElement("name"))) {
|
nuclear@19
|
328 if(!(name = elem->Attribute("string"))) {
|
nuclear@19
|
329 return 0;
|
nuclear@19
|
330 }
|
nuclear@19
|
331 }
|
nuclear@19
|
332
|
nuclear@19
|
333 if((elem = xml_attr->FirstChildElement("val"))) {
|
nuclear@19
|
334 if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
|
nuclear@19
|
335 // try a float3
|
nuclear@19
|
336 const char *valstr = elem->Attribute("float3");
|
nuclear@19
|
337 if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
|
nuclear@19
|
338 &attr->value.z) != 3) {
|
nuclear@19
|
339 // try a float4
|
nuclear@19
|
340 valstr = elem->Attribute("float4");
|
nuclear@19
|
341 if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
|
nuclear@19
|
342 &attr->value.z, &attr->value.w) != 4) {
|
nuclear@19
|
343 // no valid val attribute found
|
nuclear@19
|
344 return 0;
|
nuclear@19
|
345 }
|
nuclear@19
|
346 }
|
nuclear@19
|
347 }
|
nuclear@19
|
348 }
|
nuclear@19
|
349
|
nuclear@19
|
350 if((elem = xml_attr->FirstChildElement("map"))) {
|
nuclear@19
|
351 const char *tex = elem->Attribute("string");
|
nuclear@19
|
352 if(tex) {
|
nuclear@19
|
353 attr->map = std::string(tex);
|
nuclear@19
|
354 }
|
nuclear@19
|
355 }
|
nuclear@19
|
356
|
nuclear@19
|
357 return name;
|
nuclear@19
|
358 }
|
nuclear@19
|
359
|
nuclear@19
|
360 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
|
nuclear@19
|
361 {
|
nuclear@19
|
362 Mesh *mesh = new Mesh;
|
nuclear@75
|
363 mesh->name = get_name(xml_mesh, scn->get_mesh_count(), "mesh");
|
nuclear@19
|
364
|
nuclear@19
|
365 XMLElement *elem;
|
nuclear@19
|
366 if((elem = xml_mesh->FirstChildElement("material"))) {
|
nuclear@19
|
367 int idx;
|
nuclear@19
|
368 if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
|
nuclear@19
|
369 mesh->material = scn->get_material(idx);
|
nuclear@19
|
370 } else {
|
nuclear@19
|
371 // try string
|
nuclear@19
|
372 const char *mtlstr = elem->Attribute("string");
|
nuclear@19
|
373 if(mtlstr) {
|
nuclear@19
|
374 mesh->material = scn->get_material(mtlstr);
|
nuclear@19
|
375 }
|
nuclear@19
|
376 }
|
nuclear@19
|
377 }
|
nuclear@19
|
378
|
nuclear@19
|
379 /* reading mesh data from XML is not supported, only MESH_FILE can be used to
|
nuclear@19
|
380 * specify an external mesh file to be loaded
|
nuclear@19
|
381 */
|
nuclear@19
|
382
|
nuclear@19
|
383 if((elem = xml_mesh->FirstChildElement("file"))) {
|
nuclear@19
|
384 const char *fname = elem->Attribute("string");
|
nuclear@19
|
385 if(fname) {
|
nuclear@74
|
386 char *path = (char*)fname;
|
nuclear@74
|
387 if(scn->goat->search_path) {
|
nuclear@74
|
388 path = (char*)alloca(strlen(fname) + strlen(scn->goat->search_path) + 2);
|
nuclear@74
|
389 sprintf(path, "%s/%s", scn->goat->search_path, fname);
|
nuclear@74
|
390 }
|
nuclear@74
|
391 if(!mesh->load(path)) {
|
nuclear@19
|
392 delete mesh;
|
nuclear@19
|
393 return 0;
|
nuclear@19
|
394 }
|
nuclear@19
|
395 }
|
nuclear@19
|
396 }
|
nuclear@19
|
397
|
nuclear@19
|
398 return mesh;
|
nuclear@19
|
399 }
|
nuclear@19
|
400
|
nuclear@75
|
401 static Node *read_node(Scene *scn, XMLElement *xml_node, std::map<Node*, std::string> &linkmap)
|
nuclear@75
|
402 {
|
nuclear@75
|
403 Node *node = new Node;
|
nuclear@75
|
404 node->set_name(get_name(xml_node, scn->get_node_count(), "node").c_str());
|
nuclear@75
|
405
|
nuclear@75
|
406 XMLElement *elem;
|
nuclear@75
|
407 if((elem = xml_node->FirstChildElement("parent"))) {
|
nuclear@75
|
408 const char *pname = elem->Attribute("string");
|
nuclear@75
|
409 if(pname) {
|
nuclear@75
|
410 linkmap[node] = pname;
|
nuclear@75
|
411 }
|
nuclear@75
|
412 }
|
nuclear@75
|
413
|
nuclear@75
|
414 if((elem = xml_node->FirstChildElement("mesh"))) {
|
nuclear@75
|
415 Mesh *mesh = scn->get_mesh(elem->Attribute("string"));
|
nuclear@75
|
416 if(mesh) {
|
nuclear@75
|
417 node->set_object(mesh);
|
nuclear@75
|
418 }
|
nuclear@75
|
419 } else if((elem = xml_node->FirstChildElement("light"))) {
|
nuclear@75
|
420 Light *lt = scn->get_light(elem->Attribute("string"));
|
nuclear@75
|
421 if(lt) {
|
nuclear@75
|
422 node->set_object(lt);
|
nuclear@75
|
423 }
|
nuclear@75
|
424 } else if((elem = xml_node->FirstChildElement("camera"))) {
|
nuclear@75
|
425 Camera *cam = scn->get_camera(elem->Attribute("string"));
|
nuclear@75
|
426 if(cam) {
|
nuclear@75
|
427 node->set_object(cam);
|
nuclear@75
|
428 }
|
nuclear@75
|
429 }
|
nuclear@75
|
430
|
nuclear@75
|
431 float vec[4];
|
nuclear@75
|
432 if((elem = xml_node->FirstChildElement("pos"))) {
|
nuclear@75
|
433 const char *val = elem->Attribute("float3");
|
nuclear@75
|
434 if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) {
|
nuclear@83
|
435 node->set_position(Vector3(vec[0], vec[1], vec[2]));
|
nuclear@75
|
436 } else {
|
nuclear@75
|
437 logmsg(LOG_ERROR, "node %s: invalid position tag\n", node->get_name());
|
nuclear@75
|
438 }
|
nuclear@75
|
439 }
|
nuclear@75
|
440 if((elem = xml_node->FirstChildElement("rot"))) {
|
nuclear@75
|
441 const char *val = elem->Attribute("float4");
|
nuclear@75
|
442 if(val && sscanf(val, "%f %f %f %f", vec, vec + 1, vec + 2, vec + 3) == 4) {
|
nuclear@75
|
443 node->set_rotation(Quaternion(vec[3], Vector3(vec[0], vec[1], vec[2])));
|
nuclear@75
|
444 } else {
|
nuclear@75
|
445 logmsg(LOG_ERROR, "node %s: invalid rotation tag\n", node->get_name());
|
nuclear@75
|
446 }
|
nuclear@75
|
447 }
|
nuclear@75
|
448 if((elem = xml_node->FirstChildElement("scale"))) {
|
nuclear@75
|
449 const char *val = elem->Attribute("float3");
|
nuclear@75
|
450 if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) {
|
nuclear@75
|
451 node->set_scaling(Vector3(vec[0], vec[1], vec[2]));
|
nuclear@75
|
452 } else {
|
nuclear@75
|
453 logmsg(LOG_ERROR, "node %s: invalid scaling tag\n", node->get_name());
|
nuclear@75
|
454 }
|
nuclear@75
|
455 }
|
nuclear@75
|
456 if((elem = xml_node->FirstChildElement("pivot"))) {
|
nuclear@75
|
457 const char *val = elem->Attribute("float3");
|
nuclear@75
|
458 if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) {
|
nuclear@75
|
459 node->set_pivot(Vector3(vec[0], vec[1], vec[2]));
|
nuclear@75
|
460 } else {
|
nuclear@75
|
461 logmsg(LOG_ERROR, "node %s: invalid pivot tag\n", node->get_name());
|
nuclear@75
|
462 }
|
nuclear@75
|
463 }
|
nuclear@75
|
464
|
nuclear@75
|
465 return node;
|
nuclear@75
|
466 }
|
nuclear@75
|
467
|
nuclear@75
|
468 static std::string get_name(XMLElement *node, int idx, const char *def_prefix)
|
nuclear@19
|
469 {
|
nuclear@19
|
470 char buf[64];
|
nuclear@19
|
471 const char *name = 0;
|
nuclear@19
|
472
|
nuclear@19
|
473 XMLElement *elem;
|
nuclear@19
|
474 if((elem = node->FirstChildElement("name"))) {
|
nuclear@19
|
475 name = elem->Attribute("string");
|
nuclear@19
|
476 }
|
nuclear@19
|
477
|
nuclear@19
|
478 if(!name) {
|
nuclear@75
|
479 sprintf(buf, "%s%04d", def_prefix, idx);
|
nuclear@19
|
480 name = buf;
|
nuclear@19
|
481 }
|
nuclear@19
|
482
|
nuclear@19
|
483 return std::string(name);
|
nuclear@19
|
484 }
|