BGE: Finally adding support for additive layer blending.
authorMitchell Stokes <mogurijin@gmail.com>
Wed, 14 Aug 2013 23:31:49 +0000 (23:31 +0000)
committerMitchell Stokes <mogurijin@gmail.com>
Wed, 14 Aug 2013 23:31:49 +0000 (23:31 +0000)
Currently this is only for the Python API. The logic brick will be updated in a future commit.

doc/python_api/rst/bge.logic.rst
doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
source/gameengine/Converter/BL_ArmatureObject.cpp
source/gameengine/Converter/BL_ArmatureObject.h
source/gameengine/Ketsji/BL_Action.cpp
source/gameengine/Ketsji/BL_Action.h
source/gameengine/Ketsji/BL_ActionManager.cpp
source/gameengine/Ketsji/BL_ActionManager.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_PythonInit.cpp

index c7915ee5279d60f5a0d42f096513c571f6d6ca5d..3a79d32d91799bcb2f231e44277d5263fa61bc37 100644 (file)
@@ -1114,6 +1114,19 @@ See :class:`bge.types.KX_GameObject.playAction`
    
    :value: 2
 
+.. _gameobject-playaction-blend:
+
+.. data:: KX_ACTION_BLEND_BLEND
+
+   Blend layers using linear interpolation
+
+   :value: 0
+
+.. data:: KX_ACTION_BLEND_ADD
+
+   Adds the layers together
+
+   :value: 1
 
 -------------
 Mouse Buttons
index a9c91735f917bd6a10e3ab4a7a9c955abc459968..3be148556ef36e97231b7f5d855ecb664aa7afab 100644 (file)
@@ -776,7 +776,7 @@ base class --- :class:`SCA_IObject`
       Return the value matching key, or the default value if its not found.
       :return: The key value or a default.
 
-   .. method:: playAction(name, start_frame, end_frame, layer=0, priority=0, blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)
+   .. method:: playAction(name, start_frame, end_frame, layer=0, priority=0, blendin=0, play_mode=KX_ACTION_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0, blend_mode=KX_ACTION_BLEND_BLEND)
 
       Plays an action.
       
@@ -794,12 +794,14 @@ base class --- :class:`SCA_IObject`
       :type blendin: float
       :arg play_mode: the play mode
       :type play_mode: one of :ref:`these constants <gameobject-playaction-mode>`
-      :arg layer_weight: how much of the previous layer to use for blending (0 = add)
+      :arg layer_weight: how much of the previous layer to use for blending
       :type layer_weight: float
       :arg ipo_flags: flags for the old IPO behaviors (force, etc)
       :type ipo_flags: int bitfield
       :arg speed: the playback speed of the action as a factor (1.0 = normal speed, 2.0 = 2x speed, etc)
       :type speed: float
+         :arg blend_mode: how to blend this layer with previous layers
+         :type blend_mode: one of :ref:`these constants <gameobject-playaction-blend>`
 
    .. method:: stopAction(layer=0)
       
index 55d9decb333ae87f651e0f1b33868356ac51b9ea..d8ddb33ddc4a391dd34d397e19d7b46eda127c3c 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "BL_ArmatureObject.h"
 #include "BL_ActionActuator.h"
+#include "BL_Action.h"
 #include "KX_BlenderSceneConverter.h"
 #include "MEM_guardedalloc.h"
 #include "BLI_blenlib.h"
@@ -50,7 +51,6 @@
 #include "DNA_armature_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_nla_types.h"
 #include "DNA_constraint_types.h"
 #include "KX_PythonSeq.h"
 #include "KX_PythonInit.h"
@@ -137,25 +137,22 @@ 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*/)
+void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
 {
-       short mode= ACTSTRIPMODE_BLEND;
-       
        bPoseChannel *dchan;
        const bPoseChannel *schan;
        bConstraint *dcon, *scon;
        float dstweight;
        int i;
 
-       switch (mode) {
-       case ACTSTRIPMODE_BLEND:
-               dstweight = 1.0F - srcweight;
-               break;
-       case ACTSTRIPMODE_ADD:
-               dstweight = 1.0F;
-               break;
-       default :
-               dstweight = 1.0F;
+       if (mode == BL_Action::ACT_BLEND_BLEND)
+       {
+               dstweight = 1.0f - srcweight;
+       } else if (mode == BL_Action::ACT_BLEND_ADD)
+       {
+               dstweight = 1.0f;
+       } else {
+               dstweight = 1.0f;
        }
        
        schan= (bPoseChannel *)src->chanbase.first;
@@ -167,7 +164,7 @@ void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/)
                        
                        copy_qt_qt(dquat, dchan->quat);
                        copy_qt_qt(squat, schan->quat);
-                       if (mode==ACTSTRIPMODE_BLEND)
+                       if (mode==BL_Action::ACT_BLEND_BLEND)
                                interp_qt_qtqt(dchan->quat, dquat, squat, srcweight);
                        else {
                                mul_fac_qt_fl(squat, srcweight);
index 445b9af1b10d0781d0576efc7349708f264f58ab..81388355fc4f44fcbddb8f09fb26e47e8c5f45ea 100644 (file)
@@ -147,7 +147,7 @@ protected:
 };
 
 /* 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 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);
index 9d189a6170e8fe1132b8252adb08cb2f15ca34fc..6d9b22eed91d1a11ffe2a8c49f8e7a3b1dea4b6e 100644 (file)
@@ -65,7 +65,8 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
        m_blendstart(0.f),
        m_speed(0.f),
        m_priority(0),
-       m_playmode(0),
+       m_playmode(ACT_MODE_PLAY),
+       m_blendmode(ACT_BLEND_BLEND),
        m_ipo_flags(0),
        m_done(true),
        m_calc_localtime(true)
@@ -104,7 +105,8 @@ bool BL_Action::Play(const char* name,
                                        short play_mode,
                                        float layer_weight,
                                        short ipo_flags,
-                                       float playback_speed)
+                                       float playback_speed,
+                                       short blend_mode)
 {
 
        // Only start playing a new action if we're done, or if
@@ -229,6 +231,7 @@ bool BL_Action::Play(const char* name,
        m_endframe = end;
        m_blendin = blendin;
        m_playmode = play_mode;
+       m_blendmode = blend_mode;
        m_endtime = 0.f;
        m_blendframe = 0.f;
        m_blendstart = 0.f;
@@ -423,7 +426,7 @@ 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);
+                       game_blend_poses(m_pose, m_blendinpose, weight, ACT_BLEND_BLEND);
                }
 
 
@@ -431,7 +434,7 @@ void BL_Action::Update(float curtime)
                if (m_layer_weight >= 0)
                {
                        obj->GetMRDPose(&m_blendpose);
-                       game_blend_poses(m_pose, m_blendpose, m_layer_weight);
+                       game_blend_poses(m_pose, m_blendpose, m_layer_weight, m_blendmode);
                }
 
                obj->SetPose(m_pose);
index e4088633e61f58f2520600b07ddbed8f2ee383df..e9d099165175701ec286a26b60699517078ca47a 100644 (file)
@@ -34,7 +34,6 @@
 #include "MEM_guardedalloc.h"
 #endif
 
-
 class BL_Action
 {
 private:
@@ -64,6 +63,7 @@ private:
        short m_priority;
 
        short m_playmode;
+       short m_blendmode;
 
        short m_ipo_flags;
 
@@ -91,7 +91,8 @@ public:
                        short play_mode,
                        float layer_weight,
                        short ipo_flags,
-                       float playback_speed);
+                       float playback_speed,
+                       short blend_mode);
        /**
         * Stop playing the action
         */
@@ -114,7 +115,7 @@ public:
        void SetPlayMode(short play_mode);
        void SetTimes(float start, float end);
 
-       enum 
+       enum
        {
                ACT_MODE_PLAY = 0,
                ACT_MODE_LOOP,
@@ -122,6 +123,13 @@ public:
                ACT_MODE_MAX,
        };
 
+       enum
+       {
+               ACT_BLEND_BLEND=0,
+               ACT_BLEND_ADD=1,
+               ACT_BLEND_MAX,
+       };
+
        enum
        {
                ACT_IPOFLAG_FORCE = 1,
index e3402972ca6cad8399e3cb6c4d847275d71d7360..2e882ceba74552818403605687ddc2e2ef2d9c79 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "BL_ActionManager.h"
+#include "BL_Action.h"
 
 BL_ActionManager::BL_ActionManager(class KX_GameObject *obj)
 {
@@ -72,12 +73,13 @@ bool BL_ActionManager::PlayAction(const char* name,
                                                                short play_mode,
                                                                float layer_weight,
                                                                short ipo_flags,
-                                                               float playback_speed)
+                                                               float playback_speed,
+                                                               short blend_mode)
 {
        // 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);
+       return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode);
 }
 
 void BL_ActionManager::StopAction(short layer)
index 600e7b6621eb63769991dca3be2fc1c4928526cc..88aa241b6ce9498540afb81300b9ea0ca3198fc7 100644 (file)
 #ifndef __BL_ACTIONMANAGER_H__
 #define __BL_ACTIONMANAGER_H__
 
-#include "BL_Action.h"
-
 #define MAX_ACTION_LAYERS 8
 
+class BL_Action;
+
 /**
  * BL_ActionManager is responsible for handling a KX_GameObject's actions.
  */
@@ -52,7 +52,8 @@ public:
                                        short play_mode=0,
                                        float layer_weight=0.f,
                                        short ipo_flags=0,
-                                       float playback_speed=1.f);
+                                       float playback_speed=1.f,
+                                       short blend_mode=0);
        /**
         * Gets the current frame of an action
         */
index ec62ae63f0c5133a600fdbaf39a663818e17cf70..e0ec4983739794bf3cdbd98f92ee2babbb0ebdc8 100644 (file)
@@ -73,6 +73,7 @@ typedef unsigned long uint_ptr;
 #include "KX_ObstacleSimulation.h"
 
 #include "BL_ActionManager.h"
+#include "BL_Action.h"
 
 #include "PyObjectPlus.h" /* python stuff */
 
@@ -429,9 +430,10 @@ bool KX_GameObject::PlayAction(const char* name,
                                                                short play_mode,
                                                                float layer_weight,
                                                                short ipo_flags,
-                                                               float playback_speed)
+                                                               float playback_speed,
+                                                               short blend_mode)
 {
-       return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed);
+       return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode);
 }
 
 void KX_GameObject::StopAction(short layer)
@@ -3311,11 +3313,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction,
        short layer=0, priority=0;
        short ipo_flags=0;
        short play_mode=0;
+       short blend_mode=0;
 
-       static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", NULL};
+       static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", "blend_mode", NULL};
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhf:playAction", const_cast<char**>(kwlist),
-                                                                       &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed))
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhfh:playAction", const_cast<char**>(kwlist),
+                                                                       &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed, &blend_mode))
                return NULL;
 
        layer_check(layer, "playAction");
@@ -3323,7 +3326,13 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction,
        if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX)
        {
                printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1);
-               play_mode = BL_Action::ACT_MODE_MAX;
+               play_mode = BL_Action::ACT_MODE_PLAY;
+       }
+
+       if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX)
+       {
+               printf("KX_GameObject.playAction(): given blend_mode (%d) is out of range (0 - %d), setting to ACT_BLEND_BLEND", blend_mode, BL_Action::ACT_BLEND_MAX-1);
+               blend_mode = BL_Action::ACT_BLEND_BLEND;
        }
 
        if (layer_weight < 0.f || layer_weight > 1.f)
@@ -3332,7 +3341,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction,
                layer_weight = 0.f;
        }
 
-       PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed);
+       PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed, blend_mode);
 
        Py_RETURN_NONE;
 }
index 13a79cebefbe6ef506660ce695e7449f1916c721..5a3b9df74ee32168832da562f9a190df84ed9abd 100644 (file)
@@ -255,7 +255,8 @@ public:
                                        short play_mode=0,
                                        float layer_weight=0.f,
                                        short ipo_flags=0,
-                                       float playback_speed=1.f);
+                                       float playback_speed=1.f,
+                                       short blend_mode=0);
 
        /**
         * Gets the current frame of an action
index d8b4bf9e8bdb0f48bf827744afb1e139143a61f5..ae9cbbb2656ac4176c73dd6e7487206d2238d589 100644 (file)
@@ -1820,6 +1820,10 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
        KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_LOOP, BL_Action::ACT_MODE_LOOP);
        KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PING_PONG, BL_Action::ACT_MODE_PING_PONG);
 
+       /* BL_Action blend modes */
+       KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_BLEND, BL_Action::ACT_BLEND_BLEND);
+       KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_ADD, BL_Action::ACT_BLEND_ADD);
+
        // Check for errors
        if (PyErr_Occurred())
        {