diff options
| author | 2015-10-28 18:32:42 +0000 | |
|---|---|---|
| committer | 2015-10-28 18:32:42 +0000 | |
| commit | 816e2592578f51533930cedc269b151224abf57b (patch) | |
| tree | 8c9b13feb1355371e7ea632d0aea0d45e68cfdd7 /gb.hpp | |
| parent | gb.hpp - All References are const convention (diff) | |
gb.hpp - Reduction of implicit RAII
Diffstat (limited to 'gb.hpp')
| -rw-r--r-- | gb.hpp | 1560 |
1 files changed, 1117 insertions, 443 deletions
@@ -3,6 +3,7 @@ /* Version History: + 0.17 - Death to OOP 0.16 - All References are const convention 0.15 - Namespaced Types 0.14 - Casts and Quaternion Look At @@ -44,11 +45,13 @@ Context: - Memory - Mutex - Atomics - - Functions + - Semaphore + - Thread - Allocator - Heap Allocator - Arena Allocator - Temporary Arena Memory + - Functions - String - Array - Hash Table @@ -171,30 +174,16 @@ Context: #define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1)) -#include <float.h> #include <math.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> #include <stdio.h> -#if defined(GB_SYSTEM_WINDOWS) - #define _CRT_RAND_S - #include <stdlib.h> - #undef _CRT_RAND_S -#else - #include <stdlib.h> -#endif -#include <string.h> -#include <time.h> - #if !defined(GB_HAS_NO_CONSTEXPR) #if defined(_GNUC_VER) && _GNUC_VER < 406 // Less than gcc 4.06 - #define GB_HAS_NO_CONSTEXPR + #define GB_HAS_NO_CONSTEXPR 1 #elif defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015/MSVC++ 14.0 - #define GB_HAS_NO_CONSTEXPR + #define GB_HAS_NO_CONSTEXPR 1 #elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L - #define GB_HAS_NO_CONSTEXPR + #define GB_HAS_NO_CONSTEXPR 1 #endif #endif @@ -204,13 +193,11 @@ Context: #define GB_CONSTEXPR constexpr #endif - - #ifndef GB_FORCE_INLINE #if defined(_MSC_VER) #define GB_FORCE_INLINE __forceinline #else - #define __attribute__ ((__always_inline__)) + #define GB_FORCE_INLINE __attribute__ ((__always_inline__)) #endif #endif @@ -235,12 +222,25 @@ Context: #include <sys/time.h> #endif -#ifndef NDEBUG +#if !defined(NDEBUG) #define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__))) #else #define GB_ASSERT(x, ...) ((void)sizeof(x)) #endif +#if !defined(GB_ARRAY_BOUND_CHECKING) +#define GB_ARRAY_BOUND_CHECKING 1 +#endif + + +extern "C" inline void +gb__abort(void) +{ + // TODO(bill): Get a better way to abort + *(int*)0 = 0; + // raise(SIGABRT); +} + /// Helper function used as a better alternative to assert which allows for /// optional printf style error messages extern "C" inline void @@ -262,8 +262,7 @@ gb__assert_handler(bool condition, const char* condition_str, va_end(args); } fprintf(stderr, "\n"); - - abort(); // TODO(bill): is abort() portable and good? + gb__abort(); } //////////////////////////////// @@ -327,21 +326,33 @@ __GB_NAMESPACE_START /// /// //////////////////////////////// -using u8 = uint8_t; -using s8 = int8_t; -using u16 = uint16_t; -using s16 = int16_t; -using u32 = uint32_t; -using s32 = int32_t; + #if defined(_MSC_VER) - using s64 = signed __int64; + using u8 = unsigned __int8; + using s8 = signed __int8; + using u16 = unsigned __int16; + using s16 = signed __int16; + using u32 = unsigned __int32; + using s32 = signed __int32; using u64 = unsigned __int64; + using s64 = signed __int64; #else - using s64 = int64_t; - using u64 = uint64_t; + using u8 = unsigned char; + using s8 = signed char; + using u16 = unsigned short; + using s16 = signed short; + using u32 = unsigned int; + using s32 = signed int; + using u64 = unsigned long long; + using s64 = signed long long; #endif +static_assert( sizeof(u8) == 1, "u8 is not 8 bits"); +static_assert(sizeof(u16) == 2, "u16 is not 16 bits"); +static_assert(sizeof(u32) == 4, "u32 is not 32 bits"); +static_assert(sizeof(u64) == 8, "u64 is not 64 bits"); + using f32 = float; using f64 = double; @@ -400,17 +411,17 @@ using ptrdiff = ptrdiff_t; #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_USIZE_MIX GB_U64_MIN + #define GB_USIZE_MAX GB_U64_MAX - #define GB_SSIZE_MIX S64_MIN - #define GB_SSIZE_MAX S64_MAX + #define GB_SSIZE_MIX GB_S64_MIN + #define GB_SSIZE_MAX GB_S64_MAX #elif defined(GB_ARCH_32_BIT) - #define GB_USIZE_MIX U32_MIN - #define GB_USIZE_MAX U32_MAX + #define GB_USIZE_MIX GB_U32_MIN + #define GB_USIZE_MAX GB_U32_MAX - #define GB_SSIZE_MIX S32_MIN - #define GB_SSIZE_MAX S32_MAX + #define GB_SSIZE_MIX GB_S32_MIN + #define GB_SSIZE_MAX GB_S32_MAX #endif #if defined(GB_BASIC_WITHOUT_NAMESPACE) @@ -477,7 +488,7 @@ template <> struct Add_Lvalue_Reference_Def<void> { using Type = 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> 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&; }; @@ -550,15 +561,15 @@ namespace impl template <typename Func> struct Defer { - Func func; + Func f; - Defer(Func&& func) : func{__GB_NAMESPACE_PREFIX::forward<Func>(func)} {} - ~Defer() { func(); }; + Defer(Func&& f) : f{forward<Func>(f)} {} + ~Defer() { f(); }; }; template <typename Func> Defer<Func> -defer_func(Func&& func) { return Defer<Func>(__GB_NAMESPACE_PREFIX::forward<Func>(func)); } +defer_func(Func&& f) { return Defer<Func>(forward<Func>(f)); } } // namespace impl __GB_NAMESPACE_END @@ -568,7 +579,6 @@ __GB_NAMESPACE_END #define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__) #define defer(code) auto GB_DEFER_3(_defer_) = __GB_NAMESPACE_PREFIX::impl::defer_func([&](){code;}) - #if !defined(GB_CASTS_WITHOUT_NAMESPACE) __GB_NAMESPACE_START #endif // GB_CASTS_WITHOUT_NAMESPACE @@ -618,13 +628,12 @@ struct Mutex #else pthread_mutex_t posix_mutex; #endif - - Mutex(); - ~Mutex(); }; namespace mutex { +Mutex make(); +void destroy(Mutex* mutex); void lock(Mutex* mutex); bool try_lock(Mutex* mutex); void unlock(Mutex* mutex); @@ -636,23 +645,71 @@ struct Atomic64 { u64 nonatomic; }; namespace atomic { -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); +// TODO(bill): Should these functions have suffixes or is the overloading fine? +u32 load(const Atomic32* object); +void store(Atomic32* object, u32 value); +u32 compare_exchange_strong(Atomic32* object, u32 expected, u32 desired); +u32 exchanged(Atomic32* object, u32 desired); +u32 fetch_add(Atomic32* object, s32 operand); +u32 fetch_and(Atomic32* object, u32 operand); +u32 fetch_or(Atomic32* object, u32 operand); + +u64 load(const Atomic64* object); +void store(Atomic64* object, u64 value); +u64 compare_exchange_strong(Atomic64* object, u64 expected, u64 desired); +u64 exchanged(Atomic64* object, u64 desired); +u64 fetch_add(Atomic64* object, s64 operand); +u64 fetch_and(Atomic64* object, u64 operand); +u64 fetch_or(Atomic64* object, u64 operand); } // namespace atomic +struct Semaphore +{ +#if defined(GB_SYSTEM_WINDOWS) + HANDLE win32_handle; +#else + Mutex mutex; + pthread_cond_t cond; + s32 count; +#endif +}; + +namespace semaphore +{ +Semaphore make(); +void destroy(Semaphore* semaphore); +void post(Semaphore* semaphore, u32 count = 1); +void wait(Semaphore* semaphore); +} // namespace semaphore + +using Thread_Function = s32(void*); + +struct Thread +{ +#if defined(GB_SYSTEM_WINDOWS) + HANDLE win32_handle; +#else + pthread_t posix_handle; +#endif + + Thread_Function* function; + void* data; + + Semaphore semaphore; + usize stack_size; + b32 is_running; +}; + +namespace thread +{ +Thread make(); +void destroy(Thread* thread); +void start(Thread* thread, Thread_Function* func, void* data = nullptr, usize stack_size = 0); +void stop(Thread* thread); +bool is_running(const Thread& thread); +} // namespace thread + + /// Default alignment for memory allocations #ifndef GB_DEFAULT_ALIGNMENT #if defined(GB_ARCH_32_BIT) @@ -698,9 +755,9 @@ struct Heap_Allocator : Allocator s64 size; }; - Mutex mutex = Mutex{}; - s64 total_allocated_count = 0; - s64 allocation_count = 0; + Mutex mutex = mutex::make(); + s64 total_allocated_count = 0; + s64 allocation_count = 0; Heap_Allocator() = default; virtual ~Heap_Allocator(); @@ -760,20 +817,20 @@ struct Temp_Allocator : Allocator namespace memory { void* align_forward(void* ptr, usize align); - void* pointer_add( void* ptr, usize bytes); +void* pointer_add(void* ptr, usize bytes); +void* pointer_sub(void* ptr, usize bytes); const void* pointer_add(const void* ptr, usize bytes); - void* pointer_sub( void* ptr, usize bytes); const void* pointer_sub(const void* ptr, usize bytes); void* set(void* ptr, u8 value, usize bytes); void* zero(void* ptr, usize bytes); void* copy(void* dest, const void* src, usize bytes); void* move(void* dest, const void* src, usize bytes); -bool compare(const void* a, const void* b, usize bytes); +bool equals(const void* a, const void* b, usize bytes); } // namespace memory -inline void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT) { GB_ASSERT(a); return a->alloc(size, align); } -inline void dealloc(Allocator* a, const void* ptr) { GB_ASSERT(a); return a->dealloc(ptr); } +inline void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT) { GB_ASSERT(a != nullptr); return a->alloc(size, align); } +inline void dealloc(Allocator* a, const void* ptr) { GB_ASSERT(a != nullptr); return a->dealloc(ptr); } template <typename T> inline T* alloc_struct(Allocator* a) { return static_cast<T*>(alloc(a, sizeof(T), alignof(T))); } @@ -927,12 +984,11 @@ move(void* dest, const void* src, usize bytes) } inline bool -compare(const void* a, const void* b, usize bytes) +equals(const void* a, const void* b, usize bytes) { return (memcmp(a, b, bytes) == 0); } - } // namespace memory //////////////////////////////// @@ -961,7 +1017,7 @@ inline Header* header(String str) { return (Header*)str - 1; } String make(Allocator* a, const char* str = ""); String make(Allocator* a, const void* str, Size len); -void free(String* str); +void free(String str); String duplicate(Allocator* a, const String str); @@ -979,11 +1035,40 @@ void make_space_for(String* str, Size add_len); usize allocation_size(const String str); bool equals(const String lhs, const String rhs); +int compare(const String lhs, const String rhs); // NOTE(bill): three-way comparison void trim(String* str, const char* cut_set); } // namespace string // TODO(bill): string libraries +namespace strconv +{ +// Inspired by the golang strconv library but not exactly due to numerous reasons +// TODO(bill): Should this use gb::String or just plain old C Strings? +bool parse_bool(const char* str, bool* value); + +bool parse_f32(const char* str, f32* value); +bool parse_f64(const char* str, f64* value); + +bool parse_int(const char* str, int base, s8* value); +bool parse_int(const char* str, int base, s16* value); +bool parse_int(const char* str, int base, s32* value); +bool parse_int(const char* str, int base, s64* value); + +bool parse_uint(const char* str, int base, u8* value); +bool parse_uint(const char* str, int base, u16* value); +bool parse_uint(const char* str, int base, u32* value); +bool parse_uint(const char* str, int base, u64* value); + +void format_bool(bool value, char* buffer, usize len); + +void format_f32(f32 value, char* buffer, usize len); +void format_f64(f64 value, char* buffer, usize len); + +void format_int(s64 value, char* buffer, usize len); +void format_uint(u64 value, char* buffer, usize len); +} // namespace strconv + //////////////////////////////// /// /// /// Array /// @@ -1005,9 +1090,23 @@ struct Array ~Array(); Array& operator=(const Array& array); + inline const T& + operator[](usize index) const + { +#if GB_ARRAY_BOUND_CHECKING + GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds"); +#endif + return data[index]; + } - const T& operator[](usize index) const { return data[index]; } - T& operator[](usize index) { return data[index]; } + inline T& + operator[](usize index) + { +#if GB_ARRAY_BOUND_CHECKING + GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds"); +#endif + return data[index]; + } }; namespace array @@ -1095,9 +1194,9 @@ template <typename T> typename const Hash_Table<T>::Entry* end(const Hash_Table< namespace multi_hash_table { /// Outputs all the items that with the specified key -template <typename T> void get_multiple(const Hash_Table<T>& h, u64 key, Array<T>& items); +template <typename T> void get(const Hash_Table<T>& h, u64 key, Array<T>& items); /// Returns the count of entries with the specified key -template <typename T> usize multiple_count(const Hash_Table<T>& h, u64 key); +template <typename T> usize count(const Hash_Table<T>& h, u64 key); /// Finds the first entry with specified key in the hash table template <typename T> typename const Hash_Table<T>::Entry* find_first(const Hash_Table<T>& h, u64 key); @@ -1111,6 +1210,9 @@ template <typename T> void remove_entry(Hash_Table<T>* h, typename const Hash_Ta /// Removes all entries with from the hash table with the specified key template <typename T> void remove_all(Hash_Table<T>* h, u64 key); } // namespace multi_hash_table + + + //////////////////////////////// /// /// /// Array /// @@ -1135,6 +1237,7 @@ Array<T>::Array(Allocator* a, usize count_) template <typename T> +inline Array<T>::Array(const Array<T>& other) : allocator(other.allocator) , count(0) @@ -1148,7 +1251,8 @@ Array<T>::Array(const Array<T>& other) } template <typename T> -inline Array<T>::~Array() +inline +Array<T>::~Array() { if (allocator) dealloc(allocator, data); @@ -1209,7 +1313,7 @@ inline void append(Array<T>* a, const T* items, usize count) { if (a->capacity <= a->count + count) - grow(a, a->count + count); + array::grow(a, a->count + count); memory::copy(&a->data[a->count], items, count * sizeof(T)); a->count += count; @@ -1295,6 +1399,7 @@ Hash_Table<T>::Hash_Table(Allocator* a) } template <typename T> +inline Hash_Table<T>::Hash_Table(const Hash_Table<T>& other) : hashes(other.hashes) , entries(other.entries) @@ -1595,7 +1700,7 @@ namespace multi_hash_table { template <typename T> inline void -get_multiple(const Hash_Table<T>& h, u64 key, Array<T>& items) +get(const Hash_Table<T>& h, u64 key, Array<T>& items) { auto e = multi_hash_table::find_first(h, key); while (e) @@ -1607,7 +1712,7 @@ get_multiple(const Hash_Table<T>& h, u64 key, Array<T>& items) template <typename T> inline usize -multiple_count(const Hash_Table<T>& h, u64 key) +count(const Hash_Table<T>& h, u64 key) { usize count = 0; auto e = multi_hash_table::find_first(h, key); @@ -1720,16 +1825,19 @@ extern const Time TIME_ZERO; // NOTE(bill): namespace time cannot be used for numerous reasons -Time time_now(); -void time_sleep(Time time); +namespace time +{ +Time now(); +void sleep(Time time); Time seconds(f32 s); Time milliseconds(s32 ms); Time microseconds(s64 us); -f32 time_as_seconds(Time t); -s32 time_as_milliseconds(Time t); -s64 time_as_microseconds(Time t); +f32 as_seconds(Time t); +s32 as_milliseconds(Time t); +s64 as_microseconds(Time t); +} // namespace time bool operator==(Time left, Time right); bool operator!=(Time left, Time right); @@ -1768,12 +1876,69 @@ Time operator%(Time left, Time right); Time& operator%=(Time& left, Time right); + + +//////////////////////////////// +/// /// +/// OS /// +/// /// +//////////////////////////////// + +#if 0 +// TODO(bill): still in development +struct File +{ +#if defined(GB_SYSTEM_WINDOWS) + HANDLE win32_handle; + Mutex mutex; + + char* name; // TODO(bill): uses malloc + + b32 is_console; +#else + #error Implement file system +#endif +}; + +namespace file +{ +enum Flag : u32 +{ + READ = 0x1, + WRITE = 0x2, +}; + +uintptr fd(const File* file); + +bool new_from_fd(File* file, uintptr fd, const char* name); + +bool open(File* file, const char* filename, u32 flag, u32 perm); +bool close(File* file); + +bool create(File* file, const char* filename, u32 flag); + +bool read(File* file, void* buffer, u32 bytes_to_read); +bool write(File* file, const void* memory, u32 bytes_to_write); + +bool read_at(File* file, void* buffer, u32 bytes_to_read, s64 offset); +bool write_at(File* file, const void* memory, u32 bytes_to_write, s64 offset); + +s64 size(File* file); + +bool set_pos(File* file, s64 pos); +bool get_pos(File* file, s64* pos); +} // namespace file +#endif + + //////////////////////////////// /// /// /// Math Types /// /// /// //////////////////////////////// +// TODO(bill): Should the math part be a separate library? + struct Vector2 { union @@ -1855,7 +2020,6 @@ struct Matrix2 inline Vector2& operator[](usize index) { return columns[index]; } }; - struct Matrix3 { union @@ -2102,7 +2266,6 @@ extern const Transform TRANSFORM_IDENTITY; namespace math { -extern const f32 EPSILON; extern const f32 ZERO; extern const f32 ONE; extern const f32 THIRD; @@ -2185,7 +2348,7 @@ T lerp(const T& x, const T& y, f32 t); bool equals(f32 a, f32 b, f32 precision = F32_PRECISION); template <typename T> -void swap(T& a, T& b); +void swap(T* a, T* b); template <typename T, usize N> void swap(T (& a)[N], T (& b)[N]); @@ -2309,40 +2472,48 @@ Vector3 transform_point(const Transform& transform, const Vector3& point); Transform inverse(const Transform& t); Matrix4 transform_to_matrix4(const Transform& t); -// Aabb Functions -Aabb calculate_aabb(const void* vertices, usize num_vertices, usize stride, usize offset); +f32 perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap = 0, s32 y_wrap = 0, s32 z_wrap = 0); +} // namespace math + +namespace aabb +{ +Aabb calculate(const void* vertices, usize num_vertices, usize stride, usize offset); -f32 aabb_surface_area(const Aabb& aabb); -f32 aabb_volume(const Aabb& aabb); +f32 surface_area(const Aabb& aabb); +f32 volume(const Aabb& aabb); -Sphere aabb_to_sphere(const Aabb& aabb); +Sphere to_sphere(const Aabb& aabb); 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); +Aabb transform_affine(const Aabb& aabb, const Matrix4& m); +} // namespace aabb -// Sphere Functions +namespace sphere +{ 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); -f32 sphere_volume(const Sphere& s); +f32 surface_area(const Sphere& s); +f32 volume(const Sphere& s); + +Aabb to_aabb(const Sphere& sphere); -Aabb sphere_to_aabb(const Sphere& sphere); +bool contains_point(const Sphere& s, const Vector3& point); -bool sphere_contains_point(const Sphere& s, const Vector3& point); +f32 ray_intersection(const Vector3& from, const Vector3& dir, const Sphere& s); +} // namespace sphere -// 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); +namespace plane +{ +f32 ray_intersection(const Vector3& from, const Vector3& dir, const Plane& p); -bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip); +bool intersection3(const Plane& p1, const Plane& p2, const Plane& p3, Vector3* ip); +} // namespace plane -f32 perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap = 0, s32 y_wrap = 0, s32 z_wrap = 0); -} // namespace math namespace random { @@ -2442,7 +2613,7 @@ Random_Device make_random_device(); void set_seed(Mt19937_32* gen, Mt19937_32::Seed_Type seed); void set_seed(Mt19937_64* gen, Mt19937_64::Seed_Type seed); -template <typename Generator> typename Generator::Result_Type next(Generator& gen); +template <typename Generator> typename Generator::Result_Type next(Generator* gen); 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); @@ -2506,8 +2677,6 @@ next(Generator* gen) return gen->next(); } - - template <typename Generator> inline s32 uniform_s32_distribution(Generator* gen, s32 min_inc, s32 max_inc) @@ -2530,7 +2699,6 @@ 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) @@ -2663,51 +2831,56 @@ __GB_NAMESPACE_START /// /// //////////////////////////////// -Mutex::Mutex() +namespace mutex +{ +Mutex +make() { + Mutex m = {}; #if defined(GB_SYSTEM_WINDOWS) - win32_mutex = CreateMutex(0, 0, 0); + m.win32_mutex = CreateMutex(0, false, 0); #else - pthread_mutex_init(&posix_mutex, nullptr); + pthread_mutex_init(&m.posix_mutex, nullptr); #endif + return m; } -Mutex::~Mutex() +void +destroy(Mutex* m) { #if defined(GB_SYSTEM_WINDOWS) - CloseHandle(win32_mutex); + CloseHandle(m->win32_mutex); #else - pthread_mutex_destroy(&posix_mutex); + pthread_mutex_destroy(&m->posix_mutex); #endif } -namespace mutex -{ -void lock(Mutex& mutex) + +void lock(Mutex* m) { #if defined(GB_SYSTEM_WINDOWS) - WaitForSingleObject(mutex.win32_mutex, INFINITE); + WaitForSingleObject(m->win32_mutex, INFINITE); #else - pthread_mutex_lock(&mutex.posix_mutex); + pthread_mutex_lock(&m->posix_mutex); #endif } -bool try_lock(Mutex& mutex) +bool try_lock(Mutex* m) { #if defined(GB_SYSTEM_WINDOWS) - return WaitForSingleObject(mutex.win32_mutex, 0) == WAIT_OBJECT_0; + return WaitForSingleObject(m->win32_mutex, 0) == WAIT_OBJECT_0; #else - return pthread_mutex_trylock(&mutex.posix_mutex) == 0; + return pthread_mutex_trylock(&m->posix_mutex) == 0; #endif } -void unlock(Mutex& mutex) +void unlock(Mutex* m) { #if defined(GB_SYSTEM_WINDOWS) - ReleaseMutex(mutex.win32_mutex); + ReleaseMutex(m->win32_mutex); #else - pthread_mutex_unlock(&mutex.posix_mutex); + pthread_mutex_unlock(&m->posix_mutex); #endif } } // namespace mutex @@ -2717,49 +2890,49 @@ namespace atomic { #if defined(_MSC_VER) inline u32 -load_32_relaxed(const Atomic32* object) +load(const Atomic32* object) { return object->nonatomic; } inline void -store_32_relaxed(Atomic32* object, u32 value) +store(Atomic32* object, u32 value) { object->nonatomic = value; } inline u32 -compare_exchange_strong_32_relaxed(Atomic32* object, u32 expected, u32 desired) +compare_exchange_strong(Atomic32* object, u32 expected, u32 desired) { return _InterlockedCompareExchange(reinterpret_cast<long*>(object), desired, expected); } inline u32 -exchanged_32_relaxed(Atomic32* object, u32 desired) +exchanged(Atomic32* object, u32 desired) { return _InterlockedExchange(reinterpret_cast<long*>(object), desired); } inline u32 -fetch_add_32_relaxed(Atomic32* object, s32 operand) +fetch_add(Atomic32* object, s32 operand) { return _InterlockedExchangeAdd(reinterpret_cast<long*>(object), operand); } inline u32 -fetch_and_32_relaxed(Atomic32* object, u32 operand) +fetch_and(Atomic32* object, u32 operand) { return _InterlockedAnd(reinterpret_cast<long*>(object), operand); } inline u32 -fetch_or_32_relaxed(Atomic32* object, u32 operand) +fetch_or_32(Atomic32* object, u32 operand) { return _InterlockedOr(reinterpret_cast<long*>(object), operand); } inline u64 -load_64_relaxed(const Atomic64* object) +load(const Atomic64* object) { #if defined(GB_ARCH_64_BIT) return object->nonatomic; @@ -2780,7 +2953,7 @@ load_64_relaxed(const Atomic64* object) } inline void -store_64_relaxed(Atomic64* object, u64 value) +store(Atomic64* object, u64 value) { #if defined(GB_ARCH_64_BIT) object->nonatomic = value; @@ -2799,13 +2972,13 @@ store_64_relaxed(Atomic64* object, u64 value) } inline u64 -compare_exchange_strong_64_relaxed(Atomic64* object, u64 expected, u64 desired) +compare_exchange_strong(Atomic64* object, u64 expected, u64 desired) { _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), desired, expected); } inline u64 -exchanged_64_relaxed(Atomic64* object, u64 desired) +exchanged(Atomic64* object, u64 desired) { #if defined(GB_ARCH_64_BIT) return _InterlockedExchange64(reinterpret_cast<s64*>(object), desired); @@ -2822,7 +2995,7 @@ exchanged_64_relaxed(Atomic64* object, u64 desired) } inline u64 -fetch_add_64_relaxed(Atomic64* object, s64 operand) +fetch_add(Atomic64* object, s64 operand) { #if defined(GB_ARCH_64_BIT) return _InterlockedExchangeAdd64(reinterpret_cast<s64*>(object), operand); @@ -2839,7 +3012,7 @@ fetch_add_64_relaxed(Atomic64* object, s64 operand) } inline u64 -fetch_and_64_relaxed(Atomic64* object, u64 operand) +fetch_and(Atomic64* object, u64 operand) { #if defined(GB_ARCH_64_BIT) return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand); @@ -2856,7 +3029,7 @@ fetch_and_64_relaxed(Atomic64* object, u64 operand) } inline u64 -fetch_or_64_relaxed(Atomic64* object, u64 operand) +fetch_or(Atomic64* object, u64 operand) { #if defined(GB_ARCH_64_BIT) return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand); @@ -2877,6 +3050,206 @@ fetch_or_64_relaxed(Atomic64* object, u64 operand) #endif } // namespace atomic +namespace semaphore +{ +Semaphore +make() +{ + Semaphore semaphore = {}; +#if defined(GB_SYSTEM_WINDOWS) + semaphore.win32_handle = CreateSemaphore(nullptr, 0, GB_S32_MAX, nullptr); + GB_ASSERT(semaphore.win32_handle != nullptr, "CreateSemaphore: GetLastError = %d", GetLastError()); + +#else + semaphore.count = 0; + s32 result = pthread_cond_init(&semaphore.cond, nullptr); + GB_ASSERT(result == 0, "pthread_cond_init: errno = %d", result); + + semaphore.mutex = mutex::make(); +#endif + + return semaphore; +} + +void +destroy(Semaphore* semaphore) +{ +#if defined(GB_SYSTEM_WINDOWS) + BOOL err = CloseHandle(semaphore->win32_handle); + GB_ASSERT(err != 0, "CloseHandle: GetLastError = %d", GetLastError()); +#else + s32 result = pthread_cond_destroy(&semaphore->cond); + GB_ASSERT(result == 0, "pthread_cond_destroy: errno = %d", result); + mutex::destroy(&semaphore->mutex); +#endif +} + +void +post(Semaphore* semaphore, u32 count) +{ +#if defined(GB_SYSTEM_WINDOWS) + BOOL err = ReleaseSemaphore(semaphore->win32_handle, count, nullptr); + GB_ASSERT(err != 0, "ReleaseSemaphore: GetLastError = %d", GetLastError()); +#else + mutex::lock(semaphore->mutex); + defer (mutex::unlock(semaphore->mutex)); + + for (u32 i = 0; i < count; i++) + { + s32 result = pthread_cond_signal(&semaphore->cond); + GB_ASSERT(result == 0, "pthread_cond_signal: errno = %d", result); + } + + semaphore->count += count; +#endif +} + +void +wait(Semaphore* semaphore) +{ +#if defined(GB_SYSTEM_WINDOWS) + DWORD result = WaitForSingleObject(semaphore->win32_handle, INFINITE); + GB_ASSERT(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError = %d", GetLastError()); +#else + mutex::lock(semaphore->mutex); + defer (mutex::unlock(semaphore->mutex)); + + while (count <= 0) + { + s32 result = pthread_cond_wait(&semaphore->cond, &semaphore->mutex.posix_mutex); + GB_ASSERT(result == 0, "pthread_cond_wait: errno = %d", result); + } + + count--; +#endif +} +} // namespace semaphore + +namespace thread +{ +Thread +make() +{ + Thread thread = {}; +#if defined(GB_SYSTEM_WINDOWS) + thread.win32_handle = INVALID_HANDLE_VALUE; +#else + thread.posix_handle = 0; +#endif + thread.function = nullptr; + thread.data = nullptr; + thread.stack_size = 0; + thread.is_running = false; + thread.semaphore = semaphore::make(); + + return thread; +} + +void +destroy(Thread* thread) +{ + if (thread->is_running) + thread::stop(thread); + + semaphore::destroy(&thread->semaphore); +} + +internal s32 +run(Thread* thread) +{ + semaphore::post(&thread->semaphore); + return thread->function(thread->data); +} + +#if defined(GB_SYSTEM_WINDOWS) +internal DWORD WINAPI +thread_proc(void* arg) +{ + Thread* thread = static_cast<Thread*>(arg); + s32 result = thread::run(thread); + return result; +} + +#else +internal void* +thread_proc(void* arg) +{ + local_persist s32 result = -1; + result = thread::run(static_cast<Thread*>(arg)); + return (void*)&result; +} + +#endif + +void +start(Thread* thread, Thread_Function* func, void* data, usize stack_size) +{ + GB_ASSERT(!thread->is_running); + GB_ASSERT(func != nullptr); + thread->function = func; + thread->data = data; + thread->stack_size = stack_size; + +#if defined(GB_SYSTEM_WINDOWS) + thread->win32_handle = CreateThread(nullptr, stack_size, thread_proc, thread, 0, nullptr); + GB_ASSERT(thread->win32_handle != nullptr, + "CreateThread: GetLastError = %d", GetLastError()); + +#else + pthread_attr_t attr; + s32 result = pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + GB_ASSERT(result == 0, "pthread_attr_init: errno = %d", result); + + if (thread->stack_size != 0) + { + result = pthread_attr_setstacksize(&attr, thread->stack_size); + GB_ASSERT(result == 0, "pthread_attr_setstacksize: errno = %d", result); + } + + result = pthread_create(&thread->posix_handle, &attr, thread_proc, thread); + GB_ASSERT(result == 0, "pthread_create: errno = %d", result); + + // NOTE(bill): Free attr memory + result = pthread_attr_destroy(&attr); + GB_ASSERT(result == 0, "pthread_attr_destroy: errno = %d", result); + + // NOTE(bill): So much boiler patch compared to windows.h (for once) +#endif + + thread->is_running = true; + semaphore::wait(&thread->semaphore); +} + +void +stop(Thread* thread) +{ + if (!thread->is_running) + return; + +#if defined(GB_SYSTEM_WINDOWS) + WaitForSingleObject(thread->win32_handle, INFINITE); + CloseHandle(thread->win32_handle); + thread->win32_handle = INVALID_HANDLE_VALUE; +#else + +#endif + + thread->is_running = false; +} + +bool +is_running(const Thread& thread) +{ + return thread.is_running != 0; +} +} // namespace thread + + + + + + #define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1) Heap_Allocator::~Heap_Allocator() { @@ -2890,8 +3263,8 @@ Heap_Allocator::~Heap_Allocator() void* Heap_Allocator::alloc(usize size, usize align) { - mutex::lock(mutex); - defer (mutex::unlock(mutex)); + mutex::lock(&mutex); + defer (mutex::unlock(&mutex)); const usize total = size + align + sizeof(Header); Header* h = static_cast<Header*>(::malloc(total)); @@ -2916,8 +3289,8 @@ Heap_Allocator::dealloc(const void* ptr) if (!ptr) return; - mutex::lock(mutex); - defer (mutex::unlock(mutex)); + mutex::lock(&mutex); + defer (mutex::unlock(&mutex)); Header* h = get_header_ptr(ptr); @@ -2931,8 +3304,8 @@ Heap_Allocator::dealloc(const void* ptr) s64 Heap_Allocator::allocated_size(const void* ptr) { - mutex::lock(mutex); - defer (mutex::unlock(mutex)); + mutex::lock(&mutex); + defer (mutex::unlock(&mutex)); return get_header_ptr(ptr)->size; } @@ -3037,17 +3410,17 @@ String make(Allocator* a, const void* init_str, Size len) return str; } -void free(String& str) +void free(String str) { if (str == nullptr) return; string::Header* h = string::header(str); Allocator* a = h->allocator; - if (a) dealloc(a, h); - str = nullptr; + if (a) + dealloc(a, h); } -String duplicate_string(Allocator* a, const String str) +String duplicate(Allocator* a, const String str) { return string::make(a, str, string::length(str)); } @@ -3126,7 +3499,8 @@ string_realloc(Allocator* a, void* ptr, usize old_size, usize new_size) } } // namespace impl -void make_space_for(String* str, Size add_len) +void +make_space_for(String* str, Size add_len) { Size len = string::length(*str); Size new_len = len + add_len; @@ -3148,13 +3522,15 @@ void make_space_for(String* str, Size add_len) string::header(*str)->cap = new_len; } -usize allocation_size(const String str) +usize +allocation_size(const String str) { Size cap = string::capacity(str); return sizeof(string::Header) + cap; } -bool equals(const String lhs, const String rhs) +bool +equals(const String lhs, const String rhs) { Size lhs_len = string::length(lhs); Size rhs_len = string::length(rhs); @@ -3170,15 +3546,36 @@ bool equals(const String lhs, const String rhs) return true; } -void trim(String& str, const char* cut_set) +int +compare(const String lhs, const String rhs) // NOTE(bill): three-way comparison +{ + // Treat as cstring + const char* str1 = lhs; + const char* str2 = rhs; + int s1; + int s2; + do + { + s1 = *str1++; + s2 = *str2++; + if (s1 == 0) + break; + } + while (s1 == s2); + + return (s1 < s2) ? -1 : (s1 > s2); +} + +void +trim(String* str, 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; + start_pos = start = *str; + end_pos = end = *str + string::length(*str) - 1; while (start_pos <= end && strchr(cut_set, *start_pos)) start_pos++; @@ -3187,14 +3584,186 @@ void trim(String& str, const char* cut_set) Size len = static_cast<Size>((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); - if (str != start_pos) - memory::move(str, start_pos, len); - str[len] = '\0'; + if (*str != start_pos) + memory::move(*str, start_pos, len); + (*str)[len] = '\0'; - string::header(str)->len = len; + string::header(*str)->len = len; } } // namespace string + + + +namespace strconv +{ +// NOTE(bill): Inspired by the golang strconv library but not exactly due to numerous reasons + +bool +parse_bool(const char* str, bool* value) +{ + if (str == nullptr) + return false; + + if (str[0] == '\0') + return false; + + if (str[0] == '1' || + str[0] == 't' || + str[0] == 'T') + { + *value = true; + return true; + } + if (str[0] == '0' || + str[0] == 'f' || + str[0] == 'F') + { + *value = false; + return true; + } + if ((str[0] == 't' && + str[1] == 'r' && + str[2] == 'u' && + str[3] == 'e') || + (str[0] == 'T' && + str[1] == 'R' && + str[2] == 'U' && + str[3] == 'E')) + { + *value = true; + return true; + } + + if ((str[0] == 'f' && + str[1] == 'a' && + str[2] == 'l' && + str[3] == 's' && + str[4] == 'e') || + (str[0] == 'F' && + str[1] == 'A' && + str[2] == 'L' && + str[3] == 'S' && + str[4] == 'E')) + { + *value = false; + return true; + } + + return false; +} + +bool +parse_f32(const char* str, f32* value) +{ + // TODO(bill): + return false; +} + +bool +parse_f64(const char* str, f64* value) +{ + // TODO(bill): + return false; +} + +bool +parse_int(const char* str, int base, s8* value) +{ + // TODO(bill): + return false; +} + +bool +parse_int(const char* str, int base, s16* value) +{ + // TODO(bill): + return false; +} + +bool +parse_int(const char* str, int base, s32* value) +{ + // TODO(bill): + return false; +} + +bool +parse_int(const char* str, int base, s64* value) +{ + // TODO(bill): + return false; +} + +bool +parse_uint(const char* str, int base, u8* value) +{ + // TODO(bill): + return false; +} + +bool +parse_uint(const char* str, int base, u16* value) +{ + // TODO(bill): + return false; +} + +bool +parse_uint(const char* str, int base, u32* value) +{ + // TODO(bill): + return false; +} + +bool +parse_uint(const char* str, int base, u64* value) +{ + // TODO(bill): + return false; +} + +void +format_bool(bool value, char* buffer, usize len) +{ + // TODO(bill): +} + +void +format_f32(f32 value, char* buffer, usize len) +{ + // TODO(bill): +} + +void +format_f64(f64 value, char* buffer, usize len) +{ + // TODO(bill): +} + +void +format_int(s64 value, char* buffer, usize len) +{ + // TODO(bill): +} + +void +format_uint(u64 value, char* buffer, usize len) +{ + // TODO(bill): +} +} // namespace strconv + + + + + + + + + + + //////////////////////////////// /// /// /// Hash /// @@ -3203,7 +3772,8 @@ void trim(String& str, const char* cut_set) namespace hash { -u32 adler32(const void* key, u32 num_bytes) +u32 +adler32(const void* key, u32 num_bytes) { const u32 MOD_ADLER = 65521; @@ -3355,7 +3925,8 @@ global const u64 GB_CRC64_TABLE[256] = { }; -u32 crc32(const void* key, u32 num_bytes) +u32 +crc32(const void* key, u32 num_bytes) { u32 result = static_cast<u32>(~0); const u8* c = reinterpret_cast<const u8*>(key); @@ -3365,9 +3936,10 @@ u32 crc32(const void* key, u32 num_bytes) return ~result; } -u64 crc64(const void* key, usize num_bytes) +u64 +crc64(const void* key, usize num_bytes) { - u64 result = (u64)~0; + u64 result = static_cast<u64>(~0); const u8* c = reinterpret_cast<const u8*>(key); for (usize remaining = num_bytes; remaining--; c++) result = (result >> 8) ^ (GB_CRC64_TABLE[(result ^ *c) & 0xff]); @@ -3395,7 +3967,8 @@ u64 crc64(const void* key, usize num_bytes) // } -u32 murmur32(const void* key, u32 num_bytes, u32 seed) +u32 +murmur32(const void* key, u32 num_bytes, u32 seed) { local_persist const u32 c1 = 0xcc9e2d51; local_persist const u32 c2 = 0x1b873593; @@ -3446,7 +4019,8 @@ u32 murmur32(const void* key, u32 num_bytes, u32 seed) } #if defined(GB_ARCH_64_BIT) -u64 murmur64(const void* key, usize num_bytes, u64 seed) +u64 +murmur64(const void* key, usize num_bytes, u64 seed) { local_persist const u64 m = 0xc6a4a7935bd1e995ULL; local_persist const s32 r = 47; @@ -3472,13 +4046,13 @@ u64 murmur64(const void* key, usize num_bytes, u64 seed) switch (num_bytes & 7) { - case 7: h ^= u64{data2[6]} << 48; - case 6: h ^= u64{data2[5]} << 40; - case 5: h ^= u64{data2[4]} << 32; - case 4: h ^= u64{data2[3]} << 24; - case 3: h ^= u64{data2[2]} << 16; - case 2: h ^= u64{data2[1]} << 8; - case 1: h ^= u64{data2[0]}; + case 7: h ^= static_cast<u64>(data2[6]) << 48; + case 6: h ^= static_cast<u64>(data2[5]) << 40; + case 5: h ^= static_cast<u64>(data2[4]) << 32; + case 4: h ^= static_cast<u64>(data2[3]) << 24; + case 3: h ^= static_cast<u64>(data2[2]) << 16; + case 2: h ^= static_cast<u64>(data2[1]) << 8; + case 1: h ^= static_cast<u64>(data2[0]); h *= m; }; @@ -3489,7 +4063,8 @@ u64 murmur64(const void* key, usize num_bytes, u64 seed) return h; } #elif GB_ARCH_32_BIT -u64 murmur64(const void* key, usize num_bytes, u64 seed) +u64 +murmur64(const void* key, usize num_bytes, u64 seed) { local_persist const u32 m = 0x5bd1e995; local_persist const s32 r = 24; @@ -3563,8 +4138,10 @@ u64 murmur64(const void* key, usize num_bytes, u64 seed) /// /// //////////////////////////////// -const Time TIME_ZERO = seconds(0); +const Time TIME_ZERO = time::seconds(0); +namespace time +{ #if defined(GB_SYSTEM_WINDOWS) internal LARGE_INTEGER @@ -3575,7 +4152,8 @@ win32_get_frequency() return f; } -Time time_now() +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. @@ -3597,10 +4175,11 @@ Time time_now() // Restore the thread affinity SetThreadAffinityMask(currentThread, previousMask); - return microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart); + return time::microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart); } -void time_sleep(Time t) +void +sleep(Time t) { if (t.microseconds <= 0) return; @@ -3612,14 +4191,15 @@ void time_sleep(Time t) timeBeginPeriod(tc.wPeriodMin); // Wait... - ::Sleep(time_as_milliseconds(t)); + ::Sleep(time::as_milliseconds(t)); // Reset the timer resolution back to the system default timeBeginPeriod(tc.wPeriodMin); } #else -Time time_now() +Time +now() { #if defined(GB_SYSTEM_OSX) s64 t = static_cast<s64>(mach_absolute_time()); @@ -3632,14 +4212,15 @@ Time time_now() #endif } -void time_sleep(Time t) +void +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); + spec.tv_sec = static_cast<s64>(as_seconds(t)); + spec.tv_nsec = 1000ll * (as_microseconds(t) % 1000000ll); nanosleep(&spec, nullptr); } @@ -3649,131 +4230,221 @@ void time_sleep(Time t) Time seconds(f32 s) { return {static_cast<s64>(s * 1000000ll)}; } Time milliseconds(s32 ms) { return {static_cast<s64>(ms * 1000l)}; } Time microseconds(s64 us) { return {us}; } -f32 time_as_seconds(Time t) { return static_cast<f32>(t.microseconds / 1000000.0f); } -s32 time_as_milliseconds(Time t) { return static_cast<s32>(t.microseconds / 1000l); } -s64 time_as_microseconds(Time t) { return t.microseconds; } +f32 as_seconds(Time t) { return static_cast<f32>(t.microseconds / 1000000.0f); } +s32 as_milliseconds(Time t) { return static_cast<s32>(t.microseconds / 1000l); } +s64 as_microseconds(Time t) { return t.microseconds; } +} // namespace time +bool operator==(Time left, Time right) { return left.microseconds == right.microseconds; } +bool operator!=(Time left, Time right) { return !operator==(left, right); } -bool operator==(Time left, Time right) -{ - return left.microseconds == right.microseconds; -} +bool operator<(Time left, Time right) { return left.microseconds < right.microseconds; } +bool operator>(Time left, Time right) { return left.microseconds > right.microseconds; } -bool operator!=(Time left, Time right) -{ - return !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; } +Time operator-(Time right) { return {-right.microseconds}; } -bool 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.microseconds - right.microseconds}; } -bool 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); } -bool operator<=(Time left, Time right) -{ - return left.microseconds <= right.microseconds; -} +Time operator*(Time left, f32 right) { return time::seconds(time::as_seconds(left) * right); } +Time operator*(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) * right); } +Time operator*(f32 left, Time right) { return time::seconds(time::as_seconds(right) * left); } +Time operator*(s64 left, Time right) { return time::microseconds(time::as_microseconds(right) * left); } -bool operator>=(Time left, Time right) -{ - return left.microseconds >= right.microseconds; -} +Time& operator*=(Time& left, f32 right) { return (left = left * right); } +Time& operator*=(Time& left, s64 right) { return (left = left * right); } -Time operator-(Time right) -{ - return {-right.microseconds}; -} +Time operator/(Time left, f32 right) { return time::seconds(time::as_seconds(left) / right); } +Time operator/(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) / right); } +f32 operator/(Time left, Time right) { return time::as_seconds(left) / time::as_seconds(right); } -Time operator+(Time left, Time right) -{ - return {left.microseconds + right.microseconds}; -} +Time& operator/=(Time& left, f32 right) { return (left = left / right); } +Time& operator/=(Time& left, s64 right) { return (left = left / right); } -Time operator-(Time left, Time right) -{ - return {left.microseconds - right.microseconds}; -} -Time& operator+=(Time& left, Time right) -{ - return (left = left + right); -} +Time operator%(Time left, Time right) { return time::microseconds(time::as_microseconds(left) % time::as_microseconds(right)); } +Time& operator%=(Time& left, Time right) { return (left = left % right); } -Time& operator-=(Time& left, Time right) +//////////////////////////////// +/// /// +/// OS /// +/// /// +//////////////////////////////// +#if 0 +namespace file { - return (left = left - right); -} +#if defined(GB_SYSTEM_WINDOWS) -Time operator*(Time left, f32 right) +internal char* +duplicate_string(const char* string) { - return seconds(time_as_seconds(left) * right); + usize len = strlen(string); + char* result = (char*)malloc(len + 1); + memory::copy(result, string, len); + result[len] = '\0'; + return result; } -Time operator*(Time left, s64 right) -{ - return microseconds(time_as_microseconds(left) * right); -} -Time operator*(f32 left, Time right) +uintptr +fd(const File* file) { - return seconds(time_as_seconds(right) * left); + if (file == nullptr) + return reinterpret_cast<uintptr>(INVALID_HANDLE_VALUE); + return reinterpret_cast<uintptr>(file->win32_handle); } -Time operator*(s64 left, Time right) -{ - return microseconds(time_as_microseconds(right) * left); -} -Time& operator*=(Time& left, f32 right) +bool +new_from_fd(File* file, uintptr h, const char* name) { - return (left = left * right); + GB_ASSERT(file == nullptr, "file == nullptr"); + if (reinterpret_cast<HANDLE>(h) == INVALID_HANDLE_VALUE) + return false; + file->win32_handle = reinterpret_cast<HANDLE>(h); + file->name = duplicate_string(name); + // u32 m; + // file->is_console = GetConsoleMode(h, &m) != 0; + return true; } -Time& operator*=(Time& left, s64 right) +internal bool +win32_open_file(File* file, const char* name, u32 flag, u32 perm) { - return (left = left * right); + // TODO(bill): + return false; } -Time operator/(Time left, f32 right) +bool +open(File* file, const char* name, u32 flag, u32 perm) { - return seconds(time_as_seconds(left) / right); + if (name == nullptr || name[0] == '\0') { + return false; + } + bool b = win32_open_file(file, name, flag, perm); + if (b) + { + file->mutex = mutex::make(); + return true; + } + // TODO(bill): If directory + + return false; } -Time operator/(Time left, s64 right) +bool +close(File* file) { - return microseconds(time_as_microseconds(left) / right); + if (!file) + return false; -} + // TODO(bill): Handle directory -Time& operator/=(Time& left, f32 right) -{ - return (left = left / right); -} + bool b = CloseHandle(file->win32_handle) != 0; + if (b) + { + free(file->name); // TODO(bill): When should this be freed? + mutex::destroy(&file->mutex); + return true; + } -Time& operator/=(Time& left, s64 right) -{ - return (left = left / right); + return false; } -f32 operator/(Time left, Time right) -{ - return time_as_seconds(left) / time_as_seconds(right); -} +// internal bool +// win32_pread(File* file, void* buffer, u32 bytes_to_read, s64 offset) +// { +// mutex::lock(&file->mutex); +// defer (mutex::unlock(&file->mutex)); -Time operator%(Time left, Time right) -{ - return microseconds(time_as_microseconds(left) % time_as_microseconds(right)); -} +// return true; +// } + + +// bool +// open(File* file, const char* filename, u32 flags) +// { + +// u32 win32_flags = 0; +// if (flags & file::READ) +// win32_flags |= GENERIC_READ; +// if (flags & file::WRITE) +// win32_flags |= GENERIC_WRITE; + +// file->win32_handle = CreateFileA(filename, win32_flags, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0); +// return (file->win32_handle != INVALID_HANDLE_VALUE); +// } + +// bool +// create(File* file, const char* filename, u32 flags) +// { +// // TODO(bill): +// return false; +// } + +// bool +// close(File* file) +// { +// return (CloseHandle(file->win32_handle) != 0); +// } + + +// bool +// read(File* file, void* buffer, u32 bytes_to_read) +// { +// DWORD win32_bytes_written; +// BOOL b = ReadFile(file->win32_handle, buffer, bytes_to_read, &win32_bytes_written, nullptr); +// if (!b || (bytes_to_read != win32_bytes_written)) +// return false; +// return true; +// } + +// bool +// write(File* file, const void* memory, u32 bytes_to_write) +// { +// DWORD win32_bytes_written; +// BOOL b = WriteFile(file->win32_handle, memory, bytes_to_write, &win32_bytes_written, nullptr); +// if (!b || (bytes_to_write != win32_bytes_written)) +// return false; +// return true; +// } + +// bool read_at(File* file, void* buffer, u32 bytes_to_read, s64 offset) +// { +// file::set_pos(file, offset); +// bool b = read(file, buffer, bytes_to_reads); +// return b; +// } + +// bool write_at(File* file, const void* memory, u32 bytes_to_write, s64 offset) +// { +// file::set_pos(file, offset); +// bool b = write(file, memory, bytes_to_write); +// return b; +// } + + +// s64 +// size(File* file) +// { +// LARGE_INTEGER file_size; +// BOOL b = GetFileSizeEx(file->win32_handle, &file_size); +// if (b) +// return static_cast<s64>(file_size.QuadPart); +// return -1; +// } -Time& operator%=(Time& left, Time right) -{ - return (left = left % right); -} + +#else + #error Implement file system +#endif +} // namespace file +#endif //////////////////////////////// /// /// @@ -4507,7 +5178,6 @@ Transform& operator/=(Transform& ws, const Transform& ps) namespace math { -const f32 EPSILON = FLT_EPSILON; const f32 ZERO = 0.0f; const f32 ONE = 1.0f; const f32 THIRD = 0.33333333f; @@ -4681,11 +5351,11 @@ equals(f32 a, f32 b, f32 precision) template <typename T> inline void -swap(T& a, T& b) +swap(T* a, T* b) { - T c = gb::move(a); - a = gb::move(b); - b = gb::move(c); + T c = gb::move(*a); + *a = gb::move(*b); + *b = gb::move(c); } template <typename T, usize N> @@ -4693,7 +5363,7 @@ inline void swap(T (& a)[N], T (& b)[N]) { for (usize i = 0; i < N; i++) - math::swap(a[i], b[i]); + math::swap(&a[i], &b[i]); } // Vector2 functions @@ -5534,7 +6204,7 @@ look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up) if (math::equals(math::magnitude(center - eye), 0, 0.001f)) return QUATERNION_IDENTITY; // You cannot look at where you are! -#if 0 +#if 1 return matrix4_to_quaternion(look_at_matrix4(eye, center, up)); #else // TODO(bill): Thoroughly test this look_at_quaternion! @@ -5594,9 +6264,132 @@ transform_to_matrix4(const Transform& t) } -// Aabb Functions +global s32 g_perlin_randtab[512] = +{ + 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, + 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, + 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, + 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, + 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, + 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, + 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, + 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, + 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, + 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, + 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, + 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, + 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, + 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, + 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, + 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, + +// Copy + 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, + 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, + 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, + 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, + 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, + 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, + 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, + 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, + 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, + 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, + 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, + 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, + 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, + 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, + 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, + 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, +}; + + +internal f32 +perlin_grad(s32 hash, f32 x, f32 y, f32 z) +{ + local_persist f32 basis[12][4] = + { + { 1, 1, 0}, + {-1, 1, 0}, + { 1,-1, 0}, + {-1,-1, 0}, + { 1, 0, 1}, + {-1, 0, 1}, + { 1, 0,-1}, + {-1, 0,-1}, + { 0, 1, 1}, + { 0,-1, 1}, + { 0, 1,-1}, + { 0,-1,-1}, + }; + + local_persist u8 indices[64] = + { + 0,1,2,3,4,5,6,7,8,9,10,11, + 0,9,1,11, + 0,1,2,3,4,5,6,7,8,9,10,11, + 0,1,2,3,4,5,6,7,8,9,10,11, + 0,1,2,3,4,5,6,7,8,9,10,11, + 0,1,2,3,4,5,6,7,8,9,10,11, + }; + + f32* grad = basis[indices[hash & 63]]; + return grad[0]*x + grad[1]*y + grad[2]*z; +} + + +inline f32 +perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap, s32 y_wrap, s32 z_wrap) +{ + u32 x_mask = (x_wrap-1) & 255; + u32 y_mask = (y_wrap-1) & 255; + u32 z_mask = (z_wrap-1) & 255; + s32 px = (s32)math::floor(x); + s32 py = (s32)math::floor(y); + s32 pz = (s32)math::floor(z); + s32 x0 = px & x_mask, x1 = (px+1) & x_mask; + s32 y0 = py & y_mask, y1 = (py+1) & y_mask; + s32 z0 = pz & z_mask, z1 = (pz+1) & z_mask; + +#define GB__PERLIN_EASE(t) (((t*6-15)*t + 10) *t*t*t) + x -= px; f32 u = GB__PERLIN_EASE(x); + y -= py; f32 v = GB__PERLIN_EASE(y); + z -= pz; f32 w = GB__PERLIN_EASE(z); +#undef GB__PERLIN_EASE + + s32 r0 = g_perlin_randtab[x0]; + s32 r1 = g_perlin_randtab[x1]; + + s32 r00 = g_perlin_randtab[r0+y0]; + s32 r01 = g_perlin_randtab[r0+y1]; + s32 r10 = g_perlin_randtab[r1+y0]; + s32 r11 = g_perlin_randtab[r1+y1]; + + f32 n000 = perlin_grad(g_perlin_randtab[r00+z0], x , y , z ); + f32 n001 = perlin_grad(g_perlin_randtab[r00+z1], x , y , z-1 ); + f32 n010 = perlin_grad(g_perlin_randtab[r01+z0], x , y-1, z ); + f32 n011 = perlin_grad(g_perlin_randtab[r01+z1], x , y-1, z-1 ); + f32 n100 = perlin_grad(g_perlin_randtab[r10+z0], x-1, y , z ); + f32 n101 = perlin_grad(g_perlin_randtab[r10+z1], x-1, y , z-1 ); + f32 n110 = perlin_grad(g_perlin_randtab[r11+z0], x-1, y-1, z ); + f32 n111 = perlin_grad(g_perlin_randtab[r11+z1], x-1, y-1, z-1 ); + + f32 n00 = math::lerp(n000,n001,w); + f32 n01 = math::lerp(n010,n011,w); + f32 n10 = math::lerp(n100,n101,w); + f32 n11 = math::lerp(n110,n111,w); + + f32 n0 = math::lerp(n00,n01,v); + f32 n1 = math::lerp(n10,n11,v); + + return math::lerp(n0,n1,u); +} +} // namespace math + + +namespace aabb +{ inline Aabb -calculate_aabb(const void* vertices, usize num_vertices, usize stride, usize offset) +calculate(const void* vertices, usize num_vertices, usize stride, usize offset) { Vector3 min; Vector3 max; @@ -5631,7 +6424,7 @@ calculate_aabb(const void* vertices, usize num_vertices, usize stride, usize off } inline f32 -aabb_surface_area(const Aabb& aabb) +surface_area(const Aabb& aabb) { Vector3 h = aabb.half_size * 2.0f; f32 s = 0.0f; @@ -5643,14 +6436,14 @@ aabb_surface_area(const Aabb& aabb) } inline f32 -aabb_volume(const Aabb& aabb) +volume(const Aabb& aabb) { Vector3 h = aabb.half_size * 2.0f; return h.x * h.y * h.z; } inline Sphere -aabb_to_sphere(const Aabb& aabb) +to_sphere(const Aabb& aabb) { Sphere s; s.center = aabb.center; @@ -5695,7 +6488,7 @@ intersects(const Aabb& a, const Aabb& b) } inline Aabb -aabb_transform_affine(const Aabb& aabb, const Matrix4& m) +transform_affine(const Aabb& aabb, const Matrix4& m) { GB_ASSERT(math::is_affine(m), "Passed Matrix4 must be an affine matrix"); @@ -5717,11 +6510,12 @@ aabb_transform_affine(const Aabb& aabb, const Matrix4& m) return result; } +} // namespace aabb - -// Sphere Functions +namespace sphere +{ inline Sphere -calculate_min_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step) +calculate_min_bounding(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step) { auto ran_gen = random::make_random_device(); auto gen = random::make_mt19937_64(random::next(&ran_gen)); @@ -5773,9 +6567,9 @@ calculate_min_bounding_sphere(const void* vertices, usize num_vertices, usize st } inline Sphere -calculate_max_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset) +calculate_max_bounding(const void* vertices, usize num_vertices, usize stride, usize offset) { - Aabb aabb = calculate_aabb(vertices, num_vertices, stride, offset); + Aabb aabb = aabb::calculate(vertices, num_vertices, stride, offset); Vector3 center = aabb.center; @@ -5801,39 +6595,53 @@ calculate_max_bounding_sphere(const void* vertices, usize num_vertices, usize st } inline f32 -sphere_surface_area(const Sphere& s) +surface_area(const Sphere& s) { - return 2.0f * TAU * s.radius * s.radius; + return 2.0f * math::TAU * s.radius * s.radius; } inline f32 -sphere_volume(const Sphere& s) +volume(const Sphere& s) { - return TWO_THIRDS * TAU * s.radius * s.radius * s.radius; + return math::TWO_THIRDS * math::TAU * s.radius * s.radius * s.radius; } inline Aabb -sphere_to_aabb(const Sphere& s) +to_aabb(const Sphere& s) { 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; + a.half_size.x = s.radius * math::SQRT_3; + a.half_size.y = s.radius * math::SQRT_3; + a.half_size.z = s.radius * math::SQRT_3; return a; } inline bool -sphere_contains_point(const Sphere& s, const Vector3& point) +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) +ray_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); +} +} // namespace sphere + +namespace plane +{ +inline f32 +ray_intersection(const Vector3& from, const Vector3& dir, const Plane& p) { f32 nd = math::dot(dir, p.normal); f32 orpn = math::dot(from, p.normal); @@ -5845,20 +6653,8 @@ ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p) 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) +intersection3(const Plane& p1, const Plane& p2, const Plane& p3, Vector3* ip) { const Vector3& n1 = p1.normal; const Vector3& n2 = p2.normal; @@ -5872,133 +6668,11 @@ plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& Vector3 res = p1.distance * math::cross(n2, n3) + p2.distance * math::cross(n3, n1) + p3.distance * math::cross(n1, n2); - ip = res / den; + *ip = res / den; return true; } - -global s32 g_perlin_randtab[512] = -{ - 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, - 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, - 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, - 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, - 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, - 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, - 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, - 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, - 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, - 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, - 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, - 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, - 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, - 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, - 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, - 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, - -// Copy - 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, - 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, - 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, - 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, - 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, - 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, - 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, - 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, - 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, - 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, - 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, - 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, - 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, - 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, - 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, - 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, -}; - - -internal f32 -perlin_grad(s32 hash, f32 x, f32 y, f32 z) -{ - local_persist f32 basis[12][4] = - { - { 1, 1, 0}, - {-1, 1, 0}, - { 1,-1, 0}, - {-1,-1, 0}, - { 1, 0, 1}, - {-1, 0, 1}, - { 1, 0,-1}, - {-1, 0,-1}, - { 0, 1, 1}, - { 0,-1, 1}, - { 0, 1,-1}, - { 0,-1,-1}, - }; - - local_persist u8 indices[64] = - { - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,9,1,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - }; - - f32* grad = basis[indices[hash & 63]]; - return grad[0]*x + grad[1]*y + grad[2]*z; -} - - -inline f32 -perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap, s32 y_wrap, s32 z_wrap) -{ - u32 x_mask = (x_wrap-1) & 255; - u32 y_mask = (y_wrap-1) & 255; - u32 z_mask = (z_wrap-1) & 255; - s32 px = (s32)math::floor(x); - s32 py = (s32)math::floor(y); - s32 pz = (s32)math::floor(z); - s32 x0 = px & x_mask, x1 = (px+1) & x_mask; - s32 y0 = py & y_mask, y1 = (py+1) & y_mask; - s32 z0 = pz & z_mask, z1 = (pz+1) & z_mask; - -#define GB__PERLIN_EASE(t) (((t*6-15)*t + 10) *t*t*t) - x -= px; f32 u = GB__PERLIN_EASE(x); - y -= py; f32 v = GB__PERLIN_EASE(y); - z -= pz; f32 w = GB__PERLIN_EASE(z); -#undef GB__PERLIN_EASE - - s32 r0 = g_perlin_randtab[x0]; - s32 r1 = g_perlin_randtab[x1]; - - s32 r00 = g_perlin_randtab[r0+y0]; - s32 r01 = g_perlin_randtab[r0+y1]; - s32 r10 = g_perlin_randtab[r1+y0]; - s32 r11 = g_perlin_randtab[r1+y1]; - - f32 n000 = perlin_grad(g_perlin_randtab[r00+z0], x , y , z ); - f32 n001 = perlin_grad(g_perlin_randtab[r00+z1], x , y , z-1 ); - f32 n010 = perlin_grad(g_perlin_randtab[r01+z0], x , y-1, z ); - f32 n011 = perlin_grad(g_perlin_randtab[r01+z1], x , y-1, z-1 ); - f32 n100 = perlin_grad(g_perlin_randtab[r10+z0], x-1, y , z ); - f32 n101 = perlin_grad(g_perlin_randtab[r10+z1], x-1, y , z-1 ); - f32 n110 = perlin_grad(g_perlin_randtab[r11+z0], x-1, y-1, z ); - f32 n111 = perlin_grad(g_perlin_randtab[r11+z1], x-1, y-1, z-1 ); - - f32 n00 = math::lerp(n000,n001,w); - f32 n01 = math::lerp(n010,n011,w); - f32 n10 = math::lerp(n100,n101,w); - f32 n11 = math::lerp(n110,n111,w); - - f32 n0 = math::lerp(n00,n01,v); - f32 n1 = math::lerp(n10,n11,v); - - return math::lerp(n0,n1,u); -} - - -} // namespace math +} // namespace plane namespace random { @@ -6050,7 +6724,7 @@ Mt19937_32::next_u64() { s32 n = next(); u64 a = n; - a = (u64)(a << 32) | (u64)next(); + a = static_cast<u64>(a << 32) | static_cast<u64>(next()); return a; } @@ -6059,7 +6733,7 @@ Mt19937_32::next_s64() { s32 n = next(); u64 a = n; - a = (u64)(a << 32) | (u64)next(); + a = static_cast<u64>(a << 32) | static_cast<u64>(next()); return bit_cast<s64>(a); } @@ -6075,7 +6749,7 @@ Mt19937_32::next_f64() { s32 n = next(); u64 a = n; - a = (u64)(a << 32) | (u64)next(); + a = static_cast<u64>(a << 32) | static_cast<u64>(next()); return bit_cast<f64>(a); } @@ -6164,7 +6838,7 @@ Random_Device::next() { u32 result = 0; #if defined(GB_SYSTEM_WINDOWS) -// rand_s(&result); // TODO(bill): fix this + // rand_s(&result); // TODO(bill): fix this #else #error Implement Random_Device::next() for this platform #endif |
