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 
22 namespace irr
23 {
24 namespace scene
25 {
26 
27 
28 //! constructor
CAnimatedMeshSceneNode(IAnimatedMesh * mesh,ISceneNode * parent,ISceneManager * mgr,s32 id,const core::vector3df & position,const core::vector3df & rotation,const core::vector3df & scale)29 CAnimatedMeshSceneNode::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
~CAnimatedMeshSceneNode()51 CAnimatedMeshSceneNode::~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.
setCurrentFrame(f32 frame)68 void 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.
getFrameNr() const78 f32 CAnimatedMeshSceneNode::getFrameNr() const
79 {
80 	return CurrentFrameNr;
81 }
82 
83 
84 //! Get CurrentFrameNr and update transiting settings
buildFrameNr(u32 timeMs)85 void 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 
OnRegisterSceneNode()146 void 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 
getMeshForCurrentFrame()188 IMesh * 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.
OnAnimate(u32 timeMs)240 void 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.
render()265 void 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.
getStartFrame() const469 s32 CAnimatedMeshSceneNode::getStartFrame() const
470 {
471 	return StartFrame;
472 }
473 
474 
475 //! Returns the current start frame number.
getEndFrame() const476 s32 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.
setFrameLoop(s32 begin,s32 end)484 bool 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
setAnimationSpeed(f32 framesPerSecond)507 void CAnimatedMeshSceneNode::setAnimationSpeed(f32 framesPerSecond)
508 {
509 	FramesPerSecond = framesPerSecond * 0.001f;
510 }
511 
512 
getAnimationSpeed() const513 f32 CAnimatedMeshSceneNode::getAnimationSpeed() const
514 {
515 	return FramesPerSecond * 1000.f;
516 }
517 
518 
519 //! returns the axis aligned bounding box of this node
getBoundingBox() const520 const 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.
getMaterial(u32 i)531 video::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.
getMaterialCount() const542 u32 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.
addShadowVolumeSceneNode(const IMesh * shadowMesh,s32 id,bool zfailmethod,f32 infinity)550 IShadowVolumeSceneNode* 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.
getJointNode(const c8 * jointName)568 IBoneSceneNode* 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.
getJointNode(u32 jointID)607 IBoneSceneNode* 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.
getJointCount() const633 u32 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.
getMS3DJointNode(const c8 * jointName)651 ISceneNode* 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.
getXJointNode(const c8 * jointName)659 ISceneNode* 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.
removeChild(ISceneNode * child)667 bool 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.
setMD2Animation(EMD2_ANIMATION_TYPE anim)696 bool 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.
setMD2Animation(const c8 * animationName)713 bool 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.
setLoopMode(bool playAnimationLooped)732 void CAnimatedMeshSceneNode::setLoopMode(bool playAnimationLooped)
733 {
734 	Looping = playAnimationLooped;
735 }
736 
737 //! returns the current loop mode
getLoopMode() const738 bool 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.
setAnimationEndCallback(IAnimationEndCallBack * callback)746 void 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.
setReadOnlyMaterials(bool readonly)762 void 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
isReadOnlyMaterials() const769 bool CAnimatedMeshSceneNode::isReadOnlyMaterials() const
770 {
771 	return ReadOnlyMaterials;
772 }
773 
774 
775 //! Writes attributes of the scene node.
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options) const776 void 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.
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options)798 void 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
setMesh(IAnimatedMesh * mesh)824 void 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
getMD3TagTransformation(const core::stringc & tagname)874 const 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
updateAbsolutePosition()881 void 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)
setJointMode(E_JOINT_UPDATE_ON_RENDER mode)919 void 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
setTransitionTime(f32 time)927 void 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)
setRenderFromIdentity(bool enable)941 void CAnimatedMeshSceneNode::setRenderFromIdentity(bool enable)
942 {
943 	RenderFromIdentity=enable;
944 }
945 
946 
947 //! updates the joint positions of this mesh
animateJoints(bool CalculateAbsolutePositions)948 void 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 */
checkJoints()1029 void 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 */
beginTransition()1056 void 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 */
clone(ISceneNode * newParent,ISceneManager * newManager)1082 ISceneNode* 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
1133