/* game framework. * - rlyeh, public domain * * ## V4K License * * This software is available under 3 licenses. Choose whichever you prefer. * ------------------------------------------------------------------------------ * ALTERNATIVE A - Public Domain (https://unlicense.org/) * ------------------------------------------------------------------------------ * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this * software, either in source code form or as a compiled binary, for any purpose, * commercial or non-commercial, and by any means. * * In jurisdictions that recognize copyright laws, the author or authors of this * software dedicate any and all copyright interest in the software to the public * domain. We make this dedication for the benefit of the public at large and to * the detriment of our heirs and successors. We intend this dedication to be an * overt act of relinquishment in perpetuity of all present and future rights to * this software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ * ALTERNATIVE B - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ * ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) * ------------------------------------------------------------------------------ * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * * Dear Contributor, * * In order to ensure this project remains completely free and unencumbered by * anyone's copyright monopoly, it is advisable that you dedicate your code-base * contributions to the three licensing terms above. This removes any possible * ambiguity as to what terms somebody might have thought they were contributing * under, in case of a future dispute. These concerns are not unique to public * domain software. Most large, established open-source projects have a * Contributor License Agreement (CLA) process, of varying degrees of formality. * * Please add yourself to the list below before contributing. * Thanks. * * -- * * "I dedicate any and all copyright interest in this software to the three * license terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." * * Author (name) I agree (YES/NO) Files/Features (optional) * ------------------------------------------------------------------------------ * @r-lyeh YES Initial codebase * @zak@v4.games YES N/A * ------------------------------------------------------------------------------ */ #ifndef V4K_H #define V4K_H #ifdef __cplusplus extern "C" { #endif //----------------------------------------------------------------------------- // Headers #line 1 "engine/split/v4k_config.h" // ----------------------------------------------------------------------------- // 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 // NDEBUG>=2 ? #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 #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 unique(name) concat(concat(concat(name,concat(_L,__LINE__)),_),__COUNTER__) #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(),-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 benchmark_ms for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.2fms %2.f%% (" FILELINE ")\n", macro(t)*1000, macro(t)*100/0.016666667 )) #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]++; alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0) #define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0) #endif #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L) #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 #define AUTORUN AUTORUN_( unique(fn) ) #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) #elif defined __TINYC__ // tcc... #define AUTORUN_(fn) \ __attribute__((constructor)) \ static void fn(void) #else // gcc,clang,clang-cl... #define AUTORUN_(fn) \ __attribute__((constructor(__COUNTER__+101))) \ static void fn(void) #endif #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=EXPORT/IMPORT as needed when building/using 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 // compile with /openmp to speed up some computations #endif #include //#include //#include #include // NAN #include // va_*(), ... #include // bool,true,false #include // u/int8/16/32/64_t #include // FILE,NULL #include // malloc,free,exit, #include // strlen,memset,memcpy, #if is(tcc) && is(win32) && defined(__x86_64) #include // @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 #line 0 #line 1 "engine/split/v4k_ds.h" // data structures and utils: array, set, map, hash, sort. // - rlyeh, public domain // ----------------------------------------------------------------------------- // sort API int sort_64(const void *a, const void *b); // ----------------------------------------------------------------------------- // less API int less_64(uint64_t a, uint64_t b); API int less_int(int a, int b); API int less_ptr(void *a, void *b); API int less_str(char *a, char *b); // ----------------------------------------------------------------------------- // un/hash API uint32_t unhash_32(uint32_t x); API uint32_t hash_32(uint32_t x); API uint64_t hash_64(uint64_t x); API uint64_t hash_flt(double x); API uint64_t hash_int(int key); API uint64_t hash_ptr(const void* ptr); API uint64_t hash_bin(const void* ptr, unsigned len); API uint64_t hash_str(const char* str); // ----------------------------------------------------------------------------- // bits API uint64_t popcnt64(uint64_t x); // ----------------------------------------------------------------------------- // vector based allocator (x1.75 enlarge factor) API void* vrealloc( void* p, size_t sz ); API size_t vlen( void* p ); // ----------------------------------------------------------------------------- // arrays #if is(cpp) #define array_cast(x) (decltype x) #else #define array_cast(x) (void *) #endif #define array(t) t* #define array_init(t) ( (t) = 0 ) #define array_resize(t, n) ( array_c_ = array_count(t), array_n_ = (n), array_realloc_((t),array_n_), (array_n_>array_c_? memset(array_c_+(t),0,(array_n_-array_c_)*sizeof(0[t])) : (void*)0), (t) ) #define array_push(t, ...) ( array_realloc_((t),array_count(t)+1), (t)[ array_count(t) - 1 ] = (__VA_ARGS__) ) #define array_pop(t) ( array_realloc_((t), array_count(t)-1) ) #define array_back(t) ( &(t)[ array_count(t)-1 ] ) // ( (t) ? &(t)[ array_count(t)-1 ] : NULL ) #define array_data(t) (t) #define array_at(t,i) (t[i]) #define array_count(t) (int)( (t) ? array_vlen_(t) / sizeof(0[t]) : 0u ) #define array_bytes(t) (int)( (t) ? array_vlen_(t) : 0u ) #define array_sort(t, cmpfunc) qsort( t, array_count(t), sizeof(0[t]), (uintptr_t)cmpfunc == (uintptr_t)strcmp ? (void*)strcmp_qsort : (void*)cmpfunc ) #define array_empty(t) ( !array_count(t) ) #define array_push_front(arr,x) \ (array_resize((arr), array_count(arr)+1), memmove((arr)+1, (arr), sizeof(0[arr])*array_count(arr)), 0[arr] = (x)) #define array_pop_front(arr) ( \ (array_count(arr) > 1 ? memmove((arr), (arr)+1, sizeof(0[arr])*(array_count(arr)-1)) : (void*)0), \ (array_count(arr) > 0 ? array_resize(arr, array_count(arr) - 1 ) : array_resize( arr, 0 ) ) ) static __thread unsigned array_c_; static __thread unsigned array_n_; #if 0 // original: no reserve support #define array_reserve(t, n) ((void)0) // not implemented #define array_clear(t) ( array_realloc_((t), 0), (t) = 0 ) #define array_vlen_(t) ( vlen(t) - 0 ) #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) ) #define array_free(t) array_clear(t) #else // new: with reserve support (@todo: check for bugs?) #define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) ) #define array_clear(t) ( array_realloc_((t),0) ) // -1 #define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1 #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+1) * sizeof(0[t])) ) // +1 #define array_free(t) ( array_realloc_((t), -1), (t) = 0 ) // -1 #endif #define array_reverse(t) \ do if( array_count(t) ) { \ for(int l = array_count(t), e = l-1, i = (array_push(t, 0[t]), 0); i <= e/2; ++i ) \ { l[t] = i[t]; i[t] = (e-i)[t]; (e-i)[t] = l[t]; } \ array_pop(t); \ } while(0) #define array_foreach(t,val_t,v) for each_array(t,val_t,v) #define each_array(a,val_t,v) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \ for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \ for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 ) #define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v) #define each_array_ptr(a,val_t,v) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \ for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \ for( val_t *v = (val_t*)&i_[a_]; v; v = 0 ) #define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \ bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn ) #define array_insert(t, i, n) do { \ int ac = array_count(t); \ if( i >= ac ) { \ array_push(t, n); \ } else { \ array_push(t, array_back(t)); \ memmove( &(t)[(i)+1], &(t)[i], (ac - (i)) * sizeof(t[0]) ); \ (t)[ i ] = (n); \ } \ } while(0) #define array_copy(t, src) do { \ array_free(t); \ (t) = array_realloc_( (t), array_count(src)); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \ } while(0) #define array_erase_fast(t, i) do { /*alters ordering*/ \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ array_pop(t); \ } while(0) #define array_erase(t, i) do { \ memmove( &(t)[i], &(t)[i + 1], sizeof(0[t])*(array_count(t) - i - 1)); \ array_pop(t); \ } while(0) #define array_unique(t, cmpfunc) do { /*@todo: optimize me. requires array_sort() beforehand*/ \ int cnt = array_count(t), cnt_bak = cnt; \ if( cnt > 1 ) { \ for( int i = 1; i < cnt; ++i ) { \ while( i < cnt && !cmpfunc(&(t)[i-1], &(t)[i]) ) { \ memmove(&(t)[i-1], &(t)[i], (cnt - 1 - i) * sizeof((t)[0]) ) ; \ --cnt; \ } \ } \ if( cnt_bak != cnt ) array_resize((t), cnt); \ } \ } while(0) #if 0 // snippet below does work #define array_unique(t, cmpfunc) \ array_sort(t, cmpfunc); \ for( int i = 0, end = array_count(t) - 1; i < end; ) { \ if( !strcmp(t[i], t[i+1]) ) { \ /* array_erase(t, i+1); */ \ memmove(&(t)[i+1], &(t)[i+2], (end - 1 - i) * sizeof((t)[0]) ); \ array_pop(t); \ --end; \ } else { \ ++i; \ } \ } #endif #define array_shuffle(t) do { /* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle */ \ void* tmp = stack(sizeof(0[t])); \ for( int i = 0, n = array_count(t); i < n; ++i ) { \ int j = randi(i, n); /* j random integer such that [i,n) i<=j // ideas from: https://en.wikipedia.org/wiki/Hash_table // ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/ // ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/ // config #ifndef SET_HASHSIZE #define SET_HASHSIZE (4096 << 4) #endif #ifndef SET_DONT_ERASE #define SET_DONT_ERASE 1 #endif // public api #define set(K) \ struct { set base; struct { set_item p; K key; } tmp, *ptr; K *tmpval; \ int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } * #define set_init(m, cmpfn, hashfn) ( \ (m) = set_cast(m) REALLOC(0, sizeof(*m)), \ set_init(&(m)->base), \ (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = set_cast(cmpfn) cmpfn ), \ (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = set_cast(hashfn) hashfn ) \ ) #define set_free(m) ( \ set_clear(m), \ set_free(&(m)->base), \ (m) = set_cast(m) REALLOC((m), 0), \ (m) = 0 \ ) #define set_insert(m, k) ( \ (m)->ptr = set_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ set_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, (m)->ptr->p.keyhash, (m)->ptr), \ &(m)->ptr->key \ ) #define set_find(m, k) ( \ (m)->ptr = &(m)->tmp, \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr = set_cast((m)->ptr) set_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \ (m)->ptr ? &(m)->ptr->key : 0 \ ) #define set_find_or_add(m, k) ( \ (m)->tmp.key = (k), \ (m)->tmpval = set_find((m), ((m)->tmp.key)), \ (m)->tmpval = (m)->tmpval ? (m)->tmpval : set_insert((m), ((m)->tmp.key)) \ ) #define set_find_or_add_allocated_key(m, k) ( \ (m)->tmp.key = (k), \ (m)->tmpval = set_find((m), ((m)->tmp.key)), \ (m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : set_insert((m), ((m)->tmp.key)) \ ) #define set_erase(m, k) ( \ (m)->ptr = &(m)->tmp, \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ set_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \ ) #define set_foreach for each_set #define each_set(m,key_t,k) \ ( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \ for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( key_t k = *(key_t *)cur_->key; on_; on_ = 0 ) #define set_foreach_ptr for each_set_ptr #define each_set_ptr(m,key_t,k) \ ( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \ for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( key_t *k = (key_t *)cur_->key; on_; on_ = 0 ) #define set_clear(m) ( \ set_clear(&(m)->base) \ ) #define set_isempty(m) set_isempty(&(m)->base) #define set_count(m) set_count(&(m)->base) #define set_gc(m) set_gc(&(m)->base) #ifndef set_init_int #define set_init_int(m) set_init((m), less_int, hash_64) // hash_int) #define set_init_str(m) set_init((m), less_str, hash_str) #define set_init_ptr(m) set_init((m), less_ptr, hash_ptr) #endif // private: #if is(cpp) #define set_cast(t) (decltype(t)) #else #define set_cast(t) (void *) #endif typedef struct set_item { struct set_item *next; uint64_t keyhash; void *key; void *super; } set_item; typedef struct set { array(set_item*) array; int (*cmp)(void *, void *); uint64_t (*hash)(void *); int count; } set; API void (set_init)(set *m); API void (set_free)(set *m); API void (set_insert)(set *m, set_item *p, void *key, uint64_t keyhash, void *super); API void (set_erase)(set *m, void *key, uint64_t keyhash); API void* (set_find)(const set *m, void *key, uint64_t keyhash); API int (set_isempty)(const set *m); API int (set_count)(const set *m); API void (set_gc)(set *m); // only if using SET_DONT_ERASE API void (set_clear)(set* m); // ----------------------------------------------------------------------------- // map // ideas from: https://en.wikipedia.org/wiki/Hash_table // ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/ // ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/ // config #ifndef MAP_HASHSIZE #define MAP_HASHSIZE (4096 << 4) #endif #ifndef MAP_DONT_ERASE #define MAP_DONT_ERASE 1 #endif // public api #define map(K,V) \ struct { map base; struct { pair p; K key; V val; } tmp, *ptr; V* tmpval; \ int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } * #define map_init(m, cmpfn, hashfn) ( \ (m) = map_cast(m) REALLOC(0, sizeof(*(m))), \ map_init(&(m)->base), \ (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = map_cast((m)->typed_cmp) cmpfn), \ (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = map_cast((m)->typed_hash) hashfn ) \ ) #define map_free(m) ( \ map_free(&(m)->base), \ map_cast(m) REALLOC((m), sizeof(*(m))), (m) = 0 \ ) #define map_insert(m, k, v) ( \ (m)->ptr = map_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \ (m)->ptr->val = (v), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ map_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, &(m)->ptr->val, (m)->ptr->p.keyhash, (m)->ptr), \ &(m)->ptr->val \ ) #define map_find(m, k) ( \ (m)->ptr = &(m)->tmp, \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr = map_cast((m)->ptr) map_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \ (m)->ptr ? &(m)->ptr->val : 0 \ ) #define map_find_or_add(m, k, v) ( \ (m)->tmp.key = (k), (m)->tmp.val = (v), \ (m)->tmpval = map_find((m), ((m)->tmp.key)), \ (m)->tmpval = (m)->tmpval ? (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \ ) #define map_find_or_add_allocated_key(m, k, v) ( \ (m)->tmp.key = (k), (m)->tmp.val = (v), \ (m)->tmpval = map_find((m), ((m)->tmp.key)), \ (m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \ ) #define map_erase(m, k) ( \ (m)->ptr = &(m)->tmp, \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ map_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \ ) #define map_foreach for each_map #define each_map(m,key_t,k,val_t,v) \ ( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \ for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( key_t k = *(key_t *)cur_->key; on_; ) \ for( val_t v = *(val_t *)cur_->value; on_; on_ = 0 ) #define map_foreach_ptr for each_map_ptr #define each_map_ptr(m,key_t,k,val_t,v) \ ( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \ for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( key_t *k = (key_t *)cur_->key; on_; ) \ for( val_t *v = (val_t *)cur_->value; on_; on_ = 0 ) #define map_foreach_ptr_sorted for each_map_ptr_sorted #define each_map_ptr_sorted(m,key_t,k,val_t,v) \ ( int i_ = (map_sort(&(m)->base), 0); i_ < array_count((m)->base.sorted); ++i_) \ for( pair *cur_ = (m)->base.sorted[i_]; cur_; ) \ for( key_t *k = (key_t *)cur_->key; cur_; ) \ for( val_t *v = (val_t *)cur_->value; cur_; cur_ = 0 ) #define map_clear(m) ( \ map_clear(&(m)->base) \ ) #define map_isempty(m) map_isempty(&(m)->base) #define map_count(m) map_count(&(m)->base) #define map_gc(m) map_gc(&(m)->base) // aliases: #ifndef map_init_int #define map_init_int(m) map_init((m), less_int, hash_64) // hash_int #define map_init_str(m) map_init((m), less_str, hash_str) #define map_init_ptr(m) map_init((m), less_ptr, hash_ptr) #endif // private: #if is(cpp) #define map_cast(t) (decltype(t)) #else #define map_cast(t) (void *) #endif typedef struct pair { struct pair *next; uint64_t keyhash; void *key; void *value; void *super; } pair; typedef struct map { array(pair*) array; int (*cmp)(void *, void *); uint64_t (*hash)(void *); int count:31; int is_sorted:1; array(pair*) sorted; } map; API void (map_init)(map *m); API void (map_free)(map *m); API void (map_insert)(map *m, pair *p, void *key, void *value, uint64_t keyhash, void *super); API void (map_erase)(map *m, void *key, uint64_t keyhash); API void* (map_find)(map *m, void *key, uint64_t keyhash); API int (map_isempty)(map *m); API int (map_count)(map *m); API void (map_gc)(map *m); // only if using MAP_DONT_ERASE API bool (map_sort)(map* m); API void (map_clear)(map* m); #line 0 #line 1 "engine/split/v4k_math.h" // ----------------------------------------------------------------------------- // math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4 // - rlyeh, public domain // // Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense). #define C_EPSILON (1e-6) #define C_PI (3.14159265358979323846f) // (3.141592654f) #define TO_RAD (C_PI/180) #define TO_DEG (180/C_PI) // ---------------------------------------------------------------------------- //#define ptr(type) 0[&(type).x] #define vec2i(x, y ) C_CAST(vec2i,(int)(x), (int)(y) ) #define vec3i(x, y, z ) C_CAST(vec3i,(int)(x), (int)(y), (int)(z) ) #define vec2(x, y ) C_CAST(vec2, (float)(x), (float)(y) ) #define vec3(x, y, z ) C_CAST(vec3, (float)(x), (float)(y), (float)(z), ) #define vec4(x, y, z, w) C_CAST(vec4, (float)(x), (float)(y), (float)(z), (float)(w)) #define quat(x, y, z, w) C_CAST(quat, (float)(x), (float)(y), (float)(z), (float)(w)) #define axis(x, y, z) C_CAST(axis, (float)(x), (float)(y), (float)(z)) #define mat33(...) C_CAST(mat33, __VA_ARGS__ ) #define mat34(...) C_CAST(mat34, __VA_ARGS__ ) #define mat44(...) C_CAST(mat44, __VA_ARGS__ ) typedef union vec2i{ struct { int X,Y; }; struct { int x,y; }; struct { int r,g; }; struct { int w,h; }; struct { int min,max; }; struct { int from,to; }; struct { int src,dst; }; int v2[2]; int array[1]; } vec2i; typedef union vec3i{ struct { int X,Y,Z; }; struct { int x,y,z; }; struct { int r,g,b; }; struct { int w,h,d; }; struct { int min,max; }; struct { int from,to,step; }; struct { int src,dst; }; int v3[3]; int array[1]; } vec3i; typedef union vec2 { struct { float X,Y; }; struct { float x,y; }; struct { float r,g; }; struct { float w,h; }; struct { float min,max; }; struct { float from,to; }; struct { float src,dst; }; float v2[2]; float array[1]; } vec2; typedef union vec3 { struct { float X,Y,Z; }; struct { float x,y,z; }; struct { float r,g,b; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec2 rg; vec2 wh; float v3[3]; float array[1]; } vec3; typedef union vec4 { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; struct { float r,g,b,a; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec3 xyz; vec2 rg; vec3 rgb; vec2 wh; vec3 whd; float v4[4]; float array[1]; } vec4; typedef union quat { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; vec3 xyz; vec4 xyzw; float v4[4]; float array[1]; } quat; typedef float mat33[9]; typedef float mat34[12]; typedef float mat44[16]; // ---------------------------------------------------------------------------- API void randset(uint64_t state); API uint64_t rand64(void); API double randf(void); // [0, 1) interval API int randi(int mini, int maxi); // [mini, maxi) interval // ---------------------------------------------------------------------------- API float simplex1( float x ); API float simplex2( vec2 xy ); API float simplex3( vec3 xyz ); API float simplex4( vec4 xyzw ); // ---------------------------------------------------------------------------- API float ease_linear(float t); API float ease_out_sine(float t); API float ease_out_quad(float t); API float ease_out_cubic(float t); API float ease_out_quart(float t); API float ease_out_quint(float t); API float ease_out_expo(float t); API float ease_out_circ(float t); API float ease_out_back(float t); API float ease_out_elastic(float t); API float ease_out_bounce(float t); API float ease_in_sine(float t); API float ease_in_quad(float t); API float ease_in_cubic(float t); API float ease_in_quart(float t); API float ease_in_quint(float t); API float ease_in_expo(float t); API float ease_in_circ(float t); API float ease_in_back(float t); API float ease_in_elastic(float t); API float ease_in_bounce(float t); API float ease_inout_sine(float t); API float ease_inout_quad(float t); API float ease_inout_cubic(float t); API float ease_inout_quart(float t); API float ease_inout_quint(float t); API float ease_inout_expo(float t); API float ease_inout_circ(float t); API float ease_inout_back(float t); API float ease_inout_elastic(float t); API float ease_inout_bounce(float t); API float ease_inout_perlin(float t); enum EASE_FLAGS { EASE_LINEAR, EASE_SINE, EASE_QUAD, EASE_CUBIC, EASE_QUART, EASE_QUINT, EASE_EXPO, EASE_CIRC, EASE_BACK, EASE_ELASTIC, EASE_BOUNCE, EASE_IN, EASE_INOUT = EASE_IN * 2, EASE_OUT = 0, }; API float ease(float t01, unsigned fn); // / 0-to-1 API float ease_pong(float t01, unsigned fn); // \ 1-to-0 API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0 API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1 // ---------------------------------------------------------------------------- API float deg (float radians); API float rad (float degrees); API int mini (int a, int b); API int maxi (int a, int b); API int absi (int a ); API int clampi (int v,int a,int b); API float minf (float a, float b); API float maxf (float a, float b); API float absf (float a ); API float pmodf (float a, float b); API float signf (float a) ; API float clampf (float v,float a,float b); API float mixf (float a,float b,float t); API float fractf (float a); // ---------------------------------------------------------------------------- API vec2 ptr2 (const float *a ); // API vec2 neg2 (vec2 a ); API vec2 add2 (vec2 a, vec2 b); API vec2 sub2 (vec2 a, vec2 b); API vec2 mul2 (vec2 a, vec2 b); API vec2 div2 (vec2 a, vec2 b); API vec2 inc2 (vec2 a, float b); API vec2 dec2 (vec2 a, float b); API vec2 scale2 (vec2 a, float b); API vec2 pmod2 (vec2 a, float b); API vec2 min2 (vec2 a, vec2 b); API vec2 max2 (vec2 a, vec2 b); API vec2 abs2 (vec2 a ); API vec2 floor2 (vec2 a ); API vec2 fract2 (vec2 a ); API vec2 ceil2 (vec2 a ); API float dot2 (vec2 a, vec2 b); API vec2 refl2 (vec2 a, vec2 b); API float cross2 (vec2 a, vec2 b); API float len2sq (vec2 a ); API float len2 (vec2 a ); API vec2 norm2 (vec2 a ); API int finite2 (vec2 a ); API vec2 mix2 (vec2 a,vec2 b,float t); API vec2 clamp2(vec2 v,vec2 a,vec2 b); API vec2 clamp2f(vec2 v,float a,float b); // ---------------------------------------------------------------------------- API vec3 rnd3 (void); // @todo: rnd2,rnd4,rndq API vec3 ptr3 (const float *a ); API vec3 vec23 (vec2 a, float z ); // API vec3 neg3 (vec3 a ); API vec3 add3 (vec3 a, vec3 b); API vec3 sub3 (vec3 a, vec3 b); API vec3 mul3 (vec3 a, vec3 b); API vec3 div3 (vec3 a, vec3 b); API vec3 inc3 (vec3 a, float b); API vec3 dec3 (vec3 a, float b); API vec3 scale3 (vec3 a, float b); API vec3 pmod3 (vec3 a, float b); API vec3 min3 (vec3 a, vec3 b); API vec3 max3 (vec3 a, vec3 b); API vec3 abs3 (vec3 a ); API vec3 floor3 (vec3 a ); API vec3 fract3 (vec3 a ); API vec3 ceil3 (vec3 a ); API vec3 cross3 (vec3 a, vec3 b); API float dot3 (vec3 a, vec3 b); API vec3 refl3 (vec3 a, vec3 b); API float len3sq (vec3 a ); API float len3 (vec3 a ); API vec3 norm3 (vec3 a ); API vec3 norm3sq (vec3 a ); API int finite3 (vec3 a ); API vec3 mix3 (vec3 a,vec3 b,float t); API vec3 clamp3(vec3 v,vec3 a,vec3 b); API vec3 clamp3f(vec3 v,float a,float b); //vec3 tricross3 (vec3 a, vec3 b, vec3 c); API void ortho3 (vec3 *left, vec3 *up, vec3 v); API vec3 rotatex3 (vec3 dir, float degrees); API vec3 rotatey3 (vec3 dir, float degrees); API vec3 rotatez3 (vec3 dir, float degrees); // ---------------------------------------------------------------------------- API vec4 ptr4 (const float *a ); API vec4 vec34 (vec3 a, float w ); // API vec4 neg4 (vec4 a ); API vec4 add4 (vec4 a, vec4 b); API vec4 sub4 (vec4 a, vec4 b); API vec4 mul4 (vec4 a, vec4 b); API vec4 div4 (vec4 a, vec4 b); API vec4 inc4 (vec4 a, float b); API vec4 dec4 (vec4 a, float b); API vec4 scale4 (vec4 a, float b); API vec4 pmod4 (vec4 a, float b); API vec4 min4 (vec4 a, vec4 b); API vec4 max4 (vec4 a, vec4 b); API vec4 abs4 (vec4 a ); API vec4 floor4 (vec4 a ); API vec4 fract4 (vec4 a ); API vec4 ceil4 (vec4 a ); API float dot4 (vec4 a, vec4 b); API vec4 refl4 (vec4 a, vec4 b); API float len4sq (vec4 a ); API float len4 (vec4 a ); API vec4 norm4 (vec4 a ); API vec4 norm4sq (vec4 a ); API int finite4 (vec4 a ); API vec4 mix4 (vec4 a,vec4 b,float t); API vec4 clamp4(vec4 v,vec4 a,vec4 b); API vec4 clamp4f(vec4 v,float a,float b); // vec4 cross4(vec4 v0, vec4 v1); // ---------------------------------------------------------------------------- API quat idq ( ); API quat ptrq (const float *a ); API quat vec3q (vec3 a, float w ); API quat vec4q (vec4 a ); // API quat negq (quat a ); API quat conjq (quat a ); API quat addq (quat a, quat b); API quat subq (quat a, quat b); API quat mulq (quat p, quat q); API quat scaleq (quat a, float s); API quat normq (quat a ); API float dotq (quat a, quat b); API quat mixq(quat a, quat b, float t); /* quat lerpq(quat a, quat b, float s); return norm(quat((1-s)*a.x + s*b.x, (1-s)*a.y + s*b.y, (1-s)*a.z + s*b.z, (1-s)*a.w + s*b.w)); }*/ API quat slerpq(quat a, quat b, float s); API quat rotationq(float deg,float x,float y,float z); API quat mat44q (mat44 M); API vec3 rotate3q_2(vec3 v, quat q); API vec3 rotate3q(vec3 v, quat r); // euler <-> quat API vec3 euler (quat q); API quat eulerq (vec3 pyr_degrees); // ---------------------------------------------------------------------------- API void scaling33(mat33 m, float x, float y, float z); API void scale33(mat33 m, float x, float y, float z); API void id33(mat33 m); API void extract33(mat33 m, const mat44 m4); API void copy33(mat33 m, const mat33 a);// API vec3 mulv33(mat33 m, vec3 v); API void multiply33x2(mat33 m, const mat33 a, const mat33 b); API void rotation33(mat33 m, float degrees, float x,float y,float z); API void rotationq33(mat33 m, quat q); API void rotate33(mat33 r, float degrees, float x,float y,float z); API void compose33(mat33 m, quat r, vec3 s); // ---------------------------------------------------------------------------- API void id34(mat34 m); API void copy34(mat34 m, const mat34 a); API void scale34(mat34 m, float s); API void add34(mat34 m, mat34 n); API void muladd34(mat34 m, mat34 n, float s); API void add34x2(mat34 m, mat34 n, mat34 o); API void lerp34(mat34 m, mat34 n, mat34 o, float alpha); // mix34? API void multiply34x2(mat34 m, const mat34 m0, const mat34 m1); API void multiply34(mat34 m, const mat34 a); API void multiply34x3(mat34 m, const mat34 a, const mat34 b, const mat34 c); API void compose34(mat34 m, vec3 t, quat q, vec3 s); API void invert34(mat34 m, const mat34 o); // ---------------------------------------------------------------------------- API void id44(mat44 m); API void identity44(mat44 m); API void copy44(mat44 m, const mat44 a); API void multiply44x2(mat44 m, const mat44 a, const mat44 b); API void multiply44x3(mat44 m, const mat44 a, const mat44 b, const mat44 c); API void multiply44(mat44 m, const mat44 a); // --- API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f); API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); // --- API void translation44(mat44 m, float x, float y, float z); API void translate44(mat44 m, float x, float y, float z); API void relocate44(mat44 m, float x, float y, float z); API void rotationq44(mat44 m, quat q); API void rotation44(mat44 m, float degrees, float x, float y, float z); API void rotate44(mat44 m, float degrees, float x, float y, float z); API void scaling44(mat44 m, float x, float y, float z); API void scale44(mat44 m, float x, float y, float z); // --- API void transpose44(mat44 m, const mat44 a); API float det44(const mat44 M); API bool invert44(mat44 T, const mat44 M); API void compose44(mat44 m, vec3 t, quat q, vec3 s); // ---------------------------------------------------------------------------- API vec3 transformq(const quat q, const vec3 v); API vec3 transform33(const mat33 m, vec3 p); API vec3 transform344(const mat44 m, const vec3 p); API vec4 transform444(const mat44 m, const vec4 p); API bool unproject44(vec3 *out, vec3 xyd, vec4 viewport, mat44 mvp); // ---------------------------------------------------------------------------- // debugging and utils API void print2i( vec2i v ); API void print3i( vec3i v ); API void print2( vec2 v ); API void print3( vec3 v ); API void print4( vec4 v ); API void printq( quat q ); API void print33( float *m ); API void print34( float *m ); API void print44( float *m ); #line 0 #line 1 "engine/split/v4k_ai.h" typedef enum SWARM_DISTANCE { SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_INVERSE_LINEAR, SWARM_DISTANCE_QUADRATIC, SWARM_DISTANCE_INVERSE_QUADRATIC } SWARM_DISTANCE; #define boid(...) C_CAST(boid_t, __VA_ARGS__) typedef struct boid_t { vec3 position; vec3 velocity; vec3 acceleration; vec3 prev_position; } boid_t; typedef struct swarm_t { array(boid_t) boids; float perception_radius; // determines the vision radius of each boid. Only boids within this distance influence each other. float separation_weight; // how much boids repel each other SWARM_DISTANCE separation_type; float alignment_weight; // how much boids want go in the same direction float cohesion_weight; // how much boids want to be in the center of the swarm float steering_weight; array(vec3) steering_targets; SWARM_DISTANCE steering_target_type; float blindspot_angledeg; float max_acceleration; // how fast each boid can change its direction float max_velocity; // how fast each boid can move // private: map(vec3*, array(boid_t*)) voxel_cache_; float blindspot_angledeg_compare_value_; } swarm_t; API swarm_t swarm(); API void swarm_update(swarm_t *self, float delta); // acc,vel,pos API void swarm_update_acceleration_only(swarm_t *self); // acc API void swarm_update_acceleration_and_velocity_only(swarm_t *self, float delta); // acc,vel API int ui_swarm(swarm_t *self); // pathfinding ----------------------------------------------------------------- API int pathfind_astar(int width, int height, const unsigned* map, vec2i src, vec2i dst, vec2i* path, size_t maxpath); #line 0 #line 1 "engine/split/v4k_bt.h" // Behavior trees: decision planning and decision making. // Supersedes finite state-machines (FSM) and hierarchical finite state-machines (HFSM). // - rlyeh, public domain. typedef int (*bt_func)(); typedef struct bt_t { uint64_t type; int (*action)(); union { int argi; float argf; }; array(struct bt_t) children; } bt_t; API bt_t bt(const char *ini_file, unsigned flags); API int bt_run(bt_t *b); API void bt_addfun(const char *name, int(*func)()); API bt_func bt_findfun(const char *name); API char *bt_funcname(bt_func fn); API int ui_bt(bt_t *b); #line 0 #line 1 "engine/split/v4k_audio.h" // ----------------------------------------------------------------------------- // audio framework // - rlyeh, public domain // // fixme: leaks, audio_delete // @todo: audio_volume_fx, audio_volume_bgm, audio_volume_master instead? // @todo: destroystream() if( ss->type == WAV ) drwav_uninit(&ss->wav); // @todo: destroystream() if( ss->type == MOD ) jar_mod_unload(&ss->mod); // @todo: destroystream() if( ss->type == XM && ss->xm ) jar_xm_free_context(ss->xm); // midi interface API void midi_send(unsigned midi_msg); // audio interface typedef struct audio_handle* audio_t; API audio_t audio_clip( const char *pathfile ); API audio_t audio_stream( const char *pathfile ); API int audio_play( audio_t s, int flags ); API int audio_play_gain( audio_t a, int flags, float gain/*0*/ ); API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch/*1*/ ); API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ ); API int audio_stop( audio_t a ); API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case API int audio_mute(int mute); API int audio_muted(); API int ui_audio(); enum AUDIO_FLAGS { AUDIO_1CH = 0, // default AUDIO_2CH = 1, AUDIO_8 = 2, AUDIO_16 = 0, // default AUDIO_32 = 4, AUDIO_FLOAT = 8, AUDIO_8KHZ = 16, AUDIO_11KHZ = 32, AUDIO_22KHZ = 0, // default AUDIO_32KHZ = 64, AUDIO_44KHZ = 128, AUDIO_MIXER_GAIN = 0, // default AUDIO_IGNORE_MIXER_GAIN = 256, AUDIO_MULTIPLE_INSTANCES = 0, // default AUDIO_SINGLE_INSTANCE = 512, }; API int audio_queue( const void *samples, int num_samples, int flags ); #line 0 #line 1 "engine/split/v4k_buffer.h" // ---------------------------------------------------------------------------- // compression api enum COMPRESS_FLAGS { COMPRESS_RAW = 0, COMPRESS_PPP = (1<<4), COMPRESS_ULZ = (2<<4), COMPRESS_LZ4 = (3<<4), COMPRESS_CRUSH = (4<<4), COMPRESS_DEFLATE = (5<<4), COMPRESS_LZP1 = (6<<4), COMPRESS_LZMA = (7<<4), COMPRESS_BALZ = (8<<4), COMPRESS_LZW3 = (9<<4), COMPRESS_LZSS = (10<<4), COMPRESS_BCM = (11<<4), COMPRESS_ZLIB = (12<<4), // same as deflate with header }; API unsigned zbounds(unsigned inlen, unsigned flags); API unsigned zencode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags); API unsigned zexcess(unsigned flags); API unsigned zdecode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags); // ---------------------------------------------------------------------------- // array de/interleaving // - rlyeh, public domain. // // results: // R0G0B0 R1G1B1 R2G2B2... -> R0R1R2... B0B1B2... G0G1G2... // R0G0B0A0 R1G1B1A1 R2G2B2A2... -> R0R1R2... A0A1A2... B0B1B2... G0G1G2... API void *interleave( void *out, const void *list, int list_count, int sizeof_item, unsigned columns ); // ---------------------------------------------------------------------------- // cobs en/decoder API unsigned cobs_bounds(unsigned len); API unsigned cobs_encode(const void *in, unsigned inlen, void *out, unsigned outlen); API unsigned cobs_decode(const void *in, unsigned inlen, void *out, unsigned outlen); // ---------------------------------------------------------------------------- // base92 en/decoder API unsigned base92_encode(const void *in, unsigned inlen, void* out, unsigned outlen); API unsigned base92_decode(const void *in, unsigned inlen, void* out, unsigned outlen); API unsigned base92_bounds(unsigned inlen); // ---------------------------------------------------------------------------- // netstring en/decoder API unsigned netstring_bounds(unsigned inlen); API unsigned netstring_encode(const char *in, unsigned inlen, char *out, unsigned outlen); API unsigned netstring_decode(const char *in, unsigned inlen, char *out, unsigned outlen); // ---------------------------------------------------------------------------- // delta en/decoder API void delta8_encode(void *buffer, unsigned count); API void delta8_decode(void *buffer, unsigned count); API void delta16_encode(void *buffer, unsigned count); API void delta16_decode(void *buffer, unsigned count); API void delta32_encode(void *buffer, unsigned count); API void delta32_decode(void *buffer, unsigned count); API void delta64_encode(void *buffer, unsigned count); API void delta64_decode(void *buffer, unsigned count); // ---------------------------------------------------------------------------- // zigzag en/decoder API uint64_t zig64( int64_t value ); // convert sign|magnitude to magnitude|sign API int64_t zag64( uint64_t value ); // convert magnitude|sign to sign|magnitude API uint32_t enczig32u( int32_t n); API uint64_t enczig64u( int64_t n); API int32_t deczig32i(uint32_t n); API int64_t deczig64i(uint64_t n); // ---------------------------------------------------------------------------- // arc4 en/decryptor API void *arc4( void *buffer, unsigned buflen, const void *pass, unsigned passlen ); // ---------------------------------------------------------------------------- // crc64 API uint64_t crc64(uint64_t h, const void *ptr, uint64_t len); // ---------------------------------------------------------------------------- // entropy encoder API void entropy( void *buf, unsigned n ); #line 0 #line 1 "engine/split/v4k_collide.h" // ----------------------------------------------------------------------------- // original code by @vurtun (PD) and @barerose (CC0). // [src] https://gist.github.com/vurtun/95f088e4889da2474ad1ce82d7911fee // - rlyeh, public domain. #ifndef GJK_H #define GJK_H #define GJK_MAX_ITERATIONS 20 typedef struct gjk_support { int aid, bid; vec3 a; vec3 b; } gjk_support; typedef struct gjk_vertex { vec3 a; vec3 b; vec3 p; int aid, bid; } gjk_vertex; typedef struct gjk_simplex { int max_iter, iter; int hit, cnt; gjk_vertex v[4]; float bc[4], D; } gjk_simplex; typedef struct gjk_result { int hit; vec3 p0; vec3 p1; float distance_squared; int iterations; } gjk_result; int gjk(gjk_simplex *s, const gjk_support *sup, vec3 *dv); gjk_result gjk_analyze(const gjk_simplex *s); gjk_result gjk_quad(float a_radius, float b_radius); #endif //typedef struct gjk_result gjk_result; typedef struct line { vec3 a, b; } line; typedef struct sphere { vec3 c; float r; } sphere; typedef struct aabb { vec3 min, max; } aabb; typedef struct plane { vec3 p, n; } plane; typedef struct capsule { vec3 a, b; float r; } capsule; typedef struct ray { vec3 p, d; } ray; typedef struct triangle { vec3 p0,p1,p2; } triangle; typedef struct poly { vec3* verts; int cnt; } poly; typedef union frustum { struct { vec4 l, r, t, b, n, f; }; vec4 pl[6]; float v[24]; } frustum; #define line(...) C_CAST(line, __VA_ARGS__) #define sphere(...) C_CAST(sphere, __VA_ARGS__) #define aabb(...) C_CAST(aabb, __VA_ARGS__) #define plane(...) C_CAST(plane, __VA_ARGS__) #define capsule(...) C_CAST(capsule, __VA_ARGS__) #define ray(p,normdir) C_CAST(ray, p, normdir) #define triangle(...) C_CAST(triangle, __VA_ARGS__) #define poly(...) C_CAST(poly, __VA_ARGS__) #define frustum(...) C_CAST(frustum, __VA_ARGS__) // ---------------------------------------------------------------------------- typedef struct hit { union { // general case float depth; // rays only: penetration (t0) and extraction (t1) points along ray line struct { float t0, t1; }; // gjk only struct { int hits; vec3 p0, p1; float distance2; int iterations; }; }; union { vec3 p; vec3 contact_point; }; union { vec3 n; vec3 normal; }; } hit; #define hit(...) C_CAST(hit, __VA_ARGS__) // ---------------------------------------------------------------------------- /* line/segment */ API float line_distance2_point(line l, vec3 p); API vec3 line_closest_point(line l, vec3 p); /* ray */ API float ray_test_plane(ray r, vec4 p4); API float ray_test_triangle(ray r, triangle t); API int ray_test_sphere(float *t0, float *t1, ray r, sphere s); API int ray_test_aabb(float *t0, float *t1, ray r, aabb a); API hit* ray_hit_plane(ray r, plane p); API hit* ray_hit_triangle(ray r, triangle t); API hit* ray_hit_sphere(ray r, sphere s); API hit* ray_hit_aabb(ray r, aabb a); /* sphere */ API vec3 sphere_closest_point(sphere s, vec3 p); API hit* sphere_hit_aabb(sphere s, aabb a); API hit* sphere_hit_capsule(sphere s, capsule c); API hit* sphere_hit_sphere(sphere a, sphere b); API int sphere_test_aabb(sphere s, aabb a); API int sphere_test_capsule(sphere s, capsule c); API int sphere_test_poly(sphere s, poly p); API int sphere_test_sphere(sphere a, sphere b); /* aabb */ API vec3 aabb_closest_point(aabb a, vec3 p); API float aabb_distance2_point(aabb a, vec3 p); API int aabb_contains_point(aabb a, vec3 p); API hit* aabb_hit_aabb(aabb a, aabb b); API hit* aabb_hit_capsule(aabb a, capsule c); API hit* aabb_hit_sphere(aabb a, sphere s); API int aabb_test_aabb(aabb a, aabb b); API int aabb_test_capsule(aabb a, capsule c); API int aabb_test_poly(aabb a, poly p); API int aabb_test_sphere(aabb a, sphere s); /* capsule */ API float capsule_distance2_point(capsule c, vec3 p); API vec3 capsule_closest_point(capsule c, vec3 p); API hit* capsule_hit_aabb(capsule c, aabb a); API hit* capsule_hit_capsule(capsule a, capsule b); API hit* capsule_hit_sphere(capsule c, sphere s); API int capsule_test_aabb(capsule c, aabb a); API int capsule_test_capsule(capsule a, capsule b); API int capsule_test_poly(capsule c, poly p); API int capsule_test_sphere(capsule c, sphere s); /* poly: query */ API int poly_test_sphere(poly p, sphere s); API int poly_test_aabb(poly p, aabb a); API int poly_test_capsule(poly p, capsule c); API int poly_test_poly(poly a, poly b); /* poly: query transformed */ API int poly_test_sphere_transform(poly p, vec3 pos3, mat33 rot33, sphere s); API int poly_test_aabb_transform(poly p, vec3 apos3, mat33 arot33, aabb a); API int poly_test_capsule_transform(poly p, vec3 pos3, mat33 rot33, capsule c); API int poly_test_poly_transform(poly a, vec3 apos3, mat33 arot33, poly b, vec3 bpos3, mat33 brot33); /* poly: gjk result */ API int poly_hit_sphere(struct gjk_result *res, poly p, sphere s); API int poly_hit_aabb(struct gjk_result *res, poly p, aabb a); API int poly_hit_capsule(struct gjk_result *res, poly p, capsule c); API int poly_hit_poly(struct gjk_result *res, poly a, poly b); /* poly: gjk result transformed */ API int poly_hit_sphere_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, sphere s); API int poly_hit_aabb_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, aabb a); API int poly_hit_capsule_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, capsule c); API int poly_hit_poly_transform(struct gjk_result *res, poly a, vec3 at3, mat33 ar33, poly b, vec3 bt3, mat33 br33); API vec4 plane4(vec3 p, vec3 n); API frustum frustum_build(mat44 projview); API int frustum_test_sphere(frustum f, sphere s); API int frustum_test_aabb(frustum f, aabb a); API poly poly_alloc(int cnt); API void poly_free(poly *p); API poly pyramid(vec3 from, vec3 to, float size); // poly_free() required API poly diamond(vec3 from, vec3 to, float size); // poly_free() required API void collide_demo(); // debug draw collisions #line 0 #line 1 "engine/split/v4k_cooker.h" // ----------------------------------------------------------------------------- // asset pipeline framework // - rlyeh, public domain. // // all cooked assets are stored inside zip file at root folder, which acts as an asset database. // during game boot, the database gets rebuilt as follows: (note: step 0 is an optional optimization) // 0. for N given cores, split list of infiles into N zipfiles. then, parallelize cooks. // 1. compare local disk files against file in zip database. for each mismatch do: // 2. - invalidate its entry in database, if local file was removed from disk. // 3. - write its *cooked* contents into database, if local file was created or modified from disk. // 4. mount any existing zipfile(s) after cooking. // // notes: meta-datas from every raw asset are stored into comment field, inside .cook.zip archive. // @todo: fix leaks // @todo: symlink exact files // @todo: idle threads should steal jobs from busy threads (maybe use jobs/coroutines for this?) ... enum COOK_FLAGS { COOK_SYNC = 0, COOK_ASYNC = 1, COOK_CANCELABLE = 2, COOK_DEBUGLOG = 4, // log all cooking commands to a batch file }; API void cook_config( const char *path_to_cook_ini ); // "tools/cook.ini" API bool cook_start( const char *path_to_cook_ini, const char *masks, int flags ); // COOK_INI, "**" API void cook_stop(); API void cook_cancel(); API int cook_jobs(); // [0..N] API int cook_progress(); // [0..100] // utils API bool have_tools(); #line 0 #line 1 "engine/split/v4k_data.h" // ----------------------------------------------------------------------------- // data framework (json5, xml, compression) @todo:kvdb // - rlyeh, public domain // // @todo: vec2,vec3,vec4 typedef union json_t { char* s; double f; int64_t i; uintptr_t p; array(union json_t) arr; } json_t; // json api API bool json_push(const char *json_content); API const char* json_key(const char *keypath); API json_t* json_find(const char *type_keypath); API json_t json_get(const char *type_keypath); API int json_count(const char *keypath); #define json_int(...) (json_get(va("i" __VA_ARGS__)).i) #define json_float(...) (json_get(va("f" __VA_ARGS__)).f) #define json_string(...) (json_get(va("s" __VA_ARGS__)).s) #define json_key(...) json_key(va(__VA_ARGS__)) #define json_count(...) json_count(va(__VA_ARGS__)) API bool json_pop(); // xml api API int xml_push(const char *xml_content); API const char * xml_string(char *key); API unsigned xml_count(char *key); API array(char) xml_blob(char *key); #define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string #define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int #define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float #define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob #define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes API void xml_pop(); API bool data_tests(); #line 0 #line 1 "engine/split/v4k_dll.h" // dll utils // - rlyeh, public domain /// !!! `filename` must contain extension /// load dynamic library `file` and search for `symbol` /// return: NULL if not found, found symbol otherwise. /// filename: path to dynamic library file. must contain extension. /// symbol: symbol name. must not be NULL. /// see: dlopen^, dlclose^ /// > bool (*plugin_init)(void) = dll("plugin.dll", "init"); /// > assert(plugin_init()); API void* dll(const char *filename, const char *symbol); #line 0 #line 1 "engine/split/v4k_editor.h" // ----------------------------------------------------------------------------- // in-game editor // - rlyeh, public domain. // // @todo: merge editor1.c and editor2.c internals into this api //API void editor(); //API bool editor_active(); API vec3 editor_pick(float mouse_x, float mouse_y); API char* editor_path(const char *path); API float* editor_getf(const char *key); API int* editor_geti(const char *key); API char** editor_gets(const char *key); API int editor_send(const char *cmd, const char *optional_value); // open file dialog API char* dialog_load(); API char* dialog_save(); // transform gizmos API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); API bool gizmo_active(); API bool gizmo_hover(); // localization kit (I18N, L10N) API void kit_locale( const char *langcode_iso639_1 ); // set context language: enUS, ptBR, esES, ... API void kit_set( const char *variable, const char *value ); // set context variable API void kit_reset(); // reset all variables in context API void kit_insert( const char *id, const char *translation ); // insert single translation API bool kit_load( const char *filename ); // load translations file (xlsx) API bool kit_merge( const char *filename ); // merge translations file into existing context API void kit_clear(); // delete all translations API char* kit_translate( const char *id ); // perform a translation, given current locale API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale API void kit_dump_state( FILE *fp ); #line 0 #line 1 "engine/split/v4k_file.h" // ----------------------------------------------------------------------------- // files, cache and virtual filesystem (registered directories and/or compressed zip archives). // - rlyeh, public domain. // // - note: vfs_mount() order matters (last mounts have higher priority). // - note: directory/with/trailing/slash/ as mount_point, or zip/tar/pak archive otherwise. // // @todo: file_mmap // @todo: file_find() from first file_scan() // physical filesystem. files API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c API bool file_write( const char *file, const void *ptr, int len ); API bool file_append( const char *file, const void *ptr, int len ); API char * file_read(const char *filename); API char * file_load(const char *filename, int *len); API uint64_t file_size(const char *pathfile); API bool file_directory(const char *pathfile); API char * file_pathabs(const char *pathfile); // ../dir/./file.ext -> c:/prj/dir/file.ext API char * file_path(const char *pathfile); // c:/prj/dir/file.ext -> c:/prj/dir/ API char * file_name(const char *pathfile); // c:/prj/dir/file.ext -> file.ext API char * file_base(const char *pathfile); // c:/prj/dir/file.ext -> file API char * file_ext(const char *pathfile); // c:/prj/dir/file.ext -> .ext API char * file_id(const char *pathfile); // c:/prj/dir/file.ext -> file/dir/prj (name then alphabetical) API char * file_normalize(const char *pathfile); // c:/prj/dir/file.ext -> c/prj/dir/file_ext //API char * file_normalize_with_folder(const char *pathfile); // c:/prj/dir/file.ext -> dir/file_ext API char * file_counter(const char *pathfile); // in: v4k.ini -> out: v4k(001).ini -> out: v4k(002).ini [-> etc...] API uint64_t file_stamp(const char *pathfile); // 1616153596 (seconds since unix epoch) API uint64_t file_stamp10(const char *pathfile); // 20210319113316 (absolute datetime in base10) API bool file_exist(const char *pathfile); API bool file_delete(const char *pathfile); API bool file_copy(const char *src, const char *dst); API bool file_move(const char *src, const char *dst); API FILE* file_temp(); API char* file_tempname(); API void* file_md5(const char *file); // 16 bytes API void* file_sha1(const char *file); // 20 bytes API void* file_crc32(const char *file); // 4 bytes // compressed files API array(char*) file_zip_list(const char *zipfile); API array(char) file_zip_extract(const char *zipfile, const char *filename); API bool file_zip_append(const char *zipfile, const char *filename, int clevel); API bool file_zip_appendmem(const char *zipfile, const char *entryname, const void *ptr, unsigned len, int clevel); // storage (emscripten only) // Mounts local storage folder for writing. Useful for Emscripten only. @path_folder: "/save" for example // Reads local storage to memory. Usually call it one time only, after mount. Useful for Emscripten only. // Writes memory contents to local storage. Usually call it after all fclose API void storage_mount(const char* folder); API void storage_read(); API void storage_flush(); // virtual filesystem API bool vfs_mount(const char *mount_point); API array(char*) vfs_list(const char *masks); // **.png;*.c API char * vfs_read(const char *pathfile); API char * vfs_load(const char *pathfile, int *size); API int vfs_size(const char *pathfile); API const char * vfs_resolve(const char *fuzzyname); // guess best match. @todo: fuzzy path //API const char*vfs_extract(const char *pathfile); // extracts vfs file into local filesystem (temporary file), so it can be read by foreign/3rd party libs API FILE* vfs_handle(const char *pathfile); // same as above, but returns file handle instead. preferred way, will clean descriptors at exit // cache API void * cache_insert(const char *key, void *value, int size); API void * cache_lookup(const char *key, int *size); // ini // @todo: evaluate alt api #1 // char *ini(filename, section.key, default); // float inif(filename, section.key, default); // @todo: evaluate alt api #2 // char *val = ini(filename, section_key); // int count = ini_count(filename); // char *key = ini_key_id(filename, id); // char *val = ini_val_id(filename, id); typedef map(char*,char*) ini_t; API ini_t ini(const char *filename); API ini_t ini_from_mem(const char *data); API void ini_destroy(ini_t); API bool ini_write(const char *filename, const char *section, const char *key, const char *value); #line 0 #line 1 "engine/split/v4k_font.h" // ----------------------------------------------------------------------------- // font framework // - rlyeh, public domain // font size tags #define FONT_H1 "\1" // largest #define FONT_H2 "\2" #define FONT_H3 "\3" #define FONT_H4 "\4" #define FONT_H5 "\5" #define FONT_H6 "\6" // smallest // font color tags #define FONT_COLOR1 "\x10" #define FONT_COLOR2 "\x11" #define FONT_COLOR3 "\x12" #define FONT_COLOR4 "\x13" #define FONT_COLOR5 "\x14" #define FONT_COLOR6 "\x15" #define FONT_COLOR7 "\x16" #define FONT_COLOR8 "\x17" #define FONT_COLOR9 "\x18" #define FONT_COLOR10 "\x19" // font face tags #define FONT_FACE1 "\x1a" #define FONT_FACE2 "\x1b" #define FONT_FACE3 "\x1c" #define FONT_FACE4 "\x1d" #define FONT_FACE5 "\x1e" #define FONT_FACE6 "\x1f" // font align tags #define FONT_LEFT "\\<" #define FONT_CENTER "\\|" #define FONT_RIGHT "\\>" #define FONT_TOP "\\^" #define FONT_MIDDLE "\\-" #define FONT_BASELINE "\\_" #define FONT_BOTTOM "\\v" // font flags enum FONT_FLAGS { // font atlas size FONT_512 = 0x0, FONT_1024 = 0x1, FONT_2048 = 0x2, FONT_4096 = 0x4, // font oversampling FONT_NO_OVERSAMPLE = 0x0, FONT_OVERSAMPLE_X = 0x08, FONT_OVERSAMPLE_Y = 0x10, // unicode ranges FONT_ASCII = 0x800, // Compatible charset FONT_AR = 0x001000, // Arabic and Arabic-Indic digits FONT_ZH = 0x002000, // Chinese Simplified (@todo: add ZH_FULL) FONT_EL = 0x004000, // Greek, Coptic, modern Georgian, Svan, Mingrelian, Ancient Greek FONT_EM = 0x008000, // Emoji FONT_EU = 0x010000, // Eastern/western Europe, IPA, Latin ext A/B FONT_HE = 0x020000, // Hebrew, Yiddish, Ladino, and other diaspora languages FONT_JP = 0x040000, // Hiragana, Katakana, Punctuations, Half-width chars FONT_KR = 0x080000, // Korean, Hangul FONT_RU = 0x100000, // Cyrillic + ext A/B FONT_TH = 0x200000, // Thai FONT_VI = 0x400000, // Vietnamese FONT_CJK = FONT_ZH|FONT_JP|FONT_KR, // FONT_DEFAULTS = FONT_512 | FONT_NO_OVERSAMPLE | FONT_ASCII, }; // configures API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); API void font_color(const char *color_tag, uint32_t color); // commands API vec2 font_xy(); API void font_goto(float x, float y); API vec2 font_print(const char *text); API vec2 font_rect(const char *text); // void font_clip(vec2 topleft, vec2 bottomright); // void font_wrap(vec2 topleft, vec2 bottomright); // syntax highlighting API void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords); // comma separated tokens. expensive, please cache result. API vec2 font_highlight(const char *text, const void *colors); #line 0 #line 1 "engine/split/v4k_id.h" // ----------------------------------------------------------------------------- // factory of handle ids, based on code by randy gaul (PD/Zlib licensed) // - rlyeh, public domain // // [src] http://www.randygaul.net/wp-content/uploads/2021/04/handle_table.cpp // [ref] http://bitsquid.blogspot.com.es/2011/09/managing-decoupling-part-4-id-lookup.html // [ref] http://glampert.com/2016/05-04/dissecting-idhashindex/ // [ref] https://github.com/nlguillemot/dof/blob/master/viewer/packed_freelist.h // [ref] https://gist.github.com/pervognsen/ffd89e45b5750e9ce4c6c8589fc7f253 // convert between hard refs (pointers) and weak refs (ids) uintptr_t id_make(void *ptr); void * id_handle(uintptr_t id); void id_dispose(uintptr_t id); bool id_valid(uintptr_t id); // configuration: // ideally, these two should be 32 each. they were changed to fit our OBJHEADER bits #ifndef ID_INDEX_BITS #define ID_INDEX_BITS 16 #endif #ifndef ID_COUNT_BITS #define ID_COUNT_BITS 3 #endif // you cannot change this one: the number of ID_DATA_BITS you can store in a handle depends on ID_COUNT_BITS #define ID_DATA_BITS (64-ID_COUNT_BITS) #line 0 #line 1 "engine/split/v4k_pack.h" // ----------------------------------------------------------------------------- // semantic versioning in a single byte (octal) // - rlyeh, public domain. // // - single octal byte that represents semantic versioning (major.minor.patch). // - allowed range [0000..0377] ( <-> [0..255] decimal ) // - comparison checks only major.minor tuple as per convention. API int semver( int major, int minor, int patch ); API int semvercmp( int v1, int v2 ); #define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch)) #define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110)) #define SEMVERFMT "%03o" // ----------------------------------------------------------------------------- // storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations typedef struct byte2 { uint8_t x,y; } byte2; typedef struct byte3 { uint8_t x,y,z; } byte3; typedef struct byte4 { uint8_t x,y,z,w; } byte4; typedef struct int2 { int x,y; } int2; typedef struct int3 { int x,y,z; } int3; typedef struct int4 { int x,y,z,w; } int4; typedef struct uint2 { unsigned int x,y; } uint2; typedef struct uint3 { unsigned int x,y,z; } uint3; typedef struct uint4 { unsigned int x,y,z,w; } uint4; typedef struct float2 { float x,y; } float2; typedef struct float3 { float x,y,z; } float3; typedef struct float4 { float x,y,z,w; } float4; typedef struct double2 { double x,y; } double2; typedef struct double3 { double x,y,z; } double3; typedef struct double4 { double x,y,z,w; } double4; #define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) ) #define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) ) #define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) ) #define int2(x,y) M_CAST(int2, (int)(x), (int)(y) ) #define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) ) #define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) ) #define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) ) #define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) ) #define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) ) #define float2(x,y) M_CAST(float2, (float)(x), (float)(y) ) #define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) ) #define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) ) #define double2(x,y) M_CAST(double2, (double)(x), (double)(y) ) #define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) ) #define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) ) // ----------------------------------------------------------------------------- // compile-time fourcc, eightcc API char *cc4str(unsigned cc); API char *cc8str(uint64_t cc); enum { # define _(a,b,c,d,e) cc__##a, cc__##b, cc__##c, cc__##d, cc__##e cc__1 = '1', _(2,3,4,5,6),_(7,8,9,0,_), cc__ = ' ', cc__A = 'A', _(B,C,D,E,F),_(G,H,I,J,K),_(L,M,N,O,P),_(Q,R,S,T,U),_(V,W,X,Y,Z), cc__a = 'a', _(b,c,d,e,f),_(g,h,i,j,k),_(l,m,n,o,p),_(q,r,s,t,u),_(v,w,x,y,z), # undef _ }; #ifdef BIG #define cc4(a,b,c,d) ((uint32_t)(cc__##a<<24) | (cc__##b<<16) | (cc__##c<<8) | (cc__##d<<0)) #define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(a,b,c,d) << 32ULL) | cc4(e,f,g,h)) #else #define cc4(a,b,c,d) ((uint32_t)(cc__##d<<24) | (cc__##c<<16) | (cc__##b<<8) | (cc__##a<<0)) #define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(e,f,g,h) << 32ULL) | cc4(a,b,c,d)) #endif #define cc3(a,b,c) cc4(,a,b,c) #define cc5(a,b,c,d,e) cc6(,a,b,c,d,e) #define cc6(a,b,c,d,e,f) cc7(,a,b,c,d,e,f) #define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g) // ---------------------------------------------------------------------------- // text conversions API char* ftoa1(float v); API char* ftoa2(vec2 v); API char* ftoa3(vec3 v); API char* ftoa4(vec4 v); API float atof1(const char *s); API vec2 atof2(const char *s); API vec3 atof3(const char *s); API vec4 atof4(const char *s); API char* itoa1(int v); API char* itoa2(vec2i v); API char* itoa3(vec3i v); API int atoi1(const char *s); API vec2i atoi2(const char *s); API vec3i atoi3(const char *s); // ---------------------------------------------------------------------------- // endianness API int is_big(); API int is_little(); API uint16_t swap16( uint16_t x ); API uint32_t swap32( uint32_t x ); API uint64_t swap64( uint64_t x ); API float swap32f(float n); API double swap64f(double n); API void swapf(float *a, float *b); API void swapf2(vec2 *a, vec2 *b); API void swapf3(vec3 *a, vec3 *b); API void swapf4(vec4 *a, vec4 *b); API uint16_t lil16(uint16_t n); // swap16 as lil API uint32_t lil32(uint32_t n); // swap32 as lil API uint64_t lil64(uint64_t n); // swap64 as lil API float lil32f(float n); // swap32 as lil API double lil64f(double n); // swap64 as lil API uint16_t big16(uint16_t n); // swap16 as big API uint32_t big32(uint32_t n); // swap32 as big API uint64_t big64(uint64_t n); // swap64 as big API float big32f(float n); // swap32 as big API double big64f(double n); // swap64 as big API uint16_t* lil16p(void *p, int sz); API uint32_t* lil32p(void *p, int sz); API uint64_t* lil64p(void *p, int sz); API float * lil32pf(void *p, int sz); API double * lil64pf(void *p, int sz); API uint16_t* big16p(void *p, int sz); API uint32_t* big32p(void *p, int sz); API uint64_t* big64p(void *p, int sz); API float * big32pf(void *p, int sz); API double * big64pf(void *p, int sz); #if is(cl) #define swap16 _byteswap_ushort #define swap32 _byteswap_ulong #define swap64 _byteswap_uint64 #elif is(gcc) #define swap16 __builtin_bswap16 #define swap32 __builtin_bswap32 #define swap64 __builtin_bswap64 #endif #define hton16 big16 #define ntoh16 big16 #define hton32 big32 #define ntoh32 big32 #define hton64 big64 #define ntoh64 big64 #define IS_BIG ((*(uint16_t *)"\0\1") == 1) #define IS_LITTLE ((*(uint16_t *)"\0\1") != 1) // ---------------------------------------------------------------------------- // half packing typedef uint16_t half; API float half_to_float(half value); API half float_to_half(float value); // ---------------------------------------------------------------------------- // int packing // pack16i() -- store a 16-bit int into a char buffer (like htons()) // pack32i() -- store a 32-bit int into a char buffer (like htonl()) // pack64i() -- store a 64-bit int into a char buffer (like htonl()) API void pack16i(uint8_t *buf, uint16_t i, int swap); API void pack32i(uint8_t *buf, uint32_t i, int swap); API void pack64i(uint8_t *buf, uint64_t i, int swap); // unpack16i() -- unpack a 16-bit int from a char buffer (like ntohs()) // unpack32i() -- unpack a 32-bit int from a char buffer (like ntohl()) // unpack64i() -- unpack a 64-bit int from a char buffer (like ntohl()) // changes unsigned numbers to signed if needed. API int16_t unpack16i(const uint8_t *buf, int swap); API int32_t unpack32i(const uint8_t *buf, int swap); API int64_t unpack64i(const uint8_t *buf, int swap); // ---------------------------------------------------------------------------- // float un/packing: 8 (micro), 16 (half), 32 (float), 64 (double) types #define pack754_8(f) ( pack754((f), 8, 4)) #define pack754_16(f) ( pack754((f), 16, 5)) #define pack754_32(f) ( pack754((f), 32, 8)) #define pack754_64(f) ( pack754((f), 64, 11)) #define unpack754_8(u) (unpack754((u), 8, 4)) #define unpack754_16(u) (unpack754((u), 16, 5)) #define unpack754_32(u) (unpack754((u), 32, 8)) #define unpack754_64(u) (unpack754((u), 64, 11)) API uint64_t pack754(long double f, unsigned bits, unsigned expbits); API long double unpack754(uint64_t i, unsigned bits, unsigned expbits); // ---------------------------------------------------------------------------- // variable-length integer packing API uint64_t pack64uv( uint8_t *buffer, uint64_t value ); API uint64_t unpack64uv( const uint8_t *buffer, uint64_t *value ); API uint64_t pack64iv( uint8_t *buffer, int64_t value_ ); API uint64_t unpack64iv( const uint8_t *buffer, int64_t *value ); // ---------------------------------------------------------------------------- // msgpack v5, schema based struct/buffer bitpacking // api v2 API int msgpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of written bytes API int msgunpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of parsed args // api v1 API int msgpack_new(uint8_t *w, size_t l); API int msgpack_nil(); // write null API int msgpack_chr(bool n); // write boolean API int msgpack_uns(uint64_t n); // write unsigned integer API int msgpack_int(int64_t n); // write integer API int msgpack_str(const char *s); // write string API int msgpack_bin(const char *s, size_t n); // write binary pointer API int msgpack_flt(double g); // write real API int msgpack_ext(uint8_t key, void *val, size_t n); // write extension type API int msgpack_arr(uint32_t n); // write array mark for next N items API int msgpack_map(uint32_t n); // write map mark for next N pairs (N keys + N values) API int msgpack_eof(); // write full? API int msgpack_err(); // write error? API bool msgunpack_new( const void *opaque_or_FILE, size_t bytes ); API bool msgunpack_nil(); API bool msgunpack_chr(bool *chr); API bool msgunpack_uns(uint64_t *uns); API bool msgunpack_int(int64_t *sig); API bool msgunpack_str(char **str); API bool msgunpack_bin(void **bin, uint64_t *len); API bool msgunpack_flt(float *flt); API bool msgunpack_dbl(double *dbl); API bool msgunpack_ext(uint8_t *key, void **val, uint64_t *len); API bool msgunpack_arr(uint64_t *len); API bool msgunpack_map(uint64_t *len); API bool msgunpack_eof(); API bool msgunpack_err(); // ---------------------------------------------------------------------------- // Based on code by Brian "Beej Jorgensen" Hall (public domain) [1]. // Based on code by Ginger Bill's half<->float (public domain) [2]. // - rlyeh, public domain. // // pack.c -- perl/python-ish pack/unpack functions // like printf and scanf, but for binary data. // // format flags: // (<) little endian (>) big endian (! also) (=) native endian // (c) 8-bit char (b) 8-bit byte // (h) 16-bit half (w) 16-bit word // (i) 32-bit integer (u) 32-bit unsigned (f) 32-bit float // (l) 64-bit long (q) 64-bit quad (d) 64-bit double // (v) varint // (s) string (64-bit varint length prepended) // (S) string (32-bit fixed length prepended) // (m) memblock (64-bit varint length prepended) // (M) memblock (32-bit fixed length prepended) // (z) memblock (zeroed) // (#) number of arguments processed (only when unpacking) // // @todo: // - (x) document & test flag // @totest: // - (s) string (64-bit variable length automatically prepended) // - (S) string (32-bit fixed length automatically prepended) // - (m) memblock (64-bit variable length automatically prepended) // - (M) memblock (32-bit fixed length automatically prepended) // - (z) memblock (zeroed) // - (#) number of arguments processed (only when unpacking) // - save data dictated by the format string from the buffer. return: number of bytes written, or 0 if error. // if first argument is zero, returns number of bytes required for packing. API int savef(FILE *file, const char *format, ...); API int saveb(unsigned char *buf, const char *format, ...); // - load data dictated by the format string into the buffer. return: number of bytes read, or 0 if error. // if first argument is zero, returns number of bytes required for unpacking. API int loadf(FILE *file, const char *format, ...); API int loadb(const unsigned char *buf, const char *format, ...); #line 0 #line 1 "engine/split/v4k_input.h" // ----------------------------------------------------------------------------- // input framework // - rlyeh, public domain // // @todo: window // @todo: for extra savings (168->72 bytes), promote bits to real bits (/8 %8) & normalized floats [-1,+1] to shorts or chars // @todo: GAMEPAD_A|2, MOUSE_L|1, KEY_C|3 // @todo: load/save // @todo: send virtual presses & outputs (rumble, light, led, text, etc) // @todo: fix if logger !60 hz // @tofo: fix click2/repeat edge cases API int input_use( int controller_id ); // [0..3] // -- basic polling api (read input at current frame) API float input( int vk ); API vec2 input2( int vk ); API float input_diff( int vk ); // @todo: rename diff->delta API vec2 input_diff2( int vk ); // @todo: rename diff2->delta2 API const char* input_string( int vk ); // -- extended polling api (read input at Nth frame ago) API float input_frame( int vk, int Nth_frame ); API vec2 input_frame2( int vk, int Nth_frame ); // -- events api API int input_up( int vk ); // ON -> OFF (release) API int input_down( int vk ); // OFF -> ON (trigger) API int input_held( int vk ); // ON -> ON (pressed) API int input_idle( int vk ); // OFF -> OFF API int input_click( int vk, int ms ); // OFF -> ON -> OFF API int input_click2( int vk, int ms ); // OFF -> ON -> OFF -> ON -> OFF API int input_repeat( int vk, int ms ); // [...] ON -> ON -> ON API int input_chord2( int vk1, int vk2 ); // all vk1 && vk2 are ON API int input_chord3( int vk1, int vk2, int vk3 ); // all vk1 && vk2 && vk3 are ON API int input_chord4( int vk1, int vk2, int vk3, int vk4 ); // all vk1 && vk2 && vk3 && vk4 are ON // -- 1d/2d filters API float input_filter_positive( float v ); // [-1..1] -> [0..1] API vec2 input_filter_positive2( vec2 v ); // [-1..1] -> [0..1] API vec2 input_filter_deadzone( vec2 v, float deadzone_treshold ); API vec2 input_filter_deadzone_4way( vec2 v, float deadzone_treshold ); // -- multi-touch enum TOUCH_BUTTONS { TOUCH_0, // defaults to left screen area. input_touch_area() to override TOUCH_1, // defaults to right screen area. input_touch_area() to override }; API void input_touch_area(unsigned button, vec2 begin_coord_ndc, vec2 end_coord_ndc); API vec2 input_touch(unsigned button, float sensitivity); // absolute position in 2d coords API vec2 input_touch_delta(unsigned button, float sensitivity); // delta from previous position API vec2 input_touch_delta_from_origin(unsigned button, float sensitivity); // relative position from initial touch API bool input_touch_active(); // -- utils API void input_mappings(const char *filename); // update gamepad mappings (usually "gamecontrollerdb.txt" file) API char input_keychar(unsigned code); // Converts keyboard code to its latin char (if any) API int input_anykey(); // inject state API void input_send( int vk ); // @todo // load/save input API array(char) save_input(); // @todo API bool load_input(array(char) replay); // @todo // visualize input API int ui_keyboard(); API int ui_mouse(); API int ui_gamepad(int id); API int ui_gamepads(); // -- enum INPUT_ENUMS { // -- bits: x104 keyboard, x3 mouse, x15 gamepad, x7 window // keyboard gaming keys (53-bit): first-class keys for gaming KEY_ESC, KEY_TICK, KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0, KEY_BS, KEY_TAB, KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P, KEY_CAPS, KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L, KEY_ENTER, KEY_LSHIFT, KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M, KEY_RSHIFT, KEY_UP, KEY_LCTRL,KEY_LALT, KEY_SPACE, KEY_RALT,KEY_RCTRL, KEY_LEFT,KEY_DOWN,KEY_RIGHT, // for completeness, secondary keys below (52-bit). beware! KEY_INS,KEY_HOME,KEY_PGUP,KEY_DEL,KEY_END,KEY_PGDN, // beware: different behavior win/osx (also, osx: no home/end). KEY_LMETA,KEY_RMETA,KEY_MENU,KEY_PRINT,KEY_PAUSE,KEY_SCROLL,KEY_NUMLOCK, // beware: may trigger unexpected OS behavior. (@todo: add RSHIFT here for win?) KEY_MINUS,KEY_EQUAL,KEY_LSQUARE,KEY_RSQUARE,KEY_SEMICOLON,KEY_QUOTE,KEY_HASH,KEY_BAR,KEY_COMMA,KEY_DOT,KEY_SLASH, // beware: non-us keyboard layouts KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12, // beware: complicated on laptops/osx KEY_PAD1,KEY_PAD2,KEY_PAD3,KEY_PAD4,KEY_PAD5,KEY_PAD6,KEY_PAD7,KEY_PAD8,KEY_PAD9,KEY_PAD0, // beware: complicated on laptops KEY_PADADD,KEY_PADSUB,KEY_PADMUL,KEY_PADDIV,KEY_PADDOT,KEY_PADENTER, // beware: complicated on laptops MOUSE_L, MOUSE_M, MOUSE_R, GAMEPAD_CONNECTED, GAMEPAD_A, GAMEPAD_B, GAMEPAD_X, GAMEPAD_Y, GAMEPAD_UP, GAMEPAD_DOWN, GAMEPAD_LEFT, GAMEPAD_RIGHT, GAMEPAD_MENU, GAMEPAD_START, GAMEPAD_LB, GAMEPAD_RB, GAMEPAD_LTHUMB, GAMEPAD_RTHUMB, WINDOW_BLUR, WINDOW_FOCUS, WINDOW_CLOSE, WINDOW_MINIMIZE, WINDOW_MAXIMIZE, WINDOW_FULLSCREEN, WINDOW_WINDOWED, // MINI/MAXI/RESTORED, SHOWN/HIDDEN // -- floats: x7 gamepad, x3 mouse, x4 touch, x4 window GAMEPAD_LPAD, GAMEPAD_LPADX = GAMEPAD_LPAD, GAMEPAD_LPADY, GAMEPAD_RPAD, GAMEPAD_RPADX = GAMEPAD_RPAD, GAMEPAD_RPADY, GAMEPAD_LTRIGGER, GAMEPAD_LT = GAMEPAD_LTRIGGER, GAMEPAD_RTRIGGER, GAMEPAD_RT = GAMEPAD_RTRIGGER, GAMEPAD_BATTERY, MOUSE, MOUSE_X = MOUSE, MOUSE_Y, MOUSE_W, TOUCH_X1, TOUCH_Y1, TOUCH_X2, TOUCH_Y2, WINDOW_RESIZE, WINDOW_RESIZEX = WINDOW_RESIZE, WINDOW_RESIZEY, WINDOW_ORIENTATION, WINDOW_BATTERY, // -- strings: x2 gamepad GAMEPAD_GUID, GAMEPAD_NAME, }; #line 0 #line 1 "engine/split/v4k_memory.h" // ----------------------------------------------------------------------------- // memory framework // - rlyeh, public domain // memory leaks detector #if ENABLE_MEMORY_LEAKS #define WATCH(ptr,sz) watch((ptr), (sz)) #define FORGET(ptr) forget(ptr) #else #define WATCH(ptr,sz) (ptr) #define FORGET(ptr) (ptr) #endif // default allocator (aborts on out-of-mem) API void* xrealloc(void* p, size_t sz); API size_t xsize(void* p); API char* xstats(void); // stack based allocator (negative bytes does rewind stack, like when entering new frame) API void* stack(int bytes); // memory leaks api (this is already integrated as long as you compile with -DENABLE_MEMORY_LEAKS) API void* watch( void *ptr, int sz ); API void* forget( void *ptr ); // memory api #define ALLOCSIZE(p) xsize(p) #define MALLOC(n) REALLOC_(0,(n)) #define FREE(p) REALLOC_((p), 0) #define REALLOC(p,n) REALLOC_((p),(n)) #define CALLOC(m,n) CALLOC_((m),(n)) #define STRDUP(s) STRDUP_(s) #define ALLOCA(n) ifdef(gcc, __builtin_alloca(n), _alloca(n)) static FORCE_INLINE void *(REALLOC_)(void *p, size_t n) { return n ? WATCH(xrealloc(p,n),n) : xrealloc(FORGET(p),0); } ///- static FORCE_INLINE void *(CALLOC_)(size_t m, size_t n) { return n *= m, memset(REALLOC(0,n),0,n); } ///- static FORCE_INLINE char *(STRDUP_)(const char *s) { size_t n = strlen(s)+1; return ((char*)memcpy(REALLOC(0,n), s, n)); } ///- #line 0 #line 1 "engine/split/v4k_network.h" // ----------------------------------------------------------------------------- // network framework // - rlyeh, public domain API array(char) download( const char *url ); API int download_file( FILE *out, const char *url ); API int portname( const char *service_name, unsigned retries ); API bool network_tests(); // ----------------------------------------------------------------------------- // udp wrapper // - rlyeh, public domain. // server API int udp_bind(const char *address, const char *port); // client API int udp_open(const char *address, const char *port); // common API int udp_send(int, const void *buf, int len ); // <0 error, >0 bytes sent ok API int udp_sendto(int, const char *ip, const char *port, const void *buf, int len ); // <0 error, >0 bytes sent ok API int udp_recv(int, void *buf, int len ); // <0 error, 0 orderly shutdown, >0 received bytes API int udp_peek(int); // <0 error, 0 timeout, >0 data // ----------------------------------------------------------------------------- // tcp wrapper // - rlyeh, public domain // client API int tcp_open(const char *address, const char *port); // server API int tcp_bind(const char *interface_, const char *port, int queue); API int tcp_peek(int, int(*callback)(int)); // common API int tcp_send(int, const void* buf, int len); API int tcp_recv(int, void* buf, int len); API char* tcp_host(int); // info API char* tcp_port(int); // info API int tcp_close(int); // extras API int tcp_debug(int); // toggle traffic monitoring on/off for given socket //API int tcp_printf(int, const char *fmt, ...); // printf message in remote end //API int tcp_crypt(int,uint64_t); // set shared secret #line 0 #line 1 "engine/split/v4k_netsync.h" // high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories. // - rlyeh, public domain // // Usage: // 1. configure networked memory buffers with flags (world, player1, player2, etc). network_buffer(); // 2. then during game loop: // - modify your buffers as much as needed. // - sync buffers at least once per frame. network_sync(); // - render your world // 3. optionally, monitor network status & variables. network_get(); // // @todo: maybe network_send(msg) + msg *network_recv(); instead of event queue of network_sync() ? //enum { NETWORK_HANDSHAKE, NETWORK_ENCRYPT, NETWORK_VERSIONED, NETWORK_CHECKSUM }; // negotiation //enum { NETWORK_TCP, NETWORK_UDP, NETWORK_KCP, NETWORK_ENET, NETWORK_WEBSOCKET }; // transport, where enum { NETWORK_BIND = 2, NETWORK_CONNECT = 4, NETWORK_NOFAIL = 8 }; API void network_create(unsigned max_clients, const char *ip, const char *port, unsigned flags); // both ip and port can be null //enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes //enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when //enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much //enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ }; API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events enum { NETWORK_EVENT_CONNECT, NETWORK_EVENT_DISCONNECT, NETWORK_EVENT_RECEIVE, NETWORK_EVENT_DISCONNECT_TIMEOUT, /* offset from internal networking events */ NETWORK_EVENT_RPC = 10, NETWORK_EVENT_RPC_RESP, }; /* errcode and errstr are optional arguments, pass NULL to ignore them, errstr is filled by va() */ API int network_event(const char *msg, int *errcode, char **errstr); enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY }; enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE }; enum { NETWORK_SEND_MS = 4 }; enum { NETWORK_BUF_CLEAR_ON_JOIN = 5 }; enum { NETWORK_USERID = 7, /*NETWORK_SALT,*/ NETWORK_COUNT/*N users*/ /*...*/, NETWORK_CAPACITY }; API int64_t network_get(uint64_t key); API int64_t network_put(uint64_t key, int64_t value); API void network_rpc(const char *signature, void *function); API void network_rpc_send_to(int64_t rank, unsigned id, const char *cmdline); API void network_rpc_send(unsigned id, const char *cmdline); // ----------------------------------------------------------------------------- // low-level api (sockets based) API bool server_bind(int max_clients, int port); API char** server_poll(unsigned timeout_ms); API char** client_poll(unsigned timeout_ms); API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags); API void server_broadcast_bin(const void *ptr, int len); API void server_broadcast_flags(const char *msg, uint64_t flags); API void server_broadcast(const char *msg); API void server_terminate(); API void server_send(int64_t handle, const char *msg); API void server_send_bin(int64_t handle, const void *ptr, int len); API void server_drop(int64_t handle); API int64_t client_join(const char *ip, int port); #define client_send_flags(msg,flags) server_broadcast(msg, flags) #define client_send(msg) server_broadcast(msg) #define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags) #define client_send_bin(ptr,len) server_broadcast_bin(ptr, len) #define client_terminate() server_terminate() #define ANYHOST_IPV4 "0.0.0.0" #define ANYHOST_IPV6 "::0" #define LOCALHOST_IPV4 "127.0.0.1" #define LOCALHOST_IPV6 "::1" #line 0 #line 1 "engine/split/v4k_obj.h" // C objects framework // - rlyeh, public domain. // // ## object limitations // - 8-byte overhead per object // - XX-byte overhead per object-entity // - 32 components max per object-entity // - 256 classes max per game // - 256 references max per object // - 1024K bytes max per object // - 8 generations + 64K IDs per running instance (19-bit IDs) // - support for pragma pack(1) structs not enabled by default. /* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */ #ifndef OBJ_MIN_PRAGMAPACK_BITS //#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 8<<3, so 2048 bytes max per class (default) #define OBJ_MIN_PRAGMAPACK_BITS 2 // allows pragma packs >= 4. objsizew becomes 8<<2, so 1024 bytes max per class //#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 8<<1, so 512 bytes max per class //#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 8<<0, so 256 bytes max per class #endif #define OBJHEADER \ union { \ uintptr_t objheader; \ struct { \ uintptr_t objtype:8; \ uintptr_t objsizew:8; \ uintptr_t objrefs:8; \ uintptr_t objheap:1; \ uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \ uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \ uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \ }; \ }; #define OBJ \ struct { OBJHEADER }; // ---------------------------------------------------------------------------- // syntax sugars #ifdef OBJTYPE #undef OBJTYPE #endif #define OBJTYPE(T) \ OBJTYPE_##T #define OBJTYPEDEF(NAME,N) \ enum { OBJTYPE(NAME) = N }; \ STATIC_ASSERT( N <= 255 ); \ STATIC_ASSERT( sizeof(NAME) == ((sizeof(NAME)>>OBJ_MIN_PRAGMAPACK_BITS)<objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \ (PTR)->objtype = (OBJ_TYPE), \ (PTR)->objheap = (HEAP), \ (PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS)) #define OBJ_CTOR_PTR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \ OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE), \ obj_ctor(PTR)) #define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \ objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \ *(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \ ((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \ ( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \ OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \ ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \ obj_setname(objtmp, NAME)) #define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, sizeof(array(obj*)), __VA_ARGS__) #define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, sizeof(array(obj*)), __VA_ARGS__) #define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__) void* obj_malloc(unsigned sz); void* obj_free(void *o); // ---------------------------------------------------------------------------- // obj generics. can be extended. #define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__) #define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__) #define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__) #define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__) #define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__) #define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__) #define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__) #define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__) #define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__) #define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__) #define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__) // --- syntax sugars #define obj_extend(T,func) (obj_##func[OBJTYPE(T)] = (void*)T##_##func) #define obj_method(method,o,...) (obj_##method[((obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((obj*)(o))->objtype]((o), ##__VA_ARGS__)) #define obj_vtable(func,RC,...) RC macro(obj_##func)(){ __VA_ARGS__ }; RC (*obj_##func[256])() = { REPEAT256(macro(obj_##func)) }; #define obj_vtable_null(func,RC) RC (*obj_##func[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed #define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f #define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) #define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) // --- declare vtables API extern void (*obj_ctor[256])(); ///- API extern void (*obj_dtor[256])(); ///- API extern char* (*obj_save[256])(); ///- API extern bool (*obj_load[256])(); ///- API extern int (*obj_test[256])(); ///- API extern int (*obj_init[256])(); ///- API extern int (*obj_quit[256])(); ///- API extern int (*obj_tick[256])(); ///- API extern int (*obj_draw[256])(); ///- API extern int (*obj_lerp[256])(); ///- API extern int (*obj_edit[256])(); ///- // ---------------------------------------------------------------------------- // core API uintptr_t obj_header(const void *o); API uintptr_t obj_id(const void *o); API const char* obj_type(const void *o); API unsigned obj_typeid(const void *o); API int obj_sizeof(const void *o); API int obj_size(const void *o); // size of all members together in struct. may include padding bytes. API char* obj_data(void *o); // pointer to the first member in struct API const char* obj_datac(const void *o); // const pointer to the first struct member API void* obj_payload(const void *o); // pointer right after last member in struct API void* obj_zero(void *o); // reset all object members // ---------------------------------------------------------------------------- // refcounting API void* obj_ref(void *oo); API void* obj_unref(void *oo); // ---------------------------------------------------------------------------- // scene tree #define each_objchild(p,t,o) /*non-recursive*/ \ (array(obj*)* children = obj_children(p); children; children = 0) \ for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \ for(t *o = (t *)((*children)[_i]); o && (obj_parent(o) == p); o = 0) API obj* obj_detach(void *c); API obj* obj_attach(void *o, void *c); API obj* obj_root(const void *o); API obj* obj_parent(const void *o); API array(obj*)*obj_children(const void *o); // child[0]: parent, child[1]: 1st child, child[2]: 2nd child... API array(obj*)*obj_siblings(const void *o); // child[0]: grandpa, child[1]: sibling1, child[2]: sibling2... API int obj_dumptree(const void *o); // ---------------------------------------------------------------------------- // metadata API void* obj_setmeta(void *o, const char *key, const char *value); API const char* obj_meta(const void *o, const char *key); API void* obj_setname(void *o, const char *name); API const char* obj_name(const void *o); // ---------------------------------------------------------------------------- // stl API void* obj_swap(void *dst, void *src); API void* obj_copy_fast(void *dst, const void *src); API void* obj_copy(void *dst, const void *src); API int obj_comp_fast(const void *a, const void *b); API int obj_comp(const void *a, const void *b); API int obj_lesser(const void *a, const void *b); API int obj_greater(const void *a, const void *b); API int obj_equal(const void *a, const void *b); API uint64_t obj_hash(const void *o); // ---------------------------------------------------------------------------- // debug API bool obj_hexdump(const void *oo); API int obj_print(const void *o); API int obj_printf(const void *o, const char *text); API int obj_console(const void *o); // obj_output() ? #define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__)) // ---------------------------------------------------------------------------- // serialization API char* obj_saveini(const void *o); API obj* obj_mergeini(void *o, const char *ini); API obj* obj_loadini(void *o, const char *ini); API char* obj_savejson(const void *o); API obj* obj_mergejson(void *o, const char *json); API obj* obj_loadjson(void *o, const char *json); API char* obj_savebin(const void *o); API obj* obj_mergebin(void *o, const char *sav); API obj* obj_loadbin(void *o, const char *sav); API char* obj_savempack(const void *o); // @todo API obj* obj_mergempack(void *o, const char *sav); // @todo API obj* obj_loadmpack(void *o, const char *sav); // @todo API int obj_push(const void *o); API int obj_pop(void *o); // ---------------------------------------------------------------------------- // components API bool obj_addcomponent(void *object, unsigned c, void *ptr); API bool obj_hascomponent(void *object, unsigned c); API void* obj_getcomponent(void *object, unsigned c); API bool obj_delcomponent(void *object, unsigned c); API bool obj_usecomponent(void *object, unsigned c); API bool obj_offcomponent(void *object, unsigned c); API char* entity_save(entity *self); // ---------------------------------------------------------------------------- // reflection #define each_objmember(oo,TYPE,NAME,PTR) \ (array(reflect_t) *found_ = members_find(obj_type(oo)); found_; found_ = 0) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \ for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \ for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 ) API void* obj_clone(const void *src); API void* obj_merge(void *dst, const void *src); // @testme API void* obj_mutate(void **dst, const void *src); API void* obj_make(const char *str); // built-ins typedef enum OBJTYPE_BUILTINS { OBJTYPE_obj = 0, OBJTYPE_entity = 1, OBJTYPE_vec2 = 2, OBJTYPE_vec3 = 3, OBJTYPE_vec4 = 4, OBJTYPE_quat = 5, OBJTYPE_mat33 = 6, OBJTYPE_mat34 = 7, OBJTYPE_mat44 = 8, OBJTYPE_vec2i = 9, OBJTYPE_vec3i = 10, } OBJTYPE_BUILTINS; #line 0 #line 1 "engine/split/v4k_profile.h" // ----------------------------------------------------------------------------- // profiler & stats (@fixme: threadsafe) #if !ENABLE_PROFILER # define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0) # define profile_incstat(name, accum) do {} while(0) # define profile_setstat(name, value) do {} while(0) # define profiler_init() do {} while(0) # define profiler_enable(x) 0 # define ui_profiler() do {} while(0) #else # define profile(section) for( \ struct profile_t *found = profiler_enabled ? \ map_find_or_add(profiler, section "@" FILELINE, (struct profile_t){NAN} ) : NULL, \ *doit = found + ( found ? found->cost = -time_us(), 1 : 1 ); doit; \ doit = found ? found->cost += time_us(), found->avg = found->cost * 0.25 + found->avg * 0.75, NULL : NULL) ///+ # define profile_incstat(name, accum) for( \ struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \ found; found->stat += accum, found = NULL) ///+ # define profile_setstat(name, value) for( \ struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \ found; found->stat = value, found = NULL) ///+ API int profiler_enable(bool on); struct profile_t { double stat; int32_t cost, avg; }; ///- typedef map(char *, struct profile_t) profiler_t; ///- extern API profiler_t profiler; ///- extern API int profiler_enabled; ///- #endif #line 0 #line 1 "engine/split/v4k_reflect.h" // C reflection: enums, functions, structs, members and anotations. // - rlyeh, public domain // // @todo: nested structs? pointers in members? // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) #ifndef OBJTYPE #define OBJTYPE(T) 0 #endif typedef struct reflect_t { unsigned id, objtype; union { unsigned sz; unsigned member_offset; unsigned enum_value; }; const char *name; const char *info; void *addr; unsigned parent; const char *type; unsigned bytes; } reflect_t; // inscribe api #define ENUM(V, ...) \ enum_inscribe(#V,V, "E" __VA_ARGS__ " ("FILELINE")") #define FUNCTION(F, ...) \ function_inscribe(#F,(void*)F, "F" __VA_ARGS__ " ("FILELINE")") #define STRUCT(T, type, member, ...) \ struct_inscribe(#T,sizeof(T),OBJTYPE(T),"S" " ("FILELINE")"), \ type_inscribe(#type,sizeof(((T){0}).member),"T" __VA_ARGS__ " ("FILELINE")"), \ member_inscribe(#T, #member,(uintptr_t)&((T*)0)->member, "M" __VA_ARGS__ " ("FILELINE")", #type, sizeof(((T){0}).member) ) // find api API unsigned enum_find(const char *E); API void * function_find(const char *F); API reflect_t member_find(const char *T, const char *M); /// find specific member API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate API array(reflect_t)* members_find(const char *T); // iterate members in a struct #define each_member(T,R) \ (array(reflect_t) *found_ = members_find(T); found_; found_ = 0) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) // private api, still exposed API void type_inscribe(const char *TY,unsigned TYsz,const char *infos); API void enum_inscribe(const char *E,unsigned Eval,const char *infos); API void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos); API void member_inscribe(const char *T, const char *M,unsigned Msz, const char *infos, const char *type, unsigned bytes); API void function_inscribe(const char *F,void *func,const char *infos); API int ui_reflect(const char *mask); // *, model* or NULL #line 0 #line 1 "engine/split/v4k_render.h" // ----------------------------------------------------------------------------- // naive rendering framework // - rlyeh, public domain // // IQM skeletal meshes by @lsalzman (public domain) - https://bit.ly/2OQh0Me // SH code by @ands (public domain) - https://github.com/ands/spherical_harmonics_playground // SHM code by @jarikomppa (unlicensed) - https://github.com/jarikomppa/shadertoolkit typedef unsigned handle; // GLuint // ----------------------------------------------------------------------------- // colors API unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a ); API unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ); API unsigned rgbaf( float r, float g, float b, float a ); API unsigned bgraf( float b, float g, float r, float a ); API unsigned alpha( unsigned rgba ); #define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) ) #define RGB3(r,g,b) ( (255<<24) | ((r)<<16) | ((g)<<8) | (b) ) #define RGB4(r,g,b,a) RGBX(RGB3(r,g,b),a) #define BLACK RGBX(0x000000,255) #define WHITE RGBX(0xFFF1E8,255) #if 0 #define RED RGBX(0xFF004D,255) #define GREEN RGBX(0x00B543,255) #define BLUE RGBX(0x065AB5,255) #define ORANGE RGBX(0xFF6C24,255) #define CYAN RGBX(0x29ADFF,255) #define PURPLE RGBX(0x7E2553,255) #define YELLOW RGBX(0xFFEC27,255) #define GRAY RGBX(0x725158,255) #else #define RED RGB3( 255,48,48 ) #define GREEN RGB3( 144,255,48 ) #define CYAN RGB3( 0,192,255 ) #define ORANGE RGB3( 255,144,48 ) #define PURPLE RGB3( 102,77,102 ) // 178,128,255 ) #define YELLOW RGB3( 255,224,0 ) #define GRAY RGB3( 32,32,32 ) // dark gray #define SILVER RGB3( 149,149,149 ) // dark white, gray-ish #define PINK RGB3( 255,48,144 ) #define AQUA RGB3( 48,255,144 ) #define BLUE RGBX(0x065AB5,255) #endif // ----------------------------------------------------------------------------- // images /// flags when constructing the image_t type. see: image, image_from_mem /// IMAGE_R: 1-channel image (R) /// IMAGE_RG: 2-channel image (R,G) /// IMAGE_RGB: 3-channel image (R,G,B) /// IMAGE_RGBA: 4-channel image (R,G,B,A) /// IMAGE_FLIP: Flip image vertically /// IMAGE_FLOAT: Float pixel components enum IMAGE_FLAGS { IMAGE_R = 0x01000, IMAGE_RG = 0x02000, IMAGE_RGB = 0x04000, IMAGE_RGBA = 0x08000, IMAGE_FLIP = 0x10000, IMAGE_FLOAT = 0x20000, }; /// type that holds linear uncompressed bitmap of any given dimensions. /// w,h: image dimensions in pixels. `x,y` alias. /// comps: number of components per pixel. `n` alias. /// pixels: untyped pointer to linear bitmap data. typed pointers use `pixels8/16/32/f` aliases. /// see: texture_t typedef struct image_t { union { unsigned x, w; }; union { unsigned y, h; }; union { unsigned n, comps; }; union { void *pixels; uint8_t *pixels8; uint16_t *pixels16; uint32_t *pixels32; float *pixelsf; }; } image_t; API image_t image(const char *pathfile, int flags); API image_t image_from_mem(const void *ptr, int len, int flags); API void image_destroy(image_t *img); // ----------------------------------------------------------------------------- // textures enum TEXTURE_FLAGS { // UNIT[0..7] TEXTURE_BC1 = 8, // DXT1, RGB with 8:1 compression ratio (+ optional 1bpp for alpha) TEXTURE_BC2 = 16, // DXT3, RGBA with 4:1 compression ratio (BC1 for RGB + 4bpp for alpha) TEXTURE_BC3 = 32, // DXT5, RGBA with 4:1 compression ratio (BC1 for RGB + BC4 for A) // TEXTURE_BC4, // Alpha TEXTURE_NEAREST = 0, TEXTURE_LINEAR = 64, TEXTURE_MIPMAPS = 128, TEXTURE_CLAMP = 0, TEXTURE_BORDER = 0x100, TEXTURE_REPEAT = 0x200, TEXTURE_BYTE = 0, TEXTURE_FLOAT = IMAGE_FLOAT, TEXTURE_COLOR = 0, TEXTURE_DEPTH = 0x800, TEXTURE_R = IMAGE_R, TEXTURE_RG = IMAGE_RG, TEXTURE_RGB = IMAGE_RGB, TEXTURE_RGBA = IMAGE_RGBA, TEXTURE_FLIP = IMAGE_FLIP, // @fixme TEXTURE_SRGB = 1 << 24, TEXTURE_BGR = 1 << 25, TEXTURE_ARRAY = 1 << 26, }; typedef struct texture_t { union { unsigned x, w; }; union { unsigned y, h; }; union { unsigned z, d; }; union { unsigned n, bpp; }; handle id, unit; unsigned texel_type; unsigned flags; char* filename; bool transparent; unsigned fbo; // for texture recording } texture_t; API texture_t texture_compressed(const char *filename, unsigned flags); API texture_t texture_compressed_from_mem(const void *data, int len, unsigned flags); API texture_t texture(const char* filename, int flags); API texture_t texture_from_mem(const void* ptr, int len, int flags); API texture_t texture_create(unsigned w, unsigned h, unsigned n, const void *pixels, int flags); API texture_t texture_checker(); API void texture_destroy(texture_t *t); // textureLod(filename, dir, lod); // void texture_add_loader( int(*loader)(const char *filename, int *w, int *h, int *bpp, int reqbpp, int flags) ); API unsigned texture_update(texture_t *t, unsigned w, unsigned h, unsigned n, const void *pixels, int flags); API bool texture_rec_begin(texture_t *t, unsigned w, unsigned h); // texture_rec API void texture_rec_end(texture_t *t); // texture_rec // ----------------------------------------------------------------------------- // brdf API texture_t brdf_lut(); // ----------------------------------------------------------------------------- // pbr materials typedef struct colormap_t { vec4 color; texture_t *texture; } colormap_t; API bool colormap( colormap_t *cm, const char *pbr_material_type, bool load_as_srgb ); typedef struct pbr_material_t { char* name; colormap_t diffuse; colormap_t normals; colormap_t specular; colormap_t albedo; colormap_t roughness; colormap_t metallic; colormap_t ao; colormap_t ambient; colormap_t emissive; float specular_shininess; } pbr_material_t; API bool pbr_material(pbr_material_t *pbr, const char *material); API void pbr_material_destroy(pbr_material_t *m); // ----------------------------------------------------------------------------- // fullscreen quads API void fullscreen_quad_rgb( texture_t texture_rgb, float gamma ); API void fullscreen_quad_rgb_flipped( texture_t texture, float gamma ); API void fullscreen_quad_ycbcr( texture_t texture_YCbCr[3], float gamma ); API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3], float gamma ); // ----------------------------------------------------------------------------- // sprites // texture id, position(x,y,depth sort), tint color, rotation angle API void sprite( texture_t texture, float position[3], float rotation /*0*/, uint32_t color /*~0u*/); // texture id, rect(x,y,w,h) is [0..1] normalized, z-index, pos(xy,scale), rotation (degrees), color (rgba) API void sprite_rect( texture_t t, vec4 rect, float zindex, vec3 pos, float tilt_deg, unsigned tint_rgba); // texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant); API void sprite_flush(); // ----------------------------------------------------------------------------- // tilemaps typedef struct tileset_t { texture_t tex; // spritesheet unsigned tile_w, tile_h; // dimensions per tile in pixels unsigned cols, rows; // tileset num_cols, num_rows unsigned selected; // active tile (while editing) } tileset_t; API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows); API int tileset_ui( tileset_t t ); typedef struct tilemap_t { int blank_chr; // transparent tile unsigned cols, rows; // map dimensions (in tiles) array(int) map; vec3 position; // x,y,scale float zindex; float tilt; unsigned tint; bool is_additive; } tilemap_t; API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr); API void tilemap_render( tilemap_t m, tileset_t style ); API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ); // ----------------------------------------------------------------------------- // tiled maps typedef struct tiled_t { char *map_name; unsigned first_gid, tilew, tileh, w, h; bool parallax; vec3 position; array(bool) visible; array(tilemap_t) layers; array(tileset_t) sets; array(char*) names; } tiled_t; API tiled_t tiled(const char *file_tmx); API void tiled_render(tiled_t tmx, vec3 pos); API void tiled_ui(tiled_t *t); // ----------------------------------------------------------------------------- // spines typedef struct spine_t spine_t; API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags); API void spine_skin(spine_t *p, unsigned skin); API void spine_render(spine_t *p, vec3 offset, unsigned flags); API void spine_animate(spine_t *p, float delta); API void spine_ui(spine_t *p); // ----------------------------------------------------------------------------- // cubemaps typedef struct cubemap_t { unsigned id; // texture id vec3 sh[9]; // precomputed spherical harmonics coefficients } cubemap_t; API cubemap_t cubemap( const image_t image, int flags ); // 1 equirectangular panorama API cubemap_t cubemap6( const image_t images[6], int flags ); // 6 cubemap faces API void cubemap_destroy(cubemap_t *c); API cubemap_t* cubemap_get_active(); // ----------------------------------------------------------------------------- // fbos API unsigned fbo( unsigned texture_color, unsigned texture_depth, int wr_flags ); API void fbo_bind(unsigned id); API void fbo_unbind(); API void fbo_destroy(unsigned id); // ----------------------------------------------------------------------------- // shadowmaps // #ifndef VSMCUBE // #define VSMCUBE 0 // #endif // #ifndef VSMBLUR // #define VSMBLUR 1 // #endif typedef struct shadowmap_t { mat44 shadowmatrix; mat44 mvp; mat44 mv; mat44 proj; vec4 light_position; int saved_fb; int saved_viewport[4]; handle fbo, texture; int texture_width; } shadowmap_t; API shadowmap_t shadowmap(int texture_width); // = 1024 API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection); API void shadowmap_begin(shadowmap_t *s); API void shadowmap_end(shadowmap_t *s); // shadowmap utils API void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar); API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar); // ----------------------------------------------------------------------------- // shaders API unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_bind(unsigned program); API void shader_bool(const char *uniform, bool i ); API void shader_int(const char *uniform, int i); API void shader_uint(const char *uniform, unsigned i ); API void shader_float(const char *uniform, float f); API void shader_vec2(const char *uniform, vec2 v); API void shader_vec3(const char *uniform, vec3 v); API void shader_vec3v(const char *uniform, int count, vec3 *v); API void shader_vec4(const char *uniform, vec4 v); API void shader_mat44(const char *uniform, mat44 m); API void shader_texture(const char *sampler, texture_t texture); API void shader_texture_unit(const char *sampler, unsigned texture, unsigned unit); API void shader_colormap(const char *name, colormap_t cm); API unsigned shader_get_active(); API void shader_destroy(unsigned shader); // reflection. [0..N] are shader properties API unsigned shader_properties(unsigned shader); API char** shader_property(unsigned shader, unsigned property_no); API void shader_apply_param(unsigned shader, unsigned param_no); API void shader_apply_params(unsigned shader, const char *parameter_mask); API int ui_shader(unsigned shader); API int ui_shaders(); // compute shaders enum BUFFER_MODE { BUFFER_READ, BUFFER_WRITE, BUFFER_READ_WRITE }; /// Loads the compute shader and compiles a GL program. /// return: GL program, 0 if failed. /// cs: shader source code API unsigned compute(const char *cs); /// Runs the compute program with provided global workgroup size on x y z grid. /// wx: global workgroup size x /// wy: global workgroup size y /// wz: global workgroup size z API void compute_dispatch(unsigned wx, unsigned wy, unsigned wz); /// Binds a texture to the program /// !!! Set `layer` to -1 to disable layered access. /// t: texture to bind /// unit: texture unit bind index /// level: texture level access (MIP0, MIP1, ...) /// layer: bind layer /// access: texture access policy /// see: BUFFER_MODE API void shader_image(texture_t t, unsigned unit, unsigned level, int layer, unsigned access); /// Binds a texture to the program /// !!! Set `layer` to -1 to disable layered access. /// texture: GL texture handle /// unit: texture unit bind index /// level: texture level access (MIP0, MIP1, ...) /// layer: bind layer /// texel_type: image texel format (RGBA8, RGBA32F, ...) /// access: texture access policy /// see: BUFFER_MODE API void shader_image_unit(unsigned texture, unsigned unit, unsigned level, int layer, unsigned texel_type, unsigned access); // gpu memory barriers /// Blocks main thread until all memory operations are done by the GPU. API void write_barrier(); /// Blocks main thread until all image operations are done by the GPU. API void write_barrier_image(); // ssbo /// `STATIC`, `DYNAMIC` AND `STREAM` specify the frequency at which we intend to access the data. /// `DRAW` favors CPU->GPU operations. /// `READ` favors GPU->CPU operations. /// `COPY` favors CPU->GPU->CPU operations. enum SSBO_USAGE { STATIC_DRAW, STATIC_READ, STATIC_COPY, DYNAMIC_DRAW, DYNAMIC_READ, DYNAMIC_COPY, STREAM_DRAW, STREAM_READ, STREAM_COPY }; enum SSBO_ACCESS { SSBO_READ = BUFFER_READ, SSBO_WRITE = BUFFER_WRITE, SSBO_READ_WRITE = BUFFER_READ_WRITE }; /// Create Shader Storage Buffer Object /// !!! `data` can be NULL /// data: optional pointer to data to upload /// len: buffer size, must not be 0 /// usage: buffer usage policy /// see: SSBO_USAGE API unsigned ssbo_create(const void *data, int len, unsigned usage); /// Destroys an SSBO resource API void ssbo_destroy(unsigned ssbo); /// Updates an existing SSBO /// !!! `len` can not exceed the original buffer size specified in `ssbo_create` ! /// offset: offset to buffer memory /// len: amount of data to write /// data: pointer to data we aim to write, can not be NULL API void ssbo_update(int offset, int len, const void *data); /// Bind an SSBO resource to the provided bind unit index /// ssbo: resource object /// unit: bind unit index API void ssbo_bind(unsigned ssbo, unsigned unit); /// Map an SSBO resource to the system memory /// !!! Make sure to `ssbo_unmap` the buffer once done working with it. /// access: buffer access policy /// return: pointer to physical memory of the buffer /// see: SSBO_ACCESS API void *ssbo_map(unsigned access); /// Unmaps an SSBO resource /// !!! Pointer provided by `ssbo_map` becomes invalid. API void ssbo_unmap(); /// Unbinds an SSBO resource API void ssbo_unbind(); // ----------------------------------------------------------------------------- // meshes (@fixme: deprecate?) enum MESH_FLAGS { MESH_STATIC = 0, // STATIC, DYNAMIC, STREAM // zero|single|many updates per frame MESH_STREAM = 1, MESH_TRIANGLE_STRIP = 2, }; typedef struct mesh_t { handle vao, vbo, ibo; unsigned vertex_count; unsigned index_count; unsigned flags; array(int) lod_collapse_map; // to which neighbor each vertex collapses. ie, [10] -> 7 (used by LODs) @leak // @leaks: following members are totally unused. convenient for end-users to keep their custom datas somewhere while processing. union { array(unsigned) in_index; array(vec3i) in_index3; }; union { array(unsigned) out_index; array(vec3i) out_index3; }; union { array(float) in_vertex; array(vec3) in_vertex3; }; union { array(float) out_vertex; array(vec3) out_vertex3; }; } mesh_t; API mesh_t mesh(); API void mesh_update(mesh_t *m, const char *format, int vertex_stride,int vertex_count,const void *interleaved_vertex_data, int index_count,const void *index_data, int flags); API void mesh_render(mesh_t *m); API void mesh_render_prim(mesh_t *sm, unsigned prim); API void mesh_destroy(mesh_t *m); API aabb mesh_bounds(mesh_t *m); // ----------------------------------------------------------------------------- // materials enum MATERIAL_ENUMS { MAX_CHANNELS_PER_MATERIAL = 8 }; typedef struct material_t { char *name; int count; struct material_layer_t { char texname[32]; handle texture; float value; vec4 color; // uint32_t } layer[MAX_CHANNELS_PER_MATERIAL]; } material_t; // ----------------------------------------------------------------------------- // shadertoys enum { SHADERTOY_FLIP_Y = 2, SHADERTOY_IGNORE_FBO = 4, SHADERTOY_IGNORE_MOUSE = 8, }; typedef struct shadertoy_t { handle vao, program; int uniforms[32]; int texture_channels[4]; int frame; uint64_t t; texture_t tx; vec2i dims; int flags; vec4 mouse; } shadertoy_t; API shadertoy_t shadertoy( const char *shaderfile, unsigned flags ); API shadertoy_t* shadertoy_render( shadertoy_t *s, float delta ); // ----------------------------------------------------------------------------- // anims enum ANIM_FLAGS { ANIM_LOOP = 1, ANIM_DONT_RESET_AFTER_USE = 2, }; typedef struct anim_t { int from; int to; float blendtime; unsigned flags; float curframe; unsigned easing; float alpha; // refreshed at every tick float timer; // private bool active; vec3 pose; // private char* name; // debug } anim_t; API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags); //API array(anim_t) animlist(const char *filename); // @todo // ----------------------------------------------------------------------------- // models enum MODEL_FLAGS { MODEL_NO_ANIMATIONS = 1, MODEL_NO_MESHES = 2, MODEL_NO_TEXTURES = 4, MODEL_MATCAPS = 8, MODEL_RIMLIGHT = 16 }; //@todo: make this data-driven // enum SHADING_MODE { // SHADING_NONE, // SHADING_PHONG, // SHADING_CARTOON, // // SHADING_PBR, // }; typedef struct model_t { struct iqm_t *iqm; // private unsigned num_textures; handle *textures; char **texture_names; array(material_t) materials; unsigned num_meshes; unsigned num_triangles; unsigned num_joints; // num_poses; unsigned num_anims; unsigned num_frames; handle program; float curframe; mat44 pivot; int stride; // usually 60 bytes (12*4+4*3) for a p3 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; handle vao, ibo, vbo, vao_instanced; unsigned flags; unsigned billboard; float *instanced_matrices; unsigned num_instances; } model_t; API model_t model(const char *filename, int flags); API model_t model_from_mem(const void *mem, int sz, int flags); API float model_animate(model_t, float curframe); API float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop); API float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta); API aabb model_aabb(model_t, mat44 transform); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render_skeleton(model_t, mat44 model); API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count); API void model_set_texture(model_t, texture_t t); API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out); API void model_destroy(model_t); API vec3 pose(bool forward, float curframe, int minframe, int maxframe, bool loop, float *opt_retframe); // ----------------------------------------------------------------------------- // model animations typedef struct anims_t { int inuse; // animation number in use float speed; // x1.00 array(anim_t) anims; // [begin,end,flags] frames of every animation in set } anims_t; API anims_t animations(const char *pathfile, int flags); // ----------------------------------------------------------------------------- // skyboxes typedef struct skybox_t { handle program; mesh_t geometry; cubemap_t cubemap; int flags; // mie int framebuffers[6]; int textures[6]; float *pixels; } skybox_t; API skybox_t skybox(const char *panorama_or_cubemap_folder, int flags); API int skybox_render(skybox_t *sky, mat44 proj, mat44 view); API void skybox_destroy(skybox_t *sky); API void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity); API void skybox_sh_reset(skybox_t *sky); API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate API int skybox_pop_state(); // @to deprecate // ----------------------------------------------------------------------------- // post-fxs API void viewport_clear(bool color, bool depth); API void viewport_clip(vec2 from, vec2 to); API int fx_load(const char *file); API int fx_load_from_mem(const char *nameid, const char *content); API void fx_begin(); API void fx_begin_res(int w, int h); API void fx_end(); API void fx_enable(int pass, int enabled); API int fx_enabled(int pass); API void fx_enable_all(int enabled); API char * fx_name(int pass); API int fx_find(const char *name); API int ui_fx(int pass); API int ui_fxs(); // ----------------------------------------------------------------------------- // utils API void* screenshot(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA API void* screenshot_async(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA #line 0 #line 1 "engine/split/v4k_renderdd.h" // ----------------------------------------------------------------------------- // debugdraw framework // - rlyeh, public domain. // // Credits: Based on work by @glampert https://github.com/glampert/debug-draw (PD) // [x] grid, axis, frustum, cube, sphere, triangle, square, pentagon, hexagon, circle, normal. // [x] arrow, point, text, capsule, aabb, plane, flotilla-style locator, boid, bone, ring // [x] line batching // [*] line width and stipple // [*] (proper) gizmo, // [ ] camera, light bulb, light probe, API void ddraw_color(unsigned rgb); API void ddraw_color_push(unsigned rgb); API void ddraw_color_pop(); // API void ddraw_ontop(int enabled); API void ddraw_ontop_push(int enabled); API void ddraw_ontop_pop(); // API void ddraw_push_2d(); API void ddraw_pop_2d(); // API void ddraw_aabb(vec3 minbb, vec3 maxbb); API void ddraw_aabb_corners(vec3 minbb, vec3 maxbb); API void ddraw_arrow(vec3 begin, vec3 end); API void ddraw_axis(float units); API void ddraw_boid(vec3 pos, vec3 dir); API void ddraw_bone(vec3 center, vec3 end); // @todo: use me API void ddraw_bounds(const vec3 points[8]); API void ddraw_box(vec3 center, vec3 extents); API void ddraw_capsule(vec3 from, vec3 to, float radius); API void ddraw_circle(vec3 pos, vec3 n, float radius); API void ddraw_ring(vec3 pos, vec3 n, float radius); API void ddraw_cone(vec3 center, vec3 top, float radius); API void ddraw_cube(vec3 center, float radius); API void ddraw_cube33(vec3 center, vec3 radius, mat33 M); API void ddraw_diamond(vec3 from, vec3 to, float size); API void ddraw_frustum(float projview[16]); API void ddraw_ground(float scale); API void ddraw_grid(float scale); API void ddraw_hexagon(vec3 pos, float radius); API void ddraw_line(vec3 from, vec3 to); API void ddraw_line_dashed(vec3 from, vec3 to); API void ddraw_line_thin(vec3 from, vec3 to); API void ddraw_normal(vec3 pos, vec3 n); API void ddraw_pentagon(vec3 pos, float radius); API void ddraw_plane(vec3 p, vec3 n, float scale); API void ddraw_point(vec3 from); API void ddraw_position(vec3 pos, float radius); API void ddraw_position_dir(vec3 pos, vec3 dir, float radius); API void ddraw_pyramid(vec3 center, float height, int segments); API void ddraw_cylinder(vec3 center, float height, int segments); API void ddraw_sphere(vec3 pos, float radius); API void ddraw_square(vec3 pos, float radius); API void ddraw_text(vec3 pos, float scale, const char *text); API void ddraw_text2d(vec2 pos, const char *text); API void ddraw_triangle(vec3 p1, vec3 p2, vec3 p3); // API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int segments); // API void ddraw_demo(); API void ddraw_flush(); API void ddraw_flush_projview(mat44 proj, mat44 view); #line 0 #line 1 "engine/split/v4k_scene.h" // ----------------------------------------------------------------------------- // scene framework // - rlyeh, public domain // camera typedef struct camera_t { mat44 view, proj; vec3 position, updir, lookdir; float yaw, pitch; // mirror of (x,y) lookdir in deg; float speed, fov; // fov in deg(45) float move_friction, move_damping; float look_friction, look_damping; vec2 last_look; vec3 last_move; // used for friction and damping bool damping; } camera_t; API camera_t camera(); API void camera_teleport(camera_t *cam, vec3 pos); API void camera_moveby(camera_t *cam, vec3 inc); API void camera_fov(camera_t *cam, float fov); API void camera_fps(camera_t *cam, float yaw, float pitch); API void camera_orbit(camera_t *cam, float yaw, float pitch, float inc_distance); API void camera_lookat(camera_t *cam, vec3 target); API void camera_enable(camera_t *cam); API camera_t *camera_get_active(); API int ui_camera(camera_t *cam); API void ddraw_camera(camera_t *cam); // object typedef struct object_t { uint64_t renderbucket; mat44 transform; quat rot; vec3 sca, pos, euler, pivot; array(handle) textures; model_t model; aabb bounds; unsigned billboard; // [0..7] x(4),y(2),z(1) masks bool light_cached; //< used by scene to update light data } object_t; API object_t object(); API void object_rotate(object_t *obj, vec3 euler); API void object_pivot(object_t *obj, vec3 euler); API void object_teleport(object_t *obj, vec3 pos); API void object_move(object_t *obj, vec3 inc); API vec3 object_position(object_t *obj); API void object_scale(object_t *obj, vec3 sca); // API void object_model(object_t *obj, model_t model); API void object_diffuse(object_t *obj, texture_t tex); API void object_diffuse_push(object_t *obj, texture_t tex); API void object_diffuse_pop(object_t *obj); API void object_billboard(object_t *obj, unsigned mode); // object_pose(transform); // @todo // light enum LIGHT_TYPE { LIGHT_DIRECTIONAL, LIGHT_POINT, LIGHT_SPOT, }; enum LIGHT_FLAGS { LIGHT_CAST_SHADOWS = 1, }; typedef struct light_t { char type; vec3 diffuse, specular, ambient; vec3 pos, dir; struct { float constant, linear, quadratic; } falloff; float specularPower; float innerCone, outerCone; //@todo: cookie, flare // internals bool cached; //< used by scene to invalidate cached light data } light_t; API light_t light(); // API void light_flags(int flags); API void light_type(light_t* l, char type); API void light_diffuse(light_t* l, vec3 color); API void light_specular(light_t* l, vec3 color); API void light_ambient(light_t* l, vec3 color); API void light_teleport(light_t* l, vec3 pos); API void light_dir(light_t* l, vec3 dir); API void light_power(light_t* l, float power); API void light_falloff(light_t* l, float constant, float linear, float quadratic); API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); // scene enum SCENE_FLAGS { SCENE_WIREFRAME = 1, SCENE_CULLFACE = 2, SCENE_BACKGROUND = 4, SCENE_FOREGROUND = 8, SCENE_UPDATE_SH_COEF = 16, }; typedef struct scene_t { array(object_t) objs; array(light_t) lights; // special objects below: skybox_t skybox; int u_coefficients_sh; } scene_t; API scene_t* scene_push(); API void scene_pop(); API scene_t* scene_get_active(); API int scene_merge(const char *source); API void scene_render(int flags); API object_t* scene_spawn(); API unsigned scene_count(); API object_t* scene_index(unsigned index); API light_t* scene_spawn_light(); API unsigned scene_count_light(); API light_t* scene_index_light(unsigned index); #line 0 #line 1 "engine/split/v4k_script.h" // ----------------------------------------------------------------------------- // script framework // - rlyeh, public domain API void script_init(); API void script_run(const char *script); API void script_runfile(const char *pathfile); API void script_bind_class(const char *objname, int num_methods, const char **c_names, void **c_functions); API void script_bind_function(const char *c_name, void *c_function); API void script_call(const char *lua_function); API bool script_tests(); #line 0 #line 1 "engine/split/v4k_string.h" // string framework // - rlyeh, public domain // string: temporary api (stack) API char* tempvl(const char *fmt, va_list); API char* tempva(const char *fmt, ...); #define va(...) (((&printf) || printf(__VA_ARGS__), tempva(__VA_ARGS__))) // vs2015 check trick // string: allocated api (heap). FREE() after use API char* strcatf(char **s, const char *buf); #define strcatf(s,fmt,...) strcatf((s), va(fmt, __VA_ARGS__)) #define stringf(fmt,...) STRDUP(va(fmt, __VA_ARGS__)) // (strcatf)(0, va(fmt, __VA_ARGS__)) #if is(cl) || (is(tcc) && is(win32)) #if!is(cl) char* strtok_s(char* str,const char* delimiters,char** context); // tcc misses this in #endif #define strtok_r strtok_s #endif #if 1 #define each_substring(str, delims, keyname) \ ( char *str_ = (char*)(str); str_; str_ = 0 ) \ for( int len_ = strlen(str_) + 1, heap_ = len_ < 1024; len_ > 1; len_ = 0 ) \ for( char *ptr_ = (heap_ ? REALLOC(0, len_) : ALLOCA(len_)), *cpy_ = (snprintf(ptr_, len_, "%s", str_), ptr_); ptr_; (heap_ ? REALLOC(ptr_, 0) : 0), ptr_ = 0 ) \ for( char *next_token = 0, *keyname = strtok_r(cpy_, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) ) #else #define each_substring(str, delims, keyname) \ ( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \ for( int i_ = 0, end_ = array_count(tokens_); i_ < (keyname = tokens_[i_], end_); ++i_ ) #endif // utils API int strmatch(const char *s, const char *wildcard); API int strmatchi(const char *s, const char *wildcard); API int strcmp_qsort(const void *a, const void *b); API int strcmpi_qsort(const void *a, const void *b); API bool strbeg(const char *src, const char *sub); // returns true if both strings match at beginning. case sensitive API bool strend(const char *src, const char *sub); // returns true if both strings match at end. case sensitive API bool strbegi(const char *src, const char *sub); // returns true if both strings match at beginning. case insensitive API bool strendi(const char *src, const char *sub); // returns true if both strings match at end. case insensitive API const char * strstri(const char *src, const char *sub); // returns find first substring in string. case insensitive. #define strcmpi ifdef(cl, _stricmp, strcasecmp) API char * strupper(const char *str); API char * strlower(const char *str); API char * strrepl(char **copy, const char *target, const char *replace); // replace any 'target' as 'repl' in 'copy'. 'copy' may change (heap). returns 'copy' API char * strswap(char *copy, const char *target, const char *replace); // replaced inline only if repl is shorter than target. no allocations. API char * strcut(char *copy, const char *target); // remove any 'target' in 'copy'. returns 'copy' API const char * strlerp(unsigned numpairs, const char **pairs, const char *str); // using key-value pairs, null-terminated #ifndef __APPLE__ // BSD provides these API size_t strlcat(char *dst, const char *src, size_t dstcap); // concat 2 strings safely. always NUL terminates. may truncate. API size_t strlcpy(char *dst, const char *src, size_t dstcap); // copy 2 strings safely. always NUL terminates. truncates if retval>=dstcap #endif /// split `string` after any of `delimiters` character is found. /// returns temporary array of split strings. see: strjoin /// > array(char*) tokens = strsplit("hello! world!", " !"); // [0]="hello",[1]="world", API array(char*) strsplit(const char *string, const char *delimiters); /// concatenate all elements within `list`, with `separator` string in between. /// returns: temporary joint string. see: strsplit /// > array(char*) tokens = strsplit("hello! world!", " !"); // [0]="hello",[1]="world", /// > char *joint = strjoin(tokens, "+"); // joint="hello+world" API char* strjoin(array(char*) list, const char *separator); API char * string8(const wchar_t *str); /// convert from wchar16(win) to utf8/ascii API array(uint32_t) string32( const char *utf8 ); /// convert from utf8 to utf32 // ----------------------------------------------------------------------------- // ## string interning (quarks) // - rlyeh, public domain. API unsigned intern( const char *string ); API const char *quark( unsigned key ); typedef struct quarks_db { array(char) blob; array(vec2i) entries; } quarks_db; API unsigned quark_intern( quarks_db*, const char *string ); API const char *quark_string( quarks_db*, unsigned key ); #line 0 #line 1 "engine/split/v4k_time.h" // ----------------------------------------------------------------------------- // time framework utils // - rlyeh, public domain. API uint64_t date(); // YYYYMMDDhhmmss API uint64_t date_epoch(); // linux epoch API char* date_string(); // "YYYY-MM-DD hh:mm:ss" API double time_hh(); API double time_mm(); API double time_ss(); API uint64_t time_ms(); API uint64_t time_us(); API uint64_t time_ns(); API void sleep_ss(double ss); API void sleep_ms(double ms); API void sleep_us(double us); API void sleep_ns(double us); API unsigned timer(unsigned ms, unsigned (*callback)(unsigned ms, void *arg), void *arg); API void timer_destroy(unsigned timer_handle); // time sortable unique identifier (similar to ksuid/tuid; others: sno/xid/cuid/ulid) // - rlyeh, public domain. // // also similar to a mongo object id, 12 bytes as follows: // - 4-byte timestamp (ss). epoch: Tuesday, 12 September 2023 6:06:56 // - 2-byte (machine, hash or app id) // - 2-byte (thread-id) // - 4-byte (rand counter, that gets increased at every id creation) typedef vec3i guid; API guid guid_create(); /* AUTORUN { guid g1 = guid_create(); guid g2 = guid_create(); print3i(g1); hexdump(&g1, sizeof(g1)); print3i(g2); hexdump(&g2, sizeof(g2)); } */ #line 0 #line 1 "engine/split/v4k_system.h" // ----------------------------------------------------------------------------- // system framework utils // - rlyeh, public domain. // // Note: Windows users add `/Zi` compilation flags, else add `-g` and/or `-ldl` flags // Note: If you are linking your binary using GNU ld you need to add --export-dynamic API void* thread( int (*thread_func)(void* user_data), void* user_data ); API void thread_destroy( void *thd ); API int argc(); API char* argv(int); API int flag(const char *commalist); // --arg // app_flag? API const char* option(const char *commalist, const char *defaults); // --arg=string or --arg string API int optioni(const char *commalist, int defaults); // --arg=integer or --arg integer // argvi() ? API float optionf(const char *commalist, float defaults); // --arg=float or --arg float // flagf() ? API void tty_attach(); API void tty_detach(); API void tty_color(unsigned color); API void tty_reset(); API const char* app_exec(const char *command); // returns ("%15d %s", retcode, output_last_line) API int app_spawn(const char *command); API int app_cores(); API int app_battery(); /// returns battery level [1..100]. also positive if charging (+), negative if discharging (-), and 0 if no battery is present. API const char* app_name(); API const char* app_path(); API const char* app_cache(); API const char* app_temp(); API const char* app_cmdline(); API void app_beep(); API void app_hang(); API void app_crash(); API void app_singleton(const char *guid); API bool app_open(const char *folder_file_or_url); API const char* app_loadfile(); API const char* app_savefile(); API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free(). API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order. API void die(const char *message); API void alert(const char *message); API void hexdump( const void *ptr, unsigned len ); API void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width ); API void breakpoint(); API bool has_debugger(); API void trap_install(void); API const char *trap_name(int signal); // helper util API void trap_on_ignore(int signal); // helper util API void trap_on_quit(int signal); // helper util API void trap_on_abort(int signal); // helper util API void trap_on_debug(int signal); // helper util #define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ? API int (PANIC)(const char *error, const char *file, int line); #define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__) API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function); #define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr)) API int (test)(const char *file, int line, const char *expr, bool result); #if ENABLE_AUTOTESTS #define AUTOTEST AUTORUN #else #define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)() #endif // AUTOTEST { test(1<2); } #if ENABLE_RETAIL #undef PRINTF #define PRINTF(...) 0 #undef test #define test(expr) 0 #endif #line 0 #line 1 "engine/split/v4k_ui.h" // ----------------------------------------------------------------------------- // immediate ui framework // - rlyeh, public domain // // @todo: logger/console // @todo: surround-adaptive window resizing. ie, surrounding windows adapting theirselves to fit dragged active window enum PANEL_FLAGS { PANEL_OPEN = 1, }; API int ui_notify(const char *title, const char *body); API int ui_window(const char *title, int *enabled); API int ui_panel(const char *title, int flags); // may be embedded inside a window, or standalone API int ui_collapse(const char *label, const char *id); API int ui_contextual(); API int ui_section(const char *title); API int ui_int(const char *label, int *value); API int ui_bool(const char *label, bool *value); API int ui_short(const char *label, short *value); API int ui_float(const char *label, float *value); API int ui_float2(const char *label, float value[2]); API int ui_float3(const char *label, float value[3]); API int ui_float4(const char *label, float value[4]); API int ui_mat33(const char *label, float mat33[9]); API int ui_mat34(const char *label, float mat34[12]); API int ui_mat44(const char *label, float mat44[16]); API int ui_double(const char *label, double *value); API int ui_buffer(const char *label, char *buffer, int buflen); API int ui_string(const char *label, char **string); API int ui_color3(const char *label, float *color3); //[0..255] API int ui_color3f(const char *label, float *color3); //[0..1] API int ui_color4(const char *label, float *color4); //[0..255] API int ui_color4f(const char *label, float *color4); //[0..1] API int ui_unsigned(const char *label, unsigned *value); API int ui_button(const char *label); API int ui_button_transparent(const char *label); API int ui_buttons(int buttons, /*labels*/...); API int ui_toolbar(const char *options); // int choice = ui_toolbar("A;B;C;D"); API int ui_submenu(const char *options); // int choice = ui_submenu("A;B;C;D"); API int ui_browse(const char **outfile, bool *inlined); // may be embedded inside a window or inside a panel API int ui_toggle(const char *label, bool *value); API int ui_dialog(const char *title, const char *text, int choices, bool *show); // @fixme: return API int ui_list(const char *label, const char **items, int num_items, int *selector); API int ui_radio(const char *label, const char **items, int num_items, int *selector); API int ui_texture(const char *label, texture_t t); API int ui_subtexture(const char *label, texture_t t, unsigned x, unsigned y, unsigned w, unsigned h); API int ui_image(const char *label, handle id, unsigned w, unsigned h); //(w,h) can be 0 API int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh); API int ui_colormap(const char *label, colormap_t *cm); // returns num member changed: 1 for color, 2 for texture map API int ui_separator(); API int ui_bitmask8(const char *label, uint8_t *bits); API int ui_bitmask16(const char *label, uint16_t *bits); API int ui_console(); API int ui_clampf(const char *label, float *value, float minf, float maxf); API int ui_label(const char *label); API int ui_label2(const char *label, const char *caption); API int ui_label2_bool(const char *label, bool enabled); API int ui_label2_float(const char *label, float value); API int ui_label2_toolbar(const char *label, const char *icons); API int ui_slider(const char *label, float *value); API int ui_slider2(const char *label, float *value, const char *caption); API int ui_contextual_end(int close); API int ui_collapse_clicked(); API int ui_collapse_end(); API int ui_panel_end(); API int ui_window_end(); API int ui_show(const char *panel_or_window_title, int enabled); API int ui_dims(const char *panel_or_window_title, float width, float height); API int ui_visible(const char *panel_or_window_title); // @todo: include ui_collapse() items that are open as well? API vec2 ui_get_dims(); API int ui_enable(); API int ui_enabled(); API int ui_disable(); API int ui_has_menubar(); API int ui_menu(const char *items); // semicolon-separated or comma-separated items API int ui_menu_editbox(char *buf, int bufcap); API int ui_item(); API int ui_popups(); // ui_any_popup()? ui_has_popups()? API int ui_hover(); // ui_is_hover()? API int ui_active(); // ui_is_active()? API int ui_demo(int do_windows); #line 0 #line 1 "engine/split/v4k_video.h" // ----------------------------------------------------------------------------- // video decoder (mpeg) // - rlyeh, public domain // // [ref] https://github.com/phoboslab/pl_mpeg/blob/master/pl_mpeg_player.c // [use] ffmpeg -i infile.mp4 -c:v mpeg1video -c:a mp2 -format mpeg outfile.mpg enum VIDEO_FLAGS { VIDEO_YCBCR = 0, VIDEO_RGB = 2, VIDEO_AUDIO = 0, VIDEO_NO_AUDIO = 4, VIDEO_LOOP = 8, }; typedef struct video_t video_t; API video_t* video( const char *filename, int flags ); API texture_t* video_decode( video_t *v ); // decodes next frame, returns associated texture(s) API texture_t* video_textures( video_t *v ); // returns last video textures. does not perform any decoding. API int video_has_finished(video_t *v); API double video_duration(video_t *v); API int video_seek(video_t *v, double seek_to); API double video_position(video_t *v); API void video_pause(video_t *v, bool paused); API bool video_is_paused(video_t *v); API bool video_is_rgb(video_t *v); API void video_destroy( video_t *v ); // ----------------------------------------------------------------------------- // video recorder (uses external ffmpeg and fallbacks to built-in mpeg1 encoder) // - rlyeh, public domain // // @fixme: MSAA can cause some artifacts with Intel PBOs: either use glDisable(GL_MULTISAMPLE) before recording or do not create window with WINDOW_MSAA at all. API bool record_start(const char *outfile_mp4); API bool record_active(); API void record_stop(void); #line 0 #line 1 "engine/split/v4k_window.h" // ----------------------------------------------------------------------------- // window framework // - rlyeh, public domain // // @todo: window_cursor(ico); // @todo: if WINDOW_PORTRAIT && exist portrait monitor, use that instead of primary one // @todo: WINDOW_TRAY enum WINDOW_FLAGS { WINDOW_MSAA2 = 0x02, WINDOW_MSAA4 = 0x04, WINDOW_MSAA8 = 0x08, WINDOW_SQUARE = 0x20, WINDOW_PORTRAIT = 0x40, WINDOW_LANDSCAPE = 0x80, WINDOW_ASPECT = 0x100, // keep aspect WINDOW_FIXED = 0x200, // disable resizing WINDOW_TRANSPARENT = 0x400, WINDOW_VSYNC = 0, WINDOW_VSYNC_ADAPTIVE = 0x1000, WINDOW_VSYNC_DISABLED = 0x2000, }; API bool window_create(float scale, unsigned flags); API bool window_create_from_handle(void *handle, float scale, unsigned flags); API void window_reload(); API int window_frame_begin(); API void window_frame_end(); API void window_frame_swap(); API int window_swap(); // single function that combines above functions (desktop only) API void window_loop(void (*function)(void* loopArg), void* loopArg ); // run main loop function continuously (emscripten only) API void window_loop_exit(); // exit from main loop function (emscripten only) API void window_title(const char *title); API void window_color(unsigned color); API vec2 window_canvas(); API void* window_handle(); API char* window_stats(); API uint64_t window_frame(); API int window_width(); API int window_height(); API double window_time(); API double window_delta(); // API bool window_hook(void (*func)(), void* userdata); // deprecated // API void window_unhook(void (*func)()); // deprecated API void window_focus(); // window attribute api using haz catz language for now API int window_has_focus(); API void window_fullscreen(int enabled); API int window_has_fullscreen(); API void window_cursor(int visible); API int window_has_cursor(); API void window_pause(int paused); API int window_has_pause(); API void window_visible(int visible); API int window_has_visible(); API void window_maximize(int enabled); API int window_has_maximize(); API void window_transparent(int enabled); API int window_has_transparent(); API void window_icon(const char *file_icon); API int window_has_icon(); API double window_aspect(); API void window_aspect_lock(unsigned numer, unsigned denom); API void window_aspect_unlock(); API double window_fps(); API double window_fps_target(); API void window_fps_lock(float fps); API void window_fps_unlock(); API void window_screenshot(const char* outfile_png); // , bool record_cursor API int window_record(const char *outfile_mp4); // , bool record_cursor API vec2 window_dpi(); enum CURSOR_SHAPES { CURSOR_NONE, CURSOR_HW_ARROW, // default CURSOR_HW_IBEAM, // i-beam text cursor CURSOR_HW_CROSS, // crosshair CURSOR_HW_HAND, // hand, clickable CURSOR_HW_HDRAG, // horizontal drag/resize CURSOR_HW_VDRAG, // vertical drag/resize CURSOR_SW_AUTO, // software cursor, ui driven. note: this is the only icon that may be recorded or snapshotted }; API void window_cursor_shape(unsigned shape); #line 0 // ---- #if is(cpp) } // extern "C" #endif // expose glfw/glad apis #if is(ems) #include #include #include #include #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) #else #if is(win32) /*&& is(tcc)*/ // && WITH_DLL #ifdef GLAD_API_CALL #undef GLAD_API_CALL #endif #define GLAD_API_CALL extern API #endif #ifndef GLAD_GL_H_ #include "v4k" #endif #endif #endif // V4K_H