git-svn-id: http://bladebattles.com/kurok/SVN@11 20cd92bb-ff49-0410-b73e-96a06e42c3b9
[kurok.git] / view.c
blob7a00a82a47319d83036effa5c2a7c1ce9f73d96d
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // view.c -- player eye positioning
22 #include "quakedef.h"
23 #include "r_local.h"
24 #include <pspctrl.h>
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.
34 cvar_t lcd_x = {"lcd_x","0"};
35 cvar_t lcd_yaw = {"lcd_yaw","0"};
37 cvar_t scr_ofsx = {"scr_ofsx","0", false};
38 cvar_t scr_ofsy = {"scr_ofsy","0", false};
39 cvar_t scr_ofsz = {"scr_ofsz","0", false};
41 cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
42 cvar_t cl_rollangle = {"cl_rollangle", "3.0"};
44 cvar_t cl_bob = {"cl_bob","0.02", true};
45 cvar_t cl_bobcycle = {"cl_bobcycle","0.45", true};
46 cvar_t cl_bobup = {"cl_bobup","0.5", true};
48 cvar_t cl_bobside = {"cl_bobside","0.02", true};
49 cvar_t cl_bobsidecycle = {"cl_bobsidecycle","0.9", true};
50 cvar_t cl_bobsideup = {"cl_bobsideup","0.5", true};
52 cvar_t v_kicktime = {"v_kicktime", "0.5", false};
53 cvar_t v_kickroll = {"v_kickroll", "0.6", false};
54 cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
56 cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "6", true};
57 cvar_t v_iroll_cycle = {"v_iroll_cycle", "6", true};
58 cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "12", true};
59 cvar_t v_iyaw_level = {"v_iyaw_level", "0.15", true};
60 cvar_t v_iroll_level = {"v_iroll_level", "0.15", true};
61 cvar_t v_ipitch_level = {"v_ipitch_level", "0.15", true};
63 cvar_t v_idlescale = {"v_idlescale", "0.1", true};
65 cvar_t crosshair = {"crosshair", "2", true};
66 cvar_t cl_crossx = {"cl_crossx", "0", false};
67 cvar_t cl_crossy = {"cl_crossy", "0", false};
69 cvar_t cl_gunpitch = {"cl_gunpitch", "0", false};
71 cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
73 float v_dmg_time, v_dmg_roll, v_dmg_pitch;
75 extern int in_forward, in_forward2, in_back;
76 extern cvar_t lookcenter;
78 ===============
79 V_CalcRoll
81 Used by view and sv_user
82 ===============
84 vec3_t forward, right, up;
86 float V_CalcRoll (vec3_t angles, vec3_t velocity)
88 float sign;
89 float side;
90 float value;
92 AngleVectors (angles, forward, right, up);
93 side = DotProduct (velocity, right);
94 sign = side < 0 ? -1 : 1;
95 side = fabsf(side);
97 value = cl_rollangle.value;
98 if (cl.inwater)
99 value *= 2;
101 if (side < cl_rollspeed.value)
102 side = side * value / cl_rollspeed.value;
103 else
104 side = value;
106 return side*sign;
112 ===============
113 V_CalcBob
115 ===============
117 float V_CalcBob (void)
119 float bob;
120 float cycle;
122 cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;
123 cycle /= cl_bobcycle.value;
124 if (cycle < cl_bobup.value)
125 cycle = M_PI * cycle / cl_bobup.value;
126 else
127 cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
129 // bob is proportional to velocity in the xy plane
130 // (don't count Z, or jumping messes it up)
132 bob = sqrtf(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;
133 // Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
134 bob = bob*0.3 + bob*0.7*sinf(cycle);
135 if (bob > 4)
136 bob = 4;
137 else if (bob < -7)
138 bob = -7;
139 return bob;
144 ===============
145 V_CalcBobSide
147 ===============
149 float V_CalcBobSide (void)
151 float bobside;
152 float cycle;
154 cycle = cl.time - (int)(cl.time/cl_bobsidecycle.value)*cl_bobsidecycle.value;
155 cycle /= cl_bobsidecycle.value;
156 if (cycle < cl_bobsideup.value)
157 cycle = M_PI * cycle / cl_bobsideup.value;
158 else
159 cycle = M_PI + M_PI*(cycle-cl_bobsideup.value)/(1.0 - cl_bobsideup.value);
161 // bob is proportional to velocity in the xy plane
162 // (don't count Z, or jumping messes it up)
164 bobside = sqrtf(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bobside.value;
165 //Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
166 bobside = bobside*0.3 + bobside*0.7*sinf(cycle);
167 if (bobside > 4)
168 bobside = 4;
169 else if (bobside < -7)
170 bobside = -7;
171 return bobside;
176 ===============
177 V_ZoomIN
179 Kurok specific zoom code.
180 ===============
183 float V_ZoomIN (void)
189 //=============================================================================
192 cvar_t v_centermove = {"v_centermove", "1", true};
193 cvar_t v_centerspeed = {"v_centerspeed","100", true};
196 void V_StartPitchDrift (void)
198 #if 1
199 if (cl.laststop == cl.time)
201 return; // something else is keeping it from drifting
203 #endif
204 if (cl.nodrift || !cl.pitchvel)
206 cl.pitchvel = v_centerspeed.value;
207 cl.nodrift = false;
208 cl.driftmove = 0;
212 void V_StopPitchDrift (void)
214 cl.laststop = cl.time;
215 cl.nodrift = true;
216 cl.pitchvel = 0;
220 ===============
221 V_DriftPitch
223 Moves the client pitch angle towards cl.idealpitch sent by the server.
225 If the user is adjusting pitch manually, either with lookup/lookdown,
226 mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
228 Drifting is enabled when the center view key is hit, mlook is released and
229 lookspring is non 0, or when
230 ===============
232 void V_DriftPitch (void)
234 float delta, move;
236 if (noclip_anglehack || !cl.onground || cls.demoplayback || lookcenter.value)
238 cl.driftmove = 0;
239 cl.pitchvel = 0;
240 return;
243 // don't count small mouse motion
244 if (cl.nodrift)
246 if ( fabsf(cl.cmd.forwardmove) < cl_forwardspeed.value)
247 cl.driftmove = 0;
248 else
249 cl.driftmove += host_frametime;
251 if ( cl.driftmove > v_centermove.value)
253 V_StartPitchDrift ();
255 return;
258 delta = cl.idealpitch - cl.viewangles[PITCH];
260 if (!delta)
262 cl.pitchvel = 0;
263 return;
266 move = host_frametime * cl.pitchvel;
267 cl.pitchvel += host_frametime * v_centerspeed.value;
269 //Con_Printf ("move: %f (%f)\n", move, host_frametime);
271 if (delta > 0)
273 if (move > delta)
275 cl.pitchvel = 0;
276 move = delta;
278 cl.viewangles[PITCH] += move;
280 else if (delta < 0)
282 if (move > -delta)
284 cl.pitchvel = 0;
285 move = -delta;
287 cl.viewangles[PITCH] -= move;
296 ==============================================================================
298 PALETTE FLASHES
300 ==============================================================================
304 cshift_t cshift_empty = { {130,80,50}, 0 };
305 cshift_t cshift_water = { {130,80,50}, 128 };
306 cshift_t cshift_kwater = { {64,64,128}, 128 }; // Blue water for Kurok
307 cshift_t cshift_slime = { {0,25,5}, 150 };
308 cshift_t cshift_lava = { {255,80,0}, 150 };
310 cvar_t v_gamma = {"gamma", "1", true};
312 byte gammatable[256]; // palette is sent through this
314 #if defined(GLQUAKE) || defined(PSP_HARDWARE_VIDEO)
315 byte ramps[3][256];
316 float v_blend[4]; // rgba 0.0 - 1.0
317 #endif // GLQUAKE
319 void BuildGammaTable (float g)
321 int i, inf;
323 if (g == 1.0)
325 for (i=0 ; i<256 ; i++)
326 gammatable[i] = i;
327 return;
330 for (i=0 ; i<256 ; i++)
332 inf = 255 * powf ( (i+0.5f)/255.5f , g ) + 0.5;
333 if (inf < 0)
334 inf = 0;
335 if (inf > 255)
336 inf = 255;
337 gammatable[i] = inf;
342 =================
343 V_CheckGamma
344 =================
346 qboolean V_CheckGamma (void)
348 static float oldgammavalue;
350 if (v_gamma.value == oldgammavalue)
351 return false;
352 oldgammavalue = v_gamma.value;
354 BuildGammaTable (v_gamma.value);
355 vid.recalc_refdef = 1; // force a surface cache flush
357 return true;
363 ===============
364 V_ParseDamage
365 ===============
367 void V_ParseDamage (void)
369 int armor, blood;
370 vec3_t from;
371 int i;
372 vec3_t forward, right, up;
373 entity_t *ent;
374 float side;
375 float count;
377 armor = MSG_ReadByte ();
378 blood = MSG_ReadByte ();
379 for (i=0 ; i<3 ; i++)
380 from[i] = MSG_ReadCoord ();
382 count = blood*0.5 + armor*0.5;
383 if (count < 10)
384 count = 10;
386 cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame
388 cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
389 if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
390 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
391 if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
392 cl.cshifts[CSHIFT_DAMAGE].percent = 150;
394 if (armor > blood)
396 if (kurok) // Flash blue for damage when wearing armor
398 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 100; //r
399 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; //g
400 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 200; //b
402 else
404 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; //r
405 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; //g
406 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; //b
409 else if (armor)
411 if (kurok) // Flash blue for damage when wearing armor
413 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 0; //r
414 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; //g
415 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 255; //b
417 else
419 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; //r
420 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; //g
421 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; //b
424 else
426 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; //r
427 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; //g
428 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; //b
432 // calculate view angle kicks
434 ent = &cl_entities[cl.viewentity];
436 VectorSubtract (from, ent->origin, from);
437 VectorNormalize (from);
439 AngleVectors (ent->angles, forward, right, up);
441 side = DotProduct (from, right);
442 v_dmg_roll = count*side*v_kickroll.value;
444 side = DotProduct (from, forward);
445 v_dmg_pitch = count*side*v_kickpitch.value;
447 v_dmg_time = v_kicktime.value;
452 ==================
453 V_cshift_f
454 ==================
456 void V_cshift_f (void)
458 cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
459 cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
460 cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
461 cshift_empty.percent = atoi(Cmd_Argv(4));
466 ==================
467 V_BonusFlash_f
469 When you run over an item, the server sends this command
470 ==================
472 void V_BonusFlash_f (void)
474 cl.cshifts[CSHIFT_BONUS].destcolor[0] = 128;
475 cl.cshifts[CSHIFT_BONUS].destcolor[1] = 128;
476 cl.cshifts[CSHIFT_BONUS].destcolor[2] = 128;
477 cl.cshifts[CSHIFT_BONUS].percent = 50;
481 =============
482 V_SetContentsColor
484 Underwater, lava, etc each has a color shift
485 =============
487 void V_SetContentsColor (int contents)
489 switch (contents)
491 case CONTENTS_EMPTY:
492 case CONTENTS_SOLID:
493 cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
494 break;
495 case CONTENTS_LAVA:
496 cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
497 break;
498 case CONTENTS_SLIME:
499 cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
500 break;
501 default:
502 if (kurok)
503 cl.cshifts[CSHIFT_CONTENTS] = cshift_kwater;
504 else
505 cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
510 =============
511 V_CalcPowerupCshift
512 =============
514 void V_CalcPowerupCshift (void)
516 if (cl.items & IT_QUAD)
518 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
519 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
520 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
521 cl.cshifts[CSHIFT_POWERUP].percent = 30;
523 else if (cl.items & IT_SUIT)
525 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
526 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
527 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
528 cl.cshifts[CSHIFT_POWERUP].percent = 20;
530 else if (cl.items & IT_INVISIBILITY)
532 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
533 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
534 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
535 cl.cshifts[CSHIFT_POWERUP].percent = 50;
537 else if (cl.items & IT_INVULNERABILITY)
539 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
540 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
541 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
542 cl.cshifts[CSHIFT_POWERUP].percent = 30;
544 else
545 cl.cshifts[CSHIFT_POWERUP].percent = 0;
549 =============
550 V_CalcBlend
551 =============
553 #if defined(GLQUAKE) || defined(PSP_HARDWARE_VIDEO)
554 void V_CalcBlend (void)
556 float r, g, b, a, a2;
557 int j;
559 r = 0;
560 g = 0;
561 b = 0;
562 a = 0;
564 for (j=0 ; j<NUM_CSHIFTS ; j++)
566 if (!gl_cshiftpercent.value)
567 continue;
569 a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
571 // a2 = cl.cshifts[j].percent/255.0;
572 if (!a2)
573 continue;
574 a = a + a2*(1-a);
575 //Con_Printf ("j:%i a:%f\n", j, a);
576 a2 = a2/a;
577 r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
578 g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
579 b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
582 v_blend[0] = r/255.0;
583 v_blend[1] = g/255.0;
584 v_blend[2] = b/255.0;
585 v_blend[3] = a;
587 if (v_blend[3] > 1)
588 v_blend[3] = 1;
589 if (v_blend[3] < 0)
590 v_blend[3] = 0;
592 Draw_FadeScreenColor (v_blend[0], v_blend[1], v_blend[2], v_blend[3]);
594 #endif
597 =============
598 V_UpdatePalette
599 =============
601 #if defined(GLQUAKE) || defined(PSP_HARDWARE_VIDEO)
602 void V_UpdatePalette (void)
604 int i, j;
605 qboolean new;
606 // byte *basepal, *newpal;
607 // byte pal[768];
608 // float r,g,b,a;
609 // int ir, ig, ib;
610 // qboolean force;
612 V_CalcPowerupCshift ();
614 new = false;
616 for (i=0 ; i<NUM_CSHIFTS ; i++)
618 if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
620 new = true;
621 cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
623 for (j=0 ; j<3 ; j++)
624 if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
626 new = true;
627 cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
631 // drop the damage value
632 cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
633 if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
634 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
636 // drop the bonus value
637 cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
638 if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
639 cl.cshifts[CSHIFT_BONUS].percent = 0;
641 // force = V_CheckGamma ();
642 // if (!new && !force)
643 // return;
645 V_CalcBlend ();
648 a = v_blend[3];
649 r = 255*v_blend[0]*a;
650 g = 255*v_blend[1]*a;
651 b = 255*v_blend[2]*a;
653 a = 1-a;
654 for (i=0 ; i<256 ; i++)
656 ir = i*a + r;
657 ig = i*a + g;
658 ib = i*a + b;
659 if (ir > 255)
660 ir = 255;
661 if (ig > 255)
662 ig = 255;
663 if (ib > 255)
664 ib = 255;
666 ramps[0][i] = gammatable[ir];
667 ramps[1][i] = gammatable[ig];
668 ramps[2][i] = gammatable[ib];
671 basepal = host_basepal;
672 newpal = pal;
674 for (i=0 ; i<256 ; i++)
676 ir = basepal[0];
677 ig = basepal[1];
678 ib = basepal[2];
679 basepal += 3;
681 newpal[0] = ramps[0][ir];
682 newpal[1] = ramps[1][ig];
683 newpal[2] = ramps[2][ib];
684 newpal += 3;
687 VID_ShiftPalette (pal);
690 #else // !GLQUAKE
691 void V_UpdatePalette (void)
693 int i, j;
694 qboolean new;
695 byte *basepal, *newpal;
696 byte pal[768];
697 int r,g,b;
698 qboolean force;
700 V_CalcPowerupCshift ();
702 new = false;
704 for (i=0 ; i<NUM_CSHIFTS ; i++)
706 if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
708 new = true;
709 cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
711 for (j=0 ; j<3 ; j++)
712 if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
714 new = true;
715 cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
719 // drop the damage value
720 cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
721 if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
722 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
724 // drop the bonus value
725 cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
726 if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
727 cl.cshifts[CSHIFT_BONUS].percent = 0;
729 force = V_CheckGamma ();
730 if (!new && !force)
731 return;
733 basepal = host_basepal;
734 newpal = pal;
736 for (i=0 ; i<256 ; i++)
738 r = basepal[0];
739 g = basepal[1];
740 b = basepal[2];
741 basepal += 3;
743 for (j=0 ; j<NUM_CSHIFTS ; j++)
745 r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
746 g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
747 b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
750 newpal[0] = gammatable[r];
751 newpal[1] = gammatable[g];
752 newpal[2] = gammatable[b];
753 newpal += 3;
756 VID_ShiftPalette (pal);
758 #endif // !GLQUAKE
762 ==============================================================================
764 VIEW RENDERING
766 ==============================================================================
769 float angledelta (float a)
771 a = anglemod(a);
772 if (a > 180)
773 a -= 360;
774 return a;
778 ==================
779 CalcGunAngle
780 ==================
782 void CalcGunAngle (void)
784 float yaw, pitch, move;
785 static float oldyaw = 0;
786 static float oldpitch = 0;
788 extern cvar_t in_freelook_analog;
789 extern cvar_t in_disable_analog;
790 extern cvar_t in_analog_strafe;
792 extern cvar_t in_x_axis_adjust;
793 extern cvar_t in_y_axis_adjust;
795 yaw = r_refdef.viewangles[YAW];
796 pitch = -r_refdef.viewangles[PITCH];
798 yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
799 if (yaw > 10)
800 yaw = 10;
801 if (yaw < -10)
802 yaw = -10;
803 pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
804 if (pitch > 10)
805 pitch = 10;
806 if (pitch < -10)
807 pitch = -10;
808 move = host_frametime*20;
809 if (yaw > oldyaw)
811 if (oldyaw + move < yaw)
812 yaw = oldyaw + move;
814 else
816 if (oldyaw - move > yaw)
817 yaw = oldyaw - move;
820 if (pitch > oldpitch)
822 if (oldpitch + move < pitch)
823 pitch = oldpitch + move;
825 else
827 if (oldpitch - move > pitch)
828 pitch = oldpitch - move;
831 oldyaw = yaw;
832 oldpitch = pitch;
834 cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
835 cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
837 // Read the pad state.
838 SceCtrlData pad;
839 sceCtrlPeekBufferPositive(&pad, 1);
841 extern cvar_t scr_fov;
843 if (scr_fov.value == 90)
845 cl.viewent.angles[ROLL] -= sin(cl.time*3);
846 if (!in_disable_analog.value)
848 if (in_freelook_analog.value)
850 if (m_pitch.value < 0)
851 cl.viewent.angles[PITCH] -= sin(cl.time*1.8) - ((pad.Ly - 128) * in_y_axis_adjust.value * 0.015);
852 else
853 cl.viewent.angles[PITCH] -= sin(cl.time*1.8) + ((pad.Ly - 128) * in_y_axis_adjust.value * 0.015);
854 cl.viewent.angles[YAW] -= sin(cl.time*1.5) + ((pad.Lx - 128) * in_x_axis_adjust.value * 0.015);
856 else
858 if (!in_analog_strafe.value)
859 cl.viewent.angles[YAW] -= sin(cl.time*1.5) + ((pad.Lx - 128) * in_x_axis_adjust.value * 0.015);
863 if (cl_gunpitch.value)
864 cl.viewent.angles[PITCH] -= cl_gunpitch.value;
867 else
869 cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
870 cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
871 cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
877 ==============
878 V_BoundOffsets
879 ==============
881 void V_BoundOffsets (void)
883 entity_t *ent;
885 ent = &cl_entities[cl.viewentity];
887 // absolutely bound refresh reletive to entity clipping hull
888 // so the view can never be inside a solid wall
890 if (r_refdef.vieworg[0] < ent->origin[0] - 14)
891 r_refdef.vieworg[0] = ent->origin[0] - 14;
892 else if (r_refdef.vieworg[0] > ent->origin[0] + 14)
893 r_refdef.vieworg[0] = ent->origin[0] + 14;
894 if (r_refdef.vieworg[1] < ent->origin[1] - 14)
895 r_refdef.vieworg[1] = ent->origin[1] - 14;
896 else if (r_refdef.vieworg[1] > ent->origin[1] + 14)
897 r_refdef.vieworg[1] = ent->origin[1] + 14;
898 if (r_refdef.vieworg[2] < ent->origin[2] - 22)
899 r_refdef.vieworg[2] = ent->origin[2] - 22;
900 else if (r_refdef.vieworg[2] > ent->origin[2] + 30)
901 r_refdef.vieworg[2] = ent->origin[2] + 30;
905 ==============
906 V_AddIdle
908 Idle swaying
909 ==============
911 void V_AddIdle (void)
914 if (kurok)
916 double xyspeed;
917 float bspeed;
919 xyspeed = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]);
920 bspeed = xyspeed * 0.15f;
922 r_refdef.viewangles[ROLL] += v_idlescale.value * sinf(cl.time*v_iroll_cycle.value) * (v_iroll_level.value * bspeed);
923 r_refdef.viewangles[PITCH] += v_idlescale.value * sinf(cl.time*v_ipitch_cycle.value) * (v_ipitch_level.value * bspeed);
924 r_refdef.viewangles[YAW] += v_idlescale.value * sinf(cl.time*v_iyaw_cycle.value) * (v_iyaw_level.value * bspeed);
926 r_refdef.viewangles[ROLL] += (v_idlescale.value * 3 ) * sinf(cl.time*v_iroll_cycle.value * 0.25 ) * v_iroll_level.value;
927 r_refdef.viewangles[PITCH] += (v_idlescale.value * 3 ) * sinf(cl.time*v_ipitch_cycle.value * 0.25 ) * v_ipitch_level.value;
928 r_refdef.viewangles[YAW] += (v_idlescale.value * 3 ) * sinf(cl.time*v_iyaw_cycle.value * 0.25 ) * v_iyaw_level.value;
930 else
933 r_refdef.viewangles[ROLL] += v_idlescale.value * sinf(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
934 r_refdef.viewangles[PITCH] += v_idlescale.value * sinf(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
935 r_refdef.viewangles[YAW] += v_idlescale.value * sinf(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
941 ==============
942 V_CalcViewRoll
944 Roll is induced by movement and damage
945 ==============
947 void V_CalcViewRoll (void)
949 float side;
951 side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
952 r_refdef.viewangles[ROLL] += side;
954 if (v_dmg_time > 0)
956 r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
957 r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
958 v_dmg_time -= host_frametime;
961 if (cl.stats[STAT_HEALTH] <= 0)
963 r_refdef.viewangles[ROLL] = 80; // dead view angle
964 return;
971 ==================
972 V_CalcIntermissionRefdef
974 ==================
976 void V_CalcIntermissionRefdef (void)
978 entity_t *ent, *view;
979 float old;
981 // ent is the player model (visible when out of body)
982 ent = &cl_entities[cl.viewentity];
983 // view is the weapon model (only visible from inside body)
984 view = &cl.viewent;
986 VectorCopy (ent->origin, r_refdef.vieworg);
987 VectorCopy (ent->angles, r_refdef.viewangles);
988 view->model = NULL;
990 // allways idle in intermission
991 if (!kurok)
993 old = v_idlescale.value;
994 v_idlescale.value = 1;
995 V_AddIdle ();
996 v_idlescale.value = old;
1001 ==================
1002 V_CalcRefdef
1004 ==================
1006 void V_CalcRefdef (void)
1008 entity_t *ent, *view;
1009 int i;
1010 vec3_t forward, right, up;
1011 vec3_t angles;
1012 float bob, bobside;
1013 static float oldz = 0;
1015 V_DriftPitch ();
1017 // ent is the player model (visible when out of body)
1018 ent = &cl_entities[cl.viewentity];
1019 // view is the weapon model (only visible from inside body)
1020 view = &cl.viewent;
1023 // transform the view offset by the model's matrix to get the offset from
1024 // model origin for the view
1025 ent->angles[YAW] = cl.viewangles[YAW]; // the model should face
1026 // the view dir
1027 ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face
1028 // the view dir
1029 if (chase_active.value)
1031 bob = 0;
1032 bobside = 0;
1034 else
1036 bob = V_CalcBob ();
1037 bobside = V_CalcBobSide ();
1040 // refresh position
1041 VectorCopy (ent->origin, r_refdef.vieworg);
1042 r_refdef.vieworg[2] += cl.viewheight + bob;
1044 // never let it sit exactly on a node line, because a water plane can
1045 // dissapear when viewed with the eye exactly on it.
1046 // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis
1047 r_refdef.vieworg[0] += 1.0/32;
1048 r_refdef.vieworg[1] += 1.0/32;
1049 r_refdef.vieworg[2] += 1.0/32;
1051 VectorCopy (cl.viewangles, r_refdef.viewangles);
1053 if (!chase_active.value)
1055 V_CalcViewRoll ();
1056 V_AddIdle ();
1059 // offsets
1060 angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are
1061 // actually backward
1062 angles[YAW] = ent->angles[YAW];
1063 angles[ROLL] = ent->angles[ROLL];
1065 AngleVectors (angles, forward, right, up);
1067 for (i=0 ; i<3 ; i++)
1068 r_refdef.vieworg[i] += scr_ofsx.value*forward[i]
1069 + scr_ofsy.value*right[i]
1070 + scr_ofsz.value*up[i];
1073 V_BoundOffsets ();
1075 // set up gun position
1076 VectorCopy (cl.viewangles, view->angles);
1078 CalcGunAngle ();
1080 VectorCopy (ent->origin, view->origin);
1081 view->origin[2] += cl.viewheight;
1083 for (i=0 ; i<3 ; i++)
1085 // view->origin[i] += forward[i]*bob*0.2;
1086 view->origin[i] += right[i]*bobside*0.2;
1087 view->origin[i] += up[i]*bob*0.2;
1089 view->origin[2] += bob;
1091 if(!kurok)
1094 // fudge position around to keep amount of weapon visible
1095 // roughly equal with different FOV
1097 #if 0
1098 if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl"))
1099 #endif
1100 if (scr_viewsize.value == 130)
1101 view->origin[2] += 2.25;
1102 else if (scr_viewsize.value == 120)
1103 view->origin[2] += 2.25;
1104 else if (scr_viewsize.value == 110)
1105 view->origin[2] += 2.5;
1106 else if (scr_viewsize.value == 100)
1107 view->origin[2] += 3;
1108 else if (scr_viewsize.value == 90)
1109 view->origin[2] += 2.5;
1110 else if (scr_viewsize.value <= 80)
1111 view->origin[2] += 2;
1114 view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
1115 view->frame = cl.stats[STAT_WEAPONFRAME];
1116 view->colormap = vid.colormap;
1118 // set up the refresh position
1119 VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
1121 // smooth out stair step ups
1122 if (cl.onground && ent->origin[2] - oldz > 0)
1124 float steptime;
1126 steptime = cl.time - cl.oldtime;
1127 if (steptime < 0)
1128 //FIXME I_Error ("steptime < 0");
1129 steptime = 0;
1131 oldz += steptime * 80;
1132 if (oldz > ent->origin[2])
1133 oldz = ent->origin[2];
1134 if (ent->origin[2] - oldz > 12)
1135 oldz = ent->origin[2] - 12;
1136 r_refdef.vieworg[2] += oldz - ent->origin[2];
1137 view->origin[2] += oldz - ent->origin[2];
1139 else
1140 oldz = ent->origin[2];
1142 if (chase_active.value)
1143 Chase_Update ();
1147 ==================
1148 V_RenderView
1150 The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
1151 the entity origin, so any view position inside that will be valid
1152 ==================
1154 extern vrect_t scr_vrect;
1156 void V_RenderView (void)
1158 if (con_forcedup)
1159 return;
1161 if (!kurok)
1163 // don't allow cheats in multiplayer
1164 if (cl.maxclients > 1)
1166 Cvar_Set ("scr_ofsx", "0");
1167 Cvar_Set ("scr_ofsy", "0");
1168 Cvar_Set ("scr_ofsz", "0");
1172 if (cl.intermission)
1173 { // intermission / finale rendering
1174 V_CalcIntermissionRefdef ();
1176 else
1178 if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )
1179 V_CalcRefdef ();
1182 R_PushDlights ();
1184 if (lcd_x.value)
1187 // render two interleaved views
1189 int i;
1191 vid.rowbytes <<= 1;
1192 vid.aspect *= 0.5;
1194 r_refdef.viewangles[YAW] -= lcd_yaw.value;
1195 for (i=0 ; i<3 ; i++)
1196 r_refdef.vieworg[i] -= right[i]*lcd_x.value;
1197 R_RenderView ();
1199 vid.buffer += vid.rowbytes>>1;
1201 R_PushDlights ();
1203 r_refdef.viewangles[YAW] += lcd_yaw.value*2;
1204 for (i=0 ; i<3 ; i++)
1205 r_refdef.vieworg[i] += 2*right[i]*lcd_x.value;
1206 R_RenderView ();
1208 vid.buffer -= vid.rowbytes>>1;
1210 r_refdef.vrect.height <<= 1;
1212 vid.rowbytes >>= 1;
1213 vid.aspect *= 2;
1215 else
1217 R_RenderView ();
1220 #if !defined(GLQUAKE) && !defined(PSP_HARDWARE_VIDEO)
1221 if (crosshair.value)
1222 Draw_Crosshair();
1223 // Draw_Character (scr_vrect.x + scr_vrect.width/2 + cl_crossx.value, scr_vrect.y + scr_vrect.height/2 + cl_crossy.value, '+');
1224 #endif
1228 //============================================================================
1231 =============
1232 V_Init
1233 =============
1235 void V_Init (void)
1237 Cmd_AddCommand ("v_cshift", V_cshift_f);
1238 Cmd_AddCommand ("bf", V_BonusFlash_f);
1239 Cmd_AddCommand ("centerview", V_StartPitchDrift);
1241 Cvar_RegisterVariable (&lcd_x);
1242 Cvar_RegisterVariable (&lcd_yaw);
1244 Cvar_RegisterVariable (&v_centermove);
1245 Cvar_RegisterVariable (&v_centerspeed);
1247 Cvar_RegisterVariable (&v_iyaw_cycle);
1248 Cvar_RegisterVariable (&v_iroll_cycle);
1249 Cvar_RegisterVariable (&v_ipitch_cycle);
1250 Cvar_RegisterVariable (&v_iyaw_level);
1251 Cvar_RegisterVariable (&v_iroll_level);
1252 Cvar_RegisterVariable (&v_ipitch_level);
1254 Cvar_RegisterVariable (&v_idlescale);
1255 Cvar_RegisterVariable (&crosshair);
1256 Cvar_RegisterVariable (&cl_crossx);
1257 Cvar_RegisterVariable (&cl_crossy);
1258 Cvar_RegisterVariable (&gl_cshiftpercent);
1260 Cvar_RegisterVariable (&scr_ofsx);
1261 Cvar_RegisterVariable (&scr_ofsy);
1262 Cvar_RegisterVariable (&scr_ofsz);
1263 Cvar_RegisterVariable (&cl_rollspeed);
1264 Cvar_RegisterVariable (&cl_rollangle);
1266 Cvar_RegisterVariable (&cl_bob);
1267 Cvar_RegisterVariable (&cl_bobcycle);
1268 Cvar_RegisterVariable (&cl_bobup);
1270 Cvar_RegisterVariable (&cl_bobside);
1271 Cvar_RegisterVariable (&cl_bobsidecycle);
1272 Cvar_RegisterVariable (&cl_bobsideup);
1274 Cvar_RegisterVariable (&cl_gunpitch);
1276 Cvar_RegisterVariable (&v_kicktime);
1277 Cvar_RegisterVariable (&v_kickroll);
1278 Cvar_RegisterVariable (&v_kickpitch);
1280 BuildGammaTable (1.0); // no gamma yet
1281 Cvar_RegisterVariable (&v_gamma);