mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-11-21 11:51:27 +00:00
1749 lines
42 KiB
C++
1749 lines
42 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Game_local.h"
|
|
|
|
// _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge!
|
|
|
|
const int IMPULSE_DELAY = 150;
|
|
/*
|
|
==============
|
|
idPlayerView::idPlayerView
|
|
==============
|
|
*/
|
|
idPlayerView::idPlayerView() {
|
|
memset( screenBlobs, 0, sizeof( screenBlobs ) );
|
|
memset( &view, 0, sizeof( view ) );
|
|
player = NULL;
|
|
tunnelMaterial = declManager->FindMaterial( "textures/decals/tunnel" );
|
|
armorMaterial = declManager->FindMaterial( "armorViewEffect" );
|
|
berserkMaterial = declManager->FindMaterial( "textures/decals/berserk" );
|
|
irGogglesMaterial = declManager->FindMaterial( "textures/decals/irblend" );
|
|
bloodSprayMaterial = declManager->FindMaterial( "textures/decals/bloodspray" );
|
|
bfgMaterial = declManager->FindMaterial( "textures/decals/bfgvision" );
|
|
bfgVision = false;
|
|
dvFinishTime = 0;
|
|
kickFinishTime = 0;
|
|
kickAngles.Zero();
|
|
lastDamageTime = 0.0f;
|
|
fadeTime = 0;
|
|
fadeRate = 0.0;
|
|
fadeFromColor.Zero();
|
|
fadeToColor.Zero();
|
|
fadeColor.Zero();
|
|
shakeAng.Zero();
|
|
fxManager = NULL;
|
|
|
|
if ( fxManager == NULL ) {
|
|
fxManager = new (TAG_ENTITY) FullscreenFXManager;
|
|
fxManager->Initialize( this );
|
|
}
|
|
|
|
ClearEffects();
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::~idPlayerView
|
|
==============
|
|
*/
|
|
idPlayerView::~idPlayerView() {
|
|
delete fxManager;
|
|
}
|
|
/*
|
|
==============
|
|
idPlayerView::Save
|
|
==============
|
|
*/
|
|
void idPlayerView::Save( idSaveGame *savefile ) const {
|
|
int i;
|
|
const screenBlob_t *blob;
|
|
|
|
blob = &screenBlobs[ 0 ];
|
|
for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
|
|
savefile->WriteMaterial( blob->material );
|
|
savefile->WriteFloat( blob->x );
|
|
savefile->WriteFloat( blob->y );
|
|
savefile->WriteFloat( blob->w );
|
|
savefile->WriteFloat( blob->h );
|
|
savefile->WriteFloat( blob->s1 );
|
|
savefile->WriteFloat( blob->t1 );
|
|
savefile->WriteFloat( blob->s2 );
|
|
savefile->WriteFloat( blob->t2 );
|
|
savefile->WriteInt( blob->finishTime );
|
|
savefile->WriteInt( blob->startFadeTime );
|
|
savefile->WriteFloat( blob->driftAmount );
|
|
}
|
|
|
|
savefile->WriteInt( dvFinishTime );
|
|
savefile->WriteInt( kickFinishTime );
|
|
savefile->WriteAngles( kickAngles );
|
|
savefile->WriteBool( bfgVision );
|
|
|
|
savefile->WriteMaterial( tunnelMaterial );
|
|
savefile->WriteMaterial( armorMaterial );
|
|
savefile->WriteMaterial( berserkMaterial );
|
|
savefile->WriteMaterial( irGogglesMaterial );
|
|
savefile->WriteMaterial( bloodSprayMaterial );
|
|
savefile->WriteMaterial( bfgMaterial );
|
|
savefile->WriteFloat( lastDamageTime );
|
|
|
|
savefile->WriteVec4( fadeColor );
|
|
savefile->WriteVec4( fadeToColor );
|
|
savefile->WriteVec4( fadeFromColor );
|
|
savefile->WriteFloat( fadeRate );
|
|
savefile->WriteInt( fadeTime );
|
|
|
|
savefile->WriteAngles( shakeAng );
|
|
|
|
savefile->WriteObject( player );
|
|
savefile->WriteRenderView( view );
|
|
|
|
if ( fxManager ) {
|
|
fxManager->Save( savefile );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::Restore
|
|
==============
|
|
*/
|
|
void idPlayerView::Restore( idRestoreGame *savefile ) {
|
|
int i;
|
|
screenBlob_t *blob;
|
|
|
|
blob = &screenBlobs[ 0 ];
|
|
for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
|
|
savefile->ReadMaterial( blob->material );
|
|
savefile->ReadFloat( blob->x );
|
|
savefile->ReadFloat( blob->y );
|
|
savefile->ReadFloat( blob->w );
|
|
savefile->ReadFloat( blob->h );
|
|
savefile->ReadFloat( blob->s1 );
|
|
savefile->ReadFloat( blob->t1 );
|
|
savefile->ReadFloat( blob->s2 );
|
|
savefile->ReadFloat( blob->t2 );
|
|
savefile->ReadInt( blob->finishTime );
|
|
savefile->ReadInt( blob->startFadeTime );
|
|
savefile->ReadFloat( blob->driftAmount );
|
|
}
|
|
|
|
savefile->ReadInt( dvFinishTime );
|
|
savefile->ReadInt( kickFinishTime );
|
|
savefile->ReadAngles( kickAngles );
|
|
savefile->ReadBool( bfgVision );
|
|
|
|
savefile->ReadMaterial( tunnelMaterial );
|
|
savefile->ReadMaterial( armorMaterial );
|
|
savefile->ReadMaterial( berserkMaterial );
|
|
savefile->ReadMaterial( irGogglesMaterial );
|
|
savefile->ReadMaterial( bloodSprayMaterial );
|
|
savefile->ReadMaterial( bfgMaterial );
|
|
savefile->ReadFloat( lastDamageTime );
|
|
|
|
savefile->ReadVec4( fadeColor );
|
|
savefile->ReadVec4( fadeToColor );
|
|
savefile->ReadVec4( fadeFromColor );
|
|
savefile->ReadFloat( fadeRate );
|
|
savefile->ReadInt( fadeTime );
|
|
|
|
savefile->ReadAngles( shakeAng );
|
|
|
|
savefile->ReadObject( reinterpret_cast<idClass *&>( player ) );
|
|
savefile->ReadRenderView( view );
|
|
|
|
if ( fxManager ) {
|
|
fxManager->Restore( savefile );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::SetPlayerEntity
|
|
==============
|
|
*/
|
|
void idPlayerView::SetPlayerEntity( idPlayer *playerEnt ) {
|
|
player = playerEnt;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::ClearEffects
|
|
==============
|
|
*/
|
|
void idPlayerView::ClearEffects() {
|
|
lastDamageTime = MS2SEC( gameLocal.slow.time - 99999 );
|
|
|
|
dvFinishTime = ( gameLocal.fast.time - 99999 );
|
|
kickFinishTime = ( gameLocal.slow.time - 99999 );
|
|
|
|
for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
|
|
screenBlobs[i].finishTime = gameLocal.fast.time;
|
|
}
|
|
|
|
fadeTime = 0;
|
|
bfgVision = false;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::GetScreenBlob
|
|
==============
|
|
*/
|
|
screenBlob_t *idPlayerView::GetScreenBlob() {
|
|
screenBlob_t * oldest = &screenBlobs[0];
|
|
|
|
for ( int i = 1 ; i < MAX_SCREEN_BLOBS ; i++ ) {
|
|
if ( screenBlobs[i].finishTime < oldest->finishTime ) {
|
|
oldest = &screenBlobs[i];
|
|
}
|
|
}
|
|
return oldest;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idPlayerView::DamageImpulse
|
|
|
|
LocalKickDir is the direction of force in the player's coordinate system,
|
|
which will determine the head kick direction
|
|
==============
|
|
*/
|
|
void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) {
|
|
//
|
|
// double vision effect
|
|
//
|
|
if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.slow.time ) {
|
|
// keep shotgun from obliterating the view
|
|
return;
|
|
}
|
|
|
|
float dvTime = damageDef->GetFloat( "dv_time" );
|
|
if ( dvTime ) {
|
|
if ( dvFinishTime < gameLocal.fast.time ) {
|
|
dvFinishTime = gameLocal.fast.time;
|
|
}
|
|
dvFinishTime += g_dvTime.GetFloat() * dvTime;
|
|
// don't let it add up too much in god mode
|
|
if ( dvFinishTime > gameLocal.fast.time + 5000 ) {
|
|
dvFinishTime = gameLocal.fast.time + 5000;
|
|
}
|
|
}
|
|
|
|
//
|
|
// head angle kick
|
|
//
|
|
float kickTime = damageDef->GetFloat( "kick_time" );
|
|
if ( kickTime ) {
|
|
kickFinishTime = gameLocal.slow.time + g_kickTime.GetFloat() * kickTime;
|
|
|
|
// forward / back kick will pitch view
|
|
kickAngles[0] = localKickDir[0];
|
|
|
|
// side kick will yaw view
|
|
kickAngles[1] = localKickDir[1]*0.5f;
|
|
|
|
// up / down kick will pitch view
|
|
kickAngles[0] += localKickDir[2];
|
|
|
|
// roll will come from side
|
|
kickAngles[2] = localKickDir[1];
|
|
|
|
float kickAmplitude = damageDef->GetFloat( "kick_amplitude" );
|
|
if ( kickAmplitude ) {
|
|
kickAngles *= kickAmplitude;
|
|
}
|
|
}
|
|
|
|
//
|
|
// screen blob
|
|
//
|
|
float blobTime = damageDef->GetFloat( "blob_time" );
|
|
if ( blobTime ) {
|
|
screenBlob_t *blob = GetScreenBlob();
|
|
blob->startFadeTime = gameLocal.fast.time;
|
|
blob->finishTime = gameLocal.fast.time + blobTime * g_blobTime.GetFloat();
|
|
|
|
const char *materialName = damageDef->GetString( "mtr_blob" );
|
|
blob->material = declManager->FindMaterial( materialName );
|
|
blob->x = damageDef->GetFloat( "blob_x" );
|
|
blob->x += ( gameLocal.random.RandomInt()&63 ) - 32;
|
|
blob->y = damageDef->GetFloat( "blob_y" );
|
|
blob->y += ( gameLocal.random.RandomInt()&63 ) - 32;
|
|
|
|
float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f;
|
|
blob->w = damageDef->GetFloat( "blob_width" ) * g_blobSize.GetFloat() * scale;
|
|
blob->h = damageDef->GetFloat( "blob_height" ) * g_blobSize.GetFloat() * scale;
|
|
blob->s1 = 0.0f;
|
|
blob->t1 = 0.0f;
|
|
blob->s2 = 1.0f;
|
|
blob->t2 = 1.0f;
|
|
}
|
|
|
|
//
|
|
// save lastDamageTime for tunnel vision accentuation
|
|
//
|
|
lastDamageTime = MS2SEC( gameLocal.fast.time );
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idPlayerView::WeaponFireFeedback
|
|
|
|
Called when a weapon fires, generates head twitches, etc
|
|
==================
|
|
*/
|
|
void idPlayerView::WeaponFireFeedback( const idDict *weaponDef ) {
|
|
int recoilTime = weaponDef->GetInt( "recoilTime" );
|
|
// don't shorten a damage kick in progress
|
|
if ( recoilTime && kickFinishTime < gameLocal.slow.time ) {
|
|
idAngles angles;
|
|
weaponDef->GetAngles( "recoilAngles", "5 0 0", angles );
|
|
kickAngles = angles;
|
|
int finish = gameLocal.slow.time + g_kickTime.GetFloat() * recoilTime;
|
|
kickFinishTime = finish;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::CalculateShake
|
|
===================
|
|
*/
|
|
void idPlayerView::CalculateShake() {
|
|
float shakeVolume = gameSoundWorld->CurrentShakeAmplitude();
|
|
//
|
|
// shakeVolume should somehow be molded into an angle here
|
|
// it should be thought of as being in the range 0.0 -> 1.0, although
|
|
// since CurrentShakeAmplitudeForPosition() returns all the shake sounds
|
|
// the player can hear, it can go over 1.0 too.
|
|
//
|
|
shakeAng[0] = gameLocal.random.CRandomFloat() * shakeVolume;
|
|
shakeAng[1] = gameLocal.random.CRandomFloat() * shakeVolume;
|
|
shakeAng[2] = gameLocal.random.CRandomFloat() * shakeVolume;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::ShakeAxis
|
|
===================
|
|
*/
|
|
idMat3 idPlayerView::ShakeAxis() const {
|
|
return shakeAng.ToMat3();
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::AngleOffset
|
|
|
|
kickVector, a world space direction that the attack should
|
|
===================
|
|
*/
|
|
idAngles idPlayerView::AngleOffset() const {
|
|
idAngles ang( 0.0f, 0.0f, 0.0f );
|
|
|
|
if ( gameLocal.slow.time < kickFinishTime ) {
|
|
float offset = kickFinishTime - gameLocal.slow.time;
|
|
|
|
ang = kickAngles * offset * offset * g_kickAmplitude.GetFloat();
|
|
|
|
for ( int i = 0 ; i < 3 ; i++ ) {
|
|
if ( ang[i] > 70.0f ) {
|
|
ang[i] = 70.0f;
|
|
} else if ( ang[i] < -70.0f ) {
|
|
ang[i] = -70.0f;
|
|
}
|
|
}
|
|
}
|
|
return ang;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idPlayerView::SingleView
|
|
==================
|
|
*/
|
|
void idPlayerView::SingleView( const renderView_t *view, idMenuHandler_HUD * hudManager ) {
|
|
|
|
// normal rendering
|
|
if ( !view ) {
|
|
return;
|
|
}
|
|
|
|
// place the sound origin for the player
|
|
gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1 );
|
|
|
|
// if the objective system is up, don't do normal drawing
|
|
if ( player->objectiveSystemOpen ) {
|
|
if ( player->pdaMenu != NULL ) {
|
|
player->pdaMenu->Update();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// hack the shake in at the very last moment, so it can't cause any consistency problems
|
|
renderView_t hackedView = *view;
|
|
hackedView.viewaxis = hackedView.viewaxis * ShakeAxis();
|
|
|
|
if ( gameLocal.portalSkyEnt.GetEntity() && gameLocal.IsPortalSkyAcive() && g_enablePortalSky.GetBool() ) {
|
|
renderView_t portalView = hackedView;
|
|
portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
|
|
gameRenderWorld->RenderScene( &portalView );
|
|
renderSystem->CaptureRenderToImage( "_currentRender" );
|
|
|
|
hackedView.forceUpdate = true; // FIX: for smoke particles not drawing when portalSky present
|
|
}
|
|
|
|
// process the frame
|
|
fxManager->Process( &hackedView );
|
|
|
|
if ( !hudManager ) {
|
|
return;
|
|
}
|
|
|
|
// draw screen blobs
|
|
if ( !pm_thirdPerson.GetBool() && !g_skipViewEffects.GetBool() ) {
|
|
if ( !player->spectating ) {
|
|
for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
|
|
screenBlob_t *blob = &screenBlobs[i];
|
|
if ( blob->finishTime <= gameLocal.fast.time ) {
|
|
continue;
|
|
}
|
|
|
|
blob->y += blob->driftAmount;
|
|
|
|
float fade = (float)( blob->finishTime - gameLocal.fast.time ) / ( blob->finishTime - blob->startFadeTime );
|
|
if ( fade > 1.0f ) {
|
|
fade = 1.0f;
|
|
}
|
|
if ( fade ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, fade );
|
|
renderSystem->DrawStretchPic( blob->x, blob->y, blob->w, blob->h,blob->s1, blob->t1, blob->s2, blob->t2, blob->material );
|
|
}
|
|
}
|
|
}
|
|
player->DrawHUD( hudManager );
|
|
|
|
if ( player->spectating ) {
|
|
return;
|
|
}
|
|
|
|
// armor impulse feedback
|
|
float armorPulse = ( gameLocal.fast.time - player->lastArmorPulse ) / 250.0f;
|
|
|
|
if ( armorPulse > 0.0f && armorPulse < 1.0f ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f - armorPulse );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, armorMaterial );
|
|
}
|
|
|
|
|
|
// tunnel vision
|
|
float health = 0.0f;
|
|
if ( g_testHealthVision.GetFloat() != 0.0f ) {
|
|
health = g_testHealthVision.GetFloat();
|
|
} else {
|
|
health = player->health;
|
|
}
|
|
float alpha = health / 100.0f;
|
|
if ( alpha < 0.0f ) {
|
|
alpha = 0.0f;
|
|
}
|
|
if ( alpha > 1.0f ) {
|
|
alpha = 1.0f;
|
|
}
|
|
|
|
if ( alpha < 1.0f ) {
|
|
renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.slow.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, tunnelMaterial );
|
|
}
|
|
|
|
if ( bfgVision ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, bfgMaterial );
|
|
}
|
|
|
|
}
|
|
|
|
// test a single material drawn over everything
|
|
if ( g_testPostProcess.GetString()[0] ) {
|
|
const idMaterial *mtr = declManager->FindMaterial( g_testPostProcess.GetString(), false );
|
|
if ( !mtr ) {
|
|
common->Printf( "Material not found.\n" );
|
|
g_testPostProcess.SetString( "" );
|
|
} else {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, mtr );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
idPlayerView::Flash
|
|
|
|
flashes the player view with the given color
|
|
=================
|
|
*/
|
|
void idPlayerView::Flash(idVec4 color, int time ) {
|
|
Fade( idVec4( 0.0f, 0.0f, 0.0f, 0.0f ), time);
|
|
fadeFromColor = colorWhite;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idPlayerView::Fade
|
|
|
|
used for level transition fades
|
|
assumes: color.w is 0 or 1
|
|
=================
|
|
*/
|
|
void idPlayerView::Fade( idVec4 color, int time ) {
|
|
SetTimeState ts( player->timeGroup );
|
|
|
|
if ( !fadeTime ) {
|
|
fadeFromColor.Set( 0.0f, 0.0f, 0.0f, 1.0f - color[ 3 ] );
|
|
} else {
|
|
fadeFromColor = fadeColor;
|
|
}
|
|
fadeToColor = color;
|
|
|
|
if ( time <= 0 ) {
|
|
fadeRate = 0;
|
|
time = 0;
|
|
fadeColor = fadeToColor;
|
|
} else {
|
|
fadeRate = 1.0f / ( float )time;
|
|
}
|
|
|
|
if ( gameLocal.realClientTime == 0 && time == 0 ) {
|
|
fadeTime = 1;
|
|
} else {
|
|
fadeTime = gameLocal.realClientTime + time;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idPlayerView::ScreenFade
|
|
=================
|
|
*/
|
|
void idPlayerView::ScreenFade() {
|
|
if ( !fadeTime ) {
|
|
return;
|
|
}
|
|
|
|
SetTimeState ts( player->timeGroup );
|
|
|
|
int msec = fadeTime - gameLocal.realClientTime;
|
|
|
|
if ( msec <= 0 ) {
|
|
fadeColor = fadeToColor;
|
|
if ( fadeColor[ 3 ] == 0.0f ) {
|
|
fadeTime = 0;
|
|
}
|
|
} else {
|
|
float t = ( float )msec * fadeRate;
|
|
fadeColor = fadeFromColor * t + fadeToColor * ( 1.0f - t );
|
|
}
|
|
|
|
if ( fadeColor[ 3 ] != 0.0f ) {
|
|
renderSystem->SetColor4( fadeColor[ 0 ], fadeColor[ 1 ], fadeColor[ 2 ], fadeColor[ 3 ] );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, declManager->FindMaterial( "_white" ) );
|
|
}
|
|
}
|
|
|
|
idCVar stereoRender_interOccularCentimeters( "stereoRender_interOccularCentimeters", "3.0", CVAR_ARCHIVE | CVAR_RENDERER, "Distance between eyes" );
|
|
idCVar stereoRender_convergence( "stereoRender_convergence", "6", CVAR_RENDERER, "0 = head mounted display, otherwise world units to convergence plane" );
|
|
|
|
extern idCVar stereoRender_screenSeparation; // screen units from center to eyes
|
|
extern idCVar stereoRender_swapEyes;
|
|
|
|
// In a head mounted display with separate displays for each eye,
|
|
// screen separation will be zero and world separation will be the eye distance.
|
|
struct stereoDistances_t {
|
|
// Offset to projection matrix, positive one eye, negative the other.
|
|
// Total distance is twice this, so 0.05 would give a 10% of screen width
|
|
// separation for objects at infinity.
|
|
float screenSeparation;
|
|
|
|
// Game world units from one eye to the centerline.
|
|
// Total distance is twice this.
|
|
float worldSeparation;
|
|
};
|
|
|
|
float CentimetersToInches( const float cm ) {
|
|
return cm / 2.54f;
|
|
}
|
|
|
|
float CentimetersToWorldUnits( const float cm ) {
|
|
// In Doom 3, one world unit == one inch
|
|
return CentimetersToInches( cm );
|
|
}
|
|
|
|
float CalculateWorldSeparation(
|
|
const float screenSeparation,
|
|
const float convergenceDistance,
|
|
const float fov_x_degrees ) {
|
|
|
|
const float fovRadians = DEG2RAD( fov_x_degrees );
|
|
const float screen = tan( fovRadians * 0.5f ) * fabs( screenSeparation );
|
|
const float worldSeparation = screen * convergenceDistance / 0.5f;
|
|
|
|
return worldSeparation;
|
|
}
|
|
|
|
stereoDistances_t CaclulateStereoDistances(
|
|
const float interOcularCentimeters, // distance between two eyes, typically 6.0 - 7.0
|
|
const float screenWidthCentimeters, // read from operating system
|
|
const float convergenceWorldUnits, // pass 0 for head mounted display mode
|
|
const float fov_x_degrees ) { // edge to edge horizontal field of view, typically 60 - 90
|
|
|
|
stereoDistances_t dists = {};
|
|
|
|
if ( convergenceWorldUnits == 0.0f ) {
|
|
// head mounted display mode
|
|
dists.worldSeparation = CentimetersToInches( interOcularCentimeters * 0.5 );
|
|
dists.screenSeparation = 0.0f;
|
|
return dists;
|
|
}
|
|
|
|
// 3DTV mode
|
|
dists.screenSeparation = 0.5f * interOcularCentimeters / screenWidthCentimeters;
|
|
dists.worldSeparation = CalculateWorldSeparation( dists.screenSeparation, convergenceWorldUnits, fov_x_degrees );
|
|
|
|
return dists;
|
|
}
|
|
|
|
float GetScreenSeparationForGuis() {
|
|
const stereoDistances_t dists = CaclulateStereoDistances(
|
|
stereoRender_interOccularCentimeters.GetFloat(),
|
|
renderSystem->GetPhysicalScreenWidthInCentimeters(),
|
|
stereoRender_convergence.GetFloat(),
|
|
80.0f /* fov */ );
|
|
|
|
return dists.screenSeparation;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::EmitStereoEyeView
|
|
===================
|
|
*/
|
|
void idPlayerView::EmitStereoEyeView( const int eye, idMenuHandler_HUD * hudManager ) {
|
|
renderView_t * view = player->GetRenderView();
|
|
if ( view == NULL ) {
|
|
return;
|
|
}
|
|
|
|
renderView_t eyeView = *view;
|
|
|
|
const stereoDistances_t dists = CaclulateStereoDistances(
|
|
stereoRender_interOccularCentimeters.GetFloat(),
|
|
renderSystem->GetPhysicalScreenWidthInCentimeters(),
|
|
stereoRender_convergence.GetFloat(),
|
|
view->fov_x );
|
|
|
|
eyeView.vieworg += eye * dists.worldSeparation * eyeView.viewaxis[1];
|
|
|
|
eyeView.viewEyeBuffer = stereoRender_swapEyes.GetBool() ? eye : -eye;
|
|
eyeView.stereoScreenSeparation = eye * dists.screenSeparation;
|
|
|
|
SingleView( &eyeView, hudManager );
|
|
}
|
|
|
|
/*
|
|
===================
|
|
IsGameStereoRendered
|
|
|
|
The crosshair is swapped for a laser sight in stereo rendering
|
|
===================
|
|
*/
|
|
bool IsGameStereoRendered() {
|
|
if ( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int EyeForHalfRateFrame( const int frameCount ) {
|
|
return ( renderSystem->GetFrameCount() & 1 ) ? -1 : 1;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::RenderPlayerView
|
|
===================
|
|
*/
|
|
void idPlayerView::RenderPlayerView( idMenuHandler_HUD * hudManager ) {
|
|
const renderView_t *view = player->GetRenderView();
|
|
if ( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) {
|
|
// render both eye views each frame on the PC
|
|
for ( int eye = 1 ; eye >= -1 ; eye -= 2 ) {
|
|
EmitStereoEyeView( eye, hudManager );
|
|
}
|
|
} else
|
|
{
|
|
SingleView( view, hudManager );
|
|
}
|
|
ScreenFade();
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idPlayerView::WarpVision
|
|
===================
|
|
*/
|
|
int idPlayerView::AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ) {
|
|
FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
|
|
|
|
if ( fx ) {
|
|
fx->EnableGrabber( true );
|
|
return 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void idPlayerView::FreeWarp( int id ) {
|
|
FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
|
|
|
|
if ( fx ) {
|
|
fx->EnableGrabber( false );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FxFader::FxFader
|
|
==================
|
|
*/
|
|
FxFader::FxFader() {
|
|
time = 0;
|
|
state = FX_STATE_OFF;
|
|
alpha = 0;
|
|
msec = 1000;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FxFader::SetTriggerState
|
|
==================
|
|
*/
|
|
bool FxFader::SetTriggerState( bool active ) {
|
|
|
|
// handle on/off states
|
|
if ( active && state == FX_STATE_OFF ) {
|
|
state = FX_STATE_RAMPUP;
|
|
time = gameLocal.slow.time + msec;
|
|
}
|
|
else if ( !active && state == FX_STATE_ON ) {
|
|
state = FX_STATE_RAMPDOWN;
|
|
time = gameLocal.slow.time + msec;
|
|
}
|
|
|
|
// handle rampup/rampdown states
|
|
if ( state == FX_STATE_RAMPUP ) {
|
|
if ( gameLocal.slow.time >= time ) {
|
|
state = FX_STATE_ON;
|
|
}
|
|
}
|
|
else if ( state == FX_STATE_RAMPDOWN ) {
|
|
if ( gameLocal.slow.time >= time ) {
|
|
state = FX_STATE_OFF;
|
|
}
|
|
}
|
|
|
|
// compute alpha
|
|
switch ( state ) {
|
|
case FX_STATE_ON: alpha = 1; break;
|
|
case FX_STATE_OFF: alpha = 0; break;
|
|
case FX_STATE_RAMPUP: alpha = 1 - (float)( time - gameLocal.slow.time ) / msec; break;
|
|
case FX_STATE_RAMPDOWN: alpha = (float)( time - gameLocal.slow.time ) / msec; break;
|
|
}
|
|
|
|
if ( alpha > 0 ) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FxFader::Save
|
|
==================
|
|
*/
|
|
void FxFader::Save( idSaveGame *savefile ) {
|
|
savefile->WriteInt( time );
|
|
savefile->WriteInt( state );
|
|
savefile->WriteFloat( alpha );
|
|
savefile->WriteInt( msec );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FxFader::Restore
|
|
==================
|
|
*/
|
|
void FxFader::Restore( idRestoreGame *savefile ) {
|
|
savefile->ReadInt( time );
|
|
savefile->ReadInt( state );
|
|
savefile->ReadFloat( alpha );
|
|
savefile->ReadInt( msec );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::Save
|
|
==================
|
|
*/
|
|
void FullscreenFX::Save( idSaveGame *savefile ) {
|
|
fader.Save( savefile );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFX::Restore( idRestoreGame *savefile ) {
|
|
fader.Restore( savefile );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_Helltime::Initialize() {
|
|
initMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/init" );
|
|
drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/draw" );
|
|
|
|
captureMaterials[0] = declManager->FindMaterial( "textures/d3bfg/bloodorb1/capture" );
|
|
captureMaterials[1] = declManager->FindMaterial( "textures/d3bfg/bloodorb2/capture" );
|
|
captureMaterials[2] = declManager->FindMaterial( "textures/d3bfg/bloodorb3/capture" );
|
|
|
|
clearAccumBuffer = true;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::DetermineLevel
|
|
==================
|
|
*/
|
|
int FullscreenFX_Helltime::DetermineLevel() {
|
|
int testfx = g_testHelltimeFX.GetInteger();
|
|
|
|
// for testing purposes
|
|
if ( testfx >= 0 && testfx < 3 ) {
|
|
return testfx;
|
|
}
|
|
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if ( player != NULL && player->PowerUpActive( INVULNERABILITY ) ) {
|
|
return 2;
|
|
}
|
|
else if ( player != NULL && player->PowerUpActive( BERSERK ) ) {
|
|
return 1;
|
|
}
|
|
else if ( player != NULL && player->PowerUpActive( HELLTIME ) ) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_Helltime::Active() {
|
|
|
|
if ( gameLocal.inCinematic || common->IsMultiplayer() ) {
|
|
return false;
|
|
}
|
|
|
|
if ( DetermineLevel() >= 0 ) {
|
|
return true;
|
|
}
|
|
else {
|
|
// latch the clear flag
|
|
if ( fader.GetAlpha() == 0 ) {
|
|
clearAccumBuffer = true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::AccumPass
|
|
==================
|
|
*/
|
|
void FullscreenFX_Helltime::AccumPass( const renderView_t *view ) {
|
|
|
|
int level = DetermineLevel();
|
|
|
|
// for testing
|
|
if ( level < 0 || level > 2 ) {
|
|
level = 0;
|
|
}
|
|
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
float t0 = 1.0f;
|
|
float t1 = 0.0f;
|
|
|
|
// capture pass
|
|
if ( clearAccumBuffer ) {
|
|
clearAccumBuffer = false;
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, initMaterial );
|
|
} else {
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, captureMaterials[level] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_Helltime::HighQuality() {
|
|
float t0 = 1.0f;
|
|
float t1 = 0.0f;
|
|
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, drawMaterial );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Helltime::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFX_Helltime::Restore( idRestoreGame *savefile ) {
|
|
FullscreenFX::Restore( savefile );
|
|
|
|
// latch the clear flag
|
|
clearAccumBuffer = true;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_Multiplayer::Initialize() {
|
|
initMaterial = declManager->FindMaterial( "textures/d3bfg/multiplayer/init" );
|
|
captureMaterial = declManager->FindMaterial( "textures/d3bfg/multiplayer/capture" );
|
|
drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/draw" );
|
|
clearAccumBuffer = true;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::DetermineLevel
|
|
==================
|
|
*/
|
|
int FullscreenFX_Multiplayer::DetermineLevel() {
|
|
int testfx = g_testMultiplayerFX.GetInteger();
|
|
|
|
// for testing purposes
|
|
if ( testfx >= 0 && testfx < 3 ) {
|
|
return testfx;
|
|
}
|
|
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if ( player != NULL && player->PowerUpActive( INVULNERABILITY ) ) {
|
|
return 2;
|
|
}
|
|
//else if ( player->PowerUpActive( HASTE ) ) {
|
|
// return 1;
|
|
//}
|
|
else if ( player != NULL && player->PowerUpActive( BERSERK ) ) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_Multiplayer::Active() {
|
|
|
|
if ( !common->IsMultiplayer() && g_testMultiplayerFX.GetInteger() == -1 ) {
|
|
return false;
|
|
}
|
|
|
|
if ( DetermineLevel() >= 0 ) {
|
|
return true;
|
|
} else {
|
|
// latch the clear flag
|
|
if ( fader.GetAlpha() == 0 ) {
|
|
clearAccumBuffer = true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::AccumPass
|
|
==================
|
|
*/
|
|
void FullscreenFX_Multiplayer::AccumPass( const renderView_t *view ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
float t0 = 1.0f;
|
|
float t1 = 0.0f;
|
|
|
|
// capture pass
|
|
if ( clearAccumBuffer ) {
|
|
clearAccumBuffer = false;
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, initMaterial );
|
|
} else {
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, captureMaterial );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_Multiplayer::HighQuality() {
|
|
float t0 = 1.0f;
|
|
float t1 = 0.0f;
|
|
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, drawMaterial );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Multiplayer::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFX_Multiplayer::Restore( idRestoreGame *savefile ) {
|
|
FullscreenFX::Restore( savefile );
|
|
|
|
// latch the clear flag
|
|
clearAccumBuffer = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_Warp::Initialize() {
|
|
material = declManager->FindMaterial( "textures/d3bfg/warp" );
|
|
grabberEnabled = false;
|
|
startWarpTime = 0;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_Warp::Active() {
|
|
if ( grabberEnabled ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::Save
|
|
==================
|
|
*/
|
|
void FullscreenFX_Warp::Save( idSaveGame *savefile ) {
|
|
FullscreenFX::Save( savefile );
|
|
|
|
savefile->WriteBool( grabberEnabled );
|
|
savefile->WriteInt( startWarpTime );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFX_Warp::Restore( idRestoreGame *savefile ) {
|
|
FullscreenFX::Restore( savefile );
|
|
|
|
savefile->ReadBool( grabberEnabled );
|
|
savefile->ReadInt( startWarpTime );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::DrawWarp
|
|
==================
|
|
*/
|
|
void FullscreenFX_Warp::DrawWarp( WarpPolygon_t wp, float interp ) {
|
|
idVec4 mid1_uv, mid2_uv;
|
|
idVec4 mid1, mid2;
|
|
idVec2 drawPts[6];
|
|
WarpPolygon_t trans;
|
|
|
|
trans = wp;
|
|
|
|
// compute mid points
|
|
mid1 = trans.outer1 * ( interp ) + trans.center * ( 1 - interp );
|
|
mid2 = trans.outer2 * ( interp ) + trans.center * ( 1 - interp );
|
|
mid1_uv = trans.outer1 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
|
|
mid2_uv = trans.outer2 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
|
|
|
|
// draw [outer1, mid2, mid1]
|
|
drawPts[0].Set( trans.outer1.x, trans.outer1.y );
|
|
drawPts[1].Set( mid2.x, mid2.y );
|
|
drawPts[2].Set( mid1.x, mid1.y );
|
|
drawPts[3].Set( trans.outer1.z, trans.outer1.w );
|
|
drawPts[4].Set( mid2_uv.z, mid2_uv.w );
|
|
drawPts[5].Set( mid1_uv.z, mid1_uv.w );
|
|
renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
|
|
|
|
// draw [outer1, outer2, mid2]
|
|
drawPts[0].Set( trans.outer1.x, trans.outer1.y );
|
|
drawPts[1].Set( trans.outer2.x, trans.outer2.y );
|
|
drawPts[2].Set( mid2.x, mid2.y );
|
|
drawPts[3].Set( trans.outer1.z, trans.outer1.w );
|
|
drawPts[4].Set( trans.outer2.z, trans.outer2.w );
|
|
drawPts[5].Set( mid2_uv.z, mid2_uv.w );
|
|
renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
|
|
|
|
// draw [mid1, mid2, center]
|
|
drawPts[0].Set( mid1.x, mid1.y );
|
|
drawPts[1].Set( mid2.x, mid2.y );
|
|
drawPts[2].Set( trans.center.x, trans.center.y );
|
|
drawPts[3].Set( mid1_uv.z, mid1_uv.w );
|
|
drawPts[4].Set( mid2_uv.z, mid2_uv.w );
|
|
drawPts[5].Set( trans.center.z, trans.center.w );
|
|
renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Warp::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_Warp::HighQuality() {
|
|
float x1, y1, x2, y2, radius, interp;
|
|
idVec2 center;
|
|
int STEP = 9;
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
interp = ( idMath::Sin( (float)( gameLocal.slow.time - startWarpTime ) / 1000 ) + 1 ) / 2.f;
|
|
interp = 0.7 * ( 1 - interp ) + 0.3 * ( interp );
|
|
|
|
// draw the warps
|
|
center.x = 320;
|
|
center.y = 240;
|
|
radius = 200;
|
|
|
|
for ( float i = 0; i < 360; i += STEP ) {
|
|
// compute the values
|
|
x1 = idMath::Sin( DEG2RAD( i ) );
|
|
y1 = idMath::Cos( DEG2RAD( i ) );
|
|
|
|
x2 = idMath::Sin( DEG2RAD( i + STEP ) );
|
|
y2 = idMath::Cos( DEG2RAD( i + STEP ) );
|
|
|
|
// add warp polygon
|
|
WarpPolygon_t p;
|
|
|
|
p.outer1.x = center.x + x1 * radius;
|
|
p.outer1.y = center.y + y1 * radius;
|
|
p.outer1.z = p.outer1.x / (float)SCREEN_WIDTH;
|
|
p.outer1.w = 1 - ( p.outer1.y / (float)SCREEN_HEIGHT );
|
|
|
|
p.outer2.x = center.x + x2 * radius;
|
|
p.outer2.y = center.y + y2 * radius;
|
|
p.outer2.z = p.outer2.x / (float)SCREEN_WIDTH;
|
|
p.outer2.w = 1 - ( p.outer2.y / (float)SCREEN_HEIGHT );
|
|
|
|
p.center.x = center.x;
|
|
p.center.y = center.y;
|
|
p.center.z = p.center.x / (float)SCREEN_WIDTH;
|
|
p.center.w = 1 - ( p.center.y / (float)SCREEN_HEIGHT );
|
|
|
|
// draw it
|
|
DrawWarp( p, interp );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_EnviroSuit::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_EnviroSuit::Initialize() {
|
|
material = declManager->FindMaterial( "textures/d3bfg/enviro_suit" );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_EnviroSuit::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_EnviroSuit::Active() {
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if ( player != NULL && player->PowerUpActive( ENVIROSUIT ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_EnviroSuit::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_EnviroSuit::HighQuality() {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
float s0 = 0.0f;
|
|
float t0 = 1.0f;
|
|
float s1 = 1.0f;
|
|
float t1 = 0.0f;
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_DoubleVision::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_DoubleVision::Initialize() {
|
|
material = declManager->FindMaterial( "textures/d3bfg/doubleVision" );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_DoubleVision::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_DoubleVision::Active() {
|
|
|
|
if ( gameLocal.fast.time < fxman->GetPlayerView()->dvFinishTime ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_DoubleVision::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_DoubleVision::HighQuality() {
|
|
int offset = fxman->GetPlayerView()->dvFinishTime - gameLocal.fast.time;
|
|
float scale = offset * g_dvAmplitude.GetFloat();
|
|
|
|
// for testing purposes
|
|
if ( !Active() ) {
|
|
static int test = 0;
|
|
if ( test > 312 ) {
|
|
test = 0;
|
|
}
|
|
|
|
offset = test++;
|
|
scale = offset * g_dvAmplitude.GetFloat();
|
|
}
|
|
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if( player == NULL ) {
|
|
return;
|
|
}
|
|
|
|
offset *= 2; // crutch up for higher res
|
|
|
|
// set the scale and shift
|
|
if ( scale > 0.5f ) {
|
|
scale = 0.5f;
|
|
}
|
|
float shift = scale * sin( sqrtf( (float)offset ) * g_dvFrequency.GetFloat() );
|
|
shift = fabs( shift );
|
|
|
|
// carry red tint if in berserk mode
|
|
idVec4 color( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
if ( gameLocal.fast.time < player->inventory.powerupEndTime[ BERSERK ] ) {
|
|
color.y = 0.0f;
|
|
color.z = 0.0f;
|
|
}
|
|
|
|
if ( !common->IsMultiplayer() && gameLocal.fast.time < player->inventory.powerupEndTime[ HELLTIME ] || gameLocal.fast.time < player->inventory.powerupEndTime[ INVULNERABILITY ]) {
|
|
color.y = 0.0f;
|
|
color.z = 0.0f;
|
|
}
|
|
|
|
// uv coordinates
|
|
float s0 = shift;
|
|
float t0 = 1.0f;
|
|
float s1 = 1.0f;
|
|
float t1 = 0.0f;
|
|
|
|
|
|
renderSystem->SetColor4( color.x, color.y, color.z, 1.0f );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
|
|
|
|
renderSystem->SetColor4( color.x, color.y, color.z, 0.5f );
|
|
s0 = 0.0f;
|
|
t0 = 1.0f;
|
|
s1 = ( 1.0-shift );
|
|
t1 = 0.0f;
|
|
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_InfluenceVision::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_InfluenceVision::Initialize() {
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_InfluenceVision::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_InfluenceVision::Active() {
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if ( player != NULL && ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_InfluenceVision::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_InfluenceVision::HighQuality() {
|
|
float distance = 0.0f;
|
|
float pct = 1.0f;
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if( player == NULL ) {
|
|
return;
|
|
}
|
|
|
|
if ( player->GetInfluenceEntity() ) {
|
|
distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length();
|
|
if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) {
|
|
pct = distance / player->GetInfluenceRadius();
|
|
pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct );
|
|
}
|
|
}
|
|
|
|
if ( player->GetInfluenceMaterial() ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() );
|
|
} else if ( player->GetInfluenceEntity() == NULL ) {
|
|
return;
|
|
} else {
|
|
// int offset = 25 + sinf( gameLocal.slow.time );
|
|
// DoubleVision( hud, view, pct * offset );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Bloom::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFX_Bloom::Initialize() {
|
|
drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloom2/draw" );
|
|
initMaterial = declManager->FindMaterial( "textures/d3bfg/bloom2/init" );
|
|
|
|
currentIntensity = 0;
|
|
targetIntensity = 0;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Bloom::Active
|
|
==================
|
|
*/
|
|
bool FullscreenFX_Bloom::Active() {
|
|
idPlayer * player = fxman->GetPlayer();
|
|
|
|
if ( player != NULL && player->bloomEnabled ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Bloom::HighQuality
|
|
==================
|
|
*/
|
|
void FullscreenFX_Bloom::HighQuality() {
|
|
float shift = 1;
|
|
idPlayer * player = fxman->GetPlayer();
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
// if intensity value is different, start the blend
|
|
targetIntensity = g_testBloomIntensity.GetFloat();
|
|
|
|
if ( player != NULL && player->bloomEnabled ) {
|
|
targetIntensity = player->bloomIntensity;
|
|
}
|
|
|
|
float delta = targetIntensity - currentIntensity;
|
|
float step = 0.001f;
|
|
|
|
if ( step < fabs( delta ) ) {
|
|
if ( delta < 0 ) {
|
|
step = -step;
|
|
}
|
|
|
|
currentIntensity += step;
|
|
}
|
|
|
|
// draw the blends
|
|
int num = g_testBloomNumPasses.GetInteger();
|
|
|
|
for ( int i = 0; i < num; i++ ) {
|
|
float s1 = 0.0f, t1 = 0.0f, s2 = 1.0f, t2 = 1.0f;
|
|
float alpha;
|
|
|
|
// do the center scale
|
|
s1 -= 0.5;
|
|
s1 *= shift;
|
|
s1 += 0.5;
|
|
|
|
t1 -= 0.5;
|
|
t1 *= shift;
|
|
t1 += 0.5;
|
|
|
|
s2 -= 0.5;
|
|
s2 *= shift;
|
|
s2 += 0.5;
|
|
|
|
t2 -= 0.5;
|
|
t2 *= shift;
|
|
t2 += 0.5;
|
|
|
|
// draw it
|
|
if ( num == 1 ) {
|
|
alpha = 1;
|
|
} else {
|
|
alpha = 1 - (float)i / ( num - 1 );
|
|
}
|
|
|
|
|
|
float yScale = 1.0f;
|
|
|
|
renderSystem->SetColor4( alpha, alpha, alpha, 1 );
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s1, t2 * yScale, s2, t1 * yScale, drawMaterial );
|
|
|
|
shift += currentIntensity;
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Bloom::Save
|
|
==================
|
|
*/
|
|
void FullscreenFX_Bloom::Save( idSaveGame *savefile ) {
|
|
FullscreenFX::Save( savefile );
|
|
savefile->WriteFloat( currentIntensity );
|
|
savefile->WriteFloat( targetIntensity );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFX_Bloom::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFX_Bloom::Restore( idRestoreGame *savefile ) {
|
|
FullscreenFX::Restore( savefile );
|
|
savefile->ReadFloat( currentIntensity );
|
|
savefile->ReadFloat( targetIntensity );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::FullscreenFXManager
|
|
==================
|
|
*/
|
|
FullscreenFXManager::FullscreenFXManager() {
|
|
playerView = NULL;
|
|
blendBackMaterial = NULL;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::~FullscreenFXManager
|
|
==================
|
|
*/
|
|
FullscreenFXManager::~FullscreenFXManager() {
|
|
fx.DeleteContents();
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::FindFX
|
|
==================
|
|
*/
|
|
FullscreenFX* FullscreenFXManager::FindFX( idStr name ) {
|
|
for ( int i = 0; i < fx.Num(); i++ ) {
|
|
if ( fx[i]->GetName() == name ) {
|
|
return fx[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::CreateFX
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::CreateFX( idStr name, idStr fxtype, int fade ) {
|
|
FullscreenFX *pfx = NULL;
|
|
|
|
if ( fxtype == "helltime" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_Helltime;
|
|
} else if ( fxtype == "warp" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_Warp;
|
|
} else if ( fxtype == "envirosuit" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_EnviroSuit;
|
|
} else if ( fxtype == "doublevision" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_DoubleVision;
|
|
} else if ( fxtype == "multiplayer" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_Multiplayer;
|
|
} else if ( fxtype == "influencevision" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_InfluenceVision;
|
|
} else if ( fxtype == "bloom" ) {
|
|
pfx = new (TAG_FX) FullscreenFX_Bloom;
|
|
} else {
|
|
assert( 0 );
|
|
}
|
|
|
|
if ( pfx ) {
|
|
pfx->Initialize();
|
|
pfx->SetFXManager( this );
|
|
pfx->SetName( name );
|
|
pfx->SetFadeSpeed( fade );
|
|
fx.Append( pfx );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::Initialize
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::Initialize( idPlayerView *pv ) {
|
|
// set the playerview
|
|
playerView = pv;
|
|
blendBackMaterial = declManager->FindMaterial( "textures/d3bfg/blendBack" );
|
|
|
|
// allocate the fx
|
|
CreateFX( "helltime", "helltime", 1000 );
|
|
CreateFX( "warp", "warp", 0 );
|
|
CreateFX( "envirosuit", "envirosuit", 500 );
|
|
CreateFX( "doublevision", "doublevision", 0 );
|
|
CreateFX( "multiplayer", "multiplayer", 1000 );
|
|
CreateFX( "influencevision", "influencevision", 1000 );
|
|
CreateFX( "bloom", "bloom", 0 );
|
|
|
|
// pre-cache the texture grab so we dont hitch
|
|
renderSystem->CropRenderSize( 512, 512 );
|
|
renderSystem->CaptureRenderToImage( "_accum" );
|
|
renderSystem->UnCrop();
|
|
|
|
renderSystem->CaptureRenderToImage( "_currentRender" );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::Blendback
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::Blendback( float alpha ) {
|
|
// alpha fade
|
|
if ( alpha < 1.f ) {
|
|
renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f - alpha );
|
|
float s0 = 0.0f;
|
|
float t0 = 1.0f;
|
|
float s1 = 1.0f;
|
|
float t1 = 0.0f;
|
|
renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, blendBackMaterial );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::Save
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::Save( idSaveGame *savefile ) {
|
|
for ( int i = 0; i < fx.Num(); i++ ) {
|
|
FullscreenFX *pfx = fx[i];
|
|
pfx->Save( savefile );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::Restore
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::Restore( idRestoreGame *savefile ) {
|
|
for ( int i = 0; i < fx.Num(); i++ ) {
|
|
FullscreenFX *pfx = fx[i];
|
|
pfx->Restore( savefile );
|
|
}
|
|
}
|
|
|
|
idCVar player_allowScreenFXInStereo( "player_allowScreenFXInStereo", "1", CVAR_BOOL, "allow full screen fx in stereo mode" );
|
|
|
|
/*
|
|
==================
|
|
FullscreenFXManager::Process
|
|
==================
|
|
*/
|
|
void FullscreenFXManager::Process( const renderView_t *view ) {
|
|
bool allpass = false;
|
|
bool atLeastOneFX = false;
|
|
|
|
if ( g_testFullscreenFX.GetInteger() == -2 ) {
|
|
allpass = true;
|
|
}
|
|
|
|
// do the first render
|
|
gameRenderWorld->RenderScene( view );
|
|
|
|
// we should consider these on a case-by-case basis for stereo rendering
|
|
// double vision could be implemented "for real" by shifting the
|
|
// eye views
|
|
if ( IsGameStereoRendered() && !player_allowScreenFXInStereo.GetBool() ) {
|
|
return;
|
|
}
|
|
|
|
// do the process
|
|
for ( int i = 0; i < fx.Num(); i++ ) {
|
|
FullscreenFX *pfx = fx[i];
|
|
bool drawIt = false;
|
|
|
|
// determine if we need to draw
|
|
if ( pfx->Active() || g_testFullscreenFX.GetInteger() == i || allpass ) {
|
|
drawIt = pfx->SetTriggerState( true );
|
|
} else {
|
|
drawIt = pfx->SetTriggerState( false );
|
|
}
|
|
|
|
// do the actual drawing
|
|
if ( drawIt ) {
|
|
atLeastOneFX = true;
|
|
|
|
// we need to dump to _currentRender
|
|
renderSystem->CaptureRenderToImage( "_currentRender" );
|
|
|
|
// handle the accum pass if we have one
|
|
if ( pfx->HasAccum() ) {
|
|
// we need to crop the accum pass
|
|
renderSystem->CropRenderSize( 512, 512 );
|
|
pfx->AccumPass( view );
|
|
renderSystem->CaptureRenderToImage( "_accum" );
|
|
renderSystem->UnCrop();
|
|
}
|
|
|
|
// do the high quality pass
|
|
pfx->HighQuality();
|
|
|
|
// do the blendback
|
|
Blendback( pfx->GetFadeAlpha() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|