goat3d

annotate src/goat3d_writexml.cc @ 48:9ef9de80649c

implemented animation track XML saving
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 29 Dec 2013 06:01:59 +0200
parents 498ca7ac7047
children fa5c52ea9d59
rev   line source
nuclear@47 1 #include <list>
nuclear@14 2 #include <stdarg.h>
nuclear@14 3 #include "goat3d_impl.h"
nuclear@47 4 #include "anim/anim.h"
nuclear@17 5 #include "log.h"
nuclear@14 6
nuclear@47 7 using namespace g3dimpl;
nuclear@47 8
nuclear@14 9 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level);
nuclear@14 10 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level);
nuclear@14 11 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level);
nuclear@14 12 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level);
nuclear@14 13 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level);
nuclear@47 14 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level);
nuclear@14 15 static void xmlout(goat3d_io *io, int level, const char *fmt, ...);
nuclear@14 16
nuclear@14 17 bool Scene::savexml(goat3d_io *io) const
nuclear@14 18 {
nuclear@14 19 xmlout(io, 0, "<scene>\n");
nuclear@14 20
nuclear@14 21 // write environment stuff
nuclear@14 22 xmlout(io, 1, "<env>\n");
nuclear@18 23 xmlout(io, 2, "<ambient float3=\"%g %g %g\"/>\n", ambient.x, ambient.y, ambient.z);
nuclear@18 24 xmlout(io, 1, "</env>\n\n");
nuclear@14 25
nuclear@14 26 for(size_t i=0; i<materials.size(); i++) {
nuclear@14 27 write_material(this, io, materials[i], 1);
nuclear@14 28 }
nuclear@14 29 for(size_t i=0; i<meshes.size(); i++) {
nuclear@14 30 write_mesh(this, io, meshes[i], i, 1);
nuclear@14 31 }
nuclear@14 32 for(size_t i=0; i<lights.size(); i++) {
nuclear@14 33 write_light(this, io, lights[i], 1);
nuclear@14 34 }
nuclear@14 35 for(size_t i=0; i<cameras.size(); i++) {
nuclear@14 36 write_camera(this, io, cameras[i], 1);
nuclear@14 37 }
nuclear@14 38 for(size_t i=0; i<nodes.size(); i++) {
nuclear@14 39 write_node(this, io, nodes[i], 1);
nuclear@14 40 }
nuclear@14 41
nuclear@14 42 xmlout(io, 0, "</scene>\n");
nuclear@14 43 return true;
nuclear@14 44 }
nuclear@14 45
nuclear@47 46 static void collect_nodes(std::list<const XFormNode*> *res, const XFormNode *node)
nuclear@47 47 {
nuclear@47 48 if(!node) return;
nuclear@47 49
nuclear@47 50 res->push_back(node);
nuclear@47 51
nuclear@47 52 for(int i=0; i<node->get_children_count(); i++) {
nuclear@47 53 collect_nodes(res, node->get_child(i));
nuclear@47 54 }
nuclear@47 55 }
nuclear@47 56
nuclear@47 57 bool Scene::save_anim_xml(const XFormNode *node, goat3d_io *io) const
nuclear@47 58 {
nuclear@47 59 xmlout(io, 0, "<anim>\n");
nuclear@47 60
nuclear@47 61 const char *anim_name = node->get_animation_name();
nuclear@47 62 if(anim_name && *anim_name) {
nuclear@47 63 xmlout(io, 1, "<name string=\"%s\"/>\n", anim_name);
nuclear@47 64 }
nuclear@47 65
nuclear@47 66 std::list<const XFormNode*> allnodes;
nuclear@47 67 collect_nodes(&allnodes, node);
nuclear@47 68
nuclear@47 69 std::list<const XFormNode*>::const_iterator it = allnodes.begin();
nuclear@47 70 while(it != allnodes.end()) {
nuclear@47 71 const XFormNode *n = *it++;
nuclear@47 72 write_node_anim(io, n, 1);
nuclear@47 73 }
nuclear@47 74
nuclear@47 75 xmlout(io, 0, "</anim>\n");
nuclear@47 76 return true;
nuclear@47 77 }
nuclear@47 78
nuclear@14 79 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level)
nuclear@14 80 {
nuclear@14 81 xmlout(io, level, "<mtl>\n");
nuclear@14 82 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mat->name.c_str());
nuclear@14 83
nuclear@14 84 for(int i=0; i<mat->get_attrib_count(); i++) {
nuclear@14 85 xmlout(io, level + 1, "<attr>\n");
nuclear@14 86 xmlout(io, level + 2, "<name string=\"%s\"/>\n", mat->get_attrib_name(i));
nuclear@14 87
nuclear@14 88 const MaterialAttrib &attr = (*mat)[i];
nuclear@18 89 xmlout(io, level + 2, "<val float4=\"%g %g %g %g\"/>\n", attr.value.x,
nuclear@14 90 attr.value.y, attr.value.z, attr.value.w);
nuclear@14 91 if(!attr.map.empty()) {
nuclear@14 92 xmlout(io, level + 2, "<map string=\"%s\"/>\n", attr.map.c_str());
nuclear@14 93 }
nuclear@14 94 xmlout(io, level + 1, "</attr>\n");
nuclear@14 95 }
nuclear@18 96 xmlout(io, level, "</mtl>\n\n");
nuclear@14 97 return true;
nuclear@14 98 }
nuclear@14 99
nuclear@14 100 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level)
nuclear@14 101 {
nuclear@14 102 // first write the external (openctm) mesh file
nuclear@14 103 const char *prefix = scn->get_name();
nuclear@14 104 if(!prefix) {
nuclear@14 105 prefix = "goat";
nuclear@14 106 }
nuclear@14 107
nuclear@14 108 char *mesh_filename = (char*)alloca(strlen(prefix) + 32);
nuclear@14 109 sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx);
nuclear@14 110
nuclear@19 111 if(!mesh->save(mesh_filename)) {
nuclear@19 112 return false;
nuclear@19 113 }
nuclear@14 114
nuclear@14 115 // then refer to that filename in the XML tags
nuclear@14 116 xmlout(io, level, "<mesh>\n");
nuclear@14 117 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mesh->name.c_str());
nuclear@17 118 if(mesh->material) {
nuclear@17 119 xmlout(io, level + 1, "<material string=\"%s\"/>\n", mesh->material->name.c_str());
nuclear@17 120 }
nuclear@40 121 xmlout(io, level + 1, "<file string=\"%s\"/>\n", goat3d_clean_filename(mesh_filename).c_str());
nuclear@18 122 xmlout(io, level, "</mesh>\n\n");
nuclear@14 123 return true;
nuclear@14 124 }
nuclear@14 125
nuclear@14 126 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level)
nuclear@14 127 {
nuclear@14 128 return true;
nuclear@14 129 }
nuclear@14 130
nuclear@14 131 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level)
nuclear@14 132 {
nuclear@14 133 return true;
nuclear@14 134 }
nuclear@14 135
nuclear@14 136 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level)
nuclear@14 137 {
nuclear@30 138 xmlout(io, level, "<node>\n");
nuclear@30 139 xmlout(io, level + 1, "<name string=\"%s\"/>\n", node->get_name());
nuclear@30 140
nuclear@47 141 const XFormNode *parent = node->get_parent();
nuclear@30 142 if(parent) {
nuclear@30 143 xmlout(io, level + 1, "<parent string=\"%s\"/>\n", parent->get_name());
nuclear@30 144 }
nuclear@30 145
nuclear@30 146 const char *type = 0;
nuclear@30 147 const Object *obj = node->get_object();
nuclear@30 148 if(dynamic_cast<const Mesh*>(obj)) {
nuclear@30 149 type = "mesh";
nuclear@30 150 } else if(dynamic_cast<const Light*>(obj)) {
nuclear@30 151 type = "light";
nuclear@30 152 } else if(dynamic_cast<const Camera*>(obj)) {
nuclear@30 153 type = "camera";
nuclear@30 154 }
nuclear@30 155
nuclear@30 156 if(type) {
nuclear@30 157 xmlout(io, level + 1, "<%s string=\"%s\"/>\n", type, obj->name.c_str());
nuclear@30 158 }
nuclear@30 159
nuclear@30 160 Vector3 pos = node->get_node_position();
nuclear@30 161 Quaternion rot = node->get_node_rotation();
nuclear@30 162 Vector3 scale = node->get_node_scaling();
nuclear@30 163 Vector3 pivot = node->get_pivot();
nuclear@30 164
nuclear@30 165 Matrix4x4 xform;
nuclear@30 166 node->get_node_xform(0, &xform);
nuclear@30 167
nuclear@30 168 xmlout(io, level + 1, "<pos float3=\"%g %g %g\"/>\n", pos.x, pos.y, pos.z);
nuclear@30 169 xmlout(io, level + 1, "<rot float4=\"%g %g %g %g\"/>\n", rot.v.x, rot.v.y, rot.v.z, rot.s);
nuclear@30 170 xmlout(io, level + 1, "<scale float3=\"%g %g %g\"/>\n", scale.x, scale.y, scale.z);
nuclear@30 171 xmlout(io, level + 1, "<pivot float3=\"%g %g %g\"/>\n", pivot.x, pivot.y, pivot.z);
nuclear@30 172
nuclear@30 173 xmlout(io, level + 1, "<matrix0 float4=\"%g %g %g %g\"/>\n", xform[0][0], xform[0][1], xform[0][2], xform[0][3]);
nuclear@30 174 xmlout(io, level + 1, "<matrix1 float4=\"%g %g %g %g\"/>\n", xform[1][0], xform[1][1], xform[1][2], xform[1][3]);
nuclear@30 175 xmlout(io, level + 1, "<matrix2 float4=\"%g %g %g %g\"/>\n", xform[2][0], xform[2][1], xform[2][2], xform[2][3]);
nuclear@30 176
nuclear@30 177 xmlout(io, level, "</node>\n");
nuclear@14 178 return true;
nuclear@14 179 }
nuclear@14 180
nuclear@47 181 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level)
nuclear@47 182 {
nuclear@48 183 /* NOTE: the order of names must correspond to the order of
nuclear@48 184 * XFormNode::POSITION_TRACK/ROTATION_TRACK/SCALING_TRACK enum
nuclear@48 185 */
nuclear@47 186 static const char *attr_names[] = { "position", "rotation", "scaling" };
nuclear@47 187
nuclear@48 188 // for each of: position/rotation/scaling
nuclear@48 189 for(int i=0; i<3; i++) {
nuclear@48 190 int num_keys = node->get_key_count(i);
nuclear@48 191 if(!num_keys) continue;
nuclear@47 192
nuclear@47 193 xmlout(io, level + 1, "<track>\n");
nuclear@47 194 xmlout(io, level + 2, "<node string=\"%s\"/>\n", node->get_name());
nuclear@48 195 xmlout(io, level + 2, "<attr string=\"%s\"/>\n\n", attr_names[i]);
nuclear@47 196
nuclear@48 197 // for each key in that track
nuclear@48 198 for(int j=0; j<num_keys; j++) {
nuclear@48 199 long tm = node->get_key_time(i, j);
nuclear@48 200
nuclear@48 201 float value[4];
nuclear@48 202 int num_elems = node->get_key_value(i, j, value);
nuclear@48 203
nuclear@48 204 if(num_elems == 3) {
nuclear@48 205 xmlout(io, level + 2, "<key><time int=\"%ld\"/><value float3=\"%g %g %g\"/></key>\n",
nuclear@48 206 tm, value[0], value[1], value[2]);
nuclear@48 207 } else {
nuclear@48 208 xmlout(io, level + 2, "<key><time int=\"%ld\"/><value float4=\"%g %g %g %g\"/></key>\n",
nuclear@48 209 tm, value[0], value[1], value[2], value[3]);
nuclear@48 210 }
nuclear@48 211 }
nuclear@47 212
nuclear@47 213 xmlout(io, level + 1, "</track>\n");
nuclear@47 214 }
nuclear@47 215 return true;
nuclear@47 216 }
nuclear@14 217
nuclear@14 218 static void xmlout(goat3d_io *io, int level, const char *fmt, ...)
nuclear@14 219 {
nuclear@14 220 for(int i=0; i<level; i++) {
nuclear@14 221 io_fprintf(io, " ");
nuclear@14 222 }
nuclear@14 223
nuclear@14 224 va_list ap;
nuclear@14 225 va_start(ap, fmt);
nuclear@14 226 io_vfprintf(io, fmt, ap);
nuclear@14 227 va_end(ap);
nuclear@14 228 }