/* 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 /* SSE4.2 */ /* ========================== * * Flag defaults * ========================== */ /* Compile definition defaults */ #ifndef RTC # define RTC 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 /* ========================== * * Machine context * ========================== */ /* Compiler */ #if defined(_MSC_VER) && !defined(__clang__) # define COMPILER_MSVC 1 # define COMPILER_CLANG 0 # define COMPILER_GCC 0 #elif defined(__clang__) # define COMPILER_MSVC 0 # define COMPILER_CLANG 1 # define COMPILER_GCC 0 #elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_MSVC 0 # define COMPILER_CLANG 0 # define COMPILER_GCC 1 #else # error "Unknown compiler" #endif /* Operating system */ #if defined(_WIN32) # define OS_WINDOWS 1 # define OS_MAC 0 # define OS_LINUX 0 #elif defined(__APPLE__) && defined(__MACH__) # define OS_WINDOWS 0 # define OS_MAC 1 # define OS_LINUX 0 #elif defined(__gnu_linux__) # define OS_WINDOWS 0 # define OS_MAC 0 # define OS_LINUX 1 #else # error "Unknown OS" #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 DEBINFO /* For use after a static 'L' state variable is declared. This will create a * variable that points to the 'L' variable and is kept alive (so that the * debugger can reference the state with a variable other than 'L') */ # define DEBUG_LVAR(var) ,__attribute((used)) *var = &L; #else # define DEBUG_LVAR(var) #endif #if RTC #define ASSERT(cond) ((cond) ? 1 : (__builtin_trap(), 0)) #define DEBUGBREAK __builtin_debugtrap() #define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; (UNUSED) __DEBUGBREAKABLE_VAR; } /* Address sanitization */ #if 0 void __asan_poison_memory_region(void *, size_t); void __asan_unpoison_memory_region(void *, 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 #else #define ASSERT(cond) (void)(0) #define DEBUGBREAK #define ASAN_POISON(addr, size) #define ASAN_UNPOISON(addr, size) #endif /* ========================== * * Common macros * ========================== */ #if 1 # define INLINE static inline #else /* TODO: benchmark benefits of forced inlining */ # define INLINE __attribute((always_inline)) static inline #endif /* Separate `static` usage into different keywords for easier grepping */ #define LOCAL_PERSIST static #define INTERNAL static #define GLOBAL static #pragma section(".roglob", read) #define READONLY __declspec(allocate(".roglob")) /* Markup */ #define UNUSED void #define FALLTHROUGH __attribute((fallthrough)) /* Sizes */ #define KILOBYTE(n) (n*1024ULL) #define MEGABYTE(n) (n*KILOBYTE(1024ULL)) #define GIGABYTE(n) (n*MEGABYTE(1024ULL)) #define TERABYTE(n) (n*GIGABYTE(1024ULL)) /* Sizeof & Alignof */ #ifdef __cplusplus # define ALIGNOF(type) alignof(type) #else # define ALIGNOF(type) __alignof__(type) #endif #define ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) #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 #define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field) /* Bool */ #ifndef __cplusplus # 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 0 #if COMPILER_MSVC # define PACKED(declaration) __pragma(pack(push, 1)) declaration __pragma(pack(pop)) #else # define PACKED(declaration) declaration __attribute((__packed__)) #endif #endif #define PACKED __attribute((__packed__)) /* 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_F_TO_U8(f) ((u8)((f * 255.0f) + 0.5f)) #define RGBA_F(r, g, b, a) RGBA(_RGB_F_TO_U8(r), _RGB_F_TO_U8(g), _RGB_F_TO_U8(b), _RGB_F_TO_U8(a)) #define RGB_F(r, g, b) RGBA_F(r, g, b, 1.f) #define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF) #define COLOR_BLACK RGB(0, 0, 0 ) #define COLOR_RED RGB(0xFF, 0, 0 ) #define COLOR_GREEN RGB(0, 0xFF, 0 ) #define COLOR_BLUE RGB(0, 0, 0xFF) /* Barrier */ #if 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) #if 0 /* ========================== * * Bit utils * ========================== */ #define bit_set(i, mask) (i |= mask) #define bit_clear(i, mask) (i &= ~mask) #define bit_flip(i, mask) (i ^= mask) #endif /* ========================== * * Primitive types * ========================== */ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef float f32; typedef double f64; typedef i8 b8; typedef i32 b32; #if 0 /* Unsigned memory (like size_t) */ typedef u64 umm; #endif #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)-0x80LL) #define I16_MIN ((i16)-0x8000LL) #define I32_MIN ((i32)-0x80000000LL) #define I64_MIN ((i64)-0x8000000000000000LL) /* ========================== * * Common structs * ========================== */ struct arena { u64 pos; u64 committed; u64 reserved; u8 *base; }; struct string { u64 len; u8 *text; }; struct string32 { u64 len; u32 *text; }; struct image_rgba { u32 width; u32 height; u32 *pixels; /* Array of [width * height] pixels */ }; struct pcm { u64 count; i16 *samples; }; struct buffer { u64 size; u8 *data; }; /* ========================== * * Buffer utils * ========================== */ /* Utility buffer constructor */ #define BUFFER(size, data) (struct buffer) {size, data} /* Utility buffer constructor from static array */ #define BUFFER_FROM_ARRAY(a) \ ( \ /* Must be array */ \ ASSERT(IS_ARRAY(a)), \ /* Must be array of bytes */ \ ASSERT(sizeof(a[0]) == sizeof(u8)), \ ((struct buffer) { .size = ARRAY_COUNT(a), .data = (u8 *)a }) \ ) #define BUFFER_FROM_STRING(str) ((struct buffer) { str.len, str.text }) #define BUFFER_FROM_POINTERS(p1, p2) ((struct buffer) { (u8 *)(p2) - (u8 *)(p1), (u8 *)p1 }) #define BUFFER_FROM_STRUCT(ptr) ((struct buffer) { sizeof(*ptr), ptr }) /* ========================== * * String utils * ========================== */ /* Expand C string literal with size for string initialization */ #ifdef __cplusplus #define STR(cstr_lit) { \ (sizeof((cstr_lit)) - 1), \ (u8 *)(cstr_lit) \ } #else #define STR(cstr_lit) (struct string) { \ .len = (sizeof((cstr_lit)) - 1), \ .text = (u8 *)(cstr_lit) \ } #endif /* Same as `STR`, but works with static variable initialization */ #define STR_NOCAST(cstr_lit) { \ .len = (sizeof((cstr_lit)) - 1), \ .text = (u8 *)(cstr_lit) \ } #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) ((struct v2) { (x), (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; }; struct xform { struct { struct v2 bx; /* X basis vector */ struct v2 by; /* Y basis vector */ struct v2 tl; /* Translation vector */ }; }; struct mat4x4 { f32 e[4][4]; }; #define RECT(x, y, width, height) (struct rect) { (x), (y), (width), (height) } struct rect { f32 x, y, width, height; }; /* 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 p1, p2; }; #define QUAD_UNIT_SQUARE (struct quad) { V2(0, 0), V2(0, 1), V2(1, 1), V2(1, 0) } #define QUAD_UNIT_SQUARE_CENTERED (struct quad) { V2(-0.5f, -0.5f), V2(0.5f, -0.5f), V2(0.5f, 0.5f), V2(-0.5f, 0.5f) } struct quad { struct v2 p1, p2, p3, p4; }; /* (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; }; /* ========================== * * Common utilities * ========================== */ 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 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; } 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 u64 cstr_len(char *cstr) { u64 len = 0; for (char *c = cstr; *c != 0; ++c) { ++len; } return len; } /* ========================== * * Profiling * ========================== */ #if PROFILING #include "third_party/tracy/tracy/TracyC.h" #define PROFILING_CAPTURE_FRAME_IMAGE 1 /* Clang/GCC cleanup macros */ #if COMPILER_CLANG || COMPILER_GCC # if !TRACY_NO_CALLSTACK # define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx __tracy_ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); # define __proscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, name, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx __tracy_ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); # endif # 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 ); #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) #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 __profframeimage(image, width, height, offset, flipped) #endif /* PROFILING */ /* ========================== * * Configurable constants * ========================== */ #include "config.h" #ifdef __cplusplus } #endif