diff --git a/base.cpp b/base.cpp deleted file mode 100644 index 28b13c8..0000000 --- a/base.cpp +++ /dev/null @@ -1,1244 +0,0 @@ -#define NOMINMAX -#define _CRT_SECURE_NO_WARNINGS -#include - -#include -#include -typedef int8_t S8; -typedef int16_t S16; -typedef int32_t S32; -typedef int64_t S64; -typedef uint8_t U8; -typedef uint16_t U16; -typedef uint32_t U32; -typedef uint64_t U64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef U64 SizeU; -typedef S64 SizeS; -typedef float F32; -typedef double F64; - -#define U64MAX UINT64_MAX -#define U32MAX UINT32_MAX -#define U16MAX UINT16_MAX -#define U8MAX UINT8_MAX -#define U64MIN 0 -#define U32MIN 0 -#define U16MIN 0 -#define U8MIN 0 -#define S64MAX INT64_MAX -#define S64MIN INT64_MIN -#define S32MAX INT32_MAX -#define S32MIN INT32_MIN -#define S16MAX INT16_MAX -#define S16MIN INT16_MIN -#define S8MAX INT8_MAX -#define S8MIN INT8_MIN -#define F32MAX FLT_MAX -#define F32MIN FLT_MIN -#define F64MAX DBL_MAX -#define F64MIN DBL_MIN - -#define api -#define function -#define global -#define force_inline __forceinline -#define assert(x) do{if(!(x))__debugbreak();}while(0) -#define assert_msg(x,...) assert(x) -#define invalid_codepath assert_msg(0, "Invalid codepath") -#define invalid_return do{assert_msg(0, "Invalid codepath"); return {};}while(0) -#define invalid_default_case default: invalid_codepath -#define not_implemented assert_msg(0, "Not implemented") -#define unused(x) ((void)x) -#define buff_cap(x) (sizeof(x)/sizeof((x)[0])) -#define is_flag_set(val,flag) ((val) & (flag)) -#define set_flag(val,flag) ((val) |= (flag)) -#define unset_flag(val,flag) ((val) &= (~(flag))) -#define bit_flag(x) (1ull << (x)) -#define kib(x) ((x)*1024llu) -#define mib(x) (kib(x)*1024llu) -#define gib(x) (mib(x)*1024llu) -#define JOIN1(X,Y) X##Y // helper macro -#define JOIN(X,Y) JOIN1(X,Y) -#define string_expand(x) (int)x.len, x.str - -#define FLAG32(x) typedef U32 x; enum - -#if defined(__clang__) -# define COMPILER_CLANG 1 -# if defined(_WIN32) -# define OS_WINDOWS 1 -# elif defined(__linux__) -# define OS_LINUX 1 -# else -# error Couldnt figure out the platform automatically -# endif -#elif defined(_MSC_VER) -# define COMPILER_MSVC 1 -# define OS_WINDOWS 1 -#elif defined(__GNUC__) -# define COMPILER_GCC 1 -# if defined(__linux__) -# define OS_LINUX 1 -# endif -#else -# error Couldnt figure out the compiler -#endif - -#if !defined(COMPILER_MSVC) -# define COMPILER_MSVC 0 -#endif -#if !defined(COMPILER_GCC) -# define COMPILER_GCC 0 -#endif -#if !defined(COMPILER_CLANG) -# define COMPILER_CLANG 0 -#endif -#if !defined(OS_WINDOWS) -# define OS_WINDOWS 0 -#endif -#if !defined(OS_LINUX) -# define OS_LINUX 0 -#endif -#if !defined(OS_MAC) -# define OS_MAC 0 -#endif - -struct String{ - U8 *str; - S64 len; -}; - -union Intern_String{ // Basically just String - String s; - struct{ U8 *str; S64 len; }; -}; - -global String string_null = {(U8 *)"null", 4}; -#include -#define STB_SPRINTF_IMPLEMENTATION -#include "stb_sprintf.h" -#define snprintf stbsp_snprintf - - -union Vec2 { - struct { F32 x, y; }; - struct { F32 width, height; }; - F32 p[2]; -}; - -union Vec3 { - struct{ F32 x, y, z; }; - struct{ F32 r, g, b; }; - struct{ Vec2 xy; F32 z_; }; - struct{ F32 x_; Vec2 yz; }; - F32 p[3]; -}; - -union Vec4 { - struct{ F32 x, y, z, w; }; - struct{ F32 r, g, b, a; }; - struct{ Vec2 xy; Vec2 zw; }; - struct{ Vec2 xy_; F32 width, height; }; - struct{ Vec3 xyz; F32 w_; }; - struct{ F32 x_; Vec3 yzw; }; - struct{ Vec3 rgb; F32 a_; }; - F32 p[4]; -}; - -struct Mat4 { - F32 p[4][4]; -}; - -union Vec1I { - S32 x; - S32 p[1]; -}; - -union Vec2I { - struct { S32 x, y; }; - struct { S32 width, height; }; - S32 p[2]; -}; - -union Vec3I { - struct { S32 x, y, z; }; - struct { S32 r, g, b; }; - struct { Vec2I xy; S32 z_; }; - struct { S32 x_; Vec2I yz; }; - S32 p[3]; -}; - -union Vec4I { - struct { S32 x, y, z, w; }; - struct { S32 r, g, b, a; }; - struct { Vec2I xy; Vec2I zw; }; - struct { Vec2I xy_; S32 width, height; }; - struct { Vec3I xyz; S32 w_; }; - struct { S32 x_; Vec3I yzw; }; - struct { Vec3I rgb; S32 a_; }; - S32 p[4]; -}; - -union Rect2 { - struct {F32 min_x, min_y, max_x, max_y;}; - struct { Vec2 min; Vec2 max; }; - F32 p[4]; -}; - -union Rect2I { - struct { S32 min_x, min_y, max_x, max_y;}; - struct { Vec2I min; Vec2I max; }; - S32 p[4]; -}; - -//----------------------------------------------------------------------------- -// Utilities -//----------------------------------------------------------------------------- -function SizeU -get_align_offset(SizeU size, SizeU align){ - SizeU mask = align - 1; - SizeU val = size & mask; - if(val){ - val = align - val; - } - return val; -} - -function SizeU -align_up(SizeU size, SizeU align){ - SizeU result = size + get_align_offset(size, align); - return result; -} - -function SizeU -align_down(SizeU size, SizeU align){ - size += 1; // Make sure 8 when align is 8 doesn't get rounded down to 0 - SizeU result = size - (align - get_align_offset(size, align)); - return result; -} - -function void -memory_copy(void *dst, void *src, SizeU size){ - U8 *d = (U8*)dst; - U8 *s = (U8*)src; - for(SizeU i = 0; i < size; i++){ - d[i] = s[i]; - } -} - -function void -memory_zero(void *p, SizeU size){ - U8 *pp = (U8 *)p; - for(SizeU i = 0; i < size; i++) - pp[i] = 0; -} - -template -void swap(T &a, T &b){ - T temp = a; - a = b; - b = temp; -} - -template -T max(T a, T b){ - if(a > b) return a; - return b; -} - -template -T min(T a, T b){ - if(a > b) return b; - return a; -} - -template -T clamp_top(T val, T max){ - if(val > max) val = max; - return val; -} - -template -T clamp_bot(T bot, T val){ - if(val < bot) val = bot; - return val; -} - -template -T clamp(T min, T val, T max){ - if(val > max) val = max; - if(val < min) val = min; - return val; -} - -function U64 -hash_string(String string) { - U64 hash = (U64)14695981039346656037ULL; - for (U64 i = 0; i < string.len; i++) { - hash = hash ^ (U64)(string.str[i]); - hash = hash * (U64)1099511628211ULL; - } - return hash; -} - -function U64 -hash_u64(U64 x) { - x *= 0xff51afd7ed558ccd; - x ^= x >> 32; - return x; -} - -function U64 -hash_ptr(const void *ptr) { - return hash_u64((uintptr_t)ptr); -} - -function U64 -hash_mix(U64 x, U64 y) { - // @note: murmur hash 3 mixer but I add the 'y' - // which means it's probably bad, hopefully better - // then some random scribble I could do - x ^= (y >> 33); - x *= 0xff51afd7ed558ccd; - x ^= (x >> 33); - x *= 0xc4ceb9fe1a85ec53; - x ^= (y >> 33); - return x; -} - -function U64 -is_pow2(U64 x) { - assert(x != 0); - B32 result = (x & (x - 1llu)) == 0; - return result; -} - -function U64 -wrap_around_pow2(U64 x, U64 power_of_2) { - assert(is_pow2(power_of_2)); - U64 r = (((x)&((power_of_2)-1llu))); - return r; -} - -force_inline String -operator""_s(const char *str, size_t size){ - return String{(U8 *)str, (S64)size}; -} - -force_inline B32 -operator==(Intern_String a, Intern_String b){ - return a.str == b.str; -} - -force_inline B32 -operator!=(Intern_String a, Intern_String b){ - B32 result = a.str == b.str; - return !result; -} - -//----------------------------------------------------------------------------- -// Very cool macros. Since these are macros it's recommended to wrap them -// in a function and not use directly -//----------------------------------------------------------------------------- -#define SLLQueuePushMod(f, l, n, next) \ - do { \ - if ((f) == 0) { \ - (f) = (l) = (n); \ - } else { \ - (l) = (l)->next = (n); \ - } \ - } while (0) -#define SLLQueuePush(f, l, n) SLLQueuePushMod(f, l, n, next) - -#define SLLStackPush(l, n) \ - do { \ - (n)->next = (l); \ - (l) = (n); \ - } while (0) - -#define SLLStackPop(l, n) \ - do { \ - if (l) { \ - (n) = (l); \ - (l) = (l)->next; \ - (n)->next = 0; \ - } \ - } while (0) - -#define DLLQueuePushLastMod(f, l, node, next, prev) \ - do { \ - if ((f) == 0) { \ - (f) = (l) = (node); \ - (node)->prev = 0; \ - (node)->next = 0; \ - } else { \ - (l)->next = (node); \ - (node)->prev = (l); \ - (node)->next = 0; \ - (l) = (node); \ - } \ - } while (0) -#define DLLQueuePushLast(f,l,node) DLLQueuePushLastMod(f,l,node,next,prev) -#define DLLQueuePush(f,l,node) DLLQueuePushLast(f,l,node) -#define DLLFreeListAddMod(first, node, next, prev) \ - do { \ - (node)->next = (first); \ - if ((first)) \ - (first)->prev = (node); \ - (first) = (node); \ - (node)->prev = 0; \ - } while (0) -#define DLLFreeListAdd(first, node) DLLFreeListAddMod(first, node, next, prev) - -#define For_List_It(a,it) for(auto *it = (a)->first; it; it=it->next) // @todo: reference? -#define For_List(a) For_List_It(a,it) -#define For_Named(a,it) for(auto &it : (a)) -#define For(a) For_Named((a),it) - -//----------------------------------------------------------------------------- -// Base Allocator stuff -//----------------------------------------------------------------------------- -enum Allocation_Kind{ - Allocation_Alloc, - Allocation_Resize, - Allocation_FreeAll, - Allocation_Free, - Allocation_Destroy -}; - -enum Allocator_Kind{ - Allocator_None, - Allocator_Arena, - Allocator_PersonalArena, - Allocator_OSHeap, -}; - -enum Alloc_Flag{ - AF_None, - AF_ZeroMemory -}; - -struct Allocator; -typedef void *Allocator_Proc(Allocator*, Allocation_Kind, void *, SizeU); -struct Allocator{Allocator_Kind kind; Allocator_Proc *proc; String debug_name;}; - -//----------------------------------------------------------------------------- -// Memory arenas -//----------------------------------------------------------------------------- -struct OS_Memory{ - SizeU commit, reserve; - U8 *data; -}; -function OS_Memory os_reserve(SizeU size); -function B32 os_commit(OS_Memory *m, SizeU size); -function void os_release(OS_Memory *m); -function B32 os_decommit_pos(OS_Memory *m, SizeU pos); - -//----------------------------------------------------------------------------- -// Memory arenas -//----------------------------------------------------------------------------- -global const SizeU default_reserve_size = gib(4); -global const SizeU default_alignment = 8; -global const SizeU additional_commit_size = mib(1); -struct Arena:Allocator{ - OS_Memory memory; - SizeU alignment; - SizeU len; - - // Personal arena memes so we can compute correct size when resizing - // Also a pointer so that we can make sure it didn't change - SizeU old_size; - void *debug_prev_pointer; -}; -function void arena_init(Arena *arena, String debug_name); - -function void -arena_pop_pos(Arena *arena, SizeU pos){ - pos = clamp_top(pos, arena->len); - arena->len = pos; -} - -function void * -arena_pop(Arena *arena, SizeU size){ - size = clamp_top(size, arena->len); - arena->len -= size; - return arena->memory.data + arena->len; -} - -function void -arena_release(Arena *arena){ - os_release(&arena->memory); -} - -function void -arena_clear(Arena *arena){ - arena_pop_pos(arena, 0); -} - -function void * -arena_push_size(Arena *a, SizeU size){ - SizeU generous_size = size + a->alignment; - if(a->len+generous_size>a->memory.commit){ - if(a->memory.reserve == 0){ - arena_init(a, "Zero initialized arena"_s); - } - B32 result = os_commit(&a->memory, generous_size+additional_commit_size); - assert(result); - } - - a->len = align_up(a->len, a->alignment); - assert(a->memory.reserve > a->len + size); - void *result = (U8*)a->memory.data + a->len; - a->len += size; - return result; -} - -force_inline void * -arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){ - Arena *arena = (Arena *)a; - switch(kind){ - case Allocation_Alloc: return arena_push_size(arena, size); - case Allocation_Resize:{ - void *result = arena_push_size(arena, size); - memory_copy(result, old_pointer, size); - return result; - } - case Allocation_Free : return 0; - case Allocation_FreeAll: arena_clear(arena); return 0; - case Allocation_Destroy: arena_release(arena); return 0; - } - invalid_codepath; - return 0; -} - -force_inline void * -personal_arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){ - Arena *arena = (Arena *)a; - arena->alignment = 1; - - void *result = 0; - switch(kind){ - case Allocation_Resize: { - assert(arena->old_size); - assert(arena->old_size < size); - assert(arena->debug_prev_pointer == old_pointer); - result = arena_push_size(arena, size - arena->old_size); - result = old_pointer; - } break; - default: { - result = arena_allocator_proc(a, kind, old_pointer, size); - arena->debug_prev_pointer = result; - } - } - - arena->old_size = size; - return result; -} - -function void -arena_init(Arena *a, String debug_name){ - a->memory = os_reserve(default_reserve_size); - a->alignment = default_alignment; - a->debug_name = debug_name; - a->kind = Allocator_Arena; - if(!a->proc) a->proc = arena_allocator_proc; -} - -function Arena -arena_make_personal(String debug_name){ - Arena arena = {}; - arena.proc = personal_arena_allocator_proc; - arena_init(&arena, debug_name); - arena.kind = Allocator_PersonalArena; - return arena; -} - -//----------------------------------------------------------------------------- -// OS Heap allocator -//----------------------------------------------------------------------------- -struct OS_Heap:Allocator{ - HANDLE handle; -}; - -function void * -os_heap_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){ - OS_Heap *heap = (OS_Heap *)a; - switch(kind){ - case Allocation_FreeAll:{ - invalid_codepath; - return 0; - } - case Allocation_Destroy:{ - BOOL result = HeapDestroy(heap->handle); - assert(result != 0); - heap->handle = 0; - heap->proc = 0; - return 0; - } - case Allocation_Free:{ - BOOL result = HeapFree(heap->handle, 0, old_pointer); - assert(result != 0); - return 0; - } - case Allocation_Alloc:{ - void *result = HeapAlloc(heap->handle, 0, size); - assert(result); - return result; - } - case Allocation_Resize:{ - void *result = HeapReAlloc(heap->handle, 0, old_pointer, size); - assert(result); - return result; - } - default: invalid_codepath; - } - return 0; -} - -function OS_Heap // max_size == 0 == growing heap -win32_os_heap_create(B32 multithreaded, SizeU initial_size, SizeU max_size, String debug_name){ - OS_Heap result = {}; - result.debug_name = debug_name; - result.proc = os_heap_allocator_proc; - result.kind = Allocator_OSHeap; - result.handle = HeapCreate(multithreaded ? 0 : HEAP_NO_SERIALIZE, initial_size, max_size); - assert(result.handle); - return result; -} - -enum Log_Kind{Log_Kind_Normal, Log_Kind_Error}; -typedef void Log_Proc(Log_Kind kind, String string, char *file, int line); -//----------------------------------------------------------------------------- -// Thread Context -//----------------------------------------------------------------------------- -struct Thread_Ctx{ - Arena scratch[2]; - Log_Proc *log_proc; - Allocator *implicit_alloc; - - int line; - char *file; -}; - -thread_local Thread_Ctx thread_ctx; -global Arena pernament_arena; -global OS_Heap os_process_heap; - -#define REPORT_ALLOCATIONS 0 -#define report_file_and_line() report__file_and_line(__FILE__, __LINE__) -force_inline void -report__file_and_line(const char *file, int line){ - thread_ctx.file = (char *)file; - thread_ctx.line = line; -} - -//----------------------------------------------------------------------------- -// Implicit scratch stack -//----------------------------------------------------------------------------- -struct Scratch{ - SizeU saved_pos; - Arena *arena; - - Scratch(Allocator *conflict = 0){ - if(conflict == thread_ctx.scratch){ - arena = thread_ctx.scratch + 1; - } - else { - arena = thread_ctx.scratch; - } - saved_pos = arena->len; - } - ~Scratch(){ - arena_pop_pos(arena, saved_pos); - } - force_inline operator Arena*(){ return arena; } - force_inline operator Allocator*(){ return arena; } - - // @Note: Disable copy constructors, cause it caused lots of confusing errors - // Where it passed scratch instead of the arena into the constructor - // which is an error - private: - Scratch(Scratch &arena); - Scratch(Scratch &arena, Scratch &a2); -}; - -#define Set_Allocator(a) Scoped_Allocator JOIN(scoped_alloc, __LINE__)(a) -struct Scoped_Allocator{ - Allocator *prev_allocator; - Scoped_Allocator(Allocator *a){ - prev_allocator = thread_ctx.implicit_alloc; - thread_ctx.implicit_alloc = a; - } - ~Scoped_Allocator(){ - thread_ctx.implicit_alloc = prev_allocator; - } -}; - -//----------------------------------------------------------------------------- -// Explicit allocator -//----------------------------------------------------------------------------- -#define exp_alloc_array(a, T, size,...) (T *)exp_alloc(a, sizeof(T)*(size),##__VA_ARGS__) -#define exp_alloc_type(a, T, ...) exp_alloc_array(a, T, 1,##__VA_ARGS__) -#define exp_alloc(a, size, ...) (report_file_and_line(), exp__alloc(a, size,##__VA_ARGS__)) -#define exp_resize(a,p,size) (report_file_and_line(), exp__resize(a, p, size)) -#define exp_resize_array(a, p, T, size) (report_file_and_line(), (T *)exp_resize(a, p, sizeof(T)*(size))) -#define exp_free(a, p) (report_file_and_line(), exp__free(a, p)) -#define exp_free_all(a) (report_file_and_line(), exp__free_all(a)) -#define exp_destroy(a) (report_file_and_line(), exp__destroy(a)) - -force_inline void * -exp__alloc(Allocator *a, SizeU size, Alloc_Flag flag = AF_None){ - #if REPORT_ALLOCATIONS - printf("Alloc(%s) %s:%d %u\n", a->debug_name.str, thread_ctx.file, thread_ctx.line, (U32)size); - #endif - - void *result = a->proc(a, Allocation_Alloc, 0, size); - if(flag & AF_ZeroMemory) memory_zero(result, size); - return result; -} -force_inline void * -exp__resize(Allocator *a, void *pointer, SizeU size){ - #if REPORT_ALLOCATIONS - printf("Resize(%s) %s:%d %u\n", a->debug_name.str, thread_ctx.file, thread_ctx.line, (U32)size); - #endif - - return a->proc(a, Allocation_Resize, pointer, size); -} -force_inline void -exp__free(Allocator *a, void *pointer){ - #if REPORT_ALLOCATIONS - printf("Free(%s) %s:%d\n", a->debug_name.str, thread_ctx.file, thread_ctx.line); - #endif - - a->proc(a, Allocation_Free, pointer, 0); -} -force_inline void -exp__free_all(Allocator *a){ - #if REPORT_ALLOCATIONS - printf("FreeAll(%s) %s:%d\n", a->debug_name.str, thread_ctx.file, thread_ctx.line); - #endif - - a->proc(a, Allocation_FreeAll, 0, 0); -} -force_inline void -exp__destroy(Allocator *a){ - #if REPORT_ALLOCATIONS - printf("Destroy(%s) %s:%d\n", a->debug_name.str, thread_ctx.file, thread_ctx.line); - #endif - - a->proc(a, Allocation_Destroy, 0, 0); -} -force_inline Allocator * -imp_get(){ - assert(thread_ctx.implicit_alloc); - return thread_ctx.implicit_alloc; -} - -function void -thread_ctx_init(){ - arena_init(thread_ctx.scratch, "Scratch1"_s); - arena_init(thread_ctx.scratch+1, "Scratch2"_s); - arena_init(&pernament_arena, "Pernament Arena"_s); - os_process_heap.proc = os_heap_allocator_proc; - os_process_heap.handle = GetProcessHeap(); - os_process_heap.debug_name = "Win32 Process Heap"_s; - os_process_heap.kind = Allocator_OSHeap; -} - -#include "base_string.cpp" -//----------------------------------------------------------------------------- -// Logging -//----------------------------------------------------------------------------- -#define log_info(...) handle_log_message(Log_Kind_Normal, __LINE__, __FILE__,##__VA_ARGS__) -#define log_error(...) handle_log_message(Log_Kind_Error, __LINE__, __FILE__,##__VA_ARGS__) -function void -handle_log_message(Log_Kind kind, int line, const char *file, const char *str, ...){ - Scratch scratch; - STRING_FMT(scratch, str, message); - if(thread_ctx.log_proc) thread_ctx.log_proc(kind, message, (char *)file, line); - else{ - printf("%s", message.str); - } -} - -//----------------------------------------------------------------------------- -// Defer -// http://www.gingerbill.org/article/2015/08/19/defer-in-cpp/ -//----------------------------------------------------------------------------- -template -struct Defer_Scope { - F f; - Defer_Scope(F f) : f(f) {} - ~Defer_Scope() { f(); } -}; - -template -Defer_Scope defer_func(F f) { - return Defer_Scope(f); -} -#define DEFER_1(x, y) x##y -#define DEFER_2(x, y) DEFER_1(x, y) -#define DEFER_3(x) DEFER_2(x, __COUNTER__) -#define defer(code) auto DEFER_3(_defer_) = defer_func([&](){code;}) - -//----------------------------------------------------------------------------- -// Array -//----------------------------------------------------------------------------- -template -struct Array{ - Allocator *allocator; - T *data; - S64 cap; - S64 len; - - T *push_empty(S64 count = 1){ - grow(count); - T *result = data + len; - len += count; - return result; - } - - T *push_empty_zero(S64 count = 1){ - T *result = push_empty(count); - memory_zero(result, count*sizeof(T)); - return result; - } - - void grow(S64 required_size){ - if(cap == 0){ - if(!allocator) allocator = imp_get(); - S64 new_cap = max(required_size*2, (S64)16); - data = exp_alloc_array(allocator, T, new_cap); - cap = new_cap; - } - else if(len + required_size > cap){ - U64 new_cap = max(cap * 2, len+required_size+1); - data = exp_resize_array(allocator, data, T, new_cap); - cap = new_cap; - } - } - - S64 get_index(T *item){ - assert((data <= item) && ((data + len) > item)); - SizeU offset = item - data; - return (S64)offset; - } - - void add(Array items){ - For(items){ - add(it); - } - } - - void add(T item){ - grow(1); - data[len++] = item; - } - - S64 addi(T item){ - S64 result = len; - grow(1); - data[len++] = item; - return result; - } - - void unordered_remove(T *item){ - assert(len > 0); - assert((data <= item) && ((data + len) > item)); - *item = data[--len]; - } - - void init(Allocator *a, S64 size = 16){ - allocator = a; - data = exp_alloc_array(a, T, size); - cap = size; - } - - Array copy(Allocator *a){ - Array result = {}; - result.len = len; - result.cap = len*2; - result.allocator = a; - result.data = exp_alloc_array(a, T, result.cap); - memory_copy(result.data, data, sizeof(T)*result.len); - return result; - } - - Array tight_copy(Allocator *a){ - Array result = {}; - result.len = len; - result.cap = len; - result.allocator = 0; - result.data = exp_alloc_array(a, T, len); - memory_copy(result.data, data, sizeof(T)*len); - return result; - } - - force_inline B32 is_last(T *item){ return item == last(); } - force_inline B32 is_first(T *item){ return item == begin(); } - force_inline void clear(){ len = 0; } - force_inline T pop() { return data[--len]; } - force_inline T *last() { return data + len - 1; } - force_inline T *begin() { return data; } - force_inline T *end () { return data + len; } - force_inline T &operator[](S64 i){ assert(i >= 0 && i < cap); return data[i]; } - - - struct Array_Iter{ - Array *array; - S64 i; - T *it; - - force_inline void next(){ i+=1; it = &array->data[i]; } - force_inline B32 should_continue(){ return i < array->len; } - }; - - force_inline Array_Iter iter(){ return {this, 0, begin()};} - #define For_It_Named(array, it) for(auto it = (array).iter(); it.should_continue(); it.next()) - #define For_It(array) For_It_Named(array, it) -}; - - -template -function Array -array_make(Allocator *a, S64 size = 16){ - Array result = {}; - result.init(a, size); - return result; -} - -function void -test_array(){ - Scratch scratch; - Array array = {scratch}; - - int size = 1000; - for(int i = 0; i < size; i++){ - array.add(i); - } - S32 i = 0; - For(array){ - assert(it == i++); - } - - Arena arena = arena_make_personal("Test personal arena"_s); - Array array2 = {&arena}; - for(int i = 0; i < size; i++){ - array2.add(i); - } - i=0; - For(array2){ - assert(it == i++); - } - exp_destroy(&arena); - assert(arena.memory.data == 0); - assert(thread_ctx.scratch->memory.data != 0); -} - - -template -struct Simple_Bucket_Array{ - struct Bucket{ Bucket *next; T data[bucket_size]; S64 len; }; - Bucket *first; - Bucket *last ; - - void grow(Allocator *allocator){ - if(!first){ - Bucket *bucket = exp_alloc_type(allocator, Bucket); - bucket->next = 0; bucket->len = 0; - first = last = bucket; - } - - if(last->len >= bucket_size){ - Bucket *bucket = exp_alloc_type(allocator, Bucket); - bucket->next = 0; bucket->len = 0; - last = last->next = bucket; - } - } - - T *allocate(Allocator *allocator){ - grow(allocator); - return last->data + last->len++; - } - - void add(Allocator *allocator, T item){ - grow(allocator); - last->data[last->len++] = item; - } - - struct Iter{ - Simple_Bucket_Array *ref; - Bucket *bucket; - T *it; - S64 iter_i; - S64 i; - - force_inline B32 should_continue(){ return it != 0; } - force_inline void next(){ - if(iter_i >= bucket->len){ - if(bucket->next){ - bucket = bucket->next; - iter_i = 0; - } - else{ - it = 0; - return; - } - } - - it = bucket->data + iter_i++; - i += 1; - } - }; - - force_inline Iter iter(){ - if(!this->first || this->first->len == 0) return {}; - return {this, this->first, this->first->data, 1}; - } -}; - -function void -test_bucket_arrays(){ - Scratch scratch; - Simple_Bucket_Array a = {}; - for(int i = 0; i < 32; i++) - a.add(scratch, i); - - For_It(a){ - assert(*it.it == it.i); - } - - for(auto i = a.iter(); i.should_continue(); i.next()){ - assert(*i.it == i.i); - } - - int total_i = 0; - for(auto bucket = a.first; bucket; bucket=bucket->next){ - for(int i = 0; i < bucket->len; i++){ - assert(bucket->data[i] == total_i++); - } - } -} - -//----------------------------------------------------------------------------- -// Map -//----------------------------------------------------------------------------- -struct Map_Key_Value{ - int occupied; - U64 key; - void *value; -}; - -struct Map{ - Allocator *allocator; - Map_Key_Value *data; - S64 len; - S64 cap; -}; -function void map_insert(Map *map, U64 key, void *val); - -function void -map_grow(Map *map, S64 new_size){ - new_size = max((S64)16, new_size); - assert(new_size > map->cap); - assert(is_pow2(new_size)); - if(map->cap == 0 && map->allocator == 0) map->allocator = imp_get(); - - Map new_map = {}; - new_map.data = exp_alloc_array(map->allocator, Map_Key_Value, new_size, AF_ZeroMemory); - new_map.cap = new_size; - new_map.allocator = map->allocator; - - for(S64 i = 0; i < map->cap; i++){ - if(map->data[i].occupied){ - map_insert(&new_map, map->data[i].key, map->data[i].value); - } - } - if(map->data) exp_free(map->allocator, map->data); - *map = new_map; -} - -function Map -map_make(Allocator *a, S64 size){ - Map result = {a}; - map_grow(&result, size); - return result; -} - -function void -map_insert(Map *map, U64 key, void *val){ - assert(val); - assert(key); - // if(key == 0) key+=1; - - if((2*map->len) + 1 > map->cap){ - map_grow(map, 2*map->cap); - } - - U64 hash = hash_u64(key); - U64 index = wrap_around_pow2(hash, map->cap); - U64 i = index; - for(;;){ - if(map->data[i].occupied == false){ - map->len++; - map->data[i].occupied = true; - map->data[i].key = key; - map->data[i].value = val; - return; - } - else if(map->data[i].key == key){ - map->data[i].value = val; - return; - } - - i = wrap_around_pow2(i+1, map->cap); - if(i == map->cap){ - return; - } - } -} - -function Map_Key_Value * -map_base_get(Map *map, U64 key){ - if(map->len == 0) return 0; - assert(key); - // if(key == 0) key+=1; - - U64 hash = hash_u64(key); - U64 index = wrap_around_pow2(hash, map->cap); - U64 i = index; - for(;;){ - if(map->data[i].key == key){ - return map->data + i; - } - else if(map->data[i].key == 0){ - return 0; - } - - i = wrap_around_pow2(i+1, map->cap); - if(i == map->cap){ - return 0; - } - } -} - -function void * -map_get(Map *map, U64 key){ - Map_Key_Value *result = map_base_get(map, key); - if(result && result->occupied) return result->value; - return 0; -} - -function void * -map_remove(Map *map, U64 key){ - Map_Key_Value *kv = map_base_get(map, key); - if(kv){ - kv->occupied = false; - return kv->value; - } - return 0; -} - -function void * -map_get(Map *map, void *pointer){ - return map_get(map, (U64)pointer); -} - -function void * -map_get(Map *map, Intern_String string){ - return map_get(map, hash_string(string.s)); -} - -function void -map_insert(Map *map, void *key, void *value){ - map_insert(map, (U64)key, value); -} - -function void -map_insert(Map *map, Intern_String key, void *value){ - map_insert(map, hash_string(key.s), value); -} - -function void -map_test(){ - Scratch scratch; - Map map = {scratch}; - const SizeU size = 1025; - for(SizeU i = 1; i < size; i++){ - map_insert(&map, i, (void *)i); - } - for(SizeU i = 1; i < size; i++){ - SizeU val = (SizeU)map_get(&map, i); - assert(val == i); - } -} - -//----------------------------------------------------------------------------- -// String intern -//----------------------------------------------------------------------------- -struct Intern_Table{ - Allocator *string_allocator; - Map map; - U8 *first_keyword; - U8 *last_keyword; -}; - -function Intern_Table -intern_table_make(Allocator *string_allocator, Allocator *map_allocator, S64 initial_size = 32){ - Intern_Table result = {}; - result.map = map_make(map_allocator, initial_size); - result.string_allocator = string_allocator; - return result; -} - -function Intern_String -intern_string(Intern_Table *t, String string){ - assert(t->string_allocator); - U64 hash = hash_string(string); - U8 *slot = (U8 *)map_get(&t->map, hash); - if(slot){ - Intern_String result = {{slot, *(slot-sizeof(S64))}}; - return result; - } - - S64 *len_address = (S64 *)exp_alloc(t->string_allocator, string.len+1+sizeof(S64)); - *len_address = string.len; - - U8 *string_address = (U8 *)(len_address + 1); - memory_copy(string_address, string.str, string.len); - string_address[string.len] = 0; - - map_insert(&t->map, hash, string_address); - Intern_String result = {{string_address, *len_address}}; - - return result; -} - -function void -test_intern_table(){ - Scratch scratch; - Intern_Table table = intern_table_make(scratch, scratch); - Intern_String intern1 = intern_string(&table, "Thing"_s); - Intern_String intern2 = intern_string(&table, "Thing"_s); - Intern_String intern3 = intern_string(&table, "Not Thing"_s); - assert(intern1.str == intern2.str); - assert(intern3.str != intern2.str); -} - -function Arena -arena_sub(Allocator *base, SizeU size, String debug_name) { - Arena result = {}; - result.memory.data = (U8 *)exp_alloc(base, size); - result.memory.commit = size; - result.memory.reserve = size; - result.alignment = default_alignment; - result.len = 0; - result.debug_name = debug_name; - result.kind = Allocator_Arena; - if(!result.proc) result.proc = arena_allocator_proc; - return result; -} diff --git a/base_math.cpp b/base_math.cpp deleted file mode 100644 index b9d57fb..0000000 --- a/base_math.cpp +++ /dev/null @@ -1,1712 +0,0 @@ -#pragma once - -/////////////////////////////////////// -// @Section Math -#include -constexpr F32 PI32 = 3.14159265359f; - -api F32 power(S64 pow, F32 value) { - F32 result = value; - if (pow == 0) { - result = 1; - } else { - for (S64 i = 1; i < pow; i++) { - result *= result; - } - } - return result; -} - -api F32 to_radians(F32 degrees) { - F32 result = degrees * (PI32 / 180.f); - return result; -} - -api F32 to_degrees(F32 radians) { - F32 result = radians * (180.f / PI32); - return result; -} - -api F32 fraction(F32 value) { - F32 result = value - floorf(value); - return result; -} - -api F32 absolute(F32 value) { - if (value < 0) - value = -value; - return value; -} - -api S32 square(S32 val) { return val * val; } - -api S32 clamp01(S32 val) { - S32 result = clamp(0, val, 1); - return result; -} - -api S32 sign(S32 val) { - if (val > 0) - return 1; - else if (val < 0) - return -1; - return 0; -} - -api F32 square(F32 val) { return val * val; } - -api F32 clamp01(F32 val) { - F32 result = clamp(0.f, val, 1.f); - return result; -} - -api F32 sign(F32 val) { - if (val > 0) - return 1; - else if (val < 0) - return -1; - return 0; -} - -api F32 floor(F32 val) { return floorf(val); } - -api F32 ceil(F32 val) { return ceilf(val); } - -api F32 round(F32 val) { return roundf(val); } - -api F32 sine(F32 val) { return sinf(val); } - -api F32 sine01(F32 val) { - F32 result = sine(val); - result += 1; - result /= 2; - return result; -} - -api F32 cosine(F32 val) { return cosf(val); } - -api F32 square_root(F32 val) { return sqrtf(val); } - -api Vec2 vec2(F32 x, F32 y) { - Vec2 result; - result.x = x; - result.y = y; - return result; -} -api Vec2 vec2() { return vec2(0, 0); } -api Vec2 operator+(Vec2 a, Vec2 b) { - Vec2 result = vec2(a.x + b.x, a.y + b.y); - return result; -} -api Vec2 operator+(Vec2 a, F32 b) { - Vec2 result = vec2(a.x + b, a.y + b); - return result; -} -api Vec2 operator+(F32 a, Vec2 b) { - Vec2 result = vec2(a + b.x, a + b.y); - return result; -} -api Vec2 &operator+=(Vec2 &a, Vec2 b) { - a = a + b; - return a; -} -api Vec2 &operator+=(Vec2 &a, F32 b) { - a = a + b; - return a; -} -api Vec2 operator-(Vec2 a, Vec2 b) { - Vec2 result = vec2(a.x - b.x, a.y - b.y); - return result; -} -api Vec2 operator-(Vec2 a, F32 b) { - Vec2 result = vec2(a.x - b, a.y - b); - return result; -} -api Vec2 operator-(F32 a, Vec2 b) { - Vec2 result = vec2(a - b.x, a - b.y); - return result; -} -api Vec2 &operator-=(Vec2 &a, Vec2 b) { - a = a - b; - return a; -} -api Vec2 &operator-=(Vec2 &a, F32 b) { - a = a - b; - return a; -} -api Vec2 operator*(Vec2 a, Vec2 b) { - Vec2 result = vec2(a.x * b.x, a.y * b.y); - return result; -} -api Vec2 operator*(Vec2 a, F32 b) { - Vec2 result = vec2(a.x * b, a.y * b); - return result; -} -api Vec2 operator*(F32 a, Vec2 b) { - Vec2 result = vec2(a * b.x, a * b.y); - return result; -} -api Vec2 &operator*=(Vec2 &a, Vec2 b) { - a = a * b; - return a; -} -api Vec2 &operator*=(Vec2 &a, F32 b) { - a = a * b; - return a; -} -api Vec2 operator/(Vec2 a, Vec2 b) { - Vec2 result = vec2(a.x / b.x, a.y / b.y); - return result; -} -api Vec2 operator/(Vec2 a, F32 b) { - Vec2 result = vec2(a.x / b, a.y / b); - return result; -} -api Vec2 operator/(F32 a, Vec2 b) { - Vec2 result = vec2(a / b.x, a / b.y); - return result; -} -api Vec2 &operator/=(Vec2 &a, Vec2 b) { - a = a / b; - return a; -} -api Vec2 &operator/=(Vec2 &a, F32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec2 a, Vec2 b) { - B32 result = (a.x != b.x) || (a.y != b.y); - return result; -} -api B32 operator==(Vec2 a, Vec2 b) { - B32 result = (a.x == b.x) && (a.y == b.y); - return result; -} -api Vec2 operator-(Vec2 a) { - Vec2 result = vec2(-a.x, -a.y); - return result; -} -api Vec2 clamp(Vec2 min, Vec2 val, Vec2 max) { - Vec2 result = vec2(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y)); - return result; -} -api Vec2 clamp(F32 min, Vec2 val, F32 max) { - Vec2 result = vec2(clamp(min, val.x, max), clamp(min, val.y, max)); - return result; -} -api Vec2 clamp01(Vec2 val) { - Vec2 result = vec2(clamp01(val.x), clamp01(val.y)); - return result; -} -api Vec2 ceil(Vec2 a) { - Vec2 result = vec2(ceil(a.x), ceil(a.y)); - return result; -} -api Vec2 floor(Vec2 a) { - Vec2 result = vec2(floor(a.x), floor(a.y)); - return result; -} -api Vec2 round(Vec2 a) { - Vec2 result = vec2(round(a.x), round(a.y)); - return result; -} -api Vec2 absolute(Vec2 a) { - Vec2 result = vec2(absolute(a.x), absolute(a.y)); - return result; -} -api Vec2 sign(Vec2 a) { - Vec2 result = vec2(sign(a.x), sign(a.y)); - return result; -} -api Vec2 fraction(Vec2 a) { - Vec2 result = vec2(fraction(a.x), fraction(a.y)); - return result; -} -api Vec2 square(Vec2 a) { - Vec2 result = vec2(square(a.x), square(a.y)); - return result; -} -api Vec2 square_root(Vec2 a) { - Vec2 result = vec2(square_root(a.x), square_root(a.y)); - return result; -} -api F32 dot(Vec2 a, Vec2 b) { - F32 result = a.x * b.x + a.y * b.y; - return result; -} -api F32 length_squared(Vec2 a) { - F32 result = dot(a, a); - return result; -} -api F32 length(Vec2 a) { - F32 result = square_root(length_squared(a)); - return result; -} -api Vec2 lerp(Vec2 from, Vec2 to, F32 t) { - Vec2 result = (1 - t) * from + to * t; - return result; -} -api Vec3 vec3(F32 x, F32 y, F32 z) { - Vec3 result; - result.x = x; - result.y = y; - result.z = z; - return result; -} -api Vec3 vec3() { return vec3(0, 0, 0); } -api Vec3 operator+(Vec3 a, Vec3 b) { - Vec3 result = vec3(a.x + b.x, a.y + b.y, a.z + b.z); - return result; -} -api Vec3 operator+(Vec3 a, F32 b) { - Vec3 result = vec3(a.x + b, a.y + b, a.z + b); - return result; -} -api Vec3 operator+(F32 a, Vec3 b) { - Vec3 result = vec3(a + b.x, a + b.y, a + b.z); - return result; -} -api Vec3 &operator+=(Vec3 &a, Vec3 b) { - a = a + b; - return a; -} -api Vec3 &operator+=(Vec3 &a, F32 b) { - a = a + b; - return a; -} -api Vec3 operator-(Vec3 a, Vec3 b) { - Vec3 result = vec3(a.x - b.x, a.y - b.y, a.z - b.z); - return result; -} -api Vec3 operator-(Vec3 a, F32 b) { - Vec3 result = vec3(a.x - b, a.y - b, a.z - b); - return result; -} -api Vec3 operator-(F32 a, Vec3 b) { - Vec3 result = vec3(a - b.x, a - b.y, a - b.z); - return result; -} -api Vec3 &operator-=(Vec3 &a, Vec3 b) { - a = a - b; - return a; -} -api Vec3 &operator-=(Vec3 &a, F32 b) { - a = a - b; - return a; -} -api Vec3 operator*(Vec3 a, Vec3 b) { - Vec3 result = vec3(a.x * b.x, a.y * b.y, a.z * b.z); - return result; -} -api Vec3 operator*(Vec3 a, F32 b) { - Vec3 result = vec3(a.x * b, a.y * b, a.z * b); - return result; -} -api Vec3 operator*(F32 a, Vec3 b) { - Vec3 result = vec3(a * b.x, a * b.y, a * b.z); - return result; -} -api Vec3 &operator*=(Vec3 &a, Vec3 b) { - a = a * b; - return a; -} -api Vec3 &operator*=(Vec3 &a, F32 b) { - a = a * b; - return a; -} -api Vec3 operator/(Vec3 a, Vec3 b) { - Vec3 result = vec3(a.x / b.x, a.y / b.y, a.z / b.z); - return result; -} -api Vec3 operator/(Vec3 a, F32 b) { - Vec3 result = vec3(a.x / b, a.y / b, a.z / b); - return result; -} -api Vec3 operator/(F32 a, Vec3 b) { - Vec3 result = vec3(a / b.x, a / b.y, a / b.z); - return result; -} -api Vec3 &operator/=(Vec3 &a, Vec3 b) { - a = a / b; - return a; -} -api Vec3 &operator/=(Vec3 &a, F32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec3 a, Vec3 b) { - B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z); - return result; -} -api B32 operator==(Vec3 a, Vec3 b) { - B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z); - return result; -} -api Vec3 operator-(Vec3 a) { - Vec3 result = vec3(-a.x, -a.y, -a.z); - return result; -} -api Vec3 clamp(Vec3 min, Vec3 val, Vec3 max) { - Vec3 result = vec3(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z)); - return result; -} -api Vec3 clamp(F32 min, Vec3 val, F32 max) { - Vec3 result = vec3(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max)); - return result; -} -api Vec3 clamp01(Vec3 val) { - Vec3 result = vec3(clamp01(val.x), clamp01(val.y), clamp01(val.z)); - return result; -} -api Vec3 ceil(Vec3 a) { - Vec3 result = vec3(ceil(a.x), ceil(a.y), ceil(a.z)); - return result; -} -api Vec3 floor(Vec3 a) { - Vec3 result = vec3(floor(a.x), floor(a.y), floor(a.z)); - return result; -} -api Vec3 round(Vec3 a) { - Vec3 result = vec3(round(a.x), round(a.y), round(a.z)); - return result; -} -api Vec3 absolute(Vec3 a) { - Vec3 result = vec3(absolute(a.x), absolute(a.y), absolute(a.z)); - return result; -} -api Vec3 sign(Vec3 a) { - Vec3 result = vec3(sign(a.x), sign(a.y), sign(a.z)); - return result; -} -api Vec3 fraction(Vec3 a) { - Vec3 result = vec3(fraction(a.x), fraction(a.y), fraction(a.z)); - return result; -} -api Vec3 square(Vec3 a) { - Vec3 result = vec3(square(a.x), square(a.y), square(a.z)); - return result; -} -api Vec3 square_root(Vec3 a) { - Vec3 result = vec3(square_root(a.x), square_root(a.y), square_root(a.z)); - return result; -} -api F32 dot(Vec3 a, Vec3 b) { - F32 result = a.x * b.x + a.y * b.y + a.z * b.z; - return result; -} -api F32 length_squared(Vec3 a) { - F32 result = dot(a, a); - return result; -} -api F32 length(Vec3 a) { - F32 result = square_root(length_squared(a)); - return result; -} -api Vec3 lerp(Vec3 from, Vec3 to, F32 t) { - Vec3 result = (1 - t) * from + to * t; - return result; -} -api Vec4 vec4(F32 x, F32 y, F32 z, F32 w) { - Vec4 result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - return result; -} -api Vec4 vec4() { return vec4(0, 0, 0, 0); } -api Vec4 operator+(Vec4 a, Vec4 b) { - Vec4 result = vec4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - return result; -} -api Vec4 operator+(Vec4 a, F32 b) { - Vec4 result = vec4(a.x + b, a.y + b, a.z + b, a.w + b); - return result; -} -api Vec4 operator+(F32 a, Vec4 b) { - Vec4 result = vec4(a + b.x, a + b.y, a + b.z, a + b.w); - return result; -} -api Vec4 &operator+=(Vec4 &a, Vec4 b) { - a = a + b; - return a; -} -api Vec4 &operator+=(Vec4 &a, F32 b) { - a = a + b; - return a; -} -api Vec4 operator-(Vec4 a, Vec4 b) { - Vec4 result = vec4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); - return result; -} -api Vec4 operator-(Vec4 a, F32 b) { - Vec4 result = vec4(a.x - b, a.y - b, a.z - b, a.w - b); - return result; -} -api Vec4 operator-(F32 a, Vec4 b) { - Vec4 result = vec4(a - b.x, a - b.y, a - b.z, a - b.w); - return result; -} -api Vec4 &operator-=(Vec4 &a, Vec4 b) { - a = a - b; - return a; -} -api Vec4 &operator-=(Vec4 &a, F32 b) { - a = a - b; - return a; -} -api Vec4 operator*(Vec4 a, Vec4 b) { - Vec4 result = vec4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); - return result; -} -api Vec4 operator*(Vec4 a, F32 b) { - Vec4 result = vec4(a.x * b, a.y * b, a.z * b, a.w * b); - return result; -} -api Vec4 operator*(F32 a, Vec4 b) { - Vec4 result = vec4(a * b.x, a * b.y, a * b.z, a * b.w); - return result; -} -api Vec4 &operator*=(Vec4 &a, Vec4 b) { - a = a * b; - return a; -} -api Vec4 &operator*=(Vec4 &a, F32 b) { - a = a * b; - return a; -} -api Vec4 operator/(Vec4 a, Vec4 b) { - Vec4 result = vec4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); - return result; -} -api Vec4 operator/(Vec4 a, F32 b) { - Vec4 result = vec4(a.x / b, a.y / b, a.z / b, a.w / b); - return result; -} -api Vec4 operator/(F32 a, Vec4 b) { - Vec4 result = vec4(a / b.x, a / b.y, a / b.z, a / b.w); - return result; -} -api Vec4 &operator/=(Vec4 &a, Vec4 b) { - a = a / b; - return a; -} -api Vec4 &operator/=(Vec4 &a, F32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec4 a, Vec4 b) { - B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); - return result; -} -api B32 operator==(Vec4 a, Vec4 b) { - B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); - return result; -} -api Vec4 operator-(Vec4 a) { - Vec4 result = vec4(-a.x, -a.y, -a.z, -a.w); - return result; -} -api Vec4 clamp(Vec4 min, Vec4 val, Vec4 max) { - Vec4 result = vec4(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z), - clamp(min.w, val.w, max.w)); - return result; -} -api Vec4 clamp(F32 min, Vec4 val, F32 max) { - Vec4 result = - vec4(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max), clamp(min, val.w, max)); - return result; -} -api Vec4 clamp01(Vec4 val) { - Vec4 result = vec4(clamp01(val.x), clamp01(val.y), clamp01(val.z), clamp01(val.w)); - return result; -} -api Vec4 ceil(Vec4 a) { - Vec4 result = vec4(ceil(a.x), ceil(a.y), ceil(a.z), ceil(a.w)); - return result; -} -api Vec4 floor(Vec4 a) { - Vec4 result = vec4(floor(a.x), floor(a.y), floor(a.z), floor(a.w)); - return result; -} -api Vec4 round(Vec4 a) { - Vec4 result = vec4(round(a.x), round(a.y), round(a.z), round(a.w)); - return result; -} -api Vec4 absolute(Vec4 a) { - Vec4 result = vec4(absolute(a.x), absolute(a.y), absolute(a.z), absolute(a.w)); - return result; -} -api Vec4 sign(Vec4 a) { - Vec4 result = vec4(sign(a.x), sign(a.y), sign(a.z), sign(a.w)); - return result; -} -api Vec4 fraction(Vec4 a) { - Vec4 result = vec4(fraction(a.x), fraction(a.y), fraction(a.z), fraction(a.w)); - return result; -} -api Vec4 square(Vec4 a) { - Vec4 result = vec4(square(a.x), square(a.y), square(a.z), square(a.w)); - return result; -} -api Vec4 square_root(Vec4 a) { - Vec4 result = vec4(square_root(a.x), square_root(a.y), square_root(a.z), square_root(a.w)); - return result; -} -api F32 dot(Vec4 a, Vec4 b) { - F32 result = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; - return result; -} -api F32 length_squared(Vec4 a) { - F32 result = dot(a, a); - return result; -} -api F32 length(Vec4 a) { - F32 result = square_root(length_squared(a)); - return result; -} -api Vec4 lerp(Vec4 from, Vec4 to, F32 t) { - Vec4 result = (1 - t) * from + to * t; - return result; -} -api Vec2I vec2i(S32 x, S32 y) { - Vec2I result; - result.x = x; - result.y = y; - return result; -} -api Vec2I vec2i() { return vec2i(0, 0); } -api Vec2I operator+(Vec2I a, Vec2I b) { - Vec2I result = vec2i(a.x + b.x, a.y + b.y); - return result; -} -api Vec2I operator+(Vec2I a, S32 b) { - Vec2I result = vec2i(a.x + b, a.y + b); - return result; -} -api Vec2I operator+(S32 a, Vec2I b) { - Vec2I result = vec2i(a + b.x, a + b.y); - return result; -} -api Vec2I &operator+=(Vec2I &a, Vec2I b) { - a = a + b; - return a; -} -api Vec2I &operator+=(Vec2I &a, S32 b) { - a = a + b; - return a; -} -api Vec2I operator-(Vec2I a, Vec2I b) { - Vec2I result = vec2i(a.x - b.x, a.y - b.y); - return result; -} -api Vec2I operator-(Vec2I a, S32 b) { - Vec2I result = vec2i(a.x - b, a.y - b); - return result; -} -api Vec2I operator-(S32 a, Vec2I b) { - Vec2I result = vec2i(a - b.x, a - b.y); - return result; -} -api Vec2I &operator-=(Vec2I &a, Vec2I b) { - a = a - b; - return a; -} -api Vec2I &operator-=(Vec2I &a, S32 b) { - a = a - b; - return a; -} -api Vec2I operator*(Vec2I a, Vec2I b) { - Vec2I result = vec2i(a.x * b.x, a.y * b.y); - return result; -} -api Vec2I operator*(Vec2I a, S32 b) { - Vec2I result = vec2i(a.x * b, a.y * b); - return result; -} -api Vec2I operator*(S32 a, Vec2I b) { - Vec2I result = vec2i(a * b.x, a * b.y); - return result; -} -api Vec2I &operator*=(Vec2I &a, Vec2I b) { - a = a * b; - return a; -} -api Vec2I &operator*=(Vec2I &a, S32 b) { - a = a * b; - return a; -} -api Vec2I operator/(Vec2I a, Vec2I b) { - Vec2I result = vec2i(a.x / b.x, a.y / b.y); - return result; -} -api Vec2I operator/(Vec2I a, S32 b) { - Vec2I result = vec2i(a.x / b, a.y / b); - return result; -} -api Vec2I operator/(S32 a, Vec2I b) { - Vec2I result = vec2i(a / b.x, a / b.y); - return result; -} -api Vec2I &operator/=(Vec2I &a, Vec2I b) { - a = a / b; - return a; -} -api Vec2I &operator/=(Vec2I &a, S32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec2I a, Vec2I b) { - B32 result = (a.x != b.x) || (a.y != b.y); - return result; -} -api B32 operator==(Vec2I a, Vec2I b) { - B32 result = (a.x == b.x) && (a.y == b.y); - return result; -} -api Vec2I operator-(Vec2I a) { - Vec2I result = vec2i(-a.x, -a.y); - return result; -} -api Vec2I clamp(Vec2I min, Vec2I val, Vec2I max) { - Vec2I result = vec2i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y)); - return result; -} -api Vec2I clamp(S32 min, Vec2I val, S32 max) { - Vec2I result = vec2i(clamp(min, val.x, max), clamp(min, val.y, max)); - return result; -} -api Vec2I clamp01(Vec2I val) { - Vec2I result = vec2i(clamp01(val.x), clamp01(val.y)); - return result; -} -api Vec3I vec3i(S32 x, S32 y, S32 z) { - Vec3I result; - result.x = x; - result.y = y; - result.z = z; - return result; -} -api Vec3I vec3i() { return vec3i(0, 0, 0); } -api Vec3I operator+(Vec3I a, Vec3I b) { - Vec3I result = vec3i(a.x + b.x, a.y + b.y, a.z + b.z); - return result; -} -api Vec3I operator+(Vec3I a, S32 b) { - Vec3I result = vec3i(a.x + b, a.y + b, a.z + b); - return result; -} -api Vec3I operator+(S32 a, Vec3I b) { - Vec3I result = vec3i(a + b.x, a + b.y, a + b.z); - return result; -} -api Vec3I &operator+=(Vec3I &a, Vec3I b) { - a = a + b; - return a; -} -api Vec3I &operator+=(Vec3I &a, S32 b) { - a = a + b; - return a; -} -api Vec3I operator-(Vec3I a, Vec3I b) { - Vec3I result = vec3i(a.x - b.x, a.y - b.y, a.z - b.z); - return result; -} -api Vec3I operator-(Vec3I a, S32 b) { - Vec3I result = vec3i(a.x - b, a.y - b, a.z - b); - return result; -} -api Vec3I operator-(S32 a, Vec3I b) { - Vec3I result = vec3i(a - b.x, a - b.y, a - b.z); - return result; -} -api Vec3I &operator-=(Vec3I &a, Vec3I b) { - a = a - b; - return a; -} -api Vec3I &operator-=(Vec3I &a, S32 b) { - a = a - b; - return a; -} -api Vec3I operator*(Vec3I a, Vec3I b) { - Vec3I result = vec3i(a.x * b.x, a.y * b.y, a.z * b.z); - return result; -} -api Vec3I operator*(Vec3I a, S32 b) { - Vec3I result = vec3i(a.x * b, a.y * b, a.z * b); - return result; -} -api Vec3I operator*(S32 a, Vec3I b) { - Vec3I result = vec3i(a * b.x, a * b.y, a * b.z); - return result; -} -api Vec3I &operator*=(Vec3I &a, Vec3I b) { - a = a * b; - return a; -} -api Vec3I &operator*=(Vec3I &a, S32 b) { - a = a * b; - return a; -} -api Vec3I operator/(Vec3I a, Vec3I b) { - Vec3I result = vec3i(a.x / b.x, a.y / b.y, a.z / b.z); - return result; -} -api Vec3I operator/(Vec3I a, S32 b) { - Vec3I result = vec3i(a.x / b, a.y / b, a.z / b); - return result; -} -api Vec3I operator/(S32 a, Vec3I b) { - Vec3I result = vec3i(a / b.x, a / b.y, a / b.z); - return result; -} -api Vec3I &operator/=(Vec3I &a, Vec3I b) { - a = a / b; - return a; -} -api Vec3I &operator/=(Vec3I &a, S32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec3I a, Vec3I b) { - B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z); - return result; -} -api B32 operator==(Vec3I a, Vec3I b) { - B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z); - return result; -} -api Vec3I operator-(Vec3I a) { - Vec3I result = vec3i(-a.x, -a.y, -a.z); - return result; -} -api Vec3I clamp(Vec3I min, Vec3I val, Vec3I max) { - Vec3I result = vec3i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z)); - return result; -} -api Vec3I clamp(S32 min, Vec3I val, S32 max) { - Vec3I result = vec3i(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max)); - return result; -} -api Vec3I clamp01(Vec3I val) { - Vec3I result = vec3i(clamp01(val.x), clamp01(val.y), clamp01(val.z)); - return result; -} -api Vec4I v4i(S32 x, S32 y, S32 z, S32 w) { - Vec4I result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - return result; -} -api Vec4I v4i() { return v4i(0, 0, 0, 0); } -api Vec4I operator+(Vec4I a, Vec4I b) { - Vec4I result = v4i(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - return result; -} -api Vec4I operator+(Vec4I a, S32 b) { - Vec4I result = v4i(a.x + b, a.y + b, a.z + b, a.w + b); - return result; -} -api Vec4I operator+(S32 a, Vec4I b) { - Vec4I result = v4i(a + b.x, a + b.y, a + b.z, a + b.w); - return result; -} -api Vec4I &operator+=(Vec4I &a, Vec4I b) { - a = a + b; - return a; -} -api Vec4I &operator+=(Vec4I &a, S32 b) { - a = a + b; - return a; -} -api Vec4I operator-(Vec4I a, Vec4I b) { - Vec4I result = v4i(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); - return result; -} -api Vec4I operator-(Vec4I a, S32 b) { - Vec4I result = v4i(a.x - b, a.y - b, a.z - b, a.w - b); - return result; -} -api Vec4I operator-(S32 a, Vec4I b) { - Vec4I result = v4i(a - b.x, a - b.y, a - b.z, a - b.w); - return result; -} -api Vec4I &operator-=(Vec4I &a, Vec4I b) { - a = a - b; - return a; -} -api Vec4I &operator-=(Vec4I &a, S32 b) { - a = a - b; - return a; -} -api Vec4I operator*(Vec4I a, Vec4I b) { - Vec4I result = v4i(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); - return result; -} -api Vec4I operator*(Vec4I a, S32 b) { - Vec4I result = v4i(a.x * b, a.y * b, a.z * b, a.w * b); - return result; -} -api Vec4I operator*(S32 a, Vec4I b) { - Vec4I result = v4i(a * b.x, a * b.y, a * b.z, a * b.w); - return result; -} -api Vec4I &operator*=(Vec4I &a, Vec4I b) { - a = a * b; - return a; -} -api Vec4I &operator*=(Vec4I &a, S32 b) { - a = a * b; - return a; -} -api Vec4I operator/(Vec4I a, Vec4I b) { - Vec4I result = v4i(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); - return result; -} -api Vec4I operator/(Vec4I a, S32 b) { - Vec4I result = v4i(a.x / b, a.y / b, a.z / b, a.w / b); - return result; -} -api Vec4I operator/(S32 a, Vec4I b) { - Vec4I result = v4i(a / b.x, a / b.y, a / b.z, a / b.w); - return result; -} -api Vec4I &operator/=(Vec4I &a, Vec4I b) { - a = a / b; - return a; -} -api Vec4I &operator/=(Vec4I &a, S32 b) { - a = a / b; - return a; -} -api B32 operator!=(Vec4I a, Vec4I b) { - B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); - return result; -} -api B32 operator==(Vec4I a, Vec4I b) { - B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); - return result; -} -api Vec4I operator-(Vec4I a) { - Vec4I result = v4i(-a.x, -a.y, -a.z, -a.w); - return result; -} -api Vec4I clamp(Vec4I min, Vec4I val, Vec4I max) { - Vec4I result = v4i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z), - clamp(min.w, val.w, max.w)); - return result; -} -api Vec4I clamp(S32 min, Vec4I val, S32 max) { - Vec4I result = - v4i(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max), clamp(min, val.w, max)); - return result; -} -api Vec4I clamp01(Vec4I val) { - Vec4I result = v4i(clamp01(val.x), clamp01(val.y), clamp01(val.z), clamp01(val.w)); - return result; -} -api Rect2 rect2(F32 min_x, F32 min_y, F32 max_x, F32 max_y) { - Rect2 result; - result.min_x = min_x; - result.min_y = min_y; - result.max_x = max_x; - result.max_y = max_y; - return result; -} -api Rect2 rect2() { return rect2(0, 0, 0, 0); } -api Rect2 operator+(Rect2 a, Rect2 b) { - Rect2 result = rect2(a.min_x + b.min_x, a.min_y + b.min_y, a.max_x + b.max_x, a.max_y + b.max_y); - return result; -} -api Rect2 operator+(Rect2 a, F32 b) { - Rect2 result = rect2(a.min_x + b, a.min_y + b, a.max_x + b, a.max_y + b); - return result; -} -api Rect2 operator+(F32 a, Rect2 b) { - Rect2 result = rect2(a + b.min_x, a + b.min_y, a + b.max_x, a + b.max_y); - return result; -} -api Rect2 &operator+=(Rect2 &a, Rect2 b) { - a = a + b; - return a; -} -api Rect2 &operator+=(Rect2 &a, F32 b) { - a = a + b; - return a; -} -api Rect2 operator-(Rect2 a, Rect2 b) { - Rect2 result = rect2(a.min_x - b.min_x, a.min_y - b.min_y, a.max_x - b.max_x, a.max_y - b.max_y); - return result; -} -api Rect2 operator-(Rect2 a, F32 b) { - Rect2 result = rect2(a.min_x - b, a.min_y - b, a.max_x - b, a.max_y - b); - return result; -} -api Rect2 operator-(F32 a, Rect2 b) { - Rect2 result = rect2(a - b.min_x, a - b.min_y, a - b.max_x, a - b.max_y); - return result; -} -api Rect2 &operator-=(Rect2 &a, Rect2 b) { - a = a - b; - return a; -} -api Rect2 &operator-=(Rect2 &a, F32 b) { - a = a - b; - return a; -} -api Rect2 operator*(Rect2 a, Rect2 b) { - Rect2 result = rect2(a.min_x * b.min_x, a.min_y * b.min_y, a.max_x * b.max_x, a.max_y * b.max_y); - return result; -} -api Rect2 operator*(Rect2 a, F32 b) { - Rect2 result = rect2(a.min_x * b, a.min_y * b, a.max_x * b, a.max_y * b); - return result; -} -api Rect2 operator*(F32 a, Rect2 b) { - Rect2 result = rect2(a * b.min_x, a * b.min_y, a * b.max_x, a * b.max_y); - return result; -} -api Rect2 &operator*=(Rect2 &a, Rect2 b) { - a = a * b; - return a; -} -api Rect2 &operator*=(Rect2 &a, F32 b) { - a = a * b; - return a; -} -api Rect2 operator/(Rect2 a, Rect2 b) { - Rect2 result = rect2(a.min_x / b.min_x, a.min_y / b.min_y, a.max_x / b.max_x, a.max_y / b.max_y); - return result; -} -api Rect2 operator/(Rect2 a, F32 b) { - Rect2 result = rect2(a.min_x / b, a.min_y / b, a.max_x / b, a.max_y / b); - return result; -} -api Rect2 operator/(F32 a, Rect2 b) { - Rect2 result = rect2(a / b.min_x, a / b.min_y, a / b.max_x, a / b.max_y); - return result; -} -api Rect2 &operator/=(Rect2 &a, Rect2 b) { - a = a / b; - return a; -} -api Rect2 &operator/=(Rect2 &a, F32 b) { - a = a / b; - return a; -} -api B32 operator!=(Rect2 a, Rect2 b) { - B32 result = (a.min_x != b.min_x) || (a.min_y != b.min_y) || (a.max_x != b.max_x) || (a.max_y != b.max_y); - return result; -} -api B32 operator==(Rect2 a, Rect2 b) { - B32 result = (a.min_x == b.min_x) && (a.min_y == b.min_y) && (a.max_x == b.max_x) && (a.max_y == b.max_y); - return result; -} -api Rect2 operator-(Rect2 a) { - Rect2 result = rect2(-a.min_x, -a.min_y, -a.max_x, -a.max_y); - return result; -} -api Rect2 clamp(Rect2 min, Rect2 val, Rect2 max) { - Rect2 result = rect2(clamp(min.min_x, val.min_x, max.min_x), clamp(min.min_y, val.min_y, max.min_y), - clamp(min.max_x, val.max_x, max.max_x), clamp(min.max_y, val.max_y, max.max_y)); - return result; -} -api Rect2 clamp(F32 min, Rect2 val, F32 max) { - Rect2 result = rect2(clamp(min, val.min_x, max), clamp(min, val.min_y, max), clamp(min, val.max_x, max), - clamp(min, val.max_y, max)); - return result; -} -api Rect2 clamp01(Rect2 val) { - Rect2 result = rect2(clamp01(val.min_x), clamp01(val.min_y), clamp01(val.max_x), clamp01(val.max_y)); - return result; -} -api Rect2I rect2i(S32 min_x, S32 min_y, S32 max_x, S32 max_y) { - Rect2I result; - result.min_x = min_x; - result.min_y = min_y; - result.max_x = max_x; - result.max_y = max_y; - return result; -} -api Rect2I rect2i() { return rect2i(0, 0, 0, 0); } -api Rect2I operator+(Rect2I a, Rect2I b) { - Rect2I result = rect2i(a.min_x + b.min_x, a.min_y + b.min_y, a.max_x + b.max_x, a.max_y + b.max_y); - return result; -} -api Rect2I operator+(Rect2I a, S32 b) { - Rect2I result = rect2i(a.min_x + b, a.min_y + b, a.max_x + b, a.max_y + b); - return result; -} -api Rect2I operator+(S32 a, Rect2I b) { - Rect2I result = rect2i(a + b.min_x, a + b.min_y, a + b.max_x, a + b.max_y); - return result; -} -api Rect2I &operator+=(Rect2I &a, Rect2I b) { - a = a + b; - return a; -} -api Rect2I &operator+=(Rect2I &a, S32 b) { - a = a + b; - return a; -} -api Rect2I operator-(Rect2I a, Rect2I b) { - Rect2I result = rect2i(a.min_x - b.min_x, a.min_y - b.min_y, a.max_x - b.max_x, a.max_y - b.max_y); - return result; -} -api Rect2I operator-(Rect2I a, S32 b) { - Rect2I result = rect2i(a.min_x - b, a.min_y - b, a.max_x - b, a.max_y - b); - return result; -} -api Rect2I operator-(S32 a, Rect2I b) { - Rect2I result = rect2i(a - b.min_x, a - b.min_y, a - b.max_x, a - b.max_y); - return result; -} -api Rect2I &operator-=(Rect2I &a, Rect2I b) { - a = a - b; - return a; -} -api Rect2I &operator-=(Rect2I &a, S32 b) { - a = a - b; - return a; -} -api Rect2I operator*(Rect2I a, Rect2I b) { - Rect2I result = rect2i(a.min_x * b.min_x, a.min_y * b.min_y, a.max_x * b.max_x, a.max_y * b.max_y); - return result; -} -api Rect2I operator*(Rect2I a, S32 b) { - Rect2I result = rect2i(a.min_x * b, a.min_y * b, a.max_x * b, a.max_y * b); - return result; -} -api Rect2I operator*(S32 a, Rect2I b) { - Rect2I result = rect2i(a * b.min_x, a * b.min_y, a * b.max_x, a * b.max_y); - return result; -} -api Rect2I &operator*=(Rect2I &a, Rect2I b) { - a = a * b; - return a; -} -api Rect2I &operator*=(Rect2I &a, S32 b) { - a = a * b; - return a; -} -api Rect2I operator/(Rect2I a, Rect2I b) { - Rect2I result = rect2i(a.min_x / b.min_x, a.min_y / b.min_y, a.max_x / b.max_x, a.max_y / b.max_y); - return result; -} -api Rect2I operator/(Rect2I a, S32 b) { - Rect2I result = rect2i(a.min_x / b, a.min_y / b, a.max_x / b, a.max_y / b); - return result; -} -api Rect2I operator/(S32 a, Rect2I b) { - Rect2I result = rect2i(a / b.min_x, a / b.min_y, a / b.max_x, a / b.max_y); - return result; -} -api Rect2I &operator/=(Rect2I &a, Rect2I b) { - a = a / b; - return a; -} -api Rect2I &operator/=(Rect2I &a, S32 b) { - a = a / b; - return a; -} -api B32 operator!=(Rect2I a, Rect2I b) { - B32 result = (a.min_x != b.min_x) || (a.min_y != b.min_y) || (a.max_x != b.max_x) || (a.max_y != b.max_y); - return result; -} -api B32 operator==(Rect2I a, Rect2I b) { - B32 result = (a.min_x == b.min_x) && (a.min_y == b.min_y) && (a.max_x == b.max_x) && (a.max_y == b.max_y); - return result; -} -api Rect2I operator-(Rect2I a) { - Rect2I result = rect2i(-a.min_x, -a.min_y, -a.max_x, -a.max_y); - return result; -} -api Rect2I clamp(Rect2I min, Rect2I val, Rect2I max) { - Rect2I result = rect2i(clamp(min.min_x, val.min_x, max.min_x), clamp(min.min_y, val.min_y, max.min_y), - clamp(min.max_x, val.max_x, max.max_x), clamp(min.max_y, val.max_y, max.max_y)); - return result; -} -api Rect2I clamp(S32 min, Rect2I val, S32 max) { - Rect2I result = rect2i(clamp(min, val.min_x, max), clamp(min, val.min_y, max), clamp(min, val.max_x, max), - clamp(min, val.max_y, max)); - return result; -} -api Rect2I clamp01(Rect2I val) { - Rect2I result = rect2i(clamp01(val.min_x), clamp01(val.min_y), clamp01(val.max_x), clamp01(val.max_y)); - return result; -} -api Vec2 cast_v2(Vec2I a) { - Vec2 result = vec2((F32)(a.x), (F32)(a.y)); - return result; -} -api Vec2I cast_v2i(Vec2 a) { - Vec2I result = vec2i((S32)(a.x), (S32)(a.y)); - return result; -} -api Vec2I round_cast_v2i(Vec2 a) { - Vec2I result = vec2i((S32)round(a.x), (S32)round(a.y)); - return result; -} -api Vec2I ceil_cast_v2i(Vec2 a) { - Vec2I result = vec2i((S32)ceil(a.x), (S32)ceil(a.y)); - return result; -} -api Vec2I floor_cast_v2i(Vec2 a) { - Vec2I result = vec2i((S32)floor(a.x), (S32)floor(a.y)); - return result; -} -api Vec3 cast_v3(Vec3I a) { - Vec3 result = vec3((F32)(a.x), (F32)(a.y), (F32)(a.z)); - return result; -} -api Vec3I cast_v3i(Vec3 a) { - Vec3I result = vec3i((S32)(a.x), (S32)(a.y), (S32)(a.z)); - return result; -} -api Vec3I round_cast_v3i(Vec3 a) { - Vec3I result = vec3i((S32)round(a.x), (S32)round(a.y), (S32)round(a.z)); - return result; -} -api Vec3I ceil_cast_v3i(Vec3 a) { - Vec3I result = vec3i((S32)ceil(a.x), (S32)ceil(a.y), (S32)ceil(a.z)); - return result; -} -api Vec3I floor_cast_v3i(Vec3 a) { - Vec3I result = vec3i((S32)floor(a.x), (S32)floor(a.y), (S32)floor(a.z)); - return result; -} -api Vec4 cast_v4(Vec4I a) { - Vec4 result = vec4((F32)(a.x), (F32)(a.y), (F32)(a.z), (F32)(a.w)); - return result; -} -api Vec4I cast_v4i(Vec4 a) { - Vec4I result = v4i((S32)(a.x), (S32)(a.y), (S32)(a.z), (S32)(a.w)); - return result; -} -api Vec4I round_cast_v4i(Vec4 a) { - Vec4I result = v4i((S32)round(a.x), (S32)round(a.y), (S32)round(a.z), (S32)round(a.w)); - return result; -} -api Vec4I ceil_cast_v4i(Vec4 a) { - Vec4I result = v4i((S32)ceil(a.x), (S32)ceil(a.y), (S32)ceil(a.z), (S32)ceil(a.w)); - return result; -} -api Vec4I floor_cast_v4i(Vec4 a) { - Vec4I result = v4i((S32)floor(a.x), (S32)floor(a.y), (S32)floor(a.z), (S32)floor(a.w)); - return result; -} -api Rect2 cast_rect2(Rect2I a) { - Rect2 result = rect2((F32)(a.min_x), (F32)(a.min_y), (F32)(a.max_x), (F32)(a.max_y)); - return result; -} -api Rect2I cast_rect2i(Rect2 a) { - Rect2I result = rect2i((S32)(a.min_x), (S32)(a.min_y), (S32)(a.max_x), (S32)(a.max_y)); - return result; -} -api Rect2I round_cast_rect2i(Rect2 a) { - Rect2I result = rect2i((S32)round(a.min_x), (S32)round(a.min_y), (S32)round(a.max_x), (S32)round(a.max_y)); - return result; -} -api Rect2I ceil_cast_rect2i(Rect2 a) { - Rect2I result = rect2i((S32)ceil(a.min_x), (S32)ceil(a.min_y), (S32)ceil(a.max_x), (S32)ceil(a.max_y)); - return result; -} -api Rect2I floor_cast_rect2i(Rect2 a) { - Rect2I result = rect2i((S32)floor(a.min_x), (S32)floor(a.min_y), (S32)floor(a.max_x), (S32)floor(a.max_y)); - return result; -} -api Rect2I rect2i(Vec2I a, Vec2I b) { - Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); - return result; -} -api Rect2I rect2i(S32 a, Vec3I b) { - Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); - return result; -} -api Rect2I rect2i(Vec3I a, S32 b) { - Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); - return result; -} -api Rect2I rect2i(Vec2I a, S32 b, S32 c) { - Rect2I result = rect2i(a.p[0], a.p[1], b, c); - return result; -} -api Rect2I rect2i(S32 a, S32 b, Vec2I c) { - Rect2I result = rect2i(a, b, c.p[0], c.p[1]); - return result; -} -api Vec4I v4i(Vec2I a, Vec2I b) { - Vec4I result = v4i(a.p[0], a.p[1], b.p[0], b.p[1]); - return result; -} -api Vec4I v4i(S32 a, Vec3I b) { - Vec4I result = v4i(a, b.p[0], b.p[1], b.p[2]); - return result; -} -api Vec4I v4i(Vec3I a, S32 b) { - Vec4I result = v4i(a.p[0], a.p[1], a.p[2], b); - return result; -} -api Vec4I v4i(Vec2I a, S32 b, S32 c) { - Vec4I result = v4i(a.p[0], a.p[1], b, c); - return result; -} -api Vec4I v4i(S32 a, S32 b, Vec2I c) { - Vec4I result = v4i(a, b, c.p[0], c.p[1]); - return result; -} -api Rect2 rect2(Vec2 a, Vec2 b) { - Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); - return result; -} -api Rect2 rect2(F32 a, Vec3 b) { - Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); - return result; -} -api Rect2 rect2(Vec3 a, F32 b) { - Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); - return result; -} -api Rect2 rect2(Vec2 a, F32 b, F32 c) { - Rect2 result = rect2(a.p[0], a.p[1], b, c); - return result; -} -api Rect2 rect2(F32 a, F32 b, Vec2 c) { - Rect2 result = rect2(a, b, c.p[0], c.p[1]); - return result; -} -api Vec4 vec4(Vec2 a, Vec2 b) { - Vec4 result = vec4(a.p[0], a.p[1], b.p[0], b.p[1]); - return result; -} -api Vec4 vec4(F32 a, Vec3 b) { - Vec4 result = vec4(a, b.p[0], b.p[1], b.p[2]); - return result; -} -api Vec4 vec4(Vec3 a, F32 b) { - Vec4 result = vec4(a.p[0], a.p[1], a.p[2], b); - return result; -} -api Vec4 vec4(Vec2 a, F32 b, F32 c) { - Vec4 result = vec4(a.p[0], a.p[1], b, c); - return result; -} -api Vec4 vec4(F32 a, F32 b, Vec2 c) { - Vec4 result = vec4(a, b, c.p[0], c.p[1]); - return result; -} -api Rect2 rect2_min_size(Vec2 a, Vec2 b) { - Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); - result.max += result.min; - return result; -} -api Rect2 rect2_min_size(F32 a, Vec3 b) { - Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); - result.max += result.min; - return result; -} -api Rect2 rect2_min_size(Vec3 a, F32 b) { - Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); - result.max += result.min; - return result; -} -api Rect2 rect2_min_size(Vec2 a, F32 b, F32 c) { - Rect2 result = rect2(a.p[0], a.p[1], b, c); - result.max += result.min; - return result; -} -api Rect2 rect2_min_size(F32 a, F32 b, Vec2 c) { - Rect2 result = rect2(a, b, c.p[0], c.p[1]); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(Vec2I a, Vec2I b) { - Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(S32 a, Vec3I b) { - Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(Vec3I a, S32 b) { - Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(Vec2I a, S32 b, S32 c) { - Rect2I result = rect2i(a.p[0], a.p[1], b, c); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(S32 a, S32 b, Vec2I c) { - Rect2I result = rect2i(a, b, c.p[0], c.p[1]); - result.max += result.min; - return result; -} -api Rect2 rect2_center_half_dim(Vec2 a, Vec2 b) { - Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2 rect2_center_half_dim(F32 a, Vec3 b) { - Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2 rect2_center_half_dim(Vec3 a, F32 b) { - Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2 rect2_center_half_dim(Vec2 a, F32 b, F32 c) { - Rect2 result = rect2(a.p[0], a.p[1], b, c); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2 rect2_center_half_dim(F32 a, F32 b, Vec2 c) { - Rect2 result = rect2(a, b, c.p[0], c.p[1]); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(Vec2I a, Vec2I b) { - Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(S32 a, Vec3I b) { - Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(Vec3I a, S32 b) { - Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(Vec2I a, S32 b, S32 c) { - Rect2I result = rect2i(a.p[0], a.p[1], b, c); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(S32 a, S32 b, Vec2I c) { - Rect2I result = rect2i(a, b, c.p[0], c.p[1]); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2 rect2_min_size(F32 a, F32 b, F32 c, F32 d) { - Rect2 result = rect2(a, b, c, d); - result.max += result.min; - return result; -} -api Rect2I rect2i_min_size(S32 a, S32 b, S32 c, S32 d) { - Rect2I result = rect2i(a, b, c, d); - result.max += result.min; - return result; -} -api Rect2 rect2_center_half_dim(F32 a, F32 b, F32 c, F32 d) { - Rect2 result = rect2(a, b, c, d); - Vec2 center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Rect2I rect2i_center_half_dim(S32 a, S32 b, S32 c, S32 d) { - Rect2I result = rect2i(a, b, c, d); - Vec2I center = result.min; - result.min -= result.max; - result.max += center; - return result; -} -api Vec3 vec3(F32 a, Vec2 b) { - Vec3 result = vec3(a, b.p[0], b.p[1]); - return result; -} -api Vec3 vec3(Vec2 a, F32 b) { - Vec3 result = vec3(a.p[0], a.p[1], b); - return result; -} -api Vec3I vec3i(S32 a, Vec2I b) { - Vec3I result = vec3i(a, b.p[0], b.p[1]); - return result; -} -api Vec3I vec3i(Vec2I a, S32 b) { - Vec3I result = vec3i(a.p[0], a.p[1], b); - return result; -} - -api Rect2I intersect(Rect2I a, Rect2I clip) { - Rect2I result; - result.min.x = max(a.min.x, clip.min.x); - result.min.y = max(a.min.y, clip.min.y); - result.max.x = min(a.max.x, clip.max.x); - result.max.y = min(a.max.y, clip.max.y); - return result; -} - -api B32 has_area(Rect2I a) { - B32 result = (a.max_x - a.min_x > 0) && (a.max_y - a.min_y > 0); - return result; -} - -api Rect2 intersect(Rect2 a, Rect2 clip) { - Rect2 result; - result.min.x = max(a.min.x, clip.min.x); - result.min.y = max(a.min.y, clip.min.y); - result.max.x = min(a.max.x, clip.max.x); - result.max.y = min(a.max.y, clip.max.y); - return result; -} - -api B32 has_area(Rect2 a) { - B32 result = (a.max_x - a.min_x > 0) && (a.max_y - a.min_y > 0); - return result; -} - -api Vec2 perp(Vec2 a) { - Vec2 result = vec2(-a.y, a.x); - return result; -} - -api Vec4 vec4argb(U32 v) { - U8 a = (v >> 24) & 0x000000ff; - U8 r = (v >> 16) & 0x000000ff; - U8 g = (v >> 8) & 0x000000ff; - U8 b = (v >> 0) & 0x000000ff; - Vec4 result = vec4((F32)r / 255.f, (F32)g / 255.f, (F32)b / 255.f, (F32)a / 255.f); - return result; -} - -api Vec4 vec4abgr(U32 c) { - float a = ((c & 0xff000000) >> 24) / 255.f; - float b = ((c & 0x00ff0000) >> 16) / 255.f; - float g = ((c & 0x0000ff00) >> 8) / 255.f; - float r = ((c & 0x000000ff) >> 0) / 255.f; - Vec4 result = vec4(r, g, b, a); - return result; -} - -api U32 vec4_to_u32argb(Vec4 c) { - U32 result = (U32)((U8)(c.a * 255.f) << 24u | (U8)(c.r * 255.f) << 16u | (U8)(c.g * 255.f) << 8u | - (U8)(c.b * 255.f) << 0u); - return result; -} - -api U32 vec4_to_u32abgr(Vec4 color) { - U8 red = (U8)(color.r * 255); - U8 green = (U8)(color.g * 255); - U8 blue = (U8)(color.b * 255); - U8 alpha = (U8)(color.a * 255); - U32 result = (U32)(alpha << 24 | blue << 16 | green << 8 | red << 0); - return result; -} - -api Mat4 operator*(Mat4 a, Mat4 b) { - Mat4 result; - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - result.p[y][x] = - a.p[y][0] * b.p[0][x] + a.p[y][1] * b.p[1][x] + a.p[y][2] * b.p[2][x] + a.p[y][3] * b.p[3][x]; - } - } - return result; -} - -api Vec4 operator*(Mat4 a, Vec4 b) { - Vec4 result; - for (int y = 0; y < 4; y++) { - result.p[y] = a.p[y][0] * b.p[0] + a.p[y][1] * b.p[1] + a.p[y][2] * b.p[2] + a.p[y][3] * b.p[3]; - } - return result; -} - -api Vec3 operator*(Mat4 a, Vec3 b) { - Vec4 result; - for (int y = 0; y < 4; y++) - result.p[y] = a.p[y][0] * b.p[0] + a.p[y][1] * b.p[1] + a.p[y][2] * b.p[2] + a.p[y][3] * 1; - return result.xyz; -} - -api Vec3 cross(Vec3 a, Vec3 b) { - Vec3 result; - result.x = a.y * b.z - a.z * b.y; - result.y = a.z * b.x - a.x * b.z; - result.z = a.x * b.y - a.y * b.x; - return result; -} - -api Vec2 normalize(Vec2 a) { - Vec2 result = {}; - F32 len = length(a); - if (len != 0.f) { - F32 inv_len = 1.0f / len; - result.x = a.x * inv_len; - result.y = a.y * inv_len; - } - return result; -} - -api Vec3 normalize(Vec3 a) { - Vec3 result = {}; - F32 len = length(a); - if (len != 0.f) { - F32 inv_len = 1.0f / len; - result.x = a.x * inv_len; - result.y = a.y * inv_len; - result.z = a.z * inv_len; - } - return result; -} - -api Vec4 normalize(Vec4 a) { - Vec4 result = {}; - F32 len = length(a); - if (len != 0.f) { - F32 inv_len = 1.0f / len; - result.x = a.x * inv_len; - result.y = a.y * inv_len; - result.z = a.z * inv_len; - result.w = a.w * inv_len; - } - return result; -} - -function -Mat4 mat4_identity() { - Mat4 result = {}; - result.p[0][0] = 1; - result.p[1][1] = 1; - result.p[2][2] = 1; - result.p[3][3] = 1; - return result; -} - -function -Mat4 mat4_scale(Vec3 a) { - Mat4 result = {}; - result.p[0][0] = a.x; - result.p[1][1] = a.y; - result.p[2][2] = a.z; - result.p[3][3] = 1; - return result; -} - -function -Mat4 mat4_translation(Vec3 a) { - return { - 1, 0, 0, a.x, - 0, 1, 0, a.y, - 0, 0, 1, a.z, - 0, 0, 0, 1 - }; -} - -function -Mat4 mat4_rotation_z(float rotation) { - float s = sinf(rotation); - float c = cosf(rotation); - Mat4 result = { - c, s, 0, 0, - -s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, - }; - return result; -} - -function -Mat4 mat4_rotation_y(float rotation) { - float s = sinf(rotation); - float c = cosf(rotation); - Mat4 result = { - c, 0, -s, 0, - 0, 1, 0, 0, - s, 0, c, 0, - 0, 0, 0, 1, - }; - return result; -} - -function -Mat4 mat4_rotation_x(float rotation) { - float s = sinf(rotation); - float c = cosf(rotation); - Mat4 result = { - 1, 0, 0, 0, - 0, c, s, 0, - 0, -s, c, 0, - 0, 0, 0, 1, - }; - return result; -} - -constexpr F32 deg2rad = (PI32 / 180.f); // @Usage: degree * deg2rad = radians; -constexpr F32 rad2deg = (180.f / PI32); -function -Mat4 mat4_perspective(float fov, float window_x, float window_y, float znear, float zfar) { - float aspect_ratio = window_y / window_x; - float f = (1.f / tanf((fov/2.f)*deg2rad)); - Mat4 result = { - aspect_ratio*f, 0, 0, 0, - 0, f, 0, 0, - 0, 0, (zfar)-(zfar-znear),(-zfar*znear)-(zfar - znear), - 0,0,1,0 - }; - return result; -} - -function Mat4 mat4_look_at(Vec3 pos, Vec3 target, Vec3 up) { - Vec3 z = normalize(target - pos); - Vec3 x = normalize(cross(up, z)); - Vec3 y = cross(z, x); - Mat4 result = { - x.x,x.y,x.z,-dot(x,pos), - y.x,y.y,y.z,-dot(y,pos), - z.x,z.y,z.z,-dot(z,pos), - 0,0,0, 1, - }; - return result; -} - -function -Mat4 mat4_transpose(Mat4 a) { - Mat4 result = a; - result.p[0][1] = result.p[1][0]; - result.p[0][2] = result.p[2][0]; - result.p[0][3] = result.p[3][0]; - result.p[2][1] = result.p[1][2]; - result.p[3][1] = result.p[1][3]; - result.p[3][2] = result.p[2][3]; - return result; -} - -function -Mat4 mat4_translate(Mat4 a, Vec3 translation) { - a.p[0][0] += translation.x; - a.p[0][1] += translation.y; - a.p[0][2] += translation.z; - return a; -} \ No newline at end of file diff --git a/base_string.cpp b/base_string.cpp deleted file mode 100644 index 57ee60a..0000000 --- a/base_string.cpp +++ /dev/null @@ -1,476 +0,0 @@ - -function U8 -to_lower_case(U8 a) { - if (a >= 'A' && a <= 'Z') - a += 32; - return a; -} - -function U8 -to_upper_case(U8 a) { - if (a >= 'a' && a <= 'z') - a -= 32; - return a; -} - -function U8 -char_to_lower(U8 c){ - if(c >= 'A' && c <= 'Z') - c += 32; - return c; -} - -function U8 -char_to_upper(U8 c){ - if(c >= 'a' && c <= 'z') - c -= 32; - return c; -} - -function B32 -is_whitespace(U8 w) { - bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r'; - return result; -} - -function B32 -is_alphabetic(U8 a) { - if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) { - return true; - } - return false; -} - -function B32 -is_number(U8 a) { - B32 result = a >= '0' && a <= '9'; - return result; -} - -function B32 -is_alphanumeric(U8 a) { - B32 result = is_number(a) || is_alphabetic(a); - return result; -} - -function B32 -string_compare(String a, String b, B32 ignore_case = false) { - if (a.len != b.len) - return false; - for (S64 i = 0; i < a.len; i++) { - U8 A = a.str[i]; - U8 B = b.str[i]; - if (ignore_case) { - A = to_lower_case(A); - B = to_lower_case(B); - } - if (A != B) - return false; - } - return true; -} - -function B32 -operator==(String a, String b){ - return string_compare(a,b); -} - -function String -string_copy(Allocator *a, String string){ - U8 *copy = exp_alloc_array(a, U8, string.len+1); - memory_copy(copy, string.str, string.len); - copy[string.len] = 0; - return String{copy, string.len}; -} - -function String -string_fmtv(Allocator *a, const char *str, va_list args1) { - va_list args2; - va_copy(args2, args1); - S64 len = stbsp_vsnprintf(0, 0, str, args2); - va_end(args2); - - char *result = exp_alloc_array(a, char, len + 1); - stbsp_vsnprintf(result, len + 1, str, args1); - - String res = {(U8 *)result, len}; - return res; -} - -#define STRING_FMT(alloc, str, result) \ -va_list args1; \ -va_start(args1, str); \ -String result = string_fmtv(alloc, str, args1); \ -va_end(args1) - -function String -string_fmt(Allocator *a, const char *str, ...) { - STRING_FMT(a, str, result); - return result; -} - -//----------------------------------------------------------------------------- -// String builder -//----------------------------------------------------------------------------- -struct String_Builder_Block{ - String_Builder_Block *next; - S64 cap; - S64 len; - U8 data[0]; -}; - -struct String_Builder{ - Allocator *allocator; - String_Builder_Block *first_free; - String_Builder_Block *first; - String_Builder_Block *last; - U64 di; - - void reset(){ - for(;;){ - auto *block = first; - first = first->next; - - block->next = first_free; - first_free = block; - - if(!first) break; - } - - last = 0; - assert(!last && !first); - } - - void push_block(SizeU size){ - String_Builder_Block *block = 0; - if(first_free){ - block = first_free; - first_free = first_free->next; - } else{ - block = (String_Builder_Block *)exp_alloc(allocator, sizeof(String_Builder_Block) + size); - } - memory_zero(block, sizeof(String_Builder_Block)+1); // Also clear first byte of character data - block->cap = size; - SLLQueuePush(first, last, block); - } - - void init(S64 size = 4096){ - assert(allocator); - push_block(size); - } - - void append_data(void *data, S64 size){ - if(first == 0){ - init(); - } - - S64 remaining_cap = last->cap - last->len; - if(size > remaining_cap){ - S64 new_block_size = max(last->cap*2, size*2); - push_block(new_block_size); - } - - U8 *write_address = last->data + last->len; - last->len += size; - memory_copy(write_address, data, size); - } - - void addf(const char *str, ...){ - if(first == 0){ - init(); - } - va_list args, args2; - va_start(args, str); - retry:{ - String_Builder_Block *block = last; - S64 block_size = block->cap - block->len; - char *write_address = (char *)block->data + block->len; - - va_copy(args2, args); - int written = stbsp_vsnprintf(write_address, block_size, str, args2); - va_end(args2); - - if(written > (block_size-1)){ - S64 new_block_size = max(4096, (written+1)*2); - push_block(new_block_size); - goto retry; - } - block->len += written; - } - va_end(args); - di++; - } -}; - -function String_Builder -string_builder_make(Allocator *a, S64 first_block_size = 4096){ - String_Builder sb = {a}; - sb.init(first_block_size); - return sb; -} - -enum String_Builder_Flag{ - String_Builder_Flag_None = 0, - String_Builder_Flag_AddSize = 0, -}; - -function String -string_flatten(Allocator *a, String_Builder *b, String_Builder_Flag flags = String_Builder_Flag_None){ - // @Note(Krzosa): Compute size to allocate - S64 size = 1; - if(is_flag_set(flags, String_Builder_Flag_AddSize)) size += sizeof(SizeU); - For_List(b){ - size += it->len; - } - - String result = {}; - result.str = (U8 *)exp_alloc(a, size); - if(is_flag_set(flags, String_Builder_Flag_AddSize)) { - memory_copy(result.str + result.len, &size, sizeof(S64)); - result.len += sizeof(S64); - } - - // @Note(Krzosa): Copy the content of each block into the string - For_List(b){ - memory_copy(result.str + result.len, it->data, it->len); - result.len += it->len; - } - - result.str[result.len] = 0; - return result; -} - -function void -test_string_builder(){ - Scratch scratch; - String_Builder sb = string_builder_make(scratch, 4); - sb.addf("Thing, %d", 242252); - String f = string_flatten(scratch, &sb); - assert(string_compare(f, "Thing, 242252"_s)); - sb.addf("-%f %f %f", 23.0, 42.29, 2925.2); - f = string_flatten(scratch, &sb); - sb.reset(); -} - -//----------------------------------------------------------------------------- -// String ops -//----------------------------------------------------------------------------- -function void -string_path_normalize(String s) { - for (S64 i = 0; i < s.len; i++) { - if (s.str[i] == '\\') - s.str[i] = '/'; - } -} - -function String -string_make(char *str, S64 len) { - String result; - result.str = (U8 *)str; - result.len = len; - return result; -} - -function String -string_make(U8 *str, S64 len) { - return string_make((char*)str, len); -} - -function String -string_chop(String string, S64 len) { - len = clamp_top(len, string.len); - String result = string_make(string.str, string.len - len); - return result; -} - -function String -string_skip(String string, S64 len) { - len = clamp_top(len, string.len); - S64 remain = string.len - len; - String result = string_make(string.str + len, remain); - return result; -} - -function String -string_get_postfix(String string, S64 len) { - len = clamp_top(len, string.len); - S64 remain_len = string.len - len; - String result = string_make(string.str + remain_len, len); - return result; -} - -function String -string_get_prefix(String string, S64 len) { - len = clamp_top(len, string.len); - String result = string_make(string.str, len); - return result; -} - -function String -string_slice(String string, S64 first_index, S64 one_past_last_index) { - assert_msg(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index"); - assert_msg(string.len > 0, "Slicing string of length 0! Might be an error!"); - String result = string; - if (string.len > 0) { - if (one_past_last_index > first_index) { - first_index = clamp_top(first_index, string.len - 1); - one_past_last_index = clamp_top(one_past_last_index, string.len); - result.str += first_index; - result.len = one_past_last_index - first_index; - } - else { - result.len = 0; - } - } - return result; -} - -function String -string_trim(String string) { - if (string.len == 0) return string; - - - S64 whitespace_begin = 0; - for (; whitespace_begin < string.len; whitespace_begin++) { - if (!is_whitespace(string.str[whitespace_begin])) { - break; - } - } - - S64 whitespace_end = string.len; - for (; whitespace_end != whitespace_begin; whitespace_end--) { - if (!is_whitespace(string.str[whitespace_end - 1])) { - break; - } - } - - if (whitespace_begin == whitespace_end) { - string.len = 0; - } - else { - string = string_slice(string, whitespace_begin, whitespace_end); - } - - return string; -} - -function String -string_trim_end(String string) { - S64 whitespace_end = string.len; - for (; whitespace_end != 0; whitespace_end--) { - if (!is_whitespace(string.str[whitespace_end - 1])) { - break; - } - } - - String result = string_get_prefix(string, whitespace_end); - return result; -} - -function String -string_to_lower_case(Allocator *arena, String s) { - String copy = string_copy(arena, s); - for (U64 i = 0; i < copy.len; i++) { - copy.str[i] = to_lower_case(copy.str[i]); - } - return copy; -} - -function String -string_to_upper_case(Allocator *arena, String s) { - String copy = string_copy(arena, s); - for (U64 i = 0; i < copy.len; i++) { - copy.str[i] = to_upper_case(copy.str[i]); - } - return copy; -} - -FLAG32(MatchFlag){ - MatchFlag_None=0, - MatchFlag_FindLast=1, - MatchFlag_IgnoreCase=2, -}; - -function B32 -string_find(String string, String find, MatchFlag flags, S64 *index_out) { - B32 result = false; - if (flags & MatchFlag_FindLast) { - for (S64 i = string.len; i != 0; i--) { - S64 index = i - 1; - String substring = string_slice(string, index, index + find.len); - if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { - if (index_out) - *index_out = index; - result = true; - break; - } - } - } - else { - for (S64 i = 0; i < string.len; i++) { - String substring = string_slice(string, i, i + find.len); - if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { - if (index_out) - *index_out = i; - result = true; - break; - } - } - } - - return result; -} - -function String -string_chop_last_slash(String s) { - String result = s; - string_find(s, "/"_s, MatchFlag_FindLast, &result.len); - return result; -} - -function String -string_chop_last_period(String s) { - String result = s; - string_find(s, "."_s, MatchFlag_FindLast, &result.len); - return result; -} - -function String -string_skip_to_last_slash(String s) { - S64 pos; - String result = s; - if (string_find(s, "/"_s, MatchFlag_FindLast, &pos)) { - result = string_skip(result, pos + 1); - } - return result; -} - -function String -string_skip_to_last_period(String s) { - S64 pos; - String result = s; - if (string_find(s, "."_s, MatchFlag_FindLast, &pos)) { - result = string_skip(result, pos + 1); - } - return result; -} - -function S64 -string_len(char *string){ - S64 len = 0; - while(*string++!=0)len++; - return len; -} - -function String -string_from_cstring(char *string){ - String result; - result.str = (U8 *)string; - result.len = string_len(string); - return result; -} - - - - - diff --git a/base_unicode.cpp b/base_unicode.cpp deleted file mode 100644 index c613c81..0000000 --- a/base_unicode.cpp +++ /dev/null @@ -1,379 +0,0 @@ -global U32 question_mark32 = '?'; -global U16 question_mark16 = 0x003f; -global U8 question_mark8 = '?'; - -struct String32{ - U32 *str; - S64 len; -}; - -struct UTF32_Result{ - U32 out_str; - S64 advance; - B32 error; -}; - -function UTF32_Result -utf8_to_utf32(U8 *c, S64 max_advance) { - UTF32_Result result = {}; - - if ((c[0] & 0b10000000) == 0) { // Check if leftmost zero of first byte is unset - if(max_advance >= 1){ - result.out_str = c[0]; - result.advance = 1; - } - else result.error = 1; - } - - else if ((c[0] & 0b11100000) == 0b11000000) { - if ((c[1] & 0b11000000) == 0b10000000) { // Continuation byte required - if(max_advance >= 2){ - result.out_str = (U32)(c[0] & 0b00011111) << 6u | (c[1] & 0b00111111); - result.advance = 2; - } - else result.error = 2; - } - else result.error = 2; - } - - else if ((c[0] & 0b11110000) == 0b11100000) { - if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000) { // Two continuation bytes required - if(max_advance >= 3){ - result.out_str = (U32)(c[0] & 0b00001111) << 12u | (U32)(c[1] & 0b00111111) << 6u | (c[2] & 0b00111111); - result.advance = 3; - } - else result.error = 3; - } - else result.error = 3; - } - - else if ((c[0] & 0b11111000) == 0b11110000) { - if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000) { // Three continuation bytes required - if(max_advance >= 4){ - result.out_str = (U32)(c[0] & 0b00001111) << 18u | (U32)(c[1] & 0b00111111) << 12u | (U32)(c[2] & 0b00111111) << 6u | (U32)(c[3] & 0b00111111); - result.advance = 4; - } - else result.error = 4; - } - else result.error = 4; - } - else result.error = 4; - - return result; -} - -struct String16{ - U16 *str; - S64 len; -}; - -struct UTF16_Result{ - U16 out_str[2]; - S32 len; - B32 error; -}; - -function UTF16_Result -utf32_to_utf16(U32 codepoint){ - UTF16_Result result = {}; - if (codepoint < 0x10000) { - result.out_str[0] = (U16)codepoint; - result.out_str[1] = 0; - result.len = 1; - } - else if (codepoint <= 0x10FFFF) { - U32 code = (codepoint - 0x10000); - result.out_str[0] = (U16)(0xD800 | (code >> 10)); - result.out_str[1] = (U16)(0xDC00 | (code & 0x3FF)); - result.len = 2; - } - else{ - result.error = 1; - } - - return result; -} - -struct UTF8_Result{ - U8 out_str[4]; - S32 len; - B32 error; -}; - -function UTF8_Result -utf32_to_utf8(U32 codepoint) { - UTF8_Result result = {}; - if (codepoint <= 0x7F) { - result.len = 1; - result.out_str[0] = (U8)codepoint; - } - else if (codepoint <= 0x7FF) { - result.len= 2; - result.out_str[0] = 0b11000000 | (0b00011111 & (codepoint >> 6)); - result.out_str[1] = 0b10000000 | (0b00111111 & codepoint); - } - else if (codepoint <= 0xFFFF) { // 16 bit word - result.len= 3; - result.out_str[0] = 0b11100000 | (0b00001111 & (codepoint >> 12)); // 4 bits - result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits - result.out_str[2] = 0b10000000 | (0b00111111 & codepoint); // 6 bits - } - else if (codepoint <= 0x10FFFF) { // 21 bit word - result.len= 4; - result.out_str[0] = 0b11110000 | (0b00000111 & (codepoint >> 18)); // 3 bits - result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 12)); // 6 bits - result.out_str[2] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits - result.out_str[3] = 0b10000000 | (0b00111111 & codepoint); // 6 bits - } - else{ - result.error = true; - } - - return result; -} - -function UTF32_Result -utf16_to_utf32(U16 *c, S32 max_advance) { - UTF32_Result result = {}; - if(max_advance >= 1){ - result.advance = 1; - result.out_str = c[0]; - if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) { - if(max_advance >= 2){ - result.out_str = 0x10000; - result.out_str += (U32)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF); - result.advance = 2; - } - else result.error = 2; - } - } - else result.error = 1; - - return result; -} - -#define unicode_error(question_mark) \ - { \ - result.str[result.len++] = question_mark; \ - break; \ - } - -function String32 -string16_to_string32(Allocator *allocator, String16 string){ - String32 result = {exp_alloc_array(allocator, U32, string.len+1)}; - for(S64 i = 0; i < string.len;){ - UTF32_Result decode = utf16_to_utf32(string.str + i, string.len - i); - if(!decode.error){ - i += decode.advance; - result.str[result.len++] = decode.out_str; - } - else unicode_error(question_mark32); - } - - result.str[result.len] = 0; - return result; -} - -function String32 -string8_to_string32(Allocator *allocator, String string){ - String32 result = {exp_alloc_array(allocator, U32, string.len+1)}; - for(S64 i = 0; i < string.len;){ - UTF32_Result decode = utf8_to_utf32(string.str + i, string.len - i); - if(!decode.error){ - i += decode.advance; - result.str[result.len++] = decode.out_str; - } - else unicode_error(question_mark32); - } - result.str[result.len] = 0; - return result; -} - -function String16 -string8_to_string16(Allocator *allocator, String in){ - String16 result = {exp_alloc_array(allocator, U16, (in.len*2)+1)}; // @Note(Krzosa): Should be more then enough space - for(S64 i = 0; i < in.len;){ - UTF32_Result decode = utf8_to_utf32(in.str + i, in.len - i); - if(!decode.error){ - i += decode.advance; - UTF16_Result encode = utf32_to_utf16(decode.out_str); - if(!encode.error){ - for(S32 j = 0; j < encode.len; j++){ - result.str[result.len++] = encode.out_str[j]; - } - } - else unicode_error(question_mark16); - } - else unicode_error(question_mark16); - } - - result.str[result.len] = 0; - return result; -} - -function String -string16_to_string8(Allocator *allocator, String16 in){ - String result = {exp_alloc_array(allocator, U8, in.len*4+1)}; - for(S64 i = 0; i < in.len;){ - UTF32_Result decode = utf16_to_utf32(in.str + i, in.len - i); - if(!decode.error){ - i += decode.advance; - UTF8_Result encode = utf32_to_utf8(decode.out_str); - if(!encode.error){ - for(S32 j = 0; j < encode.len; j++) - result.str[result.len++] = encode.out_str[j]; - } - else unicode_error(question_mark8); - } - else unicode_error(question_mark8); - } - - result.str[result.len] = 0; - return result; -} - -function B32 -string_compare(String16 a, String16 b){ - if(a.len != b.len) return false; - for(S64 i = 0; i < a.len; i++){ - if(a.str[i] != b.str[i]) return false; - } - return true; -} - -function B32 -string_compare(String32 a, String32 b){ - if(a.len != b.len) return false; - for(S64 i = 0; i < a.len; i++){ - if(a.str[i] != b.str[i]) return false; - } - return true; -} - -function S64 -widechar_len(wchar_t *string){ - S64 len = 0; - while(*string++!=0)len++; - return len; -} - -function String16 -string16_from_widechar(wchar_t *string){ - String16 result; - result.str = (U16 *)string; - result.len = widechar_len(string); - return result; -} - -function String -string16_copy(Allocator *a, String string){ - U8 *copy = exp_alloc_array(a, U8, string.len+1); - memory_copy(copy, string.str, string.len); - copy[string.len] = 0; - return String{copy, string.len}; -} - -function void -test_unicode(){ - assert(utf8_to_utf32((U8 *)"A", 1).out_str == 'A'); - assert(utf8_to_utf32((U8 *)"ć", 2).out_str == 0x107); - assert(utf8_to_utf32((U8 *)"ó", 2).out_str == 0x000000f3); - - Scratch scratch; - String32 result = string8_to_string32(scratch, "Thing"_s); - assert(result.len == 5); - assert(result.str[0] == 'T'); - assert(result.str[4] == 'g'); - result = string8_to_string32(scratch, "óźćłŁQ42-=?"_s); - { - U16 u16_code[] = {0x0054, 0x0068, 0x0069, 0x006e, 0x0067, 0x0020, 0x0069, 0x0073}; - String16 thing_is16 = {u16_code, buff_cap(u16_code)}; - String string = "Thing is"_s; - String16 thing_is_convert = string8_to_string16(scratch, string); - assert(string_compare(thing_is16, thing_is_convert)); - - String32 a = string16_to_string32(scratch, thing_is16); - String32 b = string16_to_string32(scratch, thing_is_convert); - String32 c = string8_to_string32 (scratch, string); - assert(string_compare(a, b) && string_compare(b,c)); - } - - { - U16 code[] = {0x015a, 0x0104, 0x00f3, 0x015b, 0x017a, 0x0107, 0x0144, 0x0143, 0x0119, 0x00f3}; - String16 code_str = {code, buff_cap(code)}; - String string = "ŚĄóśźćńŃęó"_s; - String16 convert = string8_to_string16(scratch, string); - assert(string_compare(convert, code_str)); - - String32 a = string16_to_string32(scratch, code_str); - String32 b = string16_to_string32(scratch, convert); - String32 c = string8_to_string32 (scratch, string); - assert(string_compare(a, b) && string_compare(b,c)); - } - - { - String str = " ം ഃ അ ആ ഇ ഈ ഉ ഊ ഋ ഌ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഠ ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര റ ല ള ഴ വ ശ ഷ സ ഹ ാ ി ീ ു ൂ ൃ െ േ ൈ ൊ ോ ൌ ് ൗ ൠ ൡ ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯ "_s; - U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0x0d02, 0x0020, 0x0d03, 0x0020, 0x0d05, 0x0020, 0x0d06, 0x0020, 0x0d07, 0x0020, 0x0d08, 0x0020, 0x0d09, 0x0020, 0x0d0a, 0x0020, 0x0d0b, 0x0020, 0x0d0c, 0x0020, 0x0d0e, 0x0020, 0x0d0f, 0x0020, 0x0d10, 0x0020, 0x0d12, 0x0020, 0x0d13, 0x0020, 0x0d14, 0x0020, 0x0d15, 0x0020, 0x0d16, 0x0020, 0x0d17, 0x0020, 0x0d18, 0x0020, 0x0d19, 0x0020, 0x0d1a, 0x0020, 0x0d1b, 0x0020, 0x0d1c, 0x0020, 0x0d1d, 0x0020, 0x0d1e, 0x0020, 0x0d1f, 0x0020, 0x0d20, 0x0020, 0x0d21, 0x0020, 0x0d22, 0x0020, 0x0d23, 0x0020, 0x0d24, 0x0020, 0x0d25, 0x0020, 0x0d26, 0x0020, 0x0d27, 0x0020, 0x0d28, 0x0020, 0x0d2a, 0x0020, 0x0d2b, 0x0020, 0x0d2c, 0x0020, 0x0d2d, 0x0020, 0x0d2e, 0x0020, 0x0d2f, 0x0020, 0x0d30, 0x0020, 0x0d31, 0x0020, 0x0d32, 0x0020, 0x0d33, 0x0020, 0x0d34, 0x0020, 0x0d35, 0x0020, 0x0d36, 0x0020, 0x0d37, 0x0020, 0x0d38, 0x0020, 0x0d39, 0x0020, 0x0d3e, 0x0020, 0x0d3f, 0x0020, 0x0d40, 0x0020, 0x0d41, 0x0020, 0x0d42, 0x0020, 0x0d43, 0x0020, 0x0d46, 0x0020, 0x0d47, 0x0020, 0x0d48, 0x0020, 0x0d4a, 0x0020, 0x0d4b, 0x0020, 0x0d4c, 0x0020, 0x0d4d, 0x0020, 0x0d57, 0x0020, 0x0d60, 0x0020, 0x0d61, 0x0020, 0x0d66, 0x0020, 0x0d67, 0x0020, 0x0d68, 0x0020, 0x0d69, 0x0020, 0x0d6a, 0x0020, 0x0d6b, 0x0020, 0x0d6c, 0x0020, 0x0d6d, 0x0020, 0x0d6e, 0x0020, 0x0d6f, 0x0020}; - String16 a = {arr, buff_cap(arr)}; - String16 b = string8_to_string16(scratch, str); - assert(string_compare(a,b)); - - String32 c = string16_to_string32(scratch, a); - String32 d = string16_to_string32(scratch, b); - assert(string_compare(c,d)); - - String e = string16_to_string8(scratch, a); - String f = string16_to_string8(scratch, b); - assert(string_compare(e,f)); - } - - { - String str = " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..."_s; - U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0xf900, 0x0020, 0xf901, 0x0020, 0xf902, 0x0020, 0xf903, 0x0020, 0xf904, 0x0020, 0xf905, 0x0020, 0xf906, 0x0020, 0xf907, 0x0020, 0xf908, 0x0020, 0xf909, 0x0020, 0xf90a, 0x0020, 0xf90b, 0x0020, 0xf90c, 0x0020, 0xf90d, 0x0020, 0xf90e, 0x0020, 0xf90f, 0x0020, 0xf910, 0x0020, 0xf911, 0x0020, 0xf912, 0x0020, 0xf913, 0x0020, 0xf914, 0x0020, 0xf915, 0x0020, 0xf916, 0x0020, 0xf917, 0x0020, 0xf918, 0x0020, 0xf919, 0x0020, 0xf91a, 0x0020, 0xf91b, 0x0020, 0xf91c, 0x0020, 0xf91d, 0x0020, 0xf91e, 0x0020, 0xf91f, 0x0020, 0xf920, 0x0020, 0xf921, 0x0020, 0xf922, 0x0020, 0xf923, 0x0020, 0xf924, 0x0020, 0xf925, 0x0020, 0xf926, 0x0020, 0xf927, 0x0020, 0xf928, 0x0020, 0xf929, 0x0020, 0xf92a, 0x0020, 0xf92b, 0x0020, 0xf92c, 0x0020, 0xf92d, 0x0020, 0xf92e, 0x0020, 0xf92f, 0x0020, 0xf930, 0x0020, 0xf931, 0x0020, 0xf932, 0x0020, 0xf933, 0x0020, 0xf934, 0x0020, 0xf935, 0x0020, 0xf936, 0x0020, 0xf937, 0x0020, 0xf938, 0x0020, 0xf939, 0x0020, 0xf93a, 0x0020, 0xf93b, 0x0020, 0xf93c, 0x0020, 0xf93d, 0x0020, 0xf93e, 0x0020, 0xf93f, 0x0020, 0xf940, 0x0020, 0xf941, 0x0020, 0xf942, 0x0020, 0xf943, 0x0020, 0xf944, 0x0020, 0xf945, 0x0020, 0xf946, 0x0020, 0xf947, 0x0020, 0xf948, 0x0020, 0xf949, 0x0020, 0xf94a, 0x0020, 0xf94b, 0x0020, 0xf94c, 0x0020, 0xf94d, 0x0020, 0xf94e, 0x0020, 0xf94f, 0x0020, 0xf950, 0x0020, 0xf951, 0x0020, 0xf952, 0x0020, 0xf953, 0x0020, 0xf954, 0x0020, 0xf955, 0x0020, 0xf956, 0x0020, 0xf957, 0x0020, 0xf958, 0x0020, 0xf959, 0x0020, 0xf95a, 0x0020, 0xf95b, 0x0020, 0xf95c, 0x0020, 0xf95d, 0x0020, 0xf95e, 0x0020, 0xf95f, 0x0020, 0xf960, 0x0020, 0xf961, 0x0020, 0xf962, 0x0020, 0xf963, 0x0020, 0xf964, 0x0020, 0xf965, 0x0020, 0xf966, 0x0020, 0xf967, 0x0020, 0xf968, 0x0020, 0xf969, 0x0020, 0xf96a, 0x0020, 0xf96b, 0x0020, 0xf96c, 0x0020, 0xf96d, 0x0020, 0xf96e, 0x0020, 0xf96f, 0x0020, 0xf970, 0x0020, 0xf971, 0x0020, 0xf972, 0x0020, 0xf973, 0x0020, 0xf974, 0x0020, 0xf975, 0x0020, 0xf976, 0x0020, 0xf977, 0x0020, 0xf978, 0x0020, 0xf979, 0x0020, 0xf97a, 0x0020, 0xf97b, 0x0020, 0xf97c, 0x0020, 0xf97d, 0x0020, 0xf97e, 0x0020, 0xf97f, 0x0020, 0x002e, 0x002e, 0x002e}; - String16 a = {arr, buff_cap(arr)}; - String16 b = string8_to_string16(scratch, str); - assert(string_compare(a,b)); - - String32 c = string16_to_string32(scratch, a); - String32 d = string16_to_string32(scratch, b); - assert(string_compare(c,d)); - - String e = string16_to_string8(scratch, a); - String f = string16_to_string8(scratch, b); - assert(string_compare(e,f)); - } - - { - String str = " ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ 。 「 」 、 ・ ヲ ァ ィ ゥ ェ ォ ャ ュ ョ ッ ー ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ ... "_s; - U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0xff01, 0x0020, 0xff02, 0x0020, 0xff03, 0x0020, 0xff04, 0x0020, 0xff05, 0x0020, 0xff06, 0x0020, 0xff07, 0x0020, 0xff08, 0x0020, 0xff09, 0x0020, 0xff0a, 0x0020, 0xff0b, 0x0020, 0xff0c, 0x0020, 0xff0d, 0x0020, 0xff0e, 0x0020, 0xff0f, 0x0020, 0xff10, 0x0020, 0xff11, 0x0020, 0xff12, 0x0020, 0xff13, 0x0020, 0xff14, 0x0020, 0xff15, 0x0020, 0xff16, 0x0020, 0xff17, 0x0020, 0xff18, 0x0020, 0xff19, 0x0020, 0xff1a, 0x0020, 0xff1b, 0x0020, 0xff1c, 0x0020, 0xff1d, 0x0020, 0xff1e, 0x0020, 0xff1f, 0x0020, 0xff20, 0x0020, 0xff21, 0x0020, 0xff22, 0x0020, 0xff23, 0x0020, 0xff24, 0x0020, 0xff25, 0x0020, 0xff26, 0x0020, 0xff27, 0x0020, 0xff28, 0x0020, 0xff29, 0x0020, 0xff2a, 0x0020, 0xff2b, 0x0020, 0xff2c, 0x0020, 0xff2d, 0x0020, 0xff2e, 0x0020, 0xff2f, 0x0020, 0xff30, 0x0020, 0xff31, 0x0020, 0xff32, 0x0020, 0xff33, 0x0020, 0xff34, 0x0020, 0xff35, 0x0020, 0xff36, 0x0020, 0xff37, 0x0020, 0xff38, 0x0020, 0xff39, 0x0020, 0xff3a, 0x0020, 0xff3b, 0x0020, 0xff3c, 0x0020, 0xff3d, 0x0020, 0xff3e, 0x0020, 0xff3f, 0x0020, 0xff40, 0x0020, 0xff41, 0x0020, 0xff42, 0x0020, 0xff43, 0x0020, 0xff44, 0x0020, 0xff45, 0x0020, 0xff46, 0x0020, 0xff47, 0x0020, 0xff48, 0x0020, 0xff49, 0x0020, 0xff4a, 0x0020, 0xff4b, 0x0020, 0xff4c, 0x0020, 0xff4d, 0x0020, 0xff4e, 0x0020, 0xff4f, 0x0020, 0xff50, 0x0020, 0xff51, 0x0020, 0xff52, 0x0020, 0xff53, 0x0020, 0xff54, 0x0020, 0xff55, 0x0020, 0xff56, 0x0020, 0xff57, 0x0020, 0xff58, 0x0020, 0xff59, 0x0020, 0xff5a, 0x0020, 0xff5b, 0x0020, 0xff5c, 0x0020, 0xff5d, 0x0020, 0xff5e, 0x0020, 0xff61, 0x0020, 0xff62, 0x0020, 0xff63, 0x0020, 0xff64, 0x0020, 0xff65, 0x0020, 0xff66, 0x0020, 0xff67, 0x0020, 0xff68, 0x0020, 0xff69, 0x0020, 0xff6a, 0x0020, 0xff6b, 0x0020, 0xff6c, 0x0020, 0xff6d, 0x0020, 0xff6e, 0x0020, 0xff6f, 0x0020, 0xff70, 0x0020, 0xff71, 0x0020, 0xff72, 0x0020, 0xff73, 0x0020, 0xff74, 0x0020, 0xff75, 0x0020, 0xff76, 0x0020, 0xff77, 0x0020, 0xff78, 0x0020, 0xff79, 0x0020, 0xff7a, 0x0020, 0xff7b, 0x0020, 0xff7c, 0x0020, 0xff7d, 0x0020, 0xff7e, 0x0020, 0xff7f, 0x0020, 0xff80, 0x0020, 0xff81, 0x0020, 0xff82, 0x0020, 0x002e, 0x002e, 0x002e, 0x0020}; - String16 a = {arr, buff_cap(arr)}; - String16 b = string8_to_string16(scratch, str); - assert(string_compare(a,b)); - - String32 c = string16_to_string32(scratch, a); - String32 d = string16_to_string32(scratch, b); - assert(string_compare(c,d)); - - String e = string16_to_string8(scratch, a); - String f = string16_to_string8(scratch, b); - assert(string_compare(e,f)); - } - - { // With surrogate pairs - U8 arr8[] = {0xf0, 0x90, 0x90, 0x90, 0xf0, 0x90, 0x90, 0x91}; - String str = {arr8, buff_cap(arr8)}; - U16 arr[] = {0xd801, 0xdc10, 0xd801, 0xdc11}; - String16 a = {arr, buff_cap(arr)}; - String16 b = string8_to_string16(scratch, str); - assert(string_compare(a,b)); - - String32 c = string16_to_string32(scratch, a); - String32 d = string16_to_string32(scratch, b); - assert(string_compare(c,d)); - - String e = string16_to_string8(scratch, a); - String f = string16_to_string8(scratch, b); - assert(string_compare(e,f)); - } - -} diff --git a/build.bat b/build.bat index 564d5a0..45cf1db 100644 --- a/build.bat +++ b/build.bat @@ -1,5 +1,5 @@ @echo off pushd %~dp0 -clang main.cpp -O2 -mavx2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -g -o main.exe -Wl,user32.lib +clang main.cpp -O2 -mavx2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -I".." -g -o main.exe -Wl,user32.lib popd \ No newline at end of file diff --git a/main.cpp b/main.cpp index 057800a..2e65a28 100644 --- a/main.cpp +++ b/main.cpp @@ -464,14 +464,14 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig // Origin UV (0,0) is in bottom left _mm256_maskstore_epi32((int *)depth_pointer, should_fill, interpolated_w); + // + // Fetch and calculate texel values + // S32x8 indices_to_fetch0 = _mm256_sub_epi32(var_src_y_minus_one_int, vi); S32x8 indices_to_fetch1 = _mm256_mullo_epi32(var_src_x_int, indices_to_fetch0); S32x8 indices_to_fetch2 = _mm256_add_epi32(indices_to_fetch1, ui); S32x8 indices_to_fetch3 = _mm256_and_si256(indices_to_fetch2, should_fill); - // - // Fetch and calculate texel values - // S32x8 pixel = _mm256_set_epi32( src->pixels[_mm256_extract_epi32(indices_to_fetch3, 7)], src->pixels[_mm256_extract_epi32(indices_to_fetch3, 6)], diff --git a/multimedia.cpp b/multimedia.cpp deleted file mode 100644 index b5b458b..0000000 --- a/multimedia.cpp +++ /dev/null @@ -1,1129 +0,0 @@ -#include "base.cpp" -#include "base_unicode.cpp" -#include "os_windows.cpp" - -#include -#include -#include -#include - -#pragma comment(linker, "/subsystem:windows") -#pragma comment(lib, "gdi32.lib") -#pragma comment(lib, "Shcore.lib") -#pragma comment(lib, "opengl32.lib") - -// Symbols taken from GLFW -// -// Executables (but not DLLs) exporting this symbol with this value will be -// automatically directed to the high-performance GPU on Nvidia Optimus systems -// with up-to-date drivers -// -__declspec(dllexport) DWORD NvOptimusEnablement = 1; - -// Executables (but not DLLs) exporting this symbol with this value will be -// automatically directed to the high-performance GPU on AMD PowerXpress systems -// with up-to-date drivers -// -__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; - -struct Bitmap { - union { - U32 *pixels; - U64 id; - }; - union { - Vec2I size; - struct { - S32 x, y; - }; - }; - Vec2 align; -}; - -enum EventKind { - EventKind_None, - EventKind_KeyDown, - EventKind_KeyUp, - EventKind_MouseMove, - EventKind_MouseWheel, - EventKind_KeyboardText, -}; - -enum Key { - Key_None, - Key_Up, - Key_Down, - Key_Left, - Key_Right, - Key_Escape, - Key_F1, - Key_F2, - Key_F3, - Key_F4, - Key_F5, - Key_F6, - Key_F7, - Key_F8, - Key_F9, - Key_F10, - Key_F11, - Key_F12, - Key_MouseLeft, - Key_MouseRight, - Key_MouseMiddle, - Key_0 = '0', - Key_1, - Key_2, - Key_3, - Key_4, - Key_5, - Key_6, - Key_7, - Key_8, - Key_9 = '9', - Key_A = 'a', - Key_B, - Key_C, - Key_D, - Key_E, - Key_F, - Key_G, - Key_H, - Key_I, - Key_J, - Key_K, - Key_L, - Key_M, - Key_N, - Key_O, - Key_P, - Key_Q, - Key_R, - Key_S, - Key_T, - Key_U, - Key_V, - Key_W, - Key_X, - Key_Y, - Key_Z = 'z', - Key_Count = 256, -}; - -#define KEY_MAPPING \ - X(Up, VK_UP) \ - X(Down, VK_DOWN) \ - X(Left, VK_LEFT) \ - X(Right, VK_RIGHT) \ - X(Escape, VK_ESCAPE) \ - X(F1, VK_F1) \ - X(F2, VK_F2) \ - X(F3, VK_F3) \ - X(F4, VK_F4) \ - X(F5, VK_F5) \ - X(F6, VK_F6) \ - X(F7, VK_F7) \ - X(F8, VK_F8) \ - X(F9, VK_F9) \ - X(F10, VK_F10) \ - X(F11, VK_F11) \ - X(F12, VK_F12) \ - X(A, 65) \ - X(B, 66) \ - X(C, 67) \ - X(D, 68) \ - X(E, 69) \ - X(F, 70) \ - X(G, 71) \ - X(H, 72) \ - X(I, 73) \ - X(J, 74) \ - X(K, 75) \ - X(L, 76) \ - X(M, 77) \ - X(N, 78) \ - X(O, 79) \ - X(P, 80) \ - X(Q, 81) \ - X(R, 82) \ - X(S, 83) \ - X(T, 84) \ - X(U, 85) \ - X(V, 86) \ - X(W, 87) \ - X(X, 88) \ - X(Y, 89) \ - X(Z, 90) \ - X(0, 48) \ - X(1, 49) \ - X(2, 50) \ - X(3, 51) \ - X(4, 52) \ - X(5, 53) \ - X(6, 54) \ - X(7, 55) \ - X(8, 56) \ - X(9, 57) - -struct DigitalKey { - bool pressed; - bool down; - bool released; -}; - -enum RenderBackend { - RenderBackend_Software, - RenderBackend_OpenGL1, -}; - -struct OS { - bool quit; - bool initialized; - Arena *frame_arena; - Arena *perm_arena; - - F64 ms_per_frame; - bool window_resizable; - bool window_was_resized; - String window_title; - Vec2I window_size; - Vec2I window_pos; - RenderBackend render_backend; - - Bitmap *screen; - Vec2I monitor_size; - F32 dpi_scale; - - F64 fps; - F64 delta_time; - F64 time; - U64 frame; - F64 update_time; - U64 update_begin_cycles; - U64 update_end_cycles; - F64 frame_start_time; - F64 app_start_time; - - B32 cursor_visible; - DigitalKey key[Key_Count]; - F32 mouse_wheel; - Vec2I mouse_pos; - Vec2I delta_mouse_pos; - - String text; - - char platform[256]; - struct { - char *vendor; - char *version; - char *renderer; - char *extensions; - } opengl; -}; - -struct FontGlyph { - F32 xadvance; - U32 codepoint; - Bitmap bitmap; -}; - -struct Font { - F32 line_advance; - F32 ascent; - F32 descent; - F32 height; - FontGlyph *glyphs; - U32 glyphs_len; -}; - -struct Audio; -#define AUDIO_CALLBACK(name) void name(Audio *audio, U32* buffer, U32 frames_to_fill) -typedef AUDIO_CALLBACK(AudioCallback); - -struct Audio { - AudioCallback *callback; - B32 initialized; - U32 samples_per_second; - U32 number_of_channels; - - // NOTE: one frame is 2 samples (left, right) 32 bits if - // one sample is equal 16 bit - U32 buffer_frame_count; - U32 latency_frame_count; - S32 bits_per_sample; - - char platform[128]; -}; - -OS os; -#include "base_math.cpp" - -typedef HRESULT tSetProcessDpiAwareness(PROCESS_DPI_AWARENESS); -typedef MMRESULT TimeBeginPeriod(MMRESULT); -constexpr DWORD window_style_simplified = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; -constexpr DWORD window_style_resizable = WS_OVERLAPPEDWINDOW; -constexpr DWORD window_style_borderless = WS_POPUP; - -struct Win32Bitmap { - Bitmap bitmap; - HDC dc; - HBITMAP dib; -}; - -struct Win32FontCtx { - HFONT font; - Win32Bitmap bitmap; - TEXTMETRIC text_metric; - Font result; -}; - -struct OS_Win32 { - HWND window; - HDC window_dc; - Win32Bitmap screen; - HINSTANCE instance; - int show_cmd; - char *cmd_line; - bool good_scheduling; - void *main_fiber; - void *msg_fiber; - U8 text_buff[32]; - Vec2I prev_window_size; - Vec2I prev_mouse_pos; -}; -static_assert(sizeof(OS_Win32) < 256, "Too big"); -#define w32(a) (*(OS_Win32 *)(a).platform) - -api Bitmap -bitmap(U32 *pixels, Vec2I size, Vec2 align_in_pixels = {}) { - Bitmap result; - result.pixels = pixels; - result.size = size; - result.align = align_in_pixels; - return result; -} - -function Win32Bitmap -win32_create_bitmap(Vec2I size) { - Win32Bitmap result; - result.bitmap.size = size; - if (result.bitmap.size.y < 0) - result.bitmap.size.y = -result.bitmap.size.y; - - HDC hdc = GetDC(0); - BITMAPINFO bminfo = {}; - bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader); - bminfo.bmiHeader.biWidth = (LONG)size.x; - bminfo.bmiHeader.biHeight = (LONG)-size.y; - bminfo.bmiHeader.biPlanes = 1; - bminfo.bmiHeader.biBitCount = 32; - bminfo.bmiHeader.biCompression = BI_RGB; // AA RR GG BB - bminfo.bmiHeader.biXPelsPerMeter = 1; - bminfo.bmiHeader.biYPelsPerMeter = 1; - - void *mem = 0; - result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (void **)&mem, 0, 0); - assert_msg(mem != 0, "Failed to create win32 bitmap"); - result.dc = CreateCompatibleDC(hdc); - result.bitmap.pixels = (U32 *)mem; - return result; -} - -function void -win32_destroy_bitmap(Win32Bitmap *b) { - if (b->bitmap.pixels) { - b->bitmap.pixels = 0; - DeleteDC(b->dc); - DeleteObject(b->dib); - } -} - -function void -win32_write_user_text(U8 *text, S32 len){ - if(os.text.len+len < buff_cap(w32(os).text_buff)){ - for(S32 i = 0; i < len; i++){ - os.text.str[os.text.len++] = text[i]; - } - } -} - -function LRESULT -CALLBACK win32_window_proc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) { - EventKind kind = EventKind_None; - Key key = Key_None; - LRESULT result = 0; - switch (uMsg) { - case WM_CLOSE: - DestroyWindow(window); - os.quit = 1; - break; - case WM_DESTROY: - PostQuitMessage(0); - os.quit = 1; - break; - case WM_SYSKEYDOWN: - case WM_KEYDOWN: { - kind = EventKind_KeyDown; - switch (wParam) { - -#define X(button, win) \ -case win: \ -key = Key_##button; \ -break; - - KEY_MAPPING - } - } break; - case WM_SYSKEYUP: - case WM_KEYUP: { - kind = EventKind_KeyUp; - switch (wParam) { - KEY_MAPPING -#undef X - } - } break; - case WM_TIMER: { - SwitchToFiber(w32(os).main_fiber); - } break; - case WM_ENTERMENULOOP: - case WM_ENTERSIZEMOVE: { - SetTimer(w32(os).window, 0, 1, 0); - } break; - case WM_EXITMENULOOP: - case WM_EXITSIZEMOVE: { - KillTimer(w32(os).window, 0); - } break; - case WM_MOUSEMOVE: { - POINT p; - GetCursorPos(&p); - ScreenToClient(w32(os).window, &p); - os.mouse_pos = vec2i(p.x, p.y); - os.mouse_pos.y = os.window_size.y - os.mouse_pos.y; - kind = EventKind_MouseMove; - } break; - case WM_LBUTTONDOWN: { - kind = EventKind_KeyDown; - key = Key_MouseLeft; - } break; - case WM_LBUTTONUP: { - kind = EventKind_KeyUp; - key = Key_MouseLeft; - } break; - case WM_RBUTTONDOWN: { - kind = EventKind_KeyDown; - key = Key_MouseRight; - } break; - case WM_RBUTTONUP: { - kind = EventKind_KeyUp; - key = Key_MouseRight; - } break; - case WM_MBUTTONDOWN: { - kind = EventKind_KeyDown; - key = Key_MouseMiddle; - } break; - case WM_MBUTTONUP: { - kind = EventKind_KeyUp; - key = Key_MouseMiddle; - } break; - case WM_MOUSEWHEEL: { - if ((int)wParam > 0) - os.mouse_wheel = 1; - else - os.mouse_wheel = -1; - kind = EventKind_MouseWheel; - } break; - case WM_CHAR: { - kind = EventKind_KeyboardText; - // @Note(Krzosa): No surrogate extensions - UTF32_Result decode = utf16_to_utf32((U16 *)&wParam, 1); - if(!decode.error){ - UTF8_Result encode = utf32_to_utf8(decode.out_str); - if(!encode.error){ - win32_write_user_text(encode.out_str, encode.len); - } - else win32_write_user_text((U8 *)"?", 1); - } - else win32_write_user_text((U8 *)"?", 1); - } break; - default: - result = DefWindowProcW(window, uMsg, wParam, lParam); - break; - } - - if (kind) { - if (kind == EventKind_KeyDown) { - if (os.key[key].down == 0) - os.key[key].pressed = 1; - os.key[key].down = 1; - } else if (kind == EventKind_KeyUp) { - os.key[key].released = 1; - os.key[key].down = 0; - } - } - - return result; -} - -function void -CALLBACK _os_fiber_event_proc(void *data) { - unused(data); - for (;;) { - MSG msg; - while (PeekMessageW(&msg, w32(os).window, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - SwitchToFiber(w32(os).main_fiber); - } -} - -function Vec2I -get_window_size(HWND window) { - Vec2I result; - RECT window_rect; - GetClientRect(window, &window_rect); - result.x = window_rect.right - window_rect.left; - result.y = window_rect.bottom - window_rect.top; - return result; -} - -function Vec2I -get_window_size_with_border(HWND window) { - RECT ClientRect; - GetWindowRect(window, &ClientRect); - Vec2I draw_area; - draw_area.x = (ClientRect.right - ClientRect.left); - draw_area.y = (ClientRect.bottom - ClientRect.top); - return draw_area; -} - -function Vec2I -get_border_size(HWND window) { - Vec2I client = get_window_size(window); - Vec2I wind_size = get_window_size_with_border(window); - Vec2I result = vec2i(wind_size.x - client.x, wind_size.y - client.y); - return result; -} - -api void os_quit() { os.quit = 1; } -api void os_set_fps(F64 fps) { os.ms_per_frame = 1 / fps; } -api void os_set_ms_per_frame(F64 ms) { os.ms_per_frame = ms; } - -api void os_show_cursor(B32 status) { - ShowCursor(status); - os.cursor_visible = status; -} - -api void os_set_window_title(String title) { - Scratch scratch; - BOOL result = SetWindowTextA(w32(os).window, (char *)title.str); - assert_msg(result != 0, "Failed to set window title"); - os.window_title = title; -} - -api void os_set_window_size(S32 x, S32 y) { - Vec2I border = get_border_size(w32(os).window); - int actual_width = (int)(x + border.x); - int actual_height = (int)(y + border.y); - bool result = - SetWindowPos(w32(os).window, 0, 0, 0, actual_width, actual_height, SWP_NOMOVE | SWP_NOOWNERZORDER); - assert_msg(result, "SetWindowPos returned invalid value"); - os.window_size = get_window_size(w32(os).window); -} - -api void os_pull_state() { - os.window_was_resized = false; - os.window_size = get_window_size(w32(os).window); - if (os.window_size != w32(os).prev_window_size) { - os.window_was_resized = true; - w32(os).prev_window_size = os.window_size; - } - os.monitor_size = vec2i(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); - - // @Note: Client relative - POINT point = {0, 0}; - ClientToScreen(w32(os).window, &point); - os.window_pos.x = point.x; - os.window_pos.y = point.y; - - // @Note: Get DPI scale - UINT dpi = GetDpiForWindow(w32(os).window); - assert_msg(dpi != 0, "Failed to get dpi for window"); - os.dpi_scale = (F32)dpi / 96.f; - - // @Note: Reset text - os.text.len = 0; - // @Note: Reset keys - for (int i = 0; i < Key_Count; i++) { - os.key[i].released = 0; - os.key[i].pressed = 0; - } - os.mouse_wheel = 0; - SwitchToFiber(w32(os).msg_fiber); - if (!os.quit) { - os.delta_mouse_pos = w32(os).prev_mouse_pos - os.mouse_pos; - w32(os).prev_mouse_pos = os.mouse_pos; - - // @Note: Resize - if (os.render_backend == RenderBackend_Software) { - if (os.window_size != w32(os).screen.bitmap.size && os.window_size.x != 0 && os.window_size.y != 0) { - win32_destroy_bitmap(&w32(os).screen); - w32(os).screen = win32_create_bitmap(vec2i(os.window_size.x, -(os.window_size.y))); - os.screen = &w32(os).screen.bitmap; - } - } - } -} - -api void os_init_software_render() { os.render_backend = RenderBackend_Software; } - -api B32 os_init_opengl() { - PIXELFORMATDESCRIPTOR p = {}; - p.nSize = sizeof(p); - p.nVersion = 1; - p.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - p.iPixelType = PFD_TYPE_RGBA; - p.cColorBits = 32; - p.cDepthBits = 24; - p.cStencilBits = 8; - p.iLayerType = PFD_MAIN_PLANE; - - S32 pixel_format = ChoosePixelFormat(w32(os).window_dc, &p); - if (pixel_format != 0) { - if (SetPixelFormat(w32(os).window_dc, pixel_format, &p)) { - HGLRC gl_ctx = wglCreateContext(w32(os).window_dc); - if (gl_ctx != NULL) { - if (wglMakeCurrent(w32(os).window_dc, gl_ctx)) { - // Success - } - else { - log_error("Failed on wglMakeCurrent!"); - return false; - } - } - else { - log_error("Failed on wglCreateContext!"); - return false; - } - } - else { - log_error("Failed on SetPixelFormat!"); - return false; - } - } - else { - log_error("Failed on ChoosePixelFormat!"); - return false; - } - - os.opengl.vendor = (char *)glGetString(GL_VENDOR); - os.opengl.renderer = (char *)glGetString(GL_RENDERER); - os.opengl.version = (char *)glGetString(GL_VERSION); - os.opengl.extensions = (char *)glGetString(GL_EXTENSIONS); - os.render_backend = RenderBackend_OpenGL1; - - return true; -} - -api B32 os_init() { - HMODULE shcore = LoadLibraryA("Shcore.dll"); - if (shcore) { - tSetProcessDpiAwareness *set_dpi_awr = - (tSetProcessDpiAwareness *)GetProcAddress(shcore, "SetProcessDpiAwareness"); - if (set_dpi_awr) { - HRESULT hr = set_dpi_awr(PROCESS_PER_MONITOR_DPI_AWARE); - assert_msg(SUCCEEDED(hr), "Failed to set dpi awareness"); - } - } - - HMODULE winmm = LoadLibraryA("winmm.dll"); - if (winmm) { - TimeBeginPeriod *timeBeginPeriod = (TimeBeginPeriod *)GetProcAddress(winmm, "timeBeginPeriod"); - if (timeBeginPeriod) { - if (timeBeginPeriod(1) == TIMERR_NOERROR) { - w32(os).good_scheduling = true; - } - } - } - - DWORD window_style_chosen = window_style_resizable; - if (!os.window_resizable) - window_style_chosen = window_style_simplified; - - os.app_start_time = os_time(); - os.frame_start_time = os.app_start_time; - os.update_begin_cycles = __rdtsc(); - - Scratch scratch; - WNDCLASSW wc = {}; - wc.lpfnWndProc = win32_window_proc; - wc.hInstance = w32(os).instance; - wc.lpszClassName = (LPCWSTR)string8_to_string16(scratch, os.window_title).str; - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; - if (!RegisterClassW(&wc)) { - log_error("Failed to create window class!"); - return false; - } - - RECT window_rect; - window_rect.left = (LONG)os.window_pos.x; - window_rect.top = (LONG)os.window_pos.y; - window_rect.right = (LONG)os.window_size.x + window_rect.left; - window_rect.bottom = (LONG)os.window_size.y + window_rect.top; - AdjustWindowRectEx(&window_rect, window_style_chosen, false, 0); - - w32(os).window = CreateWindowW(wc.lpszClassName, wc.lpszClassName, window_style_chosen, window_rect.left, window_rect.top, window_rect.right - window_rect.left,window_rect.bottom - window_rect.top, NULL, NULL, w32(os).instance, NULL); - if (w32(os).window == 0) { - log_error("Failed to create window!"); - return false; - } - - ShowWindow(w32(os).window, w32(os).show_cmd); - UpdateWindow(w32(os).window); - w32(os).window_dc = GetDC(w32(os).window); - - w32(os).main_fiber = ConvertThreadToFiber(0); - assert_msg(w32(os).main_fiber, "Failed to create main fiber"); - w32(os).msg_fiber = CreateFiber(0, _os_fiber_event_proc, 0); - assert_msg(w32(os).msg_fiber, "Failed to create message fiber"); - - if (os.cursor_visible == false) - os_show_cursor(false); - - switch (os.render_backend) { - case RenderBackend_Software: { - os_init_software_render(); - } break; - case RenderBackend_OpenGL1: { - os_init_opengl(); - } break; - default: assert_msg(0, "Invalid value for render backend"); - break; - } - - os_pull_state(); - os.initialized = true; - return true; -} - -api bool os_game_loop() { - assert_msg(os.initialized, "Platform is not initialized! Please call os_init"); - switch (os.render_backend) { - case RenderBackend_Software: { - if (os.screen) { // @Note: Draw screen - U32 *p = os.screen->pixels; - for (int y = 0; y < os.screen->y; y++) { - for (int x = 0; x < os.screen->x; x++) { - *p = ((*p & 0xff000000)) | ((*p & 0x00ff0000) >> 16) | ((*p & 0x0000ff00)) | - ((*p & 0x000000ff) << 16); - p += 1; - } - } - - HDC hdc = w32(os).window_dc; - SelectObject(w32(os).screen.dc, w32(os).screen.dib); - BitBlt(hdc, 0, 0, (LONG)os.screen->size.x, (LONG)os.screen->size.y, w32(os).screen.dc, 0, 0, SRCCOPY); - } - } break; - case RenderBackend_OpenGL1: { - SwapBuffers(w32(os).window_dc); - } break; - default: - assert_msg(0, "Please select a rendering backend!"); - break; - } - arena_clear(os.frame_arena); - os.update_time = os_time() - os.frame_start_time; - os.update_end_cycles = __rdtsc(); - F64 frame_time = os.update_time; - F64 ms_per_frame = os.ms_per_frame; - if (frame_time < ms_per_frame) { - if (w32(os).good_scheduling) { - // @Todo: I have no idea if letting over sleep is bad or not - // Busy waiting is chugging cpu alot more, not sure what to do - F64 time_to_sleep = (ms_per_frame - frame_time) * 1000; - if (time_to_sleep > 0) { - Sleep((DWORD)time_to_sleep); - } - } - - do { - frame_time = os_time() - os.frame_start_time; - } while (frame_time < ms_per_frame); - } - os.frame++; - os.delta_time = frame_time; - os.fps = 1 / os.delta_time; - os.time += os.delta_time; - os.frame_start_time = os_time(); - os.update_begin_cycles = __rdtsc(); - os_pull_state(); - return !os.quit; -} - -int main(int argc, char **argv); -int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmd_line, int show_cmd) { - thread_ctx_init(); - w32(os).instance = instance; - w32(os).show_cmd = show_cmd; - w32(os).cmd_line = cmd_line; - - Arena frame_arena = {}; - arena_init(&frame_arena, "Frame arena"_s); - os.perm_arena = &pernament_arena; - os.frame_arena = &frame_arena; - - os.dpi_scale = 1; - os.text.str = w32(os).text_buff; - os.window_title = "Have a good day!"_s; - os.window_pos.x = 0; - os.window_pos.y = 50; - os.window_size.x = 1280; - os.window_size.y = 720; - os.ms_per_frame = 1.f / 60.f; - os.cursor_visible = true; - - if(AttachConsole(-1)) { - freopen("CONIN$", "r",stdin); - freopen("CONOUT$", "w",stdout); - freopen("CONOUT$", "w",stderr); - } - - return main(__argc, __argv); -} - -//----------------------------------------------------------------------------- -// Font API -//----------------------------------------------------------------------------- -function FontGlyph extract_glyph(Allocator *arena, Win32FontCtx *ctx, wchar_t glyph) { - SIZE size; - GetTextExtentPoint32W(ctx->bitmap.dc, &glyph, 1, &size); - TextOutW(ctx->bitmap.dc, 0, 0, &glyph, 1); - - // @Note: Find bitmap edges - int minx = 100000; - int miny = 100000; - int maxx = -100000; - int maxy = -100000; - for (int y = 499; y >= 500 - size.cy; y--) { - for (int x = 0; x < size.cx; x++) { - if (ctx->bitmap.bitmap.pixels[x + y * (int)ctx->bitmap.bitmap.size.x] != 0) { - if (minx > x) - minx = x; - if (miny > y) - miny = y; - if (maxx < x) - maxx = x; - if (maxy < y) - maxy = y; - } - } - } - - assert(minx >= 0 && miny >= 0); - int bwidth = maxx - minx + 1; - int bheight = maxy - miny + 1; - U32 *cropped = - (U32 *)exp_alloc(arena, sizeof(U32) * (U32)(bwidth) * (U32)(bheight)); - for (int y = miny; y <= maxy; y++) { - for (int x = minx; x <= maxx; x++) { - U32 value = ctx->bitmap.bitmap.pixels[x + y * (int)ctx->bitmap.bitmap.size.x]; - U32 *dst = cropped + ((size_t)(x - minx) + (size_t)(y - miny) * bwidth); -#if 1 // Premultiplied alpha - F32 alpha = (F32)((value & 0x000000ff) >> 0); - F32 rgb = (F32)0xff*(alpha/255.f); - U8 val = (U8)(rgb + 0.5f); - *dst = (((U32)(alpha+0.5f) << 24) | val << 16 | val << 8 | val); -#else - U8 grey = (value & 0x000000ff); - *dst = (grey << 24 | 0xff << 16 | 0xff << 8 | 0xff); -#endif - } - } - exp_alloc(arena, sizeof(U32) * (U32)bwidth); - - // @Note: Calculate char metrics - int glyph_descent = (499 - size.cy) - miny; - - FontGlyph result; - INT width; - GetCharWidth32W(ctx->bitmap.dc, glyph, glyph, &width); - result.xadvance = (F32)width; - result.bitmap = bitmap(cropped, vec2i(bwidth, bheight), - vec2((F32)-minx, (F32)ctx->text_metric.tmDescent + (F32)glyph_descent)); - return result; -} - -function Win32FontCtx begin_font_extraction(char *filename, char *font_name, S64 height) { - assert_msg(height < 500, "Height of font over 500"); - Win32FontCtx ctx = {}; - if (filename) { - int fonts_added = AddFontResourceExA(filename, FR_PRIVATE, 0); - assert_msg(fonts_added != 0, "AddFontResourceEx added 0 fonts"); - } - - ctx.bitmap = win32_create_bitmap(vec2i(500, -500)); - ctx.font = - CreateFontA((S32)height, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, font_name); - assert_msg(ctx.font != NULL, "CreateFont returned a 0 pointer"); - SelectObject(ctx.bitmap.dc, ctx.bitmap.dib); - SelectObject(ctx.bitmap.dc, ctx.font); - GetTextMetrics(ctx.bitmap.dc, &ctx.text_metric); - ctx.result.height = (F32)height; - ctx.result.descent = (F32)ctx.text_metric.tmDescent; - ctx.result.ascent = (F32)ctx.text_metric.tmAscent; - ctx.result.line_advance = (F32)(height + ctx.text_metric.tmExternalLeading); - SetBkColor(ctx.bitmap.dc, RGB(0, 0, 0)); - SetTextColor(ctx.bitmap.dc, RGB(255, 255, 255)); - return ctx; -} - -function Font end_font_extraction(Win32FontCtx *ctx) { - win32_destroy_bitmap(&ctx->bitmap); - DeleteObject(ctx->font); - return ctx->result; -} - -api Font os_load_font(Allocator *arena, S32 height, const char *font_name, const char *filename) { - FontGlyph *glyphs = exp_alloc_array(arena, FontGlyph, 96, AF_ZeroMemory); - Win32FontCtx font_ctx = begin_font_extraction((char *)filename, (char *)font_name, height); - for (U32 i = '!'; i <= '~'; i++) { - glyphs[i - '!'] = extract_glyph(arena, &font_ctx, (wchar_t)i); - } - Font font = end_font_extraction(&font_ctx); - font.glyphs = glyphs; - font.glyphs_len = '~' - '!'; - return font; -} - -#undef w32 - -//----------------------------------------------------------------------------- -// Audio -//----------------------------------------------------------------------------- -#include -#include -#include -#include - -const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); -const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); -const IID IID_IAudioClient = __uuidof(IAudioClient); -const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); - -// NOTE: typedefines for the functions which are goint to be loaded -typedef HRESULT CoCreateInstanceFunction(REFCLSID rclsid, LPUNKNOWN *pUnkOuter, DWORD dwClsContext, - REFIID riid, LPVOID *ppv); -typedef HRESULT CoInitializeExFunction(LPVOID pvReserved, DWORD dwCoInit); - -// NOTE: empty functions(stubs) which are used when library fails to load -HRESULT CoCreateInstanceStub(REFCLSID rclsid, LPUNKNOWN *pUnkOuter, DWORD dwClsContext, REFIID riid, - LPVOID *ppv) { - unused(rclsid); - unused(pUnkOuter); - unused(dwClsContext); - unused(riid); - unused(ppv); - return S_FALSE; -} - -HRESULT CoInitializeExStub(LPVOID pvReserved, DWORD dwCoInit) { - unused(pvReserved); - unused(dwCoInit); - return S_FALSE; -} - -// NOTE: pointers to the functions from the dll -CoCreateInstanceFunction *CoCreateInstanceFunctionPointer = CoCreateInstanceStub; -CoInitializeExFunction *CoInitializeExFunctionPointer = CoInitializeExStub; - -// NOTE: Number of REFERENCE_TIME units per second -// One unit is equal to 100 nano seconds -#define REF_TIMES_PER_SECOND 10000000 -#define REF_TIMES_PER_MSECOND 10000 -#define w32(a) (*(Audio_Win32 *)(a)->platform) - -struct Audio_Win32 { - IMMDevice *device; - IAudioClient *audio_client; - - IMMDeviceEnumerator *device_enum; - IAudioRenderClient *audio_render_client; - IAudioCaptureClient *audio_capture_client; -}; -static_assert(sizeof(Audio::platform) > sizeof(Audio_Win32), - "Audio::platform is too small to hold Audio_Win32 struct"); - -// Load COM Library functions dynamically, -// this way sound is not necessary to run the game -function B32 win32_load_com() { - B32 result = true; - HMODULE ole32Library = LoadLibraryA("ole32.dll"); - if (ole32Library) { - CoCreateInstanceFunctionPointer = - (CoCreateInstanceFunction *)GetProcAddress(ole32Library, "CoCreateInstance"); - if (!CoCreateInstanceFunctionPointer) { - CoCreateInstanceFunctionPointer = CoCreateInstanceStub; - log_error("CoCreateInstance failed to load"); - result = false; - } - CoInitializeExFunctionPointer = (CoInitializeExFunction *)GetProcAddress(ole32Library, "CoInitializeEx"); - if (!CoInitializeExFunctionPointer) { - CoInitializeExFunctionPointer = CoInitializeExStub; - log_error("CoInitializeEx failed to load"); - result = false; - } - } else { - CoCreateInstanceFunctionPointer = CoCreateInstanceStub; - CoInitializeExFunctionPointer = CoInitializeExStub; - log_error("Failed to load OLE32.dll"); - result = false; - } - return result; -} - -api void os_clean_audio(Audio *audio) { - if (w32(audio).audio_client) - w32(audio).audio_client->Stop(); - if (w32(audio).device_enum) - w32(audio).device_enum->Release(); - if (w32(audio).device) - w32(audio).device->Release(); - if (w32(audio).audio_client) - w32(audio).audio_client->Release(); - if (w32(audio).audio_render_client) - w32(audio).audio_render_client->Release(); - audio->initialized = false; -} - -function DWORD win32_audio_thread(void *parameter) { - Audio *audio = (Audio *)parameter; - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); - HANDLE buffer_ready_event = CreateEvent(0, 0, 0, 0); - if (!buffer_ready_event) { - return -1; - } - if (FAILED(w32(audio).audio_client->SetEventHandle(buffer_ready_event))) { - return -1; - } - U32 buffer_frame_count; - if (FAILED(w32(audio).audio_client->GetBufferSize(&buffer_frame_count))) { - return -1; - } - // U32 buffer_sample_count = buffer_frame_count * audio->number_of_channels; - if (FAILED(w32(audio).audio_client->Start())) { - w32(audio).audio_client->Stop(); - return -1; - } - for (;;) { - if (WaitForSingleObject(buffer_ready_event, INFINITE) != WAIT_OBJECT_0) { - w32(audio).audio_client->Stop(); - return -1; - } - U32 padding_frame_count; - if (FAILED(w32(audio).audio_client->GetCurrentPadding(&padding_frame_count))) { - w32(audio).audio_client->Stop(); - return -1; - } - U32 *samples; - U32 fill_frame_count = buffer_frame_count - padding_frame_count; - if (FAILED(w32(audio).audio_render_client->GetBuffer(fill_frame_count, (BYTE **)&samples))) { - w32(audio).audio_client->Stop(); - return -1; - } - audio->callback(audio, samples, fill_frame_count); - if (FAILED(w32(audio).audio_render_client->ReleaseBuffer(fill_frame_count, 0))) { - w32(audio).audio_client->Stop(); - return -1; - } - } - return 0; -} - -function AUDIO_CALLBACK(default_audio_callback) { - memory_zero(buffer, (U64)frames_to_fill * (U64)audio->samples_per_second); -} - -api B32 os_init_audio(Audio *audio) { - audio->bits_per_sample = 16; - if (audio->number_of_channels == 0) - audio->number_of_channels = 2; - if (audio->samples_per_second == 0) - audio->samples_per_second = 44100; - if (audio->callback == 0) - audio->callback = default_audio_callback; - - B32 success = win32_load_com(); - if (!success) { - return false; - } - if (FAILED(CoInitializeExFunctionPointer(0, COINITBASE_MULTITHREADED))) { - log_error("Failed to initialize COM, CoInitializeEx"); - return false; - } - if (FAILED(CoCreateInstanceFunctionPointer(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, - IID_IMMDeviceEnumerator, (LPVOID *)&w32(audio).device_enum))) { - log_error("Failed to initialize COM, CoCreateInstance"); - return false; - } - if (FAILED(w32(audio).device_enum->GetDefaultAudioEndpoint(eRender, eConsole, &w32(audio).device))) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, GetDefaultAudioEndpoint"); - return false; - } - if (FAILED( - w32(audio).device->Activate(IID_IAudioClient, CLSCTX_ALL, 0, (void **)&w32(audio).audio_client))) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, " - "w32(audio).device->Activate(IID_IAudioClient,"); - return false; - } - - WAVEFORMATEX waveFormat = {}; - waveFormat.wFormatTag = WAVE_FORMAT_PCM; - waveFormat.nChannels = audio->number_of_channels; - waveFormat.nSamplesPerSec = audio->samples_per_second; - waveFormat.wBitsPerSample = audio->bits_per_sample; - waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; - waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; - REFERENCE_TIME requestedBufferDuration = REF_TIMES_PER_MSECOND * 40; - if (FAILED(w32(audio).audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, - requestedBufferDuration, 0, &waveFormat, 0))) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, w32(audio).audio_client->Initialize"); - return false; - } - if (FAILED(w32(audio).audio_client->GetService(IID_IAudioRenderClient, - (void **)&w32(audio).audio_render_client))) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, " - "w32(audio).audio_client->GetService(IID_IAudioRenderClient"); - return false; - } - if (FAILED(w32(audio).audio_client->GetBufferSize(&audio->buffer_frame_count))) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, w32(audio).audio_client->GetBufferSize"); - return false; - } - HANDLE thread_handle = CreateThread(0, 0, win32_audio_thread, audio, 0, 0); - if (!thread_handle) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, CreateThread returned 0 in handle"); - return false; - } - if (thread_handle == INVALID_HANDLE_VALUE) { - os_clean_audio(audio); - log_error("Failed to initialize WASAPI, CreateThread for " - "audio failed with INVALID HANDLE VALUE"); - return false; - } - CloseHandle(thread_handle); - audio->initialized = true; -#undef w32 - return true; -} - diff --git a/os_windows.cpp b/os_windows.cpp deleted file mode 100644 index 6dddc2a..0000000 --- a/os_windows.cpp +++ /dev/null @@ -1,249 +0,0 @@ -//----------------------------------------------------------------------------- -// Memory -//----------------------------------------------------------------------------- -const SizeU os_page_size = 4096; - -function OS_Memory -os_reserve(SizeU size){ - OS_Memory result = {}; - SizeU adjusted_size = align_up(size, os_page_size); - result.data = (U8*)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE); - assert_msg(result.data, "Failed to reserve virtual memory"); - result.reserve = adjusted_size; - return result; -} - -function B32 -os_commit(OS_Memory *m, SizeU size){ - SizeU commit = align_up(size, os_page_size); - SizeU total_commit = m->commit + commit; - total_commit = clamp_top(total_commit, m->reserve); - SizeU adjusted_commit = total_commit - m->commit; - if(adjusted_commit != 0){ - void *result = VirtualAlloc((U8*)m->data + m->commit, adjusted_commit, MEM_COMMIT, PAGE_READWRITE); - assert_msg(result, "Failed to commit more memory"); - m->commit += adjusted_commit; - return true; - } - return false; -} - -function void -os_release(OS_Memory *m){ - BOOL result = VirtualFree(m->data, 0, MEM_RELEASE); - assert_msg(result != 0, "Failed to release OS_Memory"); - if(result){ - m->data = 0; - m->commit = 0; - m->reserve = 0; - } -} - -function B32 -os_decommit_pos(OS_Memory *m, SizeU pos){ - SizeU aligned = align_down(pos, os_page_size); - SizeU adjusted_pos = clamp_top(aligned, m->commit); - SizeU size_to_decommit = m->commit - adjusted_pos; - if(size_to_decommit){ - U8 *base_address = m->data + adjusted_pos; - BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT); - if(result){ - m->commit -= size_to_decommit; - return true; - } - } - return false; -} - -function void -test_os_memory(){ - assert(align_down(4096, 4096) == 4096); - assert(align_down(4095, 4096) == 0); - - OS_Memory memory = os_reserve(9000); - assert(memory.reserve == 4096*3 && memory.data && memory.commit == 0); - os_commit(&memory, 100); - assert(memory.commit == 4096); - os_commit(&memory, 100); - assert(memory.commit == 4096*2); - os_commit(&memory, 9000); - assert(memory.commit == 4096*3); - os_commit(&memory, 9000); - assert(memory.commit == 4096*3); - - os_decommit_pos(&memory, 4096); - assert(memory.commit == 4096); - os_decommit_pos(&memory, 4096); - assert(memory.commit == 4096); - os_decommit_pos(&memory, 0); - assert(memory.commit == 0); - - os_release(&memory); - assert(memory.data == 0); -} - -//----------------------------------------------------------------------------- -// Time -//----------------------------------------------------------------------------- -global S64 Global_counts_per_second; -api F64 os_time() { - if (Global_counts_per_second == 0) { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - Global_counts_per_second = freq.QuadPart; - } - - LARGE_INTEGER time; - QueryPerformanceCounter(&time); - F64 result = (F64)time.QuadPart / (F64)Global_counts_per_second; - return result; -} - -//----------------------------------------------------------------------------- -// Filesystem -//----------------------------------------------------------------------------- -function B32 -os_write_file(String filename, String filecontent){ - FILE *f = fopen((const char *)filename.str, "w"); - if(f){ - fwrite(filecontent.str, 1, filecontent.len, f); - fclose(f); - return true; - } - return false; -} - -function String -os_read_file(Allocator *a, String name){ - String result = {0}; - FILE *f = fopen((char *)name.str, "rb"); - if(f){ - fseek(f, 0, SEEK_END); - result.len = ftell(f); - fseek(f, 0, SEEK_SET); - result.str = (U8 *)exp_alloc(a, result.len + 1); - fread(result.str, result.len, 1, f); - fclose(f); - result.str[result.len] = 0; - } - - return result; -} - -function String -os_get_working_dir(Allocator *a){ - wchar_t buffer[2048]; - DWORD written = GetCurrentDirectoryW(2048, buffer); - assert(written != 0); - String16 string16 = string16_from_widechar(buffer); - String result = string16_to_string8(a, string16); - string_path_normalize(result); - return result; -} - -function String -os_get_exe_dir(Allocator *a){ - wchar_t buffer[2048]; - DWORD written = GetModuleFileNameW(0, buffer, 2048); - assert(written != 0); - String16 string16 = string16_from_widechar(buffer); - String result = string16_to_string8(a, string16); - string_path_normalize(result); - result = string_chop_last_slash(result); - - if(string16.len > result.len) result.str[result.len] = 0; - string_path_normalize(result); - return result; -} - -function String -os_get_absolute_path(Allocator *a, String path){ - Scratch scratch(a); - String16 path16 = string8_to_string16(scratch, path); - - wchar_t *buffer = exp_alloc_array(scratch, wchar_t, 2048); - DWORD written = GetFullPathNameW((wchar_t *)path16.str, 2048, buffer, 0); - if(written == 0) return {}; - - String16 absolute16 = string16_from_widechar(buffer); - String absolute = string16_to_string8(a, absolute16); - string_path_normalize(absolute); - return absolute; -} - -function B32 -os_does_file_exist(String path){ - Scratch scratch; - String16 path16 = string8_to_string16(scratch, path); - DWORD attribs = GetFileAttributesW((wchar_t *)path16.str); - B32 result = attribs == INVALID_FILE_ATTRIBUTES ? false : true; - return result; -} - -const U32 LIST_NO_FLAGS = 0; -const U32 LIST_RECURSE_INTO_DIRS = 1; - -struct OS_File_Info{ - String relative_path; - String absolute_path; - B32 is_directory; -}; - -function Array -os_list_dir(Allocator *a, String dir, U32 flags = LIST_NO_FLAGS){ - Scratch scratch(a); - Array dirs_to_read = {scratch}; - dirs_to_read.add(dir); - - Array result = {a}; - for(auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++){ - String modified_path = string_fmt(scratch, "%Q\\*", it); - String16 path16 = string8_to_string16(scratch, modified_path); - - WIN32_FIND_DATAW ffd; - HANDLE handle = FindFirstFileW((wchar_t *)path16.str, &ffd); - if(handle == INVALID_HANDLE_VALUE) continue; - - do{ - - // - // Skip '.' and '..' - // - if(ffd.cFileName[0] == '.'){ - if(ffd.cFileName[1] == '.'){ - if(ffd.cFileName[2] == 0) - continue; - } - - if(ffd.cFileName[1] == 0) - continue; - } - - String16 filename16 = string16_from_widechar(ffd.cFileName); - String filename = string16_to_string8(scratch, filename16); - - String full_file_path = string_fmt(a, "%Q/%Q", dir, filename); - OS_File_Info listing = {full_file_path, os_get_absolute_path(a, full_file_path)}; - - - if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ - listing.is_directory = true; - - if(flags & LIST_RECURSE_INTO_DIRS){ - dirs_to_read.add(full_file_path); - } - } - - result.add(listing); - - }while(FindNextFileW(handle, &ffd) != 0); - - DWORD error = GetLastError(); - if(error != ERROR_NO_MORE_FILES){ - // Not sure what to do here hmmm - } - FindClose(handle); - } - - return result; -} diff --git a/stb_sprintf.h b/stb_sprintf.h deleted file mode 100644 index b6e051a..0000000 --- a/stb_sprintf.h +++ /dev/null @@ -1,1921 +0,0 @@ -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) -#if defined(__has_feature) && defined(__has_attribute) -#if __has_feature(address_sanitizer) -#if __has_attribute(__no_sanitize__) -#define STBSP__ASAN __attribute__((__no_sanitize__("address"))) -#elif __has_attribute(__no_sanitize_address__) -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#elif __has_attribute(__no_address_safety_analysis__) -#define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) -#endif -#endif -#endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) -#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) -#if __has_attribute(format) -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) -#endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include // for va_arg(), va_list() -#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct -{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff -#define stbsp__chk_cb_bufL(bytes) \ -{ \ -int len = (int)(bf - buf); \ -if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ -tlen += len; \ -if (0 == (bf = buf = callback(buf, user, len))) \ -goto done; \ -} \ -} -#define stbsp__chk_cb_buf(bytes) \ -{ \ -if (callback) { \ -stbsp__chk_cb_bufL(bytes); \ -} \ -} -#define stbsp__flush_cb() \ -{ \ -stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ -} // flush if there is even one byte in the buffer -#define stbsp__cb_buf_clamp(cl, v) \ -cl = v; \ -if (callback) { \ -int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ -if (cl > lg) \ -cl = lg; \ -} - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; -#ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else -#endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { -#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - String str; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 'Q': - str = va_arg(va, String); - if (str.str == 0 && str.len != 0) - str = string_null; - pr = str.len; - s = (char *)str.str; - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); - // add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } - endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - - done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ -{ \ -int cn; \ -for (cn = 0; cn < 8; cn++) \ -((char *)&dest)[cn] = ((char *)&src)[cn]; \ -} - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ -{ \ -double ahi = 0, alo, bhi = 0, blo; \ -stbsp__int64 bt; \ -oh = xh * yh; \ -STBSP__COPYFP(bt, xh); \ -bt &= ((~(stbsp__uint64)0) << 27); \ -STBSP__COPYFP(ahi, bt); \ -alo = xh - ahi; \ -STBSP__COPYFP(bt, yh); \ -bt &= ((~(stbsp__uint64)0) << 27); \ -STBSP__COPYFP(bhi, bt); \ -blo = yh - bhi; \ -ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ -} - -#define stbsp__ddtoS64(ob, xh, xl) \ -{ \ -double ahi = 0, alo, vh, t; \ -ob = (stbsp__int64)xh; \ -vh = (double)ob; \ -ahi = (xh - vh); \ -t = (ahi - xh); \ -alo = (xh - (ahi - t)) - (vh + t); \ -ob += (stbsp__int64)(ahi + alo + xl); \ -} - -#define stbsp__ddrenorm(oh, ol) \ -{ \ -double s; \ -s = oh + ol; \ -ol = ol - (s - oh); \ -oh = s; \ -} - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/