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