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 );
359 health = spawnArgs.GetInt( "health", "0" );
360 spawnArgs.GetString( "broken", "", brokenModel );
361 spawnArgs.GetBool( "break", "0", breakOnTrigger );
362 spawnArgs.GetInt( "count", "1", count );
366 fadeFrom.Set( 1, 1, 1, 1 );
367 fadeTo.Set( 1, 1, 1, 1 );
371 // if we have a health make light breakable
373 idStr model = spawnArgs.GetString( "model" ); // get the visual model
374 if ( !model.Length() ) {
375 gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() );
378 fl.takedamage = true;
380 // see if we need to create a broken model name
382 if ( model.Length() && !brokenModel.Length() ) {
387 pos = model.Find( "." );
389 pos = model.Length();
392 model.Left( pos, brokenModel );
394 brokenModel += "_broken";
396 brokenModel += &model[ pos ];
400 // make sure the model gets cached
401 if ( !renderModelManager->CheckModel( brokenModel ) ) {
403 gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() );
409 GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID );
411 // make sure the collision model gets cached
412 idClipModel::CheckModel( brokenModel );
415 PostEventMS( &EV_PostSpawn, 0 );
422 idLight::SetLightLevel
425 void idLight::SetLightLevel( void ) {
429 intensity = ( float )currentLevel / ( float )levels;
430 color = baseColor * intensity;
431 renderLight.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
432 renderLight.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
433 renderLight.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
434 renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
435 renderEntity.shaderParms[ SHADERPARM_GREEN ]= color[ 1 ];
436 renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
437 PresentLightDefChange();
438 PresentModelDefChange();
446 void idLight::GetColor( idVec3 &out ) const {
447 out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
448 out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
449 out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
457 void idLight::GetColor( idVec4 &out ) const {
458 out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
459 out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
460 out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
461 out[ 3 ] = renderLight.shaderParms[ SHADERPARM_ALPHA ];
469 void idLight::SetColor( float red, float green, float blue ) {
470 baseColor.Set( red, green, blue );
479 void idLight::SetColor( const idVec4 &color ) {
480 baseColor = color.ToVec3();
481 renderLight.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
482 renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
491 void idLight::SetShader( const char *shadername ) {
492 // allow this to be NULL
493 renderLight.shader = declManager->FindMaterial( shadername, false );
494 PresentLightDefChange();
499 idLight::SetLightParm
502 void idLight::SetLightParm( int parmnum, float value ) {
503 if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
504 gameLocal.Error( "shader parm index (%d) out of range", parmnum );
507 renderLight.shaderParms[ parmnum ] = value;
508 PresentLightDefChange();
513 idLight::SetLightParms
516 void idLight::SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
517 renderLight.shaderParms[ SHADERPARM_RED ] = parm0;
518 renderLight.shaderParms[ SHADERPARM_GREEN ] = parm1;
519 renderLight.shaderParms[ SHADERPARM_BLUE ] = parm2;
520 renderLight.shaderParms[ SHADERPARM_ALPHA ] = parm3;
521 renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
522 renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
523 renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
524 renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
525 PresentLightDefChange();
526 PresentModelDefChange();
531 idLight::SetRadiusXYZ
534 void idLight::SetRadiusXYZ( float x, float y, float z ) {
535 renderLight.lightRadius[0] = x;
536 renderLight.lightRadius[1] = y;
537 renderLight.lightRadius[2] = z;
538 PresentLightDefChange();
546 void idLight::SetRadius( float radius ) {
547 renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = radius;
548 PresentLightDefChange();
556 void idLight::On( void ) {
557 currentLevel = levels;
558 // offset the start time of the shader to sync it to the game time
559 renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
560 if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) {
561 StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
562 soundWasPlaying = false;
565 BecomeActive( TH_UPDATEVISUALS );
573 void idLight::Off( void ) {
575 // kill any sound it was making
576 if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) {
577 StopSound( SND_CHANNEL_ANY, false );
578 soundWasPlaying = true;
581 BecomeActive( TH_UPDATEVISUALS );
589 void idLight::Fade( const idVec4 &to, float fadeTime ) {
590 GetColor( fadeFrom );
592 fadeStart = gameLocal.time;
593 fadeEnd = gameLocal.time + SEC2MS( fadeTime );
594 BecomeActive( TH_THINK );
602 void idLight::FadeOut( float time ) {
603 Fade( colorBlack, time );
611 void idLight::FadeIn( float time ) {
615 currentLevel = levels;
616 spawnArgs.GetVector( "_color", "1 1 1", color );
617 color4.Set( color.x, color.y, color.z, 1.0f );
618 Fade( color4, time );
626 void idLight::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
627 BecomeBroken( attacker );
632 idLight::BecomeBroken
635 void idLight::BecomeBroken( idEntity *activator ) {
636 const char *damageDefName;
638 fl.takedamage = false;
640 if ( brokenModel.Length() ) {
641 SetModel( brokenModel );
643 if ( !spawnArgs.GetBool( "nonsolid" ) ) {
644 GetPhysics()->SetClipModel( new idClipModel( brokenModel.c_str() ), 1.0f );
645 GetPhysics()->SetContents( CONTENTS_SOLID );
647 } else if ( spawnArgs.GetBool( "hideModelOnBreak" ) ) {
649 GetPhysics()->SetContents( 0 );
652 if ( gameLocal.isServer ) {
654 ServerSendEvent( EVENT_BECOMEBROKEN, NULL, true, -1 );
656 if ( spawnArgs.GetString( "def_damage", "", &damageDefName ) ) {
657 idVec3 origin = renderEntity.origin + renderEntity.bounds.GetCenter() * renderEntity.axis;
658 gameLocal.RadiusDamage( origin, activator, activator, this, this, damageDefName );
663 ActivateTargets( activator );
665 // offset the start time of the shader to sync it to the game time
666 renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
667 renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
669 // set the state parm
670 renderEntity.shaderParms[ SHADERPARM_MODE ] = 1;
671 renderLight.shaderParms[ SHADERPARM_MODE ] = 1;
673 // if the light has a sound, either start the alternate (broken) sound, or stop the sound
674 const char *parm = spawnArgs.GetString( "snd_broken" );
675 if ( refSound.shader || ( parm && *parm ) ) {
676 StopSound( SND_CHANNEL_ANY, false );
677 const idSoundShader *alternate = refSound.shader ? refSound.shader->GetAltSound() : declManager->FindSound( parm );
679 // start it with no diversity, so the leadin break sound plays
680 refSound.referenceSound->StartSound( alternate, SND_CHANNEL_ANY, 0.0, 0 );
684 parm = spawnArgs.GetString( "mtr_broken" );
685 if ( parm && *parm ) {
694 idLight::PresentLightDefChange
697 void idLight::PresentLightDefChange( void ) {
698 // let the renderer apply it to the world
699 if ( ( lightDefHandle != -1 ) ) {
700 gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight );
702 lightDefHandle = gameRenderWorld->AddLightDef( &renderLight );
708 idLight::PresentModelDefChange
711 void idLight::PresentModelDefChange( void ) {
713 if ( !renderEntity.hModel || IsHidden() ) {
717 // add to refresh list
718 if ( modelDefHandle == -1 ) {
719 modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
721 gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
730 void idLight::Present( void ) {
731 // don't present to the renderer if the entity hasn't changed
732 if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
739 // current transformation
740 renderLight.axis = localLightAxis * GetPhysics()->GetAxis();
741 renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localLightOrigin;
743 // reference the sound for shader synced effects
745 renderLight.referenceSound = lightParent->GetSoundEmitter();
746 renderEntity.referenceSound = lightParent->GetSoundEmitter();
749 renderLight.referenceSound = refSound.referenceSound;
750 renderEntity.referenceSound = refSound.referenceSound;
753 // update the renderLight and renderEntity to render the light and flare
754 PresentLightDefChange();
755 PresentModelDefChange();
763 void idLight::Think( void ) {
766 if ( thinkFlags & TH_THINK ) {
768 if ( gameLocal.time < fadeEnd ) {
769 color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
773 BecomeInactive( TH_THINK );
785 idLight::GetPhysicsToSoundTransform
788 bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
789 origin = localLightOrigin + renderLight.lightCenter;
790 axis = localLightAxis * GetPhysics()->GetAxis();
796 idLight::FreeLightDef
799 void idLight::FreeLightDef( void ) {
800 if ( lightDefHandle != -1 ) {
801 gameRenderWorld->FreeLightDef( lightDefHandle );
811 void idLight::SaveState( idDict *args ) {
812 int i, c = spawnArgs.GetNumKeyVals();
813 for ( i = 0; i < c; i++ ) {
814 const idKeyValue *pv = spawnArgs.GetKeyVal(i);
815 if ( pv->GetKey().Find( "editor_", false ) >= 0 || pv->GetKey().Find( "parse_", false ) >= 0 ) {
818 args->Set( pv->GetKey(), pv->GetValue() );
824 idLight::ShowEditingDialog
827 void idLight::ShowEditingDialog( void ) {
828 if ( g_editEntityMode.GetInteger() == 1 ) {
829 common->InitTool( EDITOR_LIGHT, &spawnArgs );
831 common->InitTool( EDITOR_SOUND, &spawnArgs );
837 idLight::Event_SetShader
840 void idLight::Event_SetShader( const char *shadername ) {
841 SetShader( shadername );
846 idLight::Event_GetLightParm
849 void idLight::Event_GetLightParm( int parmnum ) {
850 if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
851 gameLocal.Error( "shader parm index (%d) out of range", parmnum );
854 idThread::ReturnFloat( renderLight.shaderParms[ parmnum ] );
859 idLight::Event_SetLightParm
862 void idLight::Event_SetLightParm( int parmnum, float value ) {
863 SetLightParm( parmnum, value );
868 idLight::Event_SetLightParms
871 void idLight::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
872 SetLightParms( parm0, parm1, parm2, parm3 );
877 idLight::Event_SetRadiusXYZ
880 void idLight::Event_SetRadiusXYZ( float x, float y, float z ) {
881 SetRadiusXYZ( x, y, z );
886 idLight::Event_SetRadius
889 void idLight::Event_SetRadius( float radius ) {
898 void idLight::Event_Hide( void ) {
900 PresentModelDefChange();
909 void idLight::Event_Show( void ) {
911 PresentModelDefChange();
920 void idLight::Event_On( void ) {
929 void idLight::Event_Off( void ) {
935 idLight::Event_ToggleOnOff
938 void idLight::Event_ToggleOnOff( idEntity *activator ) {
940 if ( triggercount < count ) {
944 // reset trigger count
947 if ( breakOnTrigger ) {
948 BecomeBroken( activator );
949 breakOnTrigger = false;
953 if ( !currentLevel ) {
958 if ( !currentLevel ) {
969 idLight::Event_SetSoundHandles
971 set the same sound def handle on all targeted lights
974 void idLight::Event_SetSoundHandles( void ) {
978 if ( !refSound.referenceSound ) {
982 for ( i = 0; i < targets.Num(); i++ ) {
983 targetEnt = targets[ i ].GetEntity();
984 if ( targetEnt && targetEnt->IsType( idLight::Type ) ) {
985 idLight *light = static_cast<idLight*>(targetEnt);
986 light->lightParent = this;
988 // explicitly delete any sounds on the entity
989 light->FreeSoundEmitter( true );
991 // manually set the refSound to this light's refSound
992 light->renderEntity.referenceSound = renderEntity.referenceSound;
994 // update the renderEntity to the renderer
995 light->UpdateVisuals();
1002 idLight::Event_FadeOut
1005 void idLight::Event_FadeOut( float time ) {
1011 idLight::Event_FadeIn
1014 void idLight::Event_FadeIn( float time ) {
1020 idLight::ClientPredictionThink
1023 void idLight::ClientPredictionThink( void ) {
1029 idLight::WriteToSnapshot
1032 void idLight::WriteToSnapshot( idBitMsgDelta &msg ) const {
1034 GetPhysics()->WriteToSnapshot( msg );
1035 WriteBindToSnapshot( msg );
1037 msg.WriteByte( currentLevel );
1038 msg.WriteLong( PackColor( baseColor ) );
1039 // msg.WriteBits( lightParent.GetEntityNum(), GENTITYNUM_BITS );
1041 /* // only helps prediction
1042 msg.WriteLong( PackColor( fadeFrom ) );
1043 msg.WriteLong( PackColor( fadeTo ) );
1044 msg.WriteLong( fadeStart );
1045 msg.WriteLong( fadeEnd );
1048 // FIXME: send renderLight.shader
1049 msg.WriteFloat( renderLight.lightRadius[0], 5, 10 );
1050 msg.WriteFloat( renderLight.lightRadius[1], 5, 10 );
1051 msg.WriteFloat( renderLight.lightRadius[2], 5, 10 );
1053 msg.WriteLong( PackColor( idVec4( renderLight.shaderParms[SHADERPARM_RED],
1054 renderLight.shaderParms[SHADERPARM_GREEN],
1055 renderLight.shaderParms[SHADERPARM_BLUE],
1056 renderLight.shaderParms[SHADERPARM_ALPHA] ) ) );
1058 msg.WriteFloat( renderLight.shaderParms[SHADERPARM_TIMESCALE], 5, 10 );
1059 msg.WriteLong( renderLight.shaderParms[SHADERPARM_TIMEOFFSET] );
1060 //msg.WriteByte( renderLight.shaderParms[SHADERPARM_DIVERSITY] );
1061 msg.WriteShort( renderLight.shaderParms[SHADERPARM_MODE] );
1063 WriteColorToSnapshot( msg );
1068 idLight::ReadFromSnapshot
1071 void idLight::ReadFromSnapshot( const idBitMsgDelta &msg ) {
1073 int oldCurrentLevel = currentLevel;
1074 idVec3 oldBaseColor = baseColor;
1076 GetPhysics()->ReadFromSnapshot( msg );
1077 ReadBindFromSnapshot( msg );
1079 currentLevel = msg.ReadByte();
1080 if ( currentLevel != oldCurrentLevel ) {
1081 // need to call On/Off for flickering lights to start/stop the sound
1082 // while doing it this way rather than through events, the flickering is out of sync between clients
1083 // but at least there is no question about saving the event and having them happening globally in the world
1084 if ( currentLevel ) {
1090 UnpackColor( msg.ReadLong(), baseColor );
1091 // lightParentEntityNum = msg.ReadBits( GENTITYNUM_BITS );
1093 /* // only helps prediction
1094 UnpackColor( msg.ReadLong(), fadeFrom );
1095 UnpackColor( msg.ReadLong(), fadeTo );
1096 fadeStart = msg.ReadLong();
1097 fadeEnd = msg.ReadLong();
1100 // FIXME: read renderLight.shader
1101 renderLight.lightRadius[0] = msg.ReadFloat( 5, 10 );
1102 renderLight.lightRadius[1] = msg.ReadFloat( 5, 10 );
1103 renderLight.lightRadius[2] = msg.ReadFloat( 5, 10 );
1105 UnpackColor( msg.ReadLong(), shaderColor );
1106 renderLight.shaderParms[SHADERPARM_RED] = shaderColor[0];
1107 renderLight.shaderParms[SHADERPARM_GREEN] = shaderColor[1];
1108 renderLight.shaderParms[SHADERPARM_BLUE] = shaderColor[2];
1109 renderLight.shaderParms[SHADERPARM_ALPHA] = shaderColor[3];
1111 renderLight.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 );
1112 renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadLong();
1113 //renderLight.shaderParms[SHADERPARM_DIVERSITY] = msg.ReadFloat();
1114 renderLight.shaderParms[SHADERPARM_MODE] = msg.ReadShort();
1116 ReadColorFromSnapshot( msg );
1118 if ( msg.HasChanged() ) {
1119 if ( ( currentLevel != oldCurrentLevel ) || ( baseColor != oldBaseColor ) ) {
1122 PresentLightDefChange();
1123 PresentModelDefChange();
1130 idLight::ClientReceiveEvent
1133 bool idLight::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
1136 case EVENT_BECOMEBROKEN: {
1137 BecomeBroken( NULL );
1141 return idEntity::ClientReceiveEvent( event, time, msg );