1 // Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details 2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt 3 4 #include "Animation.h" 5 #include "scenegraph/Model.h" 6 #include <iostream> 7 8 namespace SceneGraph { 9 10 typedef std::vector<AnimationChannel> ChannelList; 11 typedef ChannelList::iterator ChannelIterator; 12 Animation(const std::string & name,double duration)13 Animation::Animation(const std::string &name, double duration) : 14 m_duration(duration), 15 m_time(0.0), 16 m_name(name) 17 { 18 } 19 Animation(const Animation & anim)20 Animation::Animation(const Animation &anim) : 21 m_duration(anim.m_duration), 22 m_time(0.0), 23 m_name(anim.m_name) 24 { 25 for (ChannelList::const_iterator chan = anim.m_channels.begin(); chan != anim.m_channels.end(); ++chan) { 26 m_channels.push_back(*chan); 27 } 28 } 29 UpdateChannelTargets(Node * root)30 void Animation::UpdateChannelTargets(Node *root) 31 { 32 for (ChannelList::iterator chan = m_channels.begin(); chan != m_channels.end(); ++chan) { 33 //update channels to point to new node structure 34 MatrixTransform *trans = dynamic_cast<MatrixTransform *>(root->FindNode(chan->node->GetName())); 35 assert(trans); 36 chan->node = trans; 37 } 38 } 39 Interpolate()40 void Animation::Interpolate() 41 { 42 PROFILE_SCOPED() 43 const double mtime = m_time; 44 45 //go through channels and calculate transforms 46 for (ChannelIterator chan = m_channels.begin(); chan != m_channels.end(); ++chan) { 47 matrix4x4f trans = chan->node->GetTransform(); 48 49 if (!chan->rotationKeys.empty()) { 50 //find a frame. To optimize, should begin search from previous frame (when mTime > previous mTime) 51 unsigned int frame = 0; 52 while (frame + 1 < chan->rotationKeys.size()) { 53 if (mtime < chan->rotationKeys[frame + 1].time) 54 break; 55 frame++; 56 } 57 58 const RotationKey &a = chan->rotationKeys[frame]; 59 vector3f saved_position = trans.GetTranslate(); 60 if (frame + 1 < chan->rotationKeys.size()) { 61 const RotationKey &b = chan->rotationKeys[frame + 1]; 62 double diffTime = b.time - a.time; 63 assert(diffTime > 0.0); 64 const float factor = Clamp(float((mtime - a.time) / diffTime), 0.f, 1.f); 65 trans = Quaternionf::Slerp(a.rotation, b.rotation, factor).ToMatrix3x3<float>(); 66 } else { 67 trans = a.rotation.ToMatrix3x3<float>(); 68 } 69 trans.SetTranslate(saved_position); 70 } 71 72 //scaling will not work without rotation since it would 73 //continously scale the transform (would have to add originalTransform or 74 //something to MT) 75 if (!chan->scaleKeys.empty() && !chan->rotationKeys.empty()) { 76 //find a frame. To optimize, should begin search from previous frame (when mTime > previous mTime) 77 unsigned int frame = 0; 78 while (frame + 1 < chan->scaleKeys.size()) { 79 if (mtime < chan->scaleKeys[frame + 1].time) 80 break; 81 frame++; 82 } 83 84 const ScaleKey &a = chan->scaleKeys[frame]; 85 vector3f out; 86 if (frame + 1 < chan->scaleKeys.size()) { 87 const ScaleKey &b = chan->scaleKeys[frame + 1]; 88 double diffTime = b.time - a.time; 89 assert(diffTime > 0.0); 90 const float factor = Clamp(float((mtime - a.time) / diffTime), 0.f, 1.f); 91 out = a.scale + (b.scale - a.scale) * factor; 92 } else { 93 out = a.scale; 94 } 95 trans.Scale(out.x, out.y, out.z); 96 } 97 98 if (!chan->positionKeys.empty()) { 99 //find a frame. To optimize, should begin search from previous frame (when mTime > previous mTime) 100 unsigned int frame = 0; 101 while (frame + 1 < chan->positionKeys.size()) { 102 if (mtime < chan->positionKeys[frame + 1].time) 103 break; 104 frame++; 105 } 106 107 const PositionKey &a = chan->positionKeys[frame]; 108 vector3f out; 109 if (frame + 1 < chan->positionKeys.size()) { 110 const PositionKey &b = chan->positionKeys[frame + 1]; 111 double diffTime = b.time - a.time; 112 assert(diffTime > 0.0); 113 const float factor = Clamp(float((mtime - a.time) / diffTime), 0.f, 1.f); 114 out = a.position + (b.position - a.position) * factor; 115 } else { 116 out = a.position; 117 } 118 trans.SetTranslate(out); 119 } 120 121 chan->node->SetTransform(trans); 122 } 123 } 124 GetProgress()125 double Animation::GetProgress() 126 { 127 return m_time / m_duration; 128 } 129 SetProgress(double prog)130 void Animation::SetProgress(double prog) 131 { 132 m_time = Clamp(prog, 0.0, 1.0) * m_duration; 133 } 134 135 } // namespace SceneGraph 136