Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

531 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "beam_shared.h"
  8. #include "spotlightend.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. // Spawnflags
  12. #define SF_SPOTLIGHT_START_LIGHT_ON 0x1
  13. #define SF_SPOTLIGHT_NO_DYNAMIC_LIGHT 0x2
  14. //-----------------------------------------------------------------------------
  15. // Purpose:
  16. //-----------------------------------------------------------------------------
  17. class CPointSpotlight : public CPointEntity
  18. {
  19. DECLARE_CLASS( CPointSpotlight, CPointEntity );
  20. public:
  21. DECLARE_DATADESC();
  22. CPointSpotlight();
  23. void Precache(void);
  24. void Spawn(void);
  25. virtual void Activate();
  26. virtual void OnEntityEvent( EntityEvent_t event, void *pEventData );
  27. private:
  28. int UpdateTransmitState();
  29. void SpotlightThink(void);
  30. void SpotlightUpdate(void);
  31. Vector SpotlightCurrentPos(void);
  32. void SpotlightCreate(void);
  33. void SpotlightDestroy(void);
  34. // ------------------------------
  35. // Inputs
  36. // ------------------------------
  37. void InputLightOn( inputdata_t &inputdata );
  38. void InputLightOff( inputdata_t &inputdata );
  39. // Creates the efficient spotlight
  40. void CreateEfficientSpotlight();
  41. // Computes render info for a spotlight
  42. void ComputeRenderInfo();
  43. private:
  44. bool m_bSpotlightOn;
  45. bool m_bEfficientSpotlight;
  46. bool m_bIgnoreSolid;
  47. Vector m_vSpotlightTargetPos;
  48. Vector m_vSpotlightCurrentPos;
  49. Vector m_vSpotlightDir;
  50. int m_nHaloSprite;
  51. CHandle<CBeam> m_hSpotlight;
  52. CHandle<CSpotlightEnd> m_hSpotlightTarget;
  53. float m_flSpotlightMaxLength;
  54. float m_flSpotlightCurLength;
  55. float m_flSpotlightGoalWidth;
  56. float m_flHDRColorScale;
  57. int m_nMinDXLevel;
  58. public:
  59. COutputEvent m_OnOn, m_OnOff; ///< output fires when turned on, off
  60. };
  61. BEGIN_DATADESC( CPointSpotlight )
  62. DEFINE_FIELD( m_flSpotlightCurLength, FIELD_FLOAT ),
  63. DEFINE_FIELD( m_bSpotlightOn, FIELD_BOOLEAN ),
  64. DEFINE_FIELD( m_bEfficientSpotlight, FIELD_BOOLEAN ),
  65. DEFINE_FIELD( m_vSpotlightTargetPos, FIELD_POSITION_VECTOR ),
  66. DEFINE_FIELD( m_vSpotlightCurrentPos, FIELD_POSITION_VECTOR ),
  67. // Robin: Don't Save, recreated after restore/transition
  68. //DEFINE_FIELD( m_hSpotlight, FIELD_EHANDLE ),
  69. //DEFINE_FIELD( m_hSpotlightTarget, FIELD_EHANDLE ),
  70. DEFINE_FIELD( m_vSpotlightDir, FIELD_VECTOR ),
  71. DEFINE_FIELD( m_nHaloSprite, FIELD_INTEGER ),
  72. DEFINE_KEYFIELD( m_bIgnoreSolid, FIELD_BOOLEAN, "IgnoreSolid" ),
  73. DEFINE_KEYFIELD( m_flSpotlightMaxLength,FIELD_FLOAT, "SpotlightLength"),
  74. DEFINE_KEYFIELD( m_flSpotlightGoalWidth,FIELD_FLOAT, "SpotlightWidth"),
  75. DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ),
  76. DEFINE_KEYFIELD( m_nMinDXLevel, FIELD_INTEGER, "mindxlevel" ),
  77. // Inputs
  78. DEFINE_INPUTFUNC( FIELD_VOID, "LightOn", InputLightOn ),
  79. DEFINE_INPUTFUNC( FIELD_VOID, "LightOff", InputLightOff ),
  80. DEFINE_OUTPUT( m_OnOn, "OnLightOn" ),
  81. DEFINE_OUTPUT( m_OnOff, "OnLightOff" ),
  82. DEFINE_THINKFUNC( SpotlightThink ),
  83. END_DATADESC()
  84. LINK_ENTITY_TO_CLASS(point_spotlight, CPointSpotlight);
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. CPointSpotlight::CPointSpotlight()
  89. {
  90. #ifdef _DEBUG
  91. m_vSpotlightTargetPos.Init();
  92. m_vSpotlightCurrentPos.Init();
  93. m_vSpotlightDir.Init();
  94. #endif
  95. m_flHDRColorScale = 1.0f;
  96. m_nMinDXLevel = 0;
  97. m_bIgnoreSolid = false;
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose:
  101. //-----------------------------------------------------------------------------
  102. void CPointSpotlight::Precache(void)
  103. {
  104. BaseClass::Precache();
  105. // Sprites.
  106. m_nHaloSprite = PrecacheModel("sprites/light_glow03.vmt");
  107. PrecacheModel( "sprites/glow_test02.vmt" );
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. //-----------------------------------------------------------------------------
  112. void CPointSpotlight::Spawn(void)
  113. {
  114. Precache();
  115. UTIL_SetSize( this,vec3_origin,vec3_origin );
  116. AddSolidFlags( FSOLID_NOT_SOLID );
  117. SetMoveType( MOVETYPE_NONE );
  118. m_bEfficientSpotlight = true;
  119. // Check for user error
  120. if (m_flSpotlightMaxLength <= 0)
  121. {
  122. DevMsg("%s (%s) has an invalid spotlight length <= 0, setting to 500\n", GetClassname(), GetDebugName() );
  123. m_flSpotlightMaxLength = 500;
  124. }
  125. if (m_flSpotlightGoalWidth <= 0)
  126. {
  127. DevMsg("%s (%s) has an invalid spotlight width <= 0, setting to 10\n", GetClassname(), GetDebugName() );
  128. m_flSpotlightGoalWidth = 10;
  129. }
  130. if (m_flSpotlightGoalWidth > MAX_BEAM_WIDTH )
  131. {
  132. DevMsg("%s (%s) has an invalid spotlight width %.1f (max %.1f).\n", GetClassname(), GetDebugName(), m_flSpotlightGoalWidth, MAX_BEAM_WIDTH );
  133. m_flSpotlightGoalWidth = MAX_BEAM_WIDTH;
  134. }
  135. // ------------------------------------
  136. // Init all class vars
  137. // ------------------------------------
  138. m_vSpotlightTargetPos = vec3_origin;
  139. m_vSpotlightCurrentPos = vec3_origin;
  140. m_hSpotlight = NULL;
  141. m_hSpotlightTarget = NULL;
  142. m_vSpotlightDir = vec3_origin;
  143. m_flSpotlightCurLength = m_flSpotlightMaxLength;
  144. m_bSpotlightOn = HasSpawnFlags( SF_SPOTLIGHT_START_LIGHT_ON );
  145. SetThink( &CPointSpotlight::SpotlightThink );
  146. SetNextThink( gpGlobals->curtime + 0.1f );
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Computes render info for a spotlight
  150. //-----------------------------------------------------------------------------
  151. void CPointSpotlight::ComputeRenderInfo()
  152. {
  153. // Fade out spotlight end if past max length.
  154. if ( m_flSpotlightCurLength > 2*m_flSpotlightMaxLength )
  155. {
  156. m_hSpotlightTarget->SetRenderColorA( 0 );
  157. m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength );
  158. }
  159. else if ( m_flSpotlightCurLength > m_flSpotlightMaxLength )
  160. {
  161. m_hSpotlightTarget->SetRenderColorA( (1-((m_flSpotlightCurLength-m_flSpotlightMaxLength)/m_flSpotlightMaxLength)) );
  162. m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength );
  163. }
  164. else
  165. {
  166. m_hSpotlightTarget->SetRenderColorA( 1.0 );
  167. m_hSpotlight->SetFadeLength( m_flSpotlightCurLength );
  168. }
  169. // Adjust end width to keep beam width constant
  170. float flNewWidth = m_flSpotlightGoalWidth * (m_flSpotlightCurLength / m_flSpotlightMaxLength);
  171. flNewWidth = clamp(flNewWidth, 0.f, MAX_BEAM_WIDTH );
  172. m_hSpotlight->SetEndWidth(flNewWidth);
  173. // Adjust width of light on the end.
  174. if ( FBitSet (m_spawnflags, SF_SPOTLIGHT_NO_DYNAMIC_LIGHT) )
  175. {
  176. m_hSpotlightTarget->m_flLightScale = 0.0;
  177. }
  178. else
  179. {
  180. // <<TODO>> - magic number 1.8 depends on sprite size
  181. m_hSpotlightTarget->m_flLightScale = 1.8*flNewWidth;
  182. }
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Creates the efficient spotlight
  186. //-----------------------------------------------------------------------------
  187. void CPointSpotlight::CreateEfficientSpotlight()
  188. {
  189. if ( m_hSpotlightTarget.Get() != NULL )
  190. return;
  191. SpotlightCreate();
  192. m_vSpotlightCurrentPos = SpotlightCurrentPos();
  193. m_hSpotlightTarget->SetAbsOrigin( m_vSpotlightCurrentPos );
  194. m_hSpotlightTarget->m_vSpotlightOrg = GetAbsOrigin();
  195. VectorSubtract( m_hSpotlightTarget->GetAbsOrigin(), m_hSpotlightTarget->m_vSpotlightOrg, m_hSpotlightTarget->m_vSpotlightDir );
  196. m_flSpotlightCurLength = VectorNormalize( m_hSpotlightTarget->m_vSpotlightDir );
  197. m_hSpotlightTarget->SetMoveType( MOVETYPE_NONE );
  198. ComputeRenderInfo();
  199. m_OnOn.FireOutput( this, this );
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose:
  203. //-----------------------------------------------------------------------------
  204. void CPointSpotlight::Activate(void)
  205. {
  206. BaseClass::Activate();
  207. if ( GetMoveParent() )
  208. {
  209. m_bEfficientSpotlight = false;
  210. }
  211. if ( m_bEfficientSpotlight )
  212. {
  213. if ( m_bSpotlightOn )
  214. {
  215. CreateEfficientSpotlight();
  216. }
  217. // Don't think
  218. SetThink( NULL );
  219. }
  220. }
  221. //-------------------------------------------------------------------------------------
  222. // Optimization to deal with spotlights
  223. //-------------------------------------------------------------------------------------
  224. void CPointSpotlight::OnEntityEvent( EntityEvent_t event, void *pEventData )
  225. {
  226. if ( event == ENTITY_EVENT_PARENT_CHANGED )
  227. {
  228. if ( GetMoveParent() )
  229. {
  230. m_bEfficientSpotlight = false;
  231. if ( m_hSpotlightTarget )
  232. {
  233. m_hSpotlightTarget->SetMoveType( MOVETYPE_FLY );
  234. }
  235. SetThink( &CPointSpotlight::SpotlightThink );
  236. SetNextThink( gpGlobals->curtime + 0.1f );
  237. }
  238. }
  239. BaseClass::OnEntityEvent( event, pEventData );
  240. }
  241. //-------------------------------------------------------------------------------------
  242. // Purpose : Send even though we don't have a model so spotlight gets proper position
  243. // Input :
  244. // Output :
  245. //-------------------------------------------------------------------------------------
  246. int CPointSpotlight::UpdateTransmitState()
  247. {
  248. if ( m_bEfficientSpotlight )
  249. return SetTransmitState( FL_EDICT_DONTSEND );
  250. return SetTransmitState( FL_EDICT_PVSCHECK );
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose: Plays the engine sound.
  254. //-----------------------------------------------------------------------------
  255. void CPointSpotlight::SpotlightThink( void )
  256. {
  257. if ( GetMoveParent() )
  258. {
  259. SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
  260. }
  261. else
  262. {
  263. SetNextThink( gpGlobals->curtime + 0.1f );
  264. }
  265. SpotlightUpdate();
  266. }
  267. //------------------------------------------------------------------------------
  268. // Purpose :
  269. // Input :
  270. // Output :
  271. //------------------------------------------------------------------------------
  272. void CPointSpotlight::SpotlightCreate(void)
  273. {
  274. if ( m_hSpotlightTarget.Get() != NULL )
  275. return;
  276. AngleVectors( GetAbsAngles(), &m_vSpotlightDir );
  277. Vector vTargetPos;
  278. if ( m_bIgnoreSolid )
  279. {
  280. vTargetPos = GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength;
  281. }
  282. else
  283. {
  284. trace_t tr;
  285. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  286. vTargetPos = tr.endpos;
  287. }
  288. m_hSpotlightTarget = (CSpotlightEnd*)CreateEntityByName( "spotlight_end" );
  289. m_hSpotlightTarget->Spawn();
  290. m_hSpotlightTarget->SetAbsOrigin( vTargetPos );
  291. m_hSpotlightTarget->SetOwnerEntity( this );
  292. m_hSpotlightTarget->m_clrRender = m_clrRender;
  293. m_hSpotlightTarget->m_Radius = m_flSpotlightMaxLength;
  294. if ( FBitSet (m_spawnflags, SF_SPOTLIGHT_NO_DYNAMIC_LIGHT) )
  295. {
  296. m_hSpotlightTarget->m_flLightScale = 0.0;
  297. }
  298. //m_hSpotlight = CBeam::BeamCreate( "sprites/spotlight.vmt", m_flSpotlightGoalWidth );
  299. m_hSpotlight = CBeam::BeamCreate( "sprites/glow_test02.vmt", m_flSpotlightGoalWidth );
  300. // Set the temporary spawnflag on the beam so it doesn't save (we'll recreate it on restore)
  301. m_hSpotlight->SetHDRColorScale( m_flHDRColorScale );
  302. m_hSpotlight->AddSpawnFlags( SF_BEAM_TEMPORARY );
  303. m_hSpotlight->SetColor( m_clrRender->r, m_clrRender->g, m_clrRender->b );
  304. m_hSpotlight->SetHaloTexture(m_nHaloSprite);
  305. m_hSpotlight->SetHaloScale(60);
  306. m_hSpotlight->SetEndWidth(m_flSpotlightGoalWidth);
  307. m_hSpotlight->SetBeamFlags( (FBEAM_SHADEOUT|FBEAM_NOTILE) );
  308. m_hSpotlight->SetBrightness( 64 );
  309. m_hSpotlight->SetNoise( 0 );
  310. m_hSpotlight->SetMinDXLevel( m_nMinDXLevel );
  311. if ( m_bEfficientSpotlight )
  312. {
  313. m_hSpotlight->PointsInit( GetAbsOrigin(), m_hSpotlightTarget->GetAbsOrigin() );
  314. }
  315. else
  316. {
  317. m_hSpotlight->EntsInit( this, m_hSpotlightTarget );
  318. }
  319. }
  320. //------------------------------------------------------------------------------
  321. // Purpose :
  322. // Input :
  323. // Output :
  324. //------------------------------------------------------------------------------
  325. Vector CPointSpotlight::SpotlightCurrentPos(void)
  326. {
  327. AngleVectors( GetAbsAngles(), &m_vSpotlightDir );
  328. // Get beam end point. Only collide with solid objects, not npcs
  329. Vector vEndPos = GetAbsOrigin() + ( m_vSpotlightDir * 2 * m_flSpotlightMaxLength );
  330. if ( m_bIgnoreSolid )
  331. {
  332. return vEndPos;
  333. }
  334. else
  335. {
  336. trace_t tr;
  337. UTIL_TraceLine( GetAbsOrigin(), vEndPos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  338. return tr.endpos;
  339. }
  340. }
  341. //------------------------------------------------------------------------------
  342. // Purpose :
  343. // Input :
  344. // Output :
  345. //------------------------------------------------------------------------------
  346. void CPointSpotlight::SpotlightDestroy(void)
  347. {
  348. if ( m_hSpotlight )
  349. {
  350. m_OnOff.FireOutput( this, this );
  351. UTIL_Remove(m_hSpotlight);
  352. UTIL_Remove(m_hSpotlightTarget);
  353. }
  354. }
  355. //------------------------------------------------------------------------------
  356. // Purpose : Update the direction and position of my spotlight
  357. // Input :
  358. // Output :
  359. //------------------------------------------------------------------------------
  360. void CPointSpotlight::SpotlightUpdate(void)
  361. {
  362. // ---------------------------------------------------
  363. // If I don't have a spotlight attempt to create one
  364. // ---------------------------------------------------
  365. if ( !m_hSpotlight )
  366. {
  367. if ( m_bSpotlightOn )
  368. {
  369. // Make the spotlight
  370. SpotlightCreate();
  371. }
  372. else
  373. {
  374. return;
  375. }
  376. }
  377. else if ( !m_bSpotlightOn )
  378. {
  379. SpotlightDestroy();
  380. return;
  381. }
  382. if ( !m_hSpotlightTarget )
  383. {
  384. DevWarning( "**Attempting to update point_spotlight but target ent is NULL\n" );
  385. SpotlightDestroy();
  386. SpotlightCreate();
  387. if ( !m_hSpotlightTarget )
  388. return;
  389. }
  390. m_vSpotlightCurrentPos = SpotlightCurrentPos();
  391. // Update spotlight target velocity
  392. Vector vTargetDir;
  393. VectorSubtract( m_vSpotlightCurrentPos, m_hSpotlightTarget->GetAbsOrigin(), vTargetDir );
  394. float vTargetDist = vTargetDir.Length();
  395. // If we haven't moved at all, don't recompute
  396. if ( vTargetDist < 1 )
  397. {
  398. m_hSpotlightTarget->SetAbsVelocity( vec3_origin );
  399. return;
  400. }
  401. Vector vecNewVelocity = vTargetDir;
  402. VectorNormalize(vecNewVelocity);
  403. vecNewVelocity *= (10 * vTargetDist);
  404. // If a large move is requested, just jump to final spot as we probably hit a discontinuity
  405. if (vecNewVelocity.Length() > 200)
  406. {
  407. VectorNormalize(vecNewVelocity);
  408. vecNewVelocity *= 200;
  409. VectorNormalize(vTargetDir);
  410. m_hSpotlightTarget->SetAbsOrigin( m_vSpotlightCurrentPos );
  411. }
  412. m_hSpotlightTarget->SetAbsVelocity( vecNewVelocity );
  413. m_hSpotlightTarget->m_vSpotlightOrg = GetAbsOrigin();
  414. // Avoid sudden change in where beam fades out when cross disconinuities
  415. VectorSubtract( m_hSpotlightTarget->GetAbsOrigin(), m_hSpotlightTarget->m_vSpotlightOrg, m_hSpotlightTarget->m_vSpotlightDir );
  416. float flBeamLength = VectorNormalize( m_hSpotlightTarget->m_vSpotlightDir );
  417. m_flSpotlightCurLength = (0.60*m_flSpotlightCurLength) + (0.4*flBeamLength);
  418. ComputeRenderInfo();
  419. //NDebugOverlay::Cross3D(GetAbsOrigin(),Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
  420. //NDebugOverlay::Cross3D(m_vSpotlightCurrentPos,Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
  421. //NDebugOverlay::Cross3D(m_vSpotlightTargetPos,Vector(-5,-5,-5),Vector(5,5,5),255,0,0,true,0.1);
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose:
  425. //-----------------------------------------------------------------------------
  426. void CPointSpotlight::InputLightOn( inputdata_t &inputdata )
  427. {
  428. if ( !m_bSpotlightOn )
  429. {
  430. m_bSpotlightOn = true;
  431. if ( m_bEfficientSpotlight )
  432. {
  433. CreateEfficientSpotlight();
  434. }
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose:
  439. //-----------------------------------------------------------------------------
  440. void CPointSpotlight::InputLightOff( inputdata_t &inputdata )
  441. {
  442. if ( m_bSpotlightOn )
  443. {
  444. m_bSpotlightOn = false;
  445. if ( m_bEfficientSpotlight )
  446. {
  447. SpotlightDestroy();
  448. }
  449. }
  450. }