nuclear@47: #include nuclear@14: #include nuclear@14: #include "goat3d_impl.h" nuclear@47: #include "anim/anim.h" nuclear@17: #include "log.h" nuclear@14: nuclear@47: using namespace g3dimpl; nuclear@47: nuclear@14: static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level); nuclear@14: static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level); nuclear@14: static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level); nuclear@14: static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level); nuclear@14: static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level); nuclear@47: static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level); nuclear@14: static void xmlout(goat3d_io *io, int level, const char *fmt, ...); nuclear@14: nuclear@14: bool Scene::savexml(goat3d_io *io) const nuclear@14: { nuclear@14: xmlout(io, 0, "\n"); nuclear@14: nuclear@14: // write environment stuff nuclear@14: xmlout(io, 1, "\n"); nuclear@18: xmlout(io, 2, "\n", ambient.x, ambient.y, ambient.z); nuclear@18: xmlout(io, 1, "\n\n"); nuclear@14: nuclear@14: for(size_t i=0; i\n"); nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@47: static void collect_nodes(std::list *res, const XFormNode *node) nuclear@47: { nuclear@47: if(!node) return; nuclear@47: nuclear@47: res->push_back(node); nuclear@47: nuclear@47: for(int i=0; iget_children_count(); i++) { nuclear@47: collect_nodes(res, node->get_child(i)); nuclear@47: } nuclear@47: } nuclear@47: nuclear@47: bool Scene::save_anim_xml(const XFormNode *node, goat3d_io *io) const nuclear@47: { nuclear@47: xmlout(io, 0, "\n"); nuclear@47: nuclear@47: const char *anim_name = node->get_animation_name(); nuclear@47: if(anim_name && *anim_name) { nuclear@47: xmlout(io, 1, "\n", anim_name); nuclear@47: } nuclear@47: nuclear@47: std::list allnodes; nuclear@47: collect_nodes(&allnodes, node); nuclear@47: nuclear@47: std::list::const_iterator it = allnodes.begin(); nuclear@47: while(it != allnodes.end()) { nuclear@47: const XFormNode *n = *it++; nuclear@47: write_node_anim(io, n, 1); nuclear@47: } nuclear@47: nuclear@47: xmlout(io, 0, "\n"); nuclear@47: return true; nuclear@47: } nuclear@47: nuclear@14: static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level) nuclear@14: { nuclear@14: xmlout(io, level, "\n"); nuclear@14: xmlout(io, level + 1, "\n", mat->name.c_str()); nuclear@14: nuclear@14: for(int i=0; iget_attrib_count(); i++) { nuclear@14: xmlout(io, level + 1, "\n"); nuclear@14: xmlout(io, level + 2, "\n", mat->get_attrib_name(i)); nuclear@14: nuclear@14: const MaterialAttrib &attr = (*mat)[i]; nuclear@18: xmlout(io, level + 2, "\n", attr.value.x, nuclear@14: attr.value.y, attr.value.z, attr.value.w); nuclear@14: if(!attr.map.empty()) { nuclear@14: xmlout(io, level + 2, "\n", attr.map.c_str()); nuclear@14: } nuclear@14: xmlout(io, level + 1, "\n"); nuclear@14: } nuclear@18: xmlout(io, level, "\n\n"); nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@14: static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level) nuclear@14: { nuclear@14: // first write the external (openctm) mesh file nuclear@14: const char *prefix = scn->get_name(); nuclear@14: if(!prefix) { nuclear@14: prefix = "goat"; nuclear@14: } nuclear@14: nuclear@14: char *mesh_filename = (char*)alloca(strlen(prefix) + 32); nuclear@14: sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx); nuclear@14: nuclear@19: if(!mesh->save(mesh_filename)) { nuclear@19: return false; nuclear@19: } nuclear@14: nuclear@14: // then refer to that filename in the XML tags nuclear@14: xmlout(io, level, "\n"); nuclear@14: xmlout(io, level + 1, "\n", mesh->name.c_str()); nuclear@17: if(mesh->material) { nuclear@17: xmlout(io, level + 1, "\n", mesh->material->name.c_str()); nuclear@17: } nuclear@51: xmlout(io, level + 1, "\n", clean_filename(mesh_filename).c_str()); nuclear@18: xmlout(io, level, "\n\n"); nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@14: static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level) nuclear@14: { nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@14: static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level) nuclear@14: { nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@14: static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level) nuclear@14: { nuclear@30: xmlout(io, level, "\n"); nuclear@30: xmlout(io, level + 1, "\n", node->get_name()); nuclear@30: nuclear@47: const XFormNode *parent = node->get_parent(); nuclear@30: if(parent) { nuclear@30: xmlout(io, level + 1, "\n", parent->get_name()); nuclear@30: } nuclear@30: nuclear@30: const char *type = 0; nuclear@30: const Object *obj = node->get_object(); nuclear@30: if(dynamic_cast(obj)) { nuclear@30: type = "mesh"; nuclear@30: } else if(dynamic_cast(obj)) { nuclear@30: type = "light"; nuclear@30: } else if(dynamic_cast(obj)) { nuclear@30: type = "camera"; nuclear@30: } nuclear@30: nuclear@30: if(type) { nuclear@30: xmlout(io, level + 1, "<%s string=\"%s\"/>\n", type, obj->name.c_str()); nuclear@30: } nuclear@30: nuclear@30: Vector3 pos = node->get_node_position(); nuclear@30: Quaternion rot = node->get_node_rotation(); nuclear@30: Vector3 scale = node->get_node_scaling(); nuclear@30: Vector3 pivot = node->get_pivot(); nuclear@30: nuclear@30: Matrix4x4 xform; nuclear@30: node->get_node_xform(0, &xform); nuclear@30: nuclear@30: xmlout(io, level + 1, "\n", pos.x, pos.y, pos.z); nuclear@30: xmlout(io, level + 1, "\n", rot.v.x, rot.v.y, rot.v.z, rot.s); nuclear@30: xmlout(io, level + 1, "\n", scale.x, scale.y, scale.z); nuclear@30: xmlout(io, level + 1, "\n", pivot.x, pivot.y, pivot.z); nuclear@30: nuclear@30: xmlout(io, level + 1, "\n", xform[0][0], xform[0][1], xform[0][2], xform[0][3]); nuclear@30: xmlout(io, level + 1, "\n", xform[1][0], xform[1][1], xform[1][2], xform[1][3]); nuclear@30: xmlout(io, level + 1, "\n", xform[2][0], xform[2][1], xform[2][2], xform[2][3]); nuclear@30: nuclear@30: xmlout(io, level, "\n"); nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@47: static bool write_node_anim(goat3d_io *io, const XFormNode *node, int level) nuclear@47: { nuclear@51: /* NOTE: the order of names must correspond to the order of the nuclear@48: * XFormNode::POSITION_TRACK/ROTATION_TRACK/SCALING_TRACK enum nuclear@48: */ nuclear@47: static const char *attr_names[] = { "position", "rotation", "scaling" }; nuclear@47: nuclear@48: // for each of: position/rotation/scaling nuclear@48: for(int i=0; i<3; i++) { nuclear@48: int num_keys = node->get_key_count(i); nuclear@48: if(!num_keys) continue; nuclear@47: nuclear@47: xmlout(io, level + 1, "\n"); nuclear@47: xmlout(io, level + 2, "\n", node->get_name()); nuclear@48: xmlout(io, level + 2, "\n\n", attr_names[i]); nuclear@47: nuclear@48: // for each key in that track nuclear@48: for(int j=0; jget_key_time(i, j); nuclear@48: nuclear@48: float value[4]; nuclear@48: int num_elems = node->get_key_value(i, j, value); nuclear@48: nuclear@48: if(num_elems == 3) { nuclear@48: xmlout(io, level + 2, "\n", nuclear@48: tm, value[0], value[1], value[2]); nuclear@48: } else { nuclear@48: xmlout(io, level + 2, "\n", nuclear@48: tm, value[0], value[1], value[2], value[3]); nuclear@48: } nuclear@48: } nuclear@47: nuclear@47: xmlout(io, level + 1, "\n"); nuclear@47: } nuclear@47: return true; nuclear@47: } nuclear@14: nuclear@14: static void xmlout(goat3d_io *io, int level, const char *fmt, ...) nuclear@14: { nuclear@14: for(int i=0; i