Revision: 22111
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=22111
Author:   chingachgook
Date:     2009-08-01 08:44:18 +0200 (Sat, 01 Aug 2009)

Log Message:
-----------
Importer now creates skin vertex groups and reads vertex weights.

Modified Paths:
--------------
    branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp
    branches/soc-2009-chingachgook/source/blender/collada/SConscript

Modified: 
branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp
===================================================================
--- branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp  
2009-08-01 06:27:40 UTC (rev 22110)
+++ branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp  
2009-08-01 06:44:18 UTC (rev 22111)
@@ -37,6 +37,10 @@
 {
 #include "ED_keyframing.h"
 #include "ED_armature.h"
+#include "ED_mesh.h" // add_vert_to_defgroup, ...
+#include "ED_anim_api.h"
+#include "WM_types.h"
+#include "WM_api.h"
 
 #include "BKE_main.h"
 #include "BKE_customdata.h"
@@ -126,21 +130,39 @@
        return "UNKNOWN";
 }
 
+// works for COLLADAFW::Node, COLLADAFW::Geometry
+template<class T>
+const char *get_dae_name(T *node)
+{
+       const std::string& name = node->getName();
+       return name.size() ? name.c_str() : node->getOriginalId().c_str();
+}
+
+float get_float_value(const COLLADAFW::FloatOrDoubleArray& array, int index)
+{
+       if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
+               return array.getFloatValues()->getData()[index];
+       else 
+               return array.getDoubleValues()->getData()[index];
+}
+
 typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > 
TexIndexTextureArrayMap;
 
+// this is only for ArmatureImporter to "see" 
MeshImporter::get_object_by_geom_uid
+class MeshImporterBase
+{
+public:
+       virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& 
geom_uid) = 0;
+};
+
 class ArmatureImporter
 {
 private:
        Scene *scene;
        UnitConverter *unit_converter;
 
-       // to build armature bones from inverse bind matrices
-       struct JointData {
-               float inv_bind_mat[4][4]; // joint inverse bind matrix
-               Object *ob_arm;                   // armature object
-       };
-       std::map<int, JointData> joint_index_to_joint_info_map;
-       std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
+       // std::map<int, JointData> joint_index_to_joint_info_map;
+       // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
 
        struct LeafBone {
                // COLLADAFW::Node *node;
@@ -155,17 +177,244 @@
        // XXX not used
        // float min_angle; // minimum angle between bone head-tail and a row 
of bone matrix
 
+#if 0
        struct ArmatureJoints {
                Object *ob_arm;
                std::vector<COLLADAFW::Node*> root_joints;
        };
        std::vector<ArmatureJoints> armature_joints;
+#endif
 
        Object *empty; // empty for leaf bones
 
+       std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> 
geom_uid_by_controller_uid;
+       std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // 
contains all joints
        std::vector<COLLADAFW::Node*> root_joints;
-       std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> 
controller_id_to_geom_id_map;
 
+       // This is used to store data passed in write_controller_data.
+       // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this 
class members
+       // so that arrays don't get freed until we free them explicitly.
+       class SkinInfo
+       {
+       private:
+               // to build armature bones from inverse bind matrices
+               struct JointData {
+                       float inv_bind_mat[4][4]; // joint inverse bind matrix
+                       COLLADAFW::UniqueId joint_uid; // joint node UID
+                       // Object *ob_arm;                        // armature 
object
+               };
+
+               float bind_shape_matrix[4][4];
+
+               // data from COLLADAFW::SkinControllerData, each array should 
be freed
+               COLLADAFW::UIntValuesArray joints_per_vertex;
+               COLLADAFW::UIntValuesArray weight_indices;
+               COLLADAFW::UIntValuesArray joint_indices;
+               // COLLADAFW::FloatOrDoubleArray weights;
+               std::vector<float> weights;
+
+               std::vector<JointData> joint_data; // index to this vector is 
joint index
+
+               UnitConverter *unit_converter;
+
+               Object *ob_arm;
+               COLLADAFW::UniqueId controller_uid;
+       public:
+
+               SkinInfo() {}
+
+               SkinInfo(const SkinInfo& skin) : weights(skin.weights),
+                                                                               
 joint_data(skin.joint_data),
+                                                                               
 unit_converter(skin.unit_converter),
+                                                                               
 ob_arm(skin.ob_arm),
+                                                                               
 controller_uid(skin.controller_uid)
+               {
+                       Mat4CpyMat4(bind_shape_matrix, (float 
(*)[4])skin.bind_shape_matrix);
+
+                       transfer_array_data_const(skin.joints_per_vertex, 
joints_per_vertex);
+                       transfer_array_data_const(skin.weight_indices, 
weight_indices);
+                       transfer_array_data_const(skin.joint_indices, 
joint_indices);
+               }
+
+               SkinInfo(UnitConverter *conv) : unit_converter(conv), 
ob_arm(NULL) {}
+
+               // nobody owns the data after this, so it should be freed 
manually with releaseMemory
+               void transfer_array_data(COLLADAFW::UIntValuesArray& src, 
COLLADAFW::UIntValuesArray& dest)
+               {
+                       dest.setData((unsigned int*)src.getData(), 
src.getCount());
+                       src.yieldOwnerShip();
+                       dest.yieldOwnerShip();
+               }
+
+               // when src is const we cannot src.yieldOwnerShip, this is used 
by copy constructor
+               void transfer_array_data_const(const 
COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
+               {
+                       dest.setData((unsigned int*)src.getData(), 
src.getCount());
+                       dest.yieldOwnerShip();
+               }
+
+               void borrow_skin_controller_data(const 
COLLADAFW::SkinControllerData* skin)
+               {
+                       
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), 
joints_per_vertex);
+                       
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), 
weight_indices);
+                       
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointIndices(), 
joint_indices);
+                       // transfer_array_data(skin->getWeights(), weights);
+
+                       // cannot transfer data for FloatOrDoubleArray, copy 
values manually
+                       const COLLADAFW::FloatOrDoubleArray& weight = 
skin->getWeights();
+                       for (int i = 0; i < weight.getValuesCount(); i++)
+                               weights.push_back(get_float_value(weight, i));
+
+                       unit_converter->mat4_from_dae(bind_shape_matrix, 
skin->getBindShapeMatrix());
+               }
+                       
+               void free()
+               {
+                       joints_per_vertex.releaseMemory();
+                       weight_indices.releaseMemory();
+                       joint_indices.releaseMemory();
+                       // weights.releaseMemory();
+               }
+
+               // using inverse bind matrices to construct armature
+               // it is safe to invert them to get the original matrices
+               // because if they are inverse matrices, they can be inverted
+               void add_joint(const COLLADABU::Math::Matrix4& matrix)
+               {
+                       JointData jd;
+                       unit_converter->mat4_from_dae(jd.inv_bind_mat, matrix);
+                       joint_data.push_back(jd);
+               }
+
+               // called from write_controller
+               void create_armature(const COLLADAFW::SkinController* co, Scene 
*scene)
+               {
+                       ob_arm = add_object(scene, OB_ARMATURE);
+
+                       controller_uid = co->getUniqueId();
+
+                       const COLLADAFW::UniqueIdArray& joint_uids = 
co->getJoints();
+                       for (int i = 0; i < joint_uids.getCount(); i++) {
+                               joint_data[i].joint_uid = joint_uids[i];
+
+                               // // store armature pointer
+                               // JointData& jd = 
joint_index_to_joint_info_map[i];
+                               // jd.ob_arm = ob_arm;
+
+                               // now we'll be able to get inv bind matrix 
from joint id
+                               // joint_id_to_joint_index_map[joint_ids[i]] = 
i;
+                       }
+               }
+
+               bool get_joint_inv_bind_matrix(float inv_bind_mat[][4], 
COLLADAFW::Node *node)
+               {
+                       const COLLADAFW::UniqueId& uid = node->getUniqueId();
+                       std::vector<JointData>::iterator it;
+                       for (it = joint_data.begin(); it != joint_data.end(); 
it++) {
+                               if ((*it).joint_uid == uid) {
+                                       Mat4CpyMat4(inv_bind_mat, 
(*it).inv_bind_mat);
+                                       return true;
+                               }
+                       }
+
+                       return false;
+               }
+
+               Object *get_armature()
+               {
+                       return ob_arm;
+               }
+
+               const COLLADAFW::UniqueId& get_controller_uid()
+               {
+                       return controller_uid;
+               }
+
+               // some nodes may not be referenced by SkinController,
+               // in this case to determine if the node belongs to this 
armature,
+               // we need to search down the tree
+               bool uses_joint(COLLADAFW::Node *node)
+               {
+                       const COLLADAFW::UniqueId& uid = node->getUniqueId();
+                       std::vector<JointData>::iterator it;
+                       for (it = joint_data.begin(); it != joint_data.end(); 
it++) {
+                               if ((*it).joint_uid == uid)
+                                       return true;
+                       }
+
+                       COLLADAFW::NodePointerArray& children = 
node->getChildNodes();
+                       for (int i = 0; i < children.getCount(); i++) {
+                               if (this->uses_joint(children[i]))
+                                       return true;
+                       }
+
+                       return false;
+               }
+
+               void link_armature(bContext *C, Object *ob, 
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid)
+               {
+                       ob->parent = ob_arm;
+                       ob->partype = PARSKEL;
+                       ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
+
+                       ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP;
+
+                       // we need armature matrix here... where do we get it 
from I wonder...
+                       // root node/joint? or node with <instance_controller>?
+                       float parmat[4][4];
+                       Mat4One(parmat);
+                       Mat4Invert(ob->parentinv, parmat);
+
+                       // create all vertex groups
+                       std::vector<JointData>::iterator it;
+                       int joint_index;
+                       for (it = joint_data.begin(), joint_index = 0; it != 
joint_data.end(); it++, joint_index++) {
+                               const char *name = "Group";
+
+                               // name group by joint node name
+                               if (joint_by_uid.find((*it).joint_uid) != 
joint_by_uid.end()) {
+                                       name = 
get_dae_name(joint_by_uid[(*it).joint_uid]);
+                               }
+
+                               add_defgroup_name(ob, (char*)name);
+                       }
+
+                       // <vcount> - number of joints per vertex - 
joints_per_vertex
+                       // <v> - [[bone index, weight index] * joints per 
vertex] * vertices - weight indices
+                       // ^ bone index can be -1 meaning weight toward bind 
shape, how to express this in Blender?
+
+                       // for each vertex in weight indices
+                       //   for each bone index in vertex
+                       //     add vertex to group at group index
+                       //     treat group index -1 specially
+
+                       // get def group by index with BLI_findlink
+
+                       for (int vertex = 0, weight = 0; vertex < 
joints_per_vertex.getCount(); vertex++) {
+
+                               int limit = weight + joints_per_vertex[vertex];
+                               for ( ; weight < limit; weight++) {
+                                       int joint = joint_indices[weight], 
joint_weight = weight_indices[weight];
+
+                                       // -1 means "weight towards the bind 
shape", we just don't assign it to any group
+                                       if (joint != -1) {
+                                               bDeformGroup *def = 
(bDeformGroup*)BLI_findlink(&ob->defbase, joint);
+
+                                               add_vert_to_defgroup(ob, def, 
vertex, weights[joint_weight], WEIGHT_REPLACE);
+                                       }
+                               }
+                       }
+
+                       DAG_scene_sort(CTX_data_scene(C));
+                       ED_anim_dag_flush_update(C);
+                       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+               }
+       };
+
+       std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = 
skin controller data UID
+       MeshImporterBase *mesh_importer;
+
+#if 0
        JointData *get_joint_data(COLLADAFW::Node *node)
        {
                const COLLADAFW::UniqueId& joint_id = node->getUniqueId();
@@ -180,24 +429,22 @@
 
                return &joint_index_to_joint_info_map[joint_index];
        }
+#endif
 

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to