2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
32 #include "Game_local.h"
35 ===============================================================================
39 ===============================================================================
42 const idEventDef EV_Light_SetShader( "setShader", "s" );
43 const idEventDef EV_Light_GetLightParm( "getLightParm", "d", 'f' );
44 const idEventDef EV_Light_SetLightParm( "setLightParm", "df" );
45 const idEventDef EV_Light_SetLightParms( "setLightParms", "ffff" );
46 const idEventDef EV_Light_SetRadiusXYZ( "setRadiusXYZ", "fff" );
47 const idEventDef EV_Light_SetRadius( "setRadius", "f" );
48 const idEventDef EV_Light_On( "On", NULL );
49 const idEventDef EV_Light_Off( "Off", NULL );
50 const idEventDef EV_Light_FadeOut( "fadeOutLight", "f" );
51 const idEventDef EV_Light_FadeIn( "fadeInLight", "f" );
53 CLASS_DECLARATION( idEntity, idLight )
54 EVENT( EV_Light_SetShader, idLight::Event_SetShader )
55 EVENT( EV_Light_GetLightParm, idLight::Event_GetLightParm )
56 EVENT( EV_Light_SetLightParm, idLight::Event_SetLightParm )
57 EVENT( EV_Light_SetLightParms, idLight::Event_SetLightParms )
58 EVENT( EV_Light_SetRadiusXYZ, idLight::Event_SetRadiusXYZ )
59 EVENT( EV_Light_SetRadius, idLight::Event_SetRadius )
60 EVENT( EV_Hide, idLight::Event_Hide )
61 EVENT( EV_Show, idLight::Event_Show )
62 EVENT( EV_Light_On, idLight::Event_On )
63 EVENT( EV_Light_Off, idLight::Event_Off )
64 EVENT( EV_Activate, idLight::Event_ToggleOnOff )
65 EVENT( EV_PostSpawn, idLight::Event_SetSoundHandles )
66 EVENT( EV_Light_FadeOut, idLight::Event_FadeOut )
67 EVENT( EV_Light_FadeIn, idLight::Event_FadeIn )
73 idGameEdit::ParseSpawnArgsToRenderLight
75 parse the light parameters
76 this is the canonical renderLight parm parsing,
77 which should be used by dmap and the editor
80 void idGameEdit::ParseSpawnArgsToRenderLight( const idDict *args, renderLight_t *renderLight ) {
81 bool gotTarget, gotUp, gotRight;
85 memset( renderLight, 0, sizeof( *renderLight ) );
87 if (!args->GetVector("light_origin", "", renderLight->origin)) {
88 args->GetVector( "origin", "", renderLight->origin );
91 gotTarget = args->GetVector( "light_target", "", renderLight->target );
92 gotUp = args->GetVector( "light_up", "", renderLight->up );
93 gotRight = args->GetVector( "light_right", "", renderLight->right );
94 args->GetVector( "light_start", "0 0 0", renderLight->start );
95 if ( !args->GetVector( "light_end", "", renderLight->end ) ) {
96 renderLight->end = renderLight->target;
99 // we should have all of the target/right/up or none of them
100 if ( ( gotTarget || gotUp || gotRight ) != ( gotTarget && gotUp && gotRight ) ) {
101 gameLocal.Printf( "Light at (%f,%f,%f) has bad target info\n",
102 renderLight->origin[0], renderLight->origin[1], renderLight->origin[2] );
107 renderLight->pointLight = true;
109 // allow an optional relative center of light and shadow offset
110 args->GetVector( "light_center", "0 0 0", renderLight->lightCenter );
112 // create a point light
113 if (!args->GetVector( "light_radius", "300 300 300", renderLight->lightRadius ) ) {
116 args->GetFloat( "light", "300", radius );
117 renderLight->lightRadius[0] = renderLight->lightRadius[1] = renderLight->lightRadius[2] = radius;
121 // get the rotation matrix in either full form, or single angle form
124 if ( !args->GetMatrix( "light_rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
125 if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
126 args->GetFloat( "angle", "0", angles[ 1 ] );
128 angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] );
130 mat = angles.ToMat3();
134 // fix degenerate identity matrices
135 mat[0].FixDegenerateNormal();
136 mat[1].FixDegenerateNormal();
137 mat[2].FixDegenerateNormal();
139 renderLight->axis = mat;
141 // check for other attributes
142 args->GetVector( "_color", "1 1 1", color );
143 renderLight->shaderParms[ SHADERPARM_RED ] = color[0];
144 renderLight->shaderParms[ SHADERPARM_GREEN ] = color[1];
145 renderLight->shaderParms[ SHADERPARM_BLUE ] = color[2];
146 args->GetFloat( "shaderParm3", "1", renderLight->shaderParms[ SHADERPARM_TIMESCALE ] );
147 if ( !args->GetFloat( "shaderParm4", "0", renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] ) ) {
148 // offset the start time of the shader to sync it to the game time
149 renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
152 args->GetFloat( "shaderParm5", "0", renderLight->shaderParms[5] );
153 args->GetFloat( "shaderParm6", "0", renderLight->shaderParms[6] );
154 args->GetFloat( "shaderParm7", "0", renderLight->shaderParms[ SHADERPARM_MODE ] );
155 args->GetBool( "noshadows", "0", renderLight->noShadows );
156 args->GetBool( "nospecular", "0", renderLight->noSpecular );
157 args->GetBool( "parallel", "0", renderLight->parallel );
159 args->GetString( "texture", "lights/squarelight1", &texture );
160 // allow this to be NULL
161 renderLight->shader = declManager->FindMaterial( texture, false );
166 idLight::UpdateChangeableSpawnArgs
169 void idLight::UpdateChangeableSpawnArgs( const idDict *source ) {
171 idEntity::UpdateChangeableSpawnArgs( source );
176 FreeSoundEmitter( true );
177 gameEdit->ParseSpawnArgsToRefSound( source ? source : &spawnArgs, &refSound );
178 if ( refSound.shader && !refSound.waitfortrigger ) {
179 StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
182 gameEdit->ParseSpawnArgsToRenderLight( source ? source : &spawnArgs, &renderLight );
193 memset( &renderLight, 0, sizeof( renderLight ) );
194 localLightOrigin = vec3_zero;
195 localLightAxis = mat3_identity;
199 baseColor = vec3_zero;
200 breakOnTrigger = false;
204 fadeFrom.Set( 1, 1, 1, 1 );
205 fadeTo.Set( 1, 1, 1, 1 );
208 soundWasPlaying = false;
216 idLight::~idLight() {
217 if ( lightDefHandle != -1 ) {
218 gameRenderWorld->FreeLightDef( lightDefHandle );
226 archives object for save game file
229 void idLight::Save( idSaveGame *savefile ) const {
230 savefile->WriteRenderLight( renderLight );
232 savefile->WriteBool( renderLight.prelightModel != NULL );
234 savefile->WriteVec3( localLightOrigin );
235 savefile->WriteMat3( localLightAxis );
237 savefile->WriteString( brokenModel );
238 savefile->WriteInt( levels );
239 savefile->WriteInt( currentLevel );
241 savefile->WriteVec3( baseColor );
242 savefile->WriteBool( breakOnTrigger );
243 savefile->WriteInt( count );
244 savefile->WriteInt( triggercount );
245 savefile->WriteObject( lightParent );
247 savefile->WriteVec4( fadeFrom );
248 savefile->WriteVec4( fadeTo );
249 savefile->WriteInt( fadeStart );
250 savefile->WriteInt( fadeEnd );
251 savefile->WriteBool( soundWasPlaying );
258 unarchives object from save game file
261 void idLight::Restore( idRestoreGame *savefile ) {
262 bool hadPrelightModel;
264 savefile->ReadRenderLight( renderLight );
266 savefile->ReadBool( hadPrelightModel );
267 renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
268 if ( ( renderLight.prelightModel == NULL ) && hadPrelightModel ) {
270 if ( developer.GetBool() ) {
271 // we really want to know if this happens
272 gameLocal.Error( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
274 // but let it slide after release
275 gameLocal.Warning( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
279 savefile->ReadVec3( localLightOrigin );
280 savefile->ReadMat3( localLightAxis );
282 savefile->ReadString( brokenModel );
283 savefile->ReadInt( levels );
284 savefile->ReadInt( currentLevel );
286 savefile->ReadVec3( baseColor );
287 savefile->ReadBool( breakOnTrigger );
288 savefile->ReadInt( count );
289 savefile->ReadInt( triggercount );
290 savefile->ReadObject( reinterpret_cast<idClass *&>( lightParent ) );
292 savefile->ReadVec4( fadeFrom );
293 savefile->ReadVec4( fadeTo );
294 savefile->ReadInt( fadeStart );
295 savefile->ReadInt( fadeEnd );
296 savefile->ReadBool( soundWasPlaying );
308 void idLight::Spawn( void ) {
311 const char *demonic_shader;
313 // do the parsing the same way dmap and the editor do
314 gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &renderLight );
316 // we need the origin and axis relative to the physics origin/axis
317 localLightOrigin = ( renderLight.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose();
318 localLightAxis = renderLight.axis * GetPhysics()->GetAxis().Transpose();
320 // set the base color from the shader parms
321 baseColor.Set( renderLight.shaderParms[ SHADERPARM_RED ], renderLight.shaderParms[ SHADERPARM_GREEN ], renderLight.shaderParms[ SHADERPARM_BLUE ] );
323 // set the number of light levels
324 spawnArgs.GetInt( "levels", "1", levels );
325 currentLevel = levels;
327 gameLocal.Error( "Invalid light level set on entity #%d(%s)", entityNumber, name.c_str() );
330 // make sure the demonic shader is cached
331 if ( spawnArgs.GetString( "mat_demonic", NULL, &demonic_shader ) ) {
332 declManager->FindType( DECL_MATERIAL, demonic_shader );
335 // game specific functionality, not mirrored in
336 // editor or dmap light parsing
338 // also put the light texture on the model, so light flares
339 // can get the current intensity of the light
340 renderEntity.referenceShader = renderLight.shader;
342 lightDefHandle = -1; // no static version yet
344 // see if an optimized shadow volume exists
345 // the renderer will ignore this value after a light has been moved,
346 // but there may still be a chance to get it wrong if the game moves
347 // a light before the first present, and doesn't clear the prelight
348 renderLight.prelightModel = 0;
350 // this will return 0 if not found
351 renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
354 spawnArgs.GetBool( "start_off", "0", start_off );
361 if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") && !spawnArgs.GetBool("midnight_override") ) {
366 health = spawnArgs.GetInt( "health", "0" );
367 spawnArgs.GetString( "broken", "", brokenModel );
368 spawnArgs.GetBool( "break", "0", breakOnTrigger );
369 spawnArgs.GetInt( "count", "1", count );
373 fadeFrom.Set( 1, 1, 1, 1 );
374 fadeTo.Set( 1, 1, 1, 1 );
378 // if we have a health make light breakable
380 idStr model = spawnArgs.GetString( "model" ); // get the visual model
381 if ( !model.Length() ) {
382 gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() );
385 fl.takedamage = true;
387 // see if we need to create a broken model name
389 if ( model.Length() && !brokenModel.Length() ) {
394 pos = model.Find( "." );
396 pos = model.Length();
399 model.Left( pos, brokenModel );
401 brokenModel += "_broken";
403 brokenModel += &model[ pos ];
407 // make sure the model gets cached
408 if ( !renderModelManager->CheckModel( brokenModel ) ) {
410 gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() );
416 GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID );
418 // make sure the collision model gets cached
419 idClipModel::CheckModel( brokenModel );
422 PostEventMS( &EV_PostSpawn, 0 );
429 idLight::SetLightLevel
432 void idLight::SetLightLevel( void ) {
436 intensity = ( float )currentLevel / ( float )levels;
437 color = baseColor * intensity;
438 renderLight.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
439 renderLight.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
440 renderLight.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
441 renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
442 renderEntity.shaderParms[ SHADERPARM_GREEN ]= color[ 1 ];
443 renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
444 PresentLightDefChange();
445 PresentModelDefChange();
453 void idLight::GetColor( idVec3 &out ) const {
454 out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
455 out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
456 out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
464 void idLight::GetColor( idVec4 &out ) const {
465 out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
466 out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
467 out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
468 out[ 3 ] = renderLight.shaderParms[ SHADERPARM_ALPHA ];
476 void idLight::SetColor( float red, float green, float blue ) {
477 baseColor.Set( red, green, blue );
486 void idLight::SetColor( const idVec4 &color ) {
487 baseColor = color.ToVec3();
488 renderLight.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
489 renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
498 void idLight::SetShader( const char *shadername ) {
499 // allow this to be NULL
500 renderLight.shader = declManager->FindMaterial( shadername, false );
501 PresentLightDefChange();
506 idLight::SetLightParm
509 void idLight::SetLightParm( int parmnum, float value ) {
510 if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
511 gameLocal.Error( "shader parm index (%d) out of range", parmnum );
514 renderLight.shaderParms[ parmnum ] = value;
515 PresentLightDefChange();
520 idLight::SetLightParms
523 void idLight::SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
524 renderLight.shaderParms[ SHADERPARM_RED ] = parm0;
525 renderLight.shaderParms[ SHADERPARM_GREEN ] = parm1;
526 renderLight.shaderParms[ SHADERPARM_BLUE ] = parm2;
527 renderLight.shaderParms[ SHADERPARM_ALPHA ] = parm3;
528 renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
529 renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
530 renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
531 renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
532 PresentLightDefChange();
533 PresentModelDefChange();
538 idLight::SetRadiusXYZ
541 void idLight::SetRadiusXYZ( float x, float y, float z ) {
542 renderLight.lightRadius[0] = x;
543 renderLight.lightRadius[1] = y;
544 renderLight.lightRadius[2] = z;
545 PresentLightDefChange();
553 void idLight::SetRadius( float radius ) {
554 renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = radius;
555 PresentLightDefChange();
563 void idLight::On( void ) {
564 currentLevel = levels;
565 // offset the start time of the shader to sync it to the game time
566 renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
567 if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) {
568 StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
569 soundWasPlaying = false;
572 BecomeActive( TH_UPDATEVISUALS );
580 void idLight::Off( void ) {
582 // kill any sound it was making
583 if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) {
584 StopSound( SND_CHANNEL_ANY, false );
585 soundWasPlaying = true;
588 BecomeActive( TH_UPDATEVISUALS );
596 void idLight::Fade( const idVec4 &to, float fadeTime ) {
597 GetColor( fadeFrom );
599 fadeStart = gameLocal.time;
600 fadeEnd = gameLocal.time + SEC2MS( fadeTime );
601 BecomeActive( TH_THINK );
609 void idLight::FadeOut( float time ) {
610 Fade( colorBlack, time );
618 void idLight::FadeIn( float time ) {
622 currentLevel = levels;
623 spawnArgs.GetVector( "_color", "1 1 1", color );
624 color4.Set( color.x, color.y, color.z, 1.0f );
625 Fade( color4, time );
633 void idLight::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
634 BecomeBroken( attacker );
639 idLight::BecomeBroken
642 void idLight::BecomeBroken( idEntity *activator ) {
643 const char *damageDefName;
645 fl.takedamage = false;
647 if ( brokenModel.Length() ) {
648 SetModel( brokenModel );
650 if ( !spawnArgs.GetBool( "nonsolid" ) ) {
651 GetPhysics()->SetClipModel( new idClipModel( brokenModel.c_str() ), 1.0f );
652 GetPhysics()->SetContents( CONTENTS_SOLID );
654 } else if ( spawnArgs.GetBool( "hideModelOnBreak" ) ) {
656 GetPhysics()->SetContents( 0 );
659 if ( gameLocal.isServer ) {
661 ServerSendEvent( EVENT_BECOMEBROKEN, NULL, true, -1 );
663 if ( spawnArgs.GetString( "def_damage", "", &damageDefName ) ) {
664 idVec3 origin = renderEntity.origin + renderEntity.bounds.GetCenter() * renderEntity.axis;
665 gameLocal.RadiusDamage( origin, activator, activator, this, this, damageDefName );
670 ActivateTargets( activator );
672 // offset the start time of the shader to sync it to the game time
673 renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
674 renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
676 // set the state parm
677 renderEntity.shaderParms[ SHADERPARM_MODE ] = 1;
678 renderLight.shaderParms[ SHADERPARM_MODE ] = 1;
680 // if the light has a sound, either start the alternate (broken) sound, or stop the sound
681 const char *parm = spawnArgs.GetString( "snd_broken" );
682 if ( refSound.shader || ( parm && *parm ) ) {
683 StopSound( SND_CHANNEL_ANY, false );
684 const idSoundShader *alternate = refSound.shader ? refSound.shader->GetAltSound() : declManager->FindSound( parm );
686 // start it with no diversity, so the leadin break sound plays
687 refSound.referenceSound->StartSound( alternate, SND_CHANNEL_ANY, 0.0, 0 );
691 parm = spawnArgs.GetString( "mtr_broken" );
692 if ( parm && *parm ) {
701 idLight::PresentLightDefChange
704 void idLight::PresentLightDefChange( void ) {
705 // let the renderer apply it to the world
706 if ( ( lightDefHandle != -1 ) ) {
707 gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight );
709 lightDefHandle = gameRenderWorld->AddLightDef( &renderLight );
715 idLight::PresentModelDefChange
718 void idLight::PresentModelDefChange( void ) {
720 if ( !renderEntity.hModel || IsHidden() ) {
724 // add to refresh list
725 if ( modelDefHandle == -1 ) {
726 modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
728 gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
737 void idLight::Present( void ) {
738 // don't present to the renderer if the entity hasn't changed
739 if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
746 // current transformation
747 renderLight.axis = localLightAxis * GetPhysics()->GetAxis();
748 renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localLightOrigin;
750 // reference the sound for shader synced effects
752 renderLight.referenceSound = lightParent->GetSoundEmitter();
753 renderEntity.referenceSound = lightParent->GetSoundEmitter();
756 renderLight.referenceSound = refSound.referenceSound;
757 renderEntity.referenceSound = refSound.referenceSound;
760 // update the renderLight and renderEntity to render the light and flare
761 PresentLightDefChange();
762 PresentModelDefChange();
770 void idLight::Think( void ) {
773 if ( thinkFlags & TH_THINK ) {
775 if ( gameLocal.time < fadeEnd ) {
776 color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
780 BecomeInactive( TH_THINK );
792 idLight::GetPhysicsToSoundTransform
795 bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
796 origin = localLightOrigin + renderLight.lightCenter;
797 axis = localLightAxis * GetPhysics()->GetAxis();
803 idLight::FreeLightDef
806 void idLight::FreeLightDef( void ) {
807 if ( lightDefHandle != -1 ) {
808 gameRenderWorld->FreeLightDef( lightDefHandle );
818 void idLight::SaveState( idDict *args ) {
819 int i, c = spawnArgs.GetNumKeyVals();
820 for ( i = 0; i < c; i++ ) {
821 const idKeyValue *pv = spawnArgs.GetKeyVal(i);
822 if ( pv->GetKey().Find( "editor_", false ) >= 0 || pv->GetKey().Find( "parse_", false ) >= 0 ) {
825 args->Set( pv->GetKey(), pv->GetValue() );
831 idLight::ShowEditingDialog
834 void idLight::ShowEditingDialog( void ) {
835 if ( g_editEntityMode.GetInteger() == 1 ) {
836 common->InitTool( EDITOR_LIGHT, &spawnArgs );
838 common->InitTool( EDITOR_SOUND, &spawnArgs );
844 idLight::Event_SetShader
847 void idLight::Event_SetShader( const char *shadername ) {
848 SetShader( shadername );
853 idLight::Event_GetLightParm
856 void idLight::Event_GetLightParm( int parmnum ) {
857 if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
858 gameLocal.Error( "shader parm index (%d) out of range", parmnum );
861 idThread::ReturnFloat( renderLight.shaderParms[ parmnum ] );
866 idLight::Event_SetLightParm
869 void idLight::Event_SetLightParm( int parmnum, float value ) {
870 SetLightParm( parmnum, value );
875 idLight::Event_SetLightParms
878 void idLight::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
879 SetLightParms( parm0, parm1, parm2, parm3 );
884 idLight::Event_SetRadiusXYZ
887 void idLight::Event_SetRadiusXYZ( float x, float y, float z ) {
888 SetRadiusXYZ( x, y, z );
893 idLight::Event_SetRadius
896 void idLight::Event_SetRadius( float radius ) {
905 void idLight::Event_Hide( void ) {
907 PresentModelDefChange();
916 void idLight::Event_Show( void ) {
918 PresentModelDefChange();
927 void idLight::Event_On( void ) {
936 void idLight::Event_Off( void ) {
942 idLight::Event_ToggleOnOff
945 void idLight::Event_ToggleOnOff( idEntity *activator ) {
947 if ( triggercount < count ) {
951 // reset trigger count
954 if ( breakOnTrigger ) {
955 BecomeBroken( activator );
956 breakOnTrigger = false;
960 if ( !currentLevel ) {
965 if ( !currentLevel ) {
976 idLight::Event_SetSoundHandles
978 set the same sound def handle on all targeted lights
981 void idLight::Event_SetSoundHandles( void ) {
985 if ( !refSound.referenceSound ) {
989 for ( i = 0; i < targets.Num(); i++ ) {
990 targetEnt = targets[ i ].GetEntity();
991 if ( targetEnt && targetEnt->IsType( idLight::Type ) ) {
992 idLight *light = static_cast<idLight*>(targetEnt);
993 light->lightParent = this;
995 // explicitly delete any sounds on the entity
996 light->FreeSoundEmitter( true );
998 // manually set the refSound to this light's refSound
999 light->renderEntity.referenceSound = renderEntity.referenceSound;
1001 // update the renderEntity to the renderer
1002 light->UpdateVisuals();
1009 idLight::Event_FadeOut
1012 void idLight::Event_FadeOut( float time ) {
1018 idLight::Event_FadeIn
1021 void idLight::Event_FadeIn( float time ) {
1027 idLight::ClientPredictionThink
1030 void idLight::ClientPredictionThink( void ) {
1036 idLight::WriteToSnapshot
1039 void idLight::WriteToSnapshot( idBitMsgDelta &msg ) const {
1041 GetPhysics()->WriteToSnapshot( msg );
1042 WriteBindToSnapshot( msg );
1044 msg.WriteByte( currentLevel );
1045 msg.WriteLong( PackColor( baseColor ) );
1046 // msg.WriteBits( lightParent.GetEntityNum(), GENTITYNUM_BITS );
1048 /* // only helps prediction
1049 msg.WriteLong( PackColor( fadeFrom ) );
1050 msg.WriteLong( PackColor( fadeTo ) );
1051 msg.WriteLong( fadeStart );
1052 msg.WriteLong( fadeEnd );
1055 // FIXME: send renderLight.shader
1056 msg.WriteFloat( renderLight.lightRadius[0], 5, 10 );
1057 msg.WriteFloat( renderLight.lightRadius[1], 5, 10 );
1058 msg.WriteFloat( renderLight.lightRadius[2], 5, 10 );
1060 msg.WriteLong( PackColor( idVec4( renderLight.shaderParms[SHADERPARM_RED],
1061 renderLight.shaderParms[SHADERPARM_GREEN],
1062 renderLight.shaderParms[SHADERPARM_BLUE],
1063 renderLight.shaderParms[SHADERPARM_ALPHA] ) ) );
1065 msg.WriteFloat( renderLight.shaderParms[SHADERPARM_TIMESCALE], 5, 10 );
1066 msg.WriteLong( renderLight.shaderParms[SHADERPARM_TIMEOFFSET] );
1067 //msg.WriteByte( renderLight.shaderParms[SHADERPARM_DIVERSITY] );
1068 msg.WriteShort( renderLight.shaderParms[SHADERPARM_MODE] );
1070 WriteColorToSnapshot( msg );
1075 idLight::ReadFromSnapshot
1078 void idLight::ReadFromSnapshot( const idBitMsgDelta &msg ) {
1080 int oldCurrentLevel = currentLevel;
1081 idVec3 oldBaseColor = baseColor;
1083 GetPhysics()->ReadFromSnapshot( msg );
1084 ReadBindFromSnapshot( msg );
1086 currentLevel = msg.ReadByte();
1087 if ( currentLevel != oldCurrentLevel ) {
1088 // need to call On/Off for flickering lights to start/stop the sound
1089 // while doing it this way rather than through events, the flickering is out of sync between clients
1090 // but at least there is no question about saving the event and having them happening globally in the world
1091 if ( currentLevel ) {
1097 UnpackColor( msg.ReadLong(), baseColor );
1098 // lightParentEntityNum = msg.ReadBits( GENTITYNUM_BITS );
1100 /* // only helps prediction
1101 UnpackColor( msg.ReadLong(), fadeFrom );
1102 UnpackColor( msg.ReadLong(), fadeTo );
1103 fadeStart = msg.ReadLong();
1104 fadeEnd = msg.ReadLong();
1107 // FIXME: read renderLight.shader
1108 renderLight.lightRadius[0] = msg.ReadFloat( 5, 10 );
1109 renderLight.lightRadius[1] = msg.ReadFloat( 5, 10 );
1110 renderLight.lightRadius[2] = msg.ReadFloat( 5, 10 );
1112 UnpackColor( msg.ReadLong(), shaderColor );
1113 renderLight.shaderParms[SHADERPARM_RED] = shaderColor[0];
1114 renderLight.shaderParms[SHADERPARM_GREEN] = shaderColor[1];
1115 renderLight.shaderParms[SHADERPARM_BLUE] = shaderColor[2];
1116 renderLight.shaderParms[SHADERPARM_ALPHA] = shaderColor[3];
1118 renderLight.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 );
1119 renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadLong();
1120 //renderLight.shaderParms[SHADERPARM_DIVERSITY] = msg.ReadFloat();
1121 renderLight.shaderParms[SHADERPARM_MODE] = msg.ReadShort();
1123 ReadColorFromSnapshot( msg );
1125 if ( msg.HasChanged() ) {
1126 if ( ( currentLevel != oldCurrentLevel ) || ( baseColor != oldBaseColor ) ) {
1129 PresentLightDefChange();
1130 PresentModelDefChange();
1137 idLight::ClientReceiveEvent
1140 bool idLight::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
1143 case EVENT_BECOMEBROKEN: {
1144 BecomeBroken( NULL );
1148 return idEntity::ClientReceiveEvent( event, time, msg );