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).
This commit is contained in:
parent
be8b4b8b0c
commit
fe05f97841
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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<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,47 +487,31 @@ 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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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())
|
||||
// We do everything in UpdateInternal() now so we can thread it.
|
||||
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;
|
||||
}
|
||||
|
||||
RAS_Deformer *BL_SkinDeformer::GetReplica()
|
||||
@ -342,15 +306,10 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied)
|
||||
|
||||
m_armobj->ApplyPose();
|
||||
|
||||
switch (m_armobj->GetVertDeformType())
|
||||
{
|
||||
case ARM_VDEF_BGE_CPU:
|
||||
if (m_armobj->GetVertDeformType() == ARM_VDEF_BGE_CPU)
|
||||
BGEDeformVerts();
|
||||
break;
|
||||
case ARM_VDEF_BLENDER:
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
if (m_layer_weight >= 0)
|
||||
obj->GetPose(&m_blendpose);
|
||||
|
||||
// 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);
|
||||
|
||||
arm->pose = temp;
|
||||
}
|
||||
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->BlendInPose(m_blendpose, m_layer_weight, m_blendmode);
|
||||
|
||||
obj->SetPose(m_pose);
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -102,6 +102,8 @@
|
||||
|
||||
#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,13 +1598,14 @@ 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);
|
||||
gameobj = (KX_GameObject*)taskdata;
|
||||
|
||||
// Non-armature updates are fast enough, so just update them
|
||||
needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE;
|
||||
@ -1610,8 +1613,7 @@ void KX_Scene::UpdateAnimations(double curtime)
|
||||
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;
|
||||
children = gameobj->GetChildren();
|
||||
|
||||
bool has_mesh = false, has_non_mesh = false;
|
||||
|
||||
@ -1639,9 +1641,31 @@ void KX_Scene::UpdateAnimations(double curtime)
|
||||
children->Release();
|
||||
}
|
||||
|
||||
if (needs_update)
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user