You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

677 lines
17 KiB
C

// 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 <stdint.h>
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 <stdarg.h>
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