Fix for T41536: 2.71 getActionFrame no longer returns frames accurately
[blender.git] / source / gameengine / Ketsji / BL_ActionManager.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Mitchell Stokes.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file BL_ActionManager.cpp
24  *  \ingroup ketsji
25  */
26
27 #include "BL_Action.h"
28 #include "BL_ActionManager.h"
29 #include "DNA_ID.h"
30
31 #define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT))
32
33 BL_ActionManager::BL_ActionManager(class KX_GameObject *obj):
34         m_obj(obj),
35         m_prevUpdate(-1.0f)
36 {
37 }
38
39 BL_ActionManager::~BL_ActionManager()
40 {
41         BL_ActionMap::iterator it;
42
43         for (it = m_layers.begin(); it != m_layers.end(); it++)
44                 delete it->second;
45
46         m_layers.clear();
47 }
48
49 BL_Action *BL_ActionManager::GetAction(short layer)
50 {
51         BL_ActionMap::iterator it = m_layers.find(layer);
52
53         return (it != m_layers.end()) ? it->second : 0;
54 }
55
56 float BL_ActionManager::GetActionFrame(short layer)
57 {
58         BL_Action *action = GetAction(layer);
59
60         return action ? action->GetFrame() : 0.f;
61 }
62
63 const char *BL_ActionManager::GetActionName(short layer)
64 {
65         BL_Action *action = GetAction(layer);
66         return action ? action->GetName() : "";
67 }
68
69 void BL_ActionManager::SetActionFrame(short layer, float frame)
70 {
71         BL_Action *action = GetAction(layer);
72
73         if (action) action->SetFrame(frame);
74 }
75
76 struct bAction *BL_ActionManager::GetCurrentAction(short layer)
77 {
78         BL_Action *action = GetAction(layer);
79
80         return action ? action->GetAction() : 0;
81 }
82
83 void BL_ActionManager::SetPlayMode(short layer, short mode)
84 {
85         BL_Action *action = GetAction(layer);
86
87         if (action) action->SetPlayMode(mode);
88 }
89
90 void BL_ActionManager::SetTimes(short layer, float start, float end)
91 {
92         BL_Action *action = GetAction(layer);
93
94         if (action) action->SetTimes(start, end);
95 }
96
97 bool BL_ActionManager::PlayAction(const char* name,
98                                                                 float start,
99                                                                 float end,
100                                                                 short layer,
101                                                                 short priority,
102                                                                 float blendin,
103                                                                 short play_mode,
104                                                                 float layer_weight,
105                                                                 short ipo_flags,
106                                                                 float playback_speed,
107                                                                 short blend_mode)
108 {
109         // Only this method will create layer if non-existent
110         BL_Action *action = GetAction(layer);
111         if (!action) {
112                 action = new BL_Action(m_obj);
113                 m_layers[layer] = action;
114         }
115
116         // Disable layer blending on the first layer
117         if (layer == 0) layer_weight = -1.f;
118
119         return action->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode);
120 }
121
122 void BL_ActionManager::StopAction(short layer)
123 {
124         BL_Action *action = GetAction(layer);
125
126         if (action) {
127                 m_layers.erase(layer);
128                 delete action;
129         }
130 }
131
132 void BL_ActionManager::RemoveTaggedActions()
133 {
134         for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end();) {
135                 if (IS_TAGGED(it->second->GetAction())) {
136                         delete it->second;
137                         m_layers.erase(it++);
138                 }
139                 else
140                         ++it;
141         }
142 }
143
144 bool BL_ActionManager::IsActionDone(short layer)
145 {
146         BL_Action *action = GetAction(layer);
147
148         return action ? action->IsDone() : true;
149 }
150
151 void BL_ActionManager::Update(float curtime)
152 {
153         if (m_prevUpdate == curtime)
154                 return;
155         m_prevUpdate = curtime;
156
157         BL_ActionMap::iterator it;
158         for (it = m_layers.begin(); it != m_layers.end(); ++it)
159         {
160                 if (!it->second->IsDone()) {
161                         it->second->Update(curtime);
162                 }
163         }
164 }
165
166 void BL_ActionManager::UpdateIPOs()
167 {
168         BL_ActionMap::iterator it;
169         for (it = m_layers.begin(); it != m_layers.end(); ++it)
170         {
171                 if (!it->second->IsDone())
172                         it->second->UpdateIPOs();
173         }
174 }