UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_camera.cpp
Go to the documentation of this file.
1
4
5/*
6All original material Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8Original file from Quake 2 v3.21: quake2-2.31/client/cl_input.c
9Copyright (C) 1997-2001 Id Software, Inc.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26*/
27
28#include "../client.h"
29#include "cl_view.h"
30#include "cl_hud.h"
31#include "../input/cl_input.h"
32#include "events/e_parse.h"
33
34static bool cameraRoute = false;
35static int cameraRouteEnd;
37static float routeDist;
38
39
40const float MIN_ZOOM = 0.5;
41#ifdef ANDROID
42const float MAX_ZOOM = 16.0; /* Too far zoom will cause the game to run terribly slow on low-end devices */
43#else
44const float MAX_ZOOM = 32.0;
45#endif
46
47#define MIN_CAMROT_SPEED 5
48#define MIN_CAMROT_ACCEL 5
49#define MAX_CAMROT_SPEED 1000
50#define MAX_CAMROT_ACCEL 1000
51#define MIN_CAMMOVE_SPEED 150
52#define MIN_CAMMOVE_ACCEL 150
53#define MAX_CAMMOVE_SPEED 3000
54#define MAX_CAMMOVE_ACCEL 3000
55#define LEVEL_MIN 0.05
56#define LEVEL_SPEED 3.0
57#define MIN_CAMZOOM_QUANT 0.05
58#define MAX_CAMZOOM_QUANT 1.0
59
70
75static inline void CL_ClampCamToMap (const float border)
76{
77 if (cl.cam.origin[0] < cl.mapData->mapBox.getMinX() - border)
78 cl.cam.origin[0] = cl.mapData->mapBox.getMinX() - border;
79 else if (cl.cam.origin[0] > cl.mapData->mapBox.getMaxX() + border)
80 cl.cam.origin[0] = cl.mapData->mapBox.getMaxX() + border;
81
82 if (cl.cam.origin[1] < cl.mapData->mapBox.getMinY() - border)
83 cl.cam.origin[1] = cl.mapData->mapBox.getMinY() - border;
84 else if (cl.cam.origin[1] > cl.mapData->mapBox.getMaxY() + border)
85 cl.cam.origin[1] = cl.mapData->mapBox.getMaxY() + border;
86}
87
93void CL_CameraMove (void)
94{
95 if (cls.state != ca_active)
96 return;
97
98 if (!viddef.viewWidth || !viddef.viewHeight)
99 return;
100
101 /* get relevant variables */
102 const float rotspeed =
104 const float movespeed =
106 ((cl_cammovespeed->value < MAX_CAMMOVE_SPEED) ? cl_cammovespeed->value / cl.cam.zoom : MAX_CAMMOVE_SPEED / cl.cam.zoom) : MIN_CAMMOVE_SPEED / cl.cam.zoom;
107 const float moveaccel =
109 ((cl_cammoveaccel->value < MAX_CAMMOVE_ACCEL) ? cl_cammoveaccel->value / cl.cam.zoom : MAX_CAMMOVE_ACCEL / cl.cam.zoom) : MIN_CAMMOVE_ACCEL / cl.cam.zoom;
110
111 /* calculate camera omega */
112 /* stop acceleration */
113 float frac = cls.frametime * moveaccel * 2.5;
114
115 for (int i = 0; i < 2; i++) {
116 if (fabs(cl.cam.omega[i]) > frac) {
117 if (cl.cam.omega[i] > 0)
118 cl.cam.omega[i] -= frac;
119 else
120 cl.cam.omega[i] += frac;
121 } else
122 cl.cam.omega[i] = 0;
123
124 /* rotational acceleration */
125 if (i == YAW)
126 cl.cam.omega[i] += CL_GetKeyMouseState(STATE_ROT) * frac * 2;
127 else
128 cl.cam.omega[i] += CL_GetKeyMouseState(STATE_TILT) * frac * 2;
129
130 if (cl.cam.omega[i] > rotspeed)
131 cl.cam.omega[i] = rotspeed;
132 if (-cl.cam.omega[i] > rotspeed)
133 cl.cam.omega[i] = -rotspeed;
134 }
135
136 cl.cam.omega[ROLL] = 0;
137 /* calculate new camera angles for this frame */
138 VectorMA(cl.cam.angles, cls.frametime, cl.cam.omega, cl.cam.angles);
139
140 if (cl.cam.angles[PITCH] > cl_campitchmax->value)
141 cl.cam.angles[PITCH] = cl_campitchmax->value;
142 if (cl.cam.angles[PITCH] < cl_campitchmin->value)
143 cl.cam.angles[PITCH] = cl_campitchmin->value;
144
145 AngleVectors(cl.cam.angles, cl.cam.axis[0], cl.cam.axis[1], cl.cam.axis[2]);
146
147 /* camera route overrides user input */
148 vec3_t delta;
149 if (cameraRouteEnd > 0) {
150 if (cameraRouteEnd <= cl.time) {
152 cameraRouteEnd = 0;
153 } else {
154 return;
155 }
156 } else if (cameraRoute) {
157 /* camera route */
158 frac = cls.frametime * moveaccel * 2;
159 if (VectorDist(cl.cam.origin, routeFrom) > routeDist - UNIT_SIZE) {
160 VectorMA(cl.cam.speed, -frac, routeDelta, cl.cam.speed);
161 VectorNormalize2(cl.cam.speed, delta);
162 if (DotProduct(delta, routeDelta) < 0.05) {
163 cameraRoute = false;
164 cameraRouteEnd = cl.time + 500;
165 }
166 } else {
167 VectorMA(cl.cam.speed, frac, routeDelta, cl.cam.speed);
168 }
169 } else {
170 /* normal camera movement */
171 /* calculate ground-based movement vectors */
172 const float angle = cl.cam.angles[YAW] * torad;
173 const float sy = sin(angle);
174 const float cy = cos(angle);
175 vec3_t g_forward, g_right;
176
177 VectorSet(g_forward, cy, sy, 0.0);
178 VectorSet(g_right, sy, -cy, 0.0);
179
180 /* calculate camera speed */
181 /* stop acceleration */
182 frac = cls.frametime * moveaccel;
183 if (VectorLength(cl.cam.speed) > frac) {
184 VectorNormalize2(cl.cam.speed, delta);
185 VectorMA(cl.cam.speed, -frac, delta, cl.cam.speed);
186 } else {
187 VectorClear(cl.cam.speed);
188 }
189
190 /* acceleration */
191 frac = cls.frametime * moveaccel * 3.5;
192 VectorClear(delta);
194 VectorMA(delta, CL_GetKeyMouseState(STATE_RIGHT), g_right, delta);
195 VectorNormalize(delta);
196 VectorMA(cl.cam.speed, frac, delta, cl.cam.speed);
197
198 /* lerp the level change */
199 if (cl.cam.lerplevel < cl_worldlevel->value) {
200 cl.cam.lerplevel += LEVEL_SPEED * (cl_worldlevel->value - cl.cam.lerplevel + LEVEL_MIN) * cls.frametime;
201 if (cl.cam.lerplevel > cl_worldlevel->value)
202 cl.cam.lerplevel = cl_worldlevel->value;
203 } else if (cl.cam.lerplevel > cl_worldlevel->value) {
204 cl.cam.lerplevel -= LEVEL_SPEED * (cl.cam.lerplevel - cl_worldlevel->value + LEVEL_MIN) * cls.frametime;
205 if (cl.cam.lerplevel < cl_worldlevel->value)
206 cl.cam.lerplevel = cl_worldlevel->value;
207 }
208 }
209
210 /* clamp speed */
211 frac = VectorLength(cl.cam.speed) / movespeed;
212 if (frac > 1.0)
213 VectorScale(cl.cam.speed, 1.0 / frac, cl.cam.speed);
214
215 /* zoom change */
217 if (frac > 0.1) {
218 cl.cam.zoom *= 1.0 + cls.frametime * cl_camzoomspeed->value * frac;
219 /* ensure zoom isn't greater than either MAX_ZOOM or cl_camzoommax */
220 cl.cam.zoom = std::min(std::min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
221 } else if (frac < -0.1) {
222 cl.cam.zoom /= 1.0 - cls.frametime * cl_camzoomspeed->value * frac;
223 /* ensure zoom isn't less than either MIN_ZOOM or cl_camzoommin */
224 cl.cam.zoom = std::max(std::max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
225 }
227
228 /* calc new camera reference and new camera real origin */
229 VectorMA(cl.cam.origin, cls.frametime, cl.cam.speed, cl.cam.origin);
230 cl.cam.origin[2] = 0.;
231 if (cl_isometric->integer) {
232 CL_ClampCamToMap(72.);
233 VectorMA(cl.cam.origin, -CAMERA_START_DIST + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT, cl.cam.axis[0], cl.cam.camorg);
234 cl.cam.camorg[2] += CAMERA_START_HEIGHT + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
235 } else {
236 const double border = 144.0 * (cl.cam.zoom - cl_camzoommin->value - 0.4) / cl_camzoommax->value;
237 CL_ClampCamToMap(std::min(border, 86.0));
238 VectorMA(cl.cam.origin, -CAMERA_START_DIST / cl.cam.zoom , cl.cam.axis[0], cl.cam.camorg);
239 cl.cam.camorg[2] += CAMERA_START_HEIGHT / cl.cam.zoom + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
240 }
241}
242
250void CL_CameraRoute (const pos3_t from, const pos3_t target)
251{
252 if (!cl_centerview->integer)
253 return;
254
255 vec3_t targetCamera;
256 PosToVec(target, targetCamera);
257 const bool closeEnough = VectorCompareEps(targetCamera, cl.cam.origin, UNIT_SIZE);
258 if (closeEnough)
259 return;
260
261 /* initialize the camera route variables */
262 PosToVec(from, routeFrom);
263 PosToVec(target, routeDelta);
265 routeDelta[2] = 0;
268
269 /* center the camera on the route starting position */
270 VectorCopy(routeFrom, cl.cam.origin);
271 /* set the world level to the z axis value of the camera target
272 * the camera lerp will do a smooth translate from the old level
273 * to the new one */
274 Cvar_SetValue("cl_worldlevel", target[2]);
275
276 VectorClear(cl.cam.speed);
277 cameraRoute = true;
278
280}
281
285void CL_CheckCameraRoute (const pos3_t from, const pos3_t target)
286{
287 pos3_t current;
288 VecToPos(cl.cam.origin, current);
289 const float minDistToMove = 4.0f;
290 const float dist = Vector2Dist(target, current);
291 if (dist < minDistToMove) {
292 if (target[2] != current[2])
293 Cvar_SetValue("cl_worldlevel", target[2]);
294 return;
295 }
296 CL_CameraRoute(from, target);
297}
298
303{
304 float quant;
305
306 /* check zoom quant */
308 quant = 1 + MIN_CAMZOOM_QUANT;
309 else if (cl_camzoomquant->value > MAX_CAMZOOM_QUANT)
310 quant = 1 + MAX_CAMZOOM_QUANT;
311 else
312 quant = 1 + cl_camzoomquant->value;
313
314 /* change zoom */
315 cl.cam.zoom *= quant;
316
317 /* ensure zoom doesn't exceed either MAX_ZOOM or cl_camzoommax */
318 cl.cam.zoom = std::min(std::min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
320}
321
326{
327 float quant;
328
329 /* check zoom quant */
331 quant = 1 + MIN_CAMZOOM_QUANT;
332 else if (cl_camzoomquant->value > MAX_CAMZOOM_QUANT)
333 quant = 1 + MAX_CAMZOOM_QUANT;
334 else
335 quant = 1 + cl_camzoomquant->value;
336
337 /* change zoom */
338 cl.cam.zoom /= quant;
339
340 /* ensure zoom isnt less than either MIN_ZOOM or cl_camzoommin */
341 cl.cam.zoom = std::max(std::max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
343}
344
345#ifdef DEBUG
351static void CL_CamPrintAngles_f (void)
352{
353 Com_Printf("camera angles %0.3f:%0.3f:%0.3f\n", cl.cam.angles[0], cl.cam.angles[1], cl.cam.angles[2]);
354}
355#endif /* DEBUG */
356
357static void CL_CamSetAngles_f (void)
358{
359 const int c = Cmd_Argc();
360
361 if (c < 3) {
362 Com_Printf("Usage %s <value> <value>\n", Cmd_Argv(0));
363 return;
364 }
365
366 cl.cam.angles[PITCH] = atof(Cmd_Argv(1));
367 cl.cam.angles[YAW] = atof(Cmd_Argv(2));
368 cl.cam.angles[ROLL] = 0.0f;
369}
370
371static void CL_CamSetZoom_f (void)
372{
373 const int c = Cmd_Argc();
374
375 if (c < 2) {
376 Com_Printf("Usage %s <value>\n", Cmd_Argv(0));
377 return;
378 }
379
380 Com_Printf("old zoom value: %.2f\n", cl.cam.zoom);
381 cl.cam.zoom = atof(Cmd_Argv(1));
382 cl.cam.zoom = std::min(std::min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
383 cl.cam.zoom = std::max(std::max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
384}
385
386static void CL_CenterCameraIntoMap_f (void)
387{
388 cl.mapData->mapBox.getCenter(cl.cam.origin);
389}
390
391void CL_CameraInit (void)
392{
393 cl_camrotspeed = Cvar_Get("cl_camrotspeed", "250", CVAR_ARCHIVE, "Rotation speed of the battlescape camera.");
394 cl_cammovespeed = Cvar_Get("cl_cammovespeed", "450", CVAR_ARCHIVE, "Movement speed of the battlescape camera.");
395 cl_cammoveaccel = Cvar_Get("cl_cammoveaccel", "1250", CVAR_ARCHIVE, "Movement acceleration of the battlescape camera.");
396 cl_campitchmax = Cvar_Get("cl_campitchmax", "89", 0, "Max. battlescape camera pitch - over 90 presents apparent mouse inversion.");
397 cl_camzoomspeed = Cvar_Get("cl_camzoomspeed", "2.0", 0);
398 cl_campitchmin = Cvar_Get("cl_campitchmin", "10", 0, "Min. battlescape camera pitch - under 35 presents difficulty positioning cursor.");
399 cl_camzoomquant = Cvar_Get("cl_camzoomquant", "0.16", CVAR_ARCHIVE, "Battlescape camera zoom quantisation.");
400 cl_camzoommin = Cvar_Get("cl_camzoommin", "0.3", 0, "Minimum zoom value for tactical missions.");
401 cl_camzoommax = Cvar_Get("cl_camzoommax", "3.4", 0, "Maximum zoom value for tactical missions.");
402 cl_centerview = Cvar_Get("cl_centerview", "1", CVAR_ARCHIVE, "Center the view when selecting a new soldier.");
403
404#ifdef DEBUG
405 Cmd_AddCommand("debug_camangles", CL_CamPrintAngles_f, "Print current camera angles.");
406#endif /* DEBUG */
407 Cmd_AddCommand("camsetangles", CL_CamSetAngles_f, "Set camera angles to the given values.");
408 Cmd_AddCommand("camsetzoom", CL_CamSetZoom_f, "Set camera zoom level.");
409 Cmd_AddCommand("centercamera", CL_CenterCameraIntoMap_f, "Center camera on the map.");
410}
clientBattleScape_t cl
static cvar_t * cl_cammovespeed
Definition cl_camera.cpp:61
void CL_CheckCameraRoute(const pos3_t from, const pos3_t target)
Only moves the camera to the given target location if its not yet close enough.
static cvar_t * cl_cammoveaccel
Definition cl_camera.cpp:62
cvar_t * cl_centerview
Definition cl_camera.cpp:69
void CL_CameraMove(void)
Update the camera position. This can be done in two different reasons. The first is the user input,...
Definition cl_camera.cpp:93
#define MIN_CAMROT_SPEED
Definition cl_camera.cpp:47
static cvar_t * cl_campitchmax
Definition cl_camera.cpp:64
#define LEVEL_MIN
Definition cl_camera.cpp:55
static void CL_CamSetAngles_f(void)
static vec3_t routeDelta
Definition cl_camera.cpp:36
#define MAX_CAMZOOM_QUANT
Definition cl_camera.cpp:58
#define MAX_CAMMOVE_ACCEL
Definition cl_camera.cpp:54
static float routeDist
Definition cl_camera.cpp:37
cvar_t * cl_camzoommax
Definition cl_camera.cpp:66
static cvar_t * cl_campitchmin
Definition cl_camera.cpp:63
void CL_CameraRoute(const pos3_t from, const pos3_t target)
Interpolates the camera movement from the given start point to the given end point.
void CL_CameraZoomIn(void)
Zooms the scene of the battlefield in.
static int cameraRouteEnd
Definition cl_camera.cpp:35
cvar_t * cl_camzoommin
Definition cl_camera.cpp:68
static vec3_t routeFrom
Definition cl_camera.cpp:36
#define MIN_CAMMOVE_ACCEL
Definition cl_camera.cpp:52
static cvar_t * cl_camzoomspeed
Definition cl_camera.cpp:65
static void CL_CenterCameraIntoMap_f(void)
cvar_t * cl_camzoomquant
Definition cl_camera.cpp:67
#define MIN_CAMMOVE_SPEED
Definition cl_camera.cpp:51
static void CL_ClampCamToMap(const float border)
forces the camera to stay within the horizontal bounds of the map plus some border
Definition cl_camera.cpp:75
#define LEVEL_SPEED
Definition cl_camera.cpp:56
static cvar_t * cl_camrotspeed
Definition cl_camera.cpp:60
#define MAX_CAMROT_SPEED
Definition cl_camera.cpp:49
void CL_CameraZoomOut(void)
Zooms the scene of the battlefield out.
void CL_CameraInit(void)
static void CL_CamSetZoom_f(void)
const float MAX_ZOOM
Definition cl_camera.cpp:44
const float MIN_ZOOM
Definition cl_camera.cpp:40
#define MAX_CAMMOVE_SPEED
Definition cl_camera.cpp:53
#define MIN_CAMZOOM_QUANT
Definition cl_camera.cpp:57
static bool cameraRoute
Definition cl_camera.cpp:34
#define CAMERA_LEVEL_HEIGHT
Definition cl_camera.h:45
#define CAMERA_START_DIST
Definition cl_camera.h:43
#define CAMERA_START_HEIGHT
Definition cl_camera.h:44
cvar_t * cl_worldlevel
Definition cl_hud.cpp:46
HUD related routines.
float CL_GetKeyMouseState(int dir)
Definition cl_input.cpp:542
External (non-keyboard) input devices.
#define STATE_FORWARD
Definition cl_input.h:39
#define STATE_RIGHT
Definition cl_input.h:40
#define STATE_TILT
Definition cl_input.h:43
#define STATE_ZOOM
Definition cl_input.h:41
#define STATE_ROT
Definition cl_input.h:42
client_static_t cls
Definition cl_main.cpp:83
@ ca_active
Definition cl_shared.h:80
viddef_t viddef
Definition cl_video.cpp:34
void CL_ViewCalcFieldOfViewX(void)
Calculates refdef's FOV_X. Should generally be called after any changes are made to the zoom level (v...
Definition cl_view.cpp:189
cvar_t * cl_isometric
Definition cl_input.cpp:73
Primary header for client.
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition cmd.cpp:505
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
void Cvar_SetValue(const char *varName, float value)
Expands value to a string and calls Cvar_Set.
Definition cvar.cpp:671
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
#define CVAR_ARCHIVE
Definition cvar.h:40
#define UNIT_SIZE
Definition defines.h:121
void CL_BlockBattlescapeEvents(bool block)
Adds the ability to block battlescape event execution until something other is finished....
Definition e_parse.cpp:83
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition mathlib.cpp:745
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition mathlib.cpp:434
void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector)
Sets vector_out (vc) to vevtor1 (va) + scale * vector2 (vb).
Definition mathlib.cpp:261
vec_t VectorNormalize2(const vec3_t v, vec3_t out)
Calculated the normal vector for a given vec3_t.
Definition mathlib.cpp:237
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition mathlib.cpp:631
int VectorCompareEps(const vec3_t v1, const vec3_t v2, float epsilon)
Compare two vectors that may have an epsilon difference but still be the same vectors.
Definition mathlib.cpp:413
#define PosToVec(p, v)
Pos boundary size is +/- 128 - to get into the positive area we add the possible max negative value a...
Definition mathlib.h:110
#define torad
Definition mathlib.h:50
#define YAW
Definition mathlib.h:55
#define VecToPos(v, p)
Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the possible max negative ...
Definition mathlib.h:100
#define PITCH
Definition mathlib.h:54
#define ROLL
Definition mathlib.h:56
QGL_EXTERN GLint i
Definition r_gl.h:113
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
pos_t pos3_t[3]
Definition ufotypes.h:58
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorDist(a, b)
Definition vector.h:69
#define VectorClear(a)
Definition vector.h:55
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define Vector2Dist(a, b)
Definition vector.h:70
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44
#define VectorSet(v, x, y, z)
Definition vector.h:59
#define VectorScale(in, scale, out)
Definition vector.h:79