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.

355 lines
9.3 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <ssemath.h>
  7. #include <lightdesc.h>
  8. #include "mathlib.h"
  9. // NOTE: This has to be the last file included!
  10. #include "tier0/memdbgon.h"
  11. void LightDesc_t::RecalculateOneOverThetaDotMinusPhiDot()
  12. {
  13. float flSpread = m_ThetaDot - m_PhiDot;
  14. if ( flSpread > 1.0e-10f )
  15. {
  16. // note - this quantity is very sensitive to round off error. the sse
  17. // reciprocal approximation won't cut it here.
  18. m_OneOverThetaDotMinusPhiDot = 1.0f / flSpread;
  19. }
  20. else
  21. {
  22. // hard falloff instead of divide by zero
  23. m_OneOverThetaDotMinusPhiDot = 1.0f;
  24. }
  25. }
  26. void LightDesc_t::RecalculateDerivedValues(void)
  27. {
  28. m_Flags = LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED;
  29. if ( m_Attenuation0 )
  30. {
  31. m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0;
  32. }
  33. if ( m_Attenuation1 )
  34. {
  35. m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1;
  36. }
  37. if ( m_Attenuation2 )
  38. {
  39. m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2;
  40. }
  41. if ( m_Type == MATERIAL_LIGHT_SPOT )
  42. {
  43. m_ThetaDot = cos( m_Theta );
  44. m_PhiDot = cos( m_Phi );
  45. RecalculateOneOverThetaDotMinusPhiDot();
  46. }
  47. if ( m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  48. {
  49. // set position to be real far away in the right direction
  50. m_Position = m_Direction;
  51. m_Position *= 2.0e6;
  52. }
  53. m_RangeSquared = m_Range*m_Range;
  54. }
  55. void LightDesc_t::ComputeLightAtPointsForDirectional(
  56. const FourVectors &pos, const FourVectors &normal,
  57. FourVectors &color, bool DoHalfLambert ) const
  58. {
  59. FourVectors delta;
  60. delta.DuplicateVector(m_Direction);
  61. // delta.VectorNormalizeFast();
  62. fltx4 strength=delta*normal;
  63. if (DoHalfLambert)
  64. {
  65. strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives);
  66. }
  67. else
  68. strength=MaxSIMD(Four_Zeros,delta*normal);
  69. color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
  70. color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
  71. color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
  72. }
  73. float LightDesc_t::DistanceAtWhichBrightnessIsLessThan( float flAmount ) const
  74. {
  75. float bright = m_Color.Length();
  76. if ( bright > 0.0 )
  77. {
  78. flAmount /= m_Color.Length();
  79. // calculate terms for quadratic equation
  80. float a = flAmount * m_Attenuation2;
  81. float b = flAmount * m_Attenuation1;
  82. float c = flAmount * m_Attenuation0 - 1;
  83. float r0, r1;
  84. if ( SolveQuadratic( a, b, c, r0, r1 ) )
  85. {
  86. float rslt = MAX( 0, MAX( r0, r1 ) );
  87. #ifdef _DEBUG
  88. if ( rslt > 0.0 )
  89. {
  90. float fltest = 1.0 / ( m_Attenuation0 + rslt * m_Attenuation1 + rslt * rslt * m_Attenuation2 );
  91. Assert( fabs( fltest - flAmount ) < 0.1 );
  92. }
  93. #endif
  94. return rslt;
  95. }
  96. }
  97. return 0;
  98. }
  99. void LightDesc_t::ComputeLightAtPoints( const FourVectors &pos, const FourVectors &normal,
  100. FourVectors &color, bool DoHalfLambert ) const
  101. {
  102. FourVectors delta;
  103. Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL));
  104. switch (m_Type)
  105. {
  106. case MATERIAL_LIGHT_POINT:
  107. case MATERIAL_LIGHT_SPOT:
  108. delta.DuplicateVector(m_Position);
  109. delta-=pos;
  110. break;
  111. case MATERIAL_LIGHT_DIRECTIONAL:
  112. ComputeLightAtPointsForDirectional( pos, normal, color, DoHalfLambert );
  113. return;
  114. }
  115. fltx4 dist2 = delta*delta;
  116. dist2=MaxSIMD( Four_Ones, dist2 );
  117. fltx4 falloff;
  118. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
  119. {
  120. falloff = ReplicateX4(m_Attenuation0);
  121. }
  122. else
  123. falloff= Four_Epsilons;
  124. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
  125. {
  126. falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2)));
  127. }
  128. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
  129. {
  130. falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2));
  131. }
  132. falloff=ReciprocalEstSIMD(falloff);
  133. // Cull out light beyond this radius
  134. // now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format
  135. if (m_Range != 0.f)
  136. {
  137. fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
  138. falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared));
  139. }
  140. delta.VectorNormalizeFast();
  141. fltx4 strength=delta*normal;
  142. if (DoHalfLambert)
  143. {
  144. strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives);
  145. }
  146. else
  147. strength=MaxSIMD(Four_Zeros,delta*normal);
  148. switch(m_Type)
  149. {
  150. case MATERIAL_LIGHT_POINT:
  151. // half-lambert
  152. break;
  153. case MATERIAL_LIGHT_SPOT:
  154. {
  155. fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
  156. fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(m_OneOverThetaDotMinusPhiDot),
  157. SubSIMD(dot2,ReplicateX4(m_PhiDot)));
  158. cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones);
  159. if ((m_Falloff!=0.0) && (m_Falloff!=1.0))
  160. {
  161. // !!speed!! could compute integer exponent needed by powsimd and store in light
  162. cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff);
  163. }
  164. strength=MulSIMD(cone_falloff_scale,strength);
  165. // now, zero out lighting where dot2<phidot. This will mask out any invalid results
  166. // from pow function, etc
  167. bi32x4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
  168. strength=AndSIMD(OutsideMask,strength);
  169. }
  170. break;
  171. }
  172. strength=MulSIMD(strength,falloff);
  173. color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
  174. color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
  175. color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
  176. }
  177. void LightDesc_t::ComputeNonincidenceLightAtPoints( const FourVectors &pos, FourVectors &color ) const
  178. {
  179. FourVectors delta;
  180. Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL));
  181. switch (m_Type)
  182. {
  183. case MATERIAL_LIGHT_POINT:
  184. case MATERIAL_LIGHT_SPOT:
  185. delta.DuplicateVector(m_Position);
  186. delta-=pos;
  187. break;
  188. case MATERIAL_LIGHT_DIRECTIONAL:
  189. return;
  190. }
  191. fltx4 dist2 = delta*delta;
  192. dist2=MaxSIMD( Four_Ones, dist2 );
  193. fltx4 falloff;
  194. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
  195. {
  196. falloff = ReplicateX4(m_Attenuation0);
  197. }
  198. else
  199. falloff= Four_Epsilons;
  200. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
  201. {
  202. falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2)));
  203. }
  204. if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
  205. {
  206. falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2));
  207. }
  208. falloff=ReciprocalEstSIMD(falloff);
  209. // Cull out light beyond this radius
  210. // now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format
  211. if (m_Range != 0.f)
  212. {
  213. fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
  214. falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared));
  215. }
  216. delta.VectorNormalizeFast();
  217. fltx4 strength = Four_Ones;
  218. //fltx4 strength=delta;
  219. //fltx4 strength = MaxSIMD(Four_Zeros,delta);
  220. switch(m_Type)
  221. {
  222. case MATERIAL_LIGHT_POINT:
  223. // half-lambert
  224. break;
  225. case MATERIAL_LIGHT_SPOT:
  226. {
  227. fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
  228. fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(m_OneOverThetaDotMinusPhiDot),
  229. SubSIMD(dot2,ReplicateX4(m_PhiDot)));
  230. cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones);
  231. if ((m_Falloff!=0.0) && (m_Falloff!=1.0))
  232. {
  233. // !!speed!! could compute integer exponent needed by powsimd and store in light
  234. cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff);
  235. }
  236. strength=MulSIMD(cone_falloff_scale,strength);
  237. // now, zero out lighting where dot2<phidot. This will mask out any invalid results
  238. // from pow function, etc
  239. bi32x4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
  240. strength=AndSIMD(OutsideMask,strength);
  241. }
  242. break;
  243. }
  244. strength=MulSIMD(strength,falloff);
  245. color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
  246. color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
  247. color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
  248. }
  249. void LightDesc_t::SetupOldStyleAttenuation( float fQuadraticAttn, float fLinearAttn, float fConstantAttn )
  250. {
  251. // old-style manually typed quadrtiac coefficients
  252. if ( fQuadraticAttn < EQUAL_EPSILON )
  253. fQuadraticAttn = 0;
  254. if ( fLinearAttn < EQUAL_EPSILON)
  255. fLinearAttn = 0;
  256. if ( fConstantAttn < EQUAL_EPSILON)
  257. fConstantAttn = 0;
  258. if ( ( fConstantAttn < EQUAL_EPSILON ) &&
  259. ( fLinearAttn < EQUAL_EPSILON ) &&
  260. ( fQuadraticAttn < EQUAL_EPSILON ) )
  261. fConstantAttn = 1;
  262. m_Attenuation2=fQuadraticAttn;
  263. m_Attenuation1=fLinearAttn;
  264. m_Attenuation0=fConstantAttn;
  265. float fScaleFactor = fQuadraticAttn * 10000 + fLinearAttn * 100 + fConstantAttn;
  266. if ( fScaleFactor > 0 )
  267. m_Color *= fScaleFactor;
  268. }
  269. void LightDesc_t::SetupNewStyleAttenuation( float fFiftyPercentDistance,
  270. float fZeroPercentDistance )
  271. {
  272. // new style storing 50% and 0% distances
  273. float d50=fFiftyPercentDistance;
  274. float d0=fZeroPercentDistance;
  275. if (d0<d50)
  276. {
  277. // !!warning in lib code???!!!
  278. Warning("light has _fifty_percent_distance of %f but no zero_percent_distance\n",d50);
  279. d0=2.0*d50;
  280. }
  281. float a=0,b=1,c=0;
  282. if (! SolveInverseQuadraticMonotonic(0,1.0,d50,2.0,d0,256.0,a,b,c))
  283. {
  284. Warning("can't solve quadratic for light %f %f\n",d50,d0);
  285. }
  286. float v50=c+d50*(b+d50*a);
  287. float scale=2.0/v50;
  288. a*=scale;
  289. b*=scale;
  290. c*=scale;
  291. m_Attenuation2=a;
  292. m_Attenuation1=b;
  293. m_Attenuation0=c;
  294. }