summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/view.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/quake/view.c')
-rw-r--r--apps/plugins/sdl/progs/quake/view.c1113
1 files changed, 1113 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/view.c b/apps/plugins/sdl/progs/quake/view.c
new file mode 100644
index 0000000000..f621c3c428
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/view.c
@@ -0,0 +1,1113 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
27The view is allowed to move slightly from it's true position for bobbing,
28but if it exceeds 8 pixels linear distance (spherical, not box), the list of
29entities sent from the server may not include everything in the pvs, especially
30when crossing a water boudnary.
31
32*/
33
34cvar_t lcd_x = {"lcd_x","0"};
35cvar_t lcd_yaw = {"lcd_yaw","0"};
36
37cvar_t scr_ofsx = {"scr_ofsx","0", false};
38cvar_t scr_ofsy = {"scr_ofsy","0", false};
39cvar_t scr_ofsz = {"scr_ofsz","0", false};
40
41cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
42cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
43
44cvar_t cl_bob = {"cl_bob","0.02", false};
45cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
46cvar_t cl_bobup = {"cl_bobup","0.5", false};
47
48cvar_t v_kicktime = {"v_kicktime", "0.5", false};
49cvar_t v_kickroll = {"v_kickroll", "0.6", false};
50cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
51
52cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
53cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
54cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
55cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
56cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
57cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
58
59cvar_t v_idlescale = {"v_idlescale", "0", false};
60
61cvar_t crosshair = {"crosshair", "0", true};
62cvar_t cl_crossx = {"cl_crossx", "0", false};
63cvar_t cl_crossy = {"cl_crossy", "0", false};
64
65cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
66
67float v_dmg_time, v_dmg_roll, v_dmg_pitch;
68
69extern int in_forward, in_forward2, in_back;
70
71
72/*
73===============
74V_CalcRoll
75
76Used by view and sv_user
77===============
78*/
79vec3_t forward, right, up;
80
81float 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===============
108V_CalcBob
109
110===============
111*/
112float 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
142cvar_t v_centermove = {"v_centermove", "0.15", false};
143cvar_t v_centerspeed = {"v_centerspeed","500"};
144
145
146void 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
162void V_StopPitchDrift (void)
163{
164 cl.laststop = cl.time;
165 cl.nodrift = true;
166 cl.pitchvel = 0;
167}
168
169/*
170===============
171V_DriftPitch
172
173Moves the client pitch angle towards cl.idealpitch sent by the server.
174
175If the user is adjusting pitch manually, either with lookup/lookdown,
176mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
177
178Drifting is enabled when the center view key is hit, mlook is released and
179lookspring is non 0, or when
180===============
181*/
182void 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
254cshift_t cshift_empty = { {130,80,50}, 0 };
255cshift_t cshift_water = { {130,80,50}, 128 };
256cshift_t cshift_slime = { {0,25,5}, 150 };
257cshift_t cshift_lava = { {255,80,0}, 150 };
258
259cvar_t v_gamma = {"gamma", "1", true};
260
261byte gammatable[256]; // palette is sent through this
262
263#ifdef GLQUAKE
264byte ramps[3][256];
265float v_blend[4]; // rgba 0.0 - 1.0
266#endif // GLQUAKE
267
268void 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 = 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=================
292V_CheckGamma
293=================
294*/
295qboolean 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===============
313V_ParseDamage
314===============
315*/
316void 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 += 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 VectorNormalizeNoRet (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==================
384V_cshift_f
385==================
386*/
387void 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==================
398V_BonusFlash_f
399
400When you run over an item, the server sends this command
401==================
402*/
403void 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=============
413V_SetContentsColor
414
415Underwater, lava, etc each has a color shift
416=============
417*/
418void 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=============
439V_CalcPowerupCshift
440=============
441*/
442void 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=============
478V_CalcBlend
479=============
480*/
481#ifdef GLQUAKE
482void 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=============
523V_UpdatePalette
524=============
525*/
526#ifdef GLQUAKE
527void V_UpdatePalette (void)
528{
529 int i, j;
530 qboolean new;
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 new = false;
540
541 for (i=0 ; i<NUM_CSHIFTS ; i++)
542 {
543 if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
544 {
545 new = 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 new = 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 -= 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 -= 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 (!new && !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 = i*a + r;
581 ig = i*a + g;
582 ib = 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
614void 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
692float angledelta (float a)
693{
694 a = anglemod(a);
695 if (a > 180)
696 a -= 360;
697 return a;
698}
699
700/*
701==================
702CalcGunAngle
703==================
704*/
705void 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==============
760V_BoundOffsets
761==============
762*/
763void 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==============
788V_AddIdle
789
790Idle swaying
791==============
792*/
793void 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==============
803V_CalcViewRoll
804
805Roll is induced by movement and damage
806==============
807*/
808void 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==================
833V_CalcIntermissionRefdef
834
835==================
836*/
837void 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==================
860V_CalcRefdef
861
862==================
863*/
864void 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
961if (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}
978else
979 oldz = ent->origin[2];
980
981 if (chase_active.value)
982 Chase_Update ();
983}
984
985/*
986==================
987V_RenderView
988
989The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
990the entity origin, so any view position inside that will be valid
991==================
992*/
993extern vrect_t scr_vrect;
994
995void 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=============
1068V_Init
1069=============
1070*/
1071void 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