Cogs.Core
CinematicCameraSystem.cpp
1#include "CinematicCameraSystem.h"
2#include "Components/Core/TransformComponent.h"
3
4#include "Foundation/Logging/Logger.h"
5
6#include <memory>
7
8namespace {
9 Cogs::Logging::Log logger = Cogs::Logging::getLogger("CinematicCameraSystem");
10}
11
12Cogs::Core::CinematicCameraSystem::~CinematicCameraSystem()
13{
14}
15
17{
19 easingFn = {
20 &EasingFn::linear,
21 &EasingFn::quadraticIn, &EasingFn::quadraticOut, &EasingFn::quadraticInOut,
22 &EasingFn::cubicIn, &EasingFn::cubicOut, &EasingFn::cubicInOut,
23 &EasingFn::quarticIn, &EasingFn::quarticOut, &EasingFn::quarticInOut,
24 &EasingFn::quinticIn, &EasingFn::quinticOut, &EasingFn::quinticInOut,
25 &EasingFn::sinusoidalIn, &EasingFn::sinusoidalOut, &EasingFn::sinusoidalInOut,
26 &EasingFn::exponentialIn, &EasingFn::exponentialOut, &EasingFn::exponentialInOut,
27 &EasingFn::circularIn, &EasingFn::circularOut, &EasingFn::circularInOut,
28 &EasingFn::elasticIn, &EasingFn::elasticOut, &EasingFn::elasticInOut,
29 &EasingFn::backIn, &EasingFn::backOut, &EasingFn::backInOut,
30 &EasingFn::bounceIn, &EasingFn::bounceOut, &EasingFn::bounceInOut };
31}
32
34{
35 for (auto& cinematicCamComp : pool)
36 {
37 // comtainers should be of equal length. see CinematicCameraComponent.h 65
38
39 if (cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointRotation.size()
40 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointTimeToReach.size()
41 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointWaitingTime.size()
42 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointEasingMode.size())
43 {
44 LOG_ERROR(logger, "Mismatching size of component data arrays, cannot interpolate with incomplete data");
45 return;
46 }
47
48 auto& compData = getData(&cinematicCamComp);
49 auto transform = cinematicCamComp.getComponent<TransformComponent>();
50
51 if (cinematicCamComp.hasChanged())
52 {
53 if (!compData.positionInterpolator && !compData.rotationInterpolator && transform != nullptr)
54 {
55 // Initialize interpolators by giving a ref to the scene camera.
56 compData.positionInterpolator = std::make_unique<Cogs::Interpolator<glm::vec3>>(transform->position);
57 compData.rotationInterpolator = std::make_unique<Cogs::Interpolator<glm::quat>>(transform->rotation);
58 }
59
60 if (cinematicCamComp.isCinematicPlaying)
61 {
62 triggerTargetPoint(cinematicCamComp, 0);
63 compData.currentRunningID = 0;
64 }
65 }
66
67 // Skip block if component does not need to interpolate or is finished doing so
68 if (cinematicCamComp.isCinematicPlaying)
69 {
70 if (compData.timer.elapsedSeconds() >=
71 cinematicCamComp.interestPointTimeToReach[compData.currentRunningID] + cinematicCamComp.interestPointWaitingTime[compData.currentRunningID])
72 {
73 compData.timer.stop();
74
75 // Try to set a 'next' point, set camera angles and return if not available.
76 if (!triggerTargetPoint(cinematicCamComp, ++(compData.currentRunningID)))
77 {
78 return;
79 }
80 }
81
82 // Keep interpolating the camera.
83 compData.positionInterpolator->process();
84 compData.rotationInterpolator->process();
85 if(transform != nullptr)
86 transform->setChanged();
87 }
88 }
89}
90
92{
93 for (auto& cinematicCamComp : pool)
94 {
95 auto& compData = getData(&cinematicCamComp);
96 if (compData.positionInterpolator) compData.positionInterpolator = nullptr;
97 if (compData.rotationInterpolator) compData.rotationInterpolator = nullptr;
98 }
99}
100
102{
103 for (auto& cinematicCamComp : pool)
104 {
105 // Make sure we are operating over the desired component
106 if (std::addressof(targetComp) == std::addressof(cinematicCamComp))
107 {
108 auto transform = cinematicCamComp.getComponent<TransformComponent>();
109 if (transform != nullptr)
110 {
111 cinematicCamComp.interestPointPosition.push_back(transform->position);
112 cinematicCamComp.interestPointRotation.push_back(transform->rotation);
113 cinematicCamComp.interestPointTimeToReach.push_back(3.f);
114 cinematicCamComp.interestPointWaitingTime.push_back(3.f);
115 cinematicCamComp.interestPointEasingMode.push_back(CameraEasingMode::Linear);
116 }
117 return;
118 }
119 }
120}
121
122void Cogs::Core::CinematicCameraSystem::addInterestPoint(const CinematicCameraComponent& targetComp, glm::vec3& pos, glm::quat& rot, float time, float waitTime, CameraEasingMode mode)
123{
124 for (auto& cinematicCamComp : pool)
125 {
126 // Make sure we are operating over the desired component
127 if (std::addressof(targetComp) == std::addressof(cinematicCamComp))
128 {
129 cinematicCamComp.interestPointPosition.push_back(pos);
130 cinematicCamComp.interestPointRotation.push_back(rot);
131 cinematicCamComp.interestPointTimeToReach.push_back(time);
132 cinematicCamComp.interestPointWaitingTime.push_back(waitTime);
133 cinematicCamComp.interestPointEasingMode.push_back(mode);
134 return;
135 }
136 }
137}
138
140{
141 for (auto& cinematicCamComp : pool)
142 {
143 // Make sure we are operating over the desired component
144 if (std::addressof(targetComp) == std::addressof(cinematicCamComp))
145 {
146 auto& compData = getData(&cinematicCamComp);
147
148 //Skip if there are no points to run
149 if (cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointRotation.size()
150 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointTimeToReach.size()
151 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointWaitingTime.size()
152 || cinematicCamComp.interestPointPosition.size() != cinematicCamComp.interestPointEasingMode.size())
153 {
154 LOG_ERROR(logger, "Mismatching size of component data arrays, cannot interpolate with incomplete data");
155 return;
156 }
157
158
159 // Set initial conditions
160 {
161 cinematicCamComp.isCinematicPlaying = true;
162 triggerTargetPoint(targetComp, 0);
163 compData.currentRunningID = 0;
164 }
165 }
166 }
167
168}
169
171{
172 // It is assumed that the arrays are of equal length (ALWAYS)
173 // All codepaths should assert equal lenghts before reaching this method.
174 for (auto& cinematicCamComp : pool)
175 {
176 // Make sure we are operating over the desired component
177 if (std::addressof(targetComp) == std::addressof(cinematicCamComp))
178 {
179 auto& compData = getData(&cinematicCamComp);
180 if (id < cinematicCamComp.interestPointPosition.size())
181 {
182 // TODO: Find a better way of reflecting EasingFn
183 compData.positionInterpolator->setTarget(cinematicCamComp.interestPointPosition[id], easingFn[(size_t)cinematicCamComp.interestPointEasingMode[id]], cinematicCamComp.interestPointTimeToReach[id]);
184 compData.rotationInterpolator->setTarget(cinematicCamComp.interestPointRotation[id], easingFn[(size_t)cinematicCamComp.interestPointEasingMode[id]], cinematicCamComp.interestPointTimeToReach[id]);
185
186 // start processing first iteration
187 compData.positionInterpolator->process();
188 compData.rotationInterpolator->process();
189 compData.timer.start();
190
191 return true;
192 }
193 else
194 {
195 if (cinematicCamComp.loop)
196 {
197 playCameraSequence(cinematicCamComp);
198 return true;
199 }
200 else
201 {
202 // There are no more points to be processed, stop sequence
203 cinematicCamComp.isCinematicPlaying = false;
204 compData.currentRunningID = -1;
205 cinematicCamComp.setChanged();
206 return false;
207 }
208 }
209 }
210 }
211 return false;
212}
void addInterestPoint(const CinematicCameraComponent &targetComp)
Add default point (camPos, camRot, 2.0f, 2.0f, linear)
void cleanup(Context *context) override
Provided for custom cleanup logic in derived systems.
bool triggerTargetPoint(const CinematicCameraComponent &targetComp, const short &id=0)
Trigger Interpolator segment "id" belonging to interpolator [{start,0},...,{n-1,n}].
void playCameraSequence(const CinematicCameraComponent &targetComp)
Notify system to start playing the whole sequence.
void initialize(Context *context) override
Initialize the system.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Defines a 4x4 transformation matrix for the entity and a global offset for root entities.
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180