goat3d
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/goat3d_readxml.cc Fri Sep 27 06:58:37 2013 +0300 1.3 @@ -0,0 +1,175 @@ 1.4 +#include <stdio.h> 1.5 +#include "goat3d.h" 1.6 +#include "goat3d_impl.h" 1.7 +#include "tinyxml2.h" 1.8 +#include "log.h" 1.9 + 1.10 +using namespace tinyxml2; 1.11 + 1.12 +static Material *read_material(Scene *scn, XMLElement *xml_mtl); 1.13 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr); 1.14 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh); 1.15 +static std::string get_name(XMLElement *node, int idx); 1.16 + 1.17 +bool Scene::loadxml(goat3d_io *io) 1.18 +{ 1.19 + long bytes = io->seek(0, SEEK_END, io->cls); 1.20 + io->seek(0, SEEK_SET, io->cls); 1.21 + 1.22 + char *buf = new char[bytes]; 1.23 + if(io->read(buf, bytes, io->cls) < bytes) { 1.24 + logmsg(LOG_ERROR, "failed to read XML scene file\n"); 1.25 + return false; 1.26 + } 1.27 + 1.28 + XMLDocument xml; 1.29 + XMLError err = xml.Parse(buf, bytes); 1.30 + if(err) { 1.31 + logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(), 1.32 + xml.GetErrorStr2()); 1.33 + return false; 1.34 + } 1.35 + 1.36 + XMLElement *root = xml.RootElement(); 1.37 + if(strcmp(root->Name(), "scene") != 0) { 1.38 + logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n"); 1.39 + return false; 1.40 + } 1.41 + 1.42 + XMLElement *elem; 1.43 + 1.44 + // get all materials 1.45 + elem = root->FirstChildElement("mtl"); 1.46 + while(elem) { 1.47 + Material *mtl = read_material(this, elem); 1.48 + if(mtl) { 1.49 + add_material(mtl); 1.50 + } 1.51 + elem = elem->NextSiblingElement("mtl"); 1.52 + } 1.53 + 1.54 + // get all meshes 1.55 + elem = root->FirstChildElement("mesh"); 1.56 + while(elem) { 1.57 + Mesh *mesh = read_mesh(this, elem); 1.58 + if(mesh) { 1.59 + add_mesh(mesh); 1.60 + } 1.61 + elem = elem->NextSiblingElement("mesh"); 1.62 + } 1.63 + 1.64 + return false; 1.65 +} 1.66 + 1.67 + 1.68 +static Material *read_material(Scene *scn, XMLElement *xml_mtl) 1.69 +{ 1.70 + Material *mtl = new Material; 1.71 + mtl->name = get_name(xml_mtl, scn->get_material_count()); 1.72 + 1.73 + // get all the material attributes in turn 1.74 + XMLElement *elem = xml_mtl->FirstChildElement("attr"); 1.75 + while(elem) { 1.76 + MaterialAttrib attr; 1.77 + const char *name = read_material_attrib(&attr, elem); 1.78 + if(name) { 1.79 + (*mtl)[name] = attr; 1.80 + } 1.81 + 1.82 + elem = elem->NextSiblingElement("attr"); 1.83 + } 1.84 + 1.85 + return mtl; 1.86 +} 1.87 + 1.88 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr) 1.89 +{ 1.90 + const char *name; 1.91 + 1.92 + XMLElement *elem; 1.93 + if((elem = xml_attr->FirstChildElement("name"))) { 1.94 + if(!(name = elem->Attribute("string"))) { 1.95 + return 0; 1.96 + } 1.97 + } 1.98 + 1.99 + if((elem = xml_attr->FirstChildElement("val"))) { 1.100 + if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) { 1.101 + // try a float3 1.102 + const char *valstr = elem->Attribute("float3"); 1.103 + if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y, 1.104 + &attr->value.z) != 3) { 1.105 + // try a float4 1.106 + valstr = elem->Attribute("float4"); 1.107 + if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y, 1.108 + &attr->value.z, &attr->value.w) != 4) { 1.109 + // no valid val attribute found 1.110 + return 0; 1.111 + } 1.112 + } 1.113 + } 1.114 + } 1.115 + 1.116 + if((elem = xml_attr->FirstChildElement("map"))) { 1.117 + const char *tex = elem->Attribute("string"); 1.118 + if(tex) { 1.119 + attr->map = std::string(tex); 1.120 + } 1.121 + } 1.122 + 1.123 + return name; 1.124 +} 1.125 + 1.126 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh) 1.127 +{ 1.128 + Mesh *mesh = new Mesh; 1.129 + mesh->name = get_name(xml_mesh, scn->get_mesh_count()); 1.130 + 1.131 + XMLElement *elem; 1.132 + if((elem = xml_mesh->FirstChildElement("material"))) { 1.133 + int idx; 1.134 + if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) { 1.135 + mesh->material = scn->get_material(idx); 1.136 + } else { 1.137 + // try string 1.138 + const char *mtlstr = elem->Attribute("string"); 1.139 + if(mtlstr) { 1.140 + mesh->material = scn->get_material(mtlstr); 1.141 + } 1.142 + } 1.143 + } 1.144 + 1.145 + /* reading mesh data from XML is not supported, only MESH_FILE can be used to 1.146 + * specify an external mesh file to be loaded 1.147 + */ 1.148 + 1.149 + if((elem = xml_mesh->FirstChildElement("file"))) { 1.150 + const char *fname = elem->Attribute("string"); 1.151 + if(fname) { 1.152 + if(!mesh->load(fname)) { 1.153 + delete mesh; 1.154 + return 0; 1.155 + } 1.156 + } 1.157 + } 1.158 + 1.159 + return mesh; 1.160 +} 1.161 + 1.162 +static std::string get_name(XMLElement *node, int idx) 1.163 +{ 1.164 + char buf[64]; 1.165 + const char *name = 0; 1.166 + 1.167 + XMLElement *elem; 1.168 + if((elem = node->FirstChildElement("name"))) { 1.169 + name = elem->Attribute("string"); 1.170 + } 1.171 + 1.172 + if(!name) { 1.173 + sprintf(buf, "mesh%04d", idx); 1.174 + name = buf; 1.175 + } 1.176 + 1.177 + return std::string(name); 1.178 +}