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.

241 lines
6.4 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "physics.h"
  10. #include "te_effect_dispatch.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. static int BestAxisMatchingNormal( matrix3x4_t &matrix, const Vector &normal )
  14. {
  15. float bestDot = -1;
  16. int best = 0;
  17. for ( int i = 0; i < 3; i++ )
  18. {
  19. Vector tmp;
  20. MatrixGetColumn( matrix, i, tmp );
  21. float dot = fabs(DotProduct( tmp, normal ));
  22. if ( dot > bestDot )
  23. {
  24. bestDot = dot;
  25. best = i;
  26. }
  27. }
  28. return best;
  29. }
  30. void PhysicsSplash( IPhysicsFluidController *pFluid, IPhysicsObject *pObject, CBaseEntity *pEntity )
  31. {
  32. Vector normal;
  33. float dist;
  34. pFluid->GetSurfacePlane( &normal, &dist );
  35. matrix3x4_t &matrix = pEntity->EntityToWorldTransform();
  36. // Find the local axis that best matches the water surface normal
  37. int bestAxis = BestAxisMatchingNormal( matrix, normal );
  38. Vector tangent, binormal;
  39. MatrixGetColumn( matrix, (bestAxis+1)%3, tangent );
  40. binormal = CrossProduct( normal, tangent );
  41. VectorNormalize( binormal );
  42. tangent = CrossProduct( binormal, normal );
  43. VectorNormalize( tangent );
  44. // Now we have a basis tangent to the surface that matches the object's local orientation as well as possible
  45. // compute an OBB using this basis
  46. // Get object extents in basis
  47. Vector tanPts[2], binPts[2];
  48. tanPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -tangent );
  49. tanPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), tangent );
  50. binPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -binormal );
  51. binPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), binormal );
  52. // now compute the centered bbox
  53. float mins[2], maxs[2], center[2], extents[2];
  54. mins[0] = DotProduct( tanPts[0], tangent );
  55. maxs[0] = DotProduct( tanPts[1], tangent );
  56. mins[1] = DotProduct( binPts[0], binormal );
  57. maxs[1] = DotProduct( binPts[1], binormal );
  58. center[0] = 0.5 * (mins[0] + maxs[0]);
  59. center[1] = 0.5 * (mins[1] + maxs[1]);
  60. extents[0] = maxs[0] - center[0];
  61. extents[1] = maxs[1] - center[1];
  62. Vector centerPoint = center[0] * tangent + center[1] * binormal + dist * normal;
  63. Vector axes[2];
  64. axes[0] = (maxs[0] - center[0]) * tangent;
  65. axes[1] = (maxs[1] - center[1]) * binormal;
  66. // visualize OBB hit
  67. /*
  68. Vector corner1 = centerPoint - axes[0] - axes[1];
  69. Vector corner2 = centerPoint + axes[0] - axes[1];
  70. Vector corner3 = centerPoint + axes[0] + axes[1];
  71. Vector corner4 = centerPoint - axes[0] + axes[1];
  72. NDebugOverlay::Line( corner1, corner2, 0, 0, 255, false, 10 );
  73. NDebugOverlay::Line( corner2, corner3, 0, 0, 255, false, 10 );
  74. NDebugOverlay::Line( corner3, corner4, 0, 0, 255, false, 10 );
  75. NDebugOverlay::Line( corner4, corner1, 0, 0, 255, false, 10 );
  76. */
  77. Vector corner[4];
  78. corner[0] = centerPoint - axes[0] - axes[1];
  79. corner[1] = centerPoint + axes[0] - axes[1];
  80. corner[2] = centerPoint + axes[0] + axes[1];
  81. corner[3] = centerPoint - axes[0] + axes[1];
  82. CEffectData data;
  83. if ( pObject->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL )
  84. {
  85. /*
  86. data.m_vOrigin = centerPoint;
  87. data.m_vNormal = normal;
  88. VectorAngles( normal, data.m_vAngles );
  89. data.m_flScale = random->RandomFloat( 8, 10 );
  90. DispatchEffect( "watersplash", data );
  91. int splashes = 4;
  92. Vector point;
  93. for ( int i = 0; i < splashes; i++ )
  94. {
  95. point = RandomVector( -32.0f, 32.0f );
  96. point[2] = 0.0f;
  97. point += corner[i];
  98. data.m_vOrigin = point;
  99. data.m_vNormal = normal;
  100. VectorAngles( normal, data.m_vAngles );
  101. data.m_flScale = random->RandomFloat( 4, 6 );
  102. DispatchEffect( "watersplash", data );
  103. }
  104. */
  105. //FIXME: This code will not work correctly given how the ragdoll/fluid collision is acting currently
  106. return;
  107. }
  108. Vector vel;
  109. pObject->GetVelocity( &vel, NULL );
  110. float rawSpeed = -DotProduct( normal, vel );
  111. // proportional to cross-sectional area times velocity squared (fluid pressure)
  112. float speed = rawSpeed * rawSpeed * extents[0] * extents[1] * (1.0f / 2500000.0f) * pObject->GetMass() * (0.01f);
  113. speed = clamp( speed, 0, 50 );
  114. bool bRippleOnly = false;
  115. // allow the entity to perform a custom splash effect
  116. if ( pEntity->PhysicsSplash( centerPoint, normal, rawSpeed, speed ) )
  117. return;
  118. //Deny really weak hits
  119. //FIXME: We still need to ripple the surface in this case
  120. if ( speed <= 0.35f )
  121. {
  122. if ( speed <= 0.1f )
  123. return;
  124. bRippleOnly = true;
  125. }
  126. #ifdef PORTAL2
  127. float size = RemapVal( speed, 0.35, 50, 2, 14 );
  128. #else
  129. float size = RemapVal( speed, 0.35, 50, 8, 18 );
  130. #endif
  131. //Find the surface area
  132. float radius = extents[0] * extents[1];
  133. //int splashes = clamp ( radius / 128.0f, 1, 2 ); //One splash for every three square feet of area
  134. //Msg( "Speed: %.2f, Size: %.2f\n, Radius: %.2f, Splashes: %d", speed, size, radius, splashes );
  135. Vector point;
  136. data.m_fFlags = 0;
  137. data.m_vOrigin = centerPoint;
  138. data.m_vNormal = normal;
  139. VectorAngles( normal, data.m_vAngles );
  140. data.m_flScale = size + random->RandomFloat( 0, 2 );
  141. if ( pEntity->GetWaterType() & CONTENTS_SLIME )
  142. {
  143. data.m_fFlags |= FX_WATER_IN_SLIME;
  144. }
  145. if ( bRippleOnly )
  146. {
  147. DispatchEffect( "waterripple", data );
  148. }
  149. else
  150. {
  151. DispatchEffect( "watersplash", data );
  152. }
  153. if ( radius > 500.0f )
  154. {
  155. int splashes = random->RandomInt( 1, 4 );
  156. for ( int i = 0; i < splashes; i++ )
  157. {
  158. point = RandomVector( -4.0f, 4.0f );
  159. point[2] = 0.0f;
  160. point += corner[i];
  161. data.m_fFlags = 0;
  162. data.m_vOrigin = point;
  163. data.m_vNormal = normal;
  164. VectorAngles( normal, data.m_vAngles );
  165. data.m_flScale = size + random->RandomFloat( -3, 1 );
  166. if ( pEntity->GetWaterType() & CONTENTS_SLIME )
  167. {
  168. data.m_fFlags |= FX_WATER_IN_SLIME;
  169. }
  170. if ( bRippleOnly )
  171. {
  172. DispatchEffect( "waterripple", data );
  173. }
  174. else
  175. {
  176. DispatchEffect( "watersplash", data );
  177. }
  178. }
  179. }
  180. /*
  181. for ( i = 0; i < splashes; i++ )
  182. {
  183. point = RandomVector( -8.0f, 8.0f );
  184. point[2] = 0.0f;
  185. point += centerPoint + axes[0] * random->RandomFloat( -1, 1 ) + axes[1] * random->RandomFloat( -1, 1 );
  186. data.m_vOrigin = point;
  187. data.m_vNormal = normal;
  188. VectorAngles( normal, data.m_vAngles );
  189. data.m_flScale = size + random->RandomFloat( -2, 4 );
  190. DispatchEffect( "watersplash", data );
  191. }
  192. */
  193. }