diff --git a/neo/d3xp/EnvironmentProbe.cpp b/neo/d3xp/EnvironmentProbe.cpp new file mode 100644 index 00000000..c524a608 --- /dev/null +++ b/neo/d3xp/EnvironmentProbe.cpp @@ -0,0 +1,940 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2015 Robert Beckebans + +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 . + +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 "precompiled.h" +#pragma hdrstop + +#include "Game_local.h" + +/* +=============================================================================== + + idLight + +=============================================================================== +*/ + +const idEventDef EV_Envprobe_GetEnvprobeParm( "getEnvprobeParm", "d", 'f' ); +const idEventDef EV_Envprobe_SetEnvprobeParm( "setEnvprobeParm", "df" ); +const idEventDef EV_Envprobe_SetEnvprobeParms( "setEnvprobeParms", "ffff" ); +//const idEventDef EV_Envprobe_SetRadiusXYZ( "setRadiusXYZ", "fff" ); +//const idEventDef EV_Envprobe_SetRadius( "setRadius", "f" ); +const idEventDef EV_Envprobe_On( "On", NULL ); +const idEventDef EV_Envprobe_Off( "Off", NULL ); +const idEventDef EV_Envprobe_FadeOut( "fadeOutEnvprobe", "f" ); +const idEventDef EV_Envprobe_FadeIn( "fadeInEnvprobe", "f" ); + +CLASS_DECLARATION( idEntity, EnvironmentProbe ) +EVENT( EV_Envprobe_GetEnvprobeParm, EnvironmentProbe::Event_GetEnvprobeParm ) +EVENT( EV_Envprobe_SetEnvprobeParm, EnvironmentProbe::Event_SetEnvprobeParm ) +EVENT( EV_Envprobe_SetEnvprobeParms, EnvironmentProbe::Event_SetEnvprobeParms ) +//EVENT( EV_Envprobe_SetRadiusXYZ, EnvironmentProbe::Event_SetRadiusXYZ ) +//EVENT( EV_Envprobe_SetRadius, EnvironmentProbe::Event_SetRadius ) +EVENT( EV_Hide, EnvironmentProbe::Event_Hide ) +EVENT( EV_Show, EnvironmentProbe::Event_Show ) +EVENT( EV_Envprobe_On, EnvironmentProbe::Event_On ) +EVENT( EV_Envprobe_Off, EnvironmentProbe::Event_Off ) +EVENT( EV_Activate, EnvironmentProbe::Event_ToggleOnOff ) +//EVENT( EV_PostSpawn, EnvironmentProbe::Event_SetSoundHandles ) +EVENT( EV_Envprobe_FadeOut, EnvironmentProbe::Event_FadeOut ) +EVENT( EV_Envprobe_FadeIn, EnvironmentProbe::Event_FadeIn ) +END_CLASS + + +/* +================ +idGameEdit::ParseSpawnArgsToRenderLight + +parse the light parameters +this is the canonical renderLight parm parsing, +which should be used by dmap and the editor +================ +*/ +void idGameEdit::ParseSpawnArgsToRenderEnvprobe( const idDict* args, renderEnvironmentProbe_t* renderEnvprobe ) +{ + idVec3 color; + + memset( renderEnvprobe, 0, sizeof( *renderEnvprobe ) ); + + if( !args->GetVector( "light_origin", "", renderEnvprobe->origin ) ) + { + args->GetVector( "origin", "", renderEnvprobe->origin ); + } + + // check for other attributes + args->GetVector( "_color", "1 1 1", color ); + renderEnvprobe->shaderParms[ SHADERPARM_RED ] = color[0]; + renderEnvprobe->shaderParms[ SHADERPARM_GREEN ] = color[1]; + renderEnvprobe->shaderParms[ SHADERPARM_BLUE ] = color[2]; + args->GetFloat( "shaderParm3", "1", renderEnvprobe->shaderParms[ SHADERPARM_TIMESCALE ] ); + if( !args->GetFloat( "shaderParm4", "0", renderEnvprobe->shaderParms[ SHADERPARM_TIMEOFFSET ] ) ) + { + // offset the start time of the shader to sync it to the game time + renderEnvprobe->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); + } + + args->GetFloat( "shaderParm5", "0", renderEnvprobe->shaderParms[5] ); + args->GetFloat( "shaderParm6", "0", renderEnvprobe->shaderParms[6] ); + args->GetFloat( "shaderParm7", "0", renderEnvprobe->shaderParms[ SHADERPARM_MODE ] ); +} + +/* +================ +EnvironmentProbe::UpdateChangeableSpawnArgs +================ +*/ +void EnvironmentProbe::UpdateChangeableSpawnArgs( const idDict* source ) +{ + idEntity::UpdateChangeableSpawnArgs( source ); + + if( source ) + { + source->Print(); + } + + gameEdit->ParseSpawnArgsToRenderEnvprobe( source ? source : &spawnArgs, &renderEnvprobe ); + + UpdateVisuals(); +} + +/* +================ +EnvironmentProbe::EnvironmentProbe +================ +*/ +EnvironmentProbe::EnvironmentProbe(): + previousBaseColor( vec3_zero ) , + nextBaseColor( vec3_zero ) +{ + memset( &renderEnvprobe, 0, sizeof( renderEnvprobe ) ); + localEnvprobeOrigin = vec3_zero; + localEnvprobeAxis = mat3_identity; + envprobeDefHandle = -1; + levels = 0; + currentLevel = 0; + baseColor = vec3_zero; + count = 0; + triggercount = 0; + lightParent = NULL; + fadeFrom.Set( 1, 1, 1, 1 ); + fadeTo.Set( 1, 1, 1, 1 ); + fadeStart = 0; + fadeEnd = 0; +} + +/* +================ +EnvironmentProbe::~idLight +================ +*/ +EnvironmentProbe::~EnvironmentProbe() +{ + if( envprobeDefHandle != -1 ) + { + gameRenderWorld->FreeEnvprobeDef( envprobeDefHandle ); + } +} + +/* +================ +EnvironmentProbe::Save + +archives object for save game file +================ +*/ +void EnvironmentProbe::Save( idSaveGame* savefile ) const +{ + savefile->WriteRenderEnvprobe( renderEnvprobe ); + + savefile->WriteVec3( localEnvprobeOrigin ); + savefile->WriteMat3( localEnvprobeAxis ); + + savefile->WriteInt( levels ); + savefile->WriteInt( currentLevel ); + + savefile->WriteVec3( baseColor ); + savefile->WriteInt( count ); + savefile->WriteInt( triggercount ); + savefile->WriteObject( lightParent ); + + savefile->WriteVec4( fadeFrom ); + savefile->WriteVec4( fadeTo ); + savefile->WriteInt( fadeStart ); + savefile->WriteInt( fadeEnd ); +} + +/* +================ +EnvironmentProbe::Restore + +unarchives object from save game file +================ +*/ +void EnvironmentProbe::Restore( idRestoreGame* savefile ) +{ + savefile->ReadRenderEnvprobe( renderEnvprobe ); + + savefile->ReadVec3( localEnvprobeOrigin ); + savefile->ReadMat3( localEnvprobeAxis ); + + savefile->ReadInt( levels ); + savefile->ReadInt( currentLevel ); + + savefile->ReadVec3( baseColor ); + savefile->ReadInt( count ); + savefile->ReadInt( triggercount ); + savefile->ReadObject( reinterpret_cast( lightParent ) ); + + savefile->ReadVec4( fadeFrom ); + savefile->ReadVec4( fadeTo ); + savefile->ReadInt( fadeStart ); + savefile->ReadInt( fadeEnd ); + + envprobeDefHandle = -1; + + SetLightLevel(); +} + +/* +================ +EnvironmentProbe::Spawn +================ +*/ +void EnvironmentProbe::Spawn() +{ + bool start_off; + + // do the parsing the same way dmap and the editor do + gameEdit->ParseSpawnArgsToRenderEnvprobe( &spawnArgs, &renderEnvprobe ); + + // we need the origin and axis relative to the physics origin/axis + localEnvprobeOrigin = ( renderEnvprobe.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose(); + localEnvprobeAxis = /*renderEnvprobe.axis * */ GetPhysics()->GetAxis().Transpose(); + + // set the base color from the shader parms + baseColor.Set( renderEnvprobe.shaderParms[ SHADERPARM_RED ], renderEnvprobe.shaderParms[ SHADERPARM_GREEN ], renderEnvprobe.shaderParms[ SHADERPARM_BLUE ] ); + previousBaseColor.Set( renderEnvprobe.shaderParms[ SHADERPARM_RED ], renderEnvprobe.shaderParms[ SHADERPARM_GREEN ], renderEnvprobe.shaderParms[ SHADERPARM_BLUE ] ); + nextBaseColor.Set( renderEnvprobe.shaderParms[ SHADERPARM_RED ], renderEnvprobe.shaderParms[ SHADERPARM_GREEN ], renderEnvprobe.shaderParms[ SHADERPARM_BLUE ] ); + + // set the number of light levels + spawnArgs.GetInt( "levels", "1", levels ); + currentLevel = levels; + if( levels <= 0 ) + { + gameLocal.Error( "Invalid light level set on entity #%d(%s)", entityNumber, name.c_str() ); + } + + // game specific functionality, not mirrored in + // editor or dmap light parsing + + envprobeDefHandle = -1; // no static version yet + + spawnArgs.GetBool( "start_off", "0", start_off ); + if( start_off ) + { + Off(); + } + + // Midnight CTF + if( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool( "si_midnight" ) && !spawnArgs.GetBool( "midnight_override" ) ) + { + Off(); + } + + health = spawnArgs.GetInt( "health", "0" ); + spawnArgs.GetInt( "count", "1", count ); + + triggercount = 0; + + fadeFrom.Set( 1, 1, 1, 1 ); + fadeTo.Set( 1, 1, 1, 1 ); + fadeStart = 0; + fadeEnd = 0; + + PostEventMS( &EV_PostSpawn, 0 ); + + UpdateVisuals(); +} + +/* +================ +EnvironmentProbe::SetLightLevel +================ +*/ +void EnvironmentProbe::SetLightLevel() +{ + idVec3 color; + float intensity; + + intensity = ( float )currentLevel / ( float )levels; + color = baseColor * intensity; + renderEnvprobe.shaderParms[ SHADERPARM_RED ] = color[ 0 ]; + renderEnvprobe.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ]; + renderEnvprobe.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ]; + + PresentEnvprobeDefChange(); +} + +/* +================ +EnvironmentProbe::GetColor +================ +*/ +void EnvironmentProbe::GetColor( idVec3& out ) const +{ + out[ 0 ] = renderEnvprobe.shaderParms[ SHADERPARM_RED ]; + out[ 1 ] = renderEnvprobe.shaderParms[ SHADERPARM_GREEN ]; + out[ 2 ] = renderEnvprobe.shaderParms[ SHADERPARM_BLUE ]; +} + +/* +================ +EnvironmentProbe::GetColor +================ +*/ +void EnvironmentProbe::GetColor( idVec4& out ) const +{ + out[ 0 ] = renderEnvprobe.shaderParms[ SHADERPARM_RED ]; + out[ 1 ] = renderEnvprobe.shaderParms[ SHADERPARM_GREEN ]; + out[ 2 ] = renderEnvprobe.shaderParms[ SHADERPARM_BLUE ]; + out[ 3 ] = renderEnvprobe.shaderParms[ SHADERPARM_ALPHA ]; +} + +/* +================ +EnvironmentProbe::SetColor +================ +*/ +void EnvironmentProbe::SetColor( float red, float green, float blue ) +{ + baseColor.Set( red, green, blue ); + SetLightLevel(); +} + +/* +================ +EnvironmentProbe::SetColor +================ +*/ +void EnvironmentProbe::SetColor( const idVec4& color ) +{ + baseColor = color.ToVec3(); + renderEnvprobe.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ]; + SetLightLevel(); +} + +/* +================ +EnvironmentProbe::SetColor +================ +*/ +void EnvironmentProbe::SetColor( const idVec3& color ) +{ + baseColor = color; + SetLightLevel(); +} + +/* +================ +EnvironmentProbe::SetEnvprobeParm +================ +*/ +void EnvironmentProbe::SetEnvprobeParm( int parmnum, float value ) +{ + if( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) + { + gameLocal.Error( "shader parm index (%d) out of range", parmnum ); + return; + } + + renderEnvprobe.shaderParms[ parmnum ] = value; + PresentEnvprobeDefChange(); +} + +/* +================ +EnvironmentProbe::SetEnvprobeParms +================ +*/ +void EnvironmentProbe::SetEnvprobeParms( float parm0, float parm1, float parm2, float parm3 ) +{ + renderEnvprobe.shaderParms[ SHADERPARM_RED ] = parm0; + renderEnvprobe.shaderParms[ SHADERPARM_GREEN ] = parm1; + renderEnvprobe.shaderParms[ SHADERPARM_BLUE ] = parm2; + renderEnvprobe.shaderParms[ SHADERPARM_ALPHA ] = parm3; + PresentEnvprobeDefChange(); +} + +/* +================ +EnvironmentProbe::On +================ +*/ +void EnvironmentProbe::On() +{ + currentLevel = levels; + // offset the start time of the shader to sync it to the game time + renderEnvprobe.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); + + SetLightLevel(); + BecomeActive( TH_UPDATEVISUALS ); +} + +/* +================ +EnvironmentProbe::Off +================ +*/ +void EnvironmentProbe::Off() +{ + currentLevel = 0; + + SetLightLevel(); + BecomeActive( TH_UPDATEVISUALS ); +} + +/* +================ +EnvironmentProbe::Fade +================ +*/ +void EnvironmentProbe::Fade( const idVec4& to, float fadeTime ) +{ + GetColor( fadeFrom ); + fadeTo = to; + fadeStart = gameLocal.time; + fadeEnd = gameLocal.time + SEC2MS( fadeTime ); + BecomeActive( TH_THINK ); +} + +/* +================ +EnvironmentProbe::FadeOut +================ +*/ +void EnvironmentProbe::FadeOut( float time ) +{ + Fade( colorBlack, time ); +} + +/* +================ +EnvironmentProbe::FadeIn +================ +*/ +void EnvironmentProbe::FadeIn( float time ) +{ + idVec3 color; + idVec4 color4; + + currentLevel = levels; + spawnArgs.GetVector( "_color", "1 1 1", color ); + color4.Set( color.x, color.y, color.z, 1.0f ); + Fade( color4, time ); +} + +/* +================ +EnvironmentProbe::PresentEnvprobeDefChange +================ +*/ +void EnvironmentProbe::PresentEnvprobeDefChange() +{ + // let the renderer apply it to the world + if( ( envprobeDefHandle != -1 ) ) + { + gameRenderWorld->UpdateEnvprobeDef( envprobeDefHandle, &renderEnvprobe ); + } + else + { + envprobeDefHandle = gameRenderWorld->AddEnvprobeDef( &renderEnvprobe ); + } +} + +/* +================ +EnvironmentProbe::Present +================ +*/ +void EnvironmentProbe::Present() +{ + // don't present to the renderer if the entity hasn't changed + if( !( thinkFlags & TH_UPDATEVISUALS ) ) + { + return; + } + + // add the model + idEntity::Present(); + + // current transformation +// renderEnvprobe.axis = localEnvprobeAxis * GetPhysics()->GetAxis(); + renderEnvprobe.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localEnvprobeOrigin; + + // reference the sound for shader synced effects + // FIXME TODO? + /* + if( lightParent ) + { + renderLight.referenceSound = lightParent->GetSoundEmitter(); + renderEntity.referenceSound = lightParent->GetSoundEmitter(); + } + else + { + renderLight.referenceSound = refSound.referenceSound; + renderEntity.referenceSound = refSound.referenceSound; + } + */ + + // update the renderLight and renderEntity to render the light and flare + PresentEnvprobeDefChange(); +} + +/* +================ +EnvironmentProbe::Think +================ +*/ +void EnvironmentProbe::Think() +{ + idVec4 color; + + if( thinkFlags & TH_THINK ) + { + if( fadeEnd > 0 ) + { + if( gameLocal.time < fadeEnd ) + { + color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) ); + } + else + { + color = fadeTo; + fadeEnd = 0; + BecomeInactive( TH_THINK ); + } + SetColor( color ); + } + } + + RunPhysics(); + Present(); +} + +/* +================ +EnvironmentProbe::ClientThink +================ +*/ +void EnvironmentProbe::ClientThink( const int curTime, const float fraction, const bool predict ) +{ + + InterpolatePhysics( fraction ); + + if( baseColor != nextBaseColor ) + { + baseColor = Lerp( previousBaseColor, nextBaseColor, fraction ); + SetColor( baseColor ); + BecomeActive( TH_UPDATEVISUALS ); + } + + Present(); +} + +/* +================ +EnvironmentProbe::GetPhysicsToSoundTransform +================ +*/ +bool EnvironmentProbe::GetPhysicsToSoundTransform( idVec3& origin, idMat3& axis ) +{ + //origin = localEnvprobeOrigin + renderEnvprobe.lightCenter; + //axis = localLightAxis * GetPhysics()->GetAxis(); + //return true; + + return false; +} + +/* +================ +EnvironmentProbe::FreeEnvprobeDef +================ +*/ +void EnvironmentProbe::FreeEnvprobeDef() +{ + if( envprobeDefHandle != -1 ) + { + gameRenderWorld->FreeEnvprobeDef( envprobeDefHandle ); + envprobeDefHandle = -1; + } +} + +/* +================ +EnvironmentProbe::SaveState +================ +*/ +void EnvironmentProbe::SaveState( idDict* args ) +{ + int i, c = spawnArgs.GetNumKeyVals(); + for( i = 0; i < c; i++ ) + { + const idKeyValue* pv = spawnArgs.GetKeyVal( i ); + if( pv->GetKey().Find( "editor_", false ) >= 0 || pv->GetKey().Find( "parse_", false ) >= 0 ) + { + continue; + } + args->Set( pv->GetKey(), pv->GetValue() ); + } +} + +/* +=============== +EnvironmentProbe::ShowEditingDialog +=============== +*/ +void EnvironmentProbe::ShowEditingDialog() +{ +} + +/* +================ +EnvironmentProbe::Event_GetEnvprobeParm +================ +*/ +void EnvironmentProbe::Event_GetEnvprobeParm( int parmnum ) +{ + if( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) + { + gameLocal.Error( "shader parm index (%d) out of range", parmnum ); + return; + } + + idThread::ReturnFloat( renderEnvprobe.shaderParms[ parmnum ] ); +} + +/* +================ +EnvironmentProbe::Event_SetEnvprobeParm +================ +*/ +void EnvironmentProbe::Event_SetEnvprobeParm( int parmnum, float value ) +{ + SetEnvprobeParm( parmnum, value ); +} + +/* +================ +EnvironmentProbe::Event_SetEnvprobetParms +================ +*/ +void EnvironmentProbe::Event_SetEnvprobeParms( float parm0, float parm1, float parm2, float parm3 ) +{ + SetEnvprobeParms( parm0, parm1, parm2, parm3 ); +} + +/* +================ +EnvironmentProbe::Event_Hide +================ +*/ +void EnvironmentProbe::Event_Hide() +{ + Hide(); + Off(); +} + +/* +================ +EnvironmentProbe::Event_Show +================ +*/ +void EnvironmentProbe::Event_Show() +{ + Show(); + On(); +} + +/* +================ +EnvironmentProbe::Event_On +================ +*/ +void EnvironmentProbe::Event_On() +{ + On(); +} + +/* +================ +EnvironmentProbe::Event_Off +================ +*/ +void EnvironmentProbe::Event_Off() +{ + Off(); +} + +/* +================ +EnvironmentProbe::Event_ToggleOnOff +================ +*/ +void EnvironmentProbe::Event_ToggleOnOff( idEntity* activator ) +{ + triggercount++; + if( triggercount < count ) + { + return; + } + + // reset trigger count + triggercount = 0; + + if( !currentLevel ) + { + On(); + } + else + { + currentLevel--; + if( !currentLevel ) + { + Off(); + } + else + { + SetLightLevel(); + } + } +} + +/* +================ +EnvironmentProbe::Event_SetSoundHandles + + set the same sound def handle on all targeted lights +================ +*/ +/* +void EnvironmentProbe::Event_SetSoundHandles() +{ + int i; + idEntity* targetEnt; + + if( !refSound.referenceSound ) + { + return; + } + + for( i = 0; i < targets.Num(); i++ ) + { + targetEnt = targets[ i ].GetEntity(); + if( targetEnt != NULL && targetEnt->IsType( EnvironmentProbe::Type ) ) + { + idLight* light = static_cast( targetEnt ); + light->lightParent = this; + + // explicitly delete any sounds on the entity + light->FreeSoundEmitter( true ); + + // manually set the refSound to this light's refSound + light->renderEntity.referenceSound = renderEntity.referenceSound; + + // update the renderEntity to the renderer + light->UpdateVisuals(); + } + } +} +*/ + +/* +================ +EnvironmentProbe::Event_FadeOut +================ +*/ +void EnvironmentProbe::Event_FadeOut( float time ) +{ + FadeOut( time ); +} + +/* +================ +EnvironmentProbe::Event_FadeIn +================ +*/ +void EnvironmentProbe::Event_FadeIn( float time ) +{ + FadeIn( time ); +} + +/* +================ +EnvironmentProbe::ClientPredictionThink +================ +*/ +void EnvironmentProbe::ClientPredictionThink() +{ + Think(); +} + +/* +================ +EnvironmentProbe::WriteToSnapshot +================ +*/ +void EnvironmentProbe::WriteToSnapshot( idBitMsg& msg ) const +{ + GetPhysics()->WriteToSnapshot( msg ); + WriteBindToSnapshot( msg ); + + msg.WriteByte( currentLevel ); + msg.WriteLong( PackColor( baseColor ) ); + // msg.WriteBits( lightParent.GetEntityNum(), GENTITYNUM_BITS ); + + /* // only helps prediction + msg.WriteLong( PackColor( fadeFrom ) ); + msg.WriteLong( PackColor( fadeTo ) ); + msg.WriteLong( fadeStart ); + msg.WriteLong( fadeEnd ); + */ + + // FIXME: send renderLight.shader + //msg.WriteFloat( renderEnvprobe.lightRadius[0], 5, 10 ); + //msg.WriteFloat( renderEnvprobe.lightRadius[1], 5, 10 ); + //msg.WriteFloat( renderEnvprobe.lightRadius[2], 5, 10 ); + + msg.WriteLong( PackColor( idVec4( renderEnvprobe.shaderParms[SHADERPARM_RED], + renderEnvprobe.shaderParms[SHADERPARM_GREEN], + renderEnvprobe.shaderParms[SHADERPARM_BLUE], + renderEnvprobe.shaderParms[SHADERPARM_ALPHA] ) ) ); + + msg.WriteFloat( renderEnvprobe.shaderParms[SHADERPARM_TIMESCALE], 5, 10 ); + msg.WriteLong( renderEnvprobe.shaderParms[SHADERPARM_TIMEOFFSET] ); + msg.WriteShort( renderEnvprobe.shaderParms[SHADERPARM_MODE] ); + + WriteColorToSnapshot( msg ); +} + +/* +================ +EnvironmentProbe::ReadFromSnapshot +================ +*/ +void EnvironmentProbe::ReadFromSnapshot( const idBitMsg& msg ) +{ + idVec4 shaderColor; + int oldCurrentLevel = currentLevel; + idVec3 oldBaseColor = baseColor; + + previousBaseColor = nextBaseColor; + + GetPhysics()->ReadFromSnapshot( msg ); + ReadBindFromSnapshot( msg ); + + currentLevel = msg.ReadByte(); + if( currentLevel != oldCurrentLevel ) + { + // need to call On/Off for flickering lights to start/stop the sound + // while doing it this way rather than through events, the flickering is out of sync between clients + // but at least there is no question about saving the event and having them happening globally in the world + if( currentLevel ) + { + On(); + } + else + { + Off(); + } + } + + UnpackColor( msg.ReadLong(), nextBaseColor ); + + // lightParentEntityNum = msg.ReadBits( GENTITYNUM_BITS ); + + /* // only helps prediction + UnpackColor( msg.ReadLong(), fadeFrom ); + UnpackColor( msg.ReadLong(), fadeTo ); + fadeStart = msg.ReadLong(); + fadeEnd = msg.ReadLong(); + */ + + // FIXME: read renderLight.shader + //renderLight.lightRadius[0] = msg.ReadFloat( 5, 10 ); + //renderLight.lightRadius[1] = msg.ReadFloat( 5, 10 ); + //renderLight.lightRadius[2] = msg.ReadFloat( 5, 10 ); + + UnpackColor( msg.ReadLong(), shaderColor ); + renderEnvprobe.shaderParms[SHADERPARM_RED] = shaderColor[0]; + renderEnvprobe.shaderParms[SHADERPARM_GREEN] = shaderColor[1]; + renderEnvprobe.shaderParms[SHADERPARM_BLUE] = shaderColor[2]; + renderEnvprobe.shaderParms[SHADERPARM_ALPHA] = shaderColor[3]; + + renderEnvprobe.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 ); + renderEnvprobe.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadLong(); + renderEnvprobe.shaderParms[SHADERPARM_MODE] = msg.ReadShort(); + + ReadColorFromSnapshot( msg ); + + if( msg.HasChanged() ) + { + if( ( currentLevel != oldCurrentLevel ) || ( previousBaseColor != nextBaseColor ) ) + { + SetLightLevel(); + } + else + { + PresentEnvprobeDefChange(); + } + } +} + +/* +================ +EnvironmentProbe::ClientReceiveEvent +================ +*/ +/* +bool EnvironmentProbe::ClientReceiveEvent( int event, int time, const idBitMsg& msg ) +{ + + switch( event ) + { + case EVENT_BECOMEBROKEN: + { + BecomeBroken( NULL ); + return true; + } + default: + { + return idEntity::ClientReceiveEvent( event, time, msg ); + } + } +} +*/ \ No newline at end of file diff --git a/neo/d3xp/EnvironmentProbe.h b/neo/d3xp/EnvironmentProbe.h new file mode 100644 index 00000000..ab412edd --- /dev/null +++ b/neo/d3xp/EnvironmentProbe.h @@ -0,0 +1,143 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2015 Robert Beckebans + +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 . + +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. + +=========================================================================== +*/ + +#ifndef __GAME_ENVIRONMENTPROBE_H__ +#define __GAME_ENVIRONMENTPROBE_H__ + +/* +=============================================================================== + + Environment probe for Image Based Lighting (part of PBR). + +=============================================================================== +*/ + +class EnvironmentProbe : public idEntity +{ +public: + CLASS_PROTOTYPE( EnvironmentProbe ); + + EnvironmentProbe(); + ~EnvironmentProbe(); + + void Spawn(); + + void Save( idSaveGame* savefile ) const; // archives object for save game file + void Restore( idRestoreGame* savefile ); // unarchives object from save game file + + virtual void UpdateChangeableSpawnArgs( const idDict* source ); + virtual void Think(); + virtual void ClientThink( const int curTime, const float fraction, const bool predict ); + virtual void FreeEnvprobeDef(); + virtual bool GetPhysicsToSoundTransform( idVec3& origin, idMat3& axis ); + void Present(); + + void SaveState( idDict* args ); + virtual void SetColor( float red, float green, float blue ); + virtual void SetColor( const idVec4& color ); + void SetColor( const idVec3& color ); + virtual void GetColor( idVec3& out ) const; + virtual void GetColor( idVec4& out ) const; + const idVec3& GetBaseColor() const + { + return baseColor; + } + void SetEnvprobeParm( int parmnum, float value ); + void SetEnvprobeParms( float parm0, float parm1, float parm2, float parm3 ); + void On(); + void Off(); + void Fade( const idVec4& to, float fadeTime ); + void FadeOut( float time ); + void FadeIn( float time ); + + qhandle_t GetEnvprobeDefHandle() const + { + return envprobeDefHandle; + } + + void SetEnvprobeParent( idEntity* lparent ) + { + lightParent = lparent; + } + + void SetLightLevel(); + + virtual void ShowEditingDialog(); + + enum + { + EVENT_BECOMEBROKEN = idEntity::EVENT_MAXEVENTS, + EVENT_MAXEVENTS + }; + + virtual void ClientPredictionThink(); + virtual void WriteToSnapshot( idBitMsg& msg ) const; + virtual void ReadFromSnapshot( const idBitMsg& msg ); +// virtual bool ClientReceiveEvent( int event, int time, const idBitMsg& msg ); + +private: + renderEnvironmentProbe_t renderEnvprobe; // envprobe presented to the renderer + idVec3 localEnvprobeOrigin; // light origin relative to the physics origin + idMat3 localEnvprobeAxis; // light axis relative to physics axis + qhandle_t envprobeDefHandle; // handle to renderer light def + int levels; + int currentLevel; + idVec3 baseColor; + + // Colors used for client-side interpolation. + idVec3 previousBaseColor; + idVec3 nextBaseColor; + + int count; + int triggercount; + idEntity* lightParent; + idVec4 fadeFrom; + idVec4 fadeTo; + int fadeStart; + int fadeEnd; + +private: + void PresentEnvprobeDefChange(); + + void Event_GetEnvprobeParm( int parmnum ); + void Event_SetEnvprobeParm( int parmnum, float value ); + void Event_SetEnvprobeParms( float parm0, float parm1, float parm2, float parm3 ); + void Event_SetRadiusXYZ( float x, float y, float z ); + void Event_SetRadius( float radius ); + void Event_Hide(); + void Event_Show(); + void Event_On(); + void Event_Off(); + void Event_ToggleOnOff( idEntity* activator ); + void Event_SetSoundHandles(); + void Event_FadeOut( float time ); + void Event_FadeIn( float time ); +}; + +#endif /* !__GAME_ENVIRONMENTPROBE_H__ */ diff --git a/neo/d3xp/Game.h b/neo/d3xp/Game.h index d222d901..d3701d14 100644 --- a/neo/d3xp/Game.h +++ b/neo/d3xp/Game.h @@ -240,6 +240,7 @@ public: // These are the canonical idDict to parameter parsing routines used by both the game and tools. virtual void ParseSpawnArgsToRenderLight( const idDict* args, renderLight_t* renderLight ); virtual void ParseSpawnArgsToRenderEntity( const idDict* args, renderEntity_t* renderEntity ); + virtual void ParseSpawnArgsToRenderEnvprobe( const idDict* args, renderEnvironmentProbe_t* renderEnvprobe ); // RB virtual void ParseSpawnArgsToRefSound( const idDict* args, refSound_t* refSound ); // Animation system calls for non-game based skeletal rendering. diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index f04cb1f0..e8d61eef 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -904,6 +904,7 @@ const int CINEMATIC_SKIP_DELAY = SEC2MS( 2.0f ); #include "Projectile.h" #include "Weapon.h" #include "Light.h" +#include "EnvironmentProbe.h" #include "WorldSpawn.h" #include "Item.h" #include "PlayerView.h" diff --git a/neo/d3xp/gamesys/SaveGame.cpp b/neo/d3xp/gamesys/SaveGame.cpp index a2519110..c5536cd7 100644 --- a/neo/d3xp/gamesys/SaveGame.cpp +++ b/neo/d3xp/gamesys/SaveGame.cpp @@ -731,6 +731,21 @@ void idSaveGame::WriteRenderLight( const renderLight_t& renderLight ) } } +// RB begin +void idSaveGame::WriteRenderEnvprobe( const renderEnvironmentProbe_t& renderEnvprobe ) +{ + WriteVec3( renderEnvprobe.origin ); + + WriteInt( renderEnvprobe.suppressEnvprobeInViewID ); + WriteInt( renderEnvprobe.allowEnvprobeInViewID ); + + for( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) + { + WriteFloat( renderEnvprobe.shaderParms[ i ] ); + } +} +// Rb end + /* ================ idSaveGame::WriteRefSound @@ -1629,6 +1644,21 @@ void idRestoreGame::ReadRenderLight( renderLight_t& renderLight ) renderLight.referenceSound = gameSoundWorld->EmitterForIndex( index ); } +// RB begin +void idRestoreGame::ReadRenderEnvprobe( renderEnvironmentProbe_t& renderEnvprobe ) +{ + ReadVec3( renderEnvprobe.origin ); + + ReadInt( renderEnvprobe.suppressEnvprobeInViewID ); + ReadInt( renderEnvprobe.allowEnvprobeInViewID ); + + for( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) + { + ReadFloat( renderEnvprobe.shaderParms[ i ] ); + } +} +// RB end + /* ================ idRestoreGame::ReadRefSound diff --git a/neo/d3xp/gamesys/SaveGame.h b/neo/d3xp/gamesys/SaveGame.h index 1d872766..fc8e7493 100644 --- a/neo/d3xp/gamesys/SaveGame.h +++ b/neo/d3xp/gamesys/SaveGame.h @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2015 Robert Beckebans This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -82,6 +83,7 @@ public: void WriteUserInterface( const idUserInterface* ui, bool unique ); void WriteRenderEntity( const renderEntity_t& renderEntity ); void WriteRenderLight( const renderLight_t& renderLight ); + void WriteRenderEnvprobe( const renderEnvironmentProbe_t& renderEnvprobe ); // RB void WriteRefSound( const refSound_t& refSound ); void WriteRenderView( const renderView_t& view ); void WriteUsercmd( const usercmd_t& usercmd ); @@ -169,6 +171,7 @@ public: void ReadUserInterface( idUserInterface*& ui ); void ReadRenderEntity( renderEntity_t& renderEntity ); void ReadRenderLight( renderLight_t& renderLight ); + void ReadRenderEnvprobe( renderEnvironmentProbe_t& renderEnvprobe ); // RB void ReadRefSound( refSound_t& refSound ); void ReadRenderView( renderView_t& view ); void ReadUsercmd( usercmd_t& usercmd ); diff --git a/neo/renderer/RenderWorld.h b/neo/renderer/RenderWorld.h index 3eaefd63..b4ffd324 100644 --- a/neo/renderer/RenderWorld.h +++ b/neo/renderer/RenderWorld.h @@ -221,6 +221,7 @@ typedef struct renderLight_s typedef struct { idVec3 origin; + float shaderParms[MAX_ENTITY_SHADER_PARMS]; // if non-zero, the environment probe will not show up in the specific view, // which may be used if we want to have slightly different muzzle diff --git a/neo/renderer/RenderWorld_load.cpp b/neo/renderer/RenderWorld_load.cpp index 0d80c853..05bed311 100644 --- a/neo/renderer/RenderWorld_load.cpp +++ b/neo/renderer/RenderWorld_load.cpp @@ -418,10 +418,15 @@ void idRenderWorldLocal::SetupAreaRefs() for( int i = 0; i < numPortalAreas; i++ ) { portalAreas[i].areaNum = i; + portalAreas[i].lightRefs.areaNext = portalAreas[i].lightRefs.areaPrev = &portalAreas[i].lightRefs; + portalAreas[i].entityRefs.areaNext = portalAreas[i].entityRefs.areaPrev = &portalAreas[i].entityRefs; + + portalAreas[i].envprobeRefs.areaNext = + portalAreas[i].envprobeRefs.areaPrev = &portalAreas[i].envprobeRefs; } }