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