goat3d

view src/goat3d_writexml.cc @ 47:498ca7ac7047

- placed all the implementation stuff in the g3dimpl namespace - added animation stuff to the public API - started writing animation saving/loading
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Dec 2013 06:47:39 +0200
parents a5c5cec3cb88
children 9ef9de80649c
line source
1 #include <list>
2 #include <stdarg.h>
3 #include "goat3d_impl.h"
4 #include "anim/anim.h"
5 #include "log.h"
7 using namespace g3dimpl;
9 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level);
10 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level);
11 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level);
12 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level);
13 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level);
14 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level);
15 static void xmlout(goat3d_io *io, int level, const char *fmt, ...);
17 bool Scene::savexml(goat3d_io *io) const
18 {
19 xmlout(io, 0, "<scene>\n");
21 // write environment stuff
22 xmlout(io, 1, "<env>\n");
23 xmlout(io, 2, "<ambient float3=\"%g %g %g\"/>\n", ambient.x, ambient.y, ambient.z);
24 xmlout(io, 1, "</env>\n\n");
26 for(size_t i=0; i<materials.size(); i++) {
27 write_material(this, io, materials[i], 1);
28 }
29 for(size_t i=0; i<meshes.size(); i++) {
30 write_mesh(this, io, meshes[i], i, 1);
31 }
32 for(size_t i=0; i<lights.size(); i++) {
33 write_light(this, io, lights[i], 1);
34 }
35 for(size_t i=0; i<cameras.size(); i++) {
36 write_camera(this, io, cameras[i], 1);
37 }
38 for(size_t i=0; i<nodes.size(); i++) {
39 write_node(this, io, nodes[i], 1);
40 }
42 xmlout(io, 0, "</scene>\n");
43 return true;
44 }
46 static void collect_nodes(std::list<const XFormNode*> *res, const XFormNode *node)
47 {
48 if(!node) return;
50 res->push_back(node);
52 for(int i=0; i<node->get_children_count(); i++) {
53 collect_nodes(res, node->get_child(i));
54 }
55 }
57 bool Scene::save_anim_xml(const XFormNode *node, goat3d_io *io) const
58 {
59 xmlout(io, 0, "<anim>\n");
61 const char *anim_name = node->get_animation_name();
62 if(anim_name && *anim_name) {
63 xmlout(io, 1, "<name string=\"%s\"/>\n", anim_name);
64 }
66 std::list<const XFormNode*> allnodes;
67 collect_nodes(&allnodes, node);
69 std::list<const XFormNode*>::const_iterator it = allnodes.begin();
70 while(it != allnodes.end()) {
71 const XFormNode *n = *it++;
72 write_node_anim(io, n, 1);
73 }
75 xmlout(io, 0, "</anim>\n");
76 return true;
77 }
79 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level)
80 {
81 xmlout(io, level, "<mtl>\n");
82 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mat->name.c_str());
84 for(int i=0; i<mat->get_attrib_count(); i++) {
85 xmlout(io, level + 1, "<attr>\n");
86 xmlout(io, level + 2, "<name string=\"%s\"/>\n", mat->get_attrib_name(i));
88 const MaterialAttrib &attr = (*mat)[i];
89 xmlout(io, level + 2, "<val float4=\"%g %g %g %g\"/>\n", attr.value.x,
90 attr.value.y, attr.value.z, attr.value.w);
91 if(!attr.map.empty()) {
92 xmlout(io, level + 2, "<map string=\"%s\"/>\n", attr.map.c_str());
93 }
94 xmlout(io, level + 1, "</attr>\n");
95 }
96 xmlout(io, level, "</mtl>\n\n");
97 return true;
98 }
100 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level)
101 {
102 // first write the external (openctm) mesh file
103 const char *prefix = scn->get_name();
104 if(!prefix) {
105 prefix = "goat";
106 }
108 char *mesh_filename = (char*)alloca(strlen(prefix) + 32);
109 sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx);
111 if(!mesh->save(mesh_filename)) {
112 return false;
113 }
115 // then refer to that filename in the XML tags
116 xmlout(io, level, "<mesh>\n");
117 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mesh->name.c_str());
118 if(mesh->material) {
119 xmlout(io, level + 1, "<material string=\"%s\"/>\n", mesh->material->name.c_str());
120 }
121 xmlout(io, level + 1, "<file string=\"%s\"/>\n", goat3d_clean_filename(mesh_filename).c_str());
122 xmlout(io, level, "</mesh>\n\n");
123 return true;
124 }
126 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level)
127 {
128 return true;
129 }
131 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level)
132 {
133 return true;
134 }
136 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level)
137 {
138 xmlout(io, level, "<node>\n");
139 xmlout(io, level + 1, "<name string=\"%s\"/>\n", node->get_name());
141 const XFormNode *parent = node->get_parent();
142 if(parent) {
143 xmlout(io, level + 1, "<parent string=\"%s\"/>\n", parent->get_name());
144 }
146 const char *type = 0;
147 const Object *obj = node->get_object();
148 if(dynamic_cast<const Mesh*>(obj)) {
149 type = "mesh";
150 } else if(dynamic_cast<const Light*>(obj)) {
151 type = "light";
152 } else if(dynamic_cast<const Camera*>(obj)) {
153 type = "camera";
154 }
156 if(type) {
157 xmlout(io, level + 1, "<%s string=\"%s\"/>\n", type, obj->name.c_str());
158 }
160 Vector3 pos = node->get_node_position();
161 Quaternion rot = node->get_node_rotation();
162 Vector3 scale = node->get_node_scaling();
163 Vector3 pivot = node->get_pivot();
165 Matrix4x4 xform;
166 node->get_node_xform(0, &xform);
168 xmlout(io, level + 1, "<pos float3=\"%g %g %g\"/>\n", pos.x, pos.y, pos.z);
169 xmlout(io, level + 1, "<rot float4=\"%g %g %g %g\"/>\n", rot.v.x, rot.v.y, rot.v.z, rot.s);
170 xmlout(io, level + 1, "<scale float3=\"%g %g %g\"/>\n", scale.x, scale.y, scale.z);
171 xmlout(io, level + 1, "<pivot float3=\"%g %g %g\"/>\n", pivot.x, pivot.y, pivot.z);
173 xmlout(io, level + 1, "<matrix0 float4=\"%g %g %g %g\"/>\n", xform[0][0], xform[0][1], xform[0][2], xform[0][3]);
174 xmlout(io, level + 1, "<matrix1 float4=\"%g %g %g %g\"/>\n", xform[1][0], xform[1][1], xform[1][2], xform[1][3]);
175 xmlout(io, level + 1, "<matrix2 float4=\"%g %g %g %g\"/>\n", xform[2][0], xform[2][1], xform[2][2], xform[2][3]);
177 xmlout(io, level, "</node>\n");
178 return true;
179 }
181 static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level)
182 {
183 static const char *attr_names[] = { "position", "rotation", "scaling" };
184 struct anm_node *anode = node->get_libanim_node();
185 struct anm_animation *anim = anm_get_active_animation(anode, 0);
187 if(!anode || !anim) {
188 return false;
189 }
191 struct anm_track *trk[4];
193 for(int i=0; i<3; i++) { // 3 attributes
194 switch(i) {
195 case 0: // position
196 trk[0] = anim->tracks + ANM_TRACK_POS_X;
197 trk[1] = anim->tracks + ANM_TRACK_POS_Y;
198 trk[2] = anim->tracks + ANM_TRACK_POS_Z;
199 trk[3] = 0;
200 break;
202 case 1: // rotation
203 trk[0] = anim->tracks + ANM_TRACK_ROT_X;
204 trk[1] = anim->tracks + ANM_TRACK_ROT_Y;
205 trk[2] = anim->tracks + ANM_TRACK_ROT_Z;
206 trk[3] = anim->tracks + ANM_TRACK_ROT_W;
207 break;
209 case 2: // scaling
210 trk[0] = anim->tracks + ANM_TRACK_SCL_X;
211 trk[1] = anim->tracks + ANM_TRACK_SCL_Y;
212 trk[2] = anim->tracks + ANM_TRACK_SCL_Z;
213 trk[3] = 0;
214 }
216 if(trk[0]->count <= 0) {
217 continue; // skip tracks without any keyframes
218 }
220 xmlout(io, level + 1, "<track>\n");
221 xmlout(io, level + 2, "<node string=\"%s\"/>\n", node->get_name());
222 xmlout(io, level + 2, "<attr string=\"%s\"/>\n", attr_names[i]);
224 // TODO cont: move all the keyframe retreival to XFormNode and use that...
226 xmlout(io, level + 1, "</track>\n");
227 }
228 return true;
229 }
231 static void xmlout(goat3d_io *io, int level, const char *fmt, ...)
232 {
233 for(int i=0; i<level; i++) {
234 io_fprintf(io, " ");
235 }
237 va_list ap;
238 va_start(ap, fmt);
239 io_vfprintf(io, fmt, ap);
240 va_end(ap);
241 }