Light.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. idLight
  26. ===============================================================================
  27. */
  28. const idEventDef EV_Light_SetShader( "setShader", "s" );
  29. const idEventDef EV_Light_GetLightParm( "getLightParm", "d", 'f' );
  30. const idEventDef EV_Light_SetLightParm( "setLightParm", "df" );
  31. const idEventDef EV_Light_SetLightParms( "setLightParms", "ffff" );
  32. const idEventDef EV_Light_SetRadiusXYZ( "setRadiusXYZ", "fff" );
  33. const idEventDef EV_Light_SetRadius( "setRadius", "f" );
  34. const idEventDef EV_Light_On( "On", NULL );
  35. const idEventDef EV_Light_Off( "Off", NULL );
  36. const idEventDef EV_Light_FadeOut( "fadeOutLight", "f" );
  37. const idEventDef EV_Light_FadeIn( "fadeInLight", "f" );
  38. CLASS_DECLARATION( idEntity, idLight )
  39. EVENT( EV_Light_SetShader, idLight::Event_SetShader )
  40. EVENT( EV_Light_GetLightParm, idLight::Event_GetLightParm )
  41. EVENT( EV_Light_SetLightParm, idLight::Event_SetLightParm )
  42. EVENT( EV_Light_SetLightParms, idLight::Event_SetLightParms )
  43. EVENT( EV_Light_SetRadiusXYZ, idLight::Event_SetRadiusXYZ )
  44. EVENT( EV_Light_SetRadius, idLight::Event_SetRadius )
  45. EVENT( EV_Hide, idLight::Event_Hide )
  46. EVENT( EV_Show, idLight::Event_Show )
  47. EVENT( EV_Light_On, idLight::Event_On )
  48. EVENT( EV_Light_Off, idLight::Event_Off )
  49. EVENT( EV_Activate, idLight::Event_ToggleOnOff )
  50. EVENT( EV_PostSpawn, idLight::Event_SetSoundHandles )
  51. EVENT( EV_Light_FadeOut, idLight::Event_FadeOut )
  52. EVENT( EV_Light_FadeIn, idLight::Event_FadeIn )
  53. END_CLASS
  54. /*
  55. ================
  56. idGameEdit::ParseSpawnArgsToRenderLight
  57. parse the light parameters
  58. this is the canonical renderLight parm parsing,
  59. which should be used by dmap and the editor
  60. ================
  61. */
  62. void idGameEdit::ParseSpawnArgsToRenderLight( const idDict *args, renderLight_t *renderLight ) {
  63. bool gotTarget, gotUp, gotRight;
  64. const char *texture;
  65. idVec3 color;
  66. memset( renderLight, 0, sizeof( *renderLight ) );
  67. if (!args->GetVector("light_origin", "", renderLight->origin)) {
  68. args->GetVector( "origin", "", renderLight->origin );
  69. }
  70. gotTarget = args->GetVector( "light_target", "", renderLight->target );
  71. gotUp = args->GetVector( "light_up", "", renderLight->up );
  72. gotRight = args->GetVector( "light_right", "", renderLight->right );
  73. args->GetVector( "light_start", "0 0 0", renderLight->start );
  74. if ( !args->GetVector( "light_end", "", renderLight->end ) ) {
  75. renderLight->end = renderLight->target;
  76. }
  77. // we should have all of the target/right/up or none of them
  78. if ( ( gotTarget || gotUp || gotRight ) != ( gotTarget && gotUp && gotRight ) ) {
  79. gameLocal.Printf( "Light at (%f,%f,%f) has bad target info\n",
  80. renderLight->origin[0], renderLight->origin[1], renderLight->origin[2] );
  81. return;
  82. }
  83. if ( !gotTarget ) {
  84. renderLight->pointLight = true;
  85. // allow an optional relative center of light and shadow offset
  86. args->GetVector( "light_center", "0 0 0", renderLight->lightCenter );
  87. // create a point light
  88. if (!args->GetVector( "light_radius", "300 300 300", renderLight->lightRadius ) ) {
  89. float radius;
  90. args->GetFloat( "light", "300", radius );
  91. renderLight->lightRadius[0] = renderLight->lightRadius[1] = renderLight->lightRadius[2] = radius;
  92. }
  93. }
  94. // get the rotation matrix in either full form, or single angle form
  95. idAngles angles;
  96. idMat3 mat;
  97. if ( !args->GetMatrix( "light_rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
  98. if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", mat ) ) {
  99. args->GetFloat( "angle", "0", angles[ 1 ] );
  100. angles[ 0 ] = 0;
  101. angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] );
  102. angles[ 2 ] = 0;
  103. mat = angles.ToMat3();
  104. }
  105. }
  106. // fix degenerate identity matrices
  107. mat[0].FixDegenerateNormal();
  108. mat[1].FixDegenerateNormal();
  109. mat[2].FixDegenerateNormal();
  110. renderLight->axis = mat;
  111. // check for other attributes
  112. args->GetVector( "_color", "1 1 1", color );
  113. renderLight->shaderParms[ SHADERPARM_RED ] = color[0];
  114. renderLight->shaderParms[ SHADERPARM_GREEN ] = color[1];
  115. renderLight->shaderParms[ SHADERPARM_BLUE ] = color[2];
  116. args->GetFloat( "shaderParm3", "1", renderLight->shaderParms[ SHADERPARM_TIMESCALE ] );
  117. if ( !args->GetFloat( "shaderParm4", "0", renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] ) ) {
  118. // offset the start time of the shader to sync it to the game time
  119. renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  120. }
  121. args->GetFloat( "shaderParm5", "0", renderLight->shaderParms[5] );
  122. args->GetFloat( "shaderParm6", "0", renderLight->shaderParms[6] );
  123. args->GetFloat( "shaderParm7", "0", renderLight->shaderParms[ SHADERPARM_MODE ] );
  124. args->GetBool( "noshadows", "0", renderLight->noShadows );
  125. args->GetBool( "nospecular", "0", renderLight->noSpecular );
  126. args->GetBool( "parallel", "0", renderLight->parallel );
  127. args->GetString( "texture", "lights/squarelight1", &texture );
  128. // allow this to be NULL
  129. renderLight->shader = declManager->FindMaterial( texture, false );
  130. }
  131. /*
  132. ================
  133. idLight::UpdateChangeableSpawnArgs
  134. ================
  135. */
  136. void idLight::UpdateChangeableSpawnArgs( const idDict *source ) {
  137. idEntity::UpdateChangeableSpawnArgs( source );
  138. if ( source ) {
  139. source->Print();
  140. }
  141. FreeSoundEmitter( true );
  142. gameEdit->ParseSpawnArgsToRefSound( source ? source : &spawnArgs, &refSound );
  143. if ( refSound.shader && !refSound.waitfortrigger ) {
  144. StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
  145. }
  146. gameEdit->ParseSpawnArgsToRenderLight( source ? source : &spawnArgs, &renderLight );
  147. UpdateVisuals();
  148. }
  149. /*
  150. ================
  151. idLight::idLight
  152. ================
  153. */
  154. idLight::idLight() {
  155. memset( &renderLight, 0, sizeof( renderLight ) );
  156. localLightOrigin = vec3_zero;
  157. localLightAxis = mat3_identity;
  158. lightDefHandle = -1;
  159. levels = 0;
  160. currentLevel = 0;
  161. baseColor = vec3_zero;
  162. breakOnTrigger = false;
  163. count = 0;
  164. triggercount = 0;
  165. lightParent = NULL;
  166. fadeFrom.Set( 1, 1, 1, 1 );
  167. fadeTo.Set( 1, 1, 1, 1 );
  168. fadeStart = 0;
  169. fadeEnd = 0;
  170. soundWasPlaying = false;
  171. }
  172. /*
  173. ================
  174. idLight::~idLight
  175. ================
  176. */
  177. idLight::~idLight() {
  178. if ( lightDefHandle != -1 ) {
  179. gameRenderWorld->FreeLightDef( lightDefHandle );
  180. }
  181. }
  182. /*
  183. ================
  184. idLight::Save
  185. archives object for save game file
  186. ================
  187. */
  188. void idLight::Save( idSaveGame *savefile ) const {
  189. savefile->WriteRenderLight( renderLight );
  190. savefile->WriteBool( renderLight.prelightModel != NULL );
  191. savefile->WriteVec3( localLightOrigin );
  192. savefile->WriteMat3( localLightAxis );
  193. savefile->WriteString( brokenModel );
  194. savefile->WriteInt( levels );
  195. savefile->WriteInt( currentLevel );
  196. savefile->WriteVec3( baseColor );
  197. savefile->WriteBool( breakOnTrigger );
  198. savefile->WriteInt( count );
  199. savefile->WriteInt( triggercount );
  200. savefile->WriteObject( lightParent );
  201. savefile->WriteVec4( fadeFrom );
  202. savefile->WriteVec4( fadeTo );
  203. savefile->WriteInt( fadeStart );
  204. savefile->WriteInt( fadeEnd );
  205. savefile->WriteBool( soundWasPlaying );
  206. }
  207. /*
  208. ================
  209. idLight::Restore
  210. unarchives object from save game file
  211. ================
  212. */
  213. void idLight::Restore( idRestoreGame *savefile ) {
  214. bool hadPrelightModel;
  215. savefile->ReadRenderLight( renderLight );
  216. savefile->ReadBool( hadPrelightModel );
  217. renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
  218. if ( ( renderLight.prelightModel == NULL ) && hadPrelightModel ) {
  219. assert( 0 );
  220. if ( developer.GetBool() ) {
  221. // we really want to know if this happens
  222. gameLocal.Error( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
  223. } else {
  224. // but let it slide after release
  225. gameLocal.Warning( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() );
  226. }
  227. }
  228. savefile->ReadVec3( localLightOrigin );
  229. savefile->ReadMat3( localLightAxis );
  230. savefile->ReadString( brokenModel );
  231. savefile->ReadInt( levels );
  232. savefile->ReadInt( currentLevel );
  233. savefile->ReadVec3( baseColor );
  234. savefile->ReadBool( breakOnTrigger );
  235. savefile->ReadInt( count );
  236. savefile->ReadInt( triggercount );
  237. savefile->ReadObject( reinterpret_cast<idClass *&>( lightParent ) );
  238. savefile->ReadVec4( fadeFrom );
  239. savefile->ReadVec4( fadeTo );
  240. savefile->ReadInt( fadeStart );
  241. savefile->ReadInt( fadeEnd );
  242. savefile->ReadBool( soundWasPlaying );
  243. lightDefHandle = -1;
  244. SetLightLevel();
  245. }
  246. /*
  247. ================
  248. idLight::Spawn
  249. ================
  250. */
  251. void idLight::Spawn( void ) {
  252. bool start_off;
  253. bool needBroken;
  254. const char *demonic_shader;
  255. // do the parsing the same way dmap and the editor do
  256. gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &renderLight );
  257. // we need the origin and axis relative to the physics origin/axis
  258. localLightOrigin = ( renderLight.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose();
  259. localLightAxis = renderLight.axis * GetPhysics()->GetAxis().Transpose();
  260. // set the base color from the shader parms
  261. baseColor.Set( renderLight.shaderParms[ SHADERPARM_RED ], renderLight.shaderParms[ SHADERPARM_GREEN ], renderLight.shaderParms[ SHADERPARM_BLUE ] );
  262. // set the number of light levels
  263. spawnArgs.GetInt( "levels", "1", levels );
  264. currentLevel = levels;
  265. if ( levels <= 0 ) {
  266. gameLocal.Error( "Invalid light level set on entity #%d(%s)", entityNumber, name.c_str() );
  267. }
  268. // make sure the demonic shader is cached
  269. if ( spawnArgs.GetString( "mat_demonic", NULL, &demonic_shader ) ) {
  270. declManager->FindType( DECL_MATERIAL, demonic_shader );
  271. }
  272. // game specific functionality, not mirrored in
  273. // editor or dmap light parsing
  274. // also put the light texture on the model, so light flares
  275. // can get the current intensity of the light
  276. renderEntity.referenceShader = renderLight.shader;
  277. lightDefHandle = -1; // no static version yet
  278. // see if an optimized shadow volume exists
  279. // the renderer will ignore this value after a light has been moved,
  280. // but there may still be a chance to get it wrong if the game moves
  281. // a light before the first present, and doesn't clear the prelight
  282. renderLight.prelightModel = 0;
  283. if ( name[ 0 ] ) {
  284. // this will return 0 if not found
  285. renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) );
  286. }
  287. spawnArgs.GetBool( "start_off", "0", start_off );
  288. if ( start_off ) {
  289. Off();
  290. }
  291. health = spawnArgs.GetInt( "health", "0" );
  292. spawnArgs.GetString( "broken", "", brokenModel );
  293. spawnArgs.GetBool( "break", "0", breakOnTrigger );
  294. spawnArgs.GetInt( "count", "1", count );
  295. triggercount = 0;
  296. fadeFrom.Set( 1, 1, 1, 1 );
  297. fadeTo.Set( 1, 1, 1, 1 );
  298. fadeStart = 0;
  299. fadeEnd = 0;
  300. // if we have a health make light breakable
  301. if ( health ) {
  302. idStr model = spawnArgs.GetString( "model" ); // get the visual model
  303. if ( !model.Length() ) {
  304. gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() );
  305. }
  306. fl.takedamage = true;
  307. // see if we need to create a broken model name
  308. needBroken = true;
  309. if ( model.Length() && !brokenModel.Length() ) {
  310. int pos;
  311. needBroken = false;
  312. pos = model.Find( "." );
  313. if ( pos < 0 ) {
  314. pos = model.Length();
  315. }
  316. if ( pos > 0 ) {
  317. model.Left( pos, brokenModel );
  318. }
  319. brokenModel += "_broken";
  320. if ( pos > 0 ) {
  321. brokenModel += &model[ pos ];
  322. }
  323. }
  324. // make sure the model gets cached
  325. if ( !renderModelManager->CheckModel( brokenModel ) ) {
  326. if ( needBroken ) {
  327. gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() );
  328. } else {
  329. brokenModel = "";
  330. }
  331. }
  332. GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID );
  333. // make sure the collision model gets cached
  334. idClipModel::CheckModel( brokenModel );
  335. }
  336. PostEventMS( &EV_PostSpawn, 0 );
  337. UpdateVisuals();
  338. }
  339. /*
  340. ================
  341. idLight::SetLightLevel
  342. ================
  343. */
  344. void idLight::SetLightLevel( void ) {
  345. idVec3 color;
  346. float intensity;
  347. intensity = ( float )currentLevel / ( float )levels;
  348. color = baseColor * intensity;
  349. renderLight.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
  350. renderLight.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
  351. renderLight.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
  352. renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
  353. renderEntity.shaderParms[ SHADERPARM_GREEN ]= color[ 1 ];
  354. renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
  355. PresentLightDefChange();
  356. PresentModelDefChange();
  357. }
  358. /*
  359. ================
  360. idLight::GetColor
  361. ================
  362. */
  363. void idLight::GetColor( idVec3 &out ) const {
  364. out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
  365. out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
  366. out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
  367. }
  368. /*
  369. ================
  370. idLight::GetColor
  371. ================
  372. */
  373. void idLight::GetColor( idVec4 &out ) const {
  374. out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ];
  375. out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ];
  376. out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ];
  377. out[ 3 ] = renderLight.shaderParms[ SHADERPARM_ALPHA ];
  378. }
  379. /*
  380. ================
  381. idLight::SetColor
  382. ================
  383. */
  384. void idLight::SetColor( float red, float green, float blue ) {
  385. baseColor.Set( red, green, blue );
  386. SetLightLevel();
  387. }
  388. /*
  389. ================
  390. idLight::SetColor
  391. ================
  392. */
  393. void idLight::SetColor( const idVec4 &color ) {
  394. baseColor = color.ToVec3();
  395. renderLight.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
  396. renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
  397. SetLightLevel();
  398. }
  399. /*
  400. ================
  401. idLight::SetShader
  402. ================
  403. */
  404. void idLight::SetShader( const char *shadername ) {
  405. // allow this to be NULL
  406. renderLight.shader = declManager->FindMaterial( shadername, false );
  407. PresentLightDefChange();
  408. }
  409. /*
  410. ================
  411. idLight::SetLightParm
  412. ================
  413. */
  414. void idLight::SetLightParm( int parmnum, float value ) {
  415. if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
  416. gameLocal.Error( "shader parm index (%d) out of range", parmnum );
  417. }
  418. renderLight.shaderParms[ parmnum ] = value;
  419. PresentLightDefChange();
  420. }
  421. /*
  422. ================
  423. idLight::SetLightParms
  424. ================
  425. */
  426. void idLight::SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
  427. renderLight.shaderParms[ SHADERPARM_RED ] = parm0;
  428. renderLight.shaderParms[ SHADERPARM_GREEN ] = parm1;
  429. renderLight.shaderParms[ SHADERPARM_BLUE ] = parm2;
  430. renderLight.shaderParms[ SHADERPARM_ALPHA ] = parm3;
  431. renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
  432. renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
  433. renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
  434. renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
  435. PresentLightDefChange();
  436. PresentModelDefChange();
  437. }
  438. /*
  439. ================
  440. idLight::SetRadiusXYZ
  441. ================
  442. */
  443. void idLight::SetRadiusXYZ( float x, float y, float z ) {
  444. renderLight.lightRadius[0] = x;
  445. renderLight.lightRadius[1] = y;
  446. renderLight.lightRadius[2] = z;
  447. PresentLightDefChange();
  448. }
  449. /*
  450. ================
  451. idLight::SetRadius
  452. ================
  453. */
  454. void idLight::SetRadius( float radius ) {
  455. renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = radius;
  456. PresentLightDefChange();
  457. }
  458. /*
  459. ================
  460. idLight::On
  461. ================
  462. */
  463. void idLight::On( void ) {
  464. currentLevel = levels;
  465. // offset the start time of the shader to sync it to the game time
  466. renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  467. if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) {
  468. StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
  469. soundWasPlaying = false;
  470. }
  471. SetLightLevel();
  472. BecomeActive( TH_UPDATEVISUALS );
  473. }
  474. /*
  475. ================
  476. idLight::Off
  477. ================
  478. */
  479. void idLight::Off( void ) {
  480. currentLevel = 0;
  481. // kill any sound it was making
  482. if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) {
  483. StopSound( SND_CHANNEL_ANY, false );
  484. soundWasPlaying = true;
  485. }
  486. SetLightLevel();
  487. BecomeActive( TH_UPDATEVISUALS );
  488. }
  489. /*
  490. ================
  491. idLight::Fade
  492. ================
  493. */
  494. void idLight::Fade( const idVec4 &to, float fadeTime ) {
  495. GetColor( fadeFrom );
  496. fadeTo = to;
  497. fadeStart = gameLocal.time;
  498. fadeEnd = gameLocal.time + SEC2MS( fadeTime );
  499. BecomeActive( TH_THINK );
  500. }
  501. /*
  502. ================
  503. idLight::FadeOut
  504. ================
  505. */
  506. void idLight::FadeOut( float time ) {
  507. Fade( colorBlack, time );
  508. }
  509. /*
  510. ================
  511. idLight::FadeIn
  512. ================
  513. */
  514. void idLight::FadeIn( float time ) {
  515. idVec3 color;
  516. idVec4 color4;
  517. currentLevel = levels;
  518. spawnArgs.GetVector( "_color", "1 1 1", color );
  519. color4.Set( color.x, color.y, color.z, 1.0f );
  520. Fade( color4, time );
  521. }
  522. /*
  523. ================
  524. idLight::Killed
  525. ================
  526. */
  527. void idLight::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  528. BecomeBroken( attacker );
  529. }
  530. /*
  531. ================
  532. idLight::BecomeBroken
  533. ================
  534. */
  535. void idLight::BecomeBroken( idEntity *activator ) {
  536. const char *damageDefName;
  537. fl.takedamage = false;
  538. if ( brokenModel.Length() ) {
  539. SetModel( brokenModel );
  540. if ( !spawnArgs.GetBool( "nonsolid" ) ) {
  541. GetPhysics()->SetClipModel( new idClipModel( brokenModel.c_str() ), 1.0f );
  542. GetPhysics()->SetContents( CONTENTS_SOLID );
  543. }
  544. } else if ( spawnArgs.GetBool( "hideModelOnBreak" ) ) {
  545. SetModel( "" );
  546. GetPhysics()->SetContents( 0 );
  547. }
  548. if ( gameLocal.isServer ) {
  549. ServerSendEvent( EVENT_BECOMEBROKEN, NULL, true, -1 );
  550. if ( spawnArgs.GetString( "def_damage", "", &damageDefName ) ) {
  551. idVec3 origin = renderEntity.origin + renderEntity.bounds.GetCenter() * renderEntity.axis;
  552. gameLocal.RadiusDamage( origin, activator, activator, this, this, damageDefName );
  553. }
  554. }
  555. ActivateTargets( activator );
  556. // offset the start time of the shader to sync it to the game time
  557. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  558. renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  559. // set the state parm
  560. renderEntity.shaderParms[ SHADERPARM_MODE ] = 1;
  561. renderLight.shaderParms[ SHADERPARM_MODE ] = 1;
  562. // if the light has a sound, either start the alternate (broken) sound, or stop the sound
  563. const char *parm = spawnArgs.GetString( "snd_broken" );
  564. if ( refSound.shader || ( parm && *parm ) ) {
  565. StopSound( SND_CHANNEL_ANY, false );
  566. const idSoundShader *alternate = refSound.shader ? refSound.shader->GetAltSound() : declManager->FindSound( parm );
  567. if ( alternate ) {
  568. // start it with no diversity, so the leadin break sound plays
  569. refSound.referenceSound->StartSound( alternate, SND_CHANNEL_ANY, 0.0, 0 );
  570. }
  571. }
  572. parm = spawnArgs.GetString( "mtr_broken" );
  573. if ( parm && *parm ) {
  574. SetShader( parm );
  575. }
  576. UpdateVisuals();
  577. }
  578. /*
  579. ================
  580. idLight::PresentLightDefChange
  581. ================
  582. */
  583. void idLight::PresentLightDefChange( void ) {
  584. // let the renderer apply it to the world
  585. if ( ( lightDefHandle != -1 ) ) {
  586. gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight );
  587. } else {
  588. lightDefHandle = gameRenderWorld->AddLightDef( &renderLight );
  589. }
  590. }
  591. /*
  592. ================
  593. idLight::PresentModelDefChange
  594. ================
  595. */
  596. void idLight::PresentModelDefChange( void ) {
  597. if ( !renderEntity.hModel || IsHidden() ) {
  598. return;
  599. }
  600. // add to refresh list
  601. if ( modelDefHandle == -1 ) {
  602. modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
  603. } else {
  604. gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
  605. }
  606. }
  607. /*
  608. ================
  609. idLight::Present
  610. ================
  611. */
  612. void idLight::Present( void ) {
  613. // don't present to the renderer if the entity hasn't changed
  614. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  615. return;
  616. }
  617. // add the model
  618. idEntity::Present();
  619. // current transformation
  620. renderLight.axis = localLightAxis * GetPhysics()->GetAxis();
  621. renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localLightOrigin;
  622. // reference the sound for shader synced effects
  623. if ( lightParent ) {
  624. renderLight.referenceSound = lightParent->GetSoundEmitter();
  625. renderEntity.referenceSound = lightParent->GetSoundEmitter();
  626. }
  627. else {
  628. renderLight.referenceSound = refSound.referenceSound;
  629. renderEntity.referenceSound = refSound.referenceSound;
  630. }
  631. // update the renderLight and renderEntity to render the light and flare
  632. PresentLightDefChange();
  633. PresentModelDefChange();
  634. }
  635. /*
  636. ================
  637. idLight::Think
  638. ================
  639. */
  640. void idLight::Think( void ) {
  641. idVec4 color;
  642. if ( thinkFlags & TH_THINK ) {
  643. if ( fadeEnd > 0 ) {
  644. if ( gameLocal.time < fadeEnd ) {
  645. color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
  646. } else {
  647. color = fadeTo;
  648. fadeEnd = 0;
  649. BecomeInactive( TH_THINK );
  650. }
  651. SetColor( color );
  652. }
  653. }
  654. RunPhysics();
  655. Present();
  656. }
  657. /*
  658. ================
  659. idLight::GetPhysicsToSoundTransform
  660. ================
  661. */
  662. bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  663. origin = localLightOrigin + renderLight.lightCenter;
  664. axis = localLightAxis * GetPhysics()->GetAxis();
  665. return true;
  666. }
  667. /*
  668. ================
  669. idLight::FreeLightDef
  670. ================
  671. */
  672. void idLight::FreeLightDef( void ) {
  673. if ( lightDefHandle != -1 ) {
  674. gameRenderWorld->FreeLightDef( lightDefHandle );
  675. lightDefHandle = -1;
  676. }
  677. }
  678. /*
  679. ================
  680. idLight::SaveState
  681. ================
  682. */
  683. void idLight::SaveState( idDict *args ) {
  684. int i, c = spawnArgs.GetNumKeyVals();
  685. for ( i = 0; i < c; i++ ) {
  686. const idKeyValue *pv = spawnArgs.GetKeyVal(i);
  687. if ( pv->GetKey().Find( "editor_", false ) >= 0 || pv->GetKey().Find( "parse_", false ) >= 0 ) {
  688. continue;
  689. }
  690. args->Set( pv->GetKey(), pv->GetValue() );
  691. }
  692. }
  693. /*
  694. ===============
  695. idLight::ShowEditingDialog
  696. ===============
  697. */
  698. void idLight::ShowEditingDialog( void ) {
  699. if ( g_editEntityMode.GetInteger() == 1 ) {
  700. common->InitTool( EDITOR_LIGHT, &spawnArgs );
  701. } else {
  702. common->InitTool( EDITOR_SOUND, &spawnArgs );
  703. }
  704. }
  705. /*
  706. ================
  707. idLight::Event_SetShader
  708. ================
  709. */
  710. void idLight::Event_SetShader( const char *shadername ) {
  711. SetShader( shadername );
  712. }
  713. /*
  714. ================
  715. idLight::Event_GetLightParm
  716. ================
  717. */
  718. void idLight::Event_GetLightParm( int parmnum ) {
  719. if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
  720. gameLocal.Error( "shader parm index (%d) out of range", parmnum );
  721. }
  722. idThread::ReturnFloat( renderLight.shaderParms[ parmnum ] );
  723. }
  724. /*
  725. ================
  726. idLight::Event_SetLightParm
  727. ================
  728. */
  729. void idLight::Event_SetLightParm( int parmnum, float value ) {
  730. SetLightParm( parmnum, value );
  731. }
  732. /*
  733. ================
  734. idLight::Event_SetLightParms
  735. ================
  736. */
  737. void idLight::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
  738. SetLightParms( parm0, parm1, parm2, parm3 );
  739. }
  740. /*
  741. ================
  742. idLight::Event_SetRadiusXYZ
  743. ================
  744. */
  745. void idLight::Event_SetRadiusXYZ( float x, float y, float z ) {
  746. SetRadiusXYZ( x, y, z );
  747. }
  748. /*
  749. ================
  750. idLight::Event_SetRadius
  751. ================
  752. */
  753. void idLight::Event_SetRadius( float radius ) {
  754. SetRadius( radius );
  755. }
  756. /*
  757. ================
  758. idLight::Event_Hide
  759. ================
  760. */
  761. void idLight::Event_Hide( void ) {
  762. Hide();
  763. PresentModelDefChange();
  764. Off();
  765. }
  766. /*
  767. ================
  768. idLight::Event_Show
  769. ================
  770. */
  771. void idLight::Event_Show( void ) {
  772. Show();
  773. PresentModelDefChange();
  774. On();
  775. }
  776. /*
  777. ================
  778. idLight::Event_On
  779. ================
  780. */
  781. void idLight::Event_On( void ) {
  782. On();
  783. }
  784. /*
  785. ================
  786. idLight::Event_Off
  787. ================
  788. */
  789. void idLight::Event_Off( void ) {
  790. Off();
  791. }
  792. /*
  793. ================
  794. idLight::Event_ToggleOnOff
  795. ================
  796. */
  797. void idLight::Event_ToggleOnOff( idEntity *activator ) {
  798. triggercount++;
  799. if ( triggercount < count ) {
  800. return;
  801. }
  802. // reset trigger count
  803. triggercount = 0;
  804. if ( breakOnTrigger ) {
  805. BecomeBroken( activator );
  806. breakOnTrigger = false;
  807. return;
  808. }
  809. if ( !currentLevel ) {
  810. On();
  811. }
  812. else {
  813. currentLevel--;
  814. if ( !currentLevel ) {
  815. Off();
  816. }
  817. else {
  818. SetLightLevel();
  819. }
  820. }
  821. }
  822. /*
  823. ================
  824. idLight::Event_SetSoundHandles
  825. set the same sound def handle on all targeted lights
  826. ================
  827. */
  828. void idLight::Event_SetSoundHandles( void ) {
  829. int i;
  830. idEntity *targetEnt;
  831. if ( !refSound.referenceSound ) {
  832. return;
  833. }
  834. for ( i = 0; i < targets.Num(); i++ ) {
  835. targetEnt = targets[ i ].GetEntity();
  836. if ( targetEnt && targetEnt->IsType( idLight::Type ) ) {
  837. idLight *light = static_cast<idLight*>(targetEnt);
  838. light->lightParent = this;
  839. // explicitly delete any sounds on the entity
  840. light->FreeSoundEmitter( true );
  841. // manually set the refSound to this light's refSound
  842. light->renderEntity.referenceSound = renderEntity.referenceSound;
  843. // update the renderEntity to the renderer
  844. light->UpdateVisuals();
  845. }
  846. }
  847. }
  848. /*
  849. ================
  850. idLight::Event_FadeOut
  851. ================
  852. */
  853. void idLight::Event_FadeOut( float time ) {
  854. FadeOut( time );
  855. }
  856. /*
  857. ================
  858. idLight::Event_FadeIn
  859. ================
  860. */
  861. void idLight::Event_FadeIn( float time ) {
  862. FadeIn( time );
  863. }
  864. /*
  865. ================
  866. idLight::ClientPredictionThink
  867. ================
  868. */
  869. void idLight::ClientPredictionThink( void ) {
  870. Think();
  871. }
  872. /*
  873. ================
  874. idLight::WriteToSnapshot
  875. ================
  876. */
  877. void idLight::WriteToSnapshot( idBitMsgDelta &msg ) const {
  878. GetPhysics()->WriteToSnapshot( msg );
  879. WriteBindToSnapshot( msg );
  880. msg.WriteByte( currentLevel );
  881. msg.WriteLong( PackColor( baseColor ) );
  882. // msg.WriteBits( lightParent.GetEntityNum(), GENTITYNUM_BITS );
  883. /* // only helps prediction
  884. msg.WriteLong( PackColor( fadeFrom ) );
  885. msg.WriteLong( PackColor( fadeTo ) );
  886. msg.WriteLong( fadeStart );
  887. msg.WriteLong( fadeEnd );
  888. */
  889. // FIXME: send renderLight.shader
  890. msg.WriteFloat( renderLight.lightRadius[0], 5, 10 );
  891. msg.WriteFloat( renderLight.lightRadius[1], 5, 10 );
  892. msg.WriteFloat( renderLight.lightRadius[2], 5, 10 );
  893. msg.WriteLong( PackColor( idVec4( renderLight.shaderParms[SHADERPARM_RED],
  894. renderLight.shaderParms[SHADERPARM_GREEN],
  895. renderLight.shaderParms[SHADERPARM_BLUE],
  896. renderLight.shaderParms[SHADERPARM_ALPHA] ) ) );
  897. msg.WriteFloat( renderLight.shaderParms[SHADERPARM_TIMESCALE], 5, 10 );
  898. msg.WriteLong( renderLight.shaderParms[SHADERPARM_TIMEOFFSET] );
  899. //msg.WriteByte( renderLight.shaderParms[SHADERPARM_DIVERSITY] );
  900. msg.WriteShort( renderLight.shaderParms[SHADERPARM_MODE] );
  901. WriteColorToSnapshot( msg );
  902. }
  903. /*
  904. ================
  905. idLight::ReadFromSnapshot
  906. ================
  907. */
  908. void idLight::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  909. idVec4 shaderColor;
  910. int oldCurrentLevel = currentLevel;
  911. idVec3 oldBaseColor = baseColor;
  912. GetPhysics()->ReadFromSnapshot( msg );
  913. ReadBindFromSnapshot( msg );
  914. currentLevel = msg.ReadByte();
  915. if ( currentLevel != oldCurrentLevel ) {
  916. // need to call On/Off for flickering lights to start/stop the sound
  917. // while doing it this way rather than through events, the flickering is out of sync between clients
  918. // but at least there is no question about saving the event and having them happening globally in the world
  919. if ( currentLevel ) {
  920. On();
  921. } else {
  922. Off();
  923. }
  924. }
  925. UnpackColor( msg.ReadLong(), baseColor );
  926. // lightParentEntityNum = msg.ReadBits( GENTITYNUM_BITS );
  927. /* // only helps prediction
  928. UnpackColor( msg.ReadLong(), fadeFrom );
  929. UnpackColor( msg.ReadLong(), fadeTo );
  930. fadeStart = msg.ReadLong();
  931. fadeEnd = msg.ReadLong();
  932. */
  933. // FIXME: read renderLight.shader
  934. renderLight.lightRadius[0] = msg.ReadFloat( 5, 10 );
  935. renderLight.lightRadius[1] = msg.ReadFloat( 5, 10 );
  936. renderLight.lightRadius[2] = msg.ReadFloat( 5, 10 );
  937. UnpackColor( msg.ReadLong(), shaderColor );
  938. renderLight.shaderParms[SHADERPARM_RED] = shaderColor[0];
  939. renderLight.shaderParms[SHADERPARM_GREEN] = shaderColor[1];
  940. renderLight.shaderParms[SHADERPARM_BLUE] = shaderColor[2];
  941. renderLight.shaderParms[SHADERPARM_ALPHA] = shaderColor[3];
  942. renderLight.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 );
  943. renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadLong();
  944. //renderLight.shaderParms[SHADERPARM_DIVERSITY] = msg.ReadFloat();
  945. renderLight.shaderParms[SHADERPARM_MODE] = msg.ReadShort();
  946. ReadColorFromSnapshot( msg );
  947. if ( msg.HasChanged() ) {
  948. if ( ( currentLevel != oldCurrentLevel ) || ( baseColor != oldBaseColor ) ) {
  949. SetLightLevel();
  950. } else {
  951. PresentLightDefChange();
  952. PresentModelDefChange();
  953. }
  954. }
  955. }
  956. /*
  957. ================
  958. idLight::ClientReceiveEvent
  959. ================
  960. */
  961. bool idLight::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  962. switch( event ) {
  963. case EVENT_BECOMEBROKEN: {
  964. BecomeBroken( NULL );
  965. return true;
  966. }
  967. default: {
  968. return idEntity::ClientReceiveEvent( event, time, msg );
  969. }
  970. }
  971. return false;
  972. }