|
|
1.1 root 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 = {"lcd_x", "0"}; // FIXME: make this work sometime...
35:
36: cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
37: cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
38:
39: cvar_t cl_bob = {"cl_bob","0.02", false};
40: cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
41: cvar_t cl_bobup = {"cl_bobup","0.5", false};
42:
43: cvar_t v_kicktime = {"v_kicktime", "0.5", false};
44: cvar_t v_kickroll = {"v_kickroll", "0.6", false};
45: cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
46:
47: cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
48: cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
49: cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
50: cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
51: cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
52: cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
53:
54: cvar_t v_idlescale = {"v_idlescale", "0", false};
55:
56: cvar_t crosshair = {"crosshair", "0", true};
57: cvar_t crosshaircolor = {"crosshaircolor", "79", true};
58:
59: cvar_t cl_crossx = {"cl_crossx", "0", true};
60: cvar_t cl_crossy = {"cl_crossy", "0", true};
61:
62: #ifdef GLQUAKE
63: cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
64: #endif
65:
66: cvar_t v_contentblend = {"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: */
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: */
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 = {"v_centermove", "0.15", false};
149: cvar_t v_centerspeed = {"v_centerspeed","500"};
150:
151:
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:
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: */
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 = {"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:
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: */
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: */
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: */
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: */
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: */
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: */
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
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
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: */
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:
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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:
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: */
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.