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