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