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;