├── README.md ├── bcpuid.h ├── bdebug.h ├── bfile.h ├── bmath.hpp ├── bmath.natvis ├── bmem.h └── brng.h /README.md: -------------------------------------------------------------------------------- 1 | # B-Library 2 | 3 | A collection of personal single-header C/C++ libraries similar to the [stb libraries](https://github.com/nothings/stb). They are all public domain (alternatively MIT licenced). 4 | 5 | library | latest version | category | language | LoC | description 6 | :--------------------------- |:--------------:|:-----------:|:--------:| ----:|:---------------------------------------------- 7 | **[bmath.hpp](./bmath.hpp)** | `0.32` | math | C++03 | 3474 | type generic 2, 3 and 4D vector, matrix and quaternion algebra - alternative to [GLM](https://glm.g-truc.net/0.9.9/index.html) 8 | **[bmem.h](./bmem.h)** | `0.2` | utility | C99 | 598 | quick & dirty memory leak-checking and temporary storage implementation 9 | **[bdebug.h](./bdebug.h)** | `1.0` | utility | C99 | 263 | assertion macro and logging function 10 | **[bfile.h](./bfile.h)** | `0.1` | utility | C99 | 259 | linux/windows file utilities - dynamically track file changes 11 | **[brng.h](./brng.h)** | `0.9` | utility | C99 | 212 | simple [PCG generator](https://www.pcg-random.org/index.html) implementation 12 | **[bcpuid.h](./bcpuid.h)** | `1.0` | utility | C99 | 433 | determine processor features, core count, and cache size at runtime 13 | 14 | All C libraries will compile as C++. 15 | 16 | All libraries rely only on the standard library and so they should be multi-platform. The exception to this is [bfile.h](./bfile.h) which relies on the OS-specific `sys/stat.h` header. 17 | -------------------------------------------------------------------------------- /bcpuid.h: -------------------------------------------------------------------------------- 1 | /* 2 | bcpuid.h - v1.0 - public domain processor feature detector 3 | by Blat Blatnik 4 | 5 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK 6 | For licence information see end of file. 7 | 8 | Do this: 9 | #define B_CPUID_IMPLEMENTATION 10 | before you include this file in *ONE* C or C++ file to create the implementation. 11 | 12 | //i.e. it should look something like this: 13 | #include ... 14 | #include ... 15 | #include B_CPUID_IMPLEMENTATION 16 | #include "bcpuid.h" 17 | 18 | This file exposes one function: get_CPUID() which you can call to get 19 | processor information at runtime using the CPUID instruction. It only 20 | detects features that I tought would be relevant to game programming. 21 | All detected features are shown in the example program below. 22 | 23 | The library was tested with: Ryzen 5 5600X, Ryzen 7 1700X, i5-7300HQ, i7-8550U 24 | 25 | ........................... 26 | ... Example program ... 27 | ........................... 28 | 29 | #define B_CPUID_IMPLEMENTATION 30 | #include "bcpuid.h" 31 | #include 32 | 33 | int main(void) 34 | { 35 | CPUID id = get_CPUID(); 36 | 37 | printf("--------------------------------------------------\n"); 38 | printf(" vendor: %s\n", id.vendor); 39 | printf(" name: %s\n", id.name); 40 | printf(" family: %d\n", id.family); 41 | printf(" model: %d\n", id.model); 42 | printf(" stepping: %d\n", id.stepping); 43 | printf("--------------------------------------------------\n"); 44 | printf(" %2d physical cores\n", id.num_physical_cores); 45 | printf(" %2d logical cores\n", id.num_logical_cores); 46 | printf("--------------------------------------------------\n"); 47 | printf(" L1i cache size: %d kB (per core)\n", id.L1i_cache_size); 48 | printf(" L1d cache size: %d kB (per core)\n", id.L1d_cache_size); 49 | printf(" L2 cache size: %d kB (per core)\n", id.L2_cache_size); 50 | printf(" L3 cache size: %d kB (shared)\n", id.L3_cache_size); 51 | printf(" cache line size: %d bytes\n", id.cache_line_size); 52 | printf("--------------------------------------------------\n"); 53 | printf(" features: "); 54 | if (id.feature_flags & CPUID_MMX) printf("mmx "); 55 | if (id.feature_flags & CPUID_SSE) printf("sse "); 56 | if (id.feature_flags & CPUID_SSE2) printf("sse2 "); 57 | if (id.feature_flags & CPUID_SSE3) printf("sse3 "); 58 | if (id.feature_flags & CPUID_SSSE3) printf("ssse3 "); 59 | if (id.feature_flags & CPUID_FMA) printf("fma "); 60 | if (id.feature_flags & CPUID_SSE41) printf("sse41 "); 61 | if (id.feature_flags & CPUID_SSE42) printf("sse42 "); 62 | if (id.feature_flags & CPUID_AVX) printf("avx "); 63 | if (id.feature_flags & CPUID_AVX2) printf("avx2 "); 64 | if (id.feature_flags & CPUID_AVX512_f) printf("avx512_f "); 65 | if (id.feature_flags & CPUID_AVX512_dq) printf("avx512_dq "); 66 | if (id.feature_flags & CPUID_AVX512_bw) printf("avx512_bw "); 67 | if (id.feature_flags & CPUID_AVX512_vl) printf("avx512_vl "); 68 | printf("\n"); 69 | printf("--------------------------------------------------\n"); 70 | 71 | return 0; 72 | } 73 | 74 | ................... 75 | ... Options ... 76 | ................... 77 | 78 | #define B_CPUID_MEMSET(dest, val, count) your_memset_function(dest, val, count) 79 | #define B_CPUID_MEMCPY(dest, src, count) your_memcpy_function(dest, src, count) 80 | #define B_CPUID_STRSTR(str, substr) your_strstr_function(str, substr) 81 | - Avoid including string.h for memset, memcpy and strstr by defining ALL of these. 82 | You have to either define ALL of them or NONE of them. 83 | */ 84 | 85 | 86 | #ifndef B_CPUID_DEFINITION 87 | #define B_CPUID_DEFINITION 88 | 89 | enum FeatureFlags 90 | { 91 | CPUID_MMX = (1 << 0), 92 | CPUID_SSE = (1 << 1), 93 | CPUID_SSE2 = (1 << 2), 94 | CPUID_SSE3 = (1 << 3), 95 | CPUID_SSSE3 = (1 << 4), 96 | CPUID_FMA = (1 << 5), 97 | CPUID_SSE41 = (1 << 6), 98 | CPUID_SSE42 = (1 << 7), 99 | CPUID_AVX = (1 << 8), 100 | CPUID_AVX2 = (1 << 9), 101 | CPUID_AVX512_f = (1 << 10), 102 | CPUID_AVX512_dq = (1 << 11), 103 | CPUID_AVX512_bw = (1 << 12), 104 | CPUID_AVX512_vl = (1 << 13), 105 | }; 106 | 107 | typedef struct CPUID 108 | { 109 | char vendor[13]; // You can do strstr(vendor, "AMD") or strstr(vendor, "Intel") to determine the vendor. 110 | char name[49]; // You can determine the exact CPU model from this - or print it somewhere. 111 | 112 | int family; // These fields give you an integer ID you can use to identify the exact processor if you need to. 113 | int model; 114 | int stepping; 115 | 116 | int cache_line_size; // L1 cache line size in bytes. 117 | int L1i_cache_size; // L1 instruction cache size *per core* in kilobytes. 118 | int L1d_cache_size; // L1 data cache size *per core* in kilobytes. 119 | int L2_cache_size; // L2 cache size *per core* in kilobytes. 120 | int L3_cache_size; // L3 cache size (shared by all cores) in kilobytes. 121 | 122 | int num_physical_cores; // Number of physical cores on the chip. Some of them could be disabled - so this is only the maximum number possible for this CPU. 123 | int num_logical_cores; // Number of logical cores. This will be 2 x num_physical_cores when the CPU *can* hyperthread, and 1 x num_physical_cores when it cannot. 124 | 125 | int feature_flags; // Bitmask of relevant CPU features. See FeatureFlags. 126 | } CPUID; 127 | 128 | CPUID get_CPUID(void); 129 | 130 | #endif // B_CPUID_DEFINITION 131 | 132 | // 133 | // v-- Implementation --v 134 | // 135 | 136 | #if defined(B_CPUID_IMPLEMENTATION) && !defined(B_CPUID_IMPLEMENTED) 137 | #define B_CPUID_IMPLEMENTED 138 | 139 | #if !defined(B_MEMSET) 140 | #include // for memset, memcpy and strstr 141 | #define B_MEMSET(dest, val, count) memset(dest, val, count) 142 | #define B_MEMCPY(dest, src, count) memcpy(dest, src, count) 143 | #define B_STRSTR(str, substr) strstr(str, substr) 144 | #endif 145 | 146 | #if defined(_MSC_VER) 147 | #include 148 | 149 | static void b__cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int *edx) 150 | { 151 | int registers[4]; 152 | if (subleaf == 0) 153 | __cpuid(registers, leaf); 154 | else 155 | __cpuidex(registers, leaf, subleaf); 156 | 157 | *eax = registers[0]; 158 | *ebx = registers[1]; 159 | *ecx = registers[2]; 160 | *edx = registers[3]; 161 | } 162 | 163 | static int b__cpuid_is_supported(void) 164 | { 165 | // Try to set and clear bit 21 in the EFLAGS register. This indicates support for the CPUID instruction. 166 | // We bail out immediately if it's not supported. 167 | unsigned long long bit21 = 1llu << 21; 168 | 169 | __writeeflags(__readeflags() | bit21); 170 | if ((__readeflags() & bit21) == 0) 171 | return 0; 172 | 173 | __writeeflags(__readeflags() & ~bit21); 174 | if ((__readeflags() & bit21) == 1) 175 | return 0; 176 | 177 | return 1; 178 | } 179 | #elif defined(__GNUC__) || defined(__clang__) 180 | #include 181 | 182 | static void b__cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int *edx) 183 | { 184 | __cpuid_count(leaf, subleaf, *eax, *ebx, *ecx, *edx); 185 | } 186 | 187 | static int b__cpuid_is_supported(void) 188 | { 189 | return __get_cpuid_max(0, 0) != 0; 190 | } 191 | #else 192 | #error "This library only works with MSVC, clang, or GCC." 193 | #endif // Compiler detecion. 194 | 195 | static int b__extract_bits(int x, int highest, int lowest) 196 | { 197 | unsigned int u = (unsigned int)x; 198 | u <<= 31 - highest; 199 | u >>= (31 - highest) + lowest; 200 | return (int)u; 201 | } 202 | 203 | static int b__extract_bit(int x, int index) 204 | { 205 | return (int)((unsigned int)(x & (1 << index)) >> index); 206 | } 207 | 208 | CPUID get_CPUID(void) 209 | { 210 | CPUID id; 211 | B_MEMSET(&id, 0, sizeof id); 212 | 213 | if (!b__cpuid_is_supported()) 214 | return id; 215 | 216 | int eax, ebx, ecx, edx; 217 | 218 | b__cpuid(0, 0, &eax, &ebx, &ecx, &edx); 219 | int max_cpuid = eax; 220 | 221 | B_MEMCPY(id.vendor + 0, &ebx, 4); 222 | B_MEMCPY(id.vendor + 4, &edx, 4); // Note that the string is in ebx:e**D**x:e**C**x. 223 | B_MEMCPY(id.vendor + 8, &ecx, 4); 224 | 225 | if (max_cpuid < 1) 226 | return id; 227 | 228 | b__cpuid(1, 0, &eax, &ebx, &ecx, &edx); 229 | 230 | int stepping_id = b__extract_bits(eax, 3, 0); 231 | int model_id = b__extract_bits(eax, 7, 4); 232 | int family_id = b__extract_bits(eax, 11, 8); 233 | int ext_model_id = b__extract_bits(eax, 19, 16); 234 | int ext_family_id = b__extract_bits(eax, 27, 20); 235 | 236 | id.family = family_id; 237 | if (family_id == 15) 238 | id.family += ext_family_id; 239 | 240 | id.model = model_id; 241 | if (family_id == 6 || family_id == 15) 242 | id.model += (ext_model_id << 4); 243 | 244 | id.stepping = stepping_id; 245 | 246 | int has_clflush = b__extract_bit(edx, 19); 247 | if (has_clflush) 248 | id.cache_line_size = b__extract_bits(ebx, 15, 8); 249 | 250 | // Note that the value reported here is not actually accurate. On an i5-7300HQ it reports hyperthreading 251 | // even though that CPU doesn't do that. I've also read that the value reported on AMD is also not always 252 | // accurate. It basically seems like this is always on, regardless of whether the CPU actually does HT or not. 253 | int is_hyperthreaded = b__extract_bit(edx, 28); 254 | 255 | int features = 0; 256 | 257 | if (b__extract_bit(edx, 23)) features |= CPUID_MMX; 258 | if (b__extract_bit(edx, 25)) features |= CPUID_SSE; 259 | if (b__extract_bit(edx, 26)) features |= CPUID_SSE2; 260 | if (b__extract_bit(ecx, 0)) features |= CPUID_SSE3; 261 | if (b__extract_bit(ecx, 9)) features |= CPUID_SSSE3; 262 | if (b__extract_bit(ecx, 12)) features |= CPUID_FMA; 263 | if (b__extract_bit(ecx, 19)) features |= CPUID_SSE41; 264 | if (b__extract_bit(ecx, 20)) features |= CPUID_SSE42; 265 | if (b__extract_bit(ecx, 28)) features |= CPUID_AVX; 266 | 267 | if (max_cpuid >= 7) 268 | { 269 | b__cpuid(7, 0, &eax, &ebx, &ecx, &edx); 270 | if (b__extract_bit(ebx, 5)) features |= CPUID_AVX2; 271 | if (b__extract_bit(ebx, 16)) features |= CPUID_AVX512_f; 272 | if (b__extract_bit(ebx, 17)) features |= CPUID_AVX512_dq; 273 | if (b__extract_bit(ebx, 30)) features |= CPUID_AVX512_bw; 274 | if (b__extract_bit(ebx, 31)) features |= CPUID_AVX512_vl; 275 | // There are quite a few more AVX512 features - all of them are reported separately - but these are the "important" ones. 276 | } 277 | 278 | id.feature_flags = features; 279 | 280 | b__cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx); 281 | unsigned int max_cpuid_ex = (unsigned int)eax; 282 | 283 | if (max_cpuid_ex >= 0x80000004) 284 | { 285 | // We can just copy the name string directly, since it seems to be the correct endianness on both AMD and Intel. 286 | // It's also null terminated unlike the vendor string. 287 | b__cpuid(0x80000002, 0, (int *)id.name + 0, (int *)id.name + 1, (int *)id.name + 2, (int *)id.name + 3); 288 | b__cpuid(0x80000003, 0, (int *)id.name + 4, (int *)id.name + 5, (int *)id.name + 6, (int *)id.name + 7); 289 | b__cpuid(0x80000004, 0, (int *)id.name + 8, (int *)id.name + 9, (int *)id.name + 10, (int *)id.name + 11); 290 | } 291 | 292 | if (B_STRSTR(id.vendor, "AMD")) 293 | { 294 | if (max_cpuid_ex >= 0x80000008) 295 | { 296 | b__cpuid(0x80000008, 0, &eax, &ebx, &ecx, &edx); 297 | id.num_logical_cores = 1 + b__extract_bits(ecx, 7, 0); 298 | } 299 | else 300 | { 301 | b__cpuid(1, 0, &eax, &ebx, &ecx, &edx); 302 | id.num_logical_cores = b__extract_bits(ebx, 23, 16); 303 | } 304 | 305 | // This really isn't a great indication. Many sources say that CPUID reports hyperthreading even when the processor doesn't actually support it. 306 | // But I can't test this right now since I don't have a non-hyperthreaded AMD chip.. 307 | if (is_hyperthreaded) 308 | id.num_physical_cores = id.num_logical_cores / 2; 309 | else 310 | id.num_physical_cores = id.num_logical_cores; 311 | 312 | if (max_cpuid_ex >= 0x80000005) 313 | { 314 | b__cpuid(0x80000005, 0, &eax, &ebx, &ecx, &edx); 315 | id.L1d_cache_size = b__extract_bits(ecx, 31, 24); 316 | id.L1i_cache_size = b__extract_bits(edx, 31, 24); 317 | } 318 | 319 | if (max_cpuid_ex >= 0x80000006) 320 | { 321 | b__cpuid(0x80000006, 0, &eax, &ebx, &ecx, &edx); 322 | id.L2_cache_size = b__extract_bits(ecx, 31, 16); 323 | id.L3_cache_size = 512 * b__extract_bits(edx, 31, 18); // This is reported in units of 512kB. 324 | } 325 | } 326 | else if (B_STRSTR(id.vendor, "Intel")) 327 | { 328 | if (max_cpuid >= 4) 329 | { 330 | b__cpuid(4, 0, &eax, &ebx, &ecx, &edx); 331 | 332 | // The value reported here is not accurate (I'm not sure if that's always the case). 333 | // On an i5-7300HQ it reports 8 logical cores with hyperthreading, even though that CPU 334 | // doesn't have hyperthreading.. Still this is a decent approximation at least. 335 | id.num_logical_cores = 1 + b__extract_bits(eax, 31, 26); 336 | id.num_physical_cores = id.num_logical_cores; 337 | if (is_hyperthreaded) 338 | id.num_physical_cores /= 2; 339 | 340 | // Enumerate all caches to find out sizes. 341 | for (int index = 0;; ++index) 342 | { 343 | b__cpuid(4, index, &eax, &ebx, &ecx, &edx); 344 | int type = b__extract_bits(eax, 4, 0); // 0 - invalid, 1 - data cache, 2 - instruction cache, 3 - unified cache. 345 | if (type == 0) 346 | break; 347 | 348 | int level = b__extract_bits(eax, 7, 5); 349 | int ways = 1 + b__extract_bits(ebx, 31, 22); 350 | int partitions = 1 + b__extract_bits(ebx, 21, 12); 351 | int line_size = 1 + b__extract_bits(ebx, 11, 0); 352 | int sets = 1 + b__extract_bits(ecx, 31, 0); 353 | int cache_size = ways * partitions * line_size * sets / 1024; 354 | 355 | if (level == 1) 356 | { 357 | if (type == 1) 358 | id.L1d_cache_size = cache_size; 359 | else if (type == 2) 360 | id.L1i_cache_size = cache_size; 361 | else // type == 3 362 | { 363 | // For unified L1 caches, set instruction cache size to 0 and set data cache size to the actual cache size. 364 | id.L1i_cache_size = 0; 365 | id.L1d_cache_size = cache_size; 366 | } 367 | } 368 | else if (level == 2) 369 | id.L2_cache_size = cache_size; 370 | else if (level == 3) 371 | id.L3_cache_size = cache_size; 372 | } 373 | } 374 | 375 | if (max_cpuid >= 0xB) 376 | { 377 | // This is a much better way of checking the number of cores than with cpuid(4) above. 378 | // At least this one is accurate on a i5-7300HQ and i7-8550U. 379 | b__cpuid(0xB, 0, &eax, &ebx, &ecx, &edx); 380 | int num_logical_processors_per_physical_core = b__extract_bits(ebx, 15, 0); 381 | is_hyperthreaded = num_logical_processors_per_physical_core == 2; 382 | 383 | b__cpuid(0xB, 1, &eax, &ebx, &ecx, &edx); 384 | id.num_logical_cores = b__extract_bits(ebx, 15, 0); 385 | id.num_physical_cores = id.num_logical_cores / num_logical_processors_per_physical_core; 386 | } 387 | } 388 | 389 | return id; 390 | } 391 | #endif // B_CPUID_IMPLEMENTATION 392 | 393 | /* 394 | ------------------------------------------------------------------------------ 395 | This software is available under 2 licenses - choose whichever you prefer. 396 | ------------------------------------------------------------------------------ 397 | ALTERNATIVE A - MIT License 398 | Copyright (c) 2021 Blat Blatnik 399 | Permission is hereby granted, free of charge, to any person obtaining a copy of 400 | this software and associated documentation files (the "Software"), to deal in 401 | the Software without restriction, including without limitation the rights to 402 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 403 | of the Software, and to permit persons to whom the Software is furnished to do 404 | so, subject to the following conditions: 405 | The above copyright notice and this permission notice shall be included in all 406 | copies or substantial portions of the Software. 407 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 408 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 409 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 410 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 411 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 412 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 413 | SOFTWARE. 414 | ------------------------------------------------------------------------------ 415 | ALTERNATIVE B - Public Domain (www.unlicense.org) 416 | This is free and unencumbered software released into the public domain. 417 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 418 | software, either in source code form or as a compiled binary, for any purpose, 419 | commercial or non-commercial, and by any means. 420 | In jurisdictions that recognize copyright laws, the author or authors of this 421 | software dedicate any and all copyright interest in the software to the public 422 | domain. We make this dedication for the benefit of the public at large and to 423 | the detriment of our heirs and successors. We intend this dedication to be an 424 | overt act of relinquishment in perpetuity of all present and future rights to 425 | this software under copyright law. 426 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 427 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 428 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 429 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 430 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 431 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 432 | ------------------------------------------------------------------------------ 433 | */ -------------------------------------------------------------------------------- /bdebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | bdebug.h - v1.0 - public domain debuging utilities 3 | 4 | by Blat Blatnik 5 | 6 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK 7 | 8 | For licence information see end of file. 9 | 10 | Do this: 11 | #define B_DEBUG_IMPLEMENTATION 12 | before you include this file in *ONE* C or C++ file to create the implementation. 13 | 14 | //i.e. it should look something like this: 15 | #include ... 16 | #include ... 17 | #include B_DEBUG_IMPLEMENTATION 18 | #include "bdebug.h" 19 | 20 | This library includes a logging function and an assertion macro. 21 | 22 | debugLog(message, args...) 23 | Write a format message to the log file. 24 | If no log file is open, this will try to open the default log file (log.txt). 25 | The special string "CLOSE" can be passed as a first argument to close the currently open log file. 26 | The special string "OPEN" can be passed as a first argument to open a new log file, 27 | whose filename must be passed as the second argument. 28 | All log messages are printed to stdout as well. 29 | 30 | //examples 31 | ... 32 | debugLog("hello") // opens the default log file and appends "hello" 33 | debugLog("world") // appends "world" to the open log file 34 | debugLog("CLOSE") // close the log file 35 | debugLog("again") // reopens the default log file and appends "again" 36 | debugLog("OPEN", "log2.txt") // closes the open log file and opens "log2.txt" as the new log file 37 | ... 38 | 39 | ASSERT(condition, [message, args...]) 40 | Unlike the standard assert from assert.h, this assert will not call abort upon triggering. 41 | Also, you can pass in a string LITERAL (it has to be a literal) as a format message, and 42 | arguments to format it in. If the passed in condition does not hold, the message and args 43 | are passed to debugLog, and then a debugger breakpoint is triggered. 44 | If you #define NDEBUG or #define B_DONT_ASSERT before #include -ing this file, 45 | ASSERT will be defined as a NO-OP. But if you #define B_ALWAYS_ASSERT before #include -ing 46 | then NDEBUG and B_DONT_ASSERT are ignored, and ASSERT will NOT be defined as a NO-OP. 47 | 48 | //examples 49 | ... 50 | #line 1 "example.c" 51 | ASSERT(2 == 2); // condition is true, so nothing happens 52 | ASSERT(2 == 4); // output 1 is generated and a breakpoint is triggered 53 | ASSERT(2 == 4, "oh no"); // output 2 is generated and a breakpoint is triggered 54 | ASSERT(2 == 4, "oh oh, %d != %d, %s", 2, 4, "panic!!") // generates output 3 and triggers a debugger breakpoint 55 | ... 56 | 57 | output 1: 58 | ERROR assert failed "2 == 4" 59 | in file example.c 60 | on line 2 61 | 62 | output 2: 63 | ERROR assert failed "2 == 4" 64 | in file example.c 65 | on line 3 66 | oh no 67 | 68 | output 3: 69 | ERROR assert failed "2 == 4" 70 | in file example.c 71 | on line 4 72 | oh oh, 2 != 4, panic!! 73 | 74 | ------------------- 75 | ----- Options ----- 76 | ------------------- 77 | 78 | #define any of these before including this file for them to take effect: 79 | 80 | #define B_TRIGGER_BREAKPOINT() your-trigger-debugger-breakpoint() 81 | - Use this to cause ASSERT to trigger a breakpoint on failure. You have to define it 82 | to something like MSVC's __debugbreak(). 83 | 84 | #define B_DONT_ASSERT 85 | #define NDEBUG 86 | - Both these will cause ASSERT to be disabled for use in release builds. 87 | 88 | #define B_ALWAYS_ASSERT 89 | - Ignore B_DONT_ASSERT and NDEBUG and have ASSERT work in release builds as well. 90 | 91 | #define B_DEBUG_PREFIX(name) [your-name-prefix] ## name 92 | #define B_PREFIX(name) [your-name-prefix] ## name 93 | - Add a prefix to all functions/variables/types declared by this file. 94 | Useful for avoiding name-conflicts. By default no prefix is added. 95 | */ 96 | 97 | #ifndef B_DEBUG_DEFINITION 98 | #define B_DEBUG_DEFINITION 99 | 100 | #ifndef B_DEBUG_PREFIX 101 | # ifdef B_PREFIX 102 | # define B_DEBUG_PREFIX(name) B_PREFIX(name) 103 | # else 104 | # define B_DEBUG_PREFIX(name) name 105 | # endif 106 | #endif 107 | 108 | void B_DEBUG_PREFIX(debugLog)(const char *message, ...); 109 | 110 | #define B_STRINGIFY(identifier) #identifier 111 | #define B_STRINGIFY2(identifier) B_STRINGIFY(identifier) 112 | 113 | /* Triggers a debugger breakpoint. */ 114 | #ifndef B_TRIGGER_BREAKPOINT 115 | # ifdef _MSC_VER 116 | # define B_TRIGGER_BREAKPOINT() __debugbreak() 117 | # else 118 | # define B_TRIGGER_BREAKPOINT() 119 | # endif 120 | #endif 121 | 122 | #if defined(B_ALWAYS_ASSERT) || (!defined(B_DONT_ASSERT) && !defined(NDEBUG)) 123 | # define ASSERT(condition, ...)\ 124 | do {\ 125 | if (!!!(condition)) {\ 126 | B_DEBUG_PREFIX(debugLog)(\ 127 | "ERROR assert failed \"" #condition "\"\n"\ 128 | " in file " __FILE__ "\n"\ 129 | " on line " B_STRINGIFY2(__LINE__) "\n"\ 130 | " " __VA_ARGS__);\ 131 | B_TRIGGER_BREAKPOINT();\ 132 | }\ 133 | } while (0) 134 | #else 135 | # define ASSERT(condition, ...) do {} while (0) 136 | #endif 137 | 138 | #endif /* !B_DEBUG_DEFINITION */ 139 | 140 | /* 141 | * | | 142 | * v Implementation v 143 | * | | 144 | */ 145 | 146 | #ifdef B_DEBUG_IMPLEMENTATION 147 | #ifndef B_DEBUG_IMPLEMENTED 148 | #define B_DEBUG_IMPLEMENTED 149 | 150 | #include /* FILE, fopen, fclose, fprintf, vfprintf, stdout, fflush */ 151 | #include /* va_list, va_start, va_end */ 152 | #include /* strcmp */ 153 | #include /* time_t, time, localtime, struct tm, strftime */ 154 | 155 | static FILE *b__logFile; 156 | 157 | void B_DEBUG_PREFIX(debugLog)(const char *message, ...) { 158 | 159 | if (strcmp(message, "CLOSE") == 0) { 160 | 161 | if (b__logFile) { 162 | B_DEBUG_PREFIX(debugLog)("log closed"); 163 | fclose(b__logFile); 164 | b__logFile = NULL; 165 | } 166 | return; 167 | 168 | } else if (strcmp(message, "OPEN") == 0) { 169 | 170 | va_list args; 171 | va_start(args, message); 172 | const char *filename = va_arg(args, const char *); 173 | va_end(args); 174 | 175 | if (b__logFile) { 176 | B_DEBUG_PREFIX(debugLog)("log closed"); 177 | fclose(b__logFile); 178 | } 179 | 180 | b__logFile = fopen(filename, "at"); 181 | if (b__logFile) 182 | B_DEBUG_PREFIX(debugLog)("log opened"); 183 | 184 | return; 185 | } 186 | 187 | if (!b__logFile) { 188 | /* try to open the default log file */ 189 | b__logFile = fopen("log.txt", "at"); 190 | if (!b__logFile) { 191 | /* can't assert here because assert also calls 192 | debugLog so we would enter an infinite loop.. */ 193 | return; 194 | } 195 | B_DEBUG_PREFIX(debugLog)("log opened"); 196 | } 197 | 198 | char timestamp[64]; 199 | time_t timeTicks = time(NULL); 200 | struct tm *t = localtime(&timeTicks); 201 | strftime(timestamp, sizeof(timestamp), "[%T] ", t); 202 | 203 | fprintf(stdout, timestamp); 204 | va_list args1; 205 | va_start(args1, message); 206 | vfprintf(stdout, message, args1); 207 | va_end(args1); 208 | fprintf(stdout, "\n"); 209 | 210 | fprintf(b__logFile, timestamp); 211 | va_list args2; 212 | va_start(args2, message); 213 | vfprintf(b__logFile, message, args2); 214 | va_end(args2); 215 | fprintf(b__logFile, "\n"); 216 | 217 | fflush(b__logFile); 218 | } 219 | 220 | #endif /* !B_DEBUG_IMPLEMENTED */ 221 | #endif /* B_DEBUG_IMPLEMENTATION */ 222 | 223 | /* 224 | ------------------------------------------------------------------------------ 225 | This software is available under 2 licenses - choose whichever you prefer. 226 | ------------------------------------------------------------------------------ 227 | ALTERNATIVE A - MIT License 228 | Copyright (c) 2020 Blat Blatnik 229 | Permission is hereby granted, free of charge, to any person obtaining a copy of 230 | this software and associated documentation files (the "Software"), to deal in 231 | the Software without restriction, including without limitation the rights to 232 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 233 | of the Software, and to permit persons to whom the Software is furnished to do 234 | so, subject to the following conditions: 235 | The above copyright notice and this permission notice shall be included in all 236 | copies or substantial portions of the Software. 237 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 238 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 239 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 240 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 241 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 242 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 243 | SOFTWARE. 244 | ------------------------------------------------------------------------------ 245 | ALTERNATIVE B - Public Domain (www.unlicense.org) 246 | This is free and unencumbered software released into the public domain. 247 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 248 | software, either in source code form or as a compiled binary, for any purpose, 249 | commercial or non-commercial, and by any means. 250 | In jurisdictions that recognize copyright laws, the author or authors of this 251 | software dedicate any and all copyright interest in the software to the public 252 | domain. We make this dedication for the benefit of the public at large and to 253 | the detriment of our heirs and successors. We intend this dedication to be an 254 | overt act of relinquishment in perpetuity of all present and future rights to 255 | this software under copyright law. 256 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 257 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 258 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 259 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 260 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 261 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 262 | ------------------------------------------------------------------------------ 263 | */ -------------------------------------------------------------------------------- /bfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | bfile.h - v0.1 - public domain file utilities 3 | 4 | by Blat Blatnik 5 | 6 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK 7 | 8 | For licence information see end of file. 9 | 10 | Do this: 11 | #define B_FILE_IMPLEMENTATION 12 | before you include this file in *ONE* C or C++ file to create the implementation. 13 | 14 | //i.e. it should look something like this: 15 | #include ... 16 | #include ... 17 | #include B_FILE_IMPLEMENTATION 18 | #include "bfile.h" 19 | 20 | NOTE: Currently, this file depends on the sys/stat.h header to get the time of last 21 | modification. Your compiler/OS does not provide this header then this will not 22 | compile, sorry. 23 | 24 | getFileSize 25 | - Return the full size of the given file in bytes. 26 | 27 | getFileTime 28 | - Return the time of last change of the given file as a time_t. 29 | 30 | readWholeFile 31 | - Reads the entire file and stores it in a malloce'd buffer. You 32 | need to call free on the return value. 33 | 34 | trackFileChanges 35 | - Register a given file to be tracked for changes. 36 | 37 | pollFileChanges 38 | - For all tracked files, check if they were modified and call 39 | a user passed function if they were. 40 | 41 | stopTrackingFiles 42 | - Stop tracking any files and free up used memory. 43 | 44 | ------------------- 45 | ----- Options ----- 46 | ------------------- 47 | 48 | #define any of these before including this file for them to take effect: 49 | 50 | #define B_FILE_PREFIX(name) [your-name-prefix] ## name 51 | #define B_PREFIX(name) [your-name-prefix] ## name 52 | - Add a prefix to all functions/variables/types declared by this file. 53 | Useful for avoiding name-conflicts. By default no prefix is added. 54 | 55 | #define B_FILE_REALLOC(mem, size) [your-realloc(mem, size)] 56 | - Avoid using stdlib.h for realloc by definining your own realloc function 57 | that this library will use to manage memory. 58 | */ 59 | 60 | #ifndef B_FILE_DEFINITION 61 | #define B_FILE_DEFINITION 62 | 63 | #ifndef B_FILE_PREFIX 64 | # ifdef B_PREFIX 65 | # define B_FILE_PREFIX(name) B_PREFIX(name) 66 | # else 67 | # define B_FILE_PREFIX(name) name 68 | # endif 69 | #endif 70 | 71 | #include 72 | 73 | /* return '0' from callback to keep tracking file, or non-zero to stop tracking */ 74 | typedef int(*B_FILE_PREFIX(FileChangeCallback))(const char *filename, void *userData); 75 | 76 | size_t B_FILE_PREFIX(getFileSize)(const char *filename); 77 | time_t B_FILE_PREFIX(getFileTime)(const char *filename); 78 | char * B_FILE_PREFIX(readWholeFile)(const char *filename, size_t *outLength); 79 | void B_FILE_PREFIX(trackFileChanges)(const char *filename, void *userData, B_FILE_PREFIX(FileChangeCallback) callback); 80 | void B_FILE_PREFIX(pollFileChanges)(void); 81 | void B_FILE_PREFIX(stopTrackingFiles)(void); 82 | 83 | #endif /* !B_FILE_DEFINITION */ 84 | 85 | /* 86 | * | | 87 | * v Implementation v 88 | * | | 89 | */ 90 | 91 | #ifdef B_FILE_IMPLEMENTATION 92 | #ifndef B_FILE_IMPLEMENTED 93 | #define B_FILE_IMPLEMENTED 94 | 95 | #ifndef B_FILE_REALLOC 96 | #include 97 | #define B_FILE_REALLOC(mem, size) realloc(mem, size) 98 | #endif 99 | 100 | /* !!! platform dependant !!! */ 101 | #include 102 | /* !!! platform dependant !!! */ 103 | 104 | #include 105 | 106 | typedef struct b__FileTrackData { 107 | time_t lastChange; 108 | void *userData; 109 | B_FILE_PREFIX(FileChangeCallback) callback; 110 | char *filenamePtr; 111 | char filenameBuffer[64]; 112 | } b__FileTrackData; 113 | 114 | /* tracked file data is stored in a DIY dynamic array */ 115 | static size_t b__trackedFilesCapacity; 116 | static size_t b__numTrackedFiles; 117 | static b__FileTrackData *b__trackedFiles; 118 | 119 | size_t B_FILE_PREFIX(getFileSize)(const char *filename) { 120 | FILE *f = fopen(filename, "rb"); 121 | if (!f) 122 | return 0; 123 | 124 | fseek(f, 0, SEEK_END); 125 | long fsize = ftell(f); 126 | fclose(f); 127 | return (size_t)fsize; 128 | } 129 | 130 | time_t B_FILE_PREFIX(getFileTime)(const char *filename) { 131 | struct stat s; 132 | int ret = stat(filename, &s); 133 | if (ret != 0) 134 | return (time_t)0; 135 | return s.st_mtime; 136 | } 137 | 138 | char *B_FILE_PREFIX(readWholeFile)(const char *filename, size_t *outLength) { 139 | FILE *f = fopen(filename, "rb"); 140 | fseek(f, 0, SEEK_END); 141 | long fsize = ftell(f); 142 | fseek(f, 0, SEEK_SET); 143 | 144 | if (outLength) 145 | *outLength = (size_t)fsize; 146 | 147 | char *string = (char *)B_FILE_REALLOC(NULL, (size_t)fsize + 1); 148 | fread(string, 1, (size_t)fsize, f); 149 | fclose(f); 150 | 151 | string[fsize] = 0; 152 | return string; 153 | } 154 | 155 | void B_FILE_PREFIX(trackFileChanges)(const char *filename, void *userData, B_FILE_PREFIX(FileChangeCallback) callback) { 156 | FILE *f = fopen(filename, "rb"); 157 | if (!f) 158 | return; 159 | fclose(f); 160 | 161 | size_t filenameSize = 1 + strlen(filename); 162 | 163 | b__FileTrackData data; 164 | data.lastChange = B_FILE_PREFIX(getFileTime)(filename); 165 | data.callback = callback; 166 | data.userData = userData; 167 | if (filenameSize <= sizeof(data.filenameBuffer)) { 168 | data.filenamePtr = NULL; 169 | memcpy(data.filenameBuffer, filename, filenameSize); 170 | } else { 171 | data.filenamePtr = (char *)B_FILE_REALLOC(NULL, filenameSize); 172 | memcpy(data.filenamePtr, filename, filenameSize); 173 | } 174 | 175 | if (b__numTrackedFiles + 1 > b__trackedFilesCapacity) { 176 | if (b__trackedFilesCapacity == 0) 177 | b__trackedFilesCapacity = 2; 178 | b__trackedFilesCapacity *= 2; 179 | b__trackedFiles = (b__FileTrackData *)B_FILE_REALLOC(b__trackedFiles, b__trackedFilesCapacity * sizeof(b__FileTrackData)); 180 | } 181 | 182 | b__trackedFiles[b__numTrackedFiles] = data; 183 | ++b__numTrackedFiles; 184 | } 185 | 186 | void B_FILE_PREFIX(pollFileChanges)(void) { 187 | for (size_t i = 0; i < b__numTrackedFiles; ++i) { 188 | b__FileTrackData *data = &b__trackedFiles[i]; 189 | const char *filename = data->filenamePtr ? data->filenamePtr : &data->filenameBuffer[0]; 190 | time_t changeTime = B_FILE_PREFIX(getFileTime)(filename); 191 | if (difftime(changeTime, data->lastChange) > 0) { 192 | data->lastChange = changeTime; 193 | int stopTracking = data->callback(filename, data->userData); 194 | /* returning non-zero means stop tracking */ 195 | if (stopTracking) { 196 | if (data->filenamePtr) 197 | B_FILE_REALLOC(data->filenamePtr, 0); 198 | memmove(&b__trackedFiles[i], &b__trackedFiles[i + 1], (b__numTrackedFiles - i - 1) * sizeof(*data)); 199 | --b__numTrackedFiles; 200 | --i; /* make sure to correct the loop */ 201 | } 202 | } 203 | } 204 | } 205 | 206 | void B_FILE_PREFIX(stopTrackingFiles)(void) { 207 | for (size_t i = 0; i < b__numTrackedFiles; ++i) 208 | if (b__trackedFiles[i].filenamePtr) 209 | B_FILE_REALLOC(b__trackedFiles[i].filenamePtr, 0); 210 | B_FILE_REALLOC(b__trackedFiles, 0); 211 | b__trackedFiles = NULL; 212 | b__trackedFilesCapacity = 0; 213 | b__numTrackedFiles = 0; 214 | } 215 | 216 | #endif /* !B_FILE_IMPLEMENTED */ 217 | #endif /* B_FILE_IMPLEMENTATION */ 218 | 219 | /* 220 | ------------------------------------------------------------------------------ 221 | This software is available under 2 licenses - choose whichever you prefer. 222 | ------------------------------------------------------------------------------ 223 | ALTERNATIVE A - MIT License 224 | Copyright (c) 2020 Blat Blatnik 225 | Permission is hereby granted, free of charge, to any person obtaining a copy of 226 | this software and associated documentation files (the "Software"), to deal in 227 | the Software without restriction, including without limitation the rights to 228 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 229 | of the Software, and to permit persons to whom the Software is furnished to do 230 | so, subject to the following conditions: 231 | The above copyright notice and this permission notice shall be included in all 232 | copies or substantial portions of the Software. 233 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 234 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 235 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 236 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 237 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 238 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 239 | SOFTWARE. 240 | ------------------------------------------------------------------------------ 241 | ALTERNATIVE B - Public Domain (www.unlicense.org) 242 | This is free and unencumbered software released into the public domain. 243 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 244 | software, either in source code form or as a compiled binary, for any purpose, 245 | commercial or non-commercial, and by any means. 246 | In jurisdictions that recognize copyright laws, the author or authors of this 247 | software dedicate any and all copyright interest in the software to the public 248 | domain. We make this dedication for the benefit of the public at large and to 249 | the detriment of our heirs and successors. We intend this dedication to be an 250 | overt act of relinquishment in perpetuity of all present and future rights to 251 | this software under copyright law. 252 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 253 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 254 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 255 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 256 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 257 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 258 | ------------------------------------------------------------------------------ 259 | */ -------------------------------------------------------------------------------- /bmath.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | bmath.hpp v0.32 - public domain math library by Blat Blatnik 3 | 4 | last updated February 2023 5 | 6 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK! For licence information see end of file. 7 | 8 | Primarily of interest to game developers and others who only need 9 | 2D, 3D, and 4D vector/matrix math and nothing more. This library 10 | is intended to be a lightweight alternative to GLM. Unlike GLM it 11 | does not go out of its way to provide GLSL equivalent functionality. 12 | Only the commonly used stuff is provided, things like sin(vec4) are not. 13 | Just like GLM, this is a header-only library. 14 | 15 | This library provides: 16 | + 2D, 3D and 4D vectors, 2x2, 3x3, 4x4 matrices, generic to any type 17 | + quaternions, generic to any type 18 | + full suite of vector operators (unary: + - ~ binary: + - * / % & | ^ << >>) 19 | + some matrix and quaternion operators (+ - * /) 20 | + most GLSL vector and matrix functions (but not all) 21 | + some color conversion functions 22 | + transform matrix building functions (perspective, translate, rotate, lookAt ..) 23 | + constexpr where possible 24 | 25 | This library does NOT provide: 26 | - non-square matrices 27 | - vectors of arbitrary size 28 | - "1D vectors" 29 | - dual quaternions 30 | - 16-bit floats 31 | - bit-twiddling math (bitCount, findLSB, bitfieldInsert) 32 | - trigonometric functions for vectors (sin, cos, ..) 33 | - packing functions (packDouble2x32, ..) 34 | - arbitrary vector swizzles 35 | - complete set of operators for matrices and quaternions 36 | - low-level optimization (simd, forceinline, ...) 37 | 38 | Most functions are implemented as templates in order to reduce code duplication. 39 | 40 | Matrices are stored in a column-major memory order to keep compatible with OpenGL. 41 | 42 | C++11 features (constexpr, log2, exp2) are used when compiler support is detected. 43 | But the library will still work in C++98. 44 | 45 | =================== 46 | ----- Options ----- 47 | =================== 48 | 49 | #define BMATH_NAMESPACE [your-custom-namespace] 50 | - Place all type definitions and functions in a namespace of your choosing. By 51 | default everything is defined in the global namespace 52 | 53 | #define BMATH_DEPTH_CLIP_ZERO_TO_ONE 54 | - By default the projection matrix functions assume depth values are clipped when 55 | they are outside [-1,+1] which is the default in OpenGL. Using this option the 56 | projection matrices will clip depth values outside of [0,1] which is the default 57 | in Vulkan and Direct3D 58 | 59 | #define BMATH_LEFT_HANDED 60 | - By default the projection and view matrices (orthoMat,lookAtMat) use a left-handed 61 | coordinate system. You can switch to right-handed coordinates. 62 | 63 | #define BMATH_NO_CPP11 64 | - Don't use C++ 11 features: constexpr and log2, exp2 from 65 | 66 | Either #define these before including the file, or just uncomment the lines below. 67 | */ 68 | 69 | //#define BMATH_NAMESPACE [your-custom-namespace] 70 | //#define BMATH_LEFT_HANDED 71 | //#define BMATH_DEPTH_CLIP_ZERO_TO_ONE 72 | //#define BMATH_NO_CPP11 73 | 74 | #pragma once 75 | #ifndef BMATH_H 76 | #define BMATH_H 77 | 78 | #include 79 | 80 | #ifdef BMATH_NAMESPACE 81 | # define BMATH_BEGIN namespace BMATH_NAMESPACE { 82 | # define BMATH_END } 83 | #else 84 | # define BMATH_BEGIN 85 | # define BMATH_END 86 | #endif 87 | 88 | #if !defined BMATH_DEPTH_CLIP_ZERO_TO_ONE && !defined BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 89 | # define BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 90 | #endif 91 | #if !defined BMATH_LEFT_HANDED && !defined BMATH_RIGHT_HANDED 92 | # define BMATH_RIGHT_HANDED 93 | #endif 94 | 95 | #ifndef BMATH_NO_CPP11 96 | # if defined _MSC_VER 97 | # if _MSC_VER >= 1900 98 | # define BMATH_HAS_CONSTEXPR 99 | # endif 100 | # if _MSC_VER >= 1800 101 | # define BMATH_HAS_DEFAULT_CONSTRUCTOR 102 | # endif 103 | # if _MSC_VER >= 1600 104 | # define BMATH_HAS_EXP2_LOG2 105 | # endif 106 | # elif defined __GNUC__ || defined __MINGW32__ 107 | # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 108 | # define BMATH_HAS_CONSTEXPR 109 | # endif 110 | # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 111 | # define BMATH_HAS_DEFAULT_CONSTRUCTOR 112 | # endif 113 | # define BMATH_HAS_EXP2_LOG2 114 | # elif defined __clang__ 115 | # if (__clang_major__ == 3 && __clang_minor__ >= 1) || __clang_major__ > 3 116 | # define BMATH_HAS_CONSTEXPR 117 | # endif 118 | # if (__clang_major__ == 3 && __clang_minor__ >= 0) || __clang_major__ > 3 119 | # define BMATH_HAS_DEFAULT_CONSTRUCTOR 120 | # endif 121 | # define BMATH_HAS_EXP2_LOG2 122 | # elif __cplusplus >= 201103L 123 | # define BMATH_HAS_CONSTEXPR 124 | # define BMATH_HAS_DEFAULT_CONSTRUCTOR 125 | # define BMATH_HAS_EXP2_LOG2 126 | # endif 127 | #endif // !BMATH_NO_CPP11 128 | 129 | #ifdef BMATH_HAS_CONSTEXPR 130 | # define BMATH_CONSTEXPR constexpr 131 | #else 132 | # define BMATH_CONSTEXPR 133 | #endif 134 | 135 | BMATH_BEGIN 136 | 137 | #ifdef BMATH_HAS_CONSTEXPR 138 | BMATH_CONSTEXPR float PI = 3.141592741f; 139 | BMATH_CONSTEXPR double PI64 = 3.141592653589793; 140 | #endif 141 | 142 | // Type Declarations 143 | 144 | template struct vector; 145 | template struct matrix; 146 | template struct quaternion; 147 | 148 | typedef unsigned int uint; 149 | typedef vector vec2; 150 | typedef vector vec3; 151 | typedef vector vec4; 152 | typedef vector dvec2; 153 | typedef vector dvec3; 154 | typedef vector dvec4; 155 | typedef vector ivec2; 156 | typedef vector ivec3; 157 | typedef vector ivec4; 158 | typedef vector uvec2; 159 | typedef vector uvec3; 160 | typedef vector uvec4; 161 | typedef vector bvec2; 162 | typedef vector bvec3; 163 | typedef vector bvec4; 164 | typedef matrix mat2; 165 | typedef matrix mat3; 166 | typedef matrix mat4; 167 | typedef matrix dmat2; 168 | typedef matrix dmat3; 169 | typedef matrix dmat4; 170 | typedef quaternion quat; 171 | typedef quaternion dquat; 172 | 173 | // Type Definitions 174 | 175 | // disable warning: nonstandard extension used nameless struct/union 176 | #if defined _MSC_VER 177 | # pragma warning(push) 178 | # pragma warning(disable: 4201) 179 | #elif defined __GNUC__ || defined __MINGW32__ 180 | # pragma GCC diagnostic push 181 | # pragma GCC diagnostic ignored "-Wpedantic" 182 | #elif defined __clang__ 183 | # pragma clang diagnostic push 184 | # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" 185 | # pragma clang diagnostic ignored "-Wnested-anon-types" 186 | #endif 187 | 188 | template 189 | struct vector { 190 | 191 | union { 192 | struct { T x, y; }; 193 | struct { T r, g; }; 194 | struct { T u, v; }; 195 | T elem[2]; 196 | }; 197 | 198 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 199 | inline vector() = default; 200 | inline BMATH_CONSTEXPR vector(const vector &v) = default; 201 | #else 202 | inline vector() {} 203 | inline BMATH_CONSTEXPR vector(const vector &v) 204 | : x(v.x), y(v.y) {}; 205 | #endif 206 | 207 | template 208 | inline BMATH_CONSTEXPR vector(X x, Y y) 209 | : x(T(x)), y(T(y)) {} 210 | 211 | template 212 | inline BMATH_CONSTEXPR explicit vector(XY xy) 213 | : x(T(xy)), y(T(xy)) {} 214 | 215 | template 216 | inline BMATH_CONSTEXPR explicit vector(vector xy) 217 | : x(T(xy.x)), y(T(xy.y)) {} 218 | 219 | template 220 | inline BMATH_CONSTEXPR explicit vector(vector xy) 221 | : x(T(xy.x)), y(T(xy.y)) {} 222 | 223 | template 224 | inline BMATH_CONSTEXPR explicit vector(vector xy) 225 | : x(T(xy.x)), y(T(xy.y)) {} 226 | 227 | inline T &operator[](int index) { 228 | return elem[index]; 229 | } 230 | inline BMATH_CONSTEXPR const T &operator[](int index) const { 231 | return elem[index]; 232 | } 233 | }; 234 | 235 | template 236 | struct vector { 237 | 238 | union { 239 | struct { T x, y, z; }; 240 | struct { T r, g, b; }; 241 | vector xy; 242 | T elem[3]; 243 | }; 244 | 245 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 246 | inline vector() = default; 247 | inline BMATH_CONSTEXPR vector(const vector & v) = default; 248 | #else 249 | inline vector() {} 250 | inline BMATH_CONSTEXPR vector(const vector &v) 251 | : x(v.x), y(v.y), z(v.z) {}; 252 | #endif 253 | 254 | template 255 | inline BMATH_CONSTEXPR vector(X x, Y y, Z z) 256 | : x(T(x)), y(T(y)), z(T(z)) {} 257 | 258 | template 259 | inline BMATH_CONSTEXPR vector(vector xy, Z z) 260 | : x(T(xy.x)), y(T(xy.y)), z(T(z)) {} 261 | 262 | template 263 | inline BMATH_CONSTEXPR vector(X x, vector yz) 264 | : x(T(x)), y(T(yz.x)), z(T(yz.y)) {} 265 | 266 | template 267 | inline BMATH_CONSTEXPR explicit vector(XYX xyz) 268 | : x(T(xyz)), y(T(xyz)), z(T(xyz)) {} 269 | 270 | template 271 | inline BMATH_CONSTEXPR explicit vector(vector xy) 272 | : x(T(xy.x)), y(T(xy.y)), z(T(0)) {} 273 | 274 | template 275 | inline BMATH_CONSTEXPR explicit vector(vector xyz) 276 | : x(T(xyz.x)), y(T(xyz.y)), z(T(xyz.z)) {} 277 | 278 | template 279 | inline BMATH_CONSTEXPR explicit vector(vector xyz) 280 | : x(T(xyz.x)), y(T(xyz.y)), z(T(xyz.z)) {} 281 | 282 | inline T &operator[](int index) { 283 | return elem[index]; 284 | } 285 | inline BMATH_CONSTEXPR const T &operator[](int index) const { 286 | return elem[index]; 287 | } 288 | }; 289 | 290 | template 291 | struct vector { 292 | 293 | union { 294 | struct { T x, y, z, w; }; 295 | struct { T r, g, b, a; }; 296 | vector xyz; 297 | vector rgb; 298 | struct { vector xy, zw; }; 299 | T elem[4]; 300 | }; 301 | 302 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 303 | inline vector() = default; 304 | inline BMATH_CONSTEXPR vector(const vector & v) = default; 305 | #else 306 | inline vector() {} 307 | inline BMATH_CONSTEXPR vector(const vector &v) 308 | : x(v.x), y(v.y), z(v.z), w(v.w) {}; 309 | #endif 310 | 311 | template 312 | inline BMATH_CONSTEXPR vector(X x, Y y, Z z, W w) 313 | : x(T(x)), y(T(y)), z(T(z)), w(T(w)) {} 314 | 315 | template 316 | inline BMATH_CONSTEXPR vector(vector xy, Z z, W w) 317 | : x(T(xy.x)), y(T(xy.y)), z(T(z)), w(T(w)) {} 318 | 319 | template 320 | inline BMATH_CONSTEXPR vector(X x, vector yz, W w) 321 | : x(T(x)), y(T(yz.x)), z(T(yz.y)), w(T(w)) {} 322 | 323 | template 324 | inline BMATH_CONSTEXPR vector(X x, Y y, vector zw) 325 | : x(T(x)), y(T(y)), z(T(zw.x)), w(T(zw.y)) {} 326 | 327 | template 328 | inline BMATH_CONSTEXPR vector(vector xy, vector zw) 329 | : x(T(xy.x)), y(T(xy.y)), z(T(zw.x)), w(T(zw.y)) {} 330 | 331 | template 332 | inline BMATH_CONSTEXPR vector(vector xyz, W w) 333 | : x(T(xyz.x)), y(T(xyz.y)), z(T(xyz.z)), w(T(w)) {} 334 | 335 | template 336 | inline BMATH_CONSTEXPR vector(X x, vector yzw) 337 | : x(T(x)), y(T(yzw.x)), z(T(yzw.y)), w(T(yzw.z)) {} 338 | 339 | template 340 | inline BMATH_CONSTEXPR explicit vector(XYZW xyzw) 341 | : x(T(xyzw)), y(T(xyzw)), z(T(xyzw)), w(T(xyzw)) {} 342 | 343 | template 344 | inline BMATH_CONSTEXPR explicit vector(vector xy) 345 | : x(T(xy.x)), y(T(xy.y)), z(T(0)), w(T(0)) {} 346 | 347 | template 348 | inline BMATH_CONSTEXPR explicit vector(vector xyz) 349 | : x(T(xyz.x)), y(T(xyz.y)), z(T(xyz.z)), w(T(0)) {} 350 | 351 | template 352 | inline BMATH_CONSTEXPR explicit vector(vector xyzw) 353 | : x(T(xyzw.x)), y(T(xyzw.y)), z(T(xyzw.z)), w(T(xyzw.w)) {} 354 | 355 | inline T &operator[](int index) { 356 | return elem[index]; 357 | } 358 | inline BMATH_CONSTEXPR const T &operator[](int index) const { 359 | return elem[index]; 360 | } 361 | }; 362 | 363 | template 364 | struct matrix { 365 | 366 | vector col[2]; 367 | 368 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 369 | inline matrix() = default; 370 | inline BMATH_CONSTEXPR matrix(const matrix &m) = default; 371 | #else 372 | inline matrix() {} 373 | inline BMATH_CONSTEXPR matrix(const matrix &m) 374 | : col{ m.col[0], m.col[1] } {}; 375 | #endif 376 | 377 | template< 378 | class X0, class Y0, 379 | class X1, class Y1> 380 | inline BMATH_CONSTEXPR matrix( 381 | X0 x0, Y0 y0, 382 | X1 x1, Y1 y1) 383 | : col{ 384 | vector(x0, y0), 385 | vector(x1, y1) } {} 386 | 387 | template< 388 | class C0, 389 | class C1> 390 | inline BMATH_CONSTEXPR matrix( 391 | vector col0, 392 | vector col1) 393 | : col{ col0, col1 } {} 394 | 395 | template 396 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 397 | : col{ 398 | vector(m.col[0]), 399 | vector(m.col[1]) } {} 400 | 401 | template 402 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 403 | : col{ 404 | vector(m.col[0].xy), 405 | vector(m.col[1].xy) } {} 406 | 407 | template 408 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 409 | : col{ 410 | vector(m.col[0].xy), 411 | vector(m.col[1].xy) } {} 412 | 413 | template 414 | inline BMATH_CONSTEXPR explicit matrix(vector diag) 415 | : col{ 416 | vector(diag.x, 0), 417 | vector( 0, diag.y) } {} 418 | 419 | template 420 | inline BMATH_CONSTEXPR explicit matrix(D diag) 421 | : col{ 422 | vector(diag, 0), 423 | vector( 0, diag) } {} 424 | 425 | inline vector &operator[](int index) { 426 | return col[index]; 427 | } 428 | inline BMATH_CONSTEXPR const vector &operator[](int index) const { 429 | return col[index]; 430 | } 431 | }; 432 | 433 | template 434 | struct matrix { 435 | 436 | vector col[3]; 437 | 438 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 439 | inline matrix() = default; 440 | inline BMATH_CONSTEXPR matrix(const matrix & m) = default; 441 | #else 442 | inline matrix() {} 443 | inline BMATH_CONSTEXPR matrix(const matrix &m) 444 | : col{ m.col[0], m.col[1], m.col[2] } {}; 445 | #endif 446 | 447 | template< 448 | class X0, class Y0, class Z0, 449 | class X1, class Y1, class Z1, 450 | class X2, class Y2, class Z2> 451 | inline BMATH_CONSTEXPR matrix( 452 | X0 x0, Y0 y0, Z0 z0, 453 | X1 x1, Y1 y1, Z1 z1, 454 | X2 x2, Y2 y2, Z2 z2) 455 | : col{ 456 | vector(x0, y0, z0), 457 | vector(x1, y1, z1), 458 | vector(x2, y2, z2)} {} 459 | 460 | template< 461 | class C0, 462 | class C1, 463 | class C2> 464 | inline BMATH_CONSTEXPR matrix( 465 | vector col0, 466 | vector col1, 467 | vector col2) 468 | : col{ 469 | vector(col0), 470 | vector(col1), 471 | vector(col2) } {} 472 | 473 | template 474 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 475 | : col{ 476 | vector(m.col[0], 0), 477 | vector(m.col[1], 0), 478 | vector(0, 0, 1) } {} 479 | 480 | template 481 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 482 | : col{ 483 | vector(m.col[0]), 484 | vector(m.col[1]), 485 | vector(m.col[2]) } {} 486 | 487 | template 488 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 489 | : col{ 490 | vector(m.col[0].xyz), 491 | vector(m.col[1].xyz), 492 | vector(m.col[2].xyz) } {} 493 | 494 | template 495 | inline BMATH_CONSTEXPR explicit matrix(vector diag) 496 | : col{ 497 | vector(diag.x, 0, 0), 498 | vector( 0, diag.y, 0), 499 | vector( 0, 0, diag.z) } {} 500 | 501 | template 502 | inline BMATH_CONSTEXPR explicit matrix(D diag) 503 | : col{ 504 | vector(diag, 0, 0), 505 | vector( 0, diag, 0), 506 | vector( 0, 0, diag) } {} 507 | 508 | inline vector &operator[](int index) { 509 | return col[index]; 510 | } 511 | inline BMATH_CONSTEXPR const vector &operator[](int index) const { 512 | return col[index]; 513 | } 514 | }; 515 | 516 | template 517 | struct matrix { 518 | 519 | vector col[4]; 520 | 521 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 522 | inline matrix() = default; 523 | inline BMATH_CONSTEXPR matrix(const matrix & m) = default; 524 | #else 525 | inline matrix() {} 526 | inline BMATH_CONSTEXPR matrix(const matrix &m) 527 | : col{ m.col[0], m.col[1], m.col[2], m.col[3] } {}; 528 | #endif 529 | 530 | template< 531 | class X0, class Y0, class Z0, class W0, 532 | class X1, class Y1, class Z1, class W1, 533 | class X2, class Y2, class Z2, class W2, 534 | class X3, class Y3, class Z3, class W3> 535 | inline BMATH_CONSTEXPR matrix( 536 | X0 x0, Y0 y0, Z0 z0, W0 w0, 537 | X1 x1, Y1 y1, Z1 z1, W1 w1, 538 | X2 x2, Y2 y2, Z2 z2, W2 w2, 539 | X3 x3, Y3 y3, Z3 z3, W3 w3) 540 | : col{ 541 | vector(x0, y0, z0, w0), 542 | vector(x1, y1, z1, w1), 543 | vector(x2, y2, z2, w2), 544 | vector(x3, y3, z3, w3) } {} 545 | 546 | template< 547 | class C0, 548 | class C1, 549 | class C2, 550 | class C3> 551 | inline BMATH_CONSTEXPR matrix( 552 | vector col0, 553 | vector col1, 554 | vector col2, 555 | vector col3) 556 | : col{ 557 | vector(col0), 558 | vector(col1), 559 | vector(col2), 560 | vector(col3) } {} 561 | 562 | template 563 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 564 | : col{ 565 | vector(m.col[0], 0, 0), 566 | vector(m.col[1], 0, 0), 567 | vector(0, 0, 1, 1), 568 | vector(0, 0, 0, 1) } {} 569 | 570 | template 571 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 572 | : col{ 573 | vector(m.col[0], 0), 574 | vector(m.col[1], 0), 575 | vector(m.col[2], 0), 576 | vector(0, 0, 0, 1) } {} 577 | 578 | template 579 | inline BMATH_CONSTEXPR explicit matrix(matrix m) 580 | : col{ 581 | vector(m.col[0]), 582 | vector(m.col[1]), 583 | vector(m.col[2]), 584 | vector(m.col[3]) } {} 585 | 586 | template 587 | inline BMATH_CONSTEXPR explicit matrix(vector diag) 588 | : col{ 589 | vector(diag.x, 0, 0, 0), 590 | vector( 0, diag.y, 0, 0), 591 | vector( 0, 0, diag.z, 0), 592 | vector( 0, 0, 0, diag.w) } {} 593 | 594 | template 595 | inline BMATH_CONSTEXPR explicit matrix(D diag) 596 | : col{ 597 | vector(diag, 0, 0, 0), 598 | vector( 0, diag, 0, 0), 599 | vector( 0, 0, diag, 0), 600 | vector( 0, 0, 0, diag) } {} 601 | 602 | inline vector &operator[](int index) { 603 | return col[index]; 604 | } 605 | inline BMATH_CONSTEXPR const vector &operator[](int index) const { 606 | return col[index]; 607 | } 608 | }; 609 | 610 | template 611 | struct quaternion { 612 | 613 | union { 614 | struct { T x, y, z, w; }; 615 | vector xyz; 616 | vector xyzw; 617 | T elem[4]; 618 | }; 619 | 620 | #ifdef BMATH_HAS_DEFAULT_CONSTRUCTOR 621 | inline quaternion() = default; 622 | inline BMATH_CONSTEXPR quaternion(const quaternion & q) = default; 623 | #else 624 | inline quaternion() {} 625 | inline BMATH_CONSTEXPR quaternion(const quaternion &q) 626 | : x(q.x), y(q.y), z(q.z), w(q.w) {}; 627 | #endif 628 | 629 | template 630 | inline BMATH_CONSTEXPR quaternion(X x, Y y, Z z, W w) 631 | : x(T(x)), y(T(y)), z(T(z)), w(T(w)) {} 632 | 633 | template 634 | inline BMATH_CONSTEXPR quaternion(vector xyz, W w) 635 | : x(T(xyz.x)), y(T(xyz.y)), z(T(xyz.z)), w(T(w)) {} 636 | 637 | template 638 | inline BMATH_CONSTEXPR explicit quaternion(vector xyzw) 639 | : x(T(xyzw.x)), y(T(xyzw.y)), z(T(xyzw.z)), w(T(xyzw.w)) {} 640 | 641 | template 642 | inline BMATH_CONSTEXPR explicit quaternion(quaternion q) 643 | : x(T(q.x)), y(T(q.y)), z(T(q.z)), w(T(q.w)) {} 644 | 645 | inline T &operator[](int index) { 646 | return elem[index]; 647 | } 648 | inline BMATH_CONSTEXPR const T &operator[](int index) const { 649 | return elem[index]; 650 | } 651 | }; 652 | 653 | // nonstandard extension used: nameless struct/union 654 | #if defined _MSC_VER 655 | # pragma warning(pop) 656 | #elif defined __GNUC__ || defined __MINGW32__ 657 | # pragma GCC diagnostic pop 658 | #elif defined __clang__ 659 | # pragma clang diagnostic pop 660 | #endif 661 | 662 | // Vector Operators 663 | 664 | template 665 | inline BMATH_CONSTEXPR vector operator +(vector v) { 666 | return vector(+v.x, +v.y); 667 | } 668 | 669 | template 670 | inline BMATH_CONSTEXPR vector operator +(vector v) { 671 | return vector(+v.x, +v.y, +v.z); 672 | } 673 | 674 | template 675 | inline BMATH_CONSTEXPR vector operator +(vector v) { 676 | return vector(+v.x, +v.y, +v.z, +v.w); 677 | } 678 | 679 | template 680 | inline BMATH_CONSTEXPR vector operator -(vector v) { 681 | return vector(-v.x, -v.y); 682 | } 683 | 684 | template 685 | inline BMATH_CONSTEXPR vector operator -(vector v) { 686 | return vector(-v.x, -v.y, -v.z); 687 | } 688 | 689 | template 690 | inline BMATH_CONSTEXPR vector operator -(vector v) { 691 | return vector(-v.x, -v.y, -v.z, -v.w); 692 | } 693 | 694 | template 695 | inline BMATH_CONSTEXPR vector operator ~(vector v) { 696 | return vector(~v.x, ~v.y); 697 | } 698 | 699 | template 700 | inline BMATH_CONSTEXPR vector operator ~(vector v) { 701 | return vector(~v.x, ~v.y, ~v.z); 702 | } 703 | 704 | template 705 | inline BMATH_CONSTEXPR vector operator ~(vector v) { 706 | return vector(~v.x, ~v.y, ~v.z, ~v.w); 707 | } 708 | 709 | template 710 | inline BMATH_CONSTEXPR vector operator +(vector left, vector right) { 711 | return vector( 712 | left.x + right.x, 713 | left.y + right.y); 714 | } 715 | 716 | template 717 | inline BMATH_CONSTEXPR vector operator +(vector left, vector right) { 718 | return vector( 719 | left.x + right.x, 720 | left.y + right.y, 721 | left.z + right.z); 722 | } 723 | 724 | template 725 | inline BMATH_CONSTEXPR vector operator +(vector left, vector right) { 726 | return vector( 727 | left.x + right.x, 728 | left.y + right.y, 729 | left.z + right.z, 730 | left.w + right.w); 731 | } 732 | 733 | template 734 | inline BMATH_CONSTEXPR vector operator -(vector left, vector right) { 735 | return vector( 736 | left.x - right.x, 737 | left.y - right.y); 738 | } 739 | 740 | template 741 | inline BMATH_CONSTEXPR vector operator -(vector left, vector right) { 742 | return vector( 743 | left.x - right.x, 744 | left.y - right.y, 745 | left.z - right.z); 746 | } 747 | 748 | template 749 | inline BMATH_CONSTEXPR vector operator -(vector left, vector right) { 750 | return vector( 751 | left.x - right.x, 752 | left.y - right.y, 753 | left.z - right.z, 754 | left.w - right.w); 755 | } 756 | 757 | template 758 | inline BMATH_CONSTEXPR vector operator *(vector left, vector right) { 759 | return vector( 760 | left.x * right.x, 761 | left.y * right.y); 762 | } 763 | 764 | template 765 | inline BMATH_CONSTEXPR vector operator *(vector left, vector right) { 766 | return vector( 767 | left.x * right.x, 768 | left.y * right.y, 769 | left.z * right.z); 770 | } 771 | 772 | template 773 | inline BMATH_CONSTEXPR vector operator *(vector left, vector right) { 774 | return vector( 775 | left.x * right.x, 776 | left.y * right.y, 777 | left.z * right.z, 778 | left.w * right.w); 779 | } 780 | 781 | template 782 | inline BMATH_CONSTEXPR vector operator /(vector left, vector right) { 783 | return vector( 784 | left.x / right.x, 785 | left.y / right.y); 786 | } 787 | 788 | template 789 | inline BMATH_CONSTEXPR vector operator /(vector left, vector right) { 790 | return vector( 791 | left.x / right.x, 792 | left.y / right.y, 793 | left.z / right.z); 794 | } 795 | 796 | template 797 | inline BMATH_CONSTEXPR vector operator /(vector left, vector right) { 798 | return vector( 799 | left.x / right.x, 800 | left.y / right.y, 801 | left.z / right.z, 802 | left.w / right.w); 803 | } 804 | 805 | template 806 | inline BMATH_CONSTEXPR vector operator %(vector left, vector right) { 807 | return vector( 808 | left.x % right.x, 809 | left.y % right.y); 810 | } 811 | 812 | template 813 | inline BMATH_CONSTEXPR vector operator %(vector left, vector right) { 814 | return vector( 815 | left.x % right.x, 816 | left.y % right.y, 817 | left.z % right.z); 818 | } 819 | 820 | template 821 | inline BMATH_CONSTEXPR vector operator %(vector left, vector right) { 822 | return vector( 823 | left.x % right.x, 824 | left.y % right.y, 825 | left.z % right.z, 826 | left.w % right.w); 827 | } 828 | 829 | template 830 | inline BMATH_CONSTEXPR vector operator &(vector left, vector right) { 831 | return vector( 832 | left.x & right.x, 833 | left.y & right.y); 834 | } 835 | 836 | template 837 | inline BMATH_CONSTEXPR vector operator &(vector left, vector right) { 838 | return vector( 839 | left.x & right.x, 840 | left.y & right.y, 841 | left.z & right.z); 842 | } 843 | 844 | template 845 | inline BMATH_CONSTEXPR vector operator &(vector left, vector right) { 846 | return vector( 847 | left.x & right.x, 848 | left.y & right.y, 849 | left.z & right.z, 850 | left.w & right.w); 851 | } 852 | 853 | template 854 | inline BMATH_CONSTEXPR vector operator |(vector left, vector right) { 855 | return vector( 856 | left.x | right.x, 857 | left.y | right.y); 858 | } 859 | 860 | template 861 | inline BMATH_CONSTEXPR vector operator |(vector left, vector right) { 862 | return vector( 863 | left.x | right.x, 864 | left.y | right.y, 865 | left.z | right.z); 866 | } 867 | 868 | template 869 | inline BMATH_CONSTEXPR vector operator |(vector left, vector right) { 870 | return vector( 871 | left.x | right.x, 872 | left.y | right.y, 873 | left.z | right.z, 874 | left.w | right.w); 875 | } 876 | 877 | template 878 | inline BMATH_CONSTEXPR vector operator ^(vector left, vector right) { 879 | return vector( 880 | left.x ^ right.x, 881 | left.y ^ right.y); 882 | } 883 | 884 | template 885 | inline BMATH_CONSTEXPR vector operator ^(vector left, vector right) { 886 | return vector( 887 | left.x ^ right.x, 888 | left.y ^ right.y, 889 | left.z ^ right.z); 890 | } 891 | 892 | template 893 | inline BMATH_CONSTEXPR vector operator ^(vector left, vector right) { 894 | return vector( 895 | left.x ^ right.x, 896 | left.y ^ right.y, 897 | left.z ^ right.z, 898 | left.w ^ right.w); 899 | } 900 | 901 | template 902 | inline BMATH_CONSTEXPR vector operator <<(vector left, vector right) { 903 | return vector( 904 | left.x << right.x, 905 | left.y << right.y); 906 | } 907 | 908 | template 909 | inline BMATH_CONSTEXPR vector operator <<(vector left, vector right) { 910 | return vector( 911 | left.x << right.x, 912 | left.y << right.y, 913 | left.z << right.z); 914 | } 915 | 916 | template 917 | inline BMATH_CONSTEXPR vector operator <<(vector left, vector right) { 918 | return vector( 919 | left.x << right.x, 920 | left.y << right.y, 921 | left.z << right.z, 922 | left.w << right.w); 923 | } 924 | 925 | template 926 | inline BMATH_CONSTEXPR vector operator >>(vector left, vector right) { 927 | return vector( 928 | left.x >> right.x, 929 | left.y >> right.y); 930 | } 931 | 932 | template 933 | inline BMATH_CONSTEXPR vector operator >>(vector left, vector right) { 934 | return vector( 935 | left.x >> right.x, 936 | left.y >> right.y, 937 | left.z >> right.z); 938 | } 939 | 940 | template 941 | inline BMATH_CONSTEXPR vector operator >>(vector left, vector right) { 942 | return vector( 943 | left.x >> right.x, 944 | left.y >> right.y, 945 | left.z >> right.z, 946 | left.w >> right.w); 947 | } 948 | 949 | template 950 | inline BMATH_CONSTEXPR vector operator ==(vector left, vector right) { 951 | return vector( 952 | left.x == right.x, 953 | left.y == right.y); 954 | } 955 | 956 | template 957 | inline BMATH_CONSTEXPR vector operator ==(vector left, vector right) { 958 | return vector( 959 | left.x == right.x, 960 | left.y == right.y, 961 | left.z == right.z); 962 | } 963 | 964 | template 965 | inline BMATH_CONSTEXPR vector operator ==(vector left, vector right) { 966 | return vector( 967 | left.x == right.x, 968 | left.y == right.y, 969 | left.z == right.z, 970 | left.w == right.w); 971 | } 972 | 973 | template 974 | inline BMATH_CONSTEXPR vector operator !=(vector left, vector right) { 975 | return vector( 976 | left.x != right.x, 977 | left.y != right.y); 978 | } 979 | 980 | template 981 | inline BMATH_CONSTEXPR vector operator !=(vector left, vector right) { 982 | return vector( 983 | left.x != right.x, 984 | left.y != right.y, 985 | left.z != right.z); 986 | } 987 | 988 | template 989 | inline BMATH_CONSTEXPR vector operator !=(vector left, vector right) { 990 | return vector( 991 | left.x != right.x, 992 | left.y != right.y, 993 | left.z != right.z, 994 | left.w != right.w); 995 | } 996 | 997 | template 998 | inline BMATH_CONSTEXPR vector operator >=(vector left, vector right) { 999 | return vector( 1000 | left.x >= right.x, 1001 | left.y >= right.y); 1002 | } 1003 | 1004 | template 1005 | inline BMATH_CONSTEXPR vector operator >=(vector left, vector right) { 1006 | return vector( 1007 | left.x >= right.x, 1008 | left.y >= right.y, 1009 | left.z >= right.z); 1010 | } 1011 | 1012 | template 1013 | inline BMATH_CONSTEXPR vector operator >=(vector left, vector right) { 1014 | return vector( 1015 | left.x >= right.x, 1016 | left.y >= right.y, 1017 | left.z >= right.z, 1018 | left.w >= right.w); 1019 | } 1020 | 1021 | template 1022 | inline BMATH_CONSTEXPR vector operator <=(vector left, vector right) { 1023 | return vector( 1024 | left.x <= right.x, 1025 | left.y <= right.y); 1026 | } 1027 | 1028 | template 1029 | inline BMATH_CONSTEXPR vector operator <=(vector left, vector right) { 1030 | return vector( 1031 | left.x <= right.x, 1032 | left.y <= right.y, 1033 | left.z <= right.z); 1034 | } 1035 | 1036 | template 1037 | inline BMATH_CONSTEXPR vector operator <=(vector left, vector right) { 1038 | return vector( 1039 | left.x <= right.x, 1040 | left.y <= right.y, 1041 | left.z <= right.z, 1042 | left.w <= right.w); 1043 | } 1044 | 1045 | template 1046 | inline BMATH_CONSTEXPR vector operator >(vector left, vector right) { 1047 | return vector( 1048 | left.x > right.x, 1049 | left.y > right.y); 1050 | } 1051 | 1052 | template 1053 | inline BMATH_CONSTEXPR vector operator >(vector left, vector right) { 1054 | return vector( 1055 | left.x > right.x, 1056 | left.y > right.y, 1057 | left.z > right.z); 1058 | } 1059 | 1060 | template 1061 | inline BMATH_CONSTEXPR vector operator >(vector left, vector right) { 1062 | return vector( 1063 | left.x > right.x, 1064 | left.y > right.y, 1065 | left.z > right.z, 1066 | left.w > right.w); 1067 | } 1068 | 1069 | template 1070 | inline BMATH_CONSTEXPR vector operator <(vector left, vector right) { 1071 | return vector( 1072 | left.x < right.x, 1073 | left.y < right.y); 1074 | } 1075 | 1076 | template 1077 | inline BMATH_CONSTEXPR vector operator <(vector left, vector right) { 1078 | return vector( 1079 | left.x < right.x, 1080 | left.y < right.y, 1081 | left.z < right.z); 1082 | } 1083 | 1084 | template 1085 | inline BMATH_CONSTEXPR vector operator <(vector left, vector right) { 1086 | return vector( 1087 | left.x < right.x, 1088 | left.y < right.y, 1089 | left.z < right.z, 1090 | left.w < right.w); 1091 | } 1092 | 1093 | template 1094 | inline BMATH_CONSTEXPR vector operator +(vector left, T right) { 1095 | return left + vector(right); 1096 | } 1097 | 1098 | template 1099 | inline BMATH_CONSTEXPR vector operator -(vector left, T right) { 1100 | return left - vector(right); 1101 | } 1102 | 1103 | template 1104 | inline BMATH_CONSTEXPR vector operator *(vector left, T right) { 1105 | return left * vector(right); 1106 | } 1107 | 1108 | template 1109 | inline BMATH_CONSTEXPR vector operator /(vector left, T right) { 1110 | return left / vector(right); 1111 | } 1112 | 1113 | template 1114 | inline BMATH_CONSTEXPR vector operator %(vector left, T right) { 1115 | return left % vector(right); 1116 | } 1117 | 1118 | template 1119 | inline BMATH_CONSTEXPR vector operator &(vector left, T right) { 1120 | return left & vector(right); 1121 | } 1122 | 1123 | template 1124 | inline BMATH_CONSTEXPR vector operator |(vector left, T right) { 1125 | return left | vector(right); 1126 | } 1127 | 1128 | template 1129 | inline BMATH_CONSTEXPR vector operator ^(vector left, T right) { 1130 | return left ^ vector(right); 1131 | } 1132 | 1133 | template 1134 | inline BMATH_CONSTEXPR vector operator <<(vector left, T right) { 1135 | return left << vector(right); 1136 | } 1137 | 1138 | template 1139 | inline BMATH_CONSTEXPR vector operator >>(vector left, T right) { 1140 | return left >> vector(right); 1141 | } 1142 | 1143 | template 1144 | inline BMATH_CONSTEXPR vector operator ==(vector left, T right) { 1145 | return left == vector(right); 1146 | } 1147 | 1148 | template 1149 | inline BMATH_CONSTEXPR vector operator !=(vector left, T right) { 1150 | return left != vector(right); 1151 | } 1152 | 1153 | template 1154 | inline BMATH_CONSTEXPR vector operator >=(vector left, T right) { 1155 | return left >= vector(right); 1156 | } 1157 | 1158 | template 1159 | inline BMATH_CONSTEXPR vector operator <=(vector left, T right) { 1160 | return left <= vector(right); 1161 | } 1162 | 1163 | template 1164 | inline BMATH_CONSTEXPR vector operator >(vector left, T right) { 1165 | return left > vector(right); 1166 | } 1167 | 1168 | template 1169 | inline BMATH_CONSTEXPR vector operator <(vector left, T right) { 1170 | return left < vector(right); 1171 | } 1172 | 1173 | template 1174 | inline BMATH_CONSTEXPR vector operator +(T left, vector right) { 1175 | return vector(left) + right; 1176 | } 1177 | 1178 | template 1179 | inline BMATH_CONSTEXPR vector operator -(T left, vector right) { 1180 | return vector(left) - right; 1181 | } 1182 | 1183 | template 1184 | inline BMATH_CONSTEXPR vector operator *(T left, vector right) { 1185 | return vector(left) * right; 1186 | } 1187 | 1188 | template 1189 | inline BMATH_CONSTEXPR vector operator /(T left, vector right) { 1190 | return vector(left) / right; 1191 | } 1192 | 1193 | template 1194 | inline BMATH_CONSTEXPR vector operator %(T left, vector right) { 1195 | return vector(left) % right; 1196 | } 1197 | 1198 | template 1199 | inline BMATH_CONSTEXPR vector operator &(T left, vector right) { 1200 | return vector(left) & right; 1201 | } 1202 | 1203 | template 1204 | inline BMATH_CONSTEXPR vector operator |(T left, vector right) { 1205 | return vector(left) | right; 1206 | } 1207 | 1208 | template 1209 | inline BMATH_CONSTEXPR vector operator ^(T left, vector right) { 1210 | return vector(left) ^ right; 1211 | } 1212 | 1213 | template 1214 | inline BMATH_CONSTEXPR vector operator <<(T left, vector right) { 1215 | return vector(left) << right; 1216 | } 1217 | 1218 | template 1219 | inline BMATH_CONSTEXPR vector operator >>(T left, vector right) { 1220 | return vector(left) >> right; 1221 | } 1222 | 1223 | template 1224 | inline BMATH_CONSTEXPR vector operator ==(T left, vector right) { 1225 | return vector(left) == right; 1226 | } 1227 | 1228 | template 1229 | inline BMATH_CONSTEXPR vector operator !=(T left, vector right) { 1230 | return vector(left) != right; 1231 | } 1232 | 1233 | template 1234 | inline BMATH_CONSTEXPR vector operator >=(T left, vector right) { 1235 | return vector(left) >= right; 1236 | } 1237 | 1238 | template 1239 | inline BMATH_CONSTEXPR vector operator <=(T left, vector right) { 1240 | return vector(left) <= right; 1241 | } 1242 | 1243 | template 1244 | inline BMATH_CONSTEXPR vector operator >(T left, vector right) { 1245 | return vector(left) > right; 1246 | } 1247 | 1248 | template 1249 | inline BMATH_CONSTEXPR vector operator <(T left, vector right) { 1250 | return vector(left) < right; 1251 | } 1252 | 1253 | template 1254 | inline vector &operator +=(vector &left, vector right) { 1255 | return left = left + right; 1256 | } 1257 | 1258 | template 1259 | inline vector &operator -=(vector &left, vector right) { 1260 | return left = left - right; 1261 | } 1262 | 1263 | template 1264 | inline vector &operator *=(vector &left, vector right) { 1265 | return left = left * right; 1266 | } 1267 | 1268 | template 1269 | inline vector &operator /=(vector &left, vector right) { 1270 | return left = left / right; 1271 | } 1272 | 1273 | template 1274 | inline vector &operator %=(vector &left, vector right) { 1275 | return left = left % right; 1276 | } 1277 | 1278 | template 1279 | inline vector &operator &=(vector &left, vector right) { 1280 | return left = left & right; 1281 | } 1282 | 1283 | template 1284 | inline vector &operator |=(vector &left, vector right) { 1285 | return left = left | right; 1286 | } 1287 | 1288 | template 1289 | inline vector &operator ^=(vector &left, vector right) { 1290 | return left = left ^ right; 1291 | } 1292 | 1293 | template 1294 | inline vector &operator <<=(vector &left, vector right) { 1295 | return left = left << right; 1296 | } 1297 | 1298 | template 1299 | inline vector &operator >>=(vector &left, vector right) { 1300 | return left = left >> right; 1301 | } 1302 | 1303 | template 1304 | inline vector &operator +=(vector &left, T right) { 1305 | return left = left + right; 1306 | } 1307 | 1308 | template 1309 | inline vector &operator -=(vector &left, T right) { 1310 | return left = left - right; 1311 | } 1312 | 1313 | template 1314 | inline vector &operator *=(vector &left, T right) { 1315 | return left = left * right; 1316 | } 1317 | 1318 | template 1319 | inline vector &operator /=(vector &left, T right) { 1320 | return left = left / right; 1321 | } 1322 | 1323 | template 1324 | inline vector &operator %=(vector &left, T right) { 1325 | return left = left % right; 1326 | } 1327 | 1328 | template 1329 | inline vector &operator &=(vector &left, T right) { 1330 | return left = left & right; 1331 | } 1332 | 1333 | template 1334 | inline vector &operator |=(vector &left, T right) { 1335 | return left = left | right; 1336 | } 1337 | 1338 | template 1339 | inline vector &operator ^=(vector &left, T right) { 1340 | return left = left ^ right; 1341 | } 1342 | 1343 | template 1344 | inline vector &operator <<=(vector &left, T right) { 1345 | return left = left << right; 1346 | } 1347 | 1348 | template 1349 | inline vector &operator >>=(vector &left, T right) { 1350 | return left = left >> right; 1351 | } 1352 | 1353 | template 1354 | inline vector operator ++(vector &v) { 1355 | return v += T(1); 1356 | } 1357 | 1358 | template 1359 | inline vector operator ++(vector &v, int) { 1360 | vector copy = v; 1361 | v += T(1); 1362 | return copy; 1363 | } 1364 | 1365 | template 1366 | inline vector operator --(vector &v) { 1367 | return v -= T(1); 1368 | } 1369 | 1370 | template 1371 | inline vector operator --(vector &v, int) { 1372 | vector copy = v; 1373 | v -= T(1); 1374 | return copy; 1375 | } 1376 | 1377 | // Matrix Operators 1378 | 1379 | template 1380 | inline BMATH_CONSTEXPR matrix operator +(matrix m) { 1381 | return matrix( 1382 | +m.col[0], 1383 | +m.col[1]); 1384 | } 1385 | 1386 | template 1387 | inline BMATH_CONSTEXPR matrix operator +(matrix m) { 1388 | return matrix( 1389 | +m.col[0], 1390 | +m.col[1], 1391 | +m.col[2]); 1392 | } 1393 | 1394 | template 1395 | inline BMATH_CONSTEXPR matrix operator +(matrix m) { 1396 | return matrix( 1397 | +m.col[0], 1398 | +m.col[1], 1399 | +m.col[2], 1400 | +m.col[3]); 1401 | } 1402 | 1403 | template 1404 | inline BMATH_CONSTEXPR matrix operator -(matrix m) { 1405 | return matrix( 1406 | -m.col[0], 1407 | -m.col[1]); 1408 | } 1409 | 1410 | template 1411 | inline BMATH_CONSTEXPR matrix operator -(matrix m) { 1412 | return matrix( 1413 | -m.col[0], 1414 | -m.col[1], 1415 | -m.col[2]); 1416 | } 1417 | 1418 | template 1419 | inline BMATH_CONSTEXPR matrix operator -(matrix m) { 1420 | return matrix( 1421 | -m.col[0], 1422 | -m.col[1], 1423 | -m.col[2], 1424 | -m.col[3]); 1425 | } 1426 | 1427 | template 1428 | inline BMATH_CONSTEXPR matrix operator +(matrix left, matrix right) { 1429 | return matrix( 1430 | left.col[0] + right.col[0], 1431 | left.col[1] + right.col[1]); 1432 | } 1433 | 1434 | template 1435 | inline BMATH_CONSTEXPR matrix operator +(matrix left, matrix right) { 1436 | return matrix( 1437 | left.col[0] + right.col[0], 1438 | left.col[1] + right.col[1], 1439 | left.col[2] + right.col[2]); 1440 | } 1441 | 1442 | template 1443 | inline BMATH_CONSTEXPR matrix operator +(matrix left, matrix right) { 1444 | return matrix( 1445 | left.col[0] + right.col[0], 1446 | left.col[1] + right.col[1], 1447 | left.col[2] + right.col[2], 1448 | left.col[3] + right.col[3]); 1449 | } 1450 | 1451 | template 1452 | inline BMATH_CONSTEXPR matrix operator -(matrix left, matrix right) { 1453 | return matrix( 1454 | left.col[0] - right.col[0], 1455 | left.col[1] - right.col[1]); 1456 | } 1457 | 1458 | template 1459 | inline BMATH_CONSTEXPR matrix operator -(matrix left, matrix right) { 1460 | return matrix( 1461 | left.col[0] - right.col[0], 1462 | left.col[1] - right.col[1], 1463 | left.col[2] - right.col[2]); 1464 | } 1465 | 1466 | template 1467 | inline BMATH_CONSTEXPR matrix operator -(matrix left, matrix right) { 1468 | return matrix( 1469 | left.col[0] - right.col[0], 1470 | left.col[1] - right.col[1], 1471 | left.col[2] - right.col[2], 1472 | left.col[3] - right.col[3]); 1473 | } 1474 | 1475 | template 1476 | inline BMATH_CONSTEXPR matrix operator *(matrix left, matrix right) { 1477 | return matrix( 1478 | 1479 | left.col[0].x * right.col[0].x + left.col[1].x * right.col[0].y, 1480 | left.col[0].y * right.col[0].x + left.col[1].y * right.col[0].y, 1481 | 1482 | left.col[0].x * right.col[1].x + left.col[1].x * right.col[1].y, 1483 | left.col[0].y * right.col[1].x + left.col[1].y * right.col[1].y); 1484 | } 1485 | 1486 | template 1487 | inline BMATH_CONSTEXPR matrix operator *(matrix left, matrix right) { 1488 | return matrix( 1489 | 1490 | left.col[0].x * right.col[0].x + left.col[1].x * right.col[0].y + left.col[2].x * right.col[0].z, 1491 | left.col[0].y * right.col[0].x + left.col[1].y * right.col[0].y + left.col[2].y * right.col[0].z, 1492 | left.col[0].z * right.col[0].x + left.col[1].z * right.col[0].y + left.col[2].z * right.col[0].z, 1493 | 1494 | left.col[0].x * right.col[1].x + left.col[1].x * right.col[1].y + left.col[2].x * right.col[1].z, 1495 | left.col[0].y * right.col[1].x + left.col[1].y * right.col[1].y + left.col[2].y * right.col[1].z, 1496 | left.col[0].z * right.col[1].x + left.col[1].z * right.col[1].y + left.col[2].z * right.col[1].z, 1497 | 1498 | left.col[0].x * right.col[2].x + left.col[1].x * right.col[2].y + left.col[2].x * right.col[2].z, 1499 | left.col[0].y * right.col[2].x + left.col[1].y * right.col[2].y + left.col[2].y * right.col[2].z, 1500 | left.col[0].z * right.col[2].x + left.col[1].z * right.col[2].y + left.col[2].z * right.col[2].z); 1501 | } 1502 | 1503 | template 1504 | inline BMATH_CONSTEXPR matrix operator *(matrix left, matrix right) { 1505 | return matrix( 1506 | 1507 | left.col[0].x * right.col[0].x + left.col[1].x * right.col[0].y + left.col[2].x * right.col[0].z + left.col[3].x * right.col[0].w, 1508 | left.col[0].y * right.col[0].x + left.col[1].y * right.col[0].y + left.col[2].y * right.col[0].z + left.col[3].y * right.col[0].w, 1509 | left.col[0].z * right.col[0].x + left.col[1].z * right.col[0].y + left.col[2].z * right.col[0].z + left.col[3].z * right.col[0].w, 1510 | left.col[0].w * right.col[0].x + left.col[1].w * right.col[0].y + left.col[2].w * right.col[0].z + left.col[3].w * right.col[0].w, 1511 | 1512 | left.col[0].x * right.col[1].x + left.col[1].x * right.col[1].y + left.col[2].x * right.col[1].z + left.col[3].x * right.col[1].w, 1513 | left.col[0].y * right.col[1].x + left.col[1].y * right.col[1].y + left.col[2].y * right.col[1].z + left.col[3].y * right.col[1].w, 1514 | left.col[0].z * right.col[1].x + left.col[1].z * right.col[1].y + left.col[2].z * right.col[1].z + left.col[3].z * right.col[1].w, 1515 | left.col[0].w * right.col[1].x + left.col[1].w * right.col[1].y + left.col[2].w * right.col[1].z + left.col[3].w * right.col[1].w, 1516 | 1517 | left.col[0].x * right.col[2].x + left.col[1].x * right.col[2].y + left.col[2].x * right.col[2].z + left.col[3].x * right.col[2].w, 1518 | left.col[0].y * right.col[2].x + left.col[1].y * right.col[2].y + left.col[2].y * right.col[2].z + left.col[3].y * right.col[2].w, 1519 | left.col[0].z * right.col[2].x + left.col[1].z * right.col[2].y + left.col[2].z * right.col[2].z + left.col[3].z * right.col[2].w, 1520 | left.col[0].w * right.col[2].x + left.col[1].w * right.col[2].y + left.col[2].w * right.col[2].z + left.col[3].w * right.col[2].w, 1521 | 1522 | left.col[0].x * right.col[3].x + left.col[1].x * right.col[3].y + left.col[2].x * right.col[3].z + left.col[3].x * right.col[3].w, 1523 | left.col[0].y * right.col[3].x + left.col[1].y * right.col[3].y + left.col[2].y * right.col[3].z + left.col[3].y * right.col[3].w, 1524 | left.col[0].z * right.col[3].x + left.col[1].z * right.col[3].y + left.col[2].z * right.col[3].z + left.col[3].z * right.col[3].w, 1525 | left.col[0].w * right.col[3].x + left.col[1].w * right.col[3].y + left.col[2].w * right.col[3].z + left.col[3].w * right.col[3].w); 1526 | } 1527 | 1528 | template 1529 | inline BMATH_CONSTEXPR vector operator *(matrix left, vector right) { 1530 | return vector( 1531 | left.col[0].x * right.x + left.col[1].x * right.y, 1532 | left.col[0].y * right.x + left.col[1].y * right.y); 1533 | } 1534 | 1535 | template 1536 | inline BMATH_CONSTEXPR vector operator *(matrix left, vector right) { 1537 | return vector( 1538 | left.col[0].x * right.x + left.col[1].x * right.y + left.col[2].x * right.z, 1539 | left.col[0].y * right.x + left.col[1].y * right.y + left.col[2].y * right.z, 1540 | left.col[0].z * right.x + left.col[1].z * right.y + left.col[2].z * right.z); 1541 | } 1542 | 1543 | template 1544 | inline BMATH_CONSTEXPR vector operator *(matrix left, vector right) { 1545 | return vector( 1546 | left.col[0].x * right.x + left.col[1].x * right.y + left.col[2].x * right.z + left.col[3].x * right.w, 1547 | left.col[0].y * right.x + left.col[1].y * right.y + left.col[2].y * right.z + left.col[3].y * right.w, 1548 | left.col[0].z * right.x + left.col[1].z * right.y + left.col[2].z * right.z + left.col[3].z * right.w, 1549 | left.col[0].w * right.x + left.col[1].w * right.y + left.col[2].w * right.z + left.col[3].w * right.w); 1550 | } 1551 | 1552 | template 1553 | inline BMATH_CONSTEXPR matrix operator /(matrix left, matrix right) { 1554 | return matrix( 1555 | left.col[0] / right.col[0], 1556 | left.col[1] / right.col[1]); 1557 | } 1558 | 1559 | template 1560 | inline BMATH_CONSTEXPR matrix operator /(matrix left, matrix right) { 1561 | return matrix( 1562 | left.col[0] / right.col[0], 1563 | left.col[1] / right.col[1], 1564 | left.col[2] / right.col[2]); 1565 | } 1566 | 1567 | template 1568 | inline BMATH_CONSTEXPR matrix operator /(matrix left, matrix right) { 1569 | return matrix( 1570 | left.col[0] / right.col[0], 1571 | left.col[1] / right.col[1], 1572 | left.col[2] / right.col[2], 1573 | left.col[3] / right.col[3]); 1574 | } 1575 | 1576 | template 1577 | inline BMATH_CONSTEXPR matrix operator +(matrix left, T right) { 1578 | return left + matrix( 1579 | vector(right), 1580 | vector(right)); 1581 | } 1582 | 1583 | template 1584 | inline BMATH_CONSTEXPR matrix operator +(matrix left, T right) { 1585 | return left + matrix( 1586 | vector(right), 1587 | vector(right), 1588 | vector(right)); 1589 | } 1590 | 1591 | template 1592 | inline BMATH_CONSTEXPR matrix operator +(matrix left, T right) { 1593 | return left + matrix( 1594 | vector(right), 1595 | vector(right), 1596 | vector(right), 1597 | vector(right)); 1598 | } 1599 | 1600 | template 1601 | inline BMATH_CONSTEXPR matrix operator -(matrix left, T right) { 1602 | return left - matrix( 1603 | vector(right), 1604 | vector(right)); 1605 | } 1606 | 1607 | template 1608 | inline BMATH_CONSTEXPR matrix operator -(matrix left, T right) { 1609 | return left - matrix( 1610 | vector(right), 1611 | vector(right), 1612 | vector(right)); 1613 | } 1614 | 1615 | template 1616 | inline BMATH_CONSTEXPR matrix operator -(matrix left, T right) { 1617 | return left - matrix( 1618 | vector(right), 1619 | vector(right), 1620 | vector(right), 1621 | vector(right)); 1622 | } 1623 | 1624 | template 1625 | inline BMATH_CONSTEXPR matrix operator *(matrix left, T right) { 1626 | return matrix( 1627 | left.col[0] * vector(right), 1628 | left.col[1] * vector(right)); 1629 | } 1630 | 1631 | template 1632 | inline BMATH_CONSTEXPR matrix operator *(matrix left, T right) { 1633 | return matrix( 1634 | left.col[0] * vector(right), 1635 | left.col[1] * vector(right), 1636 | left.col[2] * vector(right)); 1637 | } 1638 | 1639 | template 1640 | inline BMATH_CONSTEXPR matrix operator *(matrix left, T right) { 1641 | return matrix( 1642 | left.col[0] * vector(right), 1643 | left.col[1] * vector(right), 1644 | left.col[2] * vector(right), 1645 | left.col[3] * vector(right)); 1646 | } 1647 | 1648 | template 1649 | inline BMATH_CONSTEXPR matrix operator /(matrix left, T right) { 1650 | return left / matrix( 1651 | vector(right), 1652 | vector(right)); 1653 | } 1654 | 1655 | template 1656 | inline BMATH_CONSTEXPR matrix operator /(matrix left, T right) { 1657 | return left / matrix( 1658 | vector(right), 1659 | vector(right), 1660 | vector(right)); 1661 | } 1662 | 1663 | template 1664 | inline BMATH_CONSTEXPR matrix operator /(matrix left, T right) { 1665 | return left / matrix( 1666 | vector(right), 1667 | vector(right), 1668 | vector(right), 1669 | vector(right)); 1670 | } 1671 | 1672 | template 1673 | inline BMATH_CONSTEXPR matrix operator +(T left, matrix right) { 1674 | return right + left; 1675 | } 1676 | 1677 | template 1678 | inline BMATH_CONSTEXPR matrix operator *(T left, matrix right) { 1679 | return right * left; 1680 | } 1681 | 1682 | template 1683 | inline BMATH_CONSTEXPR matrix operator -(T left, matrix right) { 1684 | return matrix( 1685 | vector(left), 1686 | vector(left)) - right; 1687 | } 1688 | 1689 | template 1690 | inline BMATH_CONSTEXPR matrix operator -(T left, matrix right) { 1691 | return matrix( 1692 | vector(left), 1693 | vector(left), 1694 | vector(left)) - right; 1695 | } 1696 | 1697 | template 1698 | inline BMATH_CONSTEXPR matrix operator -(T left, matrix right) { 1699 | return matrix( 1700 | vector(left), 1701 | vector(left), 1702 | vector(left), 1703 | vector(left)) - right; 1704 | } 1705 | 1706 | template 1707 | inline BMATH_CONSTEXPR matrix operator /(T left, matrix right) { 1708 | return matrix( 1709 | vector(left), 1710 | vector(left)) / right; 1711 | } 1712 | 1713 | template 1714 | inline BMATH_CONSTEXPR matrix operator /(T left, matrix right) { 1715 | return matrix( 1716 | vector(left), 1717 | vector(left), 1718 | vector(left)) / right; 1719 | } 1720 | 1721 | template 1722 | inline BMATH_CONSTEXPR matrix operator /(T left, matrix right) { 1723 | return matrix( 1724 | vector(left), 1725 | vector(left), 1726 | vector(left), 1727 | vector(left)) / right; 1728 | } 1729 | 1730 | template 1731 | inline BMATH_CONSTEXPR bool operator ==(matrix left, matrix right) { 1732 | return 1733 | left.col[0].x == right.col[0].x and 1734 | left.col[0].y == right.col[0].y and 1735 | left.col[1].x == right.col[1].x and 1736 | left.col[1].y == right.col[1].y; 1737 | } 1738 | 1739 | template 1740 | inline BMATH_CONSTEXPR bool operator ==(matrix left, matrix right) { 1741 | return 1742 | left.col[0].x == right.col[0].x and 1743 | left.col[0].y == right.col[0].y and 1744 | left.col[0].z == right.col[0].z and 1745 | left.col[1].x == right.col[1].x and 1746 | left.col[1].y == right.col[1].y and 1747 | left.col[1].z == right.col[1].z and 1748 | left.col[2].x == right.col[2].x and 1749 | left.col[2].y == right.col[2].y and 1750 | left.col[2].z == right.col[2].z; 1751 | } 1752 | 1753 | template 1754 | inline BMATH_CONSTEXPR bool operator ==(matrix left, matrix right) { 1755 | return 1756 | left.col[0].x == right.col[0].x and 1757 | left.col[0].y == right.col[0].y and 1758 | left.col[0].z == right.col[0].z and 1759 | left.col[0].w == right.col[0].w and 1760 | left.col[1].x == right.col[1].x and 1761 | left.col[1].y == right.col[1].y and 1762 | left.col[1].z == right.col[1].z and 1763 | left.col[1].w == right.col[1].w and 1764 | left.col[2].x == right.col[2].x and 1765 | left.col[2].y == right.col[2].y and 1766 | left.col[2].z == right.col[2].z and 1767 | left.col[2].w == right.col[2].w and 1768 | left.col[3].x == right.col[3].x and 1769 | left.col[3].y == right.col[3].y and 1770 | left.col[3].z == right.col[3].z and 1771 | left.col[3].w == right.col[3].w; 1772 | } 1773 | 1774 | template 1775 | inline BMATH_CONSTEXPR bool operator !=(matrix left, matrix right) { 1776 | return 1777 | left.col[0].x != right.col[0].x or 1778 | left.col[0].y != right.col[0].y or 1779 | left.col[1].x != right.col[1].x or 1780 | left.col[1].y != right.col[1].y; 1781 | } 1782 | 1783 | template 1784 | inline BMATH_CONSTEXPR bool operator !=(matrix left, matrix right) { 1785 | return 1786 | left.col[0].x != right.col[0].x or 1787 | left.col[0].y != right.col[0].y or 1788 | left.col[0].z != right.col[0].z or 1789 | left.col[1].x != right.col[1].x or 1790 | left.col[1].y != right.col[1].y or 1791 | left.col[1].z != right.col[1].z or 1792 | left.col[2].x != right.col[2].x or 1793 | left.col[2].y != right.col[2].y or 1794 | left.col[2].z != right.col[2].z; 1795 | } 1796 | 1797 | template 1798 | inline BMATH_CONSTEXPR bool operator !=(matrix left, matrix right) { 1799 | return 1800 | left.col[0].x != right.col[0].x or 1801 | left.col[0].y != right.col[0].y or 1802 | left.col[0].z != right.col[0].z or 1803 | left.col[0].w != right.col[0].w or 1804 | left.col[1].x != right.col[1].x or 1805 | left.col[1].y != right.col[1].y or 1806 | left.col[1].z != right.col[1].z or 1807 | left.col[1].w != right.col[1].w or 1808 | left.col[2].x != right.col[2].x or 1809 | left.col[2].y != right.col[2].y or 1810 | left.col[2].z != right.col[2].z or 1811 | left.col[2].w != right.col[2].w or 1812 | left.col[3].x != right.col[3].x or 1813 | left.col[3].y != right.col[3].y or 1814 | left.col[3].z != right.col[3].z or 1815 | left.col[3].w != right.col[3].w; 1816 | } 1817 | 1818 | template 1819 | inline matrix &operator +=(matrix &left, matrix right) { 1820 | return left = left + right; 1821 | } 1822 | 1823 | template 1824 | inline matrix &operator -=(matrix &left, matrix right) { 1825 | return left = left - right; 1826 | } 1827 | 1828 | template 1829 | inline matrix &operator *=(matrix &left, matrix right) { 1830 | return left = left * right; 1831 | } 1832 | 1833 | template 1834 | inline matrix &operator /=(matrix &left, matrix right) { 1835 | return left = left / right; 1836 | } 1837 | 1838 | template 1839 | inline matrix &operator +=(matrix &left, T right) { 1840 | return left = left + right; 1841 | } 1842 | 1843 | template 1844 | inline matrix &operator -=(matrix &left, T right) { 1845 | return left = left - right; 1846 | } 1847 | 1848 | template 1849 | inline matrix &operator *=(matrix &left, T right) { 1850 | return left = left * right; 1851 | } 1852 | 1853 | template 1854 | inline matrix &operator /=(matrix &left, T right) { 1855 | return left = left / right; 1856 | } 1857 | 1858 | // Quaternion Operators 1859 | 1860 | template 1861 | inline BMATH_CONSTEXPR quaternion operator +(quaternion q) { 1862 | return quaternion( 1863 | +q.x, 1864 | +q.y, 1865 | +q.z, 1866 | +q.w); 1867 | } 1868 | 1869 | template 1870 | inline BMATH_CONSTEXPR quaternion operator -(quaternion q) { 1871 | return quaternion( 1872 | -q.x, 1873 | -q.y, 1874 | -q.z, 1875 | -q.w); 1876 | } 1877 | 1878 | template 1879 | inline BMATH_CONSTEXPR quaternion operator +(quaternion left, quaternion right) { 1880 | return quaternion( 1881 | left.x + right.x, 1882 | left.y + right.y, 1883 | left.z + right.z, 1884 | left.w + right.w); 1885 | } 1886 | 1887 | template 1888 | inline BMATH_CONSTEXPR quaternion operator -(quaternion left, quaternion right) { 1889 | return quaternion( 1890 | left.x - right.x, 1891 | left.y - right.y, 1892 | left.z - right.z, 1893 | left.w - right.w); 1894 | } 1895 | 1896 | template 1897 | inline BMATH_CONSTEXPR quaternion operator *(quaternion left, quaternion right) { 1898 | return quaternion( 1899 | left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, 1900 | left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x, 1901 | left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w, 1902 | left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z); 1903 | } 1904 | 1905 | template 1906 | inline BMATH_CONSTEXPR quaternion operator /(quaternion left, quaternion right) { 1907 | return quaternion( 1908 | left.x / right.x, 1909 | left.y / right.y, 1910 | left.z / right.z, 1911 | left.w / right.w); 1912 | } 1913 | 1914 | template 1915 | inline BMATH_CONSTEXPR quaternion operator +(quaternion left, T right) { 1916 | return quaternion( 1917 | left.x + right, 1918 | left.y + right, 1919 | left.z + right, 1920 | left.w + right); 1921 | } 1922 | 1923 | template 1924 | inline BMATH_CONSTEXPR quaternion operator -(quaternion left, T right) { 1925 | return quaternion( 1926 | left.x - right, 1927 | left.y - right, 1928 | left.z - right, 1929 | left.w - right); 1930 | } 1931 | 1932 | template 1933 | inline BMATH_CONSTEXPR quaternion operator *(quaternion left, T right) { 1934 | return quaternion( 1935 | left.x * right, 1936 | left.y * right, 1937 | left.z * right, 1938 | left.w * right); 1939 | } 1940 | 1941 | template 1942 | inline BMATH_CONSTEXPR quaternion operator /(quaternion left, T right) { 1943 | return quaternion( 1944 | left.x / right, 1945 | left.y / right, 1946 | left.z / right, 1947 | left.w / right); 1948 | } 1949 | 1950 | template 1951 | inline BMATH_CONSTEXPR quaternion operator +(T left, quaternion right) { 1952 | return quaternion( 1953 | left + right.x, 1954 | left + right.y, 1955 | left + right.z, 1956 | left + right.w); 1957 | } 1958 | 1959 | template 1960 | inline BMATH_CONSTEXPR quaternion operator -(T left, quaternion right) { 1961 | return quaternion( 1962 | left - right.x, 1963 | left - right.y, 1964 | left - right.z, 1965 | left - right.w); 1966 | } 1967 | 1968 | template 1969 | inline BMATH_CONSTEXPR quaternion operator *(T left, quaternion right) { 1970 | return quaternion( 1971 | left * right.x, 1972 | left * right.y, 1973 | left * right.z, 1974 | left * right.w); 1975 | } 1976 | 1977 | template 1978 | inline BMATH_CONSTEXPR quaternion operator /(T left, quaternion right) { 1979 | return quaternion( 1980 | left / right.x, 1981 | left / right.y, 1982 | left / right.z, 1983 | left / right.w); 1984 | } 1985 | 1986 | template 1987 | inline BMATH_CONSTEXPR vector operator ==(quaternion left, quaternion right) { 1988 | return vector( 1989 | left.x == right.x, 1990 | left.y == right.y, 1991 | left.z == right.z, 1992 | left.w == right.w); 1993 | } 1994 | 1995 | template 1996 | inline BMATH_CONSTEXPR vector operator !=(quaternion left, quaternion right) { 1997 | return vector( 1998 | left.x != right.x, 1999 | left.y != right.y, 2000 | left.z != right.z, 2001 | left.w != right.w); 2002 | } 2003 | 2004 | template 2005 | inline quaternion &operator +=(quaternion &left, quaternion right) { 2006 | return left = left + right; 2007 | } 2008 | 2009 | template 2010 | inline quaternion &operator -=(quaternion &left, quaternion right) { 2011 | return left = left - right; 2012 | } 2013 | 2014 | template 2015 | inline quaternion &operator *=(quaternion &left, quaternion right) { 2016 | return left = left * right; 2017 | } 2018 | 2019 | template 2020 | inline quaternion &operator /=(quaternion &left, quaternion right) { 2021 | return left = left / right; 2022 | } 2023 | 2024 | template 2025 | inline quaternion &operator +=(quaternion &left, T right) { 2026 | return left = left + right; 2027 | } 2028 | 2029 | template 2030 | inline quaternion &operator -=(quaternion &left, T right) { 2031 | return left = left - right; 2032 | } 2033 | 2034 | template 2035 | inline quaternion &operator *=(quaternion &left, T right) { 2036 | return left = left * right; 2037 | } 2038 | 2039 | template 2040 | inline quaternion &operator /=(quaternion &left, T right) { 2041 | return left = left / right; 2042 | } 2043 | 2044 | // Trigonometric Functions 2045 | 2046 | using std::sin; 2047 | using std::cos; 2048 | using std::tan; 2049 | using std::asin; 2050 | using std::acos; 2051 | using std::atan; 2052 | using std::atan2; 2053 | using std::sinh; 2054 | using std::cosh; 2055 | using std::tanh; 2056 | using std::asinh; 2057 | using std::acosh; 2058 | using std::atanh; 2059 | 2060 | template 2061 | inline BMATH_CONSTEXPR T radians(T degrees) { 2062 | return degrees * T(3.141592653589793) / T(180); 2063 | } 2064 | 2065 | template 2066 | inline BMATH_CONSTEXPR T degrees(T radians) { 2067 | return radians * T(180) / T(3.141592653589793); 2068 | } 2069 | 2070 | // Exponential Functions 2071 | 2072 | using std::pow; 2073 | using std::exp; 2074 | using std::log; 2075 | using std::sqrt; 2076 | 2077 | template 2078 | inline vector pow(vector left, vector right) { 2079 | return vector( 2080 | pow(left.x, right.x), 2081 | pow(left.y, right.y)); 2082 | } 2083 | 2084 | template 2085 | inline vector pow(vector left, vector right) { 2086 | return vector( 2087 | pow(left.x, right.x), 2088 | pow(left.y, right.y), 2089 | pow(left.z, right.z)); 2090 | } 2091 | 2092 | template 2093 | inline vector pow(vector left, vector right) { 2094 | return vector( 2095 | pow(left.x, right.x), 2096 | pow(left.y, right.y), 2097 | pow(left.z, right.z), 2098 | pow(left.w, right.w)); 2099 | } 2100 | 2101 | template 2102 | inline vector pow(vector left, T right) { 2103 | return pow(left, vector(right)); 2104 | } 2105 | 2106 | template 2107 | inline vector pow(T left, vector right) { 2108 | return pow(vector(left), right); 2109 | } 2110 | 2111 | template 2112 | inline vector sqrt(vector v) { 2113 | return vector( 2114 | sqrt(v.x), 2115 | sqrt(v.y)); 2116 | } 2117 | 2118 | template 2119 | inline vector sqrt(vector v) { 2120 | return vector( 2121 | sqrt(v.x), 2122 | sqrt(v.y), 2123 | sqrt(v.z)); 2124 | } 2125 | 2126 | template 2127 | inline vector sqrt(vector v) { 2128 | return vector( 2129 | sqrt(v.x), 2130 | sqrt(v.y), 2131 | sqrt(v.z), 2132 | sqrt(v.w)); 2133 | } 2134 | 2135 | template 2136 | inline vector exp(vector v) { 2137 | return vector( 2138 | exp(v.x), 2139 | exp(v.y)); 2140 | } 2141 | 2142 | template 2143 | inline vector exp(vector v) { 2144 | return vector( 2145 | exp(v.x), 2146 | exp(v.y), 2147 | exp(v.z)); 2148 | } 2149 | 2150 | template 2151 | inline vector exp(vector v) { 2152 | return vector( 2153 | exp(v.x), 2154 | exp(v.y), 2155 | exp(v.z), 2156 | exp(v.w)); 2157 | } 2158 | 2159 | template 2160 | inline vector log(vector v) { 2161 | return vector( 2162 | log(v.x), 2163 | log(v.y)); 2164 | } 2165 | 2166 | template 2167 | inline vector log(vector v) { 2168 | return vector( 2169 | log(v.x), 2170 | log(v.y), 2171 | log(v.z)); 2172 | } 2173 | 2174 | template 2175 | inline vector log(vector v) { 2176 | return vector( 2177 | log(v.x), 2178 | log(v.y), 2179 | log(v.z), 2180 | log(v.w)); 2181 | } 2182 | 2183 | #ifdef BMATH_HAS_EXP2_LOG2 2184 | 2185 | using std::exp2; 2186 | using std::log2; 2187 | 2188 | template 2189 | inline vector exp2(vector v) { 2190 | return vector( 2191 | exp2(v.x), 2192 | exp2(v.y)); 2193 | } 2194 | 2195 | template 2196 | inline vector exp2(vector v) { 2197 | return vector( 2198 | exp2(v.x), 2199 | exp2(v.y), 2200 | exp2(v.z)); 2201 | } 2202 | 2203 | template 2204 | inline vector exp2(vector v) { 2205 | return vector( 2206 | exp2(v.x), 2207 | exp2(v.y), 2208 | exp2(v.z), 2209 | exp2(v.w)); 2210 | } 2211 | 2212 | template 2213 | inline vector log2(vector v) { 2214 | return vector( 2215 | log2(v.x), 2216 | log2(v.y)); 2217 | } 2218 | 2219 | template 2220 | inline vector log2(vector v) { 2221 | return vector( 2222 | log2(v.x), 2223 | log2(v.y), 2224 | log2(v.z)); 2225 | } 2226 | 2227 | template 2228 | inline vector log2(vector v) { 2229 | return vector( 2230 | log2(v.x), 2231 | log2(v.y), 2232 | log2(v.z), 2233 | log2(v.w)); 2234 | } 2235 | 2236 | #endif 2237 | 2238 | // Common Functions 2239 | 2240 | using std::abs; 2241 | using std::floor; 2242 | using std::trunc; 2243 | using std::round; 2244 | using std::ceil; 2245 | using std::isnan; 2246 | using std::isinf; 2247 | 2248 | template 2249 | inline BMATH_CONSTEXPR T max(T a, T b) { 2250 | return a > b ? a : b; 2251 | } 2252 | 2253 | template 2254 | inline BMATH_CONSTEXPR vector max(vector a, vector b) { 2255 | return vector( 2256 | max(a.x, b.x), 2257 | max(a.y, b.y)); 2258 | } 2259 | 2260 | template 2261 | inline BMATH_CONSTEXPR vector max(vector a, vector b) { 2262 | return vector( 2263 | max(a.x, b.x), 2264 | max(a.y, b.y), 2265 | max(a.z, b.z)); 2266 | } 2267 | 2268 | template 2269 | inline BMATH_CONSTEXPR vector max(vector a, vector b) { 2270 | return vector( 2271 | max(a.x, b.x), 2272 | max(a.y, b.y), 2273 | max(a.z, b.z), 2274 | max(a.w, b.w)); 2275 | } 2276 | 2277 | template 2278 | inline BMATH_CONSTEXPR vector max(vector a, T b) { 2279 | return max(a, vector(b)); 2280 | } 2281 | 2282 | template 2283 | inline BMATH_CONSTEXPR vector max(T a, vector b) { 2284 | return max(vector(a), b); 2285 | } 2286 | 2287 | template 2288 | inline BMATH_CONSTEXPR T min(T a, T b) { 2289 | return a < b ? a : b; 2290 | } 2291 | 2292 | template 2293 | inline BMATH_CONSTEXPR vector min(vector a, vector b) { 2294 | return vector( 2295 | min(a.x, b.x), 2296 | min(a.y, b.y)); 2297 | } 2298 | 2299 | template 2300 | inline BMATH_CONSTEXPR vector min(vector a, vector b) { 2301 | return vector( 2302 | min(a.x, b.x), 2303 | min(a.y, b.y), 2304 | min(a.z, b.z)); 2305 | } 2306 | 2307 | template 2308 | inline BMATH_CONSTEXPR vector min(vector a, vector b) { 2309 | return vector( 2310 | min(a.x, b.x), 2311 | min(a.y, b.y), 2312 | min(a.z, b.z), 2313 | min(a.w, b.w)); 2314 | } 2315 | 2316 | template 2317 | inline BMATH_CONSTEXPR vector min(vector a, T b) { 2318 | return min(a, vector(b)); 2319 | } 2320 | 2321 | template 2322 | inline BMATH_CONSTEXPR vector min(T a, vector b) { 2323 | return min(vector(a), b); 2324 | } 2325 | 2326 | template 2327 | inline BMATH_CONSTEXPR T clamp(T x, T minVal, T maxVal) { 2328 | return min(max(x, minVal), maxVal); 2329 | } 2330 | 2331 | template 2332 | inline BMATH_CONSTEXPR vector clamp(vector v, vector minVal, vector maxVal) { 2333 | return min(max(v, minVal), maxVal); 2334 | } 2335 | 2336 | template 2337 | inline BMATH_CONSTEXPR vector clamp(vector v, T minVal, T maxVal) { 2338 | return min(max(v, minVal), maxVal); 2339 | } 2340 | 2341 | template 2342 | inline BMATH_CONSTEXPR vector saturate(vector v) { 2343 | return clamp(v, T(0), T(1)); 2344 | } 2345 | 2346 | template 2347 | inline BMATH_CONSTEXPR T compSum(vector v) { 2348 | return v.x + v.y; 2349 | } 2350 | 2351 | template 2352 | inline BMATH_CONSTEXPR T compSum(vector v) { 2353 | return v.x + v.y + v.z; 2354 | } 2355 | 2356 | template 2357 | inline BMATH_CONSTEXPR T compSum(vector v) { 2358 | return v.x + v.y + v.z + v.w; 2359 | } 2360 | 2361 | template 2362 | inline BMATH_CONSTEXPR T compMax(vector v) { 2363 | return max(v.x, v.y); 2364 | } 2365 | 2366 | template 2367 | inline BMATH_CONSTEXPR T compMax(vector v) { 2368 | return max(v.x, max(v.y, v.z)); 2369 | } 2370 | 2371 | template 2372 | inline BMATH_CONSTEXPR T compMax(vector v) { 2373 | return max(v.x, max(v.y, max(v.z, v.w))); 2374 | } 2375 | 2376 | template 2377 | inline BMATH_CONSTEXPR T compMin(vector v) { 2378 | return min(v.x, v.y); 2379 | } 2380 | 2381 | template 2382 | inline BMATH_CONSTEXPR T compMin(vector v) { 2383 | return min(v.x, min(v.y, v.z)); 2384 | } 2385 | 2386 | template 2387 | inline BMATH_CONSTEXPR T compMin(vector v) { 2388 | return min(v.x, min(v.y, min(v.z, v.w))); 2389 | } 2390 | 2391 | template 2392 | inline BMATH_CONSTEXPR vector abs(vector v) { 2393 | return vector( 2394 | v.x < T(0) ? -v.x : v.x, 2395 | v.y < T(0) ? -v.y : v.y); 2396 | } 2397 | 2398 | template 2399 | inline BMATH_CONSTEXPR vector abs(vector v) { 2400 | return vector( 2401 | v.x < T(0) ? -v.x : v.x, 2402 | v.y < T(0) ? -v.y : v.y, 2403 | v.z < T(0) ? -v.z : v.z); 2404 | } 2405 | 2406 | template 2407 | inline BMATH_CONSTEXPR vector abs(vector v) { 2408 | return vector( 2409 | v.x < T(0) ? -v.x : v.x, 2410 | v.y < T(0) ? -v.y : v.y, 2411 | v.z < T(0) ? -v.z : v.z, 2412 | v.w < T(0) ? -v.w : v.w); 2413 | } 2414 | 2415 | template 2416 | inline BMATH_CONSTEXPR T sign(T x) { 2417 | return T(x > T(0)) - T(x < T(0)); 2418 | } 2419 | 2420 | template 2421 | inline vector floor(vector v) { 2422 | return vector( 2423 | floor(v.x), 2424 | floor(v.y)); 2425 | } 2426 | 2427 | template 2428 | inline vector floor(vector v) { 2429 | return vector( 2430 | floor(v.x), 2431 | floor(v.y), 2432 | floor(v.z)); 2433 | } 2434 | 2435 | template 2436 | inline vector floor(vector v) { 2437 | return vector( 2438 | floor(v.x), 2439 | floor(v.y), 2440 | floor(v.z), 2441 | floor(v.w)); 2442 | } 2443 | 2444 | template 2445 | inline vector trunc(vector v) { 2446 | return vector( 2447 | trunc(v.x), 2448 | trunc(v.y)); 2449 | } 2450 | 2451 | template 2452 | inline vector trunc(vector v) { 2453 | return vector( 2454 | trunc(v.x), 2455 | trunc(v.y), 2456 | trunc(v.z)); 2457 | } 2458 | 2459 | template 2460 | inline vector trunc(vector v) { 2461 | return vector( 2462 | trunc(v.x), 2463 | trunc(v.y), 2464 | trunc(v.z), 2465 | trunc(v.w)); 2466 | } 2467 | 2468 | template 2469 | inline vector round(vector v) { 2470 | return vector( 2471 | round(v.x), 2472 | round(v.y)); 2473 | } 2474 | 2475 | template 2476 | inline vector round(vector v) { 2477 | return vector( 2478 | round(v.x), 2479 | round(v.y), 2480 | round(v.z)); 2481 | } 2482 | 2483 | template 2484 | inline vector round(vector v) { 2485 | return vector( 2486 | round(v.x), 2487 | round(v.y), 2488 | round(v.z), 2489 | round(v.w)); 2490 | } 2491 | 2492 | template 2493 | inline vector ceil(vector v) { 2494 | return vector( 2495 | ceil(v.x), 2496 | ceil(v.y)); 2497 | } 2498 | 2499 | template 2500 | inline vector ceil(vector v) { 2501 | return vector( 2502 | ceil(v.x), 2503 | ceil(v.y), 2504 | ceil(v.z)); 2505 | } 2506 | 2507 | template 2508 | inline vector ceil(vector v) { 2509 | return vector( 2510 | ceil(v.x), 2511 | ceil(v.y), 2512 | ceil(v.z), 2513 | ceil(v.w)); 2514 | } 2515 | 2516 | template 2517 | inline T fract(T x) { 2518 | return x - trunc(x); 2519 | } 2520 | 2521 | template 2522 | inline vector fract(vector v) { 2523 | return vector( 2524 | fract(v.x), 2525 | fract(v.y)); 2526 | } 2527 | 2528 | template 2529 | inline vector fract(vector v) { 2530 | return vector( 2531 | fract(v.x), 2532 | fract(v.y), 2533 | fract(v.z)); 2534 | } 2535 | 2536 | template 2537 | inline vector fract(vector v) { 2538 | return vector( 2539 | fract(v.x), 2540 | fract(v.y), 2541 | fract(v.z), 2542 | fract(v.w)); 2543 | } 2544 | 2545 | template 2546 | inline BMATH_CONSTEXPR T mod(T a, T b) { 2547 | return a % b; 2548 | } 2549 | 2550 | inline float mod(float a, float b) { 2551 | return fmodf(a, b); 2552 | } 2553 | 2554 | inline double mod(double a, double b) { 2555 | return fmod(a, b); 2556 | } 2557 | 2558 | template 2559 | inline vector mod(vector left, vector right) { 2560 | return vector( 2561 | mod(left.x, right.x), 2562 | mod(left.y, right.y)); 2563 | } 2564 | 2565 | template 2566 | inline vector mod(vector left, vector right) { 2567 | return vector( 2568 | mod(left.x, right.x), 2569 | mod(left.y, right.y), 2570 | mod(left.z, right.z)); 2571 | } 2572 | 2573 | template 2574 | inline vector mod(vector left, vector right) { 2575 | return vector( 2576 | mod(left.x, right.x), 2577 | mod(left.y, right.y), 2578 | mod(left.z, right.z), 2579 | mod(left.w, right.w)); 2580 | } 2581 | 2582 | template 2583 | inline vector mod(vector left, T right) { 2584 | return mod(left, vector(right)); 2585 | } 2586 | 2587 | template 2588 | inline vector mod(T left, vector right) { 2589 | return mod(vector(left), right); 2590 | } 2591 | 2592 | template 2593 | inline BMATH_CONSTEXPR T step(T edge, T x) { 2594 | return T(x >= edge); 2595 | } 2596 | 2597 | template 2598 | inline BMATH_CONSTEXPR vector step(vector edge, vector x) { 2599 | return vector(x >= edge); 2600 | } 2601 | 2602 | template 2603 | inline BMATH_CONSTEXPR vector step(T edge, vector x) { 2604 | return vector(x >= edge); 2605 | } 2606 | 2607 | template 2608 | inline BMATH_CONSTEXPR T smoothstep(T edge1, T edge2, T x) { 2609 | T t = clamp((x - edge1) / (edge2 - edge1), T(0), T(1)); 2610 | return t * t * (T(3) - T(2) * t); 2611 | } 2612 | 2613 | template 2614 | inline BMATH_CONSTEXPR vector smoothstep(vector edge1, vector edge2, vector x) { 2615 | vector t = clamp((x - edge1) / (edge2 - edge1), T(0), T(1)); 2616 | return t * t * (T(3) - T(2) * t); 2617 | } 2618 | 2619 | template 2620 | inline BMATH_CONSTEXPR vector smoothstep(T edge1, T edge2, vector x) { 2621 | vector t = clamp((x - edge1) / (edge2 - edge1), T(0), T(1)); 2622 | return t * t * (T(3) - T(2) * t); 2623 | } 2624 | 2625 | template 2626 | inline BMATH_CONSTEXPR vector isnan(vector v) { 2627 | return vector( 2628 | isnan(v.x), 2629 | isnan(v.y)); 2630 | } 2631 | 2632 | template 2633 | inline BMATH_CONSTEXPR vector isnan(vector v) { 2634 | return vector( 2635 | isnan(v.x), 2636 | isnan(v.y), 2637 | isnan(v.z)); 2638 | } 2639 | 2640 | template 2641 | inline BMATH_CONSTEXPR vector isnan(vector v) { 2642 | return vector( 2643 | isnan(v.x), 2644 | isnan(v.y), 2645 | isnan(v.z), 2646 | isnan(v.w)); 2647 | } 2648 | 2649 | template 2650 | inline BMATH_CONSTEXPR vector isinf(vector v) { 2651 | return vector( 2652 | isinf(v.x), 2653 | isinf(v.y)); 2654 | } 2655 | 2656 | template 2657 | inline BMATH_CONSTEXPR vector isinf(vector v) { 2658 | return vector( 2659 | isinf(v.x), 2660 | isinf(v.y), 2661 | isinf(v.z)); 2662 | } 2663 | 2664 | template 2665 | inline BMATH_CONSTEXPR vector isinf(vector v) { 2666 | return vector( 2667 | isinf(v.x), 2668 | isinf(v.y), 2669 | isinf(v.z), 2670 | isinf(v.w)); 2671 | } 2672 | 2673 | // Color Space Functions 2674 | 2675 | inline BMATH_CONSTEXPR vec4 unpackRGBA8(uint r8g8b8a8) { 2676 | uint r = (r8g8b8a8 >> 24) & 0xFF; 2677 | uint g = (r8g8b8a8 >> 16) & 0xFF; 2678 | uint b = (r8g8b8a8 >> 8) & 0xFF; 2679 | uint a = (r8g8b8a8 >> 0) & 0xFF; 2680 | return vec4(r, g, b, a) * (1.0f / 255.0f); 2681 | } 2682 | 2683 | inline BMATH_CONSTEXPR uint packRGBA8(vec4 rgba) { 2684 | uint r = uint(rgba.x * 255.5f); 2685 | uint g = uint(rgba.g * 255.5f); 2686 | uint b = uint(rgba.b * 255.5f); 2687 | uint a = uint(rgba.a * 255.5f); 2688 | return 2689 | (r << 24) | 2690 | (g << 16) | 2691 | (b << 8) | 2692 | (a << 0); 2693 | } 2694 | 2695 | inline BMATH_CONSTEXPR vec3 HSVtoRGB(vec3 hsv) { 2696 | float h = hsv.x; 2697 | float s = hsv.y; 2698 | float v = hsv.z; 2699 | int i = (int)(h * 6.0f); 2700 | float f = h * 6.0f - i; 2701 | float p = v * (1.0f - s); 2702 | float q = v * (1.0f - f * s); 2703 | float t = v * (1.0f - (1.0f - f) * s); 2704 | switch (i % 6) { 2705 | case 0: return vec3(v, t, p); 2706 | case 1: return vec3(q, v, p); 2707 | case 2: return vec3(p, v, t); 2708 | case 3: return vec3(p, q, v); 2709 | case 4: return vec3(t, p, v); 2710 | default: return vec3(v, p, q); 2711 | } 2712 | } 2713 | 2714 | inline BMATH_CONSTEXPR vec3 RGBtoHSV(vec3 rgb) { 2715 | float min = compMin(rgb); 2716 | float max = compMax(rgb); 2717 | if (max == 0) 2718 | return vec3(0); 2719 | 2720 | float delta = max - min; 2721 | float v = max; 2722 | float s = delta / max; 2723 | float h = 2724 | rgb.x == max ? (rgb.g - rgb.b) / (6 * delta) + 0 / 3.0f : 2725 | rgb.y == max ? (rgb.b - rgb.r) / (6 * delta) + 1 / 3.0f : 2726 | (rgb.r - rgb.g) / (6 * delta) + 2 / 3.0f; 2727 | 2728 | return vec3(h < 0 ? 1 + h : h, s, v); 2729 | } 2730 | 2731 | // Geometric Functions 2732 | 2733 | template 2734 | inline BMATH_CONSTEXPR T dot(vector left, vector right) { 2735 | return compSum(left * right); 2736 | } 2737 | 2738 | template 2739 | inline BMATH_CONSTEXPR vector cross(vector left, vector right) { 2740 | return vector( 2741 | left.y * right.z - right.y * left.z, 2742 | left.z * right.x - right.z * left.x, 2743 | left.x * right.y - right.x * left.y); 2744 | } 2745 | 2746 | template 2747 | inline BMATH_CONSTEXPR T lengthSq(vector v) { 2748 | return dot(v, v); 2749 | } 2750 | 2751 | template 2752 | inline BMATH_CONSTEXPR T distanceSq(vector p1, vector p2) { 2753 | return lengthSq(p1 - p2); 2754 | } 2755 | 2756 | template 2757 | inline T length(vector v) { 2758 | return sqrt(dot(v, v)); 2759 | } 2760 | 2761 | template 2762 | inline T distance(vector p1, vector p2) { 2763 | return length(p1 - p2); 2764 | } 2765 | 2766 | template 2767 | inline vector normalize(vector v) { 2768 | return v / length(v); 2769 | } 2770 | 2771 | template 2772 | inline BMATH_CONSTEXPR vector faceforward(vector normal, vector incidence) { 2773 | return dot(incidence, normal) < T(0) ? normal : -normal; 2774 | } 2775 | 2776 | template 2777 | inline BMATH_CONSTEXPR vector reflect(vector incidence, vector normal) { 2778 | return incidence - T(2) * dot(incidence, normal) * normal; 2779 | } 2780 | 2781 | template 2782 | inline vector refract(vector incidence, vector normal, T eta) { 2783 | T d = dot(incidence, normal); 2784 | T k = T(1) - eta * eta * (T(1) - d * d); 2785 | if (k < T(0)) 2786 | return vector(T(0)); 2787 | return eta * incidence - normal * (eta * d + sqrt(k)); 2788 | } 2789 | 2790 | template 2791 | inline BMATH_CONSTEXPR T lerp(T from, T to, T amount) { 2792 | return from + (to - from) * amount; 2793 | } 2794 | 2795 | template 2796 | inline BMATH_CONSTEXPR vector lerp(vector from, vector to, vector amount) { 2797 | return from + (to - from) * amount; 2798 | } 2799 | 2800 | template 2801 | inline BMATH_CONSTEXPR vector lerp(vector from, vector to, T amount) { 2802 | return from + (to - from) * amount; 2803 | } 2804 | 2805 | template 2806 | inline vector slerp(vector from, vector to, T amount) { 2807 | vector z = to; 2808 | 2809 | T cosTheta = dot(from, to); 2810 | // if cosTheta < 0, the interpolation will take the long way around the sphere. 2811 | if (cosTheta < T(0)) { 2812 | z = -to; 2813 | cosTheta = -cosTheta; 2814 | } 2815 | 2816 | // sin(angle) -> 0! too close for comfort - do a lerp instead. 2817 | if (cosTheta > T(0.99999)) 2818 | return lerp(from, to, amount); 2819 | 2820 | // Essential Mathematics, page 467. 2821 | T angle = acos(cosTheta); 2822 | return (sin((T(1) - amount) * angle) * from + sin(amount * angle) * z) / sin(angle); 2823 | } 2824 | 2825 | // Matrix Functions 2826 | 2827 | template 2828 | inline BMATH_CONSTEXPR matrix outerProduct(vector left, vector right) { 2829 | return matrix( 2830 | left.x * right.x, left.y * right.x, 2831 | left.x * right.y, left.y * right.y); 2832 | } 2833 | 2834 | template 2835 | inline BMATH_CONSTEXPR matrix outerProduct(vector left, vector right) { 2836 | return matrix( 2837 | left.x * right.x, left.y * right.x, left.z * right.x, 2838 | left.x * right.y, left.y * right.y, left.z * right.y, 2839 | left.x * right.z, left.y * right.z, left.z * right.z); 2840 | } 2841 | 2842 | template 2843 | inline BMATH_CONSTEXPR matrix outerProduct(vector left, vector right) { 2844 | return matrix( 2845 | left.x * right.x, left.y * right.x, left.z * right.x, left.w * right.x, 2846 | left.x * right.y, left.y * right.y, left.z * right.y, left.w * right.y, 2847 | left.x * right.z, left.y * right.z, left.z * right.z, left.w * right.z, 2848 | left.x * right.w, left.y * right.w, left.z * right.w, left.w * right.w); 2849 | } 2850 | 2851 | template 2852 | inline BMATH_CONSTEXPR matrix matCompMul(matrix left, matrix right) { 2853 | return matrix( 2854 | left.col[0] * right.col[0], 2855 | left.col[1] * right.col[1]); 2856 | } 2857 | 2858 | template 2859 | inline BMATH_CONSTEXPR matrix matCompMul(matrix left, matrix right) { 2860 | return matrix( 2861 | left.col[0] * right.col[0], 2862 | left.col[1] * right.col[1], 2863 | left.col[2] * right.col[2]); 2864 | } 2865 | 2866 | template 2867 | inline BMATH_CONSTEXPR matrix matCompMul(matrix left, matrix right) { 2868 | return matrix( 2869 | left.col[0] * right.col[0], 2870 | left.col[1] * right.col[1], 2871 | left.col[2] * right.col[2], 2872 | left.col[3] * right.col[3]); 2873 | } 2874 | 2875 | template 2876 | inline BMATH_CONSTEXPR matrix transpose(matrix m) { 2877 | return matrix( 2878 | m.col[0].x, m.col[1].x, 2879 | m.col[0].y, m.col[1].y); 2880 | } 2881 | 2882 | template 2883 | inline BMATH_CONSTEXPR matrix transpose(matrix m) { 2884 | return matrix( 2885 | m.col[0].x, m.col[1].x, m.col[2].x, 2886 | m.col[0].y, m.col[1].y, m.col[2].y, 2887 | m.col[0].z, m.col[1].z, m.col[2].z); 2888 | } 2889 | 2890 | template 2891 | inline BMATH_CONSTEXPR matrix transpose(matrix m) { 2892 | return matrix( 2893 | m.col[0].x, m.col[1].x, m.col[2].x, m.col[3].x, 2894 | m.col[0].y, m.col[1].y, m.col[2].y, m.col[3].y, 2895 | m.col[0].z, m.col[1].z, m.col[2].z, m.col[3].z, 2896 | m.col[0].w, m.col[1].w, m.col[2].w, m.col[3].w); 2897 | } 2898 | 2899 | template 2900 | inline BMATH_CONSTEXPR T determinant(matrix m) { 2901 | return m.col[0].x * m.col[1].y - m.col[1].x * m.col[0].y; 2902 | } 2903 | 2904 | template 2905 | inline BMATH_CONSTEXPR T determinant(matrix m) { 2906 | return 2907 | + m.col[0].x * (m.col[1].y * m.col[2].z - m.col[2].y * m.col[1].z) 2908 | - m.col[1].x * (m.col[0].y * m.col[2].z - m.col[2].y * m.col[0].z) 2909 | + m.col[2].x * (m.col[0].y * m.col[1].z - m.col[1].y * m.col[0].z); 2910 | } 2911 | 2912 | template 2913 | inline BMATH_CONSTEXPR T determinant(matrix m) { 2914 | T f0 = m.col[2].z * m.col[3].w - m.col[3].z * m.col[2].w; 2915 | T f1 = m.col[2].y * m.col[3].w - m.col[3].y * m.col[2].w; 2916 | T f2 = m.col[2].y * m.col[3].z - m.col[3].y * m.col[2].z; 2917 | T f3 = m.col[2].x * m.col[3].w - m.col[3].x * m.col[2].w; 2918 | T f4 = m.col[2].x * m.col[3].z - m.col[3].x * m.col[2].z; 2919 | T f5 = m.col[2].x * m.col[3].y - m.col[3].x * m.col[2].y; 2920 | 2921 | return 2922 | m.col[0].x * (m.col[1].y * f0 - m.col[1].z * f1 + m.col[1].w * f2) - 2923 | m.col[0].y * (m.col[1].x * f0 - m.col[1].z * f3 + m.col[1].w * f4) + 2924 | m.col[0].z * (m.col[1].x * f1 - m.col[1].y * f3 + m.col[1].w * f5) - 2925 | m.col[0].w * (m.col[1].x * f2 - m.col[1].y * f4 + m.col[1].z * f5); 2926 | } 2927 | 2928 | template 2929 | inline BMATH_CONSTEXPR matrix inverse(matrix m) { 2930 | T inverseDet = T(1) / ( 2931 | + m.col[0].x * m.col[1].y 2932 | - m.col[1].x * m.col[0].y); 2933 | 2934 | return matrix( 2935 | +m.col[1].y * inverseDet, 2936 | -m.col[0].y * inverseDet, 2937 | -m.col[1].x * inverseDet, 2938 | +m.col[0].x * inverseDet); 2939 | } 2940 | 2941 | template 2942 | inline BMATH_CONSTEXPR matrix inverse(matrix m) { 2943 | T inverseDet = T(1) / ( 2944 | + m.col[0].x * (m.col[1].y * m.col[2].z - m.col[2].y * m.col[1].z) 2945 | - m.col[1].x * (m.col[0].y * m.col[2].z - m.col[2].y * m.col[0].z) 2946 | + m.col[2].x * (m.col[0].y * m.col[1].z - m.col[1].y * m.col[0].z)); 2947 | 2948 | return matrix( 2949 | +(m.col[1].y * m.col[2].z - m.col[2].y * m.col[1].z) * inverseDet, 2950 | -(m.col[0].y * m.col[2].z - m.col[2].y * m.col[0].z) * inverseDet, 2951 | +(m.col[0].y * m.col[1].z - m.col[1].y * m.col[0].z) * inverseDet, 2952 | -(m.col[1].x * m.col[2].z - m.col[2].x * m.col[1].z) * inverseDet, 2953 | +(m.col[0].x * m.col[2].z - m.col[2].x * m.col[0].z) * inverseDet, 2954 | -(m.col[0].x * m.col[1].z - m.col[1].x * m.col[0].z) * inverseDet, 2955 | +(m.col[1].x * m.col[2].y - m.col[2].x * m.col[1].y) * inverseDet, 2956 | -(m.col[0].x * m.col[2].y - m.col[2].x * m.col[0].y) * inverseDet, 2957 | +(m.col[0].x * m.col[1].y - m.col[1].x * m.col[0].y) * inverseDet); 2958 | } 2959 | 2960 | template 2961 | inline BMATH_CONSTEXPR matrix inverse(matrix m) { 2962 | 2963 | T c00 = m.col[2].z * m.col[3].w - m.col[3].z * m.col[2].w; 2964 | T c02 = m.col[1].z * m.col[3].w - m.col[3].z * m.col[1].w; 2965 | T c03 = m.col[1].z * m.col[2].w - m.col[2].z * m.col[1].w; 2966 | T c04 = m.col[2].y * m.col[3].w - m.col[3].y * m.col[2].w; 2967 | T c06 = m.col[1].y * m.col[3].w - m.col[3].y * m.col[1].w; 2968 | T c07 = m.col[1].y * m.col[2].w - m.col[2].y * m.col[1].w; 2969 | T c08 = m.col[2].y * m.col[3].z - m.col[3].y * m.col[2].z; 2970 | T c10 = m.col[1].y * m.col[3].z - m.col[3].y * m.col[1].z; 2971 | T c11 = m.col[1].y * m.col[2].z - m.col[2].y * m.col[1].z; 2972 | T c12 = m.col[2].x * m.col[3].w - m.col[3].x * m.col[2].w; 2973 | T c14 = m.col[1].x * m.col[3].w - m.col[3].x * m.col[1].w; 2974 | T c15 = m.col[1].x * m.col[2].w - m.col[2].x * m.col[1].w; 2975 | T c16 = m.col[2].x * m.col[3].z - m.col[3].x * m.col[2].z; 2976 | T c18 = m.col[1].x * m.col[3].z - m.col[3].x * m.col[1].z; 2977 | T c19 = m.col[1].x * m.col[2].z - m.col[2].x * m.col[1].z; 2978 | T c20 = m.col[2].x * m.col[3].y - m.col[3].x * m.col[2].y; 2979 | T c22 = m.col[1].x * m.col[3].y - m.col[3].x * m.col[1].y; 2980 | T c23 = m.col[1].x * m.col[2].y - m.col[2].x * m.col[1].y; 2981 | 2982 | vector f0(c00, c00, c02, c03); 2983 | vector f1(c04, c04, c06, c07); 2984 | vector f2(c08, c08, c10, c11); 2985 | vector f3(c12, c12, c14, c15); 2986 | vector f4(c16, c16, c18, c19); 2987 | vector f5(c20, c20, c22, c23); 2988 | 2989 | vector v0(m.col[1].x, m.col[0].x, m.col[0].x, m.col[0].x); 2990 | vector v1(m.col[1].y, m.col[0].y, m.col[0].y, m.col[0].y); 2991 | vector v2(m.col[1].z, m.col[0].z, m.col[0].z, m.col[0].z); 2992 | vector v3(m.col[1].w, m.col[0].w, m.col[0].w, m.col[0].w); 2993 | 2994 | vector inverse0(v1 * f0 - v2 * f1 + v3 * f2); 2995 | vector inverse1(v0 * f0 - v2 * f3 + v3 * f4); 2996 | vector inverse2(v0 * f1 - v1 * f3 + v3 * f5); 2997 | vector inverse3(v0 * f2 - v1 * f4 + v2 * f5); 2998 | 2999 | vector signA(+1, -1, +1, -1); 3000 | vector signB(-1, +1, -1, +1); 3001 | matrix inverse( 3002 | inverse0 * signA, 3003 | inverse1 * signB, 3004 | inverse2 * signA, 3005 | inverse3 * signB); 3006 | 3007 | vector row0( 3008 | inverse.col[0].x, 3009 | inverse.col[1].x, 3010 | inverse.col[2].x, 3011 | inverse.col[3].x); 3012 | 3013 | vector d(m.col[0] * row0); 3014 | return inverse / (d.x + d.y + d.z + d.w); 3015 | } 3016 | 3017 | template 3018 | inline BMATH_CONSTEXPR matrix scaleMat(vector xyz) { 3019 | return matrix(vector(xyz, T(1))); 3020 | } 3021 | 3022 | template 3023 | inline BMATH_CONSTEXPR matrix translationMat(vector xyz) { 3024 | return matrix( 3025 | T(1), T(0), T(0), T(0), 3026 | T(0), T(1), T(0), T(0), 3027 | T(0), T(0), T(1), T(0), 3028 | xyz.x, xyz.y, xyz.z, T(1)); 3029 | } 3030 | 3031 | template 3032 | inline matrix rotationMat(vector axis, T angleRad) { 3033 | T a = angleRad; 3034 | T s = sin(a); 3035 | T c = cos(a); 3036 | 3037 | axis = normalize(axis); 3038 | vector temp((T(1) - c) * axis); 3039 | 3040 | return matrix( 3041 | c + temp.x * axis.x, 3042 | temp.x * axis.y + s * axis.z, 3043 | temp.x * axis.z - s * axis.y, 3044 | T(0), 3045 | 3046 | temp.y * axis.x - s * axis.z, 3047 | c + temp.y * axis.y, 3048 | temp.y * axis.z + s * axis.x, 3049 | T(0), 3050 | 3051 | temp.z * axis.x + s * axis.y, 3052 | temp.z * axis.y - s * axis.x, 3053 | c + temp.z * axis.z, 3054 | T(0), 3055 | 3056 | T(0), T(0), T(0), T(1)); 3057 | } 3058 | 3059 | template 3060 | inline matrix lookToMat(vector pos, vector dir, vector up) { 3061 | #if defined BMATH_RIGHT_HANDED 3062 | { 3063 | vector f = normalize(dir); 3064 | vector r = normalize(cross(f, up)); 3065 | vector u = cross(r, f); 3066 | 3067 | return matrix( 3068 | r.x, u.x, -f.x, T(0), 3069 | r.y, u.y, -f.y, T(0), 3070 | r.z, u.z, -f.z, T(0), 3071 | -dot(r, pos), -dot(u, pos), +dot(f, pos), T(1)); 3072 | } 3073 | #elif defined BMATH_LEFT_HANDED 3074 | { 3075 | vector f = normalize(dir); 3076 | vector r = normalize(cross(up, f)); 3077 | vector u = cross(f, r); 3078 | 3079 | return matrix( 3080 | r.x, u.x, f.x, T(0), 3081 | r.y, u.y, f.y, T(0), 3082 | r.z, u.z, f.z, T(0), 3083 | -dot(r, pos), -dot(u, pos), -dot(f, pos), T(1)); 3084 | } 3085 | #endif 3086 | } 3087 | 3088 | template 3089 | inline matrix lookAtMat(vector pos, vector target, vector up) { 3090 | return lookToMat(pos, target - pos, up); 3091 | } 3092 | 3093 | template 3094 | inline matrix perspectiveMat(T vertFOV, T aspect, T near, T far) { 3095 | T theta = tan(vertFOV / T(2)); 3096 | matrix m(T(0)); 3097 | m.col[0].x = +T(1) / (aspect * theta); 3098 | m.col[1].y = +T(1) / (theta); 3099 | 3100 | #if defined BMATH_RIGHT_HANDED 3101 | { 3102 | m.col[2].w = -T(1); 3103 | #if defined BMATH_DEPTH_CLIP_ZERO_TO_ONE 3104 | { 3105 | m.col[2].z = +far / (near - far); 3106 | m.col[3].z = -(far * near) / (far - near); 3107 | } 3108 | #elif defined BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 3109 | { 3110 | m.col[2].z = -(far + near) / (far - near); 3111 | m.col[3].z = -(T(2) * far * near) / (far - near); 3112 | } 3113 | #endif 3114 | } 3115 | #elif defined BMATH_LEFT_HANDED 3116 | { 3117 | m.col[2].w = +T(1); 3118 | #if defined BMATH_DEPTH_CLIP_ZERO_TO_ONE 3119 | { 3120 | m.col[2].z = +far / (far - near); 3121 | m.col[3].z = -(far * near) / (far - near); 3122 | } 3123 | #elif defined BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 3124 | { 3125 | m.col[2].z = +(far + near) / (far - near); 3126 | m.col[3].z = -(T(2) * far * near) / (far - near); 3127 | } 3128 | #endif 3129 | } 3130 | #endif 3131 | 3132 | return m; 3133 | } 3134 | 3135 | template 3136 | inline matrix orthoMat(T left, T right, T bottom, T top, T near, T far) 3137 | { 3138 | matrix m(1); 3139 | m.col[0].x = T(2) / (right - left); 3140 | m.col[1].y = T(2) / (top - bottom); 3141 | m.col[3].x = -(right + left) / (right - left); 3142 | m.col[3].y = -(top + bottom) / (top - bottom); 3143 | 3144 | #if defined BMATH_RIGHT_HANDED 3145 | { 3146 | #if defined BMATH_DEPTH_CLIP_ZERO_TO_ONE 3147 | { 3148 | m.col[2].z = -T(1) / (zFar - near); 3149 | m.col[3].z = -near / (zFar - near); 3150 | } 3151 | #elif defined BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 3152 | { 3153 | m.col[2].z = -T(2) / (far - near); 3154 | m.col[3].z = -(far + near) / (far - near); 3155 | } 3156 | #endif 3157 | } 3158 | #elif defined BMATH_LEFT_HANDED 3159 | { 3160 | #if defined BMATH_DEPTH_CLIP_ZERO_TO_ONE 3161 | { 3162 | m.col[2].z = T(1) / (far - near); 3163 | m.col[3].z = -near / (far - near); 3164 | } 3165 | #elif defined BMATH_DEPTH_CLIP_MINUS_ONE_TO_ONE 3166 | { 3167 | m.col[2].z = T(2) / (far - near); 3168 | m.col[3].z = -(far + near) / (far - near); 3169 | } 3170 | #endif 3171 | } 3172 | #endif 3173 | 3174 | return m; 3175 | } 3176 | 3177 | // Vector Relational Functions 3178 | 3179 | inline BMATH_CONSTEXPR bool all(bvec2 v) { 3180 | return v.x and v.y; 3181 | } 3182 | 3183 | inline BMATH_CONSTEXPR bool all(bvec3 v) { 3184 | return v.x and v.y and v.z; 3185 | } 3186 | 3187 | inline BMATH_CONSTEXPR bool all(bvec4 v) { 3188 | return v.x and v.y and v.z and v.w; 3189 | } 3190 | 3191 | inline BMATH_CONSTEXPR bool any(bvec2 v) { 3192 | return v.x or v.y; 3193 | } 3194 | 3195 | inline BMATH_CONSTEXPR bool any(bvec3 v) { 3196 | return v.x or v.y or v.z; 3197 | } 3198 | 3199 | inline BMATH_CONSTEXPR bool any(bvec4 v) { 3200 | return v.x or v.y or v.z or v.w; 3201 | } 3202 | 3203 | template 3204 | inline bool epsilonEqual(T left, T right, T epsilon) { 3205 | return abs(left - right) <= epsilon; 3206 | } 3207 | 3208 | template 3209 | inline BMATH_CONSTEXPR vector epsilonEqual(vector left, vector right, T epsilon) { 3210 | return abs(left - right) <= epsilon; 3211 | } 3212 | 3213 | template 3214 | inline bool epsilonNotEqual(T left, T right, T epsilon) { 3215 | return abs(left - right) > epsilon; 3216 | } 3217 | 3218 | template 3219 | inline BMATH_CONSTEXPR vector epsilonNotEqual(vector left, vector right, T epsilon) { 3220 | return abs(left - right) > epsilon; 3221 | } 3222 | 3223 | // Quaternion Functions 3224 | 3225 | template 3226 | inline vector axis(quaternion q) { 3227 | T s = T(1) - q.w * q.w; 3228 | if (s <= T(0)) 3229 | return vector(0, 0, 1); 3230 | return q.xyz / sqrt(s); 3231 | } 3232 | 3233 | template 3234 | inline T angle(quaternion q) { 3235 | return acos(q.w) * T(2); 3236 | } 3237 | 3238 | template 3239 | inline BMATH_CONSTEXPR quaternion conjugate(quaternion q) { 3240 | return quaternion(-q.x, -q.y, -q.z, q.w); 3241 | } 3242 | 3243 | template 3244 | inline BMATH_CONSTEXPR T lengthSq(quaternion q) { 3245 | return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; 3246 | } 3247 | 3248 | template 3249 | inline T length(quaternion q) { 3250 | return sqrt(lengthSq(q)); 3251 | } 3252 | 3253 | template 3254 | inline quaternion normalize(quaternion q) { 3255 | return q / length(q); 3256 | } 3257 | 3258 | template 3259 | inline BMATH_CONSTEXPR quaternion inverse(quaternion q) { 3260 | return conjugate(q) / dot(q.xyzw, q.xyzw); 3261 | } 3262 | 3263 | template 3264 | inline quaternion slerp(quaternion from, quaternion to, T amount) { 3265 | quaternion z = to; 3266 | 3267 | T cosTheta = dot(from.xyzw, to.xyzw); 3268 | // if cosTheta < 0, the interpolation will take the long way around the sphere. 3269 | if (cosTheta < T(0)) { 3270 | z = -to; 3271 | cosTheta = -cosTheta; 3272 | } 3273 | 3274 | // sin(angle) -> 0! too close for comfort - do a lerp instead. 3275 | if (cosTheta > T(0.99999)) 3276 | return lerp(from, to, amount); 3277 | 3278 | // Essential Mathematics, page 467. 3279 | T angle = acos(cosTheta); 3280 | return (sin((T(1) - amount) * angle) * from + sin(amount * angle) * z) / sin(angle); 3281 | } 3282 | 3283 | template 3284 | inline quaternion nlerp(quaternion from, quaternion to, T amount) { 3285 | return normalize(from + (to - from) * amount); 3286 | } 3287 | 3288 | template 3289 | inline quaternion rotationQuat(vector axis, T angleRad) { 3290 | T a = angleRad / 2; 3291 | axis = normalize(axis); 3292 | return quaternion(sin(a) * axis, cos(a)); 3293 | } 3294 | 3295 | template 3296 | inline quaternion rotationQuat(vector from, vector to) { 3297 | T cosTheta = dot(from, to); 3298 | vector axis; 3299 | 3300 | if (cosTheta >= T(0.99999)) 3301 | return quat(T(0), T(0), T(0), T(1)); 3302 | 3303 | if (cosTheta < T(-0.99999)) { 3304 | // special case when vectors in opposite directions : 3305 | // there is no "ideal" rotation axis 3306 | // so guess one; any will do as long as it's perpendicular to start 3307 | // this implementation favors a rotation around the Up axis (Y), 3308 | // since it's often what you want to do. 3309 | axis = cross(vector(0, 0, 1), from); 3310 | if (lengthSq(axis) < T(0.00001)) // bad luck, they were parallel, try again! 3311 | axis = cross(vector(1, 0, 0), from); 3312 | 3313 | axis = normalize(axis); 3314 | return rotationQuat(axis, T(3.141592653589793)); 3315 | } 3316 | 3317 | // from Stan Melax's Game Programming Gems 1 article. 3318 | axis = cross(from, to); 3319 | 3320 | T s = sqrt((T(1) + cosTheta) * T(2)); 3321 | T invs = T(1) / s; 3322 | 3323 | return quaternion( 3324 | axis.x * invs, 3325 | axis.y * invs, 3326 | axis.z * invs, 3327 | s * T(0.5f)); 3328 | } 3329 | 3330 | template 3331 | inline BMATH_CONSTEXPR quaternion rotate(quaternion q, quaternion rot) { 3332 | return rot * q * inverse(rot); 3333 | } 3334 | 3335 | template 3336 | inline BMATH_CONSTEXPR quaternion rotate(vector v, quaternion rot) { 3337 | return rot * quaternion(v, T(0)) * inverse(rot); 3338 | } 3339 | 3340 | template 3341 | inline BMATH_CONSTEXPR quaternion rotate(vector v, vector axis, T angleRad) { 3342 | quaternion rot = rotationQuat(axis, angleRad); 3343 | return rotate(v, rot); 3344 | } 3345 | 3346 | template 3347 | inline BMATH_CONSTEXPR matrix quatToMat(quaternion q) { 3348 | return matrix( 3349 | T(1) - T(2) * (q.y * q.y + q.z * q.z), 3350 | T(2) * (q.x * q.y + q.w * q.z), 3351 | T(2) * (q.x * q.z - q.w * q.y), 3352 | T(0), 3353 | 3354 | T(2) * (q.x * q.y - q.w * q.z), 3355 | T(1) - T(2) * (q.x * q.x + q.z * q.z), 3356 | T(2) * (q.y * q.z + q.w * q.x), 3357 | T(0), 3358 | 3359 | T(2) * (q.x * q.z + q.w * q.y), 3360 | T(2) * (q.y * q.z - q.w * q.x), 3361 | T(1) - T(2) * (q.x * q.x + q.y * q.y), 3362 | T(0), 3363 | 3364 | T(0), T(0), T(0), T(1)); 3365 | } 3366 | 3367 | template 3368 | inline quaternion matToQuat(matrix m) { 3369 | T x = m.col[0].x - m.col[1].y - m.col[2].z; 3370 | T y = m.col[1].y - m.col[0].x - m.col[2].z; 3371 | T z = m.col[2].z - m.col[0].x - m.col[1].y; 3372 | T w = m.col[0].x + m.col[1].y + m.col[2].z; 3373 | 3374 | T maxVal = w; 3375 | int maxIdx = 0; 3376 | if (x > maxVal) { 3377 | maxVal = x; 3378 | maxIdx = 1; 3379 | } 3380 | if (y > maxVal) { 3381 | maxVal = y; 3382 | maxIdx = 2; 3383 | } 3384 | if (z > maxVal) { 3385 | maxVal = z; 3386 | maxIdx = 3; 3387 | } 3388 | 3389 | maxVal = sqrt(maxVal + T(1)) / T(2); 3390 | T mult = T(0.25) / maxVal; 3391 | 3392 | switch (maxIdx) { 3393 | case 0: 3394 | return quaternion( 3395 | (m.col[1].z - m.col[2].y) * mult, 3396 | (m.col[2].x - m.col[0].z) * mult, 3397 | (m.col[0].y - m.col[1].x) * mult, 3398 | maxVal); 3399 | case 1: 3400 | return quaternion( 3401 | maxVal, 3402 | (m.col[0].y + m.col[1].x) * mult, 3403 | (m.col[2].x + m.col[0].z) * mult, 3404 | (m.col[1].z - m.col[2].y) * mult); 3405 | case 2: 3406 | return quaternion( 3407 | (m.col[0].y + m.col[1].x) * mult, 3408 | maxVal, 3409 | (m.col[1].z + m.col[2].y) * mult, 3410 | (m.col[2].x - m.col[0].z) * mult); 3411 | case 3: 3412 | return quaternion( 3413 | (m.col[2].x + m.col[0].z) * mult, 3414 | (m.col[1].z + m.col[2].y) * mult, 3415 | maxVal, 3416 | (m.col[0].y - m.col[1].x) * mult); 3417 | default: return quaternion(0, 0, 0, 0); 3418 | } 3419 | } 3420 | 3421 | BMATH_END 3422 | 3423 | #undef BMATH_BEGIN 3424 | #undef BMATH_END 3425 | #undef BMATH_HAS_CONSTEXPR 3426 | #undef BMATH_HAS_EXP2_LOG2 3427 | #undef BMATH_HAS_DEFAULT_CONSTRUCTOR 3428 | #undef BMATH_CONSTEXPR 3429 | 3430 | #endif // !BMATH_H 3431 | 3432 | /* 3433 | ------------------------------------------------------------------------------ 3434 | This software is available under 2 licenses - choose whichever you prefer. 3435 | ------------------------------------------------------------------------------ 3436 | ALTERNATIVE A - MIT License 3437 | Copyright (c) 2020 Blat Blatnik 3438 | Permission is hereby granted, free of charge, to any person obtaining a copy of 3439 | this software and associated documentation files (the "Software"), to deal in 3440 | the Software without restriction, including without limitation the rights to 3441 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 3442 | of the Software, and to permit persons to whom the Software is furnished to do 3443 | so, subject to the following conditions: 3444 | The above copyright notice and this permission notice shall be included in all 3445 | copies or substantial portions of the Software. 3446 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3447 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 3448 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 3449 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3450 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 3451 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3452 | SOFTWARE. 3453 | ------------------------------------------------------------------------------ 3454 | ALTERNATIVE B - Public Domain (www.unlicense.org) 3455 | This is free and unencumbered software released into the public domain. 3456 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 3457 | software, either in source code form or as a compiled binary, for any purpose, 3458 | commercial or non-commercial, and by any means. 3459 | In jurisdictions that recognize copyright laws, the author or authors of this 3460 | software dedicate any and all copyright interest in the software to the public 3461 | domain. We make this dedication for the benefit of the public at large and to 3462 | the detriment of our heirs and successors. We intend this dedication to be an 3463 | overt act of relinquishment in perpetuity of all present and future rights to 3464 | this software under copyright law. 3465 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3466 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 3467 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 3468 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3469 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 3470 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 3471 | ------------------------------------------------------------------------------ 3472 | */ 3473 | -------------------------------------------------------------------------------- /bmath.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 35 | 36 | 37 | 38 | 39 | [{(int)x} {(int)y}] 40 | 41 | x 42 | y 43 | 44 | 45 | 46 | 47 | [{(int)x} {(int)y} {(int)z}] 48 | 49 | x 50 | y 51 | z 52 | 53 | 54 | 55 | 56 | [{(int)x} {(int)y} {(int)z} {(int)w}] 57 | 58 | x 59 | y 60 | z 61 | w 62 | 63 | 64 | 65 | 66 | [{x,g} {y,g}] 67 | 68 | x,g 69 | y,g 70 | 71 | 72 | 73 | 74 | [{x,g} {y,g} {z,g}] 75 | 76 | x,g 77 | y,g 78 | z,g 79 | 80 | 81 | 82 | 83 | [{x,g} {y,g} {z,g} {w,g}] 84 | 85 | x,g 86 | y,g 87 | z,g 88 | w,g 89 | 90 | 91 | 92 | 93 | [{x,g} {y,g}] 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | k = *(float *)&i 102 | k = k * (1.5f - (n * k * k)) 103 | k = k * (1.5f - (n * k * k)) 104 | k = k * (1.5f - (n * k * k)) 105 | 1/k,g 106 | 107 | 108 | 0.0f,g 109 | 110 | 111 | x,g 112 | y,g 113 | 114 | 115 | 116 | 117 | [{x,g} {y,g} {z,g}] 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | k = *(float *)&i 126 | k = k * (1.5f - (n * k * k)) 127 | k = k * (1.5f - (n * k * k)) 128 | k = k * (1.5f - (n * k * k)) 129 | 1/k,g 130 | 131 | 132 | 0.0f,g 133 | 134 | 135 | 136 | 137 | 138 | #{ 139 | (unsigned((x<0?0:(x>1?1:x))*255.5f) << 24) | 140 | (unsigned((y<0?0:(y>1?1:y))*255.5f) << 16) | 141 | (unsigned((z<0?0:(z>1?1:z))*255.5f) << 8) | 0xFF,Xb 142 | } 143 | 144 | 145 | x,g 146 | y,g 147 | z,g 148 | 149 | 150 | 151 | 152 | [{x,g} {y,g} {z,g} {w,g}] 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | k = *(float *)&i 161 | k = k * (1.5f - (n * k * k)) 162 | k = k * (1.5f - (n * k * k)) 163 | k = k * (1.5f - (n * k * k)) 164 | 1/k,g 165 | 166 | 167 | 0.0f,g 168 | 169 | 170 | 171 | 172 | 173 | #{ 174 | (unsigned((x<0?0:(x>1?1:x))*255.5f) << 24) | 175 | (unsigned((y<0?0:(y>1?1:y))*255.5f) << 16) | 176 | (unsigned((z<0?0:(z>1?1:z))*255.5f) << 8) | 177 | (unsigned((w<0?0:(w>1?1:w))*255.5f) << 0),Xb 178 | } 179 | 180 | 181 | x,g 182 | y,g 183 | z,g 184 | w,g 185 | 186 | 187 | 188 | 189 | [{x,g} {y,g}] 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | k = *(double *)&i 198 | k = k * (1.5 - (n * k * k)) 199 | k = k * (1.5 - (n * k * k)) 200 | k = k * (1.5 - (n * k * k)) 201 | 1/k,g 202 | 203 | 204 | 0.0,g 205 | 206 | 207 | x,g 208 | y,g 209 | 210 | 211 | 212 | 213 | [{x,g} {y,g} {z,g}] 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | k = *(double *)&i 222 | k = k * (1.5 - (n * k * k)) 223 | k = k * (1.5 - (n * k * k)) 224 | k = k * (1.5 - (n * k * k)) 225 | 1/k,g 226 | 227 | 228 | 0.0,g 229 | 230 | 231 | x,g 232 | y,g 233 | z,g 234 | 235 | 236 | 237 | 238 | [{x,g} {y,g} {z,g} {w,g}] 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | k = *(double *)&i 247 | k = k * (1.5 - (n * k * k)) 248 | k = k * (1.5 - (n * k * k)) 249 | k = k * (1.5 - (n * k * k)) 250 | 1/k,g 251 | 252 | 253 | 0.0,g 254 | 255 | 256 | x,g 257 | y,g 258 | z,g 259 | w,g 260 | 261 | 262 | 263 | 264 | {w,g} + {x,g}i + {y,g}j + {z,g}k 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | k = *(double *)&i 273 | k = k * (1.5 - (n * k * k)) 274 | k = k * (1.5 - (n * k * k)) 275 | k = k * (1.5 - (n * k * k)) 276 | 1/k,g 277 | 278 | 279 | 0.0,g 280 | 281 | 282 | x,g 283 | y,g 284 | z,g 285 | w,g 286 | 287 | 288 | 289 | 290 | {w,g} + {x,g}i + {y,g}j + {z,g}k 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | k = *(float *)&i 299 | k = k * (1.5f - (n * k * k)) 300 | k = k * (1.5f - (n * k * k)) 301 | k = k * (1.5f - (n * k * k)) 302 | 1/k,g 303 | 304 | 305 | 0.0f,g 306 | 307 | 308 | x,g 309 | y,g 310 | z,g 311 | w,g 312 | 313 | 314 | 315 | 316 | {w,g} + {x,g}i + {y,g}j + {z,g}k 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | k = *(double *)&i 325 | k = k * (1.5 - (n * k * k)) 326 | k = k * (1.5 - (n * k * k)) 327 | k = k * (1.5 - (n * k * k)) 328 | 1/k,g 329 | 330 | 331 | 0.0,g 332 | 333 | 334 | x,g 335 | y,g 336 | z,g 337 | w,g 338 | 339 | 340 | 341 | 342 | [{col[0]} {col[1]}] 343 | 344 | 345 | 346 | [{col[0].x,g} {col[1].x,g}] 347 | 348 | 349 | [{col[0].y,g} {col[1].y,g}] 350 | 351 | 352 | 353 | col[0] 354 | col[1] 355 | 356 | 357 | 358 | 359 | 360 | 361 | [{col[0]} {col[1]} {col[2]}] 362 | 363 | 364 | 365 | [{col[0].x,g} {col[1].x,g} {col[2].x,g}] 366 | 367 | 368 | [{col[0].y,g} {col[1].y,g} {col[2].y,g}] 369 | 370 | 371 | [{col[0].z,g} {col[1].z,g} {col[2].z,g}] 372 | 373 | 374 | 375 | col[0] 376 | col[1] 377 | col[2] 378 | 379 | 380 | 381 | 382 | 383 | 384 | [{col[0]} {col[1]} {col[2]} {col[3]}] 385 | 386 | 387 | 388 | [{col[0].x,g} {col[1].x,g} {col[2].x,g} {col[3].x,g}] 389 | 390 | 391 | [{col[0].y,g} {col[1].y,g} {col[2].y,g} {col[3].y,g}] 392 | 393 | 394 | [{col[0].z,g} {col[1].z,g} {col[2].z,g} {col[3].z,g}] 395 | 396 | 397 | [{col[0].w,g} {col[1].w,g} {col[2].w,g} {col[3].w,g}] 398 | 399 | 400 | 401 | col[0] 402 | col[1] 403 | col[2] 404 | col[3] 405 | 406 | 407 | 408 | 409 | 410 | -------------------------------------------------------------------------------- /bmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | bmem.h - v0.1 - public domain memory management utilities 3 | 4 | by Blat Blatnik 5 | 6 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK 7 | 8 | For licence information see end of file. 9 | 10 | Do this: 11 | #define B_MEM_IMPLEMENTATION 12 | before you include this file in *ONE* C or C++ file to create the implementation. 13 | 14 | //i.e. it should look something like this: 15 | #include ... 16 | #include ... 17 | #include B_MEM_IMPLEMENTATION 18 | #include "bmem.h" 19 | 20 | ----------------------------- 21 | ----- TEMPORARY STORAGE ----- 22 | ----------------------------- 23 | 24 | This library provides two sets of memory utilities. The first set of utilities 25 | provides a thread-local small "temporary storage" memory which can linearly allocated 26 | with the talloc function. I got this idea from Jonathan Blow's Jai programing 27 | language which provides a similar utility. The basic idea is to have a small thread-local 28 | memory arena which is used for allocating memory which doesn't need to live for very 29 | long. 30 | 31 | For example in a game you could use it to allocate memory that is only used within 32 | the frame of allocation, and then the allocator would be completely reset at the end of 33 | the frame, freeing up the memory to be used again for the next frame. This allocation 34 | scheme should in theory be very fast, if the memory arena is sufficiently small, most of 35 | it should fit in cache. 36 | 37 | This temporary memory is not meant to be allocated and then freed like you do with 38 | malloc/free. Rather you are supposed to talloc memory to your hearts content, and then call 39 | tempReset(0) ONCE IN A WHILE - for example every second - to clear out ALL of the temporary 40 | memory at once. If you know how long the talloce'd memory will last and you don't want to 41 | waste space in the temporary storage, you can use the following pattern: 42 | 43 | int mark = tempMark(); // save current state of the temporary storage 44 | void *memory = talloc(...); // allocate more temp storage memory 45 | // use 'memory' 46 | tempReset(mark); // reset the temporary storage back to original state - effectively freeing 'memory' 47 | 48 | Since the temporary storage memory is thread-local, it is inherently THREAD-SAFE since 49 | each thread gets its own memory arena. By default the temporary storage has a capacity of 50 | 64KiB, however you can 51 | 52 | #define B_TEMP_MEM_SIZE [size in bytes] 53 | 54 | If you want to increase this limit. If you try to talloc memory over the capacity of the 55 | temp storage, for example if you try to talloc 3 x 32KiB, then the first two tallocs will 56 | work as normal, but the last one will overflow. The overflow will be detected inside of 57 | talloc, and it will fall back to allocating memory from the heap with malloc. Since you 58 | aren't generally supposed to call 'free' on memory returned by talloc, this overflowed memory 59 | will leak, but your application will not crash and you will get the amount of memory you requested. 60 | 61 | The overflow will be logged out to the console, so you WILL be notified exactly when 62 | it happens, and exactly how many bytes got leaked. You can then adjust the temporary storage 63 | size accordingly so that the leaks stop happening. You can also call 'getTempMemStats' to 64 | get some useful statistics from your usage patterns, such as the total number of talloc calls, 65 | or the highest number of temp bytes ever active in your application. 66 | 67 | -------------------------- 68 | ----- HEAP DEBUGGING ----- 69 | -------------------------- 70 | 71 | The second set of memory utilities aim to help track down memory leaks and buffer overruns. 72 | the functions debugAlloc, debugRealloc, and debugFree act like malloc, realloc and free do 73 | but they also allocate additional memory to store some meta-info about each allocation, such 74 | as the file and line in which each allocation happened. 75 | 76 | In debug builds (when NDEBUG is not defined) malloc, realloc, and free will be #defined like this: 77 | 78 | #define malloc debugAlloc 79 | #define realloc debugRealloc 80 | #define free debugFree 81 | 82 | so that this file can be just dropped into an existing codebase and everything should continue 83 | to work as expected. You can call debugMemDump at any time to print out the currently active 84 | heap allocations in your program. So you can for example call debugMemDump at the end of 85 | your program to check for memory leaks. 86 | 87 | You can also call debugGetFirstHeapBlock to get a pointer to a the first element of a doubly 88 | linked list holding information about all of the allocations. Check the implementation of 89 | debugMemDump for an example of how to use debugGetFirstHeapBlock. You can also call debugGetHeapStats 90 | to get some information about how your application uses heap memory - such as how many times 91 | you called malloc, the average number of bytes per allocation, etc. 92 | 93 | If you need to access the default malloc/realloc/free functions inside of a debug build 94 | you can either disable the leak-checking by 95 | 96 | #define B_DONT_LEAK_CHECK 97 | 98 | before including this file, or you can call heapAlloc/heapRealloc/heapFree, which are simple 99 | aliases to malloc/realloc/free. 100 | 101 | NOTE: debugAlloc/debugRealloc/debugFree are NOT thread-safe. DO NOT use them if you 102 | have a multi-threaded application where each thread calls malloc/realloc/free. 103 | 104 | ------------------- 105 | ----- OPTIONS ----- 106 | ------------------- 107 | 108 | #define any of these before including this file for them to take effect: 109 | 110 | #define B_TEMP_MEM_SIZE [size-in-bytes] 111 | - Change the capacity of the thread-local temporary storage. 112 | 113 | #define B_ASSERT(condition) your-assertion-function(condition) 114 | - Avoid #include by defining your own assertion function. 115 | Note that if you #include "bdebug.h" before this file, the ASSERT from 116 | bdebug will automatically be used. 117 | 118 | #define B_LOG(message) your-logging-function(message) 119 | - Instead of printing information to stdout, use a custom logging utility. 120 | Note that if you #include "bdebug.h" before this file, the debugLog from 121 | bdebug will automatically be used. 122 | 123 | #define B_DONT_LEAK_CHECK 124 | - Don't #define malloc/realloc/free to debugAlloc/debugRealloc/debugFree. 125 | 126 | #define B_DONT_CLEAR_TEMP_MEM 127 | - Don't clear temporary storage memory to 0 when calling tempReset, leave the contents unchanged. 128 | This will improve performance of tempReset. 129 | 130 | #define NDEBUG 131 | - Equivalent to both B_DONT_LEAK_CHECK and B_DONT_CLEAR_TEMP_MEM combined. 132 | 133 | #define B_ALWAYS_LEAK_CHECK 134 | - Ignore B_DONT_LEAK_CHECK and always #define malloc/realloc/free 135 | 136 | #define B_ALWAYS_CLEAR_TEMP_MEM 137 | - Ignore B_DONT_CLEAR_TEMP_MEM and always clear temp memory to 0 when calling tempReset. 138 | 139 | #define B_THREAD_LOCAL ... 140 | - If your compiler does not support the standard _Thread_local qualifier, then you 141 | can define this so that something like: 142 | B_THREAD_LOCAL int x; 143 | will correctly compile on your compiler. 144 | 145 | #define B_MEM_PREFIX(name) [your-name-prefix] ## name 146 | #define B_PREFIX(name) [your-name-prefix] ## name 147 | - Add a prefix to all functions/variables/types declared by this file. 148 | Useful for avoiding name-conflicts. By default no prefix is added. 149 | */ 150 | 151 | #ifndef B_MEM_DEFINITION 152 | #define B_MEM_DEFINITION 153 | 154 | #ifndef B_MEM_PREFIX 155 | # ifdef B_PREFIX 156 | # define B_MEM_PREFIX(name) B_PREFIX(name) 157 | # else 158 | # define B_MEM_PREFIX(name) name 159 | # endif 160 | #endif 161 | 162 | /* we NEED to include stdlib.h BEFORE setting up the 163 | macro replacements for malloc, realloc, and free. 164 | stdlib will freak out otherwise.. */ 165 | #include 166 | #include 167 | #include 168 | 169 | typedef struct B_MEM_PREFIX(HeapBlockInfo) { 170 | size_t size, size0; /* allocation size in bytes */ 171 | time_t time, time0; /* allocation timestamp */ 172 | const char *file, *file0; /* file where allocation occured */ 173 | const char *func, *func0; /* function where allocation occured */ 174 | int line, line0; /* line where allocation occured */ 175 | struct B_MEM_PREFIX(HeapBlockInfo) *prev, *next; 176 | } B_MEM_PREFIX(HeapBlockInfo); 177 | 178 | typedef struct B_MEM_PREFIX(HeapStats) { 179 | size_t totalNumAllocs; /* number of calls to malloc since program start */ 180 | size_t totalNumReallocs; /* number of calls to realloc ... */ 181 | size_t totalNumFrees; /* number of calls to free ... */ 182 | size_t totalBytesAlloced; /* number of bytes alloced ... */ 183 | size_t totalBytesFreed; /* number of bytes freed ... */ 184 | size_t currNumAllocs; /* number of currently active heap allocations */ 185 | size_t currBytesAlloced; /* number of currently active heap allocated bytes */ 186 | size_t maxNumAllocs; /* highest number of active heap allocations ever reached during runtime */ 187 | size_t maxBytesAlloced; /* highest number of active heap allocated bytes ... */ 188 | double avgAllocLifespan; /* average time in seconds allocations last before being freed */ 189 | } B_MEM_PREFIX(HeapStats); 190 | 191 | typedef struct B_MEM_PREFIX(TempMemStats) { 192 | size_t totalNumAllocs; /* number of calls to tempAlloc since program start */ 193 | size_t totalNumFullResets; /* number of calls to tempReset(*0*) ... */ 194 | size_t totalBytesAlloced; /* number of temp bytes allocated ... */ 195 | size_t currBytesAlloced; /* number temp bytes currently active in this cycle */ 196 | size_t maxBytesAlloced; /* highest number of temp bytes active at a time during one cycle */ 197 | size_t totalNumLeaks; /* number of times a temp memory leak occured because temp memory was full when calling tempAlloc */ 198 | size_t totalBytesLeaked; /* number of bytes which were leaked when tempAlloc was called while temp memory was full */ 199 | size_t numAllocsSinceFullReset; /* number of calls to tempAlloc since the last time tempReset(*0*) was called */ 200 | size_t bytesAllocedSinceFullReset; /* number of temp bytes allocated ... */ 201 | double avgNumAllocsPerResetCycle; /* average number of calls to tempAlloc during a single reset cycle */ 202 | double avgBytesAllocedPerResetCycle; /* average number of temp bytes allocated ... */ 203 | } B_MEM_PREFIX(TempMemStats); 204 | 205 | /* these are always exactly the same as the stdlib malloc, realloc, and free 206 | so that we can redefine them AND still be able to access them with these.. */ 207 | static inline void *B_MEM_PREFIX(heapAlloc)(size_t size) { 208 | return malloc(size); 209 | } 210 | static inline void *B_MEM_PREFIX(heapRealloc)(void *mem, size_t size) { 211 | return realloc(mem, size); 212 | } 213 | static inline void B_MEM_PREFIX(heapFree)(void *mem) { 214 | free(mem); 215 | } 216 | 217 | void * B_MEM_PREFIX(debugAlloc)(size_t size, const char *file, const char *func, int line); 218 | void * B_MEM_PREFIX(debugRealloc)(void *mem, size_t size, const char *file, const char *func, int line); 219 | void B_MEM_PREFIX(debugFree)(void *mem, const char *file, const char *func, int line); 220 | void B_MEM_PREFIX(debugHeapDump)(void); 221 | B_MEM_PREFIX(HeapBlockInfo) * B_MEM_PREFIX(debugGetFirstHeapBlock)(void); 222 | B_MEM_PREFIX(HeapStats) B_MEM_PREFIX(debugGetHeapStats)(void); 223 | 224 | void * B_MEM_PREFIX(talloc)(size_t size, size_t align); 225 | char * B_MEM_PREFIX(tsprintf)(const char *format, ...); 226 | int B_MEM_PREFIX(tempMark)(void); 227 | void B_MEM_PREFIX(tempReset)(int mark); 228 | B_MEM_PREFIX(TempMemStats) B_MEM_PREFIX(getTempMemStats)(void); 229 | 230 | #if defined(B_ALWAYS_LEAK_CHECK) || (!defined(B_DONT_LEAK_CHECK) && !defined(NDEBUG)) 231 | # define malloc(size) B_MEM_PREFIX(debugAlloc)(size, __FILE__, __func__, __LINE__) 232 | # define realloc(mem, size) B_MEM_PREFIX(debugRealloc)(mem, size, __FILE__, __func__, __LINE__) 233 | # define free(mem) B_MEM_PREFIX(debugFree)(mem, __FILE__, __func__, __LINE__) 234 | #endif 235 | 236 | #endif /* !B_MEM_DEFINITION */ 237 | 238 | /* 239 | * | | 240 | * v Implementation v 241 | * | | 242 | */ 243 | 244 | #ifdef B_MEM_IMPLEMENTATION 245 | #ifndef B_MEM_IMPLEMENTED 246 | #define B_MEM_IMPLEMENTED 247 | 248 | #ifndef B_TEMP_MEM_SIZE 249 | # define B_TEMP_MEM_SIZE 65536 250 | #endif 251 | 252 | #ifndef B_ASSERT 253 | # ifdef B_DEBUG_DEFINITION 254 | # define B_ASSERT(condition) ASSERT(condition) 255 | # else 256 | # include 257 | # define B_ASSERT(condition) assert(condition) 258 | # endif 259 | #endif 260 | 261 | #ifndef B_LOG 262 | # ifdef B_DEBUG_DEFINITION 263 | # define B_LOG(message) B_DEBUG_PREFIX(debugLog)(message) 264 | # else 265 | # define B_LOG(message) printf(message) 266 | # endif 267 | #endif 268 | 269 | #ifndef B_THREAD_LOCAL 270 | # if defined(_MSC_VER) || defined(__INTEL_COMPILER) 271 | # define B_THREAD_LOCAL __declspec(thread) 272 | # elif defined(__GNUC__) || defined(__clang__) 273 | # define B_THREAD_LOCAL __thread 274 | # elif defined(__cplusplus) 275 | # define B_THREAD_LOCAL thread_local /* c++ fallback */ 276 | # else 277 | # define B_THREAD_LOCAL _Thread_local /* c fallback */ 278 | # endif 279 | #endif 280 | 281 | #include 282 | #include 283 | #include 284 | 285 | static B_MEM_PREFIX(HeapBlockInfo) *b__firstHeapBlock; 286 | static B_MEM_PREFIX(HeapStats) b__heapStats; 287 | static B_THREAD_LOCAL B_MEM_PREFIX(TempMemStats) b__tempMemStats; 288 | static B_THREAD_LOCAL char b__tempMem[B_TEMP_MEM_SIZE]; 289 | 290 | typedef char b__WaterMark[8]; 291 | 292 | static int b__checkForOverrun(void *mem) { 293 | char *memory = (char *)mem; 294 | B_MEM_PREFIX(HeapBlockInfo) *block = (B_MEM_PREFIX(HeapBlockInfo) *)(memory - sizeof(B_MEM_PREFIX(HeapBlockInfo)) - sizeof(b__WaterMark)); 295 | 296 | b__WaterMark *header = (b__WaterMark *)(memory - sizeof(B_MEM_PREFIX(HeapBlockInfo))); 297 | b__WaterMark *footer = (b__WaterMark *)(memory + block->size); 298 | int headerGood = memcmp(header, "MEMHEADR", sizeof(b__WaterMark)) == 0; 299 | int footerGood = memcmp(footer, "MEMFOOTR", sizeof(b__WaterMark)) == 0; 300 | 301 | return headerGood && footerGood; 302 | } 303 | 304 | void *B_MEM_PREFIX(debugAlloc)(size_t size, const char *file, const char *func, int line) { 305 | if (size == 0) 306 | return NULL; 307 | 308 | char *mem = (char *)B_MEM_PREFIX(heapAlloc)(size + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + 2 * sizeof(b__WaterMark)); 309 | B_MEM_PREFIX(HeapBlockInfo) *block = (B_MEM_PREFIX(HeapBlockInfo) *)mem; 310 | block->size0 = size; 311 | block->file0 = file; 312 | block->func0 = func; 313 | block->line0 = line; 314 | block->time0 = time(NULL); 315 | block->size = size; 316 | block->file = file; 317 | block->func = func; 318 | block->line = line; 319 | block->time = block->time0; 320 | 321 | b__WaterMark *header = (b__WaterMark *)(mem + sizeof(B_MEM_PREFIX(HeapBlockInfo))); 322 | b__WaterMark *footer = (b__WaterMark *)(mem + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + sizeof(b__WaterMark) + size); 323 | memcpy(header, "MEMHEADR", sizeof(b__WaterMark)); 324 | memcpy(footer, "MEMFOOTR", sizeof(b__WaterMark)); 325 | 326 | if (!b__firstHeapBlock) { /* this is the first memory allocation */ 327 | b__firstHeapBlock = block; 328 | b__firstHeapBlock->prev = b__firstHeapBlock; 329 | } 330 | 331 | block->next = b__firstHeapBlock; 332 | block->prev = b__firstHeapBlock->prev; 333 | b__firstHeapBlock->prev->next = block; 334 | b__firstHeapBlock->prev = block; 335 | 336 | /* update heap stats.. */ 337 | b__heapStats.totalNumAllocs++; 338 | b__heapStats.totalBytesAlloced += size; 339 | b__heapStats.currNumAllocs++; 340 | if (b__heapStats.currNumAllocs > b__heapStats.maxNumAllocs) 341 | b__heapStats.maxNumAllocs = b__heapStats.currNumAllocs; 342 | b__heapStats.currBytesAlloced += size; 343 | if (b__heapStats.currBytesAlloced > b__heapStats.maxBytesAlloced) 344 | b__heapStats.maxBytesAlloced = b__heapStats.currBytesAlloced; 345 | 346 | return mem + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + sizeof(b__WaterMark); 347 | } 348 | 349 | void *B_MEM_PREFIX(debugRealloc)(void *mem, size_t size, const char *file, const char *func, int line) { 350 | if (size == 0) { 351 | B_MEM_PREFIX(debugFree)(mem, file, func, line); 352 | return NULL; 353 | } 354 | if (mem == NULL) 355 | return B_MEM_PREFIX(debugAlloc)(size, file, func, line); 356 | 357 | int isOverrun = b__checkForOverrun(mem); 358 | B_ASSERT(!isOverrun); 359 | 360 | B_MEM_PREFIX(HeapBlockInfo) *oldBlock = (B_MEM_PREFIX(HeapBlockInfo))((char *)mem - sizeof(b__WaterMark) - sizeof(B_MEM_PREFIX(HeapBlockInfo))); 361 | char *memory = (char *)B_MEM_PREFIX(heapRealloc)(oldBlock, 362 | size + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + 2 * sizeof(b__WaterMark)); 363 | B_MEM_PREFIX(HeapBlockInfo) *block = (B_MEM_PREFIX(HeapBlockInfo) *)memory; 364 | 365 | /* block memory address changed so we need to update neighbors */ 366 | block->prev->next = block; 367 | block->next->prev = block; 368 | if (oldBlock == b__firstHeapBlock) 369 | b__firstHeapBlock = block; 370 | 371 | block->size = size; 372 | block->file = file; 373 | block->func = func; 374 | block->line = line; 375 | block->time = time(NULL); 376 | 377 | b__WaterMark *header = (b__WaterMark *)(memory + sizeof(B_MEM_PREFIX(HeapBlockInfo))); 378 | b__WaterMark *footer = (b__WaterMark *)(memory + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + sizeof(b__WaterMark) + size); 379 | memcpy(header, "MEMHEADR", sizeof(b__WaterMark)); 380 | memcpy(footer, "MEMFOOTR", sizeof(b__WaterMark)); 381 | 382 | /* update heap stats.. */ 383 | size_t size0 = block->size0; 384 | b__heapStats.totalNumReallocs++; 385 | if (size > size0) { 386 | b__heapStats.totalBytesAlloced += size - size0; 387 | b__heapStats.currBytesAlloced += size - size0; 388 | } else { 389 | b__heapStats.totalBytesFreed += size0 - size; 390 | b__heapStats.currBytesAlloced -= size0 - size; 391 | } 392 | 393 | if (b__heapStats.totalBytesAlloced > b__heapStats.maxBytesAlloced) 394 | b__heapStats.maxBytesAlloced = b__heapStats.totalBytesAlloced; 395 | 396 | return memory + sizeof(B_MEM_PREFIX(HeapBlockInfo)) + sizeof(b__WaterMark); 397 | } 398 | 399 | void B_MEM_PREFIX(debugFree)(void *mem, const char *file, const char *func, int line) { 400 | (void)file; 401 | (void)func; 402 | (void)line; 403 | if (!mem) 404 | return; 405 | 406 | int isOverrun = b__checkForOverrun(mem); 407 | B_ASSERT(!isOverrun); 408 | 409 | B_MEM_PREFIX(HeapBlockInfo) *block = (B_MEM_PREFIX(HeapBlockInfo) *)((char *)mem - sizeof(b__WaterMark) - sizeof(B_MEM_PREFIX(HeapBlockInfo))); 410 | 411 | if (block->next == block->prev) { /* either 1 or 2 active allocations */ 412 | B_MEM_PREFIX(HeapBlockInfo) *other = block->next; 413 | other->next = other; 414 | other->prev = other; 415 | } else { 416 | block->next->prev = block->prev; 417 | block->prev->next = block->next; 418 | } 419 | 420 | if (block == b__firstHeapBlock) 421 | b__firstHeapBlock = b__firstHeapBlock->next; 422 | if (block == b__firstHeapBlock) 423 | b__firstHeapBlock = NULL; 424 | 425 | b__heapStats.totalNumFrees++; 426 | b__heapStats.totalBytesFreed += block->size; 427 | b__heapStats.currNumAllocs--; 428 | b__heapStats.currBytesAlloced -= block->size; 429 | 430 | /* running-average: newAvg = oldAvg + (newVal - oldAvg) / (1 + newCount) */ 431 | double lifespan = difftime(block->time, block->time0); 432 | b__heapStats.avgAllocLifespan += (lifespan - b__heapStats.avgAllocLifespan) / b__heapStats.totalNumFrees; 433 | 434 | B_MEM_PREFIX(heapFree)(block); 435 | } 436 | 437 | void B_MEM_PREFIX(debugHeapDump)(void) { 438 | B_MEM_PREFIX(HeapBlockInfo) *block = B_MEM_PREFIX(debugGetFirstHeapBlock)(); 439 | if (!block) { 440 | printf("no allocated memory\n"); 441 | return; 442 | } 443 | 444 | int index = 1; 445 | do { 446 | char timestamp[64]; 447 | struct tm *t = localtime(&block->time); 448 | strftime(timestamp, sizeof(timestamp), "%T", t); 449 | 450 | printf("%d: %d bytes @ %s:%d (%s) %s\n", 451 | index, (int)block->size, block->file, block->line, block->func, timestamp); 452 | if (block->size != block->size0 || 453 | block->file != block->file0 || 454 | block->line != block->line0 || 455 | block->func != block->func0 || 456 | block->time != block->time0) 457 | { 458 | t = localtime(&block->time0); 459 | strftime(timestamp, sizeof(timestamp), "%T", t); 460 | printf(" .. realloced from %d bytes @ %s:%d (%s) %s\n", 461 | (int)block->size0, block->file0, block->line0, block->func0, timestamp); 462 | } 463 | 464 | block = block->next; 465 | ++index; 466 | 467 | } while (block != b__firstHeapBlock); 468 | } 469 | 470 | B_MEM_PREFIX(HeapBlockInfo) *B_MEM_PREFIX(debugGetFirstHeapBlock)(void) { 471 | return b__firstHeapBlock; 472 | } 473 | 474 | B_MEM_PREFIX(HeapStats) B_MEM_PREFIX(debugGetHeapStats)(void) { 475 | return b__heapStats; 476 | } 477 | 478 | static size_t b__roundUpPow2(size_t x, size_t pow2) { 479 | if ((x & (pow2 - 1)) == 0) 480 | return x; 481 | return (x + pow2) & ~(pow2 - 1); 482 | } 483 | 484 | void *B_MEM_PREFIX(talloc)(size_t size, size_t align) { 485 | if (align == 0) 486 | align = 8; 487 | 488 | B_ASSERT((align & (align - 1)) == 0); /* alignment must be a power of 2! */ 489 | size_t memStart = b__roundUpPow2(b__tempMemStats.currBytesAlloced, align); 490 | size_t memEnd = memStart + size; 491 | 492 | if (memEnd > B_TEMP_MEM_SIZE) { 493 | /* temp mem leak! */ 494 | char logBuffer[128]; 495 | sprintf(logBuffer, "leaked %d bytes of temp memory!\n", (int)size); 496 | B_LOG(logBuffer); 497 | b__tempMemStats.totalNumLeaks++; 498 | b__tempMemStats.totalBytesLeaked += size; 499 | return malloc(size); 500 | } 501 | 502 | b__tempMemStats.bytesAllocedSinceFullReset += (memEnd - memStart); 503 | b__tempMemStats.numAllocsSinceFullReset++; 504 | b__tempMemStats.totalNumAllocs++; 505 | b__tempMemStats.currBytesAlloced = memEnd; 506 | b__tempMemStats.totalBytesAlloced += (memEnd - memStart); 507 | if (b__tempMemStats.currBytesAlloced > b__tempMemStats.maxBytesAlloced) 508 | b__tempMemStats.maxBytesAlloced = b__tempMemStats.currBytesAlloced; 509 | return &b__tempMem[memStart]; 510 | } 511 | 512 | char *B_MEM_PREFIX(tsprintf)(const char *format, ...) { 513 | va_list args; 514 | va_start(args, format); 515 | int length = 1 + vsnprintf(NULL, 0, format, args); 516 | va_end(args); 517 | 518 | char *string = (char *)B_MEM_PREFIX(talloc)((size_t)length, 1); 519 | va_start(args, format); 520 | vsnprintf(string, (size_t)length, format, args); 521 | va_end(args); 522 | 523 | return string; 524 | } 525 | 526 | int B_MEM_PREFIX(tempMark)(void) { 527 | return (int)b__tempMemStats.currBytesAlloced; 528 | } 529 | 530 | void B_MEM_PREFIX(tempReset)(int mark) { 531 | size_t newMark = (size_t)mark; 532 | size_t currMark = b__tempMemStats.currBytesAlloced; 533 | B_ASSERT(newMark <= currMark); 534 | 535 | #if defined(B_ALWAYS_CLEAR_TEMP_MEM) || (!defined(B_DONT_CLEAR_TEMP_MEM) && !defined(NDEBUG)) 536 | /* zero out memory in debug builds */ 537 | memset(&b__tempMem[newMark], 0, currMark - newMark); 538 | #endif 539 | 540 | if (newMark == 0) { 541 | /* this is a full reset */ 542 | /* running-average: newAvg = oldAvg + (newVal - oldAvg) / (1 + newCount) */ 543 | b__tempMemStats.totalNumFullResets++; 544 | b__tempMemStats.avgBytesAllocedPerResetCycle += 545 | (b__tempMemStats.bytesAllocedSinceFullReset - b__tempMemStats.avgBytesAllocedPerResetCycle) / (b__tempMemStats.totalNumFullResets); 546 | b__tempMemStats.avgNumAllocsPerResetCycle += 547 | (b__tempMemStats.numAllocsSinceFullReset - b__tempMemStats.avgNumAllocsPerResetCycle) / (b__tempMemStats.totalNumFullResets); 548 | b__tempMemStats.numAllocsSinceFullReset = 0; 549 | b__tempMemStats.bytesAllocedSinceFullReset = 0; 550 | } 551 | 552 | b__tempMemStats.currBytesAlloced = newMark; 553 | b__tempMemStats.numAllocsSinceFullReset = 0; 554 | } 555 | 556 | B_MEM_PREFIX(TempMemStats) B_MEM_PREFIX(getTempMemStats)(void) { 557 | return b__tempMemStats; 558 | } 559 | 560 | #endif /* !B_MEM_IMPLEMENTED */ 561 | #endif /* B_MEM_IMPLEMENTATION */ 562 | 563 | /* 564 | ------------------------------------------------------------------------------ 565 | This software is available under 2 licenses - choose whichever you prefer. 566 | ------------------------------------------------------------------------------ 567 | ALTERNATIVE A - MIT License 568 | Copyright (c) 2020 Blat Blatnik 569 | Permission is hereby granted, free of charge, to any person obtaining a copy of 570 | this software and associated documentation files (the "Software"), to deal in 571 | the Software without restriction, including without limitation the rights to 572 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 573 | of the Software, and to permit persons to whom the Software is furnished to do 574 | so, subject to the following conditions: 575 | The above copyright notice and this permission notice shall be included in all 576 | copies or substantial portions of the Software. 577 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 578 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 579 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 580 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 581 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 582 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 583 | SOFTWARE. 584 | ------------------------------------------------------------------------------ 585 | ALTERNATIVE B - Public Domain (www.unlicense.org) 586 | This is free and unencumbered software released into the public domain. 587 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 588 | software, either in source code form or as a compiled binary, for any purpose, 589 | commercial or non-commercial, and by any means. 590 | In jurisdictions that recognize copyright laws, the author or authors of this 591 | software dedicate any and all copyright interest in the software to the public 592 | domain. We make this dedication for the benefit of the public at large and to 593 | the detriment of our heirs and successors. We intend this dedication to be an 594 | overt act of relinquishment in perpetuity of all present and future rights to 595 | this software under copyright law. 596 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 597 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 598 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 599 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 600 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 601 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 602 | ------------------------------------------------------------------------------ 603 | */ 604 | -------------------------------------------------------------------------------- /brng.h: -------------------------------------------------------------------------------- 1 | /* 2 | brng.h - v0.9 - public domain random number generator 3 | 4 | by Blat Blatnik 5 | 6 | NO WARRANTY IMPLIED - USE AT YOUR OWN RISK 7 | 8 | For licence information see end of file. 9 | 10 | Do this: 11 | #define B_RNG_IMPLEMENTATION 12 | before you include this file in *ONE* C or C++ file to create the implementation. 13 | 14 | //i.e. it should look something like this: 15 | #include ... 16 | #include ... 17 | #include B_MEM_IMPLEMENTATION 18 | #include "brng.h" 19 | 20 | This library contains a quick & dirty implementation of the PCG XSH-RS 21 | random number generator. This is a relatively fast non-cryptographically 22 | secure generator capable of generating 32-bit numbers. 23 | 24 | See https://www.pcg-random.org/index.html 25 | 26 | period: 2^62 27 | seed: 2^63 possible different initial states 28 | output: 32 bits 29 | secure: NO! - do NOT use this for security critical applications! 30 | speed: ~3.8 CPU cycles per generated 32-bit number (64-bit machine) 31 | 32 | ------------------- 33 | ----- Options ----- 34 | ------------------- 35 | 36 | #define any of these before including this file for them to take effect: 37 | 38 | #define B_RNG_PREFIX(name) [your-name-prefix] ## name 39 | #define B_PREFIX(name) [your-name-prefix] ## name 40 | - Add a prefix to all functions/variables/types declared by this file. 41 | Useful for avoiding name-conflicts. By default no prefix is added. 42 | 43 | #define B_RNG_USE_PCG_XSH_RR 44 | - Use the slower PCG-XSH-RR variant instead of the default PCG-XSH-RS. 45 | 46 | #define B_RNG_U64 [your-64-bit-unsigned-int-type] 47 | - Use a custom 64 bit unsigned int instead of the default unsigned long long. 48 | 49 | #define B_RNG_SQRTF(x) [your-sqrtf(x)] 50 | #define B_RNG_LOGF(x) [your-logf(x)] 51 | - Avoid using math.h for sqrtf and logf by defining BOTH of these. You 52 | have to either define BOTH of them or NONE of them. 53 | */ 54 | 55 | #ifndef B_RNG_DEFINITION 56 | #define B_RNG_DEFINITION 57 | 58 | #ifndef B_RNG_PREFIX 59 | # ifdef B_PREFIX 60 | # define B_RNG_PREFIX(name) B_PREFIX(name) 61 | # else 62 | # define B_RNG_PREFIX(name) name 63 | # endif 64 | #endif 65 | 66 | #ifndef B_RNG_U64 67 | # define B_RNG_U64 unsigned long long 68 | #endif 69 | 70 | /* PCG generator state */ 71 | typedef B_RNG_U64 B_RNG_PREFIX(RNG); 72 | 73 | /* initializes a new random generator */ 74 | B_RNG_PREFIX(RNG) B_RNG_PREFIX(seedRNG)(B_RNG_U64 seed); 75 | 76 | /* generate unsigned integer in uniform[0, UINT_MAX] */ 77 | unsigned int B_RNG_PREFIX(randu)(B_RNG_PREFIX(RNG) *rng); 78 | 79 | /* generate integer in uniform[min, max) */ 80 | int B_RNG_PREFIX(randi)(B_RNG_PREFIX(RNG) *rng, int min, int max); 81 | 82 | /* generate a '1' with the given probability p, and '0' with probability 1 - p */ 83 | int B_RNG_PREFIX(randp)(B_RNG_PREFIX(RNG) *rng, float p); 84 | 85 | /* generate float in uniform[0, 1] */ 86 | float B_RNG_PREFIX(randf)(B_RNG_PREFIX(RNG) *rng); 87 | 88 | /* generate float in uniform[min, max] */ 89 | float B_RNG_PREFIX(randUniform)(B_RNG_PREFIX(RNG) *rng, float min, float max); 90 | 91 | /* generate normally distributed float with given mean and standard deviation */ 92 | float B_RNG_PREFIX(randGaussian)(B_RNG_PREFIX(RNG) *rng, float mean, float stddev); 93 | 94 | #endif /* !B_RNG_DEFINITION */ 95 | 96 | /* 97 | * | | 98 | * v Implementation v 99 | * | | 100 | */ 101 | 102 | #ifdef B_RNG_IMPLEMENTATION 103 | #ifndef B_RNG_IMPLEMENTED 104 | #define B_RNG_IMPLEMENTED 105 | 106 | #ifndef B_RNG_SQRTF 107 | # include 108 | # define B_RNG_SQRTF(x) sqrtf(x) 109 | # define B_RNG_LOGF(x) logf(x) 110 | #endif 111 | 112 | B_RNG_PREFIX(RNG) B_RNG_PREFIX(seedRNG)(B_RNG_U64 seed) { 113 | #ifndef B_RNG_USE_PCG_XSH_RR 114 | B_RNG_PREFIX(RNG) rng = 2 * seed + 1; /* seed must be odd */ 115 | #else 116 | B_RNG_PREFIX(RNG) rng = seed; 117 | #endif 118 | B_RNG_PREFIX(randu)(&rng); 119 | return rng; 120 | } 121 | 122 | unsigned int B_RNG_PREFIX(randu)(B_RNG_PREFIX(RNG) *rng) { 123 | B_RNG_U64 x = *rng; 124 | #ifndef B_RNG_USE_PCG_XSH_RR 125 | unsigned int count = (unsigned int)(x >> 61); 126 | *rng = x * 6364136223846793005u; 127 | x ^= x >> 22; 128 | return (unsigned int)(x >> (22 + count)); 129 | #else 130 | unsigned int count = (unsigned int)(x >> 59); 131 | *rng = x * 6364136223846793005u + 1442695040888963407u ; 132 | x ^= x >> 18; 133 | x >>= 27; 134 | return x >> count | x << ((unsigned int)-(int)count & 31); 135 | #endif 136 | } 137 | 138 | int B_RNG_PREFIX(randi)(B_RNG_PREFIX(RNG) *rng, int min, int max) { 139 | B_RNG_U64 m = 140 | (B_RNG_U64)B_RNG_PREFIX(randu)(rng) * (B_RNG_U64)(max - min); 141 | return min + (int)(m >> 32); 142 | } 143 | 144 | int B_RNG_PREFIX(randp)(B_RNG_PREFIX(RNG) *rng, float p) { 145 | return B_RNG_PREFIX(randf)(rng) < p + 1.192092896e-7f; 146 | } 147 | 148 | float B_RNG_PREFIX(randf)(B_RNG_PREFIX(RNG) *rng) { 149 | return B_RNG_PREFIX(randu)(rng) / (float)0xFFFFFFFF; 150 | } 151 | 152 | float B_RNG_PREFIX(randUniform)(B_RNG_PREFIX(RNG) *rng, float min, float max) { 153 | return min + B_RNG_PREFIX(randf)(rng) * (max - min); 154 | } 155 | 156 | float B_RNG_PREFIX(randGaussian)(B_RNG_PREFIX(RNG) *rng, float mean, float stddev) { 157 | /* Marsaglia polar method: 158 | https://en.wikipedia.org/wiki/Marsaglia_polar_method */ 159 | float u, v, s; 160 | do { 161 | u = B_RNG_PREFIX(randf)(rng) * 2.0f - 1.0f; 162 | v = B_RNG_PREFIX(randf)(rng) * 2.0f - 1.0f; 163 | s = u * u + v * v; 164 | } while (s >= 1.0f || s == 0.0f); 165 | s = B_RNG_SQRTF(-2.0f * B_RNG_LOGF(s) / s); 166 | return mean + stddev * u * s; 167 | } 168 | 169 | #endif /* !B_RNG_IMPLEMENTED */ 170 | #endif /* B_RNG_IMPLEMENTATION */ 171 | 172 | /* 173 | ------------------------------------------------------------------------------ 174 | This software is available under 2 licenses - choose whichever you prefer. 175 | ------------------------------------------------------------------------------ 176 | ALTERNATIVE A - MIT License 177 | Copyright (c) 2020 Blat Blatnik 178 | Permission is hereby granted, free of charge, to any person obtaining a copy of 179 | this software and associated documentation files (the "Software"), to deal in 180 | the Software without restriction, including without limitation the rights to 181 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 182 | of the Software, and to permit persons to whom the Software is furnished to do 183 | so, subject to the following conditions: 184 | The above copyright notice and this permission notice shall be included in all 185 | copies or substantial portions of the Software. 186 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 189 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 190 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 191 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 192 | SOFTWARE. 193 | ------------------------------------------------------------------------------ 194 | ALTERNATIVE B - Public Domain (www.unlicense.org) 195 | This is free and unencumbered software released into the public domain. 196 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 197 | software, either in source code form or as a compiled binary, for any purpose, 198 | commercial or non-commercial, and by any means. 199 | In jurisdictions that recognize copyright laws, the author or authors of this 200 | software dedicate any and all copyright interest in the software to the public 201 | domain. We make this dedication for the benefit of the public at large and to 202 | the detriment of our heirs and successors. We intend this dedication to be an 203 | overt act of relinquishment in perpetuity of all present and future rights to 204 | this software under copyright law. 205 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 206 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 208 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 209 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 210 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 211 | ------------------------------------------------------------------------------ 212 | */ --------------------------------------------------------------------------------