#pragma once #define LANG_CPP 1 #define BUILD_CONSOLE_INTERFACE BUILD_DEBUG #if ARCH_CPU_X64 #include "CPU_X64.cpp" #define PLATFORM_MEMORY_PAGE_SIZE 4096 #define PLATFORM_MEMORY_LARGE_PAGE_SIZE 2097152 #define CPU_REGISTER_WIDTH_BYTES 8 #define CPU_CACHE_LINE_SIZE 64 #else #error "CPU not supported (yet)!" #endif #include // vsnprintf #include // va_list, ... #if OS_WINDOWS #define WIN32_LEAN_AND_MEAN #include #undef ERROR // why... #else #error "This configuration is NOT supported. Only Windows with MSVC is currently supported." #endif #ifndef PROTOTYPING_API #ifdef OS_WINDOWS #define PROTOTYPING_API extern "C" __declspec(dllexport) #else #define PROTOTYPING_API #endif #endif // #ifndef PROTOTYPING_API #define C_API #define TEMPORARY_API #define DEPRECATED_API #include #include // Primitive types. // typedef nullptr null typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; // typedef bool b8; // just use bool for b8s typedef s16 b16; typedef s32 b32; typedef s64 b64; typedef float f32; typedef double f64; // Units #define KB(n) (((s64)(n)) << 10) #define MB(n) (((s64)(n)) << 20) #define GB(n) (((s64)(n)) << 30) #define TB(n) (((s64)(n)) << 40) #define Thousand(n) ((n)*1000) #define Million(n) ((n)*1000000) #define Billion(n) ((n)*1000000000) #define internal static #define global static #define local_persist static // I don't like these, so I generally won't use them! #if COMPILER_MSVC # define thread_static __declspec(thread) #elif COMPILER_CLANG || COMPILER_GCC # define thread_static __thread #else # error thread_static not defined for this compiler. #endif #if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS) # pragma section(".rdata$", read) # define read_only __declspec(allocate(".rdata$")) #elif (COMPILER_CLANG && OS_LINUX) # define read_only __attribute__((section(".rodata"))) #else #endif #if COMPILER_MSVC # define force_inline __forceinline #elif COMPILER_CLANG || COMPILER_GCC # define force_inline __attribute__((always_inline)) #else # error force_inline not defined for this compiler. #endif // Maybe move to a different file. force_inline s64 Align_To_Page_Size(s64 n) { return (n + PLATFORM_MEMORY_PAGE_SIZE - 1) & (~(PLATFORM_MEMORY_PAGE_SIZE-1)); } template force_inline T Align (T value, s64 alignment) { s64 intermediate = (((s64)value) + alignment - 1) & (~(alignment - 1)); return (T)intermediate; } /* force_inline s64 Align_Forwards(s64 size, s64 alignment) { return (((size + alignment - 1) / alignment) * alignment); } */ // Branchless nextpow2 implementation. Returns zero if v is negative. // All it does is fill in all the bits to the right of the most significant bit. force_inline s64 Next_Power_Of_Two(s64 v) { v -= 1; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v |= v >> 32; v += 1; return v; } #define Stringify_(S) #S #define Stringify(S) Stringify_(S) #define Concat_(A,B) A##B #define Concat(A,B) Concat_(A,B) #if COMPILER_MSVC # define debug_break() __debugbreak() #elif COMPILER_CLANG || COMPILER_GCC # define debug_break() __builtin_trap() #else # define debug_break() # error Unknown trap intrinsic for this compiler. #endif #define AssertAlways(x) do{if(!(x)) {debug_break();}}while(0) #if BUILD_DEBUG # define Assert(x) AssertAlways(x) #else # define Assert(x) (void)(x) #endif #if LANG_CPP # define C_LINKAGE_BEGIN extern "C"{ # define C_LINKAGE_END } # define C_LINKAGE extern "C" #else # define C_LINKAGE_BEGIN # define C_LINKAGE_END # define C_LINKAGE #endif // Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) #if COMPILER_MSVC #define MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) #define MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) #else #define MSVC_RUNTIME_CHECKS_OFF #define MSVC_RUNTIME_CHECKS_RESTORE #endif // ForExpansions. Not sure if this is a good idea... // ↓TODO(Low priority): Maybe remove these. I prefer verbose and clear over this. #define ForArray(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_) #define ForArrayStartingAt(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1) #define ForUpTo(_it_, _end_) for (s64 _it_ = 0; _it_ < _end_; _it_ += 1) // Scoped Macros/Functions for auto_reset and auto_release // usage `Auto_Reset guard(arena);` within a scope. #define auto_reset(x) \ Auto_Reset Concat(_auto_reset_guard_, __LINE__)(x) #define push_allocator(x) \ Push_Allocator Concat(_push_alloc_guard_, __LINE__)(x) #define push_alignment(x, y) \ Push_Alignment Concat(_push_align_guard_, __LINE__)(x, y) #define push_arena(x) \ Push_Arena Concat(_push_arena_guard_, __LINE__)(x) #define push_expandable_arena(x) \ Push_Expandable_Arena Concat(_push_ex_arena_guard_, __LINE__)(x) #define auto_release_temp() \ auto_release(temp()); #define auto_release(x) \ Auto_Release Concat(_auto_release_guard_, __LINE__)(x) #define thread_context() thread_local_context #define temp() allocator(thread_context()->temp) #define context_allocator() thread_context()->allocator #define context_logger() &thread_context()->logger // #TODO #constexpr #MATH - make these constexpr // CHECK THAT THESE ARE CORRECT! constexpr f32 TAU = 6.283185f; constexpr f64 TAU_64 = 6.28318530717958648; constexpr f32 PI = 3.1415927f; constexpr f64 PI_64 = 3.141592653589793; constexpr f32 FLOAT16_MAX = 65504.0; constexpr f32 FLOAT32_MIN = (f32)(0x00800000); constexpr f32 FLOAT32_MAX = (f32)(0x7F7FFFFF); constexpr f32 FLOAT32_INFINITY = (f32)(0x7F800000); constexpr f32 FLOAT32_NAN = (f32)(0x7FBFFFFF); constexpr f64 FLOAT64_MIN = (f64)(0x0010000000000000ULL); constexpr f64 FLOAT64_MAX = (f64)(0x7FEFFFFFFFFFFFFFULL); constexpr f64 FLOAT64_INFINITY = (f64)(0x7FF0000000000000ULL); constexpr f64 FLOAT64_NAN = (f64)(0x7FF7FFFFFFFFFFFFULL); constexpr s8 S8_MIN = -128; constexpr s8 S8_MAX = 127; constexpr u8 U8_MAX = 255; constexpr s16 S16_MIN = -32768; constexpr s16 S16_MAX = 32767; constexpr u16 U16_MAX = 0xffff; constexpr s32 S32_MIN = 0x80000000; constexpr s32 S32_MAX = 0x7fffffff; constexpr u32 U32_MAX = 0xffffffff; constexpr s64 S64_MIN = 0x8000000000000000LL; constexpr s64 S64_MAX = 0x7fffffffffffffffLL; constexpr u64 U64_MAX = 0xffffffffffffffffULL; struct Vec2 { union { struct { float x, y; }; float data[2]; }; }; struct Vec3 { union { struct { float x, y, z; }; float data[3]; }; }; struct Vec4 { union { struct { float x, y, z, w; }; float data[4]; }; }; template T clamp (T v, T min, T max) { // T must be a scalar type: auto x = v; if (x < min) { x = min; } if (x > max) { x = max; } return x; } // #thread_primitives #move? #if OS_WINDOWS struct Condition_Variable { CONDITION_VARIABLE condition_variable; }; struct Semaphore { HANDLE event; }; struct Mutex { CRITICAL_SECTION csection; }; struct OS_Thread { HANDLE windows_thread; s32 windows_thread_id; }; struct File { HANDLE handle; }; internal void mutex_init (Mutex* mutex); internal void mutex_destroy (Mutex* mutex); internal void lock (Mutex* mutex); internal void unlock (Mutex* mutex); #endif #define POSIX_THREADS OS_LINUX || OS_MACOS || OS_IOS || OS_ANDROID #if OS_MACOS struct Semaphore { task_t owner; semaphore_t event = 0; }; #endif #if OS_LINUX || OS_ANDROID struct Semaphore { sem_t semaphore; }; #endif #if OS_IS_UNIX // #posix threads struct OS_Thread { pthread_t thread_handle; Semaphore is_alive; Semaphore suspended; b32 is_done; }; #endif #define lock_guard(x) \ Mutex_Lock_Guard Concat(_auto_lock_guard_, __LINE__)(x) struct Mutex_Lock_Guard { Mutex* mutex; Mutex_Lock_Guard (Mutex* mutex) { this->mutex = mutex; lock(mutex); } ~Mutex_Lock_Guard () { unlock(mutex); } };