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