power_play/src/common.h
2024-03-08 17:09:55 -06:00

551 lines
15 KiB
C

/* 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:
* <mmintrin.h> MMX
* <xmmintrin.h> SSE
* <emmintrin.h> SSE2
* <pmmintrin.h> SSE3
* <tmmintrin.h> SSSE3
* <smmintrin.h> SSE4.1
* <nmmintrin.h> SSE4.2
* <ammintrin.h> SSE4A
* <wmmintrin.h> AES
* <immintrin.h> AVX, AVX2, FMA
*/
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <nmmintrin.h> /* 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
/* Storage specifiers */
#pragma section(".roglob", read)
#define READ_ONLY __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)
/* ========================== *
* Nil structs
* ========================== */
/* Declare */
#define DECLARE_NIL_STRUCT(type, function_name) \
extern READ_ONLY type CAT(__nil_struct__, function_name); \
INLINE READ_ONLY type *function_name(void) { return &CAT(__nil_struct__, function_name); }
/* Expects struct body after invocation. E.g. DEFINE_NIL_STRUCT(struct a, a_nil) { 0 } */
#define DEFINE_NIL_STRUCT(type, function_name) \
type READ_ONLY CAT(__nil_struct__, function_name)
#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 v2 bx; /* X basis vector (x axis) */
struct v2 by; /* Y basis vector (y axis)*/
struct v2 og; /* Translation vector (origin) */
};
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