~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/cgame/cg_view.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
7
Quake III Arena source code is free software; you can redistribute it
 
8
and/or modify it under the terms of the GNU General Public License as
 
9
published by the Free Software Foundation; either version 2 of the License,
 
10
or (at your option) any later version.
 
11
 
 
12
Quake III Arena source code is distributed in the hope that it will be
 
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
GNU General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with Quake III Arena source code; if not, write to the Free Software
 
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
===========================================================================
 
21
*/
 
22
//
 
23
// cg_view.c -- setup all the parameters (position, angle, etc)
 
24
// for a 3D rendering
 
25
#include "cg_local.h"
 
26
 
 
27
 
 
28
/*
 
29
=============================================================================
 
30
 
 
31
  MODEL TESTING
 
32
 
 
33
The viewthing and gun positioning tools from Q2 have been integrated and
 
34
enhanced into a single model testing facility.
 
35
 
 
36
Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
 
37
 
 
38
The names must be the full pathname after the basedir, like 
 
39
"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
 
40
 
 
41
Testmodel will create a fake entity 100 units in front of the current view
 
42
position, directly facing the viewer.  It will remain immobile, so you can
 
43
move around it to view it from different angles.
 
44
 
 
45
Testgun will cause the model to follow the player around and supress the real
 
46
view weapon model.  The default frame 0 of most guns is completely off screen,
 
47
so you will probably have to cycle a couple frames to see it.
 
48
 
 
49
"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
 
50
frame or skin of the testmodel.  These are bound to F5, F6, F7, and F8 in
 
51
q3default.cfg.
 
52
 
 
53
If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
 
54
you adjust the positioning.
 
55
 
 
56
Note that none of the model testing features update while the game is paused, so
 
57
it may be convenient to test with deathmatch set to 1 so that bringing down the
 
58
console doesn't pause the game.
 
59
 
 
60
=============================================================================
 
61
*/
 
62
 
 
63
/*
 
64
=================
 
65
CG_TestModel_f
 
66
 
 
67
Creates an entity in front of the current position, which
 
68
can then be moved around
 
69
=================
 
70
*/
 
71
void CG_TestModel_f (void) {
 
72
        vec3_t          angles;
 
73
 
 
74
        memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
 
75
        if ( trap_Argc() < 2 ) {
 
76
                return;
 
77
        }
 
78
 
 
79
        Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
 
80
        cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
 
81
 
 
82
        if ( trap_Argc() == 3 ) {
 
83
                cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
 
84
                cg.testModelEntity.frame = 1;
 
85
                cg.testModelEntity.oldframe = 0;
 
86
        }
 
87
        if (! cg.testModelEntity.hModel ) {
 
88
                CG_Printf( "Can't register model\n" );
 
89
                return;
 
90
        }
 
91
 
 
92
        VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
 
93
 
 
94
        angles[PITCH] = 0;
 
95
        angles[YAW] = 180 + cg.refdefViewAngles[1];
 
96
        angles[ROLL] = 0;
 
97
 
 
98
        AnglesToAxis( angles, cg.testModelEntity.axis );
 
99
        cg.testGun = qfalse;
 
100
}
 
101
 
 
102
/*
 
103
=================
 
104
CG_TestGun_f
 
105
 
 
106
Replaces the current view weapon with the given model
 
107
=================
 
108
*/
 
109
void CG_TestGun_f (void) {
 
110
        CG_TestModel_f();
 
111
        cg.testGun = qtrue;
 
112
        cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
 
113
}
 
114
 
 
115
 
 
116
void CG_TestModelNextFrame_f (void) {
 
117
        cg.testModelEntity.frame++;
 
118
        CG_Printf( "frame %i\n", cg.testModelEntity.frame );
 
119
}
 
120
 
 
121
void CG_TestModelPrevFrame_f (void) {
 
122
        cg.testModelEntity.frame--;
 
123
        if ( cg.testModelEntity.frame < 0 ) {
 
124
                cg.testModelEntity.frame = 0;
 
125
        }
 
126
        CG_Printf( "frame %i\n", cg.testModelEntity.frame );
 
127
}
 
128
 
 
129
void CG_TestModelNextSkin_f (void) {
 
130
        cg.testModelEntity.skinNum++;
 
131
        CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
 
132
}
 
133
 
 
134
void CG_TestModelPrevSkin_f (void) {
 
135
        cg.testModelEntity.skinNum--;
 
136
        if ( cg.testModelEntity.skinNum < 0 ) {
 
137
                cg.testModelEntity.skinNum = 0;
 
138
        }
 
139
        CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
 
140
}
 
141
 
 
142
static void CG_AddTestModel (void) {
 
143
        int             i;
 
144
 
 
145
        // re-register the model, because the level may have changed
 
146
        cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
 
147
        if (! cg.testModelEntity.hModel ) {
 
148
                CG_Printf ("Can't register model\n");
 
149
                return;
 
150
        }
 
151
 
 
152
        // if testing a gun, set the origin reletive to the view origin
 
153
        if ( cg.testGun ) {
 
154
                VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
 
155
                VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
 
156
                VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
 
157
                VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
 
158
 
 
159
                // allow the position to be adjusted
 
160
                for (i=0 ; i<3 ; i++) {
 
161
                        cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
 
162
                        cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
 
163
                        cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
 
164
                }
 
165
        }
 
166
 
 
167
        trap_R_AddRefEntityToScene( &cg.testModelEntity );
 
168
}
 
169
 
 
170
 
 
171
 
 
172
//============================================================================
 
173
 
 
174
 
 
175
/*
 
176
=================
 
177
CG_CalcVrect
 
178
 
 
179
Sets the coordinates of the rendered window
 
180
=================
 
181
*/
 
182
static void CG_CalcVrect (void) {
 
183
        int             size;
 
184
 
 
185
        // the intermission should allways be full screen
 
186
        if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
 
187
                size = 100;
 
188
        } else {
 
189
                // bound normal viewsize
 
190
                if (cg_viewsize.integer < 30) {
 
191
                        trap_Cvar_Set ("cg_viewsize","30");
 
192
                        size = 30;
 
193
                } else if (cg_viewsize.integer > 100) {
 
194
                        trap_Cvar_Set ("cg_viewsize","100");
 
195
                        size = 100;
 
196
                } else {
 
197
                        size = cg_viewsize.integer;
 
198
                }
 
199
 
 
200
        }
 
201
        cg.refdef.width = cgs.glconfig.vidWidth*size/100;
 
202
        cg.refdef.width &= ~1;
 
203
 
 
204
        cg.refdef.height = cgs.glconfig.vidHeight*size/100;
 
205
        cg.refdef.height &= ~1;
 
206
 
 
207
        cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
 
208
        cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
 
209
}
 
210
 
 
211
//==============================================================================
 
212
 
 
213
 
 
214
/*
 
215
===============
 
216
CG_OffsetThirdPersonView
 
217
 
 
218
===============
 
219
*/
 
220
#define FOCUS_DISTANCE  512
 
221
static void CG_OffsetThirdPersonView( void ) {
 
222
        vec3_t          forward, right, up;
 
223
        vec3_t          view;
 
224
        vec3_t          focusAngles;
 
225
        trace_t         trace;
 
226
        static vec3_t   mins = { -4, -4, -4 };
 
227
        static vec3_t   maxs = { 4, 4, 4 };
 
228
        vec3_t          focusPoint;
 
229
        float           focusDist;
 
230
        float           forwardScale, sideScale;
 
231
 
 
232
        cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
 
233
 
 
234
        VectorCopy( cg.refdefViewAngles, focusAngles );
 
235
 
 
236
        // if dead, look at killer
 
237
        if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
 
238
                focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
 
239
                cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
 
240
        }
 
241
 
 
242
        if ( focusAngles[PITCH] > 45 ) {
 
243
                focusAngles[PITCH] = 45;                // don't go too far overhead
 
244
        }
 
245
        AngleVectors( focusAngles, forward, NULL, NULL );
 
246
 
 
247
        VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
 
248
 
 
249
        VectorCopy( cg.refdef.vieworg, view );
 
250
 
 
251
        view[2] += 8;
 
252
 
 
253
        cg.refdefViewAngles[PITCH] *= 0.5;
 
254
 
 
255
        AngleVectors( cg.refdefViewAngles, forward, right, up );
 
256
 
 
257
        forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
 
258
        sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
 
259
        VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
 
260
        VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
 
261
 
 
262
        // trace a ray from the origin to the viewpoint to make sure the view isn't
 
263
        // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything
 
264
 
 
265
        if (!cg_cameraMode.integer) {
 
266
                CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
 
267
 
 
268
                if ( trace.fraction != 1.0 ) {
 
269
                        VectorCopy( trace.endpos, view );
 
270
                        view[2] += (1.0 - trace.fraction) * 32;
 
271
                        // try another trace to this position, because a tunnel may have the ceiling
 
272
                        // close enogh that this is poking out
 
273
 
 
274
                        CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
 
275
                        VectorCopy( trace.endpos, view );
 
276
                }
 
277
        }
 
278
 
 
279
 
 
280
        VectorCopy( view, cg.refdef.vieworg );
 
281
 
 
282
        // select pitch to look at focus point from vieword
 
283
        VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
 
284
        focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
 
285
        if ( focusDist < 1 ) {
 
286
                focusDist = 1;  // should never happen
 
287
        }
 
288
        cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
 
289
        cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
 
290
}
 
291
 
 
292
 
 
293
// this causes a compiler bug on mac MrC compiler
 
294
static void CG_StepOffset( void ) {
 
295
        int             timeDelta;
 
296
        
 
297
        // smooth out stair climbing
 
298
        timeDelta = cg.time - cg.stepTime;
 
299
        if ( timeDelta < STEP_TIME ) {
 
300
                cg.refdef.vieworg[2] -= cg.stepChange 
 
301
                        * (STEP_TIME - timeDelta) / STEP_TIME;
 
302
        }
 
303
}
 
304
 
 
305
/*
 
306
===============
 
307
CG_OffsetFirstPersonView
 
308
 
 
309
===============
 
310
*/
 
311
static void CG_OffsetFirstPersonView( void ) {
 
312
        float                   *origin;
 
313
        float                   *angles;
 
314
        float                   bob;
 
315
        float                   ratio;
 
316
        float                   delta;
 
317
        float                   speed;
 
318
        float                   f;
 
319
        vec3_t                  predictedVelocity;
 
320
        int                             timeDelta;
 
321
        
 
322
        if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
 
323
                return;
 
324
        }
 
325
 
 
326
        origin = cg.refdef.vieworg;
 
327
        angles = cg.refdefViewAngles;
 
328
 
 
329
        // if dead, fix the angle and don't add any kick
 
330
        if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
 
331
                angles[ROLL] = 40;
 
332
                angles[PITCH] = -15;
 
333
                angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
 
334
                origin[2] += cg.predictedPlayerState.viewheight;
 
335
                return;
 
336
        }
 
337
 
 
338
        // add angles based on weapon kick
 
339
        VectorAdd (angles, cg.kick_angles, angles);
 
340
 
 
341
        // add angles based on damage kick
 
342
        if ( cg.damageTime ) {
 
343
                ratio = cg.time - cg.damageTime;
 
344
                if ( ratio < DAMAGE_DEFLECT_TIME ) {
 
345
                        ratio /= DAMAGE_DEFLECT_TIME;
 
346
                        angles[PITCH] += ratio * cg.v_dmg_pitch;
 
347
                        angles[ROLL] += ratio * cg.v_dmg_roll;
 
348
                } else {
 
349
                        ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
 
350
                        if ( ratio > 0 ) {
 
351
                                angles[PITCH] += ratio * cg.v_dmg_pitch;
 
352
                                angles[ROLL] += ratio * cg.v_dmg_roll;
 
353
                        }
 
354
                }
 
355
        }
 
356
 
 
357
        // add pitch based on fall kick
 
358
#if 0
 
359
        ratio = ( cg.time - cg.landTime) / FALL_TIME;
 
360
        if (ratio < 0)
 
361
                ratio = 0;
 
362
        angles[PITCH] += ratio * cg.fall_value;
 
363
#endif
 
364
 
 
365
        // add angles based on velocity
 
366
        VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
 
367
 
 
368
        delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
 
369
        angles[PITCH] += delta * cg_runpitch.value;
 
370
        
 
371
        delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
 
372
        angles[ROLL] -= delta * cg_runroll.value;
 
373
 
 
374
        // add angles based on bob
 
375
 
 
376
        // make sure the bob is visible even at low speeds
 
377
        speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
 
378
 
 
379
        delta = cg.bobfracsin * cg_bobpitch.value * speed;
 
380
        if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
 
381
                delta *= 3;             // crouching
 
382
        angles[PITCH] += delta;
 
383
        delta = cg.bobfracsin * cg_bobroll.value * speed;
 
384
        if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
 
385
                delta *= 3;             // crouching accentuates roll
 
386
        if (cg.bobcycle & 1)
 
387
                delta = -delta;
 
388
        angles[ROLL] += delta;
 
389
 
 
390
//===================================
 
391
 
 
392
        // add view height
 
393
        origin[2] += cg.predictedPlayerState.viewheight;
 
394
 
 
395
        // smooth out duck height changes
 
396
        timeDelta = cg.time - cg.duckTime;
 
397
        if ( timeDelta < DUCK_TIME) {
 
398
                cg.refdef.vieworg[2] -= cg.duckChange 
 
399
                        * (DUCK_TIME - timeDelta) / DUCK_TIME;
 
400
        }
 
401
 
 
402
        // add bob height
 
403
        bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
 
404
        if (bob > 6) {
 
405
                bob = 6;
 
406
        }
 
407
 
 
408
        origin[2] += bob;
 
409
 
 
410
 
 
411
        // add fall height
 
412
        delta = cg.time - cg.landTime;
 
413
        if ( delta < LAND_DEFLECT_TIME ) {
 
414
                f = delta / LAND_DEFLECT_TIME;
 
415
                cg.refdef.vieworg[2] += cg.landChange * f;
 
416
        } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
 
417
                delta -= LAND_DEFLECT_TIME;
 
418
                f = 1.0 - ( delta / LAND_RETURN_TIME );
 
419
                cg.refdef.vieworg[2] += cg.landChange * f;
 
420
        }
 
421
 
 
422
        // add step offset
 
423
        CG_StepOffset();
 
424
 
 
425
        // add kick offset
 
426
 
 
427
        VectorAdd (origin, cg.kick_origin, origin);
 
428
 
 
429
        // pivot the eye based on a neck length
 
430
#if 0
 
431
        {
 
432
#define NECK_LENGTH             8
 
433
        vec3_t                  forward, up;
 
434
 
 
435
        cg.refdef.vieworg[2] -= NECK_LENGTH;
 
436
        AngleVectors( cg.refdefViewAngles, forward, NULL, up );
 
437
        VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
 
438
        VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
 
439
        }
 
440
#endif
 
441
}
 
442
 
 
443
//======================================================================
 
444
 
 
445
void CG_ZoomDown_f( void ) { 
 
446
        if ( cg.zoomed ) {
 
447
                return;
 
448
        }
 
449
        cg.zoomed = qtrue;
 
450
        cg.zoomTime = cg.time;
 
451
}
 
452
 
 
453
void CG_ZoomUp_f( void ) { 
 
454
        if ( !cg.zoomed ) {
 
455
                return;
 
456
        }
 
457
        cg.zoomed = qfalse;
 
458
        cg.zoomTime = cg.time;
 
459
}
 
460
 
 
461
 
 
462
/*
 
463
====================
 
464
CG_CalcFov
 
465
 
 
466
Fixed fov at intermissions, otherwise account for fov variable and zooms.
 
467
====================
 
468
*/
 
469
#define WAVE_AMPLITUDE  1
 
470
#define WAVE_FREQUENCY  0.4
 
471
 
 
472
static int CG_CalcFov( void ) {
 
473
        float   x;
 
474
        float   phase;
 
475
        float   v;
 
476
        int             contents;
 
477
        float   fov_x, fov_y;
 
478
        float   zoomFov;
 
479
        float   f;
 
480
        int             inwater;
 
481
 
 
482
        if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
 
483
                // if in intermission, use a fixed value
 
484
                fov_x = 90;
 
485
        } else {
 
486
                // user selectable
 
487
                if ( cgs.dmflags & DF_FIXED_FOV ) {
 
488
                        // dmflag to prevent wide fov for all clients
 
489
                        fov_x = 90;
 
490
                } else {
 
491
                        fov_x = cg_fov.value;
 
492
                        if ( fov_x < 1 ) {
 
493
                                fov_x = 1;
 
494
                        } else if ( fov_x > 160 ) {
 
495
                                fov_x = 160;
 
496
                        }
 
497
                }
 
498
 
 
499
                // account for zooms
 
500
                zoomFov = cg_zoomFov.value;
 
501
                if ( zoomFov < 1 ) {
 
502
                        zoomFov = 1;
 
503
                } else if ( zoomFov > 160 ) {
 
504
                        zoomFov = 160;
 
505
                }
 
506
 
 
507
                if ( cg.zoomed ) {
 
508
                        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
 
509
                        if ( f > 1.0 ) {
 
510
                                fov_x = zoomFov;
 
511
                        } else {
 
512
                                fov_x = fov_x + f * ( zoomFov - fov_x );
 
513
                        }
 
514
                } else {
 
515
                        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
 
516
                        if ( f > 1.0 ) {
 
517
                                fov_x = fov_x;
 
518
                        } else {
 
519
                                fov_x = zoomFov + f * ( fov_x - zoomFov );
 
520
                        }
 
521
                }
 
522
        }
 
523
 
 
524
        x = cg.refdef.width / tan( fov_x / 360 * M_PI );
 
525
        fov_y = atan2( cg.refdef.height, x );
 
526
        fov_y = fov_y * 360 / M_PI;
 
527
 
 
528
        // warp if underwater
 
529
        contents = CG_PointContents( cg.refdef.vieworg, -1 );
 
530
        if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
 
531
                phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
 
532
                v = WAVE_AMPLITUDE * sin( phase );
 
533
                fov_x += v;
 
534
                fov_y -= v;
 
535
                inwater = qtrue;
 
536
        }
 
537
        else {
 
538
                inwater = qfalse;
 
539
        }
 
540
 
 
541
 
 
542
        // set it
 
543
        cg.refdef.fov_x = fov_x;
 
544
        cg.refdef.fov_y = fov_y;
 
545
 
 
546
        if ( !cg.zoomed ) {
 
547
                cg.zoomSensitivity = 1;
 
548
        } else {
 
549
                cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
 
550
        }
 
551
 
 
552
        return inwater;
 
553
}
 
554
 
 
555
 
 
556
 
 
557
/*
 
558
===============
 
559
CG_DamageBlendBlob
 
560
 
 
561
===============
 
562
*/
 
563
static void CG_DamageBlendBlob( void ) {
 
564
        int                     t;
 
565
        int                     maxTime;
 
566
        refEntity_t             ent;
 
567
 
 
568
        if ( !cg.damageValue ) {
 
569
                return;
 
570
        }
 
571
 
 
572
        //if (cg.cameraMode) {
 
573
        //      return;
 
574
        //}
 
575
 
 
576
        // ragePro systems can't fade blends, so don't obscure the screen
 
577
        if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
 
578
                return;
 
579
        }
 
580
 
 
581
        maxTime = DAMAGE_TIME;
 
582
        t = cg.time - cg.damageTime;
 
583
        if ( t <= 0 || t >= maxTime ) {
 
584
                return;
 
585
        }
 
586
 
 
587
 
 
588
        memset( &ent, 0, sizeof( ent ) );
 
589
        ent.reType = RT_SPRITE;
 
590
        ent.renderfx = RF_FIRST_PERSON;
 
591
 
 
592
        VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
 
593
        VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
 
594
        VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
 
595
 
 
596
        ent.radius = cg.damageValue * 3;
 
597
        ent.customShader = cgs.media.viewBloodShader;
 
598
        ent.shaderRGBA[0] = 255;
 
599
        ent.shaderRGBA[1] = 255;
 
600
        ent.shaderRGBA[2] = 255;
 
601
        ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
 
602
        trap_R_AddRefEntityToScene( &ent );
 
603
}
 
604
 
 
605
 
 
606
/*
 
607
===============
 
608
CG_CalcViewValues
 
609
 
 
610
Sets cg.refdef view values
 
611
===============
 
612
*/
 
613
static int CG_CalcViewValues( void ) {
 
614
        playerState_t   *ps;
 
615
 
 
616
        memset( &cg.refdef, 0, sizeof( cg.refdef ) );
 
617
 
 
618
        // strings for in game rendering
 
619
        // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
 
620
        // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
 
621
 
 
622
        // calculate size of 3D view
 
623
        CG_CalcVrect();
 
624
 
 
625
        ps = &cg.predictedPlayerState;
 
626
/*
 
627
        if (cg.cameraMode) {
 
628
                vec3_t origin, angles;
 
629
                if (trap_getCameraInfo(cg.time, &origin, &angles)) {
 
630
                        VectorCopy(origin, cg.refdef.vieworg);
 
631
                        angles[ROLL] = 0;
 
632
                        VectorCopy(angles, cg.refdefViewAngles);
 
633
                        AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
 
634
                        return CG_CalcFov();
 
635
                } else {
 
636
                        cg.cameraMode = qfalse;
 
637
                }
 
638
        }
 
639
*/
 
640
        // intermission view
 
641
        if ( ps->pm_type == PM_INTERMISSION ) {
 
642
                VectorCopy( ps->origin, cg.refdef.vieworg );
 
643
                VectorCopy( ps->viewangles, cg.refdefViewAngles );
 
644
                AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
 
645
                return CG_CalcFov();
 
646
        }
 
647
 
 
648
        cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
 
649
        cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
 
650
        cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
 
651
                ps->velocity[1] * ps->velocity[1] );
 
652
 
 
653
 
 
654
        VectorCopy( ps->origin, cg.refdef.vieworg );
 
655
        VectorCopy( ps->viewangles, cg.refdefViewAngles );
 
656
 
 
657
        if (cg_cameraOrbit.integer) {
 
658
                if (cg.time > cg.nextOrbitTime) {
 
659
                        cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
 
660
                        cg_thirdPersonAngle.value += cg_cameraOrbit.value;
 
661
                }
 
662
        }
 
663
        // add error decay
 
664
        if ( cg_errorDecay.value > 0 ) {
 
665
                int             t;
 
666
                float   f;
 
667
 
 
668
                t = cg.time - cg.predictedErrorTime;
 
669
                f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
 
670
                if ( f > 0 && f < 1 ) {
 
671
                        VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
 
672
                } else {
 
673
                        cg.predictedErrorTime = 0;
 
674
                }
 
675
        }
 
676
 
 
677
        if ( cg.renderingThirdPerson ) {
 
678
                // back away from character
 
679
                CG_OffsetThirdPersonView();
 
680
        } else {
 
681
                // offset for local bobbing and kicks
 
682
                CG_OffsetFirstPersonView();
 
683
        }
 
684
 
 
685
        // position eye reletive to origin
 
686
        AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
 
687
 
 
688
        if ( cg.hyperspace ) {
 
689
                cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
 
690
        }
 
691
 
 
692
        // field of view
 
693
        return CG_CalcFov();
 
694
}
 
695
 
 
696
 
 
697
/*
 
698
=====================
 
699
CG_PowerupTimerSounds
 
700
=====================
 
701
*/
 
702
static void CG_PowerupTimerSounds( void ) {
 
703
        int             i;
 
704
        int             t;
 
705
 
 
706
        // powerup timers going away
 
707
        for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
 
708
                t = cg.snap->ps.powerups[i];
 
709
                if ( t <= cg.time ) {
 
710
                        continue;
 
711
                }
 
712
                if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
 
713
                        continue;
 
714
                }
 
715
                if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
 
716
                        trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
 
717
                }
 
718
        }
 
719
}
 
720
 
 
721
/*
 
722
=====================
 
723
CG_AddBufferedSound
 
724
=====================
 
725
*/
 
726
void CG_AddBufferedSound( sfxHandle_t sfx ) {
 
727
        if ( !sfx )
 
728
                return;
 
729
        cg.soundBuffer[cg.soundBufferIn] = sfx;
 
730
        cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
 
731
        if (cg.soundBufferIn == cg.soundBufferOut) {
 
732
                cg.soundBufferOut++;
 
733
        }
 
734
}
 
735
 
 
736
/*
 
737
=====================
 
738
CG_PlayBufferedSounds
 
739
=====================
 
740
*/
 
741
static void CG_PlayBufferedSounds( void ) {
 
742
        if ( cg.soundTime < cg.time ) {
 
743
                if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
 
744
                        trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
 
745
                        cg.soundBuffer[cg.soundBufferOut] = 0;
 
746
                        cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
 
747
                        cg.soundTime = cg.time + 750;
 
748
                }
 
749
        }
 
750
}
 
751
 
 
752
//=========================================================================
 
753
 
 
754
/*
 
755
=================
 
756
CG_DrawActiveFrame
 
757
 
 
758
Generates and draws a game scene and status information at the given time.
 
759
=================
 
760
*/
 
761
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
 
762
        int             inwater;
 
763
 
 
764
        cg.time = serverTime;
 
765
        cg.demoPlayback = demoPlayback;
 
766
 
 
767
        // update cvars
 
768
        CG_UpdateCvars();
 
769
 
 
770
        // if we are only updating the screen as a loading
 
771
        // pacifier, don't even try to read snapshots
 
772
        if ( cg.infoScreenText[0] != 0 ) {
 
773
                CG_DrawInformation();
 
774
                return;
 
775
        }
 
776
 
 
777
        // any looped sounds will be respecified as entities
 
778
        // are added to the render list
 
779
        trap_S_ClearLoopingSounds(qfalse);
 
780
 
 
781
        // clear all the render lists
 
782
        trap_R_ClearScene();
 
783
 
 
784
        // set up cg.snap and possibly cg.nextSnap
 
785
        CG_ProcessSnapshots();
 
786
 
 
787
        // if we haven't received any snapshots yet, all
 
788
        // we can draw is the information screen
 
789
        if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
 
790
                CG_DrawInformation();
 
791
                return;
 
792
        }
 
793
 
 
794
        // let the client system know what our weapon and zoom settings are
 
795
        trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
 
796
 
 
797
        // this counter will be bumped for every valid scene we generate
 
798
        cg.clientFrame++;
 
799
 
 
800
        // update cg.predictedPlayerState
 
801
        CG_PredictPlayerState();
 
802
 
 
803
        // decide on third person view
 
804
        cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
 
805
 
 
806
        // build cg.refdef
 
807
        inwater = CG_CalcViewValues();
 
808
 
 
809
        // first person blend blobs, done after AnglesToAxis
 
810
        if ( !cg.renderingThirdPerson ) {
 
811
                CG_DamageBlendBlob();
 
812
        }
 
813
 
 
814
        // build the render lists
 
815
        if ( !cg.hyperspace ) {
 
816
                CG_AddPacketEntities();                 // adter calcViewValues, so predicted player state is correct
 
817
                CG_AddMarks();
 
818
                CG_AddParticles ();
 
819
                CG_AddLocalEntities();
 
820
        }
 
821
        CG_AddViewWeapon( &cg.predictedPlayerState );
 
822
 
 
823
        // add buffered sounds
 
824
        CG_PlayBufferedSounds();
 
825
 
 
826
        // play buffered voice chats
 
827
        CG_PlayBufferedVoiceChats();
 
828
 
 
829
        // finish up the rest of the refdef
 
830
        if ( cg.testModelEntity.hModel ) {
 
831
                CG_AddTestModel();
 
832
        }
 
833
        cg.refdef.time = cg.time;
 
834
        memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
 
835
 
 
836
        // warning sounds when powerup is wearing off
 
837
        CG_PowerupTimerSounds();
 
838
 
 
839
        // update audio positions
 
840
        trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
 
841
 
 
842
        // make sure the lagometerSample and frame timing isn't done twice when in stereo
 
843
        if ( stereoView != STEREO_RIGHT ) {
 
844
                cg.frametime = cg.time - cg.oldTime;
 
845
                if ( cg.frametime < 0 ) {
 
846
                        cg.frametime = 0;
 
847
                }
 
848
                cg.oldTime = cg.time;
 
849
                CG_AddLagometerFrameInfo();
 
850
        }
 
851
        if (cg_timescale.value != cg_timescaleFadeEnd.value) {
 
852
                if (cg_timescale.value < cg_timescaleFadeEnd.value) {
 
853
                        cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
 
854
                        if (cg_timescale.value > cg_timescaleFadeEnd.value)
 
855
                                cg_timescale.value = cg_timescaleFadeEnd.value;
 
856
                }
 
857
                else {
 
858
                        cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
 
859
                        if (cg_timescale.value < cg_timescaleFadeEnd.value)
 
860
                                cg_timescale.value = cg_timescaleFadeEnd.value;
 
861
                }
 
862
                if (cg_timescaleFadeSpeed.value) {
 
863
                        trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
 
864
                }
 
865
        }
 
866
 
 
867
        // actually issue the rendering calls
 
868
        CG_DrawActive( stereoView );
 
869
 
 
870
        if ( cg_stats.integer ) {
 
871
                CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
 
872
        }
 
873
 
 
874
 
 
875
}
 
876