Fix rest of #27022, collada export: add bone parenting of objects
authorJuha Mäki-Kanto <ih5235252@gmail.com>
Sat, 18 Feb 2012 16:55:41 +0000 (16:55 +0000)
committerJuha Mäki-Kanto <ih5235252@gmail.com>
Sat, 18 Feb 2012 16:55:41 +0000 (16:55 +0000)
- SceneExporter collects a list of child-objects for armature-object and passes it onto ArmatureExporter
- SceneExporter's writeNodes is then called from ArmatureExporter for matching child-objects for bone.
- ArmatureExporter removes written child-objects from list, objects not exported as being bone parented are exported as direct children of the armature-node.
- Should play nice with current Second Life-compatibility.

A nicer implementation would require some design changes, will have to wait.

source/blender/collada/ArmatureExporter.cpp
source/blender/collada/ArmatureExporter.h
source/blender/collada/SceneExporter.cpp
source/blender/collada/SceneExporter.h

index 277b1896397af7619a9313fd3d503e72e94a67e5..9399ce6771dc6ccfc5676ac61e3adcb55e4c02e6 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "GeometryExporter.h"
 #include "ArmatureExporter.h"
+#include "SceneExporter.h"
 
 // XXX exporter writes wrong data for shared armatures.  A separate
 // controller should be written for each armature-mesh binding how do
 ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {}
 
 // write bone nodes
-void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce)
+void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene* sce,
+                                                                                 SceneExporter* se,
+                                                                                 std::list<Object*>& child_objects)
 {
        // write bone nodes
        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);
+                       add_bone_node(bone, ob_arm, sce, se, child_objects);
        }
 }
 
@@ -163,7 +166,9 @@ std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm)
 }
 
 // parent_mat is armature-space
-void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm)
+void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene* sce,
+                                                                        SceneExporter* se,
+                                                                        std::list<Object*>& child_objects)
 {
        std::string node_id = get_joint_id(bone, ob_arm);
        std::string node_name = std::string(bone->name);
@@ -183,14 +188,54 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm)
 
        add_bone_transform(ob_arm, bone, node);
 
+       // Write nodes of childobjects, remove written objects from list
+       std::list<Object*>::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];
+
+                       // SECOND_LIFE_COMPATIBILITY
+                       // crude, temporary change to parentinv
+                       // so transform gets exported correctly.
+                       // TODO: when such objects are animated as
+                       // single matrix the tweak must be applied
+                       // to the result.
+                       if(export_settings->second_life)
+                       {
+                               copy_m4_m4(backup_parinv, (*i)->parentinv);
+                               // tweak objects parentinverse to match
+                               // the second life- compatibility
+                               float temp[4][4];
+
+                               copy_m4_m4(temp, bone->arm_mat);
+                               temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+                               mult_m4_m4m4((*i)->parentinv, temp, backup_parinv);
+                       }
+
+                       se->writeNodes(*i, sce);
+
+                       // restore original parentinv
+                       if(export_settings->second_life)
+                       {
+                               copy_m4_m4((*i)->parentinv, backup_parinv);
+                       }
+                       child_objects.erase(i++);
+               }
+               else i++;
+       }
+
        for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
-               add_bone_node(child, ob_arm);
+               add_bone_node(child, ob_arm, sce, se, child_objects);
        }
        node.end();
        //}
 }
 
-void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
+/*void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
 {
        node.start();
        
@@ -201,11 +246,11 @@ void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADA
        node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2] );
        
        for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
-               add_bone_node(child, ob_arm);
+               add_bone_node(child, ob_arm, sce, se, child_objects);
        }
        node.end();
        
-}
+}*/
 void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
 {
        bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
index 9d64664fa63ff03213d7e233ccf78b321a02af4e..e9ee38d36cf118a6467100b6ab091fc77917f0d3 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef __ARMATUREEXPORTER_H__
 #define __ARMATUREEXPORTER_H__
 
+#include <list>
 #include <string>
 //#include <vector>
 
@@ -47,6 +48,8 @@
 
 #include "ExportSettings.h"
 
+class SceneExporter;
+
 // 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?
@@ -56,7 +59,8 @@ public:
        ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
 
        // write bone nodes
-       void add_armature_bones(Object *ob_arm, Scene *sce);
+       void add_armature_bones(Object *ob_arm, Scene* sce, SceneExporter* se,
+                                                       std::list<Object*>& child_objects);
 
        bool is_skinned_mesh(Object *ob);
 
@@ -85,8 +89,10 @@ private:
 
        std::string get_joint_sid(Bone *bone, Object *ob_arm);
 
-       // parent_mat is armature-space
-       void add_bone_node(Bone *bone, Object *ob_arm);
+       // Scene, SceneExporter and the list of child_objects
+       // are required for writing bone parented objects
+       void add_bone_node(Bone *bone, Object *ob_arm, Scene* sce, SceneExporter* se,
+                                          std::list<Object*>& child_objects);
 
        void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
 
index 5dd452faa41f59d1c34a6d01248b57fdcd113b13..b6be8a57f7a7a7f7614477e99db96a47d93e4c5f 100644 (file)
@@ -77,6 +77,29 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
        node.start();
 
        bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
+       std::list<Object*> child_objects;
+
+       // list child objects
+       Base *b = (Base*) sce->base.first;
+       while(b) {
+               // cob - child object
+               Object *cob = b->object;
+
+               if (cob->parent == ob) {
+                       switch(cob->type) {
+                               case OB_MESH:
+                               case OB_CAMERA:
+                               case OB_LAMP:
+                               case OB_EMPTY:
+                               case OB_ARMATURE:
+                                       child_objects.push_back(cob);
+                                       break;
+                       }
+               }
+
+               b = b->next;
+       }
+
 
        if (ob->type == OB_MESH && is_skinned_mesh)
                // for skinned mesh we write obmat in <bind_shape_matrix>
@@ -101,7 +124,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
 
        // <instance_controller>
        else if (ob->type == OB_ARMATURE) {
-               arm_exporter->add_armature_bones(ob, sce);
+               arm_exporter->add_armature_bones(ob, sce, this, child_objects);
 
                // XXX this looks unstable...
                node.end();
@@ -131,28 +154,12 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
                }
        }
 
-       // write nodes for child objects
-       Base *b = (Base*) sce->base.first;
-       while(b) {
-               // cob - child object
-               Object *cob = b->object;
-
-               if (cob->parent == ob) {
-                       switch(cob->type) {
-                               case OB_MESH:
-                               case OB_CAMERA:
-                               case OB_LAMP:
-                               case OB_EMPTY:
-                               case OB_ARMATURE:
-                                       // write node...
-                                       writeNodes(cob, sce);
-                                       break;
-                       }
-               }
-
-               b = b->next;
+       for(std::list<Object*>::iterator i= child_objects.begin(); i != child_objects.end(); ++i)
+       {
+               writeNodes(*i, sce);
        }
 
+
        if (ob->type != OB_ARMATURE)
                node.end();
 }
index de01eb6e4594040a2c6ddd3d6984ac86a4c266e6..31b471a3e4c9adbb454ecbd78c1555cc1817f270 100644 (file)
@@ -97,6 +97,8 @@ public:
        void exportScene(Scene *sce);
 
 private:
+       // required for writeNodes() for bone-parented objects
+       friend class ArmatureExporter;
        void exportHierarchy(Scene *sce);
        void writeNodes(Object *ob, Scene *sce);