CSceneNodeAnimatorFollowSpline.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. #include "CSceneNodeAnimatorFollowSpline.h"
  5. namespace irr
  6. {
  7. namespace scene
  8. {
  9. //! constructor
  10. CSceneNodeAnimatorFollowSpline::CSceneNodeAnimatorFollowSpline(u32 time,
  11. const core::array<core::vector3df>& points, f32 speed,
  12. f32 tightness, bool loop, bool pingpong)
  13. : ISceneNodeAnimatorFinishing(0), Points(points), Speed(speed), Tightness(tightness), StartTime(time)
  14. , Loop(loop), PingPong(pingpong)
  15. {
  16. #ifdef _DEBUG
  17. setDebugName("CSceneNodeAnimatorFollowSpline");
  18. #endif
  19. }
  20. inline s32 CSceneNodeAnimatorFollowSpline::clamp(s32 idx, s32 size)
  21. {
  22. return ( idx<0 ? size+idx : ( idx>=size ? idx-size : idx ) );
  23. }
  24. //! animates a scene node
  25. void CSceneNodeAnimatorFollowSpline::animateNode(ISceneNode* node, u32 timeMs)
  26. {
  27. if(!node)
  28. return;
  29. const u32 pSize = Points.size();
  30. if (pSize==0)
  31. {
  32. if ( !Loop )
  33. HasFinished = true;
  34. return;
  35. }
  36. if (pSize==1)
  37. {
  38. if ( timeMs > StartTime )
  39. {
  40. node->setPosition(Points[0]);
  41. if ( !Loop )
  42. HasFinished = true;
  43. }
  44. return;
  45. }
  46. const f32 dt = ( (timeMs-StartTime) * Speed * 0.001f );
  47. const s32 unwrappedIdx = core::floor32( dt );
  48. if ( !Loop && unwrappedIdx >= (s32)pSize-1 )
  49. {
  50. node->setPosition(Points[pSize-1]);
  51. HasFinished = true;
  52. return;
  53. }
  54. const bool pong = PingPong && (unwrappedIdx/(pSize-1))%2;
  55. const f32 u = pong ? 1.f-core::fract ( dt ) : core::fract ( dt );
  56. const s32 idx = pong ? (pSize-2) - (unwrappedIdx % (pSize-1))
  57. : (PingPong ? unwrappedIdx % (pSize-1)
  58. : unwrappedIdx % pSize);
  59. //const f32 u = 0.001f * fmodf( dt, 1000.0f );
  60. const core::vector3df& p0 = Points[ clamp( idx - 1, pSize ) ];
  61. const core::vector3df& p1 = Points[ clamp( idx + 0, pSize ) ]; // starting point
  62. const core::vector3df& p2 = Points[ clamp( idx + 1, pSize ) ]; // end point
  63. const core::vector3df& p3 = Points[ clamp( idx + 2, pSize ) ];
  64. // hermite polynomials
  65. const f32 h1 = 2.0f * u * u * u - 3.0f * u * u + 1.0f;
  66. const f32 h2 = -2.0f * u * u * u + 3.0f * u * u;
  67. const f32 h3 = u * u * u - 2.0f * u * u + u;
  68. const f32 h4 = u * u * u - u * u;
  69. // tangents
  70. const core::vector3df t1 = ( p2 - p0 ) * Tightness;
  71. const core::vector3df t2 = ( p3 - p1 ) * Tightness;
  72. // interpolated point
  73. node->setPosition(p1 * h1 + p2 * h2 + t1 * h3 + t2 * h4);
  74. }
  75. //! Writes attributes of the scene node animator.
  76. void CSceneNodeAnimatorFollowSpline::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
  77. {
  78. out->addFloat("Speed", Speed);
  79. out->addFloat("Tightness", Tightness);
  80. out->addBool("Loop", Loop);
  81. out->addBool("PingPong", PingPong);
  82. u32 count = Points.size();
  83. if ( options && (options->Flags & io::EARWF_FOR_EDITOR))
  84. {
  85. // add one point in addition when serializing for editors
  86. // to make it easier to add points quickly
  87. count += 1;
  88. }
  89. for (u32 i=0; i<count; ++i)
  90. {
  91. core::stringc tname = "Point";
  92. tname += (int)(i+1);
  93. out->addVector3d(tname.c_str(), i<Points.size() ? Points[i] : core::vector3df(0,0,0) );
  94. }
  95. }
  96. //! Reads attributes of the scene node animator.
  97. void CSceneNodeAnimatorFollowSpline::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
  98. {
  99. Speed = in->getAttributeAsFloat("Speed");
  100. Tightness = in->getAttributeAsFloat("Tightness");
  101. Loop = in->getAttributeAsBool("Loop");
  102. PingPong = in->getAttributeAsBool("PingPong");
  103. Points.clear();
  104. for(u32 i=1; true; ++i)
  105. {
  106. core::stringc pname = "Point";
  107. pname += i;
  108. if (in->existsAttribute(pname.c_str()))
  109. Points.push_back(in->getAttributeAsVector3d(pname.c_str()));
  110. else
  111. break;
  112. }
  113. // remove last point if double entry from editor
  114. if ( options && (options->Flags & io::EARWF_FOR_EDITOR) &&
  115. Points.size() > 2 && Points.getLast() == core::vector3df(0,0,0))
  116. {
  117. Points.erase(Points.size()-1);
  118. if (Points.size() > 2 && Points.getLast() == core::vector3df(0,0,0))
  119. Points.erase(Points.size()-1);
  120. }
  121. }
  122. ISceneNodeAnimator* CSceneNodeAnimatorFollowSpline::createClone(ISceneNode* node, ISceneManager* newManager)
  123. {
  124. CSceneNodeAnimatorFollowSpline * newAnimator =
  125. new CSceneNodeAnimatorFollowSpline(StartTime, Points, Speed, Tightness);
  126. return newAnimator;
  127. }
  128. } // end namespace scene
  129. } // end namespace irr