Counter Strike : Global Offensive Source Code
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.

532 lines
16 KiB

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