406 lines
14 KiB
C
406 lines
14 KiB
C
// -----------------------------------------------------------------------------
|
|
// config directives
|
|
|
|
#ifndef ENABLE_FASTCALL_LUA
|
|
#define ENABLE_FASTCALL_LUA 1 ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_PROFILER
|
|
#define ENABLE_PROFILER ifdef(debug, 1, 0) ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_SELFIES
|
|
#define ENABLE_SELFIES 0 ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_MEMORY_POISON
|
|
#define ENABLE_MEMORY_POISON ifdef(debug, 1, 0) ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_MEMORY_LEAKS
|
|
#define ENABLE_MEMORY_LEAKS 0 ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_LINUX_CALLSTACKS
|
|
#define ENABLE_LINUX_CALLSTACKS 0 ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_AUTOTESTS
|
|
#define ENABLE_AUTOTESTS ifdef(debug, ifndef(ems, 1, 0), 0) ///+
|
|
#endif
|
|
|
|
#ifndef ENABLE_RETAIL
|
|
#define ENABLE_RETAIL 0 // ifdef(retail, 1, 0) ///+
|
|
#endif
|
|
|
|
#ifndef COOK_DISABLED
|
|
#define COOK_DISABLED 0 // ifdef(nocook, 1, 0) ///+
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// if/n/def hell
|
|
|
|
#define ifdef(macro, yes, /*no*/...) ifdef_##macro(yes, __VA_ARGS__)
|
|
#define ifndef(macro, yes, /*no*/...) ifdef_##macro(__VA_ARGS__, yes)
|
|
#define is(macro) ifdef_##macro(1,0)
|
|
#define isnt(macro) ifdef_##macro(0,1)
|
|
#define ifdef_true(yes, /*no*/...) yes
|
|
#define ifdef_false(yes, /*no*/...) __VA_ARGS__
|
|
|
|
#ifdef _MSC_VER
|
|
#define ifdef_gcc ifdef_false
|
|
#define ifdef_mingw ifdef_false
|
|
#define ifdef_tcc ifdef_false
|
|
#define ifdef_cl ifdef_true
|
|
#elif defined __TINYC__
|
|
#define ifdef_gcc ifdef_false
|
|
#define ifdef_mingw ifdef_false
|
|
#define ifdef_tcc ifdef_true
|
|
#define ifdef_cl ifdef_false
|
|
#elif defined __MINGW64__ || defined __MINGW32__
|
|
#define ifdef_gcc ifdef_true
|
|
#define ifdef_mingw ifdef_true
|
|
#define ifdef_tcc ifdef_false
|
|
#define ifdef_cl ifdef_false
|
|
#else // also __clang__
|
|
#define ifdef_gcc ifdef_true
|
|
#define ifdef_mingw ifdef_false
|
|
#define ifdef_tcc ifdef_false
|
|
#define ifdef_cl ifdef_false
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
#define ifdef_cpp ifdef_true
|
|
#define ifdef_c ifdef_false
|
|
#else
|
|
#define ifdef_c ifdef_true
|
|
#define ifdef_cpp ifdef_false
|
|
#endif
|
|
|
|
#if defined _WIN32
|
|
#define ifdef_win32 ifdef_true
|
|
#define ifdef_linux ifdef_false
|
|
#define ifdef_osx ifdef_false
|
|
#define ifdef_bsd ifdef_false
|
|
#define ifdef_ems ifdef_false
|
|
#elif defined __linux__
|
|
#define ifdef_win32 ifdef_false
|
|
#define ifdef_linux ifdef_true
|
|
#define ifdef_osx ifdef_false
|
|
#define ifdef_bsd ifdef_false
|
|
#define ifdef_ems ifdef_false
|
|
#elif defined __APPLE__
|
|
#define ifdef_win32 ifdef_false
|
|
#define ifdef_linux ifdef_false
|
|
#define ifdef_osx ifdef_true
|
|
#define ifdef_bsd ifdef_false
|
|
#define ifdef_ems ifdef_false
|
|
#elif defined __EMSCRIPTEN__
|
|
#define ifdef_win32 ifdef_false
|
|
#define ifdef_linux ifdef_false
|
|
#define ifdef_osx ifdef_false
|
|
#define ifdef_bsd ifdef_false
|
|
#define ifdef_ems ifdef_true
|
|
#else // __FreeBSD__ || @todo: __ANDROID_API__
|
|
#define ifdef_win32 ifdef_false
|
|
#define ifdef_linux ifdef_false
|
|
#define ifdef_osx ifdef_false
|
|
#define ifdef_bsd ifdef_true
|
|
#define ifdef_ems ifdef_false
|
|
#endif
|
|
|
|
#ifdef NDEBUG // rely on NDEBUG as the official/portable way to disable asserts
|
|
#define ifdef_debug ifdef_false
|
|
#define ifdef_release ifdef_true
|
|
#else
|
|
#define ifdef_debug ifdef_true
|
|
#define ifdef_release ifdef_false
|
|
#endif
|
|
|
|
#if ENABLE_RETAIL
|
|
#define ifdef_retail ifdef_true
|
|
#else
|
|
#define ifdef_retail ifdef_false
|
|
#endif
|
|
|
|
#if COOK_DISABLED
|
|
#define ifdef_nocook ifdef_true
|
|
#else
|
|
#define ifdef_nocook ifdef_false
|
|
#endif
|
|
|
|
#if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3
|
|
#define ifdef_O3 ifdef_true
|
|
#define ifdef_O2 ifdef_false
|
|
#define ifdef_O1 ifdef_false
|
|
#define ifdef_O0 ifdef_false
|
|
#elif defined NDEBUG && NDEBUG >= 2
|
|
#define ifdef_O3 ifdef_false
|
|
#define ifdef_O2 ifdef_true
|
|
#define ifdef_O1 ifdef_false
|
|
#define ifdef_O0 ifdef_false
|
|
#elif defined NDEBUG && NDEBUG >= 1
|
|
#define ifdef_O3 ifdef_false
|
|
#define ifdef_O2 ifdef_false
|
|
#define ifdef_O1 ifdef_true
|
|
#define ifdef_O0 ifdef_false
|
|
#else
|
|
#define ifdef_O3 ifdef_false
|
|
#define ifdef_O2 ifdef_false
|
|
#define ifdef_O1 ifdef_false
|
|
#define ifdef_O0 ifdef_true
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
#if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
|
|
#define ifdef_64 ifdef_true
|
|
#define ifdef_32 ifdef_false
|
|
#else
|
|
#define ifdef_64 ifdef_false
|
|
#define ifdef_32 ifdef_true
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// new C keywords
|
|
|
|
#define countof(x) (int)(sizeof (x) / sizeof 0[x])
|
|
|
|
#define concat(a,b) conc4t(a,b)
|
|
#define conc4t(a,b) a##b ///-
|
|
|
|
#define macro(name) concat(name, __LINE__)
|
|
#define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1))
|
|
#define scope(end) defer((void)0, end)
|
|
#define benchmark for(double macro(i) = 1, macro(t) = -time_ss(); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 ))
|
|
#define do_once static int macro(once) = 0; for(;!macro(once);macro(once)=1)
|
|
|
|
#if is(cl)
|
|
#define __thread __declspec(thread)
|
|
#elif is(tcc) && is(win32)
|
|
#define __thread __declspec(thread) // compiles fine apparently, but does not work
|
|
#elif is(tcc)
|
|
#define __thread
|
|
#endif
|
|
|
|
// usage: bool static(audio_is_init) = audio_init();
|
|
//#define static(var) static var; do_once var
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// new C macros
|
|
|
|
#if ENABLE_RETAIL
|
|
#define ASSERT(expr, ...) (void)0
|
|
#define ASSERT_ONCE(expr, ...) (void)0
|
|
#else
|
|
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
|
|
#define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
|
|
#endif
|
|
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_)
|
|
|
|
#define FILELINE __FILE__ ":" STRINGIZE(__LINE__)
|
|
#define STRINGIZE(x) STRINGIZ3(x)
|
|
#define STRINGIZ3(x) #x ///-
|
|
|
|
#define EXPAND(name, ...) EXPAND_QUOTE(EXPAND_JOIN(name, EXPAND_COUNT_ARGS(__VA_ARGS__)), (__VA_ARGS__))
|
|
#define EXPAND_QUOTE(x, y) x y ///-
|
|
#define EXPAND_JOIN(name, count) EXPAND_J0IN(name, count) ///-
|
|
#define EXPAND_J0IN(name, count) EXPAND_J01N(name, count) ///-
|
|
#define EXPAND_J01N(name, count) name##count ///-
|
|
#define EXPAND_COUNT_ARGS(...) EXPAND_ARGS((__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) ///-
|
|
#define EXPAND_ARGS(args) EXPAND_RETURN_COUNT args ///-
|
|
#define EXPAND_RETURN_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, count, ...) count ///-
|
|
|
|
// expands to the first argument
|
|
#define VA_FIRST(...) VA_F1RST(__VA_ARGS__, throwaway)
|
|
#define VA_F1RST(first, ...) first ///-
|
|
// if there's only one argument, expands to nothing. if there is more
|
|
// than one argument, expands to a comma followed by everything but
|
|
// the first argument. only supports up to 9 arguments but can be expanded.
|
|
#define VA_REST(...) VA_R3ST(VA_NUM(__VA_ARGS__), __VA_ARGS__)
|
|
#define VA_R3ST(qty, ...) VA_R3S7(qty, __VA_ARGS__) ///-
|
|
#define VA_R3S7(qty, ...) VA_R3S7_##qty(__VA_ARGS__) ///-
|
|
#define VA_R3S7_ONE(first) ///-
|
|
#define VA_R3S7_TWOORMORE(first, ...) , __VA_ARGS__ ///-
|
|
#define VA_NUM(...) VA_SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) ///-
|
|
#define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10
|
|
// VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N]
|
|
#define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__)
|
|
|
|
#if is(cl) && !is(cpp)
|
|
#define INLINE __inline
|
|
#else
|
|
#define INLINE inline
|
|
#endif
|
|
|
|
#if is(cl)
|
|
#define FORCE_INLINE __forceinline
|
|
#elif is(gcc)
|
|
#define FORCE_INLINE __attribute__((always_inline)) inline
|
|
#else
|
|
#define FORCE_INLINE INLINE
|
|
#endif
|
|
|
|
#if is(cl) && (_MSC_VER <= 1700)
|
|
#define FINITE _finite
|
|
#else
|
|
#define FINITE isfinite
|
|
#endif
|
|
|
|
// usage: #define vec2(...) C_CAST(vec2, __VA_ARGS__)
|
|
// typedef union vec2 { float X,Y; }; vec2 a = {0,1}, b = vec2(0,1);
|
|
#define C_CAST(type, ...) ( ifdef(c,(type),type) { __VA_ARGS__ } )
|
|
|
|
// create a WARNING(...) macro
|
|
// usage: WARNING("this is displayed at compile time")
|
|
#if is(gcc)
|
|
# define WARNING(msg) WARN1NG( message( msg ) )
|
|
# define WARN1NG(msg) _Pragma(#msg)
|
|
#elif is(cl)
|
|
# define WARNING(msg) __pragma( message( msg ) )
|
|
#else
|
|
# define WARNING(msg)
|
|
#endif
|
|
|
|
// document todos and fixmes via compiler warnings
|
|
#define TODO(str) ifdef(debug,WARNING("TO DO: " str " (" FILELINE ")"))
|
|
#define FIXME(str) ifdef(debug,WARNING("FIXME: " str " (" FILELINE ")"))
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// autorun initializers for C
|
|
// - rlyeh, public domain
|
|
//
|
|
// note: based on code by Joe Lowe (public domain).
|
|
// note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers
|
|
|
|
#ifdef __cplusplus
|
|
#define AUTORUN_(fn) \
|
|
static void fn(void); \
|
|
static const int concat(fn,__1) = (fn(), 1); \
|
|
static void fn(void)
|
|
#elif defined _MSC_VER && !defined(__clang__) // cl, but not clang-cl
|
|
#define AUTORUN_(fn) \
|
|
static void fn(void); \
|
|
static int concat(fn,__1) (){ fn(); return 0; } \
|
|
__pragma(section(".CRT$XIU", long, read)) \
|
|
__declspec(allocate(".CRT$XIU")) \
|
|
static int(* concat(fn,__2) )() = concat(fn,__1); \
|
|
static void fn(void)
|
|
#else // gcc,tcc,clang,clang-cl...
|
|
#define AUTORUN_(fn) \
|
|
__attribute__((constructor)) \
|
|
static void fn(void)
|
|
#endif
|
|
|
|
#define AUTORUN AUTORUN_( concat(concat(concat(fn_L,__LINE__),_),__COUNTER__) )
|
|
|
|
#if 0 // autorun demo
|
|
void byebye(void) { puts("seen after main()"); }
|
|
AUTORUN { puts("seen before main()"); }
|
|
AUTORUN { puts("seen before main() too"); atexit( byebye ); }
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// build info
|
|
|
|
#ifndef BUILD_VERSION
|
|
#define BUILD_VERSION ""
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// visibility
|
|
|
|
// win32 users would need to -DAPI=IMPORT/EXPORT as needed when using/building V4K as DLL.
|
|
|
|
#define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport)))
|
|
#define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport)))
|
|
#define STATIC
|
|
|
|
#ifndef API
|
|
#define API STATIC
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// system headers
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE ///- for linux
|
|
#endif
|
|
|
|
#if is(cl) && is(win32) // for VC IDE
|
|
#define _CRT_SECURE_NO_WARNINGS ///-
|
|
#define _CRT_NONSTDC_NO_DEPRECATE ///-
|
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS ///-
|
|
#define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
|
|
#endif
|
|
|
|
#if is(cl)
|
|
#include <omp.h> // compile with /openmp to speed up some computations
|
|
#endif
|
|
#include <assert.h>
|
|
//#include <float.h>
|
|
//#include <limits.h>
|
|
#include <math.h> // NAN
|
|
#include <stdarg.h> // va_*(), ...
|
|
#include <stdbool.h> // bool,true,false
|
|
#include <stdint.h> // u/int8/16/32/64_t
|
|
#include <stdio.h> // FILE,NULL
|
|
#include <stdlib.h> // malloc,free,exit,
|
|
#include <string.h> // strlen,memset,memcpy,
|
|
|
|
#if is(tcc) && is(win32) && defined(__x86_64)
|
|
#include <tgmath.h>
|
|
|
|
// @fixme workarounds on `tcc0.9.27 -m64` (win) for fmod()/trunc() functions. test: 00-easing broken otherwise
|
|
//#define trunc(x) ((double)(int64_t)(x))
|
|
//#define fmod(x,y) ((x) - trunc((x) / (y)) * (y))
|
|
|
|
// @fixme workarounds on `tcc0.9.27 -m64` (win) for all functions with ending bool argument. test: 00-anims crashes otherwise
|
|
#undef bool
|
|
typedef char bool;
|
|
|
|
// missing libm symbols on tinycc HEAD repo (tcc-x64 pre-0.9.28)
|
|
//#define fabsf fabs
|
|
#define sqrtf sqrt
|
|
#define sinf sin
|
|
#define asinf asin
|
|
#define cosf cos
|
|
#define acosf acos
|
|
#define tanf tan
|
|
#define atan2f atan2
|
|
#define powf pow
|
|
#define floorf floor
|
|
#define logf log
|
|
#define ceilf ceil
|
|
#define copysignf copysign
|
|
//#define ldexpf ldexp
|
|
#define expf exp
|
|
//#define frexpf frexp
|
|
#define fmodf fmod
|
|
#define log10f log10
|
|
//#define logf log
|
|
#define hypotf hypot
|
|
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// pragma libs
|
|
|
|
#if is(win32) && (is(cl) || is(tcc))
|
|
#pragma comment(lib, "advapi32")
|
|
#pragma comment(lib, "comdlg32")
|
|
#pragma comment(lib, "dbghelp")
|
|
#pragma comment(lib, "gdi32")
|
|
#pragma comment(lib, "ole32")
|
|
#pragma comment(lib, "shell32")
|
|
#pragma comment(lib, "user32")
|
|
#pragma comment(lib, "winmm")
|
|
#pragma comment(lib, "wininet")
|
|
#pragma comment(lib, "ws2_32")
|
|
#endif
|
|
|
|
#if is(linux) && is(tcc)
|
|
#pragma comment(lib, "dl")
|
|
#pragma comment(lib, "m")
|
|
#pragma comment(lib, "pthread")
|
|
#endif
|