aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp1132
1 files changed, 1132 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp
new file mode 100644
index 0000000..9b9f533
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshSceneNode.cpp
@@ -0,0 +1,1132 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CAnimatedMeshSceneNode.h"
6#include "IVideoDriver.h"
7#include "ISceneManager.h"
8#include "S3DVertex.h"
9#include "os.h"
10#include "CShadowVolumeSceneNode.h"
11#include "IAnimatedMeshMD3.h"
12#include "CSkinnedMesh.h"
13#include "IDummyTransformationSceneNode.h"
14#include "IBoneSceneNode.h"
15#include "IMaterialRenderer.h"
16#include "IMesh.h"
17#include "IMeshCache.h"
18#include "IAnimatedMesh.h"
19#include "quaternion.h"
20
21
22namespace irr
23{
24namespace scene
25{
26
27
28//! constructor
29CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh,
30 ISceneNode* parent, ISceneManager* mgr, s32 id,
31 const core::vector3df& position,
32 const core::vector3df& rotation,
33 const core::vector3df& scale)
34: IAnimatedMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
35 StartFrame(0), EndFrame(0), FramesPerSecond(0.025f),
36 CurrentFrameNr(0.f), LastTimeMs(0),
37 TransitionTime(0), Transiting(0.f), TransitingBlend(0.f),
38 JointMode(EJUOR_NONE), JointsUsed(false),
39 Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false),
40 LoopCallBack(0), PassCount(0), Shadow(0), MD3Special(0)
41{
42 #ifdef _DEBUG
43 setDebugName("CAnimatedMeshSceneNode");
44 #endif
45
46 setMesh(mesh);
47}
48
49
50//! destructor
51CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode()
52{
53 if (MD3Special)
54 MD3Special->drop();
55
56 if (Mesh)
57 Mesh->drop();
58
59 if (Shadow)
60 Shadow->drop();
61
62 if (LoopCallBack)
63 LoopCallBack->drop();
64}
65
66
67//! Sets the current frame. From now on the animation is played from this frame.
68void CAnimatedMeshSceneNode::setCurrentFrame(f32 frame)
69{
70 // if you pass an out of range value, we just clamp it
71 CurrentFrameNr = core::clamp ( frame, (f32)StartFrame, (f32)EndFrame );
72
73 beginTransition(); //transit to this frame if enabled
74}
75
76
77//! Returns the currently displayed frame number.
78f32 CAnimatedMeshSceneNode::getFrameNr() const
79{
80 return CurrentFrameNr;
81}
82
83
84//! Get CurrentFrameNr and update transiting settings
85void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
86{
87 if (Transiting!=0.f)
88 {
89 TransitingBlend += (f32)(timeMs) * Transiting;
90 if (TransitingBlend > 1.f)
91 {
92 Transiting=0.f;
93 TransitingBlend=0.f;
94 }
95 }
96
97 if ((StartFrame==EndFrame))
98 {
99 CurrentFrameNr = (f32)StartFrame; //Support for non animated meshes
100 }
101 else if (Looping)
102 {
103 // play animation looped
104 CurrentFrameNr += timeMs * FramesPerSecond;
105
106 // We have no interpolation between EndFrame and StartFrame,
107 // the last frame must be identical to first one with our current solution.
108 if (FramesPerSecond > 0.f) //forwards...
109 {
110 if (CurrentFrameNr > EndFrame)
111 CurrentFrameNr = StartFrame + fmod(CurrentFrameNr - StartFrame, (f32)(EndFrame-StartFrame));
112 }
113 else //backwards...
114 {
115 if (CurrentFrameNr < StartFrame)
116 CurrentFrameNr = EndFrame - fmod(EndFrame - CurrentFrameNr, (f32)(EndFrame-StartFrame));
117 }
118 }
119 else
120 {
121 // play animation non looped
122
123 CurrentFrameNr += timeMs * FramesPerSecond;
124 if (FramesPerSecond > 0.f) //forwards...
125 {
126 if (CurrentFrameNr > (f32)EndFrame)
127 {
128 CurrentFrameNr = (f32)EndFrame;
129 if (LoopCallBack)
130 LoopCallBack->OnAnimationEnd(this);
131 }
132 }
133 else //backwards...
134 {
135 if (CurrentFrameNr < (f32)StartFrame)
136 {
137 CurrentFrameNr = (f32)StartFrame;
138 if (LoopCallBack)
139 LoopCallBack->OnAnimationEnd(this);
140 }
141 }
142 }
143}
144
145
146void CAnimatedMeshSceneNode::OnRegisterSceneNode()
147{
148 if (IsVisible)
149 {
150 // because this node supports rendering of mixed mode meshes consisting of
151 // transparent and solid material at the same time, we need to go through all
152 // materials, check of what type they are and register this node for the right
153 // render pass according to that.
154
155 video::IVideoDriver* driver = SceneManager->getVideoDriver();
156
157 PassCount = 0;
158 int transparentCount = 0;
159 int solidCount = 0;
160
161 // count transparent and solid materials in this scene node
162 for (u32 i=0; i<Materials.size(); ++i)
163 {
164 video::IMaterialRenderer* rnd =
165 driver->getMaterialRenderer(Materials[i].MaterialType);
166
167 if (rnd && rnd->isTransparent())
168 ++transparentCount;
169 else
170 ++solidCount;
171
172 if (solidCount && transparentCount)
173 break;
174 }
175
176 // register according to material types counted
177
178 if (solidCount)
179 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
180
181 if (transparentCount)
182 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
183
184 ISceneNode::OnRegisterSceneNode();
185 }
186}
187
188IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
189{
190 if(Mesh->getMeshType() != EAMT_SKINNED)
191 {
192 s32 frameNr = (s32) getFrameNr();
193 s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f);
194 return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
195 }
196 else
197 {
198#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
199 return 0;
200#else
201
202 // As multiple scene nodes may be sharing the same skinned mesh, we have to
203 // re-animate it every frame to ensure that this node gets the mesh that it needs.
204
205 CSkinnedMesh* skinnedMesh = reinterpret_cast<CSkinnedMesh*>(Mesh);
206
207 if (JointMode == EJUOR_CONTROL)//write to mesh
208 skinnedMesh->transferJointsToMesh(JointChildSceneNodes);
209 else
210 skinnedMesh->animateMesh(getFrameNr(), 1.0f);
211
212 // Update the skinned mesh for the current joint transforms.
213 skinnedMesh->skinMesh();
214
215 if (JointMode == EJUOR_READ)//read from mesh
216 {
217 skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes);
218
219 //---slow---
220 for (u32 n=0;n<JointChildSceneNodes.size();++n)
221 if (JointChildSceneNodes[n]->getParent()==this)
222 {
223 JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option
224 }
225 }
226
227 if(JointMode == EJUOR_CONTROL)
228 {
229 // For meshes other than EJUOR_CONTROL, this is done by calling animateMesh()
230 skinnedMesh->updateBoundingBox();
231 }
232
233 return skinnedMesh;
234#endif
235 }
236}
237
238
239//! OnAnimate() is called just before rendering the whole scene.
240void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs)
241{
242 if (LastTimeMs==0) // first frame
243 {
244 LastTimeMs = timeMs;
245 }
246
247 // set CurrentFrameNr
248 buildFrameNr(timeMs-LastTimeMs);
249
250 // update bbox
251 if (Mesh)
252 {
253 scene::IMesh * mesh = getMeshForCurrentFrame();
254
255 if (mesh)
256 Box = mesh->getBoundingBox();
257 }
258 LastTimeMs = timeMs;
259
260 IAnimatedMeshSceneNode::OnAnimate(timeMs);
261}
262
263
264//! renders the node.
265void CAnimatedMeshSceneNode::render()
266{
267 video::IVideoDriver* driver = SceneManager->getVideoDriver();
268
269 if (!Mesh || !driver)
270 return;
271
272
273 bool isTransparentPass =
274 SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
275
276 ++PassCount;
277
278 scene::IMesh* m = getMeshForCurrentFrame();
279
280 if(m)
281 {
282 Box = m->getBoundingBox();
283 }
284 else
285 {
286 #ifdef _DEBUG
287 os::Printer::log("Animated Mesh returned no mesh to render.", Mesh->getDebugName(), ELL_WARNING);
288 #endif
289 }
290
291 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
292
293 if (Shadow && PassCount==1)
294 Shadow->updateShadowVolumes();
295
296 // for debug purposes only:
297
298 bool renderMeshes = true;
299 video::SMaterial mat;
300 if (DebugDataVisible && PassCount==1)
301 {
302 // overwrite half transparency
303 if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)
304 {
305
306 for (u32 i=0; i<m->getMeshBufferCount(); ++i)
307 {
308 scene::IMeshBuffer* mb = m->getMeshBuffer(i);
309 mat = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
310 mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
311 if (RenderFromIdentity)
312 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix );
313 else if (Mesh->getMeshType() == EAMT_SKINNED)
314 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation);
315
316 driver->setMaterial(mat);
317 driver->drawMeshBuffer(mb);
318 }
319 renderMeshes = false;
320 }
321 }
322
323 // render original meshes
324 if (renderMeshes)
325 {
326 for (u32 i=0; i<m->getMeshBufferCount(); ++i)
327 {
328 video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType);
329 bool transparent = (rnd && rnd->isTransparent());
330
331 // only render transparent buffer if this is the transparent render pass
332 // and solid only in solid pass
333 if (transparent == isTransparentPass)
334 {
335 scene::IMeshBuffer* mb = m->getMeshBuffer(i);
336 const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
337 if (RenderFromIdentity)
338 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix );
339 else if (Mesh->getMeshType() == EAMT_SKINNED)
340 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation);
341
342 driver->setMaterial(material);
343 driver->drawMeshBuffer(mb);
344 }
345 }
346 }
347
348 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
349
350 // for debug purposes only:
351 if (DebugDataVisible && PassCount==1)
352 {
353 video::SMaterial debug_mat;
354 debug_mat.Lighting = false;
355 debug_mat.AntiAliasing=0;
356 driver->setMaterial(debug_mat);
357 // show normals
358 if (DebugDataVisible & scene::EDS_NORMALS)
359 {
360 const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
361 const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
362 const u32 count = m->getMeshBufferCount();
363
364 // draw normals
365 for (u32 g=0; g < count; ++g)
366 {
367 driver->drawMeshBufferNormals(m->getMeshBuffer(g), debugNormalLength, debugNormalColor);
368 }
369 }
370
371 debug_mat.ZBuffer = video::ECFN_NEVER;
372 debug_mat.Lighting = false;
373 driver->setMaterial(debug_mat);
374
375 if (DebugDataVisible & scene::EDS_BBOX)
376 driver->draw3DBox(Box, video::SColor(255,255,255,255));
377
378 // show bounding box
379 if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
380 {
381 for (u32 g=0; g< m->getMeshBufferCount(); ++g)
382 {
383 const IMeshBuffer* mb = m->getMeshBuffer(g);
384
385 if (Mesh->getMeshType() == EAMT_SKINNED)
386 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation);
387 driver->draw3DBox(mb->getBoundingBox(), video::SColor(255,190,128,128));
388 }
389 }
390
391 // show skeleton
392 if (DebugDataVisible & scene::EDS_SKELETON)
393 {
394 if (Mesh->getMeshType() == EAMT_SKINNED)
395 {
396 // draw skeleton
397
398 for (u32 g=0; g < ((ISkinnedMesh*)Mesh)->getAllJoints().size(); ++g)
399 {
400 ISkinnedMesh::SJoint *joint=((ISkinnedMesh*)Mesh)->getAllJoints()[g];
401
402 for (u32 n=0;n<joint->Children.size();++n)
403 {
404 driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(),
405 joint->Children[n]->GlobalAnimatedMatrix.getTranslation(),
406 video::SColor(255,51,66,255));
407 }
408 }
409 }
410
411 // show tag for quake3 models
412 if (Mesh->getMeshType() == EAMT_MD3)
413 {
414 IAnimatedMesh * arrow =
415 SceneManager->addArrowMesh (
416 "__tag_show",
417 0xFF0000FF, 0xFF000088,
418 4, 8, 5.f, 4.f, 0.5f,
419 1.f);
420 if (!arrow)
421 {
422 arrow = SceneManager->getMesh ( "__tag_show" );
423 }
424 IMesh *arrowMesh = arrow->getMesh(0);
425
426 core::matrix4 matr;
427
428 SMD3QuaternionTagList *taglist = ((IAnimatedMeshMD3*)Mesh)->getTagList(
429 (s32)getFrameNr(), 255,
430 getStartFrame(), getEndFrame());
431 if (taglist)
432 {
433 for ( u32 ts = 0; ts != taglist->size(); ++ts )
434 {
435 (*taglist)[ts].setto(matr);
436
437 driver->setTransform(video::ETS_WORLD, matr );
438
439 for ( u32 a = 0; a != arrowMesh->getMeshBufferCount(); ++a )
440 driver->drawMeshBuffer(arrowMesh->getMeshBuffer(a));
441 }
442 }
443 }
444 }
445
446 // show mesh
447 if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
448 {
449 debug_mat.Lighting = false;
450 debug_mat.Wireframe = true;
451 debug_mat.ZBuffer = video::ECFN_NEVER;
452 driver->setMaterial(debug_mat);
453
454 for (u32 g=0; g<m->getMeshBufferCount(); ++g)
455 {
456 const IMeshBuffer* mb = m->getMeshBuffer(g);
457 if (RenderFromIdentity)
458 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix );
459 else if (Mesh->getMeshType() == EAMT_SKINNED)
460 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation);
461 driver->drawMeshBuffer(mb);
462 }
463 }
464 }
465}
466
467
468//! Returns the current start frame number.
469s32 CAnimatedMeshSceneNode::getStartFrame() const
470{
471 return StartFrame;
472}
473
474
475//! Returns the current start frame number.
476s32 CAnimatedMeshSceneNode::getEndFrame() const
477{
478 return EndFrame;
479}
480
481
482//! sets the frames between the animation is looped.
483//! the default is 0 - MaximalFrameCount of the mesh.
484bool CAnimatedMeshSceneNode::setFrameLoop(s32 begin, s32 end)
485{
486 const s32 maxFrameCount = Mesh->getFrameCount() - 1;
487 if (end < begin)
488 {
489 StartFrame = core::s32_clamp(end, 0, maxFrameCount);
490 EndFrame = core::s32_clamp(begin, StartFrame, maxFrameCount);
491 }
492 else
493 {
494 StartFrame = core::s32_clamp(begin, 0, maxFrameCount);
495 EndFrame = core::s32_clamp(end, StartFrame, maxFrameCount);
496 }
497 if (FramesPerSecond < 0)
498 setCurrentFrame((f32)EndFrame);
499 else
500 setCurrentFrame((f32)StartFrame);
501
502 return true;
503}
504
505
506//! sets the speed with witch the animation is played
507void CAnimatedMeshSceneNode::setAnimationSpeed(f32 framesPerSecond)
508{
509 FramesPerSecond = framesPerSecond * 0.001f;
510}
511
512
513f32 CAnimatedMeshSceneNode::getAnimationSpeed() const
514{
515 return FramesPerSecond * 1000.f;
516}
517
518
519//! returns the axis aligned bounding box of this node
520const core::aabbox3d<f32>& CAnimatedMeshSceneNode::getBoundingBox() const
521{
522 return Box;
523}
524
525
526//! returns the material based on the zero based index i. To get the amount
527//! of materials used by this scene node, use getMaterialCount().
528//! This function is needed for inserting the node into the scene hirachy on a
529//! optimal position for minimizing renderstate changes, but can also be used
530//! to directly modify the material of a scene node.
531video::SMaterial& CAnimatedMeshSceneNode::getMaterial(u32 i)
532{
533 if (i >= Materials.size())
534 return ISceneNode::getMaterial(i);
535
536 return Materials[i];
537}
538
539
540
541//! returns amount of materials used by this scene node.
542u32 CAnimatedMeshSceneNode::getMaterialCount() const
543{
544 return Materials.size();
545}
546
547
548//! Creates shadow volume scene node as child of this node
549//! and returns a pointer to it.
550IShadowVolumeSceneNode* CAnimatedMeshSceneNode::addShadowVolumeSceneNode(
551 const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
552{
553 if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
554 return 0;
555
556 if (!shadowMesh)
557 shadowMesh = Mesh; // if null is given, use the mesh of node
558
559 if (Shadow)
560 Shadow->drop();
561
562 Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
563 return Shadow;
564}
565
566//! Returns a pointer to a child node, which has the same transformation as
567//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
568IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName)
569{
570#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
571 os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
572 return 0;
573#else
574
575 if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
576 {
577 os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING);
578 return 0;
579 }
580
581 checkJoints();
582
583 ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh;
584
585 const s32 number = skinnedMesh->getJointNumber(jointName);
586
587 if (number == -1)
588 {
589 os::Printer::log("Joint with specified name not found in skinned mesh", jointName, ELL_DEBUG);
590 return 0;
591 }
592
593 if ((s32)JointChildSceneNodes.size() <= number)
594 {
595 os::Printer::log("Joint was found in mesh, but is not loaded into node", jointName, ELL_WARNING);
596 return 0;
597 }
598
599 return JointChildSceneNodes[number];
600#endif
601}
602
603
604
605//! Returns a pointer to a child node, which has the same transformation as
606//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
607IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(u32 jointID)
608{
609#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
610 os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
611 return 0;
612#else
613
614 if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
615 {
616 os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING);
617 return 0;
618 }
619
620 checkJoints();
621
622 if (JointChildSceneNodes.size() <= jointID)
623 {
624 os::Printer::log("Joint not loaded into node", ELL_WARNING);
625 return 0;
626 }
627
628 return JointChildSceneNodes[jointID];
629#endif
630}
631
632//! Gets joint count.
633u32 CAnimatedMeshSceneNode::getJointCount() const
634{
635#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
636 return 0;
637#else
638
639 if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
640 return 0;
641
642 ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh;
643
644 return skinnedMesh->getJointCount();
645#endif
646}
647
648
649//! Returns a pointer to a child node, which has the same transformation as
650//! the corresponding joint, if the mesh in this scene node is a ms3d mesh.
651ISceneNode* CAnimatedMeshSceneNode::getMS3DJointNode(const c8* jointName)
652{
653 return getJointNode(jointName);
654}
655
656
657//! Returns a pointer to a child node, which has the same transformation as
658//! the corresponding joint, if the mesh in this scene node is a .x mesh.
659ISceneNode* CAnimatedMeshSceneNode::getXJointNode(const c8* jointName)
660{
661 return getJointNode(jointName);
662}
663
664//! Removes a child from this scene node.
665//! Implemented here, to be able to remove the shadow properly, if there is one,
666//! or to remove attached childs.
667bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child)
668{
669 if (child && Shadow == child)
670 {
671 Shadow->drop();
672 Shadow = 0;
673 }
674
675 if (ISceneNode::removeChild(child))
676 {
677 if (JointsUsed) //stop weird bugs caused while changing parents as the joints are being created
678 {
679 for (u32 i=0; i<JointChildSceneNodes.size(); ++i)
680 {
681 if (JointChildSceneNodes[i] == child)
682 {
683 JointChildSceneNodes[i] = 0; //remove link to child
684 break;
685 }
686 }
687 }
688 return true;
689 }
690
691 return false;
692}
693
694
695//! Starts a MD2 animation.
696bool CAnimatedMeshSceneNode::setMD2Animation(EMD2_ANIMATION_TYPE anim)
697{
698 if (!Mesh || Mesh->getMeshType() != EAMT_MD2)
699 return false;
700
701 IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh;
702
703 s32 begin, end, speed;
704 md->getFrameLoop(anim, begin, end, speed);
705
706 setAnimationSpeed( f32(speed) );
707 setFrameLoop(begin, end);
708 return true;
709}
710
711
712//! Starts a special MD2 animation.
713bool CAnimatedMeshSceneNode::setMD2Animation(const c8* animationName)
714{
715 if (!Mesh || Mesh->getMeshType() != EAMT_MD2)
716 return false;
717
718 IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh;
719
720 s32 begin, end, speed;
721 if (!md->getFrameLoop(animationName, begin, end, speed))
722 return false;
723
724 setAnimationSpeed( (f32)speed );
725 setFrameLoop(begin, end);
726 return true;
727}
728
729
730//! Sets looping mode which is on by default. If set to false,
731//! animations will not be looped.
732void CAnimatedMeshSceneNode::setLoopMode(bool playAnimationLooped)
733{
734 Looping = playAnimationLooped;
735}
736
737//! returns the current loop mode
738bool CAnimatedMeshSceneNode::getLoopMode() const
739{
740 return Looping;
741}
742
743
744//! Sets a callback interface which will be called if an animation
745//! playback has ended. Set this to 0 to disable the callback again.
746void CAnimatedMeshSceneNode::setAnimationEndCallback(IAnimationEndCallBack* callback)
747{
748 if (callback == LoopCallBack)
749 return;
750
751 if (LoopCallBack)
752 LoopCallBack->drop();
753
754 LoopCallBack = callback;
755
756 if (LoopCallBack)
757 LoopCallBack->grab();
758}
759
760
761//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
762void CAnimatedMeshSceneNode::setReadOnlyMaterials(bool readonly)
763{
764 ReadOnlyMaterials = readonly;
765}
766
767
768//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
769bool CAnimatedMeshSceneNode::isReadOnlyMaterials() const
770{
771 return ReadOnlyMaterials;
772}
773
774
775//! Writes attributes of the scene node.
776void CAnimatedMeshSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
777{
778 IAnimatedMeshSceneNode::serializeAttributes(out, options);
779
780 if (options && (options->Flags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename)
781 {
782 const io::path path = SceneManager->getFileSystem()->getRelativeFilename(
783 SceneManager->getFileSystem()->getAbsolutePath(SceneManager->getMeshCache()->getMeshName(Mesh).getPath()),
784 options->Filename);
785 out->addString("Mesh", path.c_str());
786 }
787 else
788 out->addString("Mesh", SceneManager->getMeshCache()->getMeshName(Mesh).getPath().c_str());
789 out->addBool("Looping", Looping);
790 out->addBool("ReadOnlyMaterials", ReadOnlyMaterials);
791 out->addFloat("FramesPerSecond", FramesPerSecond);
792 out->addInt("StartFrame", StartFrame);
793 out->addInt("EndFrame", EndFrame);
794}
795
796
797//! Reads attributes of the scene node.
798void CAnimatedMeshSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
799{
800 IAnimatedMeshSceneNode::deserializeAttributes(in, options);
801
802 io::path oldMeshStr = SceneManager->getMeshCache()->getMeshName(Mesh);
803 io::path newMeshStr = in->getAttributeAsString("Mesh");
804
805 Looping = in->getAttributeAsBool("Looping");
806 ReadOnlyMaterials = in->getAttributeAsBool("ReadOnlyMaterials");
807 FramesPerSecond = in->getAttributeAsFloat("FramesPerSecond");
808 StartFrame = in->getAttributeAsInt("StartFrame");
809 EndFrame = in->getAttributeAsInt("EndFrame");
810
811 if (newMeshStr != "" && oldMeshStr != newMeshStr)
812 {
813 IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str());
814
815 if (newAnimatedMesh)
816 setMesh(newAnimatedMesh);
817 }
818
819 // TODO: read animation names instead of frame begin and ends
820}
821
822
823//! Sets a new mesh
824void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh)
825{
826 if (!mesh)
827 return; // won't set null mesh
828
829 if (Mesh != mesh)
830 {
831 if (Mesh)
832 Mesh->drop();
833
834 Mesh = mesh;
835
836 // grab the mesh (it's non-null!)
837 Mesh->grab();
838 }
839
840 // get materials and bounding box
841 Box = Mesh->getBoundingBox();
842
843 IMesh* m = Mesh->getMesh(0,0);
844 if (m)
845 {
846 Materials.clear();
847 Materials.reallocate(m->getMeshBufferCount());
848
849 for (u32 i=0; i<m->getMeshBufferCount(); ++i)
850 {
851 IMeshBuffer* mb = m->getMeshBuffer(i);
852 if (mb)
853 Materials.push_back(mb->getMaterial());
854 else
855 Materials.push_back(video::SMaterial());
856 }
857 }
858
859 // clean up joint nodes
860 if (JointsUsed)
861 {
862 JointsUsed=false;
863 checkJoints();
864 }
865
866 // get start and begin time
867// setAnimationSpeed(Mesh->getAnimationSpeed());
868 setFrameLoop(0, Mesh->getFrameCount());
869}
870
871
872// returns the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh,
873// or the absolutetransformation if it's a normal scenenode
874const SMD3QuaternionTag* CAnimatedMeshSceneNode::getMD3TagTransformation(const core::stringc& tagname)
875{
876 return MD3Special ? MD3Special->AbsoluteTagList.get(tagname) : 0;
877}
878
879
880//! updates the absolute position based on the relative and the parents position
881void CAnimatedMeshSceneNode::updateAbsolutePosition()
882{
883 IAnimatedMeshSceneNode::updateAbsolutePosition();
884
885 if (!Mesh || Mesh->getMeshType() != EAMT_MD3)
886 return;
887
888 SMD3QuaternionTagList *taglist;
889 taglist = ( (IAnimatedMeshMD3*) Mesh )->getTagList ( (s32)getFrameNr(),255,getStartFrame (),getEndFrame () );
890 if (taglist)
891 {
892 if (!MD3Special)
893 {
894 MD3Special = new SMD3Special();
895 }
896
897 SMD3QuaternionTag parent ( MD3Special->Tagname );
898 if (Parent && Parent->getType() == ESNT_ANIMATED_MESH)
899 {
900 const SMD3QuaternionTag * p = ((IAnimatedMeshSceneNode*) Parent)->getMD3TagTransformation
901 ( MD3Special->Tagname );
902
903 if (p)
904 parent = *p;
905 }
906
907 SMD3QuaternionTag relative( RelativeTranslation, RelativeRotation );
908
909 MD3Special->AbsoluteTagList.set_used ( taglist->size () );
910 for ( u32 i=0; i!= taglist->size (); ++i )
911 {
912 MD3Special->AbsoluteTagList[i].position = parent.position + (*taglist)[i].position + relative.position;
913 MD3Special->AbsoluteTagList[i].rotation = parent.rotation * (*taglist)[i].rotation * relative.rotation;
914 }
915 }
916}
917
918//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set)
919void CAnimatedMeshSceneNode::setJointMode(E_JOINT_UPDATE_ON_RENDER mode)
920{
921 checkJoints();
922 JointMode=mode;
923}
924
925//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2)
926//! you must call animateJoints(), or the mesh will not animate
927void CAnimatedMeshSceneNode::setTransitionTime(f32 time)
928{
929 const u32 ttime = (u32)core::floor32(time*1000.0f);
930 if (TransitionTime==ttime)
931 return;
932 TransitionTime = ttime;
933 if (ttime != 0)
934 setJointMode(EJUOR_CONTROL);
935 else
936 setJointMode(EJUOR_NONE);
937}
938
939
940//! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected)
941void CAnimatedMeshSceneNode::setRenderFromIdentity(bool enable)
942{
943 RenderFromIdentity=enable;
944}
945
946
947//! updates the joint positions of this mesh
948void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
949{
950#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
951 return;
952#else
953 if (Mesh && Mesh->getMeshType() == EAMT_SKINNED )
954 {
955 checkJoints();
956 const f32 frame = getFrameNr(); //old?
957
958 CSkinnedMesh* skinnedMesh=reinterpret_cast<CSkinnedMesh*>(Mesh);
959
960 skinnedMesh->transferOnlyJointsHintsToMesh( JointChildSceneNodes );
961 skinnedMesh->animateMesh(frame, 1.0f);
962 skinnedMesh->recoverJointsFromMesh( JointChildSceneNodes);
963
964 //-----------------------------------------
965 // Transition
966 //-----------------------------------------
967
968 if (Transiting != 0.f)
969 {
970 // Init additional matrices
971 if (PretransitingSave.size()<JointChildSceneNodes.size())
972 {
973 for(u32 n=PretransitingSave.size(); n<JointChildSceneNodes.size(); ++n)
974 PretransitingSave.push_back(core::matrix4());
975 }
976
977 for (u32 n=0; n<JointChildSceneNodes.size(); ++n)
978 {
979 //------Position------
980
981 JointChildSceneNodes[n]->setPosition(
982 core::lerp(
983 PretransitingSave[n].getTranslation(),
984 JointChildSceneNodes[n]->getPosition(),
985 TransitingBlend));
986
987 //------Rotation------
988
989 //Code is slow, needs to be fixed up
990
991 const core::quaternion RotationStart(PretransitingSave[n].getRotationDegrees()*core::DEGTORAD);
992 const core::quaternion RotationEnd(JointChildSceneNodes[n]->getRotation()*core::DEGTORAD);
993
994 core::quaternion QRotation;
995 QRotation.slerp(RotationStart, RotationEnd, TransitingBlend);
996
997 core::vector3df tmpVector;
998 QRotation.toEuler(tmpVector);
999 tmpVector*=core::RADTODEG; //convert from radians back to degrees
1000 JointChildSceneNodes[n]->setRotation( tmpVector );
1001
1002 //------Scale------
1003
1004 //JointChildSceneNodes[n]->setScale(
1005 // core::lerp(
1006 // PretransitingSave[n].getScale(),
1007 // JointChildSceneNodes[n]->getScale(),
1008 // TransitingBlend));
1009 }
1010 }
1011
1012 if (CalculateAbsolutePositions)
1013 {
1014 //---slow---
1015 for (u32 n=0;n<JointChildSceneNodes.size();++n)
1016 {
1017 if (JointChildSceneNodes[n]->getParent()==this)
1018 {
1019 JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option
1020 }
1021 }
1022 }
1023 }
1024#endif
1025}
1026
1027/*!
1028*/
1029void CAnimatedMeshSceneNode::checkJoints()
1030{
1031#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
1032 return;
1033#else
1034
1035 if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
1036 return;
1037
1038 if (!JointsUsed)
1039 {
1040 for (u32 i=0; i<JointChildSceneNodes.size(); ++i)
1041 removeChild(JointChildSceneNodes[i]);
1042 JointChildSceneNodes.clear();
1043
1044 //Create joints for SkinnedMesh
1045 ((CSkinnedMesh*)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager);
1046 ((CSkinnedMesh*)Mesh)->recoverJointsFromMesh(JointChildSceneNodes);
1047
1048 JointsUsed=true;
1049 JointMode=EJUOR_READ;
1050 }
1051#endif
1052}
1053
1054/*!
1055*/
1056void CAnimatedMeshSceneNode::beginTransition()
1057{
1058 if (!JointsUsed)
1059 return;
1060
1061 if (TransitionTime != 0)
1062 {
1063 //Check the array is big enough
1064 if (PretransitingSave.size()<JointChildSceneNodes.size())
1065 {
1066 for(u32 n=PretransitingSave.size(); n<JointChildSceneNodes.size(); ++n)
1067 PretransitingSave.push_back(core::matrix4());
1068 }
1069
1070 //Copy the position of joints
1071 for (u32 n=0;n<JointChildSceneNodes.size();++n)
1072 PretransitingSave[n]=JointChildSceneNodes[n]->getRelativeTransformation();
1073
1074 Transiting = core::reciprocal((f32)TransitionTime);
1075 }
1076 TransitingBlend = 0.f;
1077}
1078
1079
1080/*!
1081*/
1082ISceneNode* CAnimatedMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
1083{
1084 if (!newParent)
1085 newParent = Parent;
1086 if (!newManager)
1087 newManager = SceneManager;
1088
1089 CAnimatedMeshSceneNode* newNode =
1090 new CAnimatedMeshSceneNode(Mesh, NULL, newManager, ID, RelativeTranslation,
1091 RelativeRotation, RelativeScale);
1092
1093 if (newParent)
1094 {
1095 newNode->setParent(newParent); // not in constructor because virtual overload for updateAbsolutePosition won't be called
1096 newNode->drop();
1097 }
1098
1099 newNode->cloneMembers(this, newManager);
1100
1101 newNode->Materials = Materials;
1102 newNode->Box = Box;
1103 newNode->Mesh = Mesh;
1104 newNode->StartFrame = StartFrame;
1105 newNode->EndFrame = EndFrame;
1106 newNode->FramesPerSecond = FramesPerSecond;
1107 newNode->CurrentFrameNr = CurrentFrameNr;
1108 newNode->JointMode = JointMode;
1109 newNode->JointsUsed = JointsUsed;
1110 newNode->TransitionTime = TransitionTime;
1111 newNode->Transiting = Transiting;
1112 newNode->TransitingBlend = TransitingBlend;
1113 newNode->Looping = Looping;
1114 newNode->ReadOnlyMaterials = ReadOnlyMaterials;
1115 newNode->LoopCallBack = LoopCallBack;
1116 if (newNode->LoopCallBack)
1117 newNode->LoopCallBack->grab();
1118 newNode->PassCount = PassCount;
1119 newNode->Shadow = Shadow;
1120 if (newNode->Shadow)
1121 newNode->Shadow->grab();
1122 newNode->JointChildSceneNodes = JointChildSceneNodes;
1123 newNode->PretransitingSave = PretransitingSave;
1124 newNode->RenderFromIdentity = RenderFromIdentity;
1125 newNode->MD3Special = MD3Special;
1126
1127 return newNode;
1128}
1129
1130
1131} // end namespace scene
1132} // end namespace irr