2013-03-28 10:04:07 -07:00
// Copyright (C) 2002-2012 Nikolaus Gebhardt
2007-05-20 11:03:49 -07:00
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
# include "CAnimatedMeshSceneNode.h"
# include "IVideoDriver.h"
# include "ISceneManager.h"
# include "S3DVertex.h"
# include "os.h"
2019-04-23 13:17:39 -07:00
# ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
2007-05-20 11:03:49 -07:00
# include "CShadowVolumeSceneNode.h"
2019-04-23 13:17:39 -07:00
# else
# include "IShadowVolumeSceneNode.h"
# endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
2007-05-20 11:03:49 -07:00
# include "IAnimatedMeshMD3.h"
2007-10-16 06:34:07 -07:00
# include "CSkinnedMesh.h"
2007-05-20 11:03:49 -07:00
# include "IDummyTransformationSceneNode.h"
2007-09-04 11:51:42 -07:00
# include "IBoneSceneNode.h"
2007-05-20 11:03:49 -07:00
# include "IMaterialRenderer.h"
# include "IMesh.h"
# include "IMeshCache.h"
# include "IAnimatedMesh.h"
# include "quaternion.h"
2007-09-04 11:51:42 -07:00
2007-05-20 11:03:49 -07:00
namespace irr
{
namespace scene
{
//! constructor
2008-11-27 15:52:13 -08:00
CAnimatedMeshSceneNode : : CAnimatedMeshSceneNode ( IAnimatedMesh * mesh ,
ISceneNode * parent , ISceneManager * mgr , s32 id ,
const core : : vector3df & position ,
const core : : vector3df & rotation ,
const core : : vector3df & scale )
2007-05-20 11:03:49 -07:00
: IAnimatedMeshSceneNode ( parent , mgr , id , position , rotation , scale ) , Mesh ( 0 ) ,
2011-01-14 07:36:50 -08:00
StartFrame ( 0 ) , EndFrame ( 0 ) , FramesPerSecond ( 0.025f ) ,
2009-05-04 17:09:53 -07:00
CurrentFrameNr ( 0.f ) , LastTimeMs ( 0 ) ,
2007-09-05 05:11:28 -07:00
TransitionTime ( 0 ) , Transiting ( 0.f ) , TransitingBlend ( 0.f ) ,
2009-05-04 17:09:53 -07:00
JointMode ( EJUOR_NONE ) , JointsUsed ( false ) ,
2011-01-14 07:36:50 -08:00
Looping ( true ) , ReadOnlyMaterials ( false ) , RenderFromIdentity ( false ) ,
LoopCallBack ( 0 ) , PassCount ( 0 ) , Shadow ( 0 ) , MD3Special ( 0 )
2007-05-20 11:03:49 -07:00
{
# ifdef _DEBUG
setDebugName ( " CAnimatedMeshSceneNode " ) ;
# endif
setMesh ( mesh ) ;
}
//! destructor
CAnimatedMeshSceneNode : : ~ CAnimatedMeshSceneNode ( )
{
2009-09-16 05:48:19 -07:00
if ( MD3Special )
2011-01-14 07:36:50 -08:00
MD3Special - > drop ( ) ;
2009-05-04 17:09:53 -07:00
2007-05-20 11:03:49 -07:00
if ( Mesh )
Mesh - > drop ( ) ;
if ( Shadow )
Shadow - > drop ( ) ;
if ( LoopCallBack )
LoopCallBack - > drop ( ) ;
}
//! Sets the current frame. From now on the animation is played from this frame.
2007-09-04 11:51:42 -07:00
void CAnimatedMeshSceneNode : : setCurrentFrame ( f32 frame )
2007-05-20 11:03:49 -07:00
{
// if you pass an out of range value, we just clamp it
2007-09-04 11:51:42 -07:00
CurrentFrameNr = core : : clamp ( frame , ( f32 ) StartFrame , ( f32 ) EndFrame ) ;
2007-05-20 11:03:49 -07:00
2007-09-05 05:11:28 -07:00
beginTransition ( ) ; //transit to this frame if enabled
2007-05-20 11:03:49 -07:00
}
2008-02-09 06:12:28 -08:00
//! Returns the currently displayed frame number.
2007-09-04 11:51:42 -07:00
f32 CAnimatedMeshSceneNode : : getFrameNr ( ) const
2007-05-20 11:03:49 -07:00
{
return CurrentFrameNr ;
}
2013-03-28 10:04:07 -07:00
//! Get CurrentFrameNr and update transiting settings
2009-05-04 17:09:53 -07:00
void CAnimatedMeshSceneNode : : buildFrameNr ( u32 timeMs )
2007-05-20 11:03:49 -07:00
{
2007-09-05 05:11:28 -07:00
if ( Transiting ! = 0.f )
2007-09-04 11:51:42 -07:00
{
2009-05-04 17:09:53 -07:00
TransitingBlend + = ( f32 ) ( timeMs ) * Transiting ;
2007-09-05 05:11:28 -07:00
if ( TransitingBlend > 1.f )
2007-09-04 11:51:42 -07:00
{
2007-09-05 05:11:28 -07:00
Transiting = 0.f ;
TransitingBlend = 0.f ;
2007-09-04 11:51:42 -07:00
}
}
2014-05-08 08:23:50 -07:00
if ( StartFrame = = EndFrame )
2009-05-04 17:09:53 -07:00
{
CurrentFrameNr = ( f32 ) StartFrame ; //Support for non animated meshes
}
else if ( Looping )
2007-05-20 11:03:49 -07:00
{
// play animation looped
2009-05-04 17:09:53 -07:00
CurrentFrameNr + = timeMs * FramesPerSecond ;
2010-07-18 14:25:27 -07:00
// We have no interpolation between EndFrame and StartFrame,
// the last frame must be identical to first one with our current solution.
2007-09-05 05:11:28 -07:00
if ( FramesPerSecond > 0.f ) //forwards...
2007-09-04 11:51:42 -07:00
{
2009-05-04 17:09:53 -07:00
if ( CurrentFrameNr > EndFrame )
2010-07-18 14:25:27 -07:00
CurrentFrameNr = StartFrame + fmod ( CurrentFrameNr - StartFrame , ( f32 ) ( EndFrame - StartFrame ) ) ;
2007-09-04 11:51:42 -07:00
}
else //backwards...
{
2009-05-04 17:09:53 -07:00
if ( CurrentFrameNr < StartFrame )
2010-07-18 14:25:27 -07:00
CurrentFrameNr = EndFrame - fmod ( EndFrame - CurrentFrameNr , ( f32 ) ( EndFrame - StartFrame ) ) ;
2007-09-04 11:51:42 -07:00
}
2007-05-20 11:03:49 -07:00
}
else
{
// play animation non looped
2009-05-04 17:09:53 -07:00
CurrentFrameNr + = timeMs * FramesPerSecond ;
2007-09-05 05:11:28 -07:00
if ( FramesPerSecond > 0.f ) //forwards...
2007-09-04 11:51:42 -07:00
{
2009-05-04 17:09:53 -07:00
if ( CurrentFrameNr > ( f32 ) EndFrame )
2007-09-04 11:51:42 -07:00
{
2009-05-04 17:09:53 -07:00
CurrentFrameNr = ( f32 ) EndFrame ;
2007-09-04 11:51:42 -07:00
if ( LoopCallBack )
LoopCallBack - > OnAnimationEnd ( this ) ;
}
}
2009-05-04 17:09:53 -07:00
else //backwards...
2007-05-20 11:03:49 -07:00
{
2009-05-04 17:09:53 -07:00
if ( CurrentFrameNr < ( f32 ) StartFrame )
2007-09-04 11:51:42 -07:00
{
2009-05-04 17:09:53 -07:00
CurrentFrameNr = ( f32 ) StartFrame ;
2007-09-04 11:51:42 -07:00
if ( LoopCallBack )
LoopCallBack - > OnAnimationEnd ( this ) ;
}
2007-05-20 11:03:49 -07:00
}
}
}
2008-02-09 06:12:28 -08:00
2007-05-20 11:03:49 -07:00
void CAnimatedMeshSceneNode : : OnRegisterSceneNode ( )
{
2020-01-03 11:05:16 -08:00
if ( IsVisible & & Mesh )
2007-05-20 11:03:49 -07:00
{
// because this node supports rendering of mixed mode meshes consisting of
// transparent and solid material at the same time, we need to go through all
// materials, check of what type they are and register this node for the right
// render pass according to that.
video : : IVideoDriver * driver = SceneManager - > getVideoDriver ( ) ;
PassCount = 0 ;
int transparentCount = 0 ;
int solidCount = 0 ;
// count transparent and solid materials in this scene node
2020-01-03 11:05:16 -08:00
const u32 numMaterials = ReadOnlyMaterials ? Mesh - > getMeshBufferCount ( ) : Materials . size ( ) ;
for ( u32 i = 0 ; i < numMaterials ; + + i )
2007-05-20 11:03:49 -07:00
{
2020-01-03 11:05:16 -08:00
const video : : SMaterial & material = ReadOnlyMaterials ? Mesh - > getMeshBuffer ( i ) - > getMaterial ( ) : Materials [ i ] ;
2007-05-20 11:03:49 -07:00
2020-01-03 11:05:16 -08:00
if ( driver - > needsTransparentRenderPass ( material ) )
2007-05-20 11:03:49 -07:00
+ + transparentCount ;
else
+ + solidCount ;
if ( solidCount & & transparentCount )
break ;
}
// register according to material types counted
if ( solidCount )
SceneManager - > registerNodeForRendering ( this , scene : : ESNRP_SOLID ) ;
if ( transparentCount )
SceneManager - > registerNodeForRendering ( this , scene : : ESNRP_TRANSPARENT ) ;
ISceneNode : : OnRegisterSceneNode ( ) ;
}
}
2010-01-23 12:13:43 -08:00
IMesh * CAnimatedMeshSceneNode : : getMeshForCurrentFrame ( )
2008-11-27 15:52:13 -08:00
{
if ( Mesh - > getMeshType ( ) ! = EAMT_SKINNED )
{
2010-07-18 14:25:27 -07:00
s32 frameNr = ( s32 ) getFrameNr ( ) ;
s32 frameBlend = ( s32 ) ( core : : fract ( getFrameNr ( ) ) * 1000.f ) ;
return Mesh - > getMesh ( frameNr , frameBlend , StartFrame , EndFrame ) ;
2008-11-27 15:52:13 -08:00
}
else
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0 ;
2011-09-08 15:15:27 -07:00
# else
2011-01-14 07:36:50 -08:00
2008-12-19 01:56:25 -08:00
// As multiple scene nodes may be sharing the same skinned mesh, we have to
2010-01-23 12:13:43 -08:00
// re-animate it every frame to ensure that this node gets the mesh that it needs.
2008-12-19 01:56:25 -08:00
2008-11-27 15:52:13 -08:00
CSkinnedMesh * skinnedMesh = reinterpret_cast < CSkinnedMesh * > ( Mesh ) ;
2008-12-19 01:56:25 -08:00
if ( JointMode = = EJUOR_CONTROL ) //write to mesh
2008-11-27 15:52:13 -08:00
skinnedMesh - > transferJointsToMesh ( JointChildSceneNodes ) ;
2009-07-03 02:11:53 -07:00
else
2008-12-19 01:56:25 -08:00
skinnedMesh - > animateMesh ( getFrameNr ( ) , 1.0f ) ;
2008-11-27 15:52:13 -08:00
// Update the skinned mesh for the current joint transforms.
skinnedMesh - > skinMesh ( ) ;
if ( JointMode = = EJUOR_READ ) //read from mesh
{
skinnedMesh - > recoverJointsFromMesh ( JointChildSceneNodes ) ;
//---slow---
for ( u32 n = 0 ; n < JointChildSceneNodes . size ( ) ; + + n )
if ( JointChildSceneNodes [ n ] - > getParent ( ) = = this )
{
JointChildSceneNodes [ n ] - > updateAbsolutePositionOfAllChildren ( ) ; //temp, should be an option
}
}
2008-12-19 01:56:25 -08:00
if ( JointMode = = EJUOR_CONTROL )
2008-11-27 15:52:13 -08:00
{
2008-12-19 01:56:25 -08:00
// For meshes other than EJUOR_CONTROL, this is done by calling animateMesh()
2008-11-27 15:52:13 -08:00
skinnedMesh - > updateBoundingBox ( ) ;
}
2009-01-27 05:23:36 -08:00
return skinnedMesh ;
2011-09-08 15:15:27 -07:00
# endif
2008-11-27 15:52:13 -08:00
}
}
2007-05-20 11:03:49 -07:00
//! OnAnimate() is called just before rendering the whole scene.
void CAnimatedMeshSceneNode : : OnAnimate ( u32 timeMs )
{
2013-03-28 10:04:07 -07:00
if ( LastTimeMs = = 0 ) // first frame
{
LastTimeMs = timeMs ;
}
// set CurrentFrameNr
2009-07-03 02:11:53 -07:00
buildFrameNr ( timeMs - LastTimeMs ) ;
2009-05-04 17:09:53 -07:00
2013-03-28 10:04:07 -07:00
// update bbox
2009-09-16 05:48:19 -07:00
if ( Mesh )
2009-05-04 17:09:53 -07:00
{
2010-01-23 12:13:43 -08:00
scene : : IMesh * mesh = getMeshForCurrentFrame ( ) ;
2009-07-03 02:11:53 -07:00
2009-09-16 05:48:19 -07:00
if ( mesh )
2009-05-04 17:09:53 -07:00
Box = mesh - > getBoundingBox ( ) ;
}
LastTimeMs = timeMs ;
2007-05-20 11:03:49 -07:00
2013-03-28 10:04:07 -07:00
IAnimatedMeshSceneNode : : OnAnimate ( timeMs ) ;
2007-05-26 21:56:56 -07:00
}
2007-05-20 11:03:49 -07:00
//! renders the node.
void CAnimatedMeshSceneNode : : render ( )
{
video : : IVideoDriver * driver = SceneManager - > getVideoDriver ( ) ;
if ( ! Mesh | | ! driver )
return ;
2007-09-04 11:51:42 -07:00
2020-01-03 11:05:16 -08:00
const bool isTransparentPass =
2007-05-20 11:03:49 -07:00
SceneManager - > getSceneNodeRenderPass ( ) = = scene : : ESNRP_TRANSPARENT ;
+ + PassCount ;
2010-01-23 12:13:43 -08:00
scene : : IMesh * m = getMeshForCurrentFrame ( ) ;
2007-09-04 11:51:42 -07:00
2008-12-19 01:56:25 -08:00
if ( m )
{
Box = m - > getBoundingBox ( ) ;
}
else
2007-05-20 11:03:49 -07:00
{
# ifdef _DEBUG
os : : Printer : : log ( " Animated Mesh returned no mesh to render. " , Mesh - > getDebugName ( ) , ELL_WARNING ) ;
# endif
}
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation ) ;
if ( Shadow & & PassCount = = 1 )
2008-08-08 12:39:24 -07:00
Shadow - > updateShadowVolumes ( ) ;
2007-05-20 11:03:49 -07:00
// for debug purposes only:
2008-02-20 16:20:39 -08:00
bool renderMeshes = true ;
2007-05-20 11:03:49 -07:00
video : : SMaterial mat ;
if ( DebugDataVisible & & PassCount = = 1 )
{
// overwrite half transparency
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_HALF_TRANSPARENCY )
2007-05-20 11:03:49 -07:00
{
2008-03-02 06:28:48 -08:00
2008-02-20 16:20:39 -08:00
for ( u32 i = 0 ; i < m - > getMeshBufferCount ( ) ; + + i )
2007-05-20 11:03:49 -07:00
{
2008-02-20 16:20:39 -08:00
scene : : IMeshBuffer * mb = m - > getMeshBuffer ( i ) ;
2009-09-16 05:48:19 -07:00
mat = ReadOnlyMaterials ? mb - > getMaterial ( ) : Materials [ i ] ;
2008-03-19 02:33:59 -07:00
mat . MaterialType = video : : EMT_TRANSPARENT_ADD_COLOR ;
if ( RenderFromIdentity )
2009-05-04 17:09:53 -07:00
driver - > setTransform ( video : : ETS_WORLD , core : : IdentityMatrix ) ;
2008-03-02 06:28:48 -08:00
else if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
2008-02-20 16:20:39 -08:00
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation * ( ( SSkinMeshBuffer * ) mb ) - > Transformation ) ;
2007-05-20 11:03:49 -07:00
driver - > setMaterial ( mat ) ;
2008-02-20 16:20:39 -08:00
driver - > drawMeshBuffer ( mb ) ;
2007-05-20 11:03:49 -07:00
}
2008-02-20 16:20:39 -08:00
renderMeshes = false ;
2007-05-20 11:03:49 -07:00
}
}
// render original meshes
2009-09-16 05:48:19 -07:00
if ( renderMeshes )
2007-05-20 11:03:49 -07:00
{
2007-09-26 09:18:11 -07:00
for ( u32 i = 0 ; i < m - > getMeshBufferCount ( ) ; + + i )
2007-05-20 11:03:49 -07:00
{
2020-01-03 11:05:16 -08:00
const bool transparent = driver - > needsTransparentRenderPass ( Materials [ i ] ) ;
2007-05-20 11:03:49 -07:00
// only render transparent buffer if this is the transparent render pass
// and solid only in solid pass
if ( transparent = = isTransparentPass )
{
scene : : IMeshBuffer * mb = m - > getMeshBuffer ( i ) ;
2009-09-16 05:48:19 -07:00
const video : : SMaterial & material = ReadOnlyMaterials ? mb - > getMaterial ( ) : Materials [ i ] ;
2008-03-19 02:33:59 -07:00
if ( RenderFromIdentity )
2009-05-04 17:09:53 -07:00
driver - > setTransform ( video : : ETS_WORLD , core : : IdentityMatrix ) ;
2008-03-02 06:28:48 -08:00
else if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
2007-09-17 04:09:07 -07:00
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation * ( ( SSkinMeshBuffer * ) mb ) - > Transformation ) ;
2009-09-16 05:48:19 -07:00
driver - > setMaterial ( material ) ;
2007-05-20 11:03:49 -07:00
driver - > drawMeshBuffer ( mb ) ;
}
}
}
2007-09-17 04:09:07 -07:00
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation ) ;
2007-05-20 11:03:49 -07:00
// for debug purposes only:
if ( DebugDataVisible & & PassCount = = 1 )
{
2008-11-12 02:11:25 -08:00
video : : SMaterial debug_mat ;
debug_mat . Lighting = false ;
2009-11-02 09:20:21 -08:00
debug_mat . AntiAliasing = 0 ;
2008-11-12 02:11:25 -08:00
driver - > setMaterial ( debug_mat ) ;
2008-02-20 16:20:39 -08:00
// show normals
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_NORMALS )
2008-02-20 16:20:39 -08:00
{
2012-06-11 15:43:38 -07:00
const f32 debugNormalLength = SceneManager - > getParameters ( ) - > getAttributeAsFloat ( DEBUG_NORMAL_LENGTH ) ;
const video : : SColor debugNormalColor = SceneManager - > getParameters ( ) - > getAttributeAsColor ( DEBUG_NORMAL_COLOR ) ;
const u32 count = m - > getMeshBufferCount ( ) ;
2008-02-20 16:20:39 -08:00
// draw normals
2012-06-11 15:43:38 -07:00
for ( u32 g = 0 ; g < count ; + + g )
2008-02-20 16:20:39 -08:00
{
2016-03-17 15:17:43 -07:00
scene : : IMeshBuffer * mb = m - > getMeshBuffer ( g ) ;
if ( RenderFromIdentity )
driver - > setTransform ( video : : ETS_WORLD , core : : IdentityMatrix ) ;
else if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation * ( ( SSkinMeshBuffer * ) mb ) - > Transformation ) ;
driver - > drawMeshBufferNormals ( mb , debugNormalLength , debugNormalColor ) ;
2008-02-20 16:20:39 -08:00
}
}
2013-03-28 10:04:07 -07:00
debug_mat . ZBuffer = video : : ECFN_DISABLED ;
2008-11-12 02:11:25 -08:00
debug_mat . Lighting = false ;
driver - > setMaterial ( debug_mat ) ;
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_BBOX )
2008-11-12 02:11:25 -08:00
driver - > draw3DBox ( Box , video : : SColor ( 255 , 255 , 255 , 255 ) ) ;
2007-05-20 11:03:49 -07:00
// show bounding box
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_BBOX_BUFFERS )
2007-05-20 11:03:49 -07:00
{
2007-09-26 09:18:11 -07:00
for ( u32 g = 0 ; g < m - > getMeshBufferCount ( ) ; + + g )
2007-05-20 11:03:49 -07:00
{
2008-03-19 02:33:59 -07:00
const IMeshBuffer * mb = m - > getMeshBuffer ( g ) ;
2008-03-02 06:28:48 -08:00
2008-02-20 16:20:39 -08:00
if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation * ( ( SSkinMeshBuffer * ) mb ) - > Transformation ) ;
2012-06-11 15:43:38 -07:00
driver - > draw3DBox ( mb - > getBoundingBox ( ) , video : : SColor ( 255 , 190 , 128 , 128 ) ) ;
2007-05-20 11:03:49 -07:00
}
}
// show skeleton
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_SKELETON )
2007-05-20 11:03:49 -07:00
{
2007-09-04 11:51:42 -07:00
if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
2007-05-20 11:03:49 -07:00
{
// draw skeleton
2007-09-26 09:18:11 -07:00
for ( u32 g = 0 ; g < ( ( ISkinnedMesh * ) Mesh ) - > getAllJoints ( ) . size ( ) ; + + g )
2007-09-04 11:51:42 -07:00
{
ISkinnedMesh : : SJoint * joint = ( ( ISkinnedMesh * ) Mesh ) - > getAllJoints ( ) [ g ] ;
for ( u32 n = 0 ; n < joint - > Children . size ( ) ; + + n )
{
2008-04-29 04:34:54 -07:00
driver - > draw3DLine ( joint - > GlobalAnimatedMatrix . getTranslation ( ) ,
joint - > Children [ n ] - > GlobalAnimatedMatrix . getTranslation ( ) ,
2008-11-12 02:11:25 -08:00
video : : SColor ( 255 , 51 , 66 , 255 ) ) ;
2007-09-04 11:51:42 -07:00
}
}
2007-05-20 11:03:49 -07:00
}
// show tag for quake3 models
2009-09-16 05:48:19 -07:00
if ( Mesh - > getMeshType ( ) = = EAMT_MD3 )
2007-05-20 11:03:49 -07:00
{
2007-07-07 13:08:47 -07:00
IAnimatedMesh * arrow =
SceneManager - > addArrowMesh (
" __tag_show " ,
0xFF0000FF , 0xFF000088 ,
4 , 8 , 5.f , 4.f , 0.5f ,
1.f ) ;
2009-09-16 05:48:19 -07:00
if ( ! arrow )
2007-05-20 11:03:49 -07:00
{
arrow = SceneManager - > getMesh ( " __tag_show " ) ;
}
2008-11-12 02:11:25 -08:00
IMesh * arrowMesh = arrow - > getMesh ( 0 ) ;
2007-05-20 11:03:49 -07:00
2007-09-18 07:01:28 -07:00
core : : matrix4 matr ;
2007-05-20 11:03:49 -07:00
2009-05-04 17:09:53 -07:00
SMD3QuaternionTagList * taglist = ( ( IAnimatedMeshMD3 * ) Mesh ) - > getTagList (
2008-02-20 16:20:39 -08:00
( s32 ) getFrameNr ( ) , 255 ,
getStartFrame ( ) , getEndFrame ( ) ) ;
2009-09-16 05:48:19 -07:00
if ( taglist )
2007-05-20 11:03:49 -07:00
{
2007-09-18 07:01:28 -07:00
for ( u32 ts = 0 ; ts ! = taglist - > size ( ) ; + + ts )
2007-05-20 11:03:49 -07:00
{
2008-11-12 02:11:25 -08:00
( * taglist ) [ ts ] . setto ( matr ) ;
2007-05-20 11:03:49 -07:00
2007-09-18 07:01:28 -07:00
driver - > setTransform ( video : : ETS_WORLD , matr ) ;
2007-05-20 11:03:49 -07:00
for ( u32 a = 0 ; a ! = arrowMesh - > getMeshBufferCount ( ) ; + + a )
2008-11-12 02:11:25 -08:00
driver - > drawMeshBuffer ( arrowMesh - > getMeshBuffer ( a ) ) ;
2007-05-20 11:03:49 -07:00
}
}
}
}
// show mesh
2009-09-16 05:48:19 -07:00
if ( DebugDataVisible & scene : : EDS_MESH_WIRE_OVERLAY )
2007-05-20 11:03:49 -07:00
{
2008-11-12 02:11:25 -08:00
debug_mat . Lighting = false ;
debug_mat . Wireframe = true ;
2013-03-28 10:04:07 -07:00
debug_mat . ZBuffer = video : : ECFN_DISABLED ;
2008-11-12 02:11:25 -08:00
driver - > setMaterial ( debug_mat ) ;
2008-03-02 06:28:48 -08:00
2007-09-26 09:18:11 -07:00
for ( u32 g = 0 ; g < m - > getMeshBufferCount ( ) ; + + g )
2007-05-20 11:03:49 -07:00
{
2008-03-19 02:33:59 -07:00
const IMeshBuffer * mb = m - > getMeshBuffer ( g ) ;
if ( RenderFromIdentity )
2009-05-04 17:09:53 -07:00
driver - > setTransform ( video : : ETS_WORLD , core : : IdentityMatrix ) ;
2008-03-02 06:28:48 -08:00
else if ( Mesh - > getMeshType ( ) = = EAMT_SKINNED )
2008-02-20 16:20:39 -08:00
driver - > setTransform ( video : : ETS_WORLD , AbsoluteTransformation * ( ( SSkinMeshBuffer * ) mb ) - > Transformation ) ;
driver - > drawMeshBuffer ( mb ) ;
2007-05-20 11:03:49 -07:00
}
}
}
}
//! Returns the current start frame number.
s32 CAnimatedMeshSceneNode : : getStartFrame ( ) const
{
return StartFrame ;
}
2007-11-14 01:50:41 -08:00
2007-05-20 11:03:49 -07:00
//! Returns the current start frame number.
s32 CAnimatedMeshSceneNode : : getEndFrame ( ) const
{
return EndFrame ;
}
2007-11-14 01:50:41 -08:00
2007-05-20 11:03:49 -07:00
//! sets the frames between the animation is looped.
//! the default is 0 - MaximalFrameCount of the mesh.
bool CAnimatedMeshSceneNode : : setFrameLoop ( s32 begin , s32 end )
{
const s32 maxFrameCount = Mesh - > getFrameCount ( ) - 1 ;
2009-09-16 05:48:19 -07:00
if ( end < begin )
2007-05-20 11:03:49 -07:00
{
StartFrame = core : : s32_clamp ( end , 0 , maxFrameCount ) ;
EndFrame = core : : s32_clamp ( begin , StartFrame , maxFrameCount ) ;
}
else
{
StartFrame = core : : s32_clamp ( begin , 0 , maxFrameCount ) ;
EndFrame = core : : s32_clamp ( end , StartFrame , maxFrameCount ) ;
}
2009-05-04 17:09:53 -07:00
if ( FramesPerSecond < 0 )
setCurrentFrame ( ( f32 ) EndFrame ) ;
else
setCurrentFrame ( ( f32 ) StartFrame ) ;
2007-05-20 11:03:49 -07:00
return true ;
}
//! sets the speed with witch the animation is played
void CAnimatedMeshSceneNode : : setAnimationSpeed ( f32 framesPerSecond )
{
FramesPerSecond = framesPerSecond * 0.001f ;
}
2009-11-02 09:20:21 -08:00
f32 CAnimatedMeshSceneNode : : getAnimationSpeed ( ) const
{
return FramesPerSecond * 1000.f ;
}
2007-05-20 11:03:49 -07:00
//! returns the axis aligned bounding box of this node
const core : : aabbox3d < f32 > & CAnimatedMeshSceneNode : : getBoundingBox ( ) const
{
return Box ;
}
2020-01-03 11:05:16 -08:00
//! returns the material based on the zero based index i.
2007-05-20 11:03:49 -07:00
video : : SMaterial & CAnimatedMeshSceneNode : : getMaterial ( u32 i )
{
2009-09-16 05:48:19 -07:00
if ( i > = Materials . size ( ) )
2007-05-20 11:03:49 -07:00
return ISceneNode : : getMaterial ( i ) ;
return Materials [ i ] ;
}
//! returns amount of materials used by this scene node.
2007-09-16 16:41:55 -07:00
u32 CAnimatedMeshSceneNode : : getMaterialCount ( ) const
2007-05-20 11:03:49 -07:00
{
return Materials . size ( ) ;
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
2011-01-14 07:36:50 -08:00
IShadowVolumeSceneNode * CAnimatedMeshSceneNode : : addShadowVolumeSceneNode (
const IMesh * shadowMesh , s32 id , bool zfailmethod , f32 infinity )
2007-05-20 11:03:49 -07:00
{
2019-04-23 13:17:39 -07:00
# ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
2007-05-20 11:03:49 -07:00
if ( ! SceneManager - > getVideoDriver ( ) - > queryFeature ( video : : EVDF_STENCIL_BUFFER ) )
return 0 ;
2008-08-08 12:39:24 -07:00
if ( ! shadowMesh )
shadowMesh = Mesh ; // if null is given, use the mesh of node
2011-01-14 07:36:50 -08:00
if ( Shadow )
Shadow - > drop ( ) ;
2008-08-08 12:39:24 -07:00
Shadow = new CShadowVolumeSceneNode ( shadowMesh , this , SceneManager , id , zfailmethod , infinity ) ;
2007-05-20 11:03:49 -07:00
return Shadow ;
2019-04-23 13:17:39 -07:00
# else
return 0 ;
# endif
2007-05-20 11:03:49 -07:00
}
2007-11-14 01:50:41 -08:00
//! Returns a pointer to a child node, which has the same transformation as
//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
2007-09-04 11:51:42 -07:00
IBoneSceneNode * CAnimatedMeshSceneNode : : getJointNode ( const c8 * jointName )
2007-05-20 11:03:49 -07:00
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os : : Printer : : log ( " Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ " , ELL_WARNING ) ;
return 0 ;
2011-09-08 15:15:27 -07:00
# else
2011-01-14 07:36:50 -08:00
2007-09-04 11:51:42 -07:00
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_SKINNED )
2008-11-12 02:11:25 -08:00
{
os : : Printer : : log ( " No mesh, or mesh not of skinned mesh type " , ELL_WARNING ) ;
2007-05-20 11:03:49 -07:00
return 0 ;
2008-11-12 02:11:25 -08:00
}
2007-05-20 11:03:49 -07:00
2007-09-04 11:51:42 -07:00
checkJoints ( ) ;
ISkinnedMesh * skinnedMesh = ( ISkinnedMesh * ) Mesh ;
2008-03-19 02:33:59 -07:00
const s32 number = skinnedMesh - > getJointNumber ( jointName ) ;
2007-05-20 11:03:49 -07:00
if ( number = = - 1 )
{
2011-01-14 07:36:50 -08:00
os : : Printer : : log ( " Joint with specified name not found in skinned mesh " , jointName , ELL_DEBUG ) ;
2007-05-20 11:03:49 -07:00
return 0 ;
}
2007-09-04 11:51:42 -07:00
if ( ( s32 ) JointChildSceneNodes . size ( ) < = number )
2007-05-20 11:03:49 -07:00
{
2007-09-04 11:51:42 -07:00
os : : Printer : : log ( " Joint was found in mesh, but is not loaded into node " , jointName , ELL_WARNING ) ;
return 0 ;
2007-05-20 11:03:49 -07:00
}
2011-01-14 07:36:50 -08:00
return JointChildSceneNodes [ number ] ;
2011-09-08 15:15:27 -07:00
# endif
2007-09-05 01:54:40 -07:00
}
2011-01-14 07:36:50 -08:00
2007-11-14 01:50:41 -08:00
//! Returns a pointer to a child node, which has the same transformation as
//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
2007-09-05 01:54:40 -07:00
IBoneSceneNode * CAnimatedMeshSceneNode : : getJointNode ( u32 jointID )
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os : : Printer : : log ( " Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ " , ELL_WARNING ) ;
return 0 ;
2011-09-08 15:15:27 -07:00
# else
2011-01-14 07:36:50 -08:00
2008-11-12 02:11:25 -08:00
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_SKINNED )
{
os : : Printer : : log ( " No mesh, or mesh not of skinned mesh type " , ELL_WARNING ) ;
return 0 ;
}
checkJoints ( ) ;
2007-09-05 01:54:40 -07:00
if ( JointChildSceneNodes . size ( ) < = jointID )
{
os : : Printer : : log ( " Joint not loaded into node " , ELL_WARNING ) ;
return 0 ;
}
return JointChildSceneNodes [ jointID ] ;
2011-09-08 15:15:27 -07:00
# endif
2007-05-20 11:03:49 -07:00
}
2007-11-13 23:35:40 -08:00
//! Gets joint count.
u32 CAnimatedMeshSceneNode : : getJointCount ( ) const
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0 ;
2011-09-08 15:15:27 -07:00
# else
2011-01-14 07:36:50 -08:00
2007-11-13 23:35:40 -08:00
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_SKINNED )
return 0 ;
ISkinnedMesh * skinnedMesh = ( ISkinnedMesh * ) Mesh ;
return skinnedMesh - > getJointCount ( ) ;
2011-09-08 15:15:27 -07:00
# endif
2007-11-13 23:35:40 -08:00
}
2007-05-20 11:03:49 -07:00
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CAnimatedMeshSceneNode : : removeChild ( ISceneNode * child )
{
if ( child & & Shadow = = child )
{
Shadow - > drop ( ) ;
Shadow = 0 ;
}
2007-11-13 23:35:40 -08:00
if ( ISceneNode : : removeChild ( child ) )
2007-05-20 11:03:49 -07:00
{
2007-11-13 23:35:40 -08:00
if ( JointsUsed ) //stop weird bugs caused while changing parents as the joints are being created
2007-05-20 11:03:49 -07:00
{
2007-09-09 15:40:28 -07:00
for ( u32 i = 0 ; i < JointChildSceneNodes . size ( ) ; + + i )
2007-09-04 11:51:42 -07:00
{
2011-01-14 07:36:50 -08:00
if ( JointChildSceneNodes [ i ] = = child )
{
JointChildSceneNodes [ i ] = 0 ; //remove link to child
break ;
}
2007-09-04 11:51:42 -07:00
}
2007-05-20 11:03:49 -07:00
}
2007-11-13 23:35:40 -08:00
return true ;
2007-05-20 11:03:49 -07:00
}
return false ;
}
//! Starts a MD2 animation.
bool CAnimatedMeshSceneNode : : setMD2Animation ( EMD2_ANIMATION_TYPE anim )
{
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_MD2 )
return false ;
2008-11-12 02:11:25 -08:00
IAnimatedMeshMD2 * md = ( IAnimatedMeshMD2 * ) Mesh ;
2007-05-20 11:03:49 -07:00
s32 begin , end , speed ;
2008-11-12 02:11:25 -08:00
md - > getFrameLoop ( anim , begin , end , speed ) ;
2007-05-20 11:03:49 -07:00
setAnimationSpeed ( f32 ( speed ) ) ;
setFrameLoop ( begin , end ) ;
return true ;
}
//! Starts a special MD2 animation.
bool CAnimatedMeshSceneNode : : setMD2Animation ( const c8 * animationName )
{
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_MD2 )
return false ;
2008-11-12 02:11:25 -08:00
IAnimatedMeshMD2 * md = ( IAnimatedMeshMD2 * ) Mesh ;
2007-05-20 11:03:49 -07:00
s32 begin , end , speed ;
2008-11-12 02:11:25 -08:00
if ( ! md - > getFrameLoop ( animationName , begin , end , speed ) )
2007-05-20 11:03:49 -07:00
return false ;
setAnimationSpeed ( ( f32 ) speed ) ;
setFrameLoop ( begin , end ) ;
return true ;
}
//! Sets looping mode which is on by default. If set to false,
//! animations will not be looped.
void CAnimatedMeshSceneNode : : setLoopMode ( bool playAnimationLooped )
{
Looping = playAnimationLooped ;
}
2013-03-28 10:04:07 -07:00
//! returns the current loop mode
bool CAnimatedMeshSceneNode : : getLoopMode ( ) const
{
return Looping ;
}
2007-05-20 11:03:49 -07:00
//! Sets a callback interface which will be called if an animation
//! playback has ended. Set this to 0 to disable the callback again.
void CAnimatedMeshSceneNode : : setAnimationEndCallback ( IAnimationEndCallBack * callback )
{
2009-05-04 17:09:53 -07:00
if ( callback = = LoopCallBack )
return ;
2007-05-20 11:03:49 -07:00
if ( LoopCallBack )
LoopCallBack - > drop ( ) ;
LoopCallBack = callback ;
if ( LoopCallBack )
LoopCallBack - > grab ( ) ;
}
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
void CAnimatedMeshSceneNode : : setReadOnlyMaterials ( bool readonly )
{
ReadOnlyMaterials = readonly ;
}
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
2007-09-14 15:25:59 -07:00
bool CAnimatedMeshSceneNode : : isReadOnlyMaterials ( ) const
2007-05-20 11:03:49 -07:00
{
return ReadOnlyMaterials ;
}
//! Writes attributes of the scene node.
2007-09-14 15:25:59 -07:00
void CAnimatedMeshSceneNode : : serializeAttributes ( io : : IAttributes * out , io : : SAttributeReadWriteOptions * options ) const
2007-05-20 11:03:49 -07:00
{
IAnimatedMeshSceneNode : : serializeAttributes ( out , options ) ;
2011-05-18 15:21:50 -07:00
if ( options & & ( options - > Flags & io : : EARWF_USE_RELATIVE_PATHS ) & & options - > Filename )
{
const io : : path path = SceneManager - > getFileSystem ( ) - > getRelativeFilename (
SceneManager - > getFileSystem ( ) - > getAbsolutePath ( SceneManager - > getMeshCache ( ) - > getMeshName ( Mesh ) . getPath ( ) ) ,
options - > Filename ) ;
out - > addString ( " Mesh " , path . c_str ( ) ) ;
}
else
out - > addString ( " Mesh " , SceneManager - > getMeshCache ( ) - > getMeshName ( Mesh ) . getPath ( ) . c_str ( ) ) ;
2007-05-20 11:03:49 -07:00
out - > addBool ( " Looping " , Looping ) ;
out - > addBool ( " ReadOnlyMaterials " , ReadOnlyMaterials ) ;
out - > addFloat ( " FramesPerSecond " , FramesPerSecond ) ;
2009-11-02 09:20:21 -08:00
out - > addInt ( " StartFrame " , StartFrame ) ;
out - > addInt ( " EndFrame " , EndFrame ) ;
2007-05-20 11:03:49 -07:00
}
//! Reads attributes of the scene node.
void CAnimatedMeshSceneNode : : deserializeAttributes ( io : : IAttributes * in , io : : SAttributeReadWriteOptions * options )
{
IAnimatedMeshSceneNode : : deserializeAttributes ( in , options ) ;
2010-01-23 12:13:43 -08:00
io : : path oldMeshStr = SceneManager - > getMeshCache ( ) - > getMeshName ( Mesh ) ;
2009-09-16 05:48:19 -07:00
io : : path newMeshStr = in - > getAttributeAsString ( " Mesh " ) ;
2007-05-20 11:03:49 -07:00
Looping = in - > getAttributeAsBool ( " Looping " ) ;
ReadOnlyMaterials = in - > getAttributeAsBool ( " ReadOnlyMaterials " ) ;
FramesPerSecond = in - > getAttributeAsFloat ( " FramesPerSecond " ) ;
2009-11-02 09:20:21 -08:00
StartFrame = in - > getAttributeAsInt ( " StartFrame " ) ;
EndFrame = in - > getAttributeAsInt ( " EndFrame " ) ;
2007-05-20 11:03:49 -07:00
if ( newMeshStr ! = " " & & oldMeshStr ! = newMeshStr )
{
IAnimatedMesh * newAnimatedMesh = SceneManager - > getMesh ( newMeshStr . c_str ( ) ) ;
if ( newAnimatedMesh )
setMesh ( newAnimatedMesh ) ;
}
// TODO: read animation names instead of frame begin and ends
}
//! Sets a new mesh
void CAnimatedMeshSceneNode : : setMesh ( IAnimatedMesh * mesh )
{
if ( ! mesh )
return ; // won't set null mesh
2009-05-04 17:09:53 -07:00
if ( Mesh ! = mesh )
{
if ( Mesh )
Mesh - > drop ( ) ;
2007-05-20 11:03:49 -07:00
2009-05-04 17:09:53 -07:00
Mesh = mesh ;
// grab the mesh (it's non-null!)
Mesh - > grab ( ) ;
}
2007-05-20 11:03:49 -07:00
// get materials and bounding box
Box = Mesh - > getBoundingBox ( ) ;
IMesh * m = Mesh - > getMesh ( 0 , 0 ) ;
if ( m )
{
Materials . clear ( ) ;
2009-05-04 17:09:53 -07:00
Materials . reallocate ( m - > getMeshBufferCount ( ) ) ;
2007-05-20 11:03:49 -07:00
for ( u32 i = 0 ; i < m - > getMeshBufferCount ( ) ; + + i )
{
IMeshBuffer * mb = m - > getMeshBuffer ( i ) ;
if ( mb )
2009-05-04 17:09:53 -07:00
Materials . push_back ( mb - > getMaterial ( ) ) ;
else
Materials . push_back ( video : : SMaterial ( ) ) ;
2007-05-20 11:03:49 -07:00
}
}
2011-01-14 07:36:50 -08:00
// clean up joint nodes
if ( JointsUsed )
{
JointsUsed = false ;
checkJoints ( ) ;
}
2007-05-20 11:03:49 -07:00
// get start and begin time
2015-11-12 14:32:01 -08:00
setAnimationSpeed ( Mesh - > getAnimationSpeed ( ) ) ; // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in.
setFrameLoop ( 0 , Mesh - > getFrameCount ( ) - 1 ) ;
2007-05-20 11:03:49 -07:00
}
2008-03-19 02:33:59 -07:00
2007-05-20 11:03:49 -07:00
// returns the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh,
// or the absolutetransformation if it's a normal scenenode
2011-01-14 07:36:50 -08:00
const SMD3QuaternionTag * CAnimatedMeshSceneNode : : getMD3TagTransformation ( const core : : stringc & tagname )
2007-05-20 11:03:49 -07:00
{
2011-01-14 07:36:50 -08:00
return MD3Special ? MD3Special - > AbsoluteTagList . get ( tagname ) : 0 ;
2007-05-20 11:03:49 -07:00
}
//! updates the absolute position based on the relative and the parents position
void CAnimatedMeshSceneNode : : updateAbsolutePosition ( )
{
2008-04-29 08:15:51 -07:00
IAnimatedMeshSceneNode : : updateAbsolutePosition ( ) ;
2009-09-16 05:48:19 -07:00
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_MD3 )
2007-05-20 11:03:49 -07:00
return ;
2009-05-04 17:09:53 -07:00
SMD3QuaternionTagList * taglist ;
2007-09-04 11:51:42 -07:00
taglist = ( ( IAnimatedMeshMD3 * ) Mesh ) - > getTagList ( ( s32 ) getFrameNr ( ) , 255 , getStartFrame ( ) , getEndFrame ( ) ) ;
2009-09-16 05:48:19 -07:00
if ( taglist )
2007-05-20 11:03:49 -07:00
{
2009-09-16 05:48:19 -07:00
if ( ! MD3Special )
2009-05-04 17:09:53 -07:00
{
2009-09-16 05:48:19 -07:00
MD3Special = new SMD3Special ( ) ;
2009-05-04 17:09:53 -07:00
}
SMD3QuaternionTag parent ( MD3Special - > Tagname ) ;
2009-09-16 05:48:19 -07:00
if ( Parent & & Parent - > getType ( ) = = ESNT_ANIMATED_MESH )
2009-05-04 17:09:53 -07:00
{
2009-07-03 02:11:53 -07:00
const SMD3QuaternionTag * p = ( ( IAnimatedMeshSceneNode * ) Parent ) - > getMD3TagTransformation
2009-05-04 17:09:53 -07:00
( MD3Special - > Tagname ) ;
2009-09-16 05:48:19 -07:00
if ( p )
2009-05-04 17:09:53 -07:00
parent = * p ;
}
SMD3QuaternionTag relative ( RelativeTranslation , RelativeRotation ) ;
MD3Special - > AbsoluteTagList . set_used ( taglist - > size ( ) ) ;
2007-09-26 09:18:11 -07:00
for ( u32 i = 0 ; i ! = taglist - > size ( ) ; + + i )
2007-05-20 11:03:49 -07:00
{
2009-05-04 17:09:53 -07:00
MD3Special - > AbsoluteTagList [ i ] . position = parent . position + ( * taglist ) [ i ] . position + relative . position ;
MD3Special - > AbsoluteTagList [ i ] . rotation = parent . rotation * ( * taglist ) [ i ] . rotation * relative . rotation ;
2007-05-20 11:03:49 -07:00
}
}
}
2007-09-04 11:51:42 -07:00
//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set)
2007-10-16 06:34:07 -07:00
void CAnimatedMeshSceneNode : : setJointMode ( E_JOINT_UPDATE_ON_RENDER mode )
2007-09-04 11:51:42 -07:00
{
checkJoints ( ) ;
JointMode = mode ;
}
//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2)
//! you must call animateJoints(), or the mesh will not animate
2007-09-05 05:11:28 -07:00
void CAnimatedMeshSceneNode : : setTransitionTime ( f32 time )
2007-09-04 11:51:42 -07:00
{
2011-01-14 07:36:50 -08:00
const u32 ttime = ( u32 ) core : : floor32 ( time * 1000.0f ) ;
if ( TransitionTime = = ttime )
return ;
TransitionTime = ttime ;
if ( ttime ! = 0 )
2007-10-16 06:34:07 -07:00
setJointMode ( EJUOR_CONTROL ) ;
2011-01-14 07:36:50 -08:00
else
setJointMode ( EJUOR_NONE ) ;
2007-09-04 11:51:42 -07:00
}
2009-05-04 17:09:53 -07:00
2008-11-27 15:52:13 -08:00
//! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected)
2011-01-14 07:36:50 -08:00
void CAnimatedMeshSceneNode : : setRenderFromIdentity ( bool enable )
2007-10-01 21:01:08 -07:00
{
2011-01-14 07:36:50 -08:00
RenderFromIdentity = enable ;
2007-10-01 21:01:08 -07:00
}
2007-09-04 11:51:42 -07:00
//! updates the joint positions of this mesh
2007-10-16 06:34:07 -07:00
void CAnimatedMeshSceneNode : : animateJoints ( bool CalculateAbsolutePositions )
2007-09-04 11:51:42 -07:00
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return ;
2011-09-08 15:15:27 -07:00
# else
2007-09-04 11:51:42 -07:00
if ( Mesh & & Mesh - > getMeshType ( ) = = EAMT_SKINNED )
{
2011-01-14 07:36:50 -08:00
checkJoints ( ) ;
const f32 frame = getFrameNr ( ) ; //old?
2007-11-27 06:05:57 -08:00
2011-01-14 07:36:50 -08:00
CSkinnedMesh * skinnedMesh = reinterpret_cast < CSkinnedMesh * > ( Mesh ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
skinnedMesh - > transferOnlyJointsHintsToMesh ( JointChildSceneNodes ) ;
skinnedMesh - > animateMesh ( frame , 1.0f ) ;
skinnedMesh - > recoverJointsFromMesh ( JointChildSceneNodes ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//-----------------------------------------
// Transition
//-----------------------------------------
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
if ( Transiting ! = 0.f )
{
// Init additional matrices
if ( PretransitingSave . size ( ) < JointChildSceneNodes . size ( ) )
2007-09-04 11:51:42 -07:00
{
2011-01-14 07:36:50 -08:00
for ( u32 n = PretransitingSave . size ( ) ; n < JointChildSceneNodes . size ( ) ; + + n )
PretransitingSave . push_back ( core : : matrix4 ( ) ) ;
}
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
for ( u32 n = 0 ; n < JointChildSceneNodes . size ( ) ; + + n )
{
//------Position------
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
JointChildSceneNodes [ n ] - > setPosition (
core : : lerp (
PretransitingSave [ n ] . getTranslation ( ) ,
JointChildSceneNodes [ n ] - > getPosition ( ) ,
TransitingBlend ) ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//------Rotation------
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//Code is slow, needs to be fixed up
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
const core : : quaternion RotationStart ( PretransitingSave [ n ] . getRotationDegrees ( ) * core : : DEGTORAD ) ;
const core : : quaternion RotationEnd ( JointChildSceneNodes [ n ] - > getRotation ( ) * core : : DEGTORAD ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
core : : quaternion QRotation ;
QRotation . slerp ( RotationStart , RotationEnd , TransitingBlend ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
core : : vector3df tmpVector ;
QRotation . toEuler ( tmpVector ) ;
tmpVector * = core : : RADTODEG ; //convert from radians back to degrees
JointChildSceneNodes [ n ] - > setRotation ( tmpVector ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//------Scale------
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//JointChildSceneNodes[n]->setScale(
// core::lerp(
// PretransitingSave[n].getScale(),
// JointChildSceneNodes[n]->getScale(),
// TransitingBlend));
2007-09-04 11:51:42 -07:00
}
2011-01-14 07:36:50 -08:00
}
2007-11-27 06:05:57 -08:00
2011-01-14 07:36:50 -08:00
if ( CalculateAbsolutePositions )
{
//---slow---
for ( u32 n = 0 ; n < JointChildSceneNodes . size ( ) ; + + n )
2007-11-27 06:05:57 -08:00
{
2011-01-14 07:36:50 -08:00
if ( JointChildSceneNodes [ n ] - > getParent ( ) = = this )
2008-03-19 02:33:59 -07:00
{
2011-01-14 07:36:50 -08:00
JointChildSceneNodes [ n ] - > updateAbsolutePositionOfAllChildren ( ) ; //temp, should be an option
2008-03-19 02:33:59 -07:00
}
2007-11-27 06:05:57 -08:00
}
2007-09-04 11:51:42 -07:00
}
}
2011-09-08 15:15:27 -07:00
# endif
2007-09-04 11:51:42 -07:00
}
2009-05-04 17:09:53 -07:00
/*!
*/
2007-09-04 11:51:42 -07:00
void CAnimatedMeshSceneNode : : checkJoints ( )
{
2011-01-14 07:36:50 -08:00
# ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return ;
2011-09-08 15:15:27 -07:00
# else
2011-01-14 07:36:50 -08:00
2007-09-04 11:51:42 -07:00
if ( ! Mesh | | Mesh - > getMeshType ( ) ! = EAMT_SKINNED )
return ;
if ( ! JointsUsed )
{
2011-01-14 07:36:50 -08:00
for ( u32 i = 0 ; i < JointChildSceneNodes . size ( ) ; + + i )
removeChild ( JointChildSceneNodes [ i ] ) ;
JointChildSceneNodes . clear ( ) ;
2007-09-04 11:51:42 -07:00
2011-01-14 07:36:50 -08:00
//Create joints for SkinnedMesh
( ( CSkinnedMesh * ) Mesh ) - > addJoints ( JointChildSceneNodes , this , SceneManager ) ;
2007-10-16 06:34:07 -07:00
( ( CSkinnedMesh * ) Mesh ) - > recoverJointsFromMesh ( JointChildSceneNodes ) ;
2007-09-04 11:51:42 -07:00
JointsUsed = true ;
2007-10-16 06:34:07 -07:00
JointMode = EJUOR_READ ;
2007-09-04 11:51:42 -07:00
}
2011-09-08 15:15:27 -07:00
# endif
2007-09-04 11:51:42 -07:00
}
2009-05-04 17:09:53 -07:00
/*!
*/
2007-09-04 11:51:42 -07:00
void CAnimatedMeshSceneNode : : beginTransition ( )
{
2007-09-05 05:11:28 -07:00
if ( ! JointsUsed )
return ;
2007-09-04 11:51:42 -07:00
2007-09-05 05:11:28 -07:00
if ( TransitionTime ! = 0 )
2007-09-04 11:51:42 -07:00
{
//Check the array is big enough
if ( PretransitingSave . size ( ) < JointChildSceneNodes . size ( ) )
{
2007-09-05 05:11:28 -07:00
for ( u32 n = PretransitingSave . size ( ) ; n < JointChildSceneNodes . size ( ) ; + + n )
2007-09-04 11:51:42 -07:00
PretransitingSave . push_back ( core : : matrix4 ( ) ) ;
}
//Copy the position of joints
2007-09-05 05:11:28 -07:00
for ( u32 n = 0 ; n < JointChildSceneNodes . size ( ) ; + + n )
2007-09-04 11:51:42 -07:00
PretransitingSave [ n ] = JointChildSceneNodes [ n ] - > getRelativeTransformation ( ) ;
2007-09-05 05:11:28 -07:00
Transiting = core : : reciprocal ( ( f32 ) TransitionTime ) ;
2007-09-04 11:51:42 -07:00
}
2008-07-28 10:34:05 -07:00
TransitingBlend = 0.f ;
2007-09-04 11:51:42 -07:00
}
2009-05-04 17:09:53 -07:00
/*!
*/
2008-11-12 02:11:25 -08:00
ISceneNode * CAnimatedMeshSceneNode : : clone ( ISceneNode * newParent , ISceneManager * newManager )
{
2011-01-14 07:36:50 -08:00
if ( ! newParent )
newParent = Parent ;
if ( ! newManager )
newManager = SceneManager ;
2008-11-12 02:11:25 -08:00
2011-01-14 07:36:50 -08:00
CAnimatedMeshSceneNode * newNode =
2010-06-01 15:52:38 -07:00
new CAnimatedMeshSceneNode ( Mesh , NULL , newManager , ID , RelativeTranslation ,
2008-11-12 02:11:25 -08:00
RelativeRotation , RelativeScale ) ;
2011-01-14 07:36:50 -08:00
if ( newParent )
2010-06-01 15:52:38 -07:00
{
newNode - > setParent ( newParent ) ; // not in constructor because virtual overload for updateAbsolutePosition won't be called
newNode - > drop ( ) ;
}
2008-11-12 02:11:25 -08:00
newNode - > cloneMembers ( this , newManager ) ;
newNode - > Materials = Materials ;
newNode - > Box = Box ;
newNode - > Mesh = Mesh ;
newNode - > StartFrame = StartFrame ;
newNode - > EndFrame = EndFrame ;
newNode - > FramesPerSecond = FramesPerSecond ;
newNode - > CurrentFrameNr = CurrentFrameNr ;
newNode - > JointMode = JointMode ;
newNode - > JointsUsed = JointsUsed ;
newNode - > TransitionTime = TransitionTime ;
newNode - > Transiting = Transiting ;
newNode - > TransitingBlend = TransitingBlend ;
newNode - > Looping = Looping ;
newNode - > ReadOnlyMaterials = ReadOnlyMaterials ;
newNode - > LoopCallBack = LoopCallBack ;
2014-01-07 15:31:31 -08:00
if ( newNode - > LoopCallBack )
2014-05-08 08:23:50 -07:00
newNode - > LoopCallBack - > grab ( ) ;
2008-11-12 02:11:25 -08:00
newNode - > PassCount = PassCount ;
newNode - > Shadow = Shadow ;
2014-01-07 15:31:31 -08:00
if ( newNode - > Shadow )
newNode - > Shadow - > grab ( ) ;
2008-11-12 02:11:25 -08:00
newNode - > JointChildSceneNodes = JointChildSceneNodes ;
newNode - > PretransitingSave = PretransitingSave ;
newNode - > RenderFromIdentity = RenderFromIdentity ;
newNode - > MD3Special = MD3Special ;
return newNode ;
}
2007-05-20 11:03:49 -07:00
} // end namespace scene
} // end namespace irr