123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- /*
- ===========================================================================
- 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();
- }
- 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;
- }
|