Light.cpp 32 KB

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