diff --git a/source/blender/animrig/ANIM_bone_collections.h b/source/blender/animrig/ANIM_bone_collections.h index fcceed2aadf..70761cb7970 100644 --- a/source/blender/animrig/ANIM_bone_collections.h +++ b/source/blender/animrig/ANIM_bone_collections.h @@ -138,6 +138,7 @@ void ANIM_armature_bonecoll_name_set(struct bArmature *armature, struct BoneCollection *bcoll, const char *name); +void ANIM_bonecoll_show(struct BoneCollection *bcoll); void ANIM_bonecoll_hide(struct BoneCollection *bcoll); /** @@ -214,10 +215,6 @@ inline bool ANIM_bonecoll_is_visible_actbone(const struct bArmature *armature) void ANIM_armature_bonecoll_show_all(struct bArmature *armature); void ANIM_armature_bonecoll_hide_all(struct bArmature *armature); -/* Only used by the Collada I/O code: */ -void ANIM_armature_enable_layers(struct bArmature *armature, const int layers); -void ANIM_bone_set_layer_ebone(struct EditBone *ebone, int layer); - void ANIM_armature_bonecoll_show_from_bone(struct bArmature *armature, const struct Bone *bone); void ANIM_armature_bonecoll_show_from_ebone(struct bArmature *armature, const struct EditBone *ebone); diff --git a/source/blender/animrig/intern/bone_collections.cc b/source/blender/animrig/intern/bone_collections.cc index 53ed2ef6c49..58f42a5036c 100644 --- a/source/blender/animrig/intern/bone_collections.cc +++ b/source/blender/animrig/intern/bone_collections.cc @@ -477,19 +477,6 @@ void ANIM_armature_bonecoll_hide_all(bArmature *armature) /* ********************************* */ /* Armature Layers transitional API. */ -void ANIM_armature_enable_layers(bArmature *armature, const int /*layers*/) -{ - // TODO: reimplement properly. - // armature->layer |= layers; - ANIM_armature_bonecoll_show_all(armature); -} - -void ANIM_bone_set_layer_ebone(EditBone *ebone, const int layer) -{ - // TODO: reimplement for bone collections. - ebone->layer = layer; -} - void ANIM_armature_bonecoll_assign_active(const bArmature *armature, EditBone *ebone) { if (armature->runtime.active_collection == nullptr) { diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp index e84a437b251..5b5dfb39ee7 100644 --- a/source/blender/io/collada/ArmatureExporter.cpp +++ b/source/blender/io/collada/ArmatureExporter.cpp @@ -29,6 +29,42 @@ #include "GeometryExporter.h" #include "SceneExporter.h" +void ArmatureExporter::add_bone_collections(Object *ob_arm, COLLADASW::Node &node) +{ + bArmature *armature = (bArmature *)ob_arm->data; + + /* Because our importer assumes that "extras" tags have a unique name, it's not posisble to + * export a element per bone collection. This is why all the names are stored in + * one element, newline-separated. */ + + std::stringstream collection_stream; + std::stringstream visible_stream; + LISTBASE_FOREACH (const BoneCollection *, bcoll, &armature->collections) { + collection_stream << bcoll->name << "\n"; + + if (bcoll->flags & BONE_COLLECTION_VISIBLE) { + visible_stream << bcoll->name << "\n"; + } + } + + std::string collection_names = collection_stream.str(); + if (collection_names.length() > 1) { + collection_names.pop_back(); // Pop off the last \n. + node.addExtraTechniqueParameter("blender", "collections", collection_names); + } + + std::string visible_names = visible_stream.str(); + if (visible_names.length() > 1) { + visible_names.pop_back(); // Pop off the last \n. + node.addExtraTechniqueParameter("blender", "visible_collections", visible_names); + } + + if (armature->runtime.active_collection) { + node.addExtraTechniqueParameter( + "blender", "active_collection", std::string(armature->active_collection_name)); + } +} + void ArmatureExporter::add_armature_bones(Object *ob_arm, ViewLayer *view_layer, SceneExporter *se, @@ -154,8 +190,15 @@ void ArmatureExporter::add_bone_node(Bone *bone, node.addExtraTechniqueParameter("blender", "connect", true); } } - std::string layers = BoneExtended::get_bone_layers(bone->layer); - node.addExtraTechniqueParameter("blender", "layer", layers); + + std::string collection_names = ""; + LISTBASE_FOREACH (const BoneCollectionReference *, bcoll_ref, &bone->runtime.collections) { + collection_names += std::string(bcoll_ref->bcoll->name) + "\n"; + } + if (collection_names.length() > 1) { + collection_names.pop_back(); // Pop off the last \n. + node.addExtraTechniqueParameter("blender", "", collection_names, "", "collections"); + } bArmature *armature = (bArmature *)ob_arm->data; EditBone *ebone = bc_get_edit_bone(armature, bone->name); diff --git a/source/blender/io/collada/ArmatureExporter.h b/source/blender/io/collada/ArmatureExporter.h index 40fa6521ad1..a3552254d54 100644 --- a/source/blender/io/collada/ArmatureExporter.h +++ b/source/blender/io/collada/ArmatureExporter.h @@ -50,6 +50,8 @@ class ArmatureExporter : public COLLADASW::LibraryControllers, { } + void add_bone_collections(Object *ob_arm, COLLADASW::Node &node); + /* write bone nodes */ void add_armature_bones(Object *ob_arm, ViewLayer *view_layer, diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp index 5117f7d31dd..e04e3fec982 100644 --- a/source/blender/io/collada/ArmatureImporter.cpp +++ b/source/blender/io/collada/ArmatureImporter.cpp @@ -140,12 +140,13 @@ int ArmatureImporter::create_bone(SkinInfo *skin, float loc[3], size[3], rot[3][3]; BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(arm); BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels, extended_bones); - int layer = be.get_bone_layers(); - if (layer) { - ANIM_bone_set_layer_ebone(bone, layer); + + for (const std::string &bcoll_name : be.get_bone_collections()) { + BoneCollection *bcoll = ANIM_armature_bonecoll_get_by_name(arm, bcoll_name.c_str()); + if (bcoll) { + ANIM_armature_bonecoll_assign_editbone(bcoll, bone); + } } - /* Ensure that all populated bone layers are visible after import. */ - ANIM_armature_enable_layers(arm, layer); float *tail = be.get_tail(); int use_connect = be.get_use_connect(); @@ -490,8 +491,6 @@ void ArmatureImporter::create_armature_bones(Main *bmain, std::vector } ED_armature_to_edit(armature); - /* Layers are enabled according to imported bone set in create_bone(). */ - ANIM_armature_bonecoll_hide_all(armature); create_bone( nullptr, node, nullptr, node->getChildNodes().getCount(), nullptr, armature, layer_labels); @@ -530,7 +529,6 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo &skin) * - add edit bones and head/tail properties using matrices and parent-child info * - exit edit mode * - set a sphere shape to leaf bones */ - Object *ob_arm = nullptr; /* @@ -1060,7 +1058,6 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, float tail[3] = {FLT_MAX, FLT_MAX, FLT_MAX}; float roll = 0; - std::string layers; et = etit->second; @@ -1072,7 +1069,7 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, has_connect = et->setData("connect", &connect_type); bool has_roll = et->setData("roll", &roll); - layers = et->setData("layer", layers); + be->set_bone_collections(et->dataSplitString("collections")); if (has_tail && !has_connect) { /* got a bone tail definition but no connect info -> bone is not connected */ @@ -1080,7 +1077,6 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, connect_type = 0; } - be->set_bone_layers(layers, layer_labels); if (has_tail) { be->set_tail(tail); } diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp index ed0680ac568..debdfc86fcd 100644 --- a/source/blender/io/collada/DocumentImporter.cpp +++ b/source/blender/io/collada/DocumentImporter.cpp @@ -622,7 +622,8 @@ std::vector *DocumentImporter::write_node(COLLADAFW::Node *node, if ((geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) { /* Check if Object is armature, by checking if immediate child is a JOINT node. */ if (is_armature(node)) { - ob = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, name.c_str()); + ExtraTags *et = getExtraTags(node->getUniqueId()); + ob = bc_add_armature(node, et, bmain, sce, view_layer, OB_ARMATURE, name.c_str()); } else { ob = bc_add_object(bmain, sce, view_layer, OB_EMPTY, nullptr); diff --git a/source/blender/io/collada/ExtraTags.cpp b/source/blender/io/collada/ExtraTags.cpp index cd28791459c..691449cf558 100644 --- a/source/blender/io/collada/ExtraTags.cpp +++ b/source/blender/io/collada/ExtraTags.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "ExtraTags.h" @@ -110,3 +111,23 @@ std::string ExtraTags::setData(std::string tag, std::string &data) std::string tmp = asString(tag, &ok); return (ok) ? tmp : data; } + +std::vector ExtraTags::dataSplitString(const std::string &tag) +{ + bool ok = false; + const std::string value = asString(tag, &ok); + if (!ok) { + return std::vector(); + } + + std::vector values; + + const std::regex newline_re("[^\\s][^\\r\\n]+"); + const std::sregex_token_iterator end; + std::sregex_token_iterator iter(value.begin(), value.end(), newline_re); + for (; iter != end; iter++) { + values.push_back(*iter); + } + + return values; +} diff --git a/source/blender/io/collada/ExtraTags.h b/source/blender/io/collada/ExtraTags.h index dfba292faac..906dd5b2bbf 100644 --- a/source/blender/io/collada/ExtraTags.h +++ b/source/blender/io/collada/ExtraTags.h @@ -38,6 +38,9 @@ class ExtraTags { bool setData(std::string tag, char *data); std::string setData(std::string tag, std::string &data); + /** Get a string from the data, and split it by newlines. */ + std::vector dataSplitString(const std::string &tag); + /** Return true if the extra tags is for specified profile. */ bool isProfile(std::string profile); diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp index 303d43e862b..454caf8f5f8 100644 --- a/source/blender/io/collada/SceneExporter.cpp +++ b/source/blender/io/collada/SceneExporter.cpp @@ -141,6 +141,7 @@ void SceneExporter::writeNode(Object *ob) /* */ else if (ob->type == OB_ARMATURE) { + arm_exporter->add_bone_collections(ob, colladaNode); arm_exporter->add_armature_bones(ob, view_layer, this, child_objects); } diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index c85fec3c41f..2bf4b1acb59 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -12,6 +12,7 @@ #include "COLLADAFWGeometry.h" #include "COLLADAFWMeshPrimitive.h" #include "COLLADAFWMeshVertexData.h" +#include "COLLADAFWNode.h" #include #include @@ -48,6 +49,8 @@ #include "BKE_object.h" #include "BKE_scene.h" +#include "ANIM_bone_collections.h" + #include "ED_node.hh" #include "ED_object.hh" #include "ED_screen.hh" @@ -66,6 +69,7 @@ #include "BlenderContext.h" #include "ExportSettings.h" +#include "ExtraTags.h" #include "collada_utils.h" float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray &array, uint index) @@ -207,6 +211,41 @@ Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type return ob; } +static void bc_add_armature_collections(COLLADAFW::Node *node, + ExtraTags *node_extra_tags, + bArmature *arm) +{ + std::vector collection_names = node_extra_tags->dataSplitString("collections"); + std::vector visible_names = node_extra_tags->dataSplitString("visible_collections"); + std::set visible_names_set(visible_names.begin(), visible_names.end()); + for (const std::string &name : collection_names) { + BoneCollection *bcoll = ANIM_armature_bonecoll_new(arm, name.c_str()); + if (visible_names_set.find(name) == visible_names_set.end()) { + ANIM_bonecoll_hide(bcoll); + } + else { + ANIM_bonecoll_show(bcoll); + } + } + + std::string active_name; + active_name = node_extra_tags->setData("active_collection", active_name); + ANIM_armature_bonecoll_active_name_set(arm, active_name.c_str()); +} + +Object *bc_add_armature(COLLADAFW::Node *node, + ExtraTags *node_extra_tags, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + int type, + const char *name) +{ + Object *ob = bc_add_object(bmain, scene, view_layer, type, name); + bc_add_armature_collections(node, node_extra_tags, reinterpret_cast(ob->data)); + return ob; +} + Mesh *bc_get_mesh_copy(BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, @@ -500,7 +539,6 @@ BoneExtended::BoneExtended(EditBone *aBone) this->tail[2] = 0.0f; this->use_connect = -1; this->roll = 0; - this->bone_layers = 0; this->has_custom_tail = false; this->has_custom_roll = false; @@ -582,62 +620,13 @@ inline bool isInteger(const std::string &s) return (*p == 0); } -void BoneExtended::set_bone_layers(std::string layerString, std::vector &layer_labels) +void BoneExtended::set_bone_collections(std::vector bone_collections) { - std::stringstream ss(layerString); - std::string layer; - int pos; - - while (ss >> layer) { - - /* Blender uses numbers to specify layers. */ - if (isInteger(layer)) { - pos = atoi(layer.c_str()); - if (pos >= 0 && pos < 32) { - this->bone_layers = bc_set_layer(this->bone_layers, pos); - continue; - } - } - - /* Layer uses labels (not supported by blender). Map to layer numbers: */ - pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin(); - if (pos >= layer_labels.size()) { - layer_labels.push_back(layer); /* Remember layer number for future usage. */ - } - - if (pos > 31) { - fprintf(stderr, - "Too many layers in Import. Layer %s mapped to Blender layer 31\n", - layer.c_str()); - pos = 31; - } - - /* If numeric layers and labeled layers are used in parallel (unlikely), - * we get a potential mix-up. Just leave as is for now. */ - this->bone_layers = bc_set_layer(this->bone_layers, pos); - } + this->bone_collections = bone_collections; } - -std::string BoneExtended::get_bone_layers(int bitfield) +const std::vector &BoneExtended::get_bone_collections() { - std::string sep; - int bit = 1u; - - std::ostringstream ss; - for (int i = 0; i < 32; i++) { - if (bit & bitfield) { - ss << sep << i; - sep = " "; - } - bit = bit << 1; - } - return ss.str(); -} - -int BoneExtended::get_bone_layers() -{ - /* ensure that the bone is in at least one bone layer! */ - return (bone_layers == 0) ? 1 : bone_layers; + return this->bone_collections; } void BoneExtended::set_use_connect(int use_connect) diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h index 60e163f3eb8..3f1a8a06fa7 100644 --- a/source/blender/io/collada/collada_utils.h +++ b/source/blender/io/collada/collada_utils.h @@ -59,6 +59,11 @@ typedef std::map KeyImageMap; typedef std::map> TexIndexTextureArrayMap; typedef std::set BCObjectSet; +namespace COLLADAFW { +class Node; +} +class ExtraTags; + extern void bc_update_scene(BlenderContext &blender_context, float ctime); /* Action helpers */ @@ -118,6 +123,13 @@ extern bool bc_validateConstraints(bConstraint *con); bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true); extern Object *bc_add_object( Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name); +extern Object *bc_add_armature(COLLADAFW::Node *node, + ExtraTags *node_extra_tags, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + int type, + const char *name); extern Mesh *bc_get_mesh_copy(BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, @@ -362,7 +374,8 @@ class BoneExtended { float tail[3]; float roll; - int bone_layers; + std::vector bone_collections; + int use_connect; bool has_custom_tail; bool has_custom_roll; @@ -379,9 +392,8 @@ class BoneExtended { void set_leaf_bone(bool state); bool is_leaf_bone(); - void set_bone_layers(std::string layers, std::vector &layer_labels); - int get_bone_layers(); - static std::string get_bone_layers(int bitfield); + void set_bone_collections(std::vector bone_collections); + const std::vector &get_bone_collections(); void set_roll(float roll); bool has_roll();