style cleanup
[blender.git] / source / gameengine / Ketsji / BL_Action.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_Action.cpp
24  *  \ingroup ketsji
25  */
26
27 #include <cstdlib>
28 #include <stdio.h>
29
30 #include "BL_Action.h"
31 #include "BL_ArmatureObject.h"
32 #include "BL_DeformableGameObject.h"
33 #include "BL_ShapeDeformer.h"
34 #include "KX_IpoConvert.h"
35 #include "KX_GameObject.h"
36
37 // These three are for getting the action from the logic manager
38 #include "KX_Scene.h"
39 #include "SCA_LogicManager.h"
40
41 extern "C" {
42 #include "BKE_animsys.h"
43 #include "BKE_action.h"
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46
47 // Needed for material IPOs
48 #include "BKE_material.h"
49 #include "DNA_material_types.h"
50 }
51
52 BL_Action::BL_Action(class KX_GameObject* gameobj)
53 :
54         m_action(NULL),
55         m_pose(NULL),
56         m_blendpose(NULL),
57         m_blendinpose(NULL),
58         m_ptrrna(NULL),
59         m_obj(gameobj),
60         m_startframe(0.f),
61         m_endframe(0.f),
62         m_endtime(0.f),
63         m_localtime(0.f),
64         m_blendin(0.f),
65         m_blendframe(0.f),
66         m_blendstart(0.f),
67         m_speed(0.f),
68         m_priority(0),
69         m_playmode(0),
70         m_ipo_flags(0),
71         m_done(true),
72         m_calc_localtime(true)
73 {
74         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
75         {
76                 BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
77
78                 m_ptrrna = new PointerRNA();
79                 RNA_id_pointer_create(&obj->GetArmatureObject()->id, m_ptrrna);
80         }
81         else
82         {
83                 BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
84                 BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
85
86                 if (shape_deformer)
87                 {
88                         m_ptrrna = new PointerRNA();
89                         RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_ptrrna);
90                 }
91         }
92 }
93
94 BL_Action::~BL_Action()
95 {
96         if (m_pose)
97                 game_free_pose(m_pose);
98         if (m_blendpose)
99                 game_free_pose(m_blendpose);
100         if (m_blendinpose)
101                 game_free_pose(m_blendinpose);
102         if (m_ptrrna)
103                 delete m_ptrrna;
104         ClearControllerList();
105 }
106
107 void BL_Action::ClearControllerList()
108 {
109         // Clear out the controller list
110         std::vector<SG_Controller*>::iterator it;
111         for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
112         {
113                 m_obj->GetSGNode()->RemoveSGController((*it));
114                 delete *it;
115         }
116
117         m_sg_contr_list.clear();
118 }
119
120 bool BL_Action::Play(const char* name,
121                                         float start,
122                                         float end,
123                                         short priority,
124                                         float blendin,
125                                         short play_mode,
126                                         float layer_weight,
127                                         short ipo_flags,
128                                         float playback_speed)
129 {
130
131         // Only start playing a new action if we're done, or if
132         // the new action has a higher priority
133         if (!IsDone() && priority > m_priority)
134                 return false;
135         m_priority = priority;
136         bAction* prev_action = m_action;
137
138         KX_Scene* kxscene = m_obj->GetScene();
139
140         // First try to load the action
141         m_action = (bAction*)kxscene->GetLogicManager()->GetActionByName(name);
142         if (!m_action)
143         {
144                 printf("Failed to load action: %s\n", name);
145                 m_done = true;
146                 return false;
147         }
148
149         // If we have the same settings, don't play again
150         // This is to resolve potential issues with pulses on sensors such as the ones
151         // reported in bug #29412. The fix is here so it works for both logic bricks and Python.
152         // However, this may eventually lead to issues where a user wants to override an already
153         // playing action with the same action and settings. If this becomes an issue,
154         // then this fix may have to be re-evaluated.
155         if (!IsDone() && m_action == prev_action && m_startframe == start && m_endframe == end
156                         && m_priority == priority && m_speed == playback_speed)
157                 return false;
158
159         // First get rid of any old controllers
160         ClearControllerList();
161
162         // Create an SG_Controller
163         SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, kxscene->GetSceneConverter());
164         m_sg_contr_list.push_back(sg_contr);
165         m_obj->GetSGNode()->AddSGController(sg_contr);
166         sg_contr->SetObject(m_obj->GetSGNode());
167
168         // Try obcolor
169         sg_contr = BL_CreateObColorIPO(m_action, m_obj, kxscene->GetSceneConverter());
170         if (sg_contr) {
171                 m_sg_contr_list.push_back(sg_contr);
172                 m_obj->GetSGNode()->AddSGController(sg_contr);
173                 sg_contr->SetObject(m_obj->GetSGNode());
174         }
175
176         // Now try materials
177         if (m_obj->GetBlenderObject()->totcol==1) {
178                 Material *mat = give_current_material(m_obj->GetBlenderObject(), 1);
179                 if (mat) {
180                         sg_contr = BL_CreateMaterialIpo(m_action, mat, 0, m_obj, kxscene->GetSceneConverter());
181                         if (sg_contr) {
182                                 m_sg_contr_list.push_back(sg_contr);
183                                 m_obj->GetSGNode()->AddSGController(sg_contr);
184                                 sg_contr->SetObject(m_obj->GetSGNode());
185                         }
186                 }
187         } else {
188                 Material *mat;
189                 STR_HashedString matname;
190
191                 for (int matidx = 1; matidx <= m_obj->GetBlenderObject()->totcol; ++matidx) {
192                         mat = give_current_material(m_obj->GetBlenderObject(), matidx);
193                         if (mat) {
194                                 matname = mat->id.name;
195                                 sg_contr = BL_CreateMaterialIpo(m_action, mat, matname.hash(), m_obj, kxscene->GetSceneConverter());
196                                 if (sg_contr) {
197                                         m_sg_contr_list.push_back(sg_contr);
198                                         m_obj->GetSGNode()->AddSGController(sg_contr);
199                                         sg_contr->SetObject(m_obj->GetSGNode());
200                                 }
201                         }
202                 }
203         }
204
205         // Extra controllers
206         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
207         {
208                 sg_contr = BL_CreateLampIPO(m_action, m_obj, kxscene->GetSceneConverter());
209                 m_sg_contr_list.push_back(sg_contr);
210                 m_obj->GetSGNode()->AddSGController(sg_contr);
211                 sg_contr->SetObject(m_obj->GetSGNode());
212         }
213         else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
214         {
215                 sg_contr = BL_CreateCameraIPO(m_action, m_obj, kxscene->GetSceneConverter());
216                 m_sg_contr_list.push_back(sg_contr);
217                 m_obj->GetSGNode()->AddSGController(sg_contr);
218                 sg_contr->SetObject(m_obj->GetSGNode());
219         }
220         
221         m_ipo_flags = ipo_flags;
222         InitIPO();
223
224         // Setup blendin shapes/poses
225         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
226         {
227                 BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
228                 obj->GetMRDPose(&m_blendinpose);
229         }
230         else
231         {
232                 BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
233                 BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
234                 
235                 if (shape_deformer && shape_deformer->GetKey())
236                 {
237                         obj->GetShape(m_blendinshape);
238
239                         // Now that we have the previous blend shape saved, we can clear out the key to avoid any
240                         // further interference.
241                         KeyBlock *kb;
242                         for (kb=(KeyBlock *)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock *)kb->next)
243                                 kb->curval = 0.f;
244                 }
245         }
246
247         // Now that we have an action, we have something we can play
248         m_starttime = -1.f; // We get the start time on our first update
249         m_startframe = m_localtime = start;
250         m_endframe = end;
251         m_blendin = blendin;
252         m_playmode = play_mode;
253         m_endtime = 0.f;
254         m_blendframe = 0.f;
255         m_blendstart = 0.f;
256         m_speed = playback_speed;
257         m_layer_weight = layer_weight;
258         
259         m_done = false;
260
261         return true;
262 }
263
264 void BL_Action::Stop()
265 {
266         m_done = true;
267 }
268
269 bool BL_Action::IsDone()
270 {
271         return m_done;
272 }
273
274 void BL_Action::InitIPO()
275 {
276         // Initialize the IPOs
277         std::vector<SG_Controller*>::iterator it;
278         for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
279         {
280                 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
281                 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE);
282                 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD);
283                 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL);
284         }
285 }
286
287 bAction *BL_Action::GetAction()
288 {
289         return (IsDone()) ? NULL : m_action;
290 }
291
292 float BL_Action::GetFrame()
293 {
294         return m_localtime;
295 }
296
297 void BL_Action::SetFrame(float frame)
298 {
299         // Clamp the frame to the start and end frame
300         if (frame < min(m_startframe, m_endframe))
301                 frame = min(m_startframe, m_endframe);
302         else if (frame > max(m_startframe, m_endframe))
303                 frame = max(m_startframe, m_endframe);
304         
305         m_localtime = frame;
306         m_calc_localtime = false;
307 }
308
309 void BL_Action::SetPlayMode(short play_mode)
310 {
311         m_playmode = play_mode;
312 }
313
314 void BL_Action::SetTimes(float start, float end)
315 {
316         m_startframe = start;
317         m_endframe = end;
318 }
319
320 void BL_Action::SetLocalTime(float curtime)
321 {
322         float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
323
324         if (m_endframe < m_startframe)
325                 dt = -dt;
326
327         m_localtime = m_startframe + dt;
328 }
329
330 void BL_Action::ResetStartTime(float curtime)
331 {
332         float dt = (m_localtime > m_startframe) ? m_localtime - m_startframe : m_startframe - m_localtime;
333
334         m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
335         SetLocalTime(curtime);
336 }
337
338 void BL_Action::IncrementBlending(float curtime)
339 {
340         // Setup m_blendstart if we need to
341         if (m_blendstart == 0.f)
342                 m_blendstart = curtime;
343         
344         // Bump the blend frame
345         m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
346
347         // Clamp
348         if (m_blendframe>m_blendin)
349                 m_blendframe = m_blendin;
350 }
351
352
353 void BL_Action::BlendShape(Key* key, float srcweight, std::vector<float>& blendshape)
354 {
355         vector<float>::const_iterator it;
356         float dstweight;
357         KeyBlock *kb;
358         
359         dstweight = 1.0F - srcweight;
360         //printf("Dst: %f\tSrc: %f\n", srcweight, dstweight);
361         for (it=blendshape.begin(), kb = (KeyBlock *)key->block.first; 
362              kb && it != blendshape.end();
363              kb = (KeyBlock *)kb->next, it++)
364         {
365                 //printf("OirgKeys: %f\t%f\n", kb->curval, (*it));
366                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
367                 //printf("NewKey: %f\n", kb->curval);
368         }
369         //printf("\n");
370 }
371
372 void BL_Action::Update(float curtime)
373 {
374         // Don't bother if we're done with the animation
375         if (m_done)
376                 return;
377
378         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
379
380         // Grab the start time here so we don't end up with a negative m_localtime when
381         // suspending and resuming scenes.
382         if (m_starttime < 0)
383                 m_starttime = curtime;
384
385         if (m_calc_localtime)
386                 SetLocalTime(curtime);
387         else
388         {
389                 ResetStartTime(curtime);
390                 m_calc_localtime = true;
391         }
392
393         // Handle wrap around
394         if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) {
395                 switch (m_playmode) {
396                         case ACT_MODE_PLAY:
397                                 // Clamp
398                                 m_localtime = m_endframe;
399                                 m_done = true;
400                                 break;
401                         case ACT_MODE_LOOP:
402                                 // Put the time back to the beginning
403                                 m_localtime = m_startframe;
404                                 m_starttime = curtime;
405                                 break;
406                         case ACT_MODE_PING_PONG:
407                                 // Swap the start and end frames
408                                 float temp = m_startframe;
409                                 m_startframe = m_endframe;
410                                 m_endframe = temp;
411
412                                 m_starttime = curtime;
413
414                                 break;
415                 }
416         }
417
418         if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
419         {
420                 BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
421                 obj->GetPose(&m_pose);
422
423                 // Extract the pose from the action
424                 {
425                         Object *arm = obj->GetArmatureObject();
426                         bPose *temp = arm->pose;
427
428                         arm->pose = m_pose;
429                         animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
430
431                         arm->pose = temp;
432                 }
433
434                 // Handle blending between armature actions
435                 if (m_blendin && m_blendframe<m_blendin)
436                 {
437                         IncrementBlending(curtime);
438
439                         // Calculate weight
440                         float weight = 1.f - (m_blendframe/m_blendin);
441
442                         // Blend the poses
443                         game_blend_poses(m_pose, m_blendinpose, weight);
444                 }
445
446
447                 // Handle layer blending
448                 if (m_layer_weight >= 0)
449                 {
450                         obj->GetMRDPose(&m_blendpose);
451                         game_blend_poses(m_pose, m_blendpose, m_layer_weight);
452                 }
453
454                 obj->SetPose(m_pose);
455
456                 obj->SetActiveAction(NULL, 0, curtime);
457         }
458         else
459         {
460                 BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
461                 BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
462
463                 // Handle shape actions if we have any
464                 if (shape_deformer && shape_deformer->GetKey())
465                 {
466                         Key *key = shape_deformer->GetKey();
467
468
469                         animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
470
471                         // Handle blending between shape actions
472                         if (m_blendin && m_blendframe < m_blendin)
473                         {
474                                 IncrementBlending(curtime);
475
476                                 float weight = 1.f - (m_blendframe/m_blendin);
477
478                                 // We go through and clear out the keyblocks so there isn't any interference
479                                 // from other shape actions
480                                 KeyBlock *kb;
481                                 for (kb=(KeyBlock *)key->block.first; kb; kb=(KeyBlock *)kb->next)
482                                         kb->curval = 0.f;
483
484                                 // Now blend the shape
485                                 BlendShape(key, weight, m_blendinshape);
486                         }
487
488                         // Handle layer blending
489                         if (m_layer_weight >= 0)
490                         {
491                                 obj->GetShape(m_blendshape);
492                                 BlendShape(key, m_layer_weight, m_blendshape);
493                         }
494
495                         obj->SetActiveAction(NULL, 0, curtime);
496                 }
497
498                 m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
499         }
500
501         if (m_done)
502                 ClearControllerList();
503 }