goat3d

annotate src/goat3d_writexml.cc @ 90:8b156bc5205b

[maxgoat] fixed the transform export bug [goatview] added widgets for the animation controls [goatview] added a grid ground plane with automatic sizing and transitions from size to size
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 17 May 2014 06:26:24 +0300
parents 99715321ad6d
children
rev   line source
nuclear@54 1 /*
nuclear@54 2 goat3d - 3D scene, character, and animation file format library.
nuclear@54 3 Copyright (C) 2013-2014 John Tsiombikas <nuclear@member.fsf.org>
nuclear@54 4
nuclear@54 5 This program is free software: you can redistribute it and/or modify
nuclear@54 6 it under the terms of the GNU Lesser General Public License as published by
nuclear@54 7 the Free Software Foundation, either version 3 of the License, or
nuclear@54 8 (at your option) any later version.
nuclear@54 9
nuclear@54 10 This program is distributed in the hope that it will be useful,
nuclear@54 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@54 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@54 13 GNU Lesser General Public License for more details.
nuclear@54 14
nuclear@54 15 You should have received a copy of the GNU Lesser General Public License
nuclear@54 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@54 17 */
nuclear@47 18 #include <list>
nuclear@14 19 #include <stdarg.h>
nuclear@14 20 #include "goat3d_impl.h"
nuclear@47 21 #include "anim/anim.h"
nuclear@17 22 #include "log.h"
nuclear@14 23
nuclear@47 24 using namespace g3dimpl;
nuclear@47 25
nuclear@14 26 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level);
nuclear@14 27 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level);
nuclear@14 28 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level);
nuclear@14 29 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level);
nuclear@14 30 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level);
nuclear@47 31 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level);
nuclear@14 32 static void xmlout(goat3d_io *io, int level, const char *fmt, ...);
nuclear@14 33
nuclear@14 34 bool Scene::savexml(goat3d_io *io) const
nuclear@14 35 {
nuclear@82 36 xmlout(io, 0, "<!-- vi:set filetype=xml: -->\n");
nuclear@82 37 xmlout(io, 0, "<!-- Goat3D XML scene description -->\n");
nuclear@14 38 xmlout(io, 0, "<scene>\n");
nuclear@14 39
nuclear@14 40 // write environment stuff
nuclear@14 41 xmlout(io, 1, "<env>\n");
nuclear@18 42 xmlout(io, 2, "<ambient float3=\"%g %g %g\"/>\n", ambient.x, ambient.y, ambient.z);
nuclear@18 43 xmlout(io, 1, "</env>\n\n");
nuclear@14 44
nuclear@14 45 for(size_t i=0; i<materials.size(); i++) {
nuclear@14 46 write_material(this, io, materials[i], 1);
nuclear@14 47 }
nuclear@14 48 for(size_t i=0; i<meshes.size(); i++) {
nuclear@58 49 write_mesh(this, io, meshes[i], (int)i, 1);
nuclear@14 50 }
nuclear@14 51 for(size_t i=0; i<lights.size(); i++) {
nuclear@14 52 write_light(this, io, lights[i], 1);
nuclear@14 53 }
nuclear@14 54 for(size_t i=0; i<cameras.size(); i++) {
nuclear@14 55 write_camera(this, io, cameras[i], 1);
nuclear@14 56 }
nuclear@14 57 for(size_t i=0; i<nodes.size(); i++) {
nuclear@14 58 write_node(this, io, nodes[i], 1);
nuclear@14 59 }
nuclear@14 60
nuclear@14 61 xmlout(io, 0, "</scene>\n");
nuclear@14 62 return true;
nuclear@14 63 }
nuclear@14 64
nuclear@55 65 bool Scene::save_anim_xml(goat3d_io *io) const
nuclear@47 66 {
nuclear@82 67 xmlout(io, 0, "<!-- vi:set filetype=xml: -->\n");
nuclear@82 68 xmlout(io, 0, "<!-- Goat3D XML animation -->\n");
nuclear@47 69 xmlout(io, 0, "<anim>\n");
nuclear@47 70
nuclear@55 71 if(!nodes.empty()) {
nuclear@55 72 const char *anim_name = nodes[0]->get_animation_name();
nuclear@55 73 if(anim_name && *anim_name) {
nuclear@55 74 xmlout(io, 1, "<name string=\"%s\"/>\n", anim_name);
nuclear@55 75 }
nuclear@47 76 }
nuclear@47 77
nuclear@55 78 for(size_t i=0; i<nodes.size(); i++) {
nuclear@55 79 write_node_anim(io, nodes[i], 1);
nuclear@47 80 }
nuclear@47 81
nuclear@47 82 xmlout(io, 0, "</anim>\n");
nuclear@47 83 return true;
nuclear@47 84 }
nuclear@47 85
nuclear@14 86 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level)
nuclear@14 87 {
nuclear@14 88 xmlout(io, level, "<mtl>\n");
nuclear@14 89 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mat->name.c_str());
nuclear@14 90
nuclear@14 91 for(int i=0; i<mat->get_attrib_count(); i++) {
nuclear@14 92 xmlout(io, level + 1, "<attr>\n");
nuclear@14 93 xmlout(io, level + 2, "<name string=\"%s\"/>\n", mat->get_attrib_name(i));
nuclear@14 94
nuclear@14 95 const MaterialAttrib &attr = (*mat)[i];
nuclear@18 96 xmlout(io, level + 2, "<val float4=\"%g %g %g %g\"/>\n", attr.value.x,
nuclear@14 97 attr.value.y, attr.value.z, attr.value.w);
nuclear@14 98 if(!attr.map.empty()) {
nuclear@14 99 xmlout(io, level + 2, "<map string=\"%s\"/>\n", attr.map.c_str());
nuclear@14 100 }
nuclear@14 101 xmlout(io, level + 1, "</attr>\n");
nuclear@14 102 }
nuclear@18 103 xmlout(io, level, "</mtl>\n\n");
nuclear@14 104 return true;
nuclear@14 105 }
nuclear@14 106
nuclear@14 107 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level)
nuclear@14 108 {
nuclear@14 109 // first write the external (openctm) mesh file
nuclear@14 110 const char *prefix = scn->get_name();
nuclear@14 111 if(!prefix) {
nuclear@14 112 prefix = "goat";
nuclear@14 113 }
nuclear@14 114
nuclear@14 115 char *mesh_filename = (char*)alloca(strlen(prefix) + 32);
nuclear@14 116 sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx);
nuclear@14 117
nuclear@19 118 if(!mesh->save(mesh_filename)) {
nuclear@19 119 return false;
nuclear@19 120 }
nuclear@14 121
nuclear@14 122 // then refer to that filename in the XML tags
nuclear@14 123 xmlout(io, level, "<mesh>\n");
nuclear@14 124 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mesh->name.c_str());
nuclear@17 125 if(mesh->material) {
nuclear@17 126 xmlout(io, level + 1, "<material string=\"%s\"/>\n", mesh->material->name.c_str());
nuclear@17 127 }
nuclear@51 128 xmlout(io, level + 1, "<file string=\"%s\"/>\n", clean_filename(mesh_filename).c_str());
nuclear@18 129 xmlout(io, level, "</mesh>\n\n");
nuclear@14 130 return true;
nuclear@14 131 }
nuclear@14 132
nuclear@14 133 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level)
nuclear@14 134 {
nuclear@14 135 return true;
nuclear@14 136 }
nuclear@14 137
nuclear@14 138 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level)
nuclear@14 139 {
nuclear@14 140 return true;
nuclear@14 141 }
nuclear@14 142
nuclear@14 143 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level)
nuclear@14 144 {
nuclear@30 145 xmlout(io, level, "<node>\n");
nuclear@30 146 xmlout(io, level + 1, "<name string=\"%s\"/>\n", node->get_name());
nuclear@30 147
nuclear@47 148 const XFormNode *parent = node->get_parent();
nuclear@30 149 if(parent) {
nuclear@30 150 xmlout(io, level + 1, "<parent string=\"%s\"/>\n", parent->get_name());
nuclear@30 151 }
nuclear@30 152
nuclear@30 153 const char *type = 0;
nuclear@30 154 const Object *obj = node->get_object();
nuclear@30 155 if(dynamic_cast<const Mesh*>(obj)) {
nuclear@30 156 type = "mesh";
nuclear@30 157 } else if(dynamic_cast<const Light*>(obj)) {
nuclear@30 158 type = "light";
nuclear@30 159 } else if(dynamic_cast<const Camera*>(obj)) {
nuclear@30 160 type = "camera";
nuclear@30 161 }
nuclear@30 162
nuclear@30 163 if(type) {
nuclear@30 164 xmlout(io, level + 1, "<%s string=\"%s\"/>\n", type, obj->name.c_str());
nuclear@30 165 }
nuclear@30 166
nuclear@30 167 Vector3 pos = node->get_node_position();
nuclear@30 168 Quaternion rot = node->get_node_rotation();
nuclear@30 169 Vector3 scale = node->get_node_scaling();
nuclear@30 170 Vector3 pivot = node->get_pivot();
nuclear@30 171
nuclear@30 172 Matrix4x4 xform;
nuclear@30 173 node->get_node_xform(0, &xform);
nuclear@30 174
nuclear@30 175 xmlout(io, level + 1, "<pos float3=\"%g %g %g\"/>\n", pos.x, pos.y, pos.z);
nuclear@30 176 xmlout(io, level + 1, "<rot float4=\"%g %g %g %g\"/>\n", rot.v.x, rot.v.y, rot.v.z, rot.s);
nuclear@30 177 xmlout(io, level + 1, "<scale float3=\"%g %g %g\"/>\n", scale.x, scale.y, scale.z);
nuclear@30 178 xmlout(io, level + 1, "<pivot float3=\"%g %g %g\"/>\n", pivot.x, pivot.y, pivot.z);
nuclear@30 179
nuclear@30 180 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 181 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 182 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 183
nuclear@30 184 xmlout(io, level, "</node>\n");
nuclear@14 185 return true;
nuclear@14 186 }
nuclear@14 187
nuclear@47 188 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level)
nuclear@47 189 {
nuclear@51 190 /* NOTE: the order of names must correspond to the order of the
nuclear@48 191 * XFormNode::POSITION_TRACK/ROTATION_TRACK/SCALING_TRACK enum
nuclear@48 192 */
nuclear@47 193 static const char *attr_names[] = { "position", "rotation", "scaling" };
nuclear@47 194
nuclear@48 195 // for each of: position/rotation/scaling
nuclear@48 196 for(int i=0; i<3; i++) {
nuclear@48 197 int num_keys = node->get_key_count(i);
nuclear@48 198 if(!num_keys) continue;
nuclear@47 199
nuclear@47 200 xmlout(io, level + 1, "<track>\n");
nuclear@47 201 xmlout(io, level + 2, "<node string=\"%s\"/>\n", node->get_name());
nuclear@48 202 xmlout(io, level + 2, "<attr string=\"%s\"/>\n\n", attr_names[i]);
nuclear@47 203
nuclear@48 204 // for each key in that track
nuclear@48 205 for(int j=0; j<num_keys; j++) {
nuclear@48 206 long tm = node->get_key_time(i, j);
nuclear@48 207
nuclear@48 208 float value[4];
nuclear@48 209 int num_elems = node->get_key_value(i, j, value);
nuclear@48 210
nuclear@48 211 if(num_elems == 3) {
nuclear@48 212 xmlout(io, level + 2, "<key><time int=\"%ld\"/><value float3=\"%g %g %g\"/></key>\n",
nuclear@48 213 tm, value[0], value[1], value[2]);
nuclear@48 214 } else {
nuclear@48 215 xmlout(io, level + 2, "<key><time int=\"%ld\"/><value float4=\"%g %g %g %g\"/></key>\n",
nuclear@48 216 tm, value[0], value[1], value[2], value[3]);
nuclear@48 217 }
nuclear@48 218 }
nuclear@47 219
nuclear@47 220 xmlout(io, level + 1, "</track>\n");
nuclear@47 221 }
nuclear@47 222 return true;
nuclear@47 223 }
nuclear@14 224
nuclear@14 225 static void xmlout(goat3d_io *io, int level, const char *fmt, ...)
nuclear@14 226 {
nuclear@14 227 for(int i=0; i<level; i++) {
nuclear@14 228 io_fprintf(io, " ");
nuclear@14 229 }
nuclear@14 230
nuclear@14 231 va_list ap;
nuclear@14 232 va_start(ap, fmt);
nuclear@14 233 io_vfprintf(io, fmt, ap);
nuclear@14 234 va_end(ap);
nuclear@14 235 }