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