math.c (26113B)
1 /* See LICENSE for license details. */ 2 #include "external/cephes.c" 3 4 function void 5 fill_kronecker_sub_matrix_f16(f16 *out, i32 out_stride, f16 scale, const f16 *b, iv2 b_dim) 6 { 7 for (i32 i = 0; i < b_dim.y; i++) { 8 for (i32 j = 0; j < b_dim.x; j += 4, b += 4) { 9 out[j + 0] = scale * b[0]; 10 out[j + 1] = scale * b[1]; 11 out[j + 2] = scale * b[2]; 12 out[j + 3] = scale * b[3]; 13 } 14 out += out_stride; 15 } 16 } 17 18 /* NOTE: this won't check for valid space/etc and assumes row major order */ 19 function void 20 kronecker_product_f16(f16 *out, const f16 *a, iv2 a_dim, const f16 *b, iv2 b_dim) 21 { 22 iv2 out_dim = {{a_dim.x * b_dim.x, a_dim.y * b_dim.y}}; 23 assert(out_dim.y % 4 == 0); 24 for (i32 i = 0; i < a_dim.y; i++) { 25 f16 *vout = out; 26 for (i32 j = 0; j < a_dim.x; j++, a++) { 27 fill_kronecker_sub_matrix_f16(vout, out_dim.y, *a, b, b_dim); 28 vout += b_dim.y; 29 } 30 out += out_dim.y * b_dim.x; 31 } 32 } 33 34 /* NOTE/TODO: to support even more hadamard sizes use the Paley construction */ 35 function f16 * 36 make_hadamard_transpose(Arena *arena, i32 dim, b32 row_major) 37 { 38 read_only f16 hadamard_12_12_transpose[] = { 39 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 41 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 42 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 43 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 44 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 45 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 46 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 47 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 48 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 49 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 50 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 51 }; 52 53 read_only f16 hadamard_20_20_transpose[] = { 54 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 55 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 56 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 57 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 58 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 59 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 60 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 61 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 62 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 63 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 64 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 65 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 66 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 67 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 68 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 69 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 70 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 71 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 72 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 73 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 74 }; 75 76 f16 *result = 0; 77 78 i32 order = dim; 79 b32 power_of_2 = IsPowerOfTwo(dim); 80 b32 multiple_of_12 = dim % 12 == 0; 81 b32 multiple_of_20 = dim % 20 == 0; 82 i64 elements = dim * dim; 83 84 i32 base_dim = 0; 85 if (power_of_2) { 86 base_dim = dim; 87 } else if (multiple_of_20 && IsPowerOfTwo(dim / 20)) { 88 base_dim = 20; 89 dim /= 20; 90 } else if (multiple_of_12 && IsPowerOfTwo(dim / 12)) { 91 base_dim = 12; 92 dim /= 12; 93 } 94 95 if (power_of_2 && base_dim) { 96 result = push_array(arena, f16, elements); 97 98 Temp scratch = temp_begin(arena); 99 f16 *m = dim == base_dim ? result : push_array(arena, f16, elements); 100 101 #define IND(i, j) ((i) * dim + (j)) 102 m[0] = 1; 103 for (i32 k = 1; k < dim; k *= 2) { 104 for (i32 i = 0; i < k; i++) { 105 for (i32 j = 0; j < k; j++) { 106 f16 val = m[IND(i, j)]; 107 m[IND(i + k, j)] = val; 108 m[IND(i, j + k)] = val; 109 m[IND(i + k, j + k)] = -val; 110 } 111 } 112 } 113 #undef IND 114 115 const f16 *m2 = 0; 116 iv2 m2_dim; 117 switch (base_dim) { 118 case 12:{ m2 = hadamard_12_12_transpose; m2_dim = (iv2){{12, 12}}; }break; 119 case 20:{ m2 = hadamard_20_20_transpose; m2_dim = (iv2){{20, 20}}; }break; 120 } 121 if (m2) kronecker_product_f16(result, m, (iv2){{dim, dim}}, m2, m2_dim); 122 123 temp_end(scratch); 124 } 125 126 if (result && row_major) { 127 for (i32 r = 0; r < order; r++) 128 for (i32 c = 0; c < order; c++) 129 swap(result[r * order + c], result[c * order + r]); 130 } 131 132 return result; 133 } 134 135 function u32 136 ceil_div_u32(u32 a, u32 b) 137 { 138 u32 result = ((u64)a + b - 1) / b; 139 return result; 140 } 141 142 function b32 143 u128_equal(u128 a, u128 b) 144 { 145 b32 result = a.U64[0] == b.U64[0] && a.U64[1] == b.U64[1]; 146 return result; 147 } 148 149 function RangeU64 150 subrange_n_from_n_m_count(u64 n, u64 n_count, u64 m) 151 { 152 assert(n < n_count); 153 154 u64 per_lane = m / n_count; 155 u64 leftover = m - per_lane * n_count; 156 u64 leftovers_before_n = Min(leftover, n); 157 u64 base_index = n * per_lane + leftovers_before_n; 158 u64 one_past_last_index = base_index + per_lane + ((n < leftover) ? 1 : 0); 159 160 RangeU64 result = {base_index, one_past_last_index}; 161 return result; 162 } 163 164 function i32 165 iv3_dimension(iv3 points) 166 { 167 i32 result = (points.x > 1) + (points.y > 1) + (points.z > 1); 168 return result; 169 } 170 171 function bv3 172 iv3_equal(iv3 a, iv3 b) 173 { 174 bv3 result; 175 result.x = a.x == b.x; 176 result.y = a.y == b.y; 177 result.z = a.z == b.z; 178 return result; 179 } 180 181 function b32 182 bv3_all(bv3 a) 183 { 184 b32 result = a.x != 0 && a.y != 0 && a.z != 0; 185 return result; 186 } 187 188 function b32 189 bv3_any(bv3 a) 190 { 191 b32 result = a.x != 0 || a.y != 0 || a.z != 0; 192 return result; 193 } 194 195 function v2 196 clamp_v2_rect(v2 v, Rect r) 197 { 198 v2 result = v; 199 result.x = Clamp(v.x, r.pos.x, r.pos.x + r.size.x); 200 result.y = Clamp(v.y, r.pos.y, r.pos.y + r.size.y); 201 return result; 202 } 203 204 function v2 205 v2_from_iv2(iv2 v) 206 { 207 v2 result; 208 result.E[0] = (f32)v.E[0]; 209 result.E[1] = (f32)v.E[1]; 210 return result; 211 } 212 213 function v2 214 v2_abs(v2 a) 215 { 216 v2 result; 217 result.x = Abs(a.x); 218 result.y = Abs(a.y); 219 return result; 220 } 221 222 function v2 223 v2_scale(v2 a, f32 scale) 224 { 225 v2 result; 226 result.x = a.x * scale; 227 result.y = a.y * scale; 228 return result; 229 } 230 231 function v2 232 v2_add(v2 a, v2 b) 233 { 234 v2 result; 235 result.x = a.x + b.x; 236 result.y = a.y + b.y; 237 return result; 238 } 239 240 function v2 241 v2_sub(v2 a, v2 b) 242 { 243 v2 result = v2_add(a, v2_scale(b, -1.0f)); 244 return result; 245 } 246 247 function v2 248 v2_mul(v2 a, v2 b) 249 { 250 v2 result; 251 result.x = a.x * b.x; 252 result.y = a.y * b.y; 253 return result; 254 } 255 256 function v2 257 v2_div(v2 a, v2 b) 258 { 259 v2 result; 260 result.x = a.x / b.x; 261 result.y = a.y / b.y; 262 return result; 263 } 264 265 function v2 266 v2_floor(v2 a) 267 { 268 v2 result; 269 result.x = (f32)((i32)a.x); 270 result.y = (f32)((i32)a.y); 271 return result; 272 } 273 274 function f32 275 v2_magnitude_squared(v2 a) 276 { 277 f32 result = a.x * a.x + a.y * a.y; 278 return result; 279 } 280 281 function f32 282 v2_magnitude(v2 a) 283 { 284 f32 result = sqrt_f32(a.x * a.x + a.y * a.y); 285 return result; 286 } 287 288 function v3 289 cross(v3 a, v3 b) 290 { 291 v3 result; 292 result.x = a.y * b.z - a.z * b.y; 293 result.y = a.z * b.x - a.x * b.z; 294 result.z = a.x * b.y - a.y * b.x; 295 return result; 296 } 297 298 function v3 299 v3_from_iv3(iv3 v) 300 { 301 v3 result; 302 result.E[0] = (f32)v.E[0]; 303 result.E[1] = (f32)v.E[1]; 304 result.E[2] = (f32)v.E[2]; 305 return result; 306 } 307 308 function v3 309 v3_abs(v3 a) 310 { 311 v3 result; 312 result.x = Abs(a.x); 313 result.y = Abs(a.y); 314 result.z = Abs(a.z); 315 return result; 316 } 317 318 function v3 319 v3_scale(v3 a, f32 scale) 320 { 321 v3 result; 322 result.x = scale * a.x; 323 result.y = scale * a.y; 324 result.z = scale * a.z; 325 return result; 326 } 327 328 function v3 329 v3_add(v3 a, v3 b) 330 { 331 v3 result; 332 result.x = a.x + b.x; 333 result.y = a.y + b.y; 334 result.z = a.z + b.z; 335 return result; 336 } 337 338 function v3 339 v3_sub(v3 a, v3 b) 340 { 341 v3 result = v3_add(a, v3_scale(b, -1.0f)); 342 return result; 343 } 344 345 function v3 346 v3_div(v3 a, v3 b) 347 { 348 v3 result; 349 result.x = a.x / b.x; 350 result.y = a.y / b.y; 351 result.z = a.z / b.z; 352 return result; 353 } 354 355 function f32 356 v3_dot(v3 a, v3 b) 357 { 358 f32 result = a.x * b.x + a.y * b.y + a.z * b.z; 359 return result; 360 } 361 362 function f32 363 v3_magnitude_squared(v3 a) 364 { 365 f32 result = v3_dot(a, a); 366 return result; 367 } 368 369 function f32 370 v3_magnitude(v3 a) 371 { 372 f32 result = sqrt_f32(v3_dot(a, a)); 373 return result; 374 } 375 376 function v3 377 v3_normalize(v3 a) 378 { 379 v3 result = v3_scale(a, 1.0f / v3_magnitude(a)); 380 return result; 381 } 382 383 function v4 384 v4_scale(v4 a, f32 scale) 385 { 386 v4 result; 387 result.x = scale * a.x; 388 result.y = scale * a.y; 389 result.z = scale * a.z; 390 result.w = scale * a.w; 391 return result; 392 } 393 394 function v4 395 v4_add(v4 a, v4 b) 396 { 397 v4 result; 398 result.x = a.x + b.x; 399 result.y = a.y + b.y; 400 result.z = a.z + b.z; 401 result.w = a.w + b.w; 402 return result; 403 } 404 405 function v4 406 v4_sub(v4 a, v4 b) 407 { 408 v4 result = v4_add(a, v4_scale(b, -1)); 409 return result; 410 } 411 412 function f32 413 v4_dot(v4 a, v4 b) 414 { 415 f32 result = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; 416 return result; 417 } 418 419 function v4 420 v4_lerp(v4 a, v4 b, f32 t) 421 { 422 v4 result = v4_add(a, v4_scale(v4_sub(b, a), t)); 423 return result; 424 } 425 426 function b32 427 m4_equal(m4 a, m4 b) 428 { 429 b32 result = 1; 430 #ifdef __AVX512F__ 431 __m512 one = _mm512_set1_ps(1.f); 432 __m512 eps = _mm512_set1_ps(F32_EPSILON); 433 __m512 av = _mm512_loadu_ps(&a); 434 __m512 bv = _mm512_loadu_ps(&b); 435 __m512 delta = _mm512_abs_ps(_mm512_sub_ps(av, bv)); 436 __m512 test = _mm512_mul_ps(eps, _mm512_max_ps(one, _mm512_max_ps(_mm512_abs_ps(av), _mm512_abs_ps(bv)))); 437 result = _mm512_cmp_ps_mask(delta, test, _CMP_GT_OS) == 0; 438 #else 439 for EachElement(a.E, it) 440 result &= f32_equal(a.E[it], b.E[it]); 441 #endif 442 return result; 443 } 444 445 #define m4_identity() \ 446 (m4){.E = { \ 447 1, 0, 0, 0, \ 448 0, 1, 0, 0, \ 449 0, 0, 1, 0, \ 450 0, 0, 0, 1, \ 451 }} 452 453 function v4 454 m4_row(m4 a, u32 row) 455 { 456 v4 result; 457 result.E[0] = a.c[0].E[row]; 458 result.E[1] = a.c[1].E[row]; 459 result.E[2] = a.c[2].E[row]; 460 result.E[3] = a.c[3].E[row]; 461 return result; 462 } 463 464 function m4 465 m4_mul(m4 a, m4 b) 466 { 467 m4 result; 468 for (u32 i = 0; i < 4; i++) { 469 for (u32 j = 0; j < 4; j++) { 470 result.c[i].E[j] = v4_dot(m4_row(a, j), b.c[i]); 471 } 472 } 473 return result; 474 } 475 476 /* NOTE(rnp): based on: 477 * https://web.archive.org/web/20131215123403/ftp://download.intel.com/design/PentiumIII/sml/24504301.pdf 478 * TODO(rnp): redo with SIMD as given in the link (but need to rewrite for column-major) 479 */ 480 function m4 481 m4_inverse(m4 m) 482 { 483 m4 result; 484 result.E[ 0] = m.E[5] * m.E[10] * m.E[15] - m.E[5] * m.E[11] * m.E[14] - m.E[9] * m.E[6] * m.E[15] + m.E[9] * m.E[7] * m.E[14] + m.E[13] * m.E[6] * m.E[11] - m.E[13] * m.E[7] * m.E[10]; 485 result.E[ 4] = -m.E[4] * m.E[10] * m.E[15] + m.E[4] * m.E[11] * m.E[14] + m.E[8] * m.E[6] * m.E[15] - m.E[8] * m.E[7] * m.E[14] - m.E[12] * m.E[6] * m.E[11] + m.E[12] * m.E[7] * m.E[10]; 486 result.E[ 8] = m.E[4] * m.E[ 9] * m.E[15] - m.E[4] * m.E[11] * m.E[13] - m.E[8] * m.E[5] * m.E[15] + m.E[8] * m.E[7] * m.E[13] + m.E[12] * m.E[5] * m.E[11] - m.E[12] * m.E[7] * m.E[ 9]; 487 result.E[12] = -m.E[4] * m.E[ 9] * m.E[14] + m.E[4] * m.E[10] * m.E[13] + m.E[8] * m.E[5] * m.E[14] - m.E[8] * m.E[6] * m.E[13] - m.E[12] * m.E[5] * m.E[10] + m.E[12] * m.E[6] * m.E[ 9]; 488 result.E[ 1] = -m.E[1] * m.E[10] * m.E[15] + m.E[1] * m.E[11] * m.E[14] + m.E[9] * m.E[2] * m.E[15] - m.E[9] * m.E[3] * m.E[14] - m.E[13] * m.E[2] * m.E[11] + m.E[13] * m.E[3] * m.E[10]; 489 result.E[ 5] = m.E[0] * m.E[10] * m.E[15] - m.E[0] * m.E[11] * m.E[14] - m.E[8] * m.E[2] * m.E[15] + m.E[8] * m.E[3] * m.E[14] + m.E[12] * m.E[2] * m.E[11] - m.E[12] * m.E[3] * m.E[10]; 490 result.E[ 9] = -m.E[0] * m.E[ 9] * m.E[15] + m.E[0] * m.E[11] * m.E[13] + m.E[8] * m.E[1] * m.E[15] - m.E[8] * m.E[3] * m.E[13] - m.E[12] * m.E[1] * m.E[11] + m.E[12] * m.E[3] * m.E[ 9]; 491 result.E[13] = m.E[0] * m.E[ 9] * m.E[14] - m.E[0] * m.E[10] * m.E[13] - m.E[8] * m.E[1] * m.E[14] + m.E[8] * m.E[2] * m.E[13] + m.E[12] * m.E[1] * m.E[10] - m.E[12] * m.E[2] * m.E[ 9]; 492 result.E[ 2] = m.E[1] * m.E[ 6] * m.E[15] - m.E[1] * m.E[ 7] * m.E[14] - m.E[5] * m.E[2] * m.E[15] + m.E[5] * m.E[3] * m.E[14] + m.E[13] * m.E[2] * m.E[ 7] - m.E[13] * m.E[3] * m.E[ 6]; 493 result.E[ 6] = -m.E[0] * m.E[ 6] * m.E[15] + m.E[0] * m.E[ 7] * m.E[14] + m.E[4] * m.E[2] * m.E[15] - m.E[4] * m.E[3] * m.E[14] - m.E[12] * m.E[2] * m.E[ 7] + m.E[12] * m.E[3] * m.E[ 6]; 494 result.E[10] = m.E[0] * m.E[ 5] * m.E[15] - m.E[0] * m.E[ 7] * m.E[13] - m.E[4] * m.E[1] * m.E[15] + m.E[4] * m.E[3] * m.E[13] + m.E[12] * m.E[1] * m.E[ 7] - m.E[12] * m.E[3] * m.E[ 5]; 495 result.E[14] = -m.E[0] * m.E[ 5] * m.E[14] + m.E[0] * m.E[ 6] * m.E[13] + m.E[4] * m.E[1] * m.E[14] - m.E[4] * m.E[2] * m.E[13] - m.E[12] * m.E[1] * m.E[ 6] + m.E[12] * m.E[2] * m.E[ 5]; 496 result.E[ 3] = -m.E[1] * m.E[ 6] * m.E[11] + m.E[1] * m.E[ 7] * m.E[10] + m.E[5] * m.E[2] * m.E[11] - m.E[5] * m.E[3] * m.E[10] - m.E[ 9] * m.E[2] * m.E[ 7] + m.E[ 9] * m.E[3] * m.E[ 6]; 497 result.E[ 7] = m.E[0] * m.E[ 6] * m.E[11] - m.E[0] * m.E[ 7] * m.E[10] - m.E[4] * m.E[2] * m.E[11] + m.E[4] * m.E[3] * m.E[10] + m.E[ 8] * m.E[2] * m.E[ 7] - m.E[ 8] * m.E[3] * m.E[ 6]; 498 result.E[11] = -m.E[0] * m.E[ 5] * m.E[11] + m.E[0] * m.E[ 7] * m.E[ 9] + m.E[4] * m.E[1] * m.E[11] - m.E[4] * m.E[3] * m.E[ 9] - m.E[ 8] * m.E[1] * m.E[ 7] + m.E[ 8] * m.E[3] * m.E[ 5]; 499 result.E[15] = m.E[0] * m.E[ 5] * m.E[10] - m.E[0] * m.E[ 6] * m.E[ 9] - m.E[4] * m.E[1] * m.E[10] + m.E[4] * m.E[2] * m.E[ 9] + m.E[ 8] * m.E[1] * m.E[ 6] - m.E[ 8] * m.E[2] * m.E[ 5]; 500 501 f32 determinant = m.E[0] * result.E[0] + m.E[1] * result.E[4] + m.E[2] * result.E[8] + m.E[3] * result.E[12]; 502 determinant = 1.0f / determinant; 503 for(i32 i = 0; i < 16; i++) 504 result.E[i] *= determinant; 505 return result; 506 } 507 508 function m4 509 m4_translation(v3 delta) 510 { 511 m4 result; 512 result.c[0] = (v4){{1, 0, 0, 0}}; 513 result.c[1] = (v4){{0, 1, 0, 0}}; 514 result.c[2] = (v4){{0, 0, 1, 0}}; 515 result.c[3] = (v4){{delta.x, delta.y, delta.z, 1}}; 516 return result; 517 } 518 519 function m4 520 m4_scale(v3 scale) 521 { 522 m4 result; 523 result.c[0] = (v4){{scale.x, 0, 0, 0}}; 524 result.c[1] = (v4){{0, scale.y, 0, 0}}; 525 result.c[2] = (v4){{0, 0, scale.z, 0}}; 526 result.c[3] = (v4){{0, 0, 0, 1}}; 527 return result; 528 } 529 530 function m4 531 m4_rotation_about_axis(v3 axis, f32 turns) 532 { 533 assert(f32_equal(v3_magnitude_squared(axis), 1.0f)); 534 f32 sa = sin_f32(turns * 2 * PI); 535 f32 ca = cos_f32(turns * 2 * PI); 536 f32 mca = 1.0f - ca; 537 538 f32 x = axis.x, x2 = x * x; 539 f32 y = axis.y, y2 = y * y; 540 f32 z = axis.z, z2 = z * z; 541 542 m4 result; 543 result.c[0] = (v4){{ca + mca * x2, mca * x * y - sa * z, mca * x * z + sa * y, 0}}; 544 result.c[1] = (v4){{mca * x * y + sa * z, ca + mca * y2, mca * y * z - sa * x, 0}}; 545 result.c[2] = (v4){{mca * x * z - sa * y, mca * y * z + sa * x, ca + mca * z2, 0}}; 546 result.c[3] = (v4){{0, 0, 0, 1}}; 547 return result; 548 } 549 550 function m4 551 m4_rotation_about_y(f32 turns) 552 { 553 m4 result = m4_rotation_about_axis((v3){.y = 1.0f}, turns); 554 return result; 555 } 556 557 function m4 558 y_aligned_volume_transform(v3 extent, v3 translation, f32 rotation_turns) 559 { 560 m4 T = m4_translation(translation); 561 m4 R = m4_rotation_about_axis((v3){.y = 1.0f}, rotation_turns); 562 m4 S = m4_scale(extent); 563 m4 result = m4_mul(T, m4_mul(R, S)); 564 return result; 565 } 566 567 function v4 568 m4_mul_v4(m4 a, v4 v) 569 { 570 v4 result; 571 result.x = v4_dot(m4_row(a, 0), v); 572 result.y = v4_dot(m4_row(a, 1), v); 573 result.z = v4_dot(m4_row(a, 2), v); 574 result.w = v4_dot(m4_row(a, 3), v); 575 return result; 576 } 577 578 function v3 579 m4_mul_v3(m4 a, v3 v) 580 { 581 v3 result = m4_mul_v4(a, (v4){{v.x, v.y, v.z, 1.0f}}).xyz; 582 return result; 583 } 584 585 function v2 586 rect_uv(v2 p, Rect r) 587 { 588 v2 result = v2_div(v2_sub(p, r.pos), r.size); 589 return result; 590 } 591 592 function v2 593 rect_uv_ndc(v2 p, Rect r) 594 { 595 v2 uv = rect_uv(p, r); 596 v2 result = v2_sub(v2_scale(uv, 2.f), (v2){{1.f, 1.f}}); 597 return result; 598 } 599 600 function Rect 601 rect_intersect(Rect a, Rect b) 602 { 603 v2 ae = v2_add(a.pos, a.size); 604 v2 be = v2_add(b.pos, b.size); 605 606 Rect result = {0}; 607 result.pos.x = Max(a.pos.x, b.pos.x); 608 result.pos.y = Max(a.pos.y, b.pos.y); 609 result.size.x = Min(ae.x, be.x) - result.pos.x; 610 result.size.y = Min(ae.y, be.y) - result.pos.y; 611 return result; 612 } 613 614 function Rect 615 rect_squish_centered(Rect a, v2 pct) 616 { 617 v2 delta_size = v2_mul(a.size, pct); 618 Rect result; 619 result.pos = v2_add(a.pos, v2_scale(delta_size, 0.5f)); 620 result.size = v2_add(a.size, v2_scale(delta_size, -1.f)); 621 return result; 622 } 623 624 function Rect 625 rect_shrink_centered(Rect a, v2 px) 626 { 627 Rect result; 628 result.pos = v2_add(a.pos, v2_scale(px, 0.5f)); 629 result.size = v2_add(a.size, v2_scale(px, -1.f)); 630 return result; 631 } 632 633 function m4 634 orthographic_projection(f32 n, f32 f, f32 t, f32 r) 635 { 636 m4 result; 637 f32 a = -2 / (f - n); 638 f32 b = - (f + n) / (f - n); 639 result.c[0] = (v4){{1 / r, 0, 0, 0}}; 640 result.c[1] = (v4){{0, 1 / t, 0, 0}}; 641 result.c[2] = (v4){{0, 0, a, 0}}; 642 result.c[3] = (v4){{0, 0, b, 1}}; 643 return result; 644 } 645 646 function m4 647 perspective_projection(f32 n, f32 f, f32 fov, f32 aspect) 648 { 649 m4 result; 650 f32 t = n * tan_f32(fov / 2.0f); 651 f32 r = t * aspect; 652 f32 a = -(f + n) / (f - n); 653 f32 b = -2 * f * n / (f - n); 654 result.c[0] = (v4){{n / r, 0, 0, 0}}; 655 result.c[1] = (v4){{0, n / t, 0, 0}}; 656 result.c[2] = (v4){{0, 0, a, -1}}; 657 result.c[3] = (v4){{0, 0, b, 0}}; 658 return result; 659 } 660 661 function m4 662 camera_look_at(v3 camera, v3 point) 663 { 664 v3 orthogonal = {{0, 1.0f, 0}}; 665 v3 normal = v3_normalize(v3_sub(camera, point)); 666 v3 right = cross(orthogonal, normal); 667 v3 up = cross(normal, right); 668 669 v3 translate; 670 camera = v3_sub((v3){0}, camera); 671 translate.x = v3_dot(camera, right); 672 translate.y = v3_dot(camera, up); 673 translate.z = v3_dot(camera, normal); 674 675 m4 result; 676 result.c[0] = (v4){{right.x, up.x, normal.x, 0}}; 677 result.c[1] = (v4){{right.y, up.y, normal.y, 0}}; 678 result.c[2] = (v4){{right.z, up.z, normal.z, 0}}; 679 result.c[3] = (v4){{translate.x, translate.y, translate.z, 1}}; 680 return result; 681 } 682 683 /* NOTE(rnp): adapted from "Essential Mathematics for Games and Interactive Applications" (Verth, Bishop) */ 684 function f32 685 obb_raycast(m4 obb_orientation, v3 obb_size, v3 obb_center, ray r) 686 { 687 v3 p = v3_sub(obb_center, r.origin); 688 v3 X = obb_orientation.c[0].xyz; 689 v3 Y = obb_orientation.c[1].xyz; 690 v3 Z = obb_orientation.c[2].xyz; 691 692 /* NOTE(rnp): projects direction vector onto OBB axis */ 693 v3 f; 694 f.x = v3_dot(X, r.direction); 695 f.y = v3_dot(Y, r.direction); 696 f.z = v3_dot(Z, r.direction); 697 698 /* NOTE(rnp): projects relative vector onto OBB axis */ 699 v3 e; 700 e.x = v3_dot(X, p); 701 e.y = v3_dot(Y, p); 702 e.z = v3_dot(Z, p); 703 704 f32 result = 0; 705 f32 t[6] = {0}; 706 for (i32 i = 0; i < 3; i++) { 707 if (f32_equal(f.E[i], 0)) { 708 if (-e.E[i] - obb_size.E[i] > 0 || -e.E[i] + obb_size.E[i] < 0) 709 result = -1.0f; 710 f.E[i] = F32_EPSILON; 711 } 712 t[i * 2 + 0] = (e.E[i] + obb_size.E[i]) / f.E[i]; 713 t[i * 2 + 1] = (e.E[i] - obb_size.E[i]) / f.E[i]; 714 } 715 716 if (result != -1) { 717 f32 tmin = Max(Max(Min(t[0], t[1]), Min(t[2], t[3])), Min(t[4], t[5])); 718 f32 tmax = Min(Min(Max(t[0], t[1]), Max(t[2], t[3])), Max(t[4], t[5])); 719 if (tmax >= 0 && tmin <= tmax) { 720 result = tmin > 0 ? tmin : tmax; 721 } else { 722 result = -1; 723 } 724 } 725 726 return result; 727 } 728 729 function f32 730 complex_filter_first_moment(v2 *filter, i32 length, f32 sampling_frequency) 731 { 732 f32 n = 0, d = 0; 733 for (i32 i = 0; i < length; i++) { 734 f32 t = v2_magnitude_squared(filter[i]); 735 n += (f32)i * t; 736 d += t; 737 } 738 f32 result = n / d / sampling_frequency; 739 return result; 740 } 741 742 function f32 743 real_filter_first_moment(f32 *filter, i32 length, f32 sampling_frequency) 744 { 745 f32 n = 0, d = 0; 746 for (i32 i = 0; i < length; i++) { 747 f32 t = filter[i] * filter[i]; 748 n += (f32)i * t; 749 d += t; 750 } 751 f32 result = n / d / sampling_frequency; 752 return result; 753 } 754 755 function f32 756 tukey_window(f32 t, f32 tapering) 757 { 758 f32 r = tapering; 759 f32 result = 1; 760 if (t < r / 2) result = 0.5f * (1 + cos_f32(2 * PI * (t - r / 2) / r)); 761 if (t >= 1 - r / 2) result = 0.5f * (1 + cos_f32(2 * PI * (t - 1 + r / 2) / r)); 762 return result; 763 } 764 765 /* NOTE(rnp): adapted from "Discrete Time Signal Processing" (Oppenheim) */ 766 function f32 * 767 kaiser_low_pass_filter(Arena *arena, f32 cutoff_frequency, f32 sampling_frequency, f32 beta, i32 length) 768 { 769 f32 *result = push_array(arena, f32, length); 770 f32 wc = 2 * PI * cutoff_frequency / sampling_frequency; 771 f32 a = (f32)length / 2.0f; 772 f32 pi_i0_b = PI * (f32)cephes_i0(beta); 773 774 for (i32 n = 0; n < length; n++) { 775 f32 t = (f32)n - a; 776 f32 impulse = !f32_equal(t, 0) ? sin_f32(wc * t) / t : wc; 777 t = t / a; 778 f32 window = (f32)cephes_i0(beta * sqrt_f32(1 - t * t)) / pi_i0_b; 779 result[n] = impulse * window; 780 } 781 782 return result; 783 } 784 785 function f32 * 786 rf_chirp(Arena *arena, f32 min_frequency, f32 max_frequency, f32 sampling_frequency, 787 i32 length, b32 reverse) 788 { 789 f32 *result = push_array(arena, f32, length); 790 for (i32 i = 0; i < length; i++) { 791 i32 index = reverse? length - 1 - i : i; 792 f32 fc = min_frequency + (f32)i * (max_frequency - min_frequency) / (2 * (f32)length); 793 f32 arg = 2 * PI * fc * (f32)i / sampling_frequency; 794 result[index] = sin_f32(arg) * tukey_window((f32)i / (f32)length, 0.2f); 795 } 796 return result; 797 } 798 799 function v2 * 800 baseband_chirp(Arena *arena, f32 min_frequency, f32 max_frequency, f32 sampling_frequency, 801 i32 length, b32 reverse, f32 scale) 802 { 803 v2 *result = push_array(arena, v2, length); 804 f32 conjugate = reverse ? -1 : 1; 805 for (i32 i = 0; i < length; i++) { 806 i32 index = reverse? length - 1 - i : i; 807 f32 fc = min_frequency + (f32)i * (max_frequency - min_frequency) / (2 * (f32)length); 808 f32 arg = 2 * PI * fc * (f32)i / sampling_frequency; 809 v2 sample = {{scale * cos_f32(arg), conjugate * scale * sin_f32(arg)}}; 810 result[index] = v2_scale(sample, tukey_window((f32)i / (f32)length, 0.2f)); 811 } 812 return result; 813 } 814 815 function m4 816 das_transform_1d(v3 p1, v3 p2) 817 { 818 v3 extent = v3_sub(p2, p1); 819 m4 result = { 820 .c[0] = (v4){{extent.x, extent.y, extent.z, 0.0f}}, 821 .c[1] = (v4){{0.0f, 0.0f, 0.0f, 0.0f}}, 822 .c[2] = (v4){{0.0f, 0.0f, 0.0f, 0.0f}}, 823 .c[3] = (v4){{p1.x, p1.y, p1.z, 1.0f}}, 824 }; 825 return result; 826 } 827 828 function m4 829 das_transform_2d_with_normal(v3 normal, v2 min_coordinate, v2 max_coordinate, f32 offset) 830 { 831 v3 U = {{0, 1.0f, 0}}; 832 if (f32_equal(v3_dot(U, normal), 1.0f)) 833 U = (v3){{1.0f, 0, 0}}; 834 835 v3 N = normal; 836 v3 V = cross(U, N); 837 838 v3 min = v3_add(v3_scale(U, min_coordinate.x), v3_scale(V, min_coordinate.y)); 839 v3 max = v3_add(v3_scale(U, max_coordinate.x), v3_scale(V, max_coordinate.y)); 840 841 v3 extent = v3_sub(max, min); 842 U = v3_scale(U, v3_dot(U, extent)); 843 V = v3_scale(V, v3_dot(V, extent)); 844 845 v3 t = v3_add(v3_scale(N, offset), min); 846 847 m4 result; 848 result.c[0] = (v4){{U.x, U.y, U.z, 0.0f}}; 849 result.c[1] = (v4){{V.x, V.y, V.z, 0.0f}}; 850 result.c[2] = (v4){{N.x, N.y, N.z, 0.0f}}; 851 result.c[3] = (v4){{t.x, t.y, t.z, 1.0f}}; 852 853 return result; 854 } 855 856 function m4 857 das_transform_2d_xz(v2 min_coordinate, v2 max_coordinate, f32 y_off) 858 { 859 m4 result = das_transform_2d_with_normal((v3){.y = 1.0f}, min_coordinate, max_coordinate, y_off); 860 return result; 861 } 862 863 function m4 864 das_transform_2d_yz(v2 min_coordinate, v2 max_coordinate, f32 x_off) 865 { 866 // NOTE(rnp): flip so that region extends in correct direction 867 m4 result = das_transform_2d_with_normal((v3){.x = -1.0f}, min_coordinate, max_coordinate, x_off); 868 return result; 869 } 870 871 function m4 872 das_transform_2d_xy(v2 min_coordinate, v2 max_coordinate, f32 z_off) 873 { 874 m4 result = das_transform_2d_with_normal((v3){.z = 1.0f}, min_coordinate, max_coordinate, z_off); 875 return result; 876 } 877 878 function m4 879 das_transform_3d(v3 min_coordinate, v3 max_coordinate) 880 { 881 v3 extent = v3_sub(max_coordinate, min_coordinate); 882 m4 result; 883 result.c[0] = (v4){{extent.x, 0.0f, 0.0f, 0.0f}}; 884 result.c[1] = (v4){{0.0f, extent.y, 0.0f, 0.0f}}; 885 result.c[2] = (v4){{0.0f, 0.0f, extent.z, 0.0f}}; 886 result.c[3] = (v4){{min_coordinate.x, min_coordinate.y, min_coordinate.z, 1.0f}}; 887 return result; 888 } 889 890 function v3 891 plane_normal_from_transform(m4 transform) 892 { 893 v3 U = v3_normalize(transform.c[0].xyz); 894 v3 V = v3_normalize(transform.c[1].xyz); 895 v3 result = cross(V, U); 896 return result; 897 } 898 899 function f32 900 plane_offset_from_transform(m4 transform) 901 { 902 f32 result = v3_dot(plane_normal_from_transform(transform), transform.c[3].xyz); 903 return result; 904 } 905 906 function void 907 plane_corners_from_transform(m4 transform, v2 *min, v2 *max) 908 { 909 v3 U = v3_normalize(transform.c[0].xyz); 910 v3 V = v3_normalize(transform.c[1].xyz); 911 912 v3 min_3d = m4_mul_v3(transform, (v3){{0.f, 0.f, 0.f}}); 913 v3 max_3d = m4_mul_v3(transform, (v3){{1.f, 1.f, 1.f}}); 914 915 if (min) *min = (v2){{v3_dot(U, min_3d), v3_dot(V, min_3d)}}; 916 if (max) *max = (v2){{v3_dot(U, max_3d), v3_dot(V, max_3d)}}; 917 } 918 919 function v2 920 plane_uv(v3 point, v3 U, v3 V) 921 { 922 v2 result; 923 result.x = v3_dot(U, point) / v3_dot(U, U); 924 result.y = v3_dot(V, point) / v3_dot(V, V); 925 return result; 926 } 927 928 function v4 929 hsv_to_rgb(v4 hsv) 930 { 931 /* f(k(n)) = V - V*S*max(0, min(k, min(4 - k, 1))) 932 * k(n) = fmod((n + H * 6), 6) 933 * (R, G, B) = (f(n = 5), f(n = 3), f(n = 1)) 934 */ 935 alignas(16) f32 nval[4] = {5.0f, 3.0f, 1.0f, 0.0f}; 936 f32x4 n = load_f32x4(nval); 937 f32x4 H = dup_f32x4(hsv.x); 938 f32x4 S = dup_f32x4(hsv.y); 939 f32x4 V = dup_f32x4(hsv.z); 940 f32x4 six = dup_f32x4(6); 941 942 f32x4 t = add_f32x4(n, mul_f32x4(six, H)); 943 f32x4 rem = floor_f32x4(div_f32x4(t, six)); 944 f32x4 k = sub_f32x4(t, mul_f32x4(rem, six)); 945 946 t = min_f32x4(sub_f32x4(dup_f32x4(4), k), dup_f32x4(1)); 947 t = max_f32x4(dup_f32x4(0), min_f32x4(k, t)); 948 t = mul_f32x4(t, mul_f32x4(S, V)); 949 950 v4 rgba; 951 store_f32x4(rgba.E, sub_f32x4(V, t)); 952 rgba.a = hsv.a; 953 return rgba; 954 } 955 956 function f32 957 ease_in_out_cubic(f32 t) 958 { 959 f32 result; 960 if (t < 0.5f) { 961 result = 4.0f * t * t * t; 962 } else { 963 t = -2.0f * t + 2.0f; 964 result = 1.0f - t * t * t / 2.0f; 965 } 966 return result; 967 } 968 969 function f32 970 ease_in_out_quartic(f32 t) 971 { 972 f32 result; 973 if (t < 0.5f) { 974 result = 8.0f * t * t * t * t; 975 } else { 976 t = -2.0f * t + 2.0f; 977 result = 1.0f - t * t * t * t / 2.0f; 978 } 979 return result; 980 }