goat3d

view src/goat3d_readxml.cc @ 19:b35427826b60

- added XML format reading support - wrote a rudimentary version of goatview
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Sep 2013 06:58:37 +0300
parents
children 8da36540e2e9
line source
1 #include <stdio.h>
2 #include "goat3d.h"
3 #include "goat3d_impl.h"
4 #include "tinyxml2.h"
5 #include "log.h"
7 using namespace tinyxml2;
9 static Material *read_material(Scene *scn, XMLElement *xml_mtl);
10 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
11 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
12 static std::string get_name(XMLElement *node, int idx);
14 bool Scene::loadxml(goat3d_io *io)
15 {
16 long bytes = io->seek(0, SEEK_END, io->cls);
17 io->seek(0, SEEK_SET, io->cls);
19 char *buf = new char[bytes];
20 if(io->read(buf, bytes, io->cls) < bytes) {
21 logmsg(LOG_ERROR, "failed to read XML scene file\n");
22 return false;
23 }
25 XMLDocument xml;
26 XMLError err = xml.Parse(buf, bytes);
27 if(err) {
28 logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
29 xml.GetErrorStr2());
30 return false;
31 }
33 XMLElement *root = xml.RootElement();
34 if(strcmp(root->Name(), "scene") != 0) {
35 logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
36 return false;
37 }
39 XMLElement *elem;
41 // get all materials
42 elem = root->FirstChildElement("mtl");
43 while(elem) {
44 Material *mtl = read_material(this, elem);
45 if(mtl) {
46 add_material(mtl);
47 }
48 elem = elem->NextSiblingElement("mtl");
49 }
51 // get all meshes
52 elem = root->FirstChildElement("mesh");
53 while(elem) {
54 Mesh *mesh = read_mesh(this, elem);
55 if(mesh) {
56 add_mesh(mesh);
57 }
58 elem = elem->NextSiblingElement("mesh");
59 }
61 return false;
62 }
65 static Material *read_material(Scene *scn, XMLElement *xml_mtl)
66 {
67 Material *mtl = new Material;
68 mtl->name = get_name(xml_mtl, scn->get_material_count());
70 // get all the material attributes in turn
71 XMLElement *elem = xml_mtl->FirstChildElement("attr");
72 while(elem) {
73 MaterialAttrib attr;
74 const char *name = read_material_attrib(&attr, elem);
75 if(name) {
76 (*mtl)[name] = attr;
77 }
79 elem = elem->NextSiblingElement("attr");
80 }
82 return mtl;
83 }
85 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
86 {
87 const char *name;
89 XMLElement *elem;
90 if((elem = xml_attr->FirstChildElement("name"))) {
91 if(!(name = elem->Attribute("string"))) {
92 return 0;
93 }
94 }
96 if((elem = xml_attr->FirstChildElement("val"))) {
97 if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
98 // try a float3
99 const char *valstr = elem->Attribute("float3");
100 if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
101 &attr->value.z) != 3) {
102 // try a float4
103 valstr = elem->Attribute("float4");
104 if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
105 &attr->value.z, &attr->value.w) != 4) {
106 // no valid val attribute found
107 return 0;
108 }
109 }
110 }
111 }
113 if((elem = xml_attr->FirstChildElement("map"))) {
114 const char *tex = elem->Attribute("string");
115 if(tex) {
116 attr->map = std::string(tex);
117 }
118 }
120 return name;
121 }
123 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
124 {
125 Mesh *mesh = new Mesh;
126 mesh->name = get_name(xml_mesh, scn->get_mesh_count());
128 XMLElement *elem;
129 if((elem = xml_mesh->FirstChildElement("material"))) {
130 int idx;
131 if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
132 mesh->material = scn->get_material(idx);
133 } else {
134 // try string
135 const char *mtlstr = elem->Attribute("string");
136 if(mtlstr) {
137 mesh->material = scn->get_material(mtlstr);
138 }
139 }
140 }
142 /* reading mesh data from XML is not supported, only MESH_FILE can be used to
143 * specify an external mesh file to be loaded
144 */
146 if((elem = xml_mesh->FirstChildElement("file"))) {
147 const char *fname = elem->Attribute("string");
148 if(fname) {
149 if(!mesh->load(fname)) {
150 delete mesh;
151 return 0;
152 }
153 }
154 }
156 return mesh;
157 }
159 static std::string get_name(XMLElement *node, int idx)
160 {
161 char buf[64];
162 const char *name = 0;
164 XMLElement *elem;
165 if((elem = node->FirstChildElement("name"))) {
166 name = elem->Attribute("string");
167 }
169 if(!name) {
170 sprintf(buf, "mesh%04d", idx);
171 name = buf;
172 }
174 return std::string(name);
175 }