goat3d

view src/goat3d_readxml.cc @ 45:8da36540e2e9

fixed memory leak in readxml and reversed error return
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 08 Dec 2013 02:27:32 +0200
parents b35427826b60
children 498ca7ac7047
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 delete [] buf;
23 return false;
24 }
26 XMLDocument xml;
27 XMLError err = xml.Parse(buf, bytes);
28 if(err) {
29 logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
30 xml.GetErrorStr2());
31 delete [] buf;
32 return false;
33 }
35 XMLElement *root = xml.RootElement();
36 if(strcmp(root->Name(), "scene") != 0) {
37 logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
38 delete [] buf;
39 return false;
40 }
42 XMLElement *elem;
44 // get all materials
45 elem = root->FirstChildElement("mtl");
46 while(elem) {
47 Material *mtl = read_material(this, elem);
48 if(mtl) {
49 add_material(mtl);
50 }
51 elem = elem->NextSiblingElement("mtl");
52 }
54 // get all meshes
55 elem = root->FirstChildElement("mesh");
56 while(elem) {
57 Mesh *mesh = read_mesh(this, elem);
58 if(mesh) {
59 add_mesh(mesh);
60 }
61 elem = elem->NextSiblingElement("mesh");
62 }
64 delete [] buf;
65 return true;
66 }
69 static Material *read_material(Scene *scn, XMLElement *xml_mtl)
70 {
71 Material *mtl = new Material;
72 mtl->name = get_name(xml_mtl, scn->get_material_count());
74 // get all the material attributes in turn
75 XMLElement *elem = xml_mtl->FirstChildElement("attr");
76 while(elem) {
77 MaterialAttrib attr;
78 const char *name = read_material_attrib(&attr, elem);
79 if(name) {
80 (*mtl)[name] = attr;
81 }
83 elem = elem->NextSiblingElement("attr");
84 }
86 return mtl;
87 }
89 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
90 {
91 const char *name;
93 XMLElement *elem;
94 if((elem = xml_attr->FirstChildElement("name"))) {
95 if(!(name = elem->Attribute("string"))) {
96 return 0;
97 }
98 }
100 if((elem = xml_attr->FirstChildElement("val"))) {
101 if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
102 // try a float3
103 const char *valstr = elem->Attribute("float3");
104 if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
105 &attr->value.z) != 3) {
106 // try a float4
107 valstr = elem->Attribute("float4");
108 if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
109 &attr->value.z, &attr->value.w) != 4) {
110 // no valid val attribute found
111 return 0;
112 }
113 }
114 }
115 }
117 if((elem = xml_attr->FirstChildElement("map"))) {
118 const char *tex = elem->Attribute("string");
119 if(tex) {
120 attr->map = std::string(tex);
121 }
122 }
124 return name;
125 }
127 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
128 {
129 Mesh *mesh = new Mesh;
130 mesh->name = get_name(xml_mesh, scn->get_mesh_count());
132 XMLElement *elem;
133 if((elem = xml_mesh->FirstChildElement("material"))) {
134 int idx;
135 if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
136 mesh->material = scn->get_material(idx);
137 } else {
138 // try string
139 const char *mtlstr = elem->Attribute("string");
140 if(mtlstr) {
141 mesh->material = scn->get_material(mtlstr);
142 }
143 }
144 }
146 /* reading mesh data from XML is not supported, only MESH_FILE can be used to
147 * specify an external mesh file to be loaded
148 */
150 if((elem = xml_mesh->FirstChildElement("file"))) {
151 const char *fname = elem->Attribute("string");
152 if(fname) {
153 if(!mesh->load(fname)) {
154 delete mesh;
155 return 0;
156 }
157 }
158 }
160 return mesh;
161 }
163 static std::string get_name(XMLElement *node, int idx)
164 {
165 char buf[64];
166 const char *name = 0;
168 XMLElement *elem;
169 if((elem = node->FirstChildElement("name"))) {
170 name = elem->Attribute("string");
171 }
173 if(!name) {
174 sprintf(buf, "mesh%04d", idx);
175 name = buf;
176 }
178 return std::string(name);
179 }