Index: source/blender/windowmanager/intern/wm_operators.c =================================================================== --- source/blender/windowmanager/intern/wm_operators.c (revision 47523) +++ source/blender/windowmanager/intern/wm_operators.c (working copy) @@ -2162,7 +2162,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) { char filename[FILE_MAX]; - int selected, second_life, apply_modifiers, include_bone_children, use_object_instantiation; + int selected, second_life, + include_armatures, + apply_modifiers, + include_bone_children, + use_object_instantiation; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); @@ -2174,6 +2178,7 @@ /* Options panel */ selected = RNA_boolean_get(op->ptr, "selected"); apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); + include_armatures = RNA_boolean_get(op->ptr, "include_armatures"); include_bone_children = RNA_boolean_get(op->ptr, "include_bone_children"); use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); second_life = RNA_boolean_get(op->ptr, "second_life"); @@ -2186,6 +2191,7 @@ filename, selected, apply_modifiers, + include_armatures, include_bone_children, use_object_instantiation, second_life)) { @@ -2216,6 +2222,9 @@ RNA_def_boolean(ot->srna, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers (Preview Resolution)"); + RNA_def_boolean(ot->srna, "include_armatures", 0, "Include Armatures", + "Include armature(s) used by the exported objects"); + RNA_def_boolean(ot->srna, "include_bone_children", 0, "Include Bone Children", "Include all objects attached to bones of selected Armature(s)"); Index: source/blender/collada/collada_utils.cpp =================================================================== --- source/blender/collada/collada_utils.cpp (revision 47523) +++ source/blender/collada/collada_utils.cpp (working copy) @@ -32,8 +32,10 @@ #include "COLLADAFWMeshPrimitive.h" #include "COLLADAFWMeshVertexData.h" +#include "DNA_modifier_types.h" #include "DNA_customdata_types.h" #include "DNA_object_types.h" +#include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "BLI_math.h" @@ -42,8 +44,13 @@ #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_object.h" +#include "BKE_mesh.h" #include "BKE_scene.h" +extern "C" { +#include "BKE_DerivedMesh.h" +} + #include "WM_api.h" // XXX hrm, see if we can do without this #include "WM_types.h" @@ -125,3 +132,35 @@ return ob; } +Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob) +{ + Mesh *tmpmesh; + CustomDataMask mask = CD_MASK_MESH; + DerivedMesh *dm = mesh_create_derived_view(scene, ob, mask); + tmpmesh = BKE_mesh_add("ColladaMesh"); // name is not important here + DM_to_mesh(dm, tmpmesh, ob); + dm->release(dm); + return tmpmesh; +} + +Object *bc_get_assigned_armature(Object *ob) +{ + Object *ob_arm = NULL; + + if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { + ob_arm = ob->parent; + } + else { + ModifierData *mod = (ModifierData*)ob->modifiers.first; + while (mod) { + if (mod->type == eModifierType_Armature) { + ob_arm = ((ArmatureModifierData*)mod)->object; + } + + mod = mod->next; + } + } + + return ob_arm; +} + Index: source/blender/collada/GeometryExporter.h =================================================================== --- source/blender/collada/GeometryExporter.h (revision 47523) +++ source/blender/collada/GeometryExporter.h (working copy) @@ -105,7 +105,7 @@ const ExportSettings *export_settings; - Mesh * get_mesh(Object *ob, int apply_modifiers); + Mesh * get_mesh(Scene *sce, Object *ob, int apply_modifiers); }; struct GeometryFunctor { Index: source/blender/collada/collada.h =================================================================== --- source/blender/collada/collada.h (revision 47523) +++ source/blender/collada/collada.h (working copy) @@ -38,13 +38,17 @@ */ int collada_import(bContext *C, const char *filepath); int collada_export( - Scene *sce, + Scene *sce, const char *filepath, int selected, int apply_modifiers, + + int include_armatures, int include_bone_children, + int use_object_instantiation, int second_life); + #ifdef __cplusplus } #endif Index: source/blender/collada/SceneExporter.cpp =================================================================== --- source/blender/collada/SceneExporter.cpp (revision 47523) +++ source/blender/collada/SceneExporter.cpp (working copy) @@ -25,6 +25,7 @@ */ #include "SceneExporter.h" +#include "collada_utils.h" SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings) : COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm), export_settings(export_settings) @@ -40,19 +41,36 @@ closeLibrary(); } +// Returns true if the parent chain does not contain any selected object +// Otherwise return false (ob has selected predecessor) +bool is_exported_base_node(Object *ob, bool selection_only) { + + if (selection_only && ob->flag & SELECT) { + // Move up towards root object, + // stop at first selected predecessor's child, + // or at root, if no parent was selected + while (ob->parent && (ob->parent->type==OB_ARMATURE || !(ob->parent->flag & SELECT))) + { + ob = ob->parent; + } + } + + return !ob->parent; +} + void SceneExporter::exportHierarchy(Scene *sce) { Base *base= (Base*) sce->base.first; while (base) { Object *ob = base->object; - if (!ob->parent) { + bool is_export_base_node = is_exported_base_node(ob, this->export_settings->selected); + if (is_export_base_node) { if (sce->lay & ob->lay) { switch (ob->type) { case OB_MESH: case OB_CAMERA: case OB_LAMP: - case OB_ARMATURE: case OB_EMPTY: if (this->export_settings->selected && !(ob->flag & SELECT)) { break; @@ -70,6 +88,14 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce) { + + // Add associated armature first if available + if (this->export_settings->include_armatures) { + Object *ob_arm = bc_get_assigned_armature(ob); + if(ob_arm != NULL) + writeNodes(ob_arm, sce); + } + COLLADASW::Node node(mSW); node.setNodeId(translate_id(id_name(ob))); node.setNodeName(translate_id(id_name(ob))); @@ -80,8 +106,19 @@ bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob); std::list child_objects; + // XXX Not sure about this. + // For me this looks more like a very special case for a very special purpose. + // Wouldn't it be better to have only one option here ? + // + // - include children + // + // Instead of "include_bone_children" ? + // then we could just ask: + // if (this->export_settings->include_children) + // ... + if (this->export_settings->include_armatures + && this->export_settings->include_bone_children) { - if (this->export_settings->include_bone_children) { // list child objects Base *b = (Base*) sce->base.first; while (b) { @@ -105,7 +142,7 @@ } - if (ob->type == OB_MESH && is_skinned_mesh) + if (ob->type == OB_MESH && this->export_settings->include_armatures && is_skinned_mesh) // for skinned mesh we write obmat in TransformWriter::add_node_transform_identity(node); else @@ -113,10 +150,11 @@ // if (ob->type == OB_MESH) { - if (is_skinned_mesh) { - arm_exporter->add_instance_controller(ob); + bool instance_controller_created = false; + if (this->export_settings->include_armatures && is_skinned_mesh) { + instance_controller_created = arm_exporter->add_instance_controller(ob); } - else { + if (!instance_controller_created){ COLLADASW::InstanceGeometry instGeom(mSW); instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation))); Index: source/blender/collada/collada.cpp =================================================================== --- source/blender/collada/collada.cpp (revision 47523) +++ source/blender/collada/collada.cpp (working copy) @@ -54,14 +54,18 @@ const char *filepath, int selected, int apply_modifiers, + + int include_armatures, int include_bone_children, + int use_object_instantiation, - int second_life) + int second_life ) { ExportSettings export_settings; export_settings.selected = selected != 0; export_settings.apply_modifiers = apply_modifiers != 0; + export_settings.include_armatures = include_armatures != 0; export_settings.include_bone_children = include_bone_children != 0; export_settings.second_life = second_life != 0; export_settings.use_object_instantiation = use_object_instantiation != 0; Index: source/blender/collada/ExportSettings.h =================================================================== --- source/blender/collada/ExportSettings.h (revision 47523) +++ source/blender/collada/ExportSettings.h (working copy) @@ -32,6 +32,7 @@ public: bool selected; bool apply_modifiers; + bool include_armatures; bool include_bone_children; bool use_object_instantiation; bool second_life; Index: source/blender/collada/ArmatureExporter.h =================================================================== --- source/blender/collada/ArmatureExporter.h (revision 47523) +++ source/blender/collada/ArmatureExporter.h (working copy) @@ -64,7 +64,7 @@ bool is_skinned_mesh(Object *ob); - void add_instance_controller(Object *ob); + bool add_instance_controller(Object *ob); void export_controllers(Scene *sce); @@ -85,8 +85,6 @@ void find_objects_using_armature(Object *ob_arm, std::vector& objects, Scene *sce); #endif - Object *get_assigned_armature(Object *ob); - std::string get_joint_sid(Bone *bone, Object *ob_arm); // Scene, SceneExporter and the list of child_objects Index: source/blender/collada/collada_utils.h =================================================================== --- source/blender/collada/collada_utils.h (revision 47523) +++ source/blender/collada/collada_utils.h (working copy) @@ -36,6 +36,7 @@ #include #include "DNA_object_types.h" +#include "DNA_mesh_types.h" #include "DNA_customdata_types.h" #include "DNA_texture_types.h" #include "BKE_context.h" @@ -50,5 +51,7 @@ extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int n); extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type); extern Object *bc_add_object(Scene *scene, int type, const char *name); +extern Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob); +extern Object *bc_get_assigned_armature(Object *ob); #endif Index: source/blender/collada/GeometryExporter.cpp =================================================================== --- source/blender/collada/GeometryExporter.cpp (revision 47523) +++ source/blender/collada/GeometryExporter.cpp (working copy) @@ -49,6 +49,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "collada_internal.h" +#include "collada_utils.h" // TODO: optimize UV sets by making indexed list with duplicates removed GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings) {} @@ -65,25 +66,6 @@ closeLibrary(); } -Mesh * GeometryExporter::get_mesh(Object *ob, int apply_modifiers) -{ - Mesh *tmpmesh; - if (!apply_modifiers) - { - tmpmesh = (Mesh*)ob->data; - } - else - { - CustomDataMask mask = CD_MASK_MESH; - DerivedMesh *dm = mesh_create_derived_view(mScene, ob, mask); - tmpmesh = BKE_mesh_add("ColladaMesh"); // name is not important here - DM_to_mesh(dm, tmpmesh, ob); - dm->release(dm); - } - BKE_mesh_tessface_ensure(tmpmesh); - return tmpmesh; -} - void GeometryExporter::operator()(Object *ob) { // XXX don't use DerivedMesh, Mesh instead? @@ -93,7 +75,14 @@ #endif bool use_instantiation = this->export_settings->use_object_instantiation; - Mesh *me = get_mesh(ob, this->export_settings->apply_modifiers); + Mesh *me; + if ( this->export_settings->apply_modifiers ) { + me = bc_to_mesh_apply_modifiers(mScene, ob); + } + else { + me = (Mesh*)ob->data; + } + BKE_mesh_tessface_ensure(me); std::string geom_id = get_geometry_id(ob, use_instantiation); std::vector nor; Index: source/blender/collada/DocumentExporter.cpp =================================================================== --- source/blender/collada/DocumentExporter.cpp (revision 47523) +++ source/blender/collada/DocumentExporter.cpp (working copy) @@ -262,8 +262,10 @@ // ArmatureExporter arm_exporter(&sw, this->export_settings); - if (has_object_type(sce, OB_ARMATURE)) { - arm_exporter.export_controllers(sce); + if (this->export_settings->include_armatures) { + if (has_object_type(sce, OB_ARMATURE)) { + arm_exporter.export_controllers(sce); + } } // Index: source/blender/collada/ArmatureExporter.cpp =================================================================== --- source/blender/collada/ArmatureExporter.cpp (revision 47523) +++ source/blender/collada/ArmatureExporter.cpp (working copy) @@ -37,6 +37,14 @@ #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" @@ -45,6 +53,8 @@ #include "ArmatureExporter.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? @@ -66,12 +76,12 @@ bool ArmatureExporter::is_skinned_mesh(Object *ob) { - return get_assigned_armature(ob) != NULL; + return bc_get_assigned_armature(ob) != NULL; } -void ArmatureExporter::add_instance_controller(Object *ob) +bool ArmatureExporter::add_instance_controller(Object *ob) { - Object *ob_arm = get_assigned_armature(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); @@ -79,6 +89,9 @@ 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) { @@ -89,6 +102,7 @@ InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob); ins.add(); + return true; } void ArmatureExporter::export_controllers(Scene *sce) @@ -105,7 +119,7 @@ void ArmatureExporter::operator()(Object *ob) { - Object *ob_arm = get_assigned_armature(ob); + Object *ob_arm = bc_get_assigned_armature(ob); if (ob_arm /*&& !already_written(ob_arm)*/) export_controller(ob, ob_arm); @@ -139,27 +153,6 @@ } #endif -Object *ArmatureExporter::get_assigned_armature(Object *ob) -{ - Object *ob_arm = NULL; - - if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { - ob_arm = ob->parent; - } - else { - ModifierData *mod = (ModifierData*)ob->modifiers.first; - while (mod) { - if (mod->type == eModifierType_Armature) { - ob_arm = ((ArmatureModifierData*)mod)->object; - } - - mod = mod->next; - } - } - - return ob_arm; -} - std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm) { return get_joint_id(bone, ob_arm); @@ -325,7 +318,16 @@ */ bool use_instantiation = this->export_settings->use_object_instantiation; - Mesh *me = (Mesh*)ob->data; + Mesh *me; + + if ( this->export_settings->apply_modifiers ) { + me = bc_to_mesh_apply_modifiers(scene, ob); + } + else { + me = (Mesh*)ob->data; + } + BKE_mesh_tessface_ensure(me); + if (!me->dvert) return; std::string controller_name = id_name(ob_arm); @@ -393,6 +395,10 @@ 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(); } Index: source/blender/makesrna/intern/rna_scene_api.c =================================================================== --- source/blender/makesrna/intern/rna_scene_api.c (revision 47523) +++ source/blender/makesrna/intern/rna_scene_api.c (working copy) @@ -90,11 +90,14 @@ const char *filepath, int selected, int apply_modifiers, + int include_armatures, int include_bone_children, int use_object_instantiation, int second_life) { - collada_export(scene, filepath, selected, apply_modifiers, include_bone_children, use_object_instantiation, second_life); + collada_export(scene, filepath, selected, apply_modifiers, + include_armatures, include_bone_children, + use_object_instantiation, second_life); } #endif @@ -124,6 +127,7 @@ RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */ parm = RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements"); parm = RNA_def_boolean(func, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers (in Preview resolution)"); + parm = RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Include armature(s) used by the exported objects"); parm = RNA_def_boolean(func, "include_bone_children", 0, "Include Bone Children", "Include all objects attached to bones of selected Armature(s)"); parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instantiation", "Instantiate multiple Objects from same Data"); parm = RNA_def_boolean(func, "second_life", 0, "Export for Second Life", "Compatibility mode for Second Life");