From ee5284faf6db96bb5029f6d2ab0b62336ef84e53 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Wed, 7 May 2014 18:14:36 -0700 Subject: [PATCH] BGE: Dynamically-allocated action layers This patch removes the limitations on the number of action layers in the BGE. BL_ActionManager currently uses a fixed array to keep track of the action layers. This patch replaces the fixed array with a map which allows for dynamic allocation of action layers. Layers (map items) are automatically removed on BL_ActionManager's update function. The maximum number of layers is roughly the value of a short. Backwards functionality is maintained and there are no changes to the Python API. Task Discussion: https://developer.blender.org/T39572 Author: Kevin Ednalino Reviewers: moguri Differential Revision: https://developer.blender.org/D491 --- source/blender/makesrna/intern/rna_actuator.c | 2 +- .../Converter/BL_ActionActuator.cpp | 3 +- source/gameengine/Ketsji/BL_ActionManager.cpp | 87 ++++++++++++++----- source/gameengine/Ketsji/BL_ActionManager.h | 22 ++++- 4 files changed, 87 insertions(+), 27 deletions(-) diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 9880e7da26a..fd04fb46cf1 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -661,7 +661,7 @@ static void rna_def_action_actuator(BlenderRNA *brna) RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "layer", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 7); /* This should match BL_ActionManager::MAX_ACTION_LAYERS - 1 */ + RNA_def_property_range(prop, 0, 32766); /* This should match BL_ActionManager::MAX_ACTION_LAYERS - 1 */ RNA_def_property_ui_text(prop, "Layer", "The animation layer to play the action on"); RNA_def_property_update(prop, NC_LOGIC, NULL); diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index f8c5ffbecfd..3dd013dfd63 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -35,6 +35,7 @@ #include "BL_ArmatureObject.h" #include "BL_SkinDeformer.h" #include "BL_Action.h" +#include "BL_ActionManager.h" #include "KX_GameObject.h" #include "STR_HashedString.h" #include "MEM_guardedalloc.h" @@ -536,7 +537,7 @@ PyAttributeDef BL_ActionActuator::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names), KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), - KX_PYATTRIBUTE_SHORT_RW("layer", 0, 7, true, BL_ActionActuator, m_layer), + KX_PYATTRIBUTE_SHORT_RW("layer", 0, MAX_ACTION_LAYERS-1, true, BL_ActionActuator, m_layer), KX_PYATTRIBUTE_FLOAT_RW("layerWeight", 0, 1.0, BL_ActionActuator, m_layer_weight), KX_PYATTRIBUTE_RW_FUNCTION("frame", BL_ActionActuator, pyattr_get_frame, pyattr_set_frame), KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_propname), diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index 404f276eca8..07adce73b4a 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -24,44 +24,72 @@ * \ingroup ketsji */ -#include "BL_ActionManager.h" #include "BL_Action.h" +#include "BL_ActionManager.h" -BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) +BL_ActionManager::BL_ActionManager(class KX_GameObject *obj): + m_obj(obj) { - for (int i=0; isecond; + + m_layers.clear(); +} + +BL_Action *BL_ActionManager::GetAction(short layer) +{ + BL_ActionMap::iterator it = m_layers.find(layer); + + return (it != m_layers.end()) ? it->second : 0; +} + +BL_Action* BL_ActionManager::AddAction(short layer) +{ + BL_Action *action = new BL_Action(m_obj); + m_layers[layer] = action; + + return action; } float BL_ActionManager::GetActionFrame(short layer) { - return m_layers[layer]->GetFrame(); + BL_Action *action = GetAction(layer); + + return action ? action->GetFrame() : 0.f; } void BL_ActionManager::SetActionFrame(short layer, float frame) { - m_layers[layer]->SetFrame(frame); + BL_Action *action = GetAction(layer); + + if (action) action->SetFrame(frame); } struct bAction *BL_ActionManager::GetCurrentAction(short layer) { - return m_layers[layer]->GetAction(); + BL_Action *action = GetAction(layer); + + return action ? action->GetAction() : 0; } void BL_ActionManager::SetPlayMode(short layer, short mode) { - m_layers[layer]->SetPlayMode(mode); + BL_Action *action = GetAction(layer); + + if (action) action->SetPlayMode(mode); } void BL_ActionManager::SetTimes(short layer, float start, float end) { - m_layers[layer]->SetTimes(start, end); + BL_Action *action = GetAction(layer); + + if (action) action->SetTimes(start, end); } bool BL_ActionManager::PlayAction(const char* name, @@ -76,40 +104,53 @@ bool BL_ActionManager::PlayAction(const char* name, float playback_speed, short blend_mode) { + // Only this method will create layer if non-existent + BL_Action *action = GetAction(layer); + if (!action) + action = AddAction(layer); + // Disable layer blending on the first layer if (layer == 0) layer_weight = -1.f; - return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); + return action->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } void BL_ActionManager::StopAction(short layer) { - m_layers[layer]->Stop(); + BL_Action *action = GetAction(layer); + + if (action) action->Stop(); } bool BL_ActionManager::IsActionDone(short layer) { - return m_layers[layer]->IsDone(); + BL_Action *action = GetAction(layer); + + return action ? action->IsDone() : true; } void BL_ActionManager::Update(float curtime) { - for (int i=0; iIsDone()) - { - m_layers[i]->Update(curtime); + if (it->second->IsDone()) { + delete it->second; + m_layers.erase(it++); + } + else { + it->second->Update(curtime); + ++it; } } } void BL_ActionManager::UpdateIPOs() { - for (int i=0; iIsDone()) - { - m_layers[i]->UpdateIPOs(); - } + if (!it->second->IsDone()) + it->second->UpdateIPOs(); } } diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index be9097c3ca3..5b340257881 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -31,7 +31,12 @@ #include "MEM_guardedalloc.h" #endif -#define MAX_ACTION_LAYERS 8 +#include + +// Currently, we use the max value of a short. +// We should switch to unsigned short; doesn't make sense to support negative layers. +// This will also give us 64k layers instead of 32k. +#define MAX_ACTION_LAYERS 32767 class BL_Action; @@ -41,7 +46,20 @@ class BL_Action; class BL_ActionManager { private: - BL_Action* m_layers[MAX_ACTION_LAYERS]; + typedef std::map BL_ActionMap; + + class KX_GameObject* m_obj; + BL_ActionMap m_layers; + + /** + * Check if an action exists + */ + BL_Action* GetAction(short layer); + + /** + * Add new action with given layer + */ + BL_Action* AddAction(short layer); public: BL_ActionManager(class KX_GameObject* obj);