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.

312 lines
8.4 KiB

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