diff options
Diffstat (limited to 'apps/plugins/sdl/progs/quake/view.c')
-rw-r--r-- | apps/plugins/sdl/progs/quake/view.c | 1113 |
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 | /* | ||
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"}; | ||
35 | cvar_t lcd_yaw = {"lcd_yaw","0"}; | ||
36 | |||
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}; | ||
40 | |||
41 | cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; | ||
42 | cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; | ||
43 | |||
44 | cvar_t cl_bob = {"cl_bob","0.02", false}; | ||
45 | cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false}; | ||
46 | cvar_t cl_bobup = {"cl_bobup","0.5", false}; | ||
47 | |||
48 | cvar_t v_kicktime = {"v_kicktime", "0.5", false}; | ||
49 | cvar_t v_kickroll = {"v_kickroll", "0.6", false}; | ||
50 | cvar_t v_kickpitch = {"v_kickpitch", "0.6", false}; | ||
51 | |||
52 | cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false}; | ||
53 | cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false}; | ||
54 | cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false}; | ||
55 | cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false}; | ||
56 | cvar_t v_iroll_level = {"v_iroll_level", "0.1", false}; | ||
57 | cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false}; | ||
58 | |||
59 | cvar_t v_idlescale = {"v_idlescale", "0", false}; | ||
60 | |||
61 | cvar_t crosshair = {"crosshair", "0", true}; | ||
62 | cvar_t cl_crossx = {"cl_crossx", "0", false}; | ||
63 | cvar_t cl_crossy = {"cl_crossy", "0", false}; | ||
64 | |||
65 | cvar_t gl_cshiftpercent = {"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 = {"v_centermove", "0.15", false}; | ||
143 | cvar_t v_centerspeed = {"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 = {"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 = 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 += 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 | ================== | ||
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 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 | ||
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 | |||