extended.odin 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. package linalg
  2. import "base:builtin"
  3. import "core:math"
  4. @(require_results)
  5. to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  6. when IS_ARRAY(T) {
  7. for i in 0..<len(T) {
  8. out[i] = degrees[i] * RAD_PER_DEG
  9. }
  10. } else {
  11. out = degrees * RAD_PER_DEG
  12. }
  13. return
  14. }
  15. @(require_results)
  16. to_degrees :: proc "contextless" (radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  17. when IS_ARRAY(T) {
  18. for i in 0..<len(T) {
  19. out[i] = radians[i] * DEG_PER_RAD
  20. }
  21. } else {
  22. out = radians * DEG_PER_RAD
  23. }
  24. return
  25. }
  26. @(require_results)
  27. min_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  28. when IS_ARRAY(T) {
  29. for i in 0..<len(T) {
  30. out[i] = builtin.min(a[i], b[i])
  31. }
  32. } else {
  33. out = builtin.min(a, b)
  34. }
  35. return
  36. }
  37. @(require_results)
  38. min_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
  39. when IS_ARRAY(T) {
  40. N :: len(T)
  41. when N == 1 {
  42. out = a[0]
  43. } else when N == 2 {
  44. out = builtin.min(a[0], a[1])
  45. } else {
  46. out = builtin.min(a[0], a[1])
  47. for i in 2..<N {
  48. out = builtin.min(out, a[i])
  49. }
  50. }
  51. } else {
  52. out = a
  53. }
  54. return
  55. }
  56. @(require_results)
  57. min_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
  58. return min_double(a, min_double(b, c))
  59. }
  60. min :: proc{min_single, min_double, min_triple}
  61. @(require_results)
  62. max_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  63. when IS_ARRAY(T) {
  64. for i in 0..<len(T) {
  65. out[i] = builtin.max(a[i], b[i])
  66. }
  67. } else {
  68. out = builtin.max(a, b)
  69. }
  70. return
  71. }
  72. @(require_results)
  73. max_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
  74. when IS_ARRAY(T) {
  75. N :: len(T)
  76. when N == 1 {
  77. out = a[0]
  78. } else when N == 2 {
  79. out = builtin.max(a[0], a[1])
  80. } else when N == 3 {
  81. out = builtin.max(a[0], a[1], a[2])
  82. }else {
  83. out = builtin.max(a[0], a[1])
  84. for i in 2..<N {
  85. out = builtin.max(out, a[i])
  86. }
  87. }
  88. } else {
  89. out = a
  90. }
  91. return
  92. }
  93. @(require_results)
  94. max_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
  95. return max_double(a, max_double(b, c))
  96. }
  97. max :: proc{max_single, max_double, max_triple}
  98. @(require_results)
  99. abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  100. when IS_ARRAY(T) {
  101. for i in 0..<len(T) {
  102. out[i] = auto_cast builtin.abs(a[i])
  103. }
  104. } else {
  105. out = auto_cast builtin.abs(a)
  106. }
  107. return
  108. }
  109. @(require_results)
  110. sign :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  111. when IS_ARRAY(T) {
  112. for i in 0..<len(T) {
  113. out[i] = #force_inline math.sign(a[i])
  114. }
  115. } else {
  116. out = #force_inline math.sign(a)
  117. }
  118. return
  119. }
  120. @(require_results)
  121. clamp :: proc "contextless" (x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
  122. when IS_ARRAY(T) {
  123. for i in 0..<len(T) {
  124. out[i] = builtin.clamp(x[i], a[i], b[i])
  125. }
  126. } else {
  127. out = builtin.clamp(x, a, b)
  128. }
  129. return
  130. }
  131. @(require_results)
  132. saturate :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  133. return clamp(x, 0.0, 1.0)
  134. }
  135. @(require_results)
  136. lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  137. when IS_ARRAY(T) {
  138. for i in 0..<len(T) {
  139. out[i] = a[i]*(1-t[i]) + b[i]*t[i]
  140. }
  141. } else {
  142. out = a * (1.0 - t) + b * t
  143. }
  144. return
  145. }
  146. @(require_results)
  147. mix :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  148. when IS_ARRAY(T) {
  149. for i in 0..<len(T) {
  150. out[i] = a[i]*(1-t[i]) + b[i]*t[i]
  151. }
  152. } else {
  153. out = a * (1.0 - t) + b * t
  154. }
  155. return
  156. }
  157. @(require_results)
  158. unlerp :: proc "contextless" (a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  159. return (x - a) / (b - a)
  160. }
  161. @(require_results)
  162. step :: proc "contextless" (e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  163. when IS_ARRAY(T) {
  164. for i in 0..<len(T) {
  165. out[i] = x[i] < e[i] ? 0.0 : 1.0
  166. }
  167. } else {
  168. out = x < e ? 0.0 : 1.0
  169. }
  170. return
  171. }
  172. @(require_results)
  173. smoothstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  174. t := saturate(unlerp(e0, e1, x))
  175. return t * t * (3.0 - 2.0 * t)
  176. }
  177. @(require_results)
  178. smootherstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  179. t := saturate(unlerp(e0, e1, x))
  180. return t * t * t * (t * (6*t - 15) + 10)
  181. }
  182. @(require_results)
  183. sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  184. when IS_ARRAY(T) {
  185. for i in 0..<len(T) {
  186. out[i] = math.sqrt(x[i])
  187. }
  188. } else {
  189. out = math.sqrt(x)
  190. }
  191. return
  192. }
  193. @(require_results)
  194. inverse_sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  195. when IS_ARRAY(T) {
  196. for i in 0..<len(T) {
  197. out[i] = 1.0/math.sqrt(x[i])
  198. }
  199. } else {
  200. out = 1.0/math.sqrt(x)
  201. }
  202. return
  203. }
  204. @(require_results)
  205. cos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  206. when IS_ARRAY(T) {
  207. for i in 0..<len(T) {
  208. out[i] = math.cos(x[i])
  209. }
  210. } else {
  211. out = math.cos(x)
  212. }
  213. return
  214. }
  215. @(require_results)
  216. sin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  217. when IS_ARRAY(T) {
  218. for i in 0..<len(T) {
  219. out[i] = math.sin(x[i])
  220. }
  221. } else {
  222. out = math.sin(x)
  223. }
  224. return
  225. }
  226. @(require_results)
  227. tan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  228. when IS_ARRAY(T) {
  229. for i in 0..<len(T) {
  230. out[i] = math.tan(x[i])
  231. }
  232. } else {
  233. out = math.tan(x)
  234. }
  235. return
  236. }
  237. @(require_results)
  238. acos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  239. when IS_ARRAY(T) {
  240. for i in 0..<len(T) {
  241. out[i] = math.acos(x[i])
  242. }
  243. } else {
  244. out = math.acos(x)
  245. }
  246. return
  247. }
  248. @(require_results)
  249. asin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  250. when IS_ARRAY(T) {
  251. for i in 0..<len(T) {
  252. out[i] = math.asin(x[i])
  253. }
  254. } else {
  255. out = math.asin(x)
  256. }
  257. return
  258. }
  259. @(require_results)
  260. atan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  261. when IS_ARRAY(T) {
  262. for i in 0..<len(T) {
  263. out[i] = math.atan(x[i])
  264. }
  265. } else {
  266. out = math.atan(x)
  267. }
  268. return
  269. }
  270. @(require_results)
  271. atan2 :: proc "contextless" (y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  272. when IS_ARRAY(T) {
  273. for i in 0..<len(T) {
  274. out[i] = math.atan2(y[i], x[i])
  275. }
  276. } else {
  277. out = math.atan2(y, x)
  278. }
  279. return
  280. }
  281. @(require_results)
  282. ln :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  283. when IS_ARRAY(T) {
  284. for i in 0..<len(T) {
  285. out[i] = math.ln(x[i])
  286. }
  287. } else {
  288. out = math.ln(x)
  289. }
  290. return
  291. }
  292. @(require_results)
  293. log2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  294. INVLN2 :: 1.4426950408889634073599246810018921374266459541529859341354494069
  295. when IS_ARRAY(T) {
  296. for i in 0..<len(T) {
  297. out[i] = INVLN2 * math.ln(x[i])
  298. }
  299. } else {
  300. out = INVLN2 * math.ln(x)
  301. }
  302. return
  303. }
  304. @(require_results)
  305. log10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  306. INVLN10 :: 0.4342944819032518276511289189166050822943970058036665661144537831
  307. when IS_ARRAY(T) {
  308. for i in 0..<len(T) {
  309. out[i] = INVLN10 * math.ln(x[i])
  310. }
  311. } else {
  312. out = INVLN10 * math.ln(x)
  313. }
  314. return
  315. }
  316. @(require_results)
  317. log :: proc "contextless" (x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  318. when IS_ARRAY(T) {
  319. for i in 0..<len(T) {
  320. out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i])
  321. }
  322. } else {
  323. out = math.ln(x) / math.ln(cast(ELEM_TYPE(T))b)
  324. }
  325. return
  326. }
  327. @(require_results)
  328. exp :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  329. when IS_ARRAY(T) {
  330. for i in 0..<len(T) {
  331. out[i] = math.exp(x[i])
  332. }
  333. } else {
  334. out = math.exp(x)
  335. }
  336. return
  337. }
  338. @(require_results)
  339. exp2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  340. when IS_ARRAY(T) {
  341. for i in 0..<len(T) {
  342. out[i] = math.exp(LN2 * x[i])
  343. }
  344. } else {
  345. out = math.exp(LN2 * x)
  346. }
  347. return
  348. }
  349. @(require_results)
  350. exp10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  351. when IS_ARRAY(T) {
  352. for i in 0..<len(T) {
  353. out[i] = math.exp(LN10 * x[i])
  354. }
  355. } else {
  356. out = math.exp(LN10 * x)
  357. }
  358. return
  359. }
  360. @(require_results)
  361. pow :: proc "contextless" (x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  362. when IS_ARRAY(T) {
  363. for i in 0..<len(T) {
  364. out[i] = math.pow(x[i], e[i])
  365. }
  366. } else {
  367. out = math.pow(x, e)
  368. }
  369. return
  370. }
  371. @(require_results)
  372. ceil :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  373. when IS_ARRAY(T) {
  374. for i in 0..<len(T) {
  375. out[i] = #force_inline math.ceil(x[i])
  376. }
  377. } else {
  378. out = #force_inline math.ceil(x)
  379. }
  380. return
  381. }
  382. @(require_results)
  383. floor :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  384. when IS_ARRAY(T) {
  385. for i in 0..<len(T) {
  386. out[i] = #force_inline math.floor(x[i])
  387. }
  388. } else {
  389. out = #force_inline math.floor(x)
  390. }
  391. return
  392. }
  393. @(require_results)
  394. round :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
  395. when IS_ARRAY(T) {
  396. for i in 0..<len(T) {
  397. out[i] = #force_inline math.round(x[i])
  398. }
  399. } else {
  400. out = #force_inline math.round(x)
  401. }
  402. return
  403. }
  404. @(require_results)
  405. fract :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  406. f := #force_inline floor(x)
  407. return x - f
  408. }
  409. @(require_results)
  410. mod :: proc "contextless" (x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
  411. f := #force_inline floor(x / m)
  412. return x - f * m
  413. }
  414. @(require_results)
  415. face_forward :: proc "contextless" (N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
  416. return dot(N_ref, I) < 0 ? N : -N
  417. }
  418. @(require_results)
  419. distance :: proc "contextless" (p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
  420. return length(p1 - p0)
  421. }
  422. @(require_results)
  423. reflect :: proc "contextless" (I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
  424. b := N * (2 * dot(N, I))
  425. return I - b
  426. }
  427. @(require_results)
  428. refract :: proc "contextless" (I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) {
  429. dv := dot(Normal, I)
  430. k := 1 - eta*eta * (1 - dv*dv)
  431. a := I * eta
  432. b := Normal * (eta*dv+math.sqrt(k))
  433. return (a - b) * E(int(k >= 0))
  434. }
  435. @(require_results)
  436. is_nan_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
  437. return #force_inline math.is_nan(x)
  438. }
  439. @(require_results)
  440. is_nan_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
  441. for i in 0..<N {
  442. out[i] = #force_inline is_nan(x[i])
  443. }
  444. return
  445. }
  446. @(require_results)
  447. is_inf_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
  448. return #force_inline math.is_inf(x)
  449. }
  450. @(require_results)
  451. is_inf_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
  452. for i in 0..<N {
  453. out[i] = #force_inline is_inf(x[i])
  454. }
  455. return
  456. }
  457. @(require_results)
  458. classify_single :: proc "contextless" (x: $T) -> math.Float_Class where IS_FLOAT(T) {
  459. return #force_inline math.classify(x)
  460. }
  461. @(require_results)
  462. classify_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
  463. for i in 0..<N {
  464. out[i] = #force_inline classify_single(x[i])
  465. }
  466. return
  467. }
  468. is_nan :: proc{is_nan_single, is_nan_array}
  469. is_inf :: proc{is_inf_single, is_inf_array}
  470. classify :: proc{classify_single, classify_array}
  471. @(require_results) less_than_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y }
  472. @(require_results) less_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y }
  473. @(require_results) greater_than_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y }
  474. @(require_results) greater_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y }
  475. @(require_results) equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y }
  476. @(require_results) not_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y }
  477. @(require_results)
  478. less_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  479. for i in 0..<N {
  480. out[i] = x[i] < y[i]
  481. }
  482. return
  483. }
  484. @(require_results)
  485. less_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  486. for i in 0..<N {
  487. out[i] = x[i] <= y[i]
  488. }
  489. return
  490. }
  491. @(require_results)
  492. greater_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  493. for i in 0..<N {
  494. out[i] = x[i] > y[i]
  495. }
  496. return
  497. }
  498. @(require_results)
  499. greater_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  500. for i in 0..<N {
  501. out[i] = x[i] >= y[i]
  502. }
  503. return
  504. }
  505. @(require_results)
  506. equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  507. for i in 0..<N {
  508. out[i] = x[i] == y[i]
  509. }
  510. return
  511. }
  512. @(require_results)
  513. not_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
  514. for i in 0..<N {
  515. out[i] = x[i] != y[i]
  516. }
  517. return
  518. }
  519. less_than :: proc{less_than_single, less_than_array}
  520. less_than_equal :: proc{less_than_equal_single, less_than_equal_array}
  521. greater_than :: proc{greater_than_single, greater_than_array}
  522. greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array}
  523. equal :: proc{equal_single, equal_array}
  524. not_equal :: proc{not_equal_single, not_equal_array}
  525. @(require_results)
  526. any :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
  527. for e in x {
  528. if e {
  529. return true
  530. }
  531. }
  532. return false
  533. }
  534. @(require_results)
  535. all :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
  536. for e in x {
  537. if !e {
  538. return false
  539. }
  540. }
  541. return true
  542. }
  543. @(require_results)
  544. not :: proc "contextless" (x: $A/[$N]bool) -> (out: A) {
  545. for e, i in x {
  546. out[i] = !e
  547. }
  548. return
  549. }