Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/Ketsji/BL_Action.cpp')
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
new file mode 100644
index 00000000000..08794042e37
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -0,0 +1,453 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Mitchell Stokes.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BL_Action.cpp
+ * \ingroup ketsji
+ */
+
+#include <cstdlib>
+
+#include "BL_Action.h"
+#include "BL_ArmatureObject.h"
+#include "BL_DeformableGameObject.h"
+#include "BL_ShapeDeformer.h"
+#include "KX_IpoConvert.h"
+#include "KX_GameObject.h"
+
+// These three are for getting the action from the logic manager
+#include "KX_Scene.h"
+#include "KX_PythonInit.h"
+#include "SCA_LogicManager.h"
+
+extern "C" {
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+}
+
+BL_Action::BL_Action(class KX_GameObject* gameobj)
+:
+ m_action(NULL),
+ m_pose(NULL),
+ m_blendpose(NULL),
+ m_blendinpose(NULL),
+ m_ptrrna(NULL),
+ m_obj(gameobj),
+ m_startframe(0.f),
+ m_endframe(0.f),
+ m_endtime(0.f),
+ m_localtime(0.f),
+ m_blendin(0.f),
+ m_blendframe(0.f),
+ m_blendstart(0.f),
+ m_speed(0.f),
+ m_priority(0),
+ m_playmode(0),
+ m_ipo_flags(0),
+ m_done(true),
+ m_calc_localtime(true)
+{
+ if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ {
+ BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
+
+ m_ptrrna = new PointerRNA();
+ RNA_id_pointer_create(&obj->GetArmatureObject()->id, m_ptrrna);
+ }
+ else
+ {
+ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
+ BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
+
+ if (shape_deformer)
+ {
+ m_ptrrna = new PointerRNA();
+ RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_ptrrna);
+ }
+ }
+}
+
+BL_Action::~BL_Action()
+{
+ if (m_pose)
+ game_free_pose(m_pose);
+ if (m_blendpose)
+ game_free_pose(m_blendpose);
+ if (m_blendinpose)
+ game_free_pose(m_blendinpose);
+ if (m_ptrrna)
+ delete m_ptrrna;
+ ClearControllerList();
+}
+
+void BL_Action::ClearControllerList()
+{
+ // Clear out the controller list
+ std::vector<SG_Controller*>::iterator it;
+ for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
+ {
+ m_obj->GetSGNode()->RemoveSGController((*it));
+ delete *it;
+ }
+
+ m_sg_contr_list.clear();
+}
+
+bool BL_Action::Play(const char* name,
+ float start,
+ float end,
+ short priority,
+ float blendin,
+ short play_mode,
+ float layer_weight,
+ short ipo_flags,
+ float playback_speed)
+{
+
+ // Only start playing a new action if we're done, or if
+ // the new action has a higher priority
+ if (priority != 0 && !IsDone() && priority >= m_priority)
+ return false;
+ m_priority = priority;
+ bAction* prev_action = m_action;
+
+ // First try to load the action
+ m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
+ if (!m_action)
+ {
+ printf("Failed to load action: %s\n", name);
+ m_done = true;
+ return false;
+ }
+
+ if (prev_action != m_action)
+ {
+ // First get rid of any old controllers
+ ClearControllerList();
+
+ // Create an SG_Controller
+ SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+
+ // Extra controllers
+ if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
+ {
+ sg_contr = BL_CreateLampIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+ }
+ else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
+ {
+ sg_contr = BL_CreateCameraIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+ }
+ }
+
+ m_ipo_flags = ipo_flags;
+ InitIPO();
+
+ // Setup blendin shapes/poses
+ if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ {
+ BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
+ obj->GetMRDPose(&m_blendinpose);
+ }
+ else
+ {
+ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
+ BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
+
+ if (shape_deformer && shape_deformer->GetKey())
+ {
+ obj->GetShape(m_blendinshape);
+
+ // Now that we have the previous blend shape saved, we can clear out the key to avoid any
+ // further interference.
+ KeyBlock *kb;
+ for (kb=(KeyBlock*)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock*)kb->next)
+ kb->curval = 0.f;
+ }
+ }
+
+ // Now that we have an action, we have something we can play
+ m_starttime = KX_GetActiveEngine()->GetFrameTime();
+ m_startframe = m_localtime = start;
+ m_endframe = end;
+ m_blendin = blendin;
+ m_playmode = play_mode;
+ m_endtime = 0.f;
+ m_blendframe = 0.f;
+ m_blendstart = 0.f;
+ m_speed = playback_speed;
+ m_layer_weight = layer_weight;
+
+ m_done = false;
+
+ return true;
+}
+
+void BL_Action::Stop()
+{
+ m_done = true;
+}
+
+bool BL_Action::IsDone()
+{
+ return m_done;
+}
+
+void BL_Action::InitIPO()
+{
+ // Initialize the IPOs
+ std::vector<SG_Controller*>::iterator it;
+ for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
+ {
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL);
+ }
+}
+
+bAction *BL_Action::GetAction()
+{
+ return (IsDone()) ? NULL : m_action;
+}
+
+float BL_Action::GetFrame()
+{
+ return m_localtime;
+}
+
+void BL_Action::SetFrame(float frame)
+{
+ // Clamp the frame to the start and end frame
+ if (frame < min(m_startframe, m_endframe))
+ frame = min(m_startframe, m_endframe);
+ else if (frame > max(m_startframe, m_endframe))
+ frame = max(m_startframe, m_endframe);
+
+ m_localtime = frame;
+ m_calc_localtime = false;
+}
+
+void BL_Action::SetPlayMode(short play_mode)
+{
+ m_playmode = play_mode;
+}
+
+void BL_Action::SetTimes(float start, float end)
+{
+ m_startframe = start;
+ m_endframe = end;
+}
+
+void BL_Action::SetLocalTime(float curtime)
+{
+ float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
+
+ if (m_endframe < m_startframe)
+ dt = -dt;
+
+ m_localtime = m_startframe + dt;
+}
+
+void BL_Action::ResetStartTime(float curtime)
+{
+ float dt = m_localtime - m_startframe;
+
+ m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
+ SetLocalTime(curtime);
+}
+
+void BL_Action::IncrementBlending(float curtime)
+{
+ // Setup m_blendstart if we need to
+ if (m_blendstart == 0.f)
+ m_blendstart = curtime;
+
+ // Bump the blend frame
+ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
+
+ // Clamp
+ if (m_blendframe>m_blendin)
+ m_blendframe = m_blendin;
+}
+
+
+void BL_Action::BlendShape(Key* key, float srcweight, std::vector<float>& blendshape)
+{
+ vector<float>::const_iterator it;
+ float dstweight;
+ KeyBlock *kb;
+
+ dstweight = 1.0F - srcweight;
+ //printf("Dst: %f\tSrc: %f\n", srcweight, dstweight);
+ for (it=blendshape.begin(), kb = (KeyBlock*)key->block.first;
+ kb && it != blendshape.end();
+ kb = (KeyBlock*)kb->next, it++) {
+ //printf("OirgKeys: %f\t%f\n", kb->curval, (*it));
+ kb->curval = kb->curval * dstweight + (*it) * srcweight;
+ //printf("NewKey: %f\n", kb->curval);
+ }
+ //printf("\n");
+}
+
+void BL_Action::Update(float curtime)
+{
+ // Don't bother if we're done with the animation
+ if (m_done)
+ return;
+
+ curtime -= KX_KetsjiEngine::GetSuspendedDelta();
+
+ if (m_calc_localtime)
+ SetLocalTime(curtime);
+ else
+ {
+ ResetStartTime(curtime);
+ m_calc_localtime = true;
+ }
+
+ // Handle wrap around
+ if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe))
+ {
+ switch(m_playmode)
+ {
+ case ACT_MODE_PLAY:
+ // Clamp
+ m_localtime = m_endframe;
+ m_done = true;
+ break;
+ case ACT_MODE_LOOP:
+ // Put the time back to the beginning
+ m_localtime = m_startframe;
+ m_starttime = curtime;
+ break;
+ case ACT_MODE_PING_PONG:
+ // Swap the start and end frames
+ float temp = m_startframe;
+ m_startframe = m_endframe;
+ m_endframe = temp;
+
+ m_starttime = curtime;
+
+ break;
+ }
+
+ if (!m_done)
+ InitIPO();
+ }
+
+ 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;
+ animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
+
+ arm->pose = temp;
+ }
+
+ // Handle blending between armature actions
+ if (m_blendin && m_blendframe<m_blendin)
+ {
+ IncrementBlending(curtime);
+
+ // Calculate weight
+ float weight = 1.f - (m_blendframe/m_blendin);
+
+ // Blend the poses
+ game_blend_poses(m_pose, m_blendinpose, weight);
+ }
+
+
+ // Handle layer blending
+ if (m_layer_weight >= 0)
+ {
+ obj->GetMRDPose(&m_blendpose);
+ game_blend_poses(m_pose, m_blendpose, m_layer_weight);
+ }
+
+ obj->SetPose(m_pose);
+
+ obj->SetActiveAction(NULL, 0, curtime);
+ }
+ else
+ {
+ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
+ BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
+
+ // Handle shape actions if we have any
+ if (shape_deformer && shape_deformer->GetKey())
+ {
+ Key *key = shape_deformer->GetKey();
+
+
+ animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
+
+ // Handle blending between shape actions
+ if (m_blendin && m_blendframe < m_blendin)
+ {
+ IncrementBlending(curtime);
+
+ float weight = 1.f - (m_blendframe/m_blendin);
+
+ // We go through and clear out the keyblocks so there isn't any interference
+ // from other shape actions
+ KeyBlock *kb;
+ for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
+ kb->curval = 0.f;
+
+ // Now blend the shape
+ BlendShape(key, weight, m_blendinshape);
+ }
+
+ // Handle layer blending
+ if (m_layer_weight >= 0)
+ {
+ obj->GetShape(m_blendshape);
+ BlendShape(key, m_layer_weight, m_blendshape);
+ }
+
+ obj->SetActiveAction(NULL, 0, curtime);
+ }
+
+
+ InitIPO();
+ m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+ }
+}