00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "../client.h"
00029 #include "cl_view.h"
00030 #include "cl_hud.h"
00031 #include "../input/cl_input.h"
00032 #include "events/e_parse.h"
00033
00034 static qboolean cameraRoute = qfalse;
00035 static vec3_t routeFrom, routeDelta;
00036 static float routeDist;
00037
00038 const float MIN_ZOOM = 0.5;
00039 const float MAX_ZOOM = 32.0;
00040
00041 #define MIN_CAMROT_SPEED 50
00042 #define MIN_CAMROT_ACCEL 50
00043 #define MAX_CAMROT_SPEED 1000
00044 #define MAX_CAMROT_ACCEL 1000
00045 #define MIN_CAMMOVE_SPEED 150
00046 #define MIN_CAMMOVE_ACCEL 150
00047 #define MAX_CAMMOVE_SPEED 3000
00048 #define MAX_CAMMOVE_ACCEL 3000
00049 #define LEVEL_MIN 0.05
00050 #define LEVEL_SPEED 3.0
00051 #define ZOOM_SPEED 2.0
00052 #define MIN_CAMZOOM_QUANT 0.05
00053 #define MAX_CAMZOOM_QUANT 1.0
00054
00055 static cvar_t *cl_camrotspeed;
00056 static cvar_t *cl_cammovespeed;
00057 static cvar_t *cl_cammoveaccel;
00058 static cvar_t *cl_campitchmin;
00059 static cvar_t *cl_campitchmax;
00060 cvar_t *cl_camzoommax;
00061 cvar_t *cl_camzoomquant;
00062 cvar_t *cl_camzoommin;
00063 cvar_t *cl_centerview;
00064
00069 static inline void CL_ClampCamToMap (const float border)
00070 {
00071 if (cl.cam.origin[0] < cl.mapData->mapMin[0] - border)
00072 cl.cam.origin[0] = cl.mapData->mapMin[0] - border;
00073 else if (cl.cam.origin[0] > cl.mapData->mapMax[0] + border)
00074 cl.cam.origin[0] = cl.mapData->mapMax[0] + border;
00075
00076 if (cl.cam.origin[1] < cl.mapData->mapMin[1] - border)
00077 cl.cam.origin[1] = cl.mapData->mapMin[1] - border;
00078 else if (cl.cam.origin[1] > cl.mapData->mapMax[1] + border)
00079 cl.cam.origin[1] = cl.mapData->mapMax[1] + border;
00080 }
00081
00087 void CL_CameraMove (void)
00088 {
00089 float frac;
00090 vec3_t delta;
00091 int i;
00092
00093
00094 const float rotspeed =
00095 (cl_camrotspeed->value > MIN_CAMROT_SPEED) ? ((cl_camrotspeed->value < MAX_CAMROT_SPEED) ? cl_camrotspeed->value : MAX_CAMROT_SPEED) : MIN_CAMROT_SPEED;
00096 const float movespeed =
00097 (cl_cammovespeed->value > MIN_CAMMOVE_SPEED) ?
00098 ((cl_cammovespeed->value < MAX_CAMMOVE_SPEED) ? cl_cammovespeed->value / cl.cam.zoom : MAX_CAMMOVE_SPEED / cl.cam.zoom) : MIN_CAMMOVE_SPEED / cl.cam.zoom;
00099 const float moveaccel =
00100 (cl_cammoveaccel->value > MIN_CAMMOVE_ACCEL) ?
00101 ((cl_cammoveaccel->value < MAX_CAMMOVE_ACCEL) ? cl_cammoveaccel->value / cl.cam.zoom : MAX_CAMMOVE_ACCEL / cl.cam.zoom) : MIN_CAMMOVE_ACCEL / cl.cam.zoom;
00102
00103 if (cls.state != ca_active)
00104 return;
00105
00106 if (!viddef.viewWidth || !viddef.viewHeight)
00107 return;
00108
00109
00110
00111 frac = cls.frametime * moveaccel * 2.5;
00112
00113 for (i = 0; i < 2; i++) {
00114 if (fabs(cl.cam.omega[i]) > frac) {
00115 if (cl.cam.omega[i] > 0)
00116 cl.cam.omega[i] -= frac;
00117 else
00118 cl.cam.omega[i] += frac;
00119 } else
00120 cl.cam.omega[i] = 0;
00121
00122
00123 if (i == YAW)
00124 cl.cam.omega[i] += CL_GetKeyMouseState(STATE_ROT) * frac * 2;
00125 else
00126 cl.cam.omega[i] += CL_GetKeyMouseState(STATE_TILT) * frac * 2;
00127
00128 if (cl.cam.omega[i] > rotspeed)
00129 cl.cam.omega[i] = rotspeed;
00130 if (-cl.cam.omega[i] > rotspeed)
00131 cl.cam.omega[i] = -rotspeed;
00132 }
00133
00134 cl.cam.omega[ROLL] = 0;
00135
00136 VectorMA(cl.cam.angles, cls.frametime, cl.cam.omega, cl.cam.angles);
00137
00138 if (cl.cam.angles[PITCH] > cl_campitchmax->value)
00139 cl.cam.angles[PITCH] = cl_campitchmax->value;
00140 if (cl.cam.angles[PITCH] < cl_campitchmin->value)
00141 cl.cam.angles[PITCH] = cl_campitchmin->value;
00142
00143 AngleVectors(cl.cam.angles, cl.cam.axis[0], cl.cam.axis[1], cl.cam.axis[2]);
00144
00145
00146 if (cameraRoute) {
00147
00148 frac = cls.frametime * moveaccel * 2;
00149 if (VectorDist(cl.cam.origin, routeFrom) > routeDist - 200) {
00150 VectorMA(cl.cam.speed, -frac, routeDelta, cl.cam.speed);
00151 VectorNormalize2(cl.cam.speed, delta);
00152 if (DotProduct(delta, routeDelta) < 0.05) {
00153 cameraRoute = qfalse;
00154
00155 CL_BlockBattlescapeEvents(qfalse);
00156 }
00157 } else
00158 VectorMA(cl.cam.speed, frac, routeDelta, cl.cam.speed);
00159 } else {
00160
00161
00162 const float angle = cl.cam.angles[YAW] * torad;
00163 const float sy = sin(angle);
00164 const float cy = cos(angle);
00165 vec3_t g_forward, g_right, g_up;
00166
00167 VectorSet(g_forward, cy, sy, 0.0);
00168 VectorSet(g_right, sy, -cy, 0.0);
00169 VectorSet(g_up, 0.0, 0.0, 1.0);
00170
00171
00172
00173 frac = cls.frametime * moveaccel;
00174 if (VectorLength(cl.cam.speed) > frac) {
00175 VectorNormalize2(cl.cam.speed, delta);
00176 VectorMA(cl.cam.speed, -frac, delta, cl.cam.speed);
00177 } else
00178 VectorClear(cl.cam.speed);
00179
00180
00181 frac = cls.frametime * moveaccel * 3.5;
00182 VectorClear(delta);
00183 VectorScale(g_forward, CL_GetKeyMouseState(STATE_FORWARD), delta);
00184 VectorMA(delta, CL_GetKeyMouseState(STATE_RIGHT), g_right, delta);
00185 VectorNormalize(delta);
00186 VectorMA(cl.cam.speed, frac, delta, cl.cam.speed);
00187
00188
00189 if (cl.cam.lerplevel < cl_worldlevel->value) {
00190 cl.cam.lerplevel += LEVEL_SPEED * (cl_worldlevel->value - cl.cam.lerplevel + LEVEL_MIN) * cls.frametime;
00191 if (cl.cam.lerplevel > cl_worldlevel->value)
00192 cl.cam.lerplevel = cl_worldlevel->value;
00193 } else if (cl.cam.lerplevel > cl_worldlevel->value) {
00194 cl.cam.lerplevel -= LEVEL_SPEED * (cl.cam.lerplevel - cl_worldlevel->value + LEVEL_MIN) * cls.frametime;
00195 if (cl.cam.lerplevel < cl_worldlevel->value)
00196 cl.cam.lerplevel = cl_worldlevel->value;
00197 }
00198 }
00199
00200
00201 frac = VectorLength(cl.cam.speed) / movespeed;
00202 if (frac > 1.0)
00203 VectorScale(cl.cam.speed, 1.0 / frac, cl.cam.speed);
00204
00205
00206 frac = CL_GetKeyMouseState(STATE_ZOOM);
00207 if (frac > 0.1) {
00208 cl.cam.zoom *= 1.0 + cls.frametime * ZOOM_SPEED * frac;
00209
00210 cl.cam.zoom = min(min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
00211 } else if (frac < -0.1) {
00212 cl.cam.zoom /= 1.0 - cls.frametime * ZOOM_SPEED * frac;
00213
00214 cl.cam.zoom = max(max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
00215 }
00216 CL_ViewCalcFieldOfViewX();
00217
00218
00219 VectorMA(cl.cam.origin, cls.frametime, cl.cam.speed, cl.cam.origin);
00220 cl.cam.origin[2] = 0.;
00221 if (cl_isometric->integer) {
00222 CL_ClampCamToMap(72.);
00223 VectorMA(cl.cam.origin, -CAMERA_START_DIST + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT, cl.cam.axis[0], cl.cam.camorg);
00224 cl.cam.camorg[2] += CAMERA_START_HEIGHT + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
00225 } else {
00226 CL_ClampCamToMap(min(144. * (cl.cam.zoom - cl_camzoommin->value - 0.4) / cl_camzoommax->value, 86));
00227 VectorMA(cl.cam.origin, -CAMERA_START_DIST / cl.cam.zoom , cl.cam.axis[0], cl.cam.camorg);
00228 cl.cam.camorg[2] += CAMERA_START_HEIGHT / cl.cam.zoom + cl.cam.lerplevel * CAMERA_LEVEL_HEIGHT;
00229 }
00230 }
00231
00239 void CL_CameraRoute (const pos3_t from, const pos3_t target)
00240 {
00241 if (!cl_centerview->integer)
00242 return;
00243
00244
00245 PosToVec(from, routeFrom);
00246 PosToVec(target, routeDelta);
00247 VectorSubtract(routeDelta, routeFrom, routeDelta);
00248 routeDelta[2] = 0;
00249 routeDist = VectorLength(routeDelta);
00250 VectorNormalize(routeDelta);
00251
00252
00253 VectorCopy(routeFrom, cl.cam.origin);
00254
00255
00256
00257 Cvar_SetValue("cl_worldlevel", target[2]);
00258
00259 VectorClear(cl.cam.speed);
00260 cameraRoute = qtrue;
00261
00262 CL_BlockBattlescapeEvents(qtrue);
00263 }
00264
00268 void CL_CameraZoomIn (void)
00269 {
00270 float quant;
00271
00272
00273 if (cl_camzoomquant->value < MIN_CAMZOOM_QUANT)
00274 quant = 1 + MIN_CAMZOOM_QUANT;
00275 else if (cl_camzoomquant->value > MAX_CAMZOOM_QUANT)
00276 quant = 1 + MAX_CAMZOOM_QUANT;
00277 else
00278 quant = 1 + cl_camzoomquant->value;
00279
00280
00281 cl.cam.zoom *= quant;
00282
00283
00284 cl.cam.zoom = min(min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
00285 CL_ViewCalcFieldOfViewX();
00286 }
00287
00291 void CL_CameraZoomOut (void)
00292 {
00293 float quant;
00294
00295
00296 if (cl_camzoomquant->value < MIN_CAMZOOM_QUANT)
00297 quant = 1 + MIN_CAMZOOM_QUANT;
00298 else if (cl_camzoomquant->value > MAX_CAMZOOM_QUANT)
00299 quant = 1 + MAX_CAMZOOM_QUANT;
00300 else
00301 quant = 1 + cl_camzoomquant->value;
00302
00303
00304 cl.cam.zoom /= quant;
00305
00306
00307 cl.cam.zoom = max(max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
00308 CL_ViewCalcFieldOfViewX();
00309 }
00310
00311 #ifdef DEBUG
00312
00317 static void CL_CamPrintAngles_f (void)
00318 {
00319 Com_Printf("camera angles %0.3f:%0.3f:%0.3f\n", cl.cam.angles[0], cl.cam.angles[1], cl.cam.angles[2]);
00320 }
00321 #endif
00322
00323 static void CL_CamSetAngles_f (void)
00324 {
00325 int c = Cmd_Argc();
00326
00327 if (c < 3) {
00328 Com_Printf("Usage %s <value> <value>\n", Cmd_Argv(0));
00329 return;
00330 }
00331
00332 cl.cam.angles[PITCH] = atof(Cmd_Argv(1));
00333 cl.cam.angles[YAW] = atof(Cmd_Argv(2));
00334 cl.cam.angles[ROLL] = 0.0f;
00335 }
00336
00337 static void CL_CamSetZoom_f (void)
00338 {
00339 int c = Cmd_Argc();
00340
00341 if (c < 2) {
00342 Com_Printf("Usage %s <value>\n", Cmd_Argv(0));
00343 return;
00344 }
00345
00346 Com_Printf("old zoom value: %.2f\n", cl.cam.zoom);
00347 cl.cam.zoom = atof(Cmd_Argv(1));
00348 cl.cam.zoom = min(min(MAX_ZOOM, cl_camzoommax->value), cl.cam.zoom);
00349 cl.cam.zoom = max(max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
00350 }
00351
00352 static void CL_CenterCameraIntoMap_f (void)
00353 {
00354 VectorCenterFromMinsMaxs(cl.mapData->mapMin, cl.mapData->mapMax, cl.cam.origin);
00355 }
00356
00357 void CL_CameraInit (void)
00358 {
00359 cl_camrotspeed = Cvar_Get("cl_camrotspeed", "250", CVAR_ARCHIVE, NULL);
00360 cl_cammovespeed = Cvar_Get("cl_cammovespeed", "750", CVAR_ARCHIVE, NULL);
00361 cl_cammoveaccel = Cvar_Get("cl_cammoveaccel", "1250", CVAR_ARCHIVE, NULL);
00362 cl_campitchmax = Cvar_Get("cl_campitchmax", "89", 0, "Max camera pitch - over 90 presents apparent mouse inversion");
00363 cl_campitchmin = Cvar_Get("cl_campitchmin", "10", 0, "Min camera pitch - under 35 presents difficulty positioning cursor");
00364 cl_camzoomquant = Cvar_Get("cl_camzoomquant", "0.16", CVAR_ARCHIVE, NULL);
00365 cl_camzoommin = Cvar_Get("cl_camzoommin", "0.3", 0, "Minimum zoom value for tactical missions");
00366 cl_camzoommax = Cvar_Get("cl_camzoommax", "3.4", 0, "Maximum zoom value for tactical missions");
00367 cl_centerview = Cvar_Get("cl_centerview", "1", CVAR_ARCHIVE, "Center the view when selecting a new soldier");
00368
00369 #ifdef DEBUG
00370 Cmd_AddCommand("debug_camangles", CL_CamPrintAngles_f, "Prints current camera angles");
00371 #endif
00372 Cmd_AddCommand("camsetangles", CL_CamSetAngles_f, "Set camera angles to the given values");
00373 Cmd_AddCommand("camsetzoom", CL_CamSetZoom_f, "Set camera zoom level");
00374 Cmd_AddCommand("centercamera", CL_CenterCameraIntoMap_f, "Center camera into the map.");
00375 }