BGE patch: Add automatic support for armature driven shape keys.
authorBenoit Bolsee <benoit.bolsee@online.be>
Tue, 24 Jun 2008 22:19:00 +0000 (22:19 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Tue, 24 Jun 2008 22:19:00 +0000 (22:19 +0000)
To take advantage of this feature, you must have a mesh with
relative shape keys and shape Ipo curves with drivers referring
to bones of the mesh's parent armature.
The BGE will automatically detect the dependency between the
shape keys and the armature and execute the Ipo drivers during
the rendering of the armature actions.
This technique is used to make the armature action more natural:
the shape keys compensate in places where the armature deformation
is uggly and the drivers make sure that the shape correction
is synchronized with the bone position.

Note: This is not compatible with shape actions; BLender does
not allow to have Shape Ipo Curves and Shape actions at the same
time.

source/blender/blenkernel/BKE_ipo.h
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/BL_ShapeDeformer.cpp
source/gameengine/Converter/BL_ShapeDeformer.h
source/gameengine/Converter/BL_SkinDeformer.cpp
source/gameengine/Converter/BL_SkinDeformer.h
source/gameengine/Ketsji/KX_Scene.cpp

index 922f320134578b1bb39225bb6b49e4330ded83ae..5b209cb8f5b80838d71f4a486618936271e76f05 100644 (file)
 #ifndef BKE_IPO_H
 #define BKE_IPO_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct CfraElem {
        struct CfraElem *next, *prev;
        float cfra;
@@ -111,5 +115,9 @@ float IPO_GetFloatValue(struct Ipo *ipo,
                                                short c,
                                                float ctime);
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif
 
index 1bde5ad345049ccf3e7c399160f1a54683373ca5..665783a1ba51ac9f5ed50a3022a143e774f1aa6b 100644 (file)
@@ -1668,6 +1668,8 @@ static KX_GameObject *gameobject_from_blenderobject(
                        BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj, 
                                                                                                                        ob, (BL_SkinMeshObject*)meshobj);
                        ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
+                       if (bHasArmature)
+                               dcont->LoadShapeDrivers(ob->parent);
                } else if (bHasArmature) {
                        BL_SkinDeformer *dcont = new BL_SkinDeformer(ob, (BL_SkinMeshObject*)meshobj );                         
                        ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
index 3ae634905b91df83f70f2e39352cbaed584ac9a4..eb5c1467ea5db0dcd8ea0f144b93f54955ba5030 100644 (file)
 #include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_curve_types.h"
 #include "BKE_armature.h"
 #include "BKE_action.h"
 #include "BKE_key.h"
+#include "BKE_ipo.h"
 #include "MT_Point3.h"
 
 extern "C"{
@@ -78,11 +81,55 @@ void BL_ShapeDeformer::ProcessReplica()
 {
 }
 
+bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma)
+{
+       IpoCurve *icu;
+
+       m_shapeDrivers.clear();
+       // check if this mesh has armature driven shape keys
+       if (m_bmesh->key->ipo) {
+               for(icu= (IpoCurve*)m_bmesh->key->ipo->curve.first; icu; icu= (IpoCurve*)icu->next) {
+                       if(icu->driver && 
+                               (icu->flag & IPO_MUTE) == 0 &&
+                               icu->driver->type == IPO_DRIVER_TYPE_NORMAL &&
+                               icu->driver->ob == arma &&
+                               icu->driver->blocktype == ID_AR) {
+                               // this shape key ipo curve has a driver on the parent armature
+                               // record this curve in the shape deformer so that the corresponding
+                               m_shapeDrivers.push_back(icu);
+                       }
+               }
+       }
+       return !m_shapeDrivers.empty();
+}
+
+bool BL_ShapeDeformer::ExecuteShapeDrivers(void)
+{
+       if (!m_shapeDrivers.empty() && PoseUpdated()) {
+               vector<IpoCurve*>::iterator it;
+               void *poin;
+               int type;
+               for (it=m_shapeDrivers.begin(); it!=m_shapeDrivers.end(); it++) {
+                       // no need to set a specific time: this curve has a driver
+                       IpoCurve *icu = *it;
+                       calc_icu(icu, 1.0f);
+                       poin = get_ipo_poin((ID*)m_bmesh->key, icu, &type);
+                       if (poin) 
+                               write_ipo_poin(poin, type, icu->curval);
+               }
+               ForceUpdate();
+               return true;
+       }
+       return false;
+}
+
 bool BL_ShapeDeformer::Update(void)
 {
        bool bShapeUpdate = false;
        bool bSkinUpdate = false;
 
+       ExecuteShapeDrivers();
+
        /* See if the object shape has changed */
        if (m_lastShapeUpdate != m_gameobj->GetLastFrame()) {
                /* the key coefficient have been set already, we just need to blend the keys */
index 9bbdde3fb2ced8cb624bd1e99bc792f1c3aa1c34..9f8361dbaca58371e0e8703861cab92411be2789 100644 (file)
@@ -38,6 +38,7 @@
 #include "BL_DeformableGameObject.h"
 #include <vector>
 
+struct IpoCurve;
 
 class BL_ShapeDeformer : public BL_SkinDeformer  
 {
@@ -82,8 +83,16 @@ public:
        virtual ~BL_ShapeDeformer();
 
        bool Update (void);
+       bool LoadShapeDrivers(Object* arma);
+       bool ExecuteShapeDrivers(void);
+
+       void ForceUpdate()
+       {
+               m_lastShapeUpdate = -1.0;
+       };
 
 protected:
+       vector<IpoCurve*>                m_shapeDrivers;
        double                                   m_lastShapeUpdate;
        BL_DeformableGameObject* m_gameobj;
 
index 1015221c392c6dd104f5d8b6a7c081f4b013b5f3..dd7119b10317162ab04c334222d37c3c80a89ca9 100644 (file)
@@ -149,12 +149,9 @@ void BL_SkinDeformer::ProcessReplica()
 bool BL_SkinDeformer::Update(void)
 {
        /* See if the armature has been updated for this frame */
-       if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()){    
+       if (PoseUpdated()){     
                float obmat[4][4];      // the original object matrice 
                
-               /* Do all of the posing necessary */
-               m_armobj->ApplyPose();
-               
                /* XXX note: where_is_pose() (from BKE_armature.h) calculates all matrices needed to start deforming */
                /* but it requires the blender object pointer... */
 
index 603e716fb1e2d31aed31d9df94af42d9b40e0a31..c5568c049cbda6535989f1e29b40ce63bf56e6a2 100644 (file)
@@ -79,6 +79,14 @@ public:
        virtual ~BL_SkinDeformer();
        bool Update (void);
        bool Apply (class RAS_IPolyMaterial *polymat);
+       bool PoseUpdated(void)
+               { 
+                       if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()) {
+                               m_armobj->ApplyPose();
+                               return true;
+                       }
+                       return false;
+               }
 
        void ForceUpdate()
        {
index 1526709f42582a61f858b4e91070bbabba8b794e..a7e91e27df342626dd9d22c4138095ff28050fa2 100644 (file)
@@ -866,6 +866,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj)
                                                static_cast<BL_ArmatureObject*>( parentobj )
                                        );
                                        releaseParent= false;
+                                       shapeDeformer->LoadShapeDrivers(blendobj->parent);
                                }
                                else
                                {