From c263753d1770b5b812ea0e5c38174fa296492e2f Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Mon, 21 Jan 2013 13:45:49 +0000 Subject: Added gsoc-2012 collada improvements from bratwurst branch --- .../wm.collada_export/second_life_rigged.py | 1 + .../wm.collada_export/second_life_static.py | 1 + source/blender/collada/AnimationExporter.cpp | 274 ++++++++-- source/blender/collada/AnimationExporter.h | 30 +- source/blender/collada/AnimationImporter.cpp | 5 +- source/blender/collada/ArmatureExporter.cpp | 445 ++------------- source/blender/collada/ArmatureExporter.h | 28 +- source/blender/collada/ArmatureImporter.cpp | 250 ++++----- source/blender/collada/ArmatureImporter.h | 14 +- source/blender/collada/CMakeLists.txt | 5 + source/blender/collada/ControllerExporter.cpp | 598 +++++++++++++++++++++ source/blender/collada/ControllerExporter.h | 126 +++++ source/blender/collada/DocumentExporter.cpp | 11 +- source/blender/collada/DocumentImporter.cpp | 59 +- source/blender/collada/DocumentImporter.h | 8 + source/blender/collada/ExportSettings.h | 1 + source/blender/collada/ExtraHandler.cpp | 1 + source/blender/collada/GeometryExporter.cpp | 86 ++- source/blender/collada/GeometryExporter.h | 5 + source/blender/collada/MeshImporter.cpp | 13 +- source/blender/collada/MeshImporter.h | 29 +- source/blender/collada/SceneExporter.cpp | 43 +- source/blender/collada/SceneExporter.h | 2 + source/blender/collada/TransformReader.cpp | 46 +- source/blender/collada/TransformWriter.cpp | 19 +- source/blender/collada/collada.cpp | 2 + source/blender/collada/collada.h | 1 + source/blender/collada/collada_internal.cpp | 6 + source/blender/collada/collada_internal.h | 2 + source/blender/editors/io/io_collada.c | 10 + source/blender/makesrna/intern/rna_scene_api.c | 4 +- 31 files changed, 1426 insertions(+), 699 deletions(-) create mode 100644 source/blender/collada/ControllerExporter.cpp create mode 100644 source/blender/collada/ControllerExporter.h diff --git a/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py b/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py index 2c695a22ff9..81769a82728 100644 --- a/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py +++ b/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py @@ -7,6 +7,7 @@ op.export_mesh_type_selection = 'view' op.selected = True op.include_children = False op.include_armatures = True +op.include_shapekeys = False op.deform_bones_only = True op.active_uv_only = True op.include_uv_textures = True diff --git a/release/scripts/presets/operator/wm.collada_export/second_life_static.py b/release/scripts/presets/operator/wm.collada_export/second_life_static.py index 081788b7e9d..ad06909a276 100644 --- a/release/scripts/presets/operator/wm.collada_export/second_life_static.py +++ b/release/scripts/presets/operator/wm.collada_export/second_life_static.py @@ -7,6 +7,7 @@ op.export_mesh_type_selection = 'view' op.selected = True op.include_children = False op.include_armatures = False +op.include_shapekeys = False op.deform_bones_only = False op.active_uv_only = True op.include_uv_textures = True diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index 26b5edf7ea6..493d15135a7 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -24,6 +24,8 @@ #include "AnimationExporter.h" #include "MaterialExporter.h" +Global G; + template void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set) { @@ -82,7 +84,12 @@ void AnimationExporter::operator()(Object *ob) } } - + + export_object_constraint_animation(ob); + + //This needs to be handled by extra profiles, so postponed for now + //export_morph_animation(ob); + //Export Lamp parameter animations if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) { fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); @@ -134,7 +141,69 @@ void AnimationExporter::operator()(Object *ob) fcu = fcu->next; } } + } + + +} + +void AnimationExporter::export_object_constraint_animation(Object *ob) +{ + std::vector fra; + //Takes frames of target animations + make_anim_frames_from_targets(ob, fra); + + if (fra.size()) + dae_baked_object_animation(fra, ob); +} + +void AnimationExporter::export_morph_animation(Object *ob) +{ + FCurve *fcu; + char *transformName; + Key *key = BKE_key_from_object(ob); + if(!key) return; + + if(key->adt && key->adt->action){ + fcu = (FCurve *)key->adt->action->curves.first; + + while (fcu) { + transformName = extract_transform_name(fcu->rna_path); + + dae_animation(ob, fcu, transformName, true); + + fcu = fcu->next; + } + } + +} +void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector &frames ){ + + ListBase *conlist = get_active_constraints(ob); + if(conlist == NULL) return; + bConstraint *con; + for (con = (bConstraint*)conlist->first; con; con = con->next) { + ListBase targets = {NULL, NULL}; + + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); + + if(!validateConstraints(con)) continue; + + if (cti && cti->get_constraint_targets) { + bConstraintTarget *ct; + Object *obtar; + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, &targets); + if(cti){ + for (ct = (bConstraintTarget*)targets.first; ct; ct = ct->next){ + obtar = ct->tar; + find_frames(obtar, frames); + } + } + } } } @@ -320,6 +389,9 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa if (ma) target = translate_id(id_name(ma)) + "-effect" + "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true); + //if shape key animation, this is the main problem, how to define the channel targets. + /*target = get_morph_id(ob) + + "/value" +*/ } addChannel(COLLADABU::URI(empty, sampler_id), target); @@ -368,18 +440,23 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B //char prefix[256]; FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first; - while (fcu) { + + //Check if there is a fcurve in the armature for the bone in param + //when baking this check is not needed, solve every bone for every frame. + /*while (fcu) { std::string bone_name = getObjectBoneName(ob_arm, fcu); int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name); if (val == 0) break; fcu = fcu->next; } - if (!(fcu)) return; + if (!(fcu)) return;*/ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); if (!pchan) return; + //every inserted keyframe of bones. find_frames(ob_arm, fra); if (flag & ARM_RESTPOS) { @@ -415,7 +492,8 @@ void AnimationExporter::dae_baked_animation(std::vector &fra, Object *ob_ // create output source std::string output_id; - output_id = create_4x4_source(fra, ob_arm, bone, anim_id); + + output_id = create_4x4_source(fra, ob_arm, bone, anim_id); // create interpolations source std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, ""); @@ -439,6 +517,48 @@ void AnimationExporter::dae_baked_animation(std::vector &fra, Object *ob_ closeAnimation(); } +void AnimationExporter::dae_baked_object_animation(std::vector &fra, Object *ob) +{ + std::string ob_name = id_name(ob); + char anim_id[200]; + + if (!fra.size()) + return; + + BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char*)translate_id(ob_name).c_str(), + "object_matrix"); + + openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); + + // create input source + std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, ""); + + // create output source + std::string output_id; + output_id = create_4x4_source( fra, ob, NULL, anim_id); + + // create interpolations source + std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, ""); + + 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) + "/transform"; + addChannel(COLLADABU::URI(empty, sampler_id), target); + + closeAnimation(); +} + // dae_bone_animation -> add_bone_animation // (blend this into dae_bone_animation) void AnimationExporter::dae_bone_animation(std::vector &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name) @@ -762,7 +882,8 @@ std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemanti return source_id; } -std::string AnimationExporter::create_4x4_source(std::vector &frames, Object *ob_arm, Bone *bone, const std::string& anim_id) + +std::string AnimationExporter::create_4x4_source(std::vector &frames, Object * ob, Bone *bone, const std::string& anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); @@ -777,74 +898,94 @@ std::string AnimationExporter::create_4x4_source(std::vector &frames, Obj add_source_parameters(param, semantic, false, NULL, true); source.prepareToAppendValues(); - + bPoseChannel *parchan = NULL; bPoseChannel *pchan = NULL; - bPose *pose = ob_arm->pose; + bPoseChannel *rootchan = NULL; + + if (ob->type == OB_ARMATURE ){ + bPose *pose = ob->pose; + pchan = BKE_pose_channel_find_name(pose, bone->name); + if (!pchan) + return ""; - pchan = BKE_pose_channel_find_name(pose, bone->name); - - if (!pchan) - return ""; - - parchan = pchan->parent; - - enable_fcurves(ob_arm->adt->action, bone->name); + parchan = pchan->parent; + enable_fcurves(ob->adt->action, bone->name); + } + std::vector::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; - + float ctime = BKE_scene_frame_get_from_ctime(scene, *it); - - BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); - BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1); - - // compute bone local mat - if (bone->parent) { - invert_m4_m4(ipar, parchan->pose_mat); - mult_m4_m4m4(mat, ipar, pchan->pose_mat); - } - else - copy_m4_m4(mat, pchan->pose_mat); - UnitConverter converter; - + CFRA = BKE_scene_frame_get_from_ctime(scene, *it); + //BKE_scene_update_for_newframe(G.main,scene,scene->lay); + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); + + if (bone){ + if( pchan->flag & POSE_CHAIN) + { + enable_fcurves(ob->adt->action, NULL); + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); + BKE_pose_where_is(scene, ob); + } + else + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + + // compute bone local mat + if (bone->parent) { + invert_m4_m4(ipar, parchan->pose_mat); + mult_m4_m4m4(mat, ipar, pchan->pose_mat); + } + else + copy_m4_m4(mat, pchan->pose_mat); + // SECOND_LIFE_COMPATIBILITY // AFAIK animation to second life is via BVH, but no // reason to not have the collada-animation be correct - if (export_settings->second_life) { - float temp[4][4]; - copy_m4_m4(temp, bone->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - invert_m4(temp); + if (export_settings->second_life) { + float temp[4][4]; + copy_m4_m4(temp, bone->arm_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + invert_m4(temp); - mult_m4_m4m4(mat, mat, temp); + mult_m4_m4m4(mat, mat, temp); - if (bone->parent) { - copy_m4_m4(temp, bone->parent->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + if (bone->parent) { + copy_m4_m4(temp, bone->parent->arm_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - mult_m4_m4m4(mat, temp, mat); + mult_m4_m4m4(mat, temp, mat); + } } - } - float outmat[4][4]; - converter.mat4_to_dae(outmat, mat); + } + else { + calc_ob_mat_at_time(ob, ctime, mat); + } + + UnitConverter converter; + double outmat[4][4]; + converter.mat4_to_dae_double(outmat, mat); source.appendValues(outmat); - j++; + + BIK_release_tree(scene, ob, ctime); } - enable_fcurves(ob_arm->adt->action, NULL); + enable_fcurves(ob->adt->action, NULL); source.finish(); return source_id; } + + // only used for sources with OUTPUT semantic ( locations and scale) std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id) { @@ -1184,6 +1325,12 @@ bool AnimationExporter::hasAnimations(Scene *sce) } } + //check shape key animation + if(!fcu){ + Key *key = BKE_key_from_object(ob); + if(key && key->adt && key->adt->action) + fcu = (FCurve *)key->adt->action->curves.first; + } if (fcu) return true; } @@ -1351,3 +1498,42 @@ void AnimationExporter::sample_animation(float *v, std::vector &frames, i enable_fcurves(ob_arm->adt->action, NULL); } + +bool AnimationExporter::validateConstraints(bConstraint *con){ + + bool valid = true; + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); + /* these we can skip completely (invalid constraints...) */ + if (cti == NULL) valid = false; + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false; + /* these constraints can't be evaluated anyway */ + if (cti->evaluate_constraint == NULL) valid = false; + /* influence == 0 should be ignored */ + if (con->enforce == 0.0f) valid = false; + + return valid; +} + +void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4]){ + ListBase *conlist = get_active_constraints(ob); + bConstraint *con; + for (con = (bConstraint*)conlist->first; con; con = con->next) { + ListBase targets = {NULL, NULL}; + + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); + + if (cti && cti->get_constraint_targets) { + bConstraintTarget *ct; + Object *obtar; + cti->get_constraint_targets(con, &targets); + for (ct = (bConstraintTarget*)targets.first; ct; ct = ct->next){ + obtar = ct->tar; + BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM); + BKE_object_where_is_calc_time(scene, obtar, ctime); + } + } + } + BKE_object_where_is_calc_time(scene, ob, ctime); + copy_m4_m4(mat, ob->obmat); +} + diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h index 349930dea8f..d2f50b22d02 100644 --- a/source/blender/collada/AnimationExporter.h +++ b/source/blender/collada/AnimationExporter.h @@ -34,6 +34,7 @@ extern "C" #include "DNA_camera_types.h" #include "DNA_armature_types.h" #include "DNA_material_types.h" +#include "DNA_constraint_types.h" #include "BLI_math.h" #include "BLI_string.h" @@ -47,6 +48,10 @@ extern "C" #include "BKE_action.h" // pose functions #include "BKE_armature.h" #include "BKE_object.h" +#include "BKE_constraint.h" +#include "BIK_api.h" +#include "BKE_global.h" +#include "ED_object.h" #ifdef NAN_BUILDINFO extern char build_rev[]; @@ -73,9 +78,13 @@ extern char build_rev[]; #include "collada_internal.h" +#include "IK_solver.h" + #include #include // std::find + + class AnimationExporter: COLLADASW::LibraryAnimations { private: @@ -98,6 +107,10 @@ protected: const ExportSettings *export_settings; void dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL); + + void export_object_constraint_animation(Object *ob); + + void export_morph_animation(Object *ob); void write_bone_animation_matrix(Object *ob_arm, Bone *bone); @@ -119,6 +132,8 @@ protected: void dae_baked_animation(std::vector &fra, Object *ob_arm, Bone *bone); + void dae_baked_object_animation(std::vector &fra, Object *ob); + float convert_time(float frame); float convert_angle(float angle); @@ -130,7 +145,7 @@ protected: void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length); - float * get_eul_source_for_quat(Object *ob ); + float* get_eul_source_for_quat(Object *ob ); std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name); @@ -143,17 +158,21 @@ protected: std::string create_xyz_source(float *v, int tot, const std::string& anim_id); std::string create_4x4_source(std::vector &frames, Object * ob_arm, Bone *bone, const std::string& anim_id); - + std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents); std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name); + // 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 get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); + void find_frames(Object *ob, std::vector &fra, const char *prefix, const char *tm_name); void find_frames(Object *ob, std::vector &fra); + void make_anim_frames_from_targets(Object *ob, std::vector &frames ); + void find_rotation_frames(Object *ob, std::vector &fra, const char *prefix, int rotmode); // enable fcurves driving a specific bone, disable all the rest @@ -165,4 +184,11 @@ protected: char *extract_transform_name(char *rna_path); std::string getObjectBoneName(Object *ob, const FCurve * fcu); + + void getBakedPoseData(Object *obarm, int startFrame, int endFrame, bool ActionBake, bool ActionBakeFirstFrame); + + bool validateConstraints(bConstraint *con); + + void calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4]); + }; diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 3d0ceb560ed..943c4fb574d 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -937,10 +937,9 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, if (is_matrix) { apply_matrix_curves(ob, animcurves, root, node, transform); } - else { + else { if (is_joint) { - add_bone_animation_sampled(ob, animcurves, root, node, transform); } else { @@ -1676,8 +1675,6 @@ void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW:: default: fprintf(stderr, "unsupported transformation type %d\n", type); } - // dae_matrix_to_mat4(tm, m); - } float temp[4][4]; diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 134fd639a73..36993eae7b6 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -75,12 +75,6 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce, } } -bool ArmatureExporter::is_skinned_mesh(Object *ob) -{ - return bc_get_assigned_armature(ob) != NULL; -} - - void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) { if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) @@ -110,31 +104,17 @@ bool ArmatureExporter::add_instance_controller(Object *ob) for (bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) { write_bone_URLs(ins, ob_arm, bone); } - + InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); ins.add(); return true; } -void ArmatureExporter::export_controllers(Scene *sce) -{ - scene = sce; - - openLibrary(); - - GeometryFunctor gf; - gf.forEachMeshObjectInExportSet(sce, *this, this->export_settings->export_set); - - closeLibrary(); -} - void ArmatureExporter::operator()(Object *ob) { Object *ob_arm = bc_get_assigned_armature(ob); - if (ob_arm /*&& !already_written(ob_arm)*/) - export_controller(ob, ob_arm); } #if 0 @@ -187,67 +167,67 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, node.setNodeName(node_name); node.setNodeSid(node_sid); -#if 0 +#if 0 if (bone->childbase.first == NULL || BLI_countlist(&(bone->childbase)) >= 2) { add_blender_leaf_bone( bone, ob_arm, node); } - else { + else{ #endif - node.start(); + node.start(); - add_bone_transform(ob_arm, bone, node); + add_bone_transform(ob_arm, bone, node); - // Write nodes of childobjects, remove written objects from list - std::list::iterator i = child_objects.begin(); + // Write nodes of childobjects, remove written objects from list + std::list::iterator i = child_objects.begin(); - while (i != child_objects.end()) { - if ((*i)->partype == PARBONE && (0 == strcmp((*i)->parsubstr, bone->name))) { - float backup_parinv[4][4]; - copy_m4_m4(backup_parinv, (*i)->parentinv); + while (i != child_objects.end()) { + if ((*i)->partype == PARBONE && (0 == strcmp((*i)->parsubstr, bone->name))) { + float backup_parinv[4][4]; + copy_m4_m4(backup_parinv, (*i)->parentinv); - // crude, temporary change to parentinv - // so transform gets exported correctly. + // crude, temporary change to parentinv + // so transform gets exported correctly. - // Add bone tail- translation... don't know why - // bone parenting is against the tail of a bone - // and not it's head, seems arbitrary. - (*i)->parentinv[3][1] += bone->length; + // Add bone tail- translation... don't know why + // bone parenting is against the tail of a bone + // and not it's head, seems arbitrary. + (*i)->parentinv[3][1] += bone->length; - // SECOND_LIFE_COMPATIBILITY - // TODO: when such objects are animated as - // single matrix the tweak must be applied - // to the result. - if (export_settings->second_life) { - // tweak objects parentinverse to match compatibility - float temp[4][4]; + // SECOND_LIFE_COMPATIBILITY + // TODO: when such objects are animated as + // single matrix the tweak must be applied + // to the result. + if (export_settings->second_life) { + // tweak objects parentinverse to match compatibility + float temp[4][4]; - copy_m4_m4(temp, bone->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + copy_m4_m4(temp, bone->arm_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - mult_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv); - } + mult_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv); + } - se->writeNodes(*i, sce); + se->writeNodes(*i, sce); - copy_m4_m4((*i)->parentinv, backup_parinv); - child_objects.erase(i++); + copy_m4_m4((*i)->parentinv, backup_parinv); + child_objects.erase(i++); + } + else i++; } - else i++; - } - for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(child, ob_arm, sce, se, child_objects); + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + add_bone_node(child, ob_arm, sce, se, child_objects); + } + node.end(); } - node.end(); - } - else { - for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(child, ob_arm, sce, se, child_objects); + else { + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + add_bone_node(child, ob_arm, sce, se, child_objects); + } } - } } -#if 0 +//#if 1 void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node) { node.start(); @@ -258,13 +238,13 @@ void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADA node.addExtraTechniqueParameter("blender", "tip_y", bone->tail[1]); node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2]); - for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + /*for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { add_bone_node(child, ob_arm, sce, se, child_objects); - } + }*/ node.end(); } -#endif +//#endif void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node) { @@ -273,22 +253,27 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW: float mat[4][4]; if (bone->parent) { - // get bone-space matrix from armature-space - bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name); - + // get bone-space matrix from parent pose + /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name); float invpar[4][4]; invert_m4_m4(invpar, parchan->pose_mat); - mult_m4_m4m4(mat, invpar, pchan->pose_mat); + mult_m4_m4m4(mat, invpar, pchan->pose_mat);*/ + + float invpar[4][4]; + invert_m4_m4(invpar, bone->parent->arm_mat); + mult_m4_m4m4(mat, invpar, bone->arm_mat); + } else { - copy_m4_m4(mat, pchan->pose_mat); - // Why? Joint's localspace is still it's parent node - //get world-space from armature-space - //mult_m4_m4m4(mat, ob_arm->obmat, pchan->pose_mat); + + //copy_m4_m4(mat, pchan->pose_mat); + //pose mat is object space + //New change: export bone->arm_mat + copy_m4_m4(mat, bone->arm_mat); } // SECOND_LIFE_COMPATIBILITY - if (export_settings->second_life) { + if (export_settings->second_life) { // Remove rotations vs armature from transform // parent_rest_rot * mat * irest_rot float temp[4][4]; @@ -313,315 +298,3 @@ std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob) { return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX; } - -// ob should be of type OB_MESH -// both args are required -void ArmatureExporter::export_controller(Object *ob, Object *ob_arm) -{ - // joint names - // joint inverse bind matrices - // vertex weights - - // input: - // joint names: ob -> vertex group names - // vertex group weights: me->dvert -> groups -> index, weight - -#if 0 - me->dvert : - - typedef struct MDeformVert { - struct MDeformWeight *dw; - int totweight; - int flag; // flag only in use for weightpaint now - } MDeformVert; - - typedef struct MDeformWeight { - int def_nr; - float weight; - } MDeformWeight; -#endif - - bool use_instantiation = this->export_settings->use_object_instantiation; - Mesh *me; - - if (this->export_settings->apply_modifiers) { - me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type); - } - else { - me = (Mesh *)ob->data; - } - BKE_mesh_tessface_ensure(me); - - if (!me->dvert) return; - - std::string controller_name = id_name(ob_arm); - std::string controller_id = get_controller_id(ob_arm, ob); - - openSkin(controller_id, controller_name, - COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation))); - - add_bind_shape_mat(ob); - - std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); - std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); - - std::list vcounts; - std::list joints; - std::list weights; - - { - int i, j; - - // def group index -> joint index - std::vector joint_index_by_def_index; - bDeformGroup *def; - - for (def = (bDeformGroup *)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) { - if (is_bone_defgroup(ob_arm, def)) - joint_index_by_def_index.push_back(j++); - else - joint_index_by_def_index.push_back(-1); - } - - for (i = 0; i < me->totvert; i++) { - MDeformVert *vert = &me->dvert[i]; - std::map jw; - - // We're normalizing the weights later - float sumw = 0.0f; - - for (j = 0; j < vert->totweight; j++) { - int joint_index = joint_index_by_def_index[vert->dw[j].def_nr]; - if (joint_index != -1 && vert->dw[j].weight > 0.0f) { - jw[joint_index] += vert->dw[j].weight; - sumw += vert->dw[j].weight; - } - } - - if (sumw > 0.0f) { - float invsumw = 1.0f / sumw; - vcounts.push_back(jw.size()); - for (std::map::iterator m = jw.begin(); m != jw.end(); ++m) { - joints.push_back((*m).first); - weights.push_back(invsumw * (*m).second); - } - } - else { - vcounts.push_back(0); -#if 0 - vcounts.push_back(1); - joints.push_back(-1); - weights.push_back(1.0f); -#endif - } - } - } - - std::string weights_source_id = add_weights_source(me, controller_id, weights); - add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); - add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints); - - if (this->export_settings->apply_modifiers) - { - BKE_libblock_free_us(&(G.main->mesh), me); - } - closeSkin(); - closeController(); -} - -void ArmatureExporter::add_joints_element(ListBase *defbase, - const std::string& joints_source_id, const std::string& inv_bind_mat_source_id) -{ - COLLADASW::JointsElement joints(mSW); - COLLADASW::InputList &input = joints.getInputList(); - - input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id))); - input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX, - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id))); - joints.add(); -} - -void ArmatureExporter::add_bind_shape_mat(Object *ob) -{ - double bind_mat[4][4]; - - converter.mat4_to_dae_double(bind_mat, ob->obmat); - - addBindShapeTransform(bind_mat); -} - -std::string ArmatureExporter::add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) -{ - std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX; - - int totjoint = 0; - bDeformGroup *def; - for (def = (bDeformGroup *)defbase->first; def; def = def->next) { - if (is_bone_defgroup(ob_arm, def)) - totjoint++; - } - - COLLADASW::NameSource source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(totjoint); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("JOINT"); - - source.prepareToAppendValues(); - - for (def = (bDeformGroup *)defbase->first; def; def = def->next) { - Bone *bone = get_bone_from_defgroup(ob_arm, def); - if (bone) - source.appendValues(get_joint_sid(bone, ob_arm)); - } - - source.finish(); - - return source_id; -} - -std::string ArmatureExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) -{ - std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; - - int totjoint = 0; - for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { - if (is_bone_defgroup(ob_arm, def)) - totjoint++; - } - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(totjoint); //BLI_countlist(defbase)); - source.setAccessorStride(16); - - source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("TRANSFORM"); - - source.prepareToAppendValues(); - - bPose *pose = ob_arm->pose; - bArmature *arm = (bArmature *)ob_arm->data; - - int flag = arm->flag; - - // put armature in rest position - if (!(arm->flag & ARM_RESTPOS)) { - arm->flag |= ARM_RESTPOS; - BKE_pose_where_is(scene, ob_arm); - } - - for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { - if (is_bone_defgroup(ob_arm, def)) { - bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name); - - float mat[4][4]; - float world[4][4]; - float inv_bind_mat[4][4]; - - // SECOND_LIFE_COMPATIBILITY - if (export_settings->second_life) { - // Only translations, no rotation vs armature - float temp[4][4]; - unit_m4(temp); - copy_v3_v3(temp[3], pchan->bone->arm_mat[3]); - mult_m4_m4m4(world, ob_arm->obmat, temp); - } - else { - // make world-space matrix, arm_mat is armature-space - mult_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat); - } - - invert_m4_m4(mat, world); - converter.mat4_to_dae(inv_bind_mat, mat); - - source.appendValues(inv_bind_mat); - } - } - - // back from rest positon - if (!(flag & ARM_RESTPOS)) { - arm->flag = flag; - BKE_pose_where_is(scene, ob_arm); - } - - source.finish(); - - return source_id; -} - -Bone *ArmatureExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def) -{ - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name); - return pchan ? pchan->bone : NULL; -} - -bool ArmatureExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup *def) -{ - return get_bone_from_defgroup(ob_arm, def) != NULL; -} - -std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id, const std::list& weights) -{ - std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX; - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(weights.size()); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("WEIGHT"); - - source.prepareToAppendValues(); - - for (std::list::const_iterator i = weights.begin(); i != weights.end(); ++i) { - source.appendValues(*i); - } - - source.finish(); - - return source_id; -} - -void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, - const std::list& vcounts, - const std::list& joints) -{ - COLLADASW::VertexWeightsElement weightselem(mSW); - COLLADASW::InputList &input = weightselem.getInputList(); - - int offset = 0; - input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++)); - input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT, - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++)); - - weightselem.setCount(vcounts.size()); - - // write number of deformers per vertex - COLLADASW::PrimitivesBase::VCountList vcountlist; - - vcountlist.resize(vcounts.size()); - std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin()); - - weightselem.prepareToAppendVCountValues(); - weightselem.appendVertexCount(vcountlist); - - weightselem.CloseVCountAndOpenVElement(); - - // write deformer index - weight index pairs - int weight_index = 0; - for (std::list::const_iterator i = joints.begin(); i != joints.end(); ++i) { - weightselem.appendValues(*i, weight_index++); - } - - weightselem.finish(); -} diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 086c16f0cd5..e2496a4e578 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -41,6 +41,7 @@ #include "DNA_listBase.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" +#include "DNA_constraint_types.h" #include "DNA_scene_types.h" #include "TransformWriter.h" @@ -62,11 +63,9 @@ public: void add_armature_bones(Object *ob_arm, Scene *sce, SceneExporter *se, std::list& child_objects); - bool is_skinned_mesh(Object *ob); - bool add_instance_controller(Object *ob); - void export_controllers(Scene *sce); + //void export_controllers(Scene *sce);*/ void operator()(Object *ob); @@ -98,29 +97,6 @@ private: std::string get_controller_id(Object *ob_arm, Object *ob); - // ob should be of type OB_MESH - // both args are required - void export_controller(Object *ob, Object *ob_arm); - - void add_joints_element(ListBase *defbase, - const std::string& joints_source_id, const std::string& inv_bind_mat_source_id); - - void add_bind_shape_mat(Object *ob); - - std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); - - std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); - - Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def); - - bool is_bone_defgroup(Object *ob_arm, bDeformGroup *def); - - std::string add_weights_source(Mesh *me, const std::string& controller_id, - const std::list& weights); - - void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, - const std::list& vcount, const std::list& joints); - void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone); }; diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index f1cf732e695..58c3f34e093 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -78,84 +78,8 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node); return &joint_index_to_joint_info_map[joint_index]; } #endif -void ArmatureImporter::create_unskinned_bone(COLLADAFW::Node *node, EditBone *parent, int totchild, - float parent_mat[4][4], Object *ob_arm) -{ - std::vector::iterator it; - it = std::find(finished_joints.begin(), finished_joints.end(), node); - if (it != finished_joints.end()) return; - - float mat[4][4]; - float obmat[4][4]; - - // object-space - get_node_mat(obmat, node, NULL, NULL); - - EditBone *bone = ED_armature_edit_bone_add((bArmature *)ob_arm->data, (char *)bc_get_joint_name(node)); - totbone++; - - if (parent) bone->parent = parent; - - float angle = 0; - // get world-space - if (parent) { - mult_m4_m4m4(mat, parent_mat, obmat); - - } - else { - copy_m4_m4(mat, obmat); - - } - float loc[3], size[3], rot[3][3]; - mat4_to_loc_rot_size(loc, rot, size, obmat); - mat3_to_vec_roll(rot, NULL, &angle); - bone->roll = angle; - // set head - copy_v3_v3(bone->head, mat[3]); - - // set tail, don't set it to head because 0-length bones are not allowed - float vec[3] = {0.0f, 0.5f, 0.0f}; - add_v3_v3v3(bone->tail, bone->head, vec); - - // set parent tail - if (parent && totchild == 1) { - copy_v3_v3(parent->tail, bone->head); - - // not setting BONE_CONNECTED because this would lock child bone location with respect to parent - // bone->flag |= BONE_CONNECTED; - - // XXX increase this to prevent "very" small bones? - const float epsilon = 0.000001f; - - // derive leaf bone length - float length = len_v3v3(parent->head, parent->tail); - if ((length < leaf_bone_length || totbone == 0) && length > epsilon) { - leaf_bone_length = length; - } - - // treat zero-sized bone like a leaf bone - if (length <= epsilon) { - add_leaf_bone(parent_mat, parent, node); - } - - } - - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (unsigned int i = 0; i < children.getCount(); i++) { - create_unskinned_bone(children[i], bone, children.getCount(), mat, ob_arm); - } - - // in second case it's not a leaf bone, but we handle it the same way - if (!children.getCount() || children.getCount() > 1) { - add_leaf_bone(mat, bone, node); - } - - finished_joints.push_back(node); - -} - -void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, +void ArmatureImporter::create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[4][4], bArmature *arm) { //Checking if bone is already made. @@ -168,50 +92,51 @@ void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBo // JointData* jd = get_joint_data(node); float mat[4][4]; - + float obmat[4][4]; + // TODO rename from Node "name" attrs later EditBone *bone = ED_armature_edit_bone_add(arm, (char *)bc_get_joint_name(node)); totbone++; - if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) { + if (skin && skin->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) { // get original world-space matrix invert_m4_m4(mat, joint_inv_bind_mat); } // create a bone even if there's no joint data for it (i.e. it has no influence) else { - float obmat[4][4]; - - // object-space + // bone-space get_node_mat(obmat, node, NULL, NULL); - + // get world-space - if (parent) + if (parent){ mult_m4_m4m4(mat, parent_mat, obmat); + } else copy_m4_m4(mat, obmat); - - float loc[3], size[3], rot[3][3], angle; - mat4_to_loc_rot_size(loc, rot, size, obmat); - mat3_to_vec_roll(rot, NULL, &angle); - bone->roll = angle; } - if (parent) bone->parent = parent; + float loc[3], size[3], rot[3][3]; + float angle; + float vec[3] = {0.0f, 0.5f, 0.0f}; + mat4_to_loc_rot_size(loc, rot, size, mat); + //copy_m3_m4(bonemat,mat); + mat3_to_vec_roll(rot, vec, &angle); + + bone->roll = angle; // set head copy_v3_v3(bone->head, mat[3]); // set tail, don't set it to head because 0-length bones are not allowed - float vec[3] = {0.0f, 0.5f, 0.0f}; add_v3_v3v3(bone->tail, bone->head, vec); // set parent tail if (parent && totchild == 1) { - copy_v3_v3(parent->tail, bone->head); + copy_v3_v3(parent->tail, bone->head); // not setting BONE_CONNECTED because this would lock child bone location with respect to parent - // bone->flag |= BONE_CONNECTED; + bone->flag |= BONE_CONNECTED; // XXX increase this to prevent "very" small bones? const float epsilon = 0.000001f; @@ -227,32 +152,6 @@ void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBo add_leaf_bone(parent_mat, parent, node); } - /* -#if 0 - // and which row in mat is bone direction - float vec[3]; - sub_v3_v3v3(vec, parent->tail, parent->head); -#ifdef COLLADA_DEBUG - print_v3("tail - head", vec); - print_m4("matrix", parent_mat); -#endif - for (int i = 0; i < 3; i++) { -#ifdef COLLADA_DEBUG - char *axis_names[] = {"X", "Y", "Z"}; - printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i])); -#endif - float angle = angle_v2v2(vec, parent_mat[i]); - if (angle < min_angle) { -#ifdef COLLADA_DEBUG - print_v3("picking", parent_mat[i]); - printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node)); -#endif - bone_direction_row = i; - min_angle = angle; - } - } -#endif - */ } COLLADAFW::NodePointerArray& children = node->getChildNodes(); @@ -265,6 +164,8 @@ void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBo add_leaf_bone(mat, bone, node); } + bone->length = len_v3v3(bone->head, bone->tail); + finished_joints.push_back(node); } @@ -299,7 +200,7 @@ void ArmatureImporter::add_leaf_bone(float mat[4][4], EditBone *bone, COLLADAFW void ArmatureImporter::fix_leaf_bones( ) { // just setting tail for leaf bones here - + float correctionMin = 1.0f; std::vector::iterator it; for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { LeafBone& leaf = *it; @@ -307,12 +208,11 @@ void ArmatureImporter::fix_leaf_bones( ) // pointing up float vec[3] = {0.0f, 0.0f, 0.1f}; - // if parent: take parent length and direction - if (leaf.bone->parent) sub_v3_v3v3(vec, leaf.bone->parent->tail, leaf.bone->parent->head); + sub_v3_v3v3(vec, leaf.bone->tail , leaf.bone->head); + mul_v3_fl(vec, leaf_bone_length); + add_v3_v3v3(leaf.bone->tail, leaf.bone->head , vec); - copy_v3_v3(leaf.bone->tail, leaf.bone->head); - add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec); - } + } } #if 0 @@ -410,40 +310,36 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) void ArmatureImporter::create_armature_bones( ) { std::vector::iterator ri; + + leaf_bone_length = FLT_MAX; //if there is an armature created for root_joint next root_joint for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { if (get_armature_for_joint(*ri) != NULL) continue; - //add armature object for current joint - //Object *ob_arm = bc_add_object(scene, OB_ARMATURE, NULL); - Object *ob_arm = joint_parent_map[(*ri)->getUniqueId()]; if (!ob_arm) continue; - - //ob_arm->type = OB_ARMATURE; + ED_armature_to_edit(ob_arm); - // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix - - // create unskinned bones /* * TODO: * check if bones have already been created for a given joint */ - leaf_bone_length = FLT_MAX; - create_unskinned_bone(*ri, NULL, (*ri)->getChildNodes().getCount(), NULL, ob_arm); + create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature *)ob_arm->data); + + //leaf bone tails are derived from the matrix, so no need of this. fix_leaf_bones(); // exit armature edit mode - unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; ED_armature_from_edit(ob_arm); - - set_pose(ob_arm, *ri, NULL, NULL); + + //This serves no purpose, as pose is automatically reset later, in BKE_where_is_bone() + //set_pose(ob_arm, *ri, NULL, NULL); ED_armature_edit_free(ob_arm); DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); @@ -533,7 +429,6 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) totbone = 0; // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row leaf_bone_length = FLT_MAX; - // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix // create bones /* @@ -549,7 +444,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) // since root_joints may contain joints for multiple controllers, we need to filter if (skin.uses_joint_or_descendant(*ri)) { - create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature *)ob_arm->data); + create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature *)ob_arm->data); if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent()) skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]); @@ -563,22 +458,14 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) ED_armature_edit_free(ob_arm); DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); - // set_leaf_bone_shapes(ob_arm); - // set_euler_rotmode(); } - -// root - if this joint is the top joint in hierarchy, if a joint -// is a child of a node (not joint), root should be true since -// this is where we build armature bones from - void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]) { char *bone_name = (char *) bc_get_joint_name(root_node); float mat[4][4]; float obmat[4][4]; - float ax[3]; float angle = 0.0f; // object-space @@ -597,14 +484,16 @@ void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, con } else { + copy_m4_m4(mat, obmat); float invObmat[4][4]; invert_m4_m4(invObmat, ob_arm->obmat); mult_m4_m4m4(pchan->pose_mat, invObmat, mat); + } - mat4_to_axis_angle(ax, &angle, mat); - pchan->bone->roll = angle; + ///*mat4_to_axis_angle(ax, &angle, mat); + //pchan->bone->roll = angle;*/ COLLADAFW::NodePointerArray& children = root_node->getChildNodes(); @@ -614,6 +503,10 @@ void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, con } + +// root - if this joint is the top joint in hierarchy, if a joint +// is a child of a node (not joint), root should be true since +// this is where we build armature bones from void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce) { joint_by_uid[node->getUniqueId()] = node; @@ -729,13 +622,12 @@ bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControlle bool ArmatureImporter::write_controller(const COLLADAFW::Controller *controller) { // - create and store armature object - - const COLLADAFW::UniqueId& skin_id = controller->getUniqueId(); + const COLLADAFW::UniqueId& con_id = controller->getUniqueId(); if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) { COLLADAFW::SkinController *co = (COLLADAFW::SkinController *)controller; // to be able to find geom id by controller id - geom_uid_by_controller_uid[skin_id] = co->getSource(); + geom_uid_by_controller_uid[con_id] = co->getSource(); const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData(); if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) { @@ -746,14 +638,60 @@ bool ArmatureImporter::write_controller(const COLLADAFW::Controller *controller) skin_by_data_uid[data_uid].set_controller(co); } // morph controller - else { - // shape keys? :) - fprintf(stderr, "Morph controller is not supported yet.\n"); + else if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_MORPH) { + COLLADAFW::MorphController *co = (COLLADAFW::MorphController *)controller; + // to be able to find geom id by controller id + geom_uid_by_controller_uid[con_id] = co->getSource(); + //Shape keys are applied in DocumentImporter->finish() + morph_controllers.push_back(co); } return true; } +void ArmatureImporter::make_shape_keys(){ + std::vector::iterator mc; + float weight; + + for (mc = morph_controllers.begin(); mc != morph_controllers.end(); mc++) { + //Controller data + COLLADAFW::UniqueIdArray& morphTargetIds = (*mc)->getMorphTargets(); + COLLADAFW::FloatOrDoubleArray& morphWeights = (*mc)->getMorphWeights(); + + //Prereq: all the geometries must be imported and mesh objects must be made + Object *source_ob = this->mesh_importer->get_object_by_geom_uid((*mc)->getSource()); + + Mesh *source_me = (Mesh*) source_ob->data; + //insert key to source mesh + Key *key = source_me->key = BKE_key_add((ID *)source_me); + key->type = KEY_RELATIVE; + KeyBlock *kb; + + //insert basis key + kb = BKE_keyblock_add_ctime(key, "Basis", FALSE); + BKE_key_convert_from_mesh(source_me, kb); + + //insert other shape keys + for ( int i = 0 ; i < morphTargetIds.getCount() ; i++ ){ + //better to have a seperate map of morph objects, + //This'll do for now since only mesh morphing is imported + Mesh *me = this->mesh_importer->get_mesh_by_geom_uid(morphTargetIds[i]); + + if(me){ + me->key = key; + kb = BKE_keyblock_add_ctime(key, me->id.name, FALSE); + BKE_key_convert_from_mesh(me, kb); + + //apply weights + weight = morphWeights.getFloatValues()->getData()[i]; + kb->curval = weight; + } + else + fprintf(stderr, "Morph target geometry not found.\n"); + } + } +} + COLLADAFW::UniqueId *ArmatureImporter::get_geometry_uid(const COLLADAFW::UniqueId& controller_uid) { diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index bb710f09490..b07edfbf34d 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -29,13 +29,16 @@ #include "COLLADAFWNode.h" #include "COLLADAFWUniqueId.h" +#include "COLLADAFWMorphController.h" extern "C" { #include "BKE_context.h" +#include "BKE_key.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_key_types.h" #include "ED_armature.h" } @@ -88,6 +91,7 @@ private: std::map joint_by_uid; // contains all joints std::vector root_joints; std::vector finished_joints; + std::vector morph_controllers; std::map joint_parent_map; std::map unskinned_armature_map; @@ -103,12 +107,9 @@ private: JointData *get_joint_data(COLLADAFW::Node *node); #endif - void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, + void create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[4][4], bArmature *arm); - void create_unskinned_bone(COLLADAFW::Node *node, EditBone *parent, int totchild, - float parent_mat[4][4], Object * ob_arm); - void add_leaf_bone(float mat[4][4], EditBone *bone, COLLADAFW::Node * node); void fix_leaf_bones(); @@ -140,9 +141,6 @@ public: ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce); ~ArmatureImporter(); - // root - if this joint is the top joint in hierarchy, if a joint - // is a child of a node (not joint), root should be true since - // this is where we build armature bones from void add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce); #if 0 @@ -152,6 +150,8 @@ public: // here we add bones to armatures, having armatures previously created in write_controller void make_armatures(bContext *C); + void make_shape_keys(); + #if 0 // link with meshes, create vertex groups, assign weights void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id); diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt index 0091df3c502..7f389346a81 100644 --- a/source/blender/collada/CMakeLists.txt +++ b/source/blender/collada/CMakeLists.txt @@ -36,6 +36,9 @@ set(INC ../windowmanager ../imbuf ../../../intern/guardedalloc + ../ikplugin + ../../../intern/iksolver/extern + ) set(INC_SYS @@ -48,6 +51,7 @@ set(SRC ArmatureExporter.cpp ArmatureImporter.cpp CameraExporter.cpp + ControllerExporter.cpp DocumentExporter.cpp DocumentImporter.cpp EffectExporter.cpp @@ -74,6 +78,7 @@ set(SRC ArmatureExporter.h ArmatureImporter.h CameraExporter.h + ControllerExporter.h DocumentExporter.h DocumentImporter.h EffectExporter.h diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp new file mode 100644 index 00000000000..d41c907ee98 --- /dev/null +++ b/source/blender/collada/ControllerExporter.cpp @@ -0,0 +1,598 @@ +/* + * ***** 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, + * Nathan Letwory, Sukhitha Jayathilake + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/collada/ControllerExporter.cpp + * \ingroup collada + */ + +#include "COLLADASWBaseInputElement.h" +#include "COLLADASWInstanceController.h" +#include "COLLADASWPrimitves.h" +#include "COLLADASWSource.h" + +#include "DNA_action_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +extern "C" { +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_global.h" +#include "BKE_library.h" +} + +#include "ED_armature.h" + +#include "BLI_listbase.h" + +#include "GeometryExporter.h" +#include "ArmatureExporter.h" +#include "ControllerExporter.h" +#include "SceneExporter.h" + +#include "collada_utils.h" + +// XXX exporter writes wrong data for shared armatures. A separate +// controller should be written for each armature-mesh binding how do +// we make controller ids then? +ControllerExporter::ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) { +} + +bool ControllerExporter::is_skinned_mesh(Object *ob) +{ + return bc_get_assigned_armature(ob) != NULL; +} + + +void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) +{ + if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm))); + else { + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + write_bone_URLs(ins, ob_arm, child); + } + } +} + +bool ControllerExporter::add_instance_controller(Object *ob) +{ + Object *ob_arm = bc_get_assigned_armature(ob); + bArmature *arm = (bArmature *)ob_arm->data; + + const std::string& controller_id = get_controller_id(ob_arm, ob); + + COLLADASW::InstanceController ins(mSW); + ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id)); + + Mesh *me = (Mesh *)ob->data; + if (!me->dvert) return false; + + // write root bone URLs + Bone *bone; + for (bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) { + write_bone_URLs(ins, ob_arm, bone); + } + + InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); + + ins.add(); + return true; +} + +void ControllerExporter::export_controllers(Scene *sce) +{ + scene = sce; + + openLibrary(); + + GeometryFunctor gf; + gf.forEachMeshObjectInExportSet(sce, *this, this->export_settings->export_set); + + closeLibrary(); +} + +void ControllerExporter::operator()(Object *ob) +{ + Object *ob_arm = bc_get_assigned_armature(ob); + Key *key = BKE_key_from_object(ob); + + if (ob_arm) + export_skin_controller(ob, ob_arm); + if(key){ + export_morph_controller(ob, key); + } +} +#if 0 + +bool ArmatureExporter::already_written(Object *ob_arm) +{ + return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end(); +} + +void ArmatureExporter::wrote(Object *ob_arm) +{ + written_armatures.push_back(ob_arm); +} + +void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector& objects, Scene *sce) +{ + objects.clear(); + + Base *base = (Base *) sce->base.first; + while (base) { + Object *ob = base->object; + + if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) { + objects.push_back(ob); + } + + base = base->next; + } +} +#endif + +std::string ControllerExporter::get_joint_sid(Bone *bone, Object *ob_arm) +{ + return get_joint_id(bone, ob_arm); +} + +std::string ControllerExporter::get_controller_id(Object *ob_arm, Object *ob) +{ + return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX; +} + +std::string ControllerExporter::get_controller_id(Key *key, Object *ob) +{ + return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX; +} + +// ob should be of type OB_MESH +// both args are required +void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) +{ + // joint names + // joint inverse bind matrices + // vertex weights + + // input: + // joint names: ob -> vertex group names + // vertex group weights: me->dvert -> groups -> index, weight + +#if 0 + me->dvert : + + typedef struct MDeformVert { + struct MDeformWeight *dw; + int totweight; + int flag; // flag only in use for weightpaint now + } MDeformVert; + + typedef struct MDeformWeight { + int def_nr; + float weight; + } MDeformWeight; +#endif + + bool use_instantiation = this->export_settings->use_object_instantiation; + Mesh *me; + + if (this->export_settings->apply_modifiers) + me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type); + else + me = (Mesh *)ob->data; + + BKE_mesh_tessface_ensure(me); + + if (!me->dvert) return; + + std::string controller_name = id_name(ob_arm); + std::string controller_id = get_controller_id(ob_arm, ob); + + openSkin(controller_id, controller_name, + COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation))); + + add_bind_shape_mat(ob); + + std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); + std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); + + std::list vcounts; + std::list joints; + std::list weights; + + { + int i, j; + + // def group index -> joint index + std::vector joint_index_by_def_index; + bDeformGroup *def; + + for (def = (bDeformGroup *)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) { + if (is_bone_defgroup(ob_arm, def)) + joint_index_by_def_index.push_back(j++); + else + joint_index_by_def_index.push_back(-1); + } + + for (i = 0; i < me->totvert; i++) { + MDeformVert *vert = &me->dvert[i]; + std::map jw; + + // We're normalizing the weights later + float sumw = 0.0f; + + for (j = 0; j < vert->totweight; j++) { + int joint_index = joint_index_by_def_index[vert->dw[j].def_nr]; + if (joint_index != -1 && vert->dw[j].weight > 0.0f) { + jw[joint_index] += vert->dw[j].weight; + sumw += vert->dw[j].weight; + } + } + + if (sumw > 0.0f) { + float invsumw = 1.0f / sumw; + vcounts.push_back(jw.size()); + for (std::map::iterator m = jw.begin(); m != jw.end(); ++m) { + joints.push_back((*m).first); + weights.push_back(invsumw * (*m).second); + } + } + else { + vcounts.push_back(0); +#if 0 + vcounts.push_back(1); + joints.push_back(-1); + weights.push_back(1.0f); +#endif + } + } + } + + std::string weights_source_id = add_weights_source(me, controller_id, weights); + add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); + add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints); + + if (this->export_settings->apply_modifiers) + { + BKE_libblock_free_us(&(G.main->mesh), me); + } + closeSkin(); + closeController(); +} + +void ControllerExporter::export_morph_controller(Object *ob, Key *key) +{ + bool use_instantiation = this->export_settings->use_object_instantiation; + Mesh *me; + + if (this->export_settings->apply_modifiers) { + me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type); + } + else { + me = (Mesh *)ob->data; + } + BKE_mesh_tessface_ensure(me); + + std::string controller_name = id_name(ob) + "-morph"; + std::string controller_id = get_controller_id(key, ob); + + openMorph(controller_id, controller_name, + COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation))); + + std::string targets_id = add_morph_targets(key, ob); + std::string morph_weights_id = add_morph_weights(key, ob); + + COLLADASW::TargetsElement targets(mSW); + + COLLADASW::InputList &input = targets.getInputList(); + + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_TARGET, // constant declared in COLLADASWInputList.h + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, targets_id))); + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_WEIGHT, + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id))); + targets.add(); + + if (this->export_settings->apply_modifiers) + { + BKE_libblock_free_us(&(G.main->mesh), me); + } + + //support for animations + //can also try the base element and param alternative + add_weight_extras(key); + closeMorph(); + closeController(); +} + +std::string ControllerExporter::add_morph_targets(Key *key, Object *ob) +{ + std::string source_id = translate_id(id_name(ob)) + TARGETS_SOURCE_ID_SUFFIX; + + COLLADASW::IdRefSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(key->totkey - 1); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("IDREF"); + + source.prepareToAppendValues(); + + KeyBlock * kb = (KeyBlock*)key->block.first; + //skip the basis + kb = kb->next; + for (; kb; kb = kb->next) { + std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name); + source.appendValues(geom_id); + + } + + source.finish(); + + return source_id; +} + +std::string ControllerExporter::add_morph_weights(Key *key, Object *ob) +{ + std::string source_id = translate_id(id_name(ob)) + WEIGHTS_SOURCE_ID_SUFFIX; + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(key->totkey - 1); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("MORPH_WEIGHT"); + + source.prepareToAppendValues(); + + KeyBlock * kb = (KeyBlock*)key->block.first; + //skip the basis + kb = kb->next; + for (; kb; kb = kb->next) { + float weight = kb->curval; + source.appendValues(weight); + } + source.finish(); + + return source_id; +} + +//Added to implemente support for animations. +void ControllerExporter::add_weight_extras(Key *key){ + // can also try the base element and param alternative + COLLADASW::BaseExtraTechnique extra; + + KeyBlock * kb = (KeyBlock*)key->block.first; + //skip the basis + kb = kb->next; + for (; kb; kb = kb->next) { + float weight = kb->curval; + extra.addExtraTechniqueParameter ("KHR", "morph_weights" , 0.000, "MORPH_WEIGHT_TO_TARGET"); + } +} + + + +void ControllerExporter::add_joints_element(ListBase *defbase, + const std::string& joints_source_id, const std::string& inv_bind_mat_source_id) +{ + COLLADASW::JointsElement joints(mSW); + COLLADASW::InputList &input = joints.getInputList(); + + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id))); + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX, + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id))); + joints.add(); +} + +void ControllerExporter::add_bind_shape_mat(Object *ob) +{ + double bind_mat[4][4]; + + converter.mat4_to_dae_double(bind_mat, ob->obmat); + + addBindShapeTransform(bind_mat); +} + +std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) +{ + std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX; + + int totjoint = 0; + bDeformGroup *def; + for (def = (bDeformGroup *)defbase->first; def; def = def->next) { + if (is_bone_defgroup(ob_arm, def)) + totjoint++; + } + + COLLADASW::NameSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(totjoint); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("JOINT"); + + source.prepareToAppendValues(); + + for (def = (bDeformGroup *)defbase->first; def; def = def->next) { + Bone *bone = get_bone_from_defgroup(ob_arm, def); + if (bone) + source.appendValues(get_joint_sid(bone, ob_arm)); + } + + source.finish(); + + return source_id; +} + +std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) +{ + std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; + + int totjoint = 0; + for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { + if (is_bone_defgroup(ob_arm, def)) + totjoint++; + } + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(totjoint); //BLI_countlist(defbase)); + source.setAccessorStride(16); + + source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("TRANSFORM"); + + source.prepareToAppendValues(); + + bPose *pose = ob_arm->pose; + bArmature *arm = (bArmature *)ob_arm->data; + + int flag = arm->flag; + + // put armature in rest position + if (!(arm->flag & ARM_RESTPOS)) { + arm->flag |= ARM_RESTPOS; + BKE_pose_where_is(scene, ob_arm); + } + + for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { + if (is_bone_defgroup(ob_arm, def)) { + bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name); + + float mat[4][4]; + float world[4][4]; + float inv_bind_mat[4][4]; + + // SECOND_LIFE_COMPATIBILITY + if (export_settings->second_life) { + // Only translations, no rotation vs armature + float temp[4][4]; + unit_m4(temp); + copy_v3_v3(temp[3], pchan->bone->arm_mat[3]); + mult_m4_m4m4(world, ob_arm->obmat, temp); + } + else { + // make world-space matrix, arm_mat is armature-space + mult_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat); + } + + invert_m4_m4(mat, world); + converter.mat4_to_dae(inv_bind_mat, mat); + + source.appendValues(inv_bind_mat); + } + } + + // back from rest positon + if (!(flag & ARM_RESTPOS)) { + arm->flag = flag; + BKE_pose_where_is(scene, ob_arm); + } + + source.finish(); + + return source_id; +} + +Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def) +{ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name); + return pchan ? pchan->bone : NULL; +} + +bool ControllerExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup *def) +{ + return get_bone_from_defgroup(ob_arm, def) != NULL; +} + +std::string ControllerExporter::add_weights_source(Mesh *me, const std::string& controller_id, const std::list& weights) +{ + std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX; + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(weights.size()); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("WEIGHT"); + + source.prepareToAppendValues(); + + for (std::list::const_iterator i = weights.begin(); i != weights.end(); ++i) { + source.appendValues(*i); + } + + source.finish(); + + return source_id; +} + +void ControllerExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, + const std::list& vcounts, + const std::list& joints) +{ + COLLADASW::VertexWeightsElement weightselem(mSW); + COLLADASW::InputList &input = weightselem.getInputList(); + + int offset = 0; + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++)); + input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT, + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++)); + + weightselem.setCount(vcounts.size()); + + // write number of deformers per vertex + COLLADASW::PrimitivesBase::VCountList vcountlist; + + vcountlist.resize(vcounts.size()); + std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin()); + + weightselem.prepareToAppendVCountValues(); + weightselem.appendVertexCount(vcountlist); + + weightselem.CloseVCountAndOpenVElement(); + + // write deformer index - weight index pairs + int weight_index = 0; + for (std::list::const_iterator i = joints.begin(); i != joints.end(); ++i) { + weightselem.appendValues(*i, weight_index++); + } + + weightselem.finish(); +} diff --git a/source/blender/collada/ControllerExporter.h b/source/blender/collada/ControllerExporter.h new file mode 100644 index 00000000000..4355fb6c28f --- /dev/null +++ b/source/blender/collada/ControllerExporter.h @@ -0,0 +1,126 @@ +/* + * ***** 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, + * Nathan Letwory, Sukhitha Jayathilake + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ControllerExporter.h + * \ingroup collada + */ + +#ifndef __CONTROLLEREXPORTER_H__ +#define __CONTROLLEREXPORTER_H__ + +#include +#include +//#include + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryControllers.h" +#include "COLLADASWInputList.h" +#include "COLLADASWNode.h" +#include "COLLADASWExtraTechnique.h" + +#include "DNA_armature_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_constraint_types.h" +#include "DNA_scene_types.h" +#include "DNA_key_types.h" + +#include "TransformWriter.h" +#include "InstanceWriter.h" + +#include "ExportSettings.h" + +#include "BKE_key.h" + +class SceneExporter; + +class ControllerExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter +{ +public: + ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); + + bool is_skinned_mesh(Object *ob); + + bool add_instance_controller(Object *ob); + + void export_controllers(Scene *sce); + + void operator()(Object *ob); + +private: + Scene *scene; + UnitConverter converter; + const ExportSettings *export_settings; + +#if 0 + std::vector written_armatures; + + bool already_written(Object *ob_arm); + + void wrote(Object *ob_arm); + + void find_objects_using_armature(Object *ob_arm, std::vector& objects, Scene *sce); +#endif + + std::string get_joint_sid(Bone *bone, Object *ob_arm); + + std::string get_controller_id(Object *ob_arm, Object *ob); + + std::string get_controller_id(Key *key, Object *ob); + + // ob should be of type OB_MESH + // both args are required + void export_skin_controller(Object *ob, Object *ob_arm); + + void export_morph_controller(Object *ob, Key *key); + + void add_joints_element(ListBase *defbase, + const std::string& joints_source_id, const std::string& inv_bind_mat_source_id); + + void add_bind_shape_mat(Object *ob); + + std::string add_morph_targets(Key *key, Object *ob); + + std::string add_morph_weights(Key *key, Object *ob); + + void add_weight_extras(Key *key); + + std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); + + std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); + + Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def); + + bool is_bone_defgroup(Object *ob_arm, bDeformGroup *def); + + std::string add_weights_source(Mesh *me, const std::string& controller_id, + const std::list& weights); + + void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, + const std::list& vcount, const std::list& joints); + + void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone); +}; + +#endif diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index c491326519f..71909b33db8 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -123,6 +123,7 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype); #include "ArmatureExporter.h" #include "AnimationExporter.h" #include "CameraExporter.h" +#include "ControllerExporter.h" #include "EffectExporter.h" #include "GeometryExporter.h" #include "ImageExporter.h" @@ -269,11 +270,15 @@ void DocumentExporter::exportCurrentScene(Scene *sce) // ArmatureExporter arm_exporter(&sw, this->export_settings); - if (bc_has_object_type(export_set, OB_ARMATURE)) { - arm_exporter.export_controllers(sce); - } + ControllerExporter controller_exporter(&sw , this->export_settings); + //for Morph controller export, removing the check + /*if (bc_has_object_type(export_set, OB_ARMATURE)) + {*/ + controller_exporter.export_controllers(sce); + //} // + SceneExporter se(&sw, &arm_exporter, this->export_settings); se.exportScene(sce); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index b7797b51252..1d8be5910c6 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -210,10 +210,11 @@ void DocumentImporter::finish() } - mesh_importer.optimize_material_assignments(); + mesh_importer.optimize_material_assignements(); armature_importer.set_tags_map(this->uid_tags_map); armature_importer.make_armatures(mContext); + armature_importer.make_shape_keys(); #if 0 armature_importer.fix_animation(); @@ -256,7 +257,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW { // The split in #29246, rootmap must point at actual root when - // calculating bones in apply_curves_as_matrix. + // calculating bones in apply_curves_as_matrix. - actual root is the root node. // This has to do with inverse bind poses being world space // (the sources for skinned bones' restposes) and the way // non-skinning nodes have their "restpose" recursively calculated. @@ -265,7 +266,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW if (par) { // && par->getType() == COLLADAFW::Node::JOINT) { // par is root if there's no corresp. key in root_map if (root_map.find(par->getUniqueId()) == root_map.end()) - root_map[node->getUniqueId()] = par; + root_map[node->getUniqueId()] = node; else root_map[node->getUniqueId()] = root_map[par->getUniqueId()]; } @@ -376,8 +377,8 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod anim_importer.read_node_transform(source_node, obn); } - DAG_scene_sort(CTX_data_main(mContext), sce); - DAG_ids_flush_update(CTX_data_main(mContext), 0); + /*DAG_scene_sort(CTX_data_main(mContext), sce); + DAG_ids_flush_update(CTX_data_main(mContext), 0);*/ COLLADAFW::NodePointerArray &children = source_node->getChildNodes(); if (children.getCount()) { @@ -406,22 +407,29 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod return obn; } +// to create constraints off node tags. Assumes only constraint data in +// current with blender profile. +void DocumentImporter::create_constraints(ExtraTags *et, Object *ob){ + if ( et && et->isProfile("blender")){ + std::string name; + short* type = 0; + et->setData("type", type); + bConstraint * con = BKE_add_ob_constraint(ob, "Test_con", *type); + + } +} + void DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par, bool is_library_node) { Object *ob = NULL; bool is_joint = node->getType() == COLLADAFW::Node::JOINT; bool read_transform = true; - std::vector *objects_done = new std::vector(); + ExtraTags *et = getExtraTags(node->getUniqueId()); + std::vector *objects_done = new std::vector(); + if (is_joint) { - if (par) { - Object *empty = par; - par = bc_add_object(sce, OB_ARMATURE, NULL); - bc_set_parent(par, empty->parent, mContext); - //remove empty : todo - object_map.insert(std::make_pair(parent_node->getUniqueId(), par)); - } armature_importer.add_joint(node, parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT, par, sce); } else { @@ -487,10 +495,15 @@ void DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent read_transform = false; } + // if node is empty - create empty object // XXX empty node may not mean it is empty object, not sure about this if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) { - ob = bc_add_object(sce, OB_EMPTY, NULL); + //Check if Object is armature, by checking if immediate child is a JOINT node. + if(is_armature(node)) + ob = bc_add_object(sce, OB_ARMATURE, NULL); + else ob = bc_add_object(sce, OB_EMPTY, NULL); + objects_done->push_back(ob); } @@ -508,6 +521,8 @@ void DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent libnode_ob.push_back(ob); } + //create_constraints(et,ob); + } for (std::vector::iterator it = objects_done->begin(); it != objects_done->end(); ++it) { @@ -959,11 +974,12 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) Lamp *lamp = NULL; std::string la_id, la_name; - TagsMap::iterator etit; + ExtraTags *et = getExtraTags(light->getUniqueId()); + /*TagsMap::iterator etit; ExtraTags *et = 0; etit = uid_tags_map.find(light->getUniqueId().toAscii()); if (etit != uid_tags_map.end()) - et = etit->second; + et = etit->second;*/ la_id = light->getOriginalId(); la_name = light->getName(); @@ -1183,3 +1199,14 @@ bool DocumentImporter::addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *e return true; } +bool DocumentImporter::is_armature(COLLADAFW::Node *node){ + COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes(); + for (unsigned int i = 0; i < child_nodes.getCount(); i++) { + if(child_nodes[i]->getType() == COLLADAFW::Node::JOINT) return true; + else continue; + } + + //no child is JOINT + return false; + +} diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index d54b8db9f00..7e3476fb7e0 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -40,10 +40,12 @@ #include "BKE_object.h" +#include "BKE_constraint.h" #include "TransformReader.h" #include "AnimationImporter.h" #include "ArmatureImporter.h" +#include "ControllerExporter.h" #include "MeshImporter.h" @@ -73,9 +75,11 @@ public: Object* create_camera_object(COLLADAFW::InstanceCamera*, Scene*); Object* create_lamp_object(COLLADAFW::InstanceLight*, Scene*); Object* create_instance_node(Object*, COLLADAFW::Node*, COLLADAFW::Node*, Scene*, bool); + void create_constraints(ExtraTags *et, Object *ob); void write_node(COLLADAFW::Node*, COLLADAFW::Node*, Scene*, Object*, bool); MTex* create_texture(COLLADAFW::EffectCommon*, COLLADAFW::Texture&, Material*, int, TexIndexTextureArrayMap&); void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*); + void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*); /** @@ -128,6 +132,10 @@ public: /** Get an extisting ExtraTags for uid */ ExtraTags* getExtraTags(const COLLADAFW::UniqueId &uid); + bool is_armature(COLLADAFW::Node * node); + + + private: /** Current import stage we're in. */ diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h index 2504c276036..cf45b9b8391 100644 --- a/source/blender/collada/ExportSettings.h +++ b/source/blender/collada/ExportSettings.h @@ -37,6 +37,7 @@ public: bool selected; bool include_children; bool include_armatures; + bool include_shapekeys; bool deform_bones_only; bool active_uv_only; diff --git a/source/blender/collada/ExtraHandler.cpp b/source/blender/collada/ExtraHandler.cpp index df49b4fe8b4..bcf7e573d24 100644 --- a/source/blender/collada/ExtraHandler.cpp +++ b/source/blender/collada/ExtraHandler.cpp @@ -74,6 +74,7 @@ bool ExtraHandler::parseElement( if (!et) { et = new ExtraTags(std::string(profileName)); dimp->addExtraTags(uniqueId, et); + } currentExtraTags = et; return true; diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index f33f0fa110d..6673e1de815 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -69,9 +69,8 @@ void GeometryExporter::exportGeom(Scene *sce) } void GeometryExporter::operator()(Object *ob) -{ +{ // XXX don't use DerivedMesh, Mesh instead? - #if 0 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); #endif @@ -155,17 +154,92 @@ void GeometryExporter::operator()(Object *ob) closeGeometry(); - if (this->export_settings->apply_modifiers) - { + if (this->export_settings->apply_modifiers) { BKE_libblock_free_us(&(G.main->mesh), me); } - - + + if (this->export_settings->include_shapekeys) { + Key * key = BKE_key_from_object(ob); + if(key) { + KeyBlock * kb = (KeyBlock*)key->block.first; + //skip the basis + kb = kb->next; + for (; kb; kb = kb->next) { + BKE_key_convert_to_mesh(kb, me); + export_key_mesh(ob, me, kb); + } + } + } #if 0 dm->release(dm); #endif } +void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb){ + std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name); + std::vector nor; + std::vector norind; + + if (exportedGeometry.find(geom_id) != exportedGeometry.end()) + { + return; + } + + std::string geom_name = id_name(ob) + "_morph_" + kb->name; + + exportedGeometry.insert(geom_id); + + bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL); + + create_normals(nor, norind, me); + + // openMesh(geoId, geoName, meshId) + openMesh(geom_id, geom_name); + + // writes for vertex coords + createVertsSource(geom_id, me); + + // writes for normal coords + createNormalsSource(geom_id, me, nor); + + bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); + + // writes for uv coords if mesh has uv coords + if (has_uvs) + createTexcoordsSource(geom_id, me); + + if (has_color) + createVertexColorSource(geom_id, me); + + // + + COLLADASW::Vertices verts(mSW); + verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX)); + COLLADASW::InputList &input_list = verts.getInputList(); + COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION)); + input_list.push_back(input); + verts.add(); + + //createLooseEdgeList(ob, me, geom_id, norind); + + // XXX slow + if (ob->totcol) { + for (int a = 0; a < ob->totcol; a++) { + createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); + } + } + else { + createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); + } + + closeMesh(); + + if (me->flag & ME_TWOSIDED) { + mSW->appendTextBlock("1"); + } + + closeGeometry(); +} void GeometryExporter::createLooseEdgeList(Object *ob, Mesh *me, diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h index 7161bb751dd..7cbbf0da8fa 100644 --- a/source/blender/collada/GeometryExporter.h +++ b/source/blender/collada/GeometryExporter.h @@ -39,9 +39,12 @@ #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_key_types.h" #include "ExportSettings.h" +#include "BKE_key.h" + extern Object *bc_get_highest_selected_ancestor_or_self(Object *ob); // TODO: optimize UV sets by making indexed list with duplicates removed @@ -100,6 +103,8 @@ public: COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = ""); COLLADASW::URI makeUrl(std::string id); + + void export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb); /* int getTriCount(MFace *faces, int totface);*/ private: diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 8256618bfa3..febfb772430 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -946,6 +946,13 @@ Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid return NULL; } +Mesh *MeshImporter::get_mesh_by_geom_uid(const COLLADAFW::UniqueId& mesh_uid) +{ + if (uid_mesh_map.find(mesh_uid) != uid_mesh_map.end()) + return uid_mesh_map[mesh_uid]; + return NULL; +} + MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, MTex *color_texture) @@ -1061,7 +1068,7 @@ std::vector MeshImporter::get_all_users_of(Mesh *reference_mesh) * * During import all materials have been assigned to Object. * Now we iterate over the imported objects and optimize - * the assignments as follows: + * the assignements as follows: * * for each imported geometry: * if number of users is 1: @@ -1075,7 +1082,7 @@ std::vector MeshImporter::get_all_users_of(Mesh *reference_mesh) * adjust all other users accordingly. * **/ -void MeshImporter::optimize_material_assignments() +void MeshImporter::optimize_material_assignements() { for (std::vector::iterator it = imported_objects.begin(); it != imported_objects.end(); ++it) @@ -1119,7 +1126,7 @@ void MeshImporter::optimize_material_assignments() * come along with different materials. So we first create the objects * and assign the materials to Object, then in a later cleanup we decide * which materials shall be moved to the created geometries. Also see - * optimize_material_assignments() above. + * optimize_material_assignements() above. */ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, std::map& uid_material_map, diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index 746b0738108..946f9ff99e3 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -59,6 +59,7 @@ class MeshImporterBase { public: virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0; + virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& mesh_uid) = 0; }; class UVDataWrapper @@ -106,10 +107,10 @@ private: #endif void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, - COLLADAFW::IndexList& index_list, unsigned int *tris_indices); + COLLADAFW::IndexList& index_list, unsigned int *tris_indices); void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, - COLLADAFW::IndexList& index_list, int index, bool quad); + COLLADAFW::IndexList& index_list, int index, bool quad); #ifdef COLLADA_DEBUG void print_index_list(COLLADAFW::IndexList& index_list); @@ -132,7 +133,7 @@ private: CustomData create_edge_custom_data(EdgeHash *eh); - void allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris); + void allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris); // TODO: import uv set names void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris); @@ -151,24 +152,26 @@ public: void bmeshConversion(); virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); + + virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, - Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, - MTex *color_texture); + Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, + MTex *color_texture); - void optimize_material_assignments(); + void optimize_material_assignements(); MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, - std::map& uid_material_map, - Object *ob, const COLLADAFW::UniqueId *geom_uid, - MTex **color_texture, char *layername, MTFace *texture_face, - std::map& material_texture_mapping_map, short mat_index); + std::map& uid_material_map, + Object *ob, const COLLADAFW::UniqueId *geom_uid, + MTex **color_texture, char *layername, MTFace *texture_face, + std::map& material_texture_mapping_map, short mat_index); Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, - bool isController, - std::map& uid_material_map, - std::map& material_texture_mapping_map); + bool isController, + std::map& uid_material_map, + std::map& material_texture_mapping_map); // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID bool write_geometry(const COLLADAFW::Geometry* geom); diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index 6d239ae0fb1..bb33e4084e0 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -182,6 +182,46 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce) colladaNode.end(); } + if (ob->constraints.first != NULL ){ + bConstraint *con = (bConstraint*) ob->constraints.first; + while(con){ + std::string con_name(id_name(con)); + std::string con_tag = con_name + "_constraint"; + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error); + + //not ideal: add the target object name as another parameter. + //No real mapping in the .dae + //Need support for multiple target objects also. + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + if (cti && cti->get_constraint_targets) { + + bConstraintTarget *ct; + Object *obtar; + + cti->get_constraint_targets(con, &targets); + if(cti){ + int i = 1; + for (ct = (bConstraintTarget*)targets.first; ct; ct = ct->next){ + obtar = ct->tar; + std::string tar_id(id_name(obtar)); + colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id); + } + } + } + + con = con->next; + } + } + for (std::list::iterator i = child_objects.begin(); i != child_objects.end(); ++i) { if (bc_is_marked(*i)) { bc_remove_mark(*i); @@ -189,8 +229,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce) } } - if (ob->type != OB_ARMATURE) { + if (ob->type != OB_ARMATURE) colladaNode.end(); - } } diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h index 31b471a3e4c..f438c002f91 100644 --- a/source/blender/collada/SceneExporter.h +++ b/source/blender/collada/SceneExporter.h @@ -43,6 +43,7 @@ extern "C" { #include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" +#include "DNA_constraint_types.h" #include "DNA_armature_types.h" #include "DNA_modifier_types.h" #include "DNA_userdef_types.h" @@ -51,6 +52,7 @@ extern "C" { #include "BKE_fcurve.h" #include "BKE_animsys.h" #include "BLI_path_util.h" +#include "BKE_constraint.h" #include "BLI_fileops.h" #include "ED_keyframing.h" } diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp index 5bc135e9b67..24124c7b58d 100644 --- a/source/blender/collada/TransformReader.cpp +++ b/source/blender/collada/TransformReader.cpp @@ -45,29 +45,31 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std:: COLLADAFW::Transformation *tm = node->getTransformations()[i]; COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); - - switch (type) { - case COLLADAFW::Transformation::TRANSLATE: - dae_translate_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::ROTATE: - dae_rotate_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::SCALE: - dae_scale_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::MATRIX: - dae_matrix_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::LOOKAT: - case COLLADAFW::Transformation::SKEW: - fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n"); - break; + + if(type == COLLADAFW::Transformation::MATRIX){ + dae_matrix_to_mat4(tm, mat); + return; } - - copy_m4_m4(copy, mat); - mult_m4_m4m4(mat, copy, cur); - + else{ + switch (type) { + case COLLADAFW::Transformation::TRANSLATE: + dae_translate_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::ROTATE: + dae_rotate_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::SCALE: + dae_scale_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::LOOKAT: + case COLLADAFW::Transformation::SKEW: + fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n"); + break; + } + copy_m4_m4(copy, mat); + mult_m4_m4m4(mat, copy, cur); + } + if (animation_map) { // AnimationList that drives this Transformation const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList(); diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index 3fe3f620a68..f06c8cb9e00 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -52,9 +52,9 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], TransformBase::decompose(local, loc, rot, NULL, scale); if (node.getType() == COLLADASW::Node::JOINT) - node.addMatrix("transform", dmat); + node.addMatrix("transform", dmat); else - add_transform(node, loc, rot, scale); + add_transform(node, loc, rot, scale); } void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob) @@ -93,12 +93,13 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob) add_transform(node, loc, rot, scale); #endif - + UnitConverter converter; + /* Using parentinv should allow use of existing curves */ if (ob->parent) { // If parentinv is identity don't add it. bool add_parinv = false; - + for (int i = 0; i < 16; ++i) { float f = (i % 4 == i / 4) ? 1.0f : 0.0f; add_parinv |= (ob->parentinv[i % 4][i / 4] != f); @@ -106,12 +107,14 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob) if (add_parinv) { double dmat[4][4]; - UnitConverter converter; converter.mat4_to_dae_double(dmat, ob->parentinv); node.addMatrix("parentinverse", dmat); } } - + + double d_obmat[4][4]; + converter.mat4_to_dae_double(d_obmat, ob->obmat); + node.addMatrix("transform",d_obmat); add_transform(node, ob->loc, ob->rot, ob->size); } @@ -123,7 +126,6 @@ void TransformWriter::add_node_transform_identity(COLLADASW::Node& node) void TransformWriter::add_transform(COLLADASW::Node& node, float loc[3], float rot[3], float scale[3]) { - node.addTranslate("location", loc[0], loc[1], loc[2]); #if 0 node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2])); node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1])); @@ -132,6 +134,7 @@ void TransformWriter::add_transform(COLLADASW::Node& node, float loc[3], float r node.addRotateZ("rotationZ", RAD2DEGF(rot[2])); node.addRotateY("rotationY", RAD2DEGF(rot[1])); node.addRotateX("rotationX", RAD2DEGF(rot[0])); - node.addScale("scale", scale[0], scale[1], scale[2]); + node.addTranslate("location", loc[0], loc[1], loc[2]); + } diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index fbb18887d1b..ef34c55bbe6 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -59,6 +59,7 @@ int collada_export(Scene *sce, int selected, int include_children, int include_armatures, + int include_shapekeys, int deform_bones_only, int active_uv_only, @@ -89,6 +90,7 @@ int collada_export(Scene *sce, export_settings.selected = selected != 0; export_settings.include_children = include_children != 0; export_settings.include_armatures = include_armatures != 0; + export_settings.include_shapekeys = include_shapekeys != 0; export_settings.deform_bones_only = deform_bones_only != 0; export_settings.active_uv_only = active_uv_only != 0; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 13f8151da3d..a02e3e007ae 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -55,6 +55,7 @@ int collada_export(Scene *sce, int selected, int include_children, int include_armatures, + int include_shapekeys, int deform_bones_only, int active_uv_only, diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index 51d81dc164b..64c567384a1 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -283,3 +283,9 @@ std::string get_material_id(Material *mat) { return translate_id(id_name(mat)) + "-material"; } + +std::string get_morph_id(Object *ob) +{ + return translate_id(id_name(ob)) + "-morph"; +} + diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index d92f53f714c..ba077628499 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -99,4 +99,6 @@ extern std::string get_camera_id(Object *ob); extern std::string get_material_id(Material *mat); +extern std::string get_morph_id(Object *ob); + #endif /* __COLLADA_INTERNAL_H__ */ diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index ba93206e63a..f53672b7092 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -84,6 +84,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int selected; int include_children; int include_armatures; + int include_shapekeys; int deform_bones_only; int include_uv_textures; @@ -109,6 +110,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) selected = RNA_boolean_get(op->ptr, "selected"); include_children = RNA_boolean_get(op->ptr, "include_children"); include_armatures = RNA_boolean_get(op->ptr, "include_armatures"); + include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys"); deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only"); include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures"); @@ -130,6 +132,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) selected, include_children, include_armatures, + include_shapekeys, deform_bones_only, active_uv_only, @@ -176,6 +179,10 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "include_armatures", 0, NULL, ICON_NONE); uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected")); + row = uiLayoutRow(box, FALSE); + uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE); + uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected")); + /* Texture options */ box = uiLayoutBox(layout); row = uiLayoutRow(box, FALSE); @@ -266,6 +273,9 @@ void WM_OT_collada_export(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)"); + RNA_def_boolean(ot->srna, "include_shapekeys", 1, "Include Shape Keys", + "Export all Shape Keys from Mesh Objects"); + RNA_def_boolean(ot->srna, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures"); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 9b5a858a581..e877367790e 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -101,6 +101,7 @@ static void rna_Scene_collada_export( int selected, int include_children, int include_armatures, + int include_shapekeys, int deform_bones_only, int active_uv_only, @@ -113,7 +114,7 @@ static void rna_Scene_collada_export( int second_life) { collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected, - include_children, include_armatures, deform_bones_only, + include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, use_object_instantiation, sort_by_name, second_life); } @@ -149,6 +150,7 @@ void RNA_api_scene(StructRNA *srna) parm = RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements"); parm = RNA_def_boolean(func, "include_children", 0, "Include Children", "Export all children of selected objects (even if not selected)"); parm = RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)"); + parm = RNA_def_boolean(func, "include_shapekeys", 0, "Include Shape Keys", "Export all Shape Keys from Mesh Objects"); parm = RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures"); parm = RNA_def_boolean(func, "active_uv_only", 0, "Active UV Layer only", "Export only the active UV Layer"); -- cgit v1.2.3