// The Digital Grove Codebase // Copyright (c) Ryan Fleury. All rights reserved. #ifndef BASE_H #define BASE_H //////////////////////////////// //~ rjf: Context Cracking //- rjf: MSVC Extraction #if defined(_MSC_VER) # define COMPILER_MSVC 1 # if defined(_WIN32) # define PLATFORM_WINDOWS 1 # else # error _MSC_VER is defined, but _WIN32 is not. This setup is not supported. # endif # if defined(_M_AMD64) # define ARCH_X64 1 # elif defined(_M_IX86) # define ARCH_X86 1 # elif defined(_M_ARM64) # define ARCH_ARM64 1 # elif defined(_M_ARM) # define ARCH_ARM32 1 # else # error Target architecture is not supported. _MSC_VER is defined, but one of {_M_AMD64, _M_IX86, _M_ARM64, _M_ARM} is not. # endif #if _MSC_VER >= 1920 # define COMPILER_MSVC_YEAR 2019 #elif _MSC_VER >= 1910 # define COMPILER_MSVC_YEAR 2017 #elif _MSC_VER >= 1900 # define COMPILER_MSVC_YEAR 2015 #elif _MSC_VER >= 1800 # define COMPILER_MSVC_YEAR 2013 #elif _MSC_VER >= 1700 # define COMPILER_MSVC_YEAR 2012 #elif _MSC_VER >= 1600 # define COMPILER_MSVC_YEAR 2010 #elif _MSC_VER >= 1500 # define COMPILER_MSVC_YEAR 2008 #elif _MSC_VER >= 1400 # define COMPILER_MSVC_YEAR 2005 #else # define COMPILER_MSVC_YEAR 0 #endif //- rjf: Clang Extraction #elif defined(__clang__) # define COMPILER_CLANG 1 # if defined(__APPLE__) && defined(__MACH__) # define PLATFORM_MAC 1 # elif defined(__gnu_linux__) # define PLATFORM_LINUX 1 # elif defined(N64) # define PLATFORM_N64 1 # else # error __clang__ is defined, but one of {__APPLE__, __gnu_linux__, N64} is not. This setup is not supported. # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) # define ARCH_X64 1 # elif defined(i386) || defined(__i386) || defined(__i386__) # define ARCH_X86 1 # elif defined(__aarch64__) # define ARCH_ARM64 1 # elif defined(__arm__) # define ARCH_ARM32 1 # elif defined(__mips) && defined(__mips64) # define ARCH_MIPS64 1 # elif defined(__mips) && !defined(__mips64) # define ARCH_MIPS32 1 # else # error Target architecture is not supported. __clang__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__, __mips} is not. # endif //- rjf: GCC Extraction #elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_GCC 1 # if defined(__gnu_linux__) # define PLATFORM_LINUX 1 # else # error __GNUC__ or __GNUG__ is defined, but __gnu_linux__ is not. This setup is not supported. # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) # define ARCH_X64 1 # elif defined(i386) || defined(__i386) || defined(__i386__) # define ARCH_X86 1 # elif defined(__aarch64__) # define ARCH_ARM64 1 # elif defined(__arm__) # define ARCH_ARM32 1 # else # error Target architecture is not supported. __GNU_C__ or __GNUG__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__} is not. # endif #else # error Compiler is not supported. _MSC_VER, __clang__, __GNUC__, or __GNUG__ must be defined. #endif #if ARCH_X64 || ARCH_ARM64 || ARCH_MIPS64 # define ARCH_64BIT 1 #elif ARCH_X86 || ARCH_ARM32 || ARCH_MIPS32 # define ARCH_32BIT 1 #endif #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define LITTLE_ENDIAN 0 # define BIG_ENDIAN 1 #else # define LITTLE_ENDIAN 1 # define BIG_ENDIAN 0 #endif //////////////////////////////// //~ rjf: Variadic Arguments #define VariadicS64(args) va_arg(args, S64) #define VariadicU64(args) va_arg(args, U64) #if ARCH_X64 || ARCH_ARM64 # define VariadicS32(args) va_arg(args, S32) # define VariadicU32(args) va_arg(args, U32) # define VariadicInt(args) va_arg(args, int) # define VariadicAddr(args) va_arg(args, UAddr) #elif ARCH_MIPS32 || ARCH_MIPS64 # define VariadicS32(args) (S32)(va_arg(args, U64) & 0xffffffff) # define VariadicU32(args) (U64)(va_arg(args, U64) & 0xffffffff) # define VariadicInt(args) (int)(va_arg(args, U64) & 0xffffffff) # define VariadicAddr(args) (UAddr)(va_arg(args, U64) & 0xffffffff) #endif //////////////////////////////// //~ rjf: Keywords #define function static #define global static #define local_persist static #define align(n) __attribute__((aligned(n))) //////////////////////////////// //~ rjf: Preprocessor Operations #define Glue_(A, B) A##B #define Glue(A, B) Glue_(A, B) #define Stringify_(S) #S #define Stringify(S) Stringify_(S) //////////////////////////////// //~ rjf: Static Assertions #define StaticAssert(C, ID) global U8 Glue(ID, __LINE__)[(C)?1:-1] //////////////////////////////////////////////////////////////// //~ rjf: Clamps, Mins, Maxes #define Min(a, b) (((a)<(b)) ? (a) : (b)) #define Max(a, b) (((a)>(b)) ? (a) : (b)) #define ClampTop(x, a) Min(x,a) #define ClampBot(a, x) Max(a,x) #define Clamp(a, x, b) (((a)>(x))?(a):((b)<(x))?(b):(x)) //////////////////////////////////////////////////////////////// //~ rjf: Swaps #define Swap(T, a, b) do{T c = (a); (a) = (b); (b) = c;}while(0) //////////////////////////////////////////////////////////////// //~ rjf: Array Counts #define ArrayCount(a) ((sizeof(a)) / sizeof((a)[0])) #define ArrayAndCount(a) (a), ArrayCount(a) #define CountAndArray(a) ArrayCount(a), (a) //////////////////////////////////////////////////////////////// //~ rjf: Loop Helpers #define EachIndex(idx, count) (UAddr idx = 0; idx < (count); idx += 1) #define EachElement(idx, array) (UAddr idx = 0; idx < ArrayCount(array); idx += 1) #define DeferLoop(start, end) for(int _i_ = ((start), 0); _i_ == 0; (_i_ += 1, (end))) #define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) //////////////////////////////////////////////////////////////// //~ rjf: Bit Arrays #define BitArrayDecl(type, name, count) type name[(count + sizeof(type)*8-1) / sizeof(type)*8] #define BitArrayAdd(arr, bit) ((arr)[(bit) / (sizeof((arr)[0])*8)] |= (((U64)1) << ((bit) % (sizeof((arr)[0])*8)))) #define BitArrayRemove(arr, bit) ((arr)[(bit) / (sizeof((arr)[0])*8)] &= ~(((U64)1) << ((bit) % (sizeof((arr)[0])*8)))) #define BitArrayGet(arr, bit) (!!((arr)[(bit) / (sizeof((arr)[0])*8)] & (((U64)1) << ((bit) % (sizeof((arr)[0])*8))))) //////////////////////////////// //~ rjf: Masks #define Lower16(x) (((x)&0x0000ffff) >> 0) #define Upper16(x) (((x)&0xffff0000) >> 16) #define Lower32(x) (((x)&0x00000000ffffffffull) >> 0) #define Upper32(x) (((x)&0xffffffff00000000ull) >> 32) //////////////////////////////// //~ rjf: Units #define KiB(x) ((x)*1024) #define MiB(x) (KiB(x)*1024) #define GiB(x) (MiB(x)*1024) #define TiB(x) (GiB(x)*1024) //////////////////////////////////////////////////////////////// //~ rjf: Structure Packing Marker Macros #define pack_begin _Pragma("pack(push, 1)") #define pack_end _Pragma("pack(pop)") //////////////////////////////////////////////////////////////// //~ rjf: Type -> Alignment #if COMPILER_MSVC # define AlignOf(T) __alignof(T) #elif COMPILER_CLANG # define AlignOf(T) __alignof(T) #elif COMPILER_GCC # define AlignOf(T) __alignof__(T) #else # error AlignOf not defined for this compiler. #endif //////////////////////////////// //~ rjf: Basic Types #include typedef int8_t S8; typedef int16_t S16; typedef int32_t S32; typedef int64_t S64; typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; typedef S8 B8; typedef S16 B16; typedef S32 B32; typedef S64 B64; typedef float F32; typedef double F64; typedef void VoidFunction(void); #if ARCH_32BIT typedef S32 SAddr; typedef U32 UAddr; #elif ARCH_64BIT typedef S64 SAddr; typedef U64 UAddr; #endif //////////////////////////////// //~ rjf: C Runtime Implementations void *memset(void *buffer, int c, UAddr n); void *memcpy(void *dest, void *src, UAddr n); //////////////////////////////// //~ rjf: Memory Operations #define MemoryZero(ptr, size) memset((ptr), 0, (size)) #define MemoryZeroStruct(ptr) MemoryZero((ptr), sizeof(*(ptr))) #define MemoryCopy(dst, src, size) memcpy((dst), (src), (size)) #define MemoryCopyStruct(dst, src) memcpy((dst), (src), Min(sizeof(*(dst)), sizeof(*(src)))) function inline void WriteAndInc(void *buffer, void *src, UAddr size, UAddr *cursor) { MemoryCopy((U8 *)buffer + *cursor, src, size); *cursor += size; } function inline void ReadAndInc(void *buffer, void *dst, UAddr size, UAddr *cursor) { MemoryCopy(dst, (U8 *)buffer + *cursor, size); *cursor += size; } #define WriteStructAndInc(buffer, ptr, cursor_ptr) WriteAndInc((buffer), (ptr), sizeof(*(ptr)), (cursor_ptr)) #define ReadStructAndInc(buffer, ptr, cursor_ptr) ReadAndInc((buffer), (ptr), sizeof(*(ptr)), (cursor_ptr)) //////////////////////////////// //~ rjf: Float Operations function inline F32 TruncF32(F32 f) { #if ARCH_MIPS32 F32 result_int; F32 result; __asm("trunc.w.s %0,%1" : "=f"(result_int) : "f"(f)); __asm("cvt.s.w %0,%1" : "=f"(result) : "f"(result_int)); return result; #else # error TruncF32 not implemented for this architecture. #endif } function inline F32 FloorF32(F32 f) { #if ARCH_MIPS32 F32 result_int; F32 result; __asm("floor.w.s %0,%1" : "=f"(result_int) : "f"(f)); __asm("cvt.s.w %0,%1" : "=f"(result) : "f"(result_int)); return result; #else # error FloorF32 not implemented for this architecture. #endif } function inline F32 ModF32(F32 f, F32 d) { F32 result = f - TruncF32(f/d)*d; return result; } function inline S32 Fixed112FromF32(F32 f) { S32 result = (S32)(f*4.f); result = Clamp(-4096*4, result, +4095*4); return result; } function inline S32 Fixed1616FromF32(F32 f) { S32 result; if(f >= 32768.f) { result = 0x7fffffff; } else if(f < -32768.f) { result = 0x80000000; } else { result = (S32)FloorF32(f*65536.f); } return result; } //////////////////////////////// //~ rjf: Scalar Math Functions function F32 inline SquareRootF32(F32 v) { #if ARCH_MIPS32 F32 result; __asm("sqrt.s %0,%1" : "=f"(result) : "f"(v)); return result; #else # error SquareRootF32 not implemented for this architecture. #endif } function F32 SinF32(F32 turns); function F32 inline CosF32(F32 turns) { F32 result = SinF32(turns + 0.25f); return result; } function F32 inline TanF32(F32 turns) { F32 result = SinF32(turns) / CosF32(turns); return result; } //////////////////////////////// //~ rjf: Vector / Matrix Types typedef union Vec2U32 Vec2U32; union Vec2U32 { struct { U32 x; U32 y; }; U32 v[2]; }; typedef union Vec2F32 Vec2F32; union Vec2F32 { struct { F32 x; F32 y; }; F32 v[2]; }; typedef union Vec3F32 Vec3F32; union Vec3F32 { struct { F32 x; F32 y; F32 z; }; struct { Vec2F32 xy; F32 z_; }; struct { F32 x_; Vec2F32 yz; }; F32 v[3]; }; typedef union Vec4F32 Vec4F32; union Vec4F32 { struct { F32 x; F32 y; F32 z; F32 w; }; struct { Vec2F32 xy; Vec2F32 zw; }; struct { Vec3F32 xyz; F32 w_; }; struct { F32 x_; Vec3F32 yzw; }; F32 v[4]; }; typedef struct Mat3x3F32 Mat3x3F32; struct Mat3x3F32 { F32 v[3][3]; }; typedef struct Mat4x4F32 Mat4x4F32; struct Mat4x4F32 { F32 v[4][4]; }; //////////////////////////////// //~ rjf: Vector Functions //- rjf: constructors function Vec2U32 V2U32(U32 x, U32 y); function Vec2F32 V2F32(F32 x, F32 y); function Vec3F32 V3F32(F32 x, F32 y, F32 z); function Vec4F32 V4F32(F32 x, F32 y, F32 z, F32 w); //- rjf: 2-vector ops function Vec2F32 Add2F32(Vec2F32 l, Vec2F32 r); function Vec2F32 Sub2F32(Vec2F32 l, Vec2F32 r); function Vec2F32 Mul2F32(Vec2F32 l, Vec2F32 r); function Vec2F32 Div2F32(Vec2F32 l, Vec2F32 r); function F32 LengthSquared2F32(Vec2F32 v); function F32 Length2F32(Vec2F32 v); function Vec2F32 Scale2F32(Vec2F32 v, F32 s); function Vec2F32 Normalize2F32(Vec2F32 v); function F32 Dot2F32(Vec2F32 l, Vec2F32 r); //- rjf: 3-vector ops function Vec3F32 Add3F32(Vec3F32 l, Vec3F32 r); function Vec3F32 Sub3F32(Vec3F32 l, Vec3F32 r); function Vec3F32 Mul3F32(Vec3F32 l, Vec3F32 r); function Vec3F32 Div3F32(Vec3F32 l, Vec3F32 r); function F32 LengthSquared3F32(Vec3F32 v); function F32 Length3F32(Vec3F32 v); function Vec3F32 Scale3F32(Vec3F32 v, F32 s); function Vec3F32 Normalize3F32(Vec3F32 v); function F32 Dot3F32(Vec3F32 l, Vec3F32 r); function Vec3F32 Cross3F32(Vec3F32 l, Vec3F32 r); //- rjf: 4-vector ops function Vec4F32 Add4F32(Vec4F32 l, Vec4F32 r); function Vec4F32 Sub4F32(Vec4F32 l, Vec4F32 r); function Vec4F32 Mul4F32(Vec4F32 l, Vec4F32 r); function Vec4F32 Div4F32(Vec4F32 l, Vec4F32 r); function F32 LengthSquared4F32(Vec4F32 v); function F32 Length4F32(Vec4F32 v); function Vec4F32 Scale4F32(Vec4F32 v, F32 s); function Vec4F32 Normalize4F32(Vec4F32 v); function F32 Dot4F32(Vec4F32 l, Vec4F32 r); function Vec4F32 XForm4F32(Mat4x4F32 m, Vec4F32 v); //////////////////////////////// //~ rjf: Matrix Functions //- rjf: constructors function Mat3x3F32 MakeMat3x3F32(F32 d); function Mat3x3F32 MakeTranslate3x3F32(Vec2F32 translation); function Mat3x3F32 MakeScale3x3F32(Vec2F32 scale); function Mat3x3F32 MakeRotate3x3F32(F32 turns); function Mat4x4F32 MakeMat4x4F32(F32 d); function Mat4x4F32 MakeTranslate4x4F32(Vec3F32 translation); function Mat4x4F32 MakeScale4x4F32(Vec3F32 scale); function Mat4x4F32 MakePerspective4x4F32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z); function Mat4x4F32 MakeOrthographic4x4F32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z); function Mat4x4F32 MakeLookAt4x4F32(Vec3F32 eye, Vec3F32 center, Vec3F32 up); function Mat4x4F32 MakeRotate4x4F32(Vec3F32 axis, F32 turns); //- rjf: ops function Mat3x3F32 Mul3x3F32(Mat3x3F32 a, Mat3x3F32 b); function Mat3x3F32 Scale3x3F32(Mat3x3F32 m, F32 scale); function Mat4x4F32 Mul4x4F32(Mat4x4F32 a, Mat4x4F32 b); function Mat4x4F32 Scale4x4F32(Mat4x4F32 m, F32 scale); function Mat4x4F32 Inverse4x4F32(Mat4x4F32 m); function Mat4x4F32 RemoveRotation4x4F32(Mat4x4F32 mat); //////////////////////////////// //~ rjf: Arenas typedef struct Arena Arena; struct Arena { UAddr pos; UAddr cap; }; function Arena *ArenaMakeStatic(U8 *buffer, UAddr buffer_size); function void *ArenaPush(Arena *arena, UAddr size, UAddr align); function UAddr ArenaPos(Arena *arena); function void ArenaPopTo(Arena *arena, UAddr pos); function void ArenaClear(Arena *arena); function void ArenaPop(Arena *arena, UAddr amt); #define PushArrayNoZeroAligned(a, T, c, align) (T *)ArenaPush((a), sizeof(T)*(c), (align)) #define PushArrayAligned(a, T, c, align) (T *)MemoryZero(PushArrayNoZeroAligned(a, T, c, align), sizeof(T)*(c)) #define PushArrayNoZero(a, T, c) PushArrayNoZeroAligned(a, T, c, AlignOf(T)) #define PushArray(a, T, c) PushArrayAligned(a, T, c, AlignOf(T)) //////////////////////////////// //~ rjf: Arena Temporary Scopes typedef struct Temp Temp; struct Temp { Arena *arena; UAddr pos; }; function Temp TempBegin(Arena *arena); function void TempEnd(Temp temp); //////////////////////////////// //~ rjf: Thread Context typedef struct ThreadCtx ThreadCtx; struct ThreadCtx { Arena *scratch_arenas[2]; }; //- rjf: @per_platform Thread Context Functions function ThreadCtx *GetThreadCtx(void); //- rjf: Thread Context Helpers function Arena *GetScratch(Arena *conflict); #define ScratchBegin(result_arena) TempBegin(GetScratch(result_arena)) #define ScratchEnd(temp) TempEnd(temp) //////////////////////////////// //~ rjf: Strings #include typedef struct String8 String8; struct String8 { U8 *str; UAddr size; }; function UAddr CStr8Size(char *cstr); function String8 Str8(U8 *str, UAddr size); #define Str8Lit(s) Str8((U8 *)(s), sizeof(s)-1) #define Str8LitComp(s) {(U8 *)(s), sizeof(s)-1} #define S(s) Str8Lit(s) function String8 Str8FV(Arena *arena, char *fmt, va_list args); function String8 Str8F(Arena *arena, char *fmt, ...); #define SF(...) Str8F(scratch.arena, __VA_ARGS__) function String8 ByteStringFromData(Arena *arena, String8 data); global U8 dec_chars[] = "0123456789"; global U8 hex_chars_lower[] = "0123456789abcdef"; global U8 hex_chars_upper[] = "0123456789ABCDEF"; //////////////////////////////// //~ rjf: Colors function U16 RGBA5551From4F32(Vec4F32 rgba); function U32 RGBA32From4F32(Vec4F32 rgba); function Vec4F32 RGBA4F32From32(U32 rgba); //////////////////////////////// //~ rjf: Game Pads typedef enum GamePadButtonKind { GamePadButtonKind_Null, GamePadButtonKind_A, GamePadButtonKind_B, GamePadButtonKind_CLeft, GamePadButtonKind_CUp, GamePadButtonKind_CRight, GamePadButtonKind_CDown, GamePadButtonKind_Start, GamePadButtonKind_DLeft, GamePadButtonKind_DUp, GamePadButtonKind_DRight, GamePadButtonKind_DDown, GamePadButtonKind_Z, GamePadButtonKind_LeftBumper, GamePadButtonKind_RightBumper, GamePadButtonKind_COUNT } GamePadButtonKind; typedef struct GamePad GamePad; struct GamePad { U32 connect_gen; // incremented on every connection change BitArrayDecl(U32, last_buttons, GamePadButtonKind_COUNT); BitArrayDecl(U32, buttons, GamePadButtonKind_COUNT); F32 left_trigger; F32 right_trigger; Vec2F32 sticks[2]; }; #define GAME_PAD_SLOT_COUNT 4 //////////////////////////////// //~ rjf: Program Tick Entry Point function B32 Run(U64 tick_idx, Arena *permanent_arena, GamePad game_pads[GAME_PAD_SLOT_COUNT]); #endif // BASE_H