lightBase.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/lightBase.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/typeValidators.h"
  26. #include "core/stream/bitStream.h"
  27. #include "sim/netConnection.h"
  28. #include "lighting/lightManager.h"
  29. #include "lighting/shadowMap/lightShadowMap.h"
  30. #include "scene/sceneRenderState.h"
  31. #include "renderInstance/renderPassManager.h"
  32. #include "console/engineAPI.h"
  33. #include "gfx/gfxDrawUtil.h"
  34. extern bool gEditingMission;
  35. bool LightBase::smRenderViz = false;
  36. IMPLEMENT_CONOBJECT( LightBase );
  37. ConsoleDocClass( LightBase,
  38. "@brief This is the base class for light objects.\n\n"
  39. "It is *NOT* intended to be used directly in script, but exists to provide the base member variables "
  40. "and generic functionality. You should be using the derived classes PointLight and SpotLight, which "
  41. "can be declared in TorqueScript or added from the World Editor.\n\n"
  42. "For this class, we only add basic lighting options that all lighting systems would use. "
  43. "The specific lighting system options are injected at runtime by the lighting system itself.\n\n"
  44. "@see PointLight\n\n"
  45. "@see SpotLight\n\n"
  46. "@ingroup Lighting\n"
  47. );
  48. LightBase::LightBase()
  49. : mIsEnabled( true ),
  50. mColor( ColorF::WHITE ),
  51. mBrightness( 1.0f ),
  52. mCastShadows( false ),
  53. mStaticRefreshFreq( 250 ),
  54. mDynamicRefreshFreq( 8 ),
  55. mPriority( 1.0f ),
  56. mAnimationData( NULL ),
  57. mFlareData( NULL ),
  58. mFlareScale( 1.0f )
  59. {
  60. mNetFlags.set( Ghostable | ScopeAlways );
  61. mTypeMask = LightObjectType;
  62. mLight = LightManager::createLightInfo();
  63. mFlareState.clear();
  64. }
  65. LightBase::~LightBase()
  66. {
  67. SAFE_DELETE( mLight );
  68. }
  69. void LightBase::initPersistFields()
  70. {
  71. // We only add the basic lighting options that all lighting
  72. // systems would use... the specific lighting system options
  73. // are injected at runtime by the lighting system itself.
  74. addGroup( "Light" );
  75. addField( "isEnabled", TypeBool, Offset( mIsEnabled, LightBase ), "Enables/Disables the object rendering and functionality in the scene." );
  76. addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
  77. addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );
  78. addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
  79. addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
  80. addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)", AbstractClassRep::FieldFlags::FIELD_HideInInspectors);
  81. addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
  82. "Priority determines if a light has a stronger effect than, those with a lower value" );
  83. endGroup( "Light" );
  84. addGroup( "Light Animation" );
  85. addField( "animate", TypeBool, Offset( mAnimState.active, LightBase ), "Toggles animation for the light on and off" );
  86. addField( "animationType", TYPEID< LightAnimData >(), Offset( mAnimationData, LightBase ), "Datablock containing light animation information (LightAnimData)" );
  87. addFieldV( "animationPeriod", TypeF32, Offset( mAnimState.animationPeriod, LightBase ), &CommonValidators::PositiveNonZeroFloat, "The length of time in seconds for a single playback of the light animation (must be > 0)" );
  88. addField( "animationPhase", TypeF32, Offset( mAnimState.animationPhase, LightBase ), "The phase used to offset the animation start time to vary the animation of nearby lights." );
  89. endGroup( "Light Animation" );
  90. addGroup( "Misc" );
  91. addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, LightBase ), "Datablock containing light flare information (LightFlareData)" );
  92. addField( "flareScale", TypeF32, Offset( mFlareScale, LightBase ), "Globally scales all features of the light flare" );
  93. endGroup( "Misc" );
  94. // Now inject any light manager specific fields.
  95. LightManager::initLightFields();
  96. // We do the parent fields at the end so that
  97. // they show up that way in the inspector.
  98. Parent::initPersistFields();
  99. Con::addVariable( "$Light::renderViz", TypeBool, &smRenderViz,
  100. "Toggles visualization of light object's radius or cone.\n"
  101. "@ingroup Lighting");
  102. Con::addVariable( "$Light::renderLightFrustums", TypeBool, &LightShadowMap::smDebugRenderFrustums,
  103. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  104. "@note Only works for shadow mapped lights.\n\n"
  105. "@ingroup Lighting" );
  106. }
  107. bool LightBase::onAdd()
  108. {
  109. if ( !Parent::onAdd() )
  110. return false;
  111. // Update the light parameters.
  112. _conformLights();
  113. addToScene();
  114. return true;
  115. }
  116. void LightBase::onRemove()
  117. {
  118. removeFromScene();
  119. Parent::onRemove();
  120. }
  121. void LightBase::submitLights( LightManager *lm, bool staticLighting )
  122. {
  123. if ( !mIsEnabled || staticLighting )
  124. return;
  125. if ( mAnimState.active &&
  126. mAnimState.animationPeriod > 0.0f &&
  127. mAnimationData )
  128. {
  129. mAnimState.brightness = mBrightness;
  130. mAnimState.transform = getRenderTransform();
  131. mAnimState.color = mColor;
  132. mAnimationData->animate( mLight, &mAnimState );
  133. }
  134. lm->registerGlobalLight( mLight, this );
  135. }
  136. void LightBase::inspectPostApply()
  137. {
  138. // We do not call the parent here as it
  139. // will call setScale() and screw up the
  140. // real sizing fields on the light.
  141. // Ok fine... then we must set MountedMask ourself.
  142. _conformLights();
  143. setMaskBits( EnabledMask | UpdateMask | TransformMask | DatablockMask | MountedMask );
  144. }
  145. void LightBase::setTransform( const MatrixF &mat )
  146. {
  147. setMaskBits( TransformMask );
  148. Parent::setTransform( mat );
  149. }
  150. void LightBase::prepRenderImage( SceneRenderState *state )
  151. {
  152. if ( mIsEnabled && mFlareData )
  153. {
  154. mFlareState.fullBrightness = mBrightness;
  155. mFlareState.scale = mFlareScale;
  156. mFlareState.lightInfo = mLight;
  157. mFlareState.lightMat = getRenderTransform();
  158. mFlareData->prepRender( state, &mFlareState );
  159. }
  160. if ( !state->isDiffusePass() )
  161. return;
  162. const bool isSelectedInEditor = ( gEditingMission && isSelected() );
  163. // If the light is selected or light visualization
  164. // is enabled then register the callback.
  165. if ( smRenderViz || isSelectedInEditor )
  166. {
  167. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  168. ri->renderDelegate.bind( this, &LightBase::_onRenderViz );
  169. ri->type = RenderPassManager::RIT_Editor;
  170. state->getRenderPass()->addInst( ri );
  171. }
  172. }
  173. void LightBase::_onRenderViz( ObjectRenderInst *ri,
  174. SceneRenderState *state,
  175. BaseMatInstance *overrideMat )
  176. {
  177. if ( overrideMat )
  178. return;
  179. _renderViz( state );
  180. }
  181. void LightBase::_onSelected()
  182. {
  183. #ifdef TORQUE_DEBUG
  184. // Enable debug rendering on the light.
  185. if( isClientObject() )
  186. mLight->enableDebugRendering( true );
  187. #endif
  188. Parent::_onSelected();
  189. }
  190. void LightBase::_onUnselected()
  191. {
  192. #ifdef TORQUE_DEBUG
  193. // Disable debug rendering on the light.
  194. if( isClientObject() )
  195. mLight->enableDebugRendering( false );
  196. #endif
  197. Parent::_onUnselected();
  198. }
  199. void LightBase::interpolateTick( F32 delta )
  200. {
  201. }
  202. void LightBase::processTick()
  203. {
  204. }
  205. void LightBase::advanceTime( F32 timeDelta )
  206. {
  207. if ( isMounted() )
  208. {
  209. MatrixF mat( true );
  210. mMount.object->getRenderMountTransform( 0.f, mMount.node, mMount.xfm, &mat );
  211. mLight->setTransform( mat );
  212. Parent::setTransform( mat );
  213. }
  214. }
  215. U32 LightBase::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
  216. {
  217. U32 retMask = Parent::packUpdate( conn, mask, stream );
  218. stream->writeFlag( mIsEnabled );
  219. if ( stream->writeFlag( mask & TransformMask ) )
  220. stream->writeAffineTransform( mObjToWorld );
  221. if ( stream->writeFlag( mask & UpdateMask ) )
  222. {
  223. stream->write( mColor );
  224. stream->write( mBrightness );
  225. stream->writeFlag( mCastShadows );
  226. stream->write(mStaticRefreshFreq);
  227. stream->write(mDynamicRefreshFreq);
  228. stream->write( mPriority );
  229. mLight->packExtended( stream );
  230. stream->writeFlag( mAnimState.active );
  231. stream->write( mAnimState.animationPeriod );
  232. stream->write( mAnimState.animationPhase );
  233. stream->write( mFlareScale );
  234. }
  235. if ( stream->writeFlag( mask & DatablockMask ) )
  236. {
  237. if ( stream->writeFlag( mAnimationData ) )
  238. {
  239. stream->writeRangedU32( mAnimationData->getId(),
  240. DataBlockObjectIdFirst,
  241. DataBlockObjectIdLast );
  242. }
  243. if ( stream->writeFlag( mFlareData ) )
  244. {
  245. stream->writeRangedU32( mFlareData->getId(),
  246. DataBlockObjectIdFirst,
  247. DataBlockObjectIdLast );
  248. }
  249. }
  250. return retMask;
  251. }
  252. void LightBase::unpackUpdate( NetConnection *conn, BitStream *stream )
  253. {
  254. Parent::unpackUpdate( conn, stream );
  255. mIsEnabled = stream->readFlag();
  256. if ( stream->readFlag() ) // TransformMask
  257. stream->readAffineTransform( &mObjToWorld );
  258. if ( stream->readFlag() ) // UpdateMask
  259. {
  260. stream->read( &mColor );
  261. stream->read( &mBrightness );
  262. mCastShadows = stream->readFlag();
  263. stream->read(&mStaticRefreshFreq);
  264. stream->read(&mDynamicRefreshFreq);
  265. stream->read( &mPriority );
  266. mLight->unpackExtended( stream );
  267. mAnimState.active = stream->readFlag();
  268. stream->read( &mAnimState.animationPeriod );
  269. stream->read( &mAnimState.animationPhase );
  270. stream->read( &mFlareScale );
  271. }
  272. if ( stream->readFlag() ) // DatablockMask
  273. {
  274. if ( stream->readFlag() )
  275. {
  276. SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
  277. LightAnimData *datablock = NULL;
  278. if ( Sim::findObject( id, datablock ) )
  279. mAnimationData = datablock;
  280. else
  281. {
  282. conn->setLastError( "Light::unpackUpdate() - invalid LightAnimData!" );
  283. mAnimationData = NULL;
  284. }
  285. }
  286. else
  287. mAnimationData = NULL;
  288. if ( stream->readFlag() )
  289. {
  290. SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
  291. LightFlareData *datablock = NULL;
  292. if ( Sim::findObject( id, datablock ) )
  293. mFlareData = datablock;
  294. else
  295. {
  296. conn->setLastError( "Light::unpackUpdate() - invalid LightCoronaData!" );
  297. mFlareData = NULL;
  298. }
  299. }
  300. else
  301. mFlareData = NULL;
  302. }
  303. if ( isProperlyAdded() )
  304. _conformLights();
  305. }
  306. void LightBase::setLightEnabled( bool enabled )
  307. {
  308. if ( mIsEnabled != enabled )
  309. {
  310. mIsEnabled = enabled;
  311. setMaskBits( EnabledMask );
  312. }
  313. }
  314. DefineEngineMethod( LightBase, setLightEnabled, void, ( bool state ),,
  315. "@brief Toggles the light on and off\n\n"
  316. "@param state Turns the light on (true) or off (false)\n"
  317. "@tsexample\n"
  318. "// Disable the light\n"
  319. "CrystalLight.setLightEnabled(false);\n\n"
  320. "// Renable the light\n"
  321. "CrystalLight.setLightEnabled(true);\n"
  322. "@endtsexample\n\n"
  323. )
  324. {
  325. object->setLightEnabled( state );
  326. }
  327. //ConsoleMethod( LightBase, setLightEnabled, void, 3, 3, "( bool enabled )\t"
  328. // "Toggles the light on and off." )
  329. //{
  330. // object->setLightEnabled( dAtob( argv[2] ) );
  331. //}
  332. static ConsoleDocFragment _lbplayAnimation1(
  333. "@brief Plays the light animation assigned to this light with the existing LightAnimData datablock.\n\n"
  334. "@tsexample\n"
  335. "// Play the animation assigned to this light\n"
  336. "CrystalLight.playAnimation();\n"
  337. "@endtsexample\n\n",
  338. "LightBase",
  339. "void playAnimation();"
  340. );
  341. static ConsoleDocFragment _lbplayAnimation2(
  342. "@brief Plays the light animation on this light using a new LightAnimData. If no LightAnimData "
  343. "is passed the existing one is played.\n\n"
  344. "@param anim Name of the LightAnimData datablock to be played\n\n"
  345. "@tsexample\n"
  346. "// Play the animation using a new LightAnimData datablock\n"
  347. "CrystalLight.playAnimation(SubtlePulseLightAnim);\n"
  348. "@endtsexample\n\n",
  349. "LightBase",
  350. "void playAnimation(LightAnimData anim);"
  351. );
  352. DefineConsoleMethod( LightBase, playAnimation, void, (const char * anim), (""), "( [LightAnimData anim] )\t"
  353. "Plays a light animation on the light. If no LightAnimData is passed the "
  354. "existing one is played."
  355. "@hide")
  356. {
  357. if ( String::isEmpty(anim) )
  358. {
  359. object->playAnimation();
  360. return;
  361. }
  362. LightAnimData *animData;
  363. if ( !Sim::findObject( anim, animData ) )
  364. {
  365. Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", anim );
  366. return;
  367. }
  368. // Play Animation.
  369. object->playAnimation( animData );
  370. }
  371. void LightBase::playAnimation( void )
  372. {
  373. if ( !mAnimState.active )
  374. {
  375. mAnimState.active = true;
  376. setMaskBits( UpdateMask );
  377. }
  378. }
  379. void LightBase::playAnimation( LightAnimData *animData )
  380. {
  381. // Play Animation.
  382. playAnimation();
  383. // Update Datablock?
  384. if ( mAnimationData != animData )
  385. {
  386. mAnimationData = animData;
  387. setMaskBits( DatablockMask );
  388. }
  389. }
  390. DefineConsoleMethod( LightBase, pauseAnimation, void, (), , "Stops the light animation." )
  391. {
  392. object->pauseAnimation();
  393. }
  394. void LightBase::pauseAnimation( void )
  395. {
  396. if ( mAnimState.active )
  397. {
  398. mAnimState.active = false;
  399. setMaskBits( UpdateMask );
  400. }
  401. }