goat3d

diff src/goat3d_readxml.cc @ 95:da100bf13f7f

[goat3d] implemented animation loading [goatview] working on the animation controls
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 19 May 2014 06:42:40 +0300
parents 21319e71117f
children 20b04b4edad4
line diff
     1.1 --- a/src/goat3d_readxml.cc	Sun May 18 19:58:47 2014 +0300
     1.2 +++ b/src/goat3d_readxml.cc	Mon May 19 06:42:40 2014 +0300
     1.3 @@ -18,6 +18,7 @@
     1.4  #include <stdio.h>
     1.5  #include <map>
     1.6  #include <string>
     1.7 +#include <algorithm>
     1.8  #include "goat3d.h"
     1.9  #include "goat3d_impl.h"
    1.10  #include "tinyxml2.h"
    1.11 @@ -26,6 +27,14 @@
    1.12  using namespace g3dimpl;
    1.13  using namespace tinyxml2;
    1.14  
    1.15 +struct Key {
    1.16 +	long tm;
    1.17 +	Vector4 val;
    1.18 +};
    1.19 +
    1.20 +static bool read_track(Scene *scn, XMLElement *xml_track, int *anim_idx);
    1.21 +static Key read_key(XMLElement *xml_key);
    1.22 +
    1.23  static Material *read_material(Scene *scn, XMLElement *xml_mtl);
    1.24  static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
    1.25  static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
    1.26 @@ -132,27 +141,164 @@
    1.27  
    1.28  	XMLElement *root = xml.RootElement();
    1.29  	if(strcmp(root->Name(), "anim") != 0) {
    1.30 -		logmsg(LOG_ERROR, "invalid XML file, root node is not <anim>\n");
    1.31 +		logmsg(LOG_ERROR, "%s: root node is not <anim>\n", __FUNCTION__);
    1.32  		delete [] buf;
    1.33  		return false;
    1.34  	}
    1.35  
    1.36 -	XMLElement *elem;
    1.37 -
    1.38 -	elem = root->FirstChildElement();
    1.39 +	int anim_idx = -1;
    1.40 +	XMLElement *elem = root->FirstChildElement();
    1.41  	while(elem) {
    1.42  		const char *elem_name = elem->Name();
    1.43  
    1.44 -		if(strcmp(elem_name, "name") == 0) {
    1.45 -		} else if(strcmp(elem_name, "attr") == 0) {
    1.46 +		if(strcmp(elem_name, "track") != 0) {
    1.47 +			logmsg(LOG_ERROR, "%s: only <track>s allowed in <anim>\n", __FUNCTION__);
    1.48 +			delete [] buf;
    1.49 +			return false;
    1.50 +		}
    1.51 +
    1.52 +		if(!read_track(this, elem, &anim_idx)) {
    1.53 +			delete [] buf;
    1.54 +			return false;
    1.55  		}
    1.56  		elem = elem->NextSiblingElement();
    1.57  	}
    1.58  
    1.59 +	if(anim_idx == -1) {
    1.60 +		logmsg(LOG_INFO, "%s: WARNING animation affected 0 nodes\n", __FUNCTION__);
    1.61 +	}
    1.62 +
    1.63  	delete [] buf;
    1.64  	return true;
    1.65  }
    1.66  
    1.67 +static bool read_track(Scene *scn, XMLElement *xml_track, int *anim_idx)
    1.68 +{
    1.69 +	Node *node = 0;
    1.70 +	int type = -1;
    1.71 +	std::vector<Key> keys;
    1.72 +
    1.73 +	XMLElement *elem = xml_track->FirstChildElement();
    1.74 +	while(elem) {
    1.75 +		const char *elem_name = elem->Name();
    1.76 +
    1.77 +		if(strcmp(elem_name, "node") == 0) {
    1.78 +			const char *name = elem->Attribute("string");
    1.79 +			if(!name || !(node = scn->get_node(name))) {
    1.80 +				logmsg(LOG_ERROR, "%s: invalid track node: %s\n", __FUNCTION__, name);
    1.81 +				return false;
    1.82 +			}
    1.83 +
    1.84 +		} else if(strcmp(elem_name, "attr") == 0) {
    1.85 +			const char *str = elem->Attribute("string");
    1.86 +			if(str && strcmp(str, "position") == 0) {
    1.87 +				type = XFormNode::POSITION_TRACK;
    1.88 +			} else if(str && strcmp(str, "rotation") == 0) {
    1.89 +				type = XFormNode::ROTATION_TRACK;
    1.90 +			} else if(str && strcmp(str, "scaling") == 0) {
    1.91 +				type = XFormNode::SCALING_TRACK;
    1.92 +			} else {
    1.93 +				logmsg(LOG_ERROR, "%s: invalid track attribute specifier: %s\n", __FUNCTION__, str);
    1.94 +				return false;
    1.95 +			}
    1.96 +
    1.97 +		} else if(strcmp(elem_name, "key") == 0) {
    1.98 +			Key key = read_key(elem);
    1.99 +			if(key.tm == LONG_MIN) {
   1.100 +				return false;	// logging in read_key
   1.101 +			}
   1.102 +			keys.push_back(key);
   1.103 +
   1.104 +		} else {
   1.105 +			logmsg(LOG_ERROR, "%s: unexpected element <%s> in <track>\n", __FUNCTION__, elem_name);
   1.106 +			return false;
   1.107 +		}
   1.108 +		elem = elem->NextSiblingElement();
   1.109 +	}
   1.110 +
   1.111 +	if(!node) {
   1.112 +		logmsg(LOG_ERROR, "%s: invalid track, missing node reference\n", __FUNCTION__);
   1.113 +		return false;
   1.114 +	}
   1.115 +	if(type == -1) {
   1.116 +		logmsg(LOG_ERROR, "%s: invalid track, missing attribute specifier\n", __FUNCTION__);
   1.117 +		return false;
   1.118 +	}
   1.119 +
   1.120 +	if(*anim_idx == -1) {
   1.121 +		// this is the first node we encounter. add a new animation and activate it
   1.122 +		XFormNode *root = node->get_root();
   1.123 +		*anim_idx = root->get_animation_count() + 1;
   1.124 +
   1.125 +		char name[64];
   1.126 +		sprintf(name, "anim%03d\n", *anim_idx);
   1.127 +		root->add_animation(name);
   1.128 +		root->use_animation(*anim_idx);
   1.129 +	} else {
   1.130 +		// make sure this node hierarchy already has this animation, otherwise add it
   1.131 +		XFormNode *root = node->get_root();
   1.132 +		if(root->get_active_animation_index() != *anim_idx) {
   1.133 +			char name[64];
   1.134 +			sprintf(name, "anim%03d\n", *anim_idx);
   1.135 +			root->add_animation(name);
   1.136 +			root->use_animation(*anim_idx);
   1.137 +		}
   1.138 +	}
   1.139 +
   1.140 +	for(auto key : keys) {
   1.141 +		switch(type) {
   1.142 +		case XFormNode::POSITION_TRACK:
   1.143 +			node->set_position(Vector3(key.val.x, key.val.y, key.val.z), key.tm);
   1.144 +			break;
   1.145 +		case XFormNode::ROTATION_TRACK:
   1.146 +			node->set_rotation(Quaternion(key.val.w, key.val.x, key.val.y, key.val.z), key.tm);
   1.147 +			break;
   1.148 +		case XFormNode::SCALING_TRACK:
   1.149 +			node->set_scaling(Vector3(key.val.x, key.val.y, key.val.z), key.tm);
   1.150 +		}
   1.151 +	}
   1.152 +	return true;
   1.153 +}
   1.154 +
   1.155 +static Key read_key(XMLElement *xml_key)
   1.156 +{
   1.157 +	Key key;
   1.158 +	key.tm = LONG_MIN;	// initialize to invalid time
   1.159 +
   1.160 +	XMLElement *xml_time = xml_key->FirstChildElement("time");
   1.161 +	XMLElement *xml_value = xml_key->FirstChildElement("value");
   1.162 +
   1.163 +	if(!xml_time || !xml_value) {
   1.164 +		logmsg(LOG_ERROR, "%s: invalid key, missing either <time> or <value> elements\n", __FUNCTION__);
   1.165 +		return key;
   1.166 +	}
   1.167 +
   1.168 +	int ival;
   1.169 +	if(xml_time->QueryIntAttribute("int", &ival) != XML_NO_ERROR) {
   1.170 +		logmsg(LOG_ERROR, "%s: invalid time element in <key>\n", __FUNCTION__);
   1.171 +		return key;
   1.172 +	}
   1.173 +
   1.174 +	const char *vstr;
   1.175 +	if((vstr = xml_value->Attribute("float3"))) {
   1.176 +		if(sscanf(vstr, "%f %f %f", &key.val.x, &key.val.y, &key.val.z) != 3) {
   1.177 +			logmsg(LOG_ERROR, "%s: invalid float3 value element in <key>: %s\n", __FUNCTION__, vstr);
   1.178 +			return key;
   1.179 +		}
   1.180 +	} else if((vstr = xml_value->Attribute("float4"))) {
   1.181 +		if(sscanf(vstr, "%f %f %f %f", &key.val.x, &key.val.y, &key.val.z, &key.val.w) != 4) {
   1.182 +			logmsg(LOG_ERROR, "%s: invalid float4 value element in <key>: %s\n", __FUNCTION__, vstr);
   1.183 +			return key;
   1.184 +		}
   1.185 +	} else {
   1.186 +		logmsg(LOG_ERROR, "%s: invalid value element in <key>: missing float3 or float4 attributes\n", __FUNCTION__);
   1.187 +		return key;
   1.188 +	}
   1.189 +
   1.190 +	key.tm = ival;
   1.191 +	return key;
   1.192 +}
   1.193 +
   1.194  static Material *read_material(Scene *scn, XMLElement *xml_mtl)
   1.195  {
   1.196  	Material *mtl = new Material;