/* This header is precompiled and automatically included into all source files */ /* NOTE: Include guards disabled since it breaks editor parsing */ //#ifndef COMMON_H //#define COMMON_H #ifdef __cplusplus extern "C" { #endif /* ========================== * * Compiler headers * ========================== */ /* Intrinsic header info: * MMX * SSE * SSE2 * SSE3 * SSSE3 * SSE4.1 * SSE4.2 * SSE4A * AES * AVX, AVX2, FMA */ #include #include #include #include #include /* SSE4.2 */ /* ========================== * * Flag defaults * ========================== */ /* Compile definition defaults */ #ifndef RTC # define RTC 0 #endif #ifndef ASAN # define ASAN 0 #endif #ifndef CRTLIB # define CRTLIB 0 #endif #ifndef DEBINFO # define DEBINFO 0 #endif #ifndef DEVELOPER # define DEVELOPER 0 #endif #ifndef PROFILING # define PROFILING 0 #endif #ifndef UNOPTIMIZED # define UNOPTIMIZED 0 #endif #ifndef RUN_TESTS # define RUN_TESTS 0 #endif #ifndef INCBIN_DIR_RAW # define INCBIN_DIR "" #else # define INCBIN_DIR STRINGIZE(INCBIN_DIR_RAW) #endif /* ========================== * * Machine context * ========================== */ /* Compiler */ #if defined(__clang__) # define COMPILER_CLANG 1 # define COMPILER_MSVC 0 #elif defined(_MSC_VER) # define COMPILER_CLANG 0 # define COMPILER_MSVC 1 #else # error "Unknown compiler" #endif /* Operating system */ #if defined(_WIN32) # define PLATFORM_WINDOWS 1 # define PLATFORM_MAC 0 # define PLATFORM_LINUX 0 #elif defined(__APPLE__) && defined(__MACH__) # define PLATFORM_WINDOWS 0 # define PLATFORM_MAC 1 # define PLATFORM_LINUX 0 #elif defined(__gnu_linux__) # define PLATFORM_WINDOWS 0 # define PLATFORM_MAC 0 # define PLATFORM_LINUX 1 #else # error "Unknown OS" #endif #if defined(__cplusplus) # define LANGUAGE_CPP 1 # define LANGUAGE_C 0 #else # define LANGUAGE_CPP 0 # define LANGUAGE_C 1 #endif /* ========================== * * Debug * ========================== */ /* Compile time assert */ #define CT_ASSERT3(cond, line) struct CT_ASSERT_____##line {int foo[(cond) ? 1 : -1];} #define CT_ASSERT2(cond, line) CT_ASSERT3(cond, line) #define CT_ASSERT(cond) CT_ASSERT2(cond, __LINE__) #if COMPILER_MSVC # if DEBINFO # define DEBUG_ALIAS(var, alias) *(alias) = &(var) # else # define DEBUG_ALIAS(var, alias) *(alias) = &(var) # endif #else # if DEBINFO # define DEBUG_ALIAS(var, alias) __attribute((used)) *(alias) = &(var) # else # define DEBUG_ALIAS(var, alias) __attribute((unused)) *(alias) = &(var) # endif #endif #if RTC # if COMPILER_MSVC # define ASSERT(cond) ((cond) ? 1 : ((*(volatile int *)0) = 0, 0)) # define DEBUGBREAK __debugbreak # else # define ASSERT(cond) ((cond) ? 1 : (__builtin_trap(), 0)) # define DEBUGBREAK __builtin_debugtrap() # endif # define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; (UNUSED) __DEBUGBREAKABLE_VAR; } (void)0 #else # define ASSERT(cond) (void)(0) #endif /* Address sanitization */ #if ASAN void __asan_poison_memory_region(void const volatile *, size_t); void __asan_unpoison_memory_region(void const volatile *add, size_t); # define ASAN_POISON(addr, size) __asan_poison_memory_region((addr), (size)); # define ASAN_UNPOISON(addr, size) __asan_unpoison_memory_region((addr), (size)); #else # define ASAN_POISON(addr, size) # define ASAN_UNPOISON(addr, size) #endif /* ========================== * * Common macros * ========================== */ #if COMPILER_MSVC && LANGUAGE_CPP # define CPPCOMPAT_INITLIST_TYPE(type) #else # define CPPCOMPAT_INITLIST_TYPE(type) (type) #endif /* Zero initialization macro */ #if LANGUAGE_C # define ZI { 0 } #else # define ZI { } #endif #if 1 # define INLINE static inline #else /* TODO: benchmark benefits of forced inlining */ # define INLINE static inline __attribute((always_inline)) #endif #if COMPILER_MSVC # define FORCE_INLINE static inline __forceinline #else # define FORCE_INLINE static inline __attribute((always_inline)) #endif /* Separate `static` usage into different keywords for easier grepping */ #define LOCAL_PERSIST static #define INTERNAL static #define GLOBAL static /* Read-only */ #if PLATFORM_WINDOWS # if COMPILER_MSVC # pragma section(".rdata$", read) # define READONLY __declspec(allocate(".rdata$")) # else # define READONLY __declspec(allocate(".rdata")) # endif #elif PLATFORM_MAC # define READONLY __attribute((section("__TEXT,__const"))) #else # define READONLY __attribute((section(".rodata"))) #endif /* Markup */ #define UNUSED void #if COMPILER_MSVC # if LANGUAGE_CPP # define FALLTHROUGH [[fallthrough]] # else # define FALLTHROUGH # endif #elif COMPILER_CLANG # define FALLTHROUGH __attribute((fallthrough)) #else # define FALLTHROUGH #endif /* Sizes */ #define KILOBYTE(n) (n*1024ULL) #define MEGABYTE(n) (n*KILOBYTE(1024ULL)) #define GIGABYTE(n) (n*MEGABYTE(1024ULL)) #define TERABYTE(n) (n*GIGABYTE(1024ULL)) /* Time */ #define NS_FROM_SECONDS(s) ((i64)((s) * 1000000000.0)) #define SECONDS_FROM_NS(ns) ((f64)(ns) / 1000000000.0) /* typeof */ #if COMPILER_MSVC /* Typeof not supported in MSVC */ # define TYPEOF_DEFINED 0 # define typeof(type) ASSERT(false) #else # define TYPEOF_DEFINED 1 # if LANGUAGE_CPP || (__STDC_VERSION__ < 202311L) # define typeof(type) __typeof__(type) # endif #endif /* alignof */ #if COMPILER_MSVC || (LANGUAGE_C && (__STDC_VERSION__ < 202311L)) # define alignof(type) __alignof(type) #endif #define ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) /* Field macros */ #define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field) #if COMPILER_MSVC && !defined _CRT_USE_BUILTIN_OFFSETOF # define FIELD_OFFSETOF(type, field) ((u64)&(((type *)0)->field)) #else # define FIELD_OFFSETOF(type, field) __builtin_offsetof(type, field) #endif /* Bool */ #if !LANGUAGE_CPP # define true 1 # define false 0 #endif /* Array */ #define IS_INDEXABLE(a) (sizeof(a[0])) #define IS_ARRAY(a) (IS_INDEXABLE(a) && (((void *)&a) == ((void *)a))) /* Pack */ #if COMPILER_MSVC # define PACK(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) #else # define PACK(s) s __attribute((__packed__)) #endif /* Color */ #define RGBA(r, g, b, a) (u32)((u32)(r) | ((u32)(g) << 8) | ((u32)(b) << 16) | ((u32)(a) << 24)) #define RGB(r, g, b) RGBA((r), (g), (b), 0xFF) #define _RGB_U8_FROM_F(fl) ((u8)((fl * 255.0) + 0.5)) #define RGBA_F(r, g, b, a) RGBA(_RGB_U8_FROM_F((r)), _RGB_U8_FROM_F((g)), _RGB_U8_FROM_F((b)), _RGB_U8_FROM_F((a))) #define RGB_F(r, g, b) RGBA_F((r), (g), (b), 1.f) #define ALPHA_F(color, a) ((color) & 0xFFFFFF00) | _RGB_U8_FROM_F((a)) /* Palette color defines */ #define COLOR_WHITE RGB(0xE6, 0xE8, 0xE6) #define COLOR_BLACK RGB(0x4C, 0x2E, 0x05) #define COLOR_RED RGB(0x6F, 0x1D, 0x1B) #define COLOR_GREEN RGB(0x26, 0xA9, 0x6C) #define COLOR_BLUE RGB(0x25, 0x8E, 0xA6) #define COLOR_YELLOW RGB(0xFC, 0xF6, 0xB1) #define COLOR_ORANGE RGB(0xFF, 0x7F, 0x51) #define COLOR_PURPLE RGB(0xFF, 0x57, 0xBB) /* True color defines */ #define COLOR_TRUE_WHITE RGB(0xFF, 0xFF, 0xFF) #define COLOR_TRUE_BLACK RGB(0x00, 0x00, 0x00) #define COLOR_TRUE_RED RGB(0xFF, 0x00, 0x00) #define COLOR_TRUE_GREEN RGB(0x00, 0xFF, 0x00) #define COLOR_TRUE_BLUE RGB(0x00, 0x00, 0xFF) #define COLOR_TRUE_YELLOW RGB(0xFF, 0xFF, 0x00) #define COLOR_TRUE_ORANGE RGB(0xFF, 0xA5, 0x00) #define COLOR_TRUE_PURPLE RGB(0xFF, 0x00, 0XFF) /* Barrier */ #if COMPILER_MSVC # define WRITE_BARRIER() _WriteBarrier() # define READ_BARRIER() _ReadBarrier() #elif defined(__x86_64) || defined(__i386__) # define WRITE_BARRIER() __asm__ volatile("" ::: "memory") # define READ_BARRIER() __asm__ volatile("" ::: "memory") #else # error "Memory barriers not implemented" #endif /* Cat */ #define CAT1(a, b) a ## b #define CAT(a, b) CAT1(a, b) /* Stringize */ #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) /* ========================== * * Primitive types * ========================== */ typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef float f32; typedef double f64; typedef i8 b8; typedef i32 b32; #define U8_MAX (0xFF) #define U16_MAX (0xFFFF) #define U32_MAX (0xFFFFFFFF) #define U64_MAX (0xFFFFFFFFFFFFFFFFULL) #define I8_MAX (0x7F) #define I16_MAX (0x7FFF) #define I32_MAX (0x7FFFFFFF) #define I64_MAX (0x7FFFFFFFFFFFFFFFLL) #define I8_MIN ((i8)-0x80) #define I16_MIN ((i16)-0x8000) #define I32_MIN ((i32)-0x80000000) #define I64_MIN ((i64)-0x8000000000000000ULL) GLOBAL const u32 _f32_infinity_u32 = 0x7f800000; GLOBAL const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32; #define F32_INFINITY (*_f32_infinity) GLOBAL const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL; GLOBAL const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64; #define F64_INFINITY (*_f64_infinity) GLOBAL const u32 _f32_nan_u32 = 0x7f800001; GLOBAL const f32 *_f32_nan = (f32 *)&_f32_nan_u32; #define F32_NAN (*_f32_nan) GLOBAL const u64 _f64_nan_u64 = 0x7ff8000000000001; GLOBAL const f64 *_f64_nan = (f64 *)&_f64_nan_u64; #define F64_NAN (*_f64_nan) #define F32_IS_NAN(x) (x != x) #define F64_IS_NAN(x) (x != x) #define PI ((f32)3.14159265358979323846) #define TAU ((f32)6.28318530717958647693) /* ========================== * * Atomics * ========================== */ struct atomic_i32 { volatile i32 _v; }; struct atomic_i64 { volatile i64 _v; }; struct atomic_u32 { volatile u32 _v; }; struct atomic_u64 { volatile u64 _v; }; struct atomic_ptr { volatile void *_v; }; /* ========================== * * Common structs * ========================== */ struct arena { u64 pos; u64 committed; u64 reserved; u8 *base; #if RTC b32 readonly; #endif }; struct string { u64 len; u8 *text; }; struct string16 { u64 len; u16 *text; }; struct string32 { u64 len; u32 *text; }; #define UID(hi64, lo64) ((struct uid) { .hi = (hi64), .lo = (lo64) }) struct uid { u64 hi; u64 lo; }; INLINE b32 uid_eq(struct uid a, struct uid b) { return a.hi == b.hi && a.lo == b.lo; } INLINE b32 uid_is_zero(struct uid v) { return v.hi == 0 && v.lo == 0; } struct image_rgba { u32 width; u32 height; u32 *pixels; /* Array of [width * height] pixels */ }; struct pcm { u64 count; i16 *samples; }; struct sim_client_handle { u32 idx; u32 gen; }; struct sim_ent_id { struct uid uid; }; struct space_entry_handle { u64 idx; u64 gen; }; struct host_channel_id { u32 gen; u32 idx; }; /* ========================== * * Tag structs * ========================== */ struct sprite_tag { u64 hash; struct string path; }; /* ========================== * * String utils * ========================== */ /* Expand C string literal with size for string initialization */ #define LIT(cstr_lit) CPPCOMPAT_INITLIST_TYPE(struct string) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } /* Same as `STR`, but works with static variable initialization */ #define LIT_NOCAST(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } #define STRING(size, data) (CPPCOMPAT_INITLIST_TYPE(struct string) { (size), (data) }) #define STRING_FROM_POINTERS(p0, p1) (CPPCOMPAT_INITLIST_TYPE(struct string) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) #define STRING_FROM_STRUCT(ptr) (CPPCOMPAT_INITLIST_TYPE(struct string) { sizeof(*(ptr)), (u8 *)(ptr) }) /* String from static array */ #define STRING_FROM_ARRAY(a) \ ( \ /* Must be array */ \ ASSERT(IS_ARRAY(a)), \ /* Must be array of bytes */ \ ASSERT(sizeof((a)[0]) == sizeof(u8)), \ ((struct string) { .len = ARRAY_COUNT(a), .text = (u8 *)(a) }) \ ) /* ========================== * * Math types * ========================== */ #define V2(x, y) CPPCOMPAT_INITLIST_TYPE(struct v2) { (x), (y) } #define V2_FROM_V2I32(v) V2((v).x, (v).y) struct v2 { f32 x, y; }; struct v2_array { struct v2 *points; u64 count; }; #define V3(x, y, z) ((struct v3) { (x), (y), (z) }) struct v3 { f32 x, y, z; }; struct v3_array { struct v3 *points; u64 count; }; #define V4(x, y, z, w) ((struct v4) { (x), (y), (z), (w) }) struct v4 { f32 x, y, z, w; }; struct v4_array { struct v4 *points; u64 count; }; #define V2I32(x, y) CPPCOMPAT_INITLIST_TYPE(struct v2i32) { (x), (y) } struct v2i32 { i32 x, y; }; struct xform { struct v2 bx; /* X basis vector (x axis) */ struct v2 by; /* Y basis vector (y axis)*/ struct v2 og; /* Translation vector (origin) */ }; struct mat4x4 { union { struct { struct v4 bx, by, bz, bw; }; f32 e[4][4]; }; }; #define RECT(_x, _y, _width, _height) (struct rect) { .x = (_x), .y = (_y), .width = (_width), .height = (_height) } #define RECT_FROM_V2(_pos, _size) (struct rect) { .pos = (_pos), .size = (_size) } struct rect { union { struct { f32 x, y, width, height; }; struct { struct v2 pos, size; }; }; }; INLINE b32 rect_eq(struct rect r1, struct rect r2) { return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height; } struct aabb { struct v2 p0, p1; }; /* Values expected to be normalized 0.0 -> 1.0 */ #define CLIP_ALL ((struct clip_rect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } }) struct clip_rect { struct v2 p0, p1; }; #define QUAD_UNIT_SQUARE (struct quad) { .p0 = V2(0, 0), .p1 = V2(0, 1), .p2 = V2(1, 1), .p3 = V2(1, 0) } #define QUAD_UNIT_SQUARE_CENTERED (struct quad) { .p0 = V2(-0.5f, -0.5f), .p1 = V2(0.5f, -0.5f), .p2 = V2(0.5f, 0.5f), .p3 = V2(-0.5f, 0.5f) } struct quad { union { struct { struct v2 p0, p1, p2, p3; }; struct { struct v2 e[4]; }; }; }; /* (T)ranslation, (R)otation, (S)cale */ #define TRS(...) ((struct trs) { .t = V2(0,0), .s = V2(1, 1), .r = 0, __VA_ARGS__ }) struct trs { struct v2 t; struct v2 s; f32 r; }; /* ========================== * * Collider types * ========================== */ struct collider_shape { struct v2 points[8]; u32 count; f32 radius; }; /* ========================== * * Common utilities * ========================== */ INLINE u8 min_u8(u8 a, u8 b) { return a <= b ? a : b; } INLINE u8 max_u8(u8 a, u8 b) { return a >= b ? a : b; } INLINE u32 min_u32(u32 a, u32 b) { return a <= b ? a : b; } INLINE u32 max_u32(u32 a, u32 b) { return a >= b ? a : b; } INLINE u64 min_u64(u64 a, u64 b) { return a <= b ? a : b; } INLINE u64 max_u64(u64 a, u64 b) { return a >= b ? a : b; } INLINE i32 min_i32(i32 a, i32 b) { return a <= b ? a : b; } INLINE i32 max_i32(i32 a, i32 b) { return a >= b ? a : b; } INLINE i64 min_i64(i64 a, i64 b) { return a <= b ? a : b; } INLINE i64 max_i64(i64 a, i64 b) { return a >= b ? a : b; } INLINE f32 min_f32(f32 a, f32 b) { return a <= b ? a : b; } INLINE f32 max_f32(f32 a, f32 b) { return a >= b ? a : b; } INLINE f64 min_f64(f64 a, f64 b) { return a <= b ? a : b; } INLINE f64 max_f64(f64 a, f64 b) { return a >= b ? a : b; } INLINE u32 clamp_u32(u32 v, u32 min, u32 max) { return v < min ? min : v > max ? max : v; } INLINE u64 clamp_u64(u64 v, u64 min, u64 max) { return v < min ? min : v > max ? max : v; } INLINE i32 clamp_i32(i32 v, i32 min, i32 max) { return v < min ? min : v > max ? max : v; } INLINE i64 clamp_i64(i64 v, i64 min, i64 max) { return v < min ? min : v > max ? max : v; } INLINE f32 clamp_f32(f32 v, f32 min, f32 max) { return v < min ? min : v > max ? max : v; } INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; } /* ========================== * * Profiling * ========================== */ #if PROFILING #include "third_party/tracy/tracy/TracyC.h" #define PROFILING_CAPTURE_FRAME_IMAGE 1 /* Clang/GCC cleanup macros */ #if COMPILER_MSVC # error "MSVC not supported for profiling (cleanup attributes are required for profiling markup)" #else # ifdef TRACY_NO_CALLSTACK # define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); # define __profscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, #name, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); # else # define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); # define __profscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, #name, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); # endif #endif INLINE void __prof_zone_cleanup_func(TracyCZoneCtx *__tracy_ctx) { TracyCZoneEnd(*__tracy_ctx); } #define __profalloc(ptr, size) TracyCAlloc((ptr), (size)) #define __proffree(ptr) TracyCFree((ptr)) #define __profmsg(txt, len, col) TracyCMessageC((txt), (len), (col)); #define __profframe(name) TracyCFrameMarkNamed((name)) #define __profthread(name) TracyCSetThreadName((name)) #define __proflock_ctx TracyCSharedLockCtx #define __proflock_alloc(ctx) TracyCSharedLockAnnounce((ctx)) #define __proflock_release(ctx) TracyCSharedLockTerminate((ctx)) #define __proflock_before_exclusive_lock(ctx) TracyCSharedLockBeforeExclusiveLock((ctx)) #define __proflock_after_exclusive_lock(ctx) TracyCSharedLockAfterExclusiveLock((ctx)) #define __proflock_after_exclusive_unlock(ctx) TracyCSharedLockAfterExclusiveUnlock((ctx)) #define __proflock_after_try_exclusive_lock(ctx, acquired) TracyCSharedLockAfterTryExclusiveLock((ctx), (acquired)) #define __proflock_before_shared_lock(ctx) TracyCSharedLockBeforeSharedLock((ctx)) #define __proflock_after_shared_lock(ctx) TracyCSharedLockAfterSharedLock((ctx)) #define __proflock_after_shared_unlock(ctx) TracyCSharedLockAfterSharedUnlock((ctx)) #define __proflock_after_try_shared_lock(ctx, acquired) TracyCSharedLockAfterTrySharedLock((ctx), (acquired)) #define __proflock_mark(ctx) TracyCSharedLockMark((ctx)) #define __proflock_custom_name(ctx, name, len) TracyCSharedLockCustomName((ctx), (name), (len)) #if PROFILING_CAPTURE_FRAME_IMAGE # define __profframeimage(image, width, height, offset, flipped) TracyCFrameImage((image), (width), (height), (offset), (flipped)); #else # define __profframeimage(image, width, height, offset, flipped) #endif /* PROFILING_CAPTURE_FRAME_IMAGE */ #else #define PROFILING_CAPTURE_FRAME_IMAGE 0 #define __prof #define __profscope(name) #define __profalloc(ptr, size) #define __proffree(ptr) #define __profmsg(txt, len, col) #define __profframe(name) #define __profthread(name) #define __profframeimage(image, width, height, offset, flipped) #define __proflock_ctx #define __proflock_alloc(ctx) #define __proflock_release(ctx) #define __proflock_before_exclusive_lock(ctx) #define __proflock_after_exclusive_lock(ctx) #define __proflock_after_exclusive_unlock(ctx) #define __proflock_after_try_exclusive_lock(ctx, acquired) #define __proflock_before_shared_lock(ctx) #define __proflock_after_shared_lock(ctx) #define __proflock_after_shared_unlock(ctx) #define __proflock_after_try_shared_lock(ctx, acquired) #define __proflock_mark(ctx) #define __proflock_custom_name(ctx, name, len) #endif /* PROFILING */ /* ========================== * * Configurable constants * ========================== */ #include "config.h" #ifdef __cplusplus } #endif