Blender  V2.59
DocumentExporter.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: DocumentExporter.cpp 38079 2011-07-04 08:59:28Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <math.h>
00032 
00033 extern "C" 
00034 {
00035 #include "DNA_scene_types.h"
00036 #include "DNA_object_types.h"
00037 #include "DNA_meshdata_types.h"
00038 #include "DNA_mesh_types.h"
00039 #include "DNA_image_types.h"
00040 #include "DNA_material_types.h"
00041 #include "DNA_texture_types.h"
00042 #include "DNA_anim_types.h"
00043 #include "DNA_action_types.h"
00044 #include "DNA_curve_types.h"
00045 #include "DNA_armature_types.h"
00046 #include "DNA_modifier_types.h"
00047 #include "DNA_userdef_types.h"
00048 
00049 #include "BKE_DerivedMesh.h"
00050 #include "BKE_fcurve.h"
00051 #include "BKE_animsys.h"
00052 #include "BLI_path_util.h"
00053 #include "BLI_fileops.h"
00054 #include "ED_keyframing.h"
00055 #ifdef NAN_BUILDINFO
00056 extern char build_rev[];
00057 #endif
00058 }
00059 
00060 #include "MEM_guardedalloc.h"
00061 
00062 #include "BKE_blender.h" // version info
00063 #include "BKE_scene.h"
00064 #include "BKE_global.h"
00065 #include "BKE_main.h"
00066 #include "BKE_material.h"
00067 #include "BKE_action.h" // pose functions
00068 #include "BKE_armature.h"
00069 #include "BKE_image.h"
00070 #include "BKE_utildefines.h"
00071 #include "BKE_object.h"
00072 
00073 #include "BLI_math.h"
00074 #include "BLI_string.h"
00075 #include "BLI_listbase.h"
00076 
00077 #include "RNA_access.h"
00078 
00079 #include "COLLADASWAsset.h"
00080 #include "COLLADASWLibraryVisualScenes.h"
00081 #include "COLLADASWNode.h"
00082 #include "COLLADASWSource.h"
00083 #include "COLLADASWInstanceGeometry.h"
00084 #include "COLLADASWInputList.h"
00085 #include "COLLADASWPrimitves.h"
00086 #include "COLLADASWVertices.h"
00087 #include "COLLADASWLibraryAnimations.h"
00088 #include "COLLADASWLibraryImages.h"
00089 #include "COLLADASWLibraryEffects.h"
00090 #include "COLLADASWImage.h"
00091 #include "COLLADASWEffectProfile.h"
00092 #include "COLLADASWColorOrTexture.h"
00093 #include "COLLADASWParamTemplate.h"
00094 #include "COLLADASWParamBase.h"
00095 #include "COLLADASWSurfaceInitOption.h"
00096 #include "COLLADASWSampler.h"
00097 #include "COLLADASWScene.h"
00098 #include "COLLADASWTechnique.h"
00099 #include "COLLADASWTexture.h"
00100 #include "COLLADASWLibraryMaterials.h"
00101 #include "COLLADASWBindMaterial.h"
00102 #include "COLLADASWInstanceCamera.h"
00103 #include "COLLADASWInstanceLight.h"
00104 #include "COLLADASWConstants.h"
00105 #include "COLLADASWLibraryControllers.h"
00106 #include "COLLADASWInstanceController.h"
00107 #include "COLLADASWBaseInputElement.h"
00108 
00109 #include "collada_internal.h"
00110 #include "DocumentExporter.h"
00111 
00112 // can probably go after refactor is complete
00113 #include "InstanceWriter.h"
00114 #include "TransformWriter.h"
00115 
00116 #include "ArmatureExporter.h"
00117 #include "CameraExporter.h"
00118 #include "EffectExporter.h"
00119 #include "GeometryExporter.h"
00120 #include "ImageExporter.h"
00121 #include "LightExporter.h"
00122 #include "MaterialExporter.h"
00123 
00124 #include <vector>
00125 #include <algorithm> // std::find
00126 
00127 char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
00128 {
00129         int layer_index = CustomData_get_layer_index(data, type);
00130         if(layer_index < 0) return NULL;
00131 
00132         return data->layers[layer_index+n].name;
00133 }
00134 
00135 char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
00136 {
00137         /* get the layer index of the active layer of type */
00138         int layer_index = CustomData_get_active_layer_index(data, type);
00139         if(layer_index < 0) return NULL;
00140 
00141         return data->layers[layer_index].name;
00142 }
00143 
00144 
00145 /*
00146   Utilities to avoid code duplication.
00147   Definition can take some time to understand, but they should be useful.
00148 */
00149 
00150 
00151 template<class Functor>
00152 void forEachObjectInScene(Scene *sce, Functor &f)
00153 {
00154         Base *base= (Base*) sce->base.first;
00155         while(base) {
00156                 Object *ob = base->object;
00157                         
00158                 f(ob);
00159 
00160                 base= base->next;
00161         }
00162 }
00163 
00164 
00165 
00166 class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
00167 {
00168         ArmatureExporter *arm_exporter;
00169 public:
00170         SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
00171                                                                                                                                                 arm_exporter(arm) {}
00172         
00173         void exportScene(Scene *sce, bool export_selected) {
00174                 // <library_visual_scenes> <visual_scene>
00175                 std::string id_naming = id_name(sce);
00176                 openVisualScene(translate_id(id_naming), id_naming);
00177 
00178                 // write <node>s
00179                 //forEachMeshObjectInScene(sce, *this);
00180                 //forEachCameraObjectInScene(sce, *this);
00181                 //forEachLampObjectInScene(sce, *this);
00182                 exportHierarchy(sce, export_selected);
00183 
00184                 // </visual_scene> </library_visual_scenes>
00185                 closeVisualScene();
00186 
00187                 closeLibrary();
00188         }
00189 
00190         void exportHierarchy(Scene *sce, bool export_selected)
00191         {
00192                 Base *base= (Base*) sce->base.first;
00193                 while(base) {
00194                         Object *ob = base->object;
00195 
00196                         if (!ob->parent) {
00197                                 switch(ob->type) {
00198                                 case OB_MESH:
00199                                 case OB_CAMERA:
00200                                 case OB_LAMP:
00201                                 case OB_ARMATURE:
00202                                 case OB_EMPTY:
00203                                         if (export_selected && !(ob->flag & SELECT)) {
00204                                                 break;
00205                                         }
00206                                         // write nodes....
00207                                         writeNodes(ob, sce);
00208                                         break;
00209                                 }
00210                         }
00211 
00212                         base= base->next;
00213                 }
00214         }
00215 
00216 
00217         // called for each object
00218         //void operator()(Object *ob) {
00219         void writeNodes(Object *ob, Scene *sce)
00220         {
00221                 COLLADASW::Node node(mSW);
00222                 node.setNodeId(translate_id(id_name(ob)));
00223                 node.setType(COLLADASW::Node::NODE);
00224 
00225                 node.start();
00226 
00227                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
00228 
00229                 if (ob->type == OB_MESH && is_skinned_mesh)
00230                         // for skinned mesh we write obmat in <bind_shape_matrix>
00231                         TransformWriter::add_node_transform_identity(node);
00232                 else
00233                         TransformWriter::add_node_transform_ob(node, ob);
00234                 
00235                 // <instance_geometry>
00236                 if (ob->type == OB_MESH) {
00237                         if (is_skinned_mesh) {
00238                                 arm_exporter->add_instance_controller(ob);
00239                         }
00240                         else {
00241                                 COLLADASW::InstanceGeometry instGeom(mSW);
00242                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
00243 
00244                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
00245                         
00246                                 instGeom.add();
00247                         }
00248                 }
00249 
00250                 // <instance_controller>
00251                 else if (ob->type == OB_ARMATURE) {
00252                         arm_exporter->add_armature_bones(ob, sce);
00253 
00254                         // XXX this looks unstable...
00255                         node.end();
00256                 }
00257                 
00258                 // <instance_camera>
00259                 else if (ob->type == OB_CAMERA) {
00260                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
00261                         instCam.add();
00262                 }
00263                 
00264                 // <instance_light>
00265                 else if (ob->type == OB_LAMP) {
00266                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
00267                         instLa.add();
00268                 }
00269 
00270                 // empty object
00271                 else if (ob->type == OB_EMPTY) {
00272                 }
00273 
00274                 // write nodes for child objects
00275                 Base *b = (Base*) sce->base.first;
00276                 while(b) {
00277                         // cob - child object
00278                         Object *cob = b->object;
00279 
00280                         if (cob->parent == ob) {
00281                                 switch(cob->type) {
00282                                 case OB_MESH:
00283                                 case OB_CAMERA:
00284                                 case OB_LAMP:
00285                                 case OB_EMPTY:
00286                                 case OB_ARMATURE:
00287                                         // write node...
00288                                         writeNodes(cob, sce);
00289                                         break;
00290                                 }
00291                         }
00292 
00293                         b = b->next;
00294                 }
00295 
00296                 if (ob->type != OB_ARMATURE)
00297                         node.end();
00298         }
00299 };
00300 
00301 // TODO: it would be better to instantiate animations rather than create a new one per object
00302 // COLLADA allows this through multiple <channel>s in <animation>.
00303 // For this to work, we need to know objects that use a certain action.
00304 class AnimationExporter: COLLADASW::LibraryAnimations
00305 {
00306         Scene *scene;
00307         COLLADASW::StreamWriter *sw;
00308 
00309 public:
00310 
00311         AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; }
00312 
00313 
00314 
00315         void exportAnimations(Scene *sce)
00316         {
00317                 if(hasAnimations(sce)) {
00318                         this->scene = sce;
00319 
00320                         openLibrary();
00321 
00322                         forEachObjectInScene(sce, *this);
00323 
00324                         closeLibrary();
00325                 }
00326         }
00327 
00328         // called for each exported object
00329         void operator() (Object *ob) 
00330         {
00331                 if (!ob->adt || !ob->adt->action) return;
00332                 
00333                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
00334                 
00335                 if (ob->type == OB_ARMATURE) {
00336                         if (!ob->data) return;
00337 
00338                         bArmature *arm = (bArmature*)ob->data;
00339                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
00340                                 write_bone_animation(ob, bone);
00341                 }
00342                 else {
00343                         while (fcu) {
00344                                 // TODO "rotation_quaternion" is also possible for objects (although euler is default)
00345                                 if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
00346                                         (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
00347                                         dae_animation(fcu, id_name(ob));
00348 
00349                                 fcu = fcu->next;
00350                         }
00351                 }
00352         }
00353 
00354 protected:
00355 
00356         void dae_animation(FCurve *fcu, std::string ob_name)
00357         {
00358                 const char *axis_names[] = {"X", "Y", "Z"};
00359                 const char *axis_name = NULL;
00360                 char anim_id[200];
00361                 
00362                 if (fcu->array_index < 3)
00363                         axis_name = axis_names[fcu->array_index];
00364 
00365                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
00366                                          fcu->rna_path, axis_names[fcu->array_index]);
00367 
00368                 // check rna_path is one of: rotation, scale, location
00369 
00370                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
00371 
00372                 // create input source
00373                 std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
00374 
00375                 // create output source
00376                 std::string output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
00377 
00378                 // create interpolations source
00379                 std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
00380 
00381                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
00382                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
00383                 std::string empty;
00384                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
00385                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
00386 
00387                 // this input is required
00388                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
00389 
00390                 addSampler(sampler);
00391 
00392                 std::string target = translate_id(ob_name)
00393                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
00394                 addChannel(COLLADABU::URI(empty, sampler_id), target);
00395 
00396                 closeAnimation();
00397         }
00398 
00399         void write_bone_animation(Object *ob_arm, Bone *bone)
00400         {
00401                 if (!ob_arm->adt)
00402                         return;
00403 
00404                 for (int i = 0; i < 3; i++)
00405                         sample_and_write_bone_animation(ob_arm, bone, i);
00406 
00407                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
00408                         write_bone_animation(ob_arm, child);
00409         }
00410 
00411         void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
00412         {
00413                 bArmature *arm = (bArmature*)ob_arm->data;
00414                 int flag = arm->flag;
00415                 std::vector<float> fra;
00416                 char prefix[256];
00417 
00418                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
00419 
00420                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
00421                 if (!pchan)
00422                         return;
00423 
00424                 switch (transform_type) {
00425                 case 0:
00426                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
00427                         break;
00428                 case 1:
00429                         find_frames(ob_arm, fra, prefix, "scale");
00430                         break;
00431                 case 2:
00432                         find_frames(ob_arm, fra, prefix, "location");
00433                         break;
00434                 default:
00435                         return;
00436                 }
00437 
00438                 // exit rest position
00439                 if (flag & ARM_RESTPOS) {
00440                         arm->flag &= ~ARM_RESTPOS;
00441                         where_is_pose(scene, ob_arm);
00442                 }
00443 
00444                 if (fra.size()) {
00445                         float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
00446                         sample_animation(v, fra, transform_type, bone, ob_arm);
00447 
00448                         if (transform_type == 0) {
00449                                 // write x, y, z curves separately if it is rotation
00450                                 float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
00451                                 for (int i = 0; i < 3; i++) {
00452                                         for (unsigned int j = 0; j < fra.size(); j++)
00453                                                 c[j] = v[j * 3 + i];
00454 
00455                                         dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
00456                                 }
00457                                 MEM_freeN(c);
00458                         }
00459                         else {
00460                                 // write xyz at once if it is location or scale
00461                                 dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
00462                         }
00463 
00464                         MEM_freeN(v);
00465                 }
00466 
00467                 // restore restpos
00468                 if (flag & ARM_RESTPOS) 
00469                         arm->flag = flag;
00470                 where_is_pose(scene, ob_arm);
00471         }
00472 
00473         void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
00474         {
00475                 bPoseChannel *pchan, *parchan = NULL;
00476                 bPose *pose = ob_arm->pose;
00477 
00478                 pchan = get_pose_channel(pose, bone->name);
00479 
00480                 if (!pchan)
00481                         return;
00482 
00483                 parchan = pchan->parent;
00484 
00485                 enable_fcurves(ob_arm->adt->action, bone->name);
00486 
00487                 std::vector<float>::iterator it;
00488                 for (it = frames.begin(); it != frames.end(); it++) {
00489                         float mat[4][4], ipar[4][4];
00490 
00491                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
00492 
00493                         BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
00494                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
00495 
00496                         // compute bone local mat
00497                         if (bone->parent) {
00498                                 invert_m4_m4(ipar, parchan->pose_mat);
00499                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
00500                         }
00501                         else
00502                                 copy_m4_m4(mat, pchan->pose_mat);
00503 
00504                         switch (type) {
00505                         case 0:
00506                                 mat4_to_eul(v, mat);
00507                                 break;
00508                         case 1:
00509                                 mat4_to_size(v, mat);
00510                                 break;
00511                         case 2:
00512                                 copy_v3_v3(v, mat[3]);
00513                                 break;
00514                         }
00515 
00516                         v += 3;
00517                 }
00518 
00519                 enable_fcurves(ob_arm->adt->action, NULL);
00520         }
00521 
00522         // dae_bone_animation -> add_bone_animation
00523         // (blend this into dae_bone_animation)
00524         void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
00525         {
00526                 const char *axis_names[] = {"X", "Y", "Z"};
00527                 const char *axis_name = NULL;
00528                 char anim_id[200];
00529                 bool is_rot = tm_type == 0;
00530                 
00531                 if (!fra.size())
00532                         return;
00533 
00534                 char rna_path[200];
00535                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
00536                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
00537 
00538                 if (axis > -1)
00539                         axis_name = axis_names[axis];
00540                 
00541                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
00542                 
00543                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
00544                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
00545 
00546                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
00547 
00548                 // create input source
00549                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
00550 
00551                 // create output source
00552                 std::string output_id;
00553                 if (axis == -1)
00554                         output_id = create_xyz_source(v, fra.size(), anim_id);
00555                 else
00556                         output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
00557 
00558                 // create interpolations source
00559                 std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
00560 
00561                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
00562                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
00563                 std::string empty;
00564                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
00565                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
00566 
00567                 // TODO create in/out tangents source
00568 
00569                 // this input is required
00570                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
00571 
00572                 addSampler(sampler);
00573 
00574                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
00575                 addChannel(COLLADABU::URI(empty, sampler_id), target);
00576 
00577                 closeAnimation();
00578         }
00579 
00580         float convert_time(float frame)
00581         {
00582                 return FRA2TIME(frame);
00583         }
00584 
00585         float convert_angle(float angle)
00586         {
00587                 return COLLADABU::Math::Utils::radToDegF(angle);
00588         }
00589 
00590         std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
00591         {
00592                 switch(semantic) {
00593                 case COLLADASW::InputSemantic::INPUT:
00594                         return INPUT_SOURCE_ID_SUFFIX;
00595                 case COLLADASW::InputSemantic::OUTPUT:
00596                         return OUTPUT_SOURCE_ID_SUFFIX;
00597                 case COLLADASW::InputSemantic::INTERPOLATION:
00598                         return INTERPOLATION_SOURCE_ID_SUFFIX;
00599                 case COLLADASW::InputSemantic::IN_TANGENT:
00600                         return INTANGENT_SOURCE_ID_SUFFIX;
00601                 case COLLADASW::InputSemantic::OUT_TANGENT:
00602                         return OUTTANGENT_SOURCE_ID_SUFFIX;
00603                 default:
00604                         break;
00605                 }
00606                 return "";
00607         }
00608 
00609         void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
00610                                                            COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis)
00611         {
00612                 switch(semantic) {
00613                 case COLLADASW::InputSemantic::INPUT:
00614                         param.push_back("TIME");
00615                         break;
00616                 case COLLADASW::InputSemantic::OUTPUT:
00617                         if (is_rot) {
00618                                 param.push_back("ANGLE");
00619                         }
00620                         else {
00621                                 if (axis) {
00622                                         param.push_back(axis);
00623                                 }
00624                                 else {
00625                                         param.push_back("X");
00626                                         param.push_back("Y");
00627                                         param.push_back("Z");
00628                                 }
00629                         }
00630                         break;
00631                 case COLLADASW::InputSemantic::IN_TANGENT:
00632                 case COLLADASW::InputSemantic::OUT_TANGENT:
00633                         param.push_back("X");
00634                         param.push_back("Y");
00635                         break;
00636                 default:
00637                         break;
00638                 }
00639         }
00640 
00641         void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
00642         {
00643                 switch (semantic) {
00644                 case COLLADASW::InputSemantic::INPUT:
00645                         *length = 1;
00646                         values[0] = convert_time(bezt->vec[1][0]);
00647                         break;
00648                 case COLLADASW::InputSemantic::OUTPUT:
00649                         *length = 1;
00650                         if (rotation) {
00651                                 values[0] = convert_angle(bezt->vec[1][1]);
00652                         }
00653                         else {
00654                                 values[0] = bezt->vec[1][1];
00655                         }
00656                         break;
00657                 case COLLADASW::InputSemantic::IN_TANGENT:
00658                 case COLLADASW::InputSemantic::OUT_TANGENT:
00659                         // XXX
00660                         *length = 2;
00661                         break;
00662                 default:
00663                         *length = 0;
00664                         break;
00665                 }
00666         }
00667 
00668         std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
00669         {
00670                 std::string source_id = anim_id + get_semantic_suffix(semantic);
00671 
00672                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
00673                 bool is_rotation = false;
00674                 
00675                 if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
00676                 
00677                 COLLADASW::FloatSourceF source(mSW);
00678                 source.setId(source_id);
00679                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
00680                 source.setAccessorCount(fcu->totvert);
00681                 source.setAccessorStride(1);
00682                 
00683                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00684                 add_source_parameters(param, semantic, is_rotation, axis_name);
00685 
00686                 source.prepareToAppendValues();
00687 
00688                 for (unsigned int i = 0; i < fcu->totvert; i++) {
00689                         float values[3]; // be careful!
00690                         int length = 0;
00691 
00692                         get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
00693                         for (int j = 0; j < length; j++)
00694                                 source.appendValues(values[j]);
00695                 }
00696 
00697                 source.finish();
00698 
00699                 return source_id;
00700         }
00701 
00702         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)
00703         {
00704                 std::string source_id = anim_id + get_semantic_suffix(semantic);
00705 
00706                 COLLADASW::FloatSourceF source(mSW);
00707                 source.setId(source_id);
00708                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
00709                 source.setAccessorCount(tot);
00710                 source.setAccessorStride(1);
00711                 
00712                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00713                 add_source_parameters(param, semantic, is_rot, axis_name);
00714 
00715                 source.prepareToAppendValues();
00716 
00717                 for (int i = 0; i < tot; i++) {
00718                         float val = v[i];
00719                         if (semantic == COLLADASW::InputSemantic::INPUT)
00720                                 val = convert_time(val);
00721                         else if (is_rot)
00722                                 val = convert_angle(val);
00723                         source.appendValues(val);
00724                 }
00725 
00726                 source.finish();
00727 
00728                 return source_id;
00729         }
00730 
00731         std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
00732         {
00733                 std::string source_id = anim_id + get_semantic_suffix(semantic);
00734 
00735                 COLLADASW::FloatSourceF source(mSW);
00736                 source.setId(source_id);
00737                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
00738                 source.setAccessorCount(fra.size());
00739                 source.setAccessorStride(1);
00740                 
00741                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00742                 add_source_parameters(param, semantic, is_rot, axis_name);
00743 
00744                 source.prepareToAppendValues();
00745 
00746                 std::vector<float>::iterator it;
00747                 for (it = fra.begin(); it != fra.end(); it++) {
00748                         float val = *it;
00749                         if (semantic == COLLADASW::InputSemantic::INPUT)
00750                                 val = convert_time(val);
00751                         else if (is_rot)
00752                                 val = convert_angle(val);
00753                         source.appendValues(val);
00754                 }
00755 
00756                 source.finish();
00757 
00758                 return source_id;
00759         }
00760 
00761         // only used for sources with OUTPUT semantic
00762         std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
00763         {
00764                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
00765                 std::string source_id = anim_id + get_semantic_suffix(semantic);
00766 
00767                 COLLADASW::FloatSourceF source(mSW);
00768                 source.setId(source_id);
00769                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
00770                 source.setAccessorCount(tot);
00771                 source.setAccessorStride(3);
00772                 
00773                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00774                 add_source_parameters(param, semantic, false, NULL);
00775 
00776                 source.prepareToAppendValues();
00777 
00778                 for (int i = 0; i < tot; i++) {
00779                         source.appendValues(*v, *(v + 1), *(v + 2));
00780                         v += 3;
00781                 }
00782 
00783                 source.finish();
00784 
00785                 return source_id;
00786         }
00787 
00788         std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
00789         {
00790                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
00791 
00792                 COLLADASW::NameSource source(mSW);
00793                 source.setId(source_id);
00794                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
00795                 source.setAccessorCount(tot);
00796                 source.setAccessorStride(1);
00797                 
00798                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
00799                 param.push_back("INTERPOLATION");
00800 
00801                 source.prepareToAppendValues();
00802 
00803                 for (int i = 0; i < tot; i++) {
00804                         source.appendValues(LINEAR_NAME);
00805                 }
00806 
00807                 source.finish();
00808 
00809                 return source_id;
00810         }
00811 
00812         // for rotation, axis name is always appended and the value of append_axis is ignored
00813         std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
00814         {
00815                 std::string tm_name;
00816 
00817                 // when given rna_path, determine tm_type from it
00818                 if (rna_path) {
00819                         char *name = extract_transform_name(rna_path);
00820 
00821                         if (strstr(name, "rotation"))
00822                                 tm_type = 0;
00823                         else if (!strcmp(name, "scale"))
00824                                 tm_type = 1;
00825                         else if (!strcmp(name, "location"))
00826                                 tm_type = 2;
00827                         else
00828                                 tm_type = -1;
00829                 }
00830 
00831                 switch (tm_type) {
00832                 case 0:
00833                         return std::string("rotation") + std::string(axis_name) + ".ANGLE";
00834                 case 1:
00835                         tm_name = "scale";
00836                         break;
00837                 case 2:
00838                         tm_name = "location";
00839                         break;
00840                 default:
00841                         tm_name = "";
00842                         break;
00843                 }
00844 
00845                 if (tm_name.size()) {
00846                         if (append_axis)
00847                                 return tm_name + std::string(".") + std::string(axis_name);
00848                         else
00849                                 return tm_name;
00850                 }
00851 
00852                 return std::string("");
00853         }
00854 
00855         char *extract_transform_name(char *rna_path)
00856         {
00857                 char *dot = strrchr(rna_path, '.');
00858                 return dot ? (dot + 1) : rna_path;
00859         }
00860 
00861         void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
00862         {
00863                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
00864 
00865                 for (; fcu; fcu = fcu->next) {
00866                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
00867                                 continue;
00868 
00869                         char *name = extract_transform_name(fcu->rna_path);
00870                         if (!strcmp(name, tm_name)) {
00871                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
00872                                         float f = fcu->bezt[i].vec[1][0];
00873                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())
00874                                                 fra.push_back(f);
00875                                 }
00876                         }
00877                 }
00878 
00879                 // keep the keys in ascending order
00880                 std::sort(fra.begin(), fra.end());
00881         }
00882 
00883         void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
00884         {
00885                 if (rotmode > 0)
00886                         find_frames(ob, fra, prefix, "rotation_euler");
00887                 else if (rotmode == ROT_MODE_QUAT)
00888                         find_frames(ob, fra, prefix, "rotation_quaternion");
00889                 /*else if (rotmode == ROT_MODE_AXISANGLE)
00890                         ;*/
00891         }
00892 
00893         // enable fcurves driving a specific bone, disable all the rest
00894         // if bone_name = NULL enable all fcurves
00895         void enable_fcurves(bAction *act, char *bone_name)
00896         {
00897                 FCurve *fcu;
00898                 char prefix[200];
00899 
00900                 if (bone_name)
00901                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
00902 
00903                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
00904                         if (bone_name) {
00905                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
00906                                         fcu->flag &= ~FCURVE_DISABLED;
00907                                 else
00908                                         fcu->flag |= FCURVE_DISABLED;
00909                         }
00910                         else {
00911                                 fcu->flag &= ~FCURVE_DISABLED;
00912                         }
00913                 }
00914         }
00915         
00916         bool hasAnimations(Scene *sce)
00917         {
00918                 Base *base= (Base*) sce->base.first;
00919                 while(base) {
00920                         Object *ob = base->object;
00921                         
00922                         FCurve *fcu = 0;
00923                         if(ob->adt && ob->adt->action)
00924                                 fcu = (FCurve*)ob->adt->action->curves.first;
00925                                 
00926                         if ((ob->type == OB_ARMATURE && ob->data) || fcu) {
00927                                 return true;
00928                         }
00929                         base= base->next;
00930                 }
00931                 return false;
00932         }
00933 };
00934 
00935 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename, bool selected)
00936 {
00937         PointerRNA sceneptr, unit_settings;
00938         PropertyRNA *system; /* unused , *scale; */
00939 
00940         clear_global_id_map();
00941         
00942         COLLADABU::NativeString native_filename =
00943                 COLLADABU::NativeString(std::string(filename));
00944         COLLADASW::StreamWriter sw(native_filename);
00945 
00946         // open <collada>
00947         sw.startDocument();
00948 
00949         // <asset>
00950         COLLADASW::Asset asset(&sw);
00951 
00952         RNA_id_pointer_create(&(sce->id), &sceneptr);
00953         unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
00954         system = RNA_struct_find_property(&unit_settings, "system");
00955         //scale = RNA_struct_find_property(&unit_settings, "scale_length");
00956 
00957         std::string unitname = "meter";
00958         float linearmeasure = 1.0f;
00959 
00960         linearmeasure = RNA_float_get(&unit_settings, "scale_length");
00961 
00962         switch(RNA_property_enum_get(&unit_settings, system)) {
00963                 case USER_UNIT_NONE:
00964                 case USER_UNIT_METRIC:
00965                         if(linearmeasure == 0.001f) {
00966                                 unitname = "millimeter";
00967                         }
00968                         else if(linearmeasure == 0.01f) {
00969                                 unitname = "centimeter";
00970                         }
00971                         else if(linearmeasure == 0.1f) {
00972                                 unitname = "decimeter";
00973                         }
00974                         else if(linearmeasure == 1.0f) {
00975                                 unitname = "meter";
00976                         }
00977                         else if(linearmeasure == 1000.0f) {
00978                                 unitname = "kilometer";
00979                         }
00980                         break;
00981                 case USER_UNIT_IMPERIAL:
00982                         if(linearmeasure == 0.0254f) {
00983                                 unitname = "inch";
00984                         }
00985                         else if(linearmeasure == 0.3048f) {
00986                                 unitname = "foot";
00987                         }
00988                         else if(linearmeasure == 0.9144f) {
00989                                 unitname = "yard";
00990                         }
00991                         break;
00992                 default:
00993                         break;
00994         }
00995 
00996         asset.setUnit(unitname, linearmeasure);
00997         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
00998         // TODO: need an Author field in userpref
00999         if(strlen(U.author) > 0) {
01000                 asset.getContributor().mAuthor = U.author;
01001         }
01002         else {
01003                 asset.getContributor().mAuthor = "Blender User";
01004         }
01005 #ifdef NAN_BUILDINFO
01006         char version_buf[128];
01007         sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
01008         asset.getContributor().mAuthoringTool = version_buf;
01009 #else
01010         asset.getContributor().mAuthoringTool = "Blender 2.5x";
01011 #endif
01012         asset.add();
01013         
01014         // <library_cameras>
01015         if(has_object_type(sce, OB_CAMERA)) {
01016                 CamerasExporter ce(&sw);
01017                 ce.exportCameras(sce, selected);
01018         }
01019         
01020         // <library_lights>
01021         if(has_object_type(sce, OB_LAMP)) {
01022                 LightsExporter le(&sw);
01023                 le.exportLights(sce, selected);
01024         }
01025 
01026         // <library_images>
01027         ImagesExporter ie(&sw, filename);
01028         ie.exportImages(sce, selected);
01029         
01030         // <library_effects>
01031         EffectsExporter ee(&sw);
01032         ee.exportEffects(sce, selected);
01033         
01034         // <library_materials>
01035         MaterialsExporter me(&sw);
01036         me.exportMaterials(sce, selected);
01037 
01038         // <library_geometries>
01039         if(has_object_type(sce, OB_MESH)) {
01040                 GeometryExporter ge(&sw);
01041                 ge.exportGeom(sce, selected);
01042         }
01043 
01044         // <library_animations>
01045         AnimationExporter ae(&sw);
01046         ae.exportAnimations(sce);
01047 
01048         // <library_controllers>
01049         ArmatureExporter arm_exporter(&sw);
01050         if(has_object_type(sce, OB_ARMATURE)) {
01051                 arm_exporter.export_controllers(sce, selected);
01052         }
01053 
01054         // <library_visual_scenes>
01055         SceneExporter se(&sw, &arm_exporter);
01056         se.exportScene(sce, selected);
01057         
01058         // <scene>
01059         std::string scene_name(translate_id(id_name(sce)));
01060         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
01061                                                                                            scene_name));
01062         scene.add();
01063         
01064         // close <Collada>
01065         sw.endDocument();
01066 
01067 }
01068 
01069 void DocumentExporter::exportScenes(const char* filename)
01070 {
01071 }
01072 
01073 /*
01074 
01075 NOTES:
01076 
01077 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
01078 
01079  */