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 "IrrCompileConfig.h"
6 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
7 
8 #include "CSkinnedMesh.h"
9 #include "CBoneSceneNode.h"
10 #include "IAnimatedMeshSceneNode.h"
11 #include "os.h"
12 
13 namespace irr
14 {
15 namespace scene
16 {
17 
18 
19 //! constructor
CSkinnedMesh()20 CSkinnedMesh::CSkinnedMesh()
21 : SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f),
22 	LastAnimatedFrame(-1), SkinnedLastFrame(false),
23 	InterpolationMode(EIM_LINEAR),
24 	HasAnimation(false), PreparedForSkinning(false),
25 	AnimateNormals(true), HardwareSkinning(false)
26 {
27 	#ifdef _DEBUG
28 	setDebugName("CSkinnedMesh");
29 	#endif
30 
31 	SkinningBuffers=&LocalBuffers;
32 }
33 
34 
35 //! destructor
~CSkinnedMesh()36 CSkinnedMesh::~CSkinnedMesh()
37 {
38 	for (u32 i=0; i<AllJoints.size(); ++i)
39 		delete AllJoints[i];
40 
41 	for (u32 j=0; j<LocalBuffers.size(); ++j)
42 	{
43 		if (LocalBuffers[j])
44 			LocalBuffers[j]->drop();
45 	}
46 }
47 
48 
49 //! returns the amount of frames in milliseconds.
50 //! If the amount is 1, it is a static (=non animated) mesh.
getFrameCount() const51 u32 CSkinnedMesh::getFrameCount() const
52 {
53 	return core::floor32(AnimationFrames);
54 }
55 
56 
57 //! Gets the default animation speed of the animated mesh.
58 /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
getAnimationSpeed() const59 f32 CSkinnedMesh::getAnimationSpeed() const
60 {
61 	return FramesPerSecond;
62 }
63 
64 
65 //! Gets the frame count of the animated mesh.
66 /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
67 The actual speed is set in the scene node the mesh is instantiated in.*/
setAnimationSpeed(f32 fps)68 void CSkinnedMesh::setAnimationSpeed(f32 fps)
69 {
70 	FramesPerSecond=fps;
71 }
72 
73 
74 //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
getMesh(s32 frame,s32 detailLevel,s32 startFrameLoop,s32 endFrameLoop)75 IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
76 {
77 	//animate(frame,startFrameLoop, endFrameLoop);
78 	if (frame==-1)
79 		return this;
80 
81 	animateMesh((f32)frame, 1.0f);
82 	skinMesh();
83 	return this;
84 }
85 
86 
87 //--------------------------------------------------------------------------
88 //			Keyframe Animation
89 //--------------------------------------------------------------------------
90 
91 
92 //! Animates this mesh's joints based on frame input
93 //! blend: {0-old position, 1-New position}
animateMesh(f32 frame,f32 blend)94 void CSkinnedMesh::animateMesh(f32 frame, f32 blend)
95 {
96 	if (!HasAnimation || LastAnimatedFrame==frame)
97 		return;
98 
99 	LastAnimatedFrame=frame;
100 	SkinnedLastFrame=false;
101 
102 	if (blend<=0.f)
103 		return; //No need to animate
104 
105 	for (u32 i=0; i<AllJoints.size(); ++i)
106 	{
107 		//The joints can be animated here with no input from their
108 		//parents, but for setAnimationMode extra checks are needed
109 		//to their parents
110 		SJoint *joint = AllJoints[i];
111 
112 		const core::vector3df oldPosition = joint->Animatedposition;
113 		const core::vector3df oldScale = joint->Animatedscale;
114 		const core::quaternion oldRotation = joint->Animatedrotation;
115 
116 		core::vector3df position = oldPosition;
117 		core::vector3df scale = oldScale;
118 		core::quaternion rotation = oldRotation;
119 
120 		getFrameData(frame, joint,
121 				position, joint->positionHint,
122 				scale, joint->scaleHint,
123 				rotation, joint->rotationHint);
124 
125 		if (blend==1.0f)
126 		{
127 			//No blending needed
128 			joint->Animatedposition = position;
129 			joint->Animatedscale = scale;
130 			joint->Animatedrotation = rotation;
131 		}
132 		else
133 		{
134 			//Blend animation
135 			joint->Animatedposition = core::lerp(oldPosition, position, blend);
136 			joint->Animatedscale = core::lerp(oldScale, scale, blend);
137 			joint->Animatedrotation.slerp(oldRotation, rotation, blend);
138 		}
139 	}
140 
141 	//Note:
142 	//LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for
143 	//one render (to play two animations at the same time) LocalAnimatedMatrix only needs to be built once.
144 	//a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move
145 
146 	//----------------
147 	// Temp!
148 	buildAllLocalAnimatedMatrices();
149 	//-----------------
150 
151 	updateBoundingBox();
152 }
153 
154 
buildAllLocalAnimatedMatrices()155 void CSkinnedMesh::buildAllLocalAnimatedMatrices()
156 {
157 	for (u32 i=0; i<AllJoints.size(); ++i)
158 	{
159 		SJoint *joint = AllJoints[i];
160 
161 		//Could be faster:
162 
163 		if (joint->UseAnimationFrom &&
164 			(joint->UseAnimationFrom->PositionKeys.size() ||
165 			 joint->UseAnimationFrom->ScaleKeys.size() ||
166 			 joint->UseAnimationFrom->RotationKeys.size() ))
167 		{
168 			joint->GlobalSkinningSpace=false;
169 
170 			// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
171 			//								   Not tested so far if this was correct or wrong before quaternion fix!
172 			joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix);
173 
174 			// --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() ---
175 			f32 *m1 = joint->LocalAnimatedMatrix.pointer();
176 			core::vector3df &Pos = joint->Animatedposition;
177 			m1[0] += Pos.X*m1[3];
178 			m1[1] += Pos.Y*m1[3];
179 			m1[2] += Pos.Z*m1[3];
180 			m1[4] += Pos.X*m1[7];
181 			m1[5] += Pos.Y*m1[7];
182 			m1[6] += Pos.Z*m1[7];
183 			m1[8] += Pos.X*m1[11];
184 			m1[9] += Pos.Y*m1[11];
185 			m1[10] += Pos.Z*m1[11];
186 			m1[12] += Pos.X*m1[15];
187 			m1[13] += Pos.Y*m1[15];
188 			m1[14] += Pos.Z*m1[15];
189 			// -----------------------------------
190 
191 			if (joint->ScaleKeys.size())
192 			{
193 				/*
194 				core::matrix4 scaleMatrix;
195 				scaleMatrix.setScale(joint->Animatedscale);
196 				joint->LocalAnimatedMatrix *= scaleMatrix;
197 				*/
198 
199 				// -------- joint->LocalAnimatedMatrix *= scaleMatrix -----------------
200 				core::matrix4& mat = joint->LocalAnimatedMatrix;
201 				mat[0] *= joint->Animatedscale.X;
202 				mat[1] *= joint->Animatedscale.X;
203 				mat[2] *= joint->Animatedscale.X;
204 				mat[3] *= joint->Animatedscale.X;
205 				mat[4] *= joint->Animatedscale.Y;
206 				mat[5] *= joint->Animatedscale.Y;
207 				mat[6] *= joint->Animatedscale.Y;
208 				mat[7] *= joint->Animatedscale.Y;
209 				mat[8] *= joint->Animatedscale.Z;
210 				mat[9] *= joint->Animatedscale.Z;
211 				mat[10] *= joint->Animatedscale.Z;
212 				mat[11] *= joint->Animatedscale.Z;
213 				// -----------------------------------
214 			}
215 		}
216 		else
217 		{
218 			joint->LocalAnimatedMatrix=joint->LocalMatrix;
219 		}
220 	}
221 	SkinnedLastFrame=false;
222 }
223 
224 
buildAllGlobalAnimatedMatrices(SJoint * joint,SJoint * parentJoint)225 void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint)
226 {
227 	if (!joint)
228 	{
229 		for (u32 i=0; i<RootJoints.size(); ++i)
230 			buildAllGlobalAnimatedMatrices(RootJoints[i], 0);
231 		return;
232 	}
233 	else
234 	{
235 		// Find global matrix...
236 		if (!parentJoint || joint->GlobalSkinningSpace)
237 			joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix;
238 		else
239 			joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix;
240 	}
241 
242 	for (u32 j=0; j<joint->Children.size(); ++j)
243 		buildAllGlobalAnimatedMatrices(joint->Children[j], joint);
244 }
245 
246 
getFrameData(f32 frame,SJoint * joint,core::vector3df & position,s32 & positionHint,core::vector3df & scale,s32 & scaleHint,core::quaternion & rotation,s32 & rotationHint)247 void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint,
248 				core::vector3df &position, s32 &positionHint,
249 				core::vector3df &scale, s32 &scaleHint,
250 				core::quaternion &rotation, s32 &rotationHint)
251 {
252 	s32 foundPositionIndex = -1;
253 	s32 foundScaleIndex = -1;
254 	s32 foundRotationIndex = -1;
255 
256 	if (joint->UseAnimationFrom)
257 	{
258 		const core::array<SPositionKey> &PositionKeys=joint->UseAnimationFrom->PositionKeys;
259 		const core::array<SScaleKey> &ScaleKeys=joint->UseAnimationFrom->ScaleKeys;
260 		const core::array<SRotationKey> &RotationKeys=joint->UseAnimationFrom->RotationKeys;
261 
262 		if (PositionKeys.size())
263 		{
264 			foundPositionIndex = -1;
265 
266 			//Test the Hints...
267 			if (positionHint>=0 && (u32)positionHint < PositionKeys.size())
268 			{
269 				//check this hint
270 				if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame<frame )
271 					foundPositionIndex=positionHint;
272 				else if (positionHint+1 < (s32)PositionKeys.size())
273 				{
274 					//check the next index
275 					if ( PositionKeys[positionHint+1].frame>=frame &&
276 							PositionKeys[positionHint+0].frame<frame)
277 					{
278 						positionHint++;
279 						foundPositionIndex=positionHint;
280 					}
281 				}
282 			}
283 
284 			//The hint test failed, do a full scan...
285 			if (foundPositionIndex==-1)
286 			{
287 				for (u32 i=0; i<PositionKeys.size(); ++i)
288 				{
289 					if (PositionKeys[i].frame >= frame) //Keys should to be sorted by frame
290 					{
291 						foundPositionIndex=i;
292 						positionHint=i;
293 						break;
294 					}
295 				}
296 			}
297 
298 			//Do interpolation...
299 			if (foundPositionIndex!=-1)
300 			{
301 				if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0)
302 				{
303 					position = PositionKeys[foundPositionIndex].position;
304 				}
305 				else if (InterpolationMode==EIM_LINEAR)
306 				{
307 					const SPositionKey& KeyA = PositionKeys[foundPositionIndex];
308 					const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1];
309 
310 					const f32 fd1 = frame - KeyA.frame;
311 					const f32 fd2 = KeyB.frame - frame;
312 					position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position;
313 				}
314 			}
315 		}
316 
317 		//------------------------------------------------------------
318 
319 		if (ScaleKeys.size())
320 		{
321 			foundScaleIndex = -1;
322 
323 			//Test the Hints...
324 			if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size())
325 			{
326 				//check this hint
327 				if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame<frame )
328 					foundScaleIndex=scaleHint;
329 				else if (scaleHint+1 < (s32)ScaleKeys.size())
330 				{
331 					//check the next index
332 					if ( ScaleKeys[scaleHint+1].frame>=frame &&
333 							ScaleKeys[scaleHint+0].frame<frame)
334 					{
335 						scaleHint++;
336 						foundScaleIndex=scaleHint;
337 					}
338 				}
339 			}
340 
341 
342 			//The hint test failed, do a full scan...
343 			if (foundScaleIndex==-1)
344 			{
345 				for (u32 i=0; i<ScaleKeys.size(); ++i)
346 				{
347 					if (ScaleKeys[i].frame >= frame) //Keys should to be sorted by frame
348 					{
349 						foundScaleIndex=i;
350 						scaleHint=i;
351 						break;
352 					}
353 				}
354 			}
355 
356 			//Do interpolation...
357 			if (foundScaleIndex!=-1)
358 			{
359 				if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0)
360 				{
361 					scale = ScaleKeys[foundScaleIndex].scale;
362 				}
363 				else if (InterpolationMode==EIM_LINEAR)
364 				{
365 					const SScaleKey& KeyA = ScaleKeys[foundScaleIndex];
366 					const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1];
367 
368 					const f32 fd1 = frame - KeyA.frame;
369 					const f32 fd2 = KeyB.frame - frame;
370 					scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale;
371 				}
372 			}
373 		}
374 
375 		//-------------------------------------------------------------
376 
377 		if (RotationKeys.size())
378 		{
379 			foundRotationIndex = -1;
380 
381 			//Test the Hints...
382 			if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size())
383 			{
384 				//check this hint
385 				if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame<frame )
386 					foundRotationIndex=rotationHint;
387 				else if (rotationHint+1 < (s32)RotationKeys.size())
388 				{
389 					//check the next index
390 					if ( RotationKeys[rotationHint+1].frame>=frame &&
391 							RotationKeys[rotationHint+0].frame<frame)
392 					{
393 						rotationHint++;
394 						foundRotationIndex=rotationHint;
395 					}
396 				}
397 			}
398 
399 
400 			//The hint test failed, do a full scan...
401 			if (foundRotationIndex==-1)
402 			{
403 				for (u32 i=0; i<RotationKeys.size(); ++i)
404 				{
405 					if (RotationKeys[i].frame >= frame) //Keys should be sorted by frame
406 					{
407 						foundRotationIndex=i;
408 						rotationHint=i;
409 						break;
410 					}
411 				}
412 			}
413 
414 			//Do interpolation...
415 			if (foundRotationIndex!=-1)
416 			{
417 				if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0)
418 				{
419 					rotation = RotationKeys[foundRotationIndex].rotation;
420 				}
421 				else if (InterpolationMode==EIM_LINEAR)
422 				{
423 					const SRotationKey& KeyA = RotationKeys[foundRotationIndex];
424 					const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1];
425 
426 					const f32 fd1 = frame - KeyA.frame;
427 					const f32 fd2 = KeyB.frame - frame;
428 					const f32 t = fd1/(fd1+fd2);
429 
430 					/*
431 					f32 t = 0;
432 					if (KeyA.frame!=KeyB.frame)
433 						t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame);
434 					*/
435 
436 					rotation.slerp(KeyA.rotation, KeyB.rotation, t);
437 				}
438 			}
439 		}
440 	}
441 }
442 
443 //--------------------------------------------------------------------------
444 //				Software Skinning
445 //--------------------------------------------------------------------------
446 
447 //! Preforms a software skin on this mesh based of joint positions
skinMesh()448 void CSkinnedMesh::skinMesh()
449 {
450 	if (!HasAnimation || SkinnedLastFrame)
451 		return;
452 
453 	//----------------
454 	// This is marked as "Temp!".  A shiny dubloon to whomever can tell me why.
455 	buildAllGlobalAnimatedMatrices();
456 	//-----------------
457 
458 	SkinnedLastFrame=true;
459 	if (!HardwareSkinning)
460 	{
461 		//Software skin....
462 		u32 i;
463 
464 		//rigid animation
465 		for (i=0; i<AllJoints.size(); ++i)
466 		{
467 			for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
468 			{
469 				SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
470 				Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
471 			}
472 		}
473 
474 		//clear skinning helper array
475 		for (i=0; i<Vertices_Moved.size(); ++i)
476 			for (u32 j=0; j<Vertices_Moved[i].size(); ++j)
477 				Vertices_Moved[i][j]=false;
478 
479 		//skin starting with the root joints
480 		for (i=0; i<RootJoints.size(); ++i)
481 			skinJoint(RootJoints[i], 0);
482 
483 		for (i=0; i<SkinningBuffers->size(); ++i)
484 			(*SkinningBuffers)[i]->setDirty(EBT_VERTEX);
485 	}
486 	updateBoundingBox();
487 }
488 
489 
skinJoint(SJoint * joint,SJoint * parentJoint)490 void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint)
491 {
492 	if (joint->Weights.size())
493 	{
494 		//Find this joints pull on vertices...
495 		core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING);
496 		jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix);
497 
498 		core::vector3df thisVertexMove, thisNormalMove;
499 
500 		core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
501 
502 		//Skin Vertices Positions and Normals...
503 		for (u32 i=0; i<joint->Weights.size(); ++i)
504 		{
505 			SWeight& weight = joint->Weights[i];
506 
507 			// Pull this vertex...
508 			jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
509 
510 			if (AnimateNormals)
511 				jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
512 
513 			if (! (*(weight.Moved)) )
514 			{
515 				*(weight.Moved) = true;
516 
517 				buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
518 
519 				if (AnimateNormals)
520 					buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength;
521 
522 				//*(weight._Pos) = thisVertexMove * weight.strength;
523 			}
524 			else
525 			{
526 				buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
527 
528 				if (AnimateNormals)
529 					buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
530 
531 				//*(weight._Pos) += thisVertexMove * weight.strength;
532 			}
533 
534 			buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
535 		}
536 	}
537 
538 	//Skin all children
539 	for (u32 j=0; j<joint->Children.size(); ++j)
540 		skinJoint(joint->Children[j], joint);
541 }
542 
543 
getMeshType() const544 E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const
545 {
546 	return EAMT_SKINNED;
547 }
548 
549 
550 //! Gets joint count.
getJointCount() const551 u32 CSkinnedMesh::getJointCount() const
552 {
553 	return AllJoints.size();
554 }
555 
556 
557 //! Gets the name of a joint.
getJointName(u32 number) const558 const c8* CSkinnedMesh::getJointName(u32 number) const
559 {
560 	if (number >= AllJoints.size())
561 		return 0;
562 	return AllJoints[number]->Name.c_str();
563 }
564 
565 
566 //! Gets a joint number from its name
getJointNumber(const c8 * name) const567 s32 CSkinnedMesh::getJointNumber(const c8* name) const
568 {
569 	for (u32 i=0; i<AllJoints.size(); ++i)
570 	{
571 		if (AllJoints[i]->Name == name)
572 			return i;
573 	}
574 
575 	return -1;
576 }
577 
578 
579 //! returns amount of mesh buffers.
getMeshBufferCount() const580 u32 CSkinnedMesh::getMeshBufferCount() const
581 {
582 	return LocalBuffers.size();
583 }
584 
585 
586 //! returns pointer to a mesh buffer
getMeshBuffer(u32 nr) const587 IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const
588 {
589 	if (nr < LocalBuffers.size())
590 		return LocalBuffers[nr];
591 	else
592 		return 0;
593 }
594 
595 
596 //! Returns pointer to a mesh buffer which fits a material
getMeshBuffer(const video::SMaterial & material) const597 IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const
598 {
599 	for (u32 i=0; i<LocalBuffers.size(); ++i)
600 	{
601 		if (LocalBuffers[i]->getMaterial() == material)
602 			return LocalBuffers[i];
603 	}
604 	return 0;
605 }
606 
607 
608 //! returns an axis aligned bounding box
getBoundingBox() const609 const core::aabbox3d<f32>& CSkinnedMesh::getBoundingBox() const
610 {
611 	return BoundingBox;
612 }
613 
614 
615 //! set user axis aligned bounding box
setBoundingBox(const core::aabbox3df & box)616 void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box)
617 {
618 	BoundingBox = box;
619 }
620 
621 
622 //! sets a flag of all contained materials to a new value
setMaterialFlag(video::E_MATERIAL_FLAG flag,bool newvalue)623 void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
624 {
625 	for (u32 i=0; i<LocalBuffers.size(); ++i)
626 		LocalBuffers[i]->Material.setFlag(flag,newvalue);
627 }
628 
629 
630 //! set the hardware mapping hint, for driver
setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer)631 void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
632 		E_BUFFER_TYPE buffer)
633 {
634 	for (u32 i=0; i<LocalBuffers.size(); ++i)
635 		LocalBuffers[i]->setHardwareMappingHint(newMappingHint, buffer);
636 }
637 
638 
639 //! flags the meshbuffer as changed, reloads hardware buffers
setDirty(E_BUFFER_TYPE buffer)640 void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer)
641 {
642 	for (u32 i=0; i<LocalBuffers.size(); ++i)
643 		LocalBuffers[i]->setDirty(buffer);
644 }
645 
646 
647 //! uses animation from another mesh
useAnimationFrom(const ISkinnedMesh * mesh)648 bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh)
649 {
650 	bool unmatched=false;
651 
652 	for(u32 i=0;i<AllJoints.size();++i)
653 	{
654 		SJoint *joint=AllJoints[i];
655 		joint->UseAnimationFrom=0;
656 
657 		if (joint->Name=="")
658 			unmatched=true;
659 		else
660 		{
661 			for(u32 j=0;j<mesh->getAllJoints().size();++j)
662 			{
663 				SJoint *otherJoint=mesh->getAllJoints()[j];
664 				if (joint->Name==otherJoint->Name)
665 				{
666 					joint->UseAnimationFrom=otherJoint;
667 				}
668 			}
669 			if (!joint->UseAnimationFrom)
670 				unmatched=true;
671 		}
672 	}
673 
674 	checkForAnimation();
675 
676 	return !unmatched;
677 }
678 
679 
680 //!Update Normals when Animating
681 //!False= Don't animate them, faster
682 //!True= Update normals (default)
updateNormalsWhenAnimating(bool on)683 void CSkinnedMesh::updateNormalsWhenAnimating(bool on)
684 {
685 	AnimateNormals = on;
686 }
687 
688 
689 //!Sets Interpolation Mode
setInterpolationMode(E_INTERPOLATION_MODE mode)690 void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode)
691 {
692 	InterpolationMode = mode;
693 }
694 
695 
getMeshBuffers()696 core::array<scene::SSkinMeshBuffer*> &CSkinnedMesh::getMeshBuffers()
697 {
698 	return LocalBuffers;
699 }
700 
701 
getAllJoints()702 core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints()
703 {
704 	return AllJoints;
705 }
706 
707 
getAllJoints() const708 const core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() const
709 {
710 	return AllJoints;
711 }
712 
713 
714 //! (This feature is not implementated in irrlicht yet)
setHardwareSkinning(bool on)715 bool CSkinnedMesh::setHardwareSkinning(bool on)
716 {
717 	if (HardwareSkinning!=on)
718 	{
719 		if (on)
720 		{
721 
722 			//set mesh to static pose...
723 			for (u32 i=0; i<AllJoints.size(); ++i)
724 			{
725 				SJoint *joint=AllJoints[i];
726 				for (u32 j=0; j<joint->Weights.size(); ++j)
727 				{
728 					const u16 buffer_id=joint->Weights[j].buffer_id;
729 					const u32 vertex_id=joint->Weights[j].vertex_id;
730 					LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
731 					LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
732 					LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated();
733 				}
734 			}
735 		}
736 
737 		HardwareSkinning=on;
738 	}
739 	return HardwareSkinning;
740 }
741 
742 
calculateGlobalMatrices(SJoint * joint,SJoint * parentJoint)743 void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint,SJoint *parentJoint)
744 {
745 	if (!joint && parentJoint) // bit of protection from endless loops
746 		return;
747 
748 	//Go through the root bones
749 	if (!joint)
750 	{
751 		for (u32 i=0; i<RootJoints.size(); ++i)
752 			calculateGlobalMatrices(RootJoints[i],0);
753 		return;
754 	}
755 
756 	if (!parentJoint)
757 		joint->GlobalMatrix = joint->LocalMatrix;
758 	else
759 		joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix;
760 
761 	joint->LocalAnimatedMatrix=joint->LocalMatrix;
762 	joint->GlobalAnimatedMatrix=joint->GlobalMatrix;
763 
764 	if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated
765 	{
766 		joint->GlobalInversedMatrix = joint->GlobalMatrix;
767 		joint->GlobalInversedMatrix.makeInverse(); // slow
768 	}
769 
770 	for (u32 j=0; j<joint->Children.size(); ++j)
771 		calculateGlobalMatrices(joint->Children[j],joint);
772 	SkinnedLastFrame=false;
773 }
774 
775 
checkForAnimation()776 void CSkinnedMesh::checkForAnimation()
777 {
778 	u32 i,j;
779 	//Check for animation...
780 	HasAnimation = false;
781 	for(i=0;i<AllJoints.size();++i)
782 	{
783 		if (AllJoints[i]->UseAnimationFrom)
784 		{
785 			if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() ||
786 				AllJoints[i]->UseAnimationFrom->ScaleKeys.size() ||
787 				AllJoints[i]->UseAnimationFrom->RotationKeys.size() )
788 			{
789 				HasAnimation = true;
790 			}
791 		}
792 	}
793 
794 	//meshes with weights, are still counted as animated for ragdolls, etc
795 	if (!HasAnimation)
796 	{
797 		for(i=0;i<AllJoints.size();++i)
798 		{
799 			if (AllJoints[i]->Weights.size())
800 				HasAnimation = true;
801 		}
802 	}
803 
804 	if (HasAnimation)
805 	{
806 		//--- Find the length of the animation ---
807 		AnimationFrames=0;
808 		for(i=0;i<AllJoints.size();++i)
809 		{
810 			if (AllJoints[i]->UseAnimationFrom)
811 			{
812 				if (AllJoints[i]->UseAnimationFrom->PositionKeys.size())
813 					if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames)
814 						AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
815 
816 				if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size())
817 					if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames)
818 						AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
819 
820 				if (AllJoints[i]->UseAnimationFrom->RotationKeys.size())
821 					if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames)
822 						AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
823 			}
824 		}
825 	}
826 
827 	if (HasAnimation && !PreparedForSkinning)
828 	{
829 		PreparedForSkinning=true;
830 
831 		//check for bugs:
832 		for(i=0; i < AllJoints.size(); ++i)
833 		{
834 			SJoint *joint = AllJoints[i];
835 			for (j=0; j<joint->Weights.size(); ++j)
836 			{
837 				const u16 buffer_id=joint->Weights[j].buffer_id;
838 				const u32 vertex_id=joint->Weights[j].vertex_id;
839 
840 				//check for invalid ids
841 				if (buffer_id>=LocalBuffers.size())
842 				{
843 					os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING);
844 					joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
845 				}
846 				else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount())
847 				{
848 					os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING);
849 					joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
850 				}
851 			}
852 		}
853 
854 		//An array used in skinning
855 
856 		for (i=0; i<Vertices_Moved.size(); ++i)
857 			for (j=0; j<Vertices_Moved[i].size(); ++j)
858 				Vertices_Moved[i][j] = false;
859 
860 		// For skinning: cache weight values for speed
861 
862 		for (i=0; i<AllJoints.size(); ++i)
863 		{
864 			SJoint *joint = AllJoints[i];
865 			for (j=0; j<joint->Weights.size(); ++j)
866 			{
867 				const u16 buffer_id=joint->Weights[j].buffer_id;
868 				const u32 vertex_id=joint->Weights[j].vertex_id;
869 
870 				joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id];
871 				joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos;
872 				joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal;
873 
874 				//joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos;
875 			}
876 		}
877 
878 		// normalize weights
879 		normalizeWeights();
880 	}
881 	SkinnedLastFrame=false;
882 }
883 
884 
885 //! called by loader after populating with mesh and bone data
finalize()886 void CSkinnedMesh::finalize()
887 {
888 	u32 i;
889 
890 	// Make sure we recalc the next frame
891 	LastAnimatedFrame=-1;
892 	SkinnedLastFrame=false;
893 
894 	//calculate bounding box
895 	for (i=0; i<LocalBuffers.size(); ++i)
896 	{
897 		LocalBuffers[i]->recalculateBoundingBox();
898 	}
899 
900 	if (AllJoints.size() || RootJoints.size())
901 	{
902 		// populate AllJoints or RootJoints, depending on which is empty
903 		if (!RootJoints.size())
904 		{
905 
906 			for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx)
907 			{
908 
909 				bool foundParent=false;
910 				for(i=0; i < AllJoints.size(); ++i)
911 				{
912 					for(u32 n=0; n < AllJoints[i]->Children.size(); ++n)
913 					{
914 						if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx])
915 							foundParent=true;
916 					}
917 				}
918 
919 				if (!foundParent)
920 					RootJoints.push_back(AllJoints[CheckingIdx]);
921 			}
922 		}
923 		else
924 		{
925 			AllJoints=RootJoints;
926 		}
927 	}
928 
929 	for(i=0; i < AllJoints.size(); ++i)
930 	{
931 		AllJoints[i]->UseAnimationFrom=AllJoints[i];
932 	}
933 
934 	//Set array sizes...
935 
936 	for (i=0; i<LocalBuffers.size(); ++i)
937 	{
938 		Vertices_Moved.push_back( core::array<bool>() );
939 		Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
940 	}
941 
942 	//Todo: optimise keys here...
943 
944 	checkForAnimation();
945 
946 	if (HasAnimation)
947 	{
948 		//--- optimize and check keyframes ---
949 		for(i=0;i<AllJoints.size();++i)
950 		{
951 			core::array<SPositionKey> &PositionKeys =AllJoints[i]->PositionKeys;
952 			core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys;
953 			core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys;
954 
955 			if (PositionKeys.size()>2)
956 			{
957 				for(u32 j=0;j<PositionKeys.size()-2;++j)
958 				{
959 					if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position)
960 					{
961 						PositionKeys.erase(j+1); //the middle key is unneeded
962 						--j;
963 					}
964 				}
965 			}
966 
967 			if (PositionKeys.size()>1)
968 			{
969 				for(u32 j=0;j<PositionKeys.size()-1;++j)
970 				{
971 					if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems
972 					{
973 						PositionKeys.erase(j+1);
974 						--j;
975 					}
976 				}
977 			}
978 
979 			if (ScaleKeys.size()>2)
980 			{
981 				for(u32 j=0;j<ScaleKeys.size()-2;++j)
982 				{
983 					if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale)
984 					{
985 						ScaleKeys.erase(j+1); //the middle key is unneeded
986 						--j;
987 					}
988 				}
989 			}
990 
991 			if (ScaleKeys.size()>1)
992 			{
993 				for(u32 j=0;j<ScaleKeys.size()-1;++j)
994 				{
995 					if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems
996 					{
997 						ScaleKeys.erase(j+1);
998 						--j;
999 					}
1000 				}
1001 			}
1002 
1003 			if (RotationKeys.size()>2)
1004 			{
1005 				for(u32 j=0;j<RotationKeys.size()-2;++j)
1006 				{
1007 					if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation)
1008 					{
1009 						RotationKeys.erase(j+1); //the middle key is unneeded
1010 						--j;
1011 					}
1012 				}
1013 			}
1014 
1015 			if (RotationKeys.size()>1)
1016 			{
1017 				for(u32 j=0;j<RotationKeys.size()-1;++j)
1018 				{
1019 					if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems
1020 					{
1021 						RotationKeys.erase(j+1);
1022 						--j;
1023 					}
1024 				}
1025 			}
1026 
1027 
1028 			//Fill empty keyframe areas
1029 			if (PositionKeys.size())
1030 			{
1031 				SPositionKey *Key;
1032 				Key=&PositionKeys[0];//getFirst
1033 				if (Key->frame!=0)
1034 				{
1035 					PositionKeys.push_front(*Key);
1036 					Key=&PositionKeys[0];//getFirst
1037 					Key->frame=0;
1038 				}
1039 
1040 				Key=&PositionKeys.getLast();
1041 				if (Key->frame!=AnimationFrames)
1042 				{
1043 					PositionKeys.push_back(*Key);
1044 					Key=&PositionKeys.getLast();
1045 					Key->frame=AnimationFrames;
1046 				}
1047 			}
1048 
1049 			if (ScaleKeys.size())
1050 			{
1051 				SScaleKey *Key;
1052 				Key=&ScaleKeys[0];//getFirst
1053 				if (Key->frame!=0)
1054 				{
1055 					ScaleKeys.push_front(*Key);
1056 					Key=&ScaleKeys[0];//getFirst
1057 					Key->frame=0;
1058 				}
1059 
1060 				Key=&ScaleKeys.getLast();
1061 				if (Key->frame!=AnimationFrames)
1062 				{
1063 					ScaleKeys.push_back(*Key);
1064 					Key=&ScaleKeys.getLast();
1065 					Key->frame=AnimationFrames;
1066 				}
1067 			}
1068 
1069 			if (RotationKeys.size())
1070 			{
1071 				SRotationKey *Key;
1072 				Key=&RotationKeys[0];//getFirst
1073 				if (Key->frame!=0)
1074 				{
1075 					RotationKeys.push_front(*Key);
1076 					Key=&RotationKeys[0];//getFirst
1077 					Key->frame=0;
1078 				}
1079 
1080 				Key=&RotationKeys.getLast();
1081 				if (Key->frame!=AnimationFrames)
1082 				{
1083 					RotationKeys.push_back(*Key);
1084 					Key=&RotationKeys.getLast();
1085 					Key->frame=AnimationFrames;
1086 				}
1087 			}
1088 		}
1089 	}
1090 
1091 	//Needed for animation and skinning...
1092 
1093 	calculateGlobalMatrices(0,0);
1094 
1095 	//animateMesh(0, 1);
1096 	//buildAllLocalAnimatedMatrices();
1097 	//buildAllGlobalAnimatedMatrices();
1098 
1099 	//rigid animation for non animated meshes
1100 	for (i=0; i<AllJoints.size(); ++i)
1101 	{
1102 		for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
1103 		{
1104 			SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
1105 			Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
1106 		}
1107 	}
1108 
1109 	//calculate bounding box
1110 	if (LocalBuffers.empty())
1111 		BoundingBox.reset(0,0,0);
1112 	else
1113 	{
1114 		irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox);
1115 		LocalBuffers[0]->Transformation.transformBoxEx(bb);
1116 		BoundingBox.reset(bb);
1117 
1118 		for (u32 j=1; j<LocalBuffers.size(); ++j)
1119 		{
1120 			bb = LocalBuffers[j]->BoundingBox;
1121 			LocalBuffers[j]->Transformation.transformBoxEx(bb);
1122 
1123 			BoundingBox.addInternalBox(bb);
1124 		}
1125 	}
1126 }
1127 
1128 
updateBoundingBox(void)1129 void CSkinnedMesh::updateBoundingBox(void)
1130 {
1131 	if(!SkinningBuffers)
1132 		return;
1133 
1134 	core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers;
1135 	BoundingBox.reset(0,0,0);
1136 
1137 	if (!buffer.empty())
1138 	{
1139 		for (u32 j=0; j<buffer.size(); ++j)
1140 		{
1141 			buffer[j]->recalculateBoundingBox();
1142 			core::aabbox3df bb = buffer[j]->BoundingBox;
1143 			buffer[j]->Transformation.transformBoxEx(bb);
1144 
1145 			BoundingBox.addInternalBox(bb);
1146 		}
1147 	}
1148 }
1149 
1150 
addMeshBuffer()1151 scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer()
1152 {
1153 	scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer();
1154 	LocalBuffers.push_back(buffer);
1155 	return buffer;
1156 }
1157 
1158 
addJoint(SJoint * parent)1159 CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent)
1160 {
1161 	SJoint *joint=new SJoint;
1162 
1163 	AllJoints.push_back(joint);
1164 	if (!parent)
1165 	{
1166 		//Add root joints to array in finalize()
1167 	}
1168 	else
1169 	{
1170 		//Set parent (Be careful of the mesh loader also setting the parent)
1171 		parent->Children.push_back(joint);
1172 	}
1173 
1174 	return joint;
1175 }
1176 
1177 
addPositionKey(SJoint * joint)1178 CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint)
1179 {
1180 	if (!joint)
1181 		return 0;
1182 
1183 	joint->PositionKeys.push_back(SPositionKey());
1184 	return &joint->PositionKeys.getLast();
1185 }
1186 
1187 
addScaleKey(SJoint * joint)1188 CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint)
1189 {
1190 	if (!joint)
1191 		return 0;
1192 
1193 	joint->ScaleKeys.push_back(SScaleKey());
1194 	return &joint->ScaleKeys.getLast();
1195 }
1196 
1197 
addRotationKey(SJoint * joint)1198 CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint)
1199 {
1200 	if (!joint)
1201 		return 0;
1202 
1203 	joint->RotationKeys.push_back(SRotationKey());
1204 	return &joint->RotationKeys.getLast();
1205 }
1206 
1207 
addWeight(SJoint * joint)1208 CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint)
1209 {
1210 	if (!joint)
1211 		return 0;
1212 
1213 	joint->Weights.push_back(SWeight());
1214 	return &joint->Weights.getLast();
1215 }
1216 
1217 
isStatic()1218 bool CSkinnedMesh::isStatic()
1219 {
1220 	return !HasAnimation;
1221 }
1222 
1223 
normalizeWeights()1224 void CSkinnedMesh::normalizeWeights()
1225 {
1226 	// note: unsure if weights ids are going to be used.
1227 
1228 	// Normalise the weights on bones....
1229 
1230 	u32 i,j;
1231 	core::array< core::array<f32> > verticesTotalWeight;
1232 
1233 	verticesTotalWeight.reallocate(LocalBuffers.size());
1234 	for (i=0; i<LocalBuffers.size(); ++i)
1235 	{
1236 		verticesTotalWeight.push_back(core::array<f32>());
1237 		verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount());
1238 	}
1239 
1240 	for (i=0; i<verticesTotalWeight.size(); ++i)
1241 		for (j=0; j<verticesTotalWeight[i].size(); ++j)
1242 			verticesTotalWeight[i][j] = 0;
1243 
1244 	for (i=0; i<AllJoints.size(); ++i)
1245 	{
1246 		SJoint *joint=AllJoints[i];
1247 		for (j=0; j<joint->Weights.size(); ++j)
1248 		{
1249 			if (joint->Weights[j].strength<=0)//Check for invalid weights
1250 			{
1251 				joint->Weights.erase(j);
1252 				--j;
1253 			}
1254 			else
1255 			{
1256 				verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id] += joint->Weights[j].strength;
1257 			}
1258 		}
1259 	}
1260 
1261 	for (i=0; i<AllJoints.size(); ++i)
1262 	{
1263 		SJoint *joint=AllJoints[i];
1264 		for (j=0; j< joint->Weights.size(); ++j)
1265 		{
1266 			const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id];
1267 			if (total != 0 && total != 1)
1268 				joint->Weights[j].strength /= total;
1269 		}
1270 	}
1271 }
1272 
1273 
recoverJointsFromMesh(core::array<IBoneSceneNode * > & jointChildSceneNodes)1274 void CSkinnedMesh::recoverJointsFromMesh(core::array<IBoneSceneNode*> &jointChildSceneNodes)
1275 {
1276 	for (u32 i=0; i<AllJoints.size(); ++i)
1277 	{
1278 		IBoneSceneNode* node=jointChildSceneNodes[i];
1279 		SJoint *joint=AllJoints[i];
1280 		node->setPosition(joint->LocalAnimatedMatrix.getTranslation());
1281 		node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees());
1282 		node->setScale(joint->LocalAnimatedMatrix.getScale());
1283 
1284 		node->positionHint=joint->positionHint;
1285 		node->scaleHint=joint->scaleHint;
1286 		node->rotationHint=joint->rotationHint;
1287 
1288 		node->updateAbsolutePosition();
1289 	}
1290 }
1291 
1292 
transferJointsToMesh(const core::array<IBoneSceneNode * > & jointChildSceneNodes)1293 void CSkinnedMesh::transferJointsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes)
1294 {
1295 	for (u32 i=0; i<AllJoints.size(); ++i)
1296 	{
1297 		const IBoneSceneNode* const node=jointChildSceneNodes[i];
1298 		SJoint *joint=AllJoints[i];
1299 
1300 		joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation());
1301 		joint->LocalAnimatedMatrix.setTranslation(node->getPosition());
1302 		joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale());
1303 
1304 		joint->positionHint=node->positionHint;
1305 		joint->scaleHint=node->scaleHint;
1306 		joint->rotationHint=node->rotationHint;
1307 
1308 		joint->GlobalSkinningSpace=(node->getSkinningSpace()==EBSS_GLOBAL);
1309 	}
1310 	// Make sure we recalc the next frame
1311 	LastAnimatedFrame=-1;
1312 	SkinnedLastFrame=false;
1313 }
1314 
1315 
transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode * > & jointChildSceneNodes)1316 void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes)
1317 {
1318 	for (u32 i=0; i<AllJoints.size(); ++i)
1319 	{
1320 		const IBoneSceneNode* const node=jointChildSceneNodes[i];
1321 		SJoint *joint=AllJoints[i];
1322 
1323 		joint->positionHint=node->positionHint;
1324 		joint->scaleHint=node->scaleHint;
1325 		joint->rotationHint=node->rotationHint;
1326 	}
1327 	SkinnedLastFrame=false;
1328 }
1329 
1330 
addJoints(core::array<IBoneSceneNode * > & jointChildSceneNodes,IAnimatedMeshSceneNode * node,ISceneManager * smgr)1331 void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
1332 		IAnimatedMeshSceneNode* node, ISceneManager* smgr)
1333 {
1334 	//Create new joints
1335 	for (u32 i=0; i<AllJoints.size(); ++i)
1336 	{
1337 		jointChildSceneNodes.push_back(new CBoneSceneNode(0, smgr, 0, i, AllJoints[i]->Name.c_str()));
1338 	}
1339 
1340 	//Match up parents
1341 	for (u32 i=0; i<jointChildSceneNodes.size(); ++i)
1342 	{
1343 		const SJoint* const joint=AllJoints[i]; //should be fine
1344 
1345 		s32 parentID=-1;
1346 
1347 		for (u32 j=0;(parentID==-1)&&(j<AllJoints.size());++j)
1348 		{
1349 			if (i!=j)
1350 			{
1351 				const SJoint* const parentTest=AllJoints[j];
1352 				for (u32 n=0; n<parentTest->Children.size(); ++n)
1353 				{
1354 					if (parentTest->Children[n]==joint)
1355 					{
1356 						parentID=j;
1357 						break;
1358 					}
1359 				}
1360 			}
1361 		}
1362 
1363 		IBoneSceneNode* bone=jointChildSceneNodes[i];
1364 		if (parentID!=-1)
1365 			bone->setParent(jointChildSceneNodes[parentID]);
1366 		else
1367 			bone->setParent(node);
1368 
1369 		bone->drop();
1370 	}
1371 	SkinnedLastFrame=false;
1372 }
1373 
1374 
convertMeshToTangents()1375 void CSkinnedMesh::convertMeshToTangents()
1376 {
1377 	// now calculate tangents
1378 	for (u32 b=0; b < LocalBuffers.size(); ++b)
1379 	{
1380 		if (LocalBuffers[b])
1381 		{
1382 			LocalBuffers[b]->convertToTangents();
1383 
1384 			const s32 idxCnt = LocalBuffers[b]->getIndexCount();
1385 
1386 			u16* idx = LocalBuffers[b]->getIndices();
1387 			video::S3DVertexTangents* v =
1388 				(video::S3DVertexTangents*)LocalBuffers[b]->getVertices();
1389 
1390 			for (s32 i=0; i<idxCnt; i+=3)
1391 			{
1392 				calculateTangents(
1393 					v[idx[i+0]].Normal,
1394 					v[idx[i+0]].Tangent,
1395 					v[idx[i+0]].Binormal,
1396 					v[idx[i+0]].Pos,
1397 					v[idx[i+1]].Pos,
1398 					v[idx[i+2]].Pos,
1399 					v[idx[i+0]].TCoords,
1400 					v[idx[i+1]].TCoords,
1401 					v[idx[i+2]].TCoords);
1402 
1403 				calculateTangents(
1404 					v[idx[i+1]].Normal,
1405 					v[idx[i+1]].Tangent,
1406 					v[idx[i+1]].Binormal,
1407 					v[idx[i+1]].Pos,
1408 					v[idx[i+2]].Pos,
1409 					v[idx[i+0]].Pos,
1410 					v[idx[i+1]].TCoords,
1411 					v[idx[i+2]].TCoords,
1412 					v[idx[i+0]].TCoords);
1413 
1414 				calculateTangents(
1415 					v[idx[i+2]].Normal,
1416 					v[idx[i+2]].Tangent,
1417 					v[idx[i+2]].Binormal,
1418 					v[idx[i+2]].Pos,
1419 					v[idx[i+0]].Pos,
1420 					v[idx[i+1]].Pos,
1421 					v[idx[i+2]].TCoords,
1422 					v[idx[i+0]].TCoords,
1423 					v[idx[i+1]].TCoords);
1424 			}
1425 		}
1426 	}
1427 }
1428 
1429 
calculateTangents(core::vector3df & normal,core::vector3df & tangent,core::vector3df & binormal,core::vector3df & vt1,core::vector3df & vt2,core::vector3df & vt3,core::vector2df & tc1,core::vector2df & tc2,core::vector2df & tc3)1430 void CSkinnedMesh::calculateTangents(
1431 	core::vector3df& normal,
1432 	core::vector3df& tangent,
1433 	core::vector3df& binormal,
1434 	core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, // vertices
1435 	core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3) // texture coords
1436 {
1437 	core::vector3df v1 = vt1 - vt2;
1438 	core::vector3df v2 = vt3 - vt1;
1439 	normal = v2.crossProduct(v1);
1440 	normal.normalize();
1441 
1442 	// binormal
1443 
1444 	f32 deltaX1 = tc1.X - tc2.X;
1445 	f32 deltaX2 = tc3.X - tc1.X;
1446 	binormal = (v1 * deltaX2) - (v2 * deltaX1);
1447 	binormal.normalize();
1448 
1449 	// tangent
1450 
1451 	f32 deltaY1 = tc1.Y - tc2.Y;
1452 	f32 deltaY2 = tc3.Y - tc1.Y;
1453 	tangent = (v1 * deltaY2) - (v2 * deltaY1);
1454 	tangent.normalize();
1455 
1456 	// adjust
1457 
1458 	core::vector3df txb = tangent.crossProduct(binormal);
1459 	if (txb.dotProduct(normal) < 0.0f)
1460 	{
1461 		tangent *= -1.0f;
1462 		binormal *= -1.0f;
1463 	}
1464 }
1465 
1466 
1467 } // end namespace scene
1468 } // end namespace irr
1469 
1470 #endif // _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
1471 
1472