• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "r_local.h"
24 
25 /*
26 
27 The view is allowed to move slightly from it's true position for bobbing,
28 but if it exceeds 8 pixels linear distance (spherical, not box), the list of
29 entities sent from the server may not include everything in the pvs, especially
30 when crossing a water boudnary.
31 
32 */
33 
34 cvar_t	lcd_x = CVAR2("lcd_x", "0");	// FIXME: make this work sometime...
35 
36 cvar_t	cl_rollspeed = CVAR2("cl_rollspeed", "200");
37 cvar_t	cl_rollangle = CVAR2("cl_rollangle", "2.0");
38 
39 cvar_t	cl_bob = CVAR3("cl_bob","0.02", false);
40 cvar_t	cl_bobcycle = CVAR3("cl_bobcycle","0.6", false);
41 cvar_t	cl_bobup = CVAR3("cl_bobup","0.5", false);
42 
43 cvar_t	v_kicktime = CVAR3("v_kicktime", "0.5", false);
44 cvar_t	v_kickroll = CVAR3("v_kickroll", "0.6", false);
45 cvar_t	v_kickpitch = CVAR3("v_kickpitch", "0.6", false);
46 
47 cvar_t	v_iyaw_cycle = CVAR3("v_iyaw_cycle", "2", false);
48 cvar_t	v_iroll_cycle = CVAR3("v_iroll_cycle", "0.5", false);
49 cvar_t	v_ipitch_cycle = CVAR3("v_ipitch_cycle", "1", false);
50 cvar_t	v_iyaw_level = CVAR3("v_iyaw_level", "0.3", false);
51 cvar_t	v_iroll_level = CVAR3("v_iroll_level", "0.1", false);
52 cvar_t	v_ipitch_level = CVAR3("v_ipitch_level", "0.3", false);
53 
54 cvar_t	v_idlescale = CVAR3("v_idlescale", "0", false);
55 
56 cvar_t	crosshair = CVAR3("crosshair", "0", true);
57 cvar_t	crosshaircolor = CVAR3("crosshaircolor", "79", true);
58 
59 cvar_t  cl_crossx = CVAR3("cl_crossx", "0", true);
60 cvar_t  cl_crossy = CVAR3("cl_crossy", "0", true);
61 
62 #ifdef GLQUAKE
63 cvar_t	gl_cshiftpercent = CVAR3("gl_cshiftpercent", "100", false);
64 #endif
65 
66 cvar_t  v_contentblend = CVAR3("v_contentblend", "1", false);
67 
68 float	v_dmg_time, v_dmg_roll, v_dmg_pitch;
69 
70 extern	int			in_forward, in_forward2, in_back;
71 
72 frame_t		*view_frame;
73 player_state_t		*view_message;
74 
75 /*
76 ===============
77 V_CalcRoll
78 
79 ===============
80 */
V_CalcRoll(vec3_t angles,vec3_t velocity)81 float V_CalcRoll (vec3_t angles, vec3_t velocity)
82 {
83 	vec3_t	forward, right, up;
84 	float	sign;
85 	float	side;
86 	float	value;
87 
88 	AngleVectors (angles, forward, right, up);
89 	side = DotProduct (velocity, right);
90 	sign = side < 0 ? -1 : 1;
91 	side = fabs(side);
92 
93 	value = cl_rollangle.value;
94 
95 	if (side < cl_rollspeed.value)
96 		side = side * value / cl_rollspeed.value;
97 	else
98 		side = value;
99 
100 	return side*sign;
101 
102 }
103 
104 
105 /*
106 ===============
107 V_CalcBob
108 
109 ===============
110 */
V_CalcBob(void)111 float V_CalcBob (void)
112 {
113 	static	double	bobtime;
114 	static float	bob;
115 	float	cycle;
116 
117 	if (cl.spectator)
118 		return 0;
119 
120 	if (onground == -1)
121 		return bob;		// just use old value
122 
123 	bobtime += host_frametime;
124 	cycle = bobtime - (int)(bobtime/cl_bobcycle.value)*cl_bobcycle.value;
125 	cycle /= cl_bobcycle.value;
126 	if (cycle < cl_bobup.value)
127 		cycle = M_PI * cycle / cl_bobup.value;
128 	else
129 		cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
130 
131 // bob is proportional to simulated velocity in the xy plane
132 // (don't count Z, or jumping messes it up)
133 
134 	bob = sqrt(cl.simvel[0]*cl.simvel[0] + cl.simvel[1]*cl.simvel[1]) * cl_bob.value;
135 	bob = bob*0.3 + bob*0.7*sin(cycle);
136 	if (bob > 4)
137 		bob = 4;
138 	else if (bob < -7)
139 		bob = -7;
140 	return bob;
141 
142 }
143 
144 
145 //=============================================================================
146 
147 
148 cvar_t	v_centermove = CVAR3("v_centermove", "0.15", false);
149 cvar_t	v_centerspeed = CVAR2("v_centerspeed","500");
150 
151 
V_StartPitchDrift(void)152 void V_StartPitchDrift (void)
153 {
154 #if 1
155 	if (cl.laststop == cl.time)
156 	{
157 		return;		// something else is keeping it from drifting
158 	}
159 #endif
160 	if (cl.nodrift || !cl.pitchvel)
161 	{
162 		cl.pitchvel = v_centerspeed.value;
163 		cl.nodrift = false;
164 		cl.driftmove = 0;
165 	}
166 }
167 
V_StopPitchDrift(void)168 void V_StopPitchDrift (void)
169 {
170 	cl.laststop = cl.time;
171 	cl.nodrift = true;
172 	cl.pitchvel = 0;
173 }
174 
175 /*
176 ===============
177 V_DriftPitch
178 
179 Moves the client pitch angle towards cl.idealpitch sent by the server.
180 
181 If the user is adjusting pitch manually, either with lookup/lookdown,
182 mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
183 
184 Drifting is enabled when the center view key is hit, mlook is released and
185 lookspring is non 0, or when
186 ===============
187 */
V_DriftPitch(void)188 void V_DriftPitch (void)
189 {
190 	float		delta, move;
191 
192 	if (view_message->onground == -1 || cls.demoplayback )
193 	{
194 		cl.driftmove = 0;
195 		cl.pitchvel = 0;
196 		return;
197 	}
198 
199 // don't count small mouse motion
200 	if (cl.nodrift)
201 	{
202 		if ( fabs(cl.frames[(cls.netchan.outgoing_sequence-1)&UPDATE_MASK].cmd.forwardmove) < 200)
203 			cl.driftmove = 0;
204 		else
205 			cl.driftmove += host_frametime;
206 
207 		if ( cl.driftmove > v_centermove.value)
208 		{
209 			V_StartPitchDrift ();
210 		}
211 		return;
212 	}
213 
214 	delta = 0 - cl.viewangles[PITCH];
215 
216 	if (!delta)
217 	{
218 		cl.pitchvel = 0;
219 		return;
220 	}
221 
222 	move = host_frametime * cl.pitchvel;
223 	cl.pitchvel += host_frametime * v_centerspeed.value;
224 
225 //Con_Printf ("move: %f (%f)\n", move, host_frametime);
226 
227 	if (delta > 0)
228 	{
229 		if (move > delta)
230 		{
231 			cl.pitchvel = 0;
232 			move = delta;
233 		}
234 		cl.viewangles[PITCH] += move;
235 	}
236 	else if (delta < 0)
237 	{
238 		if (move > -delta)
239 		{
240 			cl.pitchvel = 0;
241 			move = -delta;
242 		}
243 		cl.viewangles[PITCH] -= move;
244 	}
245 }
246 
247 
248 
249 
250 
251 /*
252 ==============================================================================
253 
254 						PALETTE FLASHES
255 
256 ==============================================================================
257 */
258 
259 
260 cshift_t	cshift_empty = { {130,80,50}, 0 };
261 cshift_t	cshift_water = { {130,80,50}, 128 };
262 cshift_t	cshift_slime = { {0,25,5}, 150 };
263 cshift_t	cshift_lava = { {255,80,0}, 150 };
264 
265 cvar_t		v_gamma = CVAR3("gamma", "1", true);
266 
267 byte		gammatable[256];	// palette is sent through this
268 
269 
270 #ifdef	GLQUAKE
271 byte		ramps[3][256];
272 float		v_blend[4];		// rgba 0.0 - 1.0
273 #endif	// GLQUAKE
274 
BuildGammaTable(float g)275 void BuildGammaTable (float g)
276 {
277 	int		i, inf;
278 
279 	if (g == 1.0)
280 	{
281 		for (i=0 ; i<256 ; i++)
282 			gammatable[i] = i;
283 		return;
284 	}
285 
286 	for (i=0 ; i<256 ; i++)
287 	{
288 		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
289 		if (inf < 0)
290 			inf = 0;
291 		if (inf > 255)
292 			inf = 255;
293 		gammatable[i] = inf;
294 	}
295 }
296 
297 /*
298 =================
299 V_CheckGamma
300 =================
301 */
V_CheckGamma(void)302 qboolean V_CheckGamma (void)
303 {
304 	static float oldgammavalue;
305 
306 	if (v_gamma.value == oldgammavalue)
307 		return false;
308 	oldgammavalue = v_gamma.value;
309 
310 	BuildGammaTable (v_gamma.value);
311 	vid.recalc_refdef = 1;				// force a surface cache flush
312 
313 	return true;
314 }
315 
316 
317 
318 /*
319 ===============
320 V_ParseDamage
321 ===============
322 */
V_ParseDamage(void)323 void V_ParseDamage (void)
324 {
325 	int		armor, blood;
326 	vec3_t	from;
327 	int		i;
328 	vec3_t	forward, right, up;
329 	float	side;
330 	float	count;
331 
332 	armor = MSG_ReadByte ();
333 	blood = MSG_ReadByte ();
334 	for (i=0 ; i<3 ; i++)
335 		from[i] = MSG_ReadCoord ();
336 
337 	count = blood*0.5 + armor*0.5;
338 	if (count < 10)
339 		count = 10;
340 
341 	cl.faceanimtime = cl.time + 0.2;		// but sbar face into pain frame
342 
343 	cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
344 	if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
345 		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
346 	if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
347 		cl.cshifts[CSHIFT_DAMAGE].percent = 150;
348 
349 	if (armor > blood)
350 	{
351 		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
352 		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
353 		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
354 	}
355 	else if (armor)
356 	{
357 		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
358 		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
359 		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
360 	}
361 	else
362 	{
363 		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
364 		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
365 		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
366 	}
367 
368 //
369 // calculate view angle kicks
370 //
371 	VectorSubtract (from, cl.simorg, from);
372 	VectorNormalize (from);
373 
374 	AngleVectors (cl.simangles, forward, right, up);
375 
376 	side = DotProduct (from, right);
377 	v_dmg_roll = count*side*v_kickroll.value;
378 
379 	side = DotProduct (from, forward);
380 	v_dmg_pitch = count*side*v_kickpitch.value;
381 
382 	v_dmg_time = v_kicktime.value;
383 }
384 
385 
386 /*
387 ==================
388 V_cshift_f
389 ==================
390 */
V_cshift_f(void)391 void V_cshift_f (void)
392 {
393 	cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
394 	cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
395 	cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
396 	cshift_empty.percent = atoi(Cmd_Argv(4));
397 }
398 
399 
400 /*
401 ==================
402 V_BonusFlash_f
403 
404 When you run over an item, the server sends this command
405 ==================
406 */
V_BonusFlash_f(void)407 void V_BonusFlash_f (void)
408 {
409 	cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
410 	cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
411 	cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
412 	cl.cshifts[CSHIFT_BONUS].percent = 50;
413 }
414 
415 /*
416 =============
417 V_SetContentsColor
418 
419 Underwater, lava, etc each has a color shift
420 =============
421 */
V_SetContentsColor(int contents)422 void V_SetContentsColor (int contents)
423 {
424 	if (!v_contentblend.value) {
425 		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
426 		return;
427 	}
428 
429 	switch (contents)
430 	{
431 	case CONTENTS_EMPTY:
432 		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
433 		break;
434 	case CONTENTS_LAVA:
435 		cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
436 		break;
437 	case CONTENTS_SOLID:
438 	case CONTENTS_SLIME:
439 		cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
440 		break;
441 	default:
442 		cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
443 	}
444 }
445 
446 /*
447 =============
448 V_CalcPowerupCshift
449 =============
450 */
V_CalcPowerupCshift(void)451 void V_CalcPowerupCshift (void)
452 {
453 	if (cl.stats[STAT_ITEMS] & IT_QUAD)
454 	{
455 		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
456 		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
457 		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
458 		cl.cshifts[CSHIFT_POWERUP].percent = 30;
459 	}
460 	else if (cl.stats[STAT_ITEMS] & IT_SUIT)
461 	{
462 		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
463 		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
464 		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
465 		cl.cshifts[CSHIFT_POWERUP].percent = 20;
466 	}
467 	else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
468 	{
469 		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
470 		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
471 		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
472 		cl.cshifts[CSHIFT_POWERUP].percent = 100;
473 	}
474 	else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
475 	{
476 		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
477 		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
478 		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
479 		cl.cshifts[CSHIFT_POWERUP].percent = 30;
480 	}
481 	else
482 		cl.cshifts[CSHIFT_POWERUP].percent = 0;
483 }
484 
485 
486 /*
487 =============
488 V_CalcBlend
489 =============
490 */
491 #ifdef	GLQUAKE
V_CalcBlend(void)492 void V_CalcBlend (void)
493 {
494 	float	r, g, b, a, a2;
495 	int		j;
496 
497 	r = 0;
498 	g = 0;
499 	b = 0;
500 	a = 0;
501 
502 	for (j=0 ; j<NUM_CSHIFTS ; j++)
503 	{
504 		if (!gl_cshiftpercent.value)
505 			continue;
506 
507 		a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
508 
509 //		a2 = (cl.cshifts[j].percent/2)/255.0;
510 		if (!a2)
511 			continue;
512 		a = a + a2*(1-a);
513 //Con_Printf ("j:%i a:%f\n", j, a);
514 		a2 = a2/a;
515 		r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
516 		g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
517 		b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
518 	}
519 
520 	v_blend[0] = r/255.0;
521 	v_blend[1] = g/255.0;
522 	v_blend[2] = b/255.0;
523 	v_blend[3] = a;
524 	if (v_blend[3] > 1)
525 		v_blend[3] = 1;
526 	if (v_blend[3] < 0)
527 		v_blend[3] = 0;
528 }
529 #endif
530 
531 /*
532 =============
533 V_UpdatePalette
534 =============
535 */
536 #ifdef	GLQUAKE
V_UpdatePalette(void)537 void V_UpdatePalette (void)
538 {
539 	int		i, j;
540 	qboolean	new;
541 	byte	*basepal, *newpal;
542 	byte	pal[768];
543 	float	r,g,b,a;
544 	int		ir, ig, ib;
545 	qboolean force;
546 
547 	V_CalcPowerupCshift ();
548 
549 	new = false;
550 
551 	for (i=0 ; i<NUM_CSHIFTS ; i++)
552 	{
553 		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
554 		{
555 			new = true;
556 			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
557 		}
558 		for (j=0 ; j<3 ; j++)
559 			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
560 			{
561 				new = true;
562 				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
563 			}
564 	}
565 
566 // drop the damage value
567 	cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
568 	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
569 		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
570 
571 // drop the bonus value
572 	cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
573 	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
574 		cl.cshifts[CSHIFT_BONUS].percent = 0;
575 
576 	force = V_CheckGamma ();
577 	if (!new && !force)
578 		return;
579 
580 	V_CalcBlend ();
581 
582 //Con_Printf("b: %4.2f %4.2f %4.2f %4.6f\n", v_blend[0],	v_blend[1],	v_blend[2],	v_blend[3]);
583 
584 	a = v_blend[3];
585 	r = 255*v_blend[0]*a;
586 	g = 255*v_blend[1]*a;
587 	b = 255*v_blend[2]*a;
588 
589 	a = 1-a;
590 	for (i=0 ; i<256 ; i++)
591 	{
592 		ir = i*a + r;
593 		ig = i*a + g;
594 		ib = i*a + b;
595 		if (ir > 255)
596 			ir = 255;
597 		if (ig > 255)
598 			ig = 255;
599 		if (ib > 255)
600 			ib = 255;
601 
602 		ramps[0][i] = gammatable[ir];
603 		ramps[1][i] = gammatable[ig];
604 		ramps[2][i] = gammatable[ib];
605 	}
606 
607 	basepal = host_basepal;
608 	newpal = pal;
609 
610 	for (i=0 ; i<256 ; i++)
611 	{
612 		ir = basepal[0];
613 		ig = basepal[1];
614 		ib = basepal[2];
615 		basepal += 3;
616 
617 		newpal[0] = ramps[0][ir];
618 		newpal[1] = ramps[1][ig];
619 		newpal[2] = ramps[2][ib];
620 		newpal += 3;
621 	}
622 
623 	VID_ShiftPalette (pal);
624 }
625 #else	// !GLQUAKE
626 /*
627 =============
628 V_UpdatePalette
629 =============
630 */
V_UpdatePalette(void)631 void V_UpdatePalette (void)
632 {
633 	int		i, j;
634 	qboolean	new;
635 	byte	*basepal, *newpal;
636 	byte	pal[768];
637 	int		r,g,b;
638 	qboolean force;
639 
640 	V_CalcPowerupCshift ();
641 
642 	new = false;
643 
644 	for (i=0 ; i<NUM_CSHIFTS ; i++)
645 	{
646 		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
647 		{
648 			new = true;
649 			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
650 		}
651 		for (j=0 ; j<3 ; j++)
652 			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
653 			{
654 				new = true;
655 				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
656 			}
657 	}
658 
659 // drop the damage value
660 	cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
661 	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
662 		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
663 
664 // drop the bonus value
665 	cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
666 	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
667 		cl.cshifts[CSHIFT_BONUS].percent = 0;
668 
669 	force = V_CheckGamma ();
670 	if (!new && !force)
671 		return;
672 
673 	basepal = host_basepal;
674 	newpal = pal;
675 
676 	for (i=0 ; i<256 ; i++)
677 	{
678 		r = basepal[0];
679 		g = basepal[1];
680 		b = basepal[2];
681 		basepal += 3;
682 
683 		for (j=0 ; j<NUM_CSHIFTS ; j++)
684 		{
685 			r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
686 			g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
687 			b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
688 		}
689 
690 		newpal[0] = gammatable[r];
691 		newpal[1] = gammatable[g];
692 		newpal[2] = gammatable[b];
693 		newpal += 3;
694 	}
695 
696 	VID_ShiftPalette (pal);
697 }
698 
699 #endif	// !GLQUAKE
700 
701 /*
702 ==============================================================================
703 
704 						VIEW RENDERING
705 
706 ==============================================================================
707 */
708 
angledelta(float a)709 float angledelta (float a)
710 {
711 	a = anglemod(a);
712 	if (a > 180)
713 		a -= 360;
714 	return a;
715 }
716 
717 /*
718 ==================
719 CalcGunAngle
720 ==================
721 */
CalcGunAngle(void)722 void CalcGunAngle (void)
723 {
724 	float	yaw, pitch, move;
725 	static float oldyaw = 0;
726 	static float oldpitch = 0;
727 
728 	yaw = r_refdef.viewangles[YAW];
729 	pitch = -r_refdef.viewangles[PITCH];
730 
731 	yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
732 	if (yaw > 10)
733 		yaw = 10;
734 	if (yaw < -10)
735 		yaw = -10;
736 	pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
737 	if (pitch > 10)
738 		pitch = 10;
739 	if (pitch < -10)
740 		pitch = -10;
741 	move = host_frametime*20;
742 	if (yaw > oldyaw)
743 	{
744 		if (oldyaw + move < yaw)
745 			yaw = oldyaw + move;
746 	}
747 	else
748 	{
749 		if (oldyaw - move > yaw)
750 			yaw = oldyaw - move;
751 	}
752 
753 	if (pitch > oldpitch)
754 	{
755 		if (oldpitch + move < pitch)
756 			pitch = oldpitch + move;
757 	}
758 	else
759 	{
760 		if (oldpitch - move > pitch)
761 			pitch = oldpitch - move;
762 	}
763 
764 	oldyaw = yaw;
765 	oldpitch = pitch;
766 
767 	cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
768 	cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
769 }
770 
771 /*
772 ==============
773 V_BoundOffsets
774 ==============
775 */
V_BoundOffsets(void)776 void V_BoundOffsets (void)
777 {
778 // absolutely bound refresh reletive to entity clipping hull
779 // so the view can never be inside a solid wall
780 
781 	if (r_refdef.vieworg[0] < cl.simorg[0] - 14)
782 		r_refdef.vieworg[0] = cl.simorg[0] - 14;
783 	else if (r_refdef.vieworg[0] > cl.simorg[0] + 14)
784 		r_refdef.vieworg[0] = cl.simorg[0] + 14;
785 	if (r_refdef.vieworg[1] < cl.simorg[1] - 14)
786 		r_refdef.vieworg[1] = cl.simorg[1] - 14;
787 	else if (r_refdef.vieworg[1] > cl.simorg[1] + 14)
788 		r_refdef.vieworg[1] = cl.simorg[1] + 14;
789 	if (r_refdef.vieworg[2] < cl.simorg[2] - 22)
790 		r_refdef.vieworg[2] = cl.simorg[2] - 22;
791 	else if (r_refdef.vieworg[2] > cl.simorg[2] + 30)
792 		r_refdef.vieworg[2] = cl.simorg[2] + 30;
793 }
794 
795 /*
796 ==============
797 V_AddIdle
798 
799 Idle swaying
800 ==============
801 */
V_AddIdle(void)802 void V_AddIdle (void)
803 {
804 	r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
805 	r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
806 	r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
807 
808 	cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
809 	cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
810 	cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
811 }
812 
813 
814 /*
815 ==============
816 V_CalcViewRoll
817 
818 Roll is induced by movement and damage
819 ==============
820 */
V_CalcViewRoll(void)821 void V_CalcViewRoll (void)
822 {
823 	float		side;
824 
825 	side = V_CalcRoll (cl.simangles, cl.simvel);
826 	r_refdef.viewangles[ROLL] += side;
827 
828 	if (v_dmg_time > 0)
829 	{
830 		r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
831 		r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
832 		v_dmg_time -= host_frametime;
833 	}
834 
835 }
836 
837 
838 /*
839 ==================
840 V_CalcIntermissionRefdef
841 
842 ==================
843 */
V_CalcIntermissionRefdef(void)844 void V_CalcIntermissionRefdef (void)
845 {
846 	entity_t	*view;
847 	float		old;
848 
849 // view is the weapon model
850 	view = &cl.viewent;
851 
852 	VectorCopy (cl.simorg, r_refdef.vieworg);
853 	VectorCopy (cl.simangles, r_refdef.viewangles);
854 	view->model = NULL;
855 
856 // allways idle in intermission
857 	old = v_idlescale.value;
858 	v_idlescale.value = 1;
859 	V_AddIdle ();
860 	v_idlescale.value = old;
861 }
862 
863 /*
864 ==================
865 V_CalcRefdef
866 
867 ==================
868 */
V_CalcRefdef(void)869 void V_CalcRefdef (void)
870 {
871 	entity_t	*view;
872 	int			i;
873 	vec3_t		forward, right, up;
874 	float		bob;
875 	static float oldz = 0;
876 
877 	V_DriftPitch ();
878 
879 // view is the weapon model (only visible from inside body)
880 	view = &cl.viewent;
881 
882 	bob = V_CalcBob ();
883 
884 // refresh position from simulated origin
885 	VectorCopy (cl.simorg, r_refdef.vieworg);
886 
887 	r_refdef.vieworg[2] += bob;
888 
889 // never let it sit exactly on a node line, because a water plane can
890 // dissapear when viewed with the eye exactly on it.
891 // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
892 	r_refdef.vieworg[0] += 1.0/16;
893 	r_refdef.vieworg[1] += 1.0/16;
894 	r_refdef.vieworg[2] += 1.0/16;
895 
896 	VectorCopy (cl.simangles, r_refdef.viewangles);
897 	V_CalcViewRoll ();
898 	V_AddIdle ();
899 
900 	if (view_message->flags & PF_GIB)
901 		r_refdef.vieworg[2] += 8;	// gib view height
902 	else if (view_message->flags & PF_DEAD)
903 		r_refdef.vieworg[2] -= 16;	// corpse view height
904 	else
905 		r_refdef.vieworg[2] += 22;	// view height
906 
907 	if (view_message->flags & PF_DEAD)		// PF_GIB will also set PF_DEAD
908 		r_refdef.viewangles[ROLL] = 80;	// dead view angle
909 
910 
911 // offsets
912 	AngleVectors (cl.simangles, forward, right, up);
913 
914 // set up gun position
915 	VectorCopy (cl.simangles, view->angles);
916 
917 	CalcGunAngle ();
918 
919 	VectorCopy (cl.simorg, view->origin);
920 	view->origin[2] += 22;
921 
922 	for (i=0 ; i<3 ; i++)
923 	{
924 		view->origin[i] += forward[i]*bob*0.4;
925 //		view->origin[i] += right[i]*bob*0.4;
926 //		view->origin[i] += up[i]*bob*0.8;
927 	}
928 	view->origin[2] += bob;
929 
930 // fudge position around to keep amount of weapon visible
931 // roughly equal with different FOV
932 	if (scr_viewsize.value == 110)
933 		view->origin[2] += 1;
934 	else if (scr_viewsize.value == 100)
935 		view->origin[2] += 2;
936 	else if (scr_viewsize.value == 90)
937 		view->origin[2] += 1;
938 	else if (scr_viewsize.value == 80)
939 		view->origin[2] += 0.5;
940 
941 	if (view_message->flags & (PF_GIB|PF_DEAD) )
942  		view->model = NULL;
943  	else
944 		view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
945 	view->frame = view_message->weaponframe;
946 	view->colormap = vid.colormap;
947 
948 // set up the refresh position
949 	r_refdef.viewangles[PITCH] += cl.punchangle;
950 
951 // smooth out stair step ups
952 	if ( (view_message->onground != -1) && (cl.simorg[2] - oldz > 0) )
953 	{
954 		float steptime;
955 
956 		steptime = host_frametime;
957 
958 		oldz += steptime * 80;
959 		if (oldz > cl.simorg[2])
960 			oldz = cl.simorg[2];
961 		if (cl.simorg[2] - oldz > 12)
962 			oldz = cl.simorg[2] - 12;
963 		r_refdef.vieworg[2] += oldz - cl.simorg[2];
964 		view->origin[2] += oldz - cl.simorg[2];
965 	}
966 	else
967 		oldz = cl.simorg[2];
968 }
969 
970 /*
971 =============
972 DropPunchAngle
973 =============
974 */
DropPunchAngle(void)975 void DropPunchAngle (void)
976 {
977 	cl.punchangle -= 10*host_frametime;
978 	if (cl.punchangle < 0)
979 		cl.punchangle = 0;
980 }
981 
982 /*
983 ==================
984 V_RenderView
985 
986 The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
987 the entity origin, so any view position inside that will be valid
988 ==================
989 */
990 extern vrect_t scr_vrect;
991 
V_RenderView(void)992 void V_RenderView (void)
993 {
994 //	if (cl.simangles[ROLL])
995 //		Sys_Error ("cl.simangles[ROLL]");	// DEBUG
996 cl.simangles[ROLL] = 0;	// FIXME @@@
997 
998 	if (cls.state != ca_active)
999 		return;
1000 
1001 	view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
1002 	view_message = &view_frame->playerstate[cl.playernum];
1003 
1004 	DropPunchAngle ();
1005 	if (cl.intermission)
1006 	{	// intermission / finale rendering
1007 		V_CalcIntermissionRefdef ();
1008 	}
1009 	else
1010 	{
1011 		V_CalcRefdef ();
1012 	}
1013 
1014 	R_PushDlights ();
1015 	R_RenderView ();
1016 
1017 #ifndef GLQUAKE
1018 	if (crosshair.value)
1019 		Draw_Crosshair();
1020 #endif
1021 
1022 }
1023 
1024 //============================================================================
1025 
1026 /*
1027 =============
1028 V_Init
1029 =============
1030 */
V_Init(void)1031 void V_Init (void)
1032 {
1033 	Cmd_AddCommand ("v_cshift", V_cshift_f);
1034 	Cmd_AddCommand ("bf", V_BonusFlash_f);
1035 	Cmd_AddCommand ("centerview", V_StartPitchDrift);
1036 
1037 	Cvar_RegisterVariable (&v_centermove);
1038 	Cvar_RegisterVariable (&v_centerspeed);
1039 
1040 	Cvar_RegisterVariable (&v_iyaw_cycle);
1041 	Cvar_RegisterVariable (&v_iroll_cycle);
1042 	Cvar_RegisterVariable (&v_ipitch_cycle);
1043 	Cvar_RegisterVariable (&v_iyaw_level);
1044 	Cvar_RegisterVariable (&v_iroll_level);
1045 	Cvar_RegisterVariable (&v_ipitch_level);
1046 
1047 	Cvar_RegisterVariable (&v_contentblend);
1048 
1049 	Cvar_RegisterVariable (&v_idlescale);
1050 	Cvar_RegisterVariable (&crosshaircolor);
1051 	Cvar_RegisterVariable (&crosshair);
1052 	Cvar_RegisterVariable (&cl_crossx);
1053 	Cvar_RegisterVariable (&cl_crossy);
1054 #ifdef GLQUAKE
1055 	Cvar_RegisterVariable (&gl_cshiftpercent);
1056 #endif
1057 
1058 	Cvar_RegisterVariable (&cl_rollspeed);
1059 	Cvar_RegisterVariable (&cl_rollangle);
1060 	Cvar_RegisterVariable (&cl_bob);
1061 	Cvar_RegisterVariable (&cl_bobcycle);
1062 	Cvar_RegisterVariable (&cl_bobup);
1063 
1064 	Cvar_RegisterVariable (&v_kicktime);
1065 	Cvar_RegisterVariable (&v_kickroll);
1066 	Cvar_RegisterVariable (&v_kickpitch);
1067 
1068 	BuildGammaTable (1.0);	// no gamma yet
1069 	Cvar_RegisterVariable (&v_gamma);
1070 }
1071 
1072 
1073