aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar gingerBill 2016-04-23 23:07:15 +0100
committerGravatar gingerBill 2016-04-23 23:07:15 +0100
commit41f87ef70484f05bbe83984e95ac45c233a7515b (patch)
tree012d0f545e3775b8688551b498c98e4bd7657b15
parentNew Libraries (diff)
Updates!!!!!
-rw-r--r--README.md8
-rw-r--r--gb.h2955
-rw-r--r--gb.hpp4091
-rw-r--r--gb_math.h1868
-rw-r--r--gb_math.hpp3882
5 files changed, 4088 insertions, 8716 deletions
diff --git a/README.md b/README.md
index 03f3d63..8f54dfd 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,10 @@ gb single-file public domain libraries for C & C++
library | latest version | category | languages | description
----------------|----------------|----------|-----------|-------------
-**gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++
-**gb.h** | 0.01 | misc | C | A C helper library geared towards game development (NOT a port of gb.hpp)
-**gb_math.h** | 0.04 | math | C | A C vector math library geared towards game development (NOT A PORT OF gb_math.hpp)
+**gb.h** | 0.02a | misc | C, C++ | A C helper library for C & C++
+**gb_math.h** | 0.04d | math | C, C++ | A C (and C++) vector math library geared towards game development
+**gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++ (this is built into gb.h too!)
**gb_ini.h** | 0.91a | misc | C, C++ | A simple ini file loader library for C & C++
-**gb.hpp** | 0.32 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development
-**gb_math.hpp** | 0.04 | math | C++11 | A C++11 math library geared towards game development
## FAQ
diff --git a/gb.h b/gb.h
index 96a686f..9e75b6b 100644
--- a/gb.h
+++ b/gb.h
@@ -1,39 +1,47 @@
-// gb.h - v0.01 - public domain C helper library - no warranty implied; use at your own risk
-// (Experimental) A C helper library geared towards game development
+/* gb.h - v0.02a - Ginger Bill's C Helper Library - public domain
+ - no warranty implied; use at your own risk
+
+ This is a single header file with a bunch of useful stuff
+ to replace the C/C++ standard library
+
+===========================================================================
+ YOU MUST
+
+ #define GB_IMPLEMENTATION
+
+ in EXACTLY _one_ C or C++ file that includes this header, BEFORE the
+ include like this:
+
+ #define GB_IMPLEMENTATION
+ #include "gb.h"
+
+ All other files should just #include "gb.h" without #define
+===========================================================================
+
+Conventions used:
+ gbTypesAreLikeThis (None core types)
+ gb_functions_and_variables_like_this
+ Prefer // Comments
+ Never use _t suffix for types (I think they are stupid...)
+
+
+Version History:
+ 0.02a - Bug fixes
+ 0.02 - Change naming convention and gbArray(Type)
+ 0.01 - Initial Version
-/*
LICENSE
- This software is in the public domain. Where that dedication is not
- recognized, you are granted a perpetual, irrevocable license to copy,
- distribute, and modify this file as you see fit.
+ This software is dual-licensed to the public domain and under the following
+ license: you are granted a perpetual, irrevocable license to copy, modify,
+ publish, and distribute this file as you see fit.
WARNING
- - This library is _highly_ experimental and features may not work as expected.
+ - This library is _slightly_ experimental and features may not work as expected.
- This also means that many functions are not documented.
-CONTENTS
- - Common Macros
- - Assert
- - Types
- - Cast macro (easy grepping)
- - Memory
- - Custom Allocation
- - gb_Allocator
- - gb_Arena
- - gb_Pool
- - gb_String
-
-TODO
- - Mutex
- - Atomics
- - Semaphore
- - Thread
- - OS Types and Functions (File/IO/OS/etc.)
-*/
+CREDITS
+ Written by Ginger Bill
-/*
-Version History:
- 0.01 - Initial Version
*/
@@ -44,161 +52,294 @@ Version History:
extern "C" {
#endif
-#include <stdarg.h>
-#include <stddef.h>
-// NOTE(bill): Because static means three different things in C/C++
-// Great design(!)
-#ifndef local_persist
-#define global static
-#define internal static
-#define local_persist static
+#ifndef GB_EXTERN
+ #if defined(__cplusplus)
+ #define GB_EXTERN extern "C"
+ #else
+ #define GB_EXTERN extern
+ #endif
#endif
-// NOTE(bill): If I put gb_inline, I _want_ it inlined
-#ifndef gb_inline
- #if defined(_MSC_VER)
- #define gb_inline __forceinline
+#ifndef GB_DLL_EXPORT
+#define GB_DLL_EXPORT __declspec(dllexport)
+#endif
+
+#ifndef GB_DLL_IMPORT
+#define GB_DLL_IMPORT __declspec(dllimport)
+#endif
+
+
+// NOTE(bill): Redefine for DLL, etc.
+#ifndef GB_DEF
+ #ifdef GB_STATIC
+ #define GB_DEF static
#else
- #define gb_inline __attribute__ ((__always_inline__))
+ #define GB_DEF extern
+ #endif
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+ #if defined(_WIN64)
+ #ifndef GB_ARCH_64_BIT
+ #define GB_ARCH_64_BIT 1
+ #endif
+ #else
+ #ifndef GB_ARCH_32_BIT
+ #define GB_ARCH_32_BIT 1
+ #endif
#endif
#endif
+// TODO(bill): Check if this works on clang
+#if defined(__GNUC__)
+ #if defined(__x86_64__) || defined(__ppc64__)
+ #ifndef GB_ARCH_64_BIT
+ #define GB_ARCH_64_BIT 1
+ #endif
+ #else
+ #ifndef GB_ARCH_32_BIT
+ #define GB_ARCH_32_BIT 1
+ #endif
+ #endif
+#endif
-#if !defined(GB_NO_STDIO)
-#include <stdio.h>
+#ifndef GB_EDIAN_ORDER
+#define GB_EDIAN_ORDER
+ #define GB_IS_BIG_EDIAN (!*(u8*)&(u16){1})
+ #define GB_IS_LITTLE_EDIAN (!GB_IS_BIG_EDIAN)
#endif
-#ifndef GB_ASSERT
-#include <assert.h>
-#define GB_ASSERT(cond) assert(cond)
+
+#if defined(_WIN32) || defined(_WIN64)
+ #ifndef GB_SYSTEM_WINDOWS
+ #define GB_SYSTEM_WINDOWS 1
+ #endif
+#elif defined(__APPLE__) && defined(__MACH__)
+ #ifndef GB_SYSTEM_OSX
+ #define GB_SYSTEM_OSX 1
+ #endif
+#elif defined(__unix__)
+ #ifndef GB_SYSTEM_UNIX
+ #define GB_SYSTEM_UNIX 1
+ #endif
+
+ #if defined(__linux__)
+ #ifndef GB_SYSTEM_LINUX
+ #define GB_SYSTEM_LINUX 1
+ #endif
+ #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ #ifndef GB_SYSTEM_FREEBSD
+ #define GB_SYSTEM_FREEBSD 1
+ #endif
+ #else
+ #error This UNIX operating system is not supported
+ #endif
+#else
+ #error This operating system is not supported
#endif
-#define GB_STATIC_ASSERT(cond, msg) typedef char gb__static_assertion_##msg[(!!(cond))*2-1]
-// NOTE(bill): Token pasting madness
-#define GB_COMPILE_TIME_ASSERT3(cond, line) GB_STATIC_ASSERT(cond, static_assertion_at_line_##line)
-#define GB_COMPILE_TIME_ASSERT2(cond, line) GB_COMPILE_TIME_ASSERT3(cond, line)
-#define GB_COMPILE_TIME_ASSERT(cond) GB_COMPILE_TIME_ASSERT2(cond, __LINE__)
+#ifndef GB_STATIC_ASSERT
+ #define GB_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond))*2-1]
+ // NOTE(bill): Token pasting madness!!
+ #define GB_STATIC_ASSERT2(cond, line) GB_STATIC_ASSERT3(cond, static_assertion_at_line_##line)
+ #define GB_STATIC_ASSERT1(cond, line) GB_STATIC_ASSERT2(cond, line)
+ #define GB_STATIC_ASSERT(cond) GB_STATIC_ASSERT1(cond, __LINE__)
+#endif
-#if !defined(GB_NO_STDIO) && defined(_MSC_VER)
- // snprintf_msvc
- gb_inline int
- gb__vsnprintf_compatible(char* buffer, size_t size, char const *format, va_list args)
- {
- int result = -1;
- if (size > 0)
- result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
- if (result == -1)
- return _vscprintf(format, args);
- return result;
- }
- gb_inline int
- gb__snprintf_compatible(char* buffer, size_t size, char const *format, ...)
- {
- int result = -1;
- va_list args;
- va_start(args, format);
- result = gb__vsnprintf_compatible(buffer, size, format, args);
- va_end(args);
- return result;
- }
- #if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
- #define snprintf gb__snprintf_compatible
- #define vsnprintf gb__vsnprintf_compatible
- #endif /* GB_DO_NOT_USE_MSVC_SPRINTF_FIX */
-#endif /* !defined(GB_NO_STDIO) */
+////////////////////////////////////////////////////////////////
+//
+// Headers
+//
+//
+#if defined(_WIN32) && !defined(__MINGW32__)
+ #ifndef _CRT_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_WARNINGS
+ #endif
+#endif
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h> // TODO(bill): Remove and replace with OS Specific stuff
+#include <string.h> // NOTE(bill): For memcpy, memmove, memcmp, etc.
+
+#if defined(GB_SYSTEM_WINDOWS)
+ #define NOMINMAX 1
+ #define WIN32_LEAN_AND_MEAN 1
+ #define VC_EXTRALEAN 1
+ #include <windows.h>
+#else
+#error Add OS Specific headers
+#endif
+#if !defined(GB_NO_STDLIB)
+#include <stdlib.h>
+#endif
+
+#ifndef gb_malloc
+#define gb_malloc(sz) malloc(sz)
+#endif
+
+#ifndef gb_mfree
+#define gb_mfree(ptr) free(ptr)
+#endif
+
+
+////////////////////////////////////////////////////////////////
+//
+// Base Types
+//
+//
#if defined(_MSC_VER)
- typedef unsigned __int8 u8;
- typedef signed __int8 s8;
+ typedef unsigned __int8 u8;
+ typedef signed __int8 i8;
typedef unsigned __int16 u16;
- typedef signed __int16 s16;
+ typedef signed __int16 i16;
typedef unsigned __int32 u32;
- typedef signed __int32 s32;
+ typedef signed __int32 i32;
typedef unsigned __int64 u64;
- typedef signed __int64 s64;
+ typedef signed __int64 i64;
#else
#include <stdint.h>
- typedef uint8_t u8;
- typedef int8_t s8;
+ typedef uint8_t u8;
+ typedef int8_t i8;
typedef uint16_t u16;
- typedef int16_t s16;
+ typedef int16_t i16;
typedef uint32_t u32;
- typedef int32_t s32;
+ typedef int32_t i32;
typedef uint64_t u64;
- typedef int64_t s64;
+ typedef int64_t i64;
#endif
-GB_COMPILE_TIME_ASSERT(sizeof(s8) == 1);
-GB_COMPILE_TIME_ASSERT(sizeof(s16) == 2);
-GB_COMPILE_TIME_ASSERT(sizeof(s32) == 4);
-GB_COMPILE_TIME_ASSERT(sizeof(s64) == 8);
+GB_STATIC_ASSERT(sizeof(u8) == sizeof(i8));
+GB_STATIC_ASSERT(sizeof(u16) == sizeof(i16));
+GB_STATIC_ASSERT(sizeof(u32) == sizeof(i32));
+GB_STATIC_ASSERT(sizeof(u64) == sizeof(i64));
-typedef size_t usize;
+GB_STATIC_ASSERT(sizeof(u8) == 1);
+GB_STATIC_ASSERT(sizeof(u16) == 2);
+GB_STATIC_ASSERT(sizeof(u32) == 4);
+GB_STATIC_ASSERT(sizeof(u64) == 8);
+
+typedef size_t usize;
+typedef ptrdiff_t isize;
+
+GB_STATIC_ASSERT(sizeof(usize) == sizeof(isize));
typedef uintptr_t uintptr;
+typedef intptr_t intptr;
typedef float f32;
typedef double f64;
-#include <stdbool.h> // NOTE(bill): To get false/true
-
-// Boolean Types
-typedef s8 b8;
-typedef s32 b32;
-
-
+GB_STATIC_ASSERT(sizeof(f32) == 4);
+GB_STATIC_ASSERT(sizeof(f64) == 8);
+
+typedef u16 char16;
+typedef u32 char32;
+
+// NOTE(bill): I think C99 and C++ `bool` is stupid for numerous reasons but there are too many
+// to write in this small comment.
+typedef i8 b8;
+typedef i16 b16;
+typedef i32 b32;
+
+// NOTE(bill): Get true and false
+#if !defined(__cplusplus)
+ #if defined(_MSC_VER) && _MSC_VER <= 1800
+ #ifndef false
+ #define false 0
+ #endif
+ #ifndef true
+ #define true 1
+ #endif
+ #else
+ #include <stdbool.h>
+ #endif
+#endif
+#ifndef U8_MIN
#define U8_MIN 0u
#define U8_MAX 0xffu
-#define S8_MIN (-0x7f - 1)
-#define S8_MAX 0x7f
+#define I8_MIN (-0x7f - 1)
+#define I8_MAX 0x7f
#define U16_MIN 0u
#define U16_MAX 0xffffu
-#define S16_MIN (-0x7fff - 1)
-#define S16_MAX 0x7fff
+#define I16_MIN (-0x7fff - 1)
+#define I16_MAX 0x7fff
#define U32_MIN 0u
#define U32_MAX 0xffffffffu
-#define S32_MIN (-0x7fffffff - 1)
-#define S32_MAX 0x7fffffff
+#define I32_MIN (-0x7fffffff - 1)
+#define I32_MAX 0x7fffffff
#define U64_MIN 0ull
#define U64_MAX 0xffffffffffffffffull
-#define S64_MIN (-0x7fffffffffffffffll - 1)
-#define S64_MAX 0x7fffffffffffffffll
+#define I64_MIN (-0x7fffffffffffffffll - 1)
+#define I64_MAX 0x7fffffffffffffffll
+#if defined(GB_ARCH_32_BIT)
+ #define USIZE_MIX U32_MIN
+ #define USIZE_MAX U32_MAX
+ #define ISIZE_MIX S32_MIN
+ #define ISIZE_MAX S32_MAX
+#elif defined(GB_ARCH_64_BIT)
+ #define USIZE_MIX U64_MIN
+ #define USIZE_MAX U64_MAX
+ #define ISIZE_MIX I64_MIN
+ #define ISIZE_MAX I64_MAX
+#else
+ #error Unknown architecture size
+#endif
+#define F32_MIN 1.17549435e-38f
+#define F32_MAX 3.40282347e+38f
+
+#define F64_MIN 2.2250738585072014e-308
+#define F64_MAX 1.7976931348623157e+308
-#ifndef COUNT_OF
-#define COUNT_OF(x) (sizeof((x)) / sizeof(0[(x)]))
-#endif
-// NOTE(bill): Allows for easy grep of casts
-// NOTE(bill): Still not as type safe as C++ static_cast, reinterpret_cast, const_cast
-#ifndef cast
-#define cast(x) (x)
#endif
+
+
#ifndef NULL
-#define NULL ((void *)0)
+ #if defined(__cplusplus)
+ #if __cplusplus >= 201103L
+ #define NULL nullptr
+ #else
+ #define NULL 0
+ #endif
+ #else
+ #define NULL ((void *)0)
+ #endif
#endif
-#ifndef GB_UNUSED
-#define GB_UNUSED(x) ((void)(sizeof(x)))
+
+
+#if !defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER <= 1800
+ #define inline __inline
#endif
-#ifndef gb_inline
+#if !defined(gb_inline)
+ #if defined(_MSC_VER)
+ #define gb_restrict __restrict
+ #else
+ #define gb_restrict restrict
+ #endif
+#endif
+
+// TODO(bill): Should force inline be a separate keyword and gb_inline be inline?
+#if !defined(gb_inline)
#if defined(_MSC_VER)
#define gb_inline __forceinline
#else
@@ -206,39 +347,1169 @@ typedef s32 b32;
#endif
#endif
+#if !defined(gb_no_inline)
+ #if defined(_MSC_VER)
+ #define gb_no_inline __declspec(noinline)
+ #else
+ #define gb_no_inline __attribute__ ((noinline))
+ #endif
+#endif
+
+// NOTE(bill): Easy to grep
+// NOTE(bill): Not needed in macros
+#ifndef cast
+#define cast(Type) (Type)
+#endif
+
+
+// NOTE(bill): Because a signed sizeof is more useful
+#ifndef gb_size_of
+#define gb_size_of(x) (isize)(sizeof(x))
+#endif
+
+#ifndef gb_count_of
+#define gb_count_of(x) ((gb_size_of(x)/gb_size_of(0[x])) / ((isize)(!(gb_size_of(x) % gb_size_of(0[x])))))
+#endif
+
+#ifndef gb_offset_of
+#define gb_offset_of(Type, element) ((isize)&(((Type *)0)->element))
+#endif
+#if defined(__cplusplus)
+#ifndef gb_align_of
+ #if __cplusplus >= 201103L
+ #define gb_align_of(Type) (isize)alignof(Type)
+ #else
+extern "C++" {
+ // NOTE(bill): Fucking Templates!
+ template <typename T> struct gbAlignment_Trick { char c; T member; };
+ #define gb_align_of(Type) gb_offset_of(gbAlignment_Trick<Type>, member)
+}
+ #endif
+#endif
+#else
+ #ifndef gb_align_of
+ #define gb_align_of(Type) gb_offset_of(struct { char c; Type member; }, member)
+ #endif
+#endif
+// NOTE(bill): I do which I had a type_of that was portable
+#ifndef gb_swap
+#define gb_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while (0)
+#endif
+// NOTE(bill): Because static means 3/4 different things in C/C++. Great design (!)
+#ifndef gb_global
+#define gb_global static // Global variables
+#define gb_internal static // Internal linkage
+#define gb_local_persist static // Local Persisting variables
+#endif
+#ifndef gb_unused
+#define gb_unused(x) ((void)(gb_size_of(x)))
+#endif
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Defer statement
+// Akin to D's SCOPE_EXIT or
+// similar to Go's defer but scope-based
+//
+// NOTE: C++11 (and above) only!
+//
+#if defined(__cplusplus)
+extern "C++" {
+namespace gb {
+
+ // NOTE(bill): Stupid fucking templates
+ template <typename T> struct RemoveReference { typedef T Type; };
+ template <typename T> struct RemoveReference<T &> { typedef T Type; };
+ template <typename T> struct RemoveReference<T &&> { typedef T Type; };
+
+ // NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't))
+ template <typename T> inline T &&forward(typename RemoveReference<T>::Type &t) { return static_cast<T &&>(t); }
+ template <typename T> inline T &&forward(typename RemoveReference<T>::Type &&t) { return static_cast<T &&>(t); }
+ template <typename T> inline T &&move(T &&t) { return static<typename RemoveReference<T>::Type &&>(t); }
+ template <typename F>
+ struct privDefer {
+ F f;
+ privDefer(F &&f) : f(forward<F>(f)) {}
+ ~privDefer() { f(); }
+ };
+ template <typename F> privDefer<F> priv_defer_func(F &&f) { return privDefer<F>(forward<F>(f)); }
+
+ #ifndef defer
+ #define GB_DEFER_1(x, y) x##y
+ #define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
+ #define GB_DEFER_3(x) GB_DEFER_2(x, __COUNTER__)
+ #define defer(code) auto GB_DEFER_3(_defer_) = priv_defer_func([&](){code;})
+ #endif
+} // namespace gb
+}
+
+ // Example
+ #if 0
+ gbMutex m;
+ gb_mutex_init(&m);
+ {
+ gb_mutex_lock(&m);
+ defer (gb_mutex_unlock(&m));
+
+ ...
+ }
+ #endif
+
+#endif
+
////////////////////////////////
-// //
-// Memory //
-// //
+//
+// Macro Fun!
+//
+//
+
+#ifndef GB_JOIN_MACROS
+#define GB_JOIN_MACROS
+ #define GB_JOIN2_IND(a, b) a##b
+ #define GB_JOIN3_IND(a, b, c) a##b##c
+
+ #define GB_JOIN2(a, b) GB_JOIN2_IND(a, b)
+ #define GB_JOIN3(a, b, c) GB_JOIN3_IND(a, b, c)
+#endif
+
+
+#ifndef GB_BIT
+#define GB_BIT(x) (1<<x)
+#endif
+
+#ifndef gb_min
+#define gb_min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef gb_max
+#define gb_max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef gb_clamp
+#define gb_clamp(x, lower, upper) gb_min(gb_max((x), (lower)), (upper))
+#endif
+
+#ifndef gb_clamp01
+#define gb_clamp01(x) gb_clamp((x), 0, 1)
+#endif
+
+
+////////////////////////////////
+//
+// Debug
+//
+//
+
+
+#ifndef GB_DEBUG_TRAP
+ #if defined(_MSC_VER)
+ #define GB_DEBUG_TRAP() __debugbreak()
+ #else
+ #define GB_DEBUG_TRAP() __builtin_trap()
+ #endif
+#endif
+
+// TODO(bill): This relies upon variadic macros which are not supported in MSVC 2003 and below, check for it if needed
+#ifndef GB_ASSERT_MSG
+#define GB_ASSERT_MSG(cond, msg, ...) do { \
+ if (!(cond)) { \
+ gb_assert_handler(#cond, __FILE__, cast(i64)__LINE__, msg, ##__VA_ARGS__); \
+ GB_DEBUG_TRAP(); \
+ } \
+} while (0)
+#endif
+
+#ifndef GB_ASSERT
+#define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL)
+#endif
+
+#ifndef GB_ASSERT_NOT_NULL
+#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL")
+#endif
+
+// NOTE(bill): Things that shouldn't happen
+#ifndef GB_PANIC
+#define GB_PANIC(msg, ...) GB_ASSERT_MSG(0, msg, ##__VA_ARGS__)
+#endif
+
+GB_DEF void gb_assert_handler(char const *condition, char const *file, i64 line, char const *msg, ...);
+
+
+
+
+
////////////////////////////////
+//
+// Printing
+//
+//
+
+// Some compilers support applying printf-style warnings to user functions.
+#if defined(__clang__) || defined(__GNUC__)
+#define GB_PRINTF_ARGS(FMT) __attribute__((format(printf, FMT, (FMT+1))))
+#else
+#define GB_PRINTF_ARGS(FMT)
+#endif
-#include <string.h> // For memcpy/memmove/memset/etc.
+// TODO(bill): Should I completely rename these functions as they are a little weird to begin with?
-#ifndef GB_IS_POWER_OF_TWO
-#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x)-1))
+GB_DEF i32 gb_printf(char const *fmt, ...) GB_PRINTF_ARGS(1);
+GB_DEF i32 gb_printf_va(char const *fmt, va_list va);
+GB_DEF i32 gb_fprintf(FILE *f, char const *fmt, ...) GB_PRINTF_ARGS(2);
+GB_DEF i32 gb_fprintf_va(FILE *f, char const *fmt, va_list va);
+GB_DEF char *gb_sprintf(char const *fmt, ...) GB_PRINTF_ARGS(1); // NOTE(bill): A locally persisting buffer is used internally
+GB_DEF char *gb_sprintf_va(char const *fmt, va_list va); // NOTE(bill): A locally persisting buffer is used internally
+GB_DEF i32 gb_snprintf(char *str, isize n, char const *fmt, ...) GB_PRINTF_ARGS(3);
+GB_DEF i32 gb_snprintf_va(char *str, isize n, char const *fmt, va_list va);
+
+GB_DEF i32 gb_println(char const *str);
+GB_DEF i32 gb_fprintln(FILE *f, char const *str);
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Memory
+//
+//
+
+#ifndef gb_align_to
+#define gb_align_to(value, alignment) (((value) + ((alignment)-1)) & ~((alignment) - 1))
+#endif
+
+#ifndef gb_is_power_of_two
+#define gb_is_power_of_two(x) ((x) != 0) && !((x) & ((x)-1))
+#endif
+
+GB_DEF void *gb_align_forward(void *ptr, isize alignment);
+GB_DEF void *gb_pointer_add(void *ptr, isize bytes);
+GB_DEF void *gb_pointer_sub(void *ptr, isize bytes);
+
+GB_DEF void gb_zero_size(void *ptr, isize size);
+
+#ifndef gb_zero_struct
+#define gb_zero_struct(t) gb_zero_size((t), gb_size_of(*(t))) // NOTE(bill): Pass pointer of struct
+#define gb_zero_array(a, count) gb_zero_size((a), gb_size_of((a)[0])*count)
+#endif
+
+GB_DEF void *gb_memcopy(void *dest, void const *source, isize size);
+GB_DEF void *gb_memmove(void *dest, void const *source, isize size);
+GB_DEF void *gb_memset(void *data, u8 byte_value, isize size);
+
+// NOTE(bill): Very similar to doing `*cast(T *)(&u)`
+#ifndef GB_BIT_CAST
+#define GB_BIT_CAST(dest, source) do { \
+ GB_STATIC_ASSERT(gb_size_of(*(dest)) <= gb_size_of(source)); \
+ gb_memcopy((dest), &(source), gb_size_of(*dest)); \
+} while (0)
#endif
-void *gb_align_forward(void *ptr, usize align);
-void gb_zero_size(void *ptr, usize size);
-#define gb_zero_struct(t) gb_zero_size((t), sizeof(*(t))) // NOTE(bill): Pass pointer of struct
-#define gb_zero_array(a, count) gb_zero_size((a), sizeof((a)[0])*count)
+
+#ifndef gb_kilobytes
+#define gb_kilobytes(x) ( (x) * (i64)(1024))
+#define gb_megabytes(x) (gb_kilobytes(x) * (i64)(1024))
+#define gb_gigabytes(x) (gb_megabytes(x) * (i64)(1024))
+#define gb_terabytes(x) (gb_gigabytes(x) * (i64)(1024))
+#endif
+
+
+// Atomics
+typedef struct gbAtomic32 { i32 volatile value; } gbAtomic32;
+typedef struct gbAtomic64 { i64 volatile value; } gbAtomic64;
+
+GB_DEF i32 gb_atomic32_load(gbAtomic32 const volatile *a);
+GB_DEF void gb_atomic32_store(gbAtomic32 volatile *a, i32 value);
+GB_DEF i32 gb_atomic32_compare_exchange_strong(gbAtomic32 volatile *a, i32 expected, i32 desired);
+GB_DEF i32 gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired);
+GB_DEF i32 gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand);
+GB_DEF i32 gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand);
+GB_DEF i32 gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand);
+
+GB_DEF i64 gb_atomic64_load(gbAtomic64 const volatile *a);
+GB_DEF void gb_atomic64_store(gbAtomic64 volatile *a, i64 value);
+GB_DEF i64 gb_atomic64_compare_exchange_strong(gbAtomic64 volatile *a, i64 expected, i64 desired);
+GB_DEF i64 gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired);
+GB_DEF i64 gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand);
+GB_DEF i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand);
+GB_DEF i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand);
+
+
+typedef struct gbMutex {
+#if defined(GB_SYSTEM_WINDOWS)
+ HANDLE win32_handle;
+#else
+ pthread_mutex_t posix_handle;
+#endif
+} gbMutex;
+
+GB_DEF void gb_mutex_init(gbMutex *m);
+GB_DEF void gb_mutex_destroy(gbMutex *m);
+GB_DEF void gb_mutex_lock(gbMutex *m);
+GB_DEF b32 gb_mutex_try_lock(gbMutex *m);
+GB_DEF void gb_mutex_unlock(gbMutex *m);
+
+// NOTE(bill): If you wanted a Scoped Mutex in C++, why not use the defer() construct?
+// No need for a silly wrapper class
+#if 0
+gbMutex m = {0};
+gb_mutex_init(&m);
+{
+ gb_mutex_lock(&m);
+ defer (gb_mutex_unlock(&m));
+
+ // Do whatever
+}
+#endif
+
+
+
+typedef struct gbSemaphore {
+#if defined(GB_SYSTEM_WINDOWS)
+ HANDLE win32_handle;
+#else
+ gbMutex mutex;
+ pthread_cond_t cond;
+ i32 count;
+#endif
+} gbSemaphore;
+
+GB_DEF void gb_semaphore_init(gbSemaphore *s);
+GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
+GB_DEF void gb_semaphore_post(gbSemaphore *s, i32 count);
+GB_DEF void gb_semaphore_wait(gbSemaphore *s);
+
+
+
+
+#define GB_THREAD_PROC(name) void name(void *data)
+;typedef GB_THREAD_PROC(gbThreadProc);
+
+typedef struct gbThread {
+#if defined(GB_SYSTEM_WINDOWS)
+ HANDLE win32_handle;
+#else
+ pthread_t posix_handle;
+#endif
+
+ gbThreadProc *proc;
+ void *data;
+
+ gbSemaphore semaphore;
+ isize stack_size;
+ b32 is_running;
+} gbThread;
+
+GB_DEF void gb_thread_init(gbThread *t);
+GB_DEF void gb_thread_destory(gbThread *t);
+GB_DEF void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data);
+GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
+GB_DEF void gb_thread_join(gbThread *t);
+GB_DEF b32 gb_thread_is_running(gbThread const *t);
+GB_DEF u32 gb_thread_current_id(void);
+
+////////////////////////////////////////////////////////////////
+//
+// Virtual Memory
+//
+//
+
+#if 0
+typedef enum gbVmAllocationFlag {
+ GB_VM_COMMIT = GB_BIT(1),
+ GB_VM_RESERVE = GB_BIT(2),
+ GB_VM_RESET = GB_BIT(3),
+ GB_VM_RESET_UNDO = GB_BIT(4),
+} gbVmAllocationFlag;
+
+typedef enum gbVmProtectionFlag {
+ GB_VM_PAGE_NO_ACCESS = GB_BIT(1),
+ GB_VM_PAGE_GUARD = GB_BIT(2),
+ GB_VM_PAGE_NO_CACHE = GB_BIT(3),
+ GB_VM_PAGE_WRITE_COMBINE = GB_BIT(4),
+} gbVmProtectionFlag;
+
+typedef enum gbVmFreeType {
+ GB_VM_RELEASE = GB_BIT(1),
+ GB_VM_DECOMMIT = GB_BIT(2),
+} gbVmFreeType;
+
+typedef struct gbVirtualMemory {
+ void *memory;
+ isize size;
+ u32 allocation_flags;
+ u32 protection_flags;
+} gbVirtualMemory;
+
+GB_DEF gbVirtualMemory gb_vm_alloc(void *base_address, isize size, u32 allocation_flags, u32 protection_flags);
+GB_DEF void gb_vm_free(gbVirtualMemory *vm);
+#endif
+
+
+////////////////////////////////////////////////////////////////
+//
+// Custom Allocation
+//
+//
+
+typedef enum gbAllocationType {
+ GB_ALLOCATION_ALLOC,
+ GB_ALLOCATION_FREE,
+ GB_ALLOCATION_FREE_ALL,
+ GB_ALLOCATION_RESIZE,
+} gbAllocationType;
+
+// NOTE(bill): This is useful so you can define an allocator of the same type and parameters
+#define GB_ALLOCATOR_PROC(name) \
+void *name(void *allocator_data, gbAllocationType type, \
+ isize size, isize alignment, \
+ void *old_memory, isize old_size, \
+ u64 options)
+;typedef GB_ALLOCATOR_PROC(gbAllocatorProc);
+
+typedef struct gbAllocator {
+ gbAllocatorProc *proc;
+ void *data;
+} gbAllocator;
+
+#ifndef GB_DEFAULT_MEMORY_ALIGNMENT
+#define GB_DEFAULT_MEMORY_ALIGNMENT 4
+#endif
+
+GB_DEF void *gb_alloc_align(gbAllocator a, isize size, isize alignment);
+GB_DEF void *gb_alloc(gbAllocator a, isize size);
+GB_DEF void gb_free(gbAllocator a, void *ptr);
+GB_DEF void gb_free_all(gbAllocator a);
+GB_DEF void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size);
+GB_DEF void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment);
+
+GB_DEF void *gb_alloc_copy(gbAllocator a, void const *src, isize size);
+GB_DEF void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment);
+
+GB_DEF char *gb_alloc_cstring(gbAllocator a, char const *str);
+
+
+// NOTE(bill): These are very useful and the type case has saved me from numerous bugs
+#ifndef gb_alloc_struct
+#define gb_alloc_struct(allocator, Type) (Type *)gb_alloc_align(allocator, gb_size_of(Type))
+#define gb_alloc_array(allocator, Type, count) (Type *)gb_alloc(allocator, gb_size_of(Type) * (count))
+#endif
+
+
+
+
+
+GB_DEF gbAllocator gb_heap_allocator(void);
+GB_DEF GB_ALLOCATOR_PROC(gb_heap_allocator_proc);
+
+
+
+
+
+typedef struct gbArena {
+ gbAllocator backing;
+ void *physical_start;
+ isize total_size;
+ isize total_allocated;
+ u32 temp_count;
+} gbArena;
+
+GB_DEF void gb_arena_init_from_memory(gbArena *arena, void *start, isize size);
+GB_DEF void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size);
+GB_DEF void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size);
+GB_DEF void gb_arena_free(gbArena *arena);
+
+GB_DEF isize gb_arena_alignment_of(gbArena *arena, isize alignment);
+GB_DEF isize gb_arena_size_remaining(gbArena *arena, isize alignment);
+GB_DEF void gb_arena_check(gbArena *arena);
+
+
+GB_DEF gbAllocator gb_arena_allocator(gbArena *arena);
+GB_DEF GB_ALLOCATOR_PROC(gb_arena_allocator_proc);
+
+
+
+typedef struct gbTempArenaMemory {
+ gbArena *arena;
+ isize original_count;
+} gbTempArenaMemory;
+
+GB_DEF gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena);
+GB_DEF void gb_temp_arena_memory_end(gbTempArenaMemory tmp_mem);
+
+
+
+
+
+
+
+
+
+typedef struct gbPool {
+ gbAllocator backing;
+
+ void *physical_start;
+ void *free_list;
+
+ isize block_size;
+ isize block_align;
+ isize total_size;
+} gbPool;
+
+GB_DEF void gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size);
+GB_DEF void gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align);
+GB_DEF void gb_pool_free(gbPool *pool);
+
+
+GB_DEF gbAllocator gb_pool_allocator(gbPool *pool);
+GB_DEF GB_ALLOCATOR_PROC(gb_pool_allocator_proc);
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Char Functions
+//
+//
+
+GB_DEF char gb_char_to_lower(char c);
+GB_DEF char gb_char_to_upper(char c);
+GB_DEF b32 gb_char_is_space(char c);
+GB_DEF b32 gb_char_is_digit(char c);
+GB_DEF b32 gb_char_is_hex_digit(char c);
+GB_DEF b32 gb_char_is_alpha(char c);
+GB_DEF b32 gb_char_is_alphanumeric(char c);
+
+
+//
+
+GB_DEF void gb_to_lower(char *str);
+GB_DEF void gb_to_upper(char *str);
+
+GB_DEF isize gb_strlen(char const *str);
+GB_DEF i32 gb_strcmp(char const *s1, char const *s2);
+GB_DEF char * gb_strncpy(char *dest, char const *source, isize len);
+GB_DEF i32 gb_strncmp(char const *s1, char const *s2, isize len);
+
+GB_DEF char const *gb_char_first_occurence(char const *s1, char c);
+GB_DEF char const *gb_char_last_occurence(char const *s1, char c);
+
+GB_DEF void gb_cstr_concat(char *dest, isize dest_len,
+ char const *src_a, isize src_a_len,
+ char const *src_b, isize src_b_len);
+
+
+////////////////////////////////////////////////////////////////
+//
+// Windows UTF-8 Handling
+//
+//
+// Windows doesn't handle 8 bit filenames well ('cause Micro$hit)
+
+GB_DEF char16 *gb_utf8_to_utf16(char16 *buffer, char *str, isize len);
+GB_DEF char * gb_utf16_to_utf8(char *buffer, char16 *str, isize len);
+
+
+////////////////////////////////////////////////////////////////
+//
+// gbString - C Read-Only-Compatible
+//
+//
+
+
+// Pascal like strings in C
+typedef char *gbString;
+
+
+// This is stored at the beginning of the string
+// NOTE(bill): If you only need a small string, just use a standard c string or change the size
+typedef struct gbStringHeader {
+ gbAllocator allocator;
+ isize length;
+ isize capacity;
+} gbStringHeader;
+
+#define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1)
+
+GB_DEF gbString gb_string_make(gbAllocator a, char const *str);
+GB_DEF gbString gb_string_make_length(gbAllocator a, void const *str, isize num_bytes);
+GB_DEF void gb_string_free(gbString str);
+
+GB_DEF gbString gb_string_duplicate(gbAllocator a, gbString const str);
+
+GB_DEF isize gb_string_length(gbString const str);
+GB_DEF isize gb_string_capacity(gbString const str);
+GB_DEF isize gb_string_available_space(gbString const str);
+
+GB_DEF void gb_string_clear(gbString str);
+
+GB_DEF gbString gb_string_append_string(gbString str, gbString const other);
+GB_DEF gbString gb_string_append_string_length(gbString str, void const *other, isize num_bytes);
+GB_DEF gbString gb_string_append_cstring(gbString str, char const *other);
+
+GB_DEF gbString gb_string_set(gbString str, char const *cstr);
+
+GB_DEF gbString gb_string_make_space_for(gbString str, isize add_len);
+GB_DEF isize gb_string_allocation_size(gbString const str);
+
+GB_DEF b32 gb_strings_are_equal(gbString const lhs, gbString const rhs);
+
+GB_DEF gbString gb_string_trim(gbString str, char const *cut_set);
+GB_DEF gbString gb_string_trim_space(gbString str); /* Whitespace ` \t\r\n\v\f` */
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// Fixed Capacity Buffer (POD Types)
+//
+//
+
+#ifndef GB_BUFFER_TYPE
+#define GB_BUFFER_TYPE
+#endif
+
+#define gbBuffer(Type) struct { isize count, capacity; Type *data; }
+
+typedef gbBuffer(u8) gbByteBuffer;
+
+#define gb_buffer_init(x, allocator, cap) do { \
+ void **data = cast(void **)&((x)->data); \
+ gb_zero_struct(x); \
+ (x)->capacity = (cap); \
+ *data = gb_alloc((allocator), (cap)*gb_size_of((x)->data[0])); \
+} while (0)
+
+#define gb_buffer_free(x, allocator) do { gb_free(allocator, (x)->data); } while (0)
+
+#define gb_buffer_append(x, item) do { (x)->data[(x)->count++] = item; } while (0)
+
+#define gb_buffer_appendv(x, items, item_count) do { \
+ GB_ASSERT(gb_size_of((items)[0]) == gb_size_of((x)->data[0])); \
+ GB_ASSERT((x)->count+item_count <= (x)->capacity); \
+ gb_memcopy((x)->data[a->count], (items), gb_size_of((x)->data[0])*(item_count)); \
+ (x)->count += (item_count); \
+} while (0)
+
+#define gb_buffer_pop(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
+#define gb_buffer_clear(x) do { (x)->count = 0; } while (0)
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// Dynamic Array (POD Types)
+//
+//
+
+// NOTE(bill): I know this is a macro hell but C is an old (and shit) language with no proper arrays
+// Also why the fuck not?! It fucking works! And it has custom allocation, which is already better than C++!
+
+// NOTE(bill): Typedef every array or you get anonymous structures everywhere!
+// e.g. typedef gbArray(int) gb_Int_Array;
+#ifndef GB_ARRAY_TYPE
+#define GB_ARRAY_TYPE
+
+#define gbArray(Type) struct { gbAllocator allocator; isize count, capacity; Type *data; }
+
+
+typedef gbArray(void) gbVoidArray; // NOTE(bill): Useful for generic stuff
+
+// Available Procedures for gbArray(Type)
+// gb_array_init
+// gb_array_free
+// gb_array_set_capacity
+// gb_array_grow
+// gb_array_append
+// gb_array_appendv
+// gb_array_pop
+// gb_array_clear
+// gb_array_resize
+// gb_array_reserve
+//
+
+#define gb_array_init(x, allocator_) do { gb_zero_struct(x); (x)->allocator = allocator_; } while (0)
+
+#define gb_array_free(x) do { \
+ if ((x)->allocator.proc) { \
+ gbAllocator a = (x)->allocator; \
+ gb_free(a, (x)->data); \
+ gb_array_init((x), a); \
+ } \
+} while (0)
+
+#define gb_array_set_capacity(array, capacity) gb__array_set_capacity((array), (capacity), gb_size_of((array)->data[0]))
+// NOTE(bill): Do not use the thing below directly, use the macro
+GB_DEF void gb__array_set_capacity(void *array, isize capacity, isize element_size);
+
+#ifndef GB_ARRAY_GROW_FORMULA
+#define GB_ARRAY_GROW_FORMULA(x) (2*(x) + 8)
+#endif
+
+// TODO(bill): Decide on a decent growing formula for gbArray
+#define gb_array_grow(x, min_capacity) do { \
+ isize capacity = GB_ARRAY_GROW_FORMULA((x)->capacity); \
+ if (capacity < (min_capacity)) \
+ capacity = (min_capacity); \
+ gb_array_set_capacity(x, capacity); \
+} while (0)
+
+
+#define gb_array_append(x, item) do { \
+ if ((x)->capacity < (x)->count+1) \
+ gb_array_grow(x, 0); \
+ (x)->data[(x)->count++] = (item); \
+} while (0)
+
+#define gb_array_appendv(x, items, item_count) do { \
+ GB_ASSERT(gb_size_of((items)[0]) == gb_size_of((x)->data[0])); \
+ if ((x)->capacity < (x)->count+(item_count)) \
+ gb_array_grow(x, (x)->count+(item_count)); \
+ gb_memcopy((x)->data[(x)->count], (items), gb_size_of((x)->data[0])*(item_count)); \
+ (x)->count += (item_count); \
+} while (0)
+
+
+
+#define gb_array_pop(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
+#define gb_array_clear(x) do { (x)->count = 0; } while (0)
+
+#define gb_array_resize(x, count) do { \
+ if ((x)->capacity < (count)) \
+ gb_array_grow(x, count); \
+ (x)->count = (count); \
+} while (0)
+
+
+#define gb_array_reserve(x, new_capacity) do { \
+ if ((x)->capacity < (new_capacity)) \
+ gb_array_set_capacity(x, new_capacity); \
+} while (0)
+
+
+#endif /* GB_ARRAY_TYPE */
+
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+//
+// Hash_Table (POD Types)
+//
+//
+
+#if 0
+// TODO(bill): Hash Table and make it decent!!!
+
+// NOTE(bill): All keys are u64
+#ifndef GB_HASH_TABLE_TYPE
+#define GB_HASH_TABLE_TYPE
+
+typedef struct gbHashTableEntry {
+ u64 key;
+ isize value;
+ isize next;
+} gbHashTableEntry;
+
+#define GB_HASH_TABLE_HEADER \
+ gbArray(isize) hashes; \
+ gbArray(gbHashTableEntry) entries \
+
+typedef struct gbHashTableHeader {
+ GB_HASH_TABLE_HEADER;
+} gbHashTableHeader;
+
+#define gbHashTable(Type) struct { \
+ GB_HASH_TABLE_HEADER; \
+ gbArray(Type) data; \
+}
+
+typedef gbHashTable(void) gbHashTableVoid; // Generic Type
+
+#define gb_hash_table_init(h, allocator) do { \
+ gb_array_init((h)->hashes, allocator); \
+ gb_array_init((h)->entries, allocator); \
+ gb_array_init((h)->data, allocator); \
+} while (0)
+
+#define gb_hash_table_free(h) do { \
+ gb_free(&(h)->hashes); \
+ gb_free(&(h)->entries); \
+ gb_free(&(h)->data); \
+} while (0)
+
+#define gb_hash_table_header(h) (cast(gbHashTableHeader *)(h))
+
+
+// TODO(bill): Should the use have to pass the Hash Table and their array?
+
+
+
+
+/* TODO(bill): Hash_Table Procs
+ gb_hash_table_init(h, allocator)
+ gb_hash_table_free(h)
+
+ gb_hash_table_has(h, key) // Return false/true
+ gb_hash_table_get(h, key) // Return entries index
+ gb_hash_table_set(h, key, value)
+ gb_hash_table_remove(h, key)
+ gb_hash_table_reserve(h, capacity)
+ gb_hash_table_clear(h)
+
+*/
+
+
+
+#endif
+
+#endif /* GB_HASH_TABLE_TYPE */
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// File Handling
+//
+//
+typedef u64 gbFileTime;
+
+typedef enum gbFileType {
+ GB_FILE_TYPE_READ = 1,
+ GB_FILE_TYPE_WRITE = 2,
+} gbFileType;
+
+typedef struct gbFile {
+ void *handle; // File to fread/fwrite
+ char *path;
+ i64 size;
+ b32 is_open;
+ gbFileType type;
+ gbFileTime last_write_time;
+} gbFile;
+
+typedef struct gbFileContents {
+ void *data;
+ isize size;
+} gbFileContents;
+
+
+GB_DEF b32 gb_file_create(gbFile *file, char const *filepath, ...); // TODO(bill): Give file permissions
+GB_DEF b32 gb_file_open(gbFile *file, char const *filepath, ...);
+GB_DEF b32 gb_file_close(gbFile *file);
+GB_DEF b32 gb_file_read_at(gbFile *file, void *buffer, isize size, i64 offset);
+GB_DEF b32 gb_file_write_at(gbFile *file, void const *buffer, isize size, i64 offset);
+GB_DEF i64 gb_file_size(gbFile *file);
+GB_DEF b32 gb_file_has_changed(gbFile *file);
+
+GB_DEF gbFileTime gb_file_last_write_time(char const *filepath, ...);
+
+
+GB_DEF b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists);
+GB_DEF b32 gb_file_move(char const *existing_filename, char const *new_filename);
+
+
+GB_DEF gbFileContents gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *filepath, ...);
+
+
+#ifndef GB_PATH_SEPARATOR
+ #if defined(GB_SYSTEM_WINDOWS)
+ #define GB_PATH_SEPARATOR '\\'
+ #else
+ #define GB_PATH_SEPARATOR '/'
+ #endif
+#endif
+
+GB_DEF b32 gb_path_is_absolute(char const *path);
+GB_DEF b32 gb_path_is_relative(char const *path);
+GB_DEF b32 gb_path_is_root(char const *path);
+GB_DEF char const *gb_path_base_name(char const *path);
+GB_DEF char const *gb_path_extension(char const *path);
+
+
+GB_DEF void gb_exit(u32 code);
+
+
+////////////////////////////////////////////////////////////////
+//
+// DLL Handling
+//
+//
+
+typedef void *gbDllHandle;
+typedef void (*gbDllProc)(void);
+
+GB_DEF gbDllHandle gb_dll_load(char const *filepath, ...);
+GB_DEF void gb_dll_unload(gbDllHandle dll);
+GB_DEF gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name);
+
+
+////////////////////////////////////////////////////////////////
+//
+// Time
+//
+//
+
+typedef struct gbDate {
+ i32 year;
+ i32 month; // 1 - Janurary, ... 12 - December
+ i32 day; // 1 - 31
+ i32 day_of_week; // 0 - Sunday, ... 6 - Saturday
+ i32 hour; // 0 - 23
+ i32 minute; // 0 - 59
+ i32 second; // 0 - 60 (leap seconds)
+ i32 milliseconds; // 0 - 999
+} gbDate;
+
+
+GB_DEF u64 gb_rdtsc(void);
+GB_DEF f64 gb_time_now(void);
+
+GB_DEF void gb_get_system_date(gbDate *date);
+GB_DEF void gb_get_local_date(gbDate *date);
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Colour Type
+// It's quite useful
+//
+
+typedef union gbColour {
+ u32 rgba; // NOTE(bill): 0xaabbggrr
+ struct { u8 r, g, b, a; };
+ u8 e[4];
+} gbColour;
+GB_STATIC_ASSERT(gb_size_of(gbColour) == gb_size_of(u32));
+
+gb_inline gbColour
+gb_colour(f32 r, f32 g, f32 b, f32 a)
+{
+ gbColour result;
+ result.r = cast(u8)(gb_clamp01(r) * 255.0f);
+ result.g = cast(u8)(gb_clamp01(g) * 255.0f);
+ result.b = cast(u8)(gb_clamp01(b) * 255.0f);
+ result.a = cast(u8)(gb_clamp01(a) * 255.0f);
+ return result;
+}
+
+gb_global gbColour const GB_COLOUR_WHITE = {0xffffffff};
+gb_global gbColour const GB_COLOUR_GREY = {0xff808080};
+gb_global gbColour const GB_COLOUR_BLACK = {0xff000000};
+
+gb_global gbColour const GB_COLOUR_RED = {0xff0000ff};
+gb_global gbColour const GB_COLOUR_ORANGE = {0xff0099ff};
+gb_global gbColour const GB_COLOUR_YELLOW = {0xff00ffff};
+gb_global gbColour const GB_COLOUR_GREEN = {0xff00ff00};
+gb_global gbColour const GB_COLOUR_CYAN = {0xffffff00};
+gb_global gbColour const GB_COLOUR_BLUE = {0xffff0000};
+gb_global gbColour const GB_COLOUR_VIOLET = {0xffff007f};
+gb_global gbColour const GB_COLOUR_MAGENTA = {0xffff00ff};
+
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* GB_INCLUDE_GB_H */
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+// Implementation
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+////////////////////////////////////////////////////////////////
+
+#if defined(GB_IMPLEMENTATION) && !defined(GB_IMPLEMENTATION_DONE)
+#define GB_IMPLEMENTATION_DONE
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+i32
+gb_printf(char const *fmt, ...)
+{
+ i32 res;
+ va_list va;
+ va_start(va, fmt);
+ res = gb_fprintf_va(stdout, fmt, va);
+ va_end(va);
+ return res;
+}
+
+
+i32
+gb_fprintf(FILE *f, char const *fmt, ...)
+{
+ i32 res;
+ va_list va;
+ va_start(va, fmt);
+ res = gb_fprintf_va(stdout, fmt, va);
+ va_end(va);
+ return res;
+}
+
+char *
+gb_sprintf(char const *fmt, ...)
+{
+ va_list va;
+ char *str;
+ va_start(va, fmt);
+ str = gb_sprintf_va(fmt, va);
+ va_end(va);
+ return str;
+}
+
+i32
+gb_snprintf(char *str, isize n, char const *fmt, ...)
+{
+ i32 res;
+ va_list va;
+ va_start(va, fmt);
+ res = gb_snprintf_va(str, n, fmt, va);
+ va_end(va);
+ return res;
+}
+
+
+gb_inline i32 gb_printf_va(char const *fmt, va_list va) { return gb_fprintf_va(stdout, fmt, va); }
+gb_inline i32 gb_fprintf_va(FILE *f, char const *fmt, va_list va) { return vfprintf(f, fmt, va); }
+
+gb_inline char *
+gb_sprintf_va(char const *fmt, va_list va)
+{
+ gb_local_persist char buffer[1024];
+ gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va);
+ return buffer;
+}
+
+gb_inline i32
+gb_snprintf_va(char *str, isize n, char const *fmt, va_list va)
+{
+ i32 res;
+#if defined(_WIN32)
+ res = _vsnprintf(str, n, fmt, va);
+#else
+ res = vsnprintf(str, n, fmt, va)
+#endif
+ if (n) str[n-1] = 0;
+ // NOTE(bill): Unix returns length output would require, Windows returns negative when truncated.
+ return (res >= n || res < 0) ? -1 : res;
+}
+
+
+gb_inline i32 gb_println(char const *str) { return gb_fprintln(stdout, str); }
+
+gb_inline i32
+gb_fprintln(FILE *f, char const *str)
+{
+ i32 res;
+ res = gb_fprintf(f, str);
+ gb_fprintf(f, "\n");
+ res++;
+ return res;
+}
+
+
+
+
+
+void
+gb_assert_handler(char const *condition, char const *file, i64 line, char const *msg, ...)
+{
+ gb_fprintf(stderr, "%s:%lld: Assert Failure: ", file, cast(long long)line);
+ if (condition)
+ gb_fprintf(stderr, "`%s` ", condition);
+
+ if (msg) {
+ va_list va;
+ va_start(va, msg);
+ gb_fprintf(stderr, msg, va);
+ va_end(va);
+ }
+
+ gb_fprintf(stderr, "\n");
+}
+
-#if defined(GB_IMPLEMENTATION)
gb_inline void *
-gb_align_forward(void *ptr, usize align)
+gb_align_forward(void *ptr, isize align)
{
uintptr p;
- usize modulo;
+ isize modulo;
- GB_ASSERT(GB_IS_POWER_OF_TWO(align));
+ GB_ASSERT(gb_is_power_of_two(align));
p = cast(uintptr)ptr;
modulo = p % align;
@@ -246,193 +1517,510 @@ gb_align_forward(void *ptr, usize align)
return cast(void *)p;
}
-gb_inline void gb_zero_size(void *ptr, usize size) { memset(ptr, 0, size); }
+gb_inline void *gb_pointer_add(void *ptr, isize bytes) { return cast(void *)(cast(u8 *)ptr + bytes); }
+gb_inline void *gb_pointer_sub(void *ptr, isize bytes) { return cast(void *)(cast(u8 *)ptr - bytes); }
-#endif // GB_IMPLEMENTATION
+gb_inline void gb_zero_size(void *ptr, isize size) { gb_memset(ptr, 0, size); }
+gb_inline void *gb_memcopy(void *dest, void const *source, isize size) { return memcpy(dest, source, size); }
+gb_inline void *gb_memmove(void *dest, void const *source, isize size) { return memmove(dest, source, size); }
+gb_inline void *gb_memset(void *data, u8 byte_value, isize size) { return memset(data, byte_value, size); }
-////////////////////////////////
-// //
-// Custom Allocation //
-// //
-////////////////////////////////
+gb_inline void *gb_alloc_align(gbAllocator a, isize size, isize alignment) { return a.proc(a.data, GB_ALLOCATION_ALLOC, size, alignment, NULL, 0, 0); }
+gb_inline void *gb_alloc(gbAllocator a, isize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); }
+gb_inline void gb_free(gbAllocator a, void *ptr) { a.proc(a.data, GB_ALLOCATION_FREE, 0, 0, ptr, 0, 0); }
+gb_inline void gb_free_all(gbAllocator a) { a.proc(a.data, GB_ALLOCATION_FREE_ALL, 0, 0, NULL, 0, 0); }
+gb_inline void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); }
+gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, GB_ALLOCATION_RESIZE, new_size, alignment, ptr, old_size, 0); };
+
+gb_inline void *gb_alloc_copy(gbAllocator a, void const *src, isize size) { return gb_memcopy(gb_alloc(a, size), src, size); }
+gb_inline void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment) { return gb_memcopy(gb_alloc_align(a, size, alignment), src, size); }
-typedef enum gb_Allocation_Type
+gb_inline char *
+gb_alloc_cstring(gbAllocator a, char const *str)
{
- GB_ALLOCATION_TYPE_ALLOC,
- GB_ALLOCATION_TYPE_FREE,
- GB_ALLOCATION_TYPE_FREE_ALL,
- GB_ALLOCATION_TYPE_RESIZE,
-} gb_Allocation_Type;
+ char *result;
+ isize len = gb_strlen(str);
+ result = cast(char *)gb_alloc_copy(a, str, len+1);
+ result[len] = '\0';
+ return result;
+}
+
+
+
+
-#define GB_ALLOCATOR_PROCEDURE(name) void *name(void *allocator_data, gb_Allocation_Type type, usize size, usize alignment, void *old_memory, usize old_size, u32 options)
-typedef GB_ALLOCATOR_PROCEDURE(gb_Allocator_Procedure);
+////////////////////////////////////////////////////////////////
+//
+// Concurrency
+//
-typedef struct gb_Allocator
+#if defined(_MSC_VER)
+gb_inline i32
+gb_atomic32_load(gbAtomic32 const volatile *a)
{
- gb_Allocator_Procedure *procedure;
- void *data;
-} gb_Allocator;
+ return a->value;
+}
+gb_inline void
+gb_atomic32_store(gbAtomic32 volatile *a, i32 value)
+{
+ a->value = value;
+}
+
+gb_inline i32
+gb_atomic32_compare_exchange_strong(gbAtomic32 volatile *a, i32 expected, i32 desired)
+{
+ return _InterlockedCompareExchange(cast(long volatile *)a, desired, expected);
+}
+
+gb_inline i32
+gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired)
+{
+ return _InterlockedExchange(cast(long volatile *)a, desired);
+}
+
+gb_inline i32
+gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand)
+{
+ return _InterlockedExchangeAdd(cast(long volatile *)a, operand);
+}
+
+gb_inline i32
+gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand)
+{
+ return _InterlockedAnd(cast(long volatile *)a, operand);
+}
+
+gb_inline i32
+gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand)
+{
+ return _InterlockedOr(cast(long volatile *)a, operand);
+}
-#ifndef GB_DEFAULT_ALIGNMENT
-#define GB_DEFAULT_ALIGNMENT 8
+
+gb_inline i64
+gb_atomic64_load(gbAtomic64 const volatile *a)
+{
+#if defined(GB_ARCH_64_BIT)
+ return a->value;
+#else
+ // NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b
+ i64 result;
+ __asm {
+ mov esi, a;
+ mov ebx, eax;
+ mov ecx, edx;
+ lock cmpxchg8b [esi];
+ mov dword ptr result, eax;
+ mov dword ptr result[4], edx;
+ }
+ return result;
#endif
+}
-gb_inline void *gb_alloc_align(gb_Allocator a, usize size, usize alignment) { return a.procedure(a.data, GB_ALLOCATION_TYPE_ALLOC, size, alignment, NULL, 0, 0); }
-gb_inline void *gb_alloc(gb_Allocator a, usize size) { return gb_alloc_align(a, size, GB_DEFAULT_ALIGNMENT); }
-gb_inline void gb_free(gb_Allocator a, void *ptr) { a.procedure(a.data, GB_ALLOCATION_TYPE_FREE, 0, 0, ptr, 0, 0); }
-gb_inline void gb_free_all(gb_Allocator a) { a.procedure(a.data, GB_ALLOCATION_TYPE_FREE_ALL, 0, 0, NULL, 0, 0); }
-gb_inline void *gb_resize(gb_Allocator a, void *ptr, usize new_size) { return a.procedure(a.data, GB_ALLOCATION_TYPE_RESIZE, new_size, 0, ptr, 0, 0); }
+gb_inline void
+gb_atomic64_store(gbAtomic64 volatile *a, i64 value)
+{
+#if defined(GB_ARCH_64_BIT)
+ a->value = value;
+#else
+ // NOTE(bill): The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b
+ __asm {
+ mov esi, a;
+ mov ebx, dword ptr value;
+ mov ecx, dword ptr value[4];
+ retry:
+ cmpxchg8b [esi];
+ jne retry;
+ }
+#endif
+}
-gb_inline void *gb_alloc_copy(gb_Allocator a, void* src, usize size) { return memcpy(gb_alloc(a, size), src, size); }
-gb_inline void *gb_alloc_align_copy(gb_Allocator a, void* src, usize size, usize alignment) { return memcpy(gb_alloc_align(a, size, alignment), src, size); }
+gb_inline i64
+gb_atomic64_compare_exchange_strong(gbAtomic64 volatile *a, i64 expected, i64 desired)
+{
+ return _InterlockedCompareExchange64(cast(i64 volatile *)a, desired, expected);
+}
-#define gb_alloc_struct(allocator, Type) (Type *)gb_alloc_align(allocator, sizeof(Type))
-#define gb_alloc_array(allocator, Type, count) (Type *)gb_alloc(allocator, sizeof(Type) * (count))
+gb_inline i64
+gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired)
+{
+#if defined(GB_ARCH_64_BIT)
+ return _InterlockedExchange64(cast(i64 volatile *)a, desired);
+#else
+ i64 expected = a->value;
+ for (;;) {
+ i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, desired, expected);
+ if (original == expected)
+ return original;
+ expected = original;
+ }
+#endif
+}
+gb_inline i64
+gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand)
+{
+#if defined(GB_ARCH_64_BIT)
+ return _InterlockedExchangeAdd64(cast(i64 volatile *)a, operand);
+#else
+ i64 expected = a->value;
+ for (;;) {
+ i64 original = _InterlockedExchange64(cast(i64 volatile *)a, expected + operand, expected);
+ if (original == expected)
+ return original;
+ expected = original;
+ }
+#endif
+}
+
+gb_inline i64
+gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand)
+{
+#if defined(GB_ARCH_64_BIT)
+ return _InterlockedAnd64(cast(i64 volatile *)a, operand);
+#else
+ i64 expected = a->value;
+ for (;;) {
+ i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, expected & operand, expected);
+ if (original == expected)
+ return original;
+ expected = original;
+ }
+#endif
+}
+
+gb_inline i64
+gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand)
+{
+#if defined(GB_ARCH_64_BIT)
+ return _InterlockedAnd64(cast(i64 volatile *)a, operand);
+#else
+ i64 expected = object->nonatomic;
+ for (;;) {
+ i64 original = _InterlockedCompareExchange64(cast(i64 volatile *)a, expected | operand, expected);
+ if (original == expected)
+ return original;
+ expected = original;
+ }
+#endif
+}
+
+#else
+#error Implement atomics for this platform
+#endif
-typedef struct gb_Arena
+
+
+gb_inline void gb_mutex_init(gbMutex *m) { m->win32_handle = CreateMutex(0, false, 0); }
+gb_inline void gb_mutex_destroy(gbMutex *m) { CloseHandle(m->win32_handle); }
+gb_inline void gb_mutex_lock(gbMutex *m) { WaitForSingleObject(m->win32_handle, INFINITE); }
+gb_inline b32 gb_mutex_try_lock(gbMutex *m) { return WaitForSingleObject(m->win32_handle, 0) == WAIT_OBJECT_0; }
+gb_inline void gb_mutex_unlock(gbMutex *m) { ReleaseMutex(m->win32_handle); }
+
+
+
+
+gb_inline void
+gb_semaphore_init(gbSemaphore *s)
{
- gb_Allocator backing;
- void *physical_start;
- usize total_size;
- usize total_allocated_count;
- usize prev_allocated_count;
- u32 temp_count;
-} gb_Arena;
+ s->win32_handle = CreateSemaphore(NULL, 0, I32_MAX, NULL);
+ GB_ASSERT_MSG(s->win32_handle != NULL, "CreateSemaphore: GetLastError = %d", GetLastError());
+}
+
+gb_inline void
+gb_semaphore_destroy(gbSemaphore *s)
+{
+ BOOL err = CloseHandle(s->win32_handle);
+ GB_ASSERT_MSG(err != 0, "CloseHandle: GetLastError = %d", GetLastError());
+}
-void gb_init_arena_from_memory(gb_Arena *arena, void *start, usize size);
-void gb_init_arena_from_allocator(gb_Arena *arena, gb_Allocator backing, usize size);
-void gb_free_arena(gb_Arena *arena);
+gb_inline void
+gb_semaphore_post(gbSemaphore *s, i32 count)
+{
+ BOOL err = ReleaseSemaphore(s->win32_handle, count, NULL);
+ GB_ASSERT_MSG(err != 0, "ReleaseSemaphore: GetLastError = %d", GetLastError());
+}
-gb_Allocator gb_make_arena_allocator(gb_Arena *arena);
-GB_ALLOCATOR_PROCEDURE(gb_arena_allocator_procedure);
+gb_inline void
+gb_semaphore_wait(gbSemaphore *s)
+{
+ DWORD result = WaitForSingleObject(s->win32_handle, INFINITE);
+ GB_ASSERT_MSG(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError = %d", GetLastError());
+}
+void
+gb_thread_init(gbThread *t)
+{
+ gb_zero_struct(t);
+ t->win32_handle = INVALID_HANDLE_VALUE;
+ gb_semaphore_init(&t->semaphore);
+}
-typedef struct gb_Temp_Arena_Memory
+void
+gb_thread_destory(gbThread *t)
{
- gb_Arena *arena;
- usize original_count;
-} gb_Temp_Arena_Memory;
+ if (t->is_running) gb_thread_join(t);
+ gb_semaphore_destroy(&t->semaphore);
+}
-gb_Temp_Arena_Memory gb_begin_temp_arena_memory(gb_Arena *arena);
-void gb_end_temp_arena_memory(gb_Temp_Arena_Memory tmp_mem);
+gb_internal void
+gb__thread_run(gbThread *t)
+{
+ gb_semaphore_post(&t->semaphore, 1);
+ t->proc(t->data);
+}
+#if defined(GB_SYSTEM_WINDOWS)
+ gb_internal DWORD WINAPI gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return 0; }
+#else
+ gb_internal void *gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return NULL; }
+#endif
-typedef struct gb_Pool
+gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data) { gb_thread_start_with_stack(t, proc, data, 0); }
+
+gb_inline void
+gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size)
{
- gb_Allocator backing;
+ GB_ASSERT(!t->is_running);
+ GB_ASSERT(proc != NULL);
+ t->proc = proc;
+ t->data = data;
+ t->stack_size = stack_size;
- void *physical_start;
- void *free_list;
+ t->win32_handle = CreateThread(NULL, stack_size, gb__thread_proc, t, 0, NULL);
+ GB_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError = %d", GetLastError());
+
+ t->is_running = true;
+ gb_semaphore_wait(&t->semaphore);
+}
+
+gb_inline void
+gb_thread_join(gbThread *t)
+{
+ if (!t->is_running) return;
+
+ WaitForSingleObject(t->win32_handle, INFINITE);
+ CloseHandle(t->win32_handle);
+ t->win32_handle = INVALID_HANDLE_VALUE;
+ t->is_running = false;
+}
+
+gb_inline b32 gb_thread_is_running(gbThread const *t) { return t->is_running != 0; }
+
+gb_inline u32
+gb_thread_current_id(void)
+{
+ u32 thread_id;
+#if defined(GB_SYSTEM_WINDOWS)
+ thread_id = GetCurrentThreadId();
+#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
+ asm("mov %%gs:0x00,%0" : "=r"(thread_id));
+#elif defined(GB_ARCH_32_BIT)
+ asm("mov %%gs:0x08,%0" : "=r"(thread_id));
+#elif defined(GB_ARCH_64_BIT)
+ asm("mov %%gs:0x10,%0" : "=r"(thread_id));
+#else
+ #error Unsupported architecture for thread::current_id()
+#endif
+
+ return thread_id;
+}
+
+
+
+
+
+
+gb_inline gbAllocator
+gb_heap_allocator(void)
+{
+ gbAllocator a;
+ a.proc = gb_heap_allocator_proc;
+ a.data = NULL;
+ return a;
+}
+
+
+GB_ALLOCATOR_PROC(gb_heap_allocator_proc)
+{
+ switch (type) {
+ case GB_ALLOCATION_ALLOC: {
+ void *ptr;
+ isize actual_size = size + alignment;
+ ptr = gb_align_forward(gb_malloc(actual_size), alignment);
+
+ return ptr;
+ } break;
+
+ case GB_ALLOCATION_FREE: {
+ gb_mfree(old_memory);
+ } break;
+
+ case GB_ALLOCATION_FREE_ALL:
+ break;
- usize block_size;
- usize block_align;
- usize total_size;
-} gb_Pool;
+ case GB_ALLOCATION_RESIZE: {
+ // TODO(bill): Check if ptr is on top of stack and just extend
+ gbAllocator a = gb_heap_allocator();
+ if (!old_memory) return gb_alloc_align(a, size, alignment);
+
+ if (size < old_size)
+ size = old_size;
+
+ if (old_size == size) {
+ return old_memory;
+ } else {
+ void *new_memory = gb_alloc_align(a, size, alignment);
+ if (!new_memory) return NULL;
+ gb_memmove(new_memory, old_memory, gb_min(size, old_size));
+ gb_free(a, old_memory);
+ return new_memory;
+ }
+ } break;
+ }
+
+ return NULL; // NOTE(bill): Default return value
+}
-void gb_init_pool(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size);
-void gb_init_pool_align(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size, usize block_align);
-void gb_free_pool(gb_Pool *pool);
-gb_Allocator gb_make_pool_allocator(gb_Pool *pool);
-GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure);
-#if defined(GB_IMPLEMENTATION)
gb_inline void
-gb_init_arena_from_memory(gb_Arena *arena, void *start, usize size)
+gb_arena_init_from_memory(gbArena *arena, void *start, isize size)
{
- arena->backing.procedure = NULL;
+ arena->backing.proc = NULL;
arena->backing.data = NULL;
arena->physical_start = start;
arena->total_size = size;
- arena->total_allocated_count = 0;
+ arena->total_allocated = 0;
arena->temp_count = 0;
}
gb_inline void
-gb_init_arena_from_allocator(gb_Arena *arena, gb_Allocator backing, usize size)
+gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size)
{
arena->backing = backing;
- arena->physical_start = gb_alloc(backing, size);
+ arena->physical_start = gb_alloc(backing, size); // NOTE(bill): Uses default alignment
arena->total_size = size;
- arena->total_allocated_count = 0;
+ arena->total_allocated = 0;
arena->temp_count = 0;
}
+gb_inline void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size) { gb_arena_init_from_allocator(arena, gb_arena_allocator(parent_arena), size); }
+
+
gb_inline void
-gb_free_arena(gb_Arena *arena)
+gb_arena_free(gbArena *arena)
{
- if (arena->backing.procedure) {
+ if (arena->backing.proc) {
gb_free(arena->backing, arena->physical_start);
arena->physical_start = NULL;
}
}
+gb_inline isize
+gb_arena_alignment_of(gbArena *arena, isize alignment)
+{
+ isize alignment_offset, result_pointer, mask;
+ GB_ASSERT(gb_is_power_of_two(alignment));
+
+ alignment_offset = 0;
+ result_pointer = cast(isize)arena->physical_start + arena->total_allocated;
+ mask = alignment - 1;
+ if (result_pointer & mask)
+ alignment_offset = alignment - (result_pointer & mask);
+ return alignment_offset;
+}
-gb_inline gb_Allocator
-gb_make_arena_allocator(gb_Arena *arena)
+gb_inline isize
+gb_arena_size_remaining(gbArena *arena, isize alignment)
{
- gb_Allocator allocator;
- allocator.procedure = gb_arena_allocator_procedure;
+ isize result = arena->total_size - (arena->total_allocated + gb_arena_alignment_of(arena, alignment));
+ return result;
+}
+
+gb_inline void gb_arena_check(gbArena *arena) { GB_ASSERT(arena->temp_count == 0); }
+
+
+
+
+
+
+gb_inline gbAllocator
+gb_arena_allocator(gbArena *arena)
+{
+ gbAllocator allocator;
+ allocator.proc = gb_arena_allocator_proc;
allocator.data = arena;
return allocator;
}
-GB_ALLOCATOR_PROCEDURE(gb_arena_allocator_procedure)
+GB_ALLOCATOR_PROC(gb_arena_allocator_proc)
{
- gb_Arena *arena = cast(gb_Arena *)allocator_data;
+ gbArena *arena = cast(gbArena *)allocator_data;
- GB_UNUSED(options);
- GB_UNUSED(old_size);
+ gb_unused(options);
+ gb_unused(old_size);
switch (type) {
- case GB_ALLOCATION_TYPE_ALLOC: {
+ case GB_ALLOCATION_ALLOC: {
void *ptr;
- usize actual_size = size + alignment;
+ isize actual_size = size + alignment;
// NOTE(bill): Out of memory
- if (arena->total_allocated_count + actual_size > cast(usize)arena->total_size)
+ if (arena->total_allocated + actual_size > cast(isize)arena->total_size)
return NULL;
- ptr = gb_align_forward(cast(u8 *)arena->physical_start + arena->total_allocated_count, alignment);
- arena->prev_allocated_count = arena->total_allocated_count;
- arena->total_allocated_count += actual_size;
+ ptr = gb_align_forward(gb_pointer_add(arena->physical_start, arena->total_allocated), alignment);
+ arena->total_allocated += actual_size;
return ptr;
} break;
- case GB_ALLOCATION_TYPE_FREE: {
+ case GB_ALLOCATION_FREE:
// NOTE(bill): Free all at once
// NOTE(bill): Use Temp_Arena_Memory if you want to free a block
- } break;
+ // TODO(bill): Free it if it's on top of the stack
+ break;
- case GB_ALLOCATION_TYPE_FREE_ALL:
- arena->total_allocated_count = 0;
+ case GB_ALLOCATION_FREE_ALL:
+ arena->total_allocated = 0;
break;
- case GB_ALLOCATION_TYPE_RESIZE: {
- // TODO(bill): Check if ptr is at the top
- void *ptr = gb_alloc_align(gb_make_arena_allocator(arena), size, alignment);
- memcpy(ptr, old_memory, size);
- return ptr;
+ case GB_ALLOCATION_RESIZE: {
+ // TODO(bill): Check if ptr is on top of stack and just extend
+ gbAllocator a = gb_arena_allocator(arena);
+ if (!old_memory) return gb_alloc_align(a, size, alignment);
+
+ if (size < old_size)
+ size = old_size;
+
+ if (old_size == size) {
+ return old_memory;
+ } else {
+ void *new_memory = gb_alloc_align(a, size, alignment);
+ if (!new_memory) return NULL;
+ gb_memmove(new_memory, old_memory, gb_min(size, old_size));
+ gb_free(a, old_memory);
+ return new_memory;
+ }
} break;
}
@@ -440,90 +2028,94 @@ GB_ALLOCATOR_PROCEDURE(gb_arena_allocator_procedure)
}
-gb_inline gb_Temp_Arena_Memory
-gb_begin_temp_arena_memory(gb_Arena *arena)
+gb_inline gbTempArenaMemory
+gb_temp_arena_memory_begin(gbArena *arena)
{
- gb_Temp_Arena_Memory tmp;
+ gbTempArenaMemory tmp;
tmp.arena = arena;
- tmp.original_count = arena->total_allocated_count;
+ tmp.original_count = arena->total_allocated;
arena->temp_count++;
return tmp;
}
gb_inline void
-gb_end_temp_arena_memory(gb_Temp_Arena_Memory tmp)
+gb_temp_arena_memory_end(gbTempArenaMemory tmp)
{
- GB_ASSERT(tmp.arena->total_allocated_count >= tmp.original_count);
+ GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count);
GB_ASSERT(tmp.arena->temp_count > 0);
- tmp.arena->total_allocated_count = tmp.original_count;
+ tmp.arena->total_allocated = tmp.original_count;
tmp.arena->temp_count--;
}
-void
-gb_init_pool(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size)
+gb_inline void
+gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size)
{
- gb_init_pool_align(pool, backing, num_blocks, block_size, GB_DEFAULT_ALIGNMENT);
+ gb_pool_init_align(pool, backing, num_blocks, block_size, GB_DEFAULT_MEMORY_ALIGNMENT);
}
void
-gb_init_pool_align(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size, usize block_align)
+gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align)
{
- memset(pool, 0, sizeof(gb_Pool));
+ isize actual_block_size, pool_size, block_index;
+ void *data, *curr;
+ uintptr *end;
+
+ gb_zero_struct(pool);
pool->backing = backing;
pool->block_size = block_size;
pool->block_align = block_align;
- usize actual_block_size = block_size + block_align;
- usize pool_size = num_blocks * actual_block_size;
+ actual_block_size = block_size + block_align;
+ pool_size = num_blocks * actual_block_size;
- u8 *data = cast(u8 *)gb_alloc_align(backing, pool_size, block_align);
+ data = gb_alloc_align(backing, pool_size, block_align);
- // Init intrusive freelist
- u8 *curr = data;
- for (usize block_index = 0; block_index < num_blocks-1; block_index++) {
+ // NOTE(bill): Init intrusive freelist
+ curr = data;
+ for (block_index = 0; block_index < num_blocks-1; block_index++) {
uintptr *next = cast(uintptr *)curr;
*next = cast(uintptr)curr + actual_block_size;
- curr += actual_block_size;
+ curr = gb_pointer_add(curr, actual_block_size);
}
- uintptr *end = cast(uintptr*)curr;
+ end = cast(uintptr *)curr;
*end = cast(uintptr)NULL;
pool->physical_start = data;
pool->free_list = data;
}
-void
-gb_free_pool(gb_Pool *pool)
+gb_inline void
+gb_pool_free(gbPool *pool)
{
- if (pool->backing.procedure) {
+ if (pool->backing.proc) {
gb_free(pool->backing, pool->physical_start);
}
}
-gb_Allocator
-gb_make_pool_allocator(gb_Pool *pool)
+gb_inline gbAllocator
+gb_pool_allocator(gbPool *pool)
{
- gb_Allocator allocator;
- allocator.procedure = gb_pool_allocator_procedure;
+ gbAllocator allocator;
+ allocator.proc = gb_pool_allocator_proc;
allocator.data = pool;
return allocator;
}
-GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure)
+GB_ALLOCATOR_PROC(gb_pool_allocator_proc)
{
- gb_Pool *pool = cast(gb_Pool *)allocator_data;
+ gbPool *pool = cast(gbPool *)allocator_data;
- GB_UNUSED(options);
- GB_UNUSED(old_size);
+ gb_unused(options);
+ gb_unused(old_size);
switch (type) {
- case GB_ALLOCATION_TYPE_ALLOC: {
+ case GB_ALLOCATION_ALLOC: {
uintptr next_free;
void *ptr;
GB_ASSERT(size == pool->block_size);
@@ -537,7 +2129,7 @@ GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure)
return ptr;
} break;
- case GB_ALLOCATION_TYPE_FREE: {
+ case GB_ALLOCATION_FREE: {
uintptr *next;
if (old_memory == NULL) return NULL;
@@ -547,13 +2139,13 @@ GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure)
pool->total_size -= pool->block_size;
} break;
- case GB_ALLOCATION_TYPE_FREE_ALL: {
+ case GB_ALLOCATION_FREE_ALL:
// TODO(bill):
- } break;
+ break;
- case GB_ALLOCATION_TYPE_RESIZE: {
+ case GB_ALLOCATION_RESIZE:
// NOTE(bill): Cannot resize
- } break;
+ break;
}
return NULL;
@@ -565,89 +2157,212 @@ GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure)
+gb_inline char
+gb_char_to_lower(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return 'a' + (c - 'A');
+ return c;
+}
+gb_inline char
+gb_char_to_upper(char c)
+{
+ if (c >= 'a' && c <= 'z')
+ return 'A' + (c - 'a');
+ return c;
+}
+gb_inline b32
+gb_char_is_space(char c)
+{
+ if (c == ' ' ||
+ c == '\t' ||
+ c == '\n' ||
+ c == '\r' ||
+ c == '\f' ||
+ c == '\v')
+ return true;
+ return false;
+}
+gb_inline b32
+gb_char_is_digit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return true;
+ return false;
+}
-#endif // GB_IMPLEMENTATION
+gb_inline b32
+gb_char_is_hex_digit(char c)
+{
+ if (gb_char_is_digit(c) ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'))
+ return true;
+ return false;
+}
+gb_inline b32
+gb_char_is_alpha(char c)
+{
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z'))
+ return true;
+ return false;
+}
-////////////////////////////////
-// //
-// gb_String - C Compatible //
-// //
-////////////////////////////////
+gb_inline b32
+gb_char_is_alphanumeric(char c)
+{
+ return gb_char_is_alpha(c) || gb_char_is_digit(c);
+}
-// Pascal like strings in C
-typedef char *gb_String;
-#ifndef GB_STRING_SIZE
-#define GB_STRING_SIZE
-typedef u32 gb_String_Size;
-#endif
+gb_inline void
+gb_to_lower(char *str)
+{
+ if (!str) return;
+ while (*str) {
+ *str = gb_char_to_lower(*str);
+ str++;
+ }
+}
-// This is stored at the beginning of the string
-// NOTE(bill): It is (2*sizeof(gb_String_Size) + 2*sizeof(void*)) (default: 16B (32bit), 24B (64bit))
-// NOTE(bill): If you only need a small string, just use a standard c string
-typedef struct gb_String_Header
+gb_inline void
+gb_to_upper(char *str)
{
- gb_Allocator allocator;
- gb_String_Size length;
- gb_String_Size capacity;
-} gb_String_Header;
+ if (!str) return;
+ while (*str) {
+ *str = gb_char_to_upper(*str);
+ str++;
+ }
+}
-#define GB_STRING_HEADER(str) (cast(gb_String_Header *)str - 1)
-gb_String gb_string_make(gb_Allocator a, char const *str);
-gb_String gb_string_make_length(gb_Allocator a, void const *str, gb_String_Size num_bytes);
-void gb_string_free(gb_String str);
+gb_inline isize
+gb_strlen(char const *str)
+{
+ isize result = 0;
+ if (str) {
+ char const *end = str;
+ while (*end) end++;
+ result = end - str;
+ }
+ return result;
+}
-gb_String gb_string_duplicate(gb_Allocator a, gb_String const str);
+gb_inline i32
+gb_strcmp(char const *s1, char const *s2)
+{
+ while (*s1 && (*s1 == *s2)) {
+ s1++, s2++;
+ }
+ return *(u8 *)s1 - *(u8 *)s2;
+}
-gb_String_Size gb_string_length(gb_String const str);
-gb_String_Size gb_string_capacity(gb_String const str);
-gb_String_Size gb_string_available_space(gb_String const str);
-void gb_string_clear(gb_String str);
+gb_inline char *
+gb_strncpy(char *dest, char const *source, isize len)
+{
+ GB_ASSERT_NOT_NULL(dest);
+ if (source) {
+ char *str = dest;
+ while (len > 0 && *source) {
+ *str++ = *source++;
+ len--;
+ }
+ while (len > 0) {
+ *str++ = '\0';
+ len--;
+ }
+ }
+ return dest;
+}
-gb_String gb_string_append_string(gb_String str, gb_String const other);
-gb_String gb_string_append_string_length(gb_String str, void const *other, gb_String_Size num_bytes);
-gb_String gb_string_append_cstring(gb_String str, char const *other);
+gb_inline i32
+gb_strncmp(char const *s1, char const *s2, isize len)
+{
+ for(; len > 0; s1++, s2++, len--) {
+ if (*s1 != *s2)
+ return ((cast(uintptr)s1 < cast(uintptr)s2) ? -1 : +1);
+ else if (*s1 == '\0')
+ return 0;
+ }
+ return 0;
+}
-gb_String gb_string_set(gb_String str, char const *cstr);
-gb_String gb_string_make_space_for(gb_String str, gb_String_Size add_len);
-gb_String_Size gb_string_allocation_size(gb_String const str);
+gb_inline char const *
+gb_char_first_occurence(char const *s, char c)
+{
+ char ch = c;
+ for (; *s != ch; s++) {
+ if (*s == '\0')
+ return 0;
+ }
+ return s;
+}
+
+
+gb_inline char const *
+gb_char_last_occurence(char const *s, char c)
+{
+ char const *result = NULL;
+ do {
+ if (*s == c)
+ result = s;
+ } while (*s++);
+
+ return result;
+}
+
+
+
+gb_inline void
+gb_cstr_concat(char *dest, isize dest_len,
+ char const *src_a, isize src_a_len,
+ char const *src_b, isize src_b_len)
+{
+ GB_ASSERT(dest_len >= src_a_len+src_b_len+1);
+ if (dest) {
+ gb_memcopy(dest, src_a, src_a_len);
+ gb_memcopy(dest+src_a_len, src_b, src_b_len);
+ dest[src_a_len+src_b_len] = '\0';
+ }
+}
+
-b32 gb_strings_are_equal(gb_String const lhs, gb_String const rhs);
-gb_String gb_string_trim(gb_String str, char const *cut_set);
-gb_String gb_string_trim_space(gb_String str); /* Whitespace ` \t\r\n\v\f` */
-#if defined(GB_IMPLEMENTATION)
-gb_inline void gb__string_set_length(gb_String str, gb_String_Size len) { GB_STRING_HEADER(str)->length = len; }
-gb_inline void gb__string_set_capacity(gb_String str, gb_String_Size cap) { GB_STRING_HEADER(str)->capacity = cap; }
-gb_inline gb_String
-gb_string_make(gb_Allocator a, char const *str)
+
+
+gb_inline void gb__string_set_length(gbString str, isize len) { GB_STRING_HEADER(str)->length = len; }
+gb_inline void gb__string_set_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
+
+
+gb_inline gbString
+gb_string_make(gbAllocator a, char const *str)
{
- gb_String_Size len = cast(gb_String_Size)(str ? strlen(str) : 0);
+ isize len = str ? gb_strlen(str) : 0;
return gb_string_make_length(a, str, len);
}
-gb_String
-gb_string_make_length(gb_Allocator a, void const *init_str, gb_String_Size num_bytes)
+gbString
+gb_string_make_length(gbAllocator a, void const *init_str, isize num_bytes)
{
- gb_String_Size header_size = sizeof(gb_String_Header);
+ isize header_size = gb_size_of(gbStringHeader);
void *ptr = gb_alloc(a, header_size + num_bytes + 1);
- gb_String str;
- gb_String_Header *header;
+ gbString str;
+ gbStringHeader *header;
if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1);
if (ptr == NULL) return NULL;
@@ -658,76 +2373,75 @@ gb_string_make_length(gb_Allocator a, void const *init_str, gb_String_Size num_b
header->length = num_bytes;
header->capacity = num_bytes;
if (num_bytes && init_str)
- memcpy(str, init_str, num_bytes);
+ gb_memcopy(str, init_str, num_bytes);
str[num_bytes] = '\0';
return str;
}
gb_inline void
-gb_string_free(gb_String str)
+gb_string_free(gbString str)
{
if (str) {
- gb_String_Header *header;
- header = GB_STRING_HEADER(str);
+ gbStringHeader *header = GB_STRING_HEADER(str);
gb_free(header->allocator, header);
}
}
-gb_inline gb_String gb_string_duplicate(gb_Allocator a, gb_String const str) { return gb_string_make_length(a, str, gb_string_length(str)); }
+gb_inline gbString gb_string_duplicate(gbAllocator a, gbString const str) { return gb_string_make_length(a, str, gb_string_length(str)); }
-gb_inline gb_String_Size gb_string_length(gb_String const str) { return GB_STRING_HEADER(str)->length; }
-gb_inline gb_String_Size gb_string_capacity(gb_String const str) { return GB_STRING_HEADER(str)->capacity; }
+gb_inline isize gb_string_length(gbString const str) { return GB_STRING_HEADER(str)->length; }
+gb_inline isize gb_string_capacity(gbString const str) { return GB_STRING_HEADER(str)->capacity; }
-gb_inline gb_String_Size
-gb_string_available_space(gb_String const str)
+gb_inline isize
+gb_string_available_space(gbString const str)
{
- gb_String_Header *h = GB_STRING_HEADER(str);
+ gbStringHeader *h = GB_STRING_HEADER(str);
if (h->capacity > h->length)
return h->capacity - h->length;
return 0;
}
-gb_inline void gb_string_clear(gb_String str) { gb__string_set_length(str, 0); str[0] = '\0'; }
+gb_inline void gb_string_clear(gbString str) { gb__string_set_length(str, 0); str[0] = '\0'; }
-gb_inline gb_String gb_string_append_string(gb_String str, gb_String const other) { return gb_string_append_string_length(str, other, gb_string_length(other)); }
+gb_inline gbString gb_string_append_string(gbString str, gbString const other) { return gb_string_append_string_length(str, other, gb_string_length(other)); }
-gb_String
-gb_string_append_string_length(gb_String str, void const *other, gb_String_Size other_len)
+gbString
+gb_string_append_string_length(gbString str, void const *other, isize other_len)
{
- gb_String_Size curr_len = gb_string_length(str);
+ isize curr_len = gb_string_length(str);
str = gb_string_make_space_for(str, other_len);
if (str == NULL)
return NULL;
- memcpy(str + curr_len, other, other_len);
+ gb_memcopy(str + curr_len, other, other_len);
str[curr_len + other_len] = '\0';
gb__string_set_length(str, curr_len + other_len);
return str;
}
-gb_inline gb_String
-gb_string_append_cstring(gb_String str, char const *other)
+gb_inline gbString
+gb_string_append_cstring(gbString str, char const *other)
{
- return gb_string_append_string_length(str, other, cast(gb_String_Size)strlen(other));
+ return gb_string_append_string_length(str, other, cast(isize)strlen(other));
}
-gb_String
-gb_string_set(gb_String str, char const *cstr)
+gbString
+gb_string_set(gbString str, char const *cstr)
{
- gb_String_Size len = cast(gb_String_Size)strlen(cstr);
+ isize len = gb_strlen(cstr);
if (gb_string_capacity(str) < len) {
str = gb_string_make_space_for(str, len - gb_string_length(str));
if (str == NULL)
return NULL;
}
- memcpy(str, cstr, len);
+ gb_memcopy(str, cstr, len);
str[len] = '\0';
gb__string_set_length(str, len);
@@ -735,44 +2449,22 @@ gb_string_set(gb_String str, char const *cstr)
}
-local_persist void *
-gb__string_realloc(gb_Allocator a, void *ptr, gb_String_Size old_size, gb_String_Size new_size)
-{
- if (!ptr) return gb_alloc(a, new_size);
-
- if (new_size < old_size)
- new_size = old_size;
-
- if (old_size == new_size) {
- return ptr;
- } else {
- void *new_ptr = gb_alloc(a, new_size);
- if (!new_ptr)
- return NULL;
-
- memcpy(new_ptr, ptr, old_size);
- gb_free(a, ptr);
- return new_ptr;
- }
-}
-
-
-gb_String
-gb_string_make_space_for(gb_String str, gb_String_Size add_len)
+gbString
+gb_string_make_space_for(gbString str, isize add_len)
{
- gb_String_Size available = gb_string_available_space(str);
+ isize available = gb_string_available_space(str);
// Return if there is enough space left
if (available >= add_len) {
return str;
} else {
- gb_String_Size new_len = gb_string_length(str) + add_len;
+ isize new_len = gb_string_length(str) + add_len;
void *ptr = GB_STRING_HEADER(str);
- gb_String_Size old_size = sizeof(struct gb_String_Header) + gb_string_length(str) + 1;
- gb_String_Size new_size = sizeof(struct gb_String_Header) + new_len + 1;
+ isize old_size = gb_size_of(gbStringHeader) + gb_string_length(str) + 1;
+ isize new_size = gb_size_of(gbStringHeader) + new_len + 1;
- void *new_ptr = gb__string_realloc(GB_STRING_HEADER(str)->allocator, ptr, old_size, new_size);
+ void *new_ptr = gb_resize(GB_STRING_HEADER(str)->allocator, ptr, old_size, new_size);
if (new_ptr == NULL) return NULL;
str = cast(char *)(GB_STRING_HEADER(new_ptr) + 1);
@@ -782,18 +2474,18 @@ gb_string_make_space_for(gb_String str, gb_String_Size add_len)
}
}
-gb_inline gb_String_Size
-gb_string_allocation_size(gb_String const str)
+gb_inline isize
+gb_string_allocation_size(gbString const str)
{
- gb_String_Size cap = gb_string_capacity(str);
- return sizeof(gb_String_Header) + cap;
+ isize cap = gb_string_capacity(str);
+ return gb_size_of(gbStringHeader) + cap;
}
gb_inline b32
-gb_strings_are_equal(gb_String const lhs, gb_String const rhs)
+gb_strings_are_equal(gbString const lhs, gbString const rhs)
{
- gb_String_Size lhs_len, rhs_len, i;
+ isize lhs_len, rhs_len, i;
lhs_len = gb_string_length(lhs);
rhs_len = gb_string_length(rhs);
if (lhs_len != rhs_len)
@@ -808,24 +2500,24 @@ gb_strings_are_equal(gb_String const lhs, gb_String const rhs)
}
-gb_String
-gb_string_trim(gb_String str, char const *cut_set)
+gbString
+gb_string_trim(gbString str, char const *cut_set)
{
char *start, *end, *start_pos, *end_pos;
- gb_String_Size len;
+ isize len;
start_pos = start = str;
end_pos = end = str + gb_string_length(str) - 1;
- while (start_pos <= end && strchr(cut_set, *start_pos))
+ while (start_pos <= end && gb_char_first_occurence(cut_set, *start_pos))
start_pos++;
- while (end_pos > start_pos && strchr(cut_set, *end_pos))
+ while (end_pos > start_pos && gb_char_first_occurence(cut_set, *end_pos))
end_pos--;
- len = cast(gb_String_Size)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
+ len = cast(isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
if (str != start_pos)
- memmove(str, start_pos, len);
+ gb_memmove(str, start_pos, len);
str[len] = '\0';
gb__string_set_length(str, len);
@@ -833,23 +2525,512 @@ gb_string_trim(gb_String str, char const *cut_set)
return str;
}
-gb_inline gb_String gb_string_trim_space(gb_String str) { return gb_string_trim(str, " \t\r\n\v\f"); }
+gb_inline gbString gb_string_trim_space(gbString str) { return gb_string_trim(str, " \t\r\n\v\f"); }
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Windows UTF-8 Handling
+//
+//
+
+
+char16 *
+gb_utf8_to_utf16(char16 *buffer, char *s, isize len)
+{
+ u8 *str = cast(u8 *)s;
+ char32 c;
+ isize i = 0;
+ len--;
+ while (*str) {
+ if (i >= len)
+ return NULL;
+ if (!(*str & 0x80)) {
+ buffer[i++] = *str++;
+ } else if ((*str & 0xe0) == 0xc0) {
+ if (*str < 0xc2)
+ return NULL;
+ c = (*str++ & 0x1f) << 6;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ buffer[i++] = c + (*str++ & 0x3f);
+ } else if ((*str & 0xf0) == 0xe0) {
+ if (*str == 0xe0 &&
+ (str[1] < 0xa0 || str[1] > 0xbf))
+ return NULL;
+ if (*str == 0xed && str[1] > 0x9f) // str[1] < 0x80 is checked below
+ return NULL;
+ c = (*str++ & 0x0f) << 12;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ c += (*str++ & 0x3f) << 6;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ buffer[i++] = c + (*str++ & 0x3f);
+ } else if ((*str & 0xf8) == 0xf0) {
+ if (*str > 0xf4)
+ return NULL;
+ if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf))
+ return NULL;
+ if (*str == 0xf4 && str[1] > 0x8f) // str[1] < 0x80 is checked below
+ return NULL;
+ c = (*str++ & 0x07) << 18;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ c += (*str++ & 0x3f) << 12;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ c += (*str++ & 0x3f) << 6;
+ if ((*str & 0xc0) != 0x80)
+ return NULL;
+ c += (*str++ & 0x3f);
+ // UTF-8 encodings of values used in surrogate pairs are invalid
+ if ((c & 0xfffff800) == 0xd800)
+ return NULL;
+ if (c >= 0x10000) {
+ c -= 0x10000;
+ if (i+2 > len)
+ return NULL;
+ buffer[i++] = 0xd800 | (0x3ff & (c>>10));
+ buffer[i++] = 0xdc00 | (0x3ff & (c ));
+ }
+ } else {
+ return NULL;
+ }
+ }
+ buffer[i] = 0;
+ return buffer;
+}
+
+char *
+gb_utf16_to_utf8(char *buffer, char16 *str, isize len)
+{
+ isize i = 0;
+ len--;
+ while (*str) {
+ if (*str < 0x80) {
+ if (i+1 > len)
+ return NULL;
+ buffer[i++] = (char) *str++;
+ } else if (*str < 0x800) {
+ if (i+2 > len)
+ return NULL;
+ buffer[i++] = 0xc0 + (*str >> 6);
+ buffer[i++] = 0x80 + (*str & 0x3f);
+ str += 1;
+ } else if (*str >= 0xd800 && *str < 0xdc00) {
+ char32 c;
+ if (i+4 > len)
+ return NULL;
+ c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000;
+ buffer[i++] = 0xf0 + (c >> 18);
+ buffer[i++] = 0x80 + ((c >> 12) & 0x3f);
+ buffer[i++] = 0x80 + ((c >> 6) & 0x3f);
+ buffer[i++] = 0x80 + ((c ) & 0x3f);
+ str += 2;
+ } else if (*str >= 0xdc00 && *str < 0xe000) {
+ return NULL;
+ } else {
+ if (i+3 > len)
+ return NULL;
+ buffer[i++] = 0xe0 + (*str >> 12);
+ buffer[i++] = 0x80 + ((*str >> 6) & 0x3f);
+ buffer[i++] = 0x80 + ((*str ) & 0x3f);
+ str += 1;
+ }
+ }
+ buffer[i] = 0;
+ return buffer;
+}
+
+
+
+
+gb_no_inline void
+gb__array_set_capacity(void *array_, isize capacity, isize element_size)
+{
+ // NOTE(bill): I know this is unsafe so don't call this function directly
+ gbVoidArray *a = cast(gbVoidArray *)array_;
+ void *data = NULL;
+
+ GB_ASSERT(element_size > 0);
+
+ if (capacity == a->capacity)
+ return;
+
+ if (capacity < a->count) {
+ if (a->capacity < capacity) {
+ isize new_capacity = GB_ARRAY_GROW_FORMULA(a->capacity);
+ if (new_capacity < capacity)
+ new_capacity = capacity;
+ gb__array_set_capacity(a, new_capacity, element_size);
+ }
+ a->count = capacity;
+ }
+
+ if (capacity > 0) {
+ data = gb_alloc(a->allocator, element_size*capacity);
+ gb_memcopy(data, a->data, element_size*a->count);
+ }
+ gb_free(a->allocator, a->data);
+ a->data = data;
+ a->capacity = capacity;
+}
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// File Handling
+//
+//
+
+b32
+gb_file_create(gbFile *file, char const *filepath, ...)
+{
+ va_list va;
+ char *path;
+ gb_zero_struct(file);
+
+ va_start(va, filepath);
+ path = gb_sprintf_va(filepath, va);
+ va_end(va);
+
+ file->handle = fopen(path, "wb");
+ if (file->handle) {
+ file->path = gb_alloc_cstring(gb_heap_allocator(), path);
+ file->size = gb_file_size(file);
+ file->is_open = true;
+ file->type = GB_FILE_TYPE_WRITE;
+ file->last_write_time = gb_file_last_write_time(file->path);
+ return true;
+ }
+ return false;
+}
+
+
+
+b32
+gb_file_open(gbFile *file, char const *filepath, ...)
+{
+ va_list va;
+ char *path;
+ gb_zero_struct(file);
+
+ va_start(va, filepath);
+ path = gb_sprintf_va(filepath, va);
+ va_end(va);
+
+ file->handle = fopen(path, "rb");
+ if (file->handle) {
+ file->path = gb_alloc_cstring(gb_heap_allocator(), path);
+ file->size = gb_file_size(file);
+ file->is_open = true;
+ file->type = GB_FILE_TYPE_READ;
+ file->last_write_time = gb_file_last_write_time(file->path);
+ return true;
+ }
+ return false;
+}
+
+gb_inline b32
+gb_file_close(gbFile *file)
+{
+ b32 result = true;
+ if (file && file->handle)
+ result = fclose(cast(FILE *)file->handle) != 0; // TODO(bill): Handle fclose errors
+
+ if (file->path) gb_free(gb_heap_allocator(), file->path);
+ file->is_open = false;
+
+ return result;
+}
+
+gb_inline b32
+gb_file_read_at(gbFile *file, void *buffer, isize size, i64 offset)
+{
+ i64 prev_cursor_pos;
+
+ GB_ASSERT(file->type == GB_FILE_TYPE_READ);
+
+ prev_cursor_pos = ftell(cast(FILE *)file->handle);
+ fseek(cast(FILE *)file->handle, offset, SEEK_SET);
+ fread(buffer, 1, size, cast(FILE *)file->handle);
+ fseek(cast(FILE *)file->handle, prev_cursor_pos, SEEK_SET);
+ return true;
+}
+
+gb_inline b32
+gb_file_write_at(gbFile *file, void const *buffer, isize size, i64 offset)
+{
+ isize written_size;
+ i64 prev_cursor_pos;
+
+ GB_ASSERT(file->type == GB_FILE_TYPE_WRITE);
+
+ prev_cursor_pos = ftell(cast(FILE *)file->handle);
+ fseek(cast(FILE *)file->handle, offset, SEEK_SET);
+
+ written_size = fwrite(buffer, 1, size, cast(FILE *)file->handle);
+ fseek(cast(FILE *)file->handle, prev_cursor_pos, SEEK_SET);
+ if (written_size != size) {
+ GB_PANIC("Failed to write file data");
+ return false;
+ }
+
+ return true;
+}
+
+gb_inline i64
+gb_file_size(gbFile *file)
+{
+ i64 result_size;
+
+ fseek(cast(FILE *)file->handle, 0, SEEK_END);
+ result_size = cast(i64)ftell(cast(FILE *)file->handle);
+ fseek(cast(FILE *)file->handle, 0, SEEK_SET);
+ return result_size;
+}
+
+b32
+gb_file_has_changed(gbFile *file)
+{
+ b32 result = false;
+ gbFileTime last_write_time = gb_file_last_write_time(file->path);
+ if (file->last_write_time != last_write_time) {
+ result = true;
+ file->last_write_time = last_write_time;
+ }
+ return result;
+}
+
+
+
+#if defined(GB_SYSTEM_WINDOWS)
+gbFileTime
+gb_file_last_write_time(char const *filepath, ...)
+{
+ ULARGE_INTEGER li = {0};
+ FILETIME last_write_time = {0};
+ WIN32_FILE_ATTRIBUTE_DATA data = {0};
+
+ va_list va;
+ va_start(va, filepath);
+ if (GetFileAttributesEx(gb_sprintf_va(filepath, va), GetFileExInfoStandard, &data))
+ last_write_time = data.ftLastWriteTime;
+ va_end(va);
+
+ li.LowPart = last_write_time.dwLowDateTime;
+ li.HighPart = last_write_time.dwHighDateTime;
+ return cast(gbFileTime)li.QuadPart;
+}
+
+gb_inline b32
+gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists)
+{
+ return CopyFile(existing_filename, new_filename, fail_if_exists);
+}
+
+gb_inline b32
+gb_file_move(char const *existing_filename, char const *new_filename)
+{
+ return MoveFile(existing_filename, new_filename);
+}
+
+
+
+#else
+#error
#endif
-////////////////////////////////
-// //
-// Unfinished code //
-// //
-////////////////////////////////
+gbFileContents
+gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *filepath, ...)
+{
+ gbFileContents result = {0};
+ gbFile file = {0};
+ char *path;
+ va_list va;
+ va_start(va, filepath);
+ path = gb_sprintf_va(filepath, va);
+ va_end(va);
+
+ if (gb_file_open(&file, path)) {
+ i64 file_size = gb_file_size(&file);
+ if (file_size > 0) {
+ result.data = gb_alloc(a, zero_terminate ? file_size+1 : file_size);
+ result.size = file_size;
+ gb_file_read_at(&file, result.data, result.size, 0);
+ if (zero_terminate) {
+ u8 *str = cast(u8 *)result.data;
+ str[file_size] = '\0';
+ }
+ }
+ gb_file_close(&file);
+ }
-#if defined(__cplusplus)
+ return result;
+}
+
+
+
+
+
+gb_inline b32
+gb_path_is_absolute(char const *path)
+{
+ b32 result = false;
+ GB_ASSERT_NOT_NULL(path);
+#if defined(GB_SYSTEM_WINDOWS)
+ result == (gb_strlen(path) > 2) &&
+ gb_char_is_alpha(path[0]) &&
+ (path[1] == ':' && path[2] == GB_PATH_SEPARATOR);
+#else
+ result = (gb_strlen(path) > 0 && path[0] == GB_PATH_SEPARATOR);
+#endif
+ return result;
+}
+
+gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolute(path); }
+
+gb_inline b32
+gb_path_is_root(char const *path)
+{
+ b32 result = false;
+ GB_ASSERT_NOT_NULL(path);
+#if defined(GB_SYSTEM_WINDOWS)
+ result = gb_path_is_absolute(path) && gb_strlen(path) == 3;
+#else
+ result = gb_path_is_absolute(path) && gb_strlen(path) == 1;
+#endif
+ return result;
}
+
+gb_inline char const *
+gb_path_base_name(char const *path)
+{
+ char const *ls;
+ GB_ASSERT_NOT_NULL(path);
+ ls = gb_char_last_occurence(path, '/');
+ return (ls == NULL) ? path : ls+1;
+}
+
+gb_inline char const *
+gb_path_extension(char const *path)
+{
+ char const *ld;
+ GB_ASSERT_NOT_NULL(path);
+ ld = gb_char_last_occurence(path, '.');
+ return (ld == NULL) ? NULL : ld+1;
+}
+
+#if defined(GB_SYSTEM_WINDOWS)
+gb_inline void gb_exit(u32 code) { ExitProcess(code); }
+#else
+#error
+#endif
+
+
+////////////////////////////////////////////////////////////////
+//
+// DLL Handling
+//
+//
+
+#if defined(GB_SYSTEM_WINDOWS)
+
+gbDllHandle
+gb_dll_load(char const *filepath, ...)
+{
+ gb_local_persist char buffer[512];
+ va_list va;
+ va_start(va, filepath);
+ gb_snprintf_va(buffer, gb_size_of(buffer), filepath, va);
+ va_end(va);
+ return cast(gbDllHandle)LoadLibraryA(buffer);
+}
+gb_inline void gb_dll_unload(gbDllHandle dll) { FreeLibrary(cast(HMODULE)dll); }
+gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)GetProcAddress(cast(HMODULE)dll, proc_name); }
+
+#else
+#error
#endif
-#endif // GB_INCLUDE_GB_H
+
+////////////////////////////////////////////////////////////////
+//
+// Time
+//
+//
+#if defined(GB_SYSTEM_WINDOWS)
+
+gb_inline u64 gb_rdtsc(void) { return __rdtsc(); }
+
+gb_global LARGE_INTEGER gb__win32_perf_count_freq = {0};
+
+gb_inline f64
+gb_time_now(void)
+{
+ f64 result;
+ LARGE_INTEGER counter;
+ if (!gb__win32_perf_count_freq.QuadPart)
+ QueryPerformanceFrequency(&gb__win32_perf_count_freq);
+ GB_ASSERT(gb__win32_perf_count_freq.QuadPart != 0);
+
+ QueryPerformanceCounter(&counter);
+
+ result = counter.QuadPart / cast(f64)(gb__win32_perf_count_freq.QuadPart);
+ return result;
+}
+
+
+gb_inline void
+gb_get_system_date(gbDate *date)
+{
+ SYSTEMTIME st = {0};
+ GetSystemTime(&st);
+ date->year = st.wYear;
+ date->month = st.wMonth;
+ date->day_of_week = st.wDayOfWeek;
+ date->day = st.wDay;
+ date->hour = st.wHour;
+ date->minute = st.wMinute;
+ date->second = st.wSecond;
+ date->milliseconds = st.wMilliseconds;
+}
+
+gb_inline void
+gb_get_local_date(gbDate *date)
+{
+ SYSTEMTIME st = {0};
+ GetLocalTime(&st);
+ date->year = st.wYear;
+ date->month = st.wMonth;
+ date->day_of_week = st.wDayOfWeek;
+ date->day = st.wDay;
+ date->hour = st.wHour;
+ date->minute = st.wMinute;
+ date->second = st.wSecond;
+ date->milliseconds = st.wMilliseconds;
+}
+
+#else
+#error
+#endif
+
+
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* GB_IMPLEMENTATION */
diff --git a/gb.hpp b/gb.hpp
deleted file mode 100644
index 24f2cdf..0000000
--- a/gb.hpp
+++ /dev/null
@@ -1,4091 +0,0 @@
-// gb.hpp - v0.32 - public domain C++11 helper library - no warranty implied; use at your own risk
-// (Experimental) A C++11 helper library without STL geared towards game development
-
-/*
-LICENSE
- This software is in the public domain. Where that dedication is not
- recognized, you are granted a perpetual, irrevocable license to copy,
- distribute, and modify this file as you see fit.
-
-WARNING
- - This library is _highly_ experimental and features may not work as expected.
- - This also means that many functions are not documented.
- - This library is not compatible with STL at all! (By design)
-
-CONTENTS:
- - Common Macros
- - Assert
- - Types
- - Type Traits
- - C++11 Move Semantics
- - Defer
- - Casts
- - bit_cast
- - pseudo_cast
- - Memory
- - Mutex
- - Atomics
- - Semaphore
- - Thread
- - Allocator
- - Heap Allocator
- - Arena Allocator
- - Functions
- - String
- - Array
- - Hash Table
- - Hash Functions
-*/
-
-/*
-Version History:
- 0.33 - Explicit Everything! No ctor/dtor on Array<T> and Hash_Table<T>
- 0.32 - Change const position convention
- 0.31a - Minor fixes
- 0.31 - Remove `_Allocator` suffix for allocator types
- 0.30 - sort::quick
- 0.29 - GB_ASSERT prints call stack
- 0.28 - Pool Allocator
- 0.27 - Dealloc to Free & More Hashing Functions
- 0.26a - Heap_Allocator Fix
- 0.26 - Better Allocation system
- 0.25a - Array bug fix
- 0.25 - Faster Heap_Allocator for Windows using HeapAlloc
- 0.24b - Even More Hash_Table Bug Fixes
- 0.24a - Hash_Table Bug Fixes
- 0.24 - More documentation and bug fixes
- 0.23 - Move Semantics for Array and Hash_Table
- 0.22 - Code rearrangment into namespaces
- 0.21d - Fix array::free
- 0.21c - Fix Another Typo causing unresolved external symbol
- 0.21b - Typo fixes
- 0.21a - Better `static` keywords
- 0.21 - Separate Math Library
- 0.20a - #ifndef for many macros
- 0.20 - Angle
- 0.19 - Cache friendly Transform and String fixes
- 0.18 - Hash_Table bug fixes
- 0.17 - Death to OOP
- 0.16 - All References are const convention
- 0.15 - Namespaced Types
- 0.14 - Casts and Quaternion Look At
- 0.13a - Fix Todos
- 0.13 - Basic Type Traits
- 0.12 - Random
- 0.11 - Complex
- 0.10 - Atomics
- 0.09 - Bug Fixes
- 0.08 - Matrix(2,3)
- 0.07 - Bug Fixes
- 0.06 - Os spec ideas
- 0.05 - Transform Type and Quaternion Functions
- 0.04 - String
- 0.03 - Hash Functions
- 0.02 - Hash Table
- 0.01 - Initial Version
-*/
-
-
-#ifndef GB_INCLUDE_GB_HPP
-#define GB_INCLUDE_GB_HPP
-
-#if !defined(__cplusplus) && __cplusplus >= 201103L
- #error This library is only for C++11 and above
-#endif
-
-// NOTE(bill): Because static means three different things in C/C++
-// Great Design(!)
-#ifndef global_variable
-#define global_variable static
-#define internal_linkage static
-#define local_persist static
-#endif
-
-/*
- Example for static defines
-
- global_variable const f32 TAU = 6.283185f;
- global_variable void* g_memory;
-
- internal_linkage void
- some_function(...)
- {
- local_persist u32 count = 0;
- ...
- count++;
- ...
- }
-*/
-
-// `global_variable` : variable is in the global scope
-// `internal_linkage` : function is only visible for this linkage
-// `local_persist` : variable persists for the particular function scope
-
-
-#if defined(_MSC_VER)
- #define _ALLOW_KEYWORD_MACROS
-
- #ifndef alignof // Needed for MSVC 2013 'cause Microsoft "loves" standards
- #define alignof(x) __alignof(x)
- #endif
-#endif
-
-
-////////////////////////////////
-// //
-// System OS //
-// //
-////////////////////////////////
-#if defined(_WIN32) || defined(_WIN64)
- #ifndef GB_SYSTEM_WINDOWS
- #define GB_SYSTEM_WINDOWS 1
- #endif
-#elif defined(__APPLE__) && defined(__MACH__)
- #ifndef GB_SYSTEM_OSX
- #define GB_SYSTEM_OSX 1
- #endif
-#elif defined(__unix__)
- #ifndef GB_SYSTEM_UNIX
- #define GB_SYSTEM_UNIX 1
- #endif
-
- #if defined(__linux__)
- #ifndef GB_SYSTEM_LINUX
- #define GB_SYSTEM_LINUX 1
- #endif
- #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- #ifndef GB_SYSTEM_FREEBSD
- #define GB_SYSTEM_FREEBSD 1
- #endif
- #else
- #error This UNIX operating system is not supported by gb.hpp
- #endif
-#else
- #error This operating system is not supported by gb.hpp
-#endif
-
-
-#if defined(_MSC_VER)
- // Microsoft Visual Studio
- #define GB_COMPILER_MSVC 1
-#elif defined(__clang__)
- // Clang
- #define GB_COMPILER_CLANG 1
-#elif defined(__GNUC__) || defined(__GNUG__) && !(defined(__clang__) || defined(__INTEL_COMPILER))
- // GNU GCC/G++ Compiler
- #define GB_COMPILER_GNU_GCC 1
-#elif defined(__INTEL_COMPILER)
- // Intel C++ Compiler
- #define GB_COMPILER_INTEL 1
-#endif
-
-////////////////////////////////
-// //
-// Environment Bit Size //
-// //
-////////////////////////////////
-#if defined(_WIN32) || defined(_WIN64)
- #if defined(_WIN64)
- #ifndef GB_ARCH_64_BIT
- #define GB_ARCH_64_BIT 1
- #endif
- #else
- #ifndef GB_ARCH_32_BIT
- #define GB_ARCH_32_BIT 1
- #endif
- #endif
-#endif
-
-// TODO(bill): Check if this works on clang
-#if defined(__GNUC__)
- #if defined(__x86_64__) || defined(__ppc64__)
- #ifndef GB_ARCH_64_BIT
- #define GB_ARCH_64_BIT 1
- #endif
- #else
- #ifndef GB_ARCH_32_BIT
- #define GB_ARCH_32_BIT 1
- #endif
- #endif
-#endif
-
-
-#ifndef GB_EDIAN_ORDER
-#define GB_EDIAN_ORDER
- #define GB_IS_BIG_EDIAN (!*(unsigned char*)&(unsigned short){1})
- #define GB_IS_LITTLE_EDIAN (!GB_IS_BIG_EDIAN)
-#endif
-
-#ifndef GB_IS_POWER_OF_TWO
-#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1))
-#endif
-
-#if !defined(GB_HAS_NO_CONSTEXPR)
- #if defined(_GNUC_VER) && _GNUC_VER < 406 // Less than gcc 4.06
- #define GB_HAS_NO_CONSTEXPR 1
- #elif defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015/MSVC++ 14.0
- #define GB_HAS_NO_CONSTEXPR 1
- #elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
- #define GB_HAS_NO_CONSTEXPR 1
- #endif
-#endif
-
-#if defined(GB_HAS_NO_CONSTEXPR)
- #define GB_CONSTEXPR
-#else
- #define GB_CONSTEXPR constexpr
-#endif
-
-#ifndef GB_FORCE_INLINE
- #if defined(_MSC_VER)
- #define GB_FORCE_INLINE __forceinline
- #else
- #define GB_FORCE_INLINE __attribute__ ((__always_inline__))
- #endif
-#endif
-
-
-
-
-
-////////////////////////////////
-// //
-// Includes //
-// //
-////////////////////////////////
-
-#include <math.h>
-#include <stdarg.h>
-#if !defined(GB_NO_STDIO)
-#include <stdio.h>
-#endif
-
-#if defined(GB_SYSTEM_WINDOWS)
- #define NOMINMAX 1
- #define VC_EXTRALEAN 1
- #define WIN32_EXTRA_LEAN 1
- #define WIN32_LEAN_AND_MEAN 1
-
- #include <windows.h> // TODO(bill): Should we include only the needed headers?
- #include <mmsystem.h> // Time functions
-
- #undef NOMINMAX
- #undef VC_EXTRALEAN
- #undef WIN32_EXTRA_LEAN
- #undef WIN32_LEAN_AND_MEAN
-
- #include <intrin.h>
-#else
- #include <pthread.h>
- #include <sys/time.h>
-#endif
-
-
-#ifndef GB_UNUSED
-#define GB_UNUSED(x) ((void)sizeof(x))
-#endif
-
-#if !defined(GB_ASSERT)
- #if !defined(NDEBUG)
- #define GB_ASSERT(x, ...) ((void)(gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
-
- // Helper function used as a better alternative to assert which allows for
- // optional printf style error messages
- extern "C" void
- gb__assert_handler(bool condition, char const* condition_str,
- char const* filename, size_t line,
- char const* error_text = nullptr, ...);
- #else
- #define GB_ASSERT(x, ...) ((void)sizeof(x))
- #endif
-#endif
-
-////////////////////////////////
-// //
-// snprintf_msvc //
-// //
-////////////////////////////////
-#if !defined(GB_NO_STDIO) && defined(_MSC_VER)
- extern "C" inline int
- gb__vsnprintf_compatible(char* buffer, size_t size, char const* format, va_list args)
- {
- int result = -1;
- if (size > 0)
- result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
- if (result == -1)
- return _vscprintf(format, args);
-
- return result;
- }
-
- extern "C" inline int
- gb__snprintf_compatible(char* buffer, size_t size, char const* format, ...)
- {
- va_list args;
- va_start(args, format);
- int result = gb__vsnprintf_compatible(buffer, size, format, args);
- va_end(args);
- return result;
- }
-
- #if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
- #define snprintf gb__snprintf_compatible
- #define vsnprintf gb__vsnprintf_compatible
- #endif // GB_DO_NOT_USE_MSVC_SPRINTF_FIX
-#endif
-
-
-#if defined(GB_NO_GB_NAMESPACE)
- #define __GB_NAMESPACE_START
- #define __GB_NAMESPACE_END
- #define __GB_NAMESPACE_PREFIX
-#else
- #ifndef __GB_NAMESPACE_PREFIX
- #define __GB_NAMESPACE_PREFIX gb
- #endif
-
- // NOTE(bill): __GB_NAMESPACE_PREFIX cannot be blank
- // This is why macros that not meant to be touched have `__` prefix
- // You can change them if you know what you are doing
-
- #define __GB_NAMESPACE_START namespace __GB_NAMESPACE_PREFIX {
- #define __GB_NAMESPACE_END } // namespace __GB_NAMESPACE_PREFIX
-#endif
-
-#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_START
-#endif // GB_BASIC_WITHOUT_NAMESPACE
-
-////////////////////////////////
-// //
-// Types //
-// //
-////////////////////////////////
-
-#ifndef GB_BASIC_TYPES
-#define GB_BASIC_TYPES
- #if defined(_MSC_VER)
- using u8 = unsigned __int8;
- using s8 = signed __int8;
- using u16 = unsigned __int16;
- using s16 = signed __int16;
- using u32 = unsigned __int32;
- using s32 = signed __int32;
- using u64 = unsigned __int64;
- using s64 = signed __int64;
- #else
- // NOTE(bill): Of the platforms that I build for, these will be correct
- using u8 = unsigned char;
- using s8 = signed char;
- using u16 = unsigned short;
- using s16 = signed short;
- using u32 = unsigned int;
- using s32 = signed int;
- using u64 = unsigned long long;
- using s64 = signed long long;
- #endif
-
- static_assert( sizeof(u8) == 1, "u8 is not 8 bits");
- static_assert(sizeof(u16) == 2, "u16 is not 16 bits");
- static_assert(sizeof(u32) == 4, "u32 is not 32 bits");
- static_assert(sizeof(u64) == 8, "u64 is not 64 bits");
-
- using f32 = float;
- using f64 = double;
-
- #if defined(GB_B8_AS_BOOL)
- using bool8 = bool;
- #else
- using bool8 = s8;
- #endif
- using bool32 = s32;
-
- // NOTE(bill): (std::)size_t is not used not because it's a bad concept but on
- // the platforms that I will be using:
- // sizeof(size_t) == sizeof(usize) == sizeof(ssize)
- // NOTE(bill): This also allows for a signed version of size_t which is similar
- // to ptrdiff_t
- // NOTE(bill): If (u)intptr is a better fit, please use that.
- // NOTE(bill): Also, I hate the `_t` suffix
- #if defined(GB_ARCH_64_BIT)
- using ssize = s64;
- using usize = u64;
- #elif defined(GB_ARCH_32_BIT)
- using usize = s32;
- using usize = u32;
- #else
- #error Unknown architecture bit size
- #endif
-
- static_assert(sizeof(usize) == sizeof(size_t),
- "`usize` is not the same size as `size_t`");
- static_assert(sizeof(ssize) == sizeof(usize),
- "`ssize` is not the same size as `usize`");
-
- using intptr = intptr_t;
- using uintptr = uintptr_t;
-
- using ptrdiff = ptrdiff_t;
-
-#endif
-
-#if !defined(GB_U8_MIN)
- #define GB_U8_MIN 0u
- #define GB_U8_MAX 0xffu
- #define GB_S8_MIN (-0x7f - 1)
- #define GB_S8_MAX 0x7f
-
- #define GB_U16_MIN 0u
- #define GB_U16_MAX 0xffffu
- #define GB_S16_MIN (-0x7fff - 1)
- #define GB_S16_MAX 0x7fff
-
- #define GB_U32_MIN 0u
- #define GB_U32_MAX 0xffffffffu
- #define GB_S32_MIN (-0x7fffffff - 1)
- #define GB_S32_MAX 0x7fffffff
-
- #define GB_U64_MIN 0ull
- #define GB_U64_MAX 0xffffffffffffffffull
- #define GB_S64_MIN (-0x7fffffffffffffffll - 1)
- #define GB_S64_MAX 0x7fffffffffffffffll
-#endif
-
-#if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
- #define GB_USIZE_MIX GB_U64_MIN
- #define GB_USIZE_MAX GB_U64_MAX
-
- #define GB_SSIZE_MIX GB_S64_MIN
- #define GB_SSIZE_MAX GB_S64_MAX
-#elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
- #define GB_USIZE_MIX GB_U32_MIN
- #define GB_USIZE_MAX GB_U32_MAX
-
- #define GB_SSIZE_MIX GB_S32_MIN
- #define GB_SSIZE_MAX GB_S32_MAX
-#endif
-
-#if defined(GB_BASIC_WITHOUT_NAMESPACE) && !defined(U8_MIN)
- #define U8_MIN 0u
- #define U8_MAX 0xffu
- #define S8_MIN (-0x7f - 1)
- #define S8_MAX 0x7f
-
- #define U16_MIN 0u
- #define U16_MAX 0xffffu
- #define S16_MIN (-0x7fff - 1)
- #define S16_MAX 0x7fff
-
- #define U32_MIN 0u
- #define U32_MAX 0xffffffffu
- #define S32_MIN (-0x7fffffff - 1)
- #define S32_MAX 0x7fffffff
-
- #define U64_MIN 0ull
- #define U64_MAX 0xffffffffffffffffull
- #define S64_MIN (-0x7fffffffffffffffll - 1)
- #define S64_MAX 0x7fffffffffffffffll
-
- #if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
- #define USIZE_MIX U64_MIN
- #define USIZE_MAX U64_MAX
-
- #define SSIZE_MIX S64_MIN
- #define SSIZE_MAX S64_MAX
- #elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
- #define USIZE_MIX U32_MIN
- #define USIZE_MAX U32_MAX
-
- #define SSIZE_MIX S32_MIN
- #define SSIZE_MAX S32_MAX
- #endif
-#endif
-
-
-
-#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_END
-#endif // GB_BASIC_WITHOUT_NAMESPACE
-
-
-
-
-
-__GB_NAMESPACE_START
-////////////////////////////////
-// //
-// C++11 Types Traits //
-// //
-////////////////////////////////
-
-template <typename T> struct Add_Const_Def { using Type = const T; };
-template <typename T> using Add_Const = typename Add_Const_Def<T>::Type;
-
-template <typename T> struct Add_Volatile_Def { using Type = volatile T; };
-template <typename T> using Add_Volatile = typename Add_Volatile_Def<T>::Type;
-
-template <typename T> using Add_Const_Volatile = Add_Const<Add_Volatile<T>>;
-
-template <typename T> struct Add_Lvalue_Reference_Def { using Type = T&; };
-template <typename T> struct Add_Lvalue_Reference_Def<T&> { using Type = T&; };
-template <typename T> struct Add_Lvalue_Reference_Def<T&&> { using Type = T&; };
-template <> struct Add_Lvalue_Reference_Def<void> { using Type = void; };
-template <> struct Add_Lvalue_Reference_Def<void const> { using Type = void const; };
-template <> struct Add_Lvalue_Reference_Def<void volatile> { using Type = void volatile; };
-template <> struct Add_Lvalue_Reference_Def<void const volatile> { using Type = void const volatile; };
-template <typename T> using Add_Lvalue_Reference = typename Add_Lvalue_Reference_Def<T>::Type;
-
-template <typename T> struct Add_Rvalue_Reference_Def { using Type = T&&; };
-template <typename T> struct Add_Rvalue_Reference_Def<T&> { using Type = T&; };
-template <typename T> struct Add_Rvalue_Reference_Def<T&&> { using Type = T&&; };
-template <> struct Add_Rvalue_Reference_Def<void> { using Type = void; };
-template <> struct Add_Rvalue_Reference_Def<void const> { using Type = void const; };
-template <> struct Add_Rvalue_Reference_Def<void volatile> { using Type = void volatile; };
-template <> struct Add_Rvalue_Reference_Def<void const volatile> { using Type = void const volatile; };
-template <typename T> using Add_Rvalue_Reference = typename Add_Rvalue_Reference_Def<T>::Type;
-
-
-template <typename T> struct Remove_Pointer_Def { using Type = T; };
-template <typename T> struct Remove_Pointer_Def<T*> { using Type = T; };
-template <typename T> struct Remove_Pointer_Def<T* const> { using Type = T; };
-template <typename T> struct Remove_Pointer_Def<T* volatile> { using Type = T; };
-template <typename T> struct Remove_Pointer_Def<T* const volatile> { using Type = T; };
-template <typename T> using Remove_Pointer = typename Remove_Pointer_Def<T>::Type;
-
-template <typename T> struct Add_Pointer_Def { using Type = T*; };
-template <typename T> using Add_Pointer = typename Add_Pointer_Def<T>::Type;
-
-template <typename T> struct Remove_Const_Def { using Type = T; };
-template <typename T> struct Remove_Const_Def<const T> { using Type = T; };
-template <typename T> using Remove_Const = typename Remove_Const_Def<T>::Type;
-
-template <typename T> struct Remove_Volatile_Def { using Type = T; };
-template <typename T> struct Remove_Volatile_Def<volatile T> { using Type = T; };
-template <typename T> using Remove_Volatile = typename Remove_Const_Def<T>::Type;
-
-template <typename T> using Remove_Const_Volatile = Remove_Const<Remove_Volatile<T>>;
-
-template <typename T> struct Remove_Reference_Def { using Type = T; };
-template <typename T> struct Remove_Reference_Def<T&> { using Type = T; };
-template <typename T> struct Remove_Reference_Def<T&&> { using Type = T; };
-template <typename T> using Remove_Reference = typename Remove_Reference_Def<T>::Type;
-
-template <typename T, T v> struct Integral_Constant { global_variable const T VALUE = v; using Value_Type = T; using Type = Integral_Constant; };
-
-template <typename T, usize N = 0> struct Extent : Integral_Constant<usize, 0> {};
-template <typename T> struct Extent<T[], 0> : Integral_Constant<usize, 0> {};
-template <typename T, usize N> struct Extent<T[], N> : Integral_Constant<usize, Extent<T, N-1>::VALUE> {};
-template <typename T, usize N> struct Extent<T[N], 0> : Integral_Constant<usize, N> {};
-template <typename T, usize I, usize N> struct Extent<T[I], N> : Integral_Constant<usize, Extent<T, N-1>::VALUE> {};
-
-template <typename T> struct Remove_Extent_Def { using Type = T; };
-template <typename T> struct Remove_Extent_Def<T[]> { using Type = T; };
-template <typename T, usize N> struct Remove_Extent_Def<T[N]> { using Type = T; };
-
-// TODO(bill): Do I "need" all of these template traits?
-
-
-////////////////////////////////
-// //
-// C++11 Move Semantics //
-// //
-////////////////////////////////
-
-template <typename T>
-inline T&&
-forward_ownership(Remove_Reference<T>& t)
-{
- return static_cast<T&&>(t);
-}
-
-template <typename T>
-inline T&&
-forward_ownership(Remove_Reference<T>&& t)
-{
- return static_cast<T&&>(t);
-}
-
-template <typename T>
-inline Remove_Reference<T>&&
-move_ownership(T&& t)
-{
- return static_cast<Remove_Reference<T>&&>(t);
-}
-__GB_NAMESPACE_END
-
-
-
-
-
-////////////////////////////////
-// //
-// Defer //
-// //
-////////////////////////////////
-
-#ifndef GB_DEFER
-#define GB_DEFER
- __GB_NAMESPACE_START
- namespace impl
- {
- template <typename Func>
- struct Defer
- {
- Func f;
-
- Defer(Func&& f) : f{forward_ownership<Func>(f)} {}
- ~Defer() { f(); };
- };
-
- template <typename Func>
- inline Defer<Func>
- defer_func(Func&& f) { return Defer<Func>(forward_ownership<Func>(f)); }
- } // namespace impl
- __GB_NAMESPACE_END
-
- // NOTE(bill): These macros are in the global namespace thus, defer can be treated without a __GB_NAMESPACE_PREFIX:: prefix
- #define GB_DEFER_1(x, y) x##y
- #define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
- #define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__)
- #define defer(code) auto GB_DEFER_3(_defer_) = ::impl::defer_func([&](){code;})
-
- /* EXAMPLES
-
- // `defer (...)` will defer a statement till the end of scope
-
- FILE* file = fopen("test.txt", "rb");
- if (file == nullptr)
- {
- // Handle Error
- }
- defer (fclose(file)); // Will always be called at the end of scope
-
- //
-
- auto m = mutex::make();
- defer (mutex::destroy(&m)); // Mutex will be destroyed at the end of scope
-
- {
- mutex::lock(&m);
- defer (mutex::unlock(&m)); // Mutex will unlock at end of scope
-
- // Do whatever
- }
-
- // You can scope multiple statements together if needed with {...}
- defer ({
- func1();
- func2();
- func3();
- });
-
- */
-#endif
-
-
-
-
-
-#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_START
-#endif // GB_CASTS_WITHOUT_NAMESPACE
-
-#ifndef GB_SPECIAL_CASTS
-#define GB_SPECIAL_CASTS
- // NOTE(bill): Very similar to doing `*(T*)(&u)`
- template <typename Dest, typename Source>
- inline Dest
- bit_cast(Source const& source)
- {
- static_assert(sizeof(Dest) <= sizeof(Source),
- "bit_cast<Dest>(Source const&) - sizeof(Dest) <= sizeof(Source)");
- Dest dest;
- ::memcpy(&dest, &source, sizeof(Dest));
- return dest;
- }
-
- // IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write
- // however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior
- // *(T*)(&u) ~~ pseudo_cast<T>(u)
- template <typename T, typename U>
- inline T
- pseudo_cast(U const& u)
- {
- return reinterpret_cast<T const&>(u);
- }
-
- /*
- EXAMPLES:
-
- // bit_cast
-
- u8 arr[4] = {0x78, 0x56, 0x34, 0x12};
- u32 var = bit_cast<u32>(arr); // Little edian => 0x12345678
-
- // pseudo_cast - except from gb_math.hpp
- Sphere
- calculate_min_bounding(void const* vertices, usize num_vertices, usize stride, usize offset, f32 step)
- {
- auto gen = random::make(0);
-
- u8 const* vertex = reinterpret_cast<u8 const*>(vertices);
- vertex += offset;
-
- Vector3 position = pseudo_cast<Vector3>(vertex[0]);
- Vector3 center = position;
- center += pseudo_cast<Vector3>(vertex[1 * stride]);
- center *= 0.5f;
-
- Vector3 d = position - center;
- f32 max_dist_sq = math::dot(d, d);
- f32 radius_step = step * 0.37f;
-
- bool done;
- do
- {
- done = true;
- for (u32 i = 0, index = random::uniform_u32(&gen, 0, num_vertices-1);
- i < num_vertices;
- i++, index = (index + 1)%num_vertices)
- {
- Vector3 position = pseudo_cast<Vector3>(vertex[index * stride]);
-
- d = position - center;
- f32 dist_sq = math::dot(d, d);
-
- if (dist_sq > max_dist_sq)
- {
- done = false;
-
- center = d * radius_step;
- max_dist_sq = math::lerp(max_dist_sq, dist_sq, step);
-
- break;
- }
- }
- }
- while (!done);
-
- Sphere result;
-
- result.center = center;
- result.radius = math::sqrt(max_dist_sq);
-
- return result;
- }
-
- */
-#endif
-
-// FORENOTE(bill): There used to be a magic_cast that was equivalent to
-// a C-style cast but I removed it as I could not get it work as intented
-// for everything using only C++ style casts (it needed to a c-style cast)
-
-#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_END
-#endif // GB_CASTS_WITHOUT_NAMESPACE
-
-
-
-
-
-__GB_NAMESPACE_START
-
-////////////////////////////////
-// //
-// Memory //
-// //
-////////////////////////////////
-
-template <typename T, usize N>
-inline usize array_count(T const(& )[N]) { return N; }
-
-inline s64 kilobytes(s64 x) { return (x) * 1024ll; }
-inline s64 megabytes(s64 x) { return kilobytes(x) * 1024ll; }
-inline s64 gigabytes(s64 x) { return megabytes(x) * 1024ll; }
-inline s64 terabytes(s64 x) { return gigabytes(x) * 1024ll; }
-
-
-
-
-struct Mutex
-{
-#if defined(GB_SYSTEM_WINDOWS)
- HANDLE win32_mutex;
-#else
- pthread_mutex_t posix_mutex;
-#endif
-};
-
-namespace mutex
-{
-Mutex make();
-void destroy(Mutex* mutex);
-void lock(Mutex* mutex);
-bool try_lock(Mutex* mutex);
-void unlock(Mutex* mutex);
-} // namespace mutex
-
-
-
-
-// Atomic Types
-struct Atomic32 { u32 nonatomic; };
-struct Atomic64 { u64 nonatomic; };
-
-namespace atomic
-{
-u32 load(Atomic32 const volatile* object);
-void store(Atomic32 volatile* object, u32 value);
-u32 compare_exchange_strong(Atomic32 volatile* object, u32 expected, u32 desired);
-u32 exchanged(Atomic32 volatile* object, u32 desired);
-u32 fetch_add(Atomic32 volatile* object, s32 operand);
-u32 fetch_and(Atomic32 volatile* object, u32 operand);
-u32 fetch_or(Atomic32 volatile* object, u32 operand);
-
-u64 load(Atomic64 const volatile* object);
-void store(Atomic64 volatile* object, u64 value);
-u64 compare_exchange_strong(Atomic64 volatile* object, u64 expected, u64 desired);
-u64 exchanged(Atomic64 volatile* object, u64 desired);
-u64 fetch_add(Atomic64 volatile* object, s64 operand);
-u64 fetch_and(Atomic64 volatile* object, u64 operand);
-u64 fetch_or(Atomic64 volatile* object, u64 operand);
-} // namespace atomic
-
-
-
-
-struct Semaphore
-{
-#if defined(GB_SYSTEM_WINDOWS)
- HANDLE win32_handle;
-#else
- Mutex mutex;
- pthread_cond_t cond;
- s32 count;
-#endif
-};
-
-namespace semaphore
-{
-Semaphore make();
-void destroy(Semaphore* semaphore);
-void post(Semaphore* semaphore, u32 count = 1);
-void wait(Semaphore* semaphore);
-} // namespace semaphore
-
-
-
-
-// TODO(bill): Is this thread procedure definition good enough?
-using Thread_Procedure = void(void*);
-
-struct Thread
-{
-#if defined(GB_SYSTEM_WINDOWS)
- HANDLE win32_handle;
-#else
- pthread_t posix_handle;
-#endif
-
- Thread_Procedure* function;
- void* data;
-
- Semaphore semaphore;
- usize stack_size;
- bool32 is_running;
-};
-
-namespace thread
-{
-Thread make();
-void destroy(Thread* t);
-void start(Thread* t, Thread_Procedure* func, void* data = nullptr, usize stack_size = 0);
-void join(Thread* t);
-bool is_running(Thread const& t);
-u32 current_id();
-} // namespace thread
-
-
-
-
-// Default alignment for memory allocations
-#ifndef GB_DEFAULT_ALIGNMENT
-#define GB_DEFAULT_ALIGNMENT 8
-#endif
-
-// Base class for memory allocators - Pretty much a vtable
-struct Allocator
-{
- // Allocates the specified amount of memory aligned to the specified alignment
- void* (*alloc)(Allocator* a, usize size, usize align);
- // Frees an allocation made with alloc()
- void (*free)(Allocator* a, void* ptr);
- // Returns the amount of usuable memory allocated at `ptr`.
- ///
- // If the allocator does not support tracking of the allocation size,
- // the function will return -1
- s64 (*allocated_size)(Allocator* a, void const* ptr);
- // Returns the total amount of memory allocated by this allocator
- ///
- // If the allocator does not track memory, the function will return -1
- s64 (*total_allocated)(Allocator* a);
-};
-
-
-
-
-struct Heap : Allocator
-{
- struct Header
- {
- usize size;
- };
-
- Mutex mutex;
- bool32 use_mutex;
- s64 total_allocated_count;
- s64 allocation_count;
-
-#if defined(GB_SYSTEM_WINDOWS)
- HANDLE win32_heap_handle;
-#endif
-};
-
-namespace heap
-{
-Heap make(bool use_mutex = true);
-void destroy(Heap* heap);
-} // namespace heap
-
-
-
-
-
-struct Arena : Allocator
-{
- Allocator* backing;
- void* physical_start;
- s64 total_size;
- s64 total_allocated_count;
- s64 temp_count;
-};
-
-namespace arena
-{
-Arena make(Allocator* backing, usize size);
-Arena make(void* start, usize size);
-void destroy(Arena* arena);
-void clear(Arena* arena);
-} // namespace arena
-
-
-
-
-
-struct Temporary_Arena_Memory
-{
- Arena* arena;
- s64 original_count;
-};
-
-namespace temporary_arena_memory
-{
-Temporary_Arena_Memory make(Arena* arena);
-void free(Temporary_Arena_Memory tmp);
-} // namespace temporary_arena_memory
-
-
-
-
-struct Pool : Allocator
-{
- Allocator* backing;
-
- void* physical_start;
- void* free_list;
-
- usize block_size;
- usize block_align;
- s64 total_size;
-};
-
-namespace pool
-{
-Pool make(Allocator* backing, usize num_blocks, usize block_size,
- usize block_align = GB_DEFAULT_ALIGNMENT);
-void destroy(Pool* pool);
-} // namespace pool
-
-
-
-
-namespace memory
-{
-void* align_forward(void* ptr, usize align);
-
-void* pointer_add(void* ptr, usize bytes);
-void* pointer_sub(void* ptr, usize bytes);
-void const* pointer_add(void const* ptr, usize bytes);
-void const* pointer_sub(void const* ptr, usize bytes);
-
-template <typename T>
-void fill(T* ptr, usize count, T const& value);
-
-template <typename T>
-void fill(T* ptr, usize count, T&& value);
-
-void zero(void* ptr, usize bytes);
-void copy(void const* src, usize bytes, void* dest);
-void move(void const* src, usize bytes, void* dest);
-bool equals(void const* a, void const* b, usize bytes);
-
-template <typename T>
-void zero_struct(T* ptr);
-
-template <typename T>
-void zero_array(T* ptr, usize count);
-
-template <typename T>
-void copy_array(T const* src_array, usize count, T* dest_array);
-
-template <typename T>
-void copy_struct(T const* src_array, T* dest_array);
-
-
-template <typename T>
-void swap(T* a, T* b);
-
-template <typename T, usize N>
-void swap(T (& a)[N], T (& b)[N]);
-} // namespace memory
-
-
-
-
-// Allocator Functions
-void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT);
-void free(Allocator* a, void* ptr);
-s64 allocated_size(Allocator* a, void const* ptr);
-s64 total_allocated(Allocator* a);
-
-template <typename T>
-inline T* alloc_struct(Allocator* a) { return static_cast<T*>(alloc(a, sizeof(T), alignof(T))); }
-
-template <typename T>
-inline T* alloc_array(Allocator* a, usize count) { return static_cast<T*>(alloc(a, count * sizeof(T), alignof(T))); }
-
-
-
-
-
-////////////////////////////////
-// //
-// String //
-// //
-// C compatible string //
-// //
-////////////////////////////////
-
-// A "better" string type that is compatible with C style read-only functions
-using String = char*;
-
-namespace string
-{
-using Size = u32;
-
-struct Header
-{
- Allocator* allocator;
- Size length;
- Size capacity;
-};
-
-inline Header* header(String str) { return reinterpret_cast<Header*>(str) - 1; }
-
-String make(Allocator* a, char const* str = "");
-String make(Allocator* a, void const* str, Size num_bytes);
-void free(String str);
-
-String duplicate(Allocator* a, String const str);
-
-Size length(String const str);
-Size capacity(String const str);
-Size available_space(String const str);
-
-void clear(String str);
-
-void append(String* str, char c);
-void append(String* str, String const other);
-void append_cstring(String* str, char const* other);
-void append(String* str, void const* other, Size num_bytes);
-
-void make_space_for(String* str, Size add_len);
-usize allocation_size(String const str);
-
-bool equals(String const lhs, String const rhs);
-int compare(String const lhs, String const rhs); // NOTE(bill): three-way comparison
-
-void trim(String* str, char const* cut_set);
-void trim_space(String* str);
-} // namespace string
-
-
-// TODO(bill): string libraries
-
-
-
-////////////////////////////////
-// //
-// Array //
-// //
-////////////////////////////////
-
-#ifndef GB_ARRAY_BOUND_CHECKING
-#define GB_ARRAY_BOUND_CHECKING 1
-#endif
-
-// Dynamic resizable array for POD types only
-template <typename T>
-struct Array
-{
- using Type = T;
-
- Allocator* allocator;
- s64 count;
- s64 capacity;
- T* data;
-
- T const& operator[](usize index) const;
- T& operator[](usize index);
-};
-
-// NOTE(bill): There are not ctor/dtor for Array<T>.
-// These are explicit functions e.g.
-/*
-auto old_array = array::make<T>(...);
-auto new_array = array::copy(old_array);
-array::free(&old_array);
-array::free(&new_array);
-*/
-// This allows functions to be passed by value at a low cost
-
-namespace array
-{
-// Helper functions to make, free, and copy an array
-template <typename T> Array<T> make(Allocator* allocator, usize count = 0);
-template <typename T> void free(Array<T>* array);
-// TODO(bill): Is passing by value okay here or is pass by const& ?
-// (sizeof(Array<T>) = 16 + sizeof(void*)) (24 bytes on x86, 32 bytes on x64)
-template <typename T> Array<T> copy(Array<T> array, Allocator* allocator = nullptr);
-
-// Appends `item` to the end of the array
-template <typename T> void append(Array<T>* a, T const& item);
-template <typename T> void append(Array<T>* a, T&& item);
-// Appends `items[count]` to the end of the array
-template <typename T> void append(Array<T>* a, T const* items, usize count);
-// Append the contents of another array of the same type
-template <typename T> void append(Array<T>* a, Array<T> other);
-
-// Pops the last item form the array. The array cannot be empty.
-template <typename T> void pop(Array<T>* a);
-
-// Removes all items from the array - does not free memory
-template <typename T> void clear(Array<T>* a);
-// Modify the size of a array - only reallocates when necessary
-template <typename T> void resize(Array<T>* a, usize count);
-// Makes sure that the array has at least the specified capacity - or the array the grows
-template <typename T> void reserve(Array<T>* a, usize capacity);
-// Reallocates the array to the specific capacity
-template <typename T> void set_capacity(Array<T>* a, usize capacity);
-// Grows the array to keep append() to be O(1)
-template <typename T> void grow(Array<T>* a, usize min_capacity = 0);
-} // namespace array
-
-// Used to iterate over the array with a C++11 for loop
-template <typename T> inline T* begin(Array<T>& a) { return a.data; }
-template <typename T> inline T const* begin(Array<T> const& a) { return a.data; }
-template <typename T> inline T* begin(Array<T>&& a) { return a.data; }
-template <typename T> inline T* end(Array<T>& a) { return a.data + a.count; }
-template <typename T> inline T const* end(Array<T> const& a) { return a.data + a.count; }
-template <typename T> inline T* end(Array<T>&& a) { return a.data + a.count; }
-
-
-
-
-
-////////////////////////////////
-// //
-// Hash Table //
-// //
-////////////////////////////////
-
-// Hash table for POD types only with a u64 key
-template <typename T>
-struct Hash_Table
-{
- using Type = T;
-
- struct Entry
- {
- u64 key;
- s64 next;
- T value;
- };
-
- Array<s64> hashes;
- Array<Entry> entries;
-};
-
-namespace hash_table
-{
-// Helper function to make, free, and copy a hash table
-template <typename T> Hash_Table<T> make(Allocator* a);
-template <typename T> void free(Hash_Table<T>* h);
-template <typename T> Hash_Table<T> copy(Hash_Table<T> const& h, Allocator* a = nullptr);
-
-// Return `true` if the specified key exist in the hash table
-template <typename T> bool has(Hash_Table<T> const& h, u64 key);
-// Returns the value stored at the key, or a `default_value` if the key is not found in the hash table
-template <typename T> T const& get(Hash_Table<T> const& h, u64 key, T const& default_value);
-// Sets the value for the key in the hash table
-template <typename T> void set(Hash_Table<T>* h, u64 key, T const& value);
-template <typename T> void set(Hash_Table<T>* h, u64 key, T&& value);
-// Removes the key from the hash table if it exists
-template <typename T> void remove(Hash_Table<T>* h, u64 key);
-// Resizes the hash table's lookup table to the specified size
-template <typename T> void reserve(Hash_Table<T>* h, usize capacity);
-// Remove all elements from the hash table
-template <typename T> void clear(Hash_Table<T>* h);
-} // namespace hash_table
-
-// Used to iterate over the array with a C++11 for loop - in random order
-template <typename T> typename Hash_Table<T>::Entry const* begin(Hash_Table<T> const& h);
-template <typename T> typename Hash_Table<T>::Entry const* end(Hash_Table<T> const& h);
-
-namespace multi_hash_table
-{
-// Outputs all the items that with the specified key
-template <typename T> void get(Hash_Table<T> const& h, u64 key, Array<T>& items);
-// Returns the count of entries with the specified key
-template <typename T> usize count(Hash_Table<T> const& h, u64 key);
-
-// Finds the first entry with specified key in the hash table
-template <typename T> typename Hash_Table<T>::Entry const* find_first(Hash_Table<T> const& h, u64 key);
-// Finds the next entry with same key as `e`
-template <typename T> typename Hash_Table<T>::Entry const* find_next(Hash_Table<T> const& h, typename Hash_Table<T>::Entry const* e);
-
-// Inserts the `value` as an additional value for the specified key
-template <typename T> void insert(Hash_Table<T>* h, u64 key, T const& value);
-template <typename T> void insert(Hash_Table<T>* h, u64 key, T&& value);
-// Removes a specified entry `e` from the hash table
-template <typename T> void remove_entry(Hash_Table<T>* h, typename Hash_Table<T>::Entry const* e);
-// Removes all entries with from the hash table with the specified key
-template <typename T> void remove_all(Hash_Table<T>* h, u64 key);
-} // namespace multi_hash_table
-
-
-
-
-
-////////////////////////////////
-// //
-// Hash //
-// //
-////////////////////////////////
-
-namespace hash
-{
-u32 adler32(void const* key, u32 num_bytes);
-
-u32 crc32(void const* key, u32 num_bytes);
-u64 crc64(void const* key, usize num_bytes);
-
-u32 fnv32(void const* key, usize num_bytes);
-u64 fnv64(void const* key, usize num_bytes);
-u32 fnv32a(void const* key, usize num_bytes);
-u64 fnv64a(void const* key, usize num_bytes);
-
-u32 murmur32(void const* key, u32 num_bytes, u32 seed = 0x9747b28c);
-u64 murmur64(void const* key, usize num_bytes, u64 seed = 0x9747b28c);
-} // namespace hash
-
-
-
-////////////////////////////////
-// //
-// Sort //
-// //
-////////////////////////////////
-
-namespace sort
-{
-// Comparison_Function
-// NOTE(bill): Similar to str(n)cmp
-// a < b --> -1
-// a == b --> 0
-// a > b --> +1
-
-// Quick Sort (Qsort)
-template <typename T, typename Comparison_Function>
-void quick(T* array, usize count, Comparison_Function compare);
-
-// TODO(bill): Implement other sorting algorithms
-} // namespace sort
-
-
-////////////////////////////////
-// //
-// Time //
-// //
-////////////////////////////////
-
-struct Time
-{
- s64 microseconds;
-};
-
-extern Time const TIME_ZERO;
-
-namespace time
-{
-Time now();
-void sleep(Time time);
-
-Time seconds(f32 s);
-Time milliseconds(s32 ms);
-Time microseconds(s64 us);
-
-f32 as_seconds(Time t);
-s32 as_milliseconds(Time t);
-s64 as_microseconds(Time t);
-} // namespace time
-
-bool operator==(Time left, Time right);
-bool operator!=(Time left, Time right);
-
-bool operator<(Time left, Time right);
-bool operator>(Time left, Time right);
-
-bool operator<=(Time left, Time right);
-bool operator>=(Time left, Time right);
-
-Time operator+(Time right);
-Time operator-(Time right);
-
-Time operator+(Time left, Time right);
-Time operator-(Time left, Time right);
-
-Time& operator+=(Time& left, Time right);
-Time& operator-=(Time& left, Time right);
-
-Time operator*(Time left, f32 right);
-Time operator*(Time left, s64 right);
-Time operator*(f32 left, Time right);
-Time operator*(s64 left, Time right);
-
-Time& operator*=(Time& left, f32 right);
-Time& operator*=(Time& left, s64 right);
-
-Time operator/(Time left, f32 right);
-Time operator/(Time left, s64 right);
-
-Time& operator/=(Time& left, f32 right);
-Time& operator/=(Time& left, s64 right);
-
-f32 operator/(Time left, Time right);
-
-Time operator%(Time left, Time right);
-Time& operator%=(Time& left, Time right);
-
-
-
-
-
-////////////////////////////////
-// //
-// OS //
-// //
-////////////////////////////////
-
-// TODO(bill): Should this be system:: vs os:: ?
-namespace os
-{
-u64 rdtsc();
-} // namespace os
-
-
-
-
-
-
-////////////////////////////////
-// //
-// Template Implementations //
-// //
-////////////////////////////////
-
-////////////////////////////////
-// //
-// Array //
-// //
-////////////////////////////////
-
-template <typename T>
-inline T const&
-Array<T>::operator[](usize index) const
-{
-#if GB_ARRAY_BOUND_CHECKING
- GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds");
-#endif
- return data[index];
-}
-
-template <typename T>
-inline T&
-Array<T>::operator[](usize index)
-{
-#if GB_ARRAY_BOUND_CHECKING
- GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds");
-#endif
- return data[index];
-}
-
-
-namespace array
-{
-template <typename T>
-inline Array<T>
-make(Allocator* allocator, usize count)
-{
- Array<T> result = {};
- result.allocator = allocator;
-
- if (count > 0)
- {
- result.data = alloc_array<T>(allocator, count);
- if (result.data)
- result.count = result.capacity = count;
- }
-
- return result;
-}
-
-template <typename T>
-inline void
-free(Array<T>* a)
-{
- if (a->allocator)
- free(a->allocator, a->data);
- a->count = 0;
- a->capacity = 0;
- a->data = nullptr;
-}
-
-template <typename T>
-inline Array<T>
-copy(Array<T> other, Allocator* allocator)
-{
- Array<T> result = {};
-
- if (allocator)
- result.allocator = allocator;
- else
- result.allocator = other.allocator;
-
- auto new_count = other.count;
-
- array::resize(&result, new_count);
- memory::copy_array(other.data, new_count, data);
-
- return result;
-}
-
-
-
-
-template <typename T>
-inline void
-append(Array<T>* a, T const& item)
-{
- if (a->capacity < a->count + 1)
- array::grow(a);
- a->data[a->count++] = item;
-}
-
-template <typename T>
-inline void
-append(Array<T>* a, T&& item)
-{
- if (a->capacity < a->count + 1)
- array::grow(a);
- a->data[a->count++] = move_ownership(item);
-}
-
-template <typename T>
-inline void
-append(Array<T>* a, T const* items, usize count)
-{
- if (a->capacity <= a->count + static_cast<s64>(count))
- array::grow(a, a->count + count);
-
- memory::copy_array(items, count, &a->data[a->count]);
- a->count += count;
-}
-
-template <typename T>
-inline void
-append(Array<T>* a, Array<T> other)
-{
- array::append(a, other.data, other.count);
-}
-
-
-template <typename T>
-inline void
-pop(Array<T>* a)
-{
- GB_ASSERT(a->count > 0);
-
- a->count--;
-}
-
-template <typename T>
-inline void
-clear(Array<T>* a)
-{
- a->count = 0;
-}
-
-template <typename T>
-inline void
-resize(Array<T>* a, usize count)
-{
- if (a->capacity < static_cast<s64>(count))
- array::grow(a, count);
- a->count = count;
-}
-
-template <typename T>
-inline void
-reserve(Array<T>* a, usize capacity)
-{
- if (a->capacity < static_cast<s64>(capacity))
- array::set_capacity(a, capacity);
-}
-
-template <typename T>
-inline void
-set_capacity(Array<T>* a, usize capacity)
-{
- if (static_cast<s64>(capacity) == a->capacity)
- return;
-
- if (static_cast<s64>(capacity) < a->count)
- array::resize(a, capacity);
-
- T* data = nullptr;
- if (capacity > 0)
- {
- data = alloc_array<T>(a->allocator, capacity);
- memory::copy_array(a->data, a->count, data);
- }
- free(a->allocator, a->data);
- a->data = data;
- a
-
- ->capacity = capacity;
-}
-
-template <typename T>
-inline void
-grow(Array<T>* a, usize min_capacity)
-{
- // TODO(bill): Decide on decent growing formula for Array
- usize capacity = 2 * a->capacity + 8;
- if (capacity < min_capacity)
- capacity = min_capacity;
- set_capacity(a, capacity);
-}
-} // namespace array
-
-
-
-
-
-
-
-////////////////////////////////
-// //
-// Hash Table //
-// //
-////////////////////////////////
-
-namespace hash_table
-{
-template <typename T>
-inline Hash_Table<T>
-make(Allocator* a)
-{
- Hash_Table<T> result = {};
-
- result.hashes = array::make<s64>(a);
- result.entries = array::make<typename Hash_Table<T>::Entry>(a);
-
- return result;
-}
-
-template <typename T>
-inline void
-free(Hash_Table<T>* h)
-{
- if (h->hashes.allocator)
- array::free(&h->hashes);
-
- if (h->entries.allocator)
- array::free(&h->entries);
-}
-
-template <typename T>
-inline Hash_Table<T>
-copy(Hash_Table<T> const& other, Allocator* allocator)
-{
- Allocator* a = other.hashes.allocator;
- if (allocator) a = allocator;
-
- Hash_Table<T> result = {};
- result.hashes = array::copy(other.hashes, a);
- result.entries = array::copy(other.entries, a);
-
- return result;
-}
-
-
-namespace impl
-{
-struct Find_Result
-{
- s64 hash_index;
- s64 data_prev;
- s64 entry_index;
-};
-
-template <typename T> usize add_entry(Hash_Table<T>* h, u64 key);
-template <typename T> void erase(Hash_Table<T>* h, Find_Result const& fr);
-template <typename T> Find_Result find_result_from_key(Hash_Table<T> const& h, u64 key);
-template <typename T> Find_Result find_result_from_entry(Hash_Table<T> const& h, typename Hash_Table<T>::Entry const* e);
-template <typename T> s64 make_entry(Hash_Table<T>* h, u64 key);
-template <typename T> void find_and_erase_entry(Hash_Table<T>* h, u64 key);
-template <typename T> s64 find_entry_or_fail(Hash_Table<T> const& h, u64 key);
-template <typename T> s64 find_or_make_entry(Hash_Table<T>* h, u64 key);
-template <typename T> void rehash(Hash_Table<T>* h, usize new_capacity);
-template <typename T> void grow(Hash_Table<T>* h);
-template <typename T> bool is_full(Hash_Table<T>* h);
-
-template <typename T>
-usize
-add_entry(Hash_Table<T>* h, u64 key)
-{
- typename Hash_Table<T>::Entry e = {};
- e.key = key;
- e.next = -1;
- usize e_index = h->entries.count;
- array::append(&h->entries, e);
-
- return e_index;
-}
-
-template <typename T>
-void
-erase(Hash_Table<T>* h, Find_Result const& fr)
-{
- if (fr.data_prev < 0)
- h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
- else
- h->entries[fr.data_prev].next = h->entries[fr.entry_index].next;
-
- array::pop(&h->entries); // Update array count
-
- if (fr.entry_index == h->entries.count)
- return;
-
- h->entries[fr.entry_index] = h->entries[h->entries.count];
-
- auto last = impl::find_result_from_key(*h, h->entries[fr.entry_index].key);
-
- if (last.data_prev < 0)
- h->hashes[last.hash_index] = fr.entry_index;
- else
- h->entries[last.entry_index].next = fr.entry_index;
-}
-
-template <typename T>
-Find_Result
-find_result_from_key(Hash_Table<T> const& h, u64 key)
-{
- Find_Result fr = {};
- fr.hash_index = -1;
- fr.data_prev = -1;
- fr.entry_index = -1;
-
- if (h.hashes.count == 0)
- return fr;
-
- fr.hash_index = key % h.hashes.count;
- fr.entry_index = h.hashes[fr.hash_index];
- while (fr.entry_index >= 0)
- {
- if (h.entries[fr.entry_index].key == key)
- return fr;
- fr.data_prev = fr.entry_index;
- fr.entry_index = h.entries[fr.entry_index].next;
- }
-
- return fr;
-}
-
-
-template <typename T>
-Find_Result
-find_result_from_entry(Hash_Table<T> const& h, typename Hash_Table<T>::Entry const* e)
-{
- Find_Result fr = {};
- fr.hash_index = -1;
- fr.data_prev = -1;
- fr.entry_index = -1;
-
- if (h.hashes.count == 0 || !e)
- return fr;
-
- fr.hash_index = e->key % h.hashes.count;
- fr.entry_index = h.hashes[fr.hash_index];
- while (fr.entry_index >= 0)
- {
- if (&h.entries[fr.entry_index] == e)
- return fr;
- fr.data_prev = fr.entry_index;
- fr.entry_index = h.entries[fr.entry_index].next;
- }
-
- return fr;
-}
-
-template <typename T>
-s64
-make_entry(Hash_Table<T>* h, u64 key)
-{
- Find_Result const fr = impl::find_result_from_key(*h, key);
- s64 const index = impl::add_entry(h, key);
-
- if (fr.data_prev < 0)
- h->hashes[fr.hash_index] = index;
- else
- h->entries[fr.data_prev].next = index;
-
- h->entries[index].next = fr.entry_index;
-
- return index;
-}
-
-template <typename T>
-void
-find_and_erase_entry(Hash_Table<T>* h, u64 key)
-{
- Find_Result const fr = impl::find_result_from_key(*h, key);
- if (fr.entry_index >= 0)
- impl::erase(h, fr);
-}
-
-template <typename T>
-s64
-find_entry_or_fail(Hash_Table<T> const& h, u64 key)
-{
- return impl::find_result_from_key(h, key).entry_index;
-}
-
-template <typename T>
-s64
-find_or_make_entry(Hash_Table<T>* h, u64 key)
-{
- auto const fr = impl::find_result_from_key(*h, key);
- if (fr.entry_index >= 0)
- return fr.entry_index;
-
- s64 index = impl::add_entry(h, key);
- if (fr.data_prev < 0)
- h->hashes[fr.hash_index] = index;
- else
- h->entries[fr.data_prev].next = index;
-
- return index;
-}
-
-template <typename T>
-void
-rehash(Hash_Table<T>* h, usize new_capacity)
-{
- auto nh = hash_table::make<T>(h->hashes.allocator);
- array::resize(&nh.hashes, new_capacity);
- array::reserve(&nh.entries, h->entries.count);
-
- for (usize i = 0; i < new_capacity; i++)
- nh.hashes[i] = -1;
-
- for (s64 i = 0; i < h->entries.count; i++)
- {
- auto const* e = &h->entries[i];
- multi_hash_table::insert(&nh, e->key, e->value);
- }
-
- Hash_Table<T> empty_ht{h->hashes.allocator};
- hash_table::free(h);
-
- memory::copy_struct(&nh, h);
- memory::copy_struct(&empty_ht, &nh);
-}
-
-template <typename T>
-inline void
-grow(Hash_Table<T>* h)
-{
- const usize new_capacity = 2 * h->entries.count + 8;
- impl::rehash(h, new_capacity);
-}
-
-template <typename T>
-inline bool
-is_full(Hash_Table<T>* h)
-{
- // Make sure that there is enough space
- f64 const maximum_load_coefficient = 0.75;
- return h->entries.count >= maximum_load_coefficient * h->hashes.count;
-}
-} // namespace impl
-
-template <typename T>
-inline bool
-has(Hash_Table<T> const& h, u64 key)
-{
- return impl::find_entry_or_fail(h, key) >= 0;
-}
-
-template <typename T>
-inline T const&
-get(Hash_Table<T> const& h, u64 key, T const& default_value)
-{
- s64 const index = impl::find_entry_or_fail(h, key);
-
- if (index < 0)
- return default_value;
- return h.entries[index].value;
-}
-
-template <typename T>
-inline void
-set(Hash_Table<T>* h, u64 key, T const& value)
-{
- if (h->hashes.count == 0)
- impl::grow(h);
-
- s64 const index = impl::find_or_make_entry(h, key);
- h->entries[index].value = value;
- if (impl::is_full(h))
- impl::grow(h);
-}
-
-template <typename T>
-inline void
-set(Hash_Table<T>* h, u64 key, T&& value)
-{
- if (h->hashes.count == 0)
- impl::grow(h);
-
- s64 const index = impl::find_or_make_entry(h, key);
- h->entries[index].value = move_ownership(value);
- if (impl::is_full(h))
- impl::grow(h);
-}
-
-template <typename T>
-inline void
-remove(Hash_Table<T>* h, u64 key)
-{
- impl::find_and_erase_entry(h, key);
-}
-
-template <typename T>
-inline void
-reserve(Hash_Table<T>* h, usize capacity)
-{
- impl::rehash(h, capacity);
-}
-
-template <typename T>
-inline void
-clear(Hash_Table<T>* h)
-{
- array::clear(&h->hashes);
- array::clear(&h->entries);
-}
-} // namespace hash_table
-
-template <typename T>
-inline typename Hash_Table<T>::Entry const*
-begin(Hash_Table<T> const& h)
-{
- return begin(h.entries);
-}
-
-template <typename T>
-inline typename Hash_Table<T>::Entry const*
-end(Hash_Table<T> const& h)
-{
- return end(h.entries);
-}
-
-
-namespace multi_hash_table
-{
-template <typename T>
-inline void
-get(Hash_Table<T> const& h, u64 key, Array<T>& items)
-{
- auto e = multi_hash_table::find_first(h, key);
- while (e)
- {
- array::append(items, e->value);
- e = multi_hash_table::find_next(h, e);
- }
-}
-
-template <typename T>
-inline usize
-count(Hash_Table<T> const& h, u64 key)
-{
- usize count = 0;
- auto e = multi_hash_table::find_first(h, key);
- while (e)
- {
- count++;
- e = multi_hash_table::find_next(h, e);
- }
-
- return count;
-}
-
-
-template <typename T>
-inline typename Hash_Table<T>::Entry const*
-find_first(Hash_Table<T> const& h, u64 key)
-{
- s64 const index = hash_table::impl::find_entry_or_fail(h, key);
- if (index < 0)
- return nullptr;
- return &h.entries[index];
-}
-
-template <typename T>
-typename Hash_Table<T>::Entry const*
-find_next(Hash_Table<T> const& h, typename Hash_Table<T>::Entry const* e)
-{
- if (!e)
- return nullptr;
-
- auto index = e->next;
- while (index >= 0)
- {
- if (h.entries[index].key == e->key)
- return &h.entries[index];
- index = h.entries[index].next;
- }
-
- return nullptr;
-}
-
-
-template <typename T>
-inline void
-insert(Hash_Table<T>* h, u64 key, T const& value)
-{
- if (h->hashes.count == 0)
- hash_table::impl::grow(h);
-
- auto next = hash_table::impl::make_entry(h, key);
- h->entries[next].value = value;
-
- if (hash_table::impl::is_full(h))
- hash_table::impl::grow(h);
-}
-
-template <typename T>
-inline void
-insert(Hash_Table<T>* h, u64 key, T&& value)
-{
- if (h->hashes.count == 0)
- hash_table::impl::grow(h);
-
- auto next = hash_table::impl::make_entry(h, key);
- h->entries[next].value = move_ownership(value);
-
- if (hash_table::impl::is_full(h))
- hash_table::impl::grow(h);
-}
-
-template <typename T>
-inline void
-remove_entry(Hash_Table<T>* h, typename Hash_Table<T>::Entry const* e)
-{
- auto const fr = hash_table::impl::find_result_from_entry(*h, e);
- if (fr.entry_index >= 0)
- hash_table::impl::erase(h, fr);
-}
-
-template <typename T>
-inline void
-remove_all(Hash_Table<T>* h, u64 key)
-{
- while (hash_table::has(*h, key))
- hash_table::remove(h, key);
-}
-} // namespace multi_hash_table
-
-
-namespace memory
-{
-template <typename T>
-inline void
-fill(T* ptr, usize count, T const& value)
-{
- for (usize i = 0; i < count; i++)
- ptr[i] = value;
-}
-
-template <typename T>
-inline void
-fill(T* ptr, usize count, T&& value)
-{
- for (usize i = 0; i < count; i++)
- ptr[i] = move_ownership(value);
-}
-
-template <typename T>
-inline void
-zero_struct(T* ptr)
-{
- memory::zero(ptr, sizeof(T));
-}
-
-template <typename T>
-inline void
-zero_array(T* ptr, usize count)
-{
- memory::zero(ptr, count * sizeof(T));
-}
-
-template <typename T>
-inline void
-copy_array(T const* src_array, usize count, T* dest_array)
-{
- memory::copy(src_array, count * sizeof(T), dest_array);
-}
-
-template <typename T>
-inline void
-copy_struct(T const* src_array, T* dest_array)
-{
- memory::copy(src_array, sizeof(T), dest_array);
-}
-
-
-template <typename T>
-inline void
-swap(T* a, T* b)
-{
- T c = move_ownership(*a);
- *a = move_ownership(*b);
- *b = move_ownership(c);
-}
-
-template <typename T, usize N>
-inline void
-swap(T (& a)[N], T (& b)[N])
-{
- for (usize i = 0; i < N; i++)
- math::swap(&a[i], &b[i]);
-}
-} // namespace memory
-
-
-
-////////////////////////////////
-// //
-// Sort //
-// //
-////////////////////////////////
-
-namespace sort
-{
-template <typename T, typename Comparison_Function>
-void
-quick(T* array, usize count, Comparison_Function compare)
-{
- if (count < 2) return;
-
- T const& mid = array[count/2];
-
- s64 i = 0;
- s64 j = count-1;
-
- while (true)
- {
- while (compare(array[i], mid) < 0) i++;
- while (compare(mid, array[j]) < 0) j--;
-
- if (i >= j) break;
-
- memory::swap(&array[i], &array[j]);
-
- i++;
- j--;
- }
-
- sort::quick(array, i, compare);
- sort::quick(array+i, count-i, compare);
-}
-} // namespace sort
-
-
-
-__GB_NAMESPACE_END
-
-#endif // GB_INCLUDE_GB_HPP
-
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-// It's turtles all the way down!
-//
-//
-//
-//
-//
-////////////////////////////////
-// //
-// Implemenation //
-// //
-////////////////////////////////
-
-#if defined(GB_IMPLEMENTATION)
-
-#if defined(GB_SYSTEM_WINDOWS)
-
- #if !defined(GB_NO_STDIO)
- #include <dbghelp.h>
- #pragma comment(lib, "dbghelp.lib") // TODO(bill): Should this be pragma included or not?
-
- internal_linkage void
- gb__print_call_stack(FILE* out_stream)
- {
- SymInitialize(GetCurrentProcess(), nullptr, true);
- SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
-
- DWORD mtype = {};
- CONTEXT ctx = {};
- ctx.ContextFlags = CONTEXT_CONTROL;
-
- RtlCaptureContext(&ctx);
-
- STACKFRAME64 stack = {};
-
- #if defined(_M_IX86)
- mtype = IMAGE_FILE_MACHINE_I386;
- stack.AddrPC.Offset = ctx.Eip;
- stack.AddrPC.Mode = AddrModeFlat;
- stack.AddrFrame.Offset = ctx.Ebp;
- stack.AddrFrame.Mode = AddrModeFlat;
- stack.AddrStack.Offset = ctx.Esp;
- stack.AddrStack.Mode = AddrModeFlat;
- #elif defined(_M_X64)
- mtype = IMAGE_FILE_MACHINE_AMD64;
- stack.AddrPC.Offset = ctx.Rip;
- stack.AddrPC.Mode = AddrModeFlat;
- stack.AddrFrame.Offset = ctx.Rsp;
- stack.AddrFrame.Mode = AddrModeFlat;
- stack.AddrStack.Offset = ctx.Rsp;
- stack.AddrStack.Mode = AddrModeFlat;
- #else
- #error Unknown Windows Platform
- #endif
-
- DWORD ldsp = 0;
- IMAGEHLP_LINE64 line = {};
- line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
-
- char buf[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME * sizeof(TCHAR))];
-
- SYMBOL_INFO* sym = reinterpret_cast<SYMBOL_INFO*>(buf);
- sym->SizeOfStruct = sizeof(SYMBOL_INFO);
- sym->MaxNameLen = MAX_SYM_NAME;
-
- UINT layer_count = 0;
- while (StackWalk64(mtype,
- GetCurrentProcess(), GetCurrentThread(),
- &stack, &ctx, nullptr,
- SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
- {
- if (stack.AddrPC.Offset == 0)
- break;
-
- BOOL result = SymGetLineFromAddr64(GetCurrentProcess(), stack.AddrPC.Offset, &ldsp, &line);
- result = result && SymFromAddr(GetCurrentProcess(), stack.AddrPC.Offset, 0, sym);
-
- if (result)
- {
- fprintf(out_stream,
- "\t[%u] `%s` (%s:%d)\n",
- layer_count, sym->Name, line.FileName, line.LineNumber);
- }
- else
- {
- fprintf(out_stream,
- "\t[%u] 0x%p\n",
- layer_count, stack.AddrPC.Offset);
- }
-
- layer_count++;
- }
-
- SymCleanup(GetCurrentProcess());
- }
- #endif
-#else
- #error gb__print_call_stack() not implemeneted
- // TODO(bill): Implemenet gb__print_call_stack()
-#endif
-
-// Helper function used as a better alternative to assert which allows for
-// optional printf style error messages
-inline void
-gb__assert_handler(bool condition, char const* condition_str,
- char const* filename, size_t line,
- char const* error_text, ...)
-{
- if (condition)
- return;
-
-#if !defined(GB_NO_STDIO)
- FILE* out_stream = stderr;
-
- fprintf(out_stream, "ASSERT! %s(%lu): %s", filename, line, condition_str);
- if (error_text)
- {
- fprintf(out_stream, " - ");
-
- va_list args;
- va_start(args, error_text);
- vfprintf(out_stream, error_text, args);
- va_end(args);
- }
- fprintf(out_stream, "\n");
-
- fprintf(out_stream, "Stacktrack:\n");
- gb__print_call_stack(out_stream);
-#endif
-
- // TODO(bill): Are these decent breaking functions???
-#if defined(GB_COMPILER_MSVC)
- __debugbreak();
-#elif defined(GB_COMPILER_GNU_GCC)
- __builtin_trap();
-#else
- #error Implement aborting function
-#endif
-}
-
-
-
-__GB_NAMESPACE_START
-
-////////////////////////////////
-// //
-// Memory //
-// //
-////////////////////////////////
-
-namespace mutex
-{
-inline Mutex
-make()
-{
- Mutex m = {};
-#if defined(GB_SYSTEM_WINDOWS)
- m.win32_mutex = CreateMutex(0, false, 0);
-#else
- pthread_mutex_init(&m.posix_mutex, nullptr);
-#endif
- return m;
-}
-
-inline void
-destroy(Mutex* m)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- CloseHandle(m->win32_mutex);
-#else
- pthread_mutex_destroy(&m->posix_mutex);
-#endif
-}
-
-
-inline void
-lock(Mutex* m)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- WaitForSingleObject(m->win32_mutex, INFINITE);
-#else
- pthread_mutex_lock(&m->posix_mutex);
-#endif
-}
-
-inline bool
-try_lock(Mutex* m)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- return WaitForSingleObject(m->win32_mutex, 0) == WAIT_OBJECT_0;
-#else
- return pthread_mutex_trylock(&m->posix_mutex) == 0;
-#endif
-}
-
-
-inline void
-unlock(Mutex* m)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- ReleaseMutex(m->win32_mutex);
-#else
- pthread_mutex_unlock(&m->posix_mutex);
-#endif
-}
-} // namespace mutex
-
-
-
-
-
-// Atomics
-namespace atomic
-{
-#if defined(_MSC_VER)
-inline u32
-load(Atomic32 const volatile* object)
-{
- return object->nonatomic;
-}
-
-inline void
-store(Atomic32 volatile* object, u32 value)
-{
- object->nonatomic = value;
-}
-
-inline u32
-compare_exchange_strong(Atomic32 volatile* object, u32 expected, u32 desired)
-{
- return _InterlockedCompareExchange(reinterpret_cast<long volatile*>(object), desired, expected);
-}
-
-inline u32
-exchanged(Atomic32 volatile* object, u32 desired)
-{
- return _InterlockedExchange(reinterpret_cast<long volatile*>(object), desired);
-}
-
-inline u32
-fetch_add(Atomic32 volatile* object, s32 operand)
-{
- return _InterlockedExchangeAdd(reinterpret_cast<long volatile*>(object), operand);
-}
-
-inline u32
-fetch_and(Atomic32 volatile* object, u32 operand)
-{
- return _InterlockedAnd(reinterpret_cast<long volatile*>(object), operand);
-}
-
-inline u32
-fetch_or_32(Atomic32 volatile* object, u32 operand)
-{
- return _InterlockedOr(reinterpret_cast<long volatile*>(object), operand);
-}
-
-inline u64
-load(Atomic64 const volatile* object)
-{
-#if defined(GB_ARCH_64_BIT)
- return object->nonatomic;
-#else
- // NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b
- u64 result;
- __asm
- {
- mov esi, object;
- mov ebx, eax;
- mov ecx, edx;
- lock cmpxchg8b [esi];
- mov dword ptr result, eax;
- mov dword ptr result[4], edx;
- }
- return result;
-#endif
-}
-
-inline void
-store(Atomic64 volatile* object, u64 value)
-{
-#if defined(GB_ARCH_64_BIT)
- object->nonatomic = value;
-#else
- // NOTE(bill): The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b
- __asm
- {
- mov esi, object;
- mov ebx, dword ptr value;
- mov ecx, dword ptr value[4];
- retry:
- cmpxchg8b [esi];
- jne retry;
- }
-#endif
-}
-
-inline u64
-compare_exchange_strong(Atomic64 volatile* object, u64 expected, u64 desired)
-{
- return _InterlockedCompareExchange64(reinterpret_cast<s64 volatile*>(object), desired, expected);
-}
-
-inline u64
-exchanged(Atomic64 volatile* object, u64 desired)
-{
-#if defined(GB_ARCH_64_BIT)
- return _InterlockedExchange64(reinterpret_cast<s64 volatile*>(object), desired);
-#else
- u64 expected = object->nonatomic;
- while (true)
- {
- u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64 volatile*>(object), desired, expected);
- if (original == expected)
- return original;
- expected = original;
- }
-#endif
-}
-
-inline u64
-fetch_add(Atomic64 volatile* object, s64 operand)
-{
-#if defined(GB_ARCH_64_BIT)
- return _InterlockedExchangeAdd64(reinterpret_cast<s64 volatile*>(object), operand);
-#else
- u64 expected = object->nonatomic;
- while (true)
- {
- u64 original = _InterlockedExchange64(reinterpret_cast<s64 volatile*>(object), expected + operand, expected);
- if (original == expected)
- return original;
- expected = original;
- }
-#endif
-}
-
-inline u64
-fetch_and(Atomic64 volatile* object, u64 operand)
-{
-#if defined(GB_ARCH_64_BIT)
- return _InterlockedAnd64(reinterpret_cast<s64 volatile*>(object), operand);
-#else
- u64 expected = object->nonatomic;
- while (true)
- {
- u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64 volatile*>(object), expected & operand, expected);
- if (original == expected)
- return original;
- expected = original;
- }
-#endif
-}
-
-inline u64
-fetch_or(Atomic64 volatile* object, u64 operand)
-{
-#if defined(GB_ARCH_64_BIT)
- return _InterlockedAnd64(reinterpret_cast<s64 volatile*>(object), operand);
-#else
- u64 expected = object->nonatomic;
- while (true)
- {
- u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64 volatile*>(object), expected | operand, expected);
- if (original == expected)
- return original;
- expected = original;
- }
-#endif
-}
-
-#else
-#error TODO(bill): Implement atomics for this platform
-#endif
-} // namespace atomic
-
-
-
-
-namespace semaphore
-{
-Semaphore
-make()
-{
- Semaphore semaphore = {};
-#if defined(GB_SYSTEM_WINDOWS)
- semaphore.win32_handle = CreateSemaphore(nullptr, 0, GB_S32_MAX, nullptr);
-
- GB_ASSERT(semaphore.win32_handle != nullptr, "CreateSemaphore: GetLastError = %d", GetLastError());
-
-#else
- semaphore.count = 0;
- s32 result = pthread_cond_init(&semaphore.cond, nullptr);
- GB_ASSERT(result == 0, "pthread_cond_init: errno = %d", result);
-
- semaphore.mutex = mutex::make();
-#endif
-
- return semaphore;
-}
-
-void
-destroy(Semaphore* semaphore)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- BOOL err = CloseHandle(semaphore->win32_handle);
- GB_ASSERT(err != 0, "CloseHandle: GetLastError = %d", GetLastError());
-#else
- s32 result = pthread_cond_destroy(&semaphore->cond);
- GB_ASSERT(result == 0, "pthread_cond_destroy: errno = %d", result);
- mutex::destroy(&semaphore->mutex);
-#endif
-}
-
-void
-post(Semaphore* semaphore, u32 count)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- BOOL err = ReleaseSemaphore(semaphore->win32_handle, count, nullptr);
- GB_ASSERT(err != 0, "ReleaseSemaphore: GetLastError = %d", GetLastError());
-#else
- mutex::lock(&semaphore->mutex);
-
- for (u32 i = 0; i < count; i++)
- {
- s32 result = pthread_cond_signal(&semaphore->cond);
- GB_ASSERT(result == 0, "pthread_cond_signal: errno = %d", result);
- }
-
- semaphore->count += count;
-
- mutex::unlock(&semaphore->mutex);
-#endif
-}
-
-void
-wait(Semaphore* semaphore)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- DWORD result = WaitForSingleObject(semaphore->win32_handle, INFINITE);
- GB_ASSERT(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError = %d", GetLastError());
-#else
- mutex::lock(&semaphore->mutex);
-
- while (count <= 0)
- {
- s32 result = pthread_cond_wait(&semaphore->cond, &semaphore->mutex.posix_mutex);
- GB_ASSERT(result == 0, "pthread_cond_wait: errno = %d", result);
- }
-
- count--;
-
- mutex::unlock(&semaphore->mutex);
-#endif
-}
-} // namespace semaphore
-
-namespace thread
-{
-Thread
-make()
-{
- Thread t = {};
-#if defined(GB_SYSTEM_WINDOWS)
- t.win32_handle = INVALID_HANDLE_VALUE;
-#else
- t.posix_handle = 0;
-#endif
- t.function = nullptr;
- t.data = nullptr;
- t.stack_size = 0;
- t.is_running = false;
- t.semaphore = semaphore::make();
-
- return t;
-}
-
-void
-destroy(Thread* t)
-{
- if (t->is_running)
- thread::join(t);
-
- semaphore::destroy(&t->semaphore);
-}
-
-internal_linkage void
-run(Thread* t)
-{
- semaphore::post(&t->semaphore);
- t->function(t->data);
-}
-
-#if defined(GB_SYSTEM_WINDOWS)
-internal_linkage DWORD WINAPI
-thread_proc(void* arg)
-{
- thread::run(static_cast<Thread*>(arg));
- return 0;
-}
-
-#else
-internal_linkage void*
-thread_proc(void* arg)
-{
- thread::run(static_cast<Thread*>(arg));
- return nullptr;
-}
-#endif
-
-void
-start(Thread* t, Thread_Procedure* func, void* data, usize stack_size)
-{
- GB_ASSERT(!t->is_running);
- GB_ASSERT(func != nullptr);
- t->function = func;
- t->data = data;
- t->stack_size = stack_size;
-
-#if defined(GB_SYSTEM_WINDOWS)
- t->win32_handle = CreateThread(nullptr, stack_size, thread_proc, t, 0, nullptr);
- GB_ASSERT(t->win32_handle != nullptr,
- "CreateThread: GetLastError = %d", GetLastError());
-
-#else
- pthread_attr_t attr;
- s32 result = pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- GB_ASSERT(result == 0, "pthread_attr_init: errno = %d", result);
-
- if (t->stack_size != 0)
- {
- result = pthread_attr_setstacksize(&attr, t->stack_size);
- GB_ASSERT(result == 0, "pthread_attr_setstacksize: errno = %d", result);
- }
-
- result = pthread_create(&t->posix_handle, &attr, thread_proc, thread);
- GB_ASSERT(result == 0, "pthread_create: errno = %d", result);
-
- // NOTE(bill): Free attr memory
- result = pthread_attr_destroy(&attr);
- GB_ASSERT(result == 0, "pthread_attr_destroy: errno = %d", result);
-
- // NOTE(bill): So much boiler patch compared to windows.h (for once)
-#endif
-
- t->is_running = true;
- semaphore::wait(&t->semaphore);
-}
-
-void
-join(Thread* t)
-{
- if (!t->is_running) return;
-
-#if defined(GB_SYSTEM_WINDOWS)
- WaitForSingleObject(t->win32_handle, INFINITE);
- CloseHandle(t->win32_handle);
- t->win32_handle = INVALID_HANDLE_VALUE;
-#else
- int result = pthread_join(t->posix_handle, nullptr);
- t->posix_handle = 0;
-#endif
-
- t->is_running = false;
-}
-
-inline bool
-is_running(Thread const& thread)
-{
- return thread.is_running != 0;
-}
-
-inline u32
-current_id()
-{
- u32 thread_id;
-
-#if defined(GB_SYSTEM_WINDOWS)
- u8* thread_local_storage = reinterpret_cast<u8*>(__readgsqword(0x30));
- thread_id = *reinterpret_cast<u32*>(thread_local_storage + 0x48);
-
-#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
- asm("mov %%gs:0x00,%0" : "=r"(thread_id));
-#elif defined(GB_ARCH_32_BIT)
- asm("mov %%gs:0x08,%0" : "=r"(thread_id));
-#elif defined(GB_ARCH_64_BIT)
- asm("mov %%gs:0x10,%0" : "=r"(thread_id));
-#else
- #error Unsupported architecture for thread::current_id()
-#endif
-
- return thread_id;
-}
-
-
-} // namespace thread
-
-
-namespace heap
-{
-namespace functions
-{
-internal_linkage void*
-alloc(Allocator* a, usize size, usize align)
-{
- Heap* heap = reinterpret_cast<Heap*>(a);
-
- if (heap->use_mutex) mutex::lock(&heap->mutex);
-
- usize total = size + align - (size % align);
-
-#if defined (GB_SYSTEM_WINDOWS)
- total += sizeof(Heap::Header);
-
- void* data = HeapAlloc(heap->win32_heap_handle, 0, total);
-
- Heap::Header* h = static_cast<Heap::Header*>(data);
- h->size = total;
- data = (h + 1);
-
-#else
- // TODO(bill): Find a better malloc alternative for this platform
- void* data = malloc(total);
-#endif
-
- heap->total_allocated_count += total;
- heap->allocation_count++;
-
- if (heap->use_mutex) mutex::unlock(&heap->mutex);
-
- return data;
-}
-
-internal_linkage void
-free(Allocator* a, void* ptr)
-{
- if (!ptr)
- return;
-
- Heap* heap = reinterpret_cast<Heap*>(a);
-
- if (heap->use_mutex) mutex::lock(&heap->mutex);
-
- heap->total_allocated_count -= allocated_size(heap, ptr);
- heap->allocation_count--;
-
-#if defined (GB_SYSTEM_WINDOWS)
- auto* header = static_cast<Heap::Header*>(ptr) - 1;
- HeapFree(heap->win32_heap_handle, 0, header);
-#else
- ::free(ptr);
-#endif
-
- if (heap->use_mutex) mutex::unlock(&heap->mutex);
-}
-
-inline s64
-allocated_size(Allocator* a, void const* ptr)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- auto* heap = reinterpret_cast<Heap*>(a);
-
- if (heap->use_mutex) mutex::lock(&heap->mutex);
-
- auto const* h = static_cast<Heap::Header const*>(ptr) - 1;
- s64 result = h->size;
-
- if (heap->use_mutex) mutex::unlock(&heap->mutex);
-
- return static_cast<s64>(result);
-
-#elif defined(GB_SYSTEM_OSX)
- return static_cast<s64>(malloc_size(ptr));
-
-#elif defined(GB_SYSTEM_LINUX)
- return static_cast<s64>(malloc_usable_size(ptr));
-
-#else
- #error Implement Heap::allocated_size
-#endif
-}
-
-inline s64
-total_allocated(Allocator* a)
-{
- auto* heap = reinterpret_cast<Heap*>(a);
-
- if (heap->use_mutex) mutex::lock(&heap->mutex);
-
- s64 result = heap->total_allocated_count;
-
- if (heap->use_mutex) mutex::unlock(&heap->mutex);
-
- return result;
-}
-} // namespace functions
-
-Heap
-make(bool use_mutex)
-{
- Heap heap = {};
-
- heap.use_mutex = use_mutex;
- if (use_mutex) heap.mutex = mutex::make();
-
-#if defined(GB_SYSTEM_WINDOWS)
- heap.win32_heap_handle = HeapCreate(0, 0, 0);
-#endif
-
- heap.alloc = functions::alloc;
- heap.free = functions::free;
- heap.allocated_size = functions::allocated_size;
- heap.total_allocated = functions::total_allocated;
-
- return heap;
-}
-void
-destroy(Heap* heap)
-{
- if (heap->use_mutex) mutex::destroy(&heap->mutex);
-
-#if defined (GB_SYSTEM_WINDOWS)
- HeapDestroy(heap->win32_heap_handle);
-#endif
-}
-} // namespace heap
-
-
-namespace arena
-{
-namespace functions
-{
-internal_linkage void*
-alloc(Allocator* a, usize size, usize align)
-{
- Arena* arena = reinterpret_cast<Arena*>(a);
-
- s64 actual_size = size + align;
-
- if (arena->total_allocated_count + actual_size > arena->total_size)
- {
- GB_ASSERT(arena->total_allocated_count + actual_size <= arena->total_size,
- "Arena has no more space for allocation");
- return nullptr;
- }
-
- void* ptr = memory::align_forward(memory::pointer_add(arena->physical_start, arena->total_allocated_count), align);
-
- arena->total_allocated_count += actual_size;
-
- return ptr;
-}
-
-inline void free(Allocator*, void*) {} // NOTE(bill): Arenas free all at once
-
-inline s64 allocated_size(Allocator*, void const*) { return -1; }
-
-inline s64
-total_allocated(Allocator* a)
-{
- return reinterpret_cast<Arena*>(a)->total_allocated_count;
-}
-} // namespace functions
-
-Arena
-make(Allocator* backing, usize size)
-{
- Arena arena = {};
-
- arena.backing = backing;
- arena.physical_start = nullptr;
- arena.total_size = size;
- arena.temp_count = 0;
- arena.total_allocated_count = 0;
-
- arena.physical_start = alloc(arena.backing, size);
-
- arena.alloc = functions::alloc;
- arena.free = functions::free;
- arena.allocated_size = functions::allocated_size;
- arena.total_allocated = functions::total_allocated;
-
- return arena;
-}
-
-Arena
-make(void* start, usize size)
-{
- Arena arena = {};
-
- arena.backing = nullptr;
- arena.physical_start = start;
- arena.total_size = size;
- arena.temp_count = 0;
- arena.total_allocated_count = 0;
-
- arena.alloc = functions::alloc;
- arena.free = functions::free;
- arena.allocated_size = functions::allocated_size;
- arena.total_allocated = functions::total_allocated;
-
- return arena;
-}
-
-void
-destroy(Arena* arena)
-{
- if (arena->backing)
- free(arena->backing, arena->physical_start);
-
- clear(arena);
-}
-
-inline void
-clear(Arena* arena)
-{
- GB_ASSERT(arena->temp_count == 0,
- "%ld Temporary_Arena_Memory have not be cleared", arena->temp_count);
-
- arena->total_allocated_count = 0;
-}
-} // namespace arena
-
-
-namespace temporary_arena_memory
-{
-inline Temporary_Arena_Memory
-make(Arena* arena)
-{
- Temporary_Arena_Memory tmp = {};
- tmp.arena = arena;
- tmp.original_count = arena->total_allocated_count;
- arena->temp_count++;
- return tmp;
-}
-
-inline void
-free(Temporary_Arena_Memory tmp)
-{
- GB_ASSERT(total_allocated(tmp.arena) >= tmp.original_count);
- tmp.arena->total_allocated_count = tmp.original_count;
- GB_ASSERT(tmp.arena->temp_count > 0);
- tmp.arena->temp_count--;
-}
-} // namespace temporary_arena_memory
-
-
-
-
-namespace pool
-{
-namespace functions
-{
-internal_linkage void*
-alloc(Allocator* a, usize size, usize align)
-{
- Pool* pool = reinterpret_cast<Pool*>(a);
-
- GB_ASSERT(size == pool->block_size, "Size must match block size");
- GB_ASSERT(align == pool->block_align, "Align must match block align");
- GB_ASSERT(pool->free_list != nullptr, "Pool out of memory");
-
- uintptr next_free = *reinterpret_cast<uintptr*>(pool->free_list);
- void* ptr = pool->free_list;
- pool->free_list = reinterpret_cast<void*>(next_free);
-
- pool->total_size += pool->block_size;
-
- return ptr;
-}
-
-internal_linkage void
-free(Allocator* a, void* ptr)
-{
- if (!ptr) return;
-
- Pool* pool = reinterpret_cast<Pool*>(a);
-
- uintptr* next = static_cast<uintptr*>(ptr);
- *next = reinterpret_cast<uintptr>(pool->free_list);
-
- pool->free_list = ptr;
-
- pool->total_size -= pool->block_size;
-}
-
-internal_linkage s64
-allocated_size(Allocator*, void const*)
-{
- return -1;
-}
-
-internal_linkage s64
-total_allocated(Allocator* a)
-{
- Pool* pool = reinterpret_cast<Pool*>(a);
- return pool->total_size;
-}
-} // namespace functions
-
-
-Pool
-make(Allocator* backing, usize num_blocks, usize block_size, usize block_align)
-{
- Pool pool = {};
-
- pool.backing = backing;
- pool.block_size = block_size;
- pool.block_align = block_align;
-
- usize actual_block_size = block_size + block_align;
- usize pool_size = num_blocks * actual_block_size;
-
- u8* data = static_cast<u8*>(alloc(backing, pool_size, block_align));
-
-
- // Init intrusive freelist
- u8* curr = data;
- for (usize block_index = 0; block_index < num_blocks-1; block_index++)
- {
- uintptr* next = reinterpret_cast<uintptr*>(curr);
- *next = reinterpret_cast<uintptr>(curr) + actual_block_size;
- curr += actual_block_size;
- }
-
- uintptr* end = reinterpret_cast<uintptr*>(curr);
- *end = reinterpret_cast<uintptr>(nullptr);
-
- pool.physical_start = data;
- pool.free_list = data;
-
- // Set functions pointers
- pool.alloc = functions::alloc;
- pool.free = functions::free;
- pool.allocated_size = functions::allocated_size;
- pool.total_allocated = functions::total_allocated;
-
- return pool;
-}
-
-inline void
-destroy(Pool* pool)
-{
- free(pool->backing, pool->physical_start);
-}
-} // namespace pool
-
-
-
-
-
-
-////////////////////////////////
-// //
-// Memory //
-// //
-////////////////////////////////
-
-namespace memory
-{
-inline void*
-align_forward(void* ptr, usize align)
-{
- GB_ASSERT(GB_IS_POWER_OF_TWO(align),
- "Alignment must be a power of two and not zero -- %llu", align);
-
- uintptr p = uintptr(ptr);
- const usize modulo = p % align;
- if (modulo) p += (align - modulo);
- return reinterpret_cast<void*>(p);
-}
-
-inline void*
-pointer_add(void* ptr, usize bytes)
-{
- return static_cast<void*>(static_cast<u8*>(ptr) + bytes);
-}
-
-inline void const*
-pointer_add(void const* ptr, usize bytes)
-{
- return static_cast<void const*>(static_cast<u8 const*>(ptr) + bytes);
-}
-
-inline void*
-pointer_sub(void* ptr, usize bytes)
-{
- return static_cast<void*>(static_cast<u8*>(ptr) - bytes);
-}
-
-inline void const*
-pointer_sub(void const* ptr, usize bytes)
-{
- return static_cast<void const*>(static_cast<u8 const*>(ptr) - bytes);
-}
-
-
-GB_FORCE_INLINE void
-zero(void* ptr, usize bytes)
-{
- memset(ptr, 0, bytes);
-}
-
-GB_FORCE_INLINE void
-copy(void const* src, usize bytes, void* dest)
-{
- memcpy(dest, src, bytes);
-}
-
-GB_FORCE_INLINE void
-move(void const* src, usize bytes, void* dest)
-{
- memmove(dest, src, bytes);
-}
-
-GB_FORCE_INLINE bool
-equals(void const* a, void const* b, usize bytes)
-{
- return (memcmp(a, b, bytes) == 0);
-}
-} // namespace memory
-
-inline void*
-alloc(Allocator* a, usize size, usize align)
-{
- GB_ASSERT(a != nullptr);
- return a->alloc(a, size, align);
-}
-
-inline void
-free(Allocator* a, void* ptr)
-{
- GB_ASSERT(a != nullptr);
- if (ptr) a->free(a, ptr);
-}
-
-inline s64
-allocated_size(Allocator* a, void const* ptr)
-{
- GB_ASSERT(a != nullptr);
- return a->allocated_size(a, ptr);
-}
-
-inline s64
-total_allocated(Allocator* a)
-{
- GB_ASSERT(a != nullptr);
- return a->total_allocated(a);
-}
-
-////////////////////////////////
-// //
-// String //
-// //
-////////////////////////////////
-
-namespace string
-{
-inline String
-make(Allocator* a, char const* str)
-{
- return string::make(a, str, (string::Size)strlen(str));
-}
-
-String
-make(Allocator* a, void const* init_str, Size len)
-{
- usize header_size = sizeof(string::Header);
- void* ptr = alloc(a, header_size + len + 1);
- if (!ptr) return nullptr;
-
- if (!init_str) memory::zero(ptr, header_size + len + 1);
-
- String str = static_cast<char*>(ptr) + header_size;
-
- string::Header* header = string::header(str);
- header->allocator = a;
- header->length = len;
- header->capacity = len;
-
- if (len && init_str)
- memory::copy(init_str, len, str);
- str[len] = '\0';
-
- return str;
-}
-
-inline void
-free(String str)
-{
- if (str == nullptr) return;
-
- string::Header* h = string::header(str);
-
- if (h->allocator) free(h->allocator, h);
-}
-
-inline String
-duplicate(Allocator* a, String const str)
-{
- return string::make(a, str, string::length(str));
-}
-
-inline Size
-length(String const str)
-{
- return string::header(str)->length;
-}
-
-inline Size
-capacity(String const str)
-{
- return string::header(str)->capacity;
-}
-
-inline Size
-available_space(String const str)
-{
- string::Header* h = string::header(str);
- if (h->capacity > h->length)
- return h->capacity - h->length;
- return 0;
-}
-
-inline void
-clear(String str)
-{
- string::header(str)->length = 0;
- str[0] = '\0';
-}
-
-void
-append(String* str, char c)
-{
- Size curr_len = string::length(*str);
-
- string::make_space_for(str, 1);
- if (str == nullptr) return;
-
- (*str)[curr_len] = c;
- (*str)[curr_len + 1] = '\0';
- string::header(*str)->length = curr_len + 1;
-}
-
-inline void
-append(String* str, String const other)
-{
- string::append(str, other, string::length(other));
-}
-
-inline void
-append_cstring(String* str, char const* other)
-{
- string::append(str, other, (Size)strlen(other));
-}
-
-void
-append(String* str, void const* other, Size other_len)
-{
- Size curr_len = string::length(*str);
-
- string::make_space_for(str, other_len);
- if (str == nullptr)
- return;
-
- memory::copy(other, other_len, (*str) + curr_len);
- (*str)[curr_len + other_len] = '\0';
- string::header(*str)->length = curr_len + other_len;
-}
-
-namespace impl
-{
-// NOTE(bill): ptr _must_ be allocated with Allocator* a
-internal_linkage inline void*
-string_realloc(Allocator* a, void* ptr, usize old_size, usize new_size)
-{
- if (!ptr)
- return alloc(a, new_size);
-
- if (new_size < old_size)
- new_size = old_size;
-
- if (old_size == new_size)
- return ptr;
-
- void* new_ptr = alloc(a, new_size);
- if (!new_ptr)
- return nullptr;
-
- memory::copy(ptr, old_size, new_ptr);
-
- free(a, ptr);
-
- return new_ptr;
-}
-} // namespace impl
-
-void
-make_space_for(String* str, Size add_len)
-{
- Size len = string::length(*str);
- Size new_len = len + add_len;
-
- Size available = string::available_space(*str);
- if (available >= add_len) // Return if there is enough space left
- return;
-
- void* ptr = string::header(*str);
- usize old_size = sizeof(string::Header) + string::length(*str) + 1;
- usize new_size = sizeof(string::Header) + new_len + 1;
-
- Allocator* a = string::header(*str)->allocator;
- void* new_ptr = impl::string_realloc(a, ptr, old_size, new_size);
- if (new_ptr == nullptr)
- return;
-
- string::Header* header = static_cast<string::Header*>(new_ptr);
- header->allocator = a;
- header->length = len;
- header->capacity = new_len;
-
- *str = reinterpret_cast<String>(header + 1);
-}
-
-usize
-allocation_size(String const str)
-{
- Size cap = string::capacity(str);
- return sizeof(string::Header) + cap;
-}
-
-bool
-equals(String const lhs, String const rhs)
-{
- Size lhs_len = string::length(lhs);
- Size rhs_len = string::length(rhs);
- if (lhs_len != rhs_len)
- return false;
-
- for (Size i = 0; i < lhs_len; i++)
- {
- if (lhs[i] != rhs[i])
- return false;
- }
-
- return true;
-}
-
-int
-compare(String const lhs, String const rhs) // NOTE(bill): three-way comparison
-{
- // Treat as cstring
- char const* str1 = lhs;
- char const* str2 = rhs;
- int s1;
- int s2;
- do
- {
- s1 = *str1++;
- s2 = *str2++;
- if (s1 == 0)
- break;
- }
- while (s1 == s2);
-
- return (s1 < s2) ? -1 : (s1 > s2);
-}
-
-void
-trim(String* str, char const* cut_set)
-{
- char* start;
- char* end;
- char* start_pos;
- char* end_pos;
-
- start_pos = start = *str;
- end_pos = end = *str + string::length(*str) - 1;
-
- while (start_pos <= end && strchr(cut_set, *start_pos))
- start_pos++;
- while (end_pos > start_pos && strchr(cut_set, *end_pos))
- end_pos--;
-
- Size len = static_cast<Size>((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
-
- if (*str != start_pos)
- memory::move(start_pos, len, *str);
- (*str)[len] = '\0';
-
- string::header(*str)->length = len;
-}
-inline void
-trim_space(String* str)
-{
- trim(str, " \n\r\t\v\f");
-}
-} // namespace string
-
-
-
-
-
-
-
-
-
-////////////////////////////////
-// //
-// Hash //
-// //
-////////////////////////////////
-
-namespace hash
-{
-u32
-adler32(void const* key, u32 num_bytes)
-{
- const u32 MOD_ADLER = 65521;
-
- u32 a = 1;
- u32 b = 0;
-
- u8 const* bytes = static_cast<u8 const*>(key);
- for (u32 i = 0; i < num_bytes; i++)
- {
- a = (a + bytes[i]) % MOD_ADLER;
- b = (b + a) % MOD_ADLER;
- }
-
- return (b << 16) | a;
-}
-
-global_variable const u32 GB_CRC32_TABLE[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-global_variable const u64 GB_CRC64_TABLE[256] = {
- 0x0000000000000000ull, 0x42F0E1EBA9EA3693ull, 0x85E1C3D753D46D26ull, 0xC711223CFA3E5BB5ull,
- 0x493366450E42ECDFull, 0x0BC387AEA7A8DA4Cull, 0xCCD2A5925D9681F9ull, 0x8E224479F47CB76Aull,
- 0x9266CC8A1C85D9BEull, 0xD0962D61B56FEF2Dull, 0x17870F5D4F51B498ull, 0x5577EEB6E6BB820Bull,
- 0xDB55AACF12C73561ull, 0x99A54B24BB2D03F2ull, 0x5EB4691841135847ull, 0x1C4488F3E8F96ED4ull,
- 0x663D78FF90E185EFull, 0x24CD9914390BB37Cull, 0xE3DCBB28C335E8C9ull, 0xA12C5AC36ADFDE5Aull,
- 0x2F0E1EBA9EA36930ull, 0x6DFEFF5137495FA3ull, 0xAAEFDD6DCD770416ull, 0xE81F3C86649D3285ull,
- 0xF45BB4758C645C51ull, 0xB6AB559E258E6AC2ull, 0x71BA77A2DFB03177ull, 0x334A9649765A07E4ull,
- 0xBD68D2308226B08Eull, 0xFF9833DB2BCC861Dull, 0x388911E7D1F2DDA8ull, 0x7A79F00C7818EB3Bull,
- 0xCC7AF1FF21C30BDEull, 0x8E8A101488293D4Dull, 0x499B3228721766F8ull, 0x0B6BD3C3DBFD506Bull,
- 0x854997BA2F81E701ull, 0xC7B97651866BD192ull, 0x00A8546D7C558A27ull, 0x4258B586D5BFBCB4ull,
- 0x5E1C3D753D46D260ull, 0x1CECDC9E94ACE4F3ull, 0xDBFDFEA26E92BF46ull, 0x990D1F49C77889D5ull,
- 0x172F5B3033043EBFull, 0x55DFBADB9AEE082Cull, 0x92CE98E760D05399ull, 0xD03E790CC93A650Aull,
- 0xAA478900B1228E31ull, 0xE8B768EB18C8B8A2ull, 0x2FA64AD7E2F6E317ull, 0x6D56AB3C4B1CD584ull,
- 0xE374EF45BF6062EEull, 0xA1840EAE168A547Dull, 0x66952C92ECB40FC8ull, 0x2465CD79455E395Bull,
- 0x3821458AADA7578Full, 0x7AD1A461044D611Cull, 0xBDC0865DFE733AA9ull, 0xFF3067B657990C3Aull,
- 0x711223CFA3E5BB50ull, 0x33E2C2240A0F8DC3ull, 0xF4F3E018F031D676ull, 0xB60301F359DBE0E5ull,
- 0xDA050215EA6C212Full, 0x98F5E3FE438617BCull, 0x5FE4C1C2B9B84C09ull, 0x1D14202910527A9Aull,
- 0x93366450E42ECDF0ull, 0xD1C685BB4DC4FB63ull, 0x16D7A787B7FAA0D6ull, 0x5427466C1E109645ull,
- 0x4863CE9FF6E9F891ull, 0x0A932F745F03CE02ull, 0xCD820D48A53D95B7ull, 0x8F72ECA30CD7A324ull,
- 0x0150A8DAF8AB144Eull, 0x43A04931514122DDull, 0x84B16B0DAB7F7968ull, 0xC6418AE602954FFBull,
- 0xBC387AEA7A8DA4C0ull, 0xFEC89B01D3679253ull, 0x39D9B93D2959C9E6ull, 0x7B2958D680B3FF75ull,
- 0xF50B1CAF74CF481Full, 0xB7FBFD44DD257E8Cull, 0x70EADF78271B2539ull, 0x321A3E938EF113AAull,
- 0x2E5EB66066087D7Eull, 0x6CAE578BCFE24BEDull, 0xABBF75B735DC1058ull, 0xE94F945C9C3626CBull,
- 0x676DD025684A91A1ull, 0x259D31CEC1A0A732ull, 0xE28C13F23B9EFC87ull, 0xA07CF2199274CA14ull,
- 0x167FF3EACBAF2AF1ull, 0x548F120162451C62ull, 0x939E303D987B47D7ull, 0xD16ED1D631917144ull,
- 0x5F4C95AFC5EDC62Eull, 0x1DBC74446C07F0BDull, 0xDAAD56789639AB08ull, 0x985DB7933FD39D9Bull,
- 0x84193F60D72AF34Full, 0xC6E9DE8B7EC0C5DCull, 0x01F8FCB784FE9E69ull, 0x43081D5C2D14A8FAull,
- 0xCD2A5925D9681F90ull, 0x8FDAB8CE70822903ull, 0x48CB9AF28ABC72B6ull, 0x0A3B7B1923564425ull,
- 0x70428B155B4EAF1Eull, 0x32B26AFEF2A4998Dull, 0xF5A348C2089AC238ull, 0xB753A929A170F4ABull,
- 0x3971ED50550C43C1ull, 0x7B810CBBFCE67552ull, 0xBC902E8706D82EE7ull, 0xFE60CF6CAF321874ull,
- 0xE224479F47CB76A0ull, 0xA0D4A674EE214033ull, 0x67C58448141F1B86ull, 0x253565A3BDF52D15ull,
- 0xAB1721DA49899A7Full, 0xE9E7C031E063ACECull, 0x2EF6E20D1A5DF759ull, 0x6C0603E6B3B7C1CAull,
- 0xF6FAE5C07D3274CDull, 0xB40A042BD4D8425Eull, 0x731B26172EE619EBull, 0x31EBC7FC870C2F78ull,
- 0xBFC9838573709812ull, 0xFD39626EDA9AAE81ull, 0x3A28405220A4F534ull, 0x78D8A1B9894EC3A7ull,
- 0x649C294A61B7AD73ull, 0x266CC8A1C85D9BE0ull, 0xE17DEA9D3263C055ull, 0xA38D0B769B89F6C6ull,
- 0x2DAF4F0F6FF541ACull, 0x6F5FAEE4C61F773Full, 0xA84E8CD83C212C8Aull, 0xEABE6D3395CB1A19ull,
- 0x90C79D3FEDD3F122ull, 0xD2377CD44439C7B1ull, 0x15265EE8BE079C04ull, 0x57D6BF0317EDAA97ull,
- 0xD9F4FB7AE3911DFDull, 0x9B041A914A7B2B6Eull, 0x5C1538ADB04570DBull, 0x1EE5D94619AF4648ull,
- 0x02A151B5F156289Cull, 0x4051B05E58BC1E0Full, 0x87409262A28245BAull, 0xC5B073890B687329ull,
- 0x4B9237F0FF14C443ull, 0x0962D61B56FEF2D0ull, 0xCE73F427ACC0A965ull, 0x8C8315CC052A9FF6ull,
- 0x3A80143F5CF17F13ull, 0x7870F5D4F51B4980ull, 0xBF61D7E80F251235ull, 0xFD913603A6CF24A6ull,
- 0x73B3727A52B393CCull, 0x31439391FB59A55Full, 0xF652B1AD0167FEEAull, 0xB4A25046A88DC879ull,
- 0xA8E6D8B54074A6ADull, 0xEA16395EE99E903Eull, 0x2D071B6213A0CB8Bull, 0x6FF7FA89BA4AFD18ull,
- 0xE1D5BEF04E364A72ull, 0xA3255F1BE7DC7CE1ull, 0x64347D271DE22754ull, 0x26C49CCCB40811C7ull,
- 0x5CBD6CC0CC10FAFCull, 0x1E4D8D2B65FACC6Full, 0xD95CAF179FC497DAull, 0x9BAC4EFC362EA149ull,
- 0x158E0A85C2521623ull, 0x577EEB6E6BB820B0ull, 0x906FC95291867B05ull, 0xD29F28B9386C4D96ull,
- 0xCEDBA04AD0952342ull, 0x8C2B41A1797F15D1ull, 0x4B3A639D83414E64ull, 0x09CA82762AAB78F7ull,
- 0x87E8C60FDED7CF9Dull, 0xC51827E4773DF90Eull, 0x020905D88D03A2BBull, 0x40F9E43324E99428ull,
- 0x2CFFE7D5975E55E2ull, 0x6E0F063E3EB46371ull, 0xA91E2402C48A38C4ull, 0xEBEEC5E96D600E57ull,
- 0x65CC8190991CB93Dull, 0x273C607B30F68FAEull, 0xE02D4247CAC8D41Bull, 0xA2DDA3AC6322E288ull,
- 0xBE992B5F8BDB8C5Cull, 0xFC69CAB42231BACFull, 0x3B78E888D80FE17Aull, 0x7988096371E5D7E9ull,
- 0xF7AA4D1A85996083ull, 0xB55AACF12C735610ull, 0x724B8ECDD64D0DA5ull, 0x30BB6F267FA73B36ull,
- 0x4AC29F2A07BFD00Dull, 0x08327EC1AE55E69Eull, 0xCF235CFD546BBD2Bull, 0x8DD3BD16FD818BB8ull,
- 0x03F1F96F09FD3CD2ull, 0x41011884A0170A41ull, 0x86103AB85A2951F4ull, 0xC4E0DB53F3C36767ull,
- 0xD8A453A01B3A09B3ull, 0x9A54B24BB2D03F20ull, 0x5D45907748EE6495ull, 0x1FB5719CE1045206ull,
- 0x919735E51578E56Cull, 0xD367D40EBC92D3FFull, 0x1476F63246AC884Aull, 0x568617D9EF46BED9ull,
- 0xE085162AB69D5E3Cull, 0xA275F7C11F7768AFull, 0x6564D5FDE549331Aull, 0x279434164CA30589ull,
- 0xA9B6706FB8DFB2E3ull, 0xEB46918411358470ull, 0x2C57B3B8EB0BDFC5ull, 0x6EA7525342E1E956ull,
- 0x72E3DAA0AA188782ull, 0x30133B4B03F2B111ull, 0xF7021977F9CCEAA4ull, 0xB5F2F89C5026DC37ull,
- 0x3BD0BCE5A45A6B5Dull, 0x79205D0E0DB05DCEull, 0xBE317F32F78E067Bull, 0xFCC19ED95E6430E8ull,
- 0x86B86ED5267CDBD3ull, 0xC4488F3E8F96ED40ull, 0x0359AD0275A8B6F5ull, 0x41A94CE9DC428066ull,
- 0xCF8B0890283E370Cull, 0x8D7BE97B81D4019Full, 0x4A6ACB477BEA5A2Aull, 0x089A2AACD2006CB9ull,
- 0x14DEA25F3AF9026Dull, 0x562E43B4931334FEull, 0x913F6188692D6F4Bull, 0xD3CF8063C0C759D8ull,
- 0x5DEDC41A34BBEEB2ull, 0x1F1D25F19D51D821ull, 0xD80C07CD676F8394ull, 0x9AFCE626CE85B507ull,
-};
-
-
-u32
-crc32(void const* key, u32 num_bytes)
-{
- u32 result = static_cast<u32>(~0);
- u8 const* c = reinterpret_cast<u8 const*>(key);
-
- for (u32 remaining = num_bytes; remaining--; c++)
- result = (result >> 8) ^ (GB_CRC32_TABLE[(result ^ *c) & 0xff]);
-
- return ~result;
-}
-
-u64
-crc64(void const* key, usize num_bytes)
-{
- u64 result = static_cast<u64>(~0);
- u8 const* c = reinterpret_cast<u8 const*>(key);
- for (usize remaining = num_bytes; remaining--; c++)
- result = (result >> 8) ^ (GB_CRC64_TABLE[(result ^ *c) & 0xff]);
-
- return ~result;
-}
-
-inline u32
-fnv32(void const* key, usize num_bytes)
-{
- u32 h = 0x811c9dc5;
- u8 const* buffer = static_cast<u8 const*>(key);
-
- for (usize i = 0; i < num_bytes; i++)
- {
- h = (h * 0x01000193) ^ buffer[i];
- }
-
- return h;
-}
-
-inline u64
-fnv64(void const* key, usize num_bytes)
-{
- u64 h = 0xcbf29ce484222325ull;
- u8 const* buffer = static_cast<u8 const*>(key);
-
- for (usize i = 0; i < num_bytes; i++)
- {
- h = (h * 0x100000001b3ll) ^ buffer[i];
- }
-
- return h;
-}
-
-inline u32
-fnv32a(void const* key, usize num_bytes)
-{
- u32 h = 0x811c9dc5;
- u8 const* buffer = static_cast<u8 const*>(key);
-
- for (usize i = 0; i < num_bytes; i++)
- {
- h = (h ^ buffer[i]) * 0x01000193;
- }
-
- return h;
-}
-
-inline u64
-fnv64a(void const* key, usize num_bytes)
-{
- u64 h = 0xcbf29ce484222325ull;
- u8 const* buffer = static_cast<u8 const*>(key);
-
- for (usize i = 0; i < num_bytes; i++)
- {
- h = (h ^ buffer[i]) * 0x100000001b3ll;
- }
-
- return h;
-}
-
-u32
-murmur32(void const* key, u32 num_bytes, u32 seed)
-{
- const u32 c1 = 0xcc9e2d51;
- const u32 c2 = 0x1b873593;
- const u32 r1 = 15;
- const u32 r2 = 13;
- const u32 m = 5;
- const u32 n = 0xe6546b64;
-
- u32 hash = seed;
-
- const usize nblocks = num_bytes / 4;
- const u32* blocks = static_cast<const u32*>(key);
- for (usize i = 0; i < nblocks; i++) {
- u32 k = blocks[i];
- k *= c1;
- k = (k << r1) | (k >> (32 - r1));
- k *= c2;
-
- hash ^= k;
- hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
- }
-
- u8 const* tail = (static_cast<u8 const*>(key)) + nblocks * 4;
- u32 k1 = 0;
-
- switch (num_bytes & 3) {
- case 3:
- k1 ^= tail[2] << 16;
- case 2:
- k1 ^= tail[1] << 8;
- case 1:
- k1 ^= tail[0];
-
- k1 *= c1;
- k1 = (k1 << r1) | (k1 >> (32 - r1));
- k1 *= c2;
- hash ^= k1;
- }
-
- hash ^= num_bytes;
- hash ^= (hash >> 16);
- hash *= 0x85ebca6b;
- hash ^= (hash >> 13);
- hash *= 0xc2b2ae35;
- hash ^= (hash >> 16);
-
- return hash;
-}
-
-#if defined(GB_ARCH_64_BIT)
- u64
- murmur64(void const* key, usize num_bytes, u64 seed)
- {
- const u64 m = 0xc6a4a7935bd1e995ULL;
- const s32 r = 47;
-
- u64 h = seed ^ (num_bytes * m);
-
- const u64* data = static_cast<const u64*>(key);
- const u64* end = data + (num_bytes / 8);
-
- while (data != end)
- {
- u64 k = *data++;
-
- k *= m;
- k ^= k >> r;
- k *= m;
-
- h ^= k;
- h *= m;
- }
-
- u8 const* data2 = reinterpret_cast<u8 const*>(data);
-
- switch (num_bytes & 7)
- {
- case 7: h ^= static_cast<u64>(data2[6]) << 48;
- case 6: h ^= static_cast<u64>(data2[5]) << 40;
- case 5: h ^= static_cast<u64>(data2[4]) << 32;
- case 4: h ^= static_cast<u64>(data2[3]) << 24;
- case 3: h ^= static_cast<u64>(data2[2]) << 16;
- case 2: h ^= static_cast<u64>(data2[1]) << 8;
- case 1: h ^= static_cast<u64>(data2[0]);
- h *= m;
- };
-
- h ^= h >> r;
- h *= m;
- h ^= h >> r;
-
- return h;
- }
-#elif GB_ARCH_32_BIT
- u64
- murmur64(void const* key, usize num_bytes, u64 seed)
- {
- const u32 m = 0x5bd1e995;
- const s32 r = 24;
-
- u32 h1 = static_cast<u32>(seed) ^ static_cast<u32>(num_bytes);
- u32 h2 = static_cast<u32>(seed >> 32);
-
- const u32* data = static_cast<const u32*>(key);
-
- while (num_bytes >= 8)
- {
- u32 k1 = *data++;
- k1 *= m;
- k1 ^= k1 >> r;
- k1 *= m;
- h1 *= m;
- h1 ^= k1;
- num_bytes -= 4;
-
- u32 k2 = *data++;
- k2 *= m;
- k2 ^= k2 >> r;
- k2 *= m;
- h2 *= m;
- h2 ^= k2;
- num_bytes -= 4;
- }
-
- if (num_bytes >= 4)
- {
- u32 k1 = *data++;
- k1 *= m;
- k1 ^= k1 >> r;
- k1 *= m;
- h1 *= m;
- h1 ^= k1;
- num_bytes -= 4;
- }
-
- switch (num_bytes)
- {
- case 3: h2 ^= reinterpret_cast<u8 const*>(data)[2] << 16;
- case 2: h2 ^= reinterpret_cast<u8 const*>(data)[1] << 8;
- case 1: h2 ^= reinterpret_cast<u8 const*>(data)[0] << 0;
- h2 *= m;
- };
-
- h1 ^= h2 >> 18;
- h1 *= m;
- h2 ^= h1 >> 22;
- h2 *= m;
- h1 ^= h2 >> 17;
- h1 *= m;
- h2 ^= h1 >> 19;
- h2 *= m;
-
- u64 h = h1;
-
- h = (h << 32) | h2;
-
- return h;
- }
-#else
- #error murmur64 function not supported on this architecture
-#endif
-} // namespace hash
-
-////////////////////////////////
-// //
-// Time //
-// //
-////////////////////////////////
-
-Time const TIME_ZERO = time::seconds(0);
-
-namespace time
-{
-#if defined(GB_SYSTEM_WINDOWS)
- internal_linkage LARGE_INTEGER
- win32_get_frequency()
- {
- LARGE_INTEGER f;
- QueryPerformanceFrequency(&f);
- return f;
- }
-
- Time
- now()
- {
- // NOTE(bill): std::chrono does not have a good enough precision in MSVC12
- // and below. This may have been fixed in MSVC14 but unsure as of yet.
-
- // Force the following code to run on first core
- // NOTE(bill): See
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
- HANDLE currentThread = GetCurrentThread();
- DWORD_PTR previousMask = SetThreadAffinityMask(currentThread, 1);
-
- // Get the frequency of the performance counter
- // It is constant across the program's lifetime
- local_persist LARGE_INTEGER s_frequency = win32_get_frequency();
-
- // Get the current time
- LARGE_INTEGER t;
- QueryPerformanceCounter(&t);
-
- // Restore the thread affinity
- SetThreadAffinityMask(currentThread, previousMask);
-
- return time::microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart);
- }
-
- void
- sleep(Time t)
- {
- if (t.microseconds <= 0)
- return;
-
- // Get the supported timer resolutions on this system
- TIMECAPS tc;
- timeGetDevCaps(&tc, sizeof(TIMECAPS));
- // Set the timer resolution to the minimum for the Sleep call
- timeBeginPeriod(tc.wPeriodMin);
-
- // Wait...
- ::Sleep(time::as_milliseconds(t));
-
- // Reset the timer resolution back to the system default
- timeBeginPeriod(tc.wPeriodMin);
- }
-
-#else
- Time
- now()
- {
- #if defined(GB_SYSTEM_OSX)
- s64 t = static_cast<s64>(mach_absolute_time());
- return microseconds(t);
- #else
- struct timeval t;
- gettimeofday(&t, nullptr);
-
- return microseconds((t.tv_sec * 1000000ll) + (t.tv_usec * 1ll));
- #endif
- }
-
- void
- sleep(Time t)
- {
- if (t.microseconds <= 0)
- return;
-
- struct timespec spec = {};
- spec.tv_sec = static_cast<s64>(as_seconds(t));
- spec.tv_nsec = 1000ll * (as_microseconds(t) % 1000000ll);
-
- nanosleep(&spec, nullptr);
- }
-
-#endif
-
-Time seconds(f32 s) { return {static_cast<s64>(s * 1000000ll)}; }
-Time milliseconds(s32 ms) { return {static_cast<s64>(ms * 1000ll)}; }
-Time microseconds(s64 us) { return {us}; }
-f32 as_seconds(Time t) { return static_cast<f32>(t.microseconds / 1000000.0f); }
-s32 as_milliseconds(Time t) { return static_cast<s32>(t.microseconds / 1000ll); }
-s64 as_microseconds(Time t) { return t.microseconds; }
-} // namespace time
-
-bool operator==(Time left, Time right) { return left.microseconds == right.microseconds; }
-bool operator!=(Time left, Time right) { return !operator==(left, right); }
-
-bool operator<(Time left, Time right) { return left.microseconds < right.microseconds; }
-bool operator>(Time left, Time right) { return left.microseconds > right.microseconds; }
-
-bool operator<=(Time left, Time right) { return left.microseconds <= right.microseconds; }
-bool operator>=(Time left, Time right) { return left.microseconds >= right.microseconds; }
-
-Time operator+(Time right) { return {+right.microseconds}; }
-Time operator-(Time right) { return {-right.microseconds}; }
-
-Time operator+(Time left, Time right) { return {left.microseconds + right.microseconds}; }
-Time operator-(Time left, Time right) { return {left.microseconds - right.microseconds}; }
-
-Time& operator+=(Time& left, Time right) { return (left = left + right); }
-Time& operator-=(Time& left, Time right) { return (left = left - right); }
-
-Time operator*(Time left, f32 right) { return time::seconds(time::as_seconds(left) * right); }
-Time operator*(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) * right); }
-Time operator*(f32 left, Time right) { return time::seconds(time::as_seconds(right) * left); }
-Time operator*(s64 left, Time right) { return time::microseconds(time::as_microseconds(right) * left); }
-
-Time& operator*=(Time& left, f32 right) { return (left = left * right); }
-Time& operator*=(Time& left, s64 right) { return (left = left * right); }
-
-Time operator/(Time left, f32 right) { return time::seconds(time::as_seconds(left) / right); }
-Time operator/(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) / right); }
-f32 operator/(Time left, Time right) { return time::as_seconds(left) / time::as_seconds(right); }
-
-Time& operator/=(Time& left, f32 right) { return (left = left / right); }
-Time& operator/=(Time& left, s64 right) { return (left = left / right); }
-
-Time operator%(Time left, Time right) { return time::microseconds(time::as_microseconds(left) % time::as_microseconds(right)); }
-Time& operator%=(Time& left, Time right) { return (left = left % right); }
-
-////////////////////////////////
-// //
-// OS //
-// //
-////////////////////////////////
-
-namespace os
-{
-GB_FORCE_INLINE u64
-rdtsc()
-{
-#if GB_SYSTEM_WINDOWS
- return ::__rdtsc();
-#else
- // TODO(bill): Check that rdtsc() works
- return ::rdtsc();
-#endif
-}
-} // namespace os
-
-__GB_NAMESPACE_END
-
-#endif // GB_IMPLEMENTATION
diff --git a/gb_math.h b/gb_math.h
index 9158181..d8278f9 100644
--- a/gb_math.h
+++ b/gb_math.h
@@ -1,16 +1,21 @@
-// gb_math.h - v0.03 - public domain C math library - no warranty implied; use at your own risk
+// gb_math.h - v0.04d - public domain C math library - no warranty implied; use at your own risk
// A C math library geared towards game development
+// use '#define GB_MATH_IMPLEMENTATION' before including to create the implementation in _ONE_ file
/*
Version History:
+ 0.04d - License Update
+ 0.04c - Use 64-bit murmur64 version on WIN64
+ 0.04b - Fix strict aliasing in gb_quake_inv_sqrt
+ 0.04a - Minor bug fixes
+ 0.04 - Namespace everything with gb
0.03 - Complete Replacement
0.01 - Initial Version
LICENSE
- This software is in the public domain. Where that dedication is not
- recognized, you are granted a perpetual, irrevocable license to copy,
- distribute, and modify this file as you see fit.
-
+ This software is dual-licensed to the public domain and under the following
+ license: you are granted a perpetual, irrevocable license to copy, modify,
+ publish, and distribute this file as you see fit.
WARNING
- This library is _slightly_ experimental and features may not work as expected.
- This also means that many functions are not documented.
@@ -18,419 +23,1107 @@ WARNING
CONTENTS
- Common Macros
- Types
- - Vec(2,3,4)
- - Mat(2,3,4)
- - Float(2,3,4)
- - Rect(2,3)
- - Aabb(2,3)
+ - gbVec(2,3,4)
+ - gbMat(2,3,4)
+ - gbFloat(2,3,4)
+ - gbQuat
+ - gbRect(2,3)
+ - gbAabb(2,3)
+ - gb_half (16-bit floating point) (storage only)
- Operations
- Functions
- Type Functions
- Random
-
-TODO
- - Complex
- - Quaternion
- - More Math Functions
+ - Hash
*/
#ifndef GB_MATH_INCLUDE_GB_MATH_H
#define GB_MATH_INCLUDE_GB_MATH_H
+// TODO(bill): What of this do I actually need? And can include elsewhere (e.g. implementation)
#include <stddef.h>
-
-#ifdef GB_MATH_STATIC
-#define GB_MATH_DEF static
-#else
-#define GB_MATH_DEF extern
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <string.h> // memcpy, memmove, etc.
+
+#ifndef GB_MATH_DEF
+ #ifdef GB_MATH_STATIC
+ #define GB_MATH_DEF static
+ #else
+ #define GB_MATH_DEF extern
+ #endif
#endif
-typedef union Vec2
-{
+typedef union gbVec2 {
struct { float x, y; };
float e[2];
-} Vec2;
+} gbVec2;
-typedef union Vec3
-{
+typedef union gbVec3 {
struct { float x, y, z; };
struct { float r, g, b; };
- Vec2 xy;
+ gbVec2 xy;
float e[2];
-} Vec3;
+} gbVec3;
-typedef union Vec4
-{
+typedef union gbVec4 {
struct { float x, y, z, w; };
struct { float r, g, b, a; };
- struct { Vec2 xy, zw; };
- Vec3 xyz;
- Vec3 rgb;
+ struct { gbVec2 xy, zw; };
+ gbVec3 xyz;
+ gbVec3 rgb;
float e[4];
-} Vec4;
+} gbVec4;
-typedef union Mat2
-{
- struct { Vec2 x, y; };
- Vec4 col[2];
+typedef union gbMat2 {
+ struct { gbVec2 x, y; };
+ gbVec4 col[2];
float e[4];
-} Mat2;
+} gbMat2;
-typedef union Mat3
-{
- struct { Vec3 x, y, z; };
- Vec4 col[3];
+typedef union gbMat3 {
+ struct { gbVec3 x, y, z; };
+ gbVec3 col[3];
float e[9];
-} Mat3;
+} gbMat3;
-typedef union Mat4
-{
- struct { Vec4 x, y, z, w; };
- Vec4 col[4];
+typedef union gbMat4 {
+ struct { gbVec4 x, y, z, w; };
+ gbVec4 col[4];
float e[16];
-} Mat4;
+} gbMat4;
+typedef union gbQuat {
+ struct { float x, y, z, w; };
+ gbVec4 xyzw;
+ gbVec3 xyz;
+ float e[4];
+} gbQuat;
+
-typedef float Float2[2];
-typedef float Float3[3];
-typedef float Float4[4];
+typedef float gbFloat2[2];
+typedef float gbFloat3[3];
+typedef float gbFloat4[4];
-typedef struct Rect2 { Vec2 pos, dim; } Rect2;
-typedef struct Rect3 { Vec3 pos, dim; } Rect3;
+typedef struct gbRect2 { gbVec2 pos, dim; } gbRect2;
+typedef struct gbRect3 { gbVec3 pos, dim; } gbRect3;
-typedef struct Aabb2 { Vec2 center, half_size; } Aabb2;
-typedef struct Aabb3 { Vec3 center, half_size; } Aabb3;
+typedef struct gbAabb2 { gbVec2 centre, half_size; } gbAabb2;
+typedef struct gbAabb3 { gbVec3 centre, half_size; } gbAabb3;
#if defined(_MSC_VER)
- typedef unsigned __int8 gb_math_u8;
typedef unsigned __int32 gb_math_u32;
typedef unsigned __int64 gb_math_u64;
#else
- #include <stdint.h>
- typedef uint8_t gb_math_u8;
- typedef uint32_t gb_math_u32;
- typedef uint64_t gb_math_u64;
+ #if defined(GB_USE_STDINT)
+ #include <stdint.h>
+ typedef uint32_t gb_math_u32;
+ typedef uint64_t gb_math_u64;
+ #else
+ typedef unsigned int gb_math_u32;
+ typedef unsigned long long gb_math_u64;
+ #endif
#endif
+typedef short gb_half;
+
+
// Constants
-#define MATH_TAU 6.28318530718f
+#ifndef GB_MATH_CONSTANTS
+#define GB_MATH_CONSTANTS
+ #define GB_MATH_EPSILON 1.19209290e-7f
+ #define GB_MATH_ZERO 0.0f
+ #define GB_MATH_ONE 1.0f
+ #define GB_MATH_TWO_THIRDS 0.666666666666666666666666666666666666667f
+
+ #define GB_MATH_TAU 6.28318530717958647692528676655900576f
+ #define GB_MATH_PI 3.14159265358979323846264338327950288f
+ #define GB_MATH_ONE_OVER_TAU 0.636619772367581343075535053490057448f
+ #define GB_MATH_ONE_OVER_PI 0.159154943091895335768883763372514362f
+
+ #define GB_MATH_E 2.71828182845904523536f
+ #define GB_MATH_SQRT_TWO 1.41421356237309504880168872420969808f
+ #define GB_MATH_SQRT_THREE 1.73205080756887729352744634150587236f
+ #define GB_MATH_SQRT_FIVE 2.23606797749978969640917366873127623f
+
+ #define GB_MATH_LOG_TWO 0.693147180559945309417232121458176568f
+ #define GB_MATH_LOG_TEN 2.30258509299404568401799145468436421f
+#endif
+
#if defined(__cplusplus)
extern "C" {
#endif
-// Vector
+// Basic
+#ifndef gb_clamp
+#define gb_clamp(x, lower, upper) (gb_min(gb_max(x, (lower)), (upper)))
+#endif
+#ifndef gb_clamp01
+#define gb_clamp01(x) gb_clamp(x, 0, 1)
+#endif
-GB_MATH_DEF Vec2 vec2_zero(void);
-GB_MATH_DEF Vec2 vec2(float x, float y);
-GB_MATH_DEF Vec2 vec2v(float x[2]);
+#ifndef gb_square
+#define gb_square(x) ((x)*(x))
+#endif
-GB_MATH_DEF Vec3 vec3_zero(void);
-GB_MATH_DEF Vec3 vec3(float x, float y, float z);
-GB_MATH_DEF Vec3 vec3v(float x[3]);
+#ifndef gb_cube
+#define gb_cube(x) ((x)*(x)*(x))
+#endif
-GB_MATH_DEF Vec4 vec4_zero(void);
-GB_MATH_DEF Vec4 vec4(float x, float y, float z, float w);
-GB_MATH_DEF Vec4 vec4v(float x[4]);
+#ifndef gb_abs
+#define gb_abs(x) ((x) > 0 ? (x) : -(x))
+#endif
-GB_MATH_DEF void vec2_add(Vec2 *d, Vec2 v0, Vec2 v1);
-GB_MATH_DEF void vec2_sub(Vec2 *d, Vec2 v0, Vec2 v1);
-GB_MATH_DEF void vec2_mul(Vec2 *d, Vec2 v, float s);
-GB_MATH_DEF void vec2_div(Vec2 *d, Vec2 v, float s);
+#ifndef gb_sign
+#define gb_sign(x) ((x) >= 0 ? 1 : -1)
+#endif
+
+
+GB_MATH_DEF float gb_to_radians(float degrees);
+GB_MATH_DEF float gb_to_degrees(float radians);
+
+// NOTE(bill): Because to interpolate angles
+GB_MATH_DEF float gb_angle_diff(float radians_a, float radians_b);
+
+#ifndef gb_min
+#define gb_min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef gb_max
+#define gb_max(a, b) ((a) > (b) ? (a) : (b))
+#endif
-GB_MATH_DEF void vec3_add(Vec3 *d, Vec3 v0, Vec3 v1);
-GB_MATH_DEF void vec3_sub(Vec3 *d, Vec3 v0, Vec3 v1);
-GB_MATH_DEF void vec3_mul(Vec3 *d, Vec3 v, float s);
-GB_MATH_DEF void vec3_div(Vec3 *d, Vec3 v, float s);
+GB_MATH_DEF float gb_sqrt(float a);
+GB_MATH_DEF float gb_quake_inv_sqrt(float a); // NOTE(bill): It's probably better to use 1.0f/gb_sqrt(a)
+ // And for simd, there is usually isqrt functions too!
-GB_MATH_DEF void vec4_add(Vec4 *d, Vec4 v0, Vec4 v1);
-GB_MATH_DEF void vec4_sub(Vec4 *d, Vec4 v0, Vec4 v1);
-GB_MATH_DEF void vec4_mul(Vec4 *d, Vec4 v, float s);
-GB_MATH_DEF void vec4_div(Vec4 *d, Vec4 v, float s);
+GB_MATH_DEF float gb_sin(float radians);
+GB_MATH_DEF float gb_cos(float radians);
+GB_MATH_DEF float gb_tan(float radians);
+GB_MATH_DEF float gb_arcsin(float a);
+GB_MATH_DEF float gb_arccos(float a);
+GB_MATH_DEF float gb_arctan(float a);
+GB_MATH_DEF float gb_arctan2(float y, float x);
-GB_MATH_DEF void vec2_addeq(Vec2 *d, Vec2 v);
-GB_MATH_DEF void vec2_subeq(Vec2 *d, Vec2 v);
-GB_MATH_DEF void vec2_muleq(Vec2 *d, float s);
-GB_MATH_DEF void vec2_diveq(Vec2 *d, float s);
-GB_MATH_DEF void vec3_addeq(Vec3 *d, Vec3 v);
-GB_MATH_DEF void vec3_subeq(Vec3 *d, Vec3 v);
-GB_MATH_DEF void vec3_muleq(Vec3 *d, float s);
-GB_MATH_DEF void vec3_diveq(Vec3 *d, float s);
+GB_MATH_DEF float gb_exp(float x);
+GB_MATH_DEF float gb_exp2(float x);
+GB_MATH_DEF float gb_log(float x);
+GB_MATH_DEF float gb_log2(float x);
+GB_MATH_DEF float gb_fast_exp(float x); // NOTE(bill): Only valid from -1 <= x <= +1
+GB_MATH_DEF float gb_fast_exp2(float x); // NOTE(bill): Only valid from -1 <= x <= +1
+GB_MATH_DEF float gb_pow(float x, float y); // x^y
-GB_MATH_DEF void vec4_addeq(Vec4 *d, Vec4 v);
-GB_MATH_DEF void vec4_subeq(Vec4 *d, Vec4 v);
-GB_MATH_DEF void vec4_muleq(Vec4 *d, float s);
-GB_MATH_DEF void vec4_diveq(Vec4 *d, float s);
-GB_MATH_DEF float vec2_dot(Vec2 v0, Vec2 v1);
-GB_MATH_DEF float vec3_dot(Vec3 v0, Vec3 v1);
-GB_MATH_DEF float vec4_dot(Vec4 v0, Vec4 v1);
+GB_MATH_DEF float gb_half_to_float(gb_half value);
+GB_MATH_DEF gb_half gb_float_to_half(float value);
-GB_MATH_DEF void vec2_cross(float *d, Vec2 v0, Vec2 v1);
-GB_MATH_DEF void vec3_cross(Vec3 *d, Vec3 v0, Vec3 v1);
+// Vec
-GB_MATH_DEF float vec2_mag2(Vec2 v);
-GB_MATH_DEF float vec3_mag2(Vec3 v);
-GB_MATH_DEF float vec4_mag2(Vec4 v);
+GB_MATH_DEF gbVec2 gb_vec2_zero(void);
+GB_MATH_DEF gbVec2 gb_vec2(float x, float y);
+GB_MATH_DEF gbVec2 gb_vec2v(float x[2]);
-GB_MATH_DEF float vec2_mag(Vec2 v);
-GB_MATH_DEF float vec3_mag(Vec3 v);
-GB_MATH_DEF float vec4_mag(Vec4 v);
+GB_MATH_DEF gbVec3 gb_vec3_zero(void);
+GB_MATH_DEF gbVec3 gb_vec3(float x, float y, float z);
+GB_MATH_DEF gbVec3 gb_vec3v(float x[3]);
-GB_MATH_DEF void vec2_norm(Vec2 *d, Vec2 v);
-GB_MATH_DEF void vec3_norm(Vec3 *d, Vec3 v);
-GB_MATH_DEF void vec4_norm(Vec4 *d, Vec4 v);
+GB_MATH_DEF gbVec4 gb_vec4_zero(void);
+GB_MATH_DEF gbVec4 gb_vec4(float x, float y, float z, float w);
+GB_MATH_DEF gbVec4 gb_vec4v(float x[4]);
-GB_MATH_DEF float vec2_aspect(Vec2 v);
+
+GB_MATH_DEF void gb_vec2_add(gbVec2 *d, gbVec2 v0, gbVec2 v1);
+GB_MATH_DEF void gb_vec2_sub(gbVec2 *d, gbVec2 v0, gbVec2 v1);
+GB_MATH_DEF void gb_vec2_mul(gbVec2 *d, gbVec2 v, float s);
+GB_MATH_DEF void gb_vec2_div(gbVec2 *d, gbVec2 v, float s);
+
+GB_MATH_DEF void gb_vec3_add(gbVec3 *d, gbVec3 v0, gbVec3 v1);
+GB_MATH_DEF void gb_vec3_sub(gbVec3 *d, gbVec3 v0, gbVec3 v1);
+GB_MATH_DEF void gb_vec3_mul(gbVec3 *d, gbVec3 v, float s);
+GB_MATH_DEF void gb_vec3_div(gbVec3 *d, gbVec3 v, float s);
+
+GB_MATH_DEF void gb_vec4_add(gbVec4 *d, gbVec4 v0, gbVec4 v1);
+GB_MATH_DEF void gb_vec4_sub(gbVec4 *d, gbVec4 v0, gbVec4 v1);
+GB_MATH_DEF void gb_vec4_mul(gbVec4 *d, gbVec4 v, float s);
+GB_MATH_DEF void gb_vec4_div(gbVec4 *d, gbVec4 v, float s);
+
+GB_MATH_DEF void gb_vec2_addeq(gbVec2 *d, gbVec2 v);
+GB_MATH_DEF void gb_vec2_subeq(gbVec2 *d, gbVec2 v);
+GB_MATH_DEF void gb_vec2_muleq(gbVec2 *d, float s);
+GB_MATH_DEF void gb_vec2_diveq(gbVec2 *d, float s);
+
+GB_MATH_DEF void gb_vec3_addeq(gbVec3 *d, gbVec3 v);
+GB_MATH_DEF void gb_vec3_subeq(gbVec3 *d, gbVec3 v);
+GB_MATH_DEF void gb_vec3_muleq(gbVec3 *d, float s);
+GB_MATH_DEF void gb_vec3_diveq(gbVec3 *d, float s);
+
+GB_MATH_DEF void gb_vec4_addeq(gbVec4 *d, gbVec4 v);
+GB_MATH_DEF void gb_vec4_subeq(gbVec4 *d, gbVec4 v);
+GB_MATH_DEF void gb_vec4_muleq(gbVec4 *d, float s);
+GB_MATH_DEF void gb_vec4_diveq(gbVec4 *d, float s);
+
+GB_MATH_DEF float gb_vec2_dot(gbVec2 v0, gbVec2 v1);
+GB_MATH_DEF float gb_vec3_dot(gbVec3 v0, gbVec3 v1);
+GB_MATH_DEF float gb_vec4_dot(gbVec4 v0, gbVec4 v1);
+
+GB_MATH_DEF void gb_vec2_cross(float *d, gbVec2 v0, gbVec2 v1);
+GB_MATH_DEF void gb_vec3_cross(gbVec3 *d, gbVec3 v0, gbVec3 v1);
+
+GB_MATH_DEF float gb_vec2_mag2(gbVec2 v);
+GB_MATH_DEF float gb_vec3_mag2(gbVec3 v);
+GB_MATH_DEF float gb_vec4_mag2(gbVec4 v);
+
+GB_MATH_DEF float gb_vec2_mag(gbVec2 v);
+GB_MATH_DEF float gb_vec3_mag(gbVec3 v);
+GB_MATH_DEF float gb_vec4_mag(gbVec4 v);
+
+GB_MATH_DEF void gb_vec2_norm(gbVec2 *d, gbVec2 v);
+GB_MATH_DEF void gb_vec3_norm(gbVec3 *d, gbVec3 v);
+GB_MATH_DEF void gb_vec4_norm(gbVec4 *d, gbVec4 v);
+
+GB_MATH_DEF void gb_vec2_norm0(gbVec2 *d, gbVec2 v);
+GB_MATH_DEF void gb_vec3_norm0(gbVec3 *d, gbVec3 v);
+GB_MATH_DEF void gb_vec4_norm0(gbVec4 *d, gbVec4 v);
+
+GB_MATH_DEF void gb_vec2_reflect(gbVec2 *d, gbVec2 i, gbVec2 n);
+GB_MATH_DEF void gb_vec3_reflect(gbVec3 *d, gbVec3 i, gbVec3 n);
+GB_MATH_DEF void gb_vec2_refract(gbVec2 *d, gbVec2 i, gbVec2 n, float eta);
+GB_MATH_DEF void gb_vec3_refract(gbVec3 *d, gbVec3 i, gbVec3 n, float eta);
+
+GB_MATH_DEF float gb_vec2_aspect_ratio(gbVec2 v);
// Matrix
-GB_MATH_DEF void mat2_identity(Mat2 *m);
-GB_MATH_DEF void float22_identity(float m[2][2]);
+GB_MATH_DEF void gb_mat2_identity(gbMat2 *m);
+GB_MATH_DEF void gb_float22_identity(float m[2][2]);
+
+GB_MATH_DEF void gb_mat2_transpose(gbMat2 *m);
+GB_MATH_DEF void gb_mat2_mul(gbMat2 *out, gbMat2 *m1, gbMat2 *m2);
+GB_MATH_DEF void gb_mat2_mul_vec2(gbVec2 *out, gbMat2 *m, gbVec2 in);
+
+GB_MATH_DEF gbMat2 *gb_mat2_v(gbVec2 m[2]);
+GB_MATH_DEF gbMat2 *gb_mat2_f(float m[2][2]);
+GB_MATH_DEF gbFloat2 *gb_float22_m(gbMat2 *m);
+GB_MATH_DEF gbFloat2 *gb_float22_v(gbVec2 m[2]);
+GB_MATH_DEF gbFloat2 *gb_float22_4(float m[4]);
+
+GB_MATH_DEF void gb_float22_transpose(float (*vec)[2]);
+GB_MATH_DEF void gb_float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2]);
+GB_MATH_DEF void gb_float22_mul_vec2(gbVec2 *out, float m[2][2], gbVec2 in);
+
+
+GB_MATH_DEF void gb_mat3_identity(gbMat3 *m);
+GB_MATH_DEF void gb_float33_identity(float m[3][3]);
+
+GB_MATH_DEF void gb_mat3_transpose(gbMat3 *m);
+GB_MATH_DEF void gb_mat3_mul(gbMat3 *out, gbMat3 *m1, gbMat3 *m2);
+GB_MATH_DEF void gb_mat3_mul_vec3(gbVec3 *out, gbMat3 *m, gbVec3 in);
+
+GB_MATH_DEF gbMat3 *gb_mat3_v(gbVec3 m[3]);
+GB_MATH_DEF gbMat3 *gb_mat3_f(float m[3][3]);
+GB_MATH_DEF gbFloat3 *gb_float33_m(gbMat3 *m);
+GB_MATH_DEF gbFloat3 *gb_float33_v(gbVec3 m[3]);
+GB_MATH_DEF gbFloat3 *gb_float33_9(float m[9]);
+
+GB_MATH_DEF void gb_float33_transpose(float (*vec)[3]);
+GB_MATH_DEF void gb_float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3]);
+GB_MATH_DEF void gb_float33_mul_vec3(gbVec3 *out, float m[3][3], gbVec3 in);
+
+
+GB_MATH_DEF void gb_mat4_identity(gbMat4 *m);
+GB_MATH_DEF void gb_float44_identity(float m[4][4]);
+
+GB_MATH_DEF void gb_mat4_transpose(gbMat4 *m);
+GB_MATH_DEF void gb_mat4_mul(gbMat4 *out, gbMat4 *m1, gbMat4 *m2);
+GB_MATH_DEF void gb_mat4_mul_vec4(gbVec4 *out, gbMat4 *m, gbVec4 in);
+
+GB_MATH_DEF gbMat4 *gb_mat4_v(gbVec4 m[4]);
+GB_MATH_DEF gbMat4 *gb_mat4_f(float m[4][4]);
+GB_MATH_DEF gbFloat4 *gb_float44_m(gbMat4 *m);
+GB_MATH_DEF gbFloat4 *gb_float44_v(gbVec4 m[4]);
+GB_MATH_DEF gbFloat4 *gb_float44_16(float m[16]);
+
+GB_MATH_DEF void gb_float44_transpose(float (*vec)[4]);
+GB_MATH_DEF void gb_float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4]);
+GB_MATH_DEF void gb_float44_mul_vec4(gbVec4 *out, float m[4][4], gbVec4 in);
+
+
+GB_MATH_DEF void gb_mat4_translate(gbMat4 *out, gbVec3 v);
+GB_MATH_DEF void gb_mat4_rotate(gbMat4 *out, gbVec3 v, float angle_radians);
+GB_MATH_DEF void gb_mat4_scale(gbMat4 *out, gbVec3 v);
+GB_MATH_DEF void gb_mat4_scalef(gbMat4 *out, float s);
+GB_MATH_DEF void gb_mat4_ortho2d(gbMat4 *out, float left, float right, float bottom, float top);
+GB_MATH_DEF void gb_mat4_ortho3d(gbMat4 *out, float left, float right, float bottom, float top, float z_near, float z_far);
+GB_MATH_DEF void gb_mat4_perspective(gbMat4 *out, float fovy, float aspect, float z_near, float z_far);
+GB_MATH_DEF void gb_mat4_infinite_perspective(gbMat4 *out, float fovy, float aspect, float z_near);
-GB_MATH_DEF void mat2_transpose(Mat2 *m);
-GB_MATH_DEF void mat2_mul(Mat2 *out, Mat2 *m1, Mat2 *m2);
-GB_MATH_DEF void mat2_mul_vec2(Vec2 *out, Mat2 *m, Vec2 in);
+GB_MATH_DEF void gb_mat4_look_at(gbMat4 *out, gbVec3 eye, gbVec3 centre, gbVec3 up);
-GB_MATH_DEF Mat2 *mat2_v(Vec2 m[2]);
-GB_MATH_DEF Mat2 *mat2_f(float m[2][2]);
-GB_MATH_DEF Float2 *float22_m(Mat2 *m);
-GB_MATH_DEF Float2 *float22_v(Vec2 m[2]);
-GB_MATH_DEF Float2 *float22_4(float m[4]);
-GB_MATH_DEF void float22_transpose(float (*vec)[2]);
-GB_MATH_DEF void float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2]);
-GB_MATH_DEF void float22_mul_vec2(Vec2 *out, float m[2][2], Vec2 in);
+GB_MATH_DEF gbQuat gb_quat(float x, float y, float z, float w);
+GB_MATH_DEF gbQuat gb_quatv(float e[4]);
+GB_MATH_DEF gbQuat gb_quat_axis_angle(gbVec3 axis, float angle_radians);
+GB_MATH_DEF gbQuat gb_quat_euler_angles(float pitch, float yaw, float roll);
+GB_MATH_DEF gbQuat gb_quat_identity(void);
-GB_MATH_DEF void mat3_identity(Mat3 *m);
-GB_MATH_DEF void float33_identity(float m[3][3]);
+GB_MATH_DEF void gb_quat_add(gbQuat *d, gbQuat q0, gbQuat q1);
+GB_MATH_DEF void gb_quat_sub(gbQuat *d, gbQuat q0, gbQuat q1);
+GB_MATH_DEF void gb_quat_mul(gbQuat *d, gbQuat q0, gbQuat q1);
+GB_MATH_DEF void gb_quat_div(gbQuat *d, gbQuat q0, gbQuat q1);
-GB_MATH_DEF void mat3_transpose(Mat3 *m);
-GB_MATH_DEF void mat3_mul(Mat3 *out, Mat3 *m1, Mat3 *m2);
-GB_MATH_DEF void mat3_mul_vec3(Vec3 *out, Mat3 *m, Vec3 in);
+GB_MATH_DEF void gb_quat_mulf(gbQuat *d, gbQuat q, float s);
+GB_MATH_DEF void gb_quat_divf(gbQuat *d, gbQuat q, float s);
-GB_MATH_DEF Mat3 *mat3_v(Vec3 m[3]);
-GB_MATH_DEF Mat3 *mat3_f(float m[3][3]);
-GB_MATH_DEF Float3 *float33_m(Mat3 *m);
-GB_MATH_DEF Float3 *float33_v(Vec3 m[3]);
-GB_MATH_DEF Float3 *float33_9(float m[9]);
-GB_MATH_DEF void float33_transpose(float (*vec)[3]);
-GB_MATH_DEF void float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3]);
-GB_MATH_DEF void float33_mul_vec3(Vec3 *out, float m[3][3], Vec3 in);
+GB_MATH_DEF void gb_quat_addeq(gbQuat *d, gbQuat q);
+GB_MATH_DEF void gb_quat_subeq(gbQuat *d, gbQuat q);
+GB_MATH_DEF void gb_quat_muleq(gbQuat *d, gbQuat q);
+GB_MATH_DEF void gb_quat_diveq(gbQuat *d, gbQuat q);
-GB_MATH_DEF void mat4_identity(Mat4 *m);
-GB_MATH_DEF void float44_identity(float m[4][4]);
+GB_MATH_DEF void gb_quat_muleqf(gbQuat *d, float s);
+GB_MATH_DEF void gb_quat_diveqf(gbQuat *d, float s);
-GB_MATH_DEF void mat4_transpose(Mat4 *m);
-GB_MATH_DEF void mat4_mul(Mat4 *out, Mat4 *m1, Mat4 *m2);
-GB_MATH_DEF void mat4_mul_vec4(Vec4 *out, Mat4 *m, Vec4 in);
-GB_MATH_DEF Mat4 *mat4_v(Vec4 m[4]);
-GB_MATH_DEF Mat4 *mat4_f(float m[4][4]);
-GB_MATH_DEF Float4 *float44_m(Mat4 *m);
-GB_MATH_DEF Float4 *float44_v(Vec4 m[4]);
-GB_MATH_DEF Float4 *float44_16(float m[16]);
-GB_MATH_DEF void float44_transpose(float (*vec)[4]);
-GB_MATH_DEF void float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4]);
-GB_MATH_DEF void float44_mul_vec4(Vec4 *out, float m[4][4], Vec4 in);
+GB_MATH_DEF float gb_quat_dot(gbQuat q0, gbQuat q1);
+GB_MATH_DEF float gb_quat_mag(gbQuat q);
-// Hermite Interpolations
-GB_MATH_DEF float lerp(float a, float b, float t);
-GB_MATH_DEF float smooth_step(float a, float b, float t);
-GB_MATH_DEF float smoother_step(float a, float b, float t);
+GB_MATH_DEF void gb_quat_norm(gbQuat *d, gbQuat q);
+GB_MATH_DEF void gb_quat_conj(gbQuat *d, gbQuat q);
+GB_MATH_DEF void gb_quat_inverse(gbQuat *d, gbQuat q);
-GB_MATH_DEF void vec2_lerp(Vec2 *d, Vec2 a, Vec2 b, float t);
-GB_MATH_DEF void vec3_lerp(Vec3 *d, Vec3 a, Vec3 b, float t);
-GB_MATH_DEF void vec4_lerp(Vec4 *d, Vec4 a, Vec4 b, float t);
+GB_MATH_DEF void gb_quat_axis(gbVec3 *axis, gbQuat q);
+GB_MATH_DEF float gb_quat_angle(gbQuat q);
+GB_MATH_DEF float gb_quat_pitch(gbQuat q);
+GB_MATH_DEF float gb_quat_yaw(gbQuat q);
+GB_MATH_DEF float gb_quat_roll(gbQuat q);
-// Angles
-GB_MATH_DEF float to_radians(float degrees);
-GB_MATH_DEF float to_degrees(float radians);
+// Rotate v by q
+GB_MATH_DEF void gb_quat_rotate_vec3(gbVec3 *d, gbQuat q, gbVec3 v);
+GB_MATH_DEF void gb_mat4_from_quat(gbMat4 *out, gbQuat q);
+GB_MATH_DEF void gb_quat_from_mat4(gbQuat *out, gbMat4 *m);
-// Projections
-// NOTE(bill): Uses OpenGL Projection Conventions (-1 to 1)
-// NOTE(bill): If Direct3D is needed, use custom projection to shift-z to (0 to 1)
-GB_MATH_DEF void mat4_ortho2d(Mat4 *out, float left, float right, float bottom, float top);
-GB_MATH_DEF void mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float z_near, float z_far);
-#ifndef MURMUR64_SEED
-#define MURMUR64_SEED 0x9747b28c
+
+// Interpolations
+GB_MATH_DEF float gb_lerp(float a, float b, float t);
+GB_MATH_DEF float gb_smooth_step(float a, float b, float t);
+GB_MATH_DEF float gb_smoother_step(float a, float b, float t);
+
+GB_MATH_DEF void gb_vec2_lerp(gbVec2 *d, gbVec2 a, gbVec2 b, float t);
+GB_MATH_DEF void gb_vec3_lerp(gbVec3 *d, gbVec3 a, gbVec3 b, float t);
+GB_MATH_DEF void gb_vec4_lerp(gbVec4 *d, gbVec4 a, gbVec4 b, float t);
+
+GB_MATH_DEF void gb_quat_lerp(gbQuat *d, gbQuat a, gbQuat b, float t);
+GB_MATH_DEF void gb_quat_nlerp(gbQuat *d, gbQuat a, gbQuat b, float t);
+GB_MATH_DEF void gb_quat_slerp(gbQuat *d, gbQuat a, gbQuat b, float t);
+GB_MATH_DEF void gb_quat_slerp_approx(gbQuat *d, gbQuat a, gbQuat b, float t);
+GB_MATH_DEF void gb_quat_nquad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t);
+GB_MATH_DEF void gb_quat_squad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t);
+GB_MATH_DEF void gb_quat_squad_approx(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t);
+
+
+// Rects
+GB_MATH_DEF gbRect2 gb_rect2(gbVec2 pos, gbVec2 dim);
+GB_MATH_DEF gbRect3 gb_rect3(gbVec3 pos, gbVec3 dim);
+
+GB_MATH_DEF int gb_rect2_contains(gbRect2 a, float x, float y);
+GB_MATH_DEF int gb_rect2_contains_vec2(gbRect2 a, gbVec2 p);
+GB_MATH_DEF int gb_rect2_intersects(gbRect2 a, gbRect2 b);
+GB_MATH_DEF int gb_rect2_intersection_result(gbRect2 a, gbRect2 b, gbRect2 *intersection);
+
+
+#ifndef GB_MURMUR64_DEFAULT_SEED
+#define GB_MURMUR64_DEFAULT_SEED 0x9747b28c
#endif
// Hashing
-GB_MATH_DEF gb_math_u64 hash_murmur64(void const *key, size_t num_bytes);
+GB_MATH_DEF gb_math_u64 gb_hash_murmur64(void const *key, size_t num_bytes, gb_math_u64 seed);
// Random
// TODO(bill): Use a generator for the random numbers
-GB_MATH_DEF float random_range_float(float min_inc, float max_inc);
-GB_MATH_DEF int random_range_int(int min_inc, int max_inc);
+GB_MATH_DEF float gb_random_range_float(float min_inc, float max_inc);
+GB_MATH_DEF int gb_random_range_int(int min_inc, int max_inc);
#if defined(__cplusplus)
}
#endif
+#if defined(__cplusplus) && defined(GB_MATH_USE_OPERATOR_OVERLOADS)
+
+bool operator==(gbVec2 a, gbVec2 b) { return (a.x == b.x) && (a.y == b.y); }
+bool operator!=(gbVec2 a, gbVec2 b) { return !operator==(a, b); }
+
+gbVec2 operator+(gbVec2 a) { return a; }
+gbVec2 operator-(gbVec2 a) { gbVec2 r = {-a.x, -a.y}; return r; }
+
+gbVec2 operator+(gbVec2 a, gbVec2 b) { gbVec2 r; gb_vec2_add(&r, a, b); return r; }
+gbVec2 operator-(gbVec2 a, gbVec2 b) { gbVec2 r; gb_vec2_sub(&r, a, b); return r; }
+
+gbVec2 operator*(gbVec2 a, float scalar) { gbVec2 r; gb_vec2_mul(&r, a, scalar); return r; }
+gbVec2 operator*(float scalar, gbVec2 a) { return operator*(a, scalar); }
+
+gbVec2 operator/(gbVec2 a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+// Hadamard Product
+gbVec2 operator*(gbVec2 a, gbVec2 b) { gbVec2 r = {a.x*b.x, a.y*b.y}; return r; }
+gbVec2 operator/(gbVec2 a, gbVec2 b) { gbVec2 r = {a.x/b.x, a.y/b.y}; return r; }
+
+gbVec2 &operator+=(gbVec2 &a, gbVec2 b) { return (a = a + b); }
+gbVec2 &operator-=(gbVec2 &a, gbVec2 b) { return (a = a - b); }
+gbVec2 &operator*=(gbVec2 &a, float scalar) { return (a = a * scalar); }
+gbVec2 &operator/=(gbVec2 &a, float scalar) { return (a = a / scalar); }
+
+
+bool operator==(gbVec3 a, gbVec3 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); }
+bool operator!=(gbVec3 a, gbVec3 b) { return !operator==(a, b); }
+
+gbVec3 operator+(gbVec3 a) { return a; }
+gbVec3 operator-(gbVec3 a) { gbVec3 r = {-a.x, -a.y, -a.z}; return r; }
+
+gbVec3 operator+(gbVec3 a, gbVec3 b) { gbVec3 r; gb_vec3_add(&r, a, b); return r; }
+gbVec3 operator-(gbVec3 a, gbVec3 b) { gbVec3 r; gb_vec3_sub(&r, a, b); return r; }
+
+gbVec3 operator*(gbVec3 a, float scalar) { gbVec3 r; gb_vec3_mul(&r, a, scalar); return r; }
+gbVec3 operator*(float scalar, gbVec3 a) { return operator*(a, scalar); }
+
+gbVec3 operator/(gbVec3 a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+// Hadamard Product
+gbVec3 operator*(gbVec3 a, gbVec3 b) { gbVec3 r = {a.x*b.x, a.y*b.y, a.z*b.z}; return r; }
+gbVec3 operator/(gbVec3 a, gbVec3 b) { gbVec3 r = {a.x/b.x, a.y/b.y, a.z/b.z}; return r; }
+
+gbVec3 &operator+=(gbVec3 &a, gbVec3 b) { return (a = a + b); }
+gbVec3 &operator-=(gbVec3 &a, gbVec3 b) { return (a = a - b); }
+gbVec3 &operator*=(gbVec3 &a, float scalar) { return (a = a * scalar); }
+gbVec3 &operator/=(gbVec3 &a, float scalar) { return (a = a / scalar); }
+
+
+bool operator==(gbVec4 a, gbVec4 b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); }
+bool operator!=(gbVec4 a, gbVec4 b) { return !operator==(a, b); }
+
+gbVec4 operator+(gbVec4 a) { return a; }
+gbVec4 operator-(gbVec4 a) { gbVec4 r = {-a.x, -a.y, -a.z, -a.w}; return r; }
+
+gbVec4 operator+(gbVec4 a, gbVec4 b) { gbVec4 r; gb_vec4_add(&r, a, b); return r; }
+gbVec4 operator-(gbVec4 a, gbVec4 b) { gbVec4 r; gb_vec4_sub(&r, a, b); return r; }
+
+gbVec4 operator*(gbVec4 a, float scalar) { gbVec4 r; gb_vec4_mul(&r, a, scalar); return r; }
+gbVec4 operator*(float scalar, gbVec4 a) { return operator*(a, scalar); }
+
+gbVec4 operator/(gbVec4 a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+// Hadamard Product
+gbVec4 operator*(gbVec4 a, gbVec4 b) { gbVec4 r = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return r; }
+gbVec4 operator/(gbVec4 a, gbVec4 b) { gbVec4 r = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return r; }
+
+gbVec4 &operator+=(gbVec4 &a, gbVec4 b) { return (a = a + b); }
+gbVec4 &operator-=(gbVec4 &a, gbVec4 b) { return (a = a - b); }
+gbVec4 &operator*=(gbVec4 &a, float scalar) { return (a = a * scalar); }
+gbVec4 &operator/=(gbVec4 &a, float scalar) { return (a = a / scalar); }
+
+
+gbMat2 operator+(gbMat2 const &a, gbMat2 const &b)
+{
+ int i, j;
+ gbMat2 r = {0};
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < 2; i++)
+ r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i];
+ }
+ return r;
+}
+
+gbMat2 operator-(gbMat2 const &a, gbMat2 const &b)
+{
+ int i, j;
+ gbMat2 r = {0};
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < 2; i++)
+ r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i];
+ }
+ return r;
+}
+
+gbMat2 operator*(gbMat2 const &a, gbMat2 const &b) { gbMat2 r; gb_mat2_mul(&r, (gbMat2 *)&a, (gbMat2 *)&b); return r; }
+gbVec2 operator*(gbMat2 const &a, gbVec2 v) { gbVec2 r; gb_mat2_mul_vec2(&r, (gbMat2 *)&a, v); return r; }
+gbMat2 operator*(gbMat2 const &a, float scalar)
+{
+ gbMat2 r = {0};
+ int i;
+ for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar;
+ return r;
+}
+gbMat2 operator*(float scalar, gbMat2 const &a) { return operator*(a, scalar); }
+gbMat2 operator/(gbMat2 const &a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+gbMat2& operator+=(gbMat2& a, gbMat2 const &b) { return (a = a + b); }
+gbMat2& operator-=(gbMat2& a, gbMat2 const &b) { return (a = a - b); }
+gbMat2& operator*=(gbMat2& a, gbMat2 const &b) { return (a = a * b); }
+
+
+
+gbMat3 operator+(gbMat3 const &a, gbMat3 const &b)
+{
+ int i, j;
+ gbMat3 r = {0};
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i];
+ }
+ return r;
+}
+
+gbMat3 operator-(gbMat3 const &a, gbMat3 const &b)
+{
+ int i, j;
+ gbMat3 r = {0};
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i];
+ }
+ return r;
+}
+
+gbMat3 operator*(gbMat3 const &a, gbMat3 const &b) { gbMat3 r; gb_mat3_mul(&r, (gbMat3 *)&a, (gbMat3 *)&b); return r; }
+gbVec3 operator*(gbMat3 const &a, gbVec3 v) { gbVec3 r; gb_mat3_mul_vec3(&r, (gbMat3 *)&a, v); return r; }
+gbMat3 operator*(gbMat3 const &a, float scalar)
+{
+ gbMat3 r = {0};
+ int i;
+ for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar;
+ return r;
+}
+gbMat3 operator*(float scalar, gbMat3 const &a) { return operator*(a, scalar); }
+gbMat3 operator/(gbMat3 const &a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+gbMat3& operator+=(gbMat3& a, gbMat3 const &b) { return (a = a + b); }
+gbMat3& operator-=(gbMat3& a, gbMat3 const &b) { return (a = a - b); }
+gbMat3& operator*=(gbMat3& a, gbMat3 const &b) { return (a = a * b); }
+
+
+
+gbMat4 operator+(gbMat4 const &a, gbMat4 const &b)
+{
+ int i, j;
+ gbMat4 r = {0};
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i < 4; i++)
+ r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i];
+ }
+ return r;
+}
+
+gbMat4 operator-(gbMat4 const &a, gbMat4 const &b)
+{
+ int i, j;
+ gbMat4 r = {0};
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i < 4; i++)
+ r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i];
+ }
+ return r;
+}
+
+gbMat4 operator*(gbMat4 const &a, gbMat4 const &b) { gbMat4 r; gb_mat4_mul(&r, (gbMat4 *)&a, (gbMat4 *)&b); return r; }
+gbVec4 operator*(gbMat4 const &a, gbVec4 v) { gbVec4 r; gb_mat4_mul_vec4(&r, (gbMat4 *)&a, v); return r; }
+gbMat4 operator*(gbMat4 const &a, float scalar)
+{
+ gbMat4 r = {0};
+ int i;
+ for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar;
+ return r;
+}
+gbMat4 operator*(float scalar, gbMat4 const &a) { return operator*(a, scalar); }
+gbMat4 operator/(gbMat4 const &a, float scalar) { return operator*(a, 1.0f/scalar); }
+
+gbMat4& operator+=(gbMat4 &a, gbMat4 const &b) { return (a = a + b); }
+gbMat4& operator-=(gbMat4 &a, gbMat4 const &b) { return (a = a - b); }
+gbMat4& operator*=(gbMat4 &a, gbMat4 const &b) { return (a = a * b); }
+
+
+
+bool operator==(gbQuat a, gbQuat b) { return a.xyzw == b.xyzw; }
+bool operator!=(gbQuat a, gbQuat b) { return !operator==(a, b); }
+
+gbQuat operator+(gbQuat q) { return q; }
+gbQuat operator-(gbQuat q) { return gb_quat(-q.x, -q.y, -q.z, -q.w); }
+
+gbQuat operator+(gbQuat a, gbQuat b) { gbQuat r; gb_quat_add(&r, a, b); return r; }
+gbQuat operator-(gbQuat a, gbQuat b) { gbQuat r; gb_quat_sub(&r, a, b); return r; }
+
+gbQuat operator*(gbQuat a, gbQuat b) { gbQuat r; gb_quat_mul(&r, a, b); return r; }
+gbQuat operator*(gbQuat q, float s) { gbQuat r; gb_quat_mulf(&r, q, s); return r; }
+gbQuat operator*(float s, gbQuat q) { return operator*(q, s); }
+gbQuat operator/(gbQuat q, float s) { gbQuat r; gb_quat_divf(&r, q, s); return r; }
+
+gbQuat &operator+=(gbQuat &a, gbQuat b) { gb_quat_addeq(&a, b); return a; }
+gbQuat &operator-=(gbQuat &a, gbQuat b) { gb_quat_subeq(&a, b); return a; }
+gbQuat &operator*=(gbQuat &a, gbQuat b) { gb_quat_muleq(&a, b); return a; }
+gbQuat &operator/=(gbQuat &a, gbQuat b) { gb_quat_diveq(&a, b); return a; }
+
+gbQuat &operator*=(gbQuat &a, float b) { gb_quat_muleqf(&a, b); return a; }
+gbQuat &operator/=(gbQuat &a, float b) { gb_quat_diveqf(&a, b); return a; }
+
+// Rotate v by a
+gbVec3 operator*(gbQuat q, gbVec3 v) { gbVec3 r; gb_quat_rotate_vec3(&r, q, v); return r; }
+
+#endif
+
+
+
#endif // GB_MATH_INCLUDE_GB_MATH_H
////////////////////
// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
// Implementation //
// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
////////////////////
-#if defined(GB_MATH_IMPLEMENTATION)
+#if defined(GB_MATH_IMPLEMENTATION) && !defined(GB_MATH_IMPLEMENTATION_DONE)
+#define GB_MATH_IMPLEMENTATION_DONE
-#include <math.h>
-#define VEC2_2OP(a,c,post) \
- a->x = c.x post; \
+float gb_to_radians(float degrees) { return degrees * GB_MATH_TAU / 360.0f; }
+float gb_to_degrees(float radians) { return radians * 360.0f / GB_MATH_TAU; }
+
+float
+gb_angle_diff(float radians_a, float radians_b)
+{
+ float delta = fmodf(radians_b-radians_a, GB_MATH_TAU);
+ delta = fmodf(delta + 1.5f*GB_MATH_TAU, GB_MATH_TAU);
+ delta -= 0.5f*GB_MATH_TAU;
+ return delta;
+}
+
+
+float gb_sqrt(float a) { return sqrtf(a); }
+
+float
+gb_quake_inv_sqrt(float a)
+{
+ union {
+ int i;
+ float f;
+ } t;
+ float x2;
+ float const three_halfs = 1.5f;
+
+ x2 = a * 0.5f;
+ t.f = a;
+ t.i = 0x5f375a86 - (t.i >> 1); // What the fuck?
+ t.f = t.f * (three_halfs - (x2 * t.f * t.f)); // 1st iteration
+ t.f = t.f * (three_halfs - (x2 * t.f * t.f)); // 2nd iteration, this can be removed
+
+ return t.f;
+}
+
+float gb_sin(float radians) { return sinf(radians); }
+float gb_cos(float radians) { return cosf(radians); }
+float gb_tan(float radians) { return tanf(radians); }
+float gb_arcsin(float a) { return asinf(a); }
+float gb_arccos(float a) { return acosf(a); }
+float gb_arctan(float a) { return atanf(a); }
+float gb_arctan2(float y, float x) { return atan2f(y, x); }
+
+
+
+float gb_exp(float x) { return expf(x); }
+float gb_exp2(float x) { return gb_exp(GB_MATH_LOG_TWO * x); }
+float gb_log(float x) { return logf(x); }
+float gb_log2(float x) { return gb_log(x) / GB_MATH_LOG_TWO; }
+
+float
+gb_fast_exp(float x)
+{
+ // NOTE(bill): Only works in the range -1 <= x <= +1
+ float e = 1.0f + x*(1.0f + x*0.5f*(1.0f + x*0.3333333333f*(1.0f + x*0.25*(1.0f + x*0.2f))));
+ return e;
+}
+
+float gb_fast_exp2(float x) { return gb_fast_exp(GB_MATH_LOG_TWO * x); }
+
+// TODO(bill): Should this be gb_exp(y * gb_log(x)) ???
+float gb_pow(float x, float y) { return powf(x, y); }
+
+
+typedef union {
+ unsigned int i;
+ float f;
+} gb_uif32;
+
+float
+gb_half_to_float(gb_half value)
+{
+ gb_uif32 result;
+ int s = (value >> 15) & 0x001;
+ int e = (value >> 10) & 0x01f;
+ int m = value & 0x3ff;
+
+ if (e == 0) {
+ if (m == 0) {
+ // Plus or minus zero
+ result.i = (unsigned int)(s << 31);
+ return result.f;
+ } else {
+ // Denormalized number
+ while (!(m & 0x00000400)) {
+ m <<= 1;
+ e -= 1;
+ }
+
+ e += 1;
+ m &= ~0x00000400;
+ }
+ } else if (e == 31) {
+ if (m == 0) {
+ // Positive or negative infinity
+ result.i = (unsigned int)((s << 31) | 0x7f800000);
+ return result.f;
+ } else {
+ // Nan
+ result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));
+ return result.f;
+ }
+ }
+
+ e = e + (127 - 15);
+ m = m << 13;
+
+ result.i = (unsigned int)((s << 31) | (e << 23) | m);
+ return result.f;
+}
+
+gb_half
+gb_float_to_half(float value)
+{
+ gb_uif32 v;
+ int i, s, e, m;
+
+ v.f = value;
+ i = (int)v.i;
+
+ s = (i >> 16) & 0x00008000;
+ e = ((i >> 23) & 0x000000ff) - (127 - 15);
+ m = i & 0x007fffff;
+
+
+ if (e <= 0) {
+ if (e < -10) return (gb_half)s;
+ m = (m | 0x00800000) >> (1 - e);
+
+ if (m & 0x00001000)
+ m += 0x00002000;
+
+ return (gb_half)(s | (m >> 13));
+ } else if (e == 0xff - (127 - 15)) {
+ if (m == 0) {
+ return (gb_half)(s | 0x7c00); // NOTE(bill): infinity
+ } else {
+ // NOTE(bill): NAN
+ m >>= 13;
+ return (gb_half)(s | 0x7c00 | m | (m == 0));
+ }
+ } else {
+ if (m & 0x00001000) {
+ m += 0x00002000;
+ if (m & 0x00800000) {
+ m = 0;
+ e += 1;
+ }
+ }
+
+ if (e > 30) {
+ float volatile f = 1e12f;
+ int j;
+ for (j = 0; j < 10; j++)
+ f *= f; // NOTE(bill): Cause overflow
+
+ return (gb_half)(s | 0x7c00);
+ }
+
+ return (gb_half)(s | (e << 10) | (m >> 13));
+ }
+}
+
+
+
+
+
+
+
+#define GB_VEC2_2OP(a,c,post) \
+ a->x = c.x post; \
a->y = c.y post;
-#define VEC2_3OP(a,b,op,c,post) \
- a->x = b.x op c.x post; \
+#define GB_VEC2_3OP(a,b,op,c,post) \
+ a->x = b.x op c.x post; \
a->y = b.y op c.y post;
-#define VEC3_2OP(a,c,post) \
- a->x = c.x post; \
- a->y = c.y post; \
+#define GB_VEC3_2OP(a,c,post) \
+ a->x = c.x post; \
+ a->y = c.y post; \
a->z = c.z post;
-#define VEC3_3OP(a,b,op,c,post) \
- a->x = b.x op c.x post; \
- a->y = b.y op c.y post; \
+#define GB_VEC3_3OP(a,b,op,c,post) \
+ a->x = b.x op c.x post; \
+ a->y = b.y op c.y post; \
a->z = b.z op c.z post;
-#define VEC4_2OP(a,c,post) \
- a->x = c.x post; \
- a->y = c.y post; \
- a->z = c.z post; \
+#define GB_VEC4_2OP(a,c,post) \
+ a->x = c.x post; \
+ a->y = c.y post; \
+ a->z = c.z post; \
a->w = c.w post;
-#define VEC4_3OP(a,b,op,c,post) \
- a->x = b.x op c.x post; \
- a->y = b.y op c.y post; \
- a->z = b.z op c.z post; \
+#define GB_VEC4_3OP(a,b,op,c,post) \
+ a->x = b.x op c.x post; \
+ a->y = b.y op c.y post; \
+ a->z = b.z op c.z post; \
a->w = b.w op c.w post;
-Vec2 vec2_zero(void) { Vec2 v = {0, 0}; return v; }
-Vec2 vec2(float x, float y) { Vec2 v = {x, y}; return v; }
-Vec2 vec2v(float x[2]) { Vec2 v = {x[0], x[1]}; return v; }
+gbVec2 gb_vec2_zero(void) { gbVec2 v = {0, 0}; return v; }
+gbVec2 gb_vec2(float x, float y) { gbVec2 v = {x, y}; return v; }
+gbVec2 gb_vec2v(float x[2]) { gbVec2 v = {x[0], x[1]}; return v; }
+
+gbVec3 gb_vec3_zero(void) { gbVec3 v = {0, 0, 0}; return v; }
+gbVec3 gb_vec3(float x, float y, float z) { gbVec3 v = {x, y, z}; return v; }
+gbVec3 gb_vec3v(float x[3]) { gbVec3 v = {x[0], x[1], x[2]}; return v; }
+
+gbVec4 gb_vec4_zero(void) { gbVec4 v = {0, 0, 0, 0}; return v; }
+gbVec4 gb_vec4(float x, float y, float z, float w) { gbVec4 v = {x, y, z, w}; return v; }
+gbVec4 gb_vec4v(float x[4]) { gbVec4 v = {x[0], x[1], x[2], x[3]}; return v; }
+
-Vec3 vec3_zero(void) { Vec3 v = {0, 0, 0}; return v; }
-Vec3 vec3(float x, float y, float z) { Vec3 v = {x, y, z}; return v; }
-Vec3 vec3v(float x[3]) { Vec3 v = {x[0], x[1], x[2]}; return v; }
+void gb_vec2_add(gbVec2 *d, gbVec2 v0, gbVec2 v1) { GB_VEC2_3OP(d,v0,+,v1,+0); }
+void gb_vec2_sub(gbVec2 *d, gbVec2 v0, gbVec2 v1) { GB_VEC2_3OP(d,v0,-,v1,+0); }
+void gb_vec2_mul(gbVec2 *d, gbVec2 v, float s) { GB_VEC2_2OP(d,v,* s); }
+void gb_vec2_div(gbVec2 *d, gbVec2 v, float s) { GB_VEC2_2OP(d,v,/ s); }
-Vec4 vec4_zero(void) { Vec4 v = {0, 0, 0, 0}; return v; }
-Vec4 vec4(float x, float y, float z, float w) { Vec4 v = {x, y, z, w}; return v; }
-Vec4 vec4v(float x[4]) { Vec4 v = {x[0], x[1], x[2], x[3]}; return v; }
+void gb_vec3_add(gbVec3 *d, gbVec3 v0, gbVec3 v1) { GB_VEC3_3OP(d,v0,+,v1,+0); }
+void gb_vec3_sub(gbVec3 *d, gbVec3 v0, gbVec3 v1) { GB_VEC3_3OP(d,v0,-,v1,+0); }
+void gb_vec3_mul(gbVec3 *d, gbVec3 v, float s) { GB_VEC3_2OP(d,v,* s); }
+void gb_vec3_div(gbVec3 *d, gbVec3 v, float s) { GB_VEC3_2OP(d,v,/ s); }
+void gb_vec4_add(gbVec4 *d, gbVec4 v0, gbVec4 v1) { GB_VEC4_3OP(d,v0,+,v1,+0); }
+void gb_vec4_sub(gbVec4 *d, gbVec4 v0, gbVec4 v1) { GB_VEC4_3OP(d,v0,-,v1,+0); }
+void gb_vec4_mul(gbVec4 *d, gbVec4 v, float s) { GB_VEC4_2OP(d,v,* s); }
+void gb_vec4_div(gbVec4 *d, gbVec4 v, float s) { GB_VEC4_2OP(d,v,/ s); }
-void vec2_add(Vec2 *d, Vec2 v0, Vec2 v1) { VEC2_3OP(d,v0,+,v1,+0); }
-void vec2_sub(Vec2 *d, Vec2 v0, Vec2 v1) { VEC2_3OP(d,v0,-,v1,+0); }
-void vec2_mul(Vec2 *d, Vec2 v, float s) { VEC2_2OP(d,v,* s); }
-void vec2_div(Vec2 *d, Vec2 v, float s) { VEC2_2OP(d,v,/ s); }
-void vec3_add(Vec3 *d, Vec3 v0, Vec3 v1) { VEC3_3OP(d,v0,+,v1,+0); }
-void vec3_sub(Vec3 *d, Vec3 v0, Vec3 v1) { VEC3_3OP(d,v0,-,v1,+0); }
-void vec3_mul(Vec3 *d, Vec3 v, float s) { VEC3_2OP(d,v,* s); }
-void vec3_div(Vec3 *d, Vec3 v, float s) { VEC3_2OP(d,v,/ s); }
+void gb_vec2_addeq(gbVec2 *d, gbVec2 v) { GB_VEC2_3OP(d,(*d),+,v,+0); }
+void gb_vec2_subeq(gbVec2 *d, gbVec2 v) { GB_VEC2_3OP(d,(*d),-,v,+0); }
+void gb_vec2_muleq(gbVec2 *d, float s) { GB_VEC2_2OP(d,(*d),* s); }
+void gb_vec2_diveq(gbVec2 *d, float s) { GB_VEC2_2OP(d,(*d),/ s); }
-void vec4_add(Vec4 *d, Vec4 v0, Vec4 v1) { VEC4_3OP(d,v0,+,v1,+0); }
-void vec4_sub(Vec4 *d, Vec4 v0, Vec4 v1) { VEC4_3OP(d,v0,-,v1,+0); }
-void vec4_mul(Vec4 *d, Vec4 v, float s) { VEC4_2OP(d,v,* s); }
-void vec4_div(Vec4 *d, Vec4 v, float s) { VEC4_2OP(d,v,/ s); }
+void gb_vec3_addeq(gbVec3 *d, gbVec3 v) { GB_VEC3_3OP(d,(*d),+,v,+0); }
+void gb_vec3_subeq(gbVec3 *d, gbVec3 v) { GB_VEC3_3OP(d,(*d),-,v,+0); }
+void gb_vec3_muleq(gbVec3 *d, float s) { GB_VEC3_2OP(d,(*d),* s); }
+void gb_vec3_diveq(gbVec3 *d, float s) { GB_VEC3_2OP(d,(*d),/ s); }
+void gb_vec4_addeq(gbVec4 *d, gbVec4 v) { GB_VEC4_3OP(d,(*d),+,v,+0); }
+void gb_vec4_subeq(gbVec4 *d, gbVec4 v) { GB_VEC4_3OP(d,(*d),-,v,+0); }
+void gb_vec4_muleq(gbVec4 *d, float s) { GB_VEC4_2OP(d,(*d),* s); }
+void gb_vec4_diveq(gbVec4 *d, float s) { GB_VEC4_2OP(d,(*d),/ s); }
-void vec2_addeq(Vec2 *d, Vec2 v) { VEC2_3OP(d,(*d),+,v,+0); }
-void vec2_subeq(Vec2 *d, Vec2 v) { VEC2_3OP(d,(*d),-,v,+0); }
-void vec2_muleq(Vec2 *d, float s) { VEC2_2OP(d,(*d),* s); }
-void vec2_diveq(Vec2 *d, float s) { VEC2_2OP(d,(*d),/ s); }
-void vec3_addeq(Vec3 *d, Vec3 v) { VEC3_3OP(d,(*d),+,v,+0); }
-void vec3_subeq(Vec3 *d, Vec3 v) { VEC3_3OP(d,(*d),-,v,+0); }
-void vec3_muleq(Vec3 *d, float s) { VEC3_2OP(d,(*d),* s); }
-void vec3_diveq(Vec3 *d, float s) { VEC3_2OP(d,(*d),/ s); }
+#undef GB_VEC2_2OP
+#undef GB_VEC2_3OP
+#undef GB_VEC3_3OP
+#undef GB_VEC3_2OP
+#undef GB_VEC4_2OP
+#undef GB_VEC4_3OP
-void vec4_addeq(Vec4 *d, Vec4 v) { VEC4_3OP(d,(*d),+,v,+0); }
-void vec4_subeq(Vec4 *d, Vec4 v) { VEC4_3OP(d,(*d),-,v,+0); }
-void vec4_muleq(Vec4 *d, float s) { VEC4_2OP(d,(*d),* s); }
-void vec4_diveq(Vec4 *d, float s) { VEC4_2OP(d,(*d),/ s); }
-float vec2_dot(Vec2 v0, Vec2 v1) { return v0.x*v1.x + v0.y*v1.y; }
-float vec3_dot(Vec3 v0, Vec3 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z; }
-float vec4_dot(Vec4 v0, Vec4 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z + v0.w*v1.w; }
-void vec2_cross(float *d, Vec2 v0, Vec2 v1) { *d = v0.x*v1.y - v1.x*v0.y; }
-void vec3_cross(Vec3 *d, Vec3 v0, Vec3 v1) { d->x = v0.y*v1.z - v0.z*v1.y;
+float gb_vec2_dot(gbVec2 v0, gbVec2 v1) { return v0.x*v1.x + v0.y*v1.y; }
+float gb_vec3_dot(gbVec3 v0, gbVec3 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z; }
+float gb_vec4_dot(gbVec4 v0, gbVec4 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z + v0.w*v1.w; }
+
+void gb_vec2_cross(float *d, gbVec2 v0, gbVec2 v1) { *d = v0.x*v1.y - v1.x*v0.y; }
+void gb_vec3_cross(gbVec3 *d, gbVec3 v0, gbVec3 v1) { d->x = v0.y*v1.z - v0.z*v1.y;
d->y = v0.z*v1.x - v0.x*v1.z;
d->z = v0.x*v1.y - v0.y*v1.x; }
-float vec2_mag2(Vec2 v) { return vec2_dot(v, v); }
-float vec3_mag2(Vec3 v) { return vec3_dot(v, v); }
-float vec4_mag2(Vec4 v) { return vec4_dot(v, v); }
+float gb_vec2_mag2(gbVec2 v) { return gb_vec2_dot(v, v); }
+float gb_vec3_mag2(gbVec3 v) { return gb_vec3_dot(v, v); }
+float gb_vec4_mag2(gbVec4 v) { return gb_vec4_dot(v, v); }
// TODO(bill): Create custom sqrt function
-float vec2_mag(Vec2 v) { return sqrtf(vec2_dot(v, v)); }
-float vec3_mag(Vec3 v) { return sqrtf(vec3_dot(v, v)); }
-float vec4_mag(Vec4 v) { return sqrtf(vec4_dot(v, v)); }
+float gb_vec2_mag(gbVec2 v) { return gb_sqrt(gb_vec2_dot(v, v)); }
+float gb_vec3_mag(gbVec3 v) { return gb_sqrt(gb_vec3_dot(v, v)); }
+float gb_vec4_mag(gbVec4 v) { return gb_sqrt(gb_vec4_dot(v, v)); }
// TODO(bill): Should I calculate inv_sqrt directly?
-void vec2_norm(Vec2 *d, Vec2 v) { vec2_div(d, v, vec2_mag(v)); }
-void vec3_norm(Vec3 *d, Vec3 v) { vec3_div(d, v, vec3_mag(v)); }
-void vec4_norm(Vec4 *d, Vec4 v) { vec4_div(d, v, vec4_mag(v)); }
-
-float vec2_aspect(Vec2 v)
+void
+gb_vec2_norm(gbVec2 *d, gbVec2 v)
{
- if (v.y < 0.0001f)
- return 0.0f;
- return v.x/v.y;
+ float mag = gb_vec2_mag(v);
+ gb_vec2_div(d, v, mag);
+}
+void
+gb_vec3_norm(gbVec3 *d, gbVec3 v)
+{
+ float mag = gb_vec3_mag(v);
+ gb_vec3_div(d, v, mag);
+}
+void
+gb_vec4_norm(gbVec4 *d, gbVec4 v)
+{
+ float mag = gb_vec4_mag(v);
+ gb_vec4_div(d, v, mag);
}
+void
+gb_vec2_norm0(gbVec2 *d, gbVec2 v)
+{
+ float mag = gb_vec2_mag(v);
+ if (mag > 0)
+ gb_vec2_div(d, v, mag);
+ else
+ *d = gb_vec2_zero();
+}
+void
+gb_vec3_norm0(gbVec3 *d, gbVec3 v)
+{
+ float mag = gb_vec3_mag(v);
+ if (mag > 0)
+ gb_vec3_div(d, v, mag);
+ else
+ *d = gb_vec3_zero();
+}
+void
+gb_vec4_norm0(gbVec4 *d, gbVec4 v)
+{
+ float mag = gb_vec4_mag(v);
+ if (mag > 0)
+ gb_vec4_div(d, v, mag);
+ else
+ *d = gb_vec4_zero();
+}
+void
+gb_vec2_reflect(gbVec2 *d, gbVec2 i, gbVec2 n)
+{
+ gbVec2 b = n;
+ gb_vec2_muleq(&b, 2.0f*gb_vec2_dot(n, i));
+ gb_vec2_sub(d, i, b);
+}
+void
+gb_vec3_reflect(gbVec3 *d, gbVec3 i, gbVec3 n)
+{
+ gbVec3 b = n;
+ gb_vec3_muleq(&b, 2.0f*gb_vec3_dot(n, i));
+ gb_vec3_sub(d, i, b);
+}
-void mat2_transpose(Mat2 *m) { float22_transpose(float22_m(m)); }
-void mat2_identity(Mat2 *m) { float22_identity(float22_m(m)); }
-void mat2_mul(Mat2 *out, Mat2 *m1, Mat2 *m2) { float22_mul(float22_m(out), float22_m(m1), float22_m(m2)); }
+void
+gb_vec2_refract(gbVec2 *d, gbVec2 i, gbVec2 n, float eta)
+{
+ gbVec2 a, b;
+ float dv, k;
+
+ dv = gb_vec2_dot(n, i);
+ k = 1.0f - eta*eta * (1.0f - dv*dv);
+ gb_vec2_mul(&a, i, eta);
+ gb_vec2_mul(&b, n, eta*dv*gb_sqrt(k));
+ gb_vec2_sub(d, a, b);
+ gb_vec2_muleq(d, (float)(k >= 0.0f));
+}
void
-float22_identity(float m[2][2])
+gb_vec3_refract(gbVec3 *d, gbVec3 i, gbVec3 n, float eta)
{
- m[0][0] = 1; m[0][1] = 0;
- m[1][0] = 0; m[1][1] = 1;
+ gbVec3 a, b;
+ float dv, k;
+
+ dv = gb_vec3_dot(n, i);
+ k = 1.0f - eta*eta * (1.0f - dv*dv);
+ gb_vec3_mul(&a, i, eta);
+ gb_vec3_mul(&b, n, eta*dv*gb_sqrt(k));
+ gb_vec3_sub(d, a, b);
+ gb_vec3_muleq(d, (float)(k >= 0.0f));
}
+
+
+
+
+float gb_vec2_aspect_ratio(gbVec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x/v.y; }
+
+
+
+
+
+void gb_mat2_transpose(gbMat2 *m) { gb_float22_transpose(gb_float22_m(m)); }
+void gb_mat2_identity(gbMat2 *m) { gb_float22_identity(gb_float22_m(m)); }
+void gb_mat2_mul(gbMat2 *out, gbMat2 *m1, gbMat2 *m2) { gb_float22_mul(gb_float22_m(out), gb_float22_m(m1), gb_float22_m(m2)); }
+
void
-mat2_mul_vec2(Vec2 *out, Mat2 *m, Vec2 in)
+gb_float22_identity(float m[2][2])
{
- float22_mul_vec2(out, float22_m(m), in);
+ m[0][0] = 1; m[0][1] = 0;
+ m[1][0] = 0; m[1][1] = 1;
}
-Mat2 *mat2_v(Vec2 m[2]) { return (Mat2 *)m; }
-Mat2 *mat2_f(float m[2][2]) { return (Mat2 *)m; }
+void gb_mat2_mul_vec2(gbVec2 *out, gbMat2 *m, gbVec2 in) { gb_float22_mul_vec2(out, gb_float22_m(m), in); }
-Float2 *float22_m(Mat2 *m) { return (Float2 *)m; }
-Float2 *float22_v(Vec2 m[2]) { return (Float2 *)m; }
-Float2 *float22_4(float m[4]) { return (Float2 *)m; }
+gbMat2 *gb_mat2_v(gbVec2 m[2]) { return (gbMat2 *)m; }
+gbMat2 *gb_mat2_f(float m[2][2]) { return (gbMat2 *)m; }
+
+gbFloat2 *gb_float22_m(gbMat2 *m) { return (gbFloat2 *)m; }
+gbFloat2 *gb_float22_v(gbVec2 m[2]) { return (gbFloat2 *)m; }
+gbFloat2 *gb_float22_4(float m[4]) { return (gbFloat2 *)m; }
void
-float22_transpose(float (*vec)[2])
+gb_float22_transpose(float (*vec)[2])
{
int i, j;
for (j = 0; j < 2; j++) {
@@ -443,7 +1136,7 @@ float22_transpose(float (*vec)[2])
}
void
-float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2])
+gb_float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2])
{
int i, j;
float temp1[2][2], temp2[2][2];
@@ -458,10 +1151,10 @@ float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2])
}
void
-float22_mul_vec2(Vec2 *out, float m[2][2], Vec2 v)
+gb_float22_mul_vec2(gbVec2 *out, float m[2][2], gbVec2 v)
{
- out->x = m[0][0] * v.x + m[0][1] * v.y;
- out->y = m[1][0] * v.x + m[1][1] * v.y;
+ out->x = m[0][0]*v.x + m[0][1]*v.y;
+ out->y = m[1][0]*v.x + m[1][1]*v.y;
}
@@ -469,33 +1162,29 @@ float22_mul_vec2(Vec2 *out, float m[2][2], Vec2 v)
-void mat3_transpose(Mat3 *m) { float33_transpose(float33_m(m)); }
-void mat3_identity(Mat3 *m) { float33_identity(float33_m(m)); }
-void mat3_mul(Mat3 *out, Mat3 *m1, Mat3 *m2) { float33_mul(float33_m(out), float33_m(m1), float33_m(m2)); }
+void gb_mat3_transpose(gbMat3 *m) { gb_float33_transpose(gb_float33_m(m)); }
+void gb_mat3_identity(gbMat3 *m) { gb_float33_identity(gb_float33_m(m)); }
+void gb_mat3_mul(gbMat3 *out, gbMat3 *m1, gbMat3 *m2) { gb_float33_mul(gb_float33_m(out), gb_float33_m(m1), gb_float33_m(m2)); }
void
-float33_identity(float m[3][3])
+gb_float33_identity(float m[3][3])
{
m[0][0] = 1; m[0][1] = 0; m[0][2] = 0;
m[1][0] = 0; m[1][1] = 1; m[1][2] = 0;
m[2][0] = 0; m[2][1] = 0; m[2][2] = 1;
}
-void
-mat3_mul_vec3(Vec3 *out, Mat3 *m, Vec3 in)
-{
- float33_mul_vec3(out, float33_m(m), in);
-}
+void gb_mat3_mul_vec3(gbVec3 *out, gbMat3 *m, gbVec3 in) { gb_float33_mul_vec3(out, gb_float33_m(m), in); }
-Mat3 *mat3_v(Vec3 m[3]) { return (Mat3 *)m; }
-Mat3 *mat3_f(float m[3][3]) { return (Mat3 *)m; }
+gbMat3 *gb_mat3_v(gbVec3 m[3]) { return (gbMat3 *)m; }
+gbMat3 *gb_mat3_f(float m[3][3]) { return (gbMat3 *)m; }
-Float3 *float33_m(Mat3 *m) { return (Float3 *)m; }
-Float3 *float33_v(Vec3 m[3]) { return (Float3 *)m; }
-Float3 *float33_16(float m[9]) { return (Float3 *)m; }
+gbFloat3 *gb_float33_m(gbMat3 *m) { return (gbFloat3 *)m; }
+gbFloat3 *gb_float33_v(gbVec3 m[3]) { return (gbFloat3 *)m; }
+gbFloat3 *gb_float33_16(float m[9]) { return (gbFloat3 *)m; }
void
-float33_transpose(float (*vec)[3])
+gb_float33_transpose(float (*vec)[3])
{
int i, j;
for (j = 0; j < 3; j++) {
@@ -508,7 +1197,7 @@ float33_transpose(float (*vec)[3])
}
void
-float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3])
+gb_float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3])
{
int i, j;
float temp1[3][3], temp2[3][3];
@@ -524,11 +1213,11 @@ float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3])
}
void
-float33_mul_vec3(Vec3 *out, float m[3][3], Vec3 v)
+gb_float33_mul_vec3(gbVec3 *out, float m[3][3], gbVec3 v)
{
- out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z;
- out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z;
- out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z;
+ out->x = m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z;
+ out->y = m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z;
+ out->z = m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z;
}
@@ -539,12 +1228,12 @@ float33_mul_vec3(Vec3 *out, float m[3][3], Vec3 v)
-void mat4_transpose(Mat4 *m) { float44_transpose(float44_m(m)); }
-void mat4_identity(Mat4 *m) { float44_identity(float44_m(m)); }
-void mat4_mul(Mat4 *out, Mat4 *m1, Mat4 *m2) { float44_mul(float44_m(out), float44_m(m1), float44_m(m2)); }
+void gb_mat4_transpose(gbMat4 *m) { gb_float44_transpose(gb_float44_m(m)); }
+void gb_mat4_identity(gbMat4 *m) { gb_float44_identity(gb_float44_m(m)); }
+void gb_mat4_mul(gbMat4 *out, gbMat4 *m1, gbMat4 *m2) { gb_float44_mul(gb_float44_m(out), gb_float44_m(m1), gb_float44_m(m2)); }
void
-float44_identity(float m[4][4])
+gb_float44_identity(float m[4][4])
{
m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
@@ -553,20 +1242,20 @@ float44_identity(float m[4][4])
}
void
-mat4_mul_vec4(Vec4 *out, Mat4 *m, Vec4 in)
+gb_mat4_mul_vec4(gbVec4 *out, gbMat4 *m, gbVec4 in)
{
- float44_mul_vec4(out, float44_m(m), in);
+ gb_float44_mul_vec4(out, gb_float44_m(m), in);
}
-Mat4 *mat4_v(Vec4 m[4]) { return (Mat4 *)m; }
-Mat4 *mat4_f(float m[4][4]) { return (Mat4 *)m; }
+gbMat4 *gb_mat4_v(gbVec4 m[4]) { return (gbMat4 *)m; }
+gbMat4 *gb_mat4_f(float m[4][4]) { return (gbMat4 *)m; }
-Float4 *float44_m(Mat4 *m) { return (Float4 *)m; }
-Float4 *float44_v(Vec4 m[4]) { return (Float4 *)m; }
-Float4 *float44_16(float m[16]) { return (Float4 *)m; }
+gbFloat4 *gb_float44_m(gbMat4 *m) { return (gbFloat4 *)m; }
+gbFloat4 *gb_float44_v(gbVec4 m[4]) { return (gbFloat4 *)m; }
+gbFloat4 *gb_float44_16(float m[16]) { return (gbFloat4 *)m; }
void
-float44_transpose(float (*vec)[4])
+gb_float44_transpose(float (*vec)[4])
{
int i, j;
for (j = 0; j < 4; j++) {
@@ -579,7 +1268,7 @@ float44_transpose(float (*vec)[4])
}
void
-float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4])
+gb_float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4])
{
int i, j;
float temp1[4][4], temp2[4][4];
@@ -596,44 +1285,81 @@ float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4])
}
void
-float44_mul_vec4(Vec4 *out, float m[4][4], Vec4 v)
+gb_float44_mul_vec4(gbVec4 *out, float m[4][4], gbVec4 v)
{
- out->x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w;
- out->y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w;
- out->z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w;
- out->w = m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w;
+ out->x = m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3]*v.w;
+ out->y = m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3]*v.w;
+ out->z = m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]*v.w;
+ out->w = m[3][0]*v.x + m[3][1]*v.y + m[3][2]*v.z + m[3][3]*v.w;
}
+void
+gb_mat4_translate(gbMat4 *out, gbVec3 v)
+{
+ gb_mat4_identity(out);
+ out->col[3].xyz = v;
+ out->col[3].w = 1;
+}
-float lerp(float a, float b, float t) { return a*(1.0f-t) + b*t; }
-float smooth_step(float a, float b, float t) { float x = (t - a)/(b - a); return x*x*(3.0f - 2.0f*x); }
-float smoother_step(float a, float b, float t) { float x = (t - a)/(b - a); return x*x*x*(x*(6.0f*x - 15.0f) + 10.0f); }
-
-#define VEC_LERPN(N, d, a, b, t) Vec##N db; vec##N##_mul(&db, b, t); vec##N##_add(d, a, db)
-void vec2_lerp(Vec2 *d, Vec2 a, Vec2 b, float t) { VEC_LERPN(2, d, a, b, t); }
-void vec3_lerp(Vec3 *d, Vec3 a, Vec3 b, float t) { VEC_LERPN(3, d, a, b, t); }
-void vec4_lerp(Vec4 *d, Vec4 a, Vec4 b, float t) { VEC_LERPN(4, d, a, b, t); }
-
+void
+gb_mat4_rotate(gbMat4 *out, gbVec3 v, float angle_radians)
+{
+ float c, s;
+ gbVec3 axis, t;
+ gbFloat4 *rot;
+ c = gb_cos(angle_radians);
+ s = gb_sin(angle_radians);
+ gb_vec3_norm(&axis, v);
+ gb_vec3_mul(&t, axis, 1.0f-c);
+ gb_mat4_identity(out);
+ rot = gb_float44_m(out);
-float to_radians(float degrees) { return degrees * MATH_TAU / 360.0f; }
-float to_degrees(float radians) { return radians * 360.0f / MATH_TAU; }
+ rot[0][0] = c + t.x*axis.x;
+ rot[0][1] = 0 + t.x*axis.y + s*axis.z;
+ rot[0][2] = 0 + t.x*axis.z - s*axis.y;
+ rot[0][3] = 0;
+ rot[1][0] = 0 + t.y*axis.x - s*axis.z;
+ rot[1][1] = c + t.y*axis.y;
+ rot[1][2] = 0 + t.y*axis.z + s*axis.x;
+ rot[1][3] = 0;
+ rot[2][0] = 0 + t.z*axis.x + s*axis.y;
+ rot[2][1] = 0 + t.z*axis.y - s*axis.x;
+ rot[2][2] = c + t.z*axis.z;
+ rot[2][3] = 0;
+}
+void
+gb_mat4_scale(gbMat4 *out, gbVec3 v)
+{
+ gb_mat4_identity(out);
+ out->e[0] = v.x;
+ out->e[5] = v.y;
+ out->e[10] = v.z;
+}
+void
+gb_mat4_scalef(gbMat4 *out, float s)
+{
+ gb_mat4_identity(out);
+ out->e[0] = s;
+ out->e[5] = s;
+ out->e[10] = s;
+}
void
-mat4_ortho2d(Mat4 *out, float left, float right, float bottom, float top)
+gb_mat4_ortho2d(gbMat4 *out, float left, float right, float bottom, float top)
{
- Float4 *m;
- mat4_identity(out);
- m = float44_m(out);
+ gbFloat4 *m;
+ gb_mat4_identity(out);
+ m = gb_float44_m(out);
m[0][0] = 2.0f / (right - left);
m[1][1] = 2.0f / (top - bottom);
@@ -643,37 +1369,480 @@ mat4_ortho2d(Mat4 *out, float left, float right, float bottom, float top)
}
void
-mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float z_near, float z_far)
+gb_mat4_ortho3d(gbMat4 *out, float left, float right, float bottom, float top, float z_near, float z_far)
{
- Float4 *m;
- mat4_identity(out);
- m = float44_m(out);
+ gbFloat4 *m;
+ gb_mat4_identity(out);
+ m = gb_float44_m(out);
m[0][0] = +2.0f / (right - left);
m[1][1] = +2.0f / (top - bottom);
m[2][2] = -2.0f / (z_far - z_near);
- m[3][0] = -(right + left) / (right - left);
- m[3][1] = -(top + bottom) / (top - bottom);
+ m[3][0] = -(right + left) / (right - left);
+ m[3][1] = -(top + bottom) / (top - bottom);
m[3][2] = -(z_far + z_near) / (z_far - z_near);
}
-#if defined(__x86_64__) || defined(__ppc64__)
+void
+gb_mat4_perspective(gbMat4 *out, float fovy, float aspect, float z_near, float z_far)
+{
+ float tan_half_fovy = gb_tan(0.5f * fovy);
+
+ gbFloat4 *m = gb_float44_m(out);
+ memset(m, 0, sizeof(gbMat4));
+
+ m[0][0] = 1.0f / (aspect*tan_half_fovy);
+ m[1][1] = 1.0f / (tan_half_fovy);
+ m[2][2] = -(z_far + z_near) / (z_far - z_near);
+ m[2][3] = -1.0f;
+ m[3][2] = -2.0f*z_far*z_near / (z_far - z_near);
+}
+
+void
+gb_mat4_infinite_perspective(gbMat4 *out, float fovy, float aspect, float z_near)
+{
+ float range = gb_tan(0.5f * fovy) * z_near;
+ float left = -range * aspect;
+ float right = range * aspect;
+ float bottom = -range;
+ float top = range;
+
+ gbFloat4 *m = gb_float44_m(out);
+ memset(m, 0, sizeof(gbMat4));
+
+ m[0][0] = (2.0f*z_near) / (right - left);
+ m[1][1] = (2.0f*z_near) / (top - bottom);
+ m[2][2] = -1.0f;
+ m[2][3] = -1.0f;
+ m[3][2] = -2.0f*z_near;
+}
+
+void
+gb_mat4_look_at(gbMat4 *out, gbVec3 eye, gbVec3 centre, gbVec3 up)
+{
+ gbVec3 f, s, u;
+ gbFloat4 *m;
+
+ gb_vec3_sub(&f, centre, eye);
+ gb_vec3_norm(&f, f);
+
+ gb_vec3_cross(&s, f, up);
+ gb_vec3_norm(&s, s);
+
+ gb_vec3_cross(&u, s, f);
+
+ gb_mat4_identity(out);
+ m = gb_float44_m(out);
+
+ m[0][0] = +s.x;
+ m[1][0] = +s.y;
+ m[2][0] = +s.z;
+
+ m[0][1] = +u.x;
+ m[1][1] = +u.y;
+ m[2][1] = +u.z;
+
+ m[0][2] = -f.x;
+ m[1][2] = -f.y;
+ m[2][2] = -f.z;
+
+ m[3][0] = gb_vec3_dot(s, eye);
+ m[3][1] = gb_vec3_dot(u, eye);
+ m[3][2] = gb_vec3_dot(f, eye);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+gbQuat gb_quat(float x, float y, float z, float w) { gbQuat q = {x, y, z, w}; return q; }
+gbQuat gb_quatv(float e[4]) { gbQuat q = {e[0], e[1], e[2], e[3]}; return q; }
+
+gbQuat
+gb_quat_axis_angle(gbVec3 axis, float angle_radians)
+{
+ gbQuat q;
+ gb_vec3_norm(&q.xyz, axis);
+ gb_vec3_muleq(&q.xyz, gb_sin(0.5f*angle_radians));
+ q.w = gb_cos(0.5f*angle_radians);
+ return q;
+}
+
+gbQuat
+gb_quat_euler_angles(float pitch, float yaw, float roll)
+{
+ // TODO(bill): Do without multiplication, i.e. make it faster
+ gbQuat q, p, y, r;
+ p = gb_quat_axis_angle(gb_vec3(1, 0, 0), pitch);
+ y = gb_quat_axis_angle(gb_vec3(0, 1, 0), yaw);
+ r = gb_quat_axis_angle(gb_vec3(0, 0, 1), roll);
+
+ gb_quat_mul(&q, y, p);
+ gb_quat_muleq(&q, r);
+
+ return q;
+}
+
+gbQuat gb_quat_identity(void) { gbQuat q = {0, 0, 0, 1}; return q; }
+
+
+void gb_quat_add(gbQuat *d, gbQuat q0, gbQuat q1) { gb_vec4_add(&d->xyzw, q0.xyzw, q1.xyzw); }
+void gb_quat_sub(gbQuat *d, gbQuat q0, gbQuat q1) { gb_vec4_sub(&d->xyzw, q0.xyzw, q1.xyzw); }
+
+void
+gb_quat_mul(gbQuat *d, gbQuat q0, gbQuat q1)
+{
+ d->x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
+ d->y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
+ d->z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
+ d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
+}
+
+void gb_quat_div(gbQuat *d, gbQuat q0, gbQuat q1){ gbQuat iq1; gb_quat_inverse(&iq1, q1); gb_quat_mul(d, q0, iq1); }
+
+void gb_quat_mulf(gbQuat *d, gbQuat q0, float s) { gb_vec4_mul(&d->xyzw, q0.xyzw, s); }
+void gb_quat_divf(gbQuat *d, gbQuat q0, float s) { gb_vec4_div(&d->xyzw, q0.xyzw, s); }
+
+
+void gb_quat_addeq(gbQuat *d, gbQuat q) { gb_vec4_addeq(&d->xyzw, q.xyzw); }
+void gb_quat_subeq(gbQuat *d, gbQuat q) { gb_vec4_subeq(&d->xyzw, q.xyzw); }
+void gb_quat_muleq(gbQuat *d, gbQuat q) { gb_quat_mul(d, *d, q); }
+void gb_quat_diveq(gbQuat *d, gbQuat q) { gb_quat_div(d, *d, q); }
+
+
+void gb_quat_muleqf(gbQuat *d, float s) { gb_vec4_muleq(&d->xyzw, s); }
+void gb_quat_diveqf(gbQuat *d, float s) { gb_vec4_diveq(&d->xyzw, s); }
+
+float gb_quat_dot(gbQuat q0, gbQuat q1) { float r = gb_vec3_dot(q0.xyz, q1.xyz) + q0.w*q1.w; return r; }
+float gb_quat_mag(gbQuat q) { float r = gb_sqrt(gb_quat_dot(q, q)); return r; }
+
+void gb_quat_norm(gbQuat *d, gbQuat q) { gb_quat_divf(d, q, gb_quat_mag(q)); }
+void gb_quat_conj(gbQuat *d, gbQuat q) { d->xyz = gb_vec3(-q.x, -q.y, -q.z); d->w = q.w; }
+void gb_quat_inverse(gbQuat *d, gbQuat q) { gb_quat_conj(d, q); gb_quat_diveqf(d, gb_quat_dot(q, q)); }
+
+
+void
+gb_quat_axis(gbVec3 *axis, gbQuat q)
+{
+ gbQuat n; gb_quat_norm(&n, q);
+ gb_vec3_div(axis, n.xyz, gb_sin(gb_arccos(q.w)));
+}
+
+float
+gb_quat_angle(gbQuat q)
+{
+ float mag = gb_quat_mag(q);
+ float c = q.w * (1.0f/mag);
+ float angle = 2.0f*gb_arccos(c);
+ return angle;
+}
+
+
+float gb_quat_roll(gbQuat q) { return gb_arctan2(2.0f*q.x*q.y + q.z*q.w, q.x*q.x + q.w*q.w - q.y*q.y - q.z*q.z); }
+float gb_quat_pitch(gbQuat q) { return gb_arctan2(2.0f*q.y*q.z + q.w*q.x, q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z); }
+float gb_quat_yaw(gbQuat q) { return gb_arcsin(-2.0f*(q.x*q.z - q.w*q.y)); }
+
+void
+gb_quat_rotate_vec3(gbVec3 *d, gbQuat q, gbVec3 v)
+{
+ // gbVec3 t = 2.0f * cross(q.xyz, v);
+ // *d = q.w*t + v + cross(q.xyz, t);
+ gbVec3 t, p;
+ gb_vec3_cross(&t, q.xyz, v);
+ gb_vec3_muleq(&t, 2.0f);
+
+ gb_vec3_cross(&p, q.xyz, t);
+
+ gb_vec3_mul(d, t, q.w);
+ gb_vec3_addeq(d, v);
+ gb_vec3_addeq(d, p);
+}
+
+
+void
+gb_mat4_from_quat(gbMat4 *out, gbQuat q)
+{
+ gbFloat4 *m;
+ gbQuat a;
+ float xx, yy, zz,
+ xy, xz, yz,
+ wx, wy, wz;
+
+ gb_quat_norm(&a, q);
+ xx = a.x*a.x; yy = a.y*a.y; zz = a.z*a.z;
+ xy = a.x*a.y; xz = a.x*a.z; yz = a.y*a.z;
+ wx = a.w*a.x; wy = a.w*a.y; wz = a.w*a.z;
+
+ gb_mat4_identity(out);
+ m = gb_float44_m(out);
+
+ m[0][0] = 1.0f - 2.0f*(yy + zz);
+ m[0][1] = 2.0f*(xy + wz);
+ m[0][2] = 2.0f*(xz - wy);
+
+ m[1][0] = 2.0f*(xy - wz);
+ m[1][1] = 1.0f - 2.0f*(xx + zz);
+ m[1][2] = 2.0f*(yz + wx);
+
+ m[2][0] = 2.0f*(xz + wy);
+ m[2][1] = 2.0f*(yz - wx);
+ m[2][2] = 1.0f - 2.0f*(xx + yy);
+}
+
+void
+gb_quat_from_mat4(gbQuat *out, gbMat4 *mat)
+{
+ gbFloat4 *m;
+ float four_x_squared_minus_1, four_y_squared_minus_1,
+ four_z_squared_minus_1, four_w_squared_minus_1,
+ four_biggest_squared_minus_1;
+ int biggest_index = 0;
+ float biggest_value, mult;
+
+ m = gb_float44_m(mat);
+
+ four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
+ four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
+ four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
+ four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
+
+ four_biggest_squared_minus_1 = four_w_squared_minus_1;
+ if (four_x_squared_minus_1 > four_biggest_squared_minus_1) {
+ four_biggest_squared_minus_1 = four_x_squared_minus_1;
+ biggest_index = 1;
+ }
+ if (four_y_squared_minus_1 > four_biggest_squared_minus_1) {
+ four_biggest_squared_minus_1 = four_y_squared_minus_1;
+ biggest_index = 2;
+ }
+ if (four_z_squared_minus_1 > four_biggest_squared_minus_1) {
+ four_biggest_squared_minus_1 = four_z_squared_minus_1;
+ biggest_index = 3;
+ }
+
+ biggest_value = gb_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f;
+ mult = 0.25f / biggest_value;
+
+ switch (biggest_index) {
+ case 0:
+ out->w = biggest_value;
+ out->x = (m[1][2] - m[2][1]) * mult;
+ out->y = (m[2][0] - m[0][2]) * mult;
+ out->z = (m[0][1] - m[1][0]) * mult;
+ break;
+ case 1:
+ out->w = (m[1][2] - m[2][1]) * mult;
+ out->x = biggest_value;
+ out->y = (m[0][1] + m[1][0]) * mult;
+ out->z = (m[2][0] + m[0][2]) * mult;
+ break;
+ case 2:
+ out->w = (m[2][0] - m[0][2]) * mult;
+ out->x = (m[0][1] + m[1][0]) * mult;
+ out->y = biggest_value;
+ out->z = (m[1][2] + m[2][1]) * mult;
+ break;
+ case 3:
+ out->w = (m[0][1] - m[1][0]) * mult;
+ out->x = (m[2][0] + m[0][2]) * mult;
+ out->y = (m[1][2] + m[2][1]) * mult;
+ out->z = biggest_value;
+ break;
+ default:
+ // NOTE(bill): This shouldn't fucking happen!!!
+ break;
+ }
+
+}
+
+
+
+
+
+
+float gb_lerp(float a, float b, float t) { return a*(1.0f-t) + b*t; }
+float gb_smooth_step(float a, float b, float t) { float x = (t - a)/(b - a); return x*x*(3.0f - 2.0f*x); }
+float gb_smoother_step(float a, float b, float t) { float x = (t - a)/(b - a); return x*x*x*(x*(6.0f*x - 15.0f) + 10.0f); }
+
+
+#define GB_VEC_LERPN(N, d, a, b, t) \
+ gbVec##N db; \
+ gb_vec##N##_sub(&db, b, a); \
+ gb_vec##N##_muleq(&db, t); \
+ gb_vec##N##_add(d, a, db)
+void gb_vec2_lerp(gbVec2 *d, gbVec2 a, gbVec2 b, float t) { GB_VEC_LERPN(2, d, a, b, t); }
+void gb_vec3_lerp(gbVec3 *d, gbVec3 a, gbVec3 b, float t) { GB_VEC_LERPN(3, d, a, b, t); }
+void gb_vec4_lerp(gbVec4 *d, gbVec4 a, gbVec4 b, float t) { GB_VEC_LERPN(4, d, a, b, t); }
+
+#undef GB_VEC_LERPN
+
+void gb_quat_lerp(gbQuat *d, gbQuat a, gbQuat b, float t) { gb_vec4_lerp(&d->xyzw, a.xyzw, b.xyzw, t); }
+void gb_quat_nlerp(gbQuat *d, gbQuat a, gbQuat b, float t) { gb_quat_lerp(d, a, b, t); gb_quat_norm(d, *d); }
+
+void
+gb_quat_slerp(gbQuat *d, gbQuat a, gbQuat b, float t)
+{
+ gbQuat x, y, z;
+ float cos_theta, angle;
+ float s1, s0, is;
+
+ z = b;
+ cos_theta = gb_quat_dot(a, b);
+
+ if (cos_theta < 0.0f) {
+ z = gb_quat(-b.x, -b.y, -b.z, -b.w);
+ cos_theta = -cos_theta;
+ }
+
+ if (cos_theta > 1.0f) {
+ // NOTE(bill): Use lerp not nlerp as it's not a real angle or they are not normalized
+ gb_quat_lerp(d, a, b, t);
+ }
+
+ angle = gb_arccos(cos_theta);
+
+ s1 = gb_sin(1.0f - t*angle);
+ s0 = gb_sin(t*angle);
+ is = 1.0f/gb_sin(angle);
+ gb_quat_mulf(&x, z, s1);
+ gb_quat_mulf(&y, z, s0);
+ gb_quat_add(d, x, y);
+ gb_quat_muleqf(d, is);
+}
+
+void
+gb_quat_slerp_approx(gbQuat *d, gbQuat a, gbQuat b, float t)
+{
+ // NOTE(bill): Derived by taylor expanding the geometric interpolation equation
+ // Even works okay for nearly anti-parallel versors!!!
+ // NOTE(bill): Extra interations cannot be used as they require angle^4 which is not worth it to approximate
+ float tp = t + (1.0f - gb_quat_dot(a, b))/3.0f * t*(-2.0f*t*t + 3.0f*t - 1.0f);
+ gb_quat_nlerp(d, a, b, tp);
+}
+
+void
+gb_quat_nquad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t)
+{
+ gbQuat x, y;
+ gb_quat_nlerp(&x, p, q, t);
+ gb_quat_nlerp(&y, a, b, t);
+ gb_quat_nlerp(d, x, y, 2.0f*t*(1.0f-t));
+}
+
+void
+gb_quat_squad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t)
+{
+ gbQuat x, y;
+ gb_quat_slerp(&x, p, q, t);
+ gb_quat_slerp(&y, a, b, t);
+ gb_quat_slerp(d, x, y, 2.0f*t*(1.0f-t));
+}
+
+void
+gb_quat_squad_approx(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t)
+{
+ gbQuat x, y;
+ gb_quat_slerp_approx(&x, p, q, t);
+ gb_quat_slerp_approx(&y, a, b, t);
+ gb_quat_slerp_approx(d, x, y, 2.0f*t*(1.0f-t));
+}
+
+
- u64
- hash_murmur64(void const *key, size_t num_bytes)
+
+
+
+gbRect2
+gb_rect2(gbVec2 pos, gbVec2 dim)
+{
+ gbRect2 r;
+ r.pos = pos;
+ r.dim = dim;
+ return r;
+}
+
+gbRect3
+gb_rect3(gbVec3 pos, gbVec3 dim)
+{
+ gbRect3 r;
+ r.pos = pos;
+ r.dim = dim;
+ return r;
+}
+
+int
+gb_rect2_contains(gbRect2 a, float x, float y)
+{
+ float min_x = gb_min(a.pos.x, a.pos.x+a.dim.x);
+ float max_x = gb_max(a.pos.x, a.pos.x+a.dim.x);
+ float min_y = gb_min(a.pos.y, a.pos.y+a.dim.y);
+ float max_y = gb_max(a.pos.y, a.pos.y+a.dim.y);
+ int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y);
+ return result;
+}
+
+int gb_rect2_contains_vec2(gbRect2 a, gbVec2 p) { return gb_rect2_contains(a, p.x, p.y); }
+
+int
+gb_rect2_intersects(gbRect2 a, gbRect2 b)
+{
+ gbRect2 r = {0};
+ return gb_rect2_intersection_result(a, b, &r);
+}
+
+int
+gb_rect2_intersection_result(gbRect2 a, gbRect2 b, gbRect2 *intersection)
+{
+ float a_min_x = gb_min(a.pos.x, a.pos.x+a.dim.x);
+ float a_max_x = gb_max(a.pos.x, a.pos.x+a.dim.x);
+ float a_min_y = gb_min(a.pos.y, a.pos.y+a.dim.y);
+ float a_max_y = gb_max(a.pos.y, a.pos.y+a.dim.y);
+
+ float b_min_x = gb_min(b.pos.x, b.pos.x+b.dim.x);
+ float b_max_x = gb_max(b.pos.x, b.pos.x+b.dim.x);
+ float b_min_y = gb_min(b.pos.y, b.pos.y+b.dim.y);
+ float b_max_y = gb_max(b.pos.y, b.pos.y+b.dim.y);
+
+ float x0 = gb_max(a_min_x, b_min_x);
+ float y0 = gb_max(a_min_y, b_min_y);
+ float x1 = gb_min(a_max_x, b_max_x);
+ float y1 = gb_min(a_max_y, b_max_y);
+
+ if ((x0 < x1) && (y0 < y1)) {
+ gbRect2 r = gb_rect2(gb_vec2(x0, y0), gb_vec2(x1-x0, y1-y0));
+ *intersection = r;
+ return 1;
+ } else {
+ gbRect2 r = {0};
+ *intersection = r;
+ return 0;
+ }
+}
+
+
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+ gb_math_u64
+ gb_hash_murmur64(void const *key, size_t num_bytes, gb_math_u64 seed)
{
- u64 const m = 0xc6a4a7935bd1e995ULL;
- int const r = 47;
+ gb_math_u64 const m = 0xc6a4a7935bd1e995ULL;
+ gb_math_u64 const r = 47;
- u64 h = MURMUR64_SEED ^ (num_bytes * m);
+ gb_math_u64 h = seed ^ (num_bytes * m);
- u64 *data = (u64 *)(key);
- u64 *end = data + (num_bytes / 8);
- u8 *data2;
+ gb_math_u64 *data = (gb_math_u64 *)(key);
+ gb_math_u64 *end = data + (num_bytes / 8);
+ unsigned char *data2;
while (data != end) {
- u64 k = *data++;
+ gb_math_u64 k = *data++;
k *= m;
k ^= k >> r;
k *= m;
@@ -681,16 +1850,16 @@ mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float
h *= m;
}
- data2 = (u8 *)data;
+ data2 = (unsigned char *)data;
switch (num_bytes & 7) {
- case 7: h ^= (u64)data2[6] << 48;
- case 6: h ^= (u64)data2[5] << 40;
- case 5: h ^= (u64)data2[4] << 32;
- case 4: h ^= (u64)data2[3] << 24;
- case 3: h ^= (u64)data2[2] << 16;
- case 2: h ^= (u64)data2[1] << 8;
- case 1: h ^= (u64)data2[0];
+ case 7: h ^= (gb_math_u64)data2[6] << 48;
+ case 6: h ^= (gb_math_u64)data2[5] << 40;
+ case 5: h ^= (gb_math_u64)data2[4] << 32;
+ case 4: h ^= (gb_math_u64)data2[3] << 24;
+ case 3: h ^= (gb_math_u64)data2[2] << 16;
+ case 2: h ^= (gb_math_u64)data2[1] << 8;
+ case 1: h ^= (gb_math_u64)data2[0];
h *= m;
};
@@ -702,14 +1871,14 @@ mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float
}
#else
gb_math_u64
- hash_murmur64(void const *key, size_t num_bytes)
+ gb_hash_murmur64(void const *key, size_t num_bytes, gb_math_u64 seed)
{
gb_math_u32 const m = 0x5bd1e995;
gb_math_u32 const r = 24;
gb_math_u64 h = 0;
- gb_math_u32 h1 = (gb_math_u32)MURMUR64_SEED ^ (gb_math_u32)num_bytes;
- gb_math_u32 h2 = (gb_math_u32)((gb_math_u64)MURMUR64_SEED >> 32);
+ gb_math_u32 h1 = (gb_math_u32)seed ^ (gb_math_u32)num_bytes;
+ gb_math_u32 h2 = (gb_math_u32)((gb_math_u64)seed >> 32);
gb_math_u32 *data = (gb_math_u32 *)key;
@@ -744,9 +1913,10 @@ mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float
}
switch (num_bytes) {
- case 3: h2 ^= (gb_math_u32)((gb_math_u8 *)(data)[2]) << 16;
- case 2: h2 ^= (gb_math_u32)((gb_math_u8 *)(data)[1]) << 8;
- case 1: h2 ^= (gb_math_u32)((gb_math_u8 *)(data)[0]) << 0;
+ gb_math_u32 a, b, c;
+ case 3: c = data[2]; h2 ^= c << 16;
+ case 2: b = data[1]; h2 ^= b << 8;
+ case 1: a = data[0]; h2 ^= a << 0;
h2 *= m;
};
@@ -768,21 +1938,17 @@ mat4_ortho3d(Mat4 *out, float left, float right, float bottom, float top, float
// TODO(bill): Make better random number generators
float
-random_range_float(float min_inc, float max_inc)
+gb_random_range_float(float min_inc, float max_inc)
{
- static int random_value = 0xdeadbeef; // Random Value
- float result;
- random_value = random_value * 2147001325 + 715136305; // BCPL generator
- result = *(float *)&random_value; // bits
- result /= 4294967295.0f;
- result *= (max_inc - min_inc);
+ int int_result = gb_random_range_int(0, INT_MAX-1); // Prevent integer overflow
+ float result = int_result/(float)(INT_MAX-1);
+ result *= max_inc - min_inc;
result += min_inc;
-
return result;
}
int
-random_range_int(int min_inc, int max_inc)
+gb_random_range_int(int min_inc, int max_inc)
{
static int random_value = 0xdeadbeef; // Random Value
int diff, result;
diff --git a/gb_math.hpp b/gb_math.hpp
deleted file mode 100644
index b81bde9..0000000
--- a/gb_math.hpp
+++ /dev/null
@@ -1,3882 +0,0 @@
-// gb_math.hpp - v0.03a - public domain C++11 math library - no warranty implied; use at your own risk
-// A C++11 math library geared towards game development
-// This is meant to be used the gb.hpp library but it doesn't have to be
-
-/*
-Version History:
- 0.04 - Change const position convention
- 0.03a - Remove templated clamp
- 0.03 - Remove templated min/max/clamp
- 0.02b - Typo fixes
- 0.02a - Better `static` keywords
- 0.02 - More Angle Units and templated min/max/clamp/lerp
- 0.01 - Initial Version
-
-LICENSE
- This software is in the public domain. Where that dedication is not
- recognized, you are granted a perpetual, irrevocable license to copy,
- distribute, and modify this file as you see fit.
-
-WARNING
- - This library is _slightly_ experimental and features may not work as expected.
- - This also means that many functions are not documented.
- - This library was developed in conjunction with `gb.hpp`
-
-CONTENTS:
- - Common Macros
- - Assert
- - Types
- - Vector(2,3,4)
- - Complex
- - Quaternion
- - Matrix(2,3,4)
- - Euler_Angles
- - Transform
- - Aabb
- - Sphere
- - Plane
- - Operations
- - Functions & Constants
- - Type Functions
- - Random
-*/
-
-#ifndef GB_MATH_INCLUDE_GB_MATH_HPP
-#define GB_MATH_INCLUDE_GB_MATH_HPP
-
-#if !defined(__cplusplus) && __cplusplus >= 201103L
- #error This library is only for C++11 and above
-#endif
-
-// NOTE(bill): Because static means three different things in C/C++
-// Great Design(!)
-#ifndef global_variable
-#define global_variable static
-#define internal_linkage static
-#define local_persist static
-#endif
-
-#if defined(_MSC_VER)
- #define _ALLOW_KEYWORD_MACROS
-
- #ifndef alignof // Needed for MSVC 2013 'cause Microsoft "loves" standards
- #define alignof(x) __alignof(x)
- #endif
-#endif
-
-
-////////////////////////////////
-/// ///
-/// System OS ///
-/// ///
-////////////////////////////////
-#if defined(_WIN32) || defined(_WIN64)
- #ifndef GB_SYSTEM_WINDOWS
- #define GB_SYSTEM_WINDOWS 1
- #endif
-#elif defined(__APPLE__) && defined(__MACH__)
- #ifndef GB_SYSTEM_OSX
- #define GB_SYSTEM_OSX 1
- #endif
-#elif defined(__unix__)
- #ifndef GB_SYSTEM_UNIX
- #define GB_SYSTEM_UNIX 1
- #endif
-
- #if defined(__linux__)
- #ifndef GB_SYSTEM_LINUX
- #define GB_SYSTEM_LINUX 1
- #endif
- #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- #ifndef GB_SYSTEM_FREEBSD
- #define GB_SYSTEM_FREEBSD 1
- #endif
- #else
- #error This UNIX operating system is not supported by gb.hpp
- #endif
-#else
- #error This operating system is not supported by gb.hpp
-#endif
-
-
-#if defined(_MSC_VER)
- // Microsoft Visual Studio
- #define GB_COMPILER_MSVC 1
-#elif defined(__clang__)
- // Clang
- #define GB_COMPILER_CLANG 1
-#elif defined(__GNUC__) || defined(__GNUG__) && !(defined(__clang__) || defined(__INTEL_COMPILER))
- // GNU GCC/G++ Compiler
- #define GB_COMPILER_GNU_GCC 1
-#elif defined(__INTEL_COMPILER)
- // Intel C++ Compiler
- #define GB_COMPILER_INTEL 1
-#endif
-
-////////////////////////////////
-/// ///
-/// Environment Bit Size ///
-/// ///
-////////////////////////////////
-#if defined(_WIN32) || defined(_WIN64)
- #if defined(_WIN64)
- #ifndef GB_ARCH_64_BIT
- #define GB_ARCH_64_BIT 1
- #endif
- #else
- #ifndef GB_ARCH_32_BIT
- #define GB_ARCH_32_BIT 1
- #endif
- #endif
-#endif
-
-// TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang
-#if defined(__GNUC__)
- #if defined(__x86_64__) || defined(__ppc64__)
- #ifndef GB_ARCH_64_BIT
- #define GB_ARCH_64_BIT 1
- #endif
- #else
- #ifndef GB_ARCH_32_BIT
- #define GB_ARCH_32_BIT 1
- #endif
- #endif
-#endif
-
-
-
-#ifndef GB_EDIAN_ORDER
-#define GB_EDIAN_ORDER
- #define GB_IS_BIG_EDIAN (!*(unsigned char*)&(unsigned short){1})
- #define GB_IS_LITTLE_EDIAN (!GB_IS_BIG_EDIAN)
-#endif
-
-#ifndef GB_IS_POWER_OF_TWO
-#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1))
-#endif
-
-
-#if !defined(GB_HAS_NO_CONSTEXPR)
- #if defined(_GNUC_VER) && _GNUC_VER < 406 // Less than gcc 4.06
- #define GB_HAS_NO_CONSTEXPR 1
- #elif defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015/MSVC++ 14.0
- #define GB_HAS_NO_CONSTEXPR 1
- #elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
- #define GB_HAS_NO_CONSTEXPR 1
- #endif
-#endif
-
-#if defined(GB_HAS_NO_CONSTEXPR)
- #define GB_CONSTEXPR
-#else
- #define GB_CONSTEXPR constexpr
-#endif
-
-#ifndef GB_FORCE_INLINE
- #if defined(_MSC_VER)
- #define GB_FORCE_INLINE __forceinline
- #else
- #define GB_FORCE_INLINE __attribute__ ((__always_inline__))
- #endif
-#endif
-
-#if defined(GB_SYSTEM_WINDOWS)
- #define NOMINMAX 1
- #define VC_EXTRALEAN 1
- #define WIN32_EXTRA_LEAN 1
- #define WIN32_LEAN_AND_MEAN 1
-
- #include <windows.h>
- #include <wincrypt.h>
-
- #undef NOMINMAX
- #undef VC_EXTRALEAN
- #undef WIN32_EXTRA_LEAN
- #undef WIN32_LEAN_AND_MEAN
-#else
- //
-#endif
-
-
-#if !defined(GB_ASSERT)
- #if !defined(NDEBUG)
- #define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
-
- /// Helper function used as a better alternative to assert which allows for
- /// optional printf style error messages
- extern "C" inline void
- gb__assert_handler(bool condition, const char* condition_str,
- const char* filename, size_t line,
- const char* error_text = nullptr, ...)
- {
- if (condition)
- return;
-
- fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str);
- if (error_text)
- {
- fprintf(stderr, " - ");
-
- va_list args;
- va_start(args, error_text);
- vfprintf(stderr, error_text, args);
- va_end(args);
- }
- fprintf(stderr, "\n");
- // TODO(bill): Get a better way to abort
- *(int*)0 = 0;
- }
-
- #else
- #define GB_ASSERT(x, ...) ((void)sizeof(x))
- #endif
-#endif
-
-#if !defined(__GB_NAMESPACE_PREFIX) && !defined(GB_NO_GB_NAMESPACE)
- #define __GB_NAMESPACE_PREFIX gb
-#else
- #define __GB_NAMESPACE_PREFIX
-#endif
-
-#if defined(GB_NO_GB_NAMESPACE)
- #define __GB_NAMESPACE_START
- #define __GB_NAMESPACE_END
-#else
- #define __GB_NAMESPACE_START namespace __GB_NAMESPACE_PREFIX {
- #define __GB_NAMESPACE_END } // namespace __GB_NAMESPACE_PREFIX
-#endif
-
-
-#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_START
-#endif // GB_BASIC_WITHOUT_NAMESPACE
-
-////////////////////////////////
-/// ///
-/// Types ///
-/// ///
-////////////////////////////////
-
-
-#ifndef GB_BASIC_TYPES
-#define GB_BASIC_TYPES
- #if defined(_MSC_VER)
- using u8 = unsigned __int8;
- using s8 = signed __int8;
- using u16 = unsigned __int16;
- using s16 = signed __int16;
- using u32 = unsigned __int32;
- using s32 = signed __int32;
- using u64 = unsigned __int64;
- using s64 = signed __int64;
- #else
- using u8 = unsigned char;
- using s8 = signed char;
- using u16 = unsigned short;
- using s16 = signed short;
- using u32 = unsigned int;
- using s32 = signed int;
- using u64 = unsigned long long;
- using s64 = signed long long;
- #endif
-
- static_assert( sizeof(u8) == 1, "u8 is not 8 bits");
- static_assert(sizeof(u16) == 2, "u16 is not 16 bits");
- static_assert(sizeof(u32) == 4, "u32 is not 32 bits");
- static_assert(sizeof(u64) == 8, "u64 is not 64 bits");
-
- using f32 = float;
- using f64 = double;
-
- #if defined(GB_B8_AS_BOOL)
- using b8 = bool;
- #else
- using b8 = s8;
- #endif
- using b32 = s32;
-
- // NOTE(bill): (std::)size_t is not used not because it's a bad concept but on
- // the platforms that I will be using:
- // sizeof(size_t) == sizeof(usize) == sizeof(ssize)
- // NOTE(bill): This also allows for a signed version of size_t which is similar
- // to ptrdiff_t
- // NOTE(bill): If (u)intptr is a better fit, please use that.
- // NOTE(bill): Also, I hate the `_t` suffix
- #if defined(GB_ARCH_64_BIT)
- using ssize = s64;
- using usize = u64;
- #elif defined(GB_ARCH_32_BIT)
- using usize = s32;
- using usize = u32;
- #else
- #error Unknown architecture bit size
- #endif
-
- static_assert(sizeof(usize) == sizeof(size_t),
- "`usize` is not the same size as `size_t`");
- static_assert(sizeof(ssize) == sizeof(usize),
- "`ssize` is not the same size as `usize`");
-
- using intptr = intptr_t;
- using uintptr = uintptr_t;
-
- using ptrdiff = ptrdiff_t;
-
-#endif
-
-#if !defined(GB_U8_MIN)
- #define GB_U8_MIN 0u
- #define GB_U8_MAX 0xffu
- #define GB_S8_MIN (-0x7f - 1)
- #define GB_S8_MAX 0x7f
-
- #define GB_U16_MIN 0u
- #define GB_U16_MAX 0xffffu
- #define GB_S16_MIN (-0x7fff - 1)
- #define GB_S16_MAX 0x7fff
-
- #define GB_U32_MIN 0u
- #define GB_U32_MAX 0xffffffffu
- #define GB_S32_MIN (-0x7fffffff - 1)
- #define GB_S32_MAX 0x7fffffff
-
- #define GB_U64_MIN 0ull
- #define GB_U64_MAX 0xffffffffffffffffull
- #define GB_S64_MIN (-0x7fffffffffffffffll - 1)
- #define GB_S64_MAX 0x7fffffffffffffffll
-#endif
-
-#if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
- #define GB_USIZE_MIX GB_U64_MIN
- #define GB_USIZE_MAX GB_U64_MAX
-
- #define GB_SSIZE_MIX GB_S64_MIN
- #define GB_SSIZE_MAX GB_S64_MAX
-#elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
- #define GB_USIZE_MIX GB_U32_MIN
- #define GB_USIZE_MAX GB_U32_MAX
-
- #define GB_SSIZE_MIX GB_S32_MIN
- #define GB_SSIZE_MAX GB_S32_MAX
-#endif
-
-#if defined(GB_BASIC_WITHOUT_NAMESPACE) && !defined(U8_MIN)
- #define U8_MIN 0u
- #define U8_MAX 0xffu
- #define S8_MIN (-0x7f - 1)
- #define S8_MAX 0x7f
-
- #define U16_MIN 0u
- #define U16_MAX 0xffffu
- #define S16_MIN (-0x7fff - 1)
- #define S16_MAX 0x7fff
-
- #define U32_MIN 0u
- #define U32_MAX 0xffffffffu
- #define S32_MIN (-0x7fffffff - 1)
- #define S32_MAX 0x7fffffff
-
- #define U64_MIN 0ull
- #define U64_MAX 0xffffffffffffffffull
- #define S64_MIN (-0x7fffffffffffffffll - 1)
- #define S64_MAX 0x7fffffffffffffffll
-
- #if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
- #define USIZE_MIX U64_MIN
- #define USIZE_MAX U64_MAX
-
- #define SSIZE_MIX S64_MIN
- #define SSIZE_MAX S64_MAX
- #elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
- #define USIZE_MIX U32_MIN
- #define USIZE_MAX U32_MAX
-
- #define SSIZE_MIX S32_MIN
- #define SSIZE_MAX S32_MAX
- #endif
-#endif
-
-
-
-#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_END
-#endif // GB_BASIC_WITHOUT_NAMESPACE
-
-__GB_NAMESPACE_START
-#ifndef GB_SPECIAL_CASTS
-#define GB_SPECIAL_CASTS
- // IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write
- // however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior
- // *(T*)(&u) ~~ pseudo_cast<T>(u)
- template <typename T, typename U>
- inline T
- pseudo_cast(U const& u)
- {
- return reinterpret_cast<T const&>(u);
- }
-
- // NOTE(bill): Very similar to doing `*(T*)(&u)`
- template <typename Dest, typename Source>
- inline Dest
- bit_cast(Source const& source)
- {
- static_assert(sizeof(Dest) <= sizeof(Source),
- "bit_cast<Dest>(Source const&) - sizeof(Dest) <= sizeof(Source)");
- Dest dest;
- ::memcpy(&dest, &source, sizeof(Dest));
- return dest;
- }
-#endif
-// FORENOTE(bill): There used to be a magic_cast that was equivalent to
-// a C-style cast but I removed it as I could not get it work as intented
-// for everything using only C++ style casts
-
-#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
-__GB_NAMESPACE_END
-#endif // GB_CASTS_WITHOUT_NAMESPACE
-
-__GB_NAMESPACE_START
-////////////////////////////////
-/// ///
-/// Math Types ///
-/// ///
-////////////////////////////////
-
-// TODO(bill): Should the math part be a separate library?
-
-struct Vector2
-{
- union
- {
- struct { f32 x, y; };
- f32 data[2];
- };
-
- inline f32 operator[](usize index) const { return data[index]; }
- inline f32& operator[](usize index) { return data[index]; }
-};
-
-struct Vector3
-{
- union
- {
- struct { f32 x, y, z; };
- struct { f32 r, g, b; };
- Vector2 xy;
- f32 data[3];
- };
-
- inline f32 operator[](usize index) const { return data[index]; }
- inline f32& operator[](usize index) { return data[index]; }
-};
-
-struct Vector4
-{
- union
- {
- struct { f32 x, y, z, w; };
- struct { f32 r, g, b, a; };
- struct { Vector2 xy, zw; };
- Vector3 xyz;
- Vector3 rgb;
- f32 data[4];
- };
-
- inline f32 operator[](usize index) const { return data[index]; }
- inline f32& operator[](usize index) { return data[index]; }
-};
-
-struct Complex
-{
- union
- {
- struct { f32 x, y; };
- struct { f32 real, imag; };
- f32 data[2];
- };
-
- inline f32 operator[](usize index) const { return data[index]; }
- inline f32& operator[](usize index) { return data[index]; }
-};
-
-struct Quaternion
-{
- union
- {
- struct { f32 x, y, z, w; };
- Vector3 xyz;
- f32 data[4];
- };
-
- inline f32 operator[](usize index) const { return data[index]; }
- inline f32& operator[](usize index) { return data[index]; }
-};
-
-struct Matrix2
-{
- union
- {
- struct { Vector2 x, y; };
- Vector2 columns[2];
- f32 data[4];
- };
-
- inline Vector2 operator[](usize index) const { return columns[index]; }
- inline Vector2& operator[](usize index) { return columns[index]; }
-};
-
-struct Matrix3
-{
- union
- {
- struct { Vector3 x, y, z; };
- Vector3 columns[3];
- f32 data[9];
- };
-
- inline Vector3 operator[](usize index) const { return columns[index]; }
- inline Vector3& operator[](usize index) { return columns[index]; }
-};
-
-struct Matrix4
-{
- union
- {
- struct { Vector4 x, y, z, w; };
- Vector4 columns[4];
- f32 data[16];
- };
-
- inline Vector4 operator[](usize index) const { return columns[index]; }
- inline Vector4& operator[](usize index) { return columns[index]; }
-};
-
-struct Angle
-{
- f32 radians;
-};
-
-struct Euler_Angles
-{
- Angle pitch, yaw, roll;
-};
-
-struct Transform
-{
- Vector3 position;
- Quaternion orientation;
- f32 scale;
- // NOTE(bill): Scale is only f32 to make sizeof(Transform) == 32 bytes
-};
-
-struct Aabb
-{
- Vector3 center;
- Vector3 half_size;
-};
-
-struct Oobb
-{
- Matrix4 transform;
- Aabb aabb;
-};
-
-struct Sphere
-{
- Vector3 center;
- f32 radius;
-};
-
-struct Plane
-{
- Vector3 normal;
- f32 distance; // negative distance to origin
-};
-
-////////////////////////////////
-/// ///
-/// Math Type Op Overloads ///
-/// ///
-////////////////////////////////
-
-// Vector2 Operators
-bool operator==(Vector2 a, Vector2 b);
-bool operator!=(Vector2 a, Vector2 b);
-
-Vector2 operator+(Vector2 a);
-Vector2 operator-(Vector2 a);
-
-Vector2 operator+(Vector2 a, Vector2 b);
-Vector2 operator-(Vector2 a, Vector2 b);
-
-Vector2 operator*(Vector2 a, f32 scalar);
-Vector2 operator*(f32 scalar, Vector2 a);
-
-Vector2 operator/(Vector2 a, f32 scalar);
-
-Vector2 operator*(Vector2 a, Vector2 b); // Hadamard Product
-Vector2 operator/(Vector2 a, Vector2 b); // Hadamard Product
-
-Vector2& operator+=(Vector2& a, Vector2 b);
-Vector2& operator-=(Vector2& a, Vector2 b);
-Vector2& operator*=(Vector2& a, f32 scalar);
-Vector2& operator/=(Vector2& a, f32 scalar);
-
-// Vector3 Operators
-bool operator==(Vector3 a, Vector3 b);
-bool operator!=(Vector3 a, Vector3 b);
-
-Vector3 operator+(Vector3 a);
-Vector3 operator-(Vector3 a);
-
-Vector3 operator+(Vector3 a, Vector3 b);
-Vector3 operator-(Vector3 a, Vector3 b);
-
-Vector3 operator*(Vector3 a, f32 scalar);
-Vector3 operator*(f32 scalar, Vector3 a);
-
-Vector3 operator/(Vector3 a, f32 scalar);
-
-Vector3 operator*(Vector3 a, Vector3 b); // Hadamard Product
-Vector3 operator/(Vector3 a, Vector3 b); // Hadamard Product
-
-Vector3& operator+=(Vector3& a, Vector3 b);
-Vector3& operator-=(Vector3& a, Vector3 b);
-Vector3& operator*=(Vector3& a, f32 scalar);
-Vector3& operator/=(Vector3& a, f32 scalar);
-
-// Vector4 Operators
-bool operator==(Vector4 a, Vector4 b);
-bool operator!=(Vector4 a, Vector4 b);
-
-Vector4 operator+(Vector4 a);
-Vector4 operator-(Vector4 a);
-
-Vector4 operator+(Vector4 a, Vector4 b);
-Vector4 operator-(Vector4 a, Vector4 b);
-
-Vector4 operator*(Vector4 a, f32 scalar);
-Vector4 operator*(f32 scalar, Vector4 a);
-
-Vector4 operator/(Vector4 a, f32 scalar);
-
-Vector4 operator*(Vector4 a, Vector4 b); // Hadamard Product
-Vector4 operator/(Vector4 a, Vector4 b); // Hadamard Product
-
-Vector4& operator+=(Vector4& a, Vector4 b);
-Vector4& operator-=(Vector4& a, Vector4 b);
-Vector4& operator*=(Vector4& a, f32 scalar);
-Vector4& operator/=(Vector4& a, f32 scalar);
-
-// Complex Operators
-bool operator==(Complex a, Complex b);
-bool operator!=(Complex a, Complex b);
-
-Complex operator+(Complex a);
-Complex operator-(Complex a);
-
-Complex operator+(Complex a, Complex b);
-Complex operator-(Complex a, Complex b);
-
-Complex operator*(Complex a, Complex b);
-Complex operator*(Complex a, f32 s);
-Complex operator*(f32 s, Complex a);
-
-Complex operator/(Complex a, f32 s);
-
-// Quaternion Operators
-bool operator==(Quaternion a, Quaternion b);
-bool operator!=(Quaternion a, Quaternion b);
-
-Quaternion operator+(Quaternion a);
-Quaternion operator-(Quaternion a);
-
-Quaternion operator+(Quaternion a, Quaternion b);
-Quaternion operator-(Quaternion a, Quaternion b);
-
-Quaternion operator*(Quaternion a, Quaternion b);
-Quaternion operator*(Quaternion a, f32 s);
-Quaternion operator*(f32 s, Quaternion a);
-
-Quaternion operator/(Quaternion a, f32 s);
-
-Vector3 operator*(Quaternion a, Vector3 v); // Rotate v by a
-
-// Matrix2 Operators
-bool operator==(Matrix2 a, Matrix2 b);
-bool operator!=(Matrix2 a, Matrix2 b);
-
-Matrix2 operator+(Matrix2 a);
-Matrix2 operator-(Matrix2 a);
-
-Matrix2 operator+(Matrix2 a, Matrix2 b);
-Matrix2 operator-(Matrix2 a, Matrix2 b);
-
-Matrix2 operator*(Matrix2 a, Matrix2 b);
-Vector2 operator*(Matrix2 a, Vector2 v);
-Matrix2 operator*(Matrix2 a, f32 scalar);
-Matrix2 operator*(f32 scalar, Matrix2 a);
-
-Matrix2 operator/(Matrix2 a, f32 scalar);
-
-Matrix2& operator+=(Matrix2& a, Matrix2 b);
-Matrix2& operator-=(Matrix2& a, Matrix2 b);
-Matrix2& operator*=(Matrix2& a, Matrix2 b);
-
-// Matrix3 Operators
-bool operator==(Matrix3 const& a, Matrix3 const& b);
-bool operator!=(Matrix3 const& a, Matrix3 const& b);
-
-Matrix3 operator+(Matrix3 const& a);
-Matrix3 operator-(Matrix3 const& a);
-
-Matrix3 operator+(Matrix3 const& a, Matrix3 const& b);
-Matrix3 operator-(Matrix3 const& a, Matrix3 const& b);
-
-Matrix3 operator*(Matrix3 const& a, Matrix3 const& b);
-Vector3 operator*(Matrix3 const& a, Vector3 v);
-Matrix3 operator*(Matrix3 const& a, f32 scalar);
-Matrix3 operator*(f32 scalar, Matrix3 const& a);
-
-Matrix3 operator/(Matrix3 const& a, f32 scalar);
-
-Matrix3& operator+=(Matrix3& a, Matrix3 const& b);
-Matrix3& operator-=(Matrix3& a, Matrix3 const& b);
-Matrix3& operator*=(Matrix3& a, Matrix3 const& b);
-
-// Matrix4 Operators
-bool operator==(Matrix4 const& a, Matrix4 const& b);
-bool operator!=(Matrix4 const& a, Matrix4 const& b);
-
-Matrix4 operator+(Matrix4 const& a);
-Matrix4 operator-(Matrix4 const& a);
-
-Matrix4 operator+(Matrix4 const& a, Matrix4 const& b);
-Matrix4 operator-(Matrix4 const& a, Matrix4 const& b);
-
-Matrix4 operator*(Matrix4 const& a, Matrix4 const& b);
-Vector4 operator*(Matrix4 const& a, Vector4 v);
-Matrix4 operator*(Matrix4 const& a, f32 scalar);
-Matrix4 operator*(f32 scalar, Matrix4 const& a);
-
-Matrix4 operator/(Matrix4 const& a, f32 scalar);
-
-Matrix4& operator+=(Matrix4& a, Matrix4 const& b);
-Matrix4& operator-=(Matrix4& a, Matrix4 const& b);
-Matrix4& operator*=(Matrix4& a, Matrix4 const& b);
-
-// Angle Operators
-bool operator==(Angle a, Angle b);
-bool operator!=(Angle a, Angle b);
-
-Angle operator+(Angle a);
-Angle operator-(Angle a);
-
-Angle operator+(Angle a, Angle b);
-Angle operator-(Angle a, Angle b);
-
-Angle operator*(Angle a, f32 scalar);
-Angle operator*(f32 scalar, Angle a);
-
-Angle operator/(Angle a, f32 scalar);
-
-f32 operator/(Angle a, Angle b);
-
-Angle& operator+=(Angle& a, Angle b);
-Angle& operator-=(Angle& a, Angle b);
-Angle& operator*=(Angle& a, f32 scalar);
-Angle& operator/=(Angle& a, f32 scalar);
-
-// Transform Operators
-// World = Parent * Local
-Transform operator*(Transform const& ps, Transform const& ls);
-Transform& operator*=(Transform& ps, Transform const& ls);
-// Local = World / Parent
-Transform operator/(Transform const& ws, Transform const& ps);
-Transform& operator/=(Transform& ws, Transform const& ps);
-
-namespace angle
-{
-Angle radians(f32 r);
-Angle degrees(f32 d);
-Angle turns(f32 t);
-Angle grads(f32 g);
-Angle gons(f32 g);
-
-f32 as_radians(Angle a);
-f32 as_degrees(Angle a);
-f32 as_turns(Angle a);
-f32 as_grads(Angle a);
-f32 as_gons(Angle a);
-} // namespace angle
-
-//////////////////////////////////
-/// ///
-/// Math Functions & Constants ///
-/// ///
-//////////////////////////////////
-extern Vector2 const VECTOR2_ZERO;
-extern Vector3 const VECTOR3_ZERO;
-extern Vector4 const VECTOR4_ZERO;
-extern Complex const COMPLEX_ZERO;
-extern Quaternion const QUATERNION_IDENTITY;
-extern Matrix2 const MATRIX2_IDENTITY;
-extern Matrix3 const MATRIX3_IDENTITY;
-extern Matrix4 const MATRIX4_IDENTITY;
-extern Euler_Angles const EULER_ANGLES_ZERO;
-extern Transform const TRANSFORM_IDENTITY;
-
-namespace math
-{
-extern f32 const ZERO;
-extern f32 const ONE;
-extern f32 const THIRD;
-extern f32 const TWO_THIRDS;
-extern f32 const E;
-extern f32 const PI;
-extern f32 const TAU;
-extern f32 const SQRT_2;
-extern f32 const SQRT_3;
-extern f32 const SQRT_5;
-
-extern f32 const F32_PRECISION;
-
-// Power
-f32 sqrt(f32 x);
-f32 pow(f32 x, f32 y);
-f32 cbrt(f32 x);
-f32 fast_inv_sqrt(f32 x);
-
-// Trigonometric
-f32 sin(Angle a);
-f32 cos(Angle a);
-f32 tan(Angle a);
-
-Angle arcsin(f32 x);
-Angle arccos(f32 x);
-Angle arctan(f32 x);
-Angle arctan2(f32 y, f32 x);
-
-// Hyperbolic
-f32 sinh(f32 x);
-f32 cosh(f32 x);
-f32 tanh(f32 x);
-
-f32 arsinh(f32 x);
-f32 arcosh(f32 x);
-f32 artanh(f32 x);
-
-// Rounding
-f32 ceil(f32 x);
-f32 floor(f32 x);
-f32 mod(f32 x, f32 y);
-f32 truncate(f32 x);
-f32 round(f32 x);
-
-s32 sign(s32 x);
-s64 sign(s64 x);
-f32 sign(f32 x);
-
-// Other
-f32 abs(f32 x);
-s8 abs( s8 x);
-s16 abs(s16 x);
-s32 abs(s32 x);
-s64 abs(s64 x);
-
-bool is_infinite(f32 x);
-bool is_nan(f32 x);
-
-s32 kronecker_delta(s32 i, s32 j);
-s64 kronecker_delta(s64 i, s64 j);
-f32 kronecker_delta(f32 i, f32 j);
-
-// NOTE(bill): Just incase
-#undef min
-#undef max
-
-f32 min(f32 x, f32 y);
-s32 min(s32 x, s32 y);
-s64 min(s64 x, s64 y);
-
-f32 max(f32 x, f32 y);
-s32 max(s32 x, s32 y);
-s64 max(s64 x, s64 y);
-
-f32 clamp(f32 x, f32 min, f32 max);
-s32 clamp(s32 x, s32 min, s32 max);
-s64 clamp(s64 x, s64 min, s64 max);
-
-// TODO(bill): Should this be a template or just normal function overloading?
-template <typename T>
-T lerp(T const& x, T const& y, f32 t);
-
-bool equals(f32 a, f32 b, f32 precision = F32_PRECISION);
-
-// Vector2 functions
-f32 dot(Vector2 a, Vector2 b);
-f32 cross(Vector2 a, Vector2 b);
-
-f32 magnitude(Vector2 a);
-Vector2 normalize(Vector2 a);
-
-Vector2 hadamard(Vector2 a, Vector2 b);
-
-f32 aspect_ratio(Vector2 a);
-
-// Vector3 functions
-f32 dot(Vector3 a, Vector3 b);
-Vector3 cross(Vector3 a, Vector3 b);
-
-f32 magnitude(Vector3 a);
-Vector3 normalize(Vector3 a);
-
-Vector3 hadamard(Vector3 a, Vector3 b);
-
-// Vector4 functions
-f32 dot(Vector4 a, Vector4 b);
-
-f32 magnitude(Vector4 a);
-Vector4 normalize(Vector4 a);
-
-Vector4 hadamard(Vector4 a, Vector4 b);
-
-// Complex functions
-f32 dot(Complex a, Complex b);
-
-f32 magnitude(Complex a);
-f32 norm(Complex a);
-Complex normalize(Complex a);
-
-Complex conjugate(Complex a);
-Complex inverse(Complex a);
-
-f32 complex_angle(Complex a);
-inline f32 complex_argument(Complex a) { return complex_angle(a); }
-Complex magnitude_angle(f32 magnitude, Angle a);
-inline Complex complex_polar(f32 magnitude, Angle a) { return magnitude_angle(magnitude, a); }
-
-// Quaternion functions
-f32 dot(Quaternion a, Quaternion b);
-Quaternion cross(Quaternion a, Quaternion b);
-
-f32 magnitude(Quaternion a);
-f32 norm(Quaternion a);
-Quaternion normalize(Quaternion a);
-
-Quaternion conjugate(Quaternion a);
-Quaternion inverse(Quaternion a);
-
-Angle quaternion_angle(Quaternion a);
-Vector3 quaternion_axis(Quaternion a);
-Quaternion axis_angle(Vector3 axis, Angle a);
-
-Angle quaternion_roll(Quaternion a);
-Angle quaternion_pitch(Quaternion a);
-Angle quaternion_yaw(Quaternion a);
-
-Euler_Angles quaternion_to_euler_angles(Quaternion a);
-Quaternion euler_angles_to_quaternion(Euler_Angles const& e,
- Vector3 x_axis = {1, 0, 0},
- Vector3 y_axis = {0, 1, 0},
- Vector3 z_axis = {0, 0, 1});
-
-// Spherical Linear Interpolation
-Quaternion slerp(Quaternion x, Quaternion y, f32 t);
-
-// Shoemake's Quaternion Curves
-// Sqherical Cubic Interpolation
-Quaternion squad(Quaternion p,
- Quaternion a,
- Quaternion b,
- Quaternion q,
- f32 t);
-// Matrix2 functions
-Matrix2 transpose(Matrix2 m);
-f32 determinant(Matrix2 m);
-Matrix2 inverse(Matrix2 m);
-Matrix2 hadamard(Matrix2 a, const Matrix2&b);
-Matrix4 matrix2_to_matrix4(Matrix2 m);
-
-// Matrix3 functions
-Matrix3 transpose(Matrix3 const& m);
-f32 determinant(Matrix3 const& m);
-Matrix3 inverse(Matrix3 const& m);
-Matrix3 hadamard(Matrix3 const& a, const Matrix3&b);
-Matrix4 matrix3_to_matrix4(Matrix3 const& m);
-
-// Matrix4 functions
-Matrix4 transpose(Matrix4 const& m);
-f32 determinant(Matrix4 const& m);
-Matrix4 inverse(Matrix4 const& m);
-Matrix4 hadamard(Matrix4 const& a, const Matrix4&b);
-bool is_affine(Matrix4 const& m);
-
-Matrix4 quaternion_to_matrix4(Quaternion a);
-Quaternion matrix4_to_quaternion(Matrix4 const& m);
-
-Matrix4 translate(Vector3 v);
-Matrix4 rotate(Vector3 v, Angle angle);
-Matrix4 scale(Vector3 v);
-Matrix4 ortho(f32 left, f32 right, f32 bottom, f32 top);
-Matrix4 ortho(f32 left, f32 right, f32 bottom, f32 top, f32 z_near, f32 z_far);
-Matrix4 perspective(Angle fovy, f32 aspect, f32 z_near, f32 z_far);
-Matrix4 infinite_perspective(Angle fovy, f32 aspect, f32 z_near);
-
-Matrix4
-look_at_matrix4(Vector3 eye, Vector3 center, Vector3 up = {0, 1, 0});
-
-Quaternion
-look_at_quaternion(Vector3 eye, Vector3 center, Vector3 up = {0, 1, 0});
-
-// Transform Functions
-Vector3 transform_point(Transform const& transform, Vector3 point);
-Transform inverse(Transform const& t);
-Matrix4 transform_to_matrix4(Transform const& t);
-} // namespace math
-
-namespace aabb
-{
-Aabb calculate(void const* vertices, usize num_vertices, usize stride, usize offset);
-
-f32 surface_area(Aabb const& aabb);
-f32 volume(Aabb const& aabb);
-
-Sphere to_sphere(Aabb const& aabb);
-
-bool contains(Aabb const& aabb, Vector3 point);
-bool contains(Aabb const& a, Aabb const& b);
-bool intersects(Aabb const& a, Aabb const& b);
-
-Aabb transform_affine(Aabb const& aabb, Matrix4 const& m);
-} // namespace aabb
-
-namespace sphere
-{
-Sphere calculate_min_bounding_sphere(void const* vertices, usize num_vertices, usize stride, usize offset, f32 step);
-Sphere calculate_max_bounding_sphere(void const* vertices, usize num_vertices, usize stride, usize offset);
-
-f32 surface_area(Sphere s);
-f32 volume(Sphere s);
-
-Aabb to_aabb(Sphere sphere);
-
-bool contains_point(Sphere s, Vector3 point);
-
-f32 ray_intersection(Vector3 from, Vector3 dir, Sphere s);
-} // namespace sphere
-
-namespace plane
-{
-f32 ray_intersection(Vector3 from, Vector3 dir, Plane p);
-
-bool intersection3(Plane p1, Plane p2, Plane p3, Vector3* ip);
-} // namespace plane
-
-
-#if !defined(GB_MATH_NO_RANDOM)
-
-namespace random
-{
-struct Random // NOTE(bill): Mt19937_64
-{
- s64 seed;
- u32 index;
- s64 mt[312];
-};
-
-Random make(s64 seed);
-
-void set_seed(Random* r, s64 seed);
-
-s64 next(Random* r);
-
-void next_from_device(void* buffer, u32 length_in_bytes);
-
-s32 next_s32(Random* r);
-u32 next_u32(Random* r);
-f32 next_f32(Random* r);
-s64 next_s64(Random* r);
-u64 next_u64(Random* r);
-f64 next_f64(Random* r);
-
-s32 uniform_s32(Random* r, s32 min_inc, s32 max_inc);
-u32 uniform_u32(Random* r, u32 min_inc, u32 max_inc);
-f32 uniform_f32(Random* r, f32 min_inc, f32 max_inc);
-s64 uniform_s64(Random* r, s64 min_inc, s64 max_inc);
-u64 uniform_u64(Random* r, u64 min_inc, u64 max_inc);
-f64 uniform_f64(Random* r, f64 min_inc, f64 max_inc);
-
-
-// TODO(bill): Should these noise functions be in the `random` module?
-f32 perlin_3d(f32 x, f32 y, f32 z, s32 x_wrap = 0, s32 y_wrap = 0, s32 z_wrap = 0);
-
-// TODO(bill): Implement simplex noise
-// f32 simplex_2d_octave(f32 x, f32 y, f32 octaves, f32 persistence, f32 scale);
-// f32 simplex_3d_octave(f32 x, f32 y, f32 z, f32 octaves, f32 persistence, f32 scale);
-// f32 simplex_4d_octave(f32 x, f32 y, f32 z, f32 w, f32 octaves, f32 persistence, f32 scale);
-
-} // namespace random
-
-#endif
-
-namespace math
-{
-template <typename T> inline T lerp(T const& x, T const& y, f32 t) { return x + (y - x) * t; }
-} // namespace math
-
-__GB_NAMESPACE_END
-
-#endif // GB_INCLUDE_GB_HPP
-
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-/// So long and thanks for all the fish!
-///
-///
-///
-///
-///
-////////////////////////////////
-/// ///
-/// Implemenation ///
-/// ///
-////////////////////////////////
-#if defined(GB_MATH_IMPLEMENTATION)
-
-#include <math.h>
-
-__GB_NAMESPACE_START
-
-////////////////////////////////
-/// ///
-/// Math ///
-/// ///
-////////////////////////////////
-
-Vector2 const VECTOR2_ZERO = Vector2{0, 0};
-Vector3 const VECTOR3_ZERO = Vector3{0, 0, 0};
-Vector4 const VECTOR4_ZERO = Vector4{0, 0, 0, 0};
-Complex const COMPLEX_ZERO = Complex{0, 0};
-Quaternion const QUATERNION_IDENTITY = Quaternion{0, 0, 0, 1};
-Matrix2 const MATRIX2_IDENTITY = Matrix2{1, 0,
- 0, 1};
-Matrix3 const MATRIX3_IDENTITY = Matrix3{1, 0, 0,
- 0, 1, 0,
- 0, 0, 1};
-Matrix4 const MATRIX4_IDENTITY = Matrix4{1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1};
-Euler_Angles const EULER_ANGLES_ZERO = Euler_Angles{0, 0, 0};
-Transform const TRANSFORM_IDENTITY = Transform{VECTOR3_ZERO, QUATERNION_IDENTITY, 1};
-
-////////////////////////////////
-/// Math Type Op Overloads ///
-////////////////////////////////
-
-// Vector2 Operators
-inline bool
-operator==(Vector2 a, Vector2 b)
-{
- return (a.x == b.x) && (a.y == b.y);
-}
-
-inline bool
-operator!=(Vector2 a, Vector2 b)
-{
- return !operator==(a, b);
-}
-
-inline Vector2
-operator+(Vector2 a)
-{
- return a;
-}
-
-inline Vector2
-operator-(Vector2 a)
-{
- return {-a.x, -a.y};
-}
-
-inline Vector2
-operator+(Vector2 a, Vector2 b)
-{
- return {a.x + b.x, a.y + b.y};
-}
-
-inline Vector2
-operator-(Vector2 a, Vector2 b)
-{
- return {a.x - b.x, a.y - b.y};
-}
-
-inline Vector2
-operator*(Vector2 a, f32 scalar)
-{
- return {a.x * scalar, a.y * scalar};
-}
-
-inline Vector2
-operator*(f32 scalar, Vector2 a)
-{
- return {a.x * scalar, a.y * scalar};
-}
-
-inline Vector2
-operator/(Vector2 a, f32 scalar)
-{
- return {a.x / scalar, a.y / scalar};
-}
-
-inline Vector2
-operator*(Vector2 a, Vector2 b) // Hadamard Product
-{
- return {a.x * b.x, a.y * b.y};
-}
-
-inline Vector2
-operator/(Vector2 a, Vector2 b) // Hadamard Product
-{
- return {a.x / b.x, a.y / b.y};
-}
-
-inline Vector2&
-operator+=(Vector2& a, Vector2 b)
-{
- a.x += b.x;
- a.y += b.y;
-
- return a;
-}
-
-inline Vector2&
-operator-=(Vector2& a, Vector2 b)
-{
- a.x -= b.x;
- a.y -= b.y;
-
- return a;
-}
-
-inline Vector2&
-operator*=(Vector2& a, f32 scalar)
-{
- a.x *= scalar;
- a.y *= scalar;
-
- return a;
-}
-
-inline Vector2&
-operator/=(Vector2& a, f32 scalar)
-{
- a.x /= scalar;
- a.y /= scalar;
-
- return a;
-}
-
-// Vector3 Operators
-inline bool
-operator==(Vector3 a, Vector3 b)
-{
- return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
-}
-
-inline bool
-operator!=(Vector3 a, Vector3 b)
-{
- return !operator==(a, b);
-}
-
-inline Vector3
-operator+(Vector3 a)
-{
- return a;
-}
-
-inline Vector3
-operator-(Vector3 a)
-{
- return {-a.x, -a.y, -a.z};
-}
-
-inline Vector3
-operator+(Vector3 a, Vector3 b)
-{
- return {a.x + b.x, a.y + b.y, a.z + b.z};
-}
-
-inline Vector3
-operator-(Vector3 a, Vector3 b)
-{
- return {a.x - b.x, a.y - b.y, a.z - b.z};
-}
-
-inline Vector3
-operator*(Vector3 a, f32 scalar)
-{
- return {a.x * scalar, a.y * scalar, a.z * scalar};
-}
-
-inline Vector3
-operator*(f32 scalar, Vector3 a)
-{
- return {a.x * scalar, a.y * scalar, a.z * scalar};
-}
-
-inline Vector3
-operator/(Vector3 a, f32 scalar)
-{
- return {a.x / scalar, a.y / scalar, a.z / scalar};
-}
-
-inline Vector3
-operator*(Vector3 a, Vector3 b) // Hadamard Product
-{
- return {a.x * b.x, a.y * b.y, a.z * b.z};
-}
-
-inline Vector3
-operator/(Vector3 a, Vector3 b) // Hadamard Product
-{
- return {a.x / b.x, a.y / b.y, a.z / b.z};
-}
-
-inline Vector3&
-operator+=(Vector3& a, Vector3 b)
-{
- a.x += b.x;
- a.y += b.y;
- a.z += b.z;
-
- return a;
-}
-
-inline Vector3&
-operator-=(Vector3& a, Vector3 b)
-{
- a.x -= b.x;
- a.y -= b.y;
- a.z -= b.z;
-
- return a;
-}
-
-inline Vector3&
-operator*=(Vector3& a, f32 scalar)
-{
- a.x *= scalar;
- a.y *= scalar;
- a.z *= scalar;
-
- return a;
-}
-
-inline Vector3&
-operator/=(Vector3& a, f32 scalar)
-{
- a.x /= scalar;
- a.y /= scalar;
- a.z /= scalar;
-
- return a;
-}
-
-// Vector4 Operators
-inline bool
-operator==(Vector4 a, Vector4 b)
-{
- return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
-}
-
-inline bool
-operator!=(Vector4 a, Vector4 b)
-{
- return !operator==(a, b);
-}
-
-inline Vector4
-operator+(Vector4 a)
-{
- return a;
-}
-
-inline Vector4
-operator-(Vector4 a)
-{
- return {-a.x, -a.y, -a.z, -a.w};
-}
-
-inline Vector4
-operator+(Vector4 a, Vector4 b)
-{
- return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
-}
-
-inline Vector4
-operator-(Vector4 a, Vector4 b)
-{
- return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
-}
-
-inline Vector4
-operator*(Vector4 a, f32 scalar)
-{
- return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
-}
-
-inline Vector4
-operator*(f32 scalar, Vector4 a)
-{
- return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
-}
-
-inline Vector4
-operator/(Vector4 a, f32 scalar)
-{
- return {a.x / scalar, a.y / scalar, a.z / scalar, a.w / scalar};
-}
-
-inline Vector4
-operator*(Vector4 a, Vector4 b) // Hadamard Product
-{
- return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
-}
-
-inline Vector4
-operator/(Vector4 a, Vector4 b) // Hadamard Product
-{
- return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w};
-}
-
-inline Vector4&
-operator+=(Vector4& a, Vector4 b)
-{
- a.x += b.x;
- a.y += b.y;
- a.z += b.z;
- a.w += b.w;
-
- return a;
-}
-
-inline Vector4&
-operator-=(Vector4& a, Vector4 b)
-{
- a.x -= b.x;
- a.y -= b.y;
- a.z -= b.z;
- a.w -= b.w;
-
- return a;
-}
-
-inline Vector4&
-operator*=(Vector4& a, f32 scalar)
-{
- a.x *= scalar;
- a.y *= scalar;
- a.z *= scalar;
- a.w *= scalar;
-
- return a;
-}
-
-inline Vector4&
-operator/=(Vector4& a, f32 scalar)
-{
- a.x /= scalar;
- a.y /= scalar;
- a.z /= scalar;
- a.w /= scalar;
-
- return a;
-}
-
-// Complex Operators
-inline bool
-operator==(Complex a, Complex b)
-{
- return (a.x == b.x) && (a.y == b.y);
-}
-
-inline bool
-operator!=(Complex a, Complex b)
-{
- return !operator==(a, b);
-}
-
-inline Complex
-operator+(Complex a)
-{
- return a;
-}
-
-inline Complex
-operator-(Complex a)
-{
- return {-a.x, -a.y};
-}
-
-inline Complex
-operator+(Complex a, Complex b)
-{
- return {a.x + b.x, a.y + b.y};
-}
-
-inline Complex
-operator-(Complex a, Complex b)
-{
- return {a.x - b.x, a.y - b.y};
-
-}
-
-inline Complex
-operator*(Complex a, Complex b)
-{
- Complex c = {};
-
- c.x = a.x * b.x - a.y * b.y;
- c.y = a.y * b.x - a.y * b.x;
-
- return c;
-}
-
-inline Complex
-operator*(Complex a, f32 s)
-{
- return {a.x * s, a.y * s};
-}
-
-inline Complex
-operator*(f32 s, Complex a)
-{
- return {a.x * s, a.y * s};
-}
-
-inline Complex
-operator/(Complex a, f32 s)
-{
- return {a.x / s, a.y / s};
-}
-
-// Quaternion Operators
-inline bool
-operator==(Quaternion a, Quaternion b)
-{
- return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
-}
-
-inline bool
-operator!=(Quaternion a, Quaternion b)
-{
- return !operator==(a, b);
-}
-
-inline Quaternion
-operator+(Quaternion a)
-{
- return {+a.x, +a.y, +a.z, +a.w};
-}
-
-inline Quaternion
-operator-(Quaternion a)
-{
- return {-a.x, -a.y, -a.z, -a.w};
-}
-
-inline Quaternion
-operator+(Quaternion a, Quaternion b)
-{
- return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
-}
-
-inline Quaternion
-operator-(Quaternion a, Quaternion b)
-{
- return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
-
-}
-
-inline Quaternion
-operator*(Quaternion a, Quaternion b)
-{
- Quaternion q = {};
-
- q.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
- q.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
- q.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
- q.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
-
- return q;
-}
-
-inline Quaternion
-operator*(Quaternion a, f32 s)
-{
- return {a.x * s, a.y * s, a.z * s, a.w * s};
-}
-
-inline Quaternion
-operator*(f32 s, Quaternion a)
-{
- return {a.x * s, a.y * s, a.z * s, a.w * s};
-}
-
-inline Quaternion
-operator/(Quaternion a, f32 s)
-{
- return {a.x / s, a.y / s, a.z / s, a.w / s};
-}
-
-inline Vector3
-operator*(Quaternion a, Vector3 v) // Rotate v by q
-{
- // return (q * Quaternion{v.x, v.y, v.z, 0} * math::conjugate(q)).xyz; // More Expensive
- const Vector3 t = 2.0f * math::cross(a.xyz, v);
- return (v + a.w * t + math::cross(a.xyz, t));
-}
-
-// Matrix2 Operators
-inline bool
-operator==(Matrix2 a, Matrix2 b)
-{
- for (usize i = 0; i < 4; i++)
- {
- if (a[i] != b[i])
- return false;
- }
- return true;
-}
-
-inline bool
-operator!=(Matrix2 a, Matrix2 b)
-{
- return !operator==(a, b);
-}
-
-inline Matrix2
-operator+(Matrix2 a)
-{
- return a;
-}
-
-inline Matrix2
-operator-(Matrix2 a)
-{
- return {-a.x, -a.y};
-}
-
-inline Matrix2
-operator+(Matrix2 a, Matrix2 b)
-{
- Matrix2 mat;
- mat[0] = a[0] + b[0];
- mat[1] = a[1] + b[1];
- return mat;
-}
-
-inline Matrix2
-operator-(Matrix2 a, Matrix2 b)
-{
- Matrix2 mat;
- mat[0] = a[0] - b[0];
- mat[1] = a[1] - b[1];
- return mat;
-}
-
-inline Matrix2
-operator*(Matrix2 a, Matrix2 b)
-{
- Matrix2 result;
- result[0] = a[0] * b[0][0] + a[1] * b[0][1];
- result[1] = a[0] * b[1][0] + a[1] * b[1][1];
- return result;
-}
-
-inline Vector2
-operator*(Matrix2 a, Vector2 v)
-{
- return Vector2{a[0][0] * v.x + a[1][0] * v.y,
- a[0][1] * v.x + a[1][1] * v.y};
-}
-
-inline Matrix2
-operator*(Matrix2 a, f32 scalar)
-{
- Matrix2 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- return mat;
-}
-
-inline Matrix2
-operator*(f32 scalar, Matrix2 a)
-{
- Matrix2 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- return mat;
-}
-
-inline Matrix2
-operator/(Matrix2 a, f32 scalar)
-{
- Matrix2 mat;
- mat[0] = a[0] / scalar;
- mat[1] = a[1] / scalar;
- return mat;
-}
-
-inline Matrix2&
-operator+=(Matrix2& a, Matrix2 b)
-{
- return (a = a + b);
-}
-
-inline Matrix2&
-operator-=(Matrix2& a, Matrix2 b)
-{
- return (a = a - b);
-}
-
-inline Matrix2&
-operator*=(Matrix2& a, Matrix2 b)
-{
- return (a = a * b);
-}
-
-
-// Matrix3 Operators
-inline bool
-operator==(Matrix3 const& a, Matrix3 const& b)
-{
- for (usize i = 0; i < 3; i++)
- {
- if (a[i] != b[i])
- return false;
- }
- return true;
-}
-
-inline bool
-operator!=(Matrix3 const& a, Matrix3 const& b)
-{
- return !operator==(a, b);
-}
-
-inline Matrix3
-operator+(Matrix3 const& a)
-{
- return a;
-}
-
-inline Matrix3
-operator-(Matrix3 const& a)
-{
- return {-a.x, -a.y, -a.z};
-}
-
-inline Matrix3
-operator+(Matrix3 const& a, Matrix3 const& b)
-{
- Matrix3 mat;
- mat[0] = a[0] + b[0];
- mat[1] = a[1] + b[1];
- mat[2] = a[2] + b[2];
- return mat;
-}
-
-inline Matrix3
-operator-(Matrix3 const& a, Matrix3 const& b)
-{
- Matrix3 mat;
- mat[0] = a[0] - b[0];
- mat[1] = a[1] - b[1];
- mat[2] = a[2] - b[2];
- return mat;
-}
-
-inline Matrix3
-operator*(Matrix3 const& a, Matrix3 const& b)
-{
- Matrix3 result;
- result[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2];
- result[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2];
- result[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2];
- return result;
-}
-
-inline Vector3
-operator*(Matrix3 const& a, Vector3 v)
-{
- return Vector3{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z,
- a[0][1] * v.x + a[1][1] * v.y + a[2][1] * v.z,
- a[0][2] * v.x + a[1][2] * v.y + a[2][2] * v.z};
-}
-
-inline Matrix3
-operator*(Matrix3 const& a, f32 scalar)
-{
- Matrix3 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- mat[2] = a[2] * scalar;
- return mat;
-}
-
-inline Matrix3
-operator*(f32 scalar, Matrix3 const& a)
-{
- Matrix3 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- mat[2] = a[2] * scalar;
- return mat;
-}
-
-inline Matrix3
-operator/(Matrix3 const& a, f32 scalar)
-{
- Matrix3 mat;
- mat[0] = a[0] / scalar;
- mat[1] = a[1] / scalar;
- mat[2] = a[2] / scalar;
- return mat;
-}
-
-inline Matrix3&
-operator+=(Matrix3& a, Matrix3 const& b)
-{
- return (a = a + b);
-}
-
-inline Matrix3&
-operator-=(Matrix3& a, Matrix3 const& b)
-{
- return (a = a - b);
-}
-
-inline Matrix3&
-operator*=(Matrix3& a, Matrix3 const& b)
-{
- return (a = a * b);
-}
-
-
-// Matrix4 Operators
-inline bool
-operator==(Matrix4 const& a, Matrix4 const& b)
-{
- for (usize i = 0; i < 4; i++)
- {
- if (a[i] != b[i])
- return false;
- }
- return true;
-}
-
-inline bool
-operator!=(Matrix4 const& a, Matrix4 const& b)
-{
- return !operator==(a, b);
-}
-
-inline Matrix4
-operator+(Matrix4 const& a)
-{
- return a;
-}
-
-inline Matrix4
-operator-(Matrix4 const& a)
-{
- return {-a.x, -a.y, -a.z, -a.w};
-}
-
-inline Matrix4
-operator+(Matrix4 const& a, Matrix4 const& b)
-{
- Matrix4 mat;
- mat[0] = a[0] + b[0];
- mat[1] = a[1] + b[1];
- mat[2] = a[2] + b[2];
- mat[3] = a[3] + b[3];
- return mat;
-}
-
-inline Matrix4
-operator-(Matrix4 const& a, Matrix4 const& b)
-{
- Matrix4 mat;
- mat[0] = a[0] - b[0];
- mat[1] = a[1] - b[1];
- mat[2] = a[2] - b[2];
- mat[3] = a[3] - b[3];
- return mat;
-}
-
-inline Matrix4
-operator*(Matrix4 const& a, Matrix4 const& b)
-{
- Matrix4 result;
- result[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2] + a[3] * b[0][3];
- result[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2] + a[3] * b[1][3];
- result[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2] + a[3] * b[2][3];
- result[3] = a[0] * b[3][0] + a[1] * b[3][1] + a[2] * b[3][2] + a[3] * b[3][3];
- return result;
-}
-
-inline Vector4
-operator*(Matrix4 const& a, Vector4 v)
-{
- return Vector4{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z + a[3][0] * v.w,
- a[0][1] * v.x + a[1][1] * v.y + a[2][1] * v.z + a[3][1] * v.w,
- a[0][2] * v.x + a[1][2] * v.y + a[2][2] * v.z + a[3][2] * v.w,
- a[0][3] * v.x + a[1][3] * v.y + a[2][3] * v.z + a[3][3] * v.w};
-}
-
-inline Matrix4
-operator*(Matrix4 const& a, f32 scalar)
-{
- Matrix4 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- mat[2] = a[2] * scalar;
- mat[3] = a[3] * scalar;
- return mat;
-}
-
-inline Matrix4
-operator*(f32 scalar, Matrix4 const& a)
-{
- Matrix4 mat;
- mat[0] = a[0] * scalar;
- mat[1] = a[1] * scalar;
- mat[2] = a[2] * scalar;
- mat[3] = a[3] * scalar;
- return mat;
-}
-
-inline Matrix4
-operator/(Matrix4 const& a, f32 scalar)
-{
- Matrix4 mat;
- mat[0] = a[0] / scalar;
- mat[1] = a[1] / scalar;
- mat[2] = a[2] / scalar;
- mat[3] = a[3] / scalar;
- return mat;
-}
-
-inline Matrix4&
-operator+=(Matrix4& a, Matrix4 const& b)
-{
- return (a = a + b);
-}
-
-inline Matrix4&
-operator-=(Matrix4& a, Matrix4 const& b)
-{
- return (a = a - b);
-}
-
-inline Matrix4&
-operator*=(Matrix4& a, Matrix4 const& b)
-{
- return (a = a * b);
-}
-
-// Angle Operators
-inline bool
-operator==(Angle a, Angle b)
-{
- return a.radians == b.radians;
-}
-
-inline bool
-operator!=(Angle a, Angle b)
-{
- return !operator==(a, b);
-}
-
-inline Angle
-operator+(Angle a)
-{
- return {+a.radians};
-}
-
-inline Angle
-operator-(Angle a)
-{
- return {-a.radians};
-}
-
-inline Angle
-operator+(Angle a, Angle b)
-{
- return {a.radians + b.radians};
-}
-
-inline Angle
-operator-(Angle a, Angle b)
-{
- return {a.radians - b.radians};
-}
-
-inline Angle
-operator*(Angle a, f32 scalar)
-{
- return {a.radians * scalar};
-}
-
-inline Angle
-operator*(f32 scalar, Angle a)
-{
- return {a.radians * scalar};
-}
-
-inline Angle
-operator/(Angle a, f32 scalar)
-{
- return {a.radians / scalar};
-}
-
-inline f32
-operator/(Angle a, Angle b)
-{
- return a.radians / b.radians;
-}
-
-inline Angle&
-operator+=(Angle& a, Angle b)
-{
- return (a = a + b);
-}
-
-inline Angle&
-operator-=(Angle& a, Angle b)
-{
- return (a = a - b);
-}
-
-inline Angle&
-operator*=(Angle& a, f32 scalar)
-{
- return (a = a * scalar);
-}
-
-inline Angle&
-operator/=(Angle& a, f32 scalar)
-{
- return (a = a / scalar);
-}
-
-
-// Transform Operators
-// World = Parent * Local
-Transform
-operator*(Transform const& ps, Transform const& ls)
-{
- Transform ws;
-
- ws.position = ps.position + ps.orientation * (ps.scale * ls.position);
- ws.orientation = ps.orientation * ls.orientation;
- // ws.scale = ps.scale * (ps.orientation * ls.scale); // Vector3 scale
- ws.scale = ps.scale * ls.scale;
-
- return ws;
-}
-
-inline Transform&
-operator*=(Transform& ps, Transform const& ls)
-{
- return (ps = ps * ls);
-}
-
-// Local = World / Parent
-Transform
-operator/(Transform const& ws, Transform const& ps)
-{
- Transform ls;
-
- const Quaternion ps_conjugate = math::conjugate(ps.orientation);
-
- ls.position = (ps_conjugate * (ws.position - ps.position)) / ps.scale;
- ls.orientation = ps_conjugate * ws.orientation;
- // ls.scale = ps_conjugate * (ws.scale / ps.scale); // Vector3 scale
- ls.scale = ws.scale / ps.scale;
-
- return ls;
-}
-
-inline Transform&
-operator/=(Transform& ws, Transform const& ps)
-{
- return (ws = ws / ps);
-}
-
-
-namespace angle
-{
-inline Angle radians(f32 r) { return {r}; }
-inline Angle degrees(f32 d) { return {d * math::TAU / 360.0f}; }
-inline Angle turns(f32 t) { return {t * math::TAU}; }
-inline Angle grads(f32 g) { return {g * math::TAU / 400.0f}; }
-inline Angle gons(f32 g) { return {g * math::TAU / 400.0f}; }
-
-inline f32 as_radians(Angle a) { return a.radians; }
-inline f32 as_degrees(Angle a) { return a.radians * (360.0f / math::TAU); }
-inline f32 as_turns(Angle a) { return a.radians * ( 1.0f / math::TAU); }
-inline f32 as_grads(Angle a) { return a.radians * (400.0f / math::TAU); }
-inline f32 as_gons(Angle a) { return a.radians * (400.0f / math::TAU); }
-} // namespace angle
-
-////////////////////////////////
-/// ///
-/// Math Functions ///
-/// ///
-////////////////////////////////
-
-
-namespace math
-{
-f32 const ZERO = 0.0f;
-f32 const ONE = 1.0f;
-f32 const THIRD = 0.33333333f;
-f32 const TWO_THIRDS = 0.66666667f;
-f32 const E = 2.718281828f;
-f32 const PI = 3.141592654f;
-f32 const TAU = 6.283185307f;
-f32 const SQRT_2 = 1.414213562f;
-f32 const SQRT_3 = 1.732050808f;
-f32 const SQRT_5 = 2.236067978f;
-
-f32 const F32_PRECISION = 1.0e-7f;
-
-// Power
-inline f32 sqrt(f32 x) { return ::sqrtf(x); }
-inline f32 pow(f32 x, f32 y) { return static_cast<f32>(::powf(x, y)); }
-inline f32 cbrt(f32 x) { return static_cast<f32>(::cbrtf(x)); }
-
-inline f32
-fast_inv_sqrt(f32 x)
-{
- const f32 THREE_HALFS = 1.5f;
-
- const f32 x2 = x * 0.5f;
- f32 y = x;
- u32 i = bit_cast<u32>(y); // Evil floating point bit level hacking
- // i = 0x5f3759df - (i >> 1); // What the fuck? Old
- i = 0x5f375a86 - (i >> 1); // What the fuck? Improved!
- y = bit_cast<f32>(i);
- y = y * (THREE_HALFS - (x2 * y * y)); // 1st iteration
- // y = y * (THREE_HALFS - (x2 * y * y)); // 2nd iteration, this can be removed
-
- return y;
-}
-
-// Trigonometric
-inline f32 sin(Angle a) { return ::sinf(angle::as_radians(a)); }
-inline f32 cos(Angle a) { return ::cosf(angle::as_radians(a)); }
-inline f32 tan(Angle a) { return ::tanf(angle::as_radians(a)); }
-
-inline Angle arcsin(f32 x) { return angle::radians(::asinf(x)); }
-inline Angle arccos(f32 x) { return angle::radians(::acosf(x)); }
-inline Angle arctan(f32 x) { return angle::radians(::atanf(x)); }
-inline Angle arctan2(f32 y, f32 x) { return angle::radians(::atan2f(y, x)); }
-
-// Hyperbolic
-inline f32 sinh(f32 x) { return ::sinhf(x); }
-inline f32 cosh(f32 x) { return ::coshf(x); }
-inline f32 tanh(f32 x) { return ::tanhf(x); }
-
-inline f32 arsinh(f32 x) { return ::asinhf(x); }
-inline f32 arcosh(f32 x) { return ::acoshf(x); }
-inline f32 artanh(f32 x) { return ::atanhf(x); }
-
-// Rounding
-inline f32 ceil(f32 x) { return ::ceilf(x); }
-inline f32 floor(f32 x) { return ::floorf(x); }
-inline f32 mod(f32 x, f32 y) { return ::fmodf(x, y); }
-inline f32 truncate(f32 x) { return ::truncf(x); }
-inline f32 round(f32 x) { return ::roundf(x); }
-
-inline s32 sign(s32 x) { return x >= 0 ? +1 : -1; }
-inline s64 sign(s64 x) { return x >= 0 ? +1 : -1; }
-inline f32 sign(f32 x) { return x >= 0.0f ? +1.0f : -1.0f; }
-
-// Other
-inline f32
-abs(f32 x)
-{
- u32 i = bit_cast<u32>(x);
- i &= 0x7FFFFFFFul;
- return bit_cast<f32>(i);
-}
-
-inline s8
-abs(s8 x)
-{
- u8 i = bit_cast<u8>(x);
- i &= 0x7Fu;
- return bit_cast<s8>(i);
-}
-
-inline s16
-abs(s16 x)
-{
- u16 i = bit_cast<u16>(x);
- i &= 0x7FFFu;
- return bit_cast<s16>(i);
-}
-
-inline s32
-abs(s32 x)
-{
- u32 i = bit_cast<u32>(x);
- i &= 0x7FFFFFFFul;
- return bit_cast<s32>(i);
-}
-
-inline s64
-abs(s64 x)
-{
- u64 i = bit_cast<u64>(x);
- i &= 0x7FFFFFFFFFFFFFFFull;
- return bit_cast<s64>(i);
-}
-
-inline bool
-is_infinite(f32 x)
-{
- return isinf(x);
-}
-
-inline bool
-is_nan(f32 x)
-{
- return isnan(x);
-}
-
-inline s32
-kronecker_delta(s32 i, s32 j)
-{
- return static_cast<s32>(i == j);
-}
-
-inline s64
-kronecker_delta(s64 i, s64 j)
-{
- return static_cast<s64>(i == j);
-}
-
-inline f32
-kronecker_delta(f32 i, f32 j)
-{
- return static_cast<f32>(i == j);
-}
-
-inline f32
-min(f32 x, f32 y)
-{
- // TODO(bill): Check if this is even good
- return x < y ? x : y;
-}
-
-inline s32
-min(s32 x, s32 y)
-{
- return y + ((x-y) & (x-y)>>31);
-}
-
-inline s64
-min(s64 x, s64 y)
-{
- return y + ((x-y) & (x-y)>>63);
-}
-
-inline f32
-max(f32 x, f32 y)
-{
- // TODO(bill): Check if this is even good
- return x > y ? x : y;
-}
-
-inline s32
-max(s32 x, s32 y)
-{
- return x - ((x-y) & (x-y)>>31);
-}
-
-inline s64
-max(s64 x, s64 y)
-{
- return x - ((x-y) & (x-y)>>63);
-}
-
-inline f32
-clamp(f32 x, f32 min, f32 max)
-{
- const f32 t = x < min ? min : x;
- return t > max ? max : t;
-}
-
-inline s32
-clamp(s32 x, s32 min, s32 max)
-{
- const s32 t = x < min ? min : x;
- return t > max ? max : t;
-}
-
-inline s64
-clamp(s64 x, s64 min, s64 max)
-{
- const s64 t = x < min ? min : x;
- return t > max ? max : t;
-}
-
-inline bool
-equals(f32 a, f32 b, f32 precision)
-{
- return ((b <= (a + precision)) && (b >= (a - precision)));
-}
-
-// Vector2 functions
-inline f32
-dot(Vector2 a, Vector2 b)
-{
- return a.x * b.x + a.y * b.y;
-}
-
-inline f32
-cross(Vector2 a, Vector2 b)
-{
- return a.x * b.y - a.y * b.x;
-}
-
-inline f32
-magnitude(Vector2 a)
-{
- return math::sqrt(math::dot(a, a));
-}
-
-inline Vector2
-normalize(Vector2 a)
-{
- f32 m = magnitude(a);
- if (m > 0)
- return a * (1.0f / m);
- return {};
-}
-
-inline Vector2
-hadamard(Vector2 a, Vector2 b)
-{
- return {a.x * b.x, a.y * b.y};
-}
-
-inline f32
-aspect_ratio(Vector2 a)
-{
- return a.x / a.y;
-}
-
-
-inline Matrix4
-matrix2_to_matrix4(Matrix2 m)
-{
- Matrix4 result = MATRIX4_IDENTITY;
- result[0][0] = m[0][0];
- result[0][1] = m[0][1];
- result[1][0] = m[1][0];
- result[1][1] = m[1][1];
- return result;
-}
-
-// Vector3 functions
-inline f32
-dot(Vector3 a, Vector3 b)
-{
- return a.x * b.x + a.y * b.y + a.z * b.z;
-}
-
-inline Vector3
-cross(Vector3 a, Vector3 b)
-{
- return Vector3{
- a.y * b.z - b.y * a.z, // x
- a.z * b.x - b.z * a.x, // y
- a.x * b.y - b.x * a.y // z
- };
-}
-
-inline f32
-magnitude(Vector3 a)
-{
- return math::sqrt(math::dot(a, a));
-}
-
-inline Vector3
-normalize(Vector3 a)
-{
- f32 m = magnitude(a);
- if (m > 0)
- return a * (1.0f / m);
- return {};
-}
-
-inline Vector3
-hadamard(Vector3 a, Vector3 b)
-{
- return {a.x * b.x, a.y * b.y, a.z * b.z};
-}
-
-inline Matrix4
-matrix3_to_matrix4(Matrix3 const& m)
-{
- Matrix4 result = MATRIX4_IDENTITY;
- result[0][0] = m[0][0];
- result[0][1] = m[0][1];
- result[0][2] = m[0][2];
- result[1][0] = m[1][0];
- result[1][1] = m[1][1];
- result[1][2] = m[1][2];
- result[2][0] = m[2][0];
- result[2][1] = m[2][1];
- result[2][2] = m[2][2];
- return result;
-}
-
-// Vector4 functions
-inline f32
-dot(Vector4 a, Vector4 b)
-{
- return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
-}
-
-inline f32
-magnitude(Vector4 a)
-{
- return math::sqrt(math::dot(a, a));
-}
-
-inline Vector4
-normalize(Vector4 a)
-{
- f32 m = magnitude(a);
- if (m > 0)
- return a * (1.0f / m);
- return {};
-}
-
-inline Vector4
-hadamard(Vector4 a, Vector4 b)
-{
- return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
-}
-
-// Complex Functions
-inline f32
-dot(Complex a, Complex b)
-{
- return a.real * b.real + a.imag * b.imag;
-}
-
-inline f32
-magnitude(Complex a)
-{
- return math::sqrt(norm(a));
-}
-
-inline f32
-norm(Complex a)
-{
- return math::dot(a, a);
-}
-
-inline Complex
-normalize(Complex a)
-{
- f32 m = magnitude(a);
- if (m > 0)
- return a / magnitude(a);
- return COMPLEX_ZERO;
-}
-
-inline Complex
-conjugate(Complex a)
-{
- return {a.real, -a.imag};
-}
-
-inline Complex
-inverse(Complex a)
-{
- f32 m = norm(a);
- if (m > 0)
- return conjugate(a) / norm(a);
- return COMPLEX_ZERO;
-}
-
-inline f32
-complex_angle(Complex a)
-{
- return atan2f(a.imag, a.real);
-}
-
-inline Complex
-magnitude_angle(f32 magnitude, Angle a)
-{
- f32 real = magnitude * math::cos(a);
- f32 imag = magnitude * math::sin(a);
- return {real, imag};
-}
-
-// Quaternion functions
-inline f32
-dot(Quaternion a, Quaternion b)
-{
- return math::dot(a.xyz, b.xyz) + a.w*b.w;
-}
-
-inline Quaternion
-cross(Quaternion a, Quaternion b)
-{
- return Quaternion{a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
- a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z,
- a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x,
- a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z};
-}
-
-inline f32
-magnitude(Quaternion a)
-{
- return math::sqrt(math::dot(a, a));
-}
-
-inline f32
-norm(Quaternion a)
-{
- return math::dot(a, a);
-}
-
-inline Quaternion
-normalize(Quaternion a)
-{
- f32 m = magnitude(a);
- if (m > 0)
- return a * (1.0f / m);
- return {};
-}
-
-inline Quaternion
-conjugate(Quaternion a)
-{
- return {-a.x, -a.y, -a.z, a.w};
-}
-
-inline Quaternion
-inverse(Quaternion a)
-{
- f32 m = 1.0f / dot(a, a);
- return math::conjugate(a) * m;
-}
-
-inline Angle
-quaternion_angle(Quaternion a)
-{
- return 2.0f * math::arccos(a.w);
-}
-
-inline Vector3
-quaternion_axis(Quaternion a)
-{
- f32 s2 = 1.0f - a.w * a.w;
-
- if (s2 <= 0.0f)
- return {0, 0, 1};
-
- f32 invs2 = 1.0f / math::sqrt(s2);
-
- return a.xyz * invs2;
-}
-
-inline Quaternion
-axis_angle(Vector3 axis, Angle angle)
-{
- Vector3 a = math::normalize(axis);
- f32 s = math::sin(0.5f * angle);
-
- Quaternion q;
- q.xyz = a * s;
- q.w = math::cos(0.5f * angle);
-
- return q;
-}
-
-inline Angle
-quaternion_roll(Quaternion a)
-{
- return math::arctan2(2.0f * a.x * a.y + a.z * a.w,
- a.x * a.x + a.w * a.w - a.y * a.y - a.z * a.z);
-}
-
-inline Angle
-quaternion_pitch(Quaternion a)
-{
- return math::arctan2(2.0f * a.y * a.z + a.w * a.x,
- a.w * a.w - a.x * a.x - a.y * a.y + a.z * a.z);
-}
-
-inline Angle
-quaternion_yaw(Quaternion a)
-{
- return math::arcsin(-2.0f * (a.x * a.z - a.w * a.y));
-
-}
-
-inline Euler_Angles
-quaternion_to_euler_angles(Quaternion a)
-{
- return {quaternion_pitch(a), quaternion_yaw(a), quaternion_roll(a)};
-}
-
-inline Quaternion
-euler_angles_to_quaternion(Euler_Angles const& e,
- Vector3 x_axis,
- Vector3 y_axis,
- Vector3 z_axis)
-{
- Quaternion p = axis_angle(x_axis, e.pitch);
- Quaternion y = axis_angle(y_axis, e.yaw);
- Quaternion r = axis_angle(z_axis, e.roll);
-
- return y * p * r;
-}
-
-
-// Spherical Linear Interpolation
-inline Quaternion
-slerp(Quaternion x, Quaternion y, f32 t)
-{
- Quaternion z = y;
-
- f32 cos_theta = dot(x, y);
-
- if (cos_theta < 0.0f)
- {
- z = -y;
- cos_theta = -cos_theta;
- }
-
- if (cos_theta > 1.0f)
- {
- return Quaternion{lerp(x.x, y.x, t),
- lerp(x.y, y.y, t),
- lerp(x.z, y.z, t),
- lerp(x.w, y.w, t)};
- }
-
- Angle angle = math::arccos(cos_theta);
-
- Quaternion result = math::sin(angle::radians(1.0f) - (t * angle)) * x + math::sin(t * angle) * z;
- return result * (1.0f / math::sin(angle));
-}
-
-// Shoemake's Quaternion Curves
-// Sqherical Cubic Interpolation
-inline Quaternion
-squad(Quaternion p,
- Quaternion a,
- Quaternion b,
- Quaternion q,
- f32 t)
-{
- return slerp(slerp(p, q, t), slerp(a, b, t), 2.0f * t * (1.0f - t));
-}
-
-// Matrix2 functions
-inline Matrix2
-transpose(Matrix2 m)
-{
- Matrix2 result;
- for (usize i = 0; i < 2; i++)
- {
- for (usize j = 0; j < 2; j++)
- result[i][j] = m[j][i];
- }
- return result;
-}
-
-inline f32
-determinant(Matrix2 m)
-{
- return m[0][0] * m[1][1] - m[1][0] * m[0][1];
-}
-
-inline Matrix2
-inverse(Matrix2 m)
-{
- f32 inv_det = 1.0f / (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
- Matrix2 result;
- result[0][0] = m[1][1] * inv_det;
- result[0][1] = -m[0][1] * inv_det;
- result[1][0] = -m[1][0] * inv_det;
- result[1][1] = m[0][0] * inv_det;
- return result;
-}
-
-inline Matrix2
-hadamard(Matrix2 a, const Matrix2&b)
-{
- Matrix2 result;
- result[0] = a[0] * b[0];
- result[1] = a[1] * b[1];
- return result;
-}
-
-// Matrix3 functions
-inline Matrix3
-transpose(Matrix3 const& m)
-{
- Matrix3 result;
-
- for (usize i = 0; i < 3; i++)
- {
- for (usize j = 0; j < 3; j++)
- result[i][j] = m[j][i];
- }
- return result;
-}
-
-inline f32
-determinant(Matrix3 const& m)
-{
- return (+m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
- -m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
- +m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
-}
-
-inline Matrix3
-inverse(Matrix3 const& m)
-{
- f32 inv_det = 1.0f / (
- + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
- - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
- + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
-
- Matrix3 result;
-
- result[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * inv_det;
- result[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * inv_det;
- result[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * inv_det;
- result[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * inv_det;
- result[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * inv_det;
- result[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * inv_det;
- result[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * inv_det;
- result[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * inv_det;
- result[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * inv_det;
-
- return result;
-}
-
-inline Matrix3
-hadamard(Matrix3 const& a, const Matrix3&b)
-{
- Matrix3 result;
- result[0] = a[0] * b[0];
- result[1] = a[1] * b[1];
- result[2] = a[2] * b[2];
- return result;
-}
-
-// Matrix4 functions
-inline Matrix4
-transpose(Matrix4 const& m)
-{
- Matrix4 result;
-
- for (usize i = 0; i < 4; i++)
- {
- for (usize j = 0; j < 4; j++)
- result[i][j] = m[j][i];
- }
- return result;
-}
-
-f32
-determinant(Matrix4 const& m)
-{
- f32 coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
- f32 coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
- f32 coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
-
- f32 coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
- f32 coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
- f32 coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
-
- f32 coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
- f32 coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
- f32 coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
-
- f32 coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
- f32 coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
- f32 coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
-
- f32 coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
- f32 coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
- f32 coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
-
- f32 coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
- f32 coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
- f32 coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
-
- Vector4 fac0 = {coef00, coef00, coef02, coef03};
- Vector4 fac1 = {coef04, coef04, coef06, coef07};
- Vector4 fac2 = {coef08, coef08, coef10, coef11};
- Vector4 fac3 = {coef12, coef12, coef14, coef15};
- Vector4 fac4 = {coef16, coef16, coef18, coef19};
- Vector4 fac5 = {coef20, coef20, coef22, coef23};
-
- Vector4 vec0 = {m[1][0], m[0][0], m[0][0], m[0][0]};
- Vector4 vec1 = {m[1][1], m[0][1], m[0][1], m[0][1]};
- Vector4 vec2 = {m[1][2], m[0][2], m[0][2], m[0][2]};
- Vector4 vec3 = {m[1][3], m[0][3], m[0][3], m[0][3]};
-
- Vector4 inv0 = vec1 * fac0 - vec2 * fac1 + vec3 * fac2;
- Vector4 inv1 = vec0 * fac0 - vec2 * fac3 + vec3 * fac4;
- Vector4 inv2 = vec0 * fac1 - vec1 * fac3 + vec3 * fac5;
- Vector4 inv3 = vec0 * fac2 - vec1 * fac4 + vec2 * fac5;
-
- Vector4 signA = {+1, -1, +1, -1};
- Vector4 signB = {-1, +1, -1, +1};
- Matrix4 inverse = {inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB};
-
- Vector4 row0 = {inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]};
-
- Vector4 dot0 = m[0] * row0;
- f32 dot1 = (dot0[0] + dot0[1]) + (dot0[2] + dot0[3]);
- return dot1;
-}
-
-Matrix4
-inverse(Matrix4 const& m)
-{
- f32 coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
- f32 coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
- f32 coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
- f32 coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
- f32 coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
- f32 coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
- f32 coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
- f32 coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
- f32 coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
- f32 coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
- f32 coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
- f32 coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
- f32 coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
- f32 coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
- f32 coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
- f32 coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
- f32 coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
- f32 coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
-
- Vector4 fac0 = {coef00, coef00, coef02, coef03};
- Vector4 fac1 = {coef04, coef04, coef06, coef07};
- Vector4 fac2 = {coef08, coef08, coef10, coef11};
- Vector4 fac3 = {coef12, coef12, coef14, coef15};
- Vector4 fac4 = {coef16, coef16, coef18, coef19};
- Vector4 fac5 = {coef20, coef20, coef22, coef23};
-
- Vector4 vec0 = {m[1][0], m[0][0], m[0][0], m[0][0]};
- Vector4 vec1 = {m[1][1], m[0][1], m[0][1], m[0][1]};
- Vector4 vec2 = {m[1][2], m[0][2], m[0][2], m[0][2]};
- Vector4 vec3 = {m[1][3], m[0][3], m[0][3], m[0][3]};
-
- Vector4 inv0 = vec1 * fac0 - vec2 * fac1 + vec3 * fac2;
- Vector4 inv1 = vec0 * fac0 - vec2 * fac3 + vec3 * fac4;
- Vector4 inv2 = vec0 * fac1 - vec1 * fac3 + vec3 * fac5;
- Vector4 inv3 = vec0 * fac2 - vec1 * fac4 + vec2 * fac5;
-
- Vector4 signA = {+1, -1, +1, -1};
- Vector4 signB = {-1, +1, -1, +1};
- Matrix4 inverse = {inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB};
-
- Vector4 row0 = {inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]};
-
- Vector4 dot0 = m[0] * row0;
- f32 dot1 = (dot0[0] + dot0[1]) + (dot0[2] + dot0[3]);
-
- f32 oneOverDeterminant = 1.0f / dot1;
-
- return inverse * oneOverDeterminant;
-}
-
-inline Matrix4
-hadamard(Matrix4 const& a, Matrix4 const& b)
-{
- Matrix4 result;
-
- result[0] = a[0] * b[0];
- result[1] = a[1] * b[1];
- result[2] = a[2] * b[2];
- result[3] = a[3] * b[3];
-
- return result;
-}
-
-inline bool
-is_affine(Matrix4 const& m)
-{
- // E.g. No translation
- return (equals(m.columns[3].x, 0)) &
- (equals(m.columns[3].y, 0)) &
- (equals(m.columns[3].z, 0)) &
- (equals(m.columns[3].w, 1.0f));
-}
-
-
-inline Matrix4
-quaternion_to_matrix4(Quaternion q)
-{
- Matrix4 mat = MATRIX4_IDENTITY;
-
- Quaternion a = math::normalize(q);
-
- f32 xx = a.x * a.x;
- f32 yy = a.y * a.y;
- f32 zz = a.z * a.z;
- f32 xy = a.x * a.y;
- f32 xz = a.x * a.z;
- f32 yz = a.y * a.z;
- f32 wx = a.w * a.x;
- f32 wy = a.w * a.y;
- f32 wz = a.w * a.z;
-
- mat[0][0] = 1.0f - 2.0f * (yy + zz);
- mat[0][1] = 2.0f * (xy + wz);
- mat[0][2] = 2.0f * (xz - wy);
-
- mat[1][0] = 2.0f * (xy - wz);
- mat[1][1] = 1.0f - 2.0f * (xx + zz);
- mat[1][2] = 2.0f * (yz + wx);
-
- mat[2][0] = 2.0f * (xz + wy);
- mat[2][1] = 2.0f * (yz - wx);
- mat[2][2] = 1.0f - 2.0f * (xx + yy);
-
- return mat;
-}
-
-Quaternion
-matrix4_to_quaternion(Matrix4 const& m)
-{
- f32 four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
- f32 four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
- f32 four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
- f32 four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
-
- s32 biggestIndex = 0;
- f32 four_biggest_squared_minus_1 = four_w_squared_minus_1;
- if (four_x_squared_minus_1 > four_biggest_squared_minus_1)
- {
- four_biggest_squared_minus_1 = four_x_squared_minus_1;
- biggestIndex = 1;
- }
- if (four_y_squared_minus_1 > four_biggest_squared_minus_1)
- {
- four_biggest_squared_minus_1 = four_y_squared_minus_1;
- biggestIndex = 2;
- }
- if (four_z_squared_minus_1 > four_biggest_squared_minus_1)
- {
- four_biggest_squared_minus_1 = four_z_squared_minus_1;
- biggestIndex = 3;
- }
-
- f32 biggestVal = math::sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f;
- f32 mult = 0.25f / biggestVal;
-
- Quaternion q = QUATERNION_IDENTITY;
-
- switch (biggestIndex)
- {
- case 0:
- {
- q.w = biggestVal;
- q.x = (m[1][2] - m[2][1]) * mult;
- q.y = (m[2][0] - m[0][2]) * mult;
- q.z = (m[0][1] - m[1][0]) * mult;
- }
- break;
- case 1:
- {
- q.w = (m[1][2] - m[2][1]) * mult;
- q.x = biggestVal;
- q.y = (m[0][1] + m[1][0]) * mult;
- q.z = (m[2][0] + m[0][2]) * mult;
- }
- break;
- case 2:
- {
- q.w = (m[2][0] - m[0][2]) * mult;
- q.x = (m[0][1] + m[1][0]) * mult;
- q.y = biggestVal;
- q.z = (m[1][2] + m[2][1]) * mult;
- }
- break;
- case 3:
- {
- q.w = (m[0][1] - m[1][0]) * mult;
- q.x = (m[2][0] + m[0][2]) * mult;
- q.y = (m[1][2] + m[2][1]) * mult;
- q.z = biggestVal;
- }
- break;
- default: // Should never actually get here. Just for sanities sake.
- {
- GB_ASSERT(false, "How did you get here?!");
- }
- break;
- }
-
- return q;
-}
-
-
-inline Matrix4
-translate(Vector3 v)
-{
- Matrix4 result = MATRIX4_IDENTITY;
- result[3].xyz = v;
- result[3].w = 1;
- return result;
-}
-
-inline Matrix4
-rotate(Vector3 v, Angle angle)
-{
- const f32 c = math::cos(angle);
- const f32 s = math::sin(angle);
-
- const Vector3 axis = math::normalize(v);
- const Vector3 t = (1.0f - c) * axis;
-
- Matrix4 rot = MATRIX4_IDENTITY;
-
- rot[0][0] = c + t.x * axis.x;
- rot[0][1] = 0 + t.x * axis.y + s * axis.z;
- rot[0][2] = 0 + t.x * axis.z - s * axis.y;
- rot[0][3] = 0;
-
- rot[1][0] = 0 + t.y * axis.x - s * axis.z;
- rot[1][1] = c + t.y * axis.y;
- rot[1][2] = 0 + t.y * axis.z + s * axis.x;
- rot[1][3] = 0;
-
- rot[2][0] = 0 + t.z * axis.x + s * axis.y;
- rot[2][1] = 0 + t.z * axis.y - s * axis.x;
- rot[2][2] = c + t.z * axis.z;
- rot[2][3] = 0;
-
- return rot;
-}
-
-inline Matrix4
-scale(Vector3 v)
-{
- return { v.x, 0, 0, 0,
- 0, v.y, 0, 0,
- 0, 0, v.z, 0,
- 0, 0, 0, 1 };
-}
-
-inline Matrix4
-ortho(f32 left, f32 right, f32 bottom, f32 top)
-{
- return ortho(left, right, bottom, top, -1.0f, 1.0f);
-}
-
-inline Matrix4
-ortho(f32 left, f32 right, f32 bottom, f32 top, f32 z_near, f32 z_far)
-{
- Matrix4 result = MATRIX4_IDENTITY;
-
- result[0][0] = 2.0f / (right - left);
- result[1][1] = 2.0f / (top - bottom);
- result[2][2] = -2.0f / (z_far - z_near);
- result[3][0] = -(right + left) / (right - left);
- result[3][1] = -(top + bottom) / (top - bottom);
- result[3][2] = -(z_far + z_near) / (z_far - z_near);
-
- return result;
-}
-
-inline Matrix4
-perspective(Angle fovy, f32 aspect, f32 z_near, f32 z_far)
-{
- GB_ASSERT(math::abs(aspect) > 0.0f,
- "math::perspective `fovy` is %f rad", angle::as_radians(fovy));
-
- f32 tan_half_fovy = math::tan(0.5f * fovy);
-
- Matrix4 result = {};
- result[0][0] = 1.0f / (aspect * tan_half_fovy);
- result[1][1] = 1.0f / (tan_half_fovy);
- result[2][2] = -(z_far + z_near) / (z_far - z_near);
- result[2][3] = -1.0f;
- result[3][2] = -2.0f * z_far * z_near / (z_far - z_near);
-
- return result;
-}
-
-inline Matrix4
-infinite_perspective(Angle fovy, f32 aspect, f32 z_near)
-{
- f32 range = math::tan(0.5f * fovy) * z_near;
- f32 left = -range * aspect;
- f32 right = range * aspect;
- f32 bottom = -range;
- f32 top = range;
-
- Matrix4 result = {};
-
- result[0][0] = (2.0f * z_near) / (right - left);
- result[1][1] = (2.0f * z_near) / (top - bottom);
- result[2][2] = -1.0f;
- result[2][3] = -1.0f;
- result[3][2] = -2.0f * z_near;
-
- return result;
-}
-
-
-inline Matrix4
-look_at_matrix4(Vector3 eye, Vector3 center, Vector3 up)
-{
- const Vector3 f = math::normalize(center - eye);
- const Vector3 s = math::normalize(math::cross(f, up));
- const Vector3 u = math::cross(s, f);
-
- Matrix4 result = MATRIX4_IDENTITY;
-
- result[0][0] = +s.x;
- result[1][0] = +s.y;
- result[2][0] = +s.z;
-
- result[0][1] = +u.x;
- result[1][1] = +u.y;
- result[2][1] = +u.z;
-
- result[0][2] = -f.x;
- result[1][2] = -f.y;
- result[2][2] = -f.z;
-
- result[3][0] = -math::dot(s, eye);
- result[3][1] = -math::dot(u, eye);
- result[3][2] = +math::dot(f, eye);
-
- return result;
-}
-
-
-inline Quaternion
-look_at_quaternion(Vector3 eye, Vector3 center, Vector3 up)
-{
- if (math::equals(math::magnitude(center - eye), 0, 0.001f))
- return QUATERNION_IDENTITY; // You cannot look at where you are!
-
-#if 1
- return matrix4_to_quaternion(look_at_matrix4(eye, center, up));
-#else
- // TODO(bill): Thoroughly test this look_at_quaternion!
- // Is it more efficient that that a converting a Matrix4 to a Quaternion?
- Vector3 forward_l = math::normalize(center - eye);
- Vector3 forward_w = {1, 0, 0};
- Vector3 axis = math::cross(forward_l, forward_w);
-
- f32 angle = math::acos(math::dot(forward_l, forward_w));
-
- Vector3 third = math::cross(axis, forward_w);
- if (math::dot(third, forward_l) < 0)
- angle = -angle;
-
- Quaternion q1 = math::axis_angle(axis, angle);
-
- Vector3 up_l = q1 * math::normalize(up);
- Vector3 right = math::normalize(math::cross(forward_l, up));
- Vector3 up_w = math::normalize(math::cross(right, forward_l));
-
- Vector3 axis2 = math::cross(up_l, up_w);
- f32 angle2 = math::acos(math::dot(up_l, up_w));
-
- Quaternion q2 = math::axis_angle(axis2, angle2);
-
- return q2 * q1;
-#endif
-}
-
-// Transform Functions
-inline Vector3
-transform_point(Transform const& transform, Vector3 point)
-{
- return (math::conjugate(transform.orientation) * (transform.position - point)) / transform.scale;
-}
-
-inline Transform
-inverse(Transform const& t)
-{
- const Quaternion inv_orientation = math::conjugate(t.orientation);
-
- Transform inv_transform;
-
- inv_transform.position = (inv_orientation * -t.position) / t.scale;
- inv_transform.orientation = inv_orientation;
- // inv_transform.scale = inv_orientation * (Vector3{1, 1, 1} / t.scale); // Vector3 scale
- inv_transform.scale = 1.0f / t.scale;
-
- return inv_transform;
-}
-
-inline Matrix4
-transform_to_matrix4(Transform const& t)
-{
- return math::translate(t.position) *
- math::quaternion_to_matrix4(t.orientation) *
- math::scale({t.scale, t.scale, t.scale});
-}
-} // namespace math
-
-
-namespace aabb
-{
-inline Aabb
-calculate(void const* vertices, usize num_vertices, usize stride, usize offset)
-{
- Vector3 min;
- Vector3 max;
- const u8* vertex = reinterpret_cast<const u8*>(vertices);
- vertex += offset;
- Vector3 position = pseudo_cast<Vector3>(vertex);
- min.x = max.x = position.x;
- min.y = max.y = position.y;
- min.z = max.z = position.z;
- vertex += stride;
-
- for (usize i = 1; i < num_vertices; i++)
- {
- position = pseudo_cast<Vector3>(vertex);
- vertex += stride;
-
- Vector3 p = position;
- min.x = math::min(p.x, min.x);
- min.y = math::min(p.y, min.y);
- min.z = math::min(p.z, min.z);
- max.x = math::max(p.x, max.x);
- max.y = math::max(p.y, max.y);
- max.z = math::max(p.z, max.z);
- }
-
- Aabb aabb;
-
- aabb.center = 0.5f * (min + max);
- aabb.half_size = 0.5f * (max - min);
-
- return aabb;
-}
-
-inline f32
-surface_area(Aabb const& aabb)
-{
- Vector3 h = aabb.half_size * 2.0f;
- f32 s = 0.0f;
- s += h.x * h.y;
- s += h.y * h.z;
- s += h.z * h.x;
- s *= 3.0f;
- return s;
-}
-
-inline f32
-volume(Aabb const& aabb)
-{
- Vector3 h = aabb.half_size * 2.0f;
- return h.x * h.y * h.z;
-}
-
-inline Sphere
-to_sphere(Aabb const& aabb)
-{
- Sphere s;
- s.center = aabb.center;
- s.radius = math::magnitude(aabb.half_size);
- return s;
-}
-
-
-inline bool
-contains(Aabb const& aabb, Vector3 point)
-{
- Vector3 distance = aabb.center - point;
-
- // NOTE(bill): & is faster than &&
- return (math::abs(distance.x) <= aabb.half_size.x) &
- (math::abs(distance.y) <= aabb.half_size.y) &
- (math::abs(distance.z) <= aabb.half_size.z);
-}
-
-inline bool
-contains(Aabb const& a, Aabb const& b)
-{
- Vector3 dist = a.center - b.center;
-
- // NOTE(bill): & is faster than &&
- return (math::abs(dist.x) + b.half_size.x <= a.half_size.x) &
- (math::abs(dist.y) + b.half_size.y <= a.half_size.y) &
- (math::abs(dist.z) + b.half_size.z <= a.half_size.z);
-}
-
-
-inline bool
-intersects(Aabb const& a, Aabb const& b)
-{
- Vector3 dist = a.center - b.center;
- Vector3 sum_half_sizes = a.half_size + b.half_size;
-
- // NOTE(bill): & is faster than &&
- return (math::abs(dist.x) <= sum_half_sizes.x) &
- (math::abs(dist.y) <= sum_half_sizes.y) &
- (math::abs(dist.z) <= sum_half_sizes.z);
-}
-
-inline Aabb
-transform_affine(Aabb const& aabb, Matrix4 const& m)
-{
- GB_ASSERT(math::is_affine(m),
- "Passed Matrix4 must be an affine matrix");
-
- Aabb result;
- Vector4 ac;
- ac.xyz = aabb.center;
- ac.w = 1;
- result.center = (m * ac).xyz;
-
- Vector3 hs = aabb.half_size;
- f32 x = math::abs(m[0][0] * hs.x + math::abs(m[0][1]) * hs.y + math::abs(m[0][2]) * hs.z);
- f32 y = math::abs(m[1][0] * hs.x + math::abs(m[1][1]) * hs.y + math::abs(m[1][2]) * hs.z);
- f32 z = math::abs(m[2][0] * hs.x + math::abs(m[2][1]) * hs.y + math::abs(m[2][2]) * hs.z);
-
- result.half_size.x = math::is_infinite(math::abs(hs.x)) ? hs.x : x;
- result.half_size.y = math::is_infinite(math::abs(hs.y)) ? hs.y : y;
- result.half_size.z = math::is_infinite(math::abs(hs.z)) ? hs.z : z;
-
- return result;
-}
-} // namespace aabb
-
-namespace sphere
-{
-Sphere
-calculate_min_bounding(void const* vertices, usize num_vertices, usize stride, usize offset, f32 step)
-{
-#if !defined(GB_MATH_NO_RANDOM)
- auto gen = random::make(0);
-#endif
-
- u8 const* vertex = reinterpret_cast<u8 const*>(vertices);
- vertex += offset;
-
- Vector3 position = pseudo_cast<Vector3>(vertex[0]);
- Vector3 center = position;
- center += pseudo_cast<Vector3>(vertex[1 * stride]);
- center *= 0.5f;
-
- Vector3 d = position - center;
- f32 max_dist_sq = math::dot(d, d);
- f32 radius_step = step * 0.37f;
-
- bool done;
- do
- {
- done = true;
-#if !defined(GB_MATH_NO_RANDOM)
- for (u32 i = 0, index = random::uniform_u32(&gen, 0, num_vertices-1);
- i < num_vertices;
- i++, index = (index + 1)%num_vertices)
-#else
- for (u32 i = 0, index = num_vertices/2;
- i < num_vertices;
- i++, index = (index + 1)%num_vertices)
-#endif
- {
- Vector3 position = pseudo_cast<Vector3>(vertex[index * stride]);
-
- d = position - center;
- f32 dist_sq = math::dot(d, d);
-
- if (dist_sq > max_dist_sq)
- {
- done = false;
-
- center = d * radius_step;
- max_dist_sq = math::lerp(max_dist_sq, dist_sq, step);
-
- break;
- }
- }
- }
- while (!done);
-
- Sphere result;
-
- result.center = center;
- result.radius = math::sqrt(max_dist_sq);
-
- return result;
-}
-
-Sphere
-calculate_max_bounding(void const* vertices, usize num_vertices, usize stride, usize offset)
-{
- Aabb aabb = aabb::calculate(vertices, num_vertices, stride, offset);
-
- Vector3 center = aabb.center;
-
- f32 max_dist_sq = 0.0f;
- const u8* vertex = reinterpret_cast<const u8*>(vertices);
- vertex += offset;
-
- for (usize i = 0; i < num_vertices; i++)
- {
- Vector3 position = pseudo_cast<Vector3>(vertex);
- vertex += stride;
-
- Vector3 d = position - center;
- f32 dist_sq = math::dot(d, d);
- max_dist_sq = math::max(dist_sq, max_dist_sq);
- }
-
- Sphere sphere;
- sphere.center = center;
- sphere.radius = math::sqrt(max_dist_sq);
-
- return sphere;
-}
-
-inline f32
-surface_area(Sphere s)
-{
- return 2.0f * math::TAU * s.radius * s.radius;
-}
-
-inline f32
-volume(Sphere s)
-{
- return math::TWO_THIRDS * math::TAU * s.radius * s.radius * s.radius;
-}
-
-inline Aabb
-to_aabb(Sphere s)
-{
- Aabb a;
- a.center = s.center;
- a.half_size.x = s.radius * math::SQRT_3;
- a.half_size.y = s.radius * math::SQRT_3;
- a.half_size.z = s.radius * math::SQRT_3;
- return a;
-}
-
-inline bool
-contains_point(Sphere s, Vector3 point)
-{
- Vector3 dr = point - s.center;
- f32 distance = math::dot(dr, dr);
- return distance < s.radius * s.radius;
-}
-
-inline f32
-ray_intersection(Vector3 from, Vector3 dir, Sphere s)
-{
- Vector3 v = s.center - from;
- f32 b = math::dot(v, dir);
- f32 det = (s.radius * s.radius) - math::dot(v, v) + (b * b);
-
- if (det < 0.0 || b < s.radius)
- return -1.0f;
- return b - math::sqrt(det);
-}
-} // namespace sphere
-
-namespace plane
-{
-inline f32
-ray_intersection(Vector3 from, Vector3 dir, Plane p)
-{
- f32 nd = math::dot(dir, p.normal);
- f32 orpn = math::dot(from, p.normal);
- f32 dist = -1.0f;
-
- if (nd < 0.0f)
- dist = (-p.distance - orpn) / nd;
-
- return dist > 0.0f ? dist : -1.0f;
-}
-
-inline bool
-intersection3(Plane p1, Plane p2, Plane p3, Vector3* ip)
-{
- f32 den = -math::dot(math::cross(p1.normal, p2.normal), p3.normal);
-
- if (math::equals(den, 0.0f))
- return false;
-
- Vector3 res = p1.distance * math::cross(p2.normal, p3.normal)
- + p2.distance * math::cross(p3.normal, p1.normal)
- + p3.distance * math::cross(p1.normal, p2.normal);
- *ip = res / den;
-
- return true;
-}
-} // namespace plane
-
-#if !defined(GB_MATH_NO_RANDOM)
-namespace random
-{
-inline Random
-make(s64 seed)
-{
- Random r = {};
- set_seed(&r, seed);
- return r;
-}
-
-void
-set_seed(Random* r, s64 seed)
-{
- r->seed = seed;
- r->mt[0] = seed;
- for (u64 i = 1; i < 312; i++)
- r->mt[i] = 6364136223846793005ull * (r->mt[i-1] ^ r->mt[i-1] >> 62) + i;
-}
-
-s64
-next(Random* r)
-{
- const u64 MAG01[2] = {0ull, 0xb5026f5aa96619e9ull};
-
- u64 x;
- if (r->index > 312)
- {
- u32 i = 0;
- for (; i < 312-156; i++)
- {
- x = (r->mt[i] & 0xffffffff80000000ull) | (r->mt[i+1] & 0x7fffffffull);
- r->mt[i] = r->mt[i+156] ^ (x>>1) ^ MAG01[(u32)(x & 1ull)];
- }
- for (; i < 312-1; i++)
- {
- x = (r->mt[i] & 0xffffffff80000000ull) | (r->mt[i+1] & 0x7fffffffull);
- r->mt[i] = r->mt[i + (312-156)] ^ (x >> 1) ^ MAG01[(u32)(x & 1ull)];
- }
- x = (r->mt[312-1] & 0xffffffff80000000ull) | (r->mt[0] & 0x7fffffffull);
- r->mt[312-1] = r->mt[156-1] ^ (x>>1) ^ MAG01[(u32)(x & 1ull)];
-
- r->index = 0;
- }
-
- x = r->mt[r->index++];
-
- x ^= (x >> 29) & 0x5555555555555555ull;
- x ^= (x << 17) & 0x71d67fffeda60000ull;
- x ^= (x << 37) & 0xfff7eee000000000ull;
- x ^= (x >> 43);
-
- return x;
-}
-
-void
-next_from_device(void* buffer, u32 length_in_bytes)
-{
-#if defined(GB_SYSTEM_WINDOWS)
- HCRYPTPROV prov;
-
- bool ok = CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
- GB_ASSERT(ok, "CryptAcquireContext");
- ok = CryptGenRandom(prov, length_in_bytes, reinterpret_cast<u8*>(&buffer));
- GB_ASSERT(ok, "CryptGenRandom");
-
- CryptReleaseContext(prov, 0);
-
-#else
- #error Implement random::next_from_device()
-#endif
-}
-
-inline s32
-next_s32(Random* r)
-{
- return bit_cast<s32>(random::next(r));
-}
-
-inline u32
-next_u32(Random* r)
-{
- return bit_cast<u32>(random::next(r));
-}
-
-inline f32
-next_f32(Random* r)
-{
- return bit_cast<f32>(random::next(r));
-}
-
-inline s64
-next_s64(Random* r)
-{
- return random::next(r);
-}
-
-inline u64
-next_u64(Random* r)
-{
- return bit_cast<u64>(random::next(r));
-}
-
-inline f64
-next_f64(Random* r)
-{
- return bit_cast<f64>(random::next(r));
-}
-
-inline s32
-uniform_s32(Random* r, s32 min_inc, s32 max_inc)
-{
- return (random::next_s32(r) & (max_inc - min_inc + 1)) + min_inc;
-}
-
-inline u32
-uniform_u32(Random* r, u32 min_inc, u32 max_inc)
-{
- return (random::next_u32(r) & (max_inc - min_inc + 1)) + min_inc;
-}
-
-inline f32
-uniform_f32(Random* r, f32 min_inc, f32 max_inc)
-{
- f64 n = (random::next_s64(r) >> 11) * (1.0/4503599627370495.0);
- return static_cast<f32>(n * (max_inc - min_inc + 1.0) + min_inc);
-}
-
-inline s64
-uniform_s64(Random* r, s64 min_inc, s64 max_inc)
-{
- return (random::next_s32(r) & (max_inc - min_inc + 1)) + min_inc;
-}
-
-inline u64
-uniform_u64(Random* r, u64 min_inc, u64 max_inc)
-{
- return (random::next_u64(r) & (max_inc - min_inc + 1)) + min_inc;
-}
-
-inline f64
-uniform_f64(Random* r, f64 min_inc, f64 max_inc)
-{
- f64 n = (random::next_s64(r) >> 11) * (1.0/4503599627370495.0);
- return (n * (max_inc - min_inc + 1.0) + min_inc);
-}
-
-
-global_variable const s32 g_perlin_randtab[512] =
-{
- 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
- 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
- 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
- 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
- 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
- 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
- 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
- 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
- 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
- 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
- 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
- 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
- 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
- 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
- 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
- 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
-
-// Copy
- 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
- 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
- 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
- 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
- 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
- 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
- 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
- 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
- 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
- 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
- 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
- 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
- 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
- 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
- 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
- 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
-};
-
-
-internal_linkage f32
-perlin_grad(s32 hash, f32 x, f32 y, f32 z)
-{
- local_persist const f32 basis[12][4] =
- {
- { 1, 1, 0},
- {-1, 1, 0},
- { 1,-1, 0},
- {-1,-1, 0},
- { 1, 0, 1},
- {-1, 0, 1},
- { 1, 0,-1},
- {-1, 0,-1},
- { 0, 1, 1},
- { 0,-1, 1},
- { 0, 1,-1},
- { 0,-1,-1},
- };
-
- local_persist const u8 indices[64] =
- {
- 0,1,2,3,4,5,6,7,8,9,10,11,
- 0,9,1,11,
- 0,1,2,3,4,5,6,7,8,9,10,11,
- 0,1,2,3,4,5,6,7,8,9,10,11,
- 0,1,2,3,4,5,6,7,8,9,10,11,
- 0,1,2,3,4,5,6,7,8,9,10,11,
- };
-
- const f32* grad = basis[indices[hash & 63]];
- return grad[0]*x + grad[1]*y + grad[2]*z;
-}
-
-
-inline f32
-perlin_3d(f32 x, f32 y, f32 z, s32 x_wrap, s32 y_wrap, s32 z_wrap)
-{
- u32 x_mask = (x_wrap-1) & 255;
- u32 y_mask = (y_wrap-1) & 255;
- u32 z_mask = (z_wrap-1) & 255;
-
- s32 px = static_cast<s32>(math::floor(x));
- s32 py = static_cast<s32>(math::floor(y));
- s32 pz = static_cast<s32>(math::floor(z));
-
- s32 x0 = (px) & x_mask;
- s32 x1 = (px+1) & x_mask;
- s32 y0 = (py) & y_mask;
- s32 y1 = (py+1) & y_mask;
- s32 z0 = (pz) & z_mask;
- s32 z1 = (pz+1) & z_mask;
-
- x -= px;
- y -= py;
- z -= pz;
-
-#define GB__PERLIN_EASE(t) (((6*t - 15)*t + 10)*t*t*t)
- f32 u = GB__PERLIN_EASE(x);
- f32 v = GB__PERLIN_EASE(y);
- f32 w = GB__PERLIN_EASE(z);
-#undef GB__PERLIN_EASE
-
- s32 r0 = g_perlin_randtab[x0];
- s32 r1 = g_perlin_randtab[x1];
-
- s32 r00 = g_perlin_randtab[r0 + y0];
- s32 r01 = g_perlin_randtab[r0 + y1];
- s32 r10 = g_perlin_randtab[r1 + y0];
- s32 r11 = g_perlin_randtab[r1 + y1];
-
- f32 n000 = perlin_grad(g_perlin_randtab[r00 + z0], x, y, z );
- f32 n001 = perlin_grad(g_perlin_randtab[r00 + z1], x, y, z - 1);
- f32 n010 = perlin_grad(g_perlin_randtab[r01 + z0], x, y - 1, z );
- f32 n011 = perlin_grad(g_perlin_randtab[r01 + z1], x, y - 1, z - 1);
- f32 n100 = perlin_grad(g_perlin_randtab[r10 + z0], x - 1, y, z );
- f32 n101 = perlin_grad(g_perlin_randtab[r10 + z1], x - 1, y, z - 1);
- f32 n110 = perlin_grad(g_perlin_randtab[r11 + z0], x - 1, y - 1, z );
- f32 n111 = perlin_grad(g_perlin_randtab[r11 + z1], x - 1, y - 1, z - 1);
-
- f32 n00 = math::lerp(n000, n001, w);
- f32 n01 = math::lerp(n010, n011, w);
- f32 n10 = math::lerp(n100, n101, w);
- f32 n11 = math::lerp(n110, n111, w);
-
- f32 n0 = math::lerp(n00, n01, v);
- f32 n1 = math::lerp(n10, n11, v);
-
- return math::lerp(n0, n1, u);
-}
-
-} // namespace random
-#endif
-
-__GB_NAMESPACE_END
-
-#endif // GB_MATH_IMPLEMENTATION