BGE Animations: Adding the concept of priority back. Priority is handled on a per...
[blender.git] / source / gameengine / Ketsji / BL_Action.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <cstdlib>
31
32 #include "BL_Action.h"
33 #include "BL_ArmatureObject.h"
34 #include "BL_DeformableGameObject.h"
35 #include "BL_ShapeDeformer.h"
36 #include "KX_IpoConvert.h"
37 #include "KX_GameObject.h"
38
39 // These three are for getting the action from the logic manager
40 #include "KX_Scene.h"
41 #include "KX_PythonInit.h"
42 #include "SCA_LogicManager.h"
43
44 extern "C" {
45 #include "BKE_animsys.h"
46 #include "BKE_action.h"
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49 }
50
51 BL_Action::BL_Action(class KX_GameObject* gameobj)
52 :
53         m_obj(gameobj),
54         m_startframe(0.f),
55         m_endframe(0.f),
56         m_blendin(0.f),
57         m_playmode(0),
58         m_endtime(0.f),
59         m_localtime(0.f),
60         m_blendframe(0.f),
61         m_blendstart(0.f),
62         m_speed(0.f),
63         m_priority(0),
64         m_ipo_flags(0),
65         m_pose(NULL),
66         m_blendpose(NULL),
67         m_sg_contr(NULL),
68         m_ptrrna(NULL),
69         m_done(true)
70 {
71         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
72         {
73                 BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
74
75                 m_ptrrna = new PointerRNA();
76                 RNA_id_pointer_create(&obj->GetArmatureObject()->id, m_ptrrna);
77         }
78         else
79         {
80                 BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
81                 BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
82
83                 if (shape_deformer)
84                 {
85                         m_ptrrna = new PointerRNA();
86                         RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_ptrrna);
87                 }
88         }
89 }
90
91 BL_Action::~BL_Action()
92 {
93         if (m_pose)
94                 game_free_pose(m_pose);
95         if (m_blendpose)
96                 game_free_pose(m_blendpose);
97         if (m_sg_contr)
98         {
99                 m_obj->GetSGNode()->RemoveSGController(m_sg_contr);
100                 delete m_sg_contr;
101         }
102         if (m_ptrrna)
103                 delete m_ptrrna;
104 }
105
106 void BL_Action::Play(const char* name,
107                                         float start,
108                                         float end,
109                                         short priority,
110                                         float blendin,
111                                         short play_mode,
112                                         short blend_mode,
113                                         short ipo_flags,
114                                         float playback_speed)
115 {
116
117         // Only start playing a new action if we're done, or if
118         // the new action has a higher priority
119         if (priority != 0 && !IsDone() && priority >= m_priority)
120                 return;
121         m_priority = priority;
122         bAction* prev_action = m_action;
123
124         // First try to load the action
125         m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
126         if (!m_action)
127         {
128                 printf("Failed to load action: %s\n", name);
129                 m_done = true;
130                 return;
131         }
132
133         if (prev_action != m_action)
134         {
135                 // Create an SG_Controller
136                 m_sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
137                 m_obj->GetSGNode()->AddSGController(m_sg_contr);
138                 m_sg_contr->SetObject(m_obj->GetSGNode());
139         }
140         
141         m_ipo_flags = ipo_flags;
142         InitIPO();
143
144         // Now that we have an action, we have something we can play
145         m_starttime = KX_GetActiveEngine()->GetFrameTime();
146         m_startframe = m_localtime = start;
147         m_endframe = end;
148         m_blendin = blendin;
149         m_playmode = play_mode;
150         m_endtime = 0.f;
151         m_blendframe = 0.f;
152         m_blendstart = 0.f;
153         m_speed = playback_speed;
154         
155         m_done = false;
156 }
157
158 void BL_Action::Stop()
159 {
160         m_done = true;
161 }
162
163 void BL_Action::InitIPO()
164 {
165                 // Initialize the IPO
166                 m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
167                 m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE);
168                 m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD);
169                 m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL);
170 }
171
172 float BL_Action::GetFrame()
173 {
174         return m_localtime;
175 }
176
177 void BL_Action::SetFrame(float frame)
178 {
179         float dt;
180
181         // Clamp the frame to the start and end frame
182         if (frame < min(m_startframe, m_endframe))
183                 frame = min(m_startframe, m_endframe);
184         else if (frame > max(m_startframe, m_endframe))
185                 frame = max(m_startframe, m_endframe);
186
187         // We don't set m_localtime directly since it's recalculated
188         // in the next update. So, we modify the value (m_starttime) 
189         // used to calculate m_localtime the next time SetLocalTime() is called.
190
191         dt = frame-m_startframe;
192
193         if (m_endframe < m_startframe)
194                 dt = -dt;
195
196         m_starttime -= dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
197 }
198
199 void BL_Action::SetLocalTime(float curtime)
200 {
201         float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
202
203         if (m_endframe < m_startframe)
204                 dt = -dt;
205
206         m_localtime = m_startframe + dt;
207 }
208
209 void BL_Action::Update(float curtime)
210 {
211         // Don't bother if we're done with the animation
212         if (m_done)
213                 return;
214
215         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
216
217         SetLocalTime(curtime);
218
219         // Handle wrap around
220         if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe))
221         {
222                 switch(m_playmode)
223                 {
224                 case ACT_MODE_PLAY:
225                         // Clamp
226                         m_localtime = m_endframe;
227                         m_done = true;
228                         break;
229                 case ACT_MODE_LOOP:
230                         // Put the time back to the beginning
231                         m_localtime = m_startframe;
232                         m_starttime = curtime;
233                         break;
234                 case ACT_MODE_PING_PONG:
235                         // Swap the start and end frames
236                         float temp = m_startframe;
237                         m_startframe = m_endframe;
238                         m_endframe = temp;
239
240                         m_starttime = curtime;
241
242                         break;
243                 }
244
245                 if (!m_done && m_sg_contr)
246                         InitIPO();
247         }
248
249         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
250         {
251                 BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
252                 obj->GetPose(&m_pose);
253
254                 // Extract the pose from the action
255                 {
256                         Object *arm = obj->GetArmatureObject();
257                         bPose *temp = arm->pose;
258
259                         arm->pose = m_pose;
260                         animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
261
262                         arm->pose = temp;
263                 }
264
265                 // Handle blending between actions
266                 if (m_blendin && m_blendframe<m_blendin)
267                 {
268                         if (!m_blendpose)
269                         {
270                                 obj->GetMRDPose(&m_blendpose);
271                                 m_blendstart = curtime;
272                         }
273
274                         // Calculate weight
275                         float weight = 1.f - (m_blendframe/m_blendin);
276                         game_blend_poses(m_pose, m_blendpose, weight);
277
278                         // Bump the blend frame
279                         m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
280
281                         // Clamp
282                         if (m_blendframe>m_blendin)
283                                 m_blendframe = m_blendin;
284                 }
285
286                 obj->SetPose(m_pose);
287
288                 obj->SetActiveAction(NULL, 0, curtime);
289         }
290         else
291         {
292                 BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
293                 BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
294
295                 // Handle shape actions if we have any
296                 if (shape_deformer)
297                 {
298                         Key *key = shape_deformer->GetKey();
299
300                         // We go through and clear out the keyblocks so there isn't any interference
301                         // from other shape actions
302                         KeyBlock *kb;
303                         for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
304                                 kb->curval = 0.f;
305
306                         animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
307
308                         // XXX TODO handle blendin
309
310                         obj->SetActiveAction(NULL, 0, m_localtime);
311                 }
312
313
314                 InitIPO();
315                 m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
316         }
317 }