]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/d3xp/PlayerView.cpp
hello world
[icculus/iodoom3.git] / neo / d3xp / PlayerView.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "Game_local.h"
33
34 // _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge!
35
36 #ifdef _D3XP
37 static int MakePowerOfTwo( int num ) {
38         int             pot;
39         for (pot = 1 ; pot < num ; pot<<=1) {
40         }
41         return pot;
42 }
43 #endif
44
45 const int IMPULSE_DELAY = 150;
46 /*
47 ==============
48 idPlayerView::idPlayerView
49 ==============
50 */
51 idPlayerView::idPlayerView() {
52         memset( screenBlobs, 0, sizeof( screenBlobs ) );
53         memset( &view, 0, sizeof( view ) );
54         player = NULL;
55         dvMaterial = declManager->FindMaterial( "_scratch" );
56         tunnelMaterial = declManager->FindMaterial( "textures/decals/tunnel" );
57         armorMaterial = declManager->FindMaterial( "armorViewEffect" );
58         berserkMaterial = declManager->FindMaterial( "textures/decals/berserk" );
59         irGogglesMaterial = declManager->FindMaterial( "textures/decals/irblend" );
60         bloodSprayMaterial = declManager->FindMaterial( "textures/decals/bloodspray" );
61         bfgMaterial = declManager->FindMaterial( "textures/decals/bfgvision" );
62         lagoMaterial = declManager->FindMaterial( LAGO_MATERIAL, false );
63         bfgVision = false;
64         dvFinishTime = 0;
65         kickFinishTime = 0;
66         kickAngles.Zero();
67         lastDamageTime = 0.0f;
68         fadeTime = 0;
69         fadeRate = 0.0;
70         fadeFromColor.Zero();
71         fadeToColor.Zero();
72         fadeColor.Zero();
73         shakeAng.Zero();
74 #ifdef _D3XP
75         fxManager = NULL;
76
77         if ( !fxManager ) {
78                 fxManager = new FullscreenFXManager;
79                 fxManager->Initialize( this );
80         }
81 #endif
82
83         ClearEffects();
84 }
85
86 /*
87 ==============
88 idPlayerView::Save
89 ==============
90 */
91 void idPlayerView::Save( idSaveGame *savefile ) const {
92         int i;
93         const screenBlob_t *blob;
94
95         blob = &screenBlobs[ 0 ];
96         for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
97                 savefile->WriteMaterial( blob->material );
98                 savefile->WriteFloat( blob->x );
99                 savefile->WriteFloat( blob->y );
100                 savefile->WriteFloat( blob->w );
101                 savefile->WriteFloat( blob->h );
102                 savefile->WriteFloat( blob->s1 );
103                 savefile->WriteFloat( blob->t1 );
104                 savefile->WriteFloat( blob->s2 );
105                 savefile->WriteFloat( blob->t2 );
106                 savefile->WriteInt( blob->finishTime );
107                 savefile->WriteInt( blob->startFadeTime );
108                 savefile->WriteFloat( blob->driftAmount );
109         }
110
111         savefile->WriteInt( dvFinishTime );
112         savefile->WriteMaterial( dvMaterial );
113         savefile->WriteInt( kickFinishTime );
114         savefile->WriteAngles( kickAngles );
115         savefile->WriteBool( bfgVision );
116
117         savefile->WriteMaterial( tunnelMaterial );
118         savefile->WriteMaterial( armorMaterial );
119         savefile->WriteMaterial( berserkMaterial );
120         savefile->WriteMaterial( irGogglesMaterial );
121         savefile->WriteMaterial( bloodSprayMaterial );
122         savefile->WriteMaterial( bfgMaterial );
123         savefile->WriteFloat( lastDamageTime );
124
125         savefile->WriteVec4( fadeColor );
126         savefile->WriteVec4( fadeToColor );
127         savefile->WriteVec4( fadeFromColor );
128         savefile->WriteFloat( fadeRate );
129         savefile->WriteInt( fadeTime );
130
131         savefile->WriteAngles( shakeAng );
132
133         savefile->WriteObject( player );
134         savefile->WriteRenderView( view );
135
136 #ifdef _D3XP
137         if ( fxManager ) {
138                 fxManager->Save( savefile );
139         }
140 #endif
141 }
142
143 /*
144 ==============
145 idPlayerView::Restore
146 ==============
147 */
148 void idPlayerView::Restore( idRestoreGame *savefile ) {
149         int i;
150         screenBlob_t *blob;
151
152         blob = &screenBlobs[ 0 ];
153         for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
154                 savefile->ReadMaterial( blob->material );
155                 savefile->ReadFloat( blob->x );
156                 savefile->ReadFloat( blob->y );
157                 savefile->ReadFloat( blob->w );
158                 savefile->ReadFloat( blob->h );
159                 savefile->ReadFloat( blob->s1 );
160                 savefile->ReadFloat( blob->t1 );
161                 savefile->ReadFloat( blob->s2 );
162                 savefile->ReadFloat( blob->t2 );
163                 savefile->ReadInt( blob->finishTime );
164                 savefile->ReadInt( blob->startFadeTime );
165                 savefile->ReadFloat( blob->driftAmount );
166         }
167
168         savefile->ReadInt( dvFinishTime );
169         savefile->ReadMaterial( dvMaterial );
170         savefile->ReadInt( kickFinishTime );
171         savefile->ReadAngles( kickAngles );                     
172         savefile->ReadBool( bfgVision );
173
174         savefile->ReadMaterial( tunnelMaterial );
175         savefile->ReadMaterial( armorMaterial );
176         savefile->ReadMaterial( berserkMaterial );
177         savefile->ReadMaterial( irGogglesMaterial );
178         savefile->ReadMaterial( bloodSprayMaterial );
179         savefile->ReadMaterial( bfgMaterial );
180         savefile->ReadFloat( lastDamageTime );
181
182         savefile->ReadVec4( fadeColor );
183         savefile->ReadVec4( fadeToColor );
184         savefile->ReadVec4( fadeFromColor );
185         savefile->ReadFloat( fadeRate );
186         savefile->ReadInt( fadeTime );
187
188         savefile->ReadAngles( shakeAng );
189
190         savefile->ReadObject( reinterpret_cast<idClass *&>( player ) );
191         savefile->ReadRenderView( view );
192
193 #ifdef _D3XP
194         if ( fxManager ) {
195                 fxManager->Restore( savefile );
196         }
197 #endif
198 }
199
200 /*
201 ==============
202 idPlayerView::SetPlayerEntity
203 ==============
204 */
205 void idPlayerView::SetPlayerEntity( idPlayer *playerEnt ) {
206         player = playerEnt;
207 }
208
209 /*
210 ==============
211 idPlayerView::ClearEffects
212 ==============
213 */
214 void idPlayerView::ClearEffects() {
215         lastDamageTime = MS2SEC( gameLocal.slow.time - 99999 );
216
217         dvFinishTime = ( gameLocal.fast.time - 99999 );
218         kickFinishTime = ( gameLocal.slow.time - 99999 );
219
220         for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
221                 screenBlobs[i].finishTime = gameLocal.slow.time;
222         }
223
224         fadeTime = 0;
225         bfgVision = false;
226 }
227
228 /*
229 ==============
230 idPlayerView::GetScreenBlob
231 ==============
232 */
233 screenBlob_t *idPlayerView::GetScreenBlob() {
234         screenBlob_t    *oldest = &screenBlobs[0];
235
236         for ( int i = 1 ; i < MAX_SCREEN_BLOBS ; i++ ) {
237                 if ( screenBlobs[i].finishTime < oldest->finishTime ) {
238                         oldest = &screenBlobs[i];
239                 }
240         }
241         return oldest;
242 }
243
244 /*
245 ==============
246 idPlayerView::DamageImpulse
247
248 LocalKickDir is the direction of force in the player's coordinate system,
249 which will determine the head kick direction
250 ==============
251 */
252 void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) {
253         //
254         // double vision effect
255         //
256         if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.slow.time ) {
257                 // keep shotgun from obliterating the view
258                 return;
259         }
260
261         float   dvTime = damageDef->GetFloat( "dv_time" );
262         if ( dvTime ) {
263                 if ( dvFinishTime < gameLocal.fast.time ) {
264                         dvFinishTime = gameLocal.fast.time;
265                 }
266                 dvFinishTime += g_dvTime.GetFloat() * dvTime;
267                 // don't let it add up too much in god mode
268                 if ( dvFinishTime > gameLocal.fast.time + 5000 ) {
269                         dvFinishTime = gameLocal.fast.time + 5000;
270                 }
271         }
272
273         //
274         // head angle kick
275         //
276         float   kickTime = damageDef->GetFloat( "kick_time" );
277         if ( kickTime ) {
278                 kickFinishTime = gameLocal.slow.time + g_kickTime.GetFloat() * kickTime;
279
280                 // forward / back kick will pitch view
281                 kickAngles[0] = localKickDir[0];
282
283                 // side kick will yaw view
284                 kickAngles[1] = localKickDir[1]*0.5f;
285
286                 // up / down kick will pitch view
287                 kickAngles[0] += localKickDir[2];
288
289                 // roll will come from  side
290                 kickAngles[2] = localKickDir[1];
291
292                 float kickAmplitude = damageDef->GetFloat( "kick_amplitude" );
293                 if ( kickAmplitude ) {
294                         kickAngles *= kickAmplitude;
295                 }
296         }
297
298         //
299         // screen blob
300         //
301         float   blobTime = damageDef->GetFloat( "blob_time" );
302         if ( blobTime ) {
303                 screenBlob_t    *blob = GetScreenBlob();
304                 blob->startFadeTime = gameLocal.slow.time;
305                 blob->finishTime = gameLocal.slow.time + blobTime * g_blobTime.GetFloat() * ((float)gameLocal.msec / USERCMD_MSEC);
306
307                 const char *materialName = damageDef->GetString( "mtr_blob" );
308                 blob->material = declManager->FindMaterial( materialName );
309                 blob->x = damageDef->GetFloat( "blob_x" );
310                 blob->x += ( gameLocal.random.RandomInt()&63 ) - 32;
311                 blob->y = damageDef->GetFloat( "blob_y" );
312                 blob->y += ( gameLocal.random.RandomInt()&63 ) - 32;
313                 
314                 float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f;
315                 blob->w = damageDef->GetFloat( "blob_width" ) * g_blobSize.GetFloat() * scale;
316                 blob->h = damageDef->GetFloat( "blob_height" ) * g_blobSize.GetFloat() * scale;
317                 blob->s1 = 0;
318                 blob->t1 = 0;
319                 blob->s2 = 1;
320                 blob->t2 = 1;
321         }
322
323         //
324         // save lastDamageTime for tunnel vision accentuation
325         //
326         lastDamageTime = MS2SEC( gameLocal.slow.time );
327
328 }
329
330 /*
331 ==================
332 idPlayerView::AddBloodSpray
333
334 If we need a more generic way to add blobs then we can do that
335 but having it localized here lets the material be pre-looked up etc.
336 ==================
337 */
338 void idPlayerView::AddBloodSpray( float duration ) {
339 /*
340         if ( duration <= 0 || bloodSprayMaterial == NULL || g_skipViewEffects.GetBool() ) {
341                 return;
342         }
343         // visit this for chainsaw
344         screenBlob_t *blob = GetScreenBlob();
345         blob->startFadeTime = gameLocal.slow.time;
346         blob->finishTime = gameLocal.slow.time + ( duration * 1000 );
347         blob->material = bloodSprayMaterial;
348         blob->x = ( gameLocal.random.RandomInt() & 63 ) - 32;
349         blob->y = ( gameLocal.random.RandomInt() & 63 ) - 32;
350         blob->driftAmount = 0.5f + gameLocal.random.CRandomFloat() * 0.5;
351         float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f;
352         blob->w = 600 * g_blobSize.GetFloat() * scale;
353         blob->h = 480 * g_blobSize.GetFloat() * scale;
354         float s1 = 0.0f;
355         float t1 = 0.0f;
356         float s2 = 1.0f;
357         float t2 = 1.0f;
358         if ( blob->driftAmount < 0.6 ) {
359                 s1 = 1.0f;
360                 s2 = 0.0f;
361         } else if ( blob->driftAmount < 0.75 ) {
362                 t1 = 1.0f;
363                 t2 = 0.0f;
364         } else if ( blob->driftAmount < 0.85 ) {
365                 s1 = 1.0f;
366                 s2 = 0.0f;
367                 t1 = 1.0f;
368                 t2 = 0.0f;
369         }
370         blob->s1 = s1;
371         blob->t1 = t1;
372         blob->s2 = s2;
373         blob->t2 = t2;
374 */
375 }
376
377 /*
378 ==================
379 idPlayerView::WeaponFireFeedback
380
381 Called when a weapon fires, generates head twitches, etc
382 ==================
383 */
384 void idPlayerView::WeaponFireFeedback( const idDict *weaponDef ) {
385         int             recoilTime;
386
387         recoilTime = weaponDef->GetInt( "recoilTime" );
388         // don't shorten a damage kick in progress
389         if ( recoilTime && kickFinishTime < gameLocal.slow.time ) {
390                 idAngles angles;
391                 weaponDef->GetAngles( "recoilAngles", "5 0 0", angles );
392                 kickAngles = angles;
393                 int     finish = gameLocal.slow.time + g_kickTime.GetFloat() * recoilTime;
394                 kickFinishTime = finish;
395         }       
396
397 }
398
399 /*
400 ===================
401 idPlayerView::CalculateShake
402 ===================
403 */
404 void idPlayerView::CalculateShake() {
405         idVec3  origin, matrix;
406
407         float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.slow.time, player->firstPersonViewOrigin );
408         //
409         // shakeVolume should somehow be molded into an angle here
410         // it should be thought of as being in the range 0.0 -> 1.0, although
411         // since CurrentShakeAmplitudeForPosition() returns all the shake sounds
412         // the player can hear, it can go over 1.0 too.
413         //
414         shakeAng[0] = gameLocal.random.CRandomFloat() * shakeVolume;
415         shakeAng[1] = gameLocal.random.CRandomFloat() * shakeVolume;
416         shakeAng[2] = gameLocal.random.CRandomFloat() * shakeVolume;
417 }
418
419 /*
420 ===================
421 idPlayerView::ShakeAxis
422 ===================
423 */
424 idMat3 idPlayerView::ShakeAxis() const {
425         return shakeAng.ToMat3();
426 }
427
428 /*
429 ===================
430 idPlayerView::AngleOffset
431
432   kickVector, a world space direction that the attack should 
433 ===================
434 */
435 idAngles idPlayerView::AngleOffset() const {
436         idAngles        ang;
437
438         ang.Zero();
439
440         if ( gameLocal.slow.time < kickFinishTime ) {
441                 float offset = kickFinishTime - gameLocal.slow.time;
442
443                 ang = kickAngles * offset * offset * g_kickAmplitude.GetFloat();
444
445                 for ( int i = 0 ; i < 3 ; i++ ) {
446                         if ( ang[i] > 70.0f ) {
447                                 ang[i] = 70.0f;
448                         } else if ( ang[i] < -70.0f ) {
449                                 ang[i] = -70.0f;
450                         }
451                 }
452         }
453         return ang;
454 }
455
456 /*
457 ==================
458 idPlayerView::SingleView
459 ==================
460 */
461 void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) {
462
463         // normal rendering
464         if ( !view ) {
465                 return;
466         }
467
468         // place the sound origin for the player
469         gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1, gameLocal.slow.time, hud ? hud->State().GetString( "location" ) : "Undefined" );
470
471         // if the objective system is up, don't do normal drawing
472         if ( player->objectiveSystemOpen ) {
473                 player->objectiveSystem->Redraw( gameLocal.fast.time );
474                 return;
475         }
476
477         // hack the shake in at the very last moment, so it can't cause any consistency problems
478         renderView_t    hackedView = *view;
479         hackedView.viewaxis = hackedView.viewaxis * ShakeAxis();
480
481 #ifdef _D3XP
482         if ( gameLocal.portalSkyEnt.GetEntity() && gameLocal.IsPortalSkyAcive() && g_enablePortalSky.GetBool() ) {
483                 renderView_t    portalView = hackedView;
484                 portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
485
486                 // setup global fixup projection vars
487                 if ( 1 ) {
488                         int vidWidth, vidHeight;
489                         idVec2 shiftScale;
490
491                         renderSystem->GetGLSettings( vidWidth, vidHeight );
492
493                         float pot;
494                         int      w = vidWidth;
495                         pot = MakePowerOfTwo( w );
496                         shiftScale.x = (float)w / pot;
497
498                         int      h = vidHeight;
499                         pot = MakePowerOfTwo( h );
500                         shiftScale.y = (float)h / pot;
501
502                         hackedView.shaderParms[4] = shiftScale.x;
503                         hackedView.shaderParms[5] = shiftScale.y;
504                 }
505
506                 gameRenderWorld->RenderScene( &portalView );
507                 renderSystem->CaptureRenderToImage( "_currentRender" );
508
509                 hackedView.forceUpdate = true;                          // FIX: for smoke particles not drawing when portalSky present
510         }
511
512         // process the frame
513         fxManager->Process( &hackedView );
514 #endif
515
516         if ( player->spectating ) {
517                 return;
518         }
519
520 #ifdef _D3XP
521         if ( !hud ) {
522                 return;
523         }
524 #endif
525
526         // draw screen blobs
527         if ( !pm_thirdPerson.GetBool() && !g_skipViewEffects.GetBool() ) {
528                 for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
529                         screenBlob_t    *blob = &screenBlobs[i];
530                         if ( blob->finishTime <= gameLocal.slow.time ) {
531                                 continue;
532                         }
533                         
534                         blob->y += blob->driftAmount;
535
536                         float   fade = (float)( blob->finishTime - gameLocal.slow.time ) / ( blob->finishTime - blob->startFadeTime );
537                         if ( fade > 1.0f ) {
538                                 fade = 1.0f;
539                         }
540                         if ( fade ) {
541                                 renderSystem->SetColor4( 1,1,1,fade );
542                                 renderSystem->DrawStretchPic( blob->x, blob->y, blob->w, blob->h,blob->s1, blob->t1, blob->s2, blob->t2, blob->material );
543                         }
544                 }
545                 player->DrawHUD( hud );
546
547                 // armor impulse feedback
548                 float   armorPulse = ( gameLocal.fast.time - player->lastArmorPulse ) / 250.0f;
549
550                 if ( armorPulse > 0.0f && armorPulse < 1.0f ) {
551                         renderSystem->SetColor4( 1, 1, 1, 1.0 - armorPulse );
552                         renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, armorMaterial );
553                 }
554
555
556                 // tunnel vision
557                 float   health = 0.0f;
558                 if ( g_testHealthVision.GetFloat() != 0.0f ) {
559                         health = g_testHealthVision.GetFloat();
560                 } else {
561                         health = player->health;
562                 }
563                 float alpha = health / 100.0f;
564                 if ( alpha < 0.0f ) {
565                         alpha = 0.0f;
566                 }
567                 if ( alpha > 1.0f ) {
568                         alpha = 1.0f;
569                 }
570
571                 if ( alpha < 1.0f  ) {
572                         renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.slow.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha );
573                         renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, tunnelMaterial );
574                 }
575
576                 if ( bfgVision ) {
577                         renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
578                         renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, bfgMaterial );
579                 }
580                 
581         }
582
583         // test a single material drawn over everything
584         if ( g_testPostProcess.GetString()[0] ) {
585                 const idMaterial *mtr = declManager->FindMaterial( g_testPostProcess.GetString(), false );
586                 if ( !mtr ) {
587                         common->Printf( "Material not found.\n" );
588                         g_testPostProcess.SetString( "" );
589                 } else {
590                         renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
591                         renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, mtr );
592                 }
593         }
594 }
595
596
597 /*
598 =================
599 idPlayerView::Flash
600
601 flashes the player view with the given color
602 =================
603 */
604 void idPlayerView::Flash(idVec4 color, int time ) {
605         Fade(idVec4(0, 0, 0, 0), time);
606         fadeFromColor = colorWhite;
607 }
608
609 /*
610 =================
611 idPlayerView::Fade
612
613 used for level transition fades
614 assumes: color.w is 0 or 1
615 =================
616 */
617 void idPlayerView::Fade( idVec4 color, int time ) {
618 #ifdef _D3XP
619         SetTimeState ts( player->timeGroup );
620 #endif
621
622         if ( !fadeTime ) {
623                 fadeFromColor.Set( 0.0f, 0.0f, 0.0f, 1.0f - color[ 3 ] );
624         } else {
625                 fadeFromColor = fadeColor;
626         }
627         fadeToColor = color;
628
629         if ( time <= 0 ) {
630                 fadeRate = 0;
631                 time = 0;
632                 fadeColor = fadeToColor;
633         } else {
634                 fadeRate = 1.0f / ( float )time;
635         }
636
637         if ( gameLocal.realClientTime == 0 && time == 0 ) {
638                 fadeTime = 1;
639         } else {
640                 fadeTime = gameLocal.realClientTime + time;
641         }
642 }
643
644 /*
645 =================
646 idPlayerView::ScreenFade
647 =================
648 */
649 void idPlayerView::ScreenFade() {
650         int             msec;
651         float   t;
652
653         if ( !fadeTime ) {
654                 return;
655         }
656
657 #ifdef _D3XP
658         SetTimeState ts( player->timeGroup );
659 #endif
660
661         msec = fadeTime - gameLocal.realClientTime;
662
663         if ( msec <= 0 ) {
664                 fadeColor = fadeToColor;
665                 if ( fadeColor[ 3 ] == 0.0f ) {
666                         fadeTime = 0;
667                 }
668         } else {
669                 t = ( float )msec * fadeRate;
670                 fadeColor = fadeFromColor * t + fadeToColor * ( 1.0f - t );
671         }
672
673         if ( fadeColor[ 3 ] != 0.0f ) {
674                 renderSystem->SetColor4( fadeColor[ 0 ], fadeColor[ 1 ], fadeColor[ 2 ], fadeColor[ 3 ] );
675                 renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, declManager->FindMaterial( "_white" ) );
676         }
677 }
678
679 /*
680 ===================
681 idPlayerView::RenderPlayerView
682 ===================
683 */
684 void idPlayerView::RenderPlayerView( idUserInterface *hud ) {
685         const renderView_t *view = player->GetRenderView();
686
687         SingleView( hud, view );
688         ScreenFade();
689
690         if ( net_clientLagOMeter.GetBool() && lagoMaterial && gameLocal.isClient ) {
691                 renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
692                 renderSystem->DrawStretchPic( 10.0f, 380.0f, 64.0f, 64.0f, 0.0f, 0.0f, 1.0f, 1.0f, lagoMaterial );
693         }       
694 }
695
696 #ifdef _D3XP
697 /*
698 ===================
699 idPlayerView::WarpVision
700 ===================
701 */
702 int idPlayerView::AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ) {
703         FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
704
705         if ( fx ) {
706                 fx->EnableGrabber( true );
707                 return 1;
708         }
709
710         return 1;
711 }
712
713 void idPlayerView::FreeWarp( int id ) {
714         FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
715
716         if ( fx ) {
717                 fx->EnableGrabber( false );
718                 return;
719         }
720 }
721
722
723
724
725
726 /*
727 ==================
728 FxFader::FxFader
729 ==================
730 */
731 FxFader::FxFader() {
732         time = 0;
733         state = FX_STATE_OFF;
734         alpha = 0;
735         msec = 1000;
736 }
737
738 /*
739 ==================
740 FxFader::SetTriggerState
741 ==================
742 */
743 bool FxFader::SetTriggerState( bool active ) {
744
745         // handle on/off states
746         if ( active && state == FX_STATE_OFF ) {
747                 state = FX_STATE_RAMPUP;
748                 time = gameLocal.slow.time + msec;
749         }
750         else if ( !active && state == FX_STATE_ON ) {
751                 state = FX_STATE_RAMPDOWN;
752                 time = gameLocal.slow.time + msec;
753         }
754
755         // handle rampup/rampdown states
756         if ( state == FX_STATE_RAMPUP ) {
757                 if ( gameLocal.slow.time >= time ) {
758                         state = FX_STATE_ON;
759                 }
760         }
761         else if ( state == FX_STATE_RAMPDOWN ) {
762                 if ( gameLocal.slow.time >= time ) {
763                         state = FX_STATE_OFF;
764                 }
765         }
766
767         // compute alpha
768         switch ( state ) {
769                 case FX_STATE_ON:               alpha = 1; break;
770                 case FX_STATE_OFF:              alpha = 0; break;
771                 case FX_STATE_RAMPUP:   alpha = 1 - (float)( time - gameLocal.slow.time ) / msec; break;
772                 case FX_STATE_RAMPDOWN: alpha = (float)( time - gameLocal.slow.time ) / msec; break;
773         }
774
775         if ( alpha > 0 ) {
776                 return true;
777         }
778         else {
779                 return false;
780         }
781 }
782
783 /*
784 ==================
785 FxFader::Save
786 ==================
787 */
788 void FxFader::Save( idSaveGame *savefile ) {
789         savefile->WriteInt( time );
790         savefile->WriteInt( state );
791         savefile->WriteFloat( alpha );
792         savefile->WriteInt( msec );
793 }
794
795 /*
796 ==================
797 FxFader::Restore
798 ==================
799 */
800 void FxFader::Restore( idRestoreGame *savefile ) {
801         savefile->ReadInt( time );
802         savefile->ReadInt( state );
803         savefile->ReadFloat( alpha );
804         savefile->ReadInt( msec );
805 }
806
807
808
809
810
811 /*
812 ==================
813 FullscreenFX_Helltime::Save
814 ==================
815 */
816 void FullscreenFX::Save( idSaveGame *savefile ) {
817         fader.Save( savefile );
818 }
819
820 /*
821 ==================
822 FullscreenFX_Helltime::Restore
823 ==================
824 */
825 void FullscreenFX::Restore( idRestoreGame *savefile ) {
826         fader.Restore( savefile );
827 }
828
829
830 /*
831 ==================
832 FullscreenFX_Helltime::Initialize
833 ==================
834 */
835 void FullscreenFX_Helltime::Initialize() {
836         acInitMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_init" );
837         acInitMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_init" );
838         acInitMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_init" );
839
840         acCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_capture" );
841         acCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_capture" );
842         acCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_capture" );
843
844         acDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_draw" );
845         acDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_draw" );
846         acDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_draw" );
847
848         crCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_capture" );
849         crCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_capture" );
850         crCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_capture" );
851
852         crDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_draw" );
853         crDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_draw" );
854         crDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_draw" );
855
856         clearAccumBuffer = true;
857 }
858
859 /*
860 ==================
861 FullscreenFX_Helltime::DetermineLevel
862 ==================
863 */
864 int FullscreenFX_Helltime::DetermineLevel() {
865         idPlayer *player;
866         int testfx = g_testHelltimeFX.GetInteger();
867
868         // for testing purposes
869         if ( testfx >= 0 && testfx < 3 ) {
870                 return testfx;
871         }
872
873         player = fxman->GetPlayer();
874
875         if ( player->PowerUpActive( INVULNERABILITY ) ) {
876                 return 2;
877         }
878         else if ( player->PowerUpActive( BERSERK ) ) {
879                 return 1;
880         }
881         else if ( player->PowerUpActive( HELLTIME ) ) {
882                 return 0;
883         }
884
885         return -1;
886 }
887
888 /*
889 ==================
890 FullscreenFX_Helltime::Active
891 ==================
892 */
893 bool FullscreenFX_Helltime::Active() {
894
895         if ( gameLocal.inCinematic || gameLocal.isMultiplayer ) {
896                 return false;
897         }
898
899         if ( DetermineLevel() >= 0 ) {
900                 return true;
901         }
902         else {
903                 // latch the clear flag
904                 if ( fader.GetAlpha() == 0 ) {
905                         clearAccumBuffer = true;
906                 }
907         }
908
909         return false;
910 }
911
912 /*
913 ==================
914 FullscreenFX_Helltime::AccumPass
915 ==================
916 */
917 void FullscreenFX_Helltime::AccumPass( const renderView_t *view ) {
918         idVec2 shiftScale;
919         int level = DetermineLevel();
920
921         // for testing
922         if ( level < 0 || level > 2 ) {
923                 level = 0;
924         }
925
926         shiftScale = fxman->GetShiftScale();
927         renderSystem->SetColor4( 1, 1, 1, 1 );
928
929         // capture pass
930         if ( clearAccumBuffer ) {
931                 clearAccumBuffer = false;
932                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials[level] );
933         }
934         else {
935                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials[level] );
936                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials[level] );
937         }
938
939         renderSystem->CaptureRenderToImage( "_accum" );
940 }
941
942 /*
943 ==================
944 FullscreenFX_Helltime::HighQuality
945 ==================
946 */
947 void FullscreenFX_Helltime::HighQuality() {
948         idVec2 shiftScale;
949         int level = DetermineLevel();
950
951         // for testing
952         if ( level < 0 || level > 2 ) {
953                 level = 0;
954         }
955
956         shiftScale = fxman->GetShiftScale();
957         renderSystem->SetColor4( 1, 1, 1, 1 );
958
959         // draw pass
960         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials[level] );
961         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials[level] );
962 }
963
964 /*
965 ==================
966 FullscreenFX_Helltime::Restore
967 ==================
968 */
969 void FullscreenFX_Helltime::Restore( idRestoreGame *savefile ) {
970         FullscreenFX::Restore( savefile );
971
972         // latch the clear flag
973         clearAccumBuffer = true;
974 }
975
976
977
978
979
980 /*
981 ==================
982 FullscreenFX_Multiplayer::Initialize
983 ==================
984 */
985 void FullscreenFX_Multiplayer::Initialize() {
986         acInitMaterials         = declManager->FindMaterial( "textures/smf/multiplayer1/ac_init" );
987         acCaptureMaterials      = declManager->FindMaterial( "textures/smf/multiplayer1/ac_capture" );
988         acDrawMaterials         = declManager->FindMaterial( "textures/smf/multiplayer1/ac_draw" );
989         crCaptureMaterials      = declManager->FindMaterial( "textures/smf/multiplayer1/cr_capture" );
990         crDrawMaterials         = declManager->FindMaterial( "textures/smf/multiplayer1/cr_draw" );
991         clearAccumBuffer        = true;
992 }
993
994 /*
995 ==================
996 FullscreenFX_Multiplayer::DetermineLevel
997 ==================
998 */
999 int FullscreenFX_Multiplayer::DetermineLevel() {
1000         idPlayer *player;
1001         int testfx = g_testMultiplayerFX.GetInteger();
1002
1003         // for testing purposes
1004         if ( testfx >= 0 && testfx < 3 ) {
1005                 return testfx;
1006         }
1007
1008         player = fxman->GetPlayer();
1009
1010         if ( player->PowerUpActive( INVULNERABILITY ) ) {
1011                 return 2;
1012         }
1013         //else if ( player->PowerUpActive( HASTE ) ) {
1014         //      return 1;
1015         //}
1016         else if ( player->PowerUpActive( BERSERK ) ) {
1017                 return 0;
1018         }
1019
1020         return -1;
1021 }
1022
1023 /*
1024 ==================
1025 FullscreenFX_Multiplayer::Active
1026 ==================
1027 */
1028 bool FullscreenFX_Multiplayer::Active() {
1029
1030         if ( !gameLocal.isMultiplayer && g_testMultiplayerFX.GetInteger() == -1 ) {
1031                 return false;
1032         }
1033
1034         if ( DetermineLevel() >= 0 ) {
1035                 return true;
1036         }
1037         else {
1038                 // latch the clear flag
1039                 if ( fader.GetAlpha() == 0 ) {
1040                         clearAccumBuffer = true;
1041                 }
1042         }
1043
1044         return false;
1045 }
1046
1047 /*
1048 ==================
1049 FullscreenFX_Multiplayer::AccumPass
1050 ==================
1051 */
1052 void FullscreenFX_Multiplayer::AccumPass( const renderView_t *view ) {
1053         idVec2 shiftScale;
1054         int level = DetermineLevel();
1055
1056         // for testing
1057         if ( level < 0 || level > 2 ) {
1058                 level = 0;
1059         }
1060
1061         shiftScale = fxman->GetShiftScale();
1062         renderSystem->SetColor4( 1, 1, 1, 1 );
1063
1064         // capture pass
1065         if ( clearAccumBuffer ) {
1066                 clearAccumBuffer = false;
1067                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials );
1068         }
1069         else {
1070                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials );
1071                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials );
1072         }
1073
1074         renderSystem->CaptureRenderToImage( "_accum" );
1075 }
1076
1077 /*
1078 ==================
1079 FullscreenFX_Multiplayer::HighQuality
1080 ==================
1081 */
1082 void FullscreenFX_Multiplayer::HighQuality() {
1083         idVec2 shiftScale;
1084         int level = DetermineLevel();
1085
1086         // for testing
1087         if ( level < 0 || level > 2 ) {
1088                 level = 0;
1089         }
1090
1091         shiftScale = fxman->GetShiftScale();
1092         renderSystem->SetColor4( 1, 1, 1, 1 );
1093
1094         // draw pass
1095         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials );
1096         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials );
1097 }
1098
1099 /*
1100 ==================
1101 FullscreenFX_Multiplayer::Restore
1102 ==================
1103 */
1104 void FullscreenFX_Multiplayer::Restore( idRestoreGame *savefile ) {
1105         FullscreenFX::Restore( savefile );
1106
1107         // latch the clear flag
1108         clearAccumBuffer = true;
1109 }
1110
1111
1112
1113
1114
1115 /*
1116 ==================
1117 FullscreenFX_Warp::Initialize
1118 ==================
1119 */
1120 void FullscreenFX_Warp::Initialize() {
1121         material = declManager->FindMaterial( "textures/smf/warp" );
1122         grabberEnabled = false;
1123         startWarpTime = 0;
1124 }
1125
1126 /*
1127 ==================
1128 FullscreenFX_Warp::Active
1129 ==================
1130 */
1131 bool FullscreenFX_Warp::Active() {
1132         if ( grabberEnabled ) {
1133                 return true;
1134         }
1135
1136         return false;
1137 }
1138
1139 /*
1140 ==================
1141 FullscreenFX_Warp::Save
1142 ==================
1143 */
1144 void FullscreenFX_Warp::Save( idSaveGame *savefile ) {
1145         FullscreenFX::Save( savefile );
1146
1147         savefile->WriteBool( grabberEnabled );
1148         savefile->WriteInt( startWarpTime );
1149 }
1150
1151 /*
1152 ==================
1153 FullscreenFX_Warp::Restore
1154 ==================
1155 */
1156 void FullscreenFX_Warp::Restore( idRestoreGame *savefile ) {
1157         FullscreenFX::Restore( savefile );
1158
1159         savefile->ReadBool( grabberEnabled );
1160         savefile->ReadInt( startWarpTime );
1161 }
1162
1163 /*
1164 ==================
1165 FullscreenFX_Warp::DrawWarp
1166 ==================
1167 */
1168 void FullscreenFX_Warp::DrawWarp( WarpPolygon_t wp, float interp ) {
1169         idVec4 mid1_uv, mid2_uv;
1170         idVec4 mid1, mid2;
1171         idVec2 drawPts[6], shiftScale;
1172         WarpPolygon_t trans;
1173
1174         trans = wp;
1175         shiftScale = fxman->GetShiftScale();
1176
1177         // compute mid points
1178         mid1 = trans.outer1 * ( interp ) + trans.center * ( 1 - interp );
1179         mid2 = trans.outer2 * ( interp ) + trans.center * ( 1 - interp );
1180         mid1_uv = trans.outer1 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
1181         mid2_uv = trans.outer2 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
1182
1183         // draw [outer1, mid2, mid1]
1184         drawPts[0].Set( trans.outer1.x, trans.outer1.y );
1185         drawPts[1].Set( mid2.x, mid2.y );
1186         drawPts[2].Set( mid1.x, mid1.y );
1187         drawPts[3].Set( trans.outer1.z, trans.outer1.w );
1188         drawPts[4].Set( mid2_uv.z, mid2_uv.w );
1189         drawPts[5].Set( mid1_uv.z, mid1_uv.w );
1190         for ( int j = 0; j < 3; j++ ) {
1191                 drawPts[j+3].x *= shiftScale.x;
1192                 drawPts[j+3].y *= shiftScale.y;
1193         }
1194         renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
1195
1196         // draw [outer1, outer2, mid2]
1197         drawPts[0].Set( trans.outer1.x, trans.outer1.y );
1198         drawPts[1].Set( trans.outer2.x, trans.outer2.y );
1199         drawPts[2].Set( mid2.x, mid2.y );
1200         drawPts[3].Set( trans.outer1.z, trans.outer1.w );
1201         drawPts[4].Set( trans.outer2.z, trans.outer2.w );
1202         drawPts[5].Set( mid2_uv.z, mid2_uv.w );
1203         for ( int j = 0; j < 3; j++ ) {
1204                 drawPts[j+3].x *= shiftScale.x;
1205                 drawPts[j+3].y *= shiftScale.y;
1206         }
1207         renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
1208
1209         // draw [mid1, mid2, center]
1210         drawPts[0].Set( mid1.x, mid1.y );
1211         drawPts[1].Set( mid2.x, mid2.y );
1212         drawPts[2].Set( trans.center.x, trans.center.y );
1213         drawPts[3].Set( mid1_uv.z, mid1_uv.w );
1214         drawPts[4].Set( mid2_uv.z, mid2_uv.w );
1215         drawPts[5].Set( trans.center.z, trans.center.w );
1216         for ( int j = 0; j < 3; j++ ) {
1217                 drawPts[j+3].x *= shiftScale.x;
1218                 drawPts[j+3].y *= shiftScale.y;
1219         }
1220         renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
1221 }
1222
1223 /*
1224 ==================
1225 FullscreenFX_Warp::HighQuality
1226 ==================
1227 */
1228 void FullscreenFX_Warp::HighQuality() {
1229         float x1, y1, x2, y2, radius, interp;
1230         idVec2 center;
1231         int STEP = 9;
1232
1233         interp = ( idMath::Sin( (float)( gameLocal.slow.time - startWarpTime ) / 1000 ) + 1 ) / 2.f;
1234         interp = 0.7 * ( 1 - interp ) + 0.3 * ( interp );
1235
1236         // draw the warps
1237         center.x = 320;
1238         center.y = 240;
1239         radius = 200;
1240
1241         for ( float i = 0; i < 360; i += STEP ) {
1242                 // compute the values
1243                 x1 = idMath::Sin( DEG2RAD( i ) );
1244                 y1 = idMath::Cos( DEG2RAD( i ) );
1245
1246                 x2 = idMath::Sin( DEG2RAD( i + STEP ) );
1247                 y2 = idMath::Cos( DEG2RAD( i + STEP ) );
1248
1249                 // add warp polygon
1250                 WarpPolygon_t p;
1251
1252                 p.outer1.x = center.x + x1 * radius;
1253                 p.outer1.y = center.y + y1 * radius;
1254                 p.outer1.z = p.outer1.x / 640.f;
1255                 p.outer1.w = 1 - ( p.outer1.y / 480.f );
1256
1257                 p.outer2.x = center.x + x2 * radius;
1258                 p.outer2.y = center.y + y2 * radius;
1259                 p.outer2.z = p.outer2.x / 640.f;
1260                 p.outer2.w = 1 - ( p.outer2.y / 480.f );
1261
1262                 p.center.x = center.x;
1263                 p.center.y = center.y;
1264                 p.center.z = p.center.x / 640.f;
1265                 p.center.w = 1 - ( p.center.y / 480.f );
1266  
1267                 // draw it
1268                 DrawWarp( p, interp );
1269         }
1270 }
1271
1272
1273
1274
1275
1276 /*
1277 ==================
1278 FullscreenFX_EnviroSuit::Initialize
1279 ==================
1280 */
1281 void FullscreenFX_EnviroSuit::Initialize() {
1282         material = declManager->FindMaterial( "textures/smf/enviro_suit" );
1283 }
1284
1285 /*
1286 ==================
1287 FullscreenFX_EnviroSuit::Active
1288 ==================
1289 */
1290 bool FullscreenFX_EnviroSuit::Active() {
1291         idPlayer *player;
1292
1293         player = fxman->GetPlayer();
1294
1295         if ( player->PowerUpActive( ENVIROSUIT ) ) {
1296                 return true;
1297         }
1298
1299         return false;
1300 }
1301
1302 /*
1303 ==================
1304 FullscreenFX_EnviroSuit::HighQuality
1305 ==================
1306 */
1307 void FullscreenFX_EnviroSuit::HighQuality() {
1308         renderSystem->SetColor4( 1, 1, 1, 1 );
1309         renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, material );
1310 }
1311
1312
1313
1314
1315
1316 /*
1317 ==================
1318 FullscreenFX_DoubleVision::Initialize
1319 ==================
1320 */
1321 void FullscreenFX_DoubleVision::Initialize() {
1322         material = declManager->FindMaterial( "textures/smf/doubleVision" );
1323 }
1324
1325 /*
1326 ==================
1327 FullscreenFX_DoubleVision::Active
1328 ==================
1329 */
1330 bool FullscreenFX_DoubleVision::Active() {
1331
1332         if ( gameLocal.fast.time < fxman->GetPlayerView()->dvFinishTime ) {
1333                 return true;
1334         }
1335
1336         return false;
1337 }
1338
1339 /*
1340 ==================
1341 FullscreenFX_DoubleVision::HighQuality
1342 ==================
1343 */
1344 void FullscreenFX_DoubleVision::HighQuality() {
1345         int offset = fxman->GetPlayerView()->dvFinishTime - gameLocal.fast.time;
1346         float   scale = offset * g_dvAmplitude.GetFloat();
1347         idPlayer *player;
1348         idVec2 shiftScale;
1349
1350         // for testing purposes
1351         if ( !Active() ) {
1352                 static int test = 0;
1353                 if ( test > 312 ) {
1354                         test = 0;
1355                 }
1356
1357                 offset = test++;
1358                 scale = offset * g_dvAmplitude.GetFloat();
1359         }
1360
1361         player = fxman->GetPlayer();
1362         shiftScale = fxman->GetShiftScale();
1363
1364         offset *= 2;            // crutch up for higher res
1365
1366         // set the scale and shift
1367         if ( scale > 0.5f ) {
1368                 scale = 0.5f;
1369         }
1370         float shift = scale * sin( sqrtf( (float)offset ) * g_dvFrequency.GetFloat() );
1371         shift = fabs( shift );
1372
1373         // carry red tint if in berserk mode
1374         idVec4 color(1, 1, 1, 1);
1375         if ( gameLocal.fast.time < player->inventory.powerupEndTime[ BERSERK ] ) {
1376                 color.y = 0;
1377                 color.z = 0;
1378         }
1379
1380         if ( !gameLocal.isMultiplayer && gameLocal.fast.time < player->inventory.powerupEndTime[ HELLTIME ] || gameLocal.fast.time < player->inventory.powerupEndTime[ INVULNERABILITY ]) {
1381                 color.y = 0;
1382                 color.z = 0;
1383         }
1384
1385         renderSystem->SetColor4( color.x, color.y, color.z, 1.0f );
1386         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, shift, shiftScale.y, shiftScale.x, 0, material );
1387         renderSystem->SetColor4( color.x, color.y, color.z, 0.5f );
1388         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, (1-shift) * shiftScale.x, 0, material );
1389 }
1390
1391
1392
1393
1394 /*
1395 ==================
1396 FullscreenFX_InfluenceVision::Initialize
1397 ==================
1398 */
1399 void FullscreenFX_InfluenceVision::Initialize() {
1400
1401 }
1402
1403 /*
1404 ==================
1405 FullscreenFX_InfluenceVision::Active
1406 ==================
1407 */
1408 bool FullscreenFX_InfluenceVision::Active() {
1409         idPlayer *player;
1410
1411         player = fxman->GetPlayer();
1412
1413         if ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) {
1414                 return true;
1415         }
1416
1417         return false;
1418 }
1419
1420 /*
1421 ==================
1422 FullscreenFX_InfluenceVision::HighQuality
1423 ==================
1424 */
1425 void FullscreenFX_InfluenceVision::HighQuality() {
1426         float distance = 0.0f;
1427         float pct = 1.0f;
1428         idPlayer *player;
1429         idVec2 shiftScale;
1430
1431         shiftScale = fxman->GetShiftScale();
1432         player = fxman->GetPlayer();
1433
1434         if ( player->GetInfluenceEntity() ) {
1435                 distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length();
1436                 if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) {
1437                         pct = distance / player->GetInfluenceRadius();
1438                         pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct );
1439                 }
1440         }
1441
1442         if ( player->GetInfluenceMaterial() ) {
1443                 renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct );
1444                 renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() );
1445         } else if ( player->GetInfluenceEntity() == NULL ) {
1446                 return;
1447         } else {
1448 //              int offset =  25 + sinf( gameLocal.slow.time );
1449 //              DoubleVision( hud, view, pct * offset );
1450         }
1451 }
1452
1453
1454
1455
1456 /*
1457 ==================
1458 FullscreenFX_Bloom::Initialize
1459 ==================
1460 */
1461 void FullscreenFX_Bloom::Initialize() {
1462         drawMaterial            = declManager->FindMaterial( "textures/smf/bloom2/draw" );
1463         initMaterial            = declManager->FindMaterial( "textures/smf/bloom2/init" );
1464         currentMaterial         = declManager->FindMaterial( "textures/smf/bloom2/currentMaterial" );
1465
1466         currentIntensity        = 0;
1467         targetIntensity         = 0;
1468 }
1469
1470 /*
1471 ==================
1472 FullscreenFX_Bloom::Active
1473 ==================
1474 */
1475 bool FullscreenFX_Bloom::Active() {
1476         idPlayer *player;
1477
1478         player = fxman->GetPlayer();
1479
1480         if ( player && player->bloomEnabled ) {
1481                 return true;
1482         }
1483
1484         return false;
1485 }
1486
1487 /*
1488 ==================
1489 FullscreenFX_Bloom::HighQuality
1490 ==================
1491 */
1492 void FullscreenFX_Bloom::HighQuality() {
1493         float shift, delta;
1494         idVec2 shiftScale;
1495         idPlayer *player;
1496         int num;
1497
1498         shift = 1;
1499         player = fxman->GetPlayer();
1500         shiftScale = fxman->GetShiftScale();
1501         renderSystem->SetColor4( 1, 1, 1, 1 );
1502
1503         // if intensity value is different, start the blend
1504         targetIntensity = g_testBloomIntensity.GetFloat();
1505
1506         if ( player && player->bloomEnabled ) {
1507                 targetIntensity = player->bloomIntensity;
1508         }
1509
1510         delta = targetIntensity - currentIntensity;
1511         float step = 0.001f;
1512
1513         if ( step < fabs( delta ) ) {
1514                 if ( delta < 0 ) {
1515                         step = -step;
1516                 }
1517
1518                 currentIntensity += step;
1519         }
1520
1521         // draw the blends
1522         num = g_testBloomNumPasses.GetInteger();
1523
1524         for ( int i = 0; i < num; i++ ) {
1525                 float s1 = 0, t1 = 0, s2 = 1, t2 = 1;
1526                 float alpha;
1527
1528                 // do the center scale
1529                 s1 -= 0.5;
1530                 s1 *= shift;
1531                 s1 += 0.5;
1532                 s1 *= shiftScale.x;
1533
1534                 t1 -= 0.5;
1535                 t1 *= shift;
1536                 t1 += 0.5;
1537                 t1 *= shiftScale.y;
1538
1539                 s2 -= 0.5;
1540                 s2 *= shift;
1541                 s2 += 0.5;
1542                 s2 *= shiftScale.x;
1543
1544                 t2 -= 0.5;
1545                 t2 *= shift;
1546                 t2 += 0.5;
1547                 t2 *= shiftScale.y;
1548
1549                 // draw it
1550                 if ( num == 1 ) {
1551                         alpha = 1;
1552                 }
1553                 else {
1554                         alpha = 1 - (float)i / ( num - 1 );
1555                 }
1556
1557                 renderSystem->SetColor4( alpha, alpha, alpha, 1 );
1558                 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, s1, t2, s2, t1, drawMaterial );
1559
1560                 shift += currentIntensity;
1561         }
1562 }
1563
1564 /*
1565 ==================
1566 FullscreenFX_Bloom::Save
1567 ==================
1568 */
1569 void FullscreenFX_Bloom::Save( idSaveGame *savefile ) {
1570         FullscreenFX::Save( savefile );
1571         savefile->WriteFloat( currentIntensity );
1572         savefile->WriteFloat( targetIntensity );
1573 }
1574
1575 /*
1576 ==================
1577 FullscreenFX_Bloom::Restore
1578 ==================
1579 */
1580 void FullscreenFX_Bloom::Restore( idRestoreGame *savefile ) {
1581         FullscreenFX::Restore( savefile );
1582         savefile->ReadFloat( currentIntensity );
1583         savefile->ReadFloat( targetIntensity );
1584 }
1585
1586
1587
1588
1589
1590
1591 /*
1592 ==================
1593 FullscreenFXManager::FullscreenFXManager
1594 ==================
1595 */
1596 FullscreenFXManager::FullscreenFXManager() {
1597         highQualityMode = false;
1598         playerView = NULL;
1599         blendBackMaterial = NULL;
1600         shiftScale.Set( 0, 0 );
1601 }
1602
1603 /*
1604 ==================
1605 FullscreenFXManager::~FullscreenFXManager
1606 ==================
1607 */
1608 FullscreenFXManager::~FullscreenFXManager() {
1609
1610 }
1611
1612 /*
1613 ==================
1614 FullscreenFXManager::FindFX
1615 ==================
1616 */
1617 FullscreenFX* FullscreenFXManager::FindFX( idStr name ) {
1618         for ( int i = 0; i < fx.Num(); i++ ) {
1619                 if ( fx[i]->GetName() == name ) {
1620                         return fx[i];
1621                 }
1622         }
1623
1624         return NULL;
1625 }
1626
1627 /*
1628 ==================
1629 FullscreenFXManager::CreateFX
1630 ==================
1631 */
1632 void FullscreenFXManager::CreateFX( idStr name, idStr fxtype, int fade ) {
1633         FullscreenFX *pfx = NULL;
1634
1635         if ( fxtype == "helltime" ) {
1636                 pfx = new FullscreenFX_Helltime;
1637         }
1638         else if ( fxtype == "warp" ) {
1639                 pfx = new FullscreenFX_Warp;
1640         }
1641         else if ( fxtype == "envirosuit" ) {
1642                 pfx = new FullscreenFX_EnviroSuit;
1643         }
1644         else if ( fxtype == "doublevision" ) {
1645                 pfx = new FullscreenFX_DoubleVision;
1646         }
1647         else if ( fxtype == "multiplayer" ) {
1648                 pfx = new FullscreenFX_Multiplayer;
1649         }
1650         else if ( fxtype == "influencevision" ) {
1651                 pfx = new FullscreenFX_InfluenceVision;
1652         }
1653         else if ( fxtype == "bloom" ) {
1654                 pfx = new FullscreenFX_Bloom;
1655         }
1656         else {
1657                 assert( 0 );
1658         }
1659
1660         if ( pfx ) {
1661                 pfx->Initialize();
1662                 pfx->SetFXManager( this );
1663                 pfx->SetName( name );
1664                 pfx->SetFadeSpeed( fade );
1665                 fx.Append( pfx );
1666         }
1667 }
1668
1669 /*
1670 ==================
1671 FullscreenFXManager::Initialize
1672 ==================
1673 */
1674 void FullscreenFXManager::Initialize( idPlayerView *pv ) {
1675         // set the playerview
1676         playerView = pv;
1677         blendBackMaterial = declManager->FindMaterial( "textures/smf/blendBack" );
1678
1679         // allocate the fx
1680         CreateFX( "helltime", "helltime", 1000 );
1681         CreateFX( "warp", "warp", 0 );
1682         CreateFX( "envirosuit", "envirosuit", 500 );
1683         CreateFX( "doublevision", "doublevision", 0 );
1684         CreateFX( "multiplayer", "multiplayer", 1000 );
1685         CreateFX( "influencevision", "influencevision", 1000 );
1686         CreateFX( "bloom", "bloom", 0 );
1687
1688         // pre-cache the texture grab so we dont hitch
1689         renderSystem->CropRenderSize( 512, 512, true );
1690         renderSystem->CaptureRenderToImage( "_accum" );
1691         renderSystem->UnCrop();
1692
1693     renderSystem->CropRenderSize( 512, 256, true );
1694         renderSystem->CaptureRenderToImage( "_scratch" );
1695         renderSystem->UnCrop();
1696
1697         renderSystem->CaptureRenderToImage( "_currentRender" );
1698 }
1699
1700 /*
1701 ==================
1702 FullscreenFXManager::Blendback
1703 ==================
1704 */
1705 void FullscreenFXManager::Blendback( float alpha ) {
1706         // alpha fade
1707         if ( alpha < 1.f ) {
1708                 renderSystem->SetColor4( 1, 1, 1, 1 - alpha );
1709                 renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, shiftScale.y, shiftScale.x, 0.f, blendBackMaterial );
1710         }
1711 }
1712
1713 /*
1714 ==================
1715 FullscreenFXManager::Save
1716 ==================
1717 */
1718 void FullscreenFXManager::Save( idSaveGame *savefile ) {
1719         savefile->WriteBool( highQualityMode );
1720         savefile->WriteVec2( shiftScale );
1721
1722         for ( int i = 0; i < fx.Num(); i++ ) {
1723                 FullscreenFX *pfx = fx[i];
1724                 pfx->Save( savefile );
1725         }
1726 }
1727
1728 /*
1729 ==================
1730 FullscreenFXManager::Restore
1731 ==================
1732 */
1733 void FullscreenFXManager::Restore( idRestoreGame *savefile ) {
1734         savefile->ReadBool( highQualityMode );
1735         savefile->ReadVec2( shiftScale );
1736
1737         for ( int i = 0; i < fx.Num(); i++ ) {
1738                 FullscreenFX *pfx = fx[i];
1739                 pfx->Restore( savefile );
1740         }
1741 }
1742
1743 /*
1744 ==================
1745 FullscreenFXManager::CaptureCurrentRender
1746 ==================
1747 */
1748 void FullscreenFXManager::CaptureCurrentRender() {
1749         renderSystem->CaptureRenderToImage( "_currentRender" );
1750 }
1751
1752 /*
1753 ==================
1754 FullscreenFXManager::Process
1755 ==================
1756 */
1757 void FullscreenFXManager::Process( const renderView_t *view ) {
1758         bool allpass = false;
1759         bool atLeastOneFX = false;
1760
1761         if ( g_testFullscreenFX.GetInteger() == -2 ) {
1762                 allpass = true;
1763         }
1764
1765         if ( g_lowresFullscreenFX.GetBool() ) {
1766                 highQualityMode = false;
1767         }
1768         else {
1769                 highQualityMode = true;
1770         }
1771
1772         // compute the shift scale
1773         if ( highQualityMode ) {
1774                 int vidWidth, vidHeight;
1775                 renderSystem->GetGLSettings( vidWidth, vidHeight );
1776
1777                 float pot;
1778                 int      w = vidWidth;
1779                 pot = MakePowerOfTwo( w );
1780                 shiftScale.x = (float)w / pot;
1781
1782                 int      h = vidHeight;
1783                 pot = MakePowerOfTwo( h );
1784                 shiftScale.y = (float)h / pot;
1785         }
1786         else {
1787                 // if we're in low-res mode, shrink view down
1788                 shiftScale.x = 1;
1789                 shiftScale.y = 1;
1790                 renderSystem->CropRenderSize( 512, 512, true );
1791         }
1792
1793         // do the first render
1794         gameRenderWorld->RenderScene( view );
1795
1796         // do the process
1797         for ( int i = 0; i < fx.Num(); i++ ) {
1798                 FullscreenFX *pfx = fx[i];
1799                 bool drawIt = false;
1800
1801                 // determine if we need to draw
1802                 if ( pfx->Active() || g_testFullscreenFX.GetInteger() == i || allpass ) {
1803                         drawIt = pfx->SetTriggerState( true );
1804                 }
1805                 else {
1806                         drawIt = pfx->SetTriggerState( false );
1807                 }
1808
1809                 // do the actual drawing
1810                 if ( drawIt ) {
1811                         atLeastOneFX = true;
1812
1813                         // we need to dump to _currentRender
1814                         CaptureCurrentRender();
1815
1816                         // handle the accum pass if we have one
1817                         if ( pfx->HasAccum() ) {
1818
1819                                 // if we're in high quality mode, we need to crop the accum pass
1820                                 if ( highQualityMode ) {
1821                                         renderSystem->CropRenderSize( 512, 512, true );
1822                                         pfx->AccumPass( view );
1823                                         renderSystem->UnCrop();
1824                                 }
1825                                 else {
1826                                         pfx->AccumPass( view );
1827                                 }
1828                         }
1829
1830                         // do the high quality pass
1831                         pfx->HighQuality();
1832
1833                         // do the blendback
1834                         Blendback( pfx->GetFadeAlpha() );
1835                 }
1836         }
1837
1838         if ( !highQualityMode ) {
1839                 // we need to dump to _currentRender
1840                 CaptureCurrentRender();
1841
1842                 // uncrop view
1843                 renderSystem->UnCrop();
1844
1845                 // draw the final full-screen image
1846                 renderSystem->SetColor4( 1, 1, 1, 1 );
1847                 renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 1, 1, 0.f, blendBackMaterial );
1848         }
1849 }
1850
1851
1852
1853 #endif