goat3d

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