/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" #include "DNA_texture_types.h" #include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" #include "DNA_armature_types.h" #include "DNA_modifier_types.h" #include "DNA_userdef_types.h" #include "BKE_DerivedMesh.h" #include "BKE_fcurve.h" #include "BKE_animsys.h" #include "BLI_path_util.h" #include "BLI_fileops.h" #include "ED_keyframing.h" #ifdef NAN_BUILDINFO extern char build_rev[]; #endif } #include "MEM_guardedalloc.h" #include "BKE_blender.h" // version info #include "BKE_scene.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_action.h" // pose functions #include "BKE_armature.h" #include "BKE_image.h" #include "BKE_utildefines.h" #include "BKE_object.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_listbase.h" #include "RNA_access.h" #include "COLLADASWAsset.h" #include "COLLADASWLibraryVisualScenes.h" #include "COLLADASWNode.h" #include "COLLADASWSource.h" #include "COLLADASWInstanceGeometry.h" #include "COLLADASWInputList.h" #include "COLLADASWPrimitves.h" #include "COLLADASWVertices.h" #include "COLLADASWLibraryAnimations.h" #include "COLLADASWLibraryImages.h" #include "COLLADASWLibraryEffects.h" #include "COLLADASWImage.h" #include "COLLADASWEffectProfile.h" #include "COLLADASWColorOrTexture.h" #include "COLLADASWParamTemplate.h" #include "COLLADASWParamBase.h" #include "COLLADASWSurfaceInitOption.h" #include "COLLADASWSampler.h" #include "COLLADASWScene.h" #include "COLLADASWTechnique.h" #include "COLLADASWTexture.h" #include "COLLADASWLibraryMaterials.h" #include "COLLADASWBindMaterial.h" #include "COLLADASWInstanceCamera.h" #include "COLLADASWInstanceLight.h" #include "COLLADASWConstants.h" #include "COLLADASWLibraryControllers.h" #include "COLLADASWInstanceController.h" #include "COLLADASWBaseInputElement.h" #include "collada_internal.h" #include "DocumentExporter.h" // can probably go after refactor is complete #include "InstanceWriter.h" #include "TransformWriter.h" #include "ArmatureExporter.h" #include "CameraExporter.h" #include "EffectExporter.h" #include "GeometryExporter.h" #include "ImageExporter.h" #include "LightExporter.h" #include "MaterialExporter.h" #include #include // std::find char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n) { int layer_index = CustomData_get_layer_index(data, type); if(layer_index < 0) return NULL; return data->layers[layer_index+n].name; } char *bc_CustomData_get_active_layer_name(const CustomData *data, int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if(layer_index < 0) return NULL; return data->layers[layer_index].name; } /* Utilities to avoid code duplication. Definition can take some time to understand, but they should be useful. */ template void forEachObjectInScene(Scene *sce, Functor &f) { Base *base= (Base*) sce->base.first; while(base) { Object *ob = base->object; f(ob); base= base->next; } } class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter { ArmatureExporter *arm_exporter; public: SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm) {} void exportScene(Scene *sce) { // std::string id_naming = id_name(sce); openVisualScene(translate_id(id_naming), id_naming); // write s //forEachMeshObjectInScene(sce, *this); //forEachCameraObjectInScene(sce, *this); //forEachLampObjectInScene(sce, *this); exportHierarchy(sce); // closeVisualScene(); closeLibrary(); } void exportHierarchy(Scene *sce) { Base *base= (Base*) sce->base.first; while(base) { Object *ob = base->object; if (!ob->parent) { switch(ob->type) { case OB_MESH: case OB_CAMERA: case OB_LAMP: case OB_EMPTY: case OB_ARMATURE: // write nodes.... writeNodes(ob, sce); break; } } base= base->next; } } // called for each object //void operator()(Object *ob) { void writeNodes(Object *ob, Scene *sce) { COLLADASW::Node node(mSW); node.setNodeId(translate_id(id_name(ob))); node.setType(COLLADASW::Node::NODE); node.start(); bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob); if (ob->type == OB_MESH && is_skinned_mesh) // for skinned mesh we write obmat in TransformWriter::add_node_transform_identity(node); else TransformWriter::add_node_transform_ob(node, ob); // if (ob->type == OB_MESH) { if (is_skinned_mesh) { arm_exporter->add_instance_controller(ob); } else { COLLADASW::InstanceGeometry instGeom(mSW); instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob))); InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob); instGeom.add(); } } // else if (ob->type == OB_ARMATURE) { arm_exporter->add_armature_bones(ob, sce); // XXX this looks unstable... node.end(); } // else if (ob->type == OB_CAMERA) { COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob))); instCam.add(); } // else if (ob->type == OB_LAMP) { COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob))); instLa.add(); } // empty object else if (ob->type == OB_EMPTY) { } // write nodes for child objects Base *b = (Base*) sce->base.first; while(b) { // cob - child object Object *cob = b->object; if (cob->parent == ob) { switch(cob->type) { case OB_MESH: case OB_CAMERA: case OB_LAMP: case OB_EMPTY: case OB_ARMATURE: // write node... writeNodes(cob, sce); break; } } b = b->next; } if (ob->type != OB_ARMATURE) node.end(); } }; // TODO: it would be better to instantiate animations rather than create a new one per object // COLLADA allows this through multiple s in . // For this to work, we need to know objects that use a certain action. class AnimationExporter: COLLADASW::LibraryAnimations { Scene *scene; COLLADASW::StreamWriter *sw; public: AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; } void exportAnimations(Scene *sce) { this->scene = sce; openLibrary(); forEachObjectInScene(sce, *this); closeLibrary(); } // called for each exported object void operator() (Object *ob) { if (!ob->adt || !ob->adt->action) return; FCurve *fcu = (FCurve*)ob->adt->action->curves.first; if (ob->type == OB_ARMATURE) { if (!ob->data) return; bArmature *arm = (bArmature*)ob->data; for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) write_bone_animation(ob, bone); } else { while (fcu) { // TODO "rotation_quaternion" is also possible for objects (although euler is default) if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) || (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)) dae_animation(fcu, id_name(ob)); fcu = fcu->next; } } } protected: void dae_animation(FCurve *fcu, std::string ob_name) { const char *axis_names[] = {"X", "Y", "Z"}; const char *axis_name = NULL; char anim_id[200]; if (fcu->array_index < 3) axis_name = axis_names[fcu->array_index]; BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), fcu->rna_path, axis_names[fcu->array_index]); // check rna_path is one of: rotation, scale, location openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); // create input source std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name); // create output source std::string output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name); // create interpolations source std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name); std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); std::string empty; sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); // this input is required sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); addSampler(sampler); std::string target = translate_id(ob_name) + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true); addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); } void write_bone_animation(Object *ob_arm, Bone *bone) { if (!ob_arm->adt) return; for (int i = 0; i < 3; i++) sample_and_write_bone_animation(ob_arm, bone, i); for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) write_bone_animation(ob_arm, child); } void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) { bArmature *arm = (bArmature*)ob_arm->data; int flag = arm->flag; std::vector fra; char prefix[256]; BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name); bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); if (!pchan) return; switch (transform_type) { case 0: find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); break; case 1: find_frames(ob_arm, fra, prefix, "scale"); break; case 2: find_frames(ob_arm, fra, prefix, "location"); break; default: return; } // exit rest position if (flag & ARM_RESTPOS) { arm->flag &= ~ARM_RESTPOS; where_is_pose(scene, ob_arm); } if (fra.size()) { float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); sample_animation(v, fra, transform_type, bone, ob_arm); if (transform_type == 0) { // write x, y, z curves separately if it is rotation float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames"); for (int i = 0; i < 3; i++) { for (unsigned int j = 0; j < fra.size(); j++) c[j] = v[j * 3 + i]; dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name); } MEM_freeN(c); } else { // write xyz at once if it is location or scale dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name); } MEM_freeN(v); } // restore restpos if (flag & ARM_RESTPOS) arm->flag = flag; where_is_pose(scene, ob_arm); } void sample_animation(float *v, std::vector &frames, int type, Bone *bone, Object *ob_arm) { bPoseChannel *pchan, *parchan = NULL; bPose *pose = ob_arm->pose; pchan = get_pose_channel(pose, bone->name); if (!pchan) return; parchan = pchan->parent; enable_fcurves(ob_arm->adt->action, bone->name); std::vector::iterator it; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = bsystem_time(scene, ob_arm, *it, 0.0f); BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM); where_is_pose_bone(scene, ob_arm, pchan, ctime, 1); // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mul_m4_m4m4(mat, pchan->pose_mat, ipar); } else copy_m4_m4(mat, pchan->pose_mat); switch (type) { case 0: mat4_to_eul(v, mat); break; case 1: mat4_to_size(v, mat); break; case 2: copy_v3_v3(v, mat[3]); break; } v += 3; } enable_fcurves(ob_arm->adt->action, NULL); } // dae_bone_animation -> add_bone_animation // (blend this into dae_bone_animation) void dae_bone_animation(std::vector &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name) { const char *axis_names[] = {"X", "Y", "Z"}; const char *axis_name = NULL; char anim_id[200]; bool is_rot = tm_type == 0; if (!fra.size()) return; char rna_path[200]; BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(), tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location")); if (axis > -1) axis_name = axis_names[axis]; std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false); BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str()); openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); // create input source std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name); // create output source std::string output_id; if (axis == -1) output_id = create_xyz_source(v, fra.size(), anim_id); else output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name); // create interpolations source std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name); std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); std::string empty; sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); // TODO create in/out tangents source // this input is required sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); addSampler(sampler); std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); } float convert_time(float frame) { return FRA2TIME(frame); } float convert_angle(float angle) { return COLLADABU::Math::Utils::radToDegF(angle); } std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic) { switch(semantic) { case COLLADASW::InputSemantic::INPUT: return INPUT_SOURCE_ID_SUFFIX; case COLLADASW::InputSemantic::OUTPUT: return OUTPUT_SOURCE_ID_SUFFIX; case COLLADASW::InputSemantic::INTERPOLATION: return INTERPOLATION_SOURCE_ID_SUFFIX; case COLLADASW::InputSemantic::IN_TANGENT: return INTANGENT_SOURCE_ID_SUFFIX; case COLLADASW::InputSemantic::OUT_TANGENT: return OUTTANGENT_SOURCE_ID_SUFFIX; default: break; } return ""; } void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis) { switch(semantic) { case COLLADASW::InputSemantic::INPUT: param.push_back("TIME"); break; case COLLADASW::InputSemantic::OUTPUT: if (is_rot) { param.push_back("ANGLE"); } else { if (axis) { param.push_back(axis); } else { param.push_back("X"); param.push_back("Y"); param.push_back("Z"); } } break; case COLLADASW::InputSemantic::IN_TANGENT: case COLLADASW::InputSemantic::OUT_TANGENT: param.push_back("X"); param.push_back("Y"); break; default: break; } } void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length) { switch (semantic) { case COLLADASW::InputSemantic::INPUT: *length = 1; values[0] = convert_time(bezt->vec[1][0]); break; case COLLADASW::InputSemantic::OUTPUT: *length = 1; if (rotation) { values[0] = convert_angle(bezt->vec[1][1]); } else { values[0] = bezt->vec[1][1]; } break; case COLLADASW::InputSemantic::IN_TANGENT: case COLLADASW::InputSemantic::OUT_TANGENT: // XXX *length = 2; break; default: *length = 0; break; } } std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) { std::string source_id = anim_id + get_semantic_suffix(semantic); //bool is_rotation = !strcmp(fcu->rna_path, "rotation"); bool is_rotation = false; if (strstr(fcu->rna_path, "rotation")) is_rotation = true; COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(fcu->totvert); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, is_rotation, axis_name); source.prepareToAppendValues(); for (unsigned int i = 0; i < fcu->totvert; i++) { float values[3]; // be careful! int length = 0; get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length); for (int j = 0; j < length; j++) source.appendValues(values[j]); } source.finish(); return source_id; } std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name) { std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(tot); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, is_rot, axis_name); source.prepareToAppendValues(); for (int i = 0; i < tot; i++) { float val = v[i]; if (semantic == COLLADASW::InputSemantic::INPUT) val = convert_time(val); else if (is_rot) val = convert_angle(val); source.appendValues(val); } source.finish(); return source_id; } std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector &fra, bool is_rot, const std::string& anim_id, const char *axis_name) { std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(fra.size()); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, is_rot, axis_name); source.prepareToAppendValues(); std::vector::iterator it; for (it = fra.begin(); it != fra.end(); it++) { float val = *it; if (semantic == COLLADASW::InputSemantic::INPUT) val = convert_time(val); else if (is_rot) val = convert_angle(val); source.appendValues(val); } source.finish(); return source_id; } // only used for sources with OUTPUT semantic std::string create_xyz_source(float *v, int tot, const std::string& anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(tot); source.setAccessorStride(3); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, false, NULL); source.prepareToAppendValues(); for (int i = 0; i < tot; i++) { source.appendValues(*v, *(v + 1), *(v + 2)); v += 3; } source.finish(); return source_id; } std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name) { std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); COLLADASW::NameSource source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(tot); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("INTERPOLATION"); source.prepareToAppendValues(); for (int i = 0; i < tot; i++) { source.appendValues(LINEAR_NAME); } source.finish(); return source_id; } // for rotation, axis name is always appended and the value of append_axis is ignored std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) { std::string tm_name; // when given rna_path, determine tm_type from it if (rna_path) { char *name = extract_transform_name(rna_path); if (strstr(name, "rotation")) tm_type = 0; else if (!strcmp(name, "scale")) tm_type = 1; else if (!strcmp(name, "location")) tm_type = 2; else tm_type = -1; } switch (tm_type) { case 0: return std::string("rotation") + std::string(axis_name) + ".ANGLE"; case 1: tm_name = "scale"; break; case 2: tm_name = "location"; break; default: tm_name = ""; break; } if (tm_name.size()) { if (append_axis) return tm_name + std::string(".") + std::string(axis_name); else return tm_name; } return std::string(""); } char *extract_transform_name(char *rna_path) { char *dot = strrchr(rna_path, '.'); return dot ? (dot + 1) : rna_path; } void find_frames(Object *ob, std::vector &fra, const char *prefix, const char *tm_name) { FCurve *fcu= (FCurve*)ob->adt->action->curves.first; for (; fcu; fcu = fcu->next) { if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix))) continue; char *name = extract_transform_name(fcu->rna_path); if (!strcmp(name, tm_name)) { for (unsigned int i = 0; i < fcu->totvert; i++) { float f = fcu->bezt[i].vec[1][0]; if (std::find(fra.begin(), fra.end(), f) == fra.end()) fra.push_back(f); } } } // keep the keys in ascending order std::sort(fra.begin(), fra.end()); } void find_rotation_frames(Object *ob, std::vector &fra, const char *prefix, int rotmode) { if (rotmode > 0) find_frames(ob, fra, prefix, "rotation_euler"); else if (rotmode == ROT_MODE_QUAT) find_frames(ob, fra, prefix, "rotation_quaternion"); /*else if (rotmode == ROT_MODE_AXISANGLE) ;*/ } // enable fcurves driving a specific bone, disable all the rest // if bone_name = NULL enable all fcurves void enable_fcurves(bAction *act, char *bone_name) { FCurve *fcu; char prefix[200]; if (bone_name) BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) { if (bone_name) { if (!strncmp(fcu->rna_path, prefix, strlen(prefix))) fcu->flag &= ~FCURVE_DISABLED; else fcu->flag |= FCURVE_DISABLED; } else { fcu->flag &= ~FCURVE_DISABLED; } } } }; void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename) { PointerRNA sceneptr, unit_settings; PropertyRNA *system; /* unused , *scale; */ clear_global_id_map(); COLLADABU::NativeString native_filename = COLLADABU::NativeString(std::string(filename)); COLLADASW::StreamWriter sw(native_filename); // open sw.startDocument(); // COLLADASW::Asset asset(&sw); RNA_id_pointer_create(&(sce->id), &sceneptr); unit_settings = RNA_pointer_get(&sceneptr, "unit_settings"); system = RNA_struct_find_property(&unit_settings, "system"); //scale = RNA_struct_find_property(&unit_settings, "scale_length"); std::string unitname = "meter"; float linearmeasure = 1.0f; linearmeasure = RNA_float_get(&unit_settings, "scale_length"); switch(RNA_property_enum_get(&unit_settings, system)) { case USER_UNIT_NONE: case USER_UNIT_METRIC: if(linearmeasure == 0.001f) { unitname = "millimeter"; } else if(linearmeasure == 0.01f) { unitname = "centimeter"; } else if(linearmeasure == 0.1f) { unitname = "decimeter"; } else if(linearmeasure == 1.0f) { unitname = "meter"; } else if(linearmeasure == 1000.0f) { unitname = "kilometer"; } break; case USER_UNIT_IMPERIAL: if(linearmeasure == 0.0254f) { unitname = "inch"; } else if(linearmeasure == 0.3048f) { unitname = "foot"; } else if(linearmeasure == 0.9144f) { unitname = "yard"; } break; default: break; } asset.setUnit(unitname, linearmeasure); asset.setUpAxisType(COLLADASW::Asset::Z_UP); // TODO: need an Author field in userpref if(strlen(U.author) > 0) { asset.getContributor().mAuthor = U.author; } else { asset.getContributor().mAuthor = "Blender User"; } #ifdef NAN_BUILDINFO char version_buf[128]; sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev); asset.getContributor().mAuthoringTool = version_buf; #else asset.getContributor().mAuthoringTool = "Blender 2.5x"; #endif asset.add(); // CamerasExporter ce(&sw); ce.exportCameras(sce); // LightsExporter le(&sw); le.exportLights(sce); // ImagesExporter ie(&sw, filename); ie.exportImages(sce); // EffectsExporter ee(&sw); ee.exportEffects(sce); // MaterialsExporter me(&sw); me.exportMaterials(sce); // GeometryExporter ge(&sw); ge.exportGeom(sce); // AnimationExporter ae(&sw); ae.exportAnimations(sce); // ArmatureExporter arm_exporter(&sw); arm_exporter.export_controllers(sce); // SceneExporter se(&sw, &arm_exporter); se.exportScene(sce); // std::string scene_name(translate_id(id_name(sce))); COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, scene_name)); scene.add(); // close sw.endDocument(); } void DocumentExporter::exportScenes(const char* filename) { } /* NOTES: * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user */