#include "CAnimatedMeshSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "S3DVertex.h"
#include "os.h"
#include "CShadowVolumeSceneNode.h"
#include "IAnimatedMeshMD3.h"
#include "CSkinnedMesh.h"
#include "IDummyTransformationSceneNode.h"
#include "IBoneSceneNode.h"
#include "IMaterialRenderer.h"
#include "IMesh.h"
#include "IMeshCache.h"
#include "IAnimatedMesh.h"
#include "quaternion.h"
namespace irr
{
namespace scene
{
CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh,
ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position,
const core::vector3df& rotation,
const core::vector3df& scale)
: IAnimatedMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
StartFrame(0), EndFrame(0), FramesPerSecond(0.025f),
CurrentFrameNr(0.f), LastTimeMs(0),
TransitionTime(0), Transiting(0.f), TransitingBlend(0.f),
JointMode(EJUOR_NONE), JointsUsed(false),
Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false),
LoopCallBack(0), PassCount(0), Shadow(0), MD3Special(0)
{
#ifdef _DEBUG
setDebugName("CAnimatedMeshSceneNode");
#endif
setMesh(mesh);
}
CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode()
{
if (MD3Special)
MD3Special->drop();
if (Mesh)
Mesh->drop();
if (Shadow)
Shadow->drop();
if (LoopCallBack)
LoopCallBack->drop();
}
void CAnimatedMeshSceneNode::setCurrentFrame(f32 frame)
{
CurrentFrameNr = core::clamp ( frame, (f32)StartFrame, (f32)EndFrame );
beginTransition();
}
f32 CAnimatedMeshSceneNode::getFrameNr() const
{
return CurrentFrameNr;
}
void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
{
if (Transiting!=0.f)
{
TransitingBlend += (f32)(timeMs) * Transiting;
if (TransitingBlend > 1.f)
{
Transiting=0.f;
TransitingBlend=0.f;
}
}
if ((StartFrame==EndFrame))
{
CurrentFrameNr = (f32)StartFrame;
}
else if (Looping)
{
CurrentFrameNr += timeMs * FramesPerSecond;
if (FramesPerSecond > 0.f)
{
if (CurrentFrameNr > EndFrame)
CurrentFrameNr = StartFrame + fmod(CurrentFrameNr - StartFrame, (f32)(EndFrame-StartFrame));
}
else
{
if (CurrentFrameNr < StartFrame)
CurrentFrameNr = EndFrame - fmod(EndFrame - CurrentFrameNr, (f32)(EndFrame-StartFrame));
}
}
else
{
CurrentFrameNr += timeMs * FramesPerSecond;
if (FramesPerSecond > 0.f)
{
if (CurrentFrameNr > (f32)EndFrame)
{
CurrentFrameNr = (f32)EndFrame;
if (LoopCallBack)
LoopCallBack->OnAnimationEnd(this);
}
}
else
{
if (CurrentFrameNr < (f32)StartFrame)
{
CurrentFrameNr = (f32)StartFrame;
if (LoopCallBack)
LoopCallBack->OnAnimationEnd(this);
}
}
}
}
void CAnimatedMeshSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
PassCount = 0;
int transparentCount = 0;
int solidCount = 0;
for (u32 i=0; i<Materials.size(); ++i)
{
video::IMaterialRenderer* rnd =
driver->getMaterialRenderer(Materials[i].MaterialType);
if (rnd && rnd->isTransparent())
++transparentCount;
else
++solidCount;
if (solidCount && transparentCount)
break;
}
if (solidCount)
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
if (transparentCount)
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
ISceneNode::OnRegisterSceneNode();
}
}
IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
{
if(Mesh->getMeshType() != EAMT_SKINNED)
{
s32 frameNr = (s32) getFrameNr();
s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f);
return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
}
else
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0;
#endif
CSkinnedMesh* skinnedMesh = reinterpret_cast<CSkinnedMesh*>(Mesh);
if (JointMode == EJUOR_CONTROL)
skinnedMesh->transferJointsToMesh(JointChildSceneNodes);
else
skinnedMesh->animateMesh(getFrameNr(), 1.0f);
skinnedMesh->skinMesh();
if (JointMode == EJUOR_READ)
{
skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes);
for (u32 n=0;n<JointChildSceneNodes.size();++n)
if (JointChildSceneNodes[n]->getParent()==this)
{
JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren();
}
}
if(JointMode == EJUOR_CONTROL)
{
skinnedMesh->updateBoundingBox();
}
return skinnedMesh;
}
}
void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs)
{
buildFrameNr(timeMs-LastTimeMs);
if (Mesh)
{
scene::IMesh * mesh = getMeshForCurrentFrame();
if (mesh)
Box = mesh->getBoundingBox();
}
LastTimeMs = timeMs;
IAnimatedMeshSceneNode::OnAnimate ( timeMs );
}
void CAnimatedMeshSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if (!Mesh || !driver)
return;
bool isTransparentPass =
SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
++PassCount;
scene::IMesh* m = getMeshForCurrentFrame();
if(m)
{
Box = m->getBoundingBox();
}
else
{
#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)
Shadow->updateShadowVolumes();
bool renderMeshes = true;
video::SMaterial mat;
if (DebugDataVisible && PassCount==1)
{
if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)
{
for (u32 i=0; i<m->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
mat = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
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->setMaterial(mat);
driver->drawMeshBuffer(mb);
}
renderMeshes = false;
}
}
if (renderMeshes)
{
for (u32 i=0; i<m->getMeshBufferCount(); ++i)
{
video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType);
bool transparent = (rnd && rnd->isTransparent());
if (transparent == isTransparentPass)
{
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
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->setMaterial(material);
driver->drawMeshBuffer(mb);
}
}
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (DebugDataVisible && PassCount==1)
{
video::SMaterial debug_mat;
debug_mat.Lighting = false;
debug_mat.AntiAliasing=0;
driver->setMaterial(debug_mat);
if (DebugDataVisible & scene::EDS_NORMALS)
{
core::vector3df normalizedNormal;
const f32 DebugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
const video::SColor DebugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
for (u32 g=0; g < m->getMeshBufferCount(); ++g)
{
const scene::IMeshBuffer* mb = m->getMeshBuffer(g);
const u32 vSize = video::getVertexPitchFromType(mb->getVertexType());
const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices();
const bool normalize = mb->getMaterial().NormalizeNormals;
for (u32 i=0; i != mb->getVertexCount(); ++i)
{
normalizedNormal = v->Normal;
if (normalize)
normalizedNormal.normalize();
driver->draw3DLine(v->Pos, v->Pos + (normalizedNormal * DebugNormalLength), DebugNormalColor);
v = (const video::S3DVertex*) ( (u8*) v+vSize );
}
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
}
debug_mat.ZBuffer = video::ECFN_NEVER;
debug_mat.Lighting = false;
driver->setMaterial(debug_mat);
if (DebugDataVisible & scene::EDS_BBOX)
driver->draw3DBox(Box, video::SColor(255,255,255,255));
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
{
for (u32 g=0; g< m->getMeshBufferCount(); ++g)
{
const IMeshBuffer* mb = m->getMeshBuffer(g);
if (Mesh->getMeshType() == EAMT_SKINNED)
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation);
driver->draw3DBox( mb->getBoundingBox(),
video::SColor(255,190,128,128) );
}
}
if (DebugDataVisible & scene::EDS_SKELETON)
{
if (Mesh->getMeshType() == EAMT_SKINNED)
{
for (u32 g=0; g < ((ISkinnedMesh*)Mesh)->getAllJoints().size(); ++g)
{
ISkinnedMesh::SJoint *joint=((ISkinnedMesh*)Mesh)->getAllJoints()[g];
for (u32 n=0;n<joint->Children.size();++n)
{
driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(),
joint->Children[n]->GlobalAnimatedMatrix.getTranslation(),
video::SColor(255,51,66,255));
}
}
}
if (Mesh->getMeshType() == EAMT_MD3)
{
IAnimatedMesh * arrow =
SceneManager->addArrowMesh (
"__tag_show",
0xFF0000FF, 0xFF000088,
4, 8, 5.f, 4.f, 0.5f,
1.f);
if (!arrow)
{
arrow = SceneManager->getMesh ( "__tag_show" );
}
IMesh *arrowMesh = arrow->getMesh(0);
core::matrix4 matr;
SMD3QuaternionTagList *taglist = ((IAnimatedMeshMD3*)Mesh)->getTagList(
(s32)getFrameNr(), 255,
getStartFrame(), getEndFrame());
if (taglist)
{
for ( u32 ts = 0; ts != taglist->size(); ++ts )
{
(*taglist)[ts].setto(matr);
driver->setTransform(video::ETS_WORLD, matr );
for ( u32 a = 0; a != arrowMesh->getMeshBufferCount(); ++a )
driver->drawMeshBuffer(arrowMesh->getMeshBuffer(a));
}
}
}
}
if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
{
debug_mat.Lighting = false;
debug_mat.Wireframe = true;
debug_mat.ZBuffer = video::ECFN_NEVER;
driver->setMaterial(debug_mat);
for (u32 g=0; g<m->getMeshBufferCount(); ++g)
{
const 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->drawMeshBuffer(mb);
}
}
}
}
s32 CAnimatedMeshSceneNode::getStartFrame() const
{
return StartFrame;
}
s32 CAnimatedMeshSceneNode::getEndFrame() const
{
return EndFrame;
}
bool CAnimatedMeshSceneNode::setFrameLoop(s32 begin, s32 end)
{
const s32 maxFrameCount = Mesh->getFrameCount() - 1;
if (end < begin)
{
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);
}
if (FramesPerSecond < 0)
setCurrentFrame((f32)EndFrame);
else
setCurrentFrame((f32)StartFrame);
return true;
}
void CAnimatedMeshSceneNode::setAnimationSpeed(f32 framesPerSecond)
{
FramesPerSecond = framesPerSecond * 0.001f;
}
f32 CAnimatedMeshSceneNode::getAnimationSpeed() const
{
return FramesPerSecond * 1000.f;
}
const core::aabbox3d<f32>& CAnimatedMeshSceneNode::getBoundingBox() const
{
return Box;
}
video::SMaterial& CAnimatedMeshSceneNode::getMaterial(u32 i)
{
if (i >= Materials.size())
return ISceneNode::getMaterial(i);
return Materials[i];
}
u32 CAnimatedMeshSceneNode::getMaterialCount() const
{
return Materials.size();
}
IShadowVolumeSceneNode* CAnimatedMeshSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh;
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName)
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
return 0;
#endif
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
{
os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING);
return 0;
}
checkJoints();
ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh;
const s32 number = skinnedMesh->getJointNumber(jointName);
if (number == -1)
{
os::Printer::log("Joint with specified name not found in skinned mesh", jointName, ELL_DEBUG);
return 0;
}
if ((s32)JointChildSceneNodes.size() <= number)
{
os::Printer::log("Joint was found in mesh, but is not loaded into node", jointName, ELL_WARNING);
return 0;
}
return JointChildSceneNodes[number];
}
IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(u32 jointID)
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
return 0;
#endif
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
{
os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING);
return 0;
}
checkJoints();
if (JointChildSceneNodes.size() <= jointID)
{
os::Printer::log("Joint not loaded into node", ELL_WARNING);
return 0;
}
return JointChildSceneNodes[jointID];
}
u32 CAnimatedMeshSceneNode::getJointCount() const
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0;
#endif
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
return 0;
ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh;
return skinnedMesh->getJointCount();
}
ISceneNode* CAnimatedMeshSceneNode::getMS3DJointNode(const c8* jointName)
{
return getJointNode(jointName);
}
ISceneNode* CAnimatedMeshSceneNode::getXJointNode(const c8* jointName)
{
return getJointNode(jointName);
}
bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
if (ISceneNode::removeChild(child))
{
if (JointsUsed)
{
for (u32 i=0; i<JointChildSceneNodes.size(); ++i)
{
if (JointChildSceneNodes[i] == child)
{
JointChildSceneNodes[i] = 0;
break;
}
}
}
return true;
}
return false;
}
bool CAnimatedMeshSceneNode::setMD2Animation(EMD2_ANIMATION_TYPE anim)
{
if (!Mesh || Mesh->getMeshType() != EAMT_MD2)
return false;
IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh;
s32 begin, end, speed;
md->getFrameLoop(anim, begin, end, speed);
setAnimationSpeed( f32(speed) );
setFrameLoop(begin, end);
return true;
}
bool CAnimatedMeshSceneNode::setMD2Animation(const c8* animationName)
{
if (!Mesh || Mesh->getMeshType() != EAMT_MD2)
return false;
IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh;
s32 begin, end, speed;
if (!md->getFrameLoop(animationName, begin, end, speed))
return false;
setAnimationSpeed( (f32)speed );
setFrameLoop(begin, end);
return true;
}
void CAnimatedMeshSceneNode::setLoopMode(bool playAnimationLooped)
{
Looping = playAnimationLooped;
}
void CAnimatedMeshSceneNode::setAnimationEndCallback(IAnimationEndCallBack* callback)
{
if (callback == LoopCallBack)
return;
if (LoopCallBack)
LoopCallBack->drop();
LoopCallBack = callback;
if (LoopCallBack)
LoopCallBack->grab();
}
void CAnimatedMeshSceneNode::setReadOnlyMaterials(bool readonly)
{
ReadOnlyMaterials = readonly;
}
bool CAnimatedMeshSceneNode::isReadOnlyMaterials() const
{
return ReadOnlyMaterials;
}
void CAnimatedMeshSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IAnimatedMeshSceneNode::serializeAttributes(out, options);
out->addString("Mesh", SceneManager->getMeshCache()->getMeshName(Mesh).getPath().c_str());
out->addBool("Looping", Looping);
out->addBool("ReadOnlyMaterials", ReadOnlyMaterials);
out->addFloat("FramesPerSecond", FramesPerSecond);
out->addInt("StartFrame", StartFrame);
out->addInt("EndFrame", EndFrame);
}
void CAnimatedMeshSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IAnimatedMeshSceneNode::deserializeAttributes(in, options);
io::path oldMeshStr = SceneManager->getMeshCache()->getMeshName(Mesh);
io::path newMeshStr = in->getAttributeAsString("Mesh");
Looping = in->getAttributeAsBool("Looping");
ReadOnlyMaterials = in->getAttributeAsBool("ReadOnlyMaterials");
FramesPerSecond = in->getAttributeAsFloat("FramesPerSecond");
StartFrame = in->getAttributeAsInt("StartFrame");
EndFrame = in->getAttributeAsInt("EndFrame");
if (newMeshStr != "" && oldMeshStr != newMeshStr)
{
IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str());
if (newAnimatedMesh)
setMesh(newAnimatedMesh);
}
}
void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh)
{
if (!mesh)
return;
if (Mesh != mesh)
{
if (Mesh)
Mesh->drop();
Mesh = mesh;
Mesh->grab();
}
Box = Mesh->getBoundingBox();
IMesh* m = Mesh->getMesh(0,0);
if (m)
{
Materials.clear();
Materials.reallocate(m->getMeshBufferCount());
for (u32 i=0; i<m->getMeshBufferCount(); ++i)
{
IMeshBuffer* mb = m->getMeshBuffer(i);
if (mb)
Materials.push_back(mb->getMaterial());
else
Materials.push_back(video::SMaterial());
}
}
if (JointsUsed)
{
JointsUsed=false;
checkJoints();
}
setFrameLoop(0, Mesh->getFrameCount());
}
const SMD3QuaternionTag* CAnimatedMeshSceneNode::getMD3TagTransformation(const core::stringc& tagname)
{
return MD3Special ? MD3Special->AbsoluteTagList.get(tagname) : 0;
}
void CAnimatedMeshSceneNode::updateAbsolutePosition()
{
IAnimatedMeshSceneNode::updateAbsolutePosition();
if (!Mesh || Mesh->getMeshType() != EAMT_MD3)
return;
SMD3QuaternionTagList *taglist;
taglist = ( (IAnimatedMeshMD3*) Mesh )->getTagList ( (s32)getFrameNr(),255,getStartFrame (),getEndFrame () );
if (taglist)
{
if (!MD3Special)
{
MD3Special = new SMD3Special();
}
SMD3QuaternionTag parent ( MD3Special->Tagname );
if (Parent && Parent->getType() == ESNT_ANIMATED_MESH)
{
const SMD3QuaternionTag * p = ((IAnimatedMeshSceneNode*) Parent)->getMD3TagTransformation
( MD3Special->Tagname );
if (p)
parent = *p;
}
SMD3QuaternionTag relative( RelativeTranslation, RelativeRotation );
MD3Special->AbsoluteTagList.set_used ( taglist->size () );
for ( u32 i=0; i!= taglist->size (); ++i )
{
MD3Special->AbsoluteTagList[i].position = parent.position + (*taglist)[i].position + relative.position;
MD3Special->AbsoluteTagList[i].rotation = parent.rotation * (*taglist)[i].rotation * relative.rotation;
}
}
}
void CAnimatedMeshSceneNode::setJointMode(E_JOINT_UPDATE_ON_RENDER mode)
{
checkJoints();
JointMode=mode;
}
void CAnimatedMeshSceneNode::setTransitionTime(f32 time)
{
const u32 ttime = (u32)core::floor32(time*1000.0f);
if (TransitionTime==ttime)
return;
TransitionTime = ttime;
if (ttime != 0)
setJointMode(EJUOR_CONTROL);
else
setJointMode(EJUOR_NONE);
}
void CAnimatedMeshSceneNode::setRenderFromIdentity(bool enable)
{
RenderFromIdentity=enable;
}
void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return;
#endif
if (Mesh && Mesh->getMeshType() == EAMT_SKINNED )
{
checkJoints();
const f32 frame = getFrameNr();
CSkinnedMesh* skinnedMesh=reinterpret_cast<CSkinnedMesh*>(Mesh);
skinnedMesh->transferOnlyJointsHintsToMesh( JointChildSceneNodes );
skinnedMesh->animateMesh(frame, 1.0f);
skinnedMesh->recoverJointsFromMesh( JointChildSceneNodes);
if (Transiting != 0.f)
{
if (PretransitingSave.size()<JointChildSceneNodes.size())
{
for(u32 n=PretransitingSave.size(); n<JointChildSceneNodes.size(); ++n)
PretransitingSave.push_back(core::matrix4());
}
for (u32 n=0; n<JointChildSceneNodes.size(); ++n)
{
JointChildSceneNodes[n]->setPosition(
core::lerp(
PretransitingSave[n].getTranslation(),
JointChildSceneNodes[n]->getPosition(),
TransitingBlend));
const core::quaternion RotationStart(PretransitingSave[n].getRotationDegrees()*core::DEGTORAD);
const core::quaternion RotationEnd(JointChildSceneNodes[n]->getRotation()*core::DEGTORAD);
core::quaternion QRotation;
QRotation.slerp(RotationStart, RotationEnd, TransitingBlend);
core::vector3df tmpVector;
QRotation.toEuler(tmpVector);
tmpVector*=core::RADTODEG;
JointChildSceneNodes[n]->setRotation( tmpVector );
}
}
if (CalculateAbsolutePositions)
{
for (u32 n=0;n<JointChildSceneNodes.size();++n)
{
if (JointChildSceneNodes[n]->getParent()==this)
{
JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren();
}
}
}
}
}
void CAnimatedMeshSceneNode::checkJoints()
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return;
#endif
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
return;
if (!JointsUsed)
{
for (u32 i=0; i<JointChildSceneNodes.size(); ++i)
removeChild(JointChildSceneNodes[i]);
JointChildSceneNodes.clear();
((CSkinnedMesh*)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager);
((CSkinnedMesh*)Mesh)->recoverJointsFromMesh(JointChildSceneNodes);
JointsUsed=true;
JointMode=EJUOR_READ;
}
}
void CAnimatedMeshSceneNode::beginTransition()
{
if (!JointsUsed)
return;
if (TransitionTime != 0)
{
if (PretransitingSave.size()<JointChildSceneNodes.size())
{
for(u32 n=PretransitingSave.size(); n<JointChildSceneNodes.size(); ++n)
PretransitingSave.push_back(core::matrix4());
}
for (u32 n=0;n<JointChildSceneNodes.size();++n)
PretransitingSave[n]=JointChildSceneNodes[n]->getRelativeTransformation();
Transiting = core::reciprocal((f32)TransitionTime);
}
TransitingBlend = 0.f;
}
ISceneNode* CAnimatedMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CAnimatedMeshSceneNode* newNode =
new CAnimatedMeshSceneNode(Mesh, NULL, newManager, ID, RelativeTranslation,
RelativeRotation, RelativeScale);
if (newParent)
{
newNode->setParent(newParent);
newNode->drop();
}
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;
newNode->PassCount = PassCount;
newNode->Shadow = Shadow;
newNode->JointChildSceneNodes = JointChildSceneNodes;
newNode->PretransitingSave = PretransitingSave;
newNode->RenderFromIdentity = RenderFromIdentity;
newNode->MD3Special = MD3Special;
return newNode;
}
}
}