327 lines
8.2 KiB
C++
327 lines
8.2 KiB
C++
#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 <stdio.h> // vsnprintf
|
|
#include <cstdarg> // va_list, ...
|
|
|
|
|
|
#if OS_WINDOWS
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
#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 <string.h>
|
|
#include <stdint.h>
|
|
|
|
// 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 <typename T>
|
|
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 <typename T> 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);
|
|
}
|
|
};
|