2015-10-05 16:58:47 -04:00
|
|
|
// gb.hpp - v0.13a - public domain C++11 helper library - no warranty implied; use at your own risk
|
2015-09-27 14:03:47 -04:00
|
|
|
// (Experimental) A C++11 helper library without STL geared towards game development
|
2015-10-05 16:30:55 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
Version History:
|
2015-10-05 16:58:47 -04:00
|
|
|
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
|
2015-10-05 16:30:55 -04:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
Context:
|
|
|
|
- Common Macros
|
|
|
|
- Assert
|
|
|
|
- Types
|
|
|
|
- C++11 Move Semantics
|
|
|
|
- Defer
|
|
|
|
- Memory
|
|
|
|
- Mutex
|
|
|
|
- Atomics
|
|
|
|
- Functions
|
|
|
|
- Allocator
|
|
|
|
- Heap Allocator
|
|
|
|
- Arena Allocator
|
|
|
|
- Temporary Arena Memory
|
|
|
|
- String
|
|
|
|
- Array
|
|
|
|
- Hash Table
|
|
|
|
- Hash Functions
|
|
|
|
- Math
|
|
|
|
- Types
|
|
|
|
- Vector(2,3,4)
|
|
|
|
- Complex
|
|
|
|
- Quaternion
|
|
|
|
- Matrix(2,3,4)
|
|
|
|
- Euler_Angles
|
|
|
|
- Transform
|
|
|
|
- Aabb
|
|
|
|
- Sphere
|
|
|
|
- Plane
|
|
|
|
- Operations
|
|
|
|
- Functions & Constants
|
|
|
|
- Type Functions
|
|
|
|
- Random
|
|
|
|
- Generator_Type
|
|
|
|
- Geneartor Definition (Template/Concept)
|
|
|
|
- Mt19937_32
|
|
|
|
- Mt19937_64
|
2015-10-05 16:58:47 -04:00
|
|
|
- Random_Device
|
2015-10-05 16:30:55 -04:00
|
|
|
- Functions
|
|
|
|
*/
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
#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(!)
|
|
|
|
#define global static
|
|
|
|
#define internal static
|
|
|
|
#define local_persist static
|
|
|
|
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#define _ALLOW_KEYWORD_MACROS
|
|
|
|
|
|
|
|
#if !defined(alignof) // Needed for MSVC 2013
|
|
|
|
#define alignof(x) __alignof(x)
|
|
|
|
#endif
|
2015-10-05 16:30:55 -04:00
|
|
|
#define alignment_of(x) alignof(x)
|
2015-09-27 14:03:47 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// System OS ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_SYSTEM_WINDOWS 1
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
#elif defined(__APPLE__) && defined(__MACH__)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_SYSTEM_OSX 1
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
#elif defined(__unix__)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_SYSTEM_UNIX 1
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
#if defined(__linux__)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_SYSTEM_LINUX 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_SYSTEM_FREEBSD 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#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
|
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Environment Bit Size ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2015-10-04 15:59:40 -04:00
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
#if defined(_WIN64)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_ARCH_64_BIT 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#else
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_ARCH_32_BIT 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang
|
|
|
|
#if defined(__GNUC__)
|
2015-10-04 15:59:40 -04:00
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
#if defined(__x86_64__) || defined(__ppc64__)
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_ARCH_64_BIT 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#else
|
2015-10-04 15:59:40 -04:00
|
|
|
#define GB_ARCH_32_BIT 1
|
2015-09-27 14:03:47 -04:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1))
|
|
|
|
|
2015-09-29 10:11:18 -04:00
|
|
|
#include <float.h>
|
|
|
|
#include <math.h>
|
2015-09-28 18:57:43 -04:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stddef.h>
|
2015-09-27 14:03:47 -04:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2015-09-29 10:11:18 -04:00
|
|
|
#include <time.h>
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
#if !defined(GB_HAS_NO_CONSTEXPR)
|
|
|
|
#if defined(_GNUC_VER) && _GNUC_VER < 406 // Less than gcc 4.06
|
|
|
|
#define GB_HAS_NO_CONSTEXPR
|
|
|
|
#elif defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015/MSVC++ 14.0
|
|
|
|
#define GB_HAS_NO_CONSTEXPR
|
|
|
|
#elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
|
|
|
|
#define GB_HAS_NO_CONSTEXPR
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(GB_HAS_NO_CONSTEXPR)
|
|
|
|
#define GB_CONSTEXPR
|
|
|
|
#else
|
|
|
|
#define GB_CONSTEXPR constexpr
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef GB_FORCE_INLINE
|
2015-10-05 13:17:30 -04:00
|
|
|
#if defined(_MSC_VER)
|
2015-10-05 16:30:55 -04:00
|
|
|
#define GB_FORCE_INLINE __forceinline
|
2015-10-05 13:17:30 -04:00
|
|
|
#else
|
2015-10-05 16:30:55 -04:00
|
|
|
#define __attribute__ ((__always_inline__))
|
2015-10-05 13:17:30 -04:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
|
|
|
|
|
|
|
#define NOMINMAX 1
|
|
|
|
#define VC_EXTRALEAN 1
|
|
|
|
#define WIN32_EXTRA_LEAN 1
|
|
|
|
#define WIN32_LEAN_AND_MEAN 1
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
#include <windows.h>
|
2015-10-04 15:59:40 -04:00
|
|
|
#include <mmsystem.h> // Time functions
|
2015-10-05 16:30:55 -04:00
|
|
|
// #include <ntsecapi.h> // Random generation functions
|
2015-10-04 15:59:40 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
#undef NOMINMAX
|
|
|
|
#undef VC_EXTRALEAN
|
|
|
|
#undef WIN32_EXTRA_LEAN
|
2015-10-04 15:59:40 -04:00
|
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
#include <intrin.h>
|
2015-09-27 14:03:47 -04:00
|
|
|
#else
|
2015-10-04 15:59:40 -04:00
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
#include <pthread.h>
|
2015-10-02 08:11:18 -04:00
|
|
|
#include <sys/time.h>
|
2015-09-27 14:03:47 -04:00
|
|
|
#endif
|
|
|
|
|
2015-09-28 16:58:33 -04:00
|
|
|
#ifndef NDEBUG
|
2015-09-28 17:42:15 -04:00
|
|
|
#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
|
2015-09-28 16:58:33 -04:00
|
|
|
#else
|
|
|
|
#define GB_ASSERT(x, ...) ((void)sizeof(x))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern "C" inline void
|
|
|
|
gb__assert_handler(bool condition, const char* condition_str,
|
2015-10-05 16:30:55 -04:00
|
|
|
const char* filename, size_t line,
|
|
|
|
const char* error_text = nullptr, ...)
|
2015-09-28 16:58:33 -04:00
|
|
|
{
|
|
|
|
if (condition)
|
|
|
|
return;
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str);
|
2015-09-28 16:58:33 -04:00
|
|
|
if (error_text)
|
|
|
|
{
|
|
|
|
fprintf(stderr, " - ");
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, error_text);
|
|
|
|
vfprintf(stderr, error_text, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
abort(); // TODO(bill): is abort() portable and good?
|
2015-09-28 16:58:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
|
2015-09-27 14:03:47 -04:00
|
|
|
namespace gb
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
#endif // GB_BASIC_WITHOUT_NAMESPACE
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Types ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
using u8 = uint8_t;
|
|
|
|
using s8 = int8_t;
|
2015-09-27 14:03:47 -04:00
|
|
|
using u16 = uint16_t;
|
2015-10-04 15:59:40 -04:00
|
|
|
using s16 = int16_t;
|
2015-09-27 14:03:47 -04:00
|
|
|
using u32 = uint32_t;
|
2015-10-04 15:59:40 -04:00
|
|
|
using s32 = int32_t;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
#if defined(_MSC_VER)
|
2015-10-04 15:59:40 -04:00
|
|
|
using s64 = signed __int64;
|
2015-09-27 14:03:47 -04:00
|
|
|
using u64 = unsigned __int64;
|
|
|
|
#else
|
2015-10-04 15:59:40 -04:00
|
|
|
using s64 = int64_t;
|
2015-09-27 14:03:47 -04:00
|
|
|
using u64 = uint64_t;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using f32 = float;
|
|
|
|
using f64 = double;
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_B8_AS_BOOL)
|
2015-09-27 14:03:47 -04:00
|
|
|
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:
|
2015-09-27 15:43:22 -04:00
|
|
|
// sizeof(size_t) == sizeof(usize) == sizeof(s64)
|
2015-09-27 14:03:47 -04:00
|
|
|
// 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)
|
2015-09-27 15:43:22 -04:00
|
|
|
using usize = s32;
|
2015-09-27 14:03:47 -04:00
|
|
|
using usize = u32;
|
|
|
|
#else
|
|
|
|
#error Unknown architecture bit size
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static_assert(sizeof(usize) == sizeof(size_t),
|
2015-10-05 16:30:55 -04:00
|
|
|
"`usize` is not the same size as `size_t`");
|
2015-09-27 14:03:47 -04:00
|
|
|
static_assert(sizeof(ssize) == sizeof(usize),
|
2015-10-05 16:30:55 -04:00
|
|
|
"`ssize` is not the same size as `usize`");
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
using intptr = intptr_t;
|
|
|
|
using uintptr = uintptr_t;
|
|
|
|
|
|
|
|
using ptrdiff = ptrdiff_t;
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
#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)
|
|
|
|
|
|
|
|
#if defined(GB_ARCH_64_BIT)
|
|
|
|
#define GB_USIZE_MIX U64_MIN
|
|
|
|
#define GB_USIZE_MAX U64_MAX
|
|
|
|
|
|
|
|
#define GB_SSIZE_MIX S64_MIN
|
|
|
|
#define GB_SSIZE_MAX S64_MAX
|
|
|
|
|
|
|
|
#elif defined(GB_ARCH_32_BIT)
|
|
|
|
#define GB_USIZE_MIX U32_MIN
|
|
|
|
#define GB_USIZE_MAX U32_MAX
|
|
|
|
|
|
|
|
#define GB_SSIZE_MIX S32_MIN
|
|
|
|
#define GB_SSIZE_MAX S32_MAX
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
#if defined(GB_BASIC_WITHOUT_NAMESPACE)
|
2015-10-03 10:26:29 -04:00
|
|
|
#define U8_MIN 0u
|
|
|
|
#define U8_MAX 0xffu
|
2015-10-04 15:59:40 -04:00
|
|
|
#define S8_MIN (-0x7f - 1)
|
|
|
|
#define S8_MAX 0x7f
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
#define U16_MIN 0u
|
|
|
|
#define U16_MAX 0xffffu
|
2015-10-04 15:59:40 -04:00
|
|
|
#define S16_MIN (-0x7fff - 1)
|
|
|
|
#define S16_MAX 0x7fff
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
#define U32_MIN 0u
|
|
|
|
#define U32_MAX 0xffffffffu
|
2015-10-04 15:59:40 -04:00
|
|
|
#define S32_MIN (-0x7fffffff - 1)
|
|
|
|
#define S32_MAX 0x7fffffff
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
#define U64_MIN 0ull
|
|
|
|
#define U64_MAX 0xffffffffffffffffull
|
2015-10-04 15:59:40 -04:00
|
|
|
#define S64_MIN (-0x7fffffffffffffffll - 1)
|
|
|
|
#define S64_MAX 0x7fffffffffffffffll
|
|
|
|
|
|
|
|
#if defined(GB_ARCH_64_BIT)
|
|
|
|
#define USIZE_MIX U64_MIN
|
|
|
|
#define USIZE_MAX U64_MAX
|
|
|
|
|
|
|
|
#define SSIZE_MIX S64_MIN
|
|
|
|
#define SSIZE_MAX S64_MAX
|
2015-10-03 10:26:29 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
#elif defined(GB_ARCH_32_BIT)
|
|
|
|
#define USIZE_MIX U32_MIN
|
|
|
|
#define USIZE_MAX U32_MAX
|
|
|
|
|
|
|
|
#define SSIZE_MIX S32_MIN
|
|
|
|
#define SSIZE_MAX S32_MAX
|
|
|
|
|
|
|
|
#endif
|
2015-10-03 10:26:29 -04:00
|
|
|
#endif
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
|
2015-09-30 17:12:16 -04:00
|
|
|
} // namespace gb
|
2015-10-05 16:30:55 -04:00
|
|
|
#endif // GB_BASIC_WITHOUT_NAMESPACE
|
2015-09-30 17:12:16 -04:00
|
|
|
|
|
|
|
namespace gb
|
|
|
|
{
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-10-05 16:30:55 -04:00
|
|
|
/// C++11 Types Traits ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T, T t>
|
|
|
|
struct Integral_Constant
|
|
|
|
{
|
|
|
|
global GB_CONSTEXPR const T VALUE = t;
|
|
|
|
using Value_Type = T;
|
|
|
|
using Type = Integral_Constant;
|
|
|
|
|
|
|
|
GB_FORCE_INLINE
|
|
|
|
GB_CONSTEXPR operator Value_Type() const { return VALUE; }
|
|
|
|
GB_CONSTEXPR Value_Type operator()() const { return VALUE; }
|
|
|
|
};
|
|
|
|
|
|
|
|
using True_Type = Integral_Constant<bool, true>;
|
|
|
|
using False_Type = Integral_Constant<bool, true>;
|
|
|
|
|
|
|
|
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<const void> { using Type = const void; };
|
|
|
|
template <> struct Add_Lvalue_Reference_Def<volatile void> { using Type = volatile void; };
|
|
|
|
template <> struct Add_Lvalue_Reference_Def<const volatile void> { using Type = const volatile void; };
|
|
|
|
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<const void> { using Type = const void; };
|
|
|
|
template <> struct Add_Rvalue_Reference_Def<volatile void> { using Type = volatile void; };
|
|
|
|
template <> struct Add_Rvalue_Reference_Def<const volatile void> { using Type = const volatile void; };
|
|
|
|
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> struct Is_Integral_Def : False_Type {};
|
|
|
|
template <> struct Is_Integral_Def<bool> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<char> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<wchar_t> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<s8> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<u8> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<s16> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<u16> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<s32> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<u32> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<s64> : True_Type {};
|
|
|
|
template <> struct Is_Integral_Def<u64> : True_Type {};
|
|
|
|
template <typename T> struct Is_Integral : Is_Integral_Def<Remove_Const_Volatile<T>> {};
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////
|
|
|
|
/// ///
|
|
|
|
/// C++11 Move Semantics ///
|
|
|
|
/// ///
|
|
|
|
////////////////////////////////
|
2015-09-27 14:03:47 -04:00
|
|
|
template <typename T>
|
|
|
|
inline T&&
|
2015-10-05 16:30:55 -04:00
|
|
|
forward(Remove_Reference<T>& t)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
return static_cast<T&&>(t);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline T&&
|
2015-10-05 16:30:55 -04:00
|
|
|
forward(Remove_Reference<T>&& t)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
return static_cast<T&&>(t);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Remove_Reference<T>&&
|
2015-09-27 14:03:47 -04:00
|
|
|
move(T&& t)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return static_cast<Remove_Reference<T>&&>(t);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Defer ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
namespace impl
|
|
|
|
{
|
2015-09-30 17:12:16 -04:00
|
|
|
template <typename Func>
|
2015-09-27 14:03:47 -04:00
|
|
|
struct Defer
|
|
|
|
{
|
2015-09-30 17:12:16 -04:00
|
|
|
Func func;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
Defer(Func&& func) : func{gb::forward<Func>(func)} {}
|
|
|
|
~Defer() { func(); };
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
template <typename Func>
|
|
|
|
Defer<Func>
|
|
|
|
defer_func(Func&& func) { return Defer<Func>(gb::forward<Func>(func)); }
|
2015-09-27 14:03:47 -04:00
|
|
|
} // namespace impl
|
|
|
|
} // namespace gb
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// NOTE(bill): These macros are in the global namespace thus, defer can be treated without a gb:: prefix
|
2015-09-27 14:03:47 -04:00
|
|
|
#define GB_DEFER_1(x, y) x##y
|
|
|
|
#define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
|
2015-09-28 18:57:43 -04:00
|
|
|
#define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__)
|
2015-09-30 17:12:16 -04:00
|
|
|
#define defer(code) auto GB_DEFER_3(_defer_) = gb::impl::defer_func([&](){code;})
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
|
|
|
|
#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
|
|
|
|
namespace gb
|
|
|
|
{
|
|
|
|
#endif // GB_CASTS_WITHOUT_NAMESPACE
|
|
|
|
|
|
|
|
// NOTE(bill): Very similar to doing
|
|
|
|
// *(T*)(&u)
|
2015-10-05 16:58:47 -04:00
|
|
|
// But easier to write
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T, typename U>
|
|
|
|
inline T
|
|
|
|
pseudo_cast(const U& u)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<const T&>(u);
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:58:47 -04:00
|
|
|
// NOTE(bill): There used to be a magic_cast that was equivalent to
|
|
|
|
// a C-style cast but I removed it I could not get it work as intented
|
|
|
|
// for everything
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
|
|
|
|
} // namespace gb
|
|
|
|
#endif // GB_CASTS_WITHOUT_NAMESPACE
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
namespace gb
|
|
|
|
{
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Memory ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Mutex
|
2015-09-27 14:03:47 -04:00
|
|
|
struct Mutex
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
HANDLE win32_mutex;
|
|
|
|
#else
|
|
|
|
pthread_mutex_t posix_mutex;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Mutex();
|
|
|
|
~Mutex();
|
|
|
|
};
|
|
|
|
|
|
|
|
void lock_mutex(Mutex& mutex);
|
|
|
|
bool try_lock_mutex(Mutex& mutex);
|
|
|
|
void unlock_mutex(Mutex& mutex);
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Atomics
|
|
|
|
struct Atomic32 { u32 nonatomic; };
|
|
|
|
struct Atomic64 { u64 nonatomic; };
|
|
|
|
struct Atomic_Ptr { void* nonatomic; };
|
|
|
|
|
|
|
|
namespace atomic
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
u32 load_32_relaxed(const Atomic32* object);
|
|
|
|
void store_32_relaxed(Atomic32* object, u32 value);
|
|
|
|
u32 compare_exchange_strong_32_relaxed(Atomic32* object, u32 expected, u32 desired);
|
|
|
|
u32 exchanged_32_relaxed(Atomic32* object, u32 desired);
|
|
|
|
u32 fetch_add_32_relaxed(Atomic32* object, s32 operand);
|
|
|
|
u32 fetch_and_32_relaxed(Atomic32* object, u32 operand);
|
|
|
|
u32 fetch_or_32_relaxed(Atomic32* object, u32 operand);
|
|
|
|
|
|
|
|
u64 load_64_relaxed(const Atomic64* object);
|
|
|
|
void store_64_relaxed(Atomic64* object, u64 value);
|
|
|
|
u64 compare_exchange_strong_64_relaxed(Atomic64* object, u64 expected, u64 desired);
|
|
|
|
u64 exchanged_64_relaxed(Atomic64* object, u64 desired);
|
|
|
|
u64 fetch_add_64_relaxed(Atomic64* object, s64 operand);
|
|
|
|
u64 fetch_and_64_relaxed(Atomic64* object, u64 operand);
|
|
|
|
u64 fetch_or_64_relaxed(Atomic64* object, u64 operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
} // namespace atomic
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
#ifndef GB_DEFAULT_ALIGNMENT
|
2015-09-27 14:03:47 -04:00
|
|
|
#define GB_DEFAULT_ALIGNMENT 4
|
2015-09-28 15:31:26 -04:00
|
|
|
#endif
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
namespace memory
|
|
|
|
{
|
2015-09-27 14:03:47 -04:00
|
|
|
inline void*
|
|
|
|
align_forward(void* ptr, usize align)
|
|
|
|
{
|
|
|
|
GB_ASSERT(GB_IS_POWER_OF_TWO(align));
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
uintptr p = reinterpret_cast<uintptr>(ptr);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
const usize modulo = p % align;
|
|
|
|
if (modulo)
|
|
|
|
p += (uintptr)(align - modulo);
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
return reinterpret_cast<void*>(p);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
2015-10-03 10:26:29 -04:00
|
|
|
} // namespace memory
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
struct Allocator
|
|
|
|
{
|
|
|
|
Allocator() {}
|
|
|
|
virtual ~Allocator() {}
|
|
|
|
|
|
|
|
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT) = 0;
|
2015-10-04 15:59:40 -04:00
|
|
|
virtual void dealloc(const void* ptr) = 0;
|
2015-09-27 15:43:22 -04:00
|
|
|
virtual s64 allocated_size(const void* ptr) = 0;
|
|
|
|
virtual s64 total_allocated() = 0;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
// Delete copying
|
|
|
|
Allocator(const Allocator&) = delete;
|
|
|
|
Allocator& operator=(const Allocator&) = delete;
|
|
|
|
};
|
|
|
|
|
2015-09-28 18:57:43 -04:00
|
|
|
inline void* alloc(Allocator& a, usize size, usize align = GB_DEFAULT_ALIGNMENT) { return a.alloc(size, align); }
|
2015-10-04 15:59:40 -04:00
|
|
|
inline void dealloc(Allocator& a, const void* ptr) { return a.dealloc(ptr); }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
template <typename T>
|
2015-10-02 08:11:18 -04:00
|
|
|
inline T* alloc_struct(Allocator& a) { return static_cast<T*>(a.alloc(sizeof(T), alignof(T))); }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
template <typename T>
|
2015-09-28 18:57:43 -04:00
|
|
|
inline T* alloc_array(Allocator& a, usize count) { return static_cast<T*>(alloc(a, count * sizeof(T), alignof(T))); }
|
|
|
|
|
|
|
|
template <typename T, usize count>
|
|
|
|
inline T* alloc_array(Allocator& a) { return static_cast<T*>(alloc(a, count * sizeof(T), alignof(T))); }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
#define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1)
|
|
|
|
|
|
|
|
struct Heap_Allocator : Allocator
|
|
|
|
{
|
|
|
|
struct Header
|
|
|
|
{
|
2015-09-27 15:43:22 -04:00
|
|
|
s64 size;
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Mutex mutex = Mutex{};
|
|
|
|
s64 total_allocated_count = 0;
|
|
|
|
s64 allocation_count = 0;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
Heap_Allocator() = default;
|
2015-09-27 14:03:47 -04:00
|
|
|
virtual ~Heap_Allocator();
|
|
|
|
|
|
|
|
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
|
2015-10-04 15:59:40 -04:00
|
|
|
virtual void dealloc(const void* ptr);
|
2015-09-27 15:43:22 -04:00
|
|
|
virtual s64 allocated_size(const void* ptr);
|
|
|
|
virtual s64 total_allocated();
|
|
|
|
|
|
|
|
Header* get_header_ptr(const void* ptr);
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Arena_Allocator : Allocator
|
|
|
|
{
|
2015-10-03 10:26:29 -04:00
|
|
|
Allocator* backing;
|
|
|
|
void* physical_start;
|
|
|
|
s64 total_size;
|
|
|
|
s64 total_allocated_count;
|
|
|
|
s64 temp_count;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
explicit Arena_Allocator(Allocator& backing, usize size);
|
|
|
|
explicit Arena_Allocator(void* start, usize size);
|
|
|
|
virtual ~Arena_Allocator();
|
2015-09-29 10:11:18 -04:00
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
|
2015-10-04 15:59:40 -04:00
|
|
|
virtual void dealloc(const void* ptr);
|
2015-09-27 15:43:22 -04:00
|
|
|
virtual s64 allocated_size(const void* ptr);
|
|
|
|
virtual s64 total_allocated();
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline void
|
|
|
|
clear_arena(Arena_Allocator& arena)
|
|
|
|
{
|
|
|
|
GB_ASSERT(arena.temp_count == 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
"%ld Temporary_Arena_Memory have not be cleared", arena.temp_count);
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
arena.total_allocated_count = 0;
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
struct Temporary_Arena_Memory
|
|
|
|
{
|
|
|
|
Arena_Allocator* arena;
|
2015-09-27 15:43:22 -04:00
|
|
|
s64 original_count;
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
inline Temporary_Arena_Memory
|
|
|
|
make_temporary_arena_memory(Arena_Allocator& arena)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
Temporary_Arena_Memory tmp = {};
|
|
|
|
tmp.arena = &arena;
|
|
|
|
tmp.original_count = arena.total_allocated_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
free_temporary_arena_memory(Temporary_Arena_Memory& tmp)
|
|
|
|
{
|
|
|
|
if (tmp.arena == nullptr)
|
|
|
|
return;
|
|
|
|
GB_ASSERT(tmp.arena->total_allocated() >= tmp.original_count);
|
|
|
|
tmp.arena->total_allocated_count = tmp.original_count;
|
|
|
|
GB_ASSERT(tmp.arena->temp_count > 0);
|
|
|
|
tmp.arena->temp_count--;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
/// String ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-10-04 15:59:40 -04:00
|
|
|
/// C compatible string ///
|
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
|
|
|
using String = char*;
|
|
|
|
using String_Size = u32;
|
|
|
|
struct String_Header
|
|
|
|
{
|
|
|
|
Allocator* allocator;
|
|
|
|
String_Size len;
|
|
|
|
String_Size cap;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline String_Header* string_header(String str) { return (String_Header*)str - 1; }
|
|
|
|
|
|
|
|
String make_string(Allocator& a, const char* str = "");
|
|
|
|
String make_string(Allocator& a, const void* str, String_Size len);
|
|
|
|
void free_string(String& str);
|
|
|
|
|
|
|
|
String duplicate_string(Allocator& a, const String str);
|
|
|
|
|
|
|
|
String_Size string_length(const String str);
|
|
|
|
String_Size string_capacity(const String str);
|
|
|
|
String_Size string_available_space(const String str);
|
|
|
|
|
|
|
|
void clear_string(String str);
|
|
|
|
|
|
|
|
void append_string(String& str, const String other);
|
|
|
|
void append_cstring(String& str, const char* other);
|
|
|
|
void append_string(String& str, const void* other, String_Size len);
|
|
|
|
|
|
|
|
void string_make_space_for(String& str, String_Size add_len);
|
|
|
|
usize string_allocation_size(const String str);
|
|
|
|
|
|
|
|
bool strings_are_equal(const String lhs, const String rhs);
|
|
|
|
|
|
|
|
void trim_string(String& str, const char* cut_set);
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// TODO(bill): string libraries
|
2015-09-28 16:58:33 -04:00
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Array ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct Array
|
|
|
|
{
|
|
|
|
Allocator* allocator;
|
2015-09-27 15:43:22 -04:00
|
|
|
s64 count;
|
|
|
|
s64 allocation;
|
|
|
|
T* data;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Array() = default;
|
|
|
|
explicit Array(Allocator& a, usize count = 0);
|
2015-09-27 14:03:47 -04:00
|
|
|
virtual ~Array() { if (allocator) dealloc(*allocator, data); }
|
|
|
|
|
|
|
|
const T& operator[](usize index) const { return data[index]; }
|
2015-10-05 16:30:55 -04:00
|
|
|
T& operator[](usize index) { return data[index]; }
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T> Array<T> make_array(Allocator& allocator, usize count = 0);
|
|
|
|
template <typename T> void free_array(Array<T>& array);
|
|
|
|
|
|
|
|
template <typename T> void append_array(Array<T>& a, const T& item);
|
|
|
|
template <typename T> void append_array(Array<T>& a, const T* items, usize count);
|
|
|
|
|
|
|
|
template <typename T> void pop_back_array(Array<T>& a);
|
|
|
|
|
|
|
|
template <typename T> inline T* begin(Array<T>& a) { return a.data; }
|
|
|
|
template <typename T> inline const T* begin(const Array<T>& a) { return a.data; }
|
|
|
|
|
|
|
|
template <typename T> inline T* end(Array<T>& a) { return a.data + a.count; }
|
|
|
|
template <typename T> inline const T* end(const Array<T>& a) { return a.data + a.count; }
|
|
|
|
|
|
|
|
template <typename T> void clear_array(Array<T>& a);
|
|
|
|
template <typename T> void resize_array(Array<T>& a, usize count);
|
|
|
|
template <typename T> void reserve_array(Array<T>& a, usize allocation);
|
|
|
|
template <typename T> void set_array_allocation(Array<T>& a, usize allocation);
|
|
|
|
template <typename T> void grow_array(Array<T>& a, usize min_allocation = 0);
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 15:43:22 -04:00
|
|
|
/// Hash Table ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 15:43:22 -04:00
|
|
|
////////////////////////////////
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
template <typename T>
|
2015-09-27 15:43:22 -04:00
|
|
|
struct Hash_Table
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-27 15:43:22 -04:00
|
|
|
struct Entry
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-27 15:43:22 -04:00
|
|
|
u64 key;
|
|
|
|
s64 next;
|
|
|
|
T value;
|
|
|
|
};
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Array<s64> hashes;
|
|
|
|
Array<Entry> data;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Hash_Table() = default;
|
|
|
|
explicit Hash_Table(Allocator& a);
|
|
|
|
~Hash_Table() = default;
|
|
|
|
};
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
template <typename T>
|
2015-09-27 15:43:22 -04:00
|
|
|
Hash_Table<T>::Hash_Table(Allocator& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-27 15:43:22 -04:00
|
|
|
hashes = make_array<s64>(a);
|
|
|
|
data = make_array<typename Hash_Table<T>::Entry>(a);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2015-09-27 15:43:22 -04:00
|
|
|
inline Hash_Table<T>
|
|
|
|
make_hash_table(Allocator& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-27 15:43:22 -04:00
|
|
|
Hash_Table<T> h = {};
|
|
|
|
h.hashes = make_array<s64>(a);
|
|
|
|
h.data = make_array<typename Hash_Table<T>::Entry>(a);
|
|
|
|
return h;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
template <typename T> bool hash_table_has(const Hash_Table<T>& h, u64 key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
template <typename T> const T& hash_table_get(const Hash_Table<T>& h, u64 key, const T& default_value);
|
|
|
|
template <typename T> void hash_table_set(Hash_Table<T>& h, u64 key, const T& value);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
template <typename T> void remove_from_hash_table(Hash_Table<T>& h, u64 key);
|
|
|
|
template <typename T> void reserve_hash_table(Hash_Table<T>& h, usize capacity);
|
|
|
|
template <typename T> void clear_hash_table(Hash_Table<T>& h);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
// Iterators (in random order)
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T> typename const Hash_Table<T>::Entry* begin(const Hash_Table<T>& h);
|
|
|
|
template <typename T> typename const Hash_Table<T>::Entry* end(const Hash_Table<T>& h);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
// Mutli_Hash_Table
|
|
|
|
template <typename T> void get_multiple_from_hash_table(const Hash_Table<T>& h, u64 key, Array<T>& items);
|
|
|
|
template <typename T> usize multiple_count_from_hash_table(const Hash_Table<T>& h, u64 key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T> typename const Hash_Table<T>::Entry* find_first_in_hash_table(const Hash_Table<T>& h, u64 key);
|
|
|
|
template <typename T> typename const Hash_Table<T>::Entry* find_next_in_hash_table(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
template <typename T> void insert_into_hash_table(Hash_Table<T>& h, u64 key, const T& value);
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T> void remove_entry_from_hash_table(Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e);
|
2015-09-27 15:43:22 -04:00
|
|
|
template <typename T> void remove_all_from_hash_table(Hash_Table<T>& h, u64 key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Array ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline Array<T>::Array(Allocator& a, usize count_)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
allocator = &a;
|
|
|
|
count = 0;
|
|
|
|
allocation = 0;
|
|
|
|
data = nullptr;
|
|
|
|
if (count > 0)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
data = alloc_array<T>(a, count_);
|
|
|
|
if (data)
|
|
|
|
count = allocation = count_;
|
|
|
|
}
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline Array<T>
|
|
|
|
make_array(Allocator& allocator, usize count)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
Array<T> array = {};
|
|
|
|
array.allocator = &allocator;
|
|
|
|
array.count = 0;
|
|
|
|
array.allocation = 0;
|
|
|
|
array.data = nullptr;
|
|
|
|
if (count > 0)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
array.data = alloc_array<T>(allocator, count);
|
|
|
|
if (array.data)
|
|
|
|
array.count = array.allocation = count;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return array;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
dealloc_array(Array<T>& array)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
if (array.allocator)
|
|
|
|
dealloc(*array.allocator, array.data);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
append_array(Array<T>& a, const T& item)
|
|
|
|
{
|
|
|
|
if (a.allocation < a.count + 1)
|
|
|
|
grow_array(a);
|
|
|
|
a.data[a.count++] = item;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
append_array(Array<T>& a, const T* items, usize count)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
if (a.allocation <= a.count + count)
|
|
|
|
grow_array(a, a.count + count);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
memcpy(&a.data[a.count], items, count * sizeof(T));
|
|
|
|
a.count += count;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
pop_back_array(Array<T>& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
GB_ASSERT(a.count > 0);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
a.count--;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
clear_array(Array<T>& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
resize_array(a, 0);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
resize_array(Array<T>& a, usize count)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
if (a.allocation < static_cast<s64>(count))
|
2015-09-28 15:31:26 -04:00
|
|
|
grow_array(a, count);
|
|
|
|
a.count = count;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
reserve_array(Array<T>& a, usize allocation)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
if (a.allocation < static_cast<s64>(allocation))
|
2015-09-28 15:31:26 -04:00
|
|
|
set_array_allocation(a, allocation);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
set_array_allocation(Array<T>& a, usize allocation)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
if (static_cast<s64>(allocation) == a.allocation)
|
2015-09-28 15:31:26 -04:00
|
|
|
return;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
if (static_cast<s64>(allocation) < a.count)
|
2015-09-28 15:31:26 -04:00
|
|
|
resize_array(a, allocation);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
T* data = nullptr;
|
|
|
|
if (allocation > 0)
|
|
|
|
{
|
|
|
|
data = alloc_array<T>(*a.allocator, allocation);
|
|
|
|
memcpy(data, a.data, a.count * sizeof(T));
|
|
|
|
}
|
|
|
|
dealloc(*a.allocator, a.data);
|
|
|
|
a.data = data;
|
|
|
|
a.allocation = allocation;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
grow_array(Array<T>& a, usize min_allocation)
|
|
|
|
{
|
|
|
|
usize allocation = 2 * a.allocation + 2;
|
|
|
|
if (allocation < min_allocation)
|
|
|
|
allocation = min_allocation;
|
|
|
|
set_array_allocation(a, allocation);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Hash Table ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
|
|
|
namespace impl
|
|
|
|
{
|
|
|
|
struct Find_Result
|
|
|
|
{
|
|
|
|
s64 hash_index;
|
|
|
|
s64 data_prev;
|
|
|
|
s64 data_index;
|
|
|
|
};
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
usize
|
|
|
|
add_hash_table_entry(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
typename Hash_Table<T>::Entry e;
|
|
|
|
e.key = key;
|
|
|
|
e.next = -1;
|
|
|
|
usize e_index = h.data.count;
|
|
|
|
append_array(h.data, e);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return e_index;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
void
|
|
|
|
erase_from_hash_table(Hash_Table<T>& h, const Find_Result& fr)
|
|
|
|
{
|
|
|
|
if (fr.data_prev < 0)
|
|
|
|
h.hashes[fr.hash_index] = h.data[fr.data_index].next;
|
|
|
|
else
|
2015-10-02 08:11:18 -04:00
|
|
|
h.data[fr.data_prev].next = h.data[fr.data_index].next;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
pop_back_array(h.data); // updated array count
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (fr.data_index == h.data.count)
|
|
|
|
return;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
h.data[fr.data_index] = h.data[h.data.count];
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
auto last = find_result_in_hash_table(h, h.data[fr.data_index].key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (last.data_prev < 0)
|
|
|
|
h.hashes[last.hash_index] = fr.data_index;
|
|
|
|
else
|
|
|
|
h.data[last.data_index].next = fr.data_index;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
Find_Result
|
|
|
|
find_result_in_hash_table(const Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
Find_Result fr;
|
|
|
|
fr.hash_index = -1;
|
|
|
|
fr.data_prev = -1;
|
|
|
|
fr.data_index = -1;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (h.hashes.count == 0)
|
|
|
|
return fr;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
fr.hash_index = key % h.hashes.count;
|
|
|
|
fr.data_index = h.hashes[fr.hash_index];
|
|
|
|
while (fr.data_index >= 0)
|
|
|
|
{
|
|
|
|
if (h.data[fr.data_index].key == key)
|
|
|
|
return fr;
|
|
|
|
fr.data_prev = fr.data_index;
|
|
|
|
fr.data_index = h.data[fr.data_index].next;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return fr;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
Find_Result
|
2015-10-05 16:30:55 -04:00
|
|
|
find_result_in_hash_table(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e)
|
2015-09-28 15:31:26 -04:00
|
|
|
{
|
|
|
|
Find_Result fr;
|
2015-10-05 16:58:47 -04:00
|
|
|
fr.hash_index = -1;
|
|
|
|
fr.data_prev = -1;
|
|
|
|
fr.data_index = -1;
|
|
|
|
|
|
|
|
if (h.hashes.count == 0 || !e)
|
|
|
|
return fr;
|
|
|
|
|
|
|
|
fr.hash_index = key % h.hashes.count;
|
|
|
|
fr.data_index = h.hashes[fr.hash_index];
|
|
|
|
while (fr.data_index >= 0)
|
|
|
|
{
|
|
|
|
if (&h.data[fr.data_index] == e)
|
|
|
|
return fr;
|
|
|
|
fr.data_prev = fr.data_index;
|
|
|
|
fr.data_index = h.data[fr.data_index].next;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return fr;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
s64 make_entry_in_hash_table(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
const Find_Result fr = impl::find_result_in_hash_table(h, key);
|
|
|
|
const s64 index = impl::add_hash_table_entry(h, key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (fr.data_prev < 0)
|
|
|
|
h.hashes[fr.hash_index] = index;
|
|
|
|
else
|
|
|
|
h.data[fr.data_prev].next = index;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
h.data[index].next = fr.data_index;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return index;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
void
|
|
|
|
find_and_erase_entry_from_hash_table(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
const Find_Result fr = impl::find_result_in_hash_table(h, key);
|
|
|
|
if (fr.data_index >= 0)
|
|
|
|
erase_from_hash_table(h, fr);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
s64
|
|
|
|
find_entry_or_fail_in_hash_table(const Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
return find_result_in_hash_table(h, key).data_index;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
s64
|
|
|
|
find_or_make_entry_in_hash_table(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
const auto fr = find_result_in_hash_table(h, key);
|
|
|
|
if (fr.data_index >= 0)
|
|
|
|
return fr.data_index;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
s64 index = add_hash_table_entry(h, key);
|
|
|
|
if (fr.data_prev < 0)
|
|
|
|
h.hashes[fr.hash_index] = index;
|
|
|
|
else
|
|
|
|
h.data[fr.data_prev].next = index;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return index;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
void
|
|
|
|
rehash_hash_table(Hash_Table<T>& h, usize new_capacity)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
auto nh = make_hash_table<T>(*h.hashes.allocator);
|
|
|
|
resize_array(nh.hashes, new_capacity);
|
|
|
|
const usize old_count = h.data.count;
|
|
|
|
reserve_array(nh.data, old_count);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
for (usize i = 0; i < new_capacity; i++)
|
|
|
|
nh.hashes[i] = -1;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
for (usize i = 0; i < old_count; i++)
|
|
|
|
{
|
|
|
|
auto& e = h.data[i];
|
|
|
|
insert_into_hash_table(nh, e.key, e.value);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
auto empty = make_hash_table<T>(*h.hashes.allocator);
|
|
|
|
h.~Hash_Table<T>();
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
memcpy(&h, &nh, sizeof(Hash_Table<T>));
|
|
|
|
memcpy(&nh, &empty, sizeof(Hash_Table<T>));
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
void
|
|
|
|
grow_hash_table(Hash_Table<T>& h)
|
|
|
|
{
|
|
|
|
const usize new_capacity = 2 * h.data.count + 2;
|
|
|
|
rehash_hash_table(h, new_capacity);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
bool
|
|
|
|
is_hash_table_full(Hash_Table<T>& h)
|
|
|
|
{
|
|
|
|
// Make sure that there is enough space
|
|
|
|
const f32 maximum_load_coefficient = 0.75f;
|
|
|
|
return h.data.count >= maximum_load_coefficient * h.hashes.count;
|
|
|
|
}
|
|
|
|
} // namespace impl
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline bool
|
|
|
|
hash_table_has(const Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
return impl::find_entry_or_fail_in_hash_table(h, key) >= 0;
|
2015-09-28 15:31:26 -04:00
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline const T&
|
|
|
|
hash_table_get(const Hash_Table<T>& h, u64 key, const T& default_value)
|
|
|
|
{
|
|
|
|
const s64 index = impl::find_entry_or_fail_in_hash_table(h, key);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (index < 0)
|
|
|
|
return default_value;
|
|
|
|
return h.data[index].value;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
hash_table_set(Hash_Table<T>& h, u64 key, const T& value)
|
|
|
|
{
|
|
|
|
if (h.hashes.count == 0)
|
|
|
|
impl::grow_hash_table(h);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
const s64 index = impl::find_or_make_entry_in_hash_table(h, key);
|
|
|
|
h.data[index].value = value;
|
|
|
|
if (impl::is_hash_table_full(h))
|
|
|
|
impl::grow_hash_table(h);
|
|
|
|
}
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
remove_from_hash_table(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
impl::find_and_erase_entry_from_hash_table(h, key);
|
|
|
|
}
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
reserve_hash_table(Hash_Table<T>& h, usize capacity)
|
|
|
|
{
|
|
|
|
impl:;rehash_hash_table(h, capacity);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
clear_hash_table(Hash_Table<T>& h)
|
|
|
|
{
|
|
|
|
clear_array(h.hashes);
|
|
|
|
clear_array(h.data);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
2015-10-05 16:30:55 -04:00
|
|
|
inline typename const Hash_Table<T>::Entry*
|
2015-09-28 15:31:26 -04:00
|
|
|
begin(const Hash_Table<T>& h)
|
|
|
|
{
|
|
|
|
return begin(h.data);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
2015-10-05 16:30:55 -04:00
|
|
|
inline typename const Hash_Table<T>::Entry*
|
2015-09-28 15:31:26 -04:00
|
|
|
end(const Hash_Table<T>& h)
|
|
|
|
{
|
|
|
|
return end(h.data);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Mutli_Hash_Table
|
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
get_multiple_from_hash_table(const Hash_Table<T>& h, u64 key, Array<T>& items)
|
|
|
|
{
|
|
|
|
auto e = find_first_in_hash_table(h, key);
|
|
|
|
while (e)
|
|
|
|
{
|
|
|
|
append_array(items, e->value);
|
|
|
|
e = find_next_in_hash_table(h, e);
|
|
|
|
}
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline usize
|
|
|
|
multiple_count_from_hash_table(const Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
usize count = 0;
|
|
|
|
auto e = find_first_in_hash_table(h, key);
|
|
|
|
while (e)
|
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
count++;
|
2015-09-29 10:11:18 -04:00
|
|
|
e = find_next_in_hash_table(h, e);
|
2015-09-28 15:31:26 -04:00
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return count;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
2015-10-05 16:30:55 -04:00
|
|
|
inline typename const Hash_Table<T>::Entry*
|
2015-09-28 15:31:26 -04:00
|
|
|
find_first_in_hash_table(const Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
const s64 index = find_first_in_hash_table(h, key);
|
2015-09-28 15:31:26 -04:00
|
|
|
if (index < 0)
|
|
|
|
return nullptr;
|
|
|
|
return &h.data[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2015-10-05 16:30:55 -04:00
|
|
|
typename const Hash_Table<T>::Entry*
|
|
|
|
find_next_in_hash_table(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e)
|
2015-09-28 15:31:26 -04:00
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto index = e->next;
|
|
|
|
while (index >= 0)
|
|
|
|
{
|
|
|
|
if (h.data[index].ley == e->key)
|
|
|
|
return &h.data[index];
|
|
|
|
index = h.data[index].next;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
insert_into_hash_table(Hash_Table<T>& h, u64 key, const T& value)
|
|
|
|
{
|
|
|
|
if (h.hashes.count == 0)
|
|
|
|
impl::grow_hash_table(h);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
auto next = impl::make_entry_in_hash_table(h, key);
|
|
|
|
h.data[next].value = value;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
if (impl::is_hash_table_full(h))
|
|
|
|
impl::grow_hash_table(h);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
2015-10-05 16:30:55 -04:00
|
|
|
remove_entry_from_hash_table(Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e)
|
2015-09-28 15:31:26 -04:00
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
const auto fr = impl::find_result_in_hash_table(h, e);
|
2015-09-28 15:31:26 -04:00
|
|
|
if (fr.data_index >= 0)
|
|
|
|
impl::erase_from_hash_table(h, fr);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
remove_all_from_hash_table(Hash_Table<T>& h, u64 key)
|
|
|
|
{
|
|
|
|
while (hash_table_has(h, key))
|
|
|
|
remove(h, key);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
/// Hash ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
namespace hash
|
|
|
|
{
|
2015-09-28 18:57:43 -04:00
|
|
|
u32 adler32(const void* key, u32 num_bytes);
|
2015-09-28 16:58:33 -04:00
|
|
|
|
2015-09-28 18:57:43 -04:00
|
|
|
u32 crc32(const void* key, u32 num_bytes);
|
2015-09-28 16:58:33 -04:00
|
|
|
u64 crc64(const void* key, usize num_bytes);
|
|
|
|
|
|
|
|
// TODO(bill): Complete hashing functions
|
|
|
|
// u32 fnv32(const void* key, usize num_bytes);
|
|
|
|
// u64 fnv64(const void* key, usize num_bytes);
|
|
|
|
// u32 fnv32a(const void* key, usize num_bytes);
|
|
|
|
// u64 fnv64a(const void* key, usize num_bytes);
|
|
|
|
|
|
|
|
u32 murmur32(const void* key, u32 num_bytes, u32 seed = 0x9747b28c);
|
|
|
|
u64 murmur64(const void* key, usize num_bytes, u64 seed = 0x9747b28c);
|
|
|
|
} // namespace hash
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Time ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Time
|
|
|
|
{
|
|
|
|
s64 microseconds;
|
|
|
|
};
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time time_now();
|
|
|
|
void time_sleep(Time time);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time seconds(f32 s);
|
|
|
|
Time milliseconds(s32 ms);
|
|
|
|
Time microseconds(s64 us);
|
2015-10-03 10:26:29 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 time_as_seconds(Time t);
|
|
|
|
s32 time_as_milliseconds(Time t);
|
|
|
|
s64 time_as_microseconds(Time t);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
bool operator==(Time left, Time right);
|
|
|
|
bool operator!=(Time left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
bool operator<(Time left, Time right);
|
|
|
|
bool operator>(Time left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
bool operator<=(Time left, Time right);
|
|
|
|
bool operator>=(Time left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time operator-(Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time operator+(Time left, Time right);
|
|
|
|
Time operator-(Time left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time& operator+=(Time& left, Time right);
|
|
|
|
Time& operator-=(Time& left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time operator*(Time left, f32 right);
|
|
|
|
Time operator*(Time left, s64 right);
|
|
|
|
Time operator*(f32 left, Time right);
|
|
|
|
Time operator*(s64 left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time& operator*=(Time& left, f32 right);
|
|
|
|
Time& operator*=(Time& left, s64 right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time operator/(Time left, f32 right);
|
|
|
|
Time operator/(Time left, s64 right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time& operator/=(Time& left, f32 right);
|
|
|
|
Time& operator/=(Time& left, s64 right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 operator/(Time left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-29 10:11:18 -04:00
|
|
|
Time operator%(Time left, Time right);
|
2015-09-28 15:31:26 -04:00
|
|
|
Time& operator%=(Time& left, Time right);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Math Types ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 15:43:22 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Vector2
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
union
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
struct { f32 x, y; };
|
|
|
|
f32 data[2];
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
inline const f32& operator[](usize index) const { return data[index]; }
|
|
|
|
inline f32& operator[](usize index) { return data[index]; }
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Vector3
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
union
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
struct { f32 x, y, z; };
|
|
|
|
Vector2 xy;
|
2015-09-29 10:11:18 -04:00
|
|
|
f32 data[3];
|
2015-09-28 15:31:26 -04:00
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
inline const f32& operator[](usize index) const { return data[index]; }
|
|
|
|
inline f32& operator[](usize index) { return data[index]; }
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Vector4
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
union
|
|
|
|
{
|
|
|
|
struct { f32 x, y, z, w; };
|
|
|
|
struct { Vector2 xy, zw; };
|
|
|
|
Vector3 xyz;
|
|
|
|
f32 data[4];
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
inline const f32& operator[](usize index) const { return data[index]; }
|
|
|
|
inline f32& operator[](usize index) { return data[index]; }
|
|
|
|
};
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
struct Complex
|
|
|
|
{
|
2015-10-05 13:17:30 -04:00
|
|
|
union
|
2015-10-04 15:59:40 -04:00
|
|
|
{
|
|
|
|
struct { f32 x, y; };
|
|
|
|
struct { f32 real, imag; };
|
|
|
|
f32 data[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
inline const f32& operator[](usize index) const { return data[index]; }
|
|
|
|
inline f32& operator[](usize index) { return data[index]; }
|
|
|
|
};
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Quaternion
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
union
|
|
|
|
{
|
|
|
|
struct { f32 x, y, z, w; };
|
|
|
|
Vector3 xyz;
|
|
|
|
f32 data[4];
|
|
|
|
};
|
2015-09-29 10:11:18 -04:00
|
|
|
|
|
|
|
inline const 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 const Vector2& operator[](usize index) const { return columns[index]; }
|
|
|
|
inline Vector2& operator[](usize index) { return columns[index]; }
|
2015-09-28 15:31:26 -04:00
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
|
2015-09-29 10:11:18 -04:00
|
|
|
struct Matrix3
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct { Vector3 x, y, z; };
|
|
|
|
Vector3 columns[3];
|
|
|
|
f32 data[9];
|
|
|
|
};
|
|
|
|
|
|
|
|
inline const Vector3& operator[](usize index) const { return columns[index]; }
|
|
|
|
inline Vector3& operator[](usize index) { return columns[index]; }
|
|
|
|
};
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Matrix4
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
union
|
|
|
|
{
|
|
|
|
struct { Vector4 x, y, z, w; };
|
2015-09-29 10:11:18 -04:00
|
|
|
Vector4 columns[4];
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 data[16];
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-29 10:11:18 -04:00
|
|
|
inline const Vector4& operator[](usize index) const { return columns[index]; }
|
|
|
|
inline Vector4& operator[](usize index) { return columns[index]; }
|
2015-09-28 15:31:26 -04:00
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
struct Euler_Angles
|
2015-09-27 15:43:22 -04:00
|
|
|
{
|
2015-09-28 15:31:26 -04:00
|
|
|
// NOTE(bill): All angles in radians
|
|
|
|
f32 pitch;
|
|
|
|
f32 yaw;
|
|
|
|
f32 roll;
|
|
|
|
};
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
struct Transform
|
|
|
|
{
|
|
|
|
Vector3 position = Vector3{0, 0, 0};
|
|
|
|
Quaternion orientation = Quaternion{0, 0, 0, 1};
|
|
|
|
Vector3 scale = Vector3{0, 0, 0};
|
|
|
|
};
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
struct Aabb
|
|
|
|
{
|
|
|
|
Vector3 center;
|
|
|
|
Vector3 half_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Sphere
|
|
|
|
{
|
|
|
|
Vector3 center;
|
|
|
|
f32 radius;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Plane
|
|
|
|
{
|
|
|
|
Vector3 normal;
|
|
|
|
f32 distance; // negative distance to origin
|
|
|
|
};
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Math Type Op Overloads ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector2 Operators
|
|
|
|
bool operator==(const Vector2& a, const Vector2& b);
|
|
|
|
bool operator!=(const Vector2& a, const Vector2& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2 operator-(const Vector2& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2 operator+(const Vector2& a, const Vector2& b);
|
|
|
|
Vector2 operator-(const Vector2& a, const Vector2& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2 operator*(const Vector2& a, f32 scalar);
|
|
|
|
Vector2 operator*(f32 scalar, const Vector2& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2 operator/(const Vector2& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2 operator*(const Vector2& a, const Vector2& b); // Hadamard Product
|
|
|
|
Vector2 operator/(const Vector2& a, const Vector2& b); // Hadamard Product
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector2& operator+=(Vector2& a, const Vector2& b);
|
|
|
|
Vector2& operator-=(Vector2& a, const Vector2& b);
|
|
|
|
Vector2& operator*=(Vector2& a, f32 scalar);
|
|
|
|
Vector2& operator/=(Vector2& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector3 Operators
|
|
|
|
bool operator==(const Vector3& a, const Vector3& b);
|
|
|
|
bool operator!=(const Vector3& a, const Vector3& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3 operator-(const Vector3& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3 operator+(const Vector3& a, const Vector3& b);
|
|
|
|
Vector3 operator-(const Vector3& a, const Vector3& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3 operator*(const Vector3& a, f32 scalar);
|
|
|
|
Vector3 operator*(f32 scalar, const Vector3& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3 operator/(const Vector3& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3 operator*(const Vector3& a, const Vector3& b); // Hadamard Product
|
|
|
|
Vector3 operator/(const Vector3& a, const Vector3& b); // Hadamard Product
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector3& operator+=(Vector3& a, const Vector3& b);
|
|
|
|
Vector3& operator-=(Vector3& a, const Vector3& b);
|
|
|
|
Vector3& operator*=(Vector3& a, f32 scalar);
|
|
|
|
Vector3& operator/=(Vector3& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector4 Operators
|
|
|
|
bool operator==(const Vector4& a, const Vector4& b);
|
|
|
|
bool operator!=(const Vector4& a, const Vector4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4 operator-(const Vector4& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4 operator+(const Vector4& a, const Vector4& b);
|
|
|
|
Vector4 operator-(const Vector4& a, const Vector4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4 operator*(const Vector4& a, f32 scalar);
|
|
|
|
Vector4 operator*(f32 scalar, const Vector4& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4 operator/(const Vector4& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4 operator*(const Vector4& a, const Vector4& b); // Hadamard Product
|
|
|
|
Vector4 operator/(const Vector4& a, const Vector4& b); // Hadamard Product
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Vector4& operator+=(Vector4& a, const Vector4& b);
|
|
|
|
Vector4& operator-=(Vector4& a, const Vector4& b);
|
|
|
|
Vector4& operator*=(Vector4& a, f32 scalar);
|
|
|
|
Vector4& operator/=(Vector4& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
// Complex Operators
|
|
|
|
bool operator==(const Complex& a, const Complex& b);
|
|
|
|
bool operator!=(const Complex& a, const Complex& b);
|
|
|
|
|
|
|
|
Complex operator-(const Complex& a);
|
|
|
|
|
|
|
|
Complex operator+(const Complex& a, const Complex& b);
|
|
|
|
Complex operator-(const Complex& a, const Complex& b);
|
|
|
|
|
|
|
|
Complex operator*(const Complex& a, const Complex& b);
|
|
|
|
Complex operator*(const Complex& a, f32 s);
|
|
|
|
Complex operator*(f32 s, const Complex& a);
|
|
|
|
|
|
|
|
Complex operator/(const Complex& a, f32 s);
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Quaternion Operators
|
|
|
|
bool operator==(const Quaternion& a, const Quaternion& b);
|
|
|
|
bool operator!=(const Quaternion& a, const Quaternion& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion operator-(const Quaternion& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion operator+(const Quaternion& a, const Quaternion& b);
|
|
|
|
Quaternion operator-(const Quaternion& a, const Quaternion& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion operator*(const Quaternion& a, const Quaternion& b);
|
|
|
|
Quaternion operator*(const Quaternion& a, f32 s);
|
|
|
|
Quaternion operator*(f32 s, const Quaternion& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion operator/(const Quaternion& a, f32 s);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
Vector3 operator*(const Quaternion& a, const Vector3& v); // Rotate v by a
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
// Matrix2 Operators
|
|
|
|
bool operator==(const Matrix2& a, const Matrix2& b);
|
|
|
|
bool operator!=(const Matrix2& a, const Matrix2& b);
|
|
|
|
|
|
|
|
Matrix2 operator+(const Matrix2& a, const Matrix2& b);
|
|
|
|
Matrix2 operator-(const Matrix2& a, const Matrix2& b);
|
|
|
|
|
|
|
|
Matrix2 operator*(const Matrix2& a, const Matrix2& b);
|
|
|
|
Vector2 operator*(const Matrix2& a, const Vector2& v);
|
|
|
|
Matrix2 operator*(const Matrix2& a, f32 scalar);
|
|
|
|
Matrix2 operator*(f32 scalar, const Matrix2& a);
|
|
|
|
|
|
|
|
Matrix2 operator/(const Matrix2& a, f32 scalar);
|
|
|
|
|
|
|
|
Matrix2& operator+=(Matrix2& a, const Matrix2& b);
|
|
|
|
Matrix2& operator-=(Matrix2& a, const Matrix2& b);
|
|
|
|
Matrix2& operator*=(Matrix2& a, const Matrix2& b);
|
|
|
|
|
|
|
|
// Matrix3 Operators
|
|
|
|
bool operator==(const Matrix3& a, const Matrix3& b);
|
|
|
|
bool operator!=(const Matrix3& a, const Matrix3& b);
|
|
|
|
|
|
|
|
Matrix3 operator+(const Matrix3& a, const Matrix3& b);
|
|
|
|
Matrix3 operator-(const Matrix3& a, const Matrix3& b);
|
|
|
|
|
|
|
|
Matrix3 operator*(const Matrix3& a, const Matrix3& b);
|
|
|
|
Vector3 operator*(const Matrix3& a, const Vector3& v);
|
|
|
|
Matrix3 operator*(const Matrix3& a, f32 scalar);
|
|
|
|
Matrix3 operator*(f32 scalar, const Matrix3& a);
|
|
|
|
|
|
|
|
Matrix3 operator/(const Matrix3& a, f32 scalar);
|
|
|
|
|
|
|
|
Matrix3& operator+=(Matrix3& a, const Matrix3& b);
|
|
|
|
Matrix3& operator-=(Matrix3& a, const Matrix3& b);
|
|
|
|
Matrix3& operator*=(Matrix3& a, const Matrix3& b);
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Matrix4 Operators
|
|
|
|
bool operator==(const Matrix4& a, const Matrix4& b);
|
|
|
|
bool operator!=(const Matrix4& a, const Matrix4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4 operator+(const Matrix4& a, const Matrix4& b);
|
|
|
|
Matrix4 operator-(const Matrix4& a, const Matrix4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4 operator*(const Matrix4& a, const Matrix4& b);
|
|
|
|
Vector4 operator*(const Matrix4& a, const Vector4& v);
|
|
|
|
Matrix4 operator*(const Matrix4& a, f32 scalar);
|
|
|
|
Matrix4 operator*(f32 scalar, const Matrix4& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4 operator/(const Matrix4& a, f32 scalar);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4& operator+=(Matrix4& a, const Matrix4& b);
|
|
|
|
Matrix4& operator-=(Matrix4& a, const Matrix4& b);
|
|
|
|
Matrix4& operator*=(Matrix4& a, const Matrix4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Transform Operators
|
|
|
|
// World = Parent * Local
|
|
|
|
Transform operator*(const Transform& ps, const Transform& ls);
|
|
|
|
Transform& operator*=(Transform& ps, const Transform& ls);
|
|
|
|
// Local = World / Parent
|
|
|
|
Transform operator/(const Transform& ws, const Transform& ps);
|
|
|
|
Transform& operator/=(Transform& ws, const Transform& ps);
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
//////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Math Functions & Constants ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
//////////////////////////////////
|
2015-10-04 15:59:40 -04:00
|
|
|
extern const Vector2 VECTOR2_ZERO;
|
|
|
|
extern const Vector3 VECTOR3_ZERO;
|
|
|
|
extern const Vector4 VECTOR4_ZERO;
|
|
|
|
extern const Complex COMPLEX_ZERO;
|
|
|
|
extern const Quaternion QUATERNION_IDENTITY;
|
|
|
|
extern const Matrix2 MATRIX2_IDENTITY;
|
|
|
|
extern const Matrix3 MATRIX3_IDENTITY;
|
|
|
|
extern const Matrix4 MATRIX4_IDENTITY;
|
|
|
|
extern const Euler_Angles EULER_ANGLES_ZERO;
|
|
|
|
extern const Transform TRANSFORM_IDENTITY;
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
namespace math
|
|
|
|
{
|
|
|
|
extern const f32 EPSILON;
|
|
|
|
extern const f32 ZERO;
|
|
|
|
extern const f32 ONE;
|
|
|
|
extern const f32 THIRD;
|
|
|
|
extern const f32 TWO_THIRDS;
|
|
|
|
extern const f32 E;
|
|
|
|
extern const f32 PI;
|
|
|
|
extern const f32 TAU;
|
|
|
|
extern const f32 SQRT_2;
|
|
|
|
extern const f32 SQRT_3;
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
extern const f32 F32_PRECISION;
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Power
|
|
|
|
f32 sqrt(f32 x);
|
|
|
|
f32 pow(f32 x, f32 y);
|
|
|
|
f32 cbrt(f32 x);
|
|
|
|
f32 fast_inv_sqrt(f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Trigonometric
|
|
|
|
f32 sin(f32 radians);
|
|
|
|
f32 cos(f32 radians);
|
|
|
|
f32 tan(f32 radians);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 asin(f32 x);
|
|
|
|
f32 acos(f32 x);
|
|
|
|
f32 atan(f32 x);
|
|
|
|
f32 atan2(f32 y, f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 radians(f32 degrees);
|
|
|
|
f32 degrees(f32 radians);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Hyperbolic
|
|
|
|
f32 sinh(f32 x);
|
|
|
|
f32 cosh(f32 x);
|
|
|
|
f32 tanh(f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 asinh(f32 x);
|
|
|
|
f32 acosh(f32 x);
|
|
|
|
f32 atanh(f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Rounding
|
|
|
|
f32 ceil(f32 x);
|
|
|
|
f32 floor(f32 x);
|
|
|
|
f32 mod(f32 x, f32 y);
|
|
|
|
f32 truncate(f32 x);
|
|
|
|
f32 round(f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
s32 sign(s32 x);
|
|
|
|
s64 sign(s64 x);
|
|
|
|
f32 sign(f32 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Other
|
|
|
|
f32 abs(f32 x);
|
|
|
|
s8 abs( s8 x);
|
|
|
|
s16 abs(s16 x);
|
|
|
|
s32 abs(s32 x);
|
|
|
|
s64 abs(s64 x);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
bool is_infinite(f32 x);
|
|
|
|
bool is_nan(f32 x);
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
s32 min(s32 a, s32 b);
|
|
|
|
s64 min(s64 a, s64 b);
|
|
|
|
f32 min(f32 a, f32 b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
s32 max(s32 a, s32 b);
|
|
|
|
s64 max(s64 a, s64 b);
|
|
|
|
f32 max(f32 a, f32 b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
s32 clamp(s32 x, s32 min, s32 max);
|
|
|
|
s64 clamp(s64 x, s64 min, s64 max);
|
|
|
|
f32 clamp(f32 x, f32 min, f32 max);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
template <typename T>
|
|
|
|
T lerp(const T& x, const T& y, const T& t);
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
bool equals(f32 a, f32 b, f32 precision = F32_PRECISION);
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void swap(T& a, T& b);
|
|
|
|
|
|
|
|
template <typename T, usize N>
|
|
|
|
void swap(T (& a)[N], T (& b)[N]);
|
2015-09-28 17:42:15 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector2 functions
|
|
|
|
f32 dot(const Vector2& a, const Vector2& b);
|
|
|
|
f32 cross(const Vector2& a, const Vector2& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 magnitude(const Vector2& a);
|
|
|
|
Vector2 normalize(const Vector2& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Vector2 hadamard(const Vector2& a, const Vector2& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector3 functions
|
|
|
|
f32 dot(const Vector3& a, const Vector3& b);
|
|
|
|
Vector3 cross(const Vector3& a, const Vector3& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 magnitude(const Vector3& a);
|
|
|
|
Vector3 normalize(const Vector3& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Vector3 hadamard(const Vector3& a, const Vector3& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Vector4 functions
|
|
|
|
f32 dot(const Vector4& a, const Vector4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 magnitude(const Vector4& a);
|
|
|
|
Vector4 normalize(const Vector4& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Vector4 hadamard(const Vector4& a, const Vector4& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
// Complex functions
|
|
|
|
f32 dot(const Complex& a, const Complex& b);
|
|
|
|
|
|
|
|
f32 magnitude(const Complex& a);
|
|
|
|
f32 norm(const Complex& a);
|
|
|
|
Complex normalize(const Complex& a);
|
|
|
|
|
|
|
|
Complex conjugate(const Complex& a);
|
|
|
|
Complex inverse(const Complex& a);
|
|
|
|
|
|
|
|
f32 complex_angle(const Complex& a);
|
|
|
|
inline f32 complex_argument(const Complex& a) { return complex_angle(a); }
|
|
|
|
Complex magnitude_angle(f32 magnitude, f32 radians);
|
|
|
|
inline Complex complex_polar(f32 magnitude, f32 radians) { return magnitude_angle(magnitude, radians); }
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Quaternion functions
|
|
|
|
f32 dot(const Quaternion& a, const Quaternion& b);
|
|
|
|
Quaternion cross(const Quaternion& a, const Quaternion& b);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 magnitude(const Quaternion& a);
|
2015-10-04 15:59:40 -04:00
|
|
|
f32 norm(const Quaternion& a);
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion normalize(const Quaternion& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion conjugate(const Quaternion& a);
|
|
|
|
Quaternion inverse(const Quaternion& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 quaternion_angle(const Quaternion& a);
|
|
|
|
Vector3 quaternion_axis(const Quaternion& a);
|
|
|
|
Quaternion axis_angle(const Vector3& axis, f32 radians);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
f32 quaternion_roll(const Quaternion& a);
|
|
|
|
f32 quaternion_pitch(const Quaternion& a);
|
|
|
|
f32 quaternion_yaw(const Quaternion& a);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Euler_Angles quaternion_to_euler_angles(const Quaternion& a);
|
|
|
|
Quaternion euler_angles_to_quaternion(const Euler_Angles& e,
|
2015-10-05 16:30:55 -04:00
|
|
|
const Vector3& x_axis = {1, 0, 0},
|
|
|
|
const Vector3& y_axis = {0, 1, 0},
|
|
|
|
const Vector3& z_axis = {0, 0, 1});
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Spherical Linear Interpolation
|
|
|
|
Quaternion slerp(const Quaternion& x, const Quaternion& y, f32 t);
|
|
|
|
|
|
|
|
// Shoemake's Quaternion Curves
|
|
|
|
// Sqherical Cubic Interpolation
|
2015-10-04 15:59:40 -04:00
|
|
|
Quaternion squad(const Quaternion& p,
|
2015-10-05 16:30:55 -04:00
|
|
|
const Quaternion& a,
|
|
|
|
const Quaternion& b,
|
|
|
|
const Quaternion& q,
|
|
|
|
f32 t);
|
2015-09-30 17:12:16 -04:00
|
|
|
// Matrix2 functions
|
|
|
|
Matrix2 transpose(const Matrix2& m);
|
|
|
|
f32 determinant(const Matrix2& m);
|
|
|
|
Matrix2 inverse(const Matrix2& m);
|
2015-10-03 10:26:29 -04:00
|
|
|
Matrix2 hadamard(const Matrix2& a, const Matrix2&b);
|
2015-10-04 15:59:40 -04:00
|
|
|
Matrix4 matrix2_to_matrix4(const Matrix2& m);
|
2015-09-30 17:12:16 -04:00
|
|
|
|
|
|
|
// Matrix3 functions
|
|
|
|
Matrix3 transpose(const Matrix3& m);
|
|
|
|
f32 determinant(const Matrix3& m);
|
|
|
|
Matrix3 inverse(const Matrix3& m);
|
2015-10-03 10:26:29 -04:00
|
|
|
Matrix3 hadamard(const Matrix3& a, const Matrix3&b);
|
2015-10-04 15:59:40 -04:00
|
|
|
Matrix4 matrix3_to_matrix4(const Matrix3& m);
|
2015-09-28 17:42:15 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
// Matrix4 functions
|
|
|
|
Matrix4 transpose(const Matrix4& m);
|
|
|
|
f32 determinant(const Matrix4& m);
|
|
|
|
Matrix4 inverse(const Matrix4& m);
|
2015-10-03 10:26:29 -04:00
|
|
|
Matrix4 hadamard(const Matrix4& a, const Matrix4&b);
|
2015-10-05 13:17:30 -04:00
|
|
|
bool is_affine(const Matrix4& m);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4 quaternion_to_matrix4(const Quaternion& a);
|
|
|
|
Quaternion matrix4_to_quaternion(const Matrix4& m);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4 translate(const Vector3& v);
|
|
|
|
Matrix4 rotate(const Vector3& v, f32 radians);
|
|
|
|
Matrix4 scale(const 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(f32 fovy_radians, f32 aspect, f32 z_near, f32 z_far);
|
|
|
|
Matrix4 infinite_perspective(f32 fovy_radians, f32 aspect, f32 z_near);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Matrix4
|
|
|
|
look_at_matrix4(const Vector3& eye, const Vector3& center, const Vector3& up = {0, 1, 0});
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Quaternion
|
|
|
|
look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up = {0, 1, 0});
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Transform Functions
|
|
|
|
Vector3 transform_point(const Transform& transform, const Vector3& point);
|
|
|
|
Transform inverse(const Transform& t);
|
|
|
|
Matrix4 transform_to_matrix4(const Transform& t);
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Aabb Functions
|
2015-10-05 13:17:30 -04:00
|
|
|
Aabb calculate_aabb(const void* vertices, usize num_vertices, usize stride, usize offset);
|
|
|
|
|
|
|
|
f32 aabb_surface_area(const Aabb& aabb);
|
2015-10-03 10:26:29 -04:00
|
|
|
f32 aabb_volume(const Aabb& aabb);
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Sphere aabb_to_sphere(const Aabb& aabb);
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
bool contains(const Aabb& aabb, const Vector3& point);
|
|
|
|
bool contains(const Aabb& a, const Aabb& b);
|
|
|
|
bool intersects(const Aabb& a, const Aabb& b);
|
|
|
|
|
|
|
|
Aabb aabb_transform_affine(const Aabb& aabb, const Matrix4& m);
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Sphere Functions
|
2015-10-05 13:17:30 -04:00
|
|
|
Sphere calculate_min_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step);
|
|
|
|
Sphere calculate_max_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset);
|
|
|
|
|
|
|
|
f32 sphere_surface_area(const Sphere& s);
|
2015-10-03 10:26:29 -04:00
|
|
|
f32 sphere_volume(const Sphere& s);
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
Aabb sphere_to_aabb(const Sphere& sphere);
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
bool sphere_contains_point(const Sphere& s, const Vector3& point);
|
|
|
|
|
|
|
|
// Plane Functions
|
|
|
|
f32 ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p);
|
|
|
|
f32 ray_sphere_intersection(const Vector3& from, const Vector3& dir, const Sphere& s);
|
|
|
|
|
|
|
|
bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip);
|
2015-09-28 15:31:26 -04:00
|
|
|
} // namespace math
|
2015-09-29 10:11:18 -04:00
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
namespace random
|
|
|
|
{
|
|
|
|
enum Generator_Type
|
|
|
|
{
|
|
|
|
MERSENNE_TWISTER_32,
|
|
|
|
MERSENNE_TWISTER_64,
|
2015-10-05 16:30:55 -04:00
|
|
|
|
|
|
|
RANDOM_DEVICE,
|
2015-10-05 13:17:30 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// NOTE(bill): Basic Definition of a Random Number Generator
|
2015-10-05 16:30:55 -04:00
|
|
|
// NOTE(bill): C++(17)?? Concepts might be useful here
|
2015-10-05 13:17:30 -04:00
|
|
|
/*
|
|
|
|
struct Generator
|
2015-10-05 16:30:55 -04:00
|
|
|
// concept Generator<typename T, typename U>
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
using Result_Type = T;
|
|
|
|
using Seed_Type = U;
|
|
|
|
|
|
|
|
Generator_Type type;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 entropy();
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
Result_Type next();
|
|
|
|
u32 next_u32();
|
|
|
|
s32 next_s32();
|
|
|
|
u64 next_u64();
|
|
|
|
s64 next_s64();
|
|
|
|
f32 next_f32();
|
|
|
|
f64 next_f64();
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename T, typename U>
|
|
|
|
struct Generator_Base
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
using Result_Type = T;
|
|
|
|
using Seed_Type = U;
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
Seed_Type seed;
|
2015-10-05 16:30:55 -04:00
|
|
|
Generator_Type type;
|
|
|
|
};
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
struct Mt19937_32 : Generator_Base<s32, s32>
|
|
|
|
{
|
2015-10-05 13:17:30 -04:00
|
|
|
u32 index;
|
|
|
|
s32 mt[624];
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 entropy();
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
Result_Type next();
|
|
|
|
u32 next_u32();
|
|
|
|
s32 next_s32();
|
|
|
|
u64 next_u64();
|
|
|
|
s64 next_s64();
|
|
|
|
f32 next_f32();
|
|
|
|
f64 next_f64();
|
|
|
|
};
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
struct Mt19937_64 : Generator_Base<s64, s64>
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
u32 index;
|
|
|
|
s64 mt[312];
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 entropy();
|
|
|
|
|
|
|
|
Result_Type next();
|
|
|
|
u32 next_u32();
|
|
|
|
s32 next_s32();
|
|
|
|
u64 next_u64();
|
|
|
|
s64 next_s64();
|
|
|
|
f32 next_f32();
|
|
|
|
f64 next_f64();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Random_Device : Generator_Base<u32, u32>
|
|
|
|
{
|
|
|
|
u32 entropy();
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
Result_Type next();
|
|
|
|
u32 next_u32();
|
|
|
|
s32 next_s32();
|
|
|
|
u64 next_u64();
|
|
|
|
s64 next_s64();
|
|
|
|
f32 next_f32();
|
|
|
|
f64 next_f64();
|
|
|
|
};
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
// Makers for Generators
|
|
|
|
Mt19937_32 make_mt19937_32(Mt19937_32::Seed_Type seed);
|
|
|
|
Mt19937_64 make_mt19937_64(Mt19937_64::Seed_Type seed);
|
|
|
|
Random_Device make_random_device();
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
void set_seed(Mt19937_32& gen, Mt19937_32::Seed_Type seed);
|
|
|
|
void set_seed(Mt19937_64& gen, Mt19937_64::Seed_Type seed);
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename Generator> typename Generator::Result_Type next(Generator&& gen);
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
template <typename Generator> s32 uniform_s32_distribution(Generator& gen, s32 min_inc, s32 max_inc);
|
|
|
|
template <typename Generator> s64 uniform_s64_distribution(Generator& gen, s64 min_inc, s64 max_inc);
|
|
|
|
template <typename Generator> u32 uniform_u32_distribution(Generator& gen, u32 min_inc, u32 max_inc);
|
|
|
|
template <typename Generator> u64 uniform_u64_distribution(Generator& gen, u64 min_inc, u64 max_inc);
|
|
|
|
template <typename Generator> f32 uniform_f32_distribution(Generator& gen, f32 min_inc, f32 max_inc);
|
|
|
|
template <typename Generator> f64 uniform_f64_distribution(Generator& gen, f64 min_inc, f64 max_inc);
|
|
|
|
|
|
|
|
template <typename Generator> ssize uniform_ssize_distribution(Generator& gen, ssize min_inc, ssize max_inc);
|
|
|
|
template <typename Generator> usize uniform_usize_distribution(Generator& gen, usize min_inc, usize max_inc);
|
|
|
|
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Mt19937_32
|
|
|
|
make_mt19937_32(Mt19937_32::Seed_Type seed)
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32 gen = {};
|
2015-10-05 13:17:30 -04:00
|
|
|
gen.type = MERSENNE_TWISTER_32;
|
|
|
|
set_seed(gen, seed);
|
|
|
|
return gen;
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Mt19937_64
|
|
|
|
make_mt19937_64(Mt19937_64::Seed_Type seed)
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64 gen = {};
|
2015-10-05 13:17:30 -04:00
|
|
|
gen.type = MERSENNE_TWISTER_64;
|
|
|
|
set_seed(gen, seed);
|
|
|
|
return gen;
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Random_Device
|
|
|
|
make_random_device()
|
|
|
|
{
|
|
|
|
Random_Device gen = {};
|
|
|
|
gen.type = RANDOM_DEVICE;
|
|
|
|
return gen;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline void
|
2015-10-05 16:30:55 -04:00
|
|
|
set_seed(Mt19937_32& gen, Mt19937_32::Seed_Type seed)
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
gen.seed = seed;
|
|
|
|
gen.mt[0] = seed;
|
|
|
|
for (u32 i = 1; i < 624; i++)
|
|
|
|
gen.mt[i] = 1812433253 * (gen.mt[i-1] ^ gen.mt[i-1] >> 30) + i;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2015-10-05 16:30:55 -04:00
|
|
|
set_seed(Mt19937_64& gen, Mt19937_64::Seed_Type seed)
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
gen.seed = seed;
|
|
|
|
gen.mt[0] = seed;
|
|
|
|
for (u32 i = 1; i < 312; i++)
|
|
|
|
gen.mt[i] = 6364136223846793005ull * (gen.mt[i-1] ^ gen.mt[i-1] >> 62) + i;
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
template <typename Generator>
|
|
|
|
inline typename Generator::Result_Type
|
|
|
|
next(Generator&& gen)
|
|
|
|
{
|
|
|
|
return gen.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
template <typename Generator>
|
|
|
|
inline s32
|
|
|
|
uniform_s32_distribution(Generator& gen, s32 min_inc, s32 max_inc)
|
|
|
|
{
|
|
|
|
return (gen.next_s32() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline s64
|
|
|
|
uniform_s64_distribution(Generator& gen, s64 min_inc, s64 max_inc)
|
|
|
|
{
|
|
|
|
return (gen.next_s64() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline u32
|
|
|
|
uniform_u32_distribution(Generator& gen, u32 min_inc, u32 max_inc)
|
|
|
|
{
|
|
|
|
return (gen.next_u64() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline u64
|
|
|
|
uniform_u64_distribution(Generator& gen, u64 min_inc, u64 max_inc)
|
|
|
|
{
|
|
|
|
return (gen.next_u64() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline f32
|
|
|
|
uniform_f32_distribution(Generator& gen, f32 min_inc, f32 max_inc)
|
|
|
|
{
|
|
|
|
f64 n = (gen.next_s64() >> 11) * (1.0/4503599627370495.0);
|
2015-10-05 16:30:55 -04:00
|
|
|
return static_cast<f32>(n * (max_inc - min_inc + 1.0) + min_inc);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline f64
|
|
|
|
uniform_f64_distribution(Generator& gen, f64 min_inc, f64 max_inc)
|
|
|
|
{
|
|
|
|
f64 n = (gen.next_s64() >> 11) * (1.0/4503599627370495.0);
|
|
|
|
return n * (max_inc - min_inc + 1.0) + min_inc;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline ssize
|
|
|
|
uniform_ssize_distribution(Generator& gen, ssize min_inc, ssize max_inc)
|
|
|
|
{
|
|
|
|
#if GB_ARCH_32_BIT
|
|
|
|
return (gen.next_s32() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
#elif GB_ARCH_64_BIT
|
|
|
|
return (gen.next_s64() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
#else
|
|
|
|
#error Bit size not supported
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Generator>
|
|
|
|
inline usize
|
|
|
|
uniform_usize_distribution(Generator& gen, usize min_inc, usize max_inc)
|
|
|
|
{
|
|
|
|
#if GB_ARCH_32_BIT
|
|
|
|
return (gen.next_u32() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
#elif GB_ARCH_64_BIT
|
|
|
|
return (gen.next_u64() % (max_inc - min_inc + 1)) + min_inc;
|
|
|
|
#else
|
|
|
|
#error Bit size not supported
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace random
|
2015-09-29 10:11:18 -04:00
|
|
|
|
|
|
|
#if 0
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_OPENGL_TOOLS)
|
2015-09-29 10:11:18 -04:00
|
|
|
|
|
|
|
enum class Shader_Type
|
|
|
|
{
|
|
|
|
VERTEX,
|
|
|
|
FRAGMENT,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Shader_Program
|
|
|
|
{
|
|
|
|
#define GB_MAX_UNIFORM_COUNT 32
|
|
|
|
u32 handle;
|
|
|
|
b32 is_linked;
|
|
|
|
Allocator* allocator;
|
|
|
|
|
|
|
|
const char* base_directory;
|
|
|
|
|
|
|
|
|
|
|
|
u32 uniform_count;
|
|
|
|
const char* uniform_names[GB_MAX_UNIFORM_COUNT];
|
|
|
|
s32 uniform_locations[GB_MAX_UNIFORM_COUNT];
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Shader_Program make_shader_program(gb::Allocator& allocator);
|
|
|
|
void destroy_shader_program(Shader_Program* program);
|
|
|
|
|
|
|
|
b32 attach_shader_from_file(Shader_Program* program, Shader_Type type, const char* filename);
|
|
|
|
b32 attach_shader_from_memory(Shader_Program* program, Shader_Type type, const char* source, usize len);
|
|
|
|
|
|
|
|
void use_shader_program(const Shader_Program* program);
|
|
|
|
b32 is_shader_program_in_use(const Shader_Program* program);
|
|
|
|
void stop_using_shader_program(const Shader_Program* program);
|
|
|
|
|
|
|
|
b32 link_shader_program(Shader_Program* program);
|
|
|
|
|
|
|
|
void bind_attrib_location(Shader_Program* program, const char* name);
|
|
|
|
|
|
|
|
s32 get_uniform_location(Shader_Program* program, const char* name);
|
|
|
|
|
|
|
|
#endif // GB_OPENGL_TOOLS
|
|
|
|
#endif
|
2015-09-28 15:31:26 -04:00
|
|
|
} // namespace gb
|
2015-09-29 10:11:18 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
#endif // GB_INCLUDE_GB_HPP
|
2015-09-27 15:43:22 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
2015-10-05 13:17:30 -04:00
|
|
|
/// It's turtles all the way down!
|
2015-09-28 15:31:26 -04:00
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
///
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Implemenation ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_IMPLEMENTATION)
|
2015-09-28 15:31:26 -04:00
|
|
|
namespace gb
|
|
|
|
{
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Memory ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
Mutex::Mutex()
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
win32_mutex = CreateMutex(0, 0, 0);
|
|
|
|
#else
|
|
|
|
pthread_mutex_init(&posix_mutex, nullptr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
Mutex::~Mutex()
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
CloseHandle(win32_mutex);
|
|
|
|
#else
|
|
|
|
pthread_mutex_destroy(&posix_mutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void lock_mutex(Mutex& mutex)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
WaitForSingleObject(mutex.win32_mutex, INFINITE);
|
|
|
|
#else
|
|
|
|
pthread_mutex_lock(&mutex.posix_mutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool try_lock_mutex(Mutex& mutex)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
return WaitForSingleObject(mutex.win32_mutex, 0) == WAIT_OBJECT_0;
|
|
|
|
#else
|
|
|
|
return pthread_mutex_trylock(&mutex.posix_mutex) == 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void unlock_mutex(Mutex& mutex)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-27 14:03:47 -04:00
|
|
|
ReleaseMutex(mutex.win32_mutex);
|
|
|
|
#else
|
|
|
|
pthread_mutex_unlock(&mutex.posix_mutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Atomics
|
|
|
|
namespace atomic
|
|
|
|
{
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
load_32_relaxed(const Atomic32* object)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return object->nonatomic;
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2015-10-04 15:59:40 -04:00
|
|
|
store_32_relaxed(Atomic32* object, u32 value)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
object->nonatomic = value;
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
compare_exchange_strong_32_relaxed(Atomic32* object, u32 expected, u32 desired)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedCompareExchange(reinterpret_cast<long*>(object), desired, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
exchanged_32_relaxed(Atomic32* object, u32 desired)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedExchange(reinterpret_cast<long*>(object), desired);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_add_32_relaxed(Atomic32* object, s32 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedExchangeAdd(reinterpret_cast<long*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_and_32_relaxed(Atomic32* object, u32 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedAnd(reinterpret_cast<long*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_or_32_relaxed(Atomic32* object, u32 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedOr(reinterpret_cast<long*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-04 15:59:40 -04:00
|
|
|
load_64_relaxed(const Atomic64* object)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
|
|
|
return object->nonatomic;
|
2015-10-03 10:26:29 -04:00
|
|
|
#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;
|
2015-10-05 16:30:55 -04:00
|
|
|
lock cmpxchg8b [esi];
|
|
|
|
mov dword ptr result, eax;
|
|
|
|
mov dword ptr result[4], edx;
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2015-10-04 15:59:40 -04:00
|
|
|
store_64_relaxed(Atomic64* object, u64 value)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
|
|
|
object->nonatomic = value;
|
2015-10-03 10:26:29 -04:00
|
|
|
#else
|
|
|
|
// NOTE(bill): The most compatible way to get an atomic 64-bit load 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
|
2015-10-04 15:59:40 -04:00
|
|
|
compare_exchange_strong_64_relaxed(Atomic64* object, u64 expected, u64 desired)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
_InterlockedCompareExchange64(reinterpret_cast<s64*>(object), desired, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-04 15:59:40 -04:00
|
|
|
exchanged_64_relaxed(Atomic64* object, u64 desired)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedExchange64(reinterpret_cast<s64*>(object), desired);
|
2015-10-03 10:26:29 -04:00
|
|
|
#else
|
|
|
|
u64 expected = object->nonatomic;
|
|
|
|
while (true)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), desired, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
if (original == expected)
|
|
|
|
return original;
|
|
|
|
expected = original;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_add_64_relaxed(Atomic64* object, s64 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedExchangeAdd64(reinterpret_cast<s64*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
#else
|
|
|
|
u64 expected = object->nonatomic;
|
|
|
|
while (true)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 original = _InterlockedExchange64(reinterpret_cast<s64*>(object), expected + operand, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
if (original == expected)
|
|
|
|
return original;
|
|
|
|
expected = original;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_and_64_relaxed(Atomic64* object, u64 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
#else
|
|
|
|
u64 expected = object->nonatomic;
|
|
|
|
while (true)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), expected & operand, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
if (original == expected)
|
|
|
|
return original;
|
|
|
|
expected = original;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-04 15:59:40 -04:00
|
|
|
fetch_or_64_relaxed(Atomic64* object, u64 operand)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
2015-10-05 16:30:55 -04:00
|
|
|
return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand);
|
2015-10-03 10:26:29 -04:00
|
|
|
#else
|
|
|
|
u64 expected = object->nonatomic;
|
|
|
|
while (true)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), expected | operand, expected);
|
2015-10-03 10:26:29 -04:00
|
|
|
if (original == expected)
|
|
|
|
return original;
|
|
|
|
expected = original;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error TODO(bill): Implement atomics for this platform
|
|
|
|
#endif
|
|
|
|
} // namespace atomic
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
Heap_Allocator::~Heap_Allocator()
|
|
|
|
{
|
|
|
|
GB_ASSERT(allocation_count == 0 && total_allocated() == 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
"Heap Allocator: allocation count = %lld; total allocated = %lld",
|
|
|
|
allocation_count, total_allocated());
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Heap_Allocator::alloc(usize size, usize align)
|
|
|
|
{
|
|
|
|
lock_mutex(mutex);
|
|
|
|
defer(unlock_mutex(mutex));
|
|
|
|
|
|
|
|
const usize total = size + align + sizeof(Header);
|
2015-09-27 15:43:22 -04:00
|
|
|
Header* h = (Header*)::malloc(total);
|
2015-09-27 14:03:47 -04:00
|
|
|
h->size = total;
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
void* data = memory::align_forward(h + 1, align);
|
2015-09-27 14:03:47 -04:00
|
|
|
{ // Pad header
|
2015-10-05 16:30:55 -04:00
|
|
|
usize* ptr = reinterpret_cast<usize*>(h+1);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
while (ptr != data)
|
|
|
|
*ptr++ = GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE;
|
|
|
|
}
|
|
|
|
total_allocated_count += total;
|
|
|
|
allocation_count++;
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-10-04 15:59:40 -04:00
|
|
|
Heap_Allocator::dealloc(const void* ptr)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lock_mutex(mutex);
|
|
|
|
defer(unlock_mutex(mutex));
|
|
|
|
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Header* h = get_header_ptr(ptr);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
total_allocated_count -= h->size;
|
|
|
|
allocation_count--;
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
::free((void*)h);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
s64
|
2015-09-27 14:03:47 -04:00
|
|
|
Heap_Allocator::allocated_size(const void* ptr)
|
|
|
|
{
|
|
|
|
lock_mutex(mutex);
|
|
|
|
defer(unlock_mutex(mutex));
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
return get_header_ptr(ptr)->size;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
s64
|
2015-09-27 14:03:47 -04:00
|
|
|
Heap_Allocator::total_allocated()
|
|
|
|
{
|
|
|
|
return total_allocated_count;
|
|
|
|
}
|
|
|
|
|
2015-09-27 15:43:22 -04:00
|
|
|
Heap_Allocator::Header*
|
|
|
|
Heap_Allocator::get_header_ptr(const void* ptr)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
const usize* data = reinterpret_cast<const usize*>(ptr);
|
2015-09-27 15:43:22 -04:00
|
|
|
data--;
|
|
|
|
|
|
|
|
while (*data == GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE)
|
|
|
|
data--;
|
|
|
|
|
|
|
|
return (Heap_Allocator::Header*)data;
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
Arena_Allocator::Arena_Allocator(Allocator& backing_, usize size)
|
|
|
|
: backing(&backing_)
|
|
|
|
, physical_start(nullptr)
|
|
|
|
, total_size((s64)size)
|
2015-09-29 10:11:18 -04:00
|
|
|
, temp_count(0)
|
|
|
|
, total_allocated_count(0)
|
|
|
|
{
|
2015-10-03 10:26:29 -04:00
|
|
|
physical_start = backing->alloc(size);
|
2015-09-29 10:11:18 -04:00
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Arena_Allocator::Arena_Allocator(void* start, usize size)
|
|
|
|
: backing(nullptr)
|
|
|
|
, physical_start(start)
|
|
|
|
, total_size((s64)size)
|
|
|
|
, temp_count(0)
|
|
|
|
, total_allocated_count(0)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
Arena_Allocator::~Arena_Allocator()
|
|
|
|
{
|
|
|
|
if (backing)
|
|
|
|
backing->dealloc(physical_start);
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
GB_ASSERT(total_allocated_count == 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
"Memory leak of %ld bytes, maybe you forgot to call clear_arena()?", total_allocated_count);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void* Arena_Allocator::alloc(usize size, usize align)
|
|
|
|
{
|
|
|
|
s64 actual_size = size + align;
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
if (total_allocated_count + actual_size > total_size)
|
2015-10-03 10:26:29 -04:00
|
|
|
return nullptr;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
void* ptr = memory::align_forward(static_cast<u8*>(physical_start) + total_allocated_count, align);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
total_allocated_count += actual_size;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline void Arena_Allocator::dealloc(const void*) {}
|
2015-09-29 10:11:18 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s64 Arena_Allocator::allocated_size(const void*) { return -1; }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s64 Arena_Allocator::total_allocated() { return total_allocated_count; }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
/// String ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
|
|
|
String make_string(Allocator& a, const char* str)
|
|
|
|
{
|
|
|
|
return make_string(a, str, (String_Size)strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
String make_string(Allocator& a, const void* init_str, String_Size len)
|
|
|
|
{
|
|
|
|
usize header_size = sizeof(String_Header);
|
|
|
|
void* ptr = alloc(a, header_size + len + 1);
|
|
|
|
if (!init_str)
|
|
|
|
memset(ptr, 0, header_size + len + 1);
|
|
|
|
|
|
|
|
if (ptr == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
String str = static_cast<char*>(ptr) + header_size;
|
2015-09-28 16:58:33 -04:00
|
|
|
String_Header* header = string_header(str);
|
|
|
|
header->allocator = &a;
|
|
|
|
header->len = len;
|
|
|
|
header->cap = len;
|
|
|
|
if (len && init_str)
|
|
|
|
memcpy(str, init_str, len);
|
|
|
|
str[len] = '\0';
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void free_string(String& str)
|
|
|
|
{
|
|
|
|
if (str == nullptr)
|
|
|
|
return;
|
|
|
|
String_Header* h = string_header(str);
|
|
|
|
Allocator* a = h->allocator;
|
|
|
|
if (a) dealloc(*a, h);
|
|
|
|
str = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
String duplicate_string(Allocator& a, const String str)
|
|
|
|
{
|
|
|
|
return make_string(a, str, string_length(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
String_Size string_length(const String str)
|
|
|
|
{
|
|
|
|
return string_header(str)->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
String_Size string_capacity(const String str)
|
|
|
|
{
|
|
|
|
return string_header(str)->cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
String_Size string_available_space(const String str)
|
|
|
|
{
|
|
|
|
String_Header* h = string_header(str);
|
|
|
|
if (h->cap > h->len)
|
|
|
|
return h->cap - h->len;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear_string(String str)
|
|
|
|
{
|
|
|
|
string_header(str)->len = 0;
|
|
|
|
str[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
void append_string(String& str, const String other)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
append_string(str, other, string_length(other));
|
2015-09-28 16:58:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void append_cstring(String& str, const char* other)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
append_string(str, other, (String_Size)strlen(other));
|
2015-09-28 16:58:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void append_string(String& str, const void* other, String_Size other_len)
|
|
|
|
{
|
|
|
|
String_Size curr_len = string_length(str);
|
|
|
|
|
|
|
|
string_make_space_for(str, other_len);
|
|
|
|
if (str == nullptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memcpy(str + curr_len, other, other_len);
|
|
|
|
str[curr_len + other_len] = '\0';
|
|
|
|
string_header(str)->len = curr_len + other_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace impl
|
|
|
|
{
|
|
|
|
// NOTE(bill): ptr _must_ be allocated with Allocator& a
|
2015-09-28 17:42:15 -04:00
|
|
|
internal inline void*
|
2015-09-28 16:58:33 -04:00
|
|
|
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;
|
|
|
|
|
|
|
|
memcpy(new_ptr, ptr, old_size);
|
|
|
|
|
|
|
|
dealloc(a, ptr);
|
|
|
|
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
} // namespace impl
|
|
|
|
|
|
|
|
void string_make_space_for(String& str, String_Size add_len)
|
|
|
|
{
|
|
|
|
String_Size len = string_length(str);
|
|
|
|
String_Size new_len = len + add_len;
|
|
|
|
|
|
|
|
String_Size available = string_available_space(str);
|
|
|
|
if (available >= add_len) // Return if there is enough space left
|
|
|
|
return;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
void* ptr = reinterpret_cast<String_Header*>(str) - 1;
|
2015-09-28 16:58:33 -04:00
|
|
|
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;
|
2015-10-05 16:30:55 -04:00
|
|
|
str = static_cast<char*>(new_ptr) + sizeof(String_Header);
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
string_header(str)->cap = new_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
usize string_allocation_size(const String str)
|
|
|
|
{
|
|
|
|
String_Size cap = string_capacity(str);
|
|
|
|
return sizeof(String_Header) + cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool strings_are_equal(const String lhs, const String rhs)
|
|
|
|
{
|
|
|
|
String_Size lhs_len = string_length(lhs);
|
|
|
|
String_Size rhs_len = string_length(rhs);
|
|
|
|
if (lhs_len != rhs_len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (String_Size i = 0; i < lhs_len; i++)
|
|
|
|
{
|
|
|
|
if (lhs[i] != rhs[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void trim_string(String& str, const char* 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--;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
String_Size len = static_cast<String_Size>((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
if (str != start_pos)
|
|
|
|
memmove(str, start_pos, len);
|
|
|
|
str[len] = '\0';
|
|
|
|
|
|
|
|
string_header(str)->len = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
/// Hash ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 16:58:33 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
namespace hash
|
|
|
|
{
|
2015-09-28 18:57:43 -04:00
|
|
|
u32 adler32(const void* key, u32 num_bytes)
|
2015-09-28 16:58:33 -04:00
|
|
|
{
|
|
|
|
const u32 MOD_ADLER = 65521;
|
|
|
|
|
|
|
|
u32 a = 1;
|
|
|
|
u32 b = 0;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* bytes = static_cast<const u8*>(key);
|
2015-09-28 18:57:43 -04:00
|
|
|
for (u32 i = 0; i < num_bytes; i++)
|
2015-09-28 16:58:33 -04:00
|
|
|
{
|
|
|
|
a = (a + bytes[i]) % MOD_ADLER;
|
|
|
|
b = (b + a) % MOD_ADLER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (b << 16) | a;
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
global const u32 GB_CRC32_TABLE[256] = {
|
2015-09-28 16:58:33 -04:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
global const u64 GB_CRC64_TABLE[256] = {
|
2015-09-28 16:58:33 -04:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-09-28 18:57:43 -04:00
|
|
|
u32 crc32(const void* key, u32 num_bytes)
|
2015-09-28 16:58:33 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 result = static_cast<u32>(~0);
|
|
|
|
const u8* c = reinterpret_cast<const u8*>(key);
|
2015-09-28 18:57:43 -04:00
|
|
|
for (u32 remaining = num_bytes; remaining--; c++)
|
2015-09-28 16:58:33 -04:00
|
|
|
result = (result >> 8) ^ (GB_CRC32_TABLE[(result ^ *c) & 0xff]);
|
|
|
|
|
|
|
|
return ~result;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 crc64(const void* key, usize num_bytes)
|
|
|
|
{
|
|
|
|
u64 result = (u64)~0;
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* c = reinterpret_cast<const u8*>(key);
|
2015-09-28 16:58:33 -04:00
|
|
|
for (usize remaining = num_bytes; remaining--; c++)
|
|
|
|
result = (result >> 8) ^ (GB_CRC64_TABLE[(result ^ *c) & 0xff]);
|
|
|
|
|
|
|
|
return ~result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// u32 fnv32(const void* key, usize num_bytes)
|
|
|
|
// {
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// u64 fnv64(const void* key, usize num_bytes)
|
|
|
|
// {
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// u32 fnv32a(const void* key, usize num_bytes)
|
|
|
|
// {
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// u64 fnv64a(const void* key, usize num_bytes)
|
|
|
|
// {
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
u32 murmur32(const void* key, u32 num_bytes, u32 seed)
|
|
|
|
{
|
2015-09-28 17:42:15 -04:00
|
|
|
local_persist const u32 c1 = 0xcc9e2d51;
|
|
|
|
local_persist const u32 c2 = 0x1b873593;
|
|
|
|
local_persist const u32 r1 = 15;
|
|
|
|
local_persist const u32 r2 = 13;
|
|
|
|
local_persist const u32 m = 5;
|
|
|
|
local_persist const u32 n = 0xe6546b64;
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
u32 hash = seed;
|
|
|
|
|
|
|
|
const usize nblocks = num_bytes / 4;
|
2015-10-05 16:30:55 -04:00
|
|
|
const u32* blocks = static_cast<const u32*>(key);
|
2015-09-28 16:58:33 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* tail = (static_cast<const u8*>(key)) + nblocks * 4;
|
2015-09-28 16:58:33 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_ARCH_64_BIT)
|
2015-09-28 16:58:33 -04:00
|
|
|
u64 murmur64(const void* key, usize num_bytes, u64 seed)
|
|
|
|
{
|
2015-09-28 17:42:15 -04:00
|
|
|
local_persist const u64 m = 0xc6a4a7935bd1e995ULL;
|
|
|
|
local_persist const s32 r = 47;
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
u64 h = seed ^ (num_bytes * m);
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u64* data = static_cast<const u64*>(key);
|
2015-09-28 16:58:33 -04:00
|
|
|
const u64* end = data + (num_bytes / 8);
|
|
|
|
|
|
|
|
while (data != end)
|
|
|
|
{
|
|
|
|
u64 k = *data++;
|
|
|
|
|
|
|
|
k *= m;
|
|
|
|
k ^= k >> r;
|
|
|
|
k *= m;
|
|
|
|
|
|
|
|
h ^= k;
|
|
|
|
h *= m;
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* data2 = reinterpret_cast<const u8*>(data);
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
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]};
|
|
|
|
h *= m;
|
|
|
|
};
|
|
|
|
|
|
|
|
h ^= h >> r;
|
|
|
|
h *= m;
|
|
|
|
h ^= h >> r;
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
#elif GB_ARCH_32_BIT
|
|
|
|
u64 murmur64(const void* key, usize num_bytes, u64 seed)
|
|
|
|
{
|
2015-09-28 17:42:15 -04:00
|
|
|
local_persist const u32 m = 0x5bd1e995;
|
|
|
|
local_persist const s32 r = 24;
|
2015-09-28 16:58:33 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 h1 = static_cast<u32>(seed) ^ static_cast<u32>(num_bytes);
|
|
|
|
u32 h2 = static_cast<u32>(seed >> 32);
|
2015-09-28 16:58:33 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u32* data = static_cast<const u32*>(key);
|
2015-09-28 16:58:33 -04:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
case 3: h2 ^= reinterpret_cast<const u8*>(data)[2] << 16;
|
|
|
|
case 2: h2 ^= reinterpret_cast<const u8*>(data)[1] << 8;
|
|
|
|
case 1: h2 ^= reinterpret_cast<const u8*>(data)[0] << 0;
|
2015-09-28 16:58:33 -04:00
|
|
|
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
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Time ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
2015-09-28 15:31:26 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
internal LARGE_INTEGER
|
2015-09-28 15:31:26 -04:00
|
|
|
win32_get_frequency()
|
|
|
|
{
|
|
|
|
LARGE_INTEGER f;
|
|
|
|
QueryPerformanceFrequency(&f);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
Time 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
|
2015-09-28 17:42:15 -04:00
|
|
|
internal LARGE_INTEGER s_frequency = win32_get_frequency();
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
// Get the current time
|
|
|
|
LARGE_INTEGER t;
|
|
|
|
QueryPerformanceCounter(&t);
|
|
|
|
|
|
|
|
// Restore the thread affinity
|
|
|
|
SetThreadAffinityMask(currentThread, previousMask);
|
|
|
|
|
|
|
|
return microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart);
|
|
|
|
}
|
|
|
|
|
|
|
|
void time_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 time_now()
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
#if defined(GB_SYSTEM_OSX)
|
2015-10-05 16:30:55 -04:00
|
|
|
s64 t = static_cast<s64>(mach_absolute_time());
|
2015-10-03 10:26:29 -04:00
|
|
|
return microseconds(t);
|
|
|
|
#else
|
2015-10-02 08:11:18 -04:00
|
|
|
struct timeval t;
|
|
|
|
gettimeofday(&t, nullptr);
|
2015-09-28 15:31:26 -04:00
|
|
|
|
2015-10-02 08:11:18 -04:00
|
|
|
return microseconds((t.tv_sec * 1000000ll) + (t.tv_usec * 1ll));
|
2015-10-03 10:26:29 -04:00
|
|
|
#endif
|
2015-09-28 15:31:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void time_sleep(Time t)
|
|
|
|
{
|
|
|
|
if (t.microseconds <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct timespec spec = {};
|
|
|
|
spec.tv_sec = static_cast<s64>(time_as_seconds(t));
|
|
|
|
spec.tv_nsec = 1000ll * (time_as_microseconds(t) % 1000000ll);
|
|
|
|
|
|
|
|
nanosleep(&spec, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-09-29 10:11:18 -04:00
|
|
|
Time seconds(f32 s) { return {(s64)(s * 1000000ll)}; }
|
|
|
|
Time milliseconds(s32 ms) { return {(s64)(ms * 1000l)}; }
|
|
|
|
Time microseconds(s64 us) { return {us}; }
|
|
|
|
f32 time_as_seconds(Time t) { return (f32)(t.microseconds / 1000000.0f); }
|
|
|
|
s32 time_as_milliseconds(Time t) { return (s32)(t.microseconds / 1000l); }
|
|
|
|
s64 time_as_microseconds(Time t) { return t.microseconds; }
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
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 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 seconds(time_as_seconds(left) * right);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time operator*(Time left, s64 right)
|
|
|
|
{
|
|
|
|
return microseconds(time_as_microseconds(left) * right);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time operator*(f32 left, Time right)
|
|
|
|
{
|
|
|
|
return seconds(time_as_seconds(right) * left);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time operator*(s64 left, Time right)
|
|
|
|
{
|
|
|
|
return 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 seconds(time_as_seconds(left) / right);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time operator/(Time left, s64 right)
|
|
|
|
{
|
|
|
|
return microseconds(time_as_microseconds(left) / right);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Time& operator/=(Time& left, f32 right)
|
|
|
|
{
|
|
|
|
return (left = left / right);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time& operator/=(Time& left, s64 right)
|
|
|
|
{
|
|
|
|
return (left = left / right);
|
|
|
|
}
|
|
|
|
|
|
|
|
f32 operator/(Time left, Time right)
|
|
|
|
{
|
|
|
|
return time_as_seconds(left) / time_as_seconds(right);
|
|
|
|
}
|
|
|
|
|
|
|
|
Time operator%(Time left, Time right)
|
|
|
|
{
|
|
|
|
return microseconds(time_as_microseconds(left) % time_as_microseconds(right));
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
Time& operator%=(Time& left, Time right)
|
|
|
|
{
|
|
|
|
return (left = left % right);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
/// Math ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-28 15:31:26 -04:00
|
|
|
////////////////////////////////
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
const Vector2 VECTOR2_ZERO = {0, 0};
|
|
|
|
const Vector3 VECTOR3_ZERO = {0, 0, 0};
|
|
|
|
const Vector4 VECTOR4_ZERO = {0, 0, 0, 0};
|
|
|
|
const Complex COMPLEX_ZERO = {0, 0};
|
|
|
|
const Quaternion QUATERNION_IDENTITY = {0, 0, 0, 1};
|
|
|
|
const Matrix2 MATRIX2_IDENTITY = {1, 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
0, 1};
|
2015-10-04 15:59:40 -04:00
|
|
|
const Matrix3 MATRIX3_IDENTITY = {1, 0, 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
0, 1, 0,
|
|
|
|
0, 0, 1};
|
2015-10-04 15:59:40 -04:00
|
|
|
const Matrix4 MATRIX4_IDENTITY = {1, 0, 0, 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
0, 1, 0, 0,
|
|
|
|
0, 0, 1, 0,
|
|
|
|
0, 0, 0, 1};
|
2015-10-04 15:59:40 -04:00
|
|
|
const Euler_Angles EULER_ANGLES_ZERO = {0, 0, 0};
|
|
|
|
const Transform TRANSFORM_IDENTITY = Transform{};
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
////////////////////////////////
|
|
|
|
/// Math Type Op Overloads ///
|
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
// Vector2 Operators
|
|
|
|
bool operator==(const Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
return (a.x == b.x) && (a.y == b.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator-(const Vector2& a)
|
|
|
|
{
|
|
|
|
return {-a.x, -a.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator+(const Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
return {a.x + b.x, a.y + b.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator-(const Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
return {a.x - b.x, a.y - b.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator*(const Vector2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator*(f32 scalar, const Vector2& a)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator/(const Vector2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x / scalar, a.y / scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator*(const Vector2& a, const Vector2& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator/(const Vector2& a, const Vector2& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x / b.x, a.y / b.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2& operator+=(Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
a.x += b.x;
|
|
|
|
a.y += b.y;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2& operator-=(Vector2& a, const Vector2& b)
|
|
|
|
{
|
|
|
|
a.x -= b.x;
|
|
|
|
a.y -= b.y;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2& operator*=(Vector2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x *= scalar;
|
|
|
|
a.y *= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2& operator/=(Vector2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x /= scalar;
|
|
|
|
a.y /= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vector3 Operators
|
|
|
|
bool operator==(const Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator-(const Vector3& a)
|
|
|
|
{
|
|
|
|
return {-a.x, -a.y, -a.z};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator+(const Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
return {a.x + b.x, a.y + b.y, a.z + b.z};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator-(const Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
return {a.x - b.x, a.y - b.y, a.z - b.z};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator*(const Vector3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar, a.z * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator*(f32 scalar, const Vector3& a)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar, a.z * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator/(const Vector3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x / scalar, a.y / scalar, a.z / scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator*(const Vector3& a, const Vector3& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y, a.z * b.z};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator/(const Vector3& a, const Vector3& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x / b.x, a.y / b.y, a.z / b.z};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3& operator+=(Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
a.x += b.x;
|
|
|
|
a.y += b.y;
|
|
|
|
a.z += b.z;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3& operator-=(Vector3& a, const Vector3& b)
|
|
|
|
{
|
|
|
|
a.x -= b.x;
|
|
|
|
a.y -= b.y;
|
|
|
|
a.z -= b.z;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3& operator*=(Vector3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x *= scalar;
|
|
|
|
a.y *= scalar;
|
|
|
|
a.z *= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3& operator/=(Vector3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x /= scalar;
|
|
|
|
a.y /= scalar;
|
|
|
|
a.z /= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vector4 Operators
|
|
|
|
bool operator==(const Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator-(const Vector4& a)
|
|
|
|
{
|
|
|
|
return {-a.x, -a.y, -a.z, -a.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator+(const Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator-(const Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator*(const Vector4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator*(f32 scalar, const Vector4& a)
|
|
|
|
{
|
|
|
|
return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator/(const Vector4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
return {a.x / scalar, a.y / scalar, a.z / scalar, a.w / scalar};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator*(const Vector4& a, const Vector4& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator/(const Vector4& a, const Vector4& b) // Hadamard Product
|
|
|
|
{
|
|
|
|
return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4& operator+=(Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
a.x += b.x;
|
|
|
|
a.y += b.y;
|
|
|
|
a.z += b.z;
|
|
|
|
a.w += b.w;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4& operator-=(Vector4& a, const Vector4& b)
|
|
|
|
{
|
|
|
|
a.x -= b.x;
|
|
|
|
a.y -= b.y;
|
|
|
|
a.z -= b.z;
|
|
|
|
a.w -= b.w;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4& operator*=(Vector4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x *= scalar;
|
|
|
|
a.y *= scalar;
|
|
|
|
a.z *= scalar;
|
|
|
|
a.w *= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4& operator/=(Vector4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
a.x /= scalar;
|
|
|
|
a.y /= scalar;
|
|
|
|
a.z /= scalar;
|
|
|
|
a.w /= scalar;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
// Complex Operators
|
|
|
|
bool operator==(const Complex& a, const Complex& b)
|
|
|
|
{
|
|
|
|
return (a.x == b.x) && (a.y == b.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Complex& a, const Complex& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator-(const Complex& a)
|
|
|
|
{
|
|
|
|
return {-a.x, -a.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator+(const Complex& a, const Complex& b)
|
|
|
|
{
|
|
|
|
return {a.x + b.x, a.y + b.y};
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator-(const Complex& a, const Complex& b)
|
|
|
|
{
|
|
|
|
return {a.x - b.x, a.y - b.y};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator*(const Complex& a, const 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator*(const Complex& a, f32 s)
|
|
|
|
{
|
|
|
|
return {a.x * s, a.y * s};
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator*(f32 s, const Complex& a)
|
|
|
|
{
|
|
|
|
return {a.x * s, a.y * s};
|
|
|
|
}
|
|
|
|
|
|
|
|
Complex operator/(const Complex& a, f32 s)
|
|
|
|
{
|
|
|
|
return {a.x / s, a.y / s};
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Quaternion Operators
|
|
|
|
bool operator==(const Quaternion& a, const Quaternion& b)
|
|
|
|
{
|
|
|
|
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Quaternion& a, const Quaternion& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator-(const Quaternion& a)
|
|
|
|
{
|
|
|
|
return {-a.x, -a.y, -a.z, -a.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator+(const Quaternion& a, const Quaternion& b)
|
|
|
|
{
|
|
|
|
return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator-(const Quaternion& a, const Quaternion& b)
|
|
|
|
{
|
|
|
|
return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator*(const Quaternion& a, const 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator*(const Quaternion& a, f32 s)
|
|
|
|
{
|
|
|
|
return {a.x * s, a.y * s, a.z * s, a.w * s};
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator*(f32 s, const Quaternion& a)
|
|
|
|
{
|
|
|
|
return {a.x * s, a.y * s, a.z * s, a.w * s};
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion operator/(const Quaternion& a, f32 s)
|
|
|
|
{
|
|
|
|
return {a.x / s, a.y / s, a.z / s, a.w / s};
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
Vector3 operator*(const Quaternion& a, const 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));
|
|
|
|
}
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
|
|
|
|
|
|
|
|
// Matrix2 Operators
|
|
|
|
bool operator==(const Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
for (usize i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (a[i] != b[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator+(const Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
Matrix2 mat;
|
|
|
|
mat[0] = a[0] + b[0];
|
|
|
|
mat[1] = a[1] + b[1];
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator-(const Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
Matrix2 mat;
|
|
|
|
mat[0] = a[0] - b[0];
|
|
|
|
mat[1] = a[1] - b[1];
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator*(const Matrix2& a, const 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 operator*(const Matrix2& a, const Vector2& v)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return Vector2{a[0][0] * v.x + a[1][0] * v.y,
|
2015-10-05 16:30:55 -04:00
|
|
|
a[0][1] * v.x + a[1][1] * v.y};
|
2015-09-30 17:12:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator*(const Matrix2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix2 mat;
|
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator*(f32 scalar, const Matrix2& a)
|
|
|
|
{
|
|
|
|
Matrix2 mat;
|
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2 operator/(const Matrix2& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix2 mat;
|
|
|
|
mat[0] = a[0] / scalar;
|
|
|
|
mat[1] = a[1] / scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2& operator+=(Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
return (a = a + b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2& operator-=(Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
return (a = a - b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix2& operator*=(Matrix2& a, const Matrix2& b)
|
|
|
|
{
|
|
|
|
return (a = a * b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Matrix3 Operators
|
|
|
|
bool operator==(const Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
for (usize i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
if (a[i] != b[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator+(const Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
Matrix3 mat;
|
|
|
|
mat[0] = a[0] + b[0];
|
|
|
|
mat[1] = a[1] + b[1];
|
|
|
|
mat[2] = a[2] + b[2];
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator-(const Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
Matrix3 mat;
|
|
|
|
mat[0] = a[0] - b[0];
|
|
|
|
mat[1] = a[1] - b[1];
|
|
|
|
mat[2] = a[2] - b[2];
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator*(const Matrix3& a, const Matrix3& 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 operator*(const Matrix3& a, const Vector3& v)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return Vector3{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z,
|
2015-10-05 16:30:55 -04:00
|
|
|
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};
|
2015-09-30 17:12:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator*(const Matrix3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix3 mat;
|
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
mat[2] = a[2] * scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator*(f32 scalar, const Matrix3& a)
|
|
|
|
{
|
|
|
|
Matrix3 mat;
|
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
mat[2] = a[2] * scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3 operator/(const Matrix3& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix3 mat;
|
|
|
|
mat[0] = a[0] / scalar;
|
|
|
|
mat[1] = a[1] / scalar;
|
|
|
|
mat[2] = a[2] / scalar;
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3& operator+=(Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
return (a = a + b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3& operator-=(Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
return (a = a - b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix3& operator*=(Matrix3& a, const Matrix3& b)
|
|
|
|
{
|
|
|
|
return (a = a * b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Matrix4 Operators
|
|
|
|
bool operator==(const Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
for (usize i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (a[i] != b[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
return !operator==(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator+(const Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
Matrix4 mat;
|
2015-09-30 17:12:16 -04:00
|
|
|
mat[0] = a[0] + b[0];
|
|
|
|
mat[1] = a[1] + b[1];
|
|
|
|
mat[2] = a[2] + b[2];
|
|
|
|
mat[3] = a[3] + b[3];
|
2015-09-27 14:03:47 -04:00
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator-(const Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
Matrix4 mat;
|
2015-09-30 17:12:16 -04:00
|
|
|
mat[0] = a[0] - b[0];
|
|
|
|
mat[1] = a[1] - b[1];
|
|
|
|
mat[2] = a[2] - b[2];
|
|
|
|
mat[3] = a[3] - b[3];
|
2015-09-27 14:03:47 -04:00
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator*(const Matrix4& a, const Matrix4& 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 operator*(const Matrix4& a, const Vector4& v)
|
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return Vector4{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z + a[3][0] * v.w,
|
2015-10-05 16:30:55 -04:00
|
|
|
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};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator*(const Matrix4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix4 mat;
|
2015-09-30 17:12:16 -04:00
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
mat[2] = a[2] * scalar;
|
|
|
|
mat[3] = a[3] * scalar;
|
2015-09-27 14:03:47 -04:00
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator*(f32 scalar, const Matrix4& a)
|
|
|
|
{
|
|
|
|
Matrix4 mat;
|
2015-09-30 17:12:16 -04:00
|
|
|
mat[0] = a[0] * scalar;
|
|
|
|
mat[1] = a[1] * scalar;
|
|
|
|
mat[2] = a[2] * scalar;
|
|
|
|
mat[3] = a[3] * scalar;
|
2015-09-27 14:03:47 -04:00
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 operator/(const Matrix4& a, f32 scalar)
|
|
|
|
{
|
|
|
|
Matrix4 mat;
|
2015-09-30 17:12:16 -04:00
|
|
|
mat[0] = a[0] / scalar;
|
|
|
|
mat[1] = a[1] / scalar;
|
|
|
|
mat[2] = a[2] / scalar;
|
|
|
|
mat[3] = a[3] / scalar;
|
2015-09-27 14:03:47 -04:00
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4& operator+=(Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
return (a = a + b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4& operator-=(Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
return (a = a - b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4& operator*=(Matrix4& a, const Matrix4& b)
|
|
|
|
{
|
|
|
|
return (a = a * b);
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Transform Operators
|
|
|
|
// World = Parent * Local
|
|
|
|
Transform operator*(const Transform& ps, const Transform& 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);
|
|
|
|
|
|
|
|
return ws;
|
|
|
|
}
|
|
|
|
|
|
|
|
Transform& operator*=(Transform& ps, const Transform& ls)
|
|
|
|
{
|
|
|
|
return (ps = ps * ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local = World / Parent
|
|
|
|
Transform operator/(const Transform& ws, const Transform& 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);
|
|
|
|
|
|
|
|
return ls;
|
|
|
|
}
|
|
|
|
|
|
|
|
Transform& operator/=(Transform& ws, const Transform& ps)
|
|
|
|
{
|
|
|
|
return (ws = ws / ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
/// Math Functions ///
|
2015-09-30 17:12:16 -04:00
|
|
|
/// ///
|
2015-09-27 14:03:47 -04:00
|
|
|
////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
namespace math
|
|
|
|
{
|
2015-10-03 10:26:29 -04:00
|
|
|
const f32 EPSILON = FLT_EPSILON;
|
|
|
|
const f32 ZERO = 0.0f;
|
|
|
|
const f32 ONE = 1.0f;
|
|
|
|
const f32 THIRD = 0.33333333f;
|
|
|
|
const f32 TWO_THIRDS = 0.66666667f;
|
|
|
|
const f32 E = 2.718281828f;
|
|
|
|
const f32 PI = 3.141592654f;
|
|
|
|
const f32 TAU = 6.283185307f;
|
|
|
|
const f32 SQRT_2 = 1.414213562f;
|
|
|
|
const f32 SQRT_3 = 1.732050808f;
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
const f32 F32_PRECISION = 1.0e-7f;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
// Power
|
2015-09-28 15:31:26 -04:00
|
|
|
inline f32 sqrt(f32 x) { return ::sqrtf(x); }
|
2015-09-27 14:03:47 -04:00
|
|
|
inline f32 pow(f32 x, f32 y) { return (f32)::powf(x, y); }
|
2015-09-28 15:31:26 -04:00
|
|
|
inline f32 cbrt(f32 x) { return (f32)::cbrtf(x); }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
fast_inv_sqrt(f32 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
const f32 THREE_HALFS = 1.5f;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
const f32 x2 = x * 0.5f;
|
2015-09-27 14:03:47 -04:00
|
|
|
f32 y = x;
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 i = pseudo_cast<u32>(y); // Evil floating point bit level hacking
|
2015-09-27 14:03:47 -04:00
|
|
|
// i = 0x5f3759df - (i >> 1); // What the fuck? Old
|
|
|
|
i = 0x5f375a86 - (i >> 1); // What the fuck? Improved!
|
2015-10-05 16:30:55 -04:00
|
|
|
y = pseudo_cast<f32>(i);
|
2015-10-04 15:59:40 -04:00
|
|
|
y = y * (THREE_HALFS - (x2 * y * y)); // 1st iteration
|
|
|
|
// y = y * (THREE_HALFS - (x2 * y * y)); // 2nd iteration, this can be removed
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigonometric
|
|
|
|
inline f32 sin(f32 radians) { return ::sinf(radians); }
|
|
|
|
inline f32 cos(f32 radians) { return ::cosf(radians); }
|
|
|
|
inline f32 tan(f32 radians) { return ::tanf(radians); }
|
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
inline f32 asin(f32 x) { return ::asinf(x); }
|
|
|
|
inline f32 acos(f32 x) { return ::acosf(x); }
|
|
|
|
inline f32 atan(f32 x) { return ::atanf(x); }
|
2015-09-27 14:03:47 -04:00
|
|
|
inline f32 atan2(f32 y, f32 x) { return ::atan2f(y, x); }
|
|
|
|
|
|
|
|
inline f32 radians(f32 degrees) { return TAU * degrees / 360.0f; }
|
|
|
|
inline f32 degrees(f32 radians) { return 360.0f * radians / TAU; }
|
|
|
|
|
|
|
|
// 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 asinh(f32 x) { return ::asinhf(x); }
|
|
|
|
inline f32 acosh(f32 x) { return ::acoshf(x); }
|
|
|
|
inline f32 atanh(f32 x) { return ::atanhf(x); }
|
|
|
|
|
|
|
|
// Rounding
|
2015-09-28 15:31:26 -04:00
|
|
|
inline f32 ceil(f32 x) { return ::ceilf(x); }
|
|
|
|
inline f32 floor(f32 x) { return ::floorf(x); }
|
2015-09-27 14:03:47 -04:00
|
|
|
inline f32 mod(f32 x, f32 y) { return ::fmodf(x, y); }
|
2015-09-28 15:31:26 -04:00
|
|
|
inline f32 truncate(f32 x) { return ::truncf(x); }
|
|
|
|
inline f32 round(f32 x) { return ::roundf(x); }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
inline s32 sign(s32 x) { return x >= 0 ? +1 : -1; }
|
|
|
|
inline s64 sign(s64 x) { return x >= 0 ? +1 : -1; }
|
2015-09-29 10:11:18 -04:00
|
|
|
inline f32 sign(f32 x) { return x >= 0.0f ? +1.0f : -1.0f; }
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
// Other
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
abs(f32 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 i = pseudo_cast<u32>(x);
|
2015-09-27 14:03:47 -04:00
|
|
|
i &= 0x7FFFFFFFul;
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<f32>(i);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s8
|
|
|
|
abs(s8 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u8 i = pseudo_cast<u8>(x);
|
2015-09-27 14:03:47 -04:00
|
|
|
i &= 0x7Fu;
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s8>(i);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s16
|
|
|
|
abs(s16 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u16 i = pseudo_cast<u16>(x);
|
2015-09-27 14:03:47 -04:00
|
|
|
i &= 0x7FFFu;
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s16>(i);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s32
|
|
|
|
abs(s32 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u32 i = pseudo_cast<u32>(x);
|
2015-09-27 14:03:47 -04:00
|
|
|
i &= 0x7FFFFFFFul;
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s32>(i);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s64
|
|
|
|
abs(s64 x)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 i = pseudo_cast<u64>(x);
|
2015-09-27 14:03:47 -04:00
|
|
|
i &= 0x7FFFFFFFFFFFFFFFull;
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s64>(i);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline bool
|
|
|
|
is_infinite(f32 x)
|
|
|
|
{
|
|
|
|
return isinf(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
is_nan(f32 x)
|
|
|
|
{
|
|
|
|
return isnan(x);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
inline s32 min(s32 a, s32 b) { return a < b ? a : b; }
|
|
|
|
inline s64 min(s64 a, s64 b) { return a < b ? a : b; }
|
|
|
|
inline f32 min(f32 a, f32 b) { return a < b ? a : b; }
|
|
|
|
|
|
|
|
inline s32 max(s32 a, s32 b) { return a > b ? a : b; }
|
|
|
|
inline s64 max(s64 a, s64 b) { return a > b ? a : b; }
|
|
|
|
inline f32 max(f32 a, f32 b) { return a > b ? a : b; }
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline s32
|
|
|
|
clamp(s32 x, s32 min, s32 max)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
if (x < min)
|
|
|
|
return min;
|
|
|
|
if (x > max)
|
|
|
|
return max;
|
|
|
|
return x;
|
|
|
|
}
|
2015-10-04 15:59:40 -04:00
|
|
|
|
|
|
|
inline s64
|
|
|
|
clamp(s64 x, s64 min, s64 max)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
if (x < min)
|
|
|
|
return min;
|
|
|
|
if (x > max)
|
|
|
|
return max;
|
|
|
|
return x;
|
|
|
|
}
|
2015-10-04 15:59:40 -04:00
|
|
|
|
|
|
|
inline f32
|
|
|
|
clamp(f32 x, f32 min, f32 max)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
if (x < min)
|
|
|
|
return min;
|
|
|
|
if (x > max)
|
|
|
|
return max;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
template <typename T>
|
|
|
|
inline T
|
|
|
|
lerp(const T& x, const T& y, const T& t)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
2015-10-03 10:26:29 -04:00
|
|
|
return x + (y - x) * t;
|
2015-09-28 17:42:15 -04:00
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline bool
|
|
|
|
equals(f32 a, f32 b, f32 precision)
|
|
|
|
{
|
|
|
|
return ((b <= (a + precision)) && (b >= (a - precision)));
|
|
|
|
}
|
2015-09-28 17:42:15 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
template <typename T>
|
|
|
|
inline void
|
|
|
|
swap(T& a, T& b)
|
|
|
|
{
|
|
|
|
T c = gb::move(a);
|
|
|
|
a = gb::move(b);
|
|
|
|
b = gb::move(c);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
template <typename T, usize N>
|
2015-10-04 15:59:40 -04:00
|
|
|
inline void
|
|
|
|
swap(T (& a)[N], T (& b)[N])
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
|
|
|
for (usize i = 0; i < N; i++)
|
|
|
|
math::swap(a[i], b[i]);
|
|
|
|
}
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
// Vector2 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
dot(const Vector2& a, const Vector2& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return a.x * b.x + a.y * b.y;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
cross(const Vector2& a, const Vector2& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return a.x * b.y - a.y * b.x;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
magnitude(const Vector2& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::sqrt(math::dot(a, a));
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector2
|
|
|
|
normalize(const Vector2& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
f32 m = magnitude(a);
|
|
|
|
if (m > 0)
|
|
|
|
return a * (1.0f / m);
|
|
|
|
return {};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector2
|
|
|
|
hadamard(const Vector2& a, const Vector2& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y};
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
matrix2_to_matrix4(const 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;
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Vector3 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
dot(const Vector3& a, const Vector3& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector3
|
|
|
|
cross(const Vector3& a, const Vector3& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return Vector3{
|
2015-10-05 16:30:55 -04:00
|
|
|
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
|
2015-09-27 14:03:47 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
magnitude(const Vector3& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::sqrt(math::dot(a, a));
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector3
|
|
|
|
normalize(const Vector3& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
f32 m = magnitude(a);
|
|
|
|
if (m > 0)
|
|
|
|
return a * (1.0f / m);
|
|
|
|
return {};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector3
|
|
|
|
hadamard(const Vector3& a, const Vector3& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y, a.z * b.z};
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
matrix3_to_matrix4(const Matrix3& 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;
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Vector4 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
dot(const Vector4& a, const Vector4& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
magnitude(const Vector4& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::sqrt(math::dot(a, a));
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector4
|
|
|
|
normalize(const Vector4& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
f32 m = magnitude(a);
|
|
|
|
if (m > 0)
|
|
|
|
return a * (1.0f / m);
|
|
|
|
return {};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector4
|
|
|
|
hadamard(const Vector4& a, const Vector4& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
// Complex Functions
|
|
|
|
inline f32
|
|
|
|
dot(const Complex& a, const Complex& b)
|
|
|
|
{
|
|
|
|
return a.real * b.real + a.imag * b.imag;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
|
|
|
magnitude(const Complex& a)
|
|
|
|
{
|
|
|
|
return math::sqrt(norm(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
|
|
|
norm(const Complex& a)
|
|
|
|
{
|
|
|
|
return math::dot(a, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Complex
|
|
|
|
normalize(const Complex& a)
|
|
|
|
{
|
|
|
|
f32 m = magnitude(a);
|
|
|
|
if (m > 0)
|
|
|
|
return a / magnitude(a);
|
|
|
|
return COMPLEX_ZERO;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Complex
|
|
|
|
conjugate(const Complex& a)
|
|
|
|
{
|
|
|
|
return {a.real, -a.imag};
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Complex
|
|
|
|
inverse(const Complex& a)
|
|
|
|
{
|
|
|
|
f32 m = norm(a);
|
|
|
|
if (m > 0)
|
|
|
|
return conjugate(a) / norm(a);
|
|
|
|
return COMPLEX_ZERO;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
|
|
|
complex_angle(const Complex& a)
|
|
|
|
{
|
|
|
|
return atan2(a.imag, a.real);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Complex
|
|
|
|
magnitude_angle(f32 magnitude, f32 radians)
|
|
|
|
{
|
|
|
|
f32 real = magnitude * cos(radians);
|
|
|
|
f32 imag = magnitude * sin(radians);
|
|
|
|
return {real, imag};
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Quaternion functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
dot(const Quaternion& a, const Quaternion& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::dot(a.xyz, b.xyz) + a.w*b.w;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
|
|
|
cross(const Quaternion& a, const Quaternion& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-04 15:59:40 -04:00
|
|
|
return Quaternion{a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
2015-10-05 16:30:55 -04:00
|
|
|
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};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
magnitude(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::sqrt(math::dot(a, a));
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
norm(const Quaternion& a)
|
|
|
|
{
|
|
|
|
return math::dot(a, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Quaternion
|
|
|
|
normalize(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
2015-10-02 08:11:18 -04:00
|
|
|
f32 m = magnitude(a);
|
|
|
|
if (m > 0)
|
|
|
|
return a * (1.0f / m);
|
|
|
|
return {};
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
|
|
|
conjugate(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return {-a.x, -a.y, -a.z, a.w};
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
|
|
|
inverse(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
f32 m = 1.0f / dot(a, a);
|
|
|
|
return math::conjugate(a) * m;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
quaternion_angle(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return 2.0f * math::acos(a.w);
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector3
|
|
|
|
quaternion_axis(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
|
|
|
axis_angle(const Vector3& axis, f32 radians)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
Vector3 a = math::normalize(axis);
|
|
|
|
f32 s = math::sin(0.5f * radians);
|
|
|
|
|
|
|
|
Quaternion q;
|
|
|
|
q.xyz = a * s;
|
|
|
|
q.w = math::cos(0.5f * radians);
|
|
|
|
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
quaternion_roll(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::atan2(2.0f * a.x * a.y + a.z * a.w,
|
2015-10-05 16:30:55 -04:00
|
|
|
a.x * a.x + a.w * a.w - a.y * a.y - a.z * a.z);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
quaternion_pitch(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::atan2(2.0f * a.y * a.z + a.w * a.x,
|
2015-10-05 16:30:55 -04:00
|
|
|
a.w * a.w - a.x * a.x - a.y * a.y + a.z * a.z);
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
quaternion_yaw(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return math::asin(-2.0f * (a.x * a.z - a.w * a.y));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline Euler_Angles
|
|
|
|
quaternion_to_euler_angles(const Quaternion& a)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return {quaternion_pitch(a), quaternion_yaw(a), quaternion_roll(a)};
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline Quaternion
|
|
|
|
euler_angles_to_quaternion(const Euler_Angles& e,
|
2015-10-05 16:30:55 -04:00
|
|
|
const Vector3& x_axis,
|
|
|
|
const Vector3& y_axis,
|
|
|
|
const Vector3& z_axis)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Spherical Linear Interpolation
|
2015-10-03 10:26:29 -04:00
|
|
|
inline Quaternion
|
|
|
|
slerp(const Quaternion& x, const Quaternion& y, f32 t)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
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),
|
2015-10-05 16:30:55 -04:00
|
|
|
lerp(x.y, y.y, t),
|
|
|
|
lerp(x.z, y.z, t),
|
|
|
|
lerp(x.w, y.w, t)};
|
2015-09-28 17:42:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
f32 angle = math::acos(cos_theta);
|
|
|
|
|
|
|
|
Quaternion result = math::sin(1.0f - (t * angle)) * x + math::sin(t * angle) * z;
|
|
|
|
return result * (1.0f / math::sin(angle));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shoemake's Quaternion Curves
|
|
|
|
// Sqherical Cubic Interpolation
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
|
|
|
squad(const Quaternion& p,
|
2015-10-05 16:30:55 -04:00
|
|
|
const Quaternion& a,
|
|
|
|
const Quaternion& b,
|
|
|
|
const Quaternion& q,
|
|
|
|
f32 t)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
return slerp(slerp(p, q, t), slerp(a, b, t), 2.0f * t * (1.0f - t));
|
|
|
|
}
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
// Matrix2 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix2
|
|
|
|
transpose(const Matrix2& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
Matrix2 result;
|
|
|
|
for (usize i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
for (usize j = 0; j < 2; j++)
|
|
|
|
result[i][j] = m[j][i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
determinant(const Matrix2& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
return m[0][0] * m[1][1] - m[1][0] * m[0][1];
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix2
|
|
|
|
inverse(const Matrix2& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix2
|
|
|
|
hadamard(const Matrix2& a, const Matrix2&b)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
Matrix2 result;
|
|
|
|
result[0] = a[0] * b[0];
|
|
|
|
result[1] = a[1] * b[1];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Matrix3 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix3
|
|
|
|
transpose(const Matrix3& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
Matrix3 result;
|
|
|
|
|
|
|
|
for (usize i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
for (usize j = 0; j < 3; j++)
|
|
|
|
result[i][j] = m[j][i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline f32
|
|
|
|
determinant(const Matrix3& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
return ( m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
|
2015-10-05 16:30:55 -04:00
|
|
|
-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]));
|
2015-09-30 17:12:16 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix3
|
|
|
|
inverse(const Matrix3& m)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline Matrix3
|
2015-10-04 15:59:40 -04:00
|
|
|
hadamard(const Matrix3& a, const Matrix3&b)
|
2015-09-30 17:12:16 -04:00
|
|
|
{
|
|
|
|
Matrix3 result;
|
|
|
|
result[0] = a[0] * b[0];
|
|
|
|
result[1] = a[1] * b[1];
|
|
|
|
result[2] = a[2] * b[2];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
// Matrix4 functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
transpose(const Matrix4& m)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
Matrix4 result;
|
|
|
|
|
|
|
|
for (usize i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
for (usize j = 0; j < 4; j++)
|
|
|
|
result[i][j] = m[j][i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
f32
|
|
|
|
determinant(const Matrix4& m)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
Matrix4
|
|
|
|
inverse(const Matrix4& m)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
hadamard(const Matrix4& a, const Matrix4& b)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
Matrix4 result;
|
|
|
|
|
2015-09-30 17:12:16 -04:00
|
|
|
result[0] = a[0] * b[0];
|
|
|
|
result[1] = a[1] * b[1];
|
|
|
|
result[2] = a[2] * b[2];
|
|
|
|
result[3] = a[3] * b[3];
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline bool
|
|
|
|
is_affine(const Matrix4& m)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
// E.g. No translation
|
2015-10-05 13:17:30 -04:00
|
|
|
return (equals(m.columns[3].x, 0)) &
|
2015-10-05 16:30:55 -04:00
|
|
|
(equals(m.columns[3].y, 0)) &
|
|
|
|
(equals(m.columns[3].z, 0)) &
|
|
|
|
(equals(m.columns[3].w, 1.0f));
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
quaternion_to_matrix4(const Quaternion& q)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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);
|
2015-09-28 15:31:26 -04:00
|
|
|
mat[0][1] = 2.0f * (xy + wz);
|
|
|
|
mat[0][2] = 2.0f * (xz - wy);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
mat[1][0] = 2.0f * (xy - wz);
|
2015-09-27 14:03:47 -04:00
|
|
|
mat[1][1] = 1.0f - 2.0f * (xx + zz);
|
2015-09-28 15:31:26 -04:00
|
|
|
mat[1][2] = 2.0f * (yz + wx);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
2015-09-28 15:31:26 -04:00
|
|
|
mat[2][0] = 2.0f * (xz + wy);
|
|
|
|
mat[2][1] = 2.0f * (yz - wx);
|
2015-09-27 14:03:47 -04:00
|
|
|
mat[2][2] = 1.0f - 2.0f * (xx + yy);
|
|
|
|
|
|
|
|
return mat;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
Quaternion
|
|
|
|
matrix4_to_quaternion(const Matrix4& m)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
2015-09-28 15:31:26 -04:00
|
|
|
biggestIndex = 1;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
if (four_y_squared_minus_1 > four_biggest_squared_minus_1)
|
|
|
|
{
|
|
|
|
four_biggest_squared_minus_1 = four_y_squared_minus_1;
|
2015-09-28 15:31:26 -04:00
|
|
|
biggestIndex = 2;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
if (four_z_squared_minus_1 > four_biggest_squared_minus_1)
|
|
|
|
{
|
|
|
|
four_biggest_squared_minus_1 = four_z_squared_minus_1;
|
2015-09-28 15:31:26 -04:00
|
|
|
biggestIndex = 3;
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
translate(const Vector3& v)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
Matrix4 result = MATRIX4_IDENTITY;
|
|
|
|
result[3].xyz = v;
|
|
|
|
result[3].w = 1;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
rotate(const Vector3& v, f32 radians)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
const f32 c = math::cos(radians);
|
|
|
|
const f32 s = math::sin(radians);
|
|
|
|
|
|
|
|
const Vector3 axis = math::normalize(v);
|
|
|
|
const Vector3 t = (1.0f - c) * axis;
|
|
|
|
|
|
|
|
Matrix4 rot = MATRIX4_IDENTITY;
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
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;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
scale(const Vector3& v)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
return { v.x, 0, 0, 0,
|
2015-10-05 16:30:55 -04:00
|
|
|
0, v.y, 0, 0,
|
|
|
|
0, 0, v.z, 0,
|
|
|
|
0, 0, 0, 1 };
|
2015-09-27 14:03:47 -04:00
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
ortho(f32 left, f32 right, f32 bottom, f32 top)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
Matrix4 result = MATRIX4_IDENTITY;
|
|
|
|
|
|
|
|
result[0][0] = 2.0f / (right - left);
|
|
|
|
result[1][1] = 2.0f / (top - bottom);
|
|
|
|
result[2][2] = -1.0f;
|
|
|
|
result[3][1] = -(right + left) / (right - left);
|
|
|
|
result[3][1] = -(top + bottom) / (top - bottom);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
ortho(f32 left, f32 right, f32 bottom, f32 top, f32 z_near, f32 z_far)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
perspective(f32 fovy_radians, f32 aspect, f32 z_near, f32 z_far)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
GB_ASSERT(math::abs(aspect) > 0.0f,
|
2015-10-05 16:30:55 -04:00
|
|
|
"math::perspective `fovy_radians` is %f", fovy_radians);
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
f32 tan_half_fovy = math::tan(0.5f * fovy_radians);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
|
|
|
infinite_perspective(f32 fovy_radians, f32 aspect, f32 z_near)
|
2015-09-27 14:03:47 -04:00
|
|
|
{
|
|
|
|
f32 range = math::tan(0.5f * fovy_radians) * 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Matrix4
|
2015-09-27 14:03:47 -04:00
|
|
|
look_at_matrix4(const Vector3& eye, const Vector3& center, const 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;
|
2015-09-28 15:31:26 -04:00
|
|
|
|
|
|
|
result[0][0] = +s.x;
|
|
|
|
result[1][0] = +s.y;
|
|
|
|
result[2][0] = +s.z;
|
2015-09-27 14:03:47 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Quaternion
|
2015-09-27 14:03:47 -04:00
|
|
|
look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up)
|
|
|
|
{
|
|
|
|
const f32 similar = 0.001f;
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
if (math::magnitude(center - eye) < similar)
|
2015-09-27 14:03:47 -04:00
|
|
|
return QUATERNION_IDENTITY; // You cannot look at where you are!
|
|
|
|
|
|
|
|
// TODO(bill): Implement using just quaternions
|
|
|
|
return matrix4_to_quaternion(look_at_matrix4(eye, center, up));
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:42:15 -04:00
|
|
|
// Transform Functions
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Vector3
|
|
|
|
transform_point(const Transform& transform, const Vector3& point)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
return (math::conjugate(transform.orientation) * (transform.position - point)) / transform.scale;
|
|
|
|
}
|
|
|
|
|
2015-10-04 15:59:40 -04:00
|
|
|
inline Transform
|
|
|
|
inverse(const Transform& t)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
return inv_transform;
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline Matrix4
|
|
|
|
transform_to_matrix4(const Transform& t)
|
2015-09-28 17:42:15 -04:00
|
|
|
{
|
|
|
|
return math::translate(t.position) * //
|
2015-10-05 16:30:55 -04:00
|
|
|
math::quaternion_to_matrix4(t.orientation) * //
|
|
|
|
math::scale(t.scale); //
|
2015-09-28 17:42:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Aabb Functions
|
2015-10-05 13:17:30 -04:00
|
|
|
inline Aabb
|
|
|
|
calculate_aabb(const void* vertices, usize num_vertices, usize stride, usize offset)
|
|
|
|
{
|
|
|
|
Vector3 min;
|
|
|
|
Vector3 max;
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* vertex = reinterpret_cast<const u8*>(vertices);
|
2015-10-05 13:17:30 -04:00
|
|
|
vertex += offset;
|
2015-10-05 16:30:55 -04:00
|
|
|
Vector3 position = pseudo_cast<Vector3>(vertex);
|
2015-10-05 13:17:30 -04:00
|
|
|
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++)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
position = pseudo_cast<Vector3>(vertex);
|
2015-10-05 13:17:30 -04:00
|
|
|
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
|
|
|
|
aabb_surface_area(const Aabb& 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;
|
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline f32
|
|
|
|
aabb_volume(const Aabb& aabb)
|
|
|
|
{
|
2015-10-05 13:17:30 -04:00
|
|
|
Vector3 h = aabb.half_size * 2.0f;
|
|
|
|
return h.x * h.y * h.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Sphere
|
|
|
|
aabb_to_sphere(const Aabb& aabb)
|
|
|
|
{
|
|
|
|
Sphere s;
|
|
|
|
s.center = aabb.center;
|
|
|
|
s.radius = math::magnitude(aabb.half_size);
|
|
|
|
return s;
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline bool
|
2015-10-05 13:17:30 -04:00
|
|
|
contains(const Aabb& aabb, const Vector3& point)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
|
|
|
Vector3 distance = aabb.center - point;
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
// NOTE(bill): & is faster than &&
|
2015-10-03 10:26:29 -04:00
|
|
|
return (math::abs(distance.x) <= aabb.half_size.x) &
|
2015-10-05 16:30:55 -04:00
|
|
|
(math::abs(distance.y) <= aabb.half_size.y) &
|
|
|
|
(math::abs(distance.z) <= aabb.half_size.z);
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline bool
|
|
|
|
contains(const Aabb& a, const Aabb& b)
|
2015-10-03 10:26:29 -04:00
|
|
|
{
|
2015-10-05 13:17:30 -04:00
|
|
|
Vector3 dist = a.center - b.center;
|
|
|
|
|
|
|
|
// NOTE(bill): & is faster than &&
|
|
|
|
return (math::abs(dist.x) + b.half_size.x <= a.half_size.x) &
|
2015-10-05 16:30:55 -04:00
|
|
|
(math::abs(dist.y) + b.half_size.y <= a.half_size.y) &
|
|
|
|
(math::abs(dist.z) + b.half_size.z <= a.half_size.z);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
intersects(const Aabb& a, const Aabb& 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) &
|
2015-10-05 16:30:55 -04:00
|
|
|
(math::abs(dist.y) <= sum_half_sizes.y) &
|
|
|
|
(math::abs(dist.z) <= sum_half_sizes.z);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline Aabb
|
|
|
|
aabb_transform_affine(const Aabb& aabb, const Matrix4& m)
|
|
|
|
{
|
|
|
|
GB_ASSERT(math::is_affine(m),
|
2015-10-05 16:30:55 -04:00
|
|
|
"Passed Matrix4 must be an affine matrix");
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
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;
|
2015-10-03 10:26:29 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
// Sphere Functions
|
2015-10-05 13:17:30 -04:00
|
|
|
inline Sphere
|
|
|
|
calculate_min_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step)
|
|
|
|
{
|
2015-10-05 16:58:47 -04:00
|
|
|
auto gen = random::make_mt19937_64(random::next(random::make_random_device()));
|
2015-10-05 13:17:30 -04:00
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* vertex = reinterpret_cast<const u8*>(vertices);
|
2015-10-05 13:17:30 -04:00
|
|
|
vertex += offset;
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
Vector3 position = pseudo_cast<Vector3>(vertex[0]);
|
2015-10-05 13:17:30 -04:00
|
|
|
Vector3 center = position;
|
2015-10-05 16:30:55 -04:00
|
|
|
center += pseudo_cast<Vector3>(vertex[1 * stride]);
|
2015-10-05 13:17:30 -04:00
|
|
|
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 (usize i = 0, index = random::uniform_usize_distribution(gen, 0, num_vertices-1);
|
2015-10-05 16:30:55 -04:00
|
|
|
i < num_vertices;
|
|
|
|
i++, index = (index + 1)%num_vertices)
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
Vector3 position = pseudo_cast<Vector3>(vertex[index * stride]);
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Sphere
|
|
|
|
calculate_max_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset)
|
|
|
|
{
|
|
|
|
Aabb aabb = calculate_aabb(vertices, num_vertices, stride, offset);
|
|
|
|
|
|
|
|
Vector3 center = aabb.center;
|
|
|
|
|
|
|
|
f32 max_dist_sq = 0.0f;
|
2015-10-05 16:30:55 -04:00
|
|
|
const u8* vertex = reinterpret_cast<const u8*>(vertices);
|
2015-10-05 13:17:30 -04:00
|
|
|
vertex += offset;
|
|
|
|
|
|
|
|
for (usize i = 0; i < num_vertices; i++)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
Vector3 position = pseudo_cast<Vector3>(vertex);
|
2015-10-05 13:17:30 -04:00
|
|
|
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
|
|
|
|
sphere_surface_area(const Sphere& s)
|
|
|
|
{
|
2015-10-05 16:58:47 -04:00
|
|
|
return 2.0f * TAU * s.radius * s.radius;
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
2015-10-03 10:26:29 -04:00
|
|
|
inline f32
|
|
|
|
sphere_volume(const Sphere& s)
|
|
|
|
{
|
|
|
|
return TWO_THIRDS * TAU * s.radius * s.radius * s.radius;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
inline Aabb
|
|
|
|
sphere_to_aabb(const Sphere& s)
|
|
|
|
{
|
2015-10-05 16:58:47 -04:00
|
|
|
Aabb a;
|
|
|
|
a.center = s.center;
|
|
|
|
a.half_size.x = s.radius * SQRT_3;
|
|
|
|
a.half_size.y = s.radius * SQRT_3;
|
|
|
|
a.half_size.z = s.radius * SQRT_3;
|
|
|
|
return a;
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
2015-10-03 10:26:29 -04:00
|
|
|
|
|
|
|
inline bool
|
|
|
|
sphere_contains_point(const Sphere& s, const Vector3& point)
|
|
|
|
{
|
|
|
|
Vector3 dr = point - s.center;
|
|
|
|
f32 distance = math::dot(dr, dr);
|
|
|
|
return distance < s.radius * s.radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plane Functions
|
|
|
|
inline f32
|
|
|
|
ray_plane_intersection(const Vector3& from, const Vector3& dir, const 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 f32
|
|
|
|
ray_sphere_intersection(const Vector3& from, const Vector3& dir, const 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
|
|
|
|
{
|
|
|
|
const Vector3& n1 = p1.normal;
|
|
|
|
const Vector3& n2 = p2.normal;
|
|
|
|
const Vector3& n3 = p3.normal;
|
|
|
|
|
|
|
|
f32 den = -math::dot(math::cross(n1, n2), n3);
|
|
|
|
|
|
|
|
if (math::equals(den, 0.0f))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Vector3 res = p1.distance * math::cross(n2, n3)
|
2015-10-05 16:30:55 -04:00
|
|
|
+ p2.distance * math::cross(n3, n1)
|
|
|
|
+ p3.distance * math::cross(n1, n2);
|
2015-10-03 10:26:29 -04:00
|
|
|
ip = res / den;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-27 14:03:47 -04:00
|
|
|
} // namespace math
|
2015-10-05 13:17:30 -04:00
|
|
|
|
|
|
|
namespace random
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Mt19937_32::Result_Type
|
|
|
|
Mt19937_32::next()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
if (index >= 624)
|
|
|
|
{
|
|
|
|
for (u32 i = 0; i < 624; i++)
|
|
|
|
{
|
2015-10-05 16:30:55 -04:00
|
|
|
s32 y = ((mt[i] & 0x80000000) + (mt[(i + 1) % 624] & 0x7fffffff)) & 0xffffffff;
|
2015-10-05 13:17:30 -04:00
|
|
|
mt[i] = mt[(i + 397) % 624] ^ y >> 1;
|
|
|
|
|
|
|
|
if (y % 2 != 0)
|
|
|
|
mt[i] = mt[i] ^ 0x9908b0df;
|
|
|
|
}
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 y = mt[index];
|
|
|
|
|
|
|
|
y ^= (y >> 11);
|
|
|
|
y ^= (y << 7) & 2636928640;
|
|
|
|
y ^= (y << 15) & 4022730752;
|
|
|
|
y ^= (y >> 18);
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::entropy()
|
|
|
|
{
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
|
|
|
Mt19937_32::next_u32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s32 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<u32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline s32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::next_s32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
return next();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::next_u64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s32 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 a = n;
|
2015-10-05 13:17:30 -04:00
|
|
|
a = (u64)(a << 32) | (u64)next();
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline s64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::next_s64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s32 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 a = n;
|
2015-10-05 13:17:30 -04:00
|
|
|
a = (u64)(a << 32) | (u64)next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s64>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::next_f32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s32 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<f32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline f64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_32::next_f64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s32 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
u64 a = n;
|
2015-10-05 13:17:30 -04:00
|
|
|
a = (u64)(a << 32) | (u64)next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<f64>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
inline Mt19937_64::Result_Type
|
|
|
|
Mt19937_64::next()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
local_persist u64 mag01[2] = {0ull, 0xB5026F5AA96619E9ull};
|
|
|
|
|
|
|
|
u64 x;
|
|
|
|
if (index > 312)
|
|
|
|
{
|
|
|
|
u32 i = 0;
|
|
|
|
for (; i < 312-156; i++)
|
|
|
|
{
|
|
|
|
x = (mt[i] & 0xffffffff80000000ull) | (mt[i+1] & 0x7fffffffull);
|
|
|
|
mt[i] = mt[i+156] ^ (x>>1) ^ mag01[(u32)(x & 1ull)];
|
|
|
|
}
|
|
|
|
for (; i < 312-1; i++)
|
|
|
|
{
|
|
|
|
x = (mt[i] & 0xffffffff80000000ull) | (mt[i+1] & 0x7fffffffull);
|
|
|
|
mt[i] = mt[i + (312-156)] ^ (x >> 1) ^ mag01[(u32)(x & 1ull)];
|
|
|
|
}
|
|
|
|
x = (mt[312-1] & 0xffffffff80000000ull) | (mt[0] & 0x7fffffffull);
|
|
|
|
mt[312-1] = mt[156-1] ^ (x>>1) ^ mag01[(u32)(x & 1ull)];
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = mt[index++];
|
|
|
|
|
|
|
|
x ^= (x >> 29) & 0x5555555555555555ull;
|
|
|
|
x ^= (x << 17) & 0x71d67fffeda60000ull;
|
|
|
|
x ^= (x << 37) & 0xfff7eee000000000ull;
|
|
|
|
x ^= (x >> 43);
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
|
|
|
Mt19937_64::entropy()
|
|
|
|
{
|
|
|
|
return 64;
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_u32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<u32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline s32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_s32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<s32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_u64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<u64>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline s64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_s64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_f32()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<f32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline f64
|
2015-10-05 16:30:55 -04:00
|
|
|
Mt19937_64::next_f64()
|
2015-10-05 13:17:30 -04:00
|
|
|
{
|
|
|
|
s64 n = next();
|
2015-10-05 16:30:55 -04:00
|
|
|
return pseudo_cast<f64>(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Random_Device::Result_Type
|
|
|
|
Random_Device::next()
|
|
|
|
{
|
|
|
|
u32 result = 0;
|
2015-10-05 16:58:47 -04:00
|
|
|
// IMPORTANT TODO(bill): Implenent Random_Device::next()
|
2015-10-05 16:30:55 -04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
|
|
|
Random_Device::entropy()
|
|
|
|
{
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32
|
|
|
|
Random_Device::next_u32()
|
|
|
|
{
|
|
|
|
s32 n = next();
|
|
|
|
return pseudo_cast<u32>(n);
|
2015-10-05 13:17:30 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 16:30:55 -04:00
|
|
|
inline s32
|
|
|
|
Random_Device::next_s32()
|
|
|
|
{
|
|
|
|
return next();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u64
|
|
|
|
Random_Device::next_u64()
|
|
|
|
{
|
|
|
|
s32 n = next();
|
|
|
|
u64 a = n;
|
|
|
|
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline s64
|
|
|
|
Random_Device::next_s64()
|
|
|
|
{
|
|
|
|
s32 n = next();
|
|
|
|
u64 a = n;
|
|
|
|
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
|
|
|
|
return pseudo_cast<s64>(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
|
|
|
Random_Device::next_f32()
|
|
|
|
{
|
|
|
|
s32 n = next();
|
|
|
|
return pseudo_cast<f32>(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f64
|
|
|
|
Random_Device::next_f64()
|
|
|
|
{
|
|
|
|
s32 n = next();
|
|
|
|
u64 a = n;
|
|
|
|
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
|
|
|
|
return pseudo_cast<f64>(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-05 13:17:30 -04:00
|
|
|
} // namespace random
|
2015-09-27 14:03:47 -04:00
|
|
|
} // namespace gb
|
|
|
|
|
|
|
|
#endif // GB_IMPLEMENTATION
|