Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / camera_recorder.cpp
blobe863d808da3ca48317c00631d02d970b917dd4de
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
21 #include "nel/misc/time_nl.h"
22 #include "nel/misc/path.h"
23 #include "nel/misc/command.h"
24 #include "nel/misc/file.h"
25 #include "nel/3d/u_camera.h"
26 #include "nel/gui/action_handler.h"
27 #include "client_cfg.h"
28 #include "view.h"
30 #include <algorithm>
33 using namespace NLMISC;
34 using namespace NL3D;
35 using namespace NLGUI;
37 // TODO nico : that stuff was coded in a hurry, but could be good to add it to NL3D with a better packaging later...
40 //extern UCamera MainCam;
41 extern CView View;
44 // state ofthe recorder
45 enum TState
47 Idle,
48 Recording,
49 PlayBack
53 // camera sample
54 class CSample
56 public:
57 TTime Date;
58 CVector Pos;
59 CVector Heading;
60 //CVMatrix Matrix;
61 public:
62 void serial(NLMISC::IStream &f)
64 f.serial(Date);
65 f.serial(Pos);
66 f.serial(Heading);
67 //f.serial(Matrix);
71 bool operator<(const CSample &lhs, const CSample &rhs)
73 return lhs.Date < rhs.Date;
77 typedef std::vector<CSample> TTrack;
80 // recorder
81 static TState State = Idle; // current state of the camera recorder
82 static TTime TimeOrigin = 0; // time origin for record or playback
83 static TTrack Track;
87 bool isRecordingCamera()
89 return State == Recording;
93 void updateCameraRecorder()
95 switch(State)
97 case Idle:
98 // no-op
99 break;
100 case Recording:
102 CSample sample;
103 sample.Date = CTime::getLocalTime() - TimeOrigin;
104 //sample.Matrix = MainCam.getMatrix();
105 sample.Pos = View.viewPos();
106 sample.Heading = View.view();
107 if (Track.empty())
109 // push first sample
110 Track.push_back(sample);
112 else if (sample.Date > Track.back().Date)
114 // push a new sample only if more recent
115 Track.push_back(sample);
118 break;
119 case PlayBack:
121 if (Track.empty())
123 State = Idle;
124 break;
126 TTime date = CTime::getLocalTime() - TimeOrigin;
127 CSample compVal;
128 compVal.Date = date;
129 TTrack::const_iterator it = std::lower_bound(Track.begin(), Track.end(), compVal);
130 if (it == Track.end())
132 //MainCam.setMatrix(Track.back().Matrix);
133 View.viewPos(Track.back().Pos);
134 View.view(Track.back().Heading);
135 State = Idle;
136 break;
138 if (it == Track.begin())
140 //MainCam.setMatrix(Track.back().Matrix);
141 View.viewPos(Track.front().Pos);
142 View.view(Track.front().Heading);
143 break;
145 const CSample &s0 = *(it - 1);
146 const CSample &s1 = *it;
147 float lambda = float(date - s0.Date) / float(s1.Date - s0.Date);
149 CVector pos;
150 CVector heading;
152 if (ClientCfg.CameraRecorderBlend)
154 pos = lambda * s1.Pos + (1.f - lambda) * s0.Pos;
155 heading = (lambda * s1.Heading + (1.f - lambda) * s0.Heading).normed();
157 else
159 pos = s0.Pos;
160 heading = s0.Heading;
163 View.viewPos(pos);
164 View.view(heading);
168 CVector pos = lambda * s1.Matrix.getPos() + (1.f - lambda) * s0.Matrix.getPos();
169 CVector I = lambda * s1.Matrix.getI() + (1.f - lambda) * s0.Matrix.getI();
170 I.normalize();
171 CVector J = lambda * s1.Matrix.getJ() + (1.f - lambda) * s0.Matrix.getJ();
172 J = (J - (J * I) * I).normed();
173 CVector K = I ^ J;
174 CMatrix mat;
175 mat.setPos(pos);
176 mat.setRot(I, J, K);
177 UTransform::TTransformMode oldMode = MainCam.getTransformMode();
178 MainCam.setTransformMode(UTransformable::DirectMatrix);
179 MainCam.setMatrix(mat);
180 MainCam.setTransformMode(oldMode);
183 break;
187 // ***************************************************************************
188 class CAHToggleCameraRecorder : public IActionHandler
190 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
192 if (State == Recording)
194 State = Idle;
195 return;
197 State = Recording;
198 TimeOrigin = CTime::getLocalTime();
199 Track.clear();
202 // ***************************************************************************
203 REGISTER_ACTION_HANDLER (CAHToggleCameraRecorder, "toggle_camera_recorder");
205 // ***************************************************************************
206 class CAHCameraRecorderPlayback : public IActionHandler
208 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
210 if (State == PlayBack)
212 State = Idle;
213 return;
215 State = PlayBack;
216 TimeOrigin = CTime::getLocalTime();
219 // ***************************************************************************
220 REGISTER_ACTION_HANDLER (CAHCameraRecorderPlayback, "camera_recorder_playback");
222 // ***************************************************************************
223 class CAHSaveCameraRecord : public IActionHandler
225 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
229 std::string filename = ClientCfg.CameraRecorderPrefix + ".cr";
230 if (!ClientCfg.CameraRecorderPath.empty())
232 filename = ClientCfg.CameraRecorderPath + "/" + filename;
234 filename = CFile::findNewFile(filename);
235 if (!filename.empty())
237 COFile f(filename);
238 f.serialVersion(0);
239 f.serialCont(Track);
241 else
243 nlwarning("Couldn't compute camera recorder next filename");
246 catch(const EStream &e)
248 nlwarning(e.what());
252 // ***************************************************************************
253 REGISTER_ACTION_HANDLER (CAHSaveCameraRecord, "save_camera_record");
256 // ***************************************************************************
257 NLMISC_COMMAND(loadCamRec, "Load a camera path record file (.cr)", "<filename>")
259 if(args.empty())
260 return false;
261 std::string filename = args[0];
262 string::size_type pos = args[0].find_last_of ('.');
263 if (pos == string::npos)
265 filename += ".cr";
267 std::string path;
268 std::string searchFilename = filename;
269 if (!ClientCfg.CameraRecorderPath.empty())
271 searchFilename = ClientCfg.CameraRecorderPath + "/" + searchFilename;
273 if (CFile::fileExists(searchFilename))
275 path = searchFilename;
277 else
279 path = CPath::lookup(filename, false, true);
281 if (!path.empty())
285 CIFile f(path);
286 f.serialVersion(0);
287 f.serialCont(Track);
288 State = Idle;
290 catch(const EStream &e)
292 nlwarning(e.what());
295 return true;