lightBase.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. mPriority( 1.0f ),
  54. mAnimationData( NULL ),
  55. mFlareData( NULL ),
  56. mFlareScale( 1.0f )
  57. {
  58. mNetFlags.set( Ghostable | ScopeAlways );
  59. mTypeMask = EnvironmentObjectType | LightObjectType;
  60. mLight = LightManager::createLightInfo();
  61. mFlareState.clear();
  62. }
  63. LightBase::~LightBase()
  64. {
  65. SAFE_DELETE( mLight );
  66. }
  67. void LightBase::initPersistFields()
  68. {
  69. // We only add the basic lighting options that all lighting
  70. // systems would use... the specific lighting system options
  71. // are injected at runtime by the lighting system itself.
  72. addGroup( "Light" );
  73. addField( "isEnabled", TypeBool, Offset( mIsEnabled, LightBase ), "Enables/Disables the object rendering and functionality in the scene." );
  74. addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
  75. addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );
  76. addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
  77. addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
  78. "Priority determines if a light has a stronger effect than, those with a lower value" );
  79. endGroup( "Light" );
  80. addGroup( "Light Animation" );
  81. addField( "animate", TypeBool, Offset( mAnimState.active, LightBase ), "Toggles animation for the light on and off" );
  82. addField( "animationType", TYPEID< LightAnimData >(), Offset( mAnimationData, LightBase ), "Datablock containing light animation information (LightAnimData)" );
  83. 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)" );
  84. addField( "animationPhase", TypeF32, Offset( mAnimState.animationPhase, LightBase ), "The phase used to offset the animation start time to vary the animation of nearby lights." );
  85. endGroup( "Light Animation" );
  86. addGroup( "Misc" );
  87. addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, LightBase ), "Datablock containing light flare information (LightFlareData)" );
  88. addField( "flareScale", TypeF32, Offset( mFlareScale, LightBase ), "Globally scales all features of the light flare" );
  89. endGroup( "Misc" );
  90. // Now inject any light manager specific fields.
  91. LightManager::initLightFields();
  92. // We do the parent fields at the end so that
  93. // they show up that way in the inspector.
  94. Parent::initPersistFields();
  95. Con::addVariable( "$Light::renderViz", TypeBool, &smRenderViz,
  96. "Toggles visualization of light object's radius or cone.\n"
  97. "@ingroup Lighting");
  98. Con::addVariable( "$Light::renderLightFrustums", TypeBool, &LightShadowMap::smDebugRenderFrustums,
  99. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  100. "@note Only works for shadow mapped lights.\n\n"
  101. "@ingroup Lighting" );
  102. }
  103. bool LightBase::onAdd()
  104. {
  105. if ( !Parent::onAdd() )
  106. return false;
  107. // Update the light parameters.
  108. _conformLights();
  109. addToScene();
  110. return true;
  111. }
  112. void LightBase::onRemove()
  113. {
  114. removeFromScene();
  115. Parent::onRemove();
  116. }
  117. void LightBase::submitLights( LightManager *lm, bool staticLighting )
  118. {
  119. if ( !mIsEnabled || staticLighting )
  120. return;
  121. if ( mAnimState.active &&
  122. mAnimState.animationPeriod > 0.0f &&
  123. mAnimationData )
  124. {
  125. mAnimState.brightness = mBrightness;
  126. mAnimState.transform = getRenderTransform();
  127. mAnimState.color = mColor;
  128. mAnimationData->animate( mLight, &mAnimState );
  129. }
  130. lm->registerGlobalLight( mLight, this );
  131. }
  132. void LightBase::inspectPostApply()
  133. {
  134. // We do not call the parent here as it
  135. // will call setScale() and screw up the
  136. // real sizing fields on the light.
  137. // Ok fine... then we must set MountedMask ourself.
  138. _conformLights();
  139. setMaskBits( EnabledMask | UpdateMask | TransformMask | DatablockMask | MountedMask );
  140. }
  141. void LightBase::setTransform( const MatrixF &mat )
  142. {
  143. setMaskBits( TransformMask );
  144. Parent::setTransform( mat );
  145. }
  146. void LightBase::prepRenderImage( SceneRenderState *state )
  147. {
  148. if ( mIsEnabled && mFlareData )
  149. {
  150. mFlareState.fullBrightness = mBrightness;
  151. mFlareState.scale = mFlareScale;
  152. mFlareState.lightInfo = mLight;
  153. mFlareState.lightMat = getRenderTransform();
  154. mFlareData->prepRender( state, &mFlareState );
  155. }
  156. if ( !state->isDiffusePass() )
  157. return;
  158. const bool isSelectedInEditor = ( gEditingMission && isSelected() );
  159. // If the light is selected or light visualization
  160. // is enabled then register the callback.
  161. if ( smRenderViz || isSelectedInEditor )
  162. {
  163. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  164. ri->renderDelegate.bind( this, &LightBase::_onRenderViz );
  165. ri->type = RenderPassManager::RIT_Editor;
  166. state->getRenderPass()->addInst( ri );
  167. }
  168. }
  169. void LightBase::_onRenderViz( ObjectRenderInst *ri,
  170. SceneRenderState *state,
  171. BaseMatInstance *overrideMat )
  172. {
  173. if ( overrideMat )
  174. return;
  175. _renderViz( state );
  176. }
  177. void LightBase::_onSelected()
  178. {
  179. #ifdef TORQUE_DEBUG
  180. // Enable debug rendering on the light.
  181. if( isClientObject() )
  182. mLight->enableDebugRendering( true );
  183. #endif
  184. Parent::_onSelected();
  185. }
  186. void LightBase::_onUnselected()
  187. {
  188. #ifdef TORQUE_DEBUG
  189. // Disable debug rendering on the light.
  190. if( isClientObject() )
  191. mLight->enableDebugRendering( false );
  192. #endif
  193. Parent::_onUnselected();
  194. }
  195. void LightBase::interpolateTick( F32 delta )
  196. {
  197. }
  198. void LightBase::processTick()
  199. {
  200. }
  201. void LightBase::advanceTime( F32 timeDelta )
  202. {
  203. if ( isMounted() )
  204. {
  205. MatrixF mat( true );
  206. mMount.object->getRenderMountTransform( 0.f, mMount.node, mMount.xfm, &mat );
  207. mLight->setTransform( mat );
  208. Parent::setTransform( mat );
  209. }
  210. }
  211. U32 LightBase::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
  212. {
  213. U32 retMask = Parent::packUpdate( conn, mask, stream );
  214. stream->writeFlag( mIsEnabled );
  215. if ( stream->writeFlag( mask & TransformMask ) )
  216. stream->writeAffineTransform( mObjToWorld );
  217. if ( stream->writeFlag( mask & UpdateMask ) )
  218. {
  219. stream->write( mColor );
  220. stream->write( mBrightness );
  221. stream->writeFlag( mCastShadows );
  222. stream->write( mPriority );
  223. mLight->packExtended( stream );
  224. stream->writeFlag( mAnimState.active );
  225. stream->write( mAnimState.animationPeriod );
  226. stream->write( mAnimState.animationPhase );
  227. stream->write( mFlareScale );
  228. }
  229. if ( stream->writeFlag( mask & DatablockMask ) )
  230. {
  231. if ( stream->writeFlag( mAnimationData ) )
  232. {
  233. stream->writeRangedU32( mAnimationData->getId(),
  234. DataBlockObjectIdFirst,
  235. DataBlockObjectIdLast );
  236. }
  237. if ( stream->writeFlag( mFlareData ) )
  238. {
  239. stream->writeRangedU32( mFlareData->getId(),
  240. DataBlockObjectIdFirst,
  241. DataBlockObjectIdLast );
  242. }
  243. }
  244. return retMask;
  245. }
  246. void LightBase::unpackUpdate( NetConnection *conn, BitStream *stream )
  247. {
  248. Parent::unpackUpdate( conn, stream );
  249. mIsEnabled = stream->readFlag();
  250. if ( stream->readFlag() ) // TransformMask
  251. stream->readAffineTransform( &mObjToWorld );
  252. if ( stream->readFlag() ) // UpdateMask
  253. {
  254. stream->read( &mColor );
  255. stream->read( &mBrightness );
  256. mCastShadows = stream->readFlag();
  257. stream->read( &mPriority );
  258. mLight->unpackExtended( stream );
  259. mAnimState.active = stream->readFlag();
  260. stream->read( &mAnimState.animationPeriod );
  261. stream->read( &mAnimState.animationPhase );
  262. stream->read( &mFlareScale );
  263. }
  264. if ( stream->readFlag() ) // DatablockMask
  265. {
  266. if ( stream->readFlag() )
  267. {
  268. SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
  269. LightAnimData *datablock = NULL;
  270. if ( Sim::findObject( id, datablock ) )
  271. mAnimationData = datablock;
  272. else
  273. {
  274. conn->setLastError( "Light::unpackUpdate() - invalid LightAnimData!" );
  275. mAnimationData = NULL;
  276. }
  277. }
  278. else
  279. mAnimationData = NULL;
  280. if ( stream->readFlag() )
  281. {
  282. SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
  283. LightFlareData *datablock = NULL;
  284. if ( Sim::findObject( id, datablock ) )
  285. mFlareData = datablock;
  286. else
  287. {
  288. conn->setLastError( "Light::unpackUpdate() - invalid LightCoronaData!" );
  289. mFlareData = NULL;
  290. }
  291. }
  292. else
  293. mFlareData = NULL;
  294. }
  295. if ( isProperlyAdded() )
  296. _conformLights();
  297. }
  298. void LightBase::setLightEnabled( bool enabled )
  299. {
  300. if ( mIsEnabled != enabled )
  301. {
  302. mIsEnabled = enabled;
  303. setMaskBits( EnabledMask );
  304. }
  305. }
  306. DefineEngineMethod( LightBase, setLightEnabled, void, ( bool state ),,
  307. "@brief Toggles the light on and off\n\n"
  308. "@param state Turns the light on (true) or off (false)\n"
  309. "@tsexample\n"
  310. "// Disable the light\n"
  311. "CrystalLight.setLightEnabled(false);\n\n"
  312. "// Renable the light\n"
  313. "CrystalLight.setLightEnabled(true);\n"
  314. "@endtsexample\n\n"
  315. )
  316. {
  317. object->setLightEnabled( state );
  318. }
  319. //ConsoleMethod( LightBase, setLightEnabled, void, 3, 3, "( bool enabled )\t"
  320. // "Toggles the light on and off." )
  321. //{
  322. // object->setLightEnabled( dAtob( argv[2] ) );
  323. //}
  324. static ConsoleDocFragment _lbplayAnimation1(
  325. "@brief Plays the light animation assigned to this light with the existing LightAnimData datablock.\n\n"
  326. "@tsexample\n"
  327. "// Play the animation assigned to this light\n"
  328. "CrystalLight.playAnimation();\n"
  329. "@endtsexample\n\n",
  330. "LightBase",
  331. "void playAnimation();"
  332. );
  333. static ConsoleDocFragment _lbplayAnimation2(
  334. "@brief Plays the light animation on this light using a new LightAnimData. If no LightAnimData "
  335. "is passed the existing one is played.\n\n"
  336. "@param anim Name of the LightAnimData datablock to be played\n\n"
  337. "@tsexample\n"
  338. "// Play the animation using a new LightAnimData datablock\n"
  339. "CrystalLight.playAnimation(SubtlePulseLightAnim);\n"
  340. "@endtsexample\n\n",
  341. "LightBase",
  342. "void playAnimation(LightAnimData anim);"
  343. );
  344. DefineConsoleMethod( LightBase, playAnimation, void, (const char * anim), (""), "( [LightAnimData anim] )\t"
  345. "Plays a light animation on the light. If no LightAnimData is passed the "
  346. "existing one is played."
  347. "@hide")
  348. {
  349. if ( anim == "" )
  350. {
  351. object->playAnimation();
  352. return;
  353. }
  354. LightAnimData *animData;
  355. if ( !Sim::findObject( anim, animData ) )
  356. {
  357. Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", anim );
  358. return;
  359. }
  360. // Play Animation.
  361. object->playAnimation( animData );
  362. }
  363. void LightBase::playAnimation( void )
  364. {
  365. if ( !mAnimState.active )
  366. {
  367. mAnimState.active = true;
  368. setMaskBits( UpdateMask );
  369. }
  370. }
  371. void LightBase::playAnimation( LightAnimData *animData )
  372. {
  373. // Play Animation.
  374. playAnimation();
  375. // Update Datablock?
  376. if ( mAnimationData != animData )
  377. {
  378. mAnimationData = animData;
  379. setMaskBits( DatablockMask );
  380. }
  381. }
  382. DefineConsoleMethod( LightBase, pauseAnimation, void, (), , "Stops the light animation." )
  383. {
  384. object->pauseAnimation();
  385. }
  386. void LightBase::pauseAnimation( void )
  387. {
  388. if ( mAnimState.active )
  389. {
  390. mAnimState.active = false;
  391. setMaskBits( UpdateMask );
  392. }
  393. }