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.

354 lines
8.5 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "simple_physics.h"
  9. #include "mathlib/vmatrix.h"
  10. #include "beamdraw.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. class C_Hairball : public C_BaseEntity
  14. {
  15. DECLARE_CLASS( C_Hairball, C_BaseEntity );
  16. private:
  17. class CHairballDelegate : public CSimplePhysics::IHelper
  18. {
  19. public:
  20. virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel );
  21. virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes );
  22. C_Hairball *m_pParent;
  23. };
  24. public:
  25. C_Hairball();
  26. void Init();
  27. // IClientThinkable.
  28. public:
  29. virtual void ClientThink();
  30. // IClientRenderable.
  31. public:
  32. virtual int DrawModel( int flags, const RenderableInstance_t &instance );
  33. virtual RenderableTranslucencyType_t ComputeTranslucencyType();
  34. public:
  35. float m_flSphereRadius;
  36. int m_nHairs;
  37. int m_nNodesPerHair;
  38. float m_flSpringDist; // = hair length / (m_nNodesPerHair-1)
  39. CUtlVector<CSimplePhysics::CNode> m_Nodes; // This is m_nHairs * m_nNodesPerHair large.
  40. CUtlVector<Vector> m_HairPositions; // Untransformed base hair positions, distributed on the sphere.
  41. CUtlVector<Vector> m_TransformedHairPositions; // Transformed base hair positions, distributed on the sphere.
  42. CHairballDelegate m_Delegate;
  43. CSimplePhysics m_Physics;
  44. IMaterial *m_pMaterial;
  45. // Super sophisticated AI.
  46. float m_flSitStillTime;
  47. Vector m_vMoveDir;
  48. float m_flSpinDuration;
  49. float m_flCurSpinTime;
  50. float m_flSpinRateX, m_flSpinRateY;
  51. bool m_bFirstThink;
  52. };
  53. void C_Hairball::CHairballDelegate::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel )
  54. {
  55. pAccel->Init( 0, 0, -1500 );
  56. }
  57. void C_Hairball::CHairballDelegate::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes )
  58. {
  59. int nSegments = m_pParent->m_nNodesPerHair - 1;
  60. float flSpringDistSqr = m_pParent->m_flSpringDist * m_pParent->m_flSpringDist;
  61. static int nIterations = 1;
  62. for( int iIteration=0; iIteration < nIterations; iIteration++ )
  63. {
  64. for ( int iHair=0; iHair < m_pParent->m_nHairs; iHair++ )
  65. {
  66. CSimplePhysics::CNode *pBase = &pNodes[iHair * m_pParent->m_nNodesPerHair];
  67. for( int i=0; i < nSegments; i++ )
  68. {
  69. Vector &vNode1 = pBase[i].m_vPos;
  70. Vector &vNode2 = pBase[i+1].m_vPos;
  71. Vector vTo = vNode1 - vNode2;
  72. float flDistSqr = vTo.LengthSqr();
  73. if( flDistSqr > flSpringDistSqr )
  74. {
  75. float flDist = (float)sqrt( flDistSqr );
  76. vTo *= 1 - (m_pParent->m_flSpringDist / flDist);
  77. vNode1 -= vTo * 0.5f;
  78. vNode2 += vTo * 0.5f;
  79. }
  80. }
  81. // Lock the base of each hair to the right spot.
  82. pBase->m_vPos = m_pParent->m_TransformedHairPositions[iHair];
  83. }
  84. }
  85. }
  86. C_Hairball::C_Hairball()
  87. {
  88. m_nHairs = 100;
  89. m_nNodesPerHair = 3;
  90. float flHairLength = 20;
  91. m_flSpringDist = flHairLength / (m_nNodesPerHair - 1);
  92. m_Nodes.SetSize( m_nHairs * m_nNodesPerHair );
  93. m_HairPositions.SetSize( m_nHairs );
  94. m_TransformedHairPositions.SetSize( m_nHairs );
  95. m_flSphereRadius = 20;
  96. m_vMoveDir.Init();
  97. m_flSpinDuration = 1;
  98. m_flCurSpinTime = 0;
  99. m_flSpinRateX = m_flSpinRateY = 0;
  100. // Distribute on the sphere (need a better random distribution for the sphere).
  101. for ( int i=0; i < m_HairPositions.Count(); i++ )
  102. {
  103. float theta = RandomFloat( -M_PI, M_PI );
  104. float phi = RandomFloat( -M_PI/2, M_PI/2 );
  105. float cosPhi = cos( phi );
  106. m_HairPositions[i].Init(
  107. cos(theta) * cosPhi * m_flSphereRadius,
  108. sin(theta) * cosPhi * m_flSphereRadius,
  109. sin(phi) * m_flSphereRadius );
  110. }
  111. m_Delegate.m_pParent = this;
  112. m_Physics.Init( 1.0 / 20 ); // NOTE: PLAY WITH THIS FOR EFFICIENCY
  113. m_pMaterial = NULL;
  114. m_bFirstThink = true;
  115. }
  116. void C_Hairball::Init()
  117. {
  118. ClientEntityList().AddNonNetworkableEntity( this );
  119. ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
  120. AddToLeafSystem( false );
  121. m_pMaterial = materials->FindMaterial( "cable/cable", TEXTURE_GROUP_OTHER );
  122. m_flSitStillTime = 5;
  123. }
  124. void C_Hairball::ClientThink()
  125. {
  126. // Do some AI-type stuff.. move the entity around.
  127. //C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  128. //m_vecAngles = SetAbsAngles( pPlayer->GetAbsAngles() ); // copy player angles.
  129. Assert( !GetMoveParent() );
  130. // Sophisticated AI.
  131. m_flCurSpinTime += gpGlobals->frametime;
  132. if ( m_flCurSpinTime < m_flSpinDuration )
  133. {
  134. float div = m_flCurSpinTime / m_flSpinDuration;
  135. QAngle angles = GetLocalAngles();
  136. angles.x += m_flSpinRateX * SmoothCurve( div );
  137. angles.y += m_flSpinRateY * SmoothCurve( div );
  138. SetLocalAngles( angles );
  139. }
  140. else
  141. {
  142. // Flip between stopped and starting.
  143. if ( fabs( m_flSpinRateX ) > 0.01f )
  144. {
  145. m_flSpinRateX = m_flSpinRateY = 0;
  146. m_flSpinDuration = RandomFloat( 1, 2 );
  147. }
  148. else
  149. {
  150. static float flXSpeed = 3;
  151. static float flYSpeed = flXSpeed * 0.1f;
  152. m_flSpinRateX = RandomFloat( -M_PI*flXSpeed, M_PI*flXSpeed );
  153. m_flSpinRateY = RandomFloat( -M_PI*flYSpeed, M_PI*flYSpeed );
  154. m_flSpinDuration = RandomFloat( 1, 4 );
  155. }
  156. m_flCurSpinTime = 0;
  157. }
  158. if ( m_flSitStillTime > 0 )
  159. {
  160. m_flSitStillTime -= gpGlobals->frametime;
  161. if ( m_flSitStillTime <= 0 )
  162. {
  163. // Shoot out some random lines and find the longest one.
  164. m_vMoveDir.Init( 1, 0, 0 );
  165. float flLongestFraction = 0;
  166. for ( int i=0; i < 15; i++ )
  167. {
  168. Vector vDir( RandomFloat( -1, 1 ), RandomFloat( -1, 1 ), RandomFloat( -1, 1 ) );
  169. VectorNormalize( vDir );
  170. trace_t trace;
  171. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vDir * 10000, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &trace );
  172. if ( trace.fraction != 1.0 )
  173. {
  174. if ( trace.fraction > flLongestFraction )
  175. {
  176. flLongestFraction = trace.fraction;
  177. m_vMoveDir = vDir;
  178. }
  179. }
  180. }
  181. m_vMoveDir *= 650; // set speed.
  182. m_flSitStillTime = -1; // Move in this direction..
  183. }
  184. }
  185. else
  186. {
  187. // Move in the specified direction.
  188. Vector vEnd = GetAbsOrigin() + m_vMoveDir * gpGlobals->frametime;
  189. trace_t trace;
  190. UTIL_TraceLine( GetAbsOrigin(), vEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &trace );
  191. if ( trace.fraction < 1 )
  192. {
  193. // Ok, stop moving.
  194. m_flSitStillTime = RandomFloat( 1, 3 );
  195. }
  196. else
  197. {
  198. SetLocalOrigin( GetLocalOrigin() + m_vMoveDir * gpGlobals->frametime );
  199. }
  200. }
  201. // Transform the base hair positions so we can lock them down.
  202. VMatrix mTransform;
  203. mTransform.SetupMatrixOrgAngles( GetLocalOrigin(), GetLocalAngles() );
  204. for ( int i=0; i < m_HairPositions.Count(); i++ )
  205. {
  206. Vector3DMultiplyPosition( mTransform, m_HairPositions[i], m_TransformedHairPositions[i] );
  207. }
  208. if ( m_bFirstThink )
  209. {
  210. m_bFirstThink = false;
  211. for ( int i=0; i < m_HairPositions.Count(); i++ )
  212. {
  213. for ( int j=0; j < m_nNodesPerHair; j++ )
  214. {
  215. m_Nodes[i*m_nNodesPerHair+j].Init( m_TransformedHairPositions[i] );
  216. }
  217. }
  218. }
  219. // Simulate the physics and apply constraints.
  220. m_Physics.Simulate( m_Nodes.Base(), m_Nodes.Count(), &m_Delegate, gpGlobals->frametime, 0.98 );
  221. }
  222. RenderableTranslucencyType_t C_Hairball::ComputeTranslucencyType()
  223. {
  224. return ( m_pMaterial && m_pMaterial->IsTranslucent() ) ? RENDERABLE_IS_TRANSLUCENT : RENDERABLE_IS_OPAQUE;
  225. }
  226. int C_Hairball::DrawModel( int flags, const RenderableInstance_t &instance )
  227. {
  228. if ( !m_pMaterial )
  229. return 0;
  230. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  231. for ( int iHair=0; iHair < m_nHairs; iHair++ )
  232. {
  233. CSimplePhysics::CNode *pBase = &m_Nodes[iHair * m_nNodesPerHair];
  234. CBeamSegDraw beamDraw;
  235. beamDraw.Start( pRenderContext, m_nNodesPerHair-1, m_pMaterial );
  236. for ( int i=0; i < m_nNodesPerHair; i++ )
  237. {
  238. BeamSeg_t seg;
  239. seg.m_vPos = pBase[i].m_vPredicted;
  240. seg.m_color.r = seg.m_color.g = seg.m_color.b = seg.m_color.a = 0;
  241. seg.m_flTexCoord = 0;
  242. static float flHairWidth = 1;
  243. seg.m_flWidth = flHairWidth;
  244. beamDraw.NextSeg( &seg );
  245. }
  246. beamDraw.End();
  247. }
  248. return 1;
  249. }
  250. void CreateHairballCallback()
  251. {
  252. for ( int i=0; i < 20; i++ )
  253. {
  254. C_Hairball *pHairball = new C_Hairball;
  255. pHairball->Init();
  256. // Put it a short distance in front of the player.
  257. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  258. if ( !pPlayer )
  259. return;
  260. Vector vForward;
  261. AngleVectors( pPlayer->GetAbsAngles(), &vForward );
  262. pHairball->SetLocalOrigin( pPlayer->GetAbsOrigin() + vForward * 300 + RandomVector( 0, 100 ) );
  263. }
  264. }
  265. ConCommand cc_CreateHairball( "CreateHairball", CreateHairballCallback, 0, FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT );