|
Blender
V2.59
|
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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 */