1 /* Copyright (C) 2017 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "CinemaPath.h"
25 #include "graphics/Camera.h"
26 #include "maths/MathUtil.h"
27 #include "maths/Quaternion.h"
28 #include "maths/Vector3D.h"
29 #include "ps/CLogger.h"
32 CCinemaPath::CCinemaPath(const CCinemaData
& data
, const TNSpline
& spline
, const TNSpline
& targetSpline
)
33 : CCinemaData(data
), TNSpline(spline
), m_TargetSpline(targetSpline
), m_TimeElapsed(0.f
)
35 // Calculate curves by nodes
37 m_TargetSpline
.BuildSpline();
39 if (m_Orientation
== L
"target")
41 m_LookAtTarget
= true;
42 ENSURE(!m_TargetSpline
.GetAllNodes().empty());
45 // Set distortion mode and style
46 if (data
.m_Mode
== L
"ease_in")
47 DistModePtr
= &CCinemaPath::EaseIn
;
48 else if (data
.m_Mode
== L
"ease_out")
49 DistModePtr
= &CCinemaPath::EaseOut
;
50 else if (data
.m_Mode
== L
"ease_inout")
51 DistModePtr
= &CCinemaPath::EaseInOut
;
52 else if (data
.m_Mode
== L
"ease_outin")
53 DistModePtr
= &CCinemaPath::EaseOutIn
;
56 LOGWARNING("Cinematic mode not found for '%s'", data
.m_Mode
.ToUTF8().c_str());
57 DistModePtr
= &CCinemaPath::EaseInOut
;
60 if (data
.m_Style
== L
"default")
61 DistStylePtr
= &CCinemaPath::EaseDefault
;
62 else if (data
.m_Style
== L
"growth")
63 DistStylePtr
= &CCinemaPath::EaseGrowth
;
64 else if (data
.m_Style
== L
"expo")
65 DistStylePtr
= &CCinemaPath::EaseExpo
;
66 else if (data
.m_Style
== L
"circle")
67 DistStylePtr
= &CCinemaPath::EaseCircle
;
68 else if (data
.m_Style
== L
"sine")
69 DistStylePtr
= &CCinemaPath::EaseSine
;
72 LOGWARNING("Cinematic style not found for '%s'", data
.m_Style
.ToUTF8().c_str());
73 DistStylePtr
= &CCinemaPath::EaseDefault
;
77 CVector3D
CCinemaPath::GetNodePosition(const int index
) const
79 return Node
[index
].Position
;
82 fixed
CCinemaPath::GetNodeDuration(const int index
) const
84 return Node
[index
].Distance
;
87 fixed
CCinemaPath::GetDuration() const
92 float CCinemaPath::GetNodeFraction() const
94 return (m_TimeElapsed
- m_PreviousNodeTime
) / Node
[m_CurrentNode
].Distance
.ToFloat();
97 float CCinemaPath::GetElapsedTime() const
102 const CStrW
& CCinemaPath::GetName() const
107 void CCinemaPath::SetTimescale(fixed scale
)
112 void CCinemaPath::MoveToPointAt(float t
, float nodet
, const CVector3D
& startRotation
, CCamera
* camera
) const
114 t
= (this->*DistModePtr
)(t
);
116 CVector3D pos
= GetPosition(t
);
120 if (m_TimeElapsed
<= m_TargetSpline
.MaxDistance
.ToFloat())
121 camera
->LookAt(pos
, m_TargetSpline
.GetPosition(m_TimeElapsed
/ m_TargetSpline
.MaxDistance
.ToFloat()), CVector3D(0, 1, 0));
123 camera
->LookAt(pos
, m_TargetSpline
.GetAllNodes().back().Position
, CVector3D(0, 1, 0));
127 CVector3D nodeRotation
= Node
[m_CurrentNode
+ 1].Rotation
;
128 CQuaternion start
, end
;
129 start
.FromEulerAngles(DEGTORAD(startRotation
.X
), DEGTORAD(startRotation
.Y
), DEGTORAD(startRotation
.Z
));
130 end
.FromEulerAngles(DEGTORAD(nodeRotation
.X
), DEGTORAD(nodeRotation
.Y
), DEGTORAD(nodeRotation
.Z
));
131 start
.Slerp(start
, end
, nodet
);
133 camera
->m_Orientation
.SetIdentity();
134 camera
->m_Orientation
.Rotate(start
);
135 camera
->m_Orientation
.Translate(pos
);
137 camera
->UpdateFrustum();
140 // Distortion mode functions
141 float CCinemaPath::EaseIn(float t
) const
143 return (this->*DistStylePtr
)(t
);
146 float CCinemaPath::EaseOut(float t
) const
148 return 1.0f
- EaseIn(1.0f
-t
);
151 float CCinemaPath::EaseInOut(float t
) const
154 return EaseIn(1.0f
/m_Switch
* t
) * m_Switch
;
155 return EaseOut(1.0f
/m_Switch
* (t
-m_Switch
)) * m_Switch
+ m_Switch
;
158 float CCinemaPath::EaseOutIn(float t
) const
161 return EaseOut(1.0f
/m_Switch
* t
) * m_Switch
;
162 return EaseIn(1.0f
/m_Switch
* (t
-m_Switch
)) * m_Switch
+ m_Switch
;
165 // Distortion style functions
166 float CCinemaPath::EaseDefault(float t
) const
171 float CCinemaPath::EaseGrowth(float t
) const
173 return pow(t
, m_Growth
);
176 float CCinemaPath::EaseExpo(float t
) const
180 return powf(m_Growth
, 10*(t
-1.0f
));
183 float CCinemaPath::EaseCircle(float t
) const
185 t
= -(sqrt(1.0f
- t
*t
) - 1.0f
);
186 if (m_GrowthCount
> 1.0f
)
189 return (this->*DistStylePtr
)(t
);
194 float CCinemaPath::EaseSine(float t
) const
196 t
= 1.0f
- cos(t
* (float)M_PI
/2);
197 if (m_GrowthCount
> 1.0f
)
200 return (this->*DistStylePtr
)(t
);
205 const CCinemaData
* CCinemaPath::GetData() const
207 return CCinemaData::GetData();
210 bool CCinemaPath::Validate()
212 if (m_TimeElapsed
> GetDuration().ToFloat() || m_TimeElapsed
< 0.0f
)
215 // Find current node and past "node time"
216 float previousTime
= 0.0f
, cumulation
= 0.0f
;
218 // Ignore the last node, since it is a blank (node time values are shifted down one from interface)
219 for (size_t i
= 0; i
< Node
.size() - 1; ++i
)
221 cumulation
+= Node
[i
].Distance
.ToFloat();
222 if (m_TimeElapsed
<= cumulation
)
224 m_PreviousNodeTime
= previousTime
;
225 m_PreviousRotation
= Node
[i
].Rotation
;
226 m_CurrentNode
= i
; // We're moving toward this next node, so use its rotation
229 previousTime
+= Node
[i
].Distance
.ToFloat();
231 debug_warn("validation of cinema path is wrong\n");
235 bool CCinemaPath::Play(const float deltaRealTime
, CCamera
* camera
)
237 m_TimeElapsed
+= m_Timescale
.ToFloat() * deltaRealTime
;
241 MoveToPointAt(m_TimeElapsed
/ GetDuration().ToFloat(), GetNodeFraction(), m_PreviousRotation
, camera
);
245 bool CCinemaPath::Empty() const
250 void CCinemaPath::Reset()
252 m_TimeElapsed
= 0.0f
;
255 fixed
CCinemaPath::GetTimescale() const
260 const TNSpline
& CCinemaPath::GetTargetSpline() const
262 return m_TargetSpline
;