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