From fe05f97841c0ee3e2a6e15f2252ad160fefc3509 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Sun, 6 Apr 2014 16:30:59 -0700 Subject: BGE: Multi-threading animation updates and skinning. 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). --- source/gameengine/Converter/BL_ActionActuator.cpp | 13 +-- source/gameengine/Converter/BL_ActionActuator.h | 3 - .../gameengine/Converter/BL_ArmatureActuator.cpp | 2 +- source/gameengine/Converter/BL_ArmatureObject.cpp | 127 ++++++--------------- source/gameengine/Converter/BL_ArmatureObject.h | 24 ++-- .../Converter/BL_BlenderDataConversion.cpp | 21 +++- source/gameengine/Converter/BL_ShapeDeformer.cpp | 29 ++++- source/gameengine/Converter/BL_ShapeDeformer.h | 2 +- source/gameengine/Converter/BL_SkinDeformer.cpp | 88 +++++++------- source/gameengine/Ketsji/BL_Action.cpp | 57 +++++---- source/gameengine/Ketsji/BL_Action.h | 2 +- source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 6 + source/gameengine/Ketsji/KX_KetsjiEngine.h | 6 + source/gameengine/Ketsji/KX_Scene.cpp | 92 +++++++++------ 14 files changed, 225 insertions(+), 247 deletions(-) (limited to 'source/gameengine') diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index a28906254a1..34d36846968 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -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; diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index 4579a21f554..f488b0c76a6 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -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; diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp index f0c4b3d32bb..e38cb6eadaf 100644 --- a/source/gameengine/Converter/BL_ArmatureActuator.cpp +++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp @@ -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) diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 619797a8c69..3eb782961e3 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -42,7 +42,13 @@ #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(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 (prioritySetBlendTime(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; } diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 81388355fc4..691e73d6bde 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -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 *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__ */ diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 4b55d73178c..b283330266f 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -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;iGetCount();++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; jGetCount();++j) + { + BL_ShapeDeformer *deform = dynamic_cast(((KX_GameObject*)children->GetValue(j))->GetDeformer()); + if (deform) + deform->LoadShapeDrivers(armobj); + } + + children->Release(); + } } bool processCompoundChildren = false; diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index ca5b26079b1..43f719d80c4 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -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; } diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index a506fb9c7f6..f6746dd2302 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -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(); diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index e068a91bf7e..8e1f51238d5 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -152,44 +152,8 @@ void BL_SkinDeformer::Relink(CTR_Map*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; imatGetMeshMaterial(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; itotvert; 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; imatGetMeshMaterial(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; iGetGameObjectType() == 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_blendframeBlendInPose(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) diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index e9d09916517..463d177c876 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -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 m_sg_contr_list; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 231590cde83..96a3845a439 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -37,6 +37,8 @@ #include #include +#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); } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 85cd8bba2de..9e5d1893320 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -42,6 +42,7 @@ #include "KX_WorldInfo.h" #include +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(); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index a9ac13c755f..fbd9eeba8ed 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -102,6 +102,8 @@ #include +#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( 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( 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; iGetCount(); ++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; jGetCount(); ++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; jGetCount(); ++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; jGetCount(); ++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; iGetCount(); ++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) -- cgit v1.2.3