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 +}