cl_camera.c

Go to the documentation of this file.
00001 
00005 /*
00006 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 Original file from Quake 2 v3.21: quake2-2.31/client/cl_input.c
00009 Copyright (C) 1997-2001 Id Software, Inc.
00010 
00011 This program is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU General Public License
00013 as published by the Free Software Foundation; either version 2
00014 of the License, or (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020 See the GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License
00023 along with this program; if not, write to the Free Software
00024 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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     /* get relevant variables */
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     /* calculate camera omega */
00110     /* stop acceleration */
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         /* rotational acceleration */
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     /* calculate new camera angles for this frame */
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     /* camera route overrides user input */
00146     if (cameraRoute) {
00147         /* camera route */
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         /* normal camera movement */
00161         /* calculate ground-based movement vectors */
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         /* calculate camera speed */
00172         /* stop acceleration */
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         /* acceleration */
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         /* lerp the level change */
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     /* clamp speed */
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     /* zoom change */
00206     frac = CL_GetKeyMouseState(STATE_ZOOM);
00207     if (frac > 0.1) {
00208         cl.cam.zoom *= 1.0 + cls.frametime * ZOOM_SPEED * frac;
00209         /* ensure zoom isn't greater than either MAX_ZOOM or cl_camzoommax */
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         /* ensure zoom isn't less than either MIN_ZOOM or cl_camzoommin */
00214         cl.cam.zoom = max(max(MIN_ZOOM, cl_camzoommin->value), cl.cam.zoom);
00215     }
00216     CL_ViewCalcFieldOfViewX();
00217 
00218     /* calc new camera reference and new camera real origin */
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     /* initialize the camera route variables */
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     /* center the camera on the route starting position */
00253     VectorCopy(routeFrom, cl.cam.origin);
00254     /* set the world level to the z axis value of the camera target
00255      * the camera lerp will do a smooth translate from the old level
00256      * to the new one */
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     /* check zoom quant */
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     /* change zoom */
00281     cl.cam.zoom *= quant;
00282 
00283     /* ensure zoom doesn't exceed either MAX_ZOOM or cl_camzoommax */
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     /* check zoom quant */
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     /* change zoom */
00304     cl.cam.zoom /= quant;
00305 
00306     /* ensure zoom isnt less than either MIN_ZOOM or cl_camzoommin */
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 /* DEBUG */
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 /* DEBUG */
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 }

Generated by  doxygen 1.6.2