goat3d

annotate src/goat3d_readxml.cc @ 74:ab66cdabf6f2

loading scene files (no vis yet)
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 May 2014 13:26:52 +0300
parents dad392c710df
children 76dea247f75c
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@19 19 #include "goat3d.h"
nuclear@19 20 #include "goat3d_impl.h"
nuclear@19 21 #include "tinyxml2.h"
nuclear@19 22 #include "log.h"
nuclear@19 23
nuclear@47 24 using namespace g3dimpl;
nuclear@19 25 using namespace tinyxml2;
nuclear@19 26
nuclear@19 27 static Material *read_material(Scene *scn, XMLElement *xml_mtl);
nuclear@19 28 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
nuclear@19 29 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
nuclear@19 30 static std::string get_name(XMLElement *node, int idx);
nuclear@19 31
nuclear@19 32 bool Scene::loadxml(goat3d_io *io)
nuclear@19 33 {
nuclear@19 34 long bytes = io->seek(0, SEEK_END, io->cls);
nuclear@19 35 io->seek(0, SEEK_SET, io->cls);
nuclear@19 36
nuclear@19 37 char *buf = new char[bytes];
nuclear@19 38 if(io->read(buf, bytes, io->cls) < bytes) {
nuclear@19 39 logmsg(LOG_ERROR, "failed to read XML scene file\n");
nuclear@45 40 delete [] buf;
nuclear@19 41 return false;
nuclear@19 42 }
nuclear@19 43
nuclear@19 44 XMLDocument xml;
nuclear@19 45 XMLError err = xml.Parse(buf, bytes);
nuclear@19 46 if(err) {
nuclear@19 47 logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
nuclear@19 48 xml.GetErrorStr2());
nuclear@45 49 delete [] buf;
nuclear@19 50 return false;
nuclear@19 51 }
nuclear@19 52
nuclear@19 53 XMLElement *root = xml.RootElement();
nuclear@19 54 if(strcmp(root->Name(), "scene") != 0) {
nuclear@19 55 logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
nuclear@45 56 delete [] buf;
nuclear@19 57 return false;
nuclear@19 58 }
nuclear@19 59
nuclear@19 60 XMLElement *elem;
nuclear@19 61
nuclear@19 62 // get all materials
nuclear@19 63 elem = root->FirstChildElement("mtl");
nuclear@19 64 while(elem) {
nuclear@19 65 Material *mtl = read_material(this, elem);
nuclear@19 66 if(mtl) {
nuclear@19 67 add_material(mtl);
nuclear@19 68 }
nuclear@19 69 elem = elem->NextSiblingElement("mtl");
nuclear@19 70 }
nuclear@19 71
nuclear@19 72 // get all meshes
nuclear@19 73 elem = root->FirstChildElement("mesh");
nuclear@19 74 while(elem) {
nuclear@19 75 Mesh *mesh = read_mesh(this, elem);
nuclear@19 76 if(mesh) {
nuclear@19 77 add_mesh(mesh);
nuclear@19 78 }
nuclear@19 79 elem = elem->NextSiblingElement("mesh");
nuclear@19 80 }
nuclear@19 81
nuclear@45 82 delete [] buf;
nuclear@45 83 return true;
nuclear@19 84 }
nuclear@19 85
nuclear@51 86 bool Scene::load_anim_xml(goat3d_io *io)
nuclear@51 87 {
nuclear@51 88 long bytes = io->seek(0, SEEK_END, io->cls);
nuclear@51 89 io->seek(0, SEEK_SET, io->cls);
nuclear@51 90
nuclear@51 91 char *buf = new char[bytes];
nuclear@51 92 if(io->read(buf, bytes, io->cls) < bytes) {
nuclear@51 93 logmsg(LOG_ERROR, "failed to read XML animation file\n");
nuclear@51 94 delete [] buf;
nuclear@51 95 return false;
nuclear@51 96 }
nuclear@51 97
nuclear@51 98 XMLDocument xml;
nuclear@51 99 XMLError err = xml.Parse(buf, bytes);
nuclear@51 100 if(err) {
nuclear@51 101 logmsg(LOG_ERROR, "failed to parse XML animation file: %s\n%s\n", xml.GetErrorStr1(),
nuclear@51 102 xml.GetErrorStr2());
nuclear@51 103 delete [] buf;
nuclear@51 104 return false;
nuclear@51 105 }
nuclear@51 106
nuclear@51 107 XMLElement *root = xml.RootElement();
nuclear@51 108 if(strcmp(root->Name(), "anim") != 0) {
nuclear@51 109 logmsg(LOG_ERROR, "invalid XML file, root node is not <anim>\n");
nuclear@51 110 delete [] buf;
nuclear@51 111 return false;
nuclear@51 112 }
nuclear@51 113
nuclear@51 114 XMLElement *elem;
nuclear@51 115
nuclear@51 116 elem = root->FirstChildElement();
nuclear@51 117 while(elem) {
nuclear@51 118 const char *elem_name = elem->Name();
nuclear@51 119
nuclear@51 120 if(strcmp(elem_name, "name") == 0) {
nuclear@51 121 } else if(strcmp(elem_name, "attr") == 0) {
nuclear@51 122 }
nuclear@51 123 elem = elem->NextSiblingElement();
nuclear@51 124 }
nuclear@51 125
nuclear@51 126 delete [] buf;
nuclear@51 127 return true;
nuclear@51 128 }
nuclear@19 129
nuclear@19 130 static Material *read_material(Scene *scn, XMLElement *xml_mtl)
nuclear@19 131 {
nuclear@19 132 Material *mtl = new Material;
nuclear@19 133 mtl->name = get_name(xml_mtl, scn->get_material_count());
nuclear@19 134
nuclear@19 135 // get all the material attributes in turn
nuclear@19 136 XMLElement *elem = xml_mtl->FirstChildElement("attr");
nuclear@19 137 while(elem) {
nuclear@19 138 MaterialAttrib attr;
nuclear@19 139 const char *name = read_material_attrib(&attr, elem);
nuclear@19 140 if(name) {
nuclear@19 141 (*mtl)[name] = attr;
nuclear@19 142 }
nuclear@19 143
nuclear@19 144 elem = elem->NextSiblingElement("attr");
nuclear@19 145 }
nuclear@19 146
nuclear@19 147 return mtl;
nuclear@19 148 }
nuclear@19 149
nuclear@19 150 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
nuclear@19 151 {
nuclear@19 152 const char *name;
nuclear@19 153
nuclear@19 154 XMLElement *elem;
nuclear@19 155 if((elem = xml_attr->FirstChildElement("name"))) {
nuclear@19 156 if(!(name = elem->Attribute("string"))) {
nuclear@19 157 return 0;
nuclear@19 158 }
nuclear@19 159 }
nuclear@19 160
nuclear@19 161 if((elem = xml_attr->FirstChildElement("val"))) {
nuclear@19 162 if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
nuclear@19 163 // try a float3
nuclear@19 164 const char *valstr = elem->Attribute("float3");
nuclear@19 165 if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
nuclear@19 166 &attr->value.z) != 3) {
nuclear@19 167 // try a float4
nuclear@19 168 valstr = elem->Attribute("float4");
nuclear@19 169 if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
nuclear@19 170 &attr->value.z, &attr->value.w) != 4) {
nuclear@19 171 // no valid val attribute found
nuclear@19 172 return 0;
nuclear@19 173 }
nuclear@19 174 }
nuclear@19 175 }
nuclear@19 176 }
nuclear@19 177
nuclear@19 178 if((elem = xml_attr->FirstChildElement("map"))) {
nuclear@19 179 const char *tex = elem->Attribute("string");
nuclear@19 180 if(tex) {
nuclear@19 181 attr->map = std::string(tex);
nuclear@19 182 }
nuclear@19 183 }
nuclear@19 184
nuclear@19 185 return name;
nuclear@19 186 }
nuclear@19 187
nuclear@19 188 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
nuclear@19 189 {
nuclear@19 190 Mesh *mesh = new Mesh;
nuclear@19 191 mesh->name = get_name(xml_mesh, scn->get_mesh_count());
nuclear@19 192
nuclear@19 193 XMLElement *elem;
nuclear@19 194 if((elem = xml_mesh->FirstChildElement("material"))) {
nuclear@19 195 int idx;
nuclear@19 196 if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
nuclear@19 197 mesh->material = scn->get_material(idx);
nuclear@19 198 } else {
nuclear@19 199 // try string
nuclear@19 200 const char *mtlstr = elem->Attribute("string");
nuclear@19 201 if(mtlstr) {
nuclear@19 202 mesh->material = scn->get_material(mtlstr);
nuclear@19 203 }
nuclear@19 204 }
nuclear@19 205 }
nuclear@19 206
nuclear@19 207 /* reading mesh data from XML is not supported, only MESH_FILE can be used to
nuclear@19 208 * specify an external mesh file to be loaded
nuclear@19 209 */
nuclear@19 210
nuclear@19 211 if((elem = xml_mesh->FirstChildElement("file"))) {
nuclear@19 212 const char *fname = elem->Attribute("string");
nuclear@19 213 if(fname) {
nuclear@74 214 char *path = (char*)fname;
nuclear@74 215 if(scn->goat->search_path) {
nuclear@74 216 path = (char*)alloca(strlen(fname) + strlen(scn->goat->search_path) + 2);
nuclear@74 217 sprintf(path, "%s/%s", scn->goat->search_path, fname);
nuclear@74 218 }
nuclear@74 219 if(!mesh->load(path)) {
nuclear@19 220 delete mesh;
nuclear@19 221 return 0;
nuclear@19 222 }
nuclear@19 223 }
nuclear@19 224 }
nuclear@19 225
nuclear@19 226 return mesh;
nuclear@19 227 }
nuclear@19 228
nuclear@19 229 static std::string get_name(XMLElement *node, int idx)
nuclear@19 230 {
nuclear@19 231 char buf[64];
nuclear@19 232 const char *name = 0;
nuclear@19 233
nuclear@19 234 XMLElement *elem;
nuclear@19 235 if((elem = node->FirstChildElement("name"))) {
nuclear@19 236 name = elem->Attribute("string");
nuclear@19 237 }
nuclear@19 238
nuclear@19 239 if(!name) {
nuclear@19 240 sprintf(buf, "mesh%04d", idx);
nuclear@19 241 name = buf;
nuclear@19 242 }
nuclear@19 243
nuclear@19 244 return std::string(name);
nuclear@19 245 }