utils.lua 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. --- Various utility functions
  2. -- @module utils
  3. local modules = (...): gsub('%.[^%.]+$', '') .. "."
  4. local vec2 = require(modules .. "vec2")
  5. local vec3 = require(modules .. "vec3")
  6. local sqrt = math.sqrt
  7. local abs = math.abs
  8. local ceil = math.ceil
  9. local floor = math.floor
  10. local log = math.log
  11. local utils = {}
  12. -- reimplementation of math.frexp, due to its removal from Lua 5.3 :(
  13. -- courtesy of airstruck
  14. local log2 = log(2)
  15. local frexp = math.frexp or function(x)
  16. if x == 0 then return 0, 0 end
  17. local e = floor(log(abs(x)) / log2 + 1)
  18. return x / 2 ^ e, e
  19. end
  20. --- Clamps a value within the specified range.
  21. -- @param value Input value
  22. -- @param min Minimum output value
  23. -- @param max Maximum output value
  24. -- @return number
  25. function utils.clamp(value, min, max)
  26. return math.max(math.min(value, max), min)
  27. end
  28. --- Returns `value` if it is equal or greater than |`size`|, or 0.
  29. -- @param value
  30. -- @param size
  31. -- @return number
  32. function utils.deadzone(value, size)
  33. return abs(value) >= size and value or 0
  34. end
  35. --- Check if value is equal or greater than threshold.
  36. -- @param value
  37. -- @param threshold
  38. -- @return boolean
  39. function utils.threshold(value, threshold)
  40. -- I know, it barely saves any typing at all.
  41. return abs(value) >= threshold
  42. end
  43. --- Check if value is equal or less than threshold.
  44. -- @param value
  45. -- @param threshold
  46. -- @return boolean
  47. function utils.tolerance(value, threshold)
  48. -- I know, it barely saves any typing at all.
  49. return abs(value) <= threshold
  50. end
  51. --- Scales a value from one range to another.
  52. -- @param value Input value
  53. -- @param min_in Minimum input value
  54. -- @param max_in Maximum input value
  55. -- @param min_out Minimum output value
  56. -- @param max_out Maximum output value
  57. -- @return number
  58. function utils.map(value, min_in, max_in, min_out, max_out)
  59. return ((value) - (min_in)) * ((max_out) - (min_out)) / ((max_in) - (min_in)) + (min_out)
  60. end
  61. --- Linear interpolation.
  62. -- Performs linear interpolation between 0 and 1 when `low` < `progress` < `high`.
  63. -- @param low value to return when `progress` is 0
  64. -- @param high value to return when `progress` is 1
  65. -- @param progress (0-1)
  66. -- @return number
  67. function utils.lerp(low, high, progress)
  68. return low * (1 - progress) + high * progress
  69. end
  70. --- Exponential decay
  71. -- @param low initial value
  72. -- @param high target value
  73. -- @param rate portion of the original value remaining per second
  74. -- @param dt time delta
  75. -- @return number
  76. function utils.decay(low, high, rate, dt)
  77. return utils.lerp(low, high, 1.0 - math.exp(-rate * dt))
  78. end
  79. --- Hermite interpolation.
  80. -- Performs smooth Hermite interpolation between 0 and 1 when `low` < `progress` < `high`.
  81. -- @param progress (0-1)
  82. -- @param low value to return when `progress` is 0
  83. -- @param high value to return when `progress` is 1
  84. -- @return number
  85. function utils.smoothstep(progress, low, high)
  86. local t = utils.clamp((progress - low) / (high - low), 0.0, 1.0)
  87. return t * t * (3.0 - 2.0 * t)
  88. end
  89. --- Round number at a given precision.
  90. -- Truncates `value` at `precision` points after the decimal (whole number if
  91. -- left unspecified).
  92. -- @param value
  93. -- @param precision
  94. -- @return number
  95. function utils.round(value, precision)
  96. if precision then return utils.round(value / precision) * precision end
  97. return value >= 0 and floor(value+0.5) or ceil(value-0.5)
  98. end
  99. --- Wrap `value` around if it exceeds `limit`.
  100. -- @param value
  101. -- @param limit
  102. -- @return number
  103. function utils.wrap(value, limit)
  104. if value < 0 then
  105. value = value + utils.round(((-value/limit)+1))*limit
  106. end
  107. return value % limit
  108. end
  109. --- Check if a value is a power-of-two.
  110. -- Returns true if a number is a valid power-of-two, otherwise false.
  111. -- @author undef
  112. -- @param value
  113. -- @return boolean
  114. function utils.is_pot(value)
  115. -- found here: https://love2d.org/forums/viewtopic.php?p=182219#p182219
  116. -- check if a number is a power-of-two
  117. return (frexp(value)) == 0.5
  118. end
  119. -- Originally from vec3
  120. function utils.project_on(a, b)
  121. local s =
  122. (a.x * b.x + a.y * b.y + a.z or 0 * b.z or 0) /
  123. (b.x * b.x + b.y * b.y + b.z or 0 * b.z or 0)
  124. if a.z and b.z then
  125. return vec3(
  126. b.x * s,
  127. b.y * s,
  128. b.z * s
  129. )
  130. end
  131. return vec2(
  132. b.x * s,
  133. b.y * s
  134. )
  135. end
  136. -- Originally from vec3
  137. function utils.project_from(a, b)
  138. local s =
  139. (b.x * b.x + b.y * b.y + b.z or 0 * b.z or 0) /
  140. (a.x * b.x + a.y * b.y + a.z or 0 * b.z or 0)
  141. if a.z and b.z then
  142. return vec3(
  143. b.x * s,
  144. b.y * s,
  145. b.z * s
  146. )
  147. end
  148. return vec2(
  149. b.x * s,
  150. b.y * s
  151. )
  152. end
  153. -- Originally from vec3
  154. function utils.mirror_on(a, b)
  155. local s =
  156. (a.x * b.x + a.y * b.y + a.z or 0 * b.z or 0) /
  157. (b.x * b.x + b.y * b.y + b.z or 0 * b.z or 0) * 2
  158. if a.z and b.z then
  159. return vec3(
  160. b.x * s - a.x,
  161. b.y * s - a.y,
  162. b.z * s - a.z
  163. )
  164. end
  165. return vec2(
  166. b.x * s - a.x,
  167. b.y * s - a.y
  168. )
  169. end
  170. -- Originally from vec3
  171. function utils.reflect(i, n)
  172. return i - (n * (2 * n:dot(i)))
  173. end
  174. -- Originally from vec3
  175. function utils.refract(i, n, ior)
  176. local d = n:dot(i)
  177. local k = 1 - ior * ior * (1 - d * d)
  178. if k >= 0 then
  179. return (i * ior) - (n * (ior * d + sqrt(k)))
  180. end
  181. return vec3()
  182. end
  183. return utils