1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include <cstdlib>
4 #include <stdarg.h>
5
6 #include "CameraHandler.h"
7
8 #include "Action.h"
9 #include "Camera.h"
10 #include "Camera/CameraController.h"
11 #include "Camera/FPSController.h"
12 #include "Camera/OverheadController.h"
13 #include "Camera/SmoothController.h"
14 #include "Camera/RotOverheadController.h"
15 #include "Camera/FreeController.h"
16 #include "Camera/OverviewController.h"
17 #include "Camera/TWController.h"
18 #include "Camera/OrbitController.h"
19 #include "Rendering/GlobalRendering.h"
20 #include "System/myMath.h"
21 #include "System/Config/ConfigHandler.h"
22 #include "System/Log/ILog.h"
23
24
strformat(const char * fmt,...)25 static std::string strformat(const char* fmt, ...)
26 {
27 char buf[256];
28 va_list args;
29 va_start(args,fmt);
30 VSNPRINTF(buf, sizeof(buf), fmt, args);
31 va_end(args);
32 return std::string(buf);
33 }
34
35 CONFIG(std::string, CamModeName).defaultValue("");
36
37 CONFIG(int, CamMode)
38 .defaultValue(CCameraHandler::CAMERA_MODE_SMOOTH)
39 .description(strformat("Defines the used camera. Options are:\n%i = FPS\n%i = Overhead\n%i = TotalWar\n%i = RotOverhead\n%i = Free\n%i = SmoothOverhead\n%i = Orbit\n%i = Overview",
40 (int)CCameraHandler::CAMERA_MODE_FIRSTPERSON,
41 (int)CCameraHandler::CAMERA_MODE_OVERHEAD,
42 (int)CCameraHandler::CAMERA_MODE_TOTALWAR,
43 (int)CCameraHandler::CAMERA_MODE_ROTOVERHEAD,
44 (int)CCameraHandler::CAMERA_MODE_FREE,
45 (int)CCameraHandler::CAMERA_MODE_SMOOTH,
46 (int)CCameraHandler::CAMERA_MODE_ORBIT,
47 (int)CCameraHandler::CAMERA_MODE_OVERVIEW
48 ).c_str())
49 .minimumValue(0)
50 .maximumValue(CCameraHandler::CAMERA_MODE_LAST - 1);
51
52 CONFIG(float, CamTimeFactor)
53 .defaultValue(1.0f)
54 .minimumValue(0.0f);
55
56 CONFIG(float, CamTimeExponent)
57 .defaultValue(4.0f)
58 .minimumValue(0.0f);
59
60
61 CCameraHandler* camHandler = NULL;
62
63
CCameraHandler()64 CCameraHandler::CCameraHandler()
65 {
66 cameraTimeStart = 0.0f;
67 cameraTimeEnd = 0.0f;
68 startCam.fov = 90.0f;
69
70 // FPS camera must always be the first one in the list
71 camControllers.resize(CAMERA_MODE_LAST);
72 camControllers[CAMERA_MODE_FIRSTPERSON] = new CFPSController();
73 camControllers[CAMERA_MODE_OVERHEAD ] = new COverheadController();
74 camControllers[CAMERA_MODE_TOTALWAR ] = new CTWController();
75 camControllers[CAMERA_MODE_ROTOVERHEAD] = new CRotOverheadController();
76 camControllers[CAMERA_MODE_FREE ] = new CFreeController();
77 camControllers[CAMERA_MODE_SMOOTH ] = new SmoothController();
78 camControllers[CAMERA_MODE_ORBIT ] = new COrbitController();
79 camControllers[CAMERA_MODE_OVERVIEW ] = new COverviewController();
80
81 for (unsigned int i = 0; i < camControllers.size(); i++) {
82 nameMap[camControllers[i]->GetName()] = i;
83 }
84
85 int modeIndex;
86 const std::string modeName = configHandler->GetString("CamModeName");
87 if (!modeName.empty()) {
88 modeIndex = GetModeIndex(modeName);
89 } else {
90 modeIndex = configHandler->GetInt("CamMode");
91 }
92
93 currCamCtrlNum = modeIndex;
94 currCamCtrl = camControllers[currCamCtrlNum];
95
96 cameraTimeFactor = configHandler->GetFloat("CamTimeFactor");
97 cameraTimeExponent = configHandler->GetFloat("CamTimeExponent");
98
99 RegisterAction("viewfps");
100 RegisterAction("viewta");
101 RegisterAction("viewtw");
102 RegisterAction("viewrot");
103 RegisterAction("viewfree");
104 RegisterAction("viewov");
105 RegisterAction("viewlua");
106 RegisterAction("vieworbit");
107
108 RegisterAction("viewtaflip");
109
110 RegisterAction("toggleoverview");
111 RegisterAction("togglecammode");
112
113 RegisterAction("viewsave");
114 RegisterAction("viewload");
115
116 SetCameraMode(modeIndex);
117 }
118
119
~CCameraHandler()120 CCameraHandler::~CCameraHandler()
121 {
122 while (!camControllers.empty()){
123 delete camControllers.back();
124 camControllers.pop_back();
125 }
126 }
127
128
UpdateCam()129 void CCameraHandler::UpdateCam()
130 {
131
132 //??? a lot CameraControllers depend on the calling every frame the 1st part of the if-clause
133 //if (cameraTimeEnd < 0.0f)
134 // return;
135
136 const float wantedCamFOV = currCamCtrl->GetFOV();
137 const float3 wantedCamPos = currCamCtrl->GetPos();
138 const float3 wantedCamDir = currCamCtrl->GetDir();
139
140 const float curTime = spring_now().toMilliSecsf();
141
142 if (curTime >= cameraTimeEnd) {
143 camera->SetPos(wantedCamPos);
144 camera->forward = wantedCamDir;
145 camera->SetFov(wantedCamFOV);
146 } else {
147 if ((cameraTimeEnd - cameraTimeStart) > 0.0f) {
148 const float timeRatio = (cameraTimeEnd - curTime) / (cameraTimeEnd - cameraTimeStart);
149 const float tweenFact = 1.0f - (float)math::pow(timeRatio, cameraTimeExponent);
150
151 camera->SetPos( mix(startCam.pos, wantedCamPos, tweenFact));
152 camera->forward = mix(startCam.dir, wantedCamDir, tweenFact);
153 camera->SetFov( mix(startCam.fov, wantedCamFOV, tweenFact));
154 camera->forward.Normalize();
155 }
156 }
157 }
158
159
CameraTransition(float nsecs)160 void CCameraHandler::CameraTransition(float nsecs)
161 {
162 UpdateCam(); // prevents camera stutter when multithreading
163
164 nsecs = std::max(nsecs, 0.0f) * cameraTimeFactor;
165
166 // calculate when transition should end based on duration in seconds
167 cameraTimeStart = spring_now().toMilliSecsf();
168 cameraTimeEnd = cameraTimeStart + nsecs * 1000.0f;
169
170 startCam.pos = camera->GetPos();
171 startCam.dir = camera->forward;
172 startCam.fov = camera->GetFov();
173 }
174
175
SetCameraMode(unsigned int mode)176 void CCameraHandler::SetCameraMode(unsigned int mode)
177 {
178
179 if ((mode >= camControllers.size()) || (mode == static_cast<unsigned int>(currCamCtrlNum))) {
180 return;
181 }
182
183 CameraTransition(1.0f);
184
185 CCameraController* oldCamCtrl = currCamCtrl;
186
187 currCamCtrlNum = mode;
188 currCamCtrl = camControllers[mode];
189 currCamCtrl->SetPos(oldCamCtrl->SwitchFrom());
190 currCamCtrl->SwitchTo();
191 }
192
193
SetCameraMode(const std::string & modeName)194 void CCameraHandler::SetCameraMode(const std::string& modeName)
195 {
196
197 const int modeNum = GetModeIndex(modeName);
198 if (modeNum >= 0) {
199 SetCameraMode(modeNum);
200 }
201 // do nothing if the name is not matched
202 }
203
204
GetModeIndex(const std::string & name) const205 int CCameraHandler::GetModeIndex(const std::string& name) const
206 {
207
208 std::map<std::string, unsigned int>::const_iterator it = nameMap.find(name);
209 if (it != nameMap.end()) {
210 return it->second;
211 }
212 return -1;
213 }
214
215
PushMode()216 void CCameraHandler::PushMode()
217 {
218
219 controllerStack.push(GetCurrentControllerNum());
220 }
221
222
PopMode()223 void CCameraHandler::PopMode()
224 {
225
226 if (!controllerStack.empty()) {
227 SetCameraMode(controllerStack.top());
228 controllerStack.pop();
229 }
230 }
231
232
ToggleState()233 void CCameraHandler::ToggleState()
234 {
235
236 CameraTransition(1.0f);
237
238 CCameraController* oldCamCtrl = currCamCtrl;
239 currCamCtrlNum++;
240 if (currCamCtrlNum >= camControllers.size()) {
241 currCamCtrlNum = 0;
242 }
243
244 int a = 0;
245 const int maxTries = camControllers.size() - 1;
246 while ((a < maxTries) && !camControllers[currCamCtrlNum]->enabled) {
247 currCamCtrlNum++;
248 if (currCamCtrlNum >= camControllers.size()) {
249 currCamCtrlNum = 0;
250 }
251 a++;
252 }
253
254 currCamCtrl = camControllers[currCamCtrlNum];
255 currCamCtrl->SetPos(oldCamCtrl->SwitchFrom());
256 currCamCtrl->SwitchTo();
257 }
258
259
ToggleOverviewCamera()260 void CCameraHandler::ToggleOverviewCamera()
261 {
262
263 CameraTransition(1.0f);
264 if (controllerStack.empty()) {
265 PushMode();
266 SetCameraMode(CAMERA_MODE_OVERVIEW);
267 }
268 else {
269 PopMode();
270 }
271 }
272
273
SaveView(const std::string & name)274 void CCameraHandler::SaveView(const std::string& name)
275 {
276
277 if (name.empty())
278 return;
279 ViewData vd;
280 vd["mode"] = currCamCtrlNum;
281 currCamCtrl->GetState(vd);
282 views[name] = vd;
283 return;
284 }
285
286
LoadView(const std::string & name)287 bool CCameraHandler::LoadView(const std::string& name)
288 {
289
290 if (name.empty()) {
291 return false;
292 }
293
294 std::map<std::string, ViewData>::const_iterator it = views.find(name);
295 if (it == views.end()) {
296 return false;
297 }
298 const ViewData& saved = it->second;
299
300 ViewData current;
301 GetState(current);
302
303 if (saved == current) { // load a view twice to return to old settings
304 if (name != "__old_view") { // safety: should not happen, but who knows?
305 return LoadView("__old_view");
306 } else {
307 return false;
308 }
309 } else {
310 if (name != "__old_view") {
311 SaveView("__old_view");
312 }
313 return LoadViewData(saved);
314 }
315 }
316
317
GetState(CCameraController::StateMap & sm) const318 void CCameraHandler::GetState(CCameraController::StateMap& sm) const
319 {
320
321 sm.clear();
322 sm["mode"] = (float)currCamCtrlNum;
323
324 currCamCtrl->GetState(sm);
325 }
326
327
SetState(const CCameraController::StateMap & sm)328 bool CCameraHandler::SetState(const CCameraController::StateMap& sm)
329 {
330
331 CCameraController::StateMap::const_iterator it = sm.find("mode");
332 if (it != sm.end()) {
333 const unsigned int camMode = (unsigned int)it->second;
334 if (camMode >= camControllers.size()) {
335 return false;
336 }
337 if (camMode != currCamCtrlNum) {
338 CameraTransition(1.0f);
339 currCamCtrlNum = camMode;
340 currCamCtrl = camControllers[camMode];
341 currCamCtrl->SwitchTo();
342 }
343 }
344 return currCamCtrl->SetState(sm);
345 }
346
347
GetCurrentControllerName() const348 const std::string CCameraHandler::GetCurrentControllerName() const
349 {
350
351 return currCamCtrl->GetName();
352 }
353
354
PushAction(const Action & action)355 void CCameraHandler::PushAction(const Action& action)
356 {
357
358 const std::string cmd = action.command;
359
360 if (cmd == "viewfps") {
361 SetCameraMode(CAMERA_MODE_FIRSTPERSON);
362 }
363 else if (cmd == "viewta") {
364 SetCameraMode(CAMERA_MODE_OVERHEAD);
365 }
366 else if (cmd == "viewtw") {
367 SetCameraMode(CAMERA_MODE_TOTALWAR);
368 }
369 else if (cmd == "viewrot") {
370 SetCameraMode(CAMERA_MODE_ROTOVERHEAD);
371 }
372 else if (cmd == "viewfree") {
373 SetCameraMode(CAMERA_MODE_FREE);
374 }
375 else if (cmd == "viewov") {
376 SetCameraMode(CAMERA_MODE_OVERVIEW);
377 }
378 else if (cmd == "viewlua") {
379 SetCameraMode(CAMERA_MODE_SMOOTH); // ?
380 }
381 else if (cmd == "vieworbit") {
382 SetCameraMode(CAMERA_MODE_ORBIT);
383 }
384
385 else if (cmd == "viewtaflip") {
386 COverheadController* taCam = dynamic_cast<COverheadController*>(camControllers[CAMERA_MODE_OVERHEAD]);
387 SmoothController* smCam = dynamic_cast<SmoothController*>(camControllers[CAMERA_MODE_SMOOTH]);
388
389 if (taCam) {
390 if (!action.extra.empty()) {
391 taCam->flipped = !!atoi(action.extra.c_str());
392 } else {
393 taCam->flipped = !taCam->flipped;
394 }
395 taCam->KeyMove(ZeroVector); //FIXME add a more clean way to force a call to ::UpdateVectors()
396 }
397 if (smCam) {
398 if (!action.extra.empty()) {
399 smCam->flipped = !!atoi(action.extra.c_str());
400 } else {
401 smCam->flipped = !smCam->flipped;
402 }
403 smCam->KeyMove(ZeroVector); //FIXME add a more clean way to force a call to ::UpdateVectors()
404 }
405 }
406 else if (cmd == "viewsave") {
407 if (!action.extra.empty()) {
408 SaveView(action.extra);
409 LOG("Saved view: %s", action.extra.c_str());
410 }
411 }
412 else if (cmd == "viewload") {
413 if (!LoadView(action.extra)) {
414 LOG_L(L_WARNING, "Loading view failed!");
415 }
416 }
417 else if (cmd == "toggleoverview") {
418 ToggleOverviewCamera();
419 }
420 else if (cmd == "togglecammode") {
421 ToggleState();
422 }
423 }
424
425
LoadViewData(const ViewData & vd)426 bool CCameraHandler::LoadViewData(const ViewData& vd)
427 {
428
429 if (vd.empty()) {
430 return false;
431 }
432
433 ViewData::const_iterator it = vd.find("mode");
434 if (it != vd.end()) {
435 const unsigned int camMode = (unsigned int)it->second;
436 if (camMode >= camControllers.size()) {
437 return false;
438 }
439 const unsigned int currentMode = currCamCtrlNum;
440 if (camMode != currCamCtrlNum) {
441 CameraTransition(1.0f);
442 currCamCtrlNum = camMode;
443 currCamCtrl = camControllers[camMode];
444 const bool showMode = (camMode != currentMode);
445 currCamCtrl->SwitchTo(showMode);
446 }
447 }
448 return currCamCtrl->SetState(vd);
449 }
450
451