9using namespace Tempest;
11Vec3 CsCamera::KeyFrame::position(
float u)
const {
12 return ((c[0]*u + c[1])*u + c[2])*u + c[3];
15float CsCamera::KeyFrame::arcLength()
const {
18 for(
int i=1; i<=100; ++i) {
19 Vec3 at = position(
float(i)/100.f);
20 len += (at-prev).length();
27CsCamera::KbSpline::KbSpline(
const std::vector<std::shared_ptr<zenkit::VCameraTrajectoryFrame>>& frames,
const float duration, std::string_view vobName) {
28 keyframe.reserve(frames.size());
29 for(
auto& f : frames) {
31 kF.c[3] = Vec3(f->original_pose[3][0],f->original_pose[3][1],f->original_pose[3][2]);
33 kF.motionType = f->motion_type;
35 Log::e(
"CsCamera: \"", vobName,
"\" - negative frame duration");
37 keyframe.push_back(kF);
40 const size_t size = keyframe.size();
41 for(
size_t i=0; i+1<size; ++i) {
42 auto& kF0 = i==0 ? keyframe[i+0] : keyframe[i-1];
43 auto& kF1 = keyframe[i+0];
44 auto& kF2 = keyframe[i+1];
45 auto& kF3 = i+2==size ? kF2 : keyframe[i+2];
52 float dt = kF2.time-kF1.time;
53 Vec3 dd = (p2-p0) * dt/(kF2.time-kF0.time);
54 Vec3 sd = (p3-p1) * dt/(kF3.time-kF1.time);
56 auto& kF = keyframe[i];
57 kF.c[0] = 2 * p1 - 2*p2 + dd + sd;
58 kF.c[1] = -3 * p1 + 3*p2 - 2*dd - sd;
59 kF.c[2] = std::move(dd);
65 if(keyframe.front().time!=0) {
66 Log::e(
"CsCamera: \"", vobName,
"\" - invalid first frame");
70Vec3 CsCamera::KbSpline::position(
const uint64_t time)
const {
71 const float t = float(time)/1000.f;
73 if(t>=keyframe.back().time) {
75 return keyframe.back().position(1.f);
80 while(n+1<keyframe.size() && t>=keyframe[n+1].time) {
84 auto& kF0 = keyframe[n];
85 auto& kF1 = keyframe[n+1];
86 float u = (t - kF0.time) / (kF1.time - kF0.time);
88 const float k = 1.005f;
89 if(kF0.motionType==zenkit::CameraMotion::SLOW && kF1.motionType!=zenkit::CameraMotion::SLOW) {
93 else if(kF0.motionType!=zenkit::CameraMotion::SLOW && kF1.motionType==zenkit::CameraMotion::SLOW) {
95 u = std::pow(u, 1.f/k);
99 return keyframe[n].position(u);
105 if(cam.position_count<1 || cam.total_duration<=0)
108 if(cam.trajectory_for==zenkit::CameraCoordinateReference::OBJECT || cam.target_trajectory_for==zenkit::CameraCoordinateReference::OBJECT) {
109 Log::d(
"Object camera not implemented, \"",
name() ,
"\"");
113 duration = uint64_t(cam.total_duration * 1000.f);
114 delay = uint64_t(cam.auto_untrigger_last_delay * 1000.f);
115 autoUntrigger = cam.auto_untrigger_last;
116 playerMovable = cam.auto_player_movable;
118 posSpline = KbSpline(cam.trajectory_frames, cam.total_duration, cam.vob_name);
119 targetSpline = KbSpline(cam.target_frames, cam.total_duration, cam.vob_name);
123 return playerMovable;
127 static bool dbg =
false;
131 if(posSpline.size()<=1)
134 auto at = posSpline.keyframe[0].position(0);
135 for(
size_t i=1; i<posSpline.size(); ++i) {
136 auto& k = posSpline.keyframe[i];
138 for(
size_t r=0; r<100; ++r) {
139 auto pos = k.position(
float(r)/100.f);
144 auto pt = k.position(0);
147 p.
drawLine(pt-Vec3(l,0,0),pt+Vec3(l,0,0));
148 p.
drawLine(pt-Vec3(0,l,0),pt+Vec3(0,l,0));
149 p.
drawLine(pt-Vec3(0,0,l),pt+Vec3(0,0,l));
158 cs->onUntrigger(evt);
165 if(!camera.isCutscene()) {
166 auto cPos = position();
168 camera.setPosition(cPos);
169 camera.setSpin(spin(cPos));
195void CsCamera::tick(uint64_t ) {
197 if(time>duration+delay && (autoUntrigger ||
vobName==
"TIMEDEMO")) {
207 if(camera.isCutscene()) {
208 auto cPos = position();
209 camera.setPosition(cPos);
210 camera.setSpin(spin(cPos));
214Vec3 CsCamera::position() {
216 if(posSpline.size()==1) {
217 pos = posSpline.keyframe[0].c[3];
219 const uint64_t time = std::min(
world.
tickCount() - timeTrigger, duration);
220 pos = posSpline.position(time);
225PointF CsCamera::spin(Tempest::Vec3& d) {
226 if(targetSpline.size()==0)
228 else if(targetSpline.size()==1)
229 d = targetSpline.keyframe[0].c[3] - d;
230 else if(targetSpline.size()>1) {
231 const uint64_t time = std::min(
world.
tickCount() - timeTrigger, duration);
232 d = targetSpline.position(time) - d;
235 float k = 180.f/float(M_PI);
236 float spinX = k * std::asin(d.y/d.length());
238 if(d.x!=0.f || d.z!=0.f)
239 spinY = 90 + k * std::atan2(d.z,d.x);
242 return {-spinX + def.rot_offset_x, spinY + def.rot_offset_y};
bool hasTicksEnabled() const
std::string_view name() const
const zenkit::ICamera & stdCam() const
Tempest::Vec3 destPosition() const
void debugDraw(DbgPainter &p) const
CsCamera(Vob *parent, World &world, const zenkit::VCutsceneCamera &data, Flags flags)
bool isPlayerMovable() const
void drawLine(const Tempest::Vec3 &a, const Tempest::Vec3 &b)
void setPen(const Tempest::Pen &pen)
static const CameraDefinitions & cameraDef()
Tempest::Signal< void()> onBenchmarkFinished
CsCamera * currentCs() const
uint64_t tickCount() const
GameSession & gameSession() const
void setCurrentCs(CsCamera *cs)