Collada: Adding support for bone roll and bone layers
authorGaia Clary <gaia.clary@machinimatrix.org>
Sat, 28 May 2016 16:41:54 +0000 (18:41 +0200)
committerGaia Clary <gaia.clary@machinimatrix.org>
Sat, 28 May 2016 17:22:06 +0000 (19:22 +0200)
Differential Revision: https://developer.blender.org/D2034

source/blender/collada/ArmatureExporter.cpp
source/blender/collada/ArmatureImporter.cpp
source/blender/collada/ArmatureImporter.h
source/blender/collada/ExtraTags.cpp
source/blender/collada/ExtraTags.h
source/blender/collada/collada_utils.cpp
source/blender/collada/collada_utils.h

index 47a0ffda3c67e8e2ba56cfffa0a6c8dcc84e1dff..c8d92f4d329961a6baf375081f6e96468f8cfed0 100644 (file)
@@ -67,12 +67,19 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
                                           std::list<Object *>& child_objects)
 {
        // write bone nodes
+
+       bArmature * armature = (bArmature *)ob_arm->data;
+       ED_armature_to_edit(armature);
+
        bArmature *arm = (bArmature *)ob_arm->data;
        for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
                // start from root bones
                if (!bone->parent)
                        add_bone_node(bone, ob_arm, sce, se, child_objects);
        }
+
+       ED_armature_from_edit(armature);
+       ED_armature_edit_free(armature);
 }
 
 void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -174,7 +181,15 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
                                        node.addExtraTechniqueParameter("blender", "connect", true);
                                }
                        }
+                       std::string layers = BoneExtended::get_bone_layers(bone->layer);
+                       node.addExtraTechniqueParameter("blender", "layer", layers);
 
+                       bArmature *armature = (bArmature *)ob_arm->data;
+                       EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+                       if (ebone && ebone->roll > 0)
+                       {
+                               node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
+                       }
                        if (bc_is_leaf_bone(bone))
                        {
                                node.addExtraTechniqueParameter("blender", "tip_x", bone->arm_tail[0] - bone->arm_head[0]);
index 4c318cd97cce731fd2a0314552b43732be0d140f..496ca4efd062df380a59db87cdc7b530aea2defe 100644 (file)
@@ -50,19 +50,6 @@ static const char *bc_get_joint_name(T *node)
        return id.size() ? id.c_str() : node->getOriginalId().c_str();
 }
 
-static EditBone *get_edit_bone(bArmature * armature, char *name) {
-       EditBone  *eBone;
-
-       for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
-               if (STREQ(name, eBone->name))
-                       return eBone;
-       }
-
-       return NULL;
-
-}
-
-
 
 ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
        import_settings(import_settings),
@@ -157,9 +144,11 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
        if (parent) bone->parent = parent;
 
        float loc[3], size[3], rot[3][3]; 
-       float angle;
 
        BoneExtended &be = add_bone_extended(bone, node);
+       int layer = be.get_bone_layers();
+       if (layer) bone->layer = layer;
+       arm->layer |= layer; // ensure that all populated bone layers are visible after import
 
        float *tail = be.get_tail();
        int use_connect = be.get_use_connect();
@@ -171,10 +160,16 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
        case -1: break; // not defined
        }
 
-       mat4_to_loc_rot_size(loc, rot, size, mat);
-       mat3_to_vec_roll(rot, NULL, &angle);
+       if (be.has_roll()) {
+               bone->roll = be.get_roll();
+       } 
+       else {
+               float angle;
+               mat4_to_loc_rot_size(loc, rot, size, mat);
+               mat3_to_vec_roll(rot, NULL, &angle);
+       }
+
 
-       bone->roll = angle;
        copy_v3_v3(bone->head, mat[3]);
        add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
 
@@ -224,12 +219,12 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
        if (bc_is_leaf_bone(bone)) {
 
                BoneExtended *be = extended_bones[bone->name];
-               if (be == NULL || !be->has_custom_tail()) {
+               if (be == NULL || !be->has_tail()) {
 
                        /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
                        float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
 
-                       EditBone *ebone = get_edit_bone(armature, bone->name);
+                       EditBone *ebone = bc_get_edit_bone(armature, bone->name);
                        float vec[3];
 
                        if (ebone->parent != NULL) {
@@ -303,8 +298,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
        BoneExtended *pbe = extended_bones[parentbone->name];
        if (dominant_child != NULL) {
                /* Found a valid chain. Now connect current bone with that chain.*/
-               EditBone *pebone = get_edit_bone(armature, parentbone->name);
-               EditBone *cebone = get_edit_bone(armature, dominant_child->get_name());
+               EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
+               EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
                if (pebone && !(cebone->flag & BONE_CONNECTED)) {
 
                        float vec[3];
@@ -467,6 +462,7 @@ void ArmatureImporter::create_armature_bones( )
                clear_extended_boneset();
 
                ED_armature_to_edit(armature);
+               armature->layer = 0; // layer is set according to imported bone set in create_bone()
 
                create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
 
@@ -925,84 +921,6 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
        return found;
 }
 
-
-/**
-  * BoneExtended is a helper class needed for the Bone chain finder
-  * See ArmatureImporter::fix_leaf_bones()
-  * and ArmatureImporter::connect_bone_chains()
-  **/
-
-BoneExtended::BoneExtended(EditBone *aBone) 
-{
-       this->set_name(aBone->name);
-       this->chain_length = 0;
-       this->is_leaf      = false;
-       this->tail[0]      = 0.0f;
-       this->tail[1]      = 0.5f;
-       this->tail[2]      = 0.0f;
-       this->use_connect  = -1;
-       this->has_tail     = false;
-}
-
-char *BoneExtended::get_name() 
-{
-       return name;
-}
-
-void BoneExtended::set_name(char *aName) 
-{
-       BLI_strncpy(name, aName, MAXBONENAME);
-}
-
-int BoneExtended::get_chain_length() 
-{
-       return chain_length;
-}
-
-void BoneExtended::set_chain_length(const int aLength) 
-{
-       chain_length = aLength;
-}
-
-void BoneExtended::set_leaf_bone(bool state)
-{
-       is_leaf = state;
-}
-
-bool BoneExtended::is_leaf_bone()
-{
-       return is_leaf;
-}
-
-void BoneExtended::set_tail(float vec[])
-{
-       this->tail[0] = vec[0];
-       this->tail[1] = vec[1];
-       this->tail[2] = vec[2];
-       this->has_tail = true;
-}
-
-bool BoneExtended::has_custom_tail()
-{
-       return this->has_tail;
-}
-
-float *BoneExtended::get_tail()
-{
-       return this->tail;
-}
-
-void BoneExtended::set_use_connect(int use_connect)
-{
-       this->use_connect = use_connect;
-}
-
-int BoneExtended::get_use_connect()
-{
-       return this->use_connect;
-}
-
-
 BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node)
 {
        BoneExtended *be = new BoneExtended(bone);
@@ -1014,23 +932,30 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Nod
        if (etit != uid_tags_map.end()) {
 
                float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
-               int use_connect   = -1;
+               float roll = 0;
+               int use_connect = -1;
+               std::string layers;
 
                et = etit->second;
-               et->setData("tip_x",   &tail[0]);
-               et->setData("tip_y",   &tail[1]);
-               et->setData("tip_z",   &tail[2]);
-               et->setData("connect", &use_connect);
 
-               if (!(tail[0] == FLT_MAX || tail[1] == FLT_MAX || tail[2] == FLT_MAX))
+               bool has_tail = false;
+               has_tail |= et->setData("tip_x", &tail[0]);
+               has_tail |= et->setData("tip_y", &tail[1]);
+               has_tail |= et->setData("tip_z", &tail[2]);
+
+               bool has_connect = et->setData("connect", &use_connect);
+               bool has_roll    = et->setData("roll", &roll);
+               
+               layers = et->setData("layer", layers);
+
+               if (has_tail && !has_connect)
                {
-                       if (use_connect == -1)
-                       {
-                               use_connect = 0; // got a bone tail definition but no connect info -> bone is not connected
-                       }
+                       use_connect = 0; // got a bone tail definition but no connect info -> bone is not connected
                }
 
-               be->set_tail(tail);
+               be->set_bone_layers(layers);
+               if (has_tail) be->set_tail(tail);
+               if (has_roll) be->set_roll(roll);
                be->set_use_connect(use_connect);
        }
        be->set_leaf_bone(true);
index 4cef3d4fb38f0e020c764a4536a67dabb9caeb9f..fba8c5bd5d6b60629b5519627560e7392fc9560f 100644 (file)
@@ -59,37 +59,6 @@ extern "C" {
 #define UNLIMITED_CHAIN_MAX INT_MAX
 #define MINIMUM_BONE_LENGTH 0.000001f
 
-class BoneExtended {
-
-private:
-       char  name[MAXBONENAME];
-       int   chain_length;
-       bool  is_leaf;
-       float tail[3];
-       bool  use_connect;
-       bool  has_tail;
-
-public:
-
-       BoneExtended(EditBone *aBone);
-
-       void set_name(char *aName);
-       char *get_name();
-
-       void set_chain_length(const int aLength);
-       int  get_chain_length();
-
-       void set_leaf_bone(bool state);
-       bool is_leaf_bone();
-
-       void set_tail(float *vec);
-       float *get_tail();
-       bool has_custom_tail();
-
-       void set_use_connect(int use_connect);
-       int get_use_connect();
-};
-
 class ArmatureImporter : private TransformReader
 {
 private:
index 6af61432fda15571c20fd8a0bc75ec3eca9d1372..ea225d8a4ae367091b9fb42a6c72b1a6ca4d2ff7 100644 (file)
@@ -85,32 +85,45 @@ std::string ExtraTags::asString(std::string tag, bool *ok)
 }
 
 
-void ExtraTags::setData(std::string tag, short *data)
+bool ExtraTags::setData(std::string tag, short *data)
 {
        bool ok = false;
        int tmp = asInt(tag, &ok);
        if (ok)
                *data = (short)tmp;
+       return ok;
 }
-void ExtraTags::setData(std::string tag, int *data)
+
+bool ExtraTags::setData(std::string tag, int *data)
 {
        bool ok = false;
        int tmp = asInt(tag, &ok);
        if (ok)
                *data = tmp;
+       return ok;
 }
-void ExtraTags::setData(std::string tag, float *data)
+
+bool ExtraTags::setData(std::string tag, float *data)
 {
        bool ok = false;
        float tmp = asFloat(tag, &ok);
        if (ok)
                *data = tmp;
+       return ok;
 }
-void ExtraTags::setData(std::string tag, char *data)
+
+bool ExtraTags::setData(std::string tag, char *data)
 {
        bool ok = false;
        int tmp = asInt(tag, &ok);
        if (ok)
                *data = (char)tmp;
+       return ok;
+}
+
+std::string ExtraTags::setData(std::string tag, std::string &data)
+{
+       bool ok = false;
+       std::string tmp = asString(tag, &ok);
+       return (ok) ? tmp : data;
 }
-       
index 03a311a7e86ba1aac85290451aed37e439bdfa35..ad272dcba652d2e281d7626a9daf07746e0f90a8 100644 (file)
@@ -43,17 +43,18 @@ public:
        bool addTag(std::string tag, std::string data);
        
        /** Set given short pointer to value of tag, if it exists. */
-       void setData(std::string tag, short *data);
+       bool setData(std::string tag, short *data);
        
        /** Set given int pointer to value of tag, if it exists. */
-       void setData(std::string tag, int *data);
+       bool setData(std::string tag, int *data);
        
        /** Set given float pointer to value of tag, if it exists. */
-       void setData(std::string tag, float *data);
+       bool setData(std::string tag, float *data);
        
        /** Set given char pointer to value of tag, if it exists. */
-       void setData(std::string tag, char *data);
-       
+       bool setData(std::string tag, char *data);
+       std::string setData(std::string tag, std::string &data);
+
        /** Return true if the extra tags is for specified profile. */
        bool isProfile(std::string profile);
        
index 30cf404cc3d93d99415cf33609e5f7fcf49d374c..c510eb6e0e8a34ec6e2dcee67e896bfa51887140 100644 (file)
@@ -54,6 +54,8 @@ extern "C" {
 #include "BKE_scene.h"
 #include "BKE_DerivedMesh.h"
 
+#include "ED_armature.h"
+
 #include "WM_api.h" // XXX hrm, see if we can do without this
 #include "WM_types.h"
 
@@ -378,3 +380,192 @@ bool bc_is_leaf_bone(Bone *bone)
        }
        return true;
 }
+
+EditBone *bc_get_edit_bone(bArmature * armature, char *name) {
+       EditBone  *eBone;
+
+       for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
+               if (STREQ(name, eBone->name))
+                       return eBone;
+       }
+
+       return NULL;
+
+}
+int bc_set_layer(int bitfield, int layer)
+{
+       return bc_set_layer(bitfield, layer, true); /* enable */
+}
+
+int bc_set_layer(int bitfield, int layer, bool enable)
+{
+       int bit = 1u << layer;
+
+       if (enable)
+               bitfield |= bit;
+       else
+               bitfield &= ~bit;
+
+       return bitfield;
+}
+
+/**
+* BoneExtended is a helper class needed for the Bone chain finder
+* See ArmatureImporter::fix_leaf_bones()
+* and ArmatureImporter::connect_bone_chains()
+**/
+
+BoneExtended::BoneExtended(EditBone *aBone)
+{
+       this->set_name(aBone->name);
+       this->chain_length = 0;
+       this->is_leaf = false;
+       this->tail[0] = 0.0f;
+       this->tail[1] = 0.5f;
+       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;
+}
+
+char *BoneExtended::get_name()
+{
+       return name;
+}
+
+void BoneExtended::set_name(char *aName)
+{
+       BLI_strncpy(name, aName, MAXBONENAME);
+}
+
+int BoneExtended::get_chain_length()
+{
+       return chain_length;
+}
+
+void BoneExtended::set_chain_length(const int aLength)
+{
+       chain_length = aLength;
+}
+
+void BoneExtended::set_leaf_bone(bool state)
+{
+       is_leaf = state;
+}
+
+bool BoneExtended::is_leaf_bone()
+{
+       return is_leaf;
+}
+
+void BoneExtended::set_roll(float roll)
+{
+       this->roll = roll;
+       this->has_custom_roll = true;
+}
+
+bool BoneExtended::has_roll()
+{
+       return this->has_custom_roll;
+}
+
+float BoneExtended::get_roll()
+{
+       return this->roll;
+}
+
+void BoneExtended::set_tail(float vec[])
+{
+       this->tail[0] = vec[0];
+       this->tail[1] = vec[1];
+       this->tail[2] = vec[2];
+       this->has_custom_tail = true;
+}
+
+bool BoneExtended::has_tail()
+{
+       return this->has_custom_tail;
+}
+
+float *BoneExtended::get_tail()
+{
+       return this->tail;
+}
+
+inline bool isInteger(const std::string & s)
+{
+       if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
+
+       char * p;
+       strtol(s.c_str(), &p, 10);
+
+       return (*p == 0);
+}
+
+void BoneExtended::set_bone_layers(std::string layerString)
+{
+       std::stringstream ss(layerString);
+       std::istream_iterator<std::string> begin(ss);
+       std::istream_iterator<std::string> end;
+       std::vector<std::string> layers(begin, end);
+
+       for (std::vector<std::string>::iterator it = layers.begin(); it != layers.end(); ++it) {
+               std::string layer = *it;
+               int index = -1;
+
+               if (isInteger(layer))
+               {
+                       index = std::stoi(layer);
+                       if (index < 0 || index > 31)
+                               index - 1;
+               }
+
+               if (index == -1)
+               {
+                       //TODO
+                       int x = index;
+               }
+
+               if (index != -1)
+               {
+                       this->bone_layers = bc_set_layer(this->bone_layers, index);
+               }
+       }
+}
+
+std::string BoneExtended::get_bone_layers(int bitfield)
+{
+       std::string result = "";
+       std::string sep = "";
+       int bit = 1u;
+
+       for (int i = 0; i < 32; i++)
+       {
+               if (bit & bitfield)
+               {
+                       result += sep + std::to_string(i);
+                       sep = " ";
+               }
+               bit = bit << 1;
+       }
+       return result;
+}
+
+int BoneExtended::get_bone_layers()
+{
+       return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer!
+}
+
+
+void BoneExtended::set_use_connect(int use_connect)
+{
+       this->use_connect = use_connect;
+}
+
+int BoneExtended::get_use_connect()
+{
+       return this->use_connect;
+}
index 7f8e93736b5f48fcdaa743abc413ed4e954f7fae..e9f84afef6161072d51d5d2109ddce342dd80ff5 100644 (file)
@@ -46,6 +46,7 @@ extern "C" {
 
 #include "BLI_linklist.h"
 #include "BLI_utildefines.h"
+#include "BLI_string.h"
 
 #include "BKE_context.h"
 #include "BKE_object.h"
@@ -88,6 +89,9 @@ extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &u
 
 extern void bc_triangulate_mesh(Mesh *me);
 extern bool bc_is_leaf_bone(Bone *bone);
+extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
+extern int bc_set_layer(int bitfield, int layer, bool enable);
+extern int bc_set_layer(int bitfield, int layer);
 
 class BCPolygonNormalsIndices
 {
@@ -105,4 +109,48 @@ class BCPolygonNormalsIndices
 
 };
 
+class BoneExtended {
+
+private:
+       char  name[MAXBONENAME];
+       int   chain_length;
+       bool  is_leaf;
+       float tail[3];
+       float roll;
+
+       int   bone_layers;
+       bool  use_connect;
+       bool  has_custom_tail;
+       bool  has_custom_roll;
+
+public:
+
+       BoneExtended(EditBone *aBone);
+
+       void set_name(char *aName);
+       char *get_name();
+
+       void set_chain_length(const int aLength);
+       int  get_chain_length();
+
+       void set_leaf_bone(bool state);
+       bool is_leaf_bone();
+
+       void set_bone_layers(std::string layers);
+       int get_bone_layers();
+       static std::string get_bone_layers(int bitfield);
+
+       void set_roll(float roll);
+       bool has_roll();
+       float get_roll();
+
+       void set_tail(float *vec);
+       float *get_tail();
+       bool has_tail();
+
+       void set_use_connect(int use_connect);
+       int get_use_connect();
+};
+
+
 #endif