]> git.xonotic.org Git - xonotic/darkplaces.git/blob - view.c
build: minor adjustments
[xonotic/darkplaces.git] / view.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // view.c -- player eye positioning
21
22 #include "quakedef.h"
23 #include "cl_collision.h"
24 #include "image.h"
25
26 /*
27
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.
32
33 */
34
35 cvar_t cl_rollspeed = {CVAR_CLIENT, "cl_rollspeed", "200", "how much strafing is necessary to tilt the view"};
36 cvar_t cl_rollangle = {CVAR_CLIENT, "cl_rollangle", "2.0", "how much to tilt the view when strafing"};
37
38 cvar_t cl_bob = {CVAR_CLIENT | CVAR_SAVE, "cl_bob","0.02", "view bobbing amount"};
39 cvar_t cl_bobcycle = {CVAR_CLIENT | CVAR_SAVE, "cl_bobcycle","0.6", "view bobbing speed"};
40 cvar_t cl_bobup = {CVAR_CLIENT | 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_CLIENT | CVAR_SAVE, "cl_bob2","0", "sideways view bobbing amount"};
42 cvar_t cl_bob2cycle = {CVAR_CLIENT | CVAR_SAVE, "cl_bob2cycle","0.6", "sideways view bobbing speed"};
43 cvar_t cl_bob2smooth = {CVAR_CLIENT | CVAR_SAVE, "cl_bob2smooth","0.05", "how fast the view goes back when you stop touching the ground"};
44 cvar_t cl_bobfall = {CVAR_CLIENT | 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_CLIENT | CVAR_SAVE, "cl_bobfallcycle","3", "speed of the bobfall swing"};
46 cvar_t cl_bobfallminspeed = {CVAR_CLIENT | CVAR_SAVE, "cl_bobfallminspeed","200", "necessary amount of speed for bob-falling to occur"};
47 cvar_t cl_bobmodel = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel", "1", "enables gun bobbing"};
48 cvar_t cl_bobmodel_side = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel_side", "0", "gun bobbing sideways sway amount"};
49 cvar_t cl_bobmodel_up = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel_up", "0", "gun bobbing upward movement amount"};
50 cvar_t cl_bobmodel_forward = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel_forward", "0.25", "gun bobbing forward movement amount"};
51 cvar_t cl_bobmodel_classic = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel_classic", "1", "classic Quake-style forward gun bobbing"};
52 cvar_t cl_bobmodel_speed = {CVAR_CLIENT | CVAR_SAVE, "cl_bobmodel_speed", "6", "gun bobbing speed"};
53 cvar_t cl_bob_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_bob_limit", "4", "limits bobbing to this much distance from view_ofs"};
54 cvar_t cl_bob_limit_heightcheck = {CVAR_CLIENT | 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"};
55 cvar_t cl_bob_limit_heightcheck_dontcrosswatersurface = {CVAR_CLIENT | CVAR_SAVE, "cl_bob_limit_heightcheck_dontcrosswatersurface", "1", "limit cl_bob_limit to not crossing liquid surfaces also"};
56 cvar_t cl_bob_velocity_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_bob_velocity_limit", "400", "limits the xyspeed value in the bobbing code"};
57
58 cvar_t cl_leanmodel = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel", "0", "enables gun leaning"};
59 cvar_t cl_leanmodel_side_speed = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_side_speed", "0.7", "gun leaning sideways speed"};
60 cvar_t cl_leanmodel_side_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_side_limit", "35", "gun leaning sideways limit"};
61 cvar_t cl_leanmodel_side_highpass1 = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_side_highpass1", "30", "gun leaning sideways pre-highpass in 1/s"};
62 cvar_t cl_leanmodel_side_highpass = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_side_highpass", "3", "gun leaning sideways highpass in 1/s"};
63 cvar_t cl_leanmodel_side_lowpass = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_side_lowpass", "20", "gun leaning sideways lowpass in 1/s"};
64 cvar_t cl_leanmodel_up_speed = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_up_speed", "0.65", "gun leaning upward speed"};
65 cvar_t cl_leanmodel_up_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_up_limit", "50", "gun leaning upward limit"};
66 cvar_t cl_leanmodel_up_highpass1 = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_up_highpass1", "5", "gun leaning upward pre-highpass in 1/s"};
67 cvar_t cl_leanmodel_up_highpass = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_up_highpass", "15", "gun leaning upward highpass in 1/s"};
68 cvar_t cl_leanmodel_up_lowpass = {CVAR_CLIENT | CVAR_SAVE, "cl_leanmodel_up_lowpass", "20", "gun leaning upward lowpass in 1/s"};
69
70 cvar_t cl_followmodel = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel", "0", "enables gun following"};
71 cvar_t cl_followmodel_side_speed = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_side_speed", "0.25", "gun following sideways speed"};
72 cvar_t cl_followmodel_side_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_side_limit", "6", "gun following sideways limit"};
73 cvar_t cl_followmodel_side_highpass1 = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_side_highpass1", "30", "gun following sideways pre-highpass in 1/s"};
74 cvar_t cl_followmodel_side_highpass = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_side_highpass", "5", "gun following sideways highpass in 1/s"};
75 cvar_t cl_followmodel_side_lowpass = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_side_lowpass", "10", "gun following sideways lowpass in 1/s"};
76 cvar_t cl_followmodel_up_speed = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_up_speed", "0.5", "gun following upward speed"};
77 cvar_t cl_followmodel_up_limit = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_up_limit", "5", "gun following upward limit"};
78 cvar_t cl_followmodel_up_highpass1 = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_up_highpass1", "60", "gun following upward pre-highpass in 1/s"};
79 cvar_t cl_followmodel_up_highpass = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_up_highpass", "2", "gun following upward highpass in 1/s"};
80 cvar_t cl_followmodel_up_lowpass = {CVAR_CLIENT | CVAR_SAVE, "cl_followmodel_up_lowpass", "10", "gun following upward lowpass in 1/s"};
81
82 cvar_t cl_viewmodel_scale = {CVAR_CLIENT, "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"};
83
84 cvar_t v_kicktime = {CVAR_CLIENT, "v_kicktime", "0.5", "how long a view kick from damage lasts"};
85 cvar_t v_kickroll = {CVAR_CLIENT, "v_kickroll", "0.6", "how much a view kick from damage rolls your view"};
86 cvar_t v_kickpitch = {CVAR_CLIENT, "v_kickpitch", "0.6", "how much a view kick from damage pitches your view"};
87
88 cvar_t v_iyaw_cycle = {CVAR_CLIENT, "v_iyaw_cycle", "2", "v_idlescale yaw speed"};
89 cvar_t v_iroll_cycle = {CVAR_CLIENT, "v_iroll_cycle", "0.5", "v_idlescale roll speed"};
90 cvar_t v_ipitch_cycle = {CVAR_CLIENT, "v_ipitch_cycle", "1", "v_idlescale pitch speed"};
91 cvar_t v_iyaw_level = {CVAR_CLIENT, "v_iyaw_level", "0.3", "v_idlescale yaw amount"};
92 cvar_t v_iroll_level = {CVAR_CLIENT, "v_iroll_level", "0.1", "v_idlescale roll amount"};
93 cvar_t v_ipitch_level = {CVAR_CLIENT, "v_ipitch_level", "0.3", "v_idlescale pitch amount"};
94
95 cvar_t v_idlescale = {CVAR_CLIENT, "v_idlescale", "0", "how much of the quake 'drunken view' effect to use"};
96
97 cvar_t v_isometric = {CVAR_CLIENT, "v_isometric", "0", "changes view to isometric (non-perspective)"};
98 cvar_t v_isometric_verticalfov = {CVAR_CLIENT, "v_isometric_verticalfov", "512", "vertical field of view in game units (horizontal is computed using aspect ratio based on this)"};
99 cvar_t v_isometric_xx = {CVAR_CLIENT, "v_isometric_xx", "1", "camera matrix"};
100 cvar_t v_isometric_xy = {CVAR_CLIENT, "v_isometric_xy", "0", "camera matrix"};
101 cvar_t v_isometric_xz = {CVAR_CLIENT, "v_isometric_xz", "0", "camera matrix"};
102 cvar_t v_isometric_yx = {CVAR_CLIENT, "v_isometric_yx", "0", "camera matrix"};
103 cvar_t v_isometric_yy = {CVAR_CLIENT, "v_isometric_yy", "1", "camera matrix"};
104 cvar_t v_isometric_yz = {CVAR_CLIENT, "v_isometric_yz", "0", "camera matrix"};
105 cvar_t v_isometric_zx = {CVAR_CLIENT, "v_isometric_zx", "0", "camera matrix"};
106 cvar_t v_isometric_zy = {CVAR_CLIENT, "v_isometric_zy", "0", "camera matrix"};
107 cvar_t v_isometric_zz = {CVAR_CLIENT, "v_isometric_zz", "1", "camera matrix"};
108 cvar_t v_isometric_tx = {CVAR_CLIENT, "v_isometric_tx", "0", "camera position (player-relative)"};
109 cvar_t v_isometric_ty = {CVAR_CLIENT, "v_isometric_ty", "0", "camera position (player-relative)"};
110 cvar_t v_isometric_tz = {CVAR_CLIENT, "v_isometric_tz", "0", "camera position (player-relative)"};
111 cvar_t v_isometric_rot_pitch = {CVAR_CLIENT, "v_isometric_rot_pitch", "60", "camera rotation"};
112 cvar_t v_isometric_rot_yaw = {CVAR_CLIENT, "v_isometric_rot_yaw", "135", "camera rotation"};
113 cvar_t v_isometric_rot_roll = {CVAR_CLIENT, "v_isometric_rot_roll", "0", "camera rotation"};
114 cvar_t v_isometric_relx = {CVAR_CLIENT, "v_isometric_relx", "0", "camera position*forward"};
115 cvar_t v_isometric_rely = {CVAR_CLIENT, "v_isometric_rely", "0", "camera position*left"};
116 cvar_t v_isometric_relz = {CVAR_CLIENT, "v_isometric_relz", "0", "camera position*up"};
117 cvar_t v_isometric_flipcullface = {CVAR_CLIENT, "v_isometric_flipcullface", "0", "flips the backface culling"};
118 cvar_t v_isometric_locked_orientation = {CVAR_CLIENT, "v_isometric_locked_orientation", "1", "camera rotation is fixed"};
119 cvar_t v_isometric_usevieworiginculling = {CVAR_CLIENT, "v_isometric_usevieworiginculling", "0", "check visibility to the player location (can look pretty weird)"};
120
121 cvar_t crosshair = {CVAR_CLIENT | CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"};
122
123 cvar_t v_centermove = {CVAR_CLIENT, "v_centermove", "0.15", "how long before the view begins to center itself (if freelook/+mlook/+jlook/+klook are off)"};
124 cvar_t v_centerspeed = {CVAR_CLIENT, "v_centerspeed","500", "how fast the view centers itself"};
125
126 cvar_t cl_stairsmoothspeed = {CVAR_CLIENT | CVAR_SAVE, "cl_stairsmoothspeed", "160", "how fast your view moves upward/downward when running up/down stairs"};
127
128 cvar_t cl_smoothviewheight = {CVAR_CLIENT | 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."};
129
130 cvar_t chase_back = {CVAR_CLIENT | CVAR_SAVE, "chase_back", "48", "chase cam distance from the player"};
131 cvar_t chase_up = {CVAR_CLIENT | CVAR_SAVE, "chase_up", "24", "chase cam distance from the player"};
132 cvar_t chase_active = {CVAR_CLIENT | CVAR_SAVE, "chase_active", "0", "enables chase cam"};
133 cvar_t chase_overhead = {CVAR_CLIENT | CVAR_SAVE, "chase_overhead", "0", "chase cam looks straight down if this is not zero"};
134 // GAME_GOODVSBAD2
135 cvar_t chase_stevie = {CVAR_CLIENT, "chase_stevie", "0", "(GOODVSBAD2 only) chase cam view from above"};
136
137 cvar_t v_deathtilt = {CVAR_CLIENT, "v_deathtilt", "1", "whether to use sideways view when dead"};
138 cvar_t v_deathtiltangle = {CVAR_CLIENT, "v_deathtiltangle", "80", "what roll angle to use when tilting the view while dead"};
139
140 // Prophecy camera pitchangle by Alexander "motorsep" Zubov
141 cvar_t chase_pitchangle = {CVAR_CLIENT | CVAR_SAVE, "chase_pitchangle", "55", "chase cam pitch angle"};
142
143 cvar_t v_yshearing = {CVAR_CLIENT, "v_yshearing", "0", "be all out of gum (set this to the maximum angle to allow Y shearing for - try values like 75)"};
144
145 float   v_dmg_time, v_dmg_roll, v_dmg_pitch;
146
147 int cl_punchangle_applied;
148
149 /*
150 ===============
151 V_CalcRoll
152
153 Used by view and sv_user
154 ===============
155 */
156 float V_CalcRoll (const vec3_t angles, const vec3_t velocity)
157 {
158         vec3_t  right;
159         float   sign;
160         float   side;
161         float   value;
162
163         AngleVectors (angles, NULL, right, NULL);
164         side = DotProduct (velocity, right);
165         sign = side < 0 ? -1 : 1;
166         side = fabs(side);
167
168         value = cl_rollangle.value;
169
170         if (side < cl_rollspeed.value)
171                 side = side * value / cl_rollspeed.value;
172         else
173                 side = value;
174
175         return side*sign;
176
177 }
178
179 void V_StartPitchDrift (void)
180 {
181         if (cl.laststop == cl.time)
182                 return;         // something else is keeping it from drifting
183
184         if (cl.nodrift || !cl.pitchvel)
185         {
186                 cl.pitchvel = v_centerspeed.value;
187                 cl.nodrift = false;
188                 cl.driftmove = 0;
189         }
190 }
191
192 void V_StartPitchDrift_f(cmd_state_t *cmd)
193 {
194         V_StartPitchDrift();
195 }
196
197 void V_StopPitchDrift (void)
198 {
199         cl.laststop = cl.time;
200         cl.nodrift = true;
201         cl.pitchvel = 0;
202 }
203
204 /*
205 ===============
206 V_DriftPitch
207
208 Moves the client pitch angle towards cl.idealpitch sent by the server.
209
210 If the user is adjusting pitch manually, either with lookup/lookdown,
211 mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
212
213 Drifting is enabled when the center view key is hit, mlook is released and
214 lookspring is non 0, or when
215 ===============
216 */
217 void V_DriftPitch (void)
218 {
219         float           delta, move;
220
221         if (noclip_anglehack || !cl.onground || cls.demoplayback )
222         {
223                 cl.driftmove = 0;
224                 cl.pitchvel = 0;
225                 return;
226         }
227
228 // don't count small mouse motion
229         if (cl.nodrift)
230         {
231                 if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)
232                         cl.driftmove = 0;
233                 else
234                         cl.driftmove += cl.realframetime;
235
236                 if ( cl.driftmove > v_centermove.value)
237                 {
238                         V_StartPitchDrift ();
239                 }
240                 return;
241         }
242
243         delta = cl.idealpitch - cl.viewangles[PITCH];
244
245         if (!delta)
246         {
247                 cl.pitchvel = 0;
248                 return;
249         }
250
251         move = cl.realframetime * cl.pitchvel;
252         cl.pitchvel += cl.realframetime * v_centerspeed.value;
253
254         if (delta > 0)
255         {
256                 if (move > delta)
257                 {
258                         cl.pitchvel = 0;
259                         move = delta;
260                 }
261                 cl.viewangles[PITCH] += move;
262         }
263         else if (delta < 0)
264         {
265                 if (move > -delta)
266                 {
267                         cl.pitchvel = 0;
268                         move = -delta;
269                 }
270                 cl.viewangles[PITCH] -= move;
271         }
272 }
273
274
275 /*
276 ==============================================================================
277
278                                                 SCREEN FLASHES
279
280 ==============================================================================
281 */
282
283
284 /*
285 ===============
286 V_ParseDamage
287 ===============
288 */
289 void V_ParseDamage (void)
290 {
291         int armor, blood;
292         vec3_t from;
293         //vec3_t forward, right;
294         vec3_t localfrom;
295         entity_t *ent;
296         //float side;
297         float count;
298
299         armor = MSG_ReadByte(&cl_message);
300         blood = MSG_ReadByte(&cl_message);
301         MSG_ReadVector(&cl_message, from, cls.protocol);
302
303         // Send the Dmg Globals to CSQC
304         CL_VM_UpdateDmgGlobals(blood, armor, from);
305
306         count = blood*0.5 + armor*0.5;
307         if (count < 10)
308                 count = 10;
309
310         cl.faceanimtime = cl.time + 0.2;                // put sbar face into pain frame
311
312         cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
313         cl.cshifts[CSHIFT_DAMAGE].alphafade = 150;
314         if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
315                 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
316         if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
317                 cl.cshifts[CSHIFT_DAMAGE].percent = 150;
318
319         if (armor > blood)
320         {
321                 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
322                 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
323                 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
324         }
325         else if (armor)
326         {
327                 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
328                 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
329                 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
330         }
331         else
332         {
333                 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
334                 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
335                 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
336         }
337
338         // calculate view angle kicks
339         if (cl.entities[cl.viewentity].state_current.active)
340         {
341                 ent = &cl.entities[cl.viewentity];
342                 Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom);
343                 VectorNormalize(localfrom);
344                 v_dmg_pitch = count * localfrom[0] * v_kickpitch.value;
345                 v_dmg_roll = count * localfrom[1] * v_kickroll.value;
346                 v_dmg_time = v_kicktime.value;
347         }
348 }
349
350 static cshift_t v_cshift;
351
352 /*
353 ==================
354 V_cshift_f
355 ==================
356 */
357 static void V_cshift_f(cmd_state_t *cmd)
358 {
359         v_cshift.destcolor[0] = atof(Cmd_Argv(cmd, 1));
360         v_cshift.destcolor[1] = atof(Cmd_Argv(cmd, 2));
361         v_cshift.destcolor[2] = atof(Cmd_Argv(cmd, 3));
362         v_cshift.percent = atof(Cmd_Argv(cmd, 4));
363 }
364
365
366 /*
367 ==================
368 V_BonusFlash_f
369
370 When you run over an item, the server sends this command
371 ==================
372 */
373 static void V_BonusFlash_f(cmd_state_t *cmd)
374 {
375         if(Cmd_Argc(cmd) == 1)
376         {
377                 cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
378                 cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
379                 cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
380                 cl.cshifts[CSHIFT_BONUS].percent = 50;
381                 cl.cshifts[CSHIFT_BONUS].alphafade = 100;
382         }
383         else if(Cmd_Argc(cmd) >= 4 && Cmd_Argc(cmd) <= 6)
384         {
385                 cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(cmd, 1)) * 255;
386                 cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(cmd, 2)) * 255;
387                 cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(cmd, 3)) * 255;
388                 if(Cmd_Argc(cmd) >= 5)
389                         cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(cmd, 4)) * 255; // yes, these are HEXADECIMAL percent ;)
390                 else
391                         cl.cshifts[CSHIFT_BONUS].percent = 50;
392                 if(Cmd_Argc(cmd) >= 6)
393                         cl.cshifts[CSHIFT_BONUS].alphafade = atof(Cmd_Argv(cmd, 5)) * 255;
394                 else
395                         cl.cshifts[CSHIFT_BONUS].alphafade = 100;
396         }
397         else
398                 Con_Printf("usage:\nbf, or bf R G B [A [alphafade]]\n");
399 }
400
401 /*
402 ==============================================================================
403
404                                                 VIEW RENDERING
405
406 ==============================================================================
407 */
408
409 extern matrix4x4_t viewmodelmatrix_nobob;
410 extern matrix4x4_t viewmodelmatrix_withbob;
411
412 #include "cl_collision.h"
413 #include "csprogs.h"
414
415 /*
416 ==================
417 V_CalcRefdef
418
419 ==================
420 */
421 #if 0
422 static vec3_t eyeboxmins = {-16, -16, -24};
423 static vec3_t eyeboxmaxs = { 16,  16,  32};
424 #endif
425
426 static vec_t lowpass(vec_t value, vec_t frac, vec_t *store)
427 {
428         frac = bound(0, frac, 1);
429         return (*store = *store * (1 - frac) + value * frac);
430 }
431
432 static vec_t lowpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store)
433 {
434         lowpass(value, frac, store);
435         return (*store = bound(value - limit, *store, value + limit));
436 }
437
438 static vec_t highpass(vec_t value, vec_t frac, vec_t *store)
439 {
440         return value - lowpass(value, frac, store);
441 }
442
443 static vec_t highpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store)
444 {
445         return value - lowpass_limited(value, frac, limit, store);
446 }
447
448 static void lowpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out)
449 {
450         out[0] = lowpass(value[0], fracx, &store[0]);
451         out[1] = lowpass(value[1], fracy, &store[1]);
452         out[2] = lowpass(value[2], fracz, &store[2]);
453 }
454
455 static void highpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out)
456 {
457         out[0] = highpass(value[0], fracx, &store[0]);
458         out[1] = highpass(value[1], fracy, &store[1]);
459         out[2] = highpass(value[2], fracz, &store[2]);
460 }
461
462 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)
463 {
464         out[0] = highpass_limited(value[0], fracx, limitx, &store[0]);
465         out[1] = highpass_limited(value[1], fracy, limity, &store[1]);
466         out[2] = highpass_limited(value[2], fracz, limitz, &store[2]);
467 }
468
469 /*
470  * State:
471  *   cl.bob2_smooth
472  *   cl.bobfall_speed
473  *   cl.bobfall_swing
474  *   cl.gunangles_adjustment_highpass
475  *   cl.gunangles_adjustment_lowpass
476  *   cl.gunangles_highpass
477  *   cl.gunangles_prev
478  *   cl.gunorg_adjustment_highpass
479  *   cl.gunorg_adjustment_lowpass
480  *   cl.gunorg_highpass
481  *   cl.gunorg_prev
482  *   cl.hitgroundtime
483  *   cl.lastongroundtime
484  *   cl.oldongrounbd
485  *   cl.stairsmoothtime
486  *   cl.stairsmoothz
487  *   cl.calcrefdef_prevtime
488  * Extra input:
489  *   cl.movecmd[0].time
490  *   cl.movevars_stepheight
491  *   cl.movevars_timescale
492  *   cl.oldtime
493  *   cl.punchangle
494  *   cl.punchvector
495  *   cl.qw_intermission_angles
496  *   cl.qw_intermission_origin
497  *   cl.qw_weaponkick
498  *   cls.protocol
499  *   cl.time
500  * Output:
501  *   cl.csqc_viewanglesfromengine
502  *   cl.csqc_viewmodelmatrixfromengine
503  *   cl.csqc_vieworiginfromengine
504  *   r_refdef.view.matrix
505  *   viewmodelmatrix_nobob
506  *   viewmodelmatrix_withbob
507  */
508 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)
509 {
510         float vieworg[3], viewangles[3], smoothtime;
511         float gunorg[3], gunangles[3];
512         matrix4x4_t tmpmatrix;
513         
514         static float viewheightavg;
515         float viewheight;       
516 #if 0
517 // begin of chase camera bounding box size for proper collisions by Alexander Zubov
518         vec3_t camboxmins = {-3, -3, -3};
519         vec3_t camboxmaxs = {3, 3, 3};
520 // end of chase camera bounding box size for proper collisions by Alexander Zubov
521 #endif
522         trace_t trace;
523
524         // react to clonground state changes (for gun bob)
525         if (clonground)
526         {
527                 if (!cl.oldonground)
528                         cl.hitgroundtime = cl.movecmd[0].time;
529                 cl.lastongroundtime = cl.movecmd[0].time;
530         }
531         cl.oldonground = clonground;
532         cl.calcrefdef_prevtime = max(cl.calcrefdef_prevtime, cl.oldtime);
533
534         VectorClear(gunangles);
535         VectorClear(gunorg);
536         viewmodelmatrix_nobob = identitymatrix;
537         viewmodelmatrix_withbob = identitymatrix;
538         r_refdef.view.matrix = identitymatrix;
539
540         // player can look around, so take the origin from the entity,
541         // and the angles from the input system
542         Matrix4x4_OriginFromMatrix(entrendermatrix, vieworg);
543         VectorCopy(clviewangles, viewangles);
544
545         // calculate how much time has passed since the last V_CalcRefdef
546         smoothtime = bound(0, cl.time - cl.stairsmoothtime, 0.1);
547         cl.stairsmoothtime = cl.time;
548
549         // fade damage flash
550         if (v_dmg_time > 0)
551                 v_dmg_time -= bound(0, smoothtime, 0.1);
552
553         if (clintermission)
554         {
555                 // entity is a fixed camera, just copy the matrix
556                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
557                         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);
558                 else
559                 {
560                         r_refdef.view.matrix = *entrendermatrix;
561                         Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, clstatsviewheight);
562                 }
563                 if (v_yshearing.value > 0)
564                         Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
565                 Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
566                 Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
567                 Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
568
569                 VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
570                 VectorCopy(viewangles, cl.csqc_viewanglesfromengine);
571
572                 Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
573                 Matrix4x4_CreateScale(&cl.csqc_viewmodelmatrixfromengine, cl_viewmodel_scale.value);
574         }
575         else
576         {
577                 // smooth stair stepping, but only if clonground and enabled
578                 if (!clonground || cl_stairsmoothspeed.value <= 0 || teleported)
579                         cl.stairsmoothz = vieworg[2];
580                 else
581                 {
582                         if (cl.stairsmoothz < vieworg[2])
583                                 vieworg[2] = cl.stairsmoothz = bound(vieworg[2] - cl.movevars_stepheight, cl.stairsmoothz + smoothtime * cl_stairsmoothspeed.value, vieworg[2]);
584                         else if (cl.stairsmoothz > vieworg[2])
585                                 vieworg[2] = cl.stairsmoothz = bound(vieworg[2], cl.stairsmoothz - smoothtime * cl_stairsmoothspeed.value, vieworg[2] + cl.movevars_stepheight);
586                 }
587
588                 // apply qw weapon recoil effect (this did not work in QW)
589                 // TODO: add a cvar to disable this
590                 viewangles[PITCH] += cl.qw_weaponkick;
591
592                 // apply the viewofs (even if chasecam is used)
593                 // Samual: Lets add smoothing for this too so that things like crouching are done with a transition.
594                 viewheight = bound(0, (cl.time - cl.calcrefdef_prevtime) / max(0.0001, cl_smoothviewheight.value), 1);
595                 viewheightavg = viewheightavg * (1 - viewheight) + clstatsviewheight * viewheight;
596                 vieworg[2] += viewheightavg;
597
598                 if (chase_active.value)
599                 {
600                         // observing entity from third person. Added "campitch" by Alexander "motorsep" Zubov
601                         vec_t camback, camup, dist, campitch, forward[3], chase_dest[3];
602
603                         camback = chase_back.value;
604                         camup = chase_up.value;
605                         campitch = chase_pitchangle.value;
606
607                         AngleVectors(viewangles, forward, NULL, NULL);
608
609                         if (chase_overhead.integer)
610                         {
611 #if 1
612                                 vec3_t offset;
613                                 vec3_t bestvieworg;
614 #endif
615                                 vec3_t up;
616                                 viewangles[PITCH] = 0;
617                                 AngleVectors(viewangles, forward, NULL, up);
618                                 // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
619                                 chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup;
620                                 chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup;
621                                 chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup;
622 #if 0
623 #if 1
624                                 //trace = CL_TraceLine(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
625                                 trace = CL_TraceLine(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
626 #else
627                                 //trace = CL_TraceBox(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
628                                 trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, true, false, NULL, false);
629 #endif
630                                 VectorCopy(trace.endpos, vieworg);
631                                 vieworg[2] -= 8;
632 #else
633                                 // trace from first person view location to our chosen third person view location
634 #if 1
635                                 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
636 #else
637                                 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);
638 #endif
639                                 VectorCopy(trace.endpos, bestvieworg);
640                                 offset[2] = 0;
641                                 for (offset[0] = -16;offset[0] <= 16;offset[0] += 8)
642                                 {
643                                         for (offset[1] = -16;offset[1] <= 16;offset[1] += 8)
644                                         {
645                                                 AngleVectors(viewangles, NULL, NULL, up);
646                                                 chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup + offset[0];
647                                                 chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup + offset[1];
648                                                 chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup + offset[2];
649 #if 1
650                                                 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
651 #else
652                                                 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);
653 #endif
654                                                 if (bestvieworg[2] > trace.endpos[2])
655                                                         bestvieworg[2] = trace.endpos[2];
656                                         }
657                                 }
658                                 bestvieworg[2] -= 8;
659                                 VectorCopy(bestvieworg, vieworg);
660 #endif
661                                 viewangles[PITCH] = campitch;
662                         }
663                         else
664                         {
665                                 if (gamemode == GAME_GOODVSBAD2 && chase_stevie.integer)
666                                 {
667                                         // look straight down from high above
668                                         viewangles[PITCH] = 90;
669                                         camback = 2048;
670                                         VectorSet(forward, 0, 0, -1);
671                                 }
672
673                                 // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
674                                 dist = -camback - 8;
675                                 chase_dest[0] = vieworg[0] + forward[0] * dist;
676                                 chase_dest[1] = vieworg[1] + forward[1] * dist;
677                                 chase_dest[2] = vieworg[2] + forward[2] * dist + camup;
678                                 trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
679                                 VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg);
680                         }
681                 }
682                 else
683                 {
684                         // first person view from entity
685                         // angles
686                         if (cldead && v_deathtilt.integer)
687                                 viewangles[ROLL] = v_deathtiltangle.value;
688
689                         // Hanicef: don't apply punchangle twice if the scene is rendered more than once.
690                         if (!cl_punchangle_applied)
691                         {
692                                 VectorAdd(viewangles, cl.punchangle, viewangles);
693                                 cl_punchangle_applied = 1;
694                         }
695                         viewangles[ROLL] += V_CalcRoll(clviewangles, clvelocity);
696
697                         if (v_dmg_time > 0)
698                         {
699                                 viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
700                                 viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
701                         }
702                         // origin
703                         VectorAdd(vieworg, cl.punchvector, vieworg);
704                         if (!cldead)
705                         {
706                                 double xyspeed, bob, bobfall;
707                                 double bobcycle = 0, cycle; // double-precision because cl.time can be a very large number, where float would get stuttery at high time values
708                                 vec_t frametime;
709
710                                 frametime = (cl.time - cl.calcrefdef_prevtime) * cl.movevars_timescale;
711
712                                 if(cl_followmodel.integer || cl_leanmodel.integer)
713                                 {
714                                         // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then
715                                         if(teleported)
716                                         {
717                                                 // try to fix the first highpass; result is NOT
718                                                 // perfect! TODO find a better fix
719                                                 VectorCopy(viewangles, cl.gunangles_prev);
720                                                 VectorCopy(vieworg, cl.gunorg_prev);
721                                         }
722
723                                         // 2. for the gun origin, only keep the high frequency (non-DC) parts, which is "somewhat like velocity"
724                                         VectorAdd(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass);
725                                         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);
726                                         VectorCopy(vieworg, cl.gunorg_prev);
727                                         VectorSubtract(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass);
728
729                                         // in the highpass, we _store_ the DIFFERENCE to the actual view angles...
730                                         VectorAdd(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass);
731                                         cl.gunangles_highpass[PITCH] += 360 * floor((viewangles[PITCH] - cl.gunangles_highpass[PITCH]) / 360 + 0.5);
732                                         cl.gunangles_highpass[YAW] += 360 * floor((viewangles[YAW] - cl.gunangles_highpass[YAW]) / 360 + 0.5);
733                                         cl.gunangles_highpass[ROLL] += 360 * floor((viewangles[ROLL] - cl.gunangles_highpass[ROLL]) / 360 + 0.5);
734                                         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);
735                                         VectorCopy(viewangles, cl.gunangles_prev);
736                                         VectorSubtract(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass);
737
738                                         // 3. calculate the RAW adjustment vectors
739                                         gunorg[0] *= -cl_followmodel_side_speed.value;
740                                         gunorg[1] *= -cl_followmodel_side_speed.value;
741                                         gunorg[2] *= -cl_followmodel_up_speed.value;
742
743                                         gunangles[PITCH] *= -cl_leanmodel_up_speed.value;
744                                         gunangles[YAW] *= -cl_leanmodel_side_speed.value;
745                                         gunangles[ROLL] = 0;
746
747                                         // 4. perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!)
748                                         //    trick: we must do the lowpass LAST, so the lowpass vector IS the final vector!
749                                         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);
750                                         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);
751                                         // we assume here: PITCH = 0, YAW = 1, ROLL = 2
752                                         highpass3(gunangles, frametime*cl_leanmodel_up_highpass.value, frametime*cl_leanmodel_side_highpass.value, 0, cl.gunangles_adjustment_highpass, gunangles);
753                                         lowpass3(gunangles, frametime*cl_leanmodel_up_lowpass.value, frametime*cl_leanmodel_side_lowpass.value, 0, cl.gunangles_adjustment_lowpass, gunangles);
754
755                                         // 5. use the adjusted vectors
756                                         VectorAdd(vieworg, gunorg, gunorg);
757                                         VectorAdd(viewangles, gunangles, gunangles);
758                                 }
759                                 else
760                                 {
761                                         // Just initialize gunorg/gunangles.
762                                         VectorCopy(vieworg, gunorg);
763                                         VectorCopy(viewangles, gunangles);
764                                 }
765
766                                 // bounded XY speed, used by several effects below
767                                 xyspeed = bound (0, sqrt(clvelocity[0]*clvelocity[0] + clvelocity[1]*clvelocity[1]), cl_bob_velocity_limit.value);
768
769                                 // vertical view bobbing code
770                                 if (cl_bob.value && cl_bobcycle.value)
771                                 {
772                                         float bob_limit = cl_bob_limit.value;
773
774                                         if (cl_bob_limit_heightcheck.integer)
775                                         {
776                                                 // use traces to determine what range the view can bob in, and scale down the bob as needed
777                                                 float trace1fraction;
778                                                 float trace2fraction;
779                                                 vec3_t bob_height_check_dest;
780
781                                                 // 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
782                                                 bob_height_check_dest[0] = vieworg[0];
783                                                 bob_height_check_dest[1] = vieworg[1];
784                                                 bob_height_check_dest[2] = vieworg[2] + cl_bob_limit.value * 1.1f;
785                                                 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);
786                                                 trace1fraction = trace.fraction;
787
788                                                 bob_height_check_dest[0] = vieworg[0];
789                                                 bob_height_check_dest[1] = vieworg[1];
790                                                 bob_height_check_dest[2] = vieworg[2] + cl_bob_limit.value * -0.5f;
791                                                 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);
792                                                 trace2fraction = trace.fraction;
793
794                                                 bob_limit *= min(trace1fraction, trace2fraction);
795                                         }
796
797                                         // LadyHavoc: this code is *weird*, but not replacable (I think it
798                                         // should be done in QC on the server, but oh well, quake is quake)
799                                         // LadyHavoc: figured out bobup: the time at which the sin is at 180
800                                         // degrees (which allows lengthening or squishing the peak or valley)
801                                         cycle = cl.time / cl_bobcycle.value;
802                                         cycle -= (int) cycle;
803                                         if (cycle < cl_bobup.value)
804                                                 bobcycle = cycle = sin(M_PI * cycle / cl_bobup.value);
805                                         else
806                                                 bobcycle = cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
807                                         // bob is proportional to velocity in the xy plane
808                                         // (don't count Z, or jumping messes it up)
809                                         bob = xyspeed * cl_bob.value;
810                                         bob = bob*0.3 + bob*0.7*cycle;
811                                         bob = bound(-7, bob, bob_limit);
812                                         vieworg[2] += bob;
813                                         // we also need to adjust gunorg, or this appears like pushing the gun!
814                                         // In the old code, this was applied to vieworg BEFORE copying to gunorg,
815                                         // but this is not viable with the new followmodel code as that would mean
816                                         // that followmodel would work on the munged-by-bob vieworg and do feedback
817                                         gunorg[2] += bob;
818                                 }
819
820                                 // horizontal view bobbing code
821                                 if (cl_bob2.value && cl_bob2cycle.value)
822                                 {
823                                         vec3_t bob2vel;
824                                         vec3_t forward, right, up;
825                                         float side, front;
826
827                                         cycle = cl.time / cl_bob2cycle.value;
828                                         cycle -= (int) cycle;
829                                         if (cycle < 0.5)
830                                                 cycle = cos(M_PI * cycle / 0.5); // cos looks better here with the other view bobbing using sin
831                                         else
832                                                 cycle = cos(M_PI + M_PI * (cycle-0.5)/0.5);
833                                         bob = cl_bob2.value * cycle;
834
835                                         // this value slowly decreases from 1 to 0 when we stop touching the ground.
836                                         // The cycle is later multiplied with it so the view smooths back to normal
837                                         if (clonground && !clcmdjump) // also block the effect while the jump button is pressed, to avoid twitches when bunny-hopping
838                                                 cl.bob2_smooth = 1;
839                                         else
840                                         {
841                                                 if(cl.bob2_smooth > 0)
842                                                         cl.bob2_smooth -= bound(0, cl_bob2smooth.value, 1);
843                                                 else
844                                                         cl.bob2_smooth = 0;
845                                         }
846
847                                         // calculate the front and side of the player between the X and Y axes
848                                         AngleVectors(viewangles, forward, right, up);
849                                         // now get the speed based on those angles. The bounds should match the same value as xyspeed's
850                                         side = bound(-cl_bob_velocity_limit.value, DotProduct (clvelocity, right) * cl.bob2_smooth, cl_bob_velocity_limit.value);
851                                         front = bound(-cl_bob_velocity_limit.value, DotProduct (clvelocity, forward) * cl.bob2_smooth, cl_bob_velocity_limit.value);
852                                         VectorScale(forward, bob, forward);
853                                         VectorScale(right, bob, right);
854                                         // we use side with forward and front with right, so the bobbing goes
855                                         // to the side when we walk forward and to the front when we strafe
856                                         VectorMAMAM(side, forward, front, right, 0, up, bob2vel);
857                                         vieworg[0] += bob2vel[0];
858                                         vieworg[1] += bob2vel[1];
859                                         // we also need to adjust gunorg, or this appears like pushing the gun!
860                                         // In the old code, this was applied to vieworg BEFORE copying to gunorg,
861                                         // but this is not viable with the new followmodel code as that would mean
862                                         // that followmodel would work on the munged-by-bob vieworg and do feedback
863                                         gunorg[0] += bob2vel[0];
864                                         gunorg[1] += bob2vel[1];
865                                 }
866
867                                 // fall bobbing code
868                                 // causes the view to swing down and back up when touching the ground
869                                 if (cl_bobfall.value && cl_bobfallcycle.value)
870                                 {
871                                         if (!clonground)
872                                         {
873                                                 cl.bobfall_speed = bound(-400, clvelocity[2], 0) * bound(0, cl_bobfall.value, 0.1);
874                                                 if (clvelocity[2] < -cl_bobfallminspeed.value)
875                                                         cl.bobfall_swing = 1;
876                                                 else
877                                                         cl.bobfall_swing = 0; // TODO really?
878                                         }
879                                         else
880                                         {
881                                                 cl.bobfall_swing = max(0, cl.bobfall_swing - cl_bobfallcycle.value * frametime);
882
883                                                 bobfall = sin(M_PI * cl.bobfall_swing) * cl.bobfall_speed;
884                                                 vieworg[2] += bobfall;
885                                                 gunorg[2] += bobfall;
886                                         }
887                                 }
888
889                                 // gun model bobbing code
890                                 if (cl_bobmodel.value)
891                                 {
892                                         // calculate for swinging gun model
893                                         // the gun bobs when running on the ground, but doesn't bob when you're in the air.
894                                         // Sajt: I tried to smooth out the transitions between bob and no bob, which works
895                                         // for the most part, but for some reason when you go through a message trigger or
896                                         // pick up an item or anything like that it will momentarily jolt the gun.
897                                         vec3_t forward, right, up;
898                                         float bspeed;
899                                         float s;
900                                         float t;
901
902                                         s = cl.time * cl_bobmodel_speed.value;
903                                         if (clonground)
904                                         {
905                                                 if (cl.time - cl.hitgroundtime < 0.2)
906                                                 {
907                                                         // just hit the ground, speed the bob back up over the next 0.2 seconds
908                                                         t = cl.time - cl.hitgroundtime;
909                                                         t = bound(0, t, 0.2);
910                                                         t *= 5;
911                                                 }
912                                                 else
913                                                         t = 1;
914                                         }
915                                         else
916                                         {
917                                                 // recently left the ground, slow the bob down over the next 0.2 seconds
918                                                 t = cl.time - cl.lastongroundtime;
919                                                 t = 0.2 - bound(0, t, 0.2);
920                                                 t *= 5;
921                                         }
922
923                                         bspeed = xyspeed * 0.01f;
924                                         AngleVectors (gunangles, forward, right, up);
925                                         bob = bspeed * cl_bobmodel_side.value * cl_viewmodel_scale.value * sin (s) * t;
926                                         VectorMA (gunorg, bob, right, gunorg);
927                                         bob = bspeed * cl_bobmodel_up.value * cl_viewmodel_scale.value * cos (s * 2) * t;
928                                         VectorMA (gunorg, bob, up, gunorg);
929                                         // Classic Quake bobbing
930                                         bob = (cl_bobmodel_classic.integer ? xyspeed * cl_bob.value * 0.25 * bobcycle : bspeed * cl_bobmodel_forward.value * cos(s * 2) * t) * cl_viewmodel_scale.value;
931                                         VectorMA (gunorg, (cl_bobmodel_classic.integer ? (bob > 1 ? 1 : bob) : bob), forward, gunorg);
932                                 }
933                         }
934                 }
935                 // calculate a view matrix for rendering the scene
936                 if (v_idlescale.value)
937                 {
938                         viewangles[0] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
939                         viewangles[1] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
940                         viewangles[2] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
941                 }
942                 Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2], 1);
943                 if (v_yshearing.value > 0)
944                         Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
945
946                 // calculate a viewmodel matrix for use in view-attached entities
947                 Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
948                 Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
949
950                 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix_withbob, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value);
951                 if (v_yshearing.value > 0)
952                         Matrix4x4_QuakeToDuke3D(&viewmodelmatrix_withbob, &viewmodelmatrix_withbob, v_yshearing.value);
953
954                 VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
955                 VectorCopy(viewangles, cl.csqc_viewanglesfromengine);
956
957                 Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
958                 Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob);
959         }
960
961         cl.calcrefdef_prevtime = cl.time;
962 }
963
964 void V_CalcRefdef (void)
965 {
966         entity_t *ent;
967         qboolean cldead;
968
969         if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.viewentity])
970         {
971                 // ent is the view entity (visible when out of body)
972                 ent = &cl.entities[cl.viewentity];
973
974                 cldead = (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && cl.stats[STAT_HEALTH] != -2342);
975                 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
976         }
977         else
978         {
979                 viewmodelmatrix_nobob = identitymatrix;
980                 viewmodelmatrix_withbob = identitymatrix;
981                 cl.csqc_viewmodelmatrixfromengine = identitymatrix;
982                 r_refdef.view.matrix = identitymatrix;
983                 VectorClear(cl.csqc_vieworiginfromengine);
984                 VectorCopy(cl.viewangles, cl.csqc_viewanglesfromengine);
985         }
986 }
987
988 void V_MakeViewIsometric(void)
989 {
990         // 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)
991         matrix4x4_t relative;
992         matrix4x4_t modifiedview;
993         matrix4x4_t modify;
994         vec3_t forward, left, up, org;
995         float t[4][4];
996
997         r_refdef.view.useperspective = false;
998         r_refdef.view.usevieworiginculling = !r_trippy.value && v_isometric_usevieworiginculling.integer;
999         r_refdef.view.frustum_y = v_isometric_verticalfov.value * cl.viewzoom;
1000         r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
1001         r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
1002         r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
1003         r_refdef.view.ortho_x = r_refdef.view.frustum_x; // used by VM_CL_R_SetView
1004         r_refdef.view.ortho_y = r_refdef.view.frustum_y; // used by VM_CL_R_SetView
1005
1006         t[0][0] = v_isometric_xx.value;
1007         t[0][1] = v_isometric_xy.value;
1008         t[0][2] = v_isometric_xz.value;
1009         t[0][3] = 0.0f;
1010         t[1][0] = v_isometric_yx.value;
1011         t[1][1] = v_isometric_yy.value;
1012         t[1][2] = v_isometric_yz.value;
1013         t[1][3] = 0.0f;
1014         t[2][0] = v_isometric_zx.value;
1015         t[2][1] = v_isometric_zy.value;
1016         t[2][2] = v_isometric_zz.value;
1017         t[2][3] = 0.0f;
1018         t[3][0] = 0.0f;
1019         t[3][1] = 0.0f;
1020         t[3][2] = 0.0f;
1021         t[3][3] = 1.0f;
1022         Matrix4x4_FromArrayFloatGL(&modify, t[0]);
1023
1024         // if the orientation is locked, extract the origin and create just a translate matrix to start with
1025         if (v_isometric_locked_orientation.integer)
1026         {
1027                 vec3_t vx, vy, vz, origin;
1028                 Matrix4x4_ToVectors(&r_refdef.view.matrix, vx, vy, vz, origin);
1029                 Matrix4x4_CreateTranslate(&r_refdef.view.matrix, origin[0], origin[1], origin[2]);
1030         }
1031
1032         Matrix4x4_Concat(&modifiedview, &r_refdef.view.matrix, &modify);
1033         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);
1034         Matrix4x4_Concat(&r_refdef.view.matrix, &modifiedview, &relative);
1035         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, org);
1036         VectorMAMAMAM(1.0f, org, v_isometric_relx.value, forward, v_isometric_rely.value, left, v_isometric_relz.value, up, org);
1037         Matrix4x4_FromVectors(&r_refdef.view.matrix, forward, left, up, org);
1038
1039         if (v_isometric_flipcullface.integer)
1040         {
1041                 int a = r_refdef.view.cullface_front;
1042                 r_refdef.view.cullface_front = r_refdef.view.cullface_back;
1043                 r_refdef.view.cullface_back = a;
1044         }
1045 }
1046
1047
1048 void V_FadeViewFlashs(void)
1049 {
1050         // don't flash if time steps backwards
1051         if (cl.time <= cl.oldtime)
1052                 return;
1053         // drop the damage value
1054         cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_DAMAGE].alphafade;
1055         if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
1056                 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
1057         // drop the bonus value
1058         cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_BONUS].alphafade;
1059         if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
1060                 cl.cshifts[CSHIFT_BONUS].percent = 0;
1061 }
1062
1063 void V_CalcViewBlend(void)
1064 {
1065         float a2;
1066         int j;
1067         r_refdef.viewblend[0] = 0;
1068         r_refdef.viewblend[1] = 0;
1069         r_refdef.viewblend[2] = 0;
1070         r_refdef.viewblend[3] = 0;
1071         r_refdef.frustumscale_x = 1;
1072         r_refdef.frustumscale_y = 1;
1073         if (cls.state == ca_connected && cls.signon == SIGNONS)
1074         {
1075                 // set contents color
1076                 int supercontents;
1077                 vec3_t vieworigin;
1078                 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin);
1079                 supercontents = CL_PointSuperContents(vieworigin);
1080                 if (supercontents & SUPERCONTENTS_LIQUIDSMASK)
1081                 {
1082                         r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
1083                         r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
1084                         if (supercontents & SUPERCONTENTS_LAVA)
1085                         {
1086                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255;
1087                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
1088                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
1089                         }
1090                         else if (supercontents & SUPERCONTENTS_SLIME)
1091                         {
1092                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
1093                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25;
1094                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5;
1095                         }
1096                         else
1097                         {
1098                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130;
1099                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
1100                                 cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50;
1101                         }
1102                         cl.cshifts[CSHIFT_CONTENTS].percent = 150 * 0.5;
1103                 }
1104                 else
1105                 {
1106                         cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
1107                         cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0;
1108                         cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
1109                         cl.cshifts[CSHIFT_CONTENTS].percent = 0;
1110                 }
1111
1112                 if (gamemode != GAME_TRANSFUSION)
1113                 {
1114                         if (cl.stats[STAT_ITEMS] & IT_QUAD)
1115                         {
1116                                 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
1117                                 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
1118                                 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
1119                                 cl.cshifts[CSHIFT_POWERUP].percent = 30;
1120                         }
1121                         else if (cl.stats[STAT_ITEMS] & IT_SUIT)
1122                         {
1123                                 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
1124                                 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
1125                                 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
1126                                 cl.cshifts[CSHIFT_POWERUP].percent = 20;
1127                         }
1128                         else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1129                         {
1130                                 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
1131                                 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
1132                                 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
1133                                 cl.cshifts[CSHIFT_POWERUP].percent = 100;
1134                         }
1135                         else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1136                         {
1137                                 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
1138                                 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
1139                                 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
1140                                 cl.cshifts[CSHIFT_POWERUP].percent = 30;
1141                         }
1142                         else
1143                                 cl.cshifts[CSHIFT_POWERUP].percent = 0;
1144                 }
1145
1146                 cl.cshifts[CSHIFT_VCSHIFT].destcolor[0] = v_cshift.destcolor[0];
1147                 cl.cshifts[CSHIFT_VCSHIFT].destcolor[1] = v_cshift.destcolor[1];
1148                 cl.cshifts[CSHIFT_VCSHIFT].destcolor[2] = v_cshift.destcolor[2];
1149                 cl.cshifts[CSHIFT_VCSHIFT].percent = v_cshift.percent;
1150
1151                 // LadyHavoc: fixed V_CalcBlend
1152                 for (j = 0;j < NUM_CSHIFTS;j++)
1153                 {
1154                         a2 = bound(0.0f, cl.cshifts[j].percent * (1.0f / 255.0f), 1.0f);
1155                         if (a2 > 0)
1156                         {
1157                                 VectorLerp(r_refdef.viewblend, a2, cl.cshifts[j].destcolor, r_refdef.viewblend);
1158                                 r_refdef.viewblend[3] = (1 - (1 - r_refdef.viewblend[3]) * (1 - a2)); // correct alpha multiply...  took a while to find it on the web
1159                         }
1160                 }
1161                 // saturate color (to avoid blending in black)
1162                 if (r_refdef.viewblend[3])
1163                 {
1164                         a2 = 1 / r_refdef.viewblend[3];
1165                         VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend);
1166                 }
1167                 r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0], 255.0f);
1168                 r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1], 255.0f);
1169                 r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2], 255.0f);
1170                 r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f);
1171                 if (vid.sRGB3D)
1172                 {
1173                         r_refdef.viewblend[0] = Image_LinearFloatFromsRGB(r_refdef.viewblend[0]);
1174                         r_refdef.viewblend[1] = Image_LinearFloatFromsRGB(r_refdef.viewblend[1]);
1175                         r_refdef.viewblend[2] = Image_LinearFloatFromsRGB(r_refdef.viewblend[2]);
1176                 }
1177                 else
1178                 {
1179                         r_refdef.viewblend[0] *= (1.0f/256.0f);
1180                         r_refdef.viewblend[1] *= (1.0f/256.0f);
1181                         r_refdef.viewblend[2] *= (1.0f/256.0f);
1182                 }
1183                 
1184                 // Samual: Ugly hack, I know. But it's the best we can do since
1185                 // there is no way to detect client states from the engine.
1186                 if (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && 
1187                         cl.stats[STAT_HEALTH] != -2342 && cl_deathfade.value > 0)
1188                 {
1189                         cl.deathfade += cl_deathfade.value * max(0.00001, cl.time - cl.oldtime);
1190                         cl.deathfade = bound(0.0f, cl.deathfade, 0.9f);
1191                 }
1192                 else
1193                         cl.deathfade = 0.0f;
1194
1195                 if(cl.deathfade > 0)
1196                 {
1197                         float a;
1198                         float deathfadevec[3] = {0.3f, 0.0f, 0.0f};
1199                         a = r_refdef.viewblend[3] + cl.deathfade - r_refdef.viewblend[3]*cl.deathfade;
1200                         if(a > 0)
1201                                 VectorMAM(r_refdef.viewblend[3] * (1 - cl.deathfade) / a, r_refdef.viewblend, cl.deathfade / a, deathfadevec, r_refdef.viewblend);
1202                         r_refdef.viewblend[3] = a;
1203                 }
1204         }
1205 }
1206
1207 //============================================================================
1208
1209 /*
1210 =============
1211 V_Init
1212 =============
1213 */
1214 void V_Init (void)
1215 {
1216         Cmd_AddCommand(CMD_CLIENT | CMD_CLIENT_FROM_SERVER, "v_cshift", V_cshift_f, "sets tint color of view");
1217         Cmd_AddCommand(CMD_CLIENT | CMD_CLIENT_FROM_SERVER, "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");
1218         Cmd_AddCommand(CMD_CLIENT, "centerview", V_StartPitchDrift_f, "gradually recenter view (stop looking up/down)");
1219
1220         Cvar_RegisterVariable (&v_centermove);
1221         Cvar_RegisterVariable (&v_centerspeed);
1222
1223         Cvar_RegisterVariable (&v_iyaw_cycle);
1224         Cvar_RegisterVariable (&v_iroll_cycle);
1225         Cvar_RegisterVariable (&v_ipitch_cycle);
1226         Cvar_RegisterVariable (&v_iyaw_level);
1227         Cvar_RegisterVariable (&v_iroll_level);
1228         Cvar_RegisterVariable (&v_ipitch_level);
1229
1230         Cvar_RegisterVariable(&v_isometric);
1231         Cvar_RegisterVariable(&v_isometric_verticalfov);
1232         Cvar_RegisterVariable(&v_isometric_xx);
1233         Cvar_RegisterVariable(&v_isometric_xy);
1234         Cvar_RegisterVariable(&v_isometric_xz);
1235         Cvar_RegisterVariable(&v_isometric_yx);
1236         Cvar_RegisterVariable(&v_isometric_yy);
1237         Cvar_RegisterVariable(&v_isometric_yz);
1238         Cvar_RegisterVariable(&v_isometric_zx);
1239         Cvar_RegisterVariable(&v_isometric_zy);
1240         Cvar_RegisterVariable(&v_isometric_zz);
1241         Cvar_RegisterVariable(&v_isometric_tx);
1242         Cvar_RegisterVariable(&v_isometric_ty);
1243         Cvar_RegisterVariable(&v_isometric_tz);
1244         Cvar_RegisterVariable(&v_isometric_rot_pitch);
1245         Cvar_RegisterVariable(&v_isometric_rot_yaw);
1246         Cvar_RegisterVariable(&v_isometric_rot_roll);
1247         Cvar_RegisterVariable(&v_isometric_relx);
1248         Cvar_RegisterVariable(&v_isometric_rely);
1249         Cvar_RegisterVariable(&v_isometric_relz);
1250         Cvar_RegisterVariable(&v_isometric_flipcullface);
1251         Cvar_RegisterVariable(&v_isometric_locked_orientation);
1252         Cvar_RegisterVariable(&v_isometric_usevieworiginculling);
1253
1254         Cvar_RegisterVariable (&v_idlescale);
1255         Cvar_RegisterVariable (&crosshair);
1256
1257         Cvar_RegisterVariable (&cl_rollspeed);
1258         Cvar_RegisterVariable (&cl_rollangle);
1259         Cvar_RegisterVariable (&cl_bob);
1260         Cvar_RegisterVariable (&cl_bobcycle);
1261         Cvar_RegisterVariable (&cl_bobup);
1262         Cvar_RegisterVariable (&cl_bob2);
1263         Cvar_RegisterVariable (&cl_bob2cycle);
1264         Cvar_RegisterVariable (&cl_bob2smooth);
1265         Cvar_RegisterVariable (&cl_bobfall);
1266         Cvar_RegisterVariable (&cl_bobfallcycle);
1267         Cvar_RegisterVariable (&cl_bobfallminspeed);
1268         Cvar_RegisterVariable (&cl_bobmodel);
1269         Cvar_RegisterVariable (&cl_bobmodel_side);
1270         Cvar_RegisterVariable (&cl_bobmodel_up);
1271         Cvar_RegisterVariable (&cl_bobmodel_forward);
1272         Cvar_RegisterVariable (&cl_bobmodel_classic);
1273         Cvar_RegisterVariable (&cl_bobmodel_speed);
1274         Cvar_RegisterVariable (&cl_bob_limit);
1275         Cvar_RegisterVariable (&cl_bob_limit_heightcheck);
1276         Cvar_RegisterVariable (&cl_bob_limit_heightcheck_dontcrosswatersurface);
1277         Cvar_RegisterVariable (&cl_bob_velocity_limit);
1278
1279         Cvar_RegisterVariable (&cl_leanmodel);
1280         Cvar_RegisterVariable (&cl_leanmodel_side_speed);
1281         Cvar_RegisterVariable (&cl_leanmodel_side_limit);
1282         Cvar_RegisterVariable (&cl_leanmodel_side_highpass1);
1283         Cvar_RegisterVariable (&cl_leanmodel_side_lowpass);
1284         Cvar_RegisterVariable (&cl_leanmodel_side_highpass);
1285         Cvar_RegisterVariable (&cl_leanmodel_up_speed);
1286         Cvar_RegisterVariable (&cl_leanmodel_up_limit);
1287         Cvar_RegisterVariable (&cl_leanmodel_up_highpass1);
1288         Cvar_RegisterVariable (&cl_leanmodel_up_lowpass);
1289         Cvar_RegisterVariable (&cl_leanmodel_up_highpass);
1290
1291         Cvar_RegisterVariable (&cl_followmodel);
1292         Cvar_RegisterVariable (&cl_followmodel_side_speed);
1293         Cvar_RegisterVariable (&cl_followmodel_side_limit);
1294         Cvar_RegisterVariable (&cl_followmodel_side_highpass1);
1295         Cvar_RegisterVariable (&cl_followmodel_side_lowpass);
1296         Cvar_RegisterVariable (&cl_followmodel_side_highpass);
1297         Cvar_RegisterVariable (&cl_followmodel_up_speed);
1298         Cvar_RegisterVariable (&cl_followmodel_up_limit);
1299         Cvar_RegisterVariable (&cl_followmodel_up_highpass1);
1300         Cvar_RegisterVariable (&cl_followmodel_up_lowpass);
1301         Cvar_RegisterVariable (&cl_followmodel_up_highpass);
1302
1303         Cvar_RegisterVariable (&cl_viewmodel_scale);
1304
1305         Cvar_RegisterVariable (&v_kicktime);
1306         Cvar_RegisterVariable (&v_kickroll);
1307         Cvar_RegisterVariable (&v_kickpitch);
1308
1309         Cvar_RegisterVariable (&cl_stairsmoothspeed);
1310         
1311         Cvar_RegisterVariable (&cl_smoothviewheight);
1312
1313         Cvar_RegisterVariable (&chase_back);
1314         Cvar_RegisterVariable (&chase_up);
1315         Cvar_RegisterVariable (&chase_active);
1316         Cvar_RegisterVariable (&chase_overhead);
1317         Cvar_RegisterVariable (&chase_pitchangle);
1318         Cvar_RegisterVariable (&chase_stevie);
1319
1320         Cvar_RegisterVariable (&v_deathtilt);
1321         Cvar_RegisterVariable (&v_deathtiltangle);
1322
1323         Cvar_RegisterVariable (&v_yshearing);
1324 }
1325