2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // view.c -- player eye positioning
23 #include "cl_collision.h"
28 The view is allowed to move slightly from it's true position for bobbing,
29 but if it exceeds 8 pixels linear distance (spherical, not box), the list of
30 entities sent from the server may not include everything in the pvs, especially
31 when crossing a water boudnary.
35 cvar_t cl_rollspeed = {0, "cl_rollspeed", "200", "how much strafing is necessary to tilt the view"};
36 cvar_t cl_rollangle = {0, "cl_rollangle", "2.0", "how much to tilt the view when strafing"};
38 cvar_t cl_bob = {CVAR_SAVE, "cl_bob","0.02", "view bobbing amount"};
39 cvar_t cl_bobcycle = {CVAR_SAVE, "cl_bobcycle","0.6", "view bobbing speed"};
40 cvar_t cl_bobup = {CVAR_SAVE, "cl_bobup","0.5", "view bobbing adjustment that makes the up or down swing of the bob last longer"};
41 cvar_t cl_bob2 = {CVAR_SAVE, "cl_bob2","0", "sideways view bobbing amount"};
42 cvar_t cl_bob2cycle = {CVAR_SAVE, "cl_bob2cycle","0.6", "sideways view bobbing speed"};
43 cvar_t cl_bob2smooth = {CVAR_SAVE, "cl_bob2smooth","0.05", "how fast the view goes back when you stop touching the ground"};
44 cvar_t cl_bobfall = {CVAR_SAVE, "cl_bobfall","0", "how much the view swings down when falling (influenced by the speed you hit the ground with)"};
45 cvar_t cl_bobfallcycle = {CVAR_SAVE, "cl_bobfallcycle","3", "speed of the bobfall swing"};
46 cvar_t cl_bobfallminspeed = {CVAR_SAVE, "cl_bobfallminspeed","200", "necessary amount of speed for bob-falling to occur"};
47 cvar_t cl_bobmodel = {CVAR_SAVE, "cl_bobmodel", "1", "enables gun bobbing"};
48 cvar_t cl_bobmodel_side = {CVAR_SAVE, "cl_bobmodel_side", "0.15", "gun bobbing sideways sway amount"};
49 cvar_t cl_bobmodel_up = {CVAR_SAVE, "cl_bobmodel_up", "0.06", "gun bobbing upward movement amount"};
50 cvar_t cl_bobmodel_speed = {CVAR_SAVE, "cl_bobmodel_speed", "7", "gun bobbing speed"};
51 cvar_t cl_bob_limit = {CVAR_SAVE, "cl_bob_limit", "7", "limits bobbing to this much distance from view_ofs"};
52 cvar_t cl_bob_limit_heightcheck = {CVAR_SAVE, "cl_bob_limit_heightcheck", "0", "check ceiling and floor height against cl_bob_limit and scale down all view bobbing if could result in camera being in solid"};
53 cvar_t cl_bob_limit_heightcheck_dontcrosswatersurface = {CVAR_SAVE, "cl_bob_limit_heightcheck_dontcrosswatersurface", "1", "limit cl_bob_limit to not crossing liquid surfaces also"};
54 cvar_t cl_bob_velocity_limit = {CVAR_SAVE, "cl_bob_velocity_limit", "400", "limits the xyspeed value in the bobbing code"};
56 cvar_t cl_leanmodel = {CVAR_SAVE, "cl_leanmodel", "0", "enables gun leaning"};
57 cvar_t cl_leanmodel_side_speed = {CVAR_SAVE, "cl_leanmodel_side_speed", "0.7", "gun leaning sideways speed"};
58 cvar_t cl_leanmodel_side_limit = {CVAR_SAVE, "cl_leanmodel_side_limit", "35", "gun leaning sideways limit"};
59 cvar_t cl_leanmodel_side_highpass1 = {CVAR_SAVE, "cl_leanmodel_side_highpass1", "30", "gun leaning sideways pre-highpass in 1/s"};
60 cvar_t cl_leanmodel_side_highpass = {CVAR_SAVE, "cl_leanmodel_side_highpass", "3", "gun leaning sideways highpass in 1/s"};
61 cvar_t cl_leanmodel_side_lowpass = {CVAR_SAVE, "cl_leanmodel_side_lowpass", "20", "gun leaning sideways lowpass in 1/s"};
62 cvar_t cl_leanmodel_up_speed = {CVAR_SAVE, "cl_leanmodel_up_speed", "0.65", "gun leaning upward speed"};
63 cvar_t cl_leanmodel_up_limit = {CVAR_SAVE, "cl_leanmodel_up_limit", "50", "gun leaning upward limit"};
64 cvar_t cl_leanmodel_up_highpass1 = {CVAR_SAVE, "cl_leanmodel_up_highpass1", "5", "gun leaning upward pre-highpass in 1/s"};
65 cvar_t cl_leanmodel_up_highpass = {CVAR_SAVE, "cl_leanmodel_up_highpass", "15", "gun leaning upward highpass in 1/s"};
66 cvar_t cl_leanmodel_up_lowpass = {CVAR_SAVE, "cl_leanmodel_up_lowpass", "20", "gun leaning upward lowpass in 1/s"};
68 cvar_t cl_followmodel = {CVAR_SAVE, "cl_followmodel", "0", "enables gun following"};
69 cvar_t cl_followmodel_side_speed = {CVAR_SAVE, "cl_followmodel_side_speed", "0.25", "gun following sideways speed"};
70 cvar_t cl_followmodel_side_limit = {CVAR_SAVE, "cl_followmodel_side_limit", "6", "gun following sideways limit"};
71 cvar_t cl_followmodel_side_highpass1 = {CVAR_SAVE, "cl_followmodel_side_highpass1", "30", "gun following sideways pre-highpass in 1/s"};
72 cvar_t cl_followmodel_side_highpass = {CVAR_SAVE, "cl_followmodel_side_highpass", "5", "gun following sideways highpass in 1/s"};
73 cvar_t cl_followmodel_side_lowpass = {CVAR_SAVE, "cl_followmodel_side_lowpass", "10", "gun following sideways lowpass in 1/s"};
74 cvar_t cl_followmodel_up_speed = {CVAR_SAVE, "cl_followmodel_up_speed", "0.5", "gun following upward speed"};
75 cvar_t cl_followmodel_up_limit = {CVAR_SAVE, "cl_followmodel_up_limit", "5", "gun following upward limit"};
76 cvar_t cl_followmodel_up_highpass1 = {CVAR_SAVE, "cl_followmodel_up_highpass1", "60", "gun following upward pre-highpass in 1/s"};
77 cvar_t cl_followmodel_up_highpass = {CVAR_SAVE, "cl_followmodel_up_highpass", "2", "gun following upward highpass in 1/s"};
78 cvar_t cl_followmodel_up_lowpass = {CVAR_SAVE, "cl_followmodel_up_lowpass", "10", "gun following upward lowpass in 1/s"};
80 cvar_t cl_viewmodel_scale = {0, "cl_viewmodel_scale", "1", "changes size of gun model, lower values prevent poking into walls but cause strange artifacts on lighting and especially r_stereo/vid_stereobuffer options where the size of the gun becomes visible"};
82 cvar_t v_kicktime = {0, "v_kicktime", "0.5", "how long a view kick from damage lasts"};
83 cvar_t v_kickroll = {0, "v_kickroll", "0.6", "how much a view kick from damage rolls your view"};
84 cvar_t v_kickpitch = {0, "v_kickpitch", "0.6", "how much a view kick from damage pitches your view"};
86 cvar_t v_iyaw_cycle = {0, "v_iyaw_cycle", "2", "v_idlescale yaw speed"};
87 cvar_t v_iroll_cycle = {0, "v_iroll_cycle", "0.5", "v_idlescale roll speed"};
88 cvar_t v_ipitch_cycle = {0, "v_ipitch_cycle", "1", "v_idlescale pitch speed"};
89 cvar_t v_iyaw_level = {0, "v_iyaw_level", "0.3", "v_idlescale yaw amount"};
90 cvar_t v_iroll_level = {0, "v_iroll_level", "0.1", "v_idlescale roll amount"};
91 cvar_t v_ipitch_level = {0, "v_ipitch_level", "0.3", "v_idlescale pitch amount"};
93 cvar_t v_idlescale = {0, "v_idlescale", "0", "how much of the quake 'drunken view' effect to use"};
95 cvar_t v_isometric = {0, "v_isometric", "0", "changes view to isometric (non-perspective)"};
96 cvar_t v_isometric_verticalfov = { 0, "v_isometric_verticalfov", "512", "vertical field of view in game units (horizontal is computed using aspect ratio based on this)"};
97 cvar_t v_isometric_xx = {0, "v_isometric_xx", "0", "camera matrix"};
98 cvar_t v_isometric_xy = {0, "v_isometric_xy", "-1", "camera matrix"};
99 cvar_t v_isometric_xz = {0, "v_isometric_xz", "0", "camera matrix"};
100 cvar_t v_isometric_yx = {0, "v_isometric_yx", "-1", "camera matrix"};
101 cvar_t v_isometric_yy = {0, "v_isometric_yy", "0", "camera matrix"};
102 cvar_t v_isometric_yz = {0, "v_isometric_yz", "0", "camera matrix"};
103 cvar_t v_isometric_zx = {0, "v_isometric_zx", "0", "camera matrix"};
104 cvar_t v_isometric_zy = {0, "v_isometric_zy", "0", "camera matrix"};
105 cvar_t v_isometric_zz = {0, "v_isometric_zz", "1", "camera matrix"};
106 cvar_t v_isometric_tx = {0, "v_isometric_tx", "1767", "camera position"};
107 cvar_t v_isometric_ty = {0, "v_isometric_ty", "1767", "camera position"};
108 cvar_t v_isometric_tz = {0, "v_isometric_tz", "1425", "camera position"};
109 cvar_t v_isometric_rot_pitch = {0, "v_isometric_rot_pitch", "0", "camera rotation"};
110 cvar_t v_isometric_rot_yaw = {0, "v_isometric_rot_yaw", "-45", "camera rotation"};
111 cvar_t v_isometric_rot_roll = {0, "v_isometric_rot_roll", "-60", "camera rotation"};
112 cvar_t v_isometric_locked_orientation = {0, "v_isometric_locked_orientation", "1", "camera rotation is fixed"};
114 cvar_t crosshair = {CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"};
116 cvar_t v_centermove = {0, "v_centermove", "0.15", "how long before the view begins to center itself (if freelook/+mlook/+jlook/+klook are off)"};
117 cvar_t v_centerspeed = {0, "v_centerspeed","500", "how fast the view centers itself"};
119 cvar_t cl_stairsmoothspeed = {CVAR_SAVE, "cl_stairsmoothspeed", "160", "how fast your view moves upward/downward when running up/down stairs"};
121 cvar_t cl_smoothviewheight = {CVAR_SAVE, "cl_smoothviewheight", "0", "time of the averaging to the viewheight value so that it creates a smooth transition. higher values = longer transition, 0 for instant transition."};
123 cvar_t chase_back = {CVAR_SAVE, "chase_back", "48", "chase cam distance from the player"};
124 cvar_t chase_up = {CVAR_SAVE, "chase_up", "24", "chase cam distance from the player"};
125 cvar_t chase_active = {CVAR_SAVE, "chase_active", "0", "enables chase cam"};
126 cvar_t chase_overhead = {CVAR_SAVE, "chase_overhead", "0", "chase cam looks straight down if this is not zero"};
128 cvar_t chase_stevie = {0, "chase_stevie", "0", "(GOODVSBAD2 only) chase cam view from above"};
130 cvar_t v_deathtilt = {0, "v_deathtilt", "1", "whether to use sideways view when dead"};
131 cvar_t v_deathtiltangle = {0, "v_deathtiltangle", "80", "what roll angle to use when tilting the view while dead"};
133 // Prophecy camera pitchangle by Alexander "motorsep" Zubov
134 cvar_t chase_pitchangle = {CVAR_SAVE, "chase_pitchangle", "55", "chase cam pitch angle"};
136 cvar_t v_yshearing = {0, "v_yshearing", "0", "be all out of gum (set this to the maximum angle to allow Y shearing for - try values like 75)"};
138 float v_dmg_time, v_dmg_roll, v_dmg_pitch;
145 Used by view and sv_user
148 float V_CalcRoll (const vec3_t angles, const vec3_t velocity)
155 AngleVectors (angles, NULL, right, NULL);
156 side = DotProduct (velocity, right);
157 sign = side < 0 ? -1 : 1;
160 value = cl_rollangle.value;
162 if (side < cl_rollspeed.value)
163 side = side * value / cl_rollspeed.value;
171 void V_StartPitchDrift (void)
173 if (cl.laststop == cl.time)
174 return; // something else is keeping it from drifting
176 if (cl.nodrift || !cl.pitchvel)
178 cl.pitchvel = v_centerspeed.value;
184 void V_StopPitchDrift (void)
186 cl.laststop = cl.time;
195 Moves the client pitch angle towards cl.idealpitch sent by the server.
197 If the user is adjusting pitch manually, either with lookup/lookdown,
198 mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
200 Drifting is enabled when the center view key is hit, mlook is released and
201 lookspring is non 0, or when
204 void V_DriftPitch (void)
208 if (noclip_anglehack || !cl.onground || cls.demoplayback )
215 // don't count small mouse motion
218 if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)
221 cl.driftmove += cl.realframetime;
223 if ( cl.driftmove > v_centermove.value)
225 V_StartPitchDrift ();
230 delta = cl.idealpitch - cl.viewangles[PITCH];
238 move = cl.realframetime * cl.pitchvel;
239 cl.pitchvel += cl.realframetime * v_centerspeed.value;
248 cl.viewangles[PITCH] += move;
257 cl.viewangles[PITCH] -= move;
263 ==============================================================================
267 ==============================================================================
276 void V_ParseDamage (void)
280 //vec3_t forward, right;
286 armor = MSG_ReadByte(&cl_message);
287 blood = MSG_ReadByte(&cl_message);
288 MSG_ReadVector(&cl_message, from, cls.protocol);
290 // Send the Dmg Globals to CSQC
291 CL_VM_UpdateDmgGlobals(blood, armor, from);
293 count = blood*0.5 + armor*0.5;
297 cl.faceanimtime = cl.time + 0.2; // put sbar face into pain frame
299 cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
300 cl.cshifts[CSHIFT_DAMAGE].alphafade = 150;
301 if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
302 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
303 if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
304 cl.cshifts[CSHIFT_DAMAGE].percent = 150;
308 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
309 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
310 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
314 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
315 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
316 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
320 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
321 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
322 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
325 // calculate view angle kicks
326 if (cl.entities[cl.viewentity].state_current.active)
328 ent = &cl.entities[cl.viewentity];
329 Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom);
330 VectorNormalize(localfrom);
331 v_dmg_pitch = count * localfrom[0] * v_kickpitch.value;
332 v_dmg_roll = count * localfrom[1] * v_kickroll.value;
333 v_dmg_time = v_kicktime.value;
337 static cshift_t v_cshift;
344 static void V_cshift_f (void)
346 v_cshift.destcolor[0] = atof(Cmd_Argv(1));
347 v_cshift.destcolor[1] = atof(Cmd_Argv(2));
348 v_cshift.destcolor[2] = atof(Cmd_Argv(3));
349 v_cshift.percent = atof(Cmd_Argv(4));
357 When you run over an item, the server sends this command
360 static void V_BonusFlash_f (void)
364 cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
365 cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
366 cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
367 cl.cshifts[CSHIFT_BONUS].percent = 50;
368 cl.cshifts[CSHIFT_BONUS].alphafade = 100;
370 else if(Cmd_Argc() >= 4 && Cmd_Argc() <= 6)
372 cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(1)) * 255;
373 cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(2)) * 255;
374 cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(3)) * 255;
376 cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(4)) * 255; // yes, these are HEXADECIMAL percent ;)
378 cl.cshifts[CSHIFT_BONUS].percent = 50;
380 cl.cshifts[CSHIFT_BONUS].alphafade = atof(Cmd_Argv(5)) * 255;
382 cl.cshifts[CSHIFT_BONUS].alphafade = 100;
385 Con_Printf("usage:\nbf, or bf R G B [A [alphafade]]\n");
389 ==============================================================================
393 ==============================================================================
396 extern matrix4x4_t viewmodelmatrix_nobob;
397 extern matrix4x4_t viewmodelmatrix_withbob;
399 #include "cl_collision.h"
409 static vec3_t eyeboxmins = {-16, -16, -24};
410 static vec3_t eyeboxmaxs = { 16, 16, 32};
413 static vec_t lowpass(vec_t value, vec_t frac, vec_t *store)
415 frac = bound(0, frac, 1);
416 return (*store = *store * (1 - frac) + value * frac);
419 static vec_t lowpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store)
421 lowpass(value, frac, store);
422 return (*store = bound(value - limit, *store, value + limit));
425 static vec_t highpass(vec_t value, vec_t frac, vec_t *store)
427 return value - lowpass(value, frac, store);
430 static vec_t highpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store)
432 return value - lowpass_limited(value, frac, limit, store);
435 static void lowpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out)
437 out[0] = lowpass(value[0], fracx, &store[0]);
438 out[1] = lowpass(value[1], fracy, &store[1]);
439 out[2] = lowpass(value[2], fracz, &store[2]);
442 static void highpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out)
444 out[0] = highpass(value[0], fracx, &store[0]);
445 out[1] = highpass(value[1], fracy, &store[1]);
446 out[2] = highpass(value[2], fracz, &store[2]);
449 static void highpass3_limited(vec3_t value, vec_t fracx, vec_t limitx, vec_t fracy, vec_t limity, vec_t fracz, vec_t limitz, vec3_t store, vec3_t out)
451 out[0] = highpass_limited(value[0], fracx, limitx, &store[0]);
452 out[1] = highpass_limited(value[1], fracy, limity, &store[1]);
453 out[2] = highpass_limited(value[2], fracz, limitz, &store[2]);
461 * cl.gunangles_adjustment_highpass
462 * cl.gunangles_adjustment_lowpass
463 * cl.gunangles_highpass
465 * cl.gunorg_adjustment_highpass
466 * cl.gunorg_adjustment_lowpass
470 * cl.lastongroundtime
474 * cl.calcrefdef_prevtime
477 * cl.movevars_stepheight
478 * cl.movevars_timescale
482 * cl.qw_intermission_angles
483 * cl.qw_intermission_origin
488 * cl.csqc_viewanglesfromengine
489 * cl.csqc_viewmodelmatrixfromengine
490 * cl.csqc_vieworiginfromengine
491 * r_refdef.view.matrix
492 * viewmodelmatrix_nobob
493 * viewmodelmatrix_withbob
495 void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump, float clstatsviewheight, qboolean cldead, qboolean clintermission, const vec3_t clvelocity)
497 float vieworg[3], viewangles[3], smoothtime;
498 float gunorg[3], gunangles[3];
499 matrix4x4_t tmpmatrix;
501 static float viewheightavg;
504 // begin of chase camera bounding box size for proper collisions by Alexander Zubov
505 vec3_t camboxmins = {-3, -3, -3};
506 vec3_t camboxmaxs = {3, 3, 3};
507 // end of chase camera bounding box size for proper collisions by Alexander Zubov
511 // react to clonground state changes (for gun bob)
515 cl.hitgroundtime = cl.movecmd[0].time;
516 cl.lastongroundtime = cl.movecmd[0].time;
518 cl.oldonground = clonground;
519 cl.calcrefdef_prevtime = max(cl.calcrefdef_prevtime, cl.oldtime);
521 VectorClear(gunangles);
523 viewmodelmatrix_nobob = identitymatrix;
524 viewmodelmatrix_withbob = identitymatrix;
525 r_refdef.view.matrix = identitymatrix;
527 // player can look around, so take the origin from the entity,
528 // and the angles from the input system
529 Matrix4x4_OriginFromMatrix(entrendermatrix, vieworg);
530 VectorCopy(clviewangles, viewangles);
532 // calculate how much time has passed since the last V_CalcRefdef
533 smoothtime = bound(0, cl.time - cl.stairsmoothtime, 0.1);
534 cl.stairsmoothtime = cl.time;
538 v_dmg_time -= bound(0, smoothtime, 0.1);
542 // entity is a fixed camera, just copy the matrix
543 if (cls.protocol == PROTOCOL_QUAKEWORLD)
544 Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.qw_intermission_origin[0], cl.qw_intermission_origin[1], cl.qw_intermission_origin[2], cl.qw_intermission_angles[0], cl.qw_intermission_angles[1], cl.qw_intermission_angles[2], 1);
547 r_refdef.view.matrix = *entrendermatrix;
548 Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, clstatsviewheight);
550 if (v_yshearing.value > 0)
551 Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
552 Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
553 Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
554 Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
556 VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
557 VectorCopy(viewangles, cl.csqc_viewanglesfromengine);
559 Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
560 Matrix4x4_CreateScale(&cl.csqc_viewmodelmatrixfromengine, cl_viewmodel_scale.value);
564 // smooth stair stepping, but only if clonground and enabled
565 if (!clonground || cl_stairsmoothspeed.value <= 0 || teleported)
566 cl.stairsmoothz = vieworg[2];
569 if (cl.stairsmoothz < vieworg[2])
570 vieworg[2] = cl.stairsmoothz = bound(vieworg[2] - cl.movevars_stepheight, cl.stairsmoothz + smoothtime * cl_stairsmoothspeed.value, vieworg[2]);
571 else if (cl.stairsmoothz > vieworg[2])
572 vieworg[2] = cl.stairsmoothz = bound(vieworg[2], cl.stairsmoothz - smoothtime * cl_stairsmoothspeed.value, vieworg[2] + cl.movevars_stepheight);
575 // apply qw weapon recoil effect (this did not work in QW)
576 // TODO: add a cvar to disable this
577 viewangles[PITCH] += cl.qw_weaponkick;
579 // apply the viewofs (even if chasecam is used)
580 // Samual: Lets add smoothing for this too so that things like crouching are done with a transition.
581 viewheight = bound(0, (cl.time - cl.calcrefdef_prevtime) / max(0.0001, cl_smoothviewheight.value), 1);
582 viewheightavg = viewheightavg * (1 - viewheight) + clstatsviewheight * viewheight;
583 vieworg[2] += viewheightavg;
585 if (chase_active.value)
587 // observing entity from third person. Added "campitch" by Alexander "motorsep" Zubov
588 vec_t camback, camup, dist, campitch, forward[3], chase_dest[3];
590 camback = chase_back.value;
591 camup = chase_up.value;
592 campitch = chase_pitchangle.value;
594 AngleVectors(viewangles, forward, NULL, NULL);
596 if (chase_overhead.integer)
603 viewangles[PITCH] = 0;
604 AngleVectors(viewangles, forward, NULL, up);
605 // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
606 chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup;
607 chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup;
608 chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup;
611 //trace = CL_TraceLine(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
612 trace = CL_TraceLine(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
614 //trace = CL_TraceBox(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
615 trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
617 VectorCopy(trace.endpos, vieworg);
620 // trace from first person view location to our chosen third person view location
622 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
624 trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false);
626 VectorCopy(trace.endpos, bestvieworg);
628 for (offset[0] = -16;offset[0] <= 16;offset[0] += 8)
630 for (offset[1] = -16;offset[1] <= 16;offset[1] += 8)
632 AngleVectors(viewangles, NULL, NULL, up);
633 chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup + offset[0];
634 chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup + offset[1];
635 chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup + offset[2];
637 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
639 trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false);
641 if (bestvieworg[2] > trace.endpos[2])
642 bestvieworg[2] = trace.endpos[2];
646 VectorCopy(bestvieworg, vieworg);
648 viewangles[PITCH] = campitch;
652 if (gamemode == GAME_GOODVSBAD2 && chase_stevie.integer)
654 // look straight down from high above
655 viewangles[PITCH] = 90;
657 VectorSet(forward, 0, 0, -1);
660 // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
662 chase_dest[0] = vieworg[0] + forward[0] * dist;
663 chase_dest[1] = vieworg[1] + forward[1] * dist;
664 chase_dest[2] = vieworg[2] + forward[2] * dist + camup;
665 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
666 VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg);
671 // first person view from entity
673 if (cldead && v_deathtilt.integer)
674 viewangles[ROLL] = v_deathtiltangle.value;
675 VectorAdd(viewangles, cl.punchangle, viewangles);
676 viewangles[ROLL] += V_CalcRoll(clviewangles, clvelocity);
679 viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
680 viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
683 VectorAdd(vieworg, cl.punchvector, vieworg);
686 double xyspeed, bob, bobfall;
687 double cycle; // double-precision because cl.time can be a very large number, where float would get stuttery at high time values
690 frametime = (cl.time - cl.calcrefdef_prevtime) * cl.movevars_timescale;
692 if(cl_followmodel.integer || cl_leanmodel.integer)
694 // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then
697 // try to fix the first highpass; result is NOT
698 // perfect! TODO find a better fix
699 VectorCopy(viewangles, cl.gunangles_prev);
700 VectorCopy(vieworg, cl.gunorg_prev);
703 // 2. for the gun origin, only keep the high frequency (non-DC) parts, which is "somewhat like velocity"
704 VectorAdd(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass);
705 highpass3_limited(vieworg, frametime*cl_followmodel_side_highpass1.value, cl_followmodel_side_limit.value, frametime*cl_followmodel_side_highpass1.value, cl_followmodel_side_limit.value, frametime*cl_followmodel_up_highpass1.value, cl_followmodel_up_limit.value, cl.gunorg_highpass, gunorg);
706 VectorCopy(vieworg, cl.gunorg_prev);
707 VectorSubtract(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass);
709 // in the highpass, we _store_ the DIFFERENCE to the actual view angles...
710 VectorAdd(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass);
711 cl.gunangles_highpass[PITCH] += 360 * floor((viewangles[PITCH] - cl.gunangles_highpass[PITCH]) / 360 + 0.5);
712 cl.gunangles_highpass[YAW] += 360 * floor((viewangles[YAW] - cl.gunangles_highpass[YAW]) / 360 + 0.5);
713 cl.gunangles_highpass[ROLL] += 360 * floor((viewangles[ROLL] - cl.gunangles_highpass[ROLL]) / 360 + 0.5);
714 highpass3_limited(viewangles, frametime*cl_leanmodel_up_highpass1.value, cl_leanmodel_up_limit.value, frametime*cl_leanmodel_side_highpass1.value, cl_leanmodel_side_limit.value, 0, 0, cl.gunangles_highpass, gunangles);
715 VectorCopy(viewangles, cl.gunangles_prev);
716 VectorSubtract(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass);
718 // 3. calculate the RAW adjustment vectors
719 gunorg[0] *= -cl_followmodel_side_speed.value;
720 gunorg[1] *= -cl_followmodel_side_speed.value;
721 gunorg[2] *= -cl_followmodel_up_speed.value;
723 gunangles[PITCH] *= -cl_leanmodel_up_speed.value;
724 gunangles[YAW] *= -cl_leanmodel_side_speed.value;
727 // 4. perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!)
728 // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector!
729 highpass3(gunorg, frametime*cl_followmodel_side_highpass.value, frametime*cl_followmodel_side_highpass.value, frametime*cl_followmodel_up_highpass.value, cl.gunorg_adjustment_highpass, gunorg);
730 lowpass3(gunorg, frametime*cl_followmodel_side_lowpass.value, frametime*cl_followmodel_side_lowpass.value, frametime*cl_followmodel_up_lowpass.value, cl.gunorg_adjustment_lowpass, gunorg);
731 // we assume here: PITCH = 0, YAW = 1, ROLL = 2
732 highpass3(gunangles, frametime*cl_leanmodel_up_highpass.value, frametime*cl_leanmodel_side_highpass.value, 0, cl.gunangles_adjustment_highpass, gunangles);
733 lowpass3(gunangles, frametime*cl_leanmodel_up_lowpass.value, frametime*cl_leanmodel_side_lowpass.value, 0, cl.gunangles_adjustment_lowpass, gunangles);
735 // 5. use the adjusted vectors
736 VectorAdd(vieworg, gunorg, gunorg);
737 VectorAdd(viewangles, gunangles, gunangles);
741 // Just initialize gunorg/gunangles.
742 VectorCopy(vieworg, gunorg);
743 VectorCopy(viewangles, gunangles);
746 // bounded XY speed, used by several effects below
747 xyspeed = bound (0, sqrt(clvelocity[0]*clvelocity[0] + clvelocity[1]*clvelocity[1]), cl_bob_velocity_limit.value);
749 // vertical view bobbing code
750 if (cl_bob.value && cl_bobcycle.value)
752 float bob_limit = cl_bob_limit.value;
754 if (cl_bob_limit_heightcheck.integer)
756 // use traces to determine what range the view can bob in, and scale down the bob as needed
757 float trace1fraction;
758 float trace2fraction;
759 vec3_t bob_height_check_dest;
761 // these multipliers are expanded a bit (the actual bob sin range is from -0.4 to 1.0) to reduce nearclip issues, especially on water surfaces
762 bob_height_check_dest[0] = vieworg[0];
763 bob_height_check_dest[1] = vieworg[1];
764 bob_height_check_dest[2] = vieworg[2] + cl_bob_limit.value * 1.1f;
765 trace = CL_TraceLine(vieworg, bob_height_check_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY | (cl_bob_limit_heightcheck_dontcrosswatersurface.integer ? SUPERCONTENTS_LIQUIDSMASK : 0), 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
766 trace1fraction = trace.fraction;
768 bob_height_check_dest[0] = vieworg[0];
769 bob_height_check_dest[1] = vieworg[1];
770 bob_height_check_dest[2] = vieworg[2] + cl_bob_limit.value * -0.5f;
771 trace = CL_TraceLine(vieworg, bob_height_check_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY | (cl_bob_limit_heightcheck_dontcrosswatersurface.integer ? SUPERCONTENTS_LIQUIDSMASK : 0), 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
772 trace2fraction = trace.fraction;
774 bob_limit *= min(trace1fraction, trace2fraction);
777 // LordHavoc: this code is *weird*, but not replacable (I think it
778 // should be done in QC on the server, but oh well, quake is quake)
779 // LordHavoc: figured out bobup: the time at which the sin is at 180
780 // degrees (which allows lengthening or squishing the peak or valley)
781 cycle = cl.time / cl_bobcycle.value;
782 cycle -= (int) cycle;
783 if (cycle < cl_bobup.value)
784 cycle = sin(M_PI * cycle / cl_bobup.value);
786 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
787 // bob is proportional to velocity in the xy plane
788 // (don't count Z, or jumping messes it up)
789 bob = xyspeed * cl_bob.value;
790 bob = bound(0, bob, bob_limit);
791 bob = bob*0.3 + bob*0.7*cycle;
793 // we also need to adjust gunorg, or this appears like pushing the gun!
794 // In the old code, this was applied to vieworg BEFORE copying to gunorg,
795 // but this is not viable with the new followmodel code as that would mean
796 // that followmodel would work on the munged-by-bob vieworg and do feedback
800 // horizontal view bobbing code
801 if (cl_bob2.value && cl_bob2cycle.value)
804 vec3_t forward, right, up;
807 cycle = cl.time / cl_bob2cycle.value;
808 cycle -= (int) cycle;
810 cycle = cos(M_PI * cycle / 0.5); // cos looks better here with the other view bobbing using sin
812 cycle = cos(M_PI + M_PI * (cycle-0.5)/0.5);
813 bob = cl_bob2.value * cycle;
815 // this value slowly decreases from 1 to 0 when we stop touching the ground.
816 // The cycle is later multiplied with it so the view smooths back to normal
817 if (clonground && !clcmdjump) // also block the effect while the jump button is pressed, to avoid twitches when bunny-hopping
821 if(cl.bob2_smooth > 0)
822 cl.bob2_smooth -= bound(0, cl_bob2smooth.value, 1);
827 // calculate the front and side of the player between the X and Y axes
828 AngleVectors(viewangles, forward, right, up);
829 // now get the speed based on those angles. The bounds should match the same value as xyspeed's
830 side = bound(-cl_bob_velocity_limit.value, DotProduct (clvelocity, right) * cl.bob2_smooth, cl_bob_velocity_limit.value);
831 front = bound(-cl_bob_velocity_limit.value, DotProduct (clvelocity, forward) * cl.bob2_smooth, cl_bob_velocity_limit.value);
832 VectorScale(forward, bob, forward);
833 VectorScale(right, bob, right);
834 // we use side with forward and front with right, so the bobbing goes
835 // to the side when we walk forward and to the front when we strafe
836 VectorMAMAM(side, forward, front, right, 0, up, bob2vel);
837 vieworg[0] += bob2vel[0];
838 vieworg[1] += bob2vel[1];
839 // we also need to adjust gunorg, or this appears like pushing the gun!
840 // In the old code, this was applied to vieworg BEFORE copying to gunorg,
841 // but this is not viable with the new followmodel code as that would mean
842 // that followmodel would work on the munged-by-bob vieworg and do feedback
843 gunorg[0] += bob2vel[0];
844 gunorg[1] += bob2vel[1];
848 // causes the view to swing down and back up when touching the ground
849 if (cl_bobfall.value && cl_bobfallcycle.value)
853 cl.bobfall_speed = bound(-400, clvelocity[2], 0) * bound(0, cl_bobfall.value, 0.1);
854 if (clvelocity[2] < -cl_bobfallminspeed.value)
855 cl.bobfall_swing = 1;
857 cl.bobfall_swing = 0; // TODO really?
861 cl.bobfall_swing = max(0, cl.bobfall_swing - cl_bobfallcycle.value * frametime);
863 bobfall = sin(M_PI * cl.bobfall_swing) * cl.bobfall_speed;
864 vieworg[2] += bobfall;
865 gunorg[2] += bobfall;
869 // gun model bobbing code
870 if (cl_bobmodel.value)
872 // calculate for swinging gun model
873 // the gun bobs when running on the ground, but doesn't bob when you're in the air.
874 // Sajt: I tried to smooth out the transitions between bob and no bob, which works
875 // for the most part, but for some reason when you go through a message trigger or
876 // pick up an item or anything like that it will momentarily jolt the gun.
877 vec3_t forward, right, up;
882 s = cl.time * cl_bobmodel_speed.value;
885 if (cl.time - cl.hitgroundtime < 0.2)
887 // just hit the ground, speed the bob back up over the next 0.2 seconds
888 t = cl.time - cl.hitgroundtime;
889 t = bound(0, t, 0.2);
897 // recently left the ground, slow the bob down over the next 0.2 seconds
898 t = cl.time - cl.lastongroundtime;
899 t = 0.2 - bound(0, t, 0.2);
903 bspeed = xyspeed * 0.01f;
904 AngleVectors (gunangles, forward, right, up);
905 bob = bspeed * cl_bobmodel_side.value * cl_viewmodel_scale.value * sin (s) * t;
906 VectorMA (gunorg, bob, right, gunorg);
907 bob = bspeed * cl_bobmodel_up.value * cl_viewmodel_scale.value * cos (s * 2) * t;
908 VectorMA (gunorg, bob, up, gunorg);
912 // calculate a view matrix for rendering the scene
913 if (v_idlescale.value)
915 viewangles[0] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
916 viewangles[1] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
917 viewangles[2] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
919 Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2], 1);
920 if (v_yshearing.value > 0)
921 Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
923 // calculate a viewmodel matrix for use in view-attached entities
924 Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
925 Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
927 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix_withbob, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value);
928 if (v_yshearing.value > 0)
929 Matrix4x4_QuakeToDuke3D(&viewmodelmatrix_withbob, &viewmodelmatrix_withbob, v_yshearing.value);
931 VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
932 VectorCopy(viewangles, cl.csqc_viewanglesfromengine);
934 Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
935 Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob);
938 cl.calcrefdef_prevtime = cl.time;
941 void V_CalcRefdef (void)
946 if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.viewentity])
948 // ent is the view entity (visible when out of body)
949 ent = &cl.entities[cl.viewentity];
951 cldead = (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && cl.stats[STAT_HEALTH] != -2342);
952 V_CalcRefdefUsing(&ent->render.matrix, cl.viewangles, !ent->persistent.trail_allowed, cl.onground, cl.cmd.jump, cl.stats[STAT_VIEWHEIGHT], cldead, cl.intermission != 0, cl.velocity); // FIXME use a better way to detect teleport/warp than trail_allowed
956 viewmodelmatrix_nobob = identitymatrix;
957 viewmodelmatrix_withbob = identitymatrix;
958 cl.csqc_viewmodelmatrixfromengine = identitymatrix;
959 r_refdef.view.matrix = identitymatrix;
960 VectorClear(cl.csqc_vieworiginfromengine);
961 VectorCopy(cl.viewangles, cl.csqc_viewanglesfromengine);
965 void V_MakeViewIsometric(void)
967 // when using isometric view to play normal games we have to rotate the camera to make the Ortho matrix do the right thing (forward as up the screen, etc)
968 matrix4x4_t relative;
969 matrix4x4_t modifiedview;
972 t[0][0] = v_isometric_xx.value;
973 t[0][1] = v_isometric_xy.value;
974 t[0][2] = v_isometric_xz.value;
976 t[1][0] = v_isometric_yx.value;
977 t[1][1] = v_isometric_yy.value;
978 t[1][2] = v_isometric_yz.value;
980 t[2][0] = v_isometric_zx.value;
981 t[2][1] = v_isometric_zy.value;
982 t[2][2] = v_isometric_zz.value;
988 Matrix4x4_FromArrayFloatGL(&modify, t[0]);
990 // if the orientation is locked, extract the origin and create just a translate matrix to start with
991 if (v_isometric_locked_orientation.integer)
993 vec3_t vx, vy, vz, origin;
994 Matrix4x4_ToVectors(&r_refdef.view.matrix, vx, vy, vz, origin);
995 Matrix4x4_CreateTranslate(&r_refdef.view.matrix, origin[0], origin[1], origin[2]);
998 Matrix4x4_Concat(&modifiedview, &r_refdef.view.matrix, &modify);
999 Matrix4x4_CreateFromQuakeEntity(&relative, v_isometric_tx.value, v_isometric_ty.value, v_isometric_tz.value, v_isometric_rot_pitch.value, v_isometric_rot_yaw.value, v_isometric_rot_roll.value, 1.0f);
1000 Matrix4x4_Concat(&r_refdef.view.matrix, &modifiedview, &relative);
1004 void V_FadeViewFlashs(void)
1006 // don't flash if time steps backwards
1007 if (cl.time <= cl.oldtime)
1009 // drop the damage value
1010 cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_DAMAGE].alphafade;
1011 if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
1012 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
1013 // drop the bonus value
1014 cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_BONUS].alphafade;
1015 if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
1016 cl.cshifts[CSHIFT_BONUS].percent = 0;
1019 void V_CalcViewBlend(void)
1023 r_refdef.viewblend[0] = 0;
1024 r_refdef.viewblend[1] = 0;
1025 r_refdef.viewblend[2] = 0;
1026 r_refdef.viewblend[3] = 0;
1027 r_refdef.frustumscale_x = 1;
1028 r_refdef.frustumscale_y = 1;
1029 if (cls.state == ca_connected && cls.signon == SIGNONS)
1031 // set contents color
1034 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin);
1035 supercontents = CL_PointSuperContents(vieworigin);
1036 if (supercontents & SUPERCONTENTS_LIQUIDSMASK)
1038 r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
1039 r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
1040 if (supercontents & SUPERCONTENTS_LAVA)
1042 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255;
1043 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
1044 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
1046 else if (supercontents & SUPERCONTENTS_SLIME)
1048 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
1049 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25;
1050 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5;
1054 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130;
1055 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
1056 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50;
1058 cl.cshifts[CSHIFT_CONTENTS].percent = 150 * 0.5;
1062 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
1063 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0;
1064 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
1065 cl.cshifts[CSHIFT_CONTENTS].percent = 0;
1068 if (gamemode != GAME_TRANSFUSION)
1070 if (cl.stats[STAT_ITEMS] & IT_QUAD)
1072 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
1073 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
1074 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
1075 cl.cshifts[CSHIFT_POWERUP].percent = 30;
1077 else if (cl.stats[STAT_ITEMS] & IT_SUIT)
1079 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
1080 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
1081 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
1082 cl.cshifts[CSHIFT_POWERUP].percent = 20;
1084 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1086 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
1087 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
1088 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
1089 cl.cshifts[CSHIFT_POWERUP].percent = 100;
1091 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1093 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
1094 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
1095 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
1096 cl.cshifts[CSHIFT_POWERUP].percent = 30;
1099 cl.cshifts[CSHIFT_POWERUP].percent = 0;
1102 cl.cshifts[CSHIFT_VCSHIFT].destcolor[0] = v_cshift.destcolor[0];
1103 cl.cshifts[CSHIFT_VCSHIFT].destcolor[1] = v_cshift.destcolor[1];
1104 cl.cshifts[CSHIFT_VCSHIFT].destcolor[2] = v_cshift.destcolor[2];
1105 cl.cshifts[CSHIFT_VCSHIFT].percent = v_cshift.percent;
1107 // LordHavoc: fixed V_CalcBlend
1108 for (j = 0;j < NUM_CSHIFTS;j++)
1110 a2 = bound(0.0f, cl.cshifts[j].percent * (1.0f / 255.0f), 1.0f);
1113 VectorLerp(r_refdef.viewblend, a2, cl.cshifts[j].destcolor, r_refdef.viewblend);
1114 r_refdef.viewblend[3] = (1 - (1 - r_refdef.viewblend[3]) * (1 - a2)); // correct alpha multiply... took a while to find it on the web
1117 // saturate color (to avoid blending in black)
1118 if (r_refdef.viewblend[3])
1120 a2 = 1 / r_refdef.viewblend[3];
1121 VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend);
1123 r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0], 255.0f);
1124 r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1], 255.0f);
1125 r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2], 255.0f);
1126 r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f);
1129 r_refdef.viewblend[0] = Image_LinearFloatFromsRGB(r_refdef.viewblend[0]);
1130 r_refdef.viewblend[1] = Image_LinearFloatFromsRGB(r_refdef.viewblend[1]);
1131 r_refdef.viewblend[2] = Image_LinearFloatFromsRGB(r_refdef.viewblend[2]);
1135 r_refdef.viewblend[0] *= (1.0f/256.0f);
1136 r_refdef.viewblend[1] *= (1.0f/256.0f);
1137 r_refdef.viewblend[2] *= (1.0f/256.0f);
1140 // Samual: Ugly hack, I know. But it's the best we can do since
1141 // there is no way to detect client states from the engine.
1142 if (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 &&
1143 cl.stats[STAT_HEALTH] != -2342 && cl_deathfade.value > 0)
1145 cl.deathfade += cl_deathfade.value * max(0.00001, cl.time - cl.oldtime);
1146 cl.deathfade = bound(0.0f, cl.deathfade, 0.9f);
1149 cl.deathfade = 0.0f;
1151 if(cl.deathfade > 0)
1154 float deathfadevec[3] = {0.3f, 0.0f, 0.0f};
1155 a = r_refdef.viewblend[3] + cl.deathfade - r_refdef.viewblend[3]*cl.deathfade;
1157 VectorMAM(r_refdef.viewblend[3] * (1 - cl.deathfade) / a, r_refdef.viewblend, cl.deathfade / a, deathfadevec, r_refdef.viewblend);
1158 r_refdef.viewblend[3] = a;
1163 //============================================================================
1172 Cmd_AddCommand ("v_cshift", V_cshift_f, "sets tint color of view");
1173 Cmd_AddCommand ("bf", V_BonusFlash_f, "briefly flashes a bright color tint on view (used when items are picked up); optionally takes R G B [A [alphafade]] arguments to specify how the flash looks");
1174 Cmd_AddCommand ("centerview", V_StartPitchDrift, "gradually recenter view (stop looking up/down)");
1176 Cvar_RegisterVariable (&v_centermove);
1177 Cvar_RegisterVariable (&v_centerspeed);
1179 Cvar_RegisterVariable (&v_iyaw_cycle);
1180 Cvar_RegisterVariable (&v_iroll_cycle);
1181 Cvar_RegisterVariable (&v_ipitch_cycle);
1182 Cvar_RegisterVariable (&v_iyaw_level);
1183 Cvar_RegisterVariable (&v_iroll_level);
1184 Cvar_RegisterVariable (&v_ipitch_level);
1186 Cvar_RegisterVariable(&v_isometric);
1187 Cvar_RegisterVariable(&v_isometric_verticalfov);
1188 Cvar_RegisterVariable(&v_isometric_xx);
1189 Cvar_RegisterVariable(&v_isometric_xy);
1190 Cvar_RegisterVariable(&v_isometric_xz);
1191 Cvar_RegisterVariable(&v_isometric_yx);
1192 Cvar_RegisterVariable(&v_isometric_yy);
1193 Cvar_RegisterVariable(&v_isometric_yz);
1194 Cvar_RegisterVariable(&v_isometric_zx);
1195 Cvar_RegisterVariable(&v_isometric_zy);
1196 Cvar_RegisterVariable(&v_isometric_zz);
1197 Cvar_RegisterVariable(&v_isometric_tx);
1198 Cvar_RegisterVariable(&v_isometric_ty);
1199 Cvar_RegisterVariable(&v_isometric_tz);
1200 Cvar_RegisterVariable(&v_isometric_rot_pitch);
1201 Cvar_RegisterVariable(&v_isometric_rot_yaw);
1202 Cvar_RegisterVariable(&v_isometric_rot_roll);
1203 Cvar_RegisterVariable(&v_isometric_locked_orientation);
1205 Cvar_RegisterVariable (&v_idlescale);
1206 Cvar_RegisterVariable (&crosshair);
1208 Cvar_RegisterVariable (&cl_rollspeed);
1209 Cvar_RegisterVariable (&cl_rollangle);
1210 Cvar_RegisterVariable (&cl_bob);
1211 Cvar_RegisterVariable (&cl_bobcycle);
1212 Cvar_RegisterVariable (&cl_bobup);
1213 Cvar_RegisterVariable (&cl_bob2);
1214 Cvar_RegisterVariable (&cl_bob2cycle);
1215 Cvar_RegisterVariable (&cl_bob2smooth);
1216 Cvar_RegisterVariable (&cl_bobfall);
1217 Cvar_RegisterVariable (&cl_bobfallcycle);
1218 Cvar_RegisterVariable (&cl_bobfallminspeed);
1219 Cvar_RegisterVariable (&cl_bobmodel);
1220 Cvar_RegisterVariable (&cl_bobmodel_side);
1221 Cvar_RegisterVariable (&cl_bobmodel_up);
1222 Cvar_RegisterVariable (&cl_bobmodel_speed);
1223 Cvar_RegisterVariable (&cl_bob_limit);
1224 Cvar_RegisterVariable (&cl_bob_limit_heightcheck);
1225 Cvar_RegisterVariable (&cl_bob_limit_heightcheck_dontcrosswatersurface);
1226 Cvar_RegisterVariable (&cl_bob_velocity_limit);
1228 Cvar_RegisterVariable (&cl_leanmodel);
1229 Cvar_RegisterVariable (&cl_leanmodel_side_speed);
1230 Cvar_RegisterVariable (&cl_leanmodel_side_limit);
1231 Cvar_RegisterVariable (&cl_leanmodel_side_highpass1);
1232 Cvar_RegisterVariable (&cl_leanmodel_side_lowpass);
1233 Cvar_RegisterVariable (&cl_leanmodel_side_highpass);
1234 Cvar_RegisterVariable (&cl_leanmodel_up_speed);
1235 Cvar_RegisterVariable (&cl_leanmodel_up_limit);
1236 Cvar_RegisterVariable (&cl_leanmodel_up_highpass1);
1237 Cvar_RegisterVariable (&cl_leanmodel_up_lowpass);
1238 Cvar_RegisterVariable (&cl_leanmodel_up_highpass);
1240 Cvar_RegisterVariable (&cl_followmodel);
1241 Cvar_RegisterVariable (&cl_followmodel_side_speed);
1242 Cvar_RegisterVariable (&cl_followmodel_side_limit);
1243 Cvar_RegisterVariable (&cl_followmodel_side_highpass1);
1244 Cvar_RegisterVariable (&cl_followmodel_side_lowpass);
1245 Cvar_RegisterVariable (&cl_followmodel_side_highpass);
1246 Cvar_RegisterVariable (&cl_followmodel_up_speed);
1247 Cvar_RegisterVariable (&cl_followmodel_up_limit);
1248 Cvar_RegisterVariable (&cl_followmodel_up_highpass1);
1249 Cvar_RegisterVariable (&cl_followmodel_up_lowpass);
1250 Cvar_RegisterVariable (&cl_followmodel_up_highpass);
1252 Cvar_RegisterVariable (&cl_viewmodel_scale);
1254 Cvar_RegisterVariable (&v_kicktime);
1255 Cvar_RegisterVariable (&v_kickroll);
1256 Cvar_RegisterVariable (&v_kickpitch);
1258 Cvar_RegisterVariable (&cl_stairsmoothspeed);
1260 Cvar_RegisterVariable (&cl_smoothviewheight);
1262 Cvar_RegisterVariable (&chase_back);
1263 Cvar_RegisterVariable (&chase_up);
1264 Cvar_RegisterVariable (&chase_active);
1265 Cvar_RegisterVariable (&chase_overhead);
1266 Cvar_RegisterVariable (&chase_pitchangle);
1267 Cvar_RegisterVariable (&chase_stevie);
1269 Cvar_RegisterVariable (&v_deathtilt);
1270 Cvar_RegisterVariable (&v_deathtiltangle);
1272 Cvar_RegisterVariable (&v_yshearing);