1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- 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"
- /*
- ===============================================================================
- idLight
- ===============================================================================
- */
- const idEventDef EV_Light_SetShader( "setShader", "s" );
- const idEventDef EV_Light_GetLightParm( "getLightParm", "d", 'f' );
- const idEventDef EV_Light_SetLightParm( "setLightParm", "df" );
- const idEventDef EV_Light_SetLightParms( "setLightParms", "ffff" );
- const idEventDef EV_Light_SetRadiusXYZ( "setRadiusXYZ", "fff" );
- const idEventDef EV_Light_SetRadius( "setRadius", "f" );
- const idEventDef EV_Light_On( "On", NULL );
- const idEventDef EV_Light_Off( "Off", NULL );
- const idEventDef EV_Light_FadeOut( "fadeOutLight", "f" );
- const idEventDef EV_Light_FadeIn( "fadeInLight", "f" );
- CLASS_DECLARATION( idEntity, idLight )
- EVENT( EV_Light_SetShader, idLight::Event_SetShader )
- EVENT( EV_Light_GetLightParm, idLight::Event_GetLightParm )
- EVENT( EV_Light_SetLightParm, idLight::Event_SetLightParm )
- EVENT( EV_Light_SetLightParms, idLight::Event_SetLightParms )
- EVENT( EV_Light_SetRadiusXYZ, idLight::Event_SetRadiusXYZ )
- EVENT( EV_Light_SetRadius, idLight::Event_SetRadius )
- EVENT( EV_Hide, idLight::Event_Hide )
- EVENT( EV_Show, idLight::Event_Show )
- EVENT( EV_Light_On, idLight::Event_On )
- EVENT( EV_Light_Off, idLight::Event_Off )
- EVENT( EV_Activate, idLight::Event_ToggleOnOff )
- EVENT( EV_PostSpawn, idLight::Event_SetSoundHandles )
- EVENT( EV_Light_FadeOut, idLight::Event_FadeOut )
- EVENT( EV_Light_FadeIn, idLight::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::ParseSpawnArgsToRenderLight( const idDict *args, renderLight_t *renderLight ) {
- bool gotTarget, gotUp, gotRight;
- const char *texture;
- idVec3 color;
- memset( renderLight, 0, sizeof( *renderLight ) );
- if (!args->GetVector("light_origin", "", renderLight->origin)) {
- args->GetVector( "origin", "", renderLight->origin );
- }
- gotTarget = args->GetVector( "light_target", "", renderLight->target );
- gotUp = args->GetVector( "light_up", "", renderLight->up );
- gotRight = args->GetVector( "light_right", "", renderLight->right );
- args->GetVector( "light_start", "0 0 0", renderLight->start );
- if ( !args->GetVector( "light_end", "", renderLight->end ) ) {
- renderLight->end = renderLight->target;
- }
- // we should have all of the target/right/up or none of them
- if ( ( gotTarget || gotUp || gotRight ) != ( gotTarget && gotUp && gotRight ) ) {
- gameLocal.Printf( "Light at (%f,%f,%f) has bad target info\n",
- renderLight->origin[0], renderLight->origin[1], renderLight->origin[2] );
- return;
- }
- if ( !gotTarget ) {
- renderLight->pointLight = true;
- // allow an optional relative center of light and shadow offset
- args->GetVector( "light_center", "0 0 0", renderLight->lightCenter );
- // create a point light
- if (!args->GetVector( "light_radius", "300 300 300", renderLight->lightRadius ) ) {
- float radius;
- args->GetFloat( "light", "300", radius );
- renderLight->lightRadius[0] = renderLight->lightRadius[1] = renderLight->lightRadius[2] = radius;
- }
- }
- // get the rotation matrix in either full form, or single angle form
- idAngles angles;
- idMat3 mat;
- if ( !args->GetMatrix( "light_rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
- if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
- args->GetFloat( "angle", "0", angles[ 1 ] );
- angles[ 0 ] = 0;
- angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] );
- angles[ 2 ] = 0;
- mat = angles.ToMat3();
- }
- }
- // fix degenerate identity matrices
- mat[0].FixDegenerateNormal();
- mat[1].FixDegenerateNormal();
- mat[2].FixDegenerateNormal();
- renderLight->axis = mat;
- // check for other attributes
- args->GetVector( "_color", "1 1 1", color );
- renderLight->shaderParms[ SHADERPARM_RED ] = color[0];
- renderLight->shaderParms[ SHADERPARM_GREEN ] = color[1];
- renderLight->shaderParms[ SHADERPARM_BLUE ] = color[2];
- args->GetFloat( "shaderParm3", "1", renderLight->shaderParms[ SHADERPARM_TIMESCALE ] );
- if ( !args->GetFloat( "shaderParm4", "0", renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] ) ) {
- // offset the start time of the shader to sync it to the game time
- renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
- }
- args->GetFloat( "shaderParm5", "0", renderLight->shaderParms[5] );
- args->GetFloat( "shaderParm6", "0", renderLight->shaderParms[6] );
- args->GetFloat( "shaderParm7", "0", renderLight->shaderParms[ SHADERPARM_MODE ] );
- args->GetBool( "noshadows", "0", renderLight->noShadows );
- args->GetBool( "nospecular", "0", renderLight->noSpecular );
- args->GetBool( "parallel", "0", renderLight->parallel );
- args->GetString( "texture", "lights/squarelight1", &texture );
- // allow this to be NULL
- renderLight->shader = declManager->FindMaterial( texture, false );
- }
- /*
- ================
- idLight::UpdateChangeableSpawnArgs
- ================
- */
- void idLight::UpdateChangeableSpawnArgs( const idDict *source ) {
- idEntity::UpdateChangeableSpawnArgs( source );
- if ( source ) {
- source->Print();
- }
- FreeSoundEmitter( true );
- gameEdit->ParseSpawnArgsToRefSound( source ? source : &spawnArgs, &refSound );
- if ( refSound.shader && !refSound.waitfortrigger ) {
- StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
- }
- gameEdit->ParseSpawnArgsToRenderLight( source ? source : &spawnArgs, &renderLight );
- UpdateVisuals();
- }
- /*
- ================
- idLight::idLight
- ================
- */
- idLight::idLight() {
- memset( &renderLight, 0, sizeof( renderLight ) );
- localLightOrigin = vec3_zero;
- localLightAxis = mat3_identity;
- lightDefHandle = -1;
- levels = 0;
- currentLevel = 0;
- baseColor = vec3_zero;
- breakOnTrigger = false;
- count = 0;
- triggercount = 0;
- lightParent = NULL;
- fadeFrom.Set( 1, 1, 1, 1 );
- fadeTo.Set( 1, 1, 1, 1 );
- fadeStart = 0;
- fadeEnd = 0;
- soundWasPlaying = false;
- }
- /*
- ================
- idLight::~idLight
- ================
- */
- idLight::~idLight() {
- if ( lightDefHandle != -1 ) {
- gameRenderWorld->FreeLightDef( lightDefHandle );
- }
- }
- /*
- ================
- idLight::Save
- archives object for save game file
- ================
- */
- void idLight::Save( idSaveGame *savefile ) const {
- savefile->WriteRenderLight( renderLight );
-
- savefile->WriteBool( renderLight.prelightModel != NULL );
- savefile->WriteVec3( localLightOrigin );
- savefile->WriteMat3( localLightAxis );
- savefile->WriteString( brokenModel );
- savefile->WriteInt( levels );
- savefile->WriteInt( currentLevel );
- savefile->WriteVec3( baseColor );
- savefile->WriteBool( breakOnTrigger );
- savefile->WriteInt( count );
- savefile->WriteInt( triggercount );
- savefile->WriteObject( lightParent );
- savefile->WriteVec4( fadeFrom );
- savefile->WriteVec4( fadeTo );
- savefile->WriteInt( fadeStart );
- savefile->WriteInt( fadeEnd );
- savefile->WriteBool( soundWasPlaying );
- }
- /*
- ================
- idLight::Restore
- unarchives object from save game file
- ================
- */
- void idLight::Restore( idRestoreGame *savefile ) {
- bool hadPrelightModel;
- savefile->ReadRenderLight( renderLight );
- savefile->ReadBool( hadPrelightModel );
- renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
- if ( ( renderLight.prelightModel == NULL ) && hadPrelightModel ) {
- assert( 0 );
- if ( developer.GetBool() ) {
- // we really want to know if this happens
- gameLocal.Error( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
- } else {
- // but let it slide after release
- gameLocal.Warning( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
- }
- }
- savefile->ReadVec3( localLightOrigin );
- savefile->ReadMat3( localLightAxis );
- savefile->ReadString( brokenModel );
- savefile->ReadInt( levels );
- savefile->ReadInt( currentLevel );
- savefile->ReadVec3( baseColor );
- savefile->ReadBool( breakOnTrigger );
- savefile->ReadInt( count );
- savefile->ReadInt( triggercount );
- savefile->ReadObject( reinterpret_cast<idClass *&>( lightParent ) );
- savefile->ReadVec4( fadeFrom );
- savefile->ReadVec4( fadeTo );
- savefile->ReadInt( fadeStart );
- savefile->ReadInt( fadeEnd );
- savefile->ReadBool( soundWasPlaying );
- lightDefHandle = -1;
- SetLightLevel();
- }
- /*
- ================
- idLight::Spawn
- ================
- */
- void idLight::Spawn( void ) {
- bool start_off;
- bool needBroken;
- const char *demonic_shader;
- // do the parsing the same way dmap and the editor do
- gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &renderLight );
- // we need the origin and axis relative to the physics origin/axis
- localLightOrigin = ( renderLight.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose();
- localLightAxis = renderLight.axis * GetPhysics()->GetAxis().Transpose();
- // set the base color from the shader parms
- baseColor.Set( renderLight.shaderParms[ SHADERPARM_RED ], renderLight.shaderParms[ SHADERPARM_GREEN ], renderLight.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() );
- }
- // make sure the demonic shader is cached
- if ( spawnArgs.GetString( "mat_demonic", NULL, &demonic_shader ) ) {
- declManager->FindType( DECL_MATERIAL, demonic_shader );
- }
- // game specific functionality, not mirrored in
- // editor or dmap light parsing
- // also put the light texture on the model, so light flares
- // can get the current intensity of the light
- renderEntity.referenceShader = renderLight.shader;
- lightDefHandle = -1; // no static version yet
- // see if an optimized shadow volume exists
- // the renderer will ignore this value after a light has been moved,
- // but there may still be a chance to get it wrong if the game moves
- // a light before the first present, and doesn't clear the prelight
- renderLight.prelightModel = 0;
- if ( name[ 0 ] ) {
- // this will return 0 if not found
- renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
- }
- spawnArgs.GetBool( "start_off", "0", start_off );
- if ( start_off ) {
- Off();
- }
- #ifdef CTF
- // Midnight CTF
- if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") && !spawnArgs.GetBool("midnight_override") ) {
- Off();
- }
- #endif
-
- health = spawnArgs.GetInt( "health", "0" );
- spawnArgs.GetString( "broken", "", brokenModel );
- spawnArgs.GetBool( "break", "0", breakOnTrigger );
- spawnArgs.GetInt( "count", "1", count );
- triggercount = 0;
- fadeFrom.Set( 1, 1, 1, 1 );
- fadeTo.Set( 1, 1, 1, 1 );
- fadeStart = 0;
- fadeEnd = 0;
- // if we have a health make light breakable
- if ( health ) {
- idStr model = spawnArgs.GetString( "model" ); // get the visual model
- if ( !model.Length() ) {
- gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() );
- }
- fl.takedamage = true;
- // see if we need to create a broken model name
- needBroken = true;
- if ( model.Length() && !brokenModel.Length() ) {
- int pos;
- needBroken = false;
-
- pos = model.Find( "." );
- if ( pos < 0 ) {
- pos = model.Length();
- }
- if ( pos > 0 ) {
- model.Left( pos, brokenModel );
- }
- brokenModel += "_broken";
- if ( pos > 0 ) {
- brokenModel += &model[ pos ];
- }
- }
-
- // make sure the model gets cached
- if ( !renderModelManager->CheckModel( brokenModel ) ) {
- if ( needBroken ) {
- gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() );
- } else {
- brokenModel = "";
- }
- }
- GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID );
-
- // make sure the collision model gets cached
- idClipModel::CheckModel( brokenModel );
- }
- PostEventMS( &EV_PostSpawn, 0 );
- UpdateVisuals();
- }
- /*
- ================
- idLight::SetLightLevel
- ================
- */
- void idLight::SetLightLevel( void ) {
- idVec3 color;
- float intensity;
- intensity = ( float )currentLevel / ( float )levels;
- color = baseColor * intensity;
- renderLight.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
- renderLight.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
- renderLight.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
- renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
- renderEntity.shaderParms[ SHADERPARM_GREEN ]= color[ 1 ];
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
- PresentLightDefChange();
- PresentModelDefChange();
- }
- /*
- ================
- idLight::GetColor
- ================
- */
- void idLight::GetColor( idVec3 &out ) const {
- out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
- out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
- out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
- }
- /*
- ================
- idLight::GetColor
- ================
- */
- void idLight::GetColor( idVec4 &out ) const {
- out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
- out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
- out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
- out[ 3 ] = renderLight.shaderParms[ SHADERPARM_ALPHA ];
- }
- /*
- ================
- idLight::SetColor
- ================
- */
- void idLight::SetColor( float red, float green, float blue ) {
- baseColor.Set( red, green, blue );
- SetLightLevel();
- }
- /*
- ================
- idLight::SetColor
- ================
- */
- void idLight::SetColor( const idVec4 &color ) {
- baseColor = color.ToVec3();
- renderLight.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
- renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
- SetLightLevel();
- }
- /*
- ================
- idLight::SetShader
- ================
- */
- void idLight::SetShader( const char *shadername ) {
- // allow this to be NULL
- renderLight.shader = declManager->FindMaterial( shadername, false );
- PresentLightDefChange();
- }
- /*
- ================
- idLight::SetLightParm
- ================
- */
- void idLight::SetLightParm( int parmnum, float value ) {
- if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
- gameLocal.Error( "shader parm index (%d) out of range", parmnum );
- }
- renderLight.shaderParms[ parmnum ] = value;
- PresentLightDefChange();
- }
- /*
- ================
- idLight::SetLightParms
- ================
- */
- void idLight::SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
- renderLight.shaderParms[ SHADERPARM_RED ] = parm0;
- renderLight.shaderParms[ SHADERPARM_GREEN ] = parm1;
- renderLight.shaderParms[ SHADERPARM_BLUE ] = parm2;
- renderLight.shaderParms[ SHADERPARM_ALPHA ] = parm3;
- renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
- renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
- renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
- PresentLightDefChange();
- PresentModelDefChange();
- }
- /*
- ================
- idLight::SetRadiusXYZ
- ================
- */
- void idLight::SetRadiusXYZ( float x, float y, float z ) {
- renderLight.lightRadius[0] = x;
- renderLight.lightRadius[1] = y;
- renderLight.lightRadius[2] = z;
- PresentLightDefChange();
- }
- /*
- ================
- idLight::SetRadius
- ================
- */
- void idLight::SetRadius( float radius ) {
- renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = radius;
- PresentLightDefChange();
- }
- /*
- ================
- idLight::On
- ================
- */
- void idLight::On( void ) {
- currentLevel = levels;
- // offset the start time of the shader to sync it to the game time
- renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
- if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) {
- StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
- soundWasPlaying = false;
- }
- SetLightLevel();
- BecomeActive( TH_UPDATEVISUALS );
- }
- /*
- ================
- idLight::Off
- ================
- */
- void idLight::Off( void ) {
- currentLevel = 0;
- // kill any sound it was making
- if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) {
- StopSound( SND_CHANNEL_ANY, false );
- soundWasPlaying = true;
- }
- SetLightLevel();
- BecomeActive( TH_UPDATEVISUALS );
- }
- /*
- ================
- idLight::Fade
- ================
- */
- void idLight::Fade( const idVec4 &to, float fadeTime ) {
- GetColor( fadeFrom );
- fadeTo = to;
- fadeStart = gameLocal.time;
- fadeEnd = gameLocal.time + SEC2MS( fadeTime );
- BecomeActive( TH_THINK );
- }
- /*
- ================
- idLight::FadeOut
- ================
- */
- void idLight::FadeOut( float time ) {
- Fade( colorBlack, time );
- }
- /*
- ================
- idLight::FadeIn
- ================
- */
- void idLight::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 );
- }
- /*
- ================
- idLight::Killed
- ================
- */
- void idLight::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
- BecomeBroken( attacker );
- }
- /*
- ================
- idLight::BecomeBroken
- ================
- */
- void idLight::BecomeBroken( idEntity *activator ) {
- const char *damageDefName;
- fl.takedamage = false;
- if ( brokenModel.Length() ) {
- SetModel( brokenModel );
- if ( !spawnArgs.GetBool( "nonsolid" ) ) {
- GetPhysics()->SetClipModel( new idClipModel( brokenModel.c_str() ), 1.0f );
- GetPhysics()->SetContents( CONTENTS_SOLID );
- }
- } else if ( spawnArgs.GetBool( "hideModelOnBreak" ) ) {
- SetModel( "" );
- GetPhysics()->SetContents( 0 );
- }
- if ( gameLocal.isServer ) {
- ServerSendEvent( EVENT_BECOMEBROKEN, NULL, true, -1 );
- if ( spawnArgs.GetString( "def_damage", "", &damageDefName ) ) {
- idVec3 origin = renderEntity.origin + renderEntity.bounds.GetCenter() * renderEntity.axis;
- gameLocal.RadiusDamage( origin, activator, activator, this, this, damageDefName );
- }
- }
- ActivateTargets( activator );
- // offset the start time of the shader to sync it to the game time
- renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
- renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
- // set the state parm
- renderEntity.shaderParms[ SHADERPARM_MODE ] = 1;
- renderLight.shaderParms[ SHADERPARM_MODE ] = 1;
- // if the light has a sound, either start the alternate (broken) sound, or stop the sound
- const char *parm = spawnArgs.GetString( "snd_broken" );
- if ( refSound.shader || ( parm && *parm ) ) {
- StopSound( SND_CHANNEL_ANY, false );
- const idSoundShader *alternate = refSound.shader ? refSound.shader->GetAltSound() : declManager->FindSound( parm );
- if ( alternate ) {
- // start it with no diversity, so the leadin break sound plays
- refSound.referenceSound->StartSound( alternate, SND_CHANNEL_ANY, 0.0, 0 );
- }
- }
- parm = spawnArgs.GetString( "mtr_broken" );
- if ( parm && *parm ) {
- SetShader( parm );
- }
- UpdateVisuals();
- }
- /*
- ================
- idLight::PresentLightDefChange
- ================
- */
- void idLight::PresentLightDefChange( void ) {
- // let the renderer apply it to the world
- if ( ( lightDefHandle != -1 ) ) {
- gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight );
- } else {
- lightDefHandle = gameRenderWorld->AddLightDef( &renderLight );
- }
- }
- /*
- ================
- idLight::PresentModelDefChange
- ================
- */
- void idLight::PresentModelDefChange( void ) {
- if ( !renderEntity.hModel || IsHidden() ) {
- return;
- }
- // add to refresh list
- if ( modelDefHandle == -1 ) {
- modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
- } else {
- gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
- }
- }
- /*
- ================
- idLight::Present
- ================
- */
- void idLight::Present( void ) {
- // don't present to the renderer if the entity hasn't changed
- if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
- return;
- }
- // add the model
- idEntity::Present();
- // current transformation
- renderLight.axis = localLightAxis * GetPhysics()->GetAxis();
- renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localLightOrigin;
- // reference the sound for shader synced effects
- 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
- PresentLightDefChange();
- PresentModelDefChange();
- }
- /*
- ================
- idLight::Think
- ================
- */
- void idLight::Think( void ) {
- 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();
- }
- /*
- ================
- idLight::GetPhysicsToSoundTransform
- ================
- */
- bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
- origin = localLightOrigin + renderLight.lightCenter;
- axis = localLightAxis * GetPhysics()->GetAxis();
- return true;
- }
- /*
- ================
- idLight::FreeLightDef
- ================
- */
- void idLight::FreeLightDef( void ) {
- if ( lightDefHandle != -1 ) {
- gameRenderWorld->FreeLightDef( lightDefHandle );
- lightDefHandle = -1;
- }
- }
- /*
- ================
- idLight::SaveState
- ================
- */
- void idLight::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() );
- }
- }
- /*
- ===============
- idLight::ShowEditingDialog
- ===============
- */
- void idLight::ShowEditingDialog( void ) {
- if ( g_editEntityMode.GetInteger() == 1 ) {
- common->InitTool( EDITOR_LIGHT, &spawnArgs );
- } else {
- common->InitTool( EDITOR_SOUND, &spawnArgs );
- }
- }
- /*
- ================
- idLight::Event_SetShader
- ================
- */
- void idLight::Event_SetShader( const char *shadername ) {
- SetShader( shadername );
- }
- /*
- ================
- idLight::Event_GetLightParm
- ================
- */
- void idLight::Event_GetLightParm( int parmnum ) {
- if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
- gameLocal.Error( "shader parm index (%d) out of range", parmnum );
- }
- idThread::ReturnFloat( renderLight.shaderParms[ parmnum ] );
- }
- /*
- ================
- idLight::Event_SetLightParm
- ================
- */
- void idLight::Event_SetLightParm( int parmnum, float value ) {
- SetLightParm( parmnum, value );
- }
- /*
- ================
- idLight::Event_SetLightParms
- ================
- */
- void idLight::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
- SetLightParms( parm0, parm1, parm2, parm3 );
- }
- /*
- ================
- idLight::Event_SetRadiusXYZ
- ================
- */
- void idLight::Event_SetRadiusXYZ( float x, float y, float z ) {
- SetRadiusXYZ( x, y, z );
- }
- /*
- ================
- idLight::Event_SetRadius
- ================
- */
- void idLight::Event_SetRadius( float radius ) {
- SetRadius( radius );
- }
- /*
- ================
- idLight::Event_Hide
- ================
- */
- void idLight::Event_Hide( void ) {
- Hide();
- PresentModelDefChange();
- Off();
- }
- /*
- ================
- idLight::Event_Show
- ================
- */
- void idLight::Event_Show( void ) {
- Show();
- PresentModelDefChange();
- On();
- }
- /*
- ================
- idLight::Event_On
- ================
- */
- void idLight::Event_On( void ) {
- On();
- }
- /*
- ================
- idLight::Event_Off
- ================
- */
- void idLight::Event_Off( void ) {
- Off();
- }
- /*
- ================
- idLight::Event_ToggleOnOff
- ================
- */
- void idLight::Event_ToggleOnOff( idEntity *activator ) {
- triggercount++;
- if ( triggercount < count ) {
- return;
- }
- // reset trigger count
- triggercount = 0;
- if ( breakOnTrigger ) {
- BecomeBroken( activator );
- breakOnTrigger = false;
- return;
- }
- if ( !currentLevel ) {
- On();
- }
- else {
- currentLevel--;
- if ( !currentLevel ) {
- Off();
- }
- else {
- SetLightLevel();
- }
- }
- }
- /*
- ================
- idLight::Event_SetSoundHandles
- set the same sound def handle on all targeted lights
- ================
- */
- void idLight::Event_SetSoundHandles( void ) {
- int i;
- idEntity *targetEnt;
- if ( !refSound.referenceSound ) {
- return;
- }
- for ( i = 0; i < targets.Num(); i++ ) {
- targetEnt = targets[ i ].GetEntity();
- if ( targetEnt && targetEnt->IsType( idLight::Type ) ) {
- idLight *light = static_cast<idLight*>(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();
- }
- }
- }
- /*
- ================
- idLight::Event_FadeOut
- ================
- */
- void idLight::Event_FadeOut( float time ) {
- FadeOut( time );
- }
- /*
- ================
- idLight::Event_FadeIn
- ================
- */
- void idLight::Event_FadeIn( float time ) {
- FadeIn( time );
- }
- /*
- ================
- idLight::ClientPredictionThink
- ================
- */
- void idLight::ClientPredictionThink( void ) {
- Think();
- }
- /*
- ================
- idLight::WriteToSnapshot
- ================
- */
- void idLight::WriteToSnapshot( idBitMsgDelta &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( renderLight.lightRadius[0], 5, 10 );
- msg.WriteFloat( renderLight.lightRadius[1], 5, 10 );
- msg.WriteFloat( renderLight.lightRadius[2], 5, 10 );
- msg.WriteLong( PackColor( idVec4( renderLight.shaderParms[SHADERPARM_RED],
- renderLight.shaderParms[SHADERPARM_GREEN],
- renderLight.shaderParms[SHADERPARM_BLUE],
- renderLight.shaderParms[SHADERPARM_ALPHA] ) ) );
- msg.WriteFloat( renderLight.shaderParms[SHADERPARM_TIMESCALE], 5, 10 );
- msg.WriteLong( renderLight.shaderParms[SHADERPARM_TIMEOFFSET] );
- //msg.WriteByte( renderLight.shaderParms[SHADERPARM_DIVERSITY] );
- msg.WriteShort( renderLight.shaderParms[SHADERPARM_MODE] );
- WriteColorToSnapshot( msg );
- }
- /*
- ================
- idLight::ReadFromSnapshot
- ================
- */
- void idLight::ReadFromSnapshot( const idBitMsgDelta &msg ) {
- idVec4 shaderColor;
- int oldCurrentLevel = currentLevel;
- idVec3 oldBaseColor = baseColor;
- 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(), baseColor );
- // 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 );
- renderLight.shaderParms[SHADERPARM_RED] = shaderColor[0];
- renderLight.shaderParms[SHADERPARM_GREEN] = shaderColor[1];
- renderLight.shaderParms[SHADERPARM_BLUE] = shaderColor[2];
- renderLight.shaderParms[SHADERPARM_ALPHA] = shaderColor[3];
- renderLight.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 );
- renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadLong();
- //renderLight.shaderParms[SHADERPARM_DIVERSITY] = msg.ReadFloat();
- renderLight.shaderParms[SHADERPARM_MODE] = msg.ReadShort();
- ReadColorFromSnapshot( msg );
- if ( msg.HasChanged() ) {
- if ( ( currentLevel != oldCurrentLevel ) || ( baseColor != oldBaseColor ) ) {
- SetLightLevel();
- } else {
- PresentLightDefChange();
- PresentModelDefChange();
- }
- }
- }
- /*
- ================
- idLight::ClientReceiveEvent
- ================
- */
- bool idLight::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
- switch( event ) {
- case EVENT_BECOMEBROKEN: {
- BecomeBroken( NULL );
- return true;
- }
- default: {
- return idEntity::ClientReceiveEvent( event, time, msg );
- }
- }
- return false;
- }
|