am_math.h (17827B)
1 #ifndef M_PI 2 #define M_PI 3.14159265359f 3 #endif 4 5 // TODO: make sure these functions are inlineable and that the compiler does 6 // indeed inline them. 7 8 internal f32 math_min(f32 a, f32 b) 9 { 10 f32 min = a < b ? a : b; 11 return min; 12 } 13 14 internal f32 math_max(f32 a, f32 b) 15 { 16 f32 max = a > b ? a : b; 17 return max; 18 } 19 20 internal u32 math_pow_of_2(u32 exponent) 21 { 22 u32 result = 1 << exponent; 23 return result; 24 } 25 26 internal i32 math_round(f32 n) 27 { 28 return n < 0.0f ? n - 0.5 : n + 0.5; 29 } 30 31 internal f32 math_wrap(f32 n, f32 min, f32 max) 32 { 33 if (n > max) 34 { 35 return n - max; 36 } 37 else if (n < min) 38 { 39 return n + max; 40 } 41 else 42 { 43 return n; 44 } 45 } 46 47 // TODO: Test this against floorf 48 internal f32 math_floor(f32 x) 49 { 50 f32 result = (f32)((i32)x - (x < 0.0f)); 51 return result; 52 } 53 54 // TODO: Test this against ceilf 55 internal i32 math_ceil(f32 x) 56 { 57 i32 result = -math_floor(-x); 58 return result; 59 } 60 61 internal bool math_f32_is_i32(f32 x) 62 { 63 bool result = ((i32)x) == x; 64 return result; 65 } 66 67 internal m4 math_m4_init_id() 68 { 69 m4 m = {0}; 70 m.E[0][0] = 1.0f; 71 m.E[1][1] = 1.0f; 72 m.E[2][2] = 1.0f; 73 m.E[3][3] = 1.0f; 74 return m; 75 } 76 77 internal void math_m4_valueptr(m4 m, f32* out_valueptr) 78 { 79 for (u8 v = 0; v < 16; ++v) 80 { 81 u8 row = v / 4; 82 u8 col = v % 4; 83 out_valueptr[v] = m.E[row][col]; 84 } 85 } 86 87 internal bool math_m4m4_eq(m4 mat1, m4 mat2) 88 { 89 for (u8 i = 0; i < 4; ++i) 90 { 91 for (u8 j = 0; j < 4; ++j) 92 { 93 if (mat1.E[i][j] != mat2.E[i][j]) 94 { 95 return false; 96 } 97 } 98 } 99 return true; 100 } 101 102 internal m4 math_m4m4_m(m4 mat1, m4 mat2) 103 { 104 m4 r = { 105 .E[0][0] = (mat1.E[0][0] * mat2.E[0][0]) + (mat1.E[0][1] * mat2.E[1][0]) + (mat1.E[0][2] * mat2.E[2][0]) + (mat1.E[0][3] * mat2.E[3][0]), 106 .E[0][1] = (mat1.E[0][0] * mat2.E[0][1]) + (mat1.E[0][1] * mat2.E[1][1]) + (mat1.E[0][2] * mat2.E[2][1]) + (mat1.E[0][3] * mat2.E[3][1]), 107 .E[0][2] = (mat1.E[0][0] * mat2.E[0][2]) + (mat1.E[0][1] * mat2.E[1][2]) + (mat1.E[0][2] * mat2.E[2][2]) + (mat1.E[0][3] * mat2.E[3][2]), 108 .E[0][3] = (mat1.E[0][0] * mat2.E[0][3]) + (mat1.E[0][1] * mat2.E[1][3]) + (mat1.E[0][2] * mat2.E[2][3]) + (mat1.E[0][3] * mat2.E[3][3]), 109 110 .E[1][0] = (mat1.E[1][0] * mat2.E[0][0]) + (mat1.E[1][1] * mat2.E[1][0]) + (mat1.E[1][2] * mat2.E[2][0]) + (mat1.E[1][3] * mat2.E[3][0]), 111 .E[1][1] = (mat1.E[1][0] * mat2.E[0][1]) + (mat1.E[1][1] * mat2.E[1][1]) + (mat1.E[1][2] * mat2.E[2][1]) + (mat1.E[1][3] * mat2.E[3][1]), 112 .E[1][2] = (mat1.E[1][0] * mat2.E[0][2]) + (mat1.E[1][1] * mat2.E[1][2]) + (mat1.E[1][2] * mat2.E[2][2]) + (mat1.E[1][3] * mat2.E[3][2]), 113 .E[1][3] = (mat1.E[1][0] * mat2.E[0][3]) + (mat1.E[1][1] * mat2.E[1][3]) + (mat1.E[1][2] * mat2.E[2][3]) + (mat1.E[1][3] * mat2.E[3][3]), 114 115 .E[2][0] = (mat1.E[2][0] * mat2.E[0][0]) + (mat1.E[2][1] * mat2.E[1][0]) + (mat1.E[2][2] * mat2.E[2][0]) + (mat1.E[2][3] * mat2.E[3][0]), 116 .E[2][1] = (mat1.E[2][0] * mat2.E[0][1]) + (mat1.E[2][1] * mat2.E[1][1]) + (mat1.E[2][2] * mat2.E[2][1]) + (mat1.E[2][3] * mat2.E[3][1]), 117 .E[2][2] = (mat1.E[2][0] * mat2.E[0][2]) + (mat1.E[2][1] * mat2.E[1][2]) + (mat1.E[2][2] * mat2.E[2][2]) + (mat1.E[2][3] * mat2.E[3][2]), 118 .E[2][3] = (mat1.E[2][0] * mat2.E[0][3]) + (mat1.E[2][1] * mat2.E[1][3]) + (mat1.E[2][2] * mat2.E[2][3]) + (mat1.E[2][3] * mat2.E[3][3]), 119 120 .E[3][0] = (mat1.E[3][0] * mat2.E[0][0]) + (mat1.E[3][1] * mat2.E[1][0]) + (mat1.E[3][2] * mat2.E[2][0]) + (mat1.E[3][3] * mat2.E[3][0]), 121 .E[3][1] = (mat1.E[3][0] * mat2.E[0][1]) + (mat1.E[3][1] * mat2.E[1][1]) + (mat1.E[3][2] * mat2.E[2][1]) + (mat1.E[3][3] * mat2.E[3][1]), 122 .E[3][2] = (mat1.E[3][0] * mat2.E[0][2]) + (mat1.E[3][1] * mat2.E[1][2]) + (mat1.E[3][2] * mat2.E[2][2]) + (mat1.E[3][3] * mat2.E[3][2]), 123 .E[3][3] = (mat1.E[3][0] * mat2.E[0][3]) + (mat1.E[3][1] * mat2.E[1][3]) + (mat1.E[3][2] * mat2.E[2][3]) + (mat1.E[3][3] * mat2.E[3][3]), 124 }; 125 return r; 126 } 127 128 internal v4 math_m4v4_m(m4 m, v4 v) 129 { 130 v4 r = { 131 .x = (m.E[0][0] * v.x) + (m.E[0][1] * v.y) + (m.E[0][2] * v.z) + (m.E[0][3] * v.w), 132 .y = (m.E[1][0] * v.x) + (m.E[1][1] * v.y) + (m.E[1][2] * v.z) + (m.E[1][3] * v.w), 133 .z = (m.E[2][0] * v.x) + (m.E[2][1] * v.y) + (m.E[2][2] * v.z) + (m.E[2][3] * v.w), 134 .w = (m.E[3][0] * v.x) + (m.E[3][1] * v.y) + (m.E[3][2] * v.z) + (m.E[3][3] * v.w), 135 }; 136 return r; 137 } 138 139 internal bool math_approx(f32 n, f32 compare, f32 epsilon) 140 { 141 return fabsf(n - compare) <= epsilon; 142 } 143 144 internal bool math_v2_is_nonzero(v2 v) 145 { 146 // TODO: Figure out whether this epsilon is universally appropriate. 147 f32 epsilon = 0.000001; 148 return ( 149 !math_approx(v.x, 0.0f, epsilon) 150 || !math_approx(v.y, 0.0f, epsilon) 151 ); 152 } 153 154 internal v2 math_v2_a(v2 vec1, v2 vec2) 155 { 156 v2 r = { 157 .x = vec1.x + vec2.x, 158 .y = vec1.y + vec2.y, 159 }; 160 return r; 161 } 162 163 internal v2 math_v2_negate(v2 v) 164 { 165 v2 r = {-v.x, -v.y}; 166 return r; 167 } 168 169 internal v2 math_v2_s(v2 vec1, v2 vec2) 170 { 171 return math_v2_a(vec1, math_v2_negate(vec2)); 172 } 173 174 internal v2 math_v2f_m(v2 v, f32 s) 175 { 176 v2 r = {v.x * s, v.y * s}; 177 return r; 178 } 179 180 internal f32 math_v2_length(v2 v) 181 { 182 // TODO: Use inner product of v with itself 183 return sqrtf((v.x * v.x) + (v.y * v.y)); 184 } 185 186 // TODO: handle degenerate case where l is near 0.0f 187 // TODO: scale by 1.0f / l 188 internal v2 math_v2_normalize(v2 v) 189 { 190 f32 l = math_v2_length(v); 191 v2 r = {v.x / l, v.y / l}; 192 return r; 193 } 194 195 internal f32 math_v2_dot(v2 vec1, v2 vec2) 196 { 197 // dot product, a.k.a. inner product or scalar product 198 f32 dot_product = (vec1.x * vec2.x) + (vec1.y * vec2.y); 199 // NOTE: this value happens to be: 200 // |vec1| * |vec2| * Cos(theta) 201 // where theta is the angle between vec1 and vec2. This is useful in all 202 // sorts of ways: What if theta is zero? What if vec1 or vec2 is a unit 203 // vector? 204 return dot_product; 205 } 206 207 internal v2i math_v2i_a(v2i vec1, v2i vec2) 208 { 209 v2i r = {vec1.x + vec2.x, vec1.y + vec2.y}; 210 return r; 211 } 212 213 internal bool math_v2i_eq(v2i vec1, v2i vec2) 214 { 215 bool result = (vec1.x == vec2.x && vec1.y == vec2.y); 216 return result; 217 } 218 219 internal bool math_v2u_eq(v2u vec1, v2u vec2) 220 { 221 bool result = (vec1.x == vec2.x && vec1.y == vec2.y); 222 return result; 223 } 224 225 internal v3 math_v3_cross(v3 vec1, v3 vec2) 226 { 227 // cross product, a.k.a. outer product or vector product 228 v3 r = { 229 .x = (vec1.y * vec2.z) - (vec1.z * vec2.y), 230 .y = (vec1.z * vec2.x) - (vec1.x * vec2.z), 231 .z = (vec1.x * vec2.y) - (vec1.y * vec2.x), 232 }; 233 return r; 234 } 235 236 internal f32 math_v3_length(v3 v) 237 { 238 // TODO: Use inner product of v with itself 239 // NOTE: math_v3_dot(v, v) returns: 240 // |v| * |v| * Cos(theta) 241 // We know that theta, the angle between v and itself, is always 0, so we 242 // know that Cos(theta) is always 1. We can then simplify the above 243 // expression to be: 244 // (|v|)^2 245 // so sqrtf(math_v3_dot(v, v)) is the length of v 246 return sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); 247 } 248 249 internal v3 math_v3f_m(v3 v, f32 s) 250 { 251 v3 r = {.x = v.x * s, .y = v.y * s, .z = v.z * s}; 252 return r; 253 } 254 255 internal v3 math_v3_negate(v3 v) 256 { 257 v3 r = {.x = -v.x, .y = -v.y, .z = -v.z}; 258 return r; 259 } 260 261 // TODO: handle degenerate case where l is near 0.0f 262 // TODO: scale by 1.0f / l 263 internal v3 math_v3_normalize(v3 v) 264 { 265 f32 l = math_v3_length(v); 266 v3 r = {v.x / l, v.y / l, v.z / l}; 267 return r; 268 } 269 270 internal v3 math_v3_a(v3 vec1, v3 vec2) 271 { 272 v3 r = { 273 .x = vec1.x + vec2.x, 274 .y = vec1.y + vec2.y, 275 .z = vec1.z + vec2.z 276 }; 277 return r; 278 } 279 280 internal v3 math_v3_s(v3 vec1, v3 vec2) 281 { 282 return math_v3_a(vec1, math_v3_negate(vec2)); 283 } 284 285 internal v3 math_v3_from_rgb(i32 rgb) 286 { 287 v3 result = { 288 .x = ((rgb >> 16) & 0xFF) / 255.0f, 289 .y = ((rgb >> 8) & 0xFF) / 255.0f, 290 .z = ((rgb >> 0) & 0xFF) / 255.0f, 291 }; 292 return result; 293 } 294 295 internal bool math_v4v4_eq(v4 vec1, v4 vec2) 296 { 297 for (u8 i = 0; i < 4; ++i) 298 { 299 if (vec1.E[i] != vec2.E[i]) 300 { 301 return false; 302 } 303 } 304 return true; 305 } 306 307 internal void math_clamp(f32 *f, f32 min, f32 max) 308 { 309 if (*f < min) 310 { 311 *f = min; 312 } 313 else if (*f > max) 314 { 315 *f = max; 316 } 317 } 318 319 internal f32 math_deg(f32 rad) 320 { 321 return rad * (180.0f / M_PI); 322 } 323 324 internal f32 math_lerpf(f32 f, f32 min, f32 max) 325 { 326 assert(f >= 0.0f && f <= 1.0f); 327 return (1.0f - f) * min + f * max; 328 } 329 330 internal f32 math_rad(f32 deg) 331 { 332 return deg * (M_PI / 180.0f); 333 } 334 335 internal m4 math_rotate_x(m4 m, f32 rad) 336 { 337 f32 c = cosf(rad); 338 f32 s = sinf(rad); 339 340 m4 r = math_m4_init_id(); 341 342 r.E[1][1] = c; 343 r.E[1][2] = -s; 344 345 r.E[2][1] = s; 346 r.E[2][2] = c; 347 348 return math_m4m4_m(m, r); 349 } 350 351 internal m4 math_rotate_y(m4 m, f32 rad) 352 { 353 f32 c = cosf(rad); 354 f32 s = sinf(rad); 355 356 m4 r = math_m4_init_id(); 357 358 r.E[0][0] = c; 359 r.E[0][2] = s; 360 361 r.E[2][0] = -s; 362 r.E[2][2] = c; 363 364 return math_m4m4_m(m, r); 365 } 366 367 internal m4 math_rotate_z(m4 m, f32 rad) 368 { 369 f32 c = cosf(rad); 370 f32 s = sinf(rad); 371 372 m4 r = math_m4_init_id(); 373 374 r.E[0][0] = c; 375 r.E[0][1] = -s; 376 377 r.E[1][0] = s; 378 r.E[1][1] = c; 379 380 return math_m4m4_m(m, r); 381 } 382 383 internal m4 math_rotate(m4 m, f32 rad, v3 axis) 384 { 385 axis = math_v3_normalize(axis); 386 387 f32 c = cosf(rad); 388 f32 s = sinf(rad); 389 390 m4 r = math_m4_init_id(); 391 392 r.E[0][0] = c + (powf(axis.x, 2.0f) * (1 - c)); 393 r.E[0][1] = (axis.x * axis.y * (1 - c)) - (axis.z * s); 394 r.E[0][2] = (axis.x * axis.z * (1 - c)) + (axis.y * s); 395 396 r.E[1][0] = (axis.y * axis.x * (1 - c)) + (axis.z * s); 397 r.E[1][1] = c + (powf(axis.y, 2.0f) * (1 - c)); 398 r.E[1][2] = (axis.y * axis.z * (1 - c)) - (axis.x * s); 399 400 r.E[2][0] = (axis.z * axis.x * (1 - c)) - (axis.y * s); 401 r.E[2][1] = (axis.z * axis.y * (1 - c)) + (axis.x * s); 402 r.E[2][2] = c + (powf(axis.z, 2.0f) * (1 - c)); 403 404 return math_m4m4_m(m, r); 405 } 406 407 internal m4 math_scale(m4 m, v3 v) 408 { 409 m4 r = math_m4_init_id(); 410 r.E[0][0] = v.x; 411 r.E[1][1] = v.y; 412 r.E[2][2] = v.z; 413 return math_m4m4_m(m, r); 414 } 415 416 internal m4 math_translate(m4 m, v3 v) 417 { 418 m4 r = math_m4_init_id(); 419 r.E[0][3] = v.x; 420 r.E[1][3] = v.y; 421 r.E[2][3] = v.z; 422 return math_m4m4_m(m, r); 423 } 424 425 internal m4 math_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) 426 { 427 // TODO: This assert fails when you minimise the window in Windows. 428 assert(left != right); 429 assert(bottom != top); 430 assert(near != far); 431 432 m4 r = math_m4_init_id(); 433 434 r.E[0][0] = 2.0f / (right - left); 435 r.E[0][1] = 0.0f; 436 r.E[0][2] = 0.0f; 437 r.E[0][3] = -(right + left) / (right - left); 438 439 r.E[1][0] = 0.0f; 440 r.E[1][1] = 2.0f / (top - bottom); 441 r.E[1][2] = 0.0f; 442 r.E[1][3] = -(top + bottom) / (top - bottom); 443 444 r.E[2][0] = 0.0f; 445 r.E[2][1] = 0.0f; 446 r.E[2][2] = -2.0f / (far - near); 447 r.E[2][3] = -(far + near) / (far - near); 448 449 r.E[3][0] = 0.0f; 450 r.E[3][1] = 0.0f; 451 r.E[3][2] = 0.0f; 452 r.E[3][3] = 1.0f; 453 454 return r; 455 } 456 457 internal m4 math_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) 458 { 459 assert(left != right); 460 assert(bottom != top); 461 assert(near != far); 462 463 m4 r = math_m4_init_id(); 464 465 r.E[0][0] = (2.0f * near) / (right - left); 466 r.E[0][1] = 0.0f; 467 r.E[0][2] = (right + left) / (right - left); 468 r.E[0][3] = 0.0f; 469 470 r.E[1][0] = 0.0f; 471 r.E[1][1] = (2.0f * near) / (top - bottom); 472 r.E[1][2] = (top + bottom) / (top - bottom); 473 r.E[1][3] = 0.0f; 474 475 r.E[2][0] = 0.0f; 476 r.E[2][1] = 0.0f; 477 r.E[2][2] = -(far + near) / (far - near); 478 r.E[2][3] = (-2.0f * far * near) / (far - near); 479 480 r.E[3][0] = 0.0f; 481 r.E[3][1] = 0.0f; 482 r.E[3][2] = -1.0f; 483 r.E[3][3] = 0.0f; 484 485 return r; 486 } 487 488 internal m4 math_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far) 489 { 490 f32 half_height = tanf(fovy / 2.0f) * near; 491 f32 half_width = half_height * aspect; 492 f32 left = -half_width; 493 f32 right = half_width; 494 f32 bottom = -half_height; 495 f32 top = half_height; 496 497 return math_projection_perspective(left, right, bottom, top, near, far); 498 } 499 500 internal m4 math_camera_look_at(v3 camera_pos, v3 camera_target, v3 up) 501 { 502 v3 camera_direction = math_v3_normalize(math_v3_s(camera_pos, camera_target)); 503 v3 camera_right = math_v3_normalize(math_v3_cross(up, camera_direction)); 504 v3 camera_up = math_v3_cross(camera_direction, camera_right); 505 506 m4 look = math_m4_init_id(); 507 look.E[0][0] = camera_right.x; 508 look.E[0][1] = camera_right.y; 509 look.E[0][2] = camera_right.z; 510 511 look.E[1][0] = camera_up.x; 512 look.E[1][1] = camera_up.y; 513 look.E[1][2] = camera_up.z; 514 515 look.E[2][0] = camera_direction.x; 516 look.E[2][1] = camera_direction.y; 517 look.E[2][2] = camera_direction.z; 518 519 return math_m4m4_m(look, math_translate(math_m4_init_id(), math_v3_negate(camera_pos))); 520 } 521 522 internal bool math_intersect_aabb_aabb(rect r1, rect r2) 523 { 524 f32 total_w = (r1.max.x - r1.min.x) + (r2.max.x - r2.min.x); 525 f32 total_h = (r1.max.y - r1.min.y) + (r2.max.y - r2.min.y); 526 bool aabbs_do_indeed_intersect = ( 527 fabsf(r1.max.x - r2.min.x) <= total_w 528 && fabsf(r1.max.y - r2.min.y) <= total_h 529 && fabsf(r2.max.x - r1.min.x) <= total_w 530 && fabsf(r2.max.y - r1.min.y) <= total_h 531 ); 532 return aabbs_do_indeed_intersect; 533 } 534 535 internal rect math_minkowski_sum_rect(rect r1, v2 r2_dimensions) 536 { 537 v2 r2_half = { 538 .width = 0.5f * r2_dimensions.width, 539 .height = 0.5f * r2_dimensions.height, 540 }; 541 rect sum = { 542 .min = {r1.min.x - r2_half.width, r1.min.y - r2_half.height}, 543 .max = {r1.max.x + r2_half.width, r1.max.y + r2_half.height}, 544 }; 545 return sum; 546 } 547 548 internal rect math_minkowski_diff_rect(rect r1, v2 r2_dimensions) 549 { 550 v2 negated_r2_dim = math_v2_negate(r2_dimensions); 551 rect difference = math_minkowski_sum_rect(r1, negated_r2_dim); 552 return difference; 553 } 554 555 internal rect math_rect_from_center_dim(v2 center, v2 dimensions) 556 { 557 v2 half_d = {dimensions.x * 0.5f, dimensions.y * 0.5f}; 558 rect result = { 559 .min = {center.x - half_d.x, center.y - half_d.y}, 560 .max = {center.x + half_d.x, center.y + half_d.y}, 561 }; 562 return result; 563 } 564 565 enum MathRectEdge 566 { 567 RECT_EDGE_BOTTOM, 568 RECT_EDGE_TOP, 569 RECT_EDGE_LEFT, 570 RECT_EDGE_RIGHT, 571 MAX_RECT_EDGE, 572 }; 573 574 internal segment math_rect_get_edge(rect r, enum MathRectEdge e) 575 { 576 v2 nw = {r.min.x, r.max.y}; 577 v2 ne = r.max; 578 v2 sw = r.min; 579 v2 se = {r.max.x, r.min.y}; 580 581 segment edge = {0}; 582 switch(e) 583 { 584 case RECT_EDGE_BOTTOM: 585 edge = (segment) {sw, se}; 586 break; 587 case RECT_EDGE_TOP: 588 edge = (segment) {nw, ne}; 589 break; 590 case RECT_EDGE_LEFT: 591 edge = (segment) {sw, nw}; 592 break; 593 case RECT_EDGE_RIGHT: 594 edge = (segment) {se, ne}; 595 break; 596 default: 597 assert(false); 598 break; 599 } 600 return edge; 601 } 602 603 internal v2 math_rect_get_normal(enum MathRectEdge e) 604 { 605 v2 normal = {0}; 606 switch(e) 607 { 608 case RECT_EDGE_BOTTOM: 609 normal = (v2) {0.0f, -1.0f}; 610 break; 611 case RECT_EDGE_TOP: 612 normal = (v2) {0.0f, 1.0f}; 613 break; 614 case RECT_EDGE_LEFT: 615 normal = (v2) {-1.0f, 0.0f}; 616 break; 617 case RECT_EDGE_RIGHT: 618 normal = (v2) {1.0f, 0.0f}; 619 break; 620 default: 621 assert(false); 622 break; 623 } 624 return normal; 625 } 626 627 internal bool math_in_interval_open(f32 n, f32 min, f32 max) 628 { 629 assert(min <= max); 630 bool in_open_interval = false; 631 in_open_interval = (n >= min && n <= max); 632 return in_open_interval; 633 } 634 635 internal bool math_v2_lt(v2 v, v2 compare) 636 { 637 bool is_lt = false; 638 is_lt = (v.x < compare.x && v.y < compare.y); 639 return is_lt; 640 } 641 642 internal bool math_v2_le(v2 v, v2 compare) 643 { 644 bool is_le = false; 645 is_le = (v.x <= compare.x && v.y <= compare.y); 646 return is_le; 647 } 648 649 internal bool math_v2_ge(v2 v, v2 compare) 650 { 651 bool is_ge = false; 652 is_ge = (v.x >= compare.x && v.y >= compare.y); 653 return is_ge; 654 } 655 656 internal i32 math_log2(u32 x) 657 { 658 i32 result = sizeof(u32) * CHAR_BIT - intr_clz(x) - 1; 659 return result; 660 } 661 662 #define math_is_pow_2(n) ((n) & ((n) - 1)) == 0 663 664 internal void math_v2_print(v2 v) 665 { 666 printf("( %f, %f )\n", v.x, v.y); 667 } 668 669 internal void math_v2u_print(v2u v) 670 { 671 printf("( %u, %u )\n", v.x, v.y); 672 } 673 674 internal void math_v2i_print(v2i v) 675 { 676 printf("( %i, %i )\n", v.x, v.y); 677 } 678 679 internal void math_v3_print(v3 v) 680 { 681 printf("( %f, %f, %f )\n", v.x, v.y, v.z); 682 } 683 684 internal void math_v4_print(v4 v) 685 { 686 printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w); 687 } 688 689 internal void math_rect_print(rect r) 690 { 691 printf("rect:\n"); 692 printf(" min: "); 693 math_v2_print(r.min); 694 printf(" max: "); 695 math_v2_print(r.max); 696 } 697 698 internal void math_m4_print(m4 m) 699 { 700 printf("[\n"); 701 printf(" %f, %f, %f, %f\n", m.E[0][0], m.E[0][1], m.E[0][2], m.E[0][3]); 702 printf(" %f, %f, %f, %f\n", m.E[1][0], m.E[1][1], m.E[1][2], m.E[1][3]); 703 printf(" %f, %f, %f, %f\n", m.E[2][0], m.E[2][1], m.E[2][2], m.E[2][3]); 704 printf(" %f, %f, %f, %f\n", m.E[3][0], m.E[3][1], m.E[3][2], m.E[3][3]); 705 printf("]\n"); 706 } 707 708 #define math_print(x) _Generic((x),\ 709 v2: math_v2_print, \ 710 v2u: math_v2u_print, \ 711 v2i: math_v2i_print, \ 712 v3: math_v3_print, \ 713 v4: math_v4_print, \ 714 rect: math_rect_print, \ 715 m4: math_m4_print \ 716 )(x)