BGE: Multi-threading animation updates and skinning.
authorMitchell Stokes <mogurijin@gmail.com>
Sun, 6 Apr 2014 23:30:59 +0000 (16:30 -0700)
committerMitchell Stokes <mogurijin@gmail.com>
Sun, 6 Apr 2014 23:30:59 +0000 (16:30 -0700)
This required BL_ArmatureObject to have tighter control over armatures and poses.
Also, (Blender) armature objects are now copied instead of shared between
BL_ArmatureObjects to avoid race conditions. Also, due to the armature copy,
shape key drivers need a bit of extra fiddling to get the correct armature copy.

Initially OpenMP was used for threading, but then BLI_task was used due to being
less compiler dependent.

This commit also places time spent on skinning updates in the Animation
profiler category (was previously under the Rasterizer category).

14 files changed:
source/gameengine/Converter/BL_ActionActuator.cpp
source/gameengine/Converter/BL_ActionActuator.h
source/gameengine/Converter/BL_ArmatureActuator.cpp
source/gameengine/Converter/BL_ArmatureObject.cpp
source/gameengine/Converter/BL_ArmatureObject.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/Ketsji/BL_Action.cpp
source/gameengine/Ketsji/BL_Action.h
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.h
source/gameengine/Ketsji/KX_Scene.cpp

index a28906254a1edbf5b3cf91fcaf81390c029be164..34d3684696865b5698f9a9357d2293b14e7fda53 100644 (file)
@@ -93,9 +93,6 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj,
        m_priority(priority),
        m_layer(layer),
        m_ipo_flags(ipo_flags),
-       m_pose(NULL),
-       m_blendpose(NULL),
-       m_userpose(NULL),
        m_action(action),
        m_propname(propname),
        m_framepropname(framepropname)
@@ -106,20 +103,12 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj,
 
 BL_ActionActuator::~BL_ActionActuator()
 {
-       if (m_pose)
-               game_free_pose(m_pose);
-       if (m_userpose)
-               game_free_pose(m_userpose);
-       if (m_blendpose)
-               game_free_pose(m_blendpose);
 }
 
 void BL_ActionActuator::ProcessReplica()
 {
        SCA_IActuator::ProcessReplica();
-       
-       m_pose = NULL;
-       m_blendpose = NULL;
+
        m_localtime=m_startframe;
        m_lastUpdate=-1;
        
index 4579a21f5544beea91d695bc602559eb572920e2..f488b0c76a6126ae536c3e885dfcbbca1cf4fd19 100644 (file)
@@ -134,9 +134,6 @@ protected:
        short   m_priority;
        short   m_layer;
        short   m_ipo_flags;
-       struct bPose* m_pose;
-       struct bPose* m_blendpose;
-       struct bPose* m_userpose;
        struct bAction *m_action;
        STR_String      m_propname;
        STR_String      m_framepropname;
index f0c4b3d32bb349f13f65c46e067ac3e610863e96..e38cb6eadaf3a49651245594ac609706ab3d00cd 100644 (file)
@@ -155,7 +155,7 @@ bool BL_ArmatureActuator::Update(double curtime, bool frame)
                switch (m_type) {
                case ACT_ARM_RUN:
                        result = true;
-                       obj->SetActiveAction(NULL, 0, curtime);
+                       obj->UpdateTimestep(curtime);
                        break;
                case ACT_ARM_ENABLE:
                        if (m_constraint)
index 619797a8c69cc8cd37c22f8803dfbda98ba47777..3eb782961e3b780a30fffa365566acaa6ee5161e 100644 (file)
 #include "BIK_api.h"
 #include "BKE_action.h"
 #include "BKE_armature.h"
+#include "BKE_object.h"
 #include "BKE_library.h"
+#include "BKE_global.h"
+
+extern "C" {
+#include "BKE_animsys.h"
+}
 
 #include "BKE_constraint.h"
 #include "CTR_Map.h"
@@ -53,6 +59,7 @@
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_constraint_types.h"
+#include "RNA_access.h"
 #include "KX_PythonSeq.h"
 #include "KX_PythonInit.h"
 #include "KX_KetsjiEngine.h"
@@ -70,7 +77,7 @@
  * When it is about to evaluate the pose, set the KX object position in the obmat of the corresponding
  * Blender objects and restore after the evaluation.
  */
-void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
+static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
 {
        bPose *out;
        bPoseChannel *pchan, *outpchan;
@@ -85,7 +92,7 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
                return;
        }
        else if (*dst==src) {
-               printf("BKE_pose_copy_data source and target are the same\n");
+               printf("game_copy_pose source and target are the same\n");
                *dst=NULL;
                return;
        }
@@ -142,7 +149,7 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
 
 
 /* Only allowed for Poses with identical channels */
-void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
+static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
 {
        bPoseChannel *dchan;
        const bPoseChannel *schan;
@@ -202,23 +209,6 @@ void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
        dst->ctime= src->ctime;
 }
 
-void game_free_pose(bPose *pose)
-{
-       if (pose) {
-               /* free pose-channels and constraints */
-               BKE_pose_channels_free(pose);
-               
-               /* free IK solver state */
-               BIK_clear_data(pose);
-
-               /* free IK solver param */
-               if (pose->ikparam)
-                       MEM_freeN(pose->ikparam);
-
-               MEM_freeN(pose);
-       }
-}
-
 BL_ArmatureObject::BL_ArmatureObject(
                                void* sgReplicationInfo, 
                                SG_Callbacks callbacks, 
@@ -229,26 +219,18 @@ BL_ArmatureObject::BL_ArmatureObject(
 :      KX_GameObject(sgReplicationInfo,callbacks),
        m_controlledConstraints(),
        m_poseChannels(),
-       m_objArma(armature),
-       m_framePose(NULL),
        m_scene(scene), // maybe remove later. needed for BKE_pose_where_is
        m_lastframe(0.0),
        m_timestep(0.040),
-       m_activeAct(NULL),
-       m_activePriority(999),
        m_vert_deform_type(vert_deform_type),
        m_constraintNumber(0),
        m_channelNumber(0),
        m_lastapplyframe(0.0)
 {
-       m_armature = (bArmature *)armature->data;
-
-       /* we make a copy of blender object's pose, and then always swap it with
-        * the original pose before calling into blender functions, to deal with
-        * replica's or other objects using the same blender object */
-       m_pose = NULL;
-       game_copy_pose(&m_pose, m_objArma->pose, 1);
-       // store the original armature object matrix
+       m_origObjArma = armature; // Keep a copy of the original armature so we can fix drivers later
+       m_objArma = BKE_object_copy(armature);
+       m_objArma->data = BKE_armature_copy((bArmature *)armature->data);
+       m_pose = m_objArma->pose;
        memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat));
 }
 
@@ -262,10 +244,9 @@ BL_ArmatureObject::~BL_ArmatureObject()
        while ((channel = static_cast<BL_ArmatureChannel*>(m_poseChannels.Remove())) != NULL) {
                delete channel;
        }
-       if (m_pose)
-               game_free_pose(m_pose);
-       if (m_framePose)
-               game_free_pose(m_framePose);
+
+       if (m_objArma)
+               BKE_libblock_free(G.main, m_objArma);
 }
 
 
@@ -431,12 +412,12 @@ CValue* BL_ArmatureObject::GetReplica()
 
 void BL_ArmatureObject::ProcessReplica()
 {
-       bPose *pose= m_pose;
        KX_GameObject::ProcessReplica();
 
-       m_pose = NULL;
-       m_framePose = NULL;
-       game_copy_pose(&m_pose, pose, 1);
+       bArmature* tmp = (bArmature*)m_objArma->data;
+       m_objArma = BKE_object_copy(m_objArma);
+       m_objArma->data = BKE_armature_copy(tmp);
+       m_pose = m_objArma->pose;
 }
 
 void BL_ArmatureObject::ReParentLogic()
@@ -506,48 +487,32 @@ void BL_ArmatureObject::SetPose(bPose *pose)
        m_lastapplyframe = -1.0;
 }
 
-bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, double curtime)
+void BL_ArmatureObject::SetPoseByAction(bAction *action, float localtime)
+{
+       Object *arm = GetArmatureObject();
+
+       PointerRNA ptrrna;
+       RNA_id_pointer_create(&arm->id, &ptrrna);
+
+       animsys_evaluate_action(&ptrrna, action, NULL, localtime);
+}
+
+void BL_ArmatureObject::BlendInPose(bPose *blend_pose, float weight, short mode)
+{
+       game_blend_poses(m_pose, blend_pose, weight, mode);
+}
+
+bool BL_ArmatureObject::UpdateTimestep(double curtime)
 {
        if (curtime != m_lastframe) {
-               m_activePriority = 9999;
                // compute the timestep for the underlying IK algorithm
                m_timestep = curtime-m_lastframe;
                m_lastframe= curtime;
-               m_activeAct = NULL;
-               // remember the pose at the start of the frame
-               GetPose(&m_framePose);
        }
 
-       if (act) 
-       {
-               if (priority<=m_activePriority)
-               {
-                       if (priority<m_activePriority) {
-                               // this action overwrites the previous ones, start from initial pose to cancel their effects
-                               SetPose(m_framePose);
-                               if (m_activeAct && (m_activeAct!=act))
-                                       /* Reset the blend timer since this new action cancels the old one */
-                                       m_activeAct->SetBlendTime(0.0);
-                       }
-                       m_activeAct = act;
-                       m_activePriority = priority;
-                       m_lastframe = curtime;
-               
-                       return true;
-               }
-               else {
-                       act->SetBlendTime(0.0);
-                       return false;
-               }
-       }
        return false;
 }
 
-BL_ActionActuator * BL_ArmatureObject::GetActiveAction()
-{
-       return m_activeAct;
-}
-
 void BL_ArmatureObject::GetPose(bPose **pose)
 {
        /* If the caller supplies a null pose, create a new one. */
@@ -570,22 +535,6 @@ void BL_ArmatureObject::GetPose(bPose **pose)
        }
 }
 
-void BL_ArmatureObject::GetMRDPose(bPose **pose)
-{
-       /* If the caller supplies a null pose, create a new one. */
-       /* Otherwise, copy the armature's pose channels into the caller-supplied pose */
-
-       if (!*pose)
-               game_copy_pose(pose, m_pose, 0);
-       else
-               extract_pose_from_pose(*pose, m_pose);
-}
-
-short BL_ArmatureObject::GetActivePriority()
-{
-       return m_activePriority;
-}
-
 double BL_ArmatureObject::GetLastFrame()
 {
        return m_lastframe;
@@ -671,7 +620,7 @@ KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update,
                                                  "This is automatically done if a KX_ArmatureActuator with mode run is active\n"
                                                  "or if an action is playing. This function is useful in other cases.\n")
 {
-       SetActiveAction(NULL, 0, KX_GetActiveEngine()->GetFrameTime());
+       UpdateTimestep(KX_GetActiveEngine()->GetFrameTime());
        Py_RETURN_NONE;
 }
 
index 81388355fc4f44fcbddb8f09fb26e47e8c5f45ea..691e73d6bde8900eb5cc6f589c8e8be1373f0752 100644 (file)
@@ -55,14 +55,11 @@ class BL_ArmatureObject : public KX_GameObject
 public:
 
        double GetLastFrame ();
-       short GetActivePriority();
        virtual void ProcessReplica();
        virtual void ReParentLogic();
        virtual void Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map);
        virtual bool UnlinkObject(SCA_IObject* clientobj);
 
-       class BL_ActionActuator * GetActiveAction();
-       
        BL_ArmatureObject(
                void* sgReplicationInfo,
                SG_Callbacks callbacks,
@@ -73,21 +70,23 @@ public:
        virtual ~BL_ArmatureObject();
 
        virtual CValue* GetReplica();
-       void GetMRDPose(struct bPose **pose);
        void GetPose(struct bPose **pose);
        void SetPose (struct bPose *pose);
        struct bPose *GetOrigPose() {return m_pose;} // never edit this, only for accessing names
 
        void ApplyPose();
+       void SetPoseByAction(struct bAction* action, float localtime);
+       void BlendInPose(struct bPose *blend_pose, float weight, short mode);
        void RestorePose();
 
-       bool SetActiveAction(class BL_ActionActuator *act, short priority, double curtime);
+       bool UpdateTimestep(double curtime);
        
-       struct bArmature *GetArmature() { return m_armature; }
-       const struct bArmature * GetArmature() const { return m_armature; }
+       struct bArmature *GetArmature() { return (bArmature*)m_objArma->data; }
+       const struct bArmature * GetArmature() const { return (bArmature*)m_objArma->data; }
        const struct Scene * GetScene() const { return m_scene; }
        
        Object* GetArmatureObject() {return m_objArma;}
+       Object* GetOrigArmatureObject() {return m_origObjArma;}
 
        int GetVertDeformType() {return m_vert_deform_type;}
 
@@ -128,15 +127,12 @@ protected:
        /* list element: BL_ArmatureChannel. Use SG_DList to avoid list replication */
        SG_DList                        m_poseChannels;
        Object                          *m_objArma;
-       struct bArmature        *m_armature;
+       Object                          *m_origObjArma;
        struct bPose            *m_pose;
        struct bPose            *m_armpose;
-       struct bPose            *m_framePose;
        struct Scene            *m_scene; // need for BKE_pose_where_is 
        double  m_lastframe;
        double  m_timestep;             // delta since last pose evaluation.
-       class BL_ActionActuator *m_activeAct;
-       short   m_activePriority;
        int             m_vert_deform_type;
        size_t  m_constraintNumber;
        size_t  m_channelNumber;
@@ -146,10 +142,4 @@ protected:
        double                  m_lastapplyframe;
 };
 
-/* Pose function specific to the game engine */
-void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); /* was blend_poses */
-//void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
-void game_copy_pose(struct bPose **dst, struct bPose *src, int copy_con);
-void game_free_pose(struct bPose *pose);
-
 #endif  /* __BL_ARMATUREOBJECT_H__ */
index 4b55d73178cb20776ad6d640bdf21d086c9a575e..b283330266fc338f0ed1a1af92e84c660f363943 100644 (file)
@@ -1937,15 +1937,11 @@ static KX_GameObject *gameobject_from_blenderobject(
                        BL_ModifierDeformer *dcont = new BL_ModifierDeformer((BL_DeformableGameObject *)gameobj,
                                                                                                                                kxscene->GetBlenderScene(), ob, meshobj);
                        ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
-                       if (bHasShapeKey && bHasArmature)
-                               dcont->LoadShapeDrivers(ob->parent);
                } else if (bHasShapeKey) {
                        // not that we can have shape keys without dvert! 
                        BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj, 
                                                                                                                        ob, meshobj);
                        ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
-                       if (bHasArmature)
-                               dcont->LoadShapeDrivers(ob->parent);
                } else if (bHasArmature) {
                        BL_SkinDeformer *dcont = new BL_SkinDeformer((BL_DeformableGameObject*)gameobj,
                                                                                                                        ob, meshobj);
@@ -2640,12 +2636,25 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                        gameobj->GetDeformer()->UpdateBuckets();
        }
 
-       // Set up armature constraints
+       // Set up armature constraints and shapekey drivers
        for (i=0;i<sumolist->GetCount();++i)
        {
                KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
                if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
-                       ((BL_ArmatureObject*)gameobj)->LoadConstraints(converter);
+               {
+                       BL_ArmatureObject *armobj = (BL_ArmatureObject*)gameobj;
+                       armobj->LoadConstraints(converter);
+
+                       CListValue *children = armobj->GetChildren();
+                       for (int j=0; j<children->GetCount();++j)
+                       {
+                               BL_ShapeDeformer *deform = dynamic_cast<BL_ShapeDeformer*>(((KX_GameObject*)children->GetValue(j))->GetDeformer());
+                               if (deform)
+                                       deform->LoadShapeDrivers(armobj);
+                       }
+
+                       children->Release();
+               }
        }
 
        bool processCompoundChildren = false;
index ca5b26079b1adf4520977fa35b350a34bfe50eed..43f719d80c4363fe867f7f1e615f4838129665fc 100644 (file)
@@ -51,6 +51,7 @@
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_key.h"
+#include "BKE_fcurve.h"
 #include "BKE_ipo.h"
 #include "BKE_library.h"
 #include "MT_Point3.h"
@@ -119,8 +120,29 @@ void BL_ShapeDeformer::ProcessReplica()
        m_key = BKE_key_copy(m_key);
 }
 
-bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma)
+bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent)
 {
+       // Fix drivers since BL_ArmatureObject makes copies
+       if (parent->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+               BL_ArmatureObject *arma = (BL_ArmatureObject*)parent;
+               FCurve *fcu;
+
+               for (fcu = (FCurve*)GetKey()->adt->drivers.first; fcu; fcu = (FCurve*)fcu->next) {
+
+                       DriverVar *dvar;
+                       for (dvar = (DriverVar*)fcu->driver->variables.first; dvar; dvar = (DriverVar*)dvar->next) {
+                               DRIVER_TARGETS_USED_LOOPER(dvar)
+                               {
+                                       if (dtar->id) {
+                                               if ((Object*)dtar->id == arma->GetOrigArmatureObject())
+                                                       dtar->id = (ID*)arma->GetArmatureObject();
+                                       }
+                               }
+                               DRIVER_TARGETS_LOOPER_END
+                       }
+               }
+       }
+
        // This used to check if we had drivers from this armature,
        // now we just assume we want to use shape drivers
        // and let the animsys handle things.
@@ -132,15 +154,10 @@ bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma)
 bool BL_ShapeDeformer::ExecuteShapeDrivers(void)
 {
        if (m_useShapeDrivers && PoseUpdated()) {
-               // the shape drivers use the bone matrix as input. Must 
-               // update the matrix now
-               m_armobj->ApplyPose();
-
                // We don't need an actual time, just use 0
                BKE_animsys_evaluate_animdata(NULL, &GetKey()->id, GetKey()->adt, 0.f, ADT_RECALC_DRIVERS);
 
                ForceUpdate();
-               m_armobj->RestorePose();
                m_bDynamic = true;
                return true;
        }
index a506fb9c7f6ecf3cf464cbec2e59f26962d87f11..f6746dd2302a9054225952829aedca4ed81f3fe9 100644 (file)
@@ -61,7 +61,7 @@ public:
        virtual ~BL_ShapeDeformer();
 
        bool Update (void);
-       bool LoadShapeDrivers(Object* arma);
+       bool LoadShapeDrivers(KX_GameObject* parent);
        bool ExecuteShapeDrivers(void);
 
        struct Key *GetKey();
index e068a91bf7e1a076707544fd2d040340e0f7777b..8e1f51238d5dc190135d77b56a96afbb179d295e 100644 (file)
@@ -152,44 +152,8 @@ void BL_SkinDeformer::Relink(CTR_Map<class CTR_HashedPtr, void*>*map)
 
 bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat)
 {
-       RAS_MeshSlot::iterator it;
-       RAS_MeshMaterial *mmat;
-       RAS_MeshSlot *slot;
-       size_t i, nmat, imat;
-
-       // update the vertex in m_transverts
-       if (!Update())
-               return false;
-
-       if (m_transverts) {
-               // the vertex cache is unique to this deformer, no need to update it
-               // if it wasn't updated! We must update all the materials at once
-               // because we will not get here again for the other material
-               nmat = m_pMeshObject->NumMaterials();
-               for (imat=0; imat<nmat; imat++) {
-                       mmat = m_pMeshObject->GetMeshMaterial(imat);
-                       if (!mmat->m_slots[(void*)m_gameobj])
-                               continue;
-
-                       slot = *mmat->m_slots[(void*)m_gameobj];
-
-                       // for each array
-                       for (slot->begin(it); !slot->end(it); slot->next(it)) {
-                               // for each vertex
-                               // copy the untransformed data from the original mvert
-                               for (i=it.startvertex; i<it.endvertex; i++) {
-                                       RAS_TexVert& v = it.vertex[i];
-                                       v.SetXYZ(m_transverts[v.getOrigIndex()]);
-                                       if (m_copyNormals)
-                                               v.SetNormal(m_transnors[v.getOrigIndex()]);
-                               }
-                       }
-               }
-
-               if (m_copyNormals)
-                       m_copyNormals = false;
-       }
-       return true;
+       // We do everything in UpdateInternal() now so we can thread it.
+       return false;
 }
 
 RAS_Deformer *BL_SkinDeformer::GetReplica()
@@ -331,7 +295,7 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied)
                if (!shape_applied) {
                        /* store verts locally */
                        VerifyStorage();
-               
+
                        /* duplicate */
                        for (int v =0; v<m_bmesh->totvert; v++)
                        {
@@ -342,15 +306,10 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied)
 
                m_armobj->ApplyPose();
 
-               switch (m_armobj->GetVertDeformType())
-               {
-                       case ARM_VDEF_BGE_CPU:
-                               BGEDeformVerts();
-                               break;
-                       case ARM_VDEF_BLENDER:
-                       default:
-                               BlenderDeformVerts();
-               }
+               if (m_armobj->GetVertDeformType() == ARM_VDEF_BGE_CPU)
+                       BGEDeformVerts();
+               else
+                       BlenderDeformVerts();
 
                /* Update the current frame */
                m_lastArmaUpdate=m_armobj->GetLastFrame();
@@ -359,6 +318,39 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied)
                /* dynamic vertex, cannot use display list */
                m_bDynamic = true;
                /* indicate that the m_transverts and normals are up to date */
+               RAS_MeshSlot::iterator it;
+               RAS_MeshMaterial *mmat;
+               RAS_MeshSlot *slot;
+               size_t i, nmat, imat;
+
+               if (m_transverts) {
+                       // the vertex cache is unique to this deformer, no need to update it
+                       // if it wasn't updated! We must update all the materials at once
+                       // because we will not get here again for the other material
+                       nmat = m_pMeshObject->NumMaterials();
+                       for (imat=0; imat<nmat; imat++) {
+                               mmat = m_pMeshObject->GetMeshMaterial(imat);
+                               if (!mmat->m_slots[(void*)m_gameobj])
+                                       continue;
+
+                               slot = *mmat->m_slots[(void*)m_gameobj];
+
+                               // for each array
+                               for (slot->begin(it); !slot->end(it); slot->next(it)) {
+                                       // for each vertex
+                                       // copy the untransformed data from the original mvert
+                                       for (i=it.startvertex; i<it.endvertex; i++) {
+                                               RAS_TexVert& v = it.vertex[i];
+                                               v.SetXYZ(m_transverts[v.getOrigIndex()]);
+                                               if (m_copyNormals)
+                                                       v.SetNormal(m_transnors[v.getOrigIndex()]);
+                                       }
+                               }
+                       }
+
+                       if (m_copyNormals)
+                               m_copyNormals = false;
+               }
                return true;
        }
 
index a974ffbf672c51f9cb646ed9ae4eafe081181794..e4ab2d5ce28b8216293989bd926e1aa4781d51a7 100644 (file)
@@ -51,10 +51,14 @@ extern "C" {
 #include "DNA_material_types.h"
 }
 
+#include "MEM_guardedalloc.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+
 BL_Action::BL_Action(class KX_GameObject* gameobj)
 :
        m_action(NULL),
-       m_pose(NULL),
+       m_tmpaction(NULL),
        m_blendpose(NULL),
        m_blendinpose(NULL),
        m_obj(gameobj),
@@ -77,13 +81,16 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
 
 BL_Action::~BL_Action()
 {
-       if (m_pose)
-               game_free_pose(m_pose);
        if (m_blendpose)
-               game_free_pose(m_blendpose);
+               BKE_pose_free(m_blendpose);
        if (m_blendinpose)
-               game_free_pose(m_blendinpose);
+               BKE_pose_free(m_blendinpose);
        ClearControllerList();
+
+       if (m_tmpaction) {
+               BKE_libblock_free(G.main, m_tmpaction);
+               m_tmpaction = NULL;
+       }
 }
 
 void BL_Action::ClearControllerList()
@@ -139,6 +146,13 @@ bool BL_Action::Play(const char* name,
                        && m_priority == priority && m_speed == playback_speed)
                return false;
 
+       // Keep a copy of the action for threading purposes
+       if (m_tmpaction) {
+               BKE_libblock_free(G.main, m_tmpaction);
+               m_tmpaction = NULL;
+       }
+       m_tmpaction = BKE_action_copy(m_action);
+
        // First get rid of any old controllers
        ClearControllerList();
 
@@ -208,7 +222,7 @@ bool BL_Action::Play(const char* name,
        if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
        {
                BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
-               obj->GetMRDPose(&m_blendinpose);
+               obj->GetPose(&m_blendinpose);
        }
        else
        {
@@ -402,22 +416,12 @@ void BL_Action::Update(float curtime)
        if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
        {
                BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
-               obj->GetPose(&m_pose);
-
-               // Extract the pose from the action
-               {
-                       Object *arm = obj->GetArmatureObject();
-                       bPose *temp = arm->pose;
-
-                       arm->pose = m_pose;
 
-                       PointerRNA ptrrna;
-                       RNA_id_pointer_create(&arm->id, &ptrrna);
-
-                       animsys_evaluate_action(&ptrrna, m_action, NULL, m_localtime);
+               if (m_layer_weight >= 0)
+                       obj->GetPose(&m_blendpose);
 
-                       arm->pose = temp;
-               }
+               // Extract the pose from the action
+               obj->SetPoseByAction(m_tmpaction, m_localtime);
 
                // Handle blending between armature actions
                if (m_blendin && m_blendframe<m_blendin)
@@ -428,20 +432,15 @@ void BL_Action::Update(float curtime)
                        float weight = 1.f - (m_blendframe/m_blendin);
 
                        // Blend the poses
-                       game_blend_poses(m_pose, m_blendinpose, weight, ACT_BLEND_BLEND);
+                       obj->BlendInPose(m_blendinpose, weight, ACT_BLEND_BLEND);
                }
 
 
                // Handle layer blending
                if (m_layer_weight >= 0)
-               {
-                       obj->GetMRDPose(&m_blendpose);
-                       game_blend_poses(m_pose, m_blendpose, m_layer_weight, m_blendmode);
-               }
-
-               obj->SetPose(m_pose);
+                       obj->BlendInPose(m_blendpose, m_layer_weight, m_blendmode);
 
-               obj->SetActiveAction(NULL, 0, curtime);
+               obj->UpdateTimestep(curtime);
        }
        else
        {
@@ -456,7 +455,7 @@ void BL_Action::Update(float curtime)
                        PointerRNA ptrrna;
                        RNA_id_pointer_create(&key->id, &ptrrna);
 
-                       animsys_evaluate_action(&ptrrna, m_action, NULL, m_localtime);
+                       animsys_evaluate_action(&ptrrna, m_tmpaction, NULL, m_localtime);
 
                        // Handle blending between shape actions
                        if (m_blendin && m_blendframe < m_blendin)
index e9d099165175701ec286a26b60699517078ca47a..463d177c8764aaeccd581a0293ce37428ba2fbdd 100644 (file)
@@ -38,7 +38,7 @@ class BL_Action
 {
 private:
        struct bAction* m_action;
-       struct bPose* m_pose;
+       struct bAction* m_tmpaction;
        struct bPose* m_blendpose;
        struct bPose* m_blendinpose;
        std::vector<class SG_Controller*> m_sg_contr_list;
index 231590cde830289632fd11e3d1933f44a95dc30b..96a3845a4390bf79fcb76c7eb09f27a8553b9c53 100644 (file)
@@ -37,6 +37,8 @@
 #include <iostream>
 #include <stdio.h>
 
+#include "BLI_task.h"
+
 #include "KX_KetsjiEngine.h"
 
 #include "ListValue.h"
@@ -185,6 +187,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
        m_pyprofiledict = PyDict_New();
 #endif
 
+       m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
 }
 
 
@@ -201,6 +204,9 @@ KX_KetsjiEngine::~KX_KetsjiEngine()
 #ifdef WITH_PYTHON
        Py_CLEAR(m_pyprofiledict);
 #endif
+
+       if (m_taskscheduler)
+               BLI_task_scheduler_free(m_taskscheduler);
 }
 
 
index 85cd8bba2de419959bb08be23c0f812005f7b679..9e5d18933203e6ae97117ccc42409be76cd1ba7d 100644 (file)
@@ -42,6 +42,7 @@
 #include "KX_WorldInfo.h"
 #include <vector>
 
+struct TaskScheduler;
 class KX_TimeCategoryLogger;
 
 #define LEFT_EYE  1
@@ -195,6 +196,9 @@ private:
        /** Settings that doesn't go away with Game Actuator */
        GlobalSettings m_globalsettings;
 
+       /** Task scheduler for multi-threading */
+       TaskScheduler* m_taskscheduler;
+
        void                                    RenderFrame(KX_Scene* scene, KX_Camera* cam);
        void                                    PostRenderScene(KX_Scene* scene);
        void                                    RenderDebugProperties();
@@ -225,6 +229,8 @@ public:
        SCA_IInputDevice*               GetKeyboardDevice() { return m_keyboarddevice; }
        SCA_IInputDevice*               GetMouseDevice() { return m_mousedevice; }
 
+       TaskScheduler*                  GetTaskScheduler() { return m_taskscheduler; }
+
        /// Dome functions
        void                    InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text); 
        void                    EndDome();
index a9ac13c755f3faebf526a980abb3abfd347b9b1d..fbd9eeba8ed673472dbe961a80ab1bf6e1d5ef4c 100644 (file)
 
 #include <stdio.h>
 
+#include "BLI_task.h"
+
 static void *KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene)
 {
        KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj);
@@ -1196,7 +1198,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
                                                static_cast<BL_ArmatureObject*>( parentobj )
                                        );
                                        releaseParent= false;
-                                       modifierDeformer->LoadShapeDrivers(blendobj->parent);
+                                       modifierDeformer->LoadShapeDrivers(parentobj);
                                }
                                else
                                {
@@ -1224,7 +1226,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
                                                static_cast<BL_ArmatureObject*>( parentobj )
                                        );
                                        releaseParent= false;
-                                       shapeDeformer->LoadShapeDrivers(blendobj->parent);
+                                       shapeDeformer->LoadShapeDrivers(parentobj);
                                }
                                else
                                {
@@ -1596,52 +1598,74 @@ void KX_Scene::AddAnimatedObject(CValue* gameobj)
        m_animatedlist->Add(gameobj);
 }
 
-void KX_Scene::UpdateAnimations(double curtime)
+static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
 {
-       KX_GameObject *gameobj;
+       KX_GameObject *gameobj, *child;
+       CListValue *children;
        bool needs_update;
+       double curtime = *(double*)BLI_task_pool_userdata(pool);
 
-       for (int i=0; i<m_animatedlist->GetCount(); ++i) {
-               gameobj = (KX_GameObject*)m_animatedlist->GetValue(i);
-
-               // Non-armature updates are fast enough, so just update them
-               needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE;
+       gameobj = (KX_GameObject*)taskdata;
 
-               if (!needs_update) {
-                       // If we got here, we're looking to update an armature, so check its children meshes
-                       // to see if we need to bother with a more expensive pose update
-                       CListValue *children = gameobj->GetChildren();
-                       KX_GameObject *child;
+       // Non-armature updates are fast enough, so just update them
+       needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE;
 
-                       bool has_mesh = false, has_non_mesh = false;
+       if (!needs_update) {
+               // If we got here, we're looking to update an armature, so check its children meshes
+               // to see if we need to bother with a more expensive pose update
+               children = gameobj->GetChildren();
 
-                       // Check for meshes that haven't been culled
-                       for (int j=0; j<children->GetCount(); ++j) {
-                               child = (KX_GameObject*)children->GetValue(j);
+               bool has_mesh = false, has_non_mesh = false;
 
-                               if (!child->GetCulled()) {
-                                       needs_update = true;
-                                       break;
-                               }
+               // Check for meshes that haven't been culled
+               for (int j=0; j<children->GetCount(); ++j) {
+                       child = (KX_GameObject*)children->GetValue(j);
 
-                               if (child->GetMeshCount() == 0)
-                                       has_non_mesh = true;
-                               else
-                                       has_mesh = true;
+                       if (!child->GetCulled()) {
+                               needs_update = true;
+                               break;
                        }
 
-                       // If we didn't find a non-culled mesh, check to see
-                       // if we even have any meshes, and update if this
-                       // armature has only non-mesh children.
-                       if (!needs_update && !has_mesh && has_non_mesh)
-                               needs_update = true;
+                       if (child->GetMeshCount() == 0)
+                               has_non_mesh = true;
+                       else
+                               has_mesh = true;
+               }
+
+               // If we didn't find a non-culled mesh, check to see
+               // if we even have any meshes, and update if this
+               // armature has only non-mesh children.
+               if (!needs_update && !has_mesh && has_non_mesh)
+                       needs_update = true;
 
-                       children->Release();
+               children->Release();
+       }
+
+       if (needs_update) {
+               gameobj->UpdateActionManager(curtime);
+               children = gameobj->GetChildren();
+
+               for (int j=0; j<children->GetCount(); ++j) {
+                       child = (KX_GameObject*)children->GetValue(j);
+
+                       if (child->GetDeformer())
+                               child->GetDeformer()->Update();
                }
 
-               if (needs_update)
-                       gameobj->UpdateActionManager(curtime);
+               children->Release();
+       }
+}
+
+void KX_Scene::UpdateAnimations(double curtime)
+{
+       TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime);
+
+       for (int i=0; i<m_animatedlist->GetCount(); ++i) {
+               BLI_task_pool_push(pool, update_anim_thread_func, m_animatedlist->GetValue(i), false, TASK_PRIORITY_LOW);
        }
+
+       BLI_task_pool_work_and_wait(pool);
+       BLI_task_pool_free(pool);
 }
 
 void KX_Scene::LogicUpdateFrame(double curtime, bool frame)