2023-07-30 19:18:50 +00:00
/* game framework.
* - rlyeh , public domain
*
2023-08-10 14:30:56 +00:00
* # # V4K License
2023-07-30 19:18:50 +00:00
*
* 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
2023-08-10 14:30:56 +00:00
* license terms listed above . I make this dedication for the benefit of the
2023-07-30 19:18:50 +00:00
* 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
2023-09-11 05:30:12 +00:00
* @ zak @ v4 . games YES N / A
2023-07-30 19:18:50 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2023-08-10 14:30:56 +00:00
# ifndef V4K_H
# define V4K_H
2023-07-30 19:18:50 +00:00
# ifdef __cplusplus
extern " C " {
# endif
//-----------------------------------------------------------------------------
// Headers
2023-08-10 14:30:56 +00:00
# line 1 "v4k_config.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
// -----------------------------------------------------------------------------
// 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
# include <stdint.h>
# if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
# define ifdef_64 ifdef_true
# define ifdef_32 ifdef_false
# else
# define ifdef_64 ifdef_false
# define ifdef_32 ifdef_true
# endif
// -----------------------------------------------------------------------------
// new C keywords
// @todo: autorun (needed?)
# define countof(x) (int)(sizeof (x) / sizeof 0[x])
# define concat(a,b) conc4t(a,b)
# define conc4t(a,b) a##b
# define macro(name) concat(name, __LINE__)
# define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1))
# define scope(end) defer((void)0, end)
# define benchmark for(double macro(t) = -time_ss(); macro(t) < 0; printf("%.2fs (" FILELINE ")\n", macro(t)+=time_ss()))
# 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, but does not work apparently
# 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
# define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
# define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
# define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_)
# define FILELINE __FILE__ ":" STRINGIZE(__LINE__)
# define STRINGIZE(x) STRINGIZ3(x)
# define STRINGIZ3(x) #x
# define EXPAND(name, ...) EXPAND_QUOTE(EXPAND_JOIN(name, EXPAND_COUNT_ARGS(__VA_ARGS__)), (__VA_ARGS__))
# define EXPAND_QUOTE(x, y) x y
# define EXPAND_JOIN(name, count) EXPAND_J0IN(name, count)
# define EXPAND_J0IN(name, count) EXPAND_J01N(name, count)
# define EXPAND_J01N(name, count) name##count
# define EXPAND_COUNT_ARGS(...) EXPAND_ARGS((__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
# define EXPAND_ARGS(args) EXPAND_RETURN_COUNT args
# define EXPAND_RETURN_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, count, ...) count
# 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);
# if is(cpp)
# define C_CAST(type, ...) ( type { __VA_ARGS__ } )
# else
# define C_CAST(type, ...) ((type){ __VA_ARGS__ } )
# endif
// -----------------------------------------------------------------------------
// visibility
2023-08-10 14:30:56 +00:00
// win32 users would need to -DAPI=IMPORT/EXPORT as needed when using/building V4K as DLL.
2023-07-30 19:18:50 +00:00
# if is(win32)
# define IMPORT ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport))
# define EXPORT ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport))
# define STATIC
# else
# define IMPORT
# define EXPORT
# define STATIC
# endif
# ifndef API
# define API STATIC
# endif
// -----------------------------------------------------------------------------
// system headers
# ifndef _GNU_SOURCE
# define _GNU_SOURCE // for linux
# endif
# if is(cl) && is(win32) // for VC IDE
# define _CRT_SECURE_NO_WARNINGS
# define _CRT_NONSTDC_NO_DEPRECATE
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# define _WIN32_WINNT 0x0600 // 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
# endif
# if is(cl)
# include <omp.h> // compile with /openmp to speed up some computations
# endif
# include <assert.h>
//#include <float.h>
//#include <limits.h>
# include <math.h> // NAN
# include <stdarg.h> // va_*(), ...
# include <stdbool.h> // bool,true,false
# include <stdint.h> // u/int8/16/32/64_t
# include <stdio.h> // FILE,NULL
# include <stdlib.h> // malloc,free,exit,
# include <string.h> // strlen,memset,memcpy,
# if is(tcc) && is(win32) && defined(__x86_64)
# include <tgmath.h>
// @fixme workarounds on `tcc0.9.27 -m64` (win) for fmod()/trunc() functions. test: 00-easing broken otherwise
//#define trunc(x) ((double)(int64_t)(x))
//#define fmod(x,y) ((x) - trunc((x) / (y)) * (y))
// @fixme workarounds on `tcc0.9.27 -m64` (win) for all functions with ending bool argument. test: 00-anims crashes otherwise
# undef bool
typedef char bool ;
// missing libm symbols on tinycc HEAD repo (tcc-x64 pre-0.9.28)
//#define fabsf fabs
# define sqrtf sqrt
# define sinf sin
# define asinf asin
# define cosf cos
# define acosf acos
# define tanf tan
# define atan2f atan2
# define powf pow
# define floorf floor
# define logf log
# define ceilf ceil
# define copysignf copysign
//#define ldexpf ldexp
# define expf exp
//#define frexpf frexp
# define fmodf fmod
# define log10f log10
//#define logf log
# define hypotf hypot
# endif
// -----------------------------------------------------------------------------
// pragma libs
# if is(win32) && (is(cl) || is(tcc))
# pragma comment(lib, "advapi32")
# pragma comment(lib, "comdlg32")
# pragma comment(lib, "dbghelp")
# pragma comment(lib, "gdi32")
# pragma comment(lib, "ole32")
# pragma comment(lib, "shell32")
# pragma comment(lib, "user32")
# pragma comment(lib, "winmm")
# pragma comment(lib, "ws2_32")
# endif
# if is(linux) && is(tcc)
# pragma comment(lib, "dl")
# pragma comment(lib, "m")
# pragma comment(lib, "pthread")
# endif
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_ds.h"
2023-07-30 19:18:50 +00:00
// 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_str ( const char * str ) ;
API uint64_t hash_int ( int key ) ;
API uint64_t hash_ptr ( const void * ptr ) ;
// -----------------------------------------------------------------------------
// 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 (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(t,val_t,v) \
( int __it = 0 , __end = array_count ( t ) ; __it < __end ; + + __it ) \
for ( val_t v = __it [ t ] , * on__ = & v ; on__ ; on__ = 0 )
# define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v)
# define each_array_ptr(t,val_t,v) \
( int __it = 0 , __end = array_count ( t ) ; __it < __end ; + + __it ) \
for ( val_t * v = ( val_t * ) & __it [ t ] ; 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 { /*todo: review old vrealloc call!*/ \
array_free ( t ) ; \
( t ) = vrealloc ( ( t ) , array_count ( src ) * sizeof ( 0 [ t ] ) ) ; \
memcpy ( ( t ) , src , array_count ( src ) * sizeof ( 0 [ t ] ) ) ; \
} while ( 0 )
# define array_erase(t, i) do { /*may alter ordering*/ \
memcpy ( & ( t ) [ i ] , & ( t ) [ array_count ( t ) - 1 ] , sizeof ( 0 [ t ] ) ) ; \
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<n */ \
memcpy ( tmp , & j [ t ] , sizeof ( 0 [ t ] ) ) ; \
memcpy ( & j [ t ] , & i [ t ] , sizeof ( 0 [ t ] ) ) ; \
memcpy ( & i [ t ] , tmp , sizeof ( 0 [ t ] ) ) ; \
} \
} while ( 0 )
// -----------------------------------------------------------------------------
// set<K>
// 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_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_count ) ( const set * m ) ;
API void ( set_gc ) ( set * m ) ; // only if using SET_DONT_ERASE
API void ( set_clear ) ( set * m ) ;
// -----------------------------------------------------------------------------
// map<K,V>
// 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_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_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 ) ;
// -----------------------------------------------------------------------------
// four-cc, eight-cc
API unsigned cc4 ( const char * id ) ;
API uint64_t cc8 ( const char * id ) ;
API char * cc4str ( unsigned cc ) ;
API char * cc8str ( uint64_t cc ) ;
// fast path
# define cc4(abcd) ( *(unsigned*) #abcd " " ) // lil32() ?
# define cc8(abcdefgh) ( *(uint64_t*) #abcdefgh " " ) // lil64() ?
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_math.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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.141592654f) // (3.14159265358979323846f)
# define TO_RAD (C_PI / 180.f)
# define TO_DEG (180.f / 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 double rng(void); // [0..1) Lehmer RNG "minimal standard"
// ----------------------------------------------------------------------------
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 mode ) ; // 0=linear,1=out_sine...31=inout_perlin
API float ease_ping_pong ( float t , float ( * fn1 ) ( float ) , float ( * fn2 ) ( float ) ) ;
API float ease_pong_ping ( float t , float ( * fn1 ) ( float ) , float ( * fn2 ) ( float ) ) ;
// ----------------------------------------------------------------------------
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 , 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 , 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 , 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 ) ;
// ----------------------------------------------------------------------------
// !!! for debugging
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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_ai.h"
2023-07-30 19:18:50 +00:00
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 ) ;
2023-08-11 19:59:48 +00:00
// pathfinding -----------------------------------------------------------------
API int pathfind_astar ( int width , int height , const unsigned * map , vec2i src , vec2i dst , vec2i * path , size_t maxpath ) ;
2023-07-30 19:18:50 +00:00
# line 0
2023-09-16 12:35:20 +00:00
# line 1 "v4k_bt.h"
// Behavior trees: decision planning and decision making.
// Supersedes finite state-machines (FSM) and hierarchical finite state-machines (HFSM).
// - rlyeh, public domain.
//
// [ref] https://outforafight.wordpress.com/2014/07/15/behaviour-behavior-trees-for-ai-dudes-part-1/
// [ref] https://www.gameaipro.com/GameAIPro/GameAIPro_Chapter06_The_Behavior_Tree_Starter_Kit.pdf
// [ref] https://gitlab.com/NotYetGames/DlgSystem/-/wikis/Dialogue-Manual
// [ref] https://towardsdatascience.com/designing-ai-agents-behaviors-with-behavior-trees-b28aa1c3cf8a
// [ref] https://docs.nvidia.com/isaac/packages/behavior_tree/doc/behavior_trees.html
// [ref] https://docs.unrealengine.com/4.26/en-US/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/
// [ref] gdc ChampandardDaweHernandezCerpa_BehaviorTrees.pdf @todo debugging
// [ref] https://docs.cocos.com/cocos2d-x/manual/en/actions/
#if 0
The nodes in a behavior tree can be broadly categorized into three main types : control nodes , task nodes , and decorator nodes . Here is a brief description of each category :
Control Nodes : Control nodes are used to control the flow of the behavior tree . They determine the order in which child nodes are executed and how the results of those nodes are combined . They are usually parent nodes .
Action Nodes : Action nodes are used to perform specific actions or tasks within the behavior tree . They can include actions such as moving , attacking , or interacting with objects in the game world . They are usually leaf nodes .
Decorator Nodes : Decorator nodes are used to modify the behavior of child nodes in some way . They can be used to repeat child nodes , invert the result of a child node , or add a cooldown period between executions . They are usually located between control and action nodes .
- - - VARIABLES
Key Prefixes :
{ visiblity : ( l ) ocal , s ( q ) uad , ( r ) ace , ( f ) action , ( g ) lobal }
[ persistence : ( t ) emp , ( u ) serdata , ( s ) avegame , ( c ) loud ] + ' _ ' + name .
[ persistence : ( tmp ) , ( usr ) data , ( sav ) egame , ( net ) cloud ] + ' _ ' + name .
Ie , l_health = 123.4 , gsav_player = " john "
- - - ACTION NODES
[ ] * Actions / Behaviors have a common structure :
[ ] - Entry point ( function name ) for a C call or Lua script .
[ ] * Status :
[ ] - Uninitialized ( never run )
[ ] - Running ( in progress )
[ ] - Suspended ( on hold till resumed )
[ ] - Success ( finished and succeeded )
[ ] - Failure ( finished and failed )
[ ] * Optional callbacks :
[ ] - on_enter
[ ] - on_leave
[ ] - on_success
[ ] - on_failure
[ ] - on_suspend
[ ] - on_resume
[ x ] Action Node : This node performs a single action , such as moving to a specific location or attacking a target .
[ ] Blackboard Node : Node that reads and writes data to a shared memory space known as a blackboard . The blackboard can be used to store information that is relevant to multiple nodes in the behavior tree .
[ ] SetKey ( keyVar , object )
[ ] HasKey ( keyVar )
[ ] CompareKeys ( keyVar1 , operator < < = > > = = = ! = , keyVar2 )
[ ] SetTags ( names = blank , cooldownTime = inf , bIsCooldownAdditive = false )
[ ] HasTags ( names = blank , bAllRequired = true )
[ ] PushToStack ( keyVar , itemObj ) : creates a new stack if one doesn <EFBFBD> t exist , and stores it in the passed variable name , and then pushes <EFBFBD> item <EFBFBD> object onto it .
[ ] PopFromStack ( keyVar , itemVar ) : pop pops an item off the stack , and stores it in the itemVar variable , failing if the stack is already empty .
[ ] IsEmptyStack ( keyVar ) : checks if the stack passed is empty and returns success if it is , and failure if its not .
[ ] Communication Node : This is a type of action node that allows an AI agent to communicate with other agents or entities in the game world . The node takes an input specifying the message to be communicated and the recipient ( s ) of the message ( wildmask , l / p / f / g prefixes ) . The node then sends the message to the designated recipient ( s ) and returns success when the communication is completed . This node can be useful for implementing behaviors that require the AI agent to coordinate with other agents or to convey information to the player . It could use a radius argument to specify the maximum allowed distance for the recipients .
[ ] Condition Node : A leaf node that checks a specific condition , such as the distance to an object , the presence of an enemy , or the status of a health bar .
[ ] Distance Condition Node : This is a type of condition node that evaluates whether an AI agent is within a specified distance of a target object or location . The node takes two inputs : the current position of the AI agent and the position of the target object or location . If the distance between the two is within a specified range , the node returns success . If the distance is outside of the specified range , the node returns failure . This node can be useful for implementing behaviors that require the AI agent to maintain a certain distance from a target , such as following or avoiding an object . Could use a flag to disambiguate between linear distance and path distance .
[ ] Query Node : This node checks a condition and returns success or failure based on the result . For example , a query node could check whether an enemy is within range or whether a door is locked .
[ ] Query Node : A type of decorator node that retrieves information from a database or external system , such as a web service or file system . The Query node can be used to retrieve data that is not available within the game engine , such as weather or traffic conditions .
[ ] A condition is made of :
[ ] - Optional [ ! ] negate
[ ] - Mandatory Value1 ( Int / Flt / Bool / VarName / FuncName )
[ ] - Optional operator [ < < = > > = = = ! = ] and Value2 ( Int / Flt / Bool / VarName / FuncName )
[ ] AllConditions ( . . . ) : SUCCESS if ( empty array | | all conditions met )
[ ] AnyConditions ( . . . ) : SUCCESS if ( ! empty array & & one conditions met )
- - - DECORATOR NODES
[ ] Cooldown Node : Decorator node that adds a cooldown period between the execution of a child node , preventing it from being executed again until the cooldown period has elapsed .
[ x ] Counter Node : Decorator node that limits the number of times that a child node can execute . For example , if the child node has executed a certain number of times , the Counter node will return a failure .
[ x ] Once Node : Decorator node that triggers a specified action when a condition is met for the first time . This can be useful for triggering a one - time event , such as when an AI agent discovers a hidden item or reaches a new area of the game world .
[ x ] Inverter Node : Decorator node that inverts the result of a child node , returning success if the child node fails and failure if the child node succeeds . This can be useful for negating the outcome of a particular behavior , such as avoiding a certain area of the game world .
[ x ] Repeater Node : Decorator node that repeats the execution of a child node a specified number of times or indefinitely .
[ x ] Repeat ( times = inf ) : Runs child node given times . These are often used at the very base of the tree , to make the tree to run continuously .
[ ] RepeatIf ( strong / weak condition ) : Runs child node as long as the conditions are met .
[ ] RepeatIfOk ( times = inf ) : Runs child node if it succeedes , max given times .
[ ] RepeatIfFail ( times = inf ) : Runs child node if it fails , max given times .
[ ] Branch Node : 2 children [ 0 ] for true , [ 1 ] for false
[ ] Resource Node : Decorator node that manages a shared resource , such as a limited supply of ammunition or a limited amount of processing power . The Resource node The node can be used to decide when to use or conserve the resource . For example , if the AI agent is low on ammunition , the node may decide to switch to a melee weapon or to retreat to a safer location . This node can be useful for implementing behaviors that require the AI agent to make strategic decisions about resource use .
[ x ] Result Node : Decorator node that tracks the result of a child action node and returns either success or failure depending on the outcome . This can be useful for determining whether an action was successful or not , and then adjusting the AI agent ' s behavior accordingly .
[ x ] Succeeder Node : Decorator node that always returns success , regardless of the result of its child node . This can be useful for ensuring that certain behaviors are always executed , regardless of the overall success or failure of the behavior tree .
[ x ] Success ( ) : FAILURE becomes SUCCESS ( TRUE ) .
[ x ] Failure ( ) : SUCCESS becomes FAILURE ( FALSE ) .
[ ] Throttle Node : Decorator node that limits the rate at which a child node can execute . For example , a Throttle node might ensure that an AI agent can only fire its weapon , or using a special ability , only a certain number of times per second .
[ x ] Delay Node : Decorator node that adds a delay to the execution of a child node . The delay might be configured to sleep before the execution , after the execution , or both .
[ x ] Defer Delay ( duration_ss = 1 ) : Runs the child node , then sleeps for given seconds .
[ ] Ease ( time , name ) : Clamps child time to [ 0 , 1 ] range , and applies easing function on it .
[ ] Dilate ( Mul = 1 , Add = 0 ) : Dilates child time
- - - CONTROL NODES
[ x ] Root Node : The topmost node in a behavior tree that represents the start of the decision - making process . Returns success if any of its child nodes suceedes .
[ x ] Root - Failure Node : Control node that only returns failure if all of its child nodes fail . This can be useful for ensuring that a behavior tree is not prematurely terminated if one or more child nodes fail .
[ ] Event ( name ) : When name event is raised , it suspends current tree and calls child . " Incoming projectile " - > Evade . Stimulus types : may be disabled by event , or autodisabled .
[ ] Raise ( name ) : Triggers event name .
[ ] Checkpoint Node : Control node that saves a state in memory and then continues the tree execution from that point the next time the tree is executed . It can be useful in situations where the behavior tree needs to be interrupted and resumed later .
[ ] Decision Making Node : Control node that implements a decision - making process for the AI agent . The node takes input specifying the available options for the AI agent and the criteria for evaluating each option . The node then evaluates each option based on the specified criteria and selects the best option . This node can be useful for implementing behaviors that require the AI agent to make strategic decisions , such as choosing a target or selecting a path through the game world .
[ ] Could be extended with GOAP if dynamically inserting the scores on each update then calling a Probability Selector Node ( 0.2 , 0.3 , 0.5 )
[ ] https : //cdn.cloudflare.steamstatic.com/apps/valve/2012/GDC2012_Ruskin_Elan_DynamicDialog.pdf
[ ] Evaluate Node / Recheck ( ) :
[ ] Actively rechecks all existing sub - conditions on a regular basis after having made decisions about them .
[ ] Use this feature to dynamically check for risks or opportunities in selected parts of the tree .
[ ] For example , interrupting a patrol with a search behavior if a disturbance is reported .
[ ] Interrupt Node : Control node that interrupts the execution of a lower - priority node when a higher - priority node needs to be executed . It can be useful for handling urgent tasks or emergency situations .
[ ] Monitor Node : Control node that continuously monitors a condition and triggers a specified action when the condition is met . For example , a Monitor node might monitor the distance between an AI agent and a target and trigger a " retreat " behavior when the distance falls below a certain threshold .
[ ] Observer Node : Control node that monitors the state of the game world and triggers a specified action when certain conditions are met . For example , an Observer node might trigger a " hide " behavior when an enemy is spotted .
[ ] Parallel Node : Control node that executes multiple child nodes simultaneously . The Parallel node continues to execute even if some of its child nodes fail .
[ ] Parallel All Node ( required_successes = 100 % ) : Control node that executes multiple child nodes simultaneously . Returns false when first child fails , and aborts any other running tasks . Returns true if all its children succeed .
[ ] Parallel One Node ( required_successes = 1 ) : Control node that executes multiple child nodes simultaneously . Returns true when first child suceedes , and aborts any other running tasks . Returns false if all its children fail .
[ ] Subsumption Node : Control node that allows multiple behaviors to be executed simultaneously , with higher - priority behaviors taking precedence over lower - priority ones . This can be useful for implementing complex , multi - level behaviors in autonomous systems .
[ ] Semaphore Node : Control node that blocks the execution of its child nodes until a certain condition is met . For example , a Semaphore node might block the execution of a behavior until a certain object is in range or a certain event occurs .
[ ] Semaphore Wait Node : Control node that blocks the execution of its child nodes until a resource becomes available . This can be useful for controlling access to shared resources such as a pathfinding system or a communication channel .
[ ] WaitTags ( tags = blank , timeout_ss = inf ) : Stops execution of child node until the cooldown tag ( s ) do expire . May return earlier if timed out .
[ ] WaitEvent ( name = blank , timeout_ss = inf ) : Stops execution of child node until event is raised . May return earlier if timed out .
[ x ] Sequence Node ( reversed , iterator ( From , To ) ) : Control node that executes a series of child nodes in order . If any of the child nodes fail , the Sequence node stops executing and returns a failure .
[ ] Dynamic Sequence Node : Control node that dynamically changes the order in which its child nodes are executed based on certain conditions . For example , a Dynamic Sequence node might give higher priority to a child node that has recently failed or that is more likely to succeed .
[ ] Reverse ( ) : iterates children in reversed order ( Iterator : ( - 1 , 0 ) equivalent )
[ ] Iterator ( from , to ) : allows negative indexing . increments if ( abs from < abs to ) , decrements otherwise
[ x ] Selector Node : Control node that selects a child node to execute based on a predefined priority or set of conditions . The Selector node stops executing child nodes as soon as one of them succeeds .
[ ] Priority Selector Node : Control node that executes its child nodes in order of priority . If the first child node fails , it moves on to the next child node in the list until a successful node is found . This can be useful for implementing behaviors that require a specific order of execution , such as a patrol route or a search pattern .
[ ] Probability Selector Node : Control node that selects a child node to execute based on a probability distribution . For example , if there are three child nodes with probabilities of 0.2 , 0.3 , and 0.5 , the Probability Selector node will execute the third child node 50 % of the time .
[ ] Dynamic Selector Node : Control node that dynamically changes the order in which its child nodes are executed based on certain conditions . For example , a Dynamic Selector node might give higher priority to a child node that has recently succeeded or that is more likely to succeed .
[ ] Dynamic Selector Node : Control node that dynamically changes the order in which child nodes are executed based on certain conditions . For example , it may prioritize certain nodes when health is low , and other nodes when resources are scarce .
[ ] Dynamic Priority Node : Control node that dynamically changes the priority of its child nodes based on certain conditions . For example , if a child node is more likely to result in success , the Dynamic Priority node will give it a higher priority .
[ ] Weighted / Cover Selection Node : This is a type of selector node that evaluates the available cover options in the game world and selects the best cover position for the AI agent . The node takes input specifying the current position of the AI agent and the location of potential cover positions . The node then evaluates the cover positions based on criteria such as distance to enemy positions , line of sight , and available cover points , and selects the best option . This node can be useful for implementing behaviors that require the AI agent to take cover and avoid enemy fire .
[ ] Random Selector Node : Control node that selects a child node to execute at random . This can be useful for introducing variety and unpredictability into the behavior of an AI agent .
[ ] Random Weight / Stochastic Node ( 0.2 , 0.3 , 0.5 ) : Control node that introduces randomness into the decision - making process of an AI agent . For example , a Stochastic node might randomly select a child node to execute , with the probability of each child node being proportional to its likelihood of success .
[ ] Break ( bool ) : breaks parent sequence or selector . may return SUCCESS or FAILURE .
[ ] Hybrid Node : Control node that combines the functionality of multiple control nodes , such as a sequence node and a selector node . It can be useful for creating complex behavior patterns that require multiple control structures . The Hybrid Node has two modes of operation : strict mode and flexible mode . In strict mode , the child nodes are executed in a fixed order , similar to a Sequence Node . If any child node fails , the entire Hybrid Node fails . In flexible mode , the child nodes can be executed in any order , similar to a Selector Node . If any child node succeeds , the entire Hybrid Node succeeds . The Hybrid Node is often used when you need to create complex behavior patterns that require multiple control structures . For example , you might use a Hybrid Node to implement a search behavior where the AI agent first moves in a fixed direction for a certain distance ( strict mode ) , but then switches to a more exploratory mode where it randomly explores nearby areas ( flexible mode ) .
[ ] Subtree Node : Control node that calls another behavior tree as a subroutine . This is useful for breaking down complex behaviors into smaller , more manageable parts .
[ ] Call ( name ) : Calls to the child node with the matching name within behavior tree . Returns FAILURE if name is invalid or if invoked behavior returns FAILURE .
[ ] Return ( boolean ) : Exits current Call .
[ ] AttachTree ( Name , bDetachAfterUse = true ) : Attaches subtree to main tree . When a NPC founds the actor , it attaches the behavior to the tree . Ie , Level specific content : Patrols , Initial setups , Story driven events , etc . Ie , DLCs : Behaviors are added to actors in the DLC level ( enticers ) .
[ ] DetachTree ( Name )
[ ] Switch Node : Control node that evaluates a condition and then selects one of several possible child nodes to execute based on the result of the condition .
[ ] Switch ( name ) : Jumps to the child node with the matching name within behavior tree . If name is invalid will defer to Fallback child node .
[ ] Timeout Node : Control node that aborts the execution of its child node after a certain amount of time has elapsed . This can be useful for preventing an AI agent from getting stuck in a loop or waiting indefinitely for a particular event to occur .
[ ] TimeLimit ( timeout_ss = inf ) : Give the child any amount of time to finish before it gets canceled . The timer is reset every time the node gains focus .
[ ] Timer Node : Control node which invokes its child node every XX seconds . The timer can repeat the action any given number of times , or indefinitely .
# # Proposal -----------------------------------------------------------------------------
BehaviorTrees as case - insensitive INI files . Then ,
- INI - > C INTERPRETER , OR
- INI - > LUA TRANSPILER - > LUA BYTECODE - > LUA VM .
` ` ` ini
[ bt ]
recheck
sequence ; ; Approach the player if seen !
conditions = IsPlayerVisible ,
action = MoveTowardsPlayer
sequence ; ; Attack the player if seen !
conditions = IsPlayerInRange ,
repeat = 3
action = FireAtPlayer
sequence ; ; Search near last known position
conditions = HaveWeGotASuspectedLocation ,
action = MoveToPlayersLastKnownPosition
action = LookAround
sequence ; ; Randomly scanning nearby
action = MoveToRandomPosition
action = LookAround
event = IncomingProjectile
action = Evade
` ` `
# endif
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 void ui_bt ( bt_t * b ) ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_audio.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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. return current fx volume in any case
API float audio_volume_stream ( float gain ) ; // set bgm volume if gain is in [0..1] range. return current bgm volume in any case
API float audio_volume_master ( float gain ) ; // set master volume if gain is in [0..1] range. return current master volume in any case
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
2023-08-10 14:30:56 +00:00
AUDIO_32KHZ = 64 ,
AUDIO_44KHZ = 128 ,
2023-07-30 19:18:50 +00:00
AUDIO_MIXER_GAIN = 0 , // default
2023-08-10 14:30:56 +00:00
AUDIO_IGNORE_MIXER_GAIN = 256 ,
2023-07-30 19:18:50 +00:00
AUDIO_MULTIPLE_INSTANCES = 0 , // default
2023-08-10 14:30:56 +00:00
AUDIO_SINGLE_INSTANCE = 512 ,
2023-07-30 19:18:50 +00:00
} ;
API int audio_queue ( const void * samples , int num_samples , int flags ) ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_collide.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_cooker.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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]
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_data.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-25 23:32:43 +00:00
# define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int
# define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float
2023-07-30 19:18:50 +00:00
# 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 ( ) ;
// 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 ) ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_dll.h"
2023-07-30 19:18:50 +00:00
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_editor.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 ) ;
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_file.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 const char * * file_list ( const char * path , const char * masks ) ; // **.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
2023-08-10 14:30:56 +00:00
API char * file_counter ( const char * pathfile ) ; // in: v4k.ini -> out: v4k(001).ini -> out: v4k(002).ini [-> etc...]
2023-07-30 19:18:50 +00:00
2023-08-26 13:33:29 +00:00
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)
2023-07-30 19:18:50 +00:00
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 const 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_font.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_input.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
// -- extended polling api (read input at Nth frame ago)
API float input_frame ( int vk , int frame ) ;
API vec2 input_frame2 ( int vk , int frame ) ;
API const char * input_frames ( int vk , int 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_demo ( ) ;
API void input_mappings ( const char * filename ) ; // update gamepad mappings (usually "gamecontrollerdb.txt" file)
API void input_send ( int vk ) ; // @todo
API void * input_save_state ( int id , int * size ) ; // @todo
API bool input_load_state ( int id , void * ptr , int size ) ; // @todo
API char input_keychar ( unsigned code ) ; // Converts keyboard code to its latin char (if any)
API int input_anykey ( ) ;
// --
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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_memory.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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)
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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_network.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "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
2023-08-21 16:07:45 +00:00
2023-08-10 14:30:56 +00:00
enum { NETWORK_BIND = 2 , NETWORK_CONNECT = 4 , NETWORK_NOFAIL = 8 } ;
2023-08-21 16:07:45 +00:00
API void network_create ( unsigned max_clients , const char * ip , const char * port , unsigned flags ) ; // both ip and port can be null
2023-08-10 14:30:56 +00:00
//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 } ;
2023-08-21 10:32:46 +00:00
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
2023-08-10 14:30:56 +00:00
API char * * network_sync ( unsigned timeout_ms ) ; // syncs all buffers & returns null-terminated list of network events
2023-08-21 12:24:47 +00:00
enum {
NETWORK_EVENT_CONNECT ,
NETWORK_EVENT_DISCONNECT ,
NETWORK_EVENT_RECEIVE ,
NETWORK_EVENT_DISCONNECT_TIMEOUT ,
2023-08-21 12:58:12 +00:00
/* offset from internal networking events */
NETWORK_EVENT_RPC = 10 ,
NETWORK_EVENT_RPC_RESP ,
2023-08-21 12:24:47 +00:00
} ;
/* 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 ) ;
2023-08-10 14:30:56 +00:00
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 } ;
2023-08-21 10:32:46 +00:00
enum { NETWORK_SEND_MS = 4 } ;
2023-08-21 18:23:43 +00:00
enum { NETWORK_BUF_CLEAR_ON_JOIN = 5 } ;
enum { NETWORK_USERID = 7 , /*NETWORK_SALT,*/ NETWORK_COUNT /*N users*/ /*...*/ , NETWORK_CAPACITY } ;
2023-08-10 14:30:56 +00:00
API int64_t network_get ( uint64_t key ) ;
API int64_t network_put ( uint64_t key , int64_t value ) ;
2023-08-10 17:55:53 +00:00
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 ) ;
2023-08-10 14:30:56 +00:00
// -----------------------------------------------------------------------------
// low-level api (sockets based)
2023-08-21 16:35:22 +00:00
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 ) ;
2023-08-10 14:30:56 +00:00
API int64_t client_join ( const char * ip , int port ) ;
2023-08-21 10:32:46 +00:00
# define client_send_flags(msg,flags) server_broadcast(msg, flags)
2023-08-10 14:30:56 +00:00
# define client_send(msg) server_broadcast(msg)
2023-08-21 10:32:46 +00:00
# define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags)
2023-08-10 14:30:56 +00:00
# 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 "v4k_obj.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// C object framework (constructors/destructors, methods, rtti, refcounting)
// - rlyeh, public domain.
//
// ## object api (low level)
//
// - [ ] make object from reflected type (factory)
// - [x] make object (if debug, include callstack as well)
// - [x] ctor method (optional, ref to constructor)
// - [x] dtor method (optional, ref to deleter)
// - [x] zero mem object
// - [x] object logger
// - [ ] iterate members in a struct
//
// - [x] clone/copy/mutate classes
// - [x] load/save objects from/to memory/disk
// - [ ] diff/patch objects
// - [ ] experimental: support for AoSoA layout (using objcnt, 3bits)
//
// ## object decomposition
//
// <---------|--------->
// OBJ-SHADOW (64-bits) | OBJ CONTENT (N bytes)
// +-----+-----+-------------+-----------+-----+-----+-----+-----+--
// |TYPE |REFS.| OBJ NAME | obj cnt | ... | ... | ... | ... | .
// +-----+-----+-------------+-----------+-----+-----+-----+-----+--
// \-16-bits--/\---45-bits--/\--3-bits--/\-------N-bytes-----------
//
// OBJ TYPE+NAME format:
// - [type] custom tags at 0x0
// - [1..N] name
// - [\n] blank separator
// - [comments, logger, infos, etc] << obj_printf();
//
// ## object limitations
// - 256 classes max
// - 256 references max
// - 8-byte overhead per object
// - 2 total allocs per object (could be flattened into 1 with some more work)
//
// @todo: obj_extend( "class_src", "class_dst" ); call[super(obj)]()
// @todo: preferred load/save format: [ver:1,user:2,type:1] ([eof|size:7/15/23/31][blob:N])+ [crc:1/2/3/4]
// @todo: more serious loading/saving spec
// object api (heap+rtti)
API void * obj_malloc ( int sz , . . . ) ;
API void * obj_calloc ( int sz , . . . ) ;
API void obj_free ( void * obj ) ;
API bool obj_typeeq ( const void * obj1 , const void * obj2 ) ;
API const char * obj_typeof ( const void * obj ) ;
API unsigned obj_typeid ( const void * obj ) ;
API unsigned obj_typeid_from_name ( const char * name ) ;
// object api (ctor/dtor, refcounting, oop)
API void obj_new ( const char * type , . . . ) ;
API void obj_del ( void * obj ) ;
API void * obj_ref ( void * obj ) ;
API void * obj_unref ( void * obj ) ;
API void obj_extend ( const char * dstclass , const char * srcclass ) ;
API void obj_override ( const char * objclass , void ( * * vtable ) ( ) , void ( * fn ) ( ) ) ;
// object: serialize
API unsigned obj_load ( void * obj , const array ( char ) buffer ) ;
API unsigned obj_load_file ( void * obj , FILE * fp ) ;
API unsigned obj_load_inplace ( void * obj , const void * src , unsigned srclen ) ;
API array ( char ) obj_save ( const void * obj ) ; // empty if error. must array_free() after use
API unsigned obj_save_file ( FILE * fp , const void * obj ) ;
API unsigned obj_save_inplace ( void * dst , unsigned cap , const void * obj ) ;
// object: utils
API unsigned obj_instances ( const void * obj ) ;
API void obj_zero ( void * obj ) ;
API unsigned obj_sizeof ( const void * obj ) ;
API void obj_hexdump ( const void * obj ) ;
API void obj_hexdumpf ( FILE * out , const void * obj ) ;
API void obj_printf ( void * obj , const char * text ) ;
API const char * obj_output ( const void * obj ) ;
API void * obj_clone ( const void * obj ) ;
API void * obj_copy ( void * * dst , const void * src ) ;
API void * obj_mutate ( void * * dst , const void * src ) ;
// object: method dispatch tables
# define ctor(obj) obj_method0(obj, ctor) // ctor[obj_typeid(obj)](obj)
# define dtor(obj) obj_method0(obj, dtor) // dtor[obj_typeid(obj)](obj)
API extern void ( * ctor [ 256 ] ) ( ) ; ///-
API extern void ( * dtor [ 256 ] ) ( ) ; ///-
// object: syntax sugars
# define obj_malloc(sz, ...) obj_initialize((void**)MALLOC( sizeof(void*)+sz), stringf("\1untyped\n%s\n", "" #__VA_ARGS__))
# define obj_calloc(sz, ...) obj_initialize((void**)CALLOC(1,sizeof(void*)+sz), stringf("\1untyped\n%s\n", "" #__VA_ARGS__))
# define obj_new0(type) obj_new(type, 0)
# define obj_new(type, ...) ( \
obj_tmpalloc = obj_initialize ( ( void * * ) CALLOC ( 1 , sizeof ( void * ) + sizeof ( type ) ) , stringf ( " %c " # type " \n " , ( char ) obj_typeid_from_name ( # type ) ) ) , \
( * ( type * ) obj_tmpalloc = ( type ) { __VA_ARGS__ } ) , \
ctor ( obj_tmpalloc ) , \
( type * ) obj_tmpalloc )
# define obj_override(class, method) obj_override(#class, (void(**)())method, (void(*)())class##_##method)
# define obj_method0(obj, method) method[obj_typeid(obj)]((obj))
# define obj_method(obj, method, ...) method[obj_typeid(obj)]((obj), __VA_ARGS__)
# define obj_printf(obj, ...) obj_printf(obj, va(__VA_ARGS__))
# define obj_extend(dstclass, srcclass) obj_extend(#dstclass, #srcclass)
// object: implementation details
// https://stackoverflow.com/questions/16198700/using-the-extra-16-bits-in-64-bit-pointers (note: using 19-bits here)
# define OBJBOX(ptr, payload16) (void*)(((long long unsigned)(payload16) << 48) | (long long unsigned)(ptr))
# define OBJUNBOX(ptr) (void*)((long long unsigned)(ptr) & 0x0000FFFFFFFFFFFFull)
# define OBJPAYLOAD16(ptr) (((long long unsigned)(ptr)) >> 48)
# define OBJPAYLOAD3(ptr) (((long long unsigned)(ptr)) & 7)
API void * obj_initialize ( void * * ptr , char * type_and_info ) ;
static __thread void * obj_tmpalloc ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_profile.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 profile_init() do {} while(0)
# define profile_render() do {} while(0)
# define profile_enable(x) 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 profile_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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_render.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 float alpha ( unsigned rgba ) ;
# define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) )
# define RGB3(r,g,b) ( ((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( 149,149,149 )
# 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 ;
2023-09-08 06:16:32 +00:00
unsigned texel_type ;
2023-07-30 19:18:50 +00:00
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_ycbcr ( 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
2023-09-10 14:46:07 +00:00
// #ifndef VSMCUBE
// #define VSMCUBE 0
// #endif
// #ifndef VSMBLUR
// #define VSMBLUR 1
// #endif
2023-07-30 19:18:50 +00:00
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 ) ;
2023-09-08 09:19:33 +00:00
API unsigned shader_geom ( const char * gs , const char * vs , const char * fs , const char * attribs , const char * fragcolor ) ;
2023-07-30 19:18:50 +00:00
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 ) ;
2023-08-22 11:29:47 +00:00
API void shader_vec3v ( const char * uniform , int count , vec3 * v ) ;
2023-07-30 19:18:50 +00:00
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 ) ;
2023-09-11 10:23:33 +00:00
// compute shaders
enum BUFFER_MODE {
2023-09-10 16:16:25 +00:00
BUFFER_READ ,
BUFFER_WRITE ,
BUFFER_READ_WRITE
2023-09-08 06:16:32 +00:00
} ;
2023-09-08 20:14:11 +00:00
/// Loads the compute shader and compiles a GL program.
/// return: GL program, 0 if failed.
/// cs: shader source code
2023-09-08 06:16:32 +00:00
API unsigned compute ( const char * cs ) ;
2023-09-08 20:14:11 +00:00
/// 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
2023-09-11 10:23:33 +00:00
/// see: BUFFER_MODE
2023-09-08 20:14:11 +00:00
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
2023-09-11 10:23:33 +00:00
/// see: BUFFER_MODE
2023-09-08 20:14:11 +00:00
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 image operations are done by the GPU.
2023-09-08 06:31:58 +00:00
API void image_write_barrier ( ) ;
2023-09-08 20:14:11 +00:00
/// Blocks main thread until all memory operations are done by the GPU.
2023-09-08 06:31:58 +00:00
API void write_barrier ( ) ;
2023-09-08 06:16:32 +00:00
2023-09-08 08:00:26 +00:00
// ssbo
2023-09-08 20:14:11 +00:00
/// `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.
2023-09-11 10:23:33 +00:00
enum SSBO_USAGE {
2023-09-08 08:00:26 +00:00
STATIC_DRAW ,
STATIC_READ ,
STATIC_COPY ,
DYNAMIC_DRAW ,
DYNAMIC_READ ,
DYNAMIC_COPY ,
STREAM_DRAW ,
STREAM_READ ,
STREAM_COPY
} ;
2023-09-10 16:16:25 +00:00
enum SSBO_ACCESS {
SSBO_READ = BUFFER_READ ,
SSBO_WRITE = BUFFER_WRITE ,
SSBO_READ_WRITE = BUFFER_READ_WRITE
} ;
2023-09-08 20:14:11 +00:00
/// 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
2023-09-11 10:23:33 +00:00
/// see: SSBO_USAGE
2023-09-08 08:00:26 +00:00
API unsigned ssbo_create ( const void * data , int len , unsigned usage ) ;
2023-09-08 20:14:11 +00:00
/// Destroys an SSBO resource
2023-09-08 08:00:26 +00:00
API void ssbo_destroy ( unsigned ssbo ) ;
2023-09-08 20:14:11 +00:00
/// 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
2023-09-08 08:00:26 +00:00
API void ssbo_update ( int offset , int len , const void * data ) ;
2023-09-08 20:14:11 +00:00
/// Bind an SSBO resource to the provided bind unit index
/// ssbo: resource object
/// unit: bind unit index
2023-09-08 08:00:26 +00:00
API void ssbo_bind ( unsigned ssbo , unsigned unit ) ;
2023-09-08 20:14:11 +00:00
/// 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
2023-09-11 10:23:33 +00:00
/// see: SSBO_ACCESS
2023-09-08 08:00:26 +00:00
API void * ssbo_map ( unsigned access ) ;
2023-09-08 20:14:11 +00:00
/// Unmaps an SSBO resource
/// !!! Pointer provided by `ssbo_map` becomes invalid.
2023-09-08 08:00:26 +00:00
API void ssbo_unmap ( ) ;
2023-09-08 20:14:11 +00:00
/// Unbinds an SSBO resource
2023-09-08 08:00:26 +00:00
API void ssbo_unbind ( ) ;
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 ) ;
2023-09-08 09:19:33 +00:00
API void mesh_render_prim ( mesh_t * sm , unsigned prim ) ;
2023-07-30 19:18:50 +00:00
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
typedef struct shadertoy_t {
handle vao , program ;
int uniforms [ 32 ] ;
int texture_channels [ 4 ] ;
int frame ;
float clickx , clicky ;
uint64_t t ;
texture_t tx ;
unsigned dims ;
} 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 ,
} ;
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 ) ;
2023-08-14 16:30:52 +00:00
// -----------------------------------------------------------------------------
// 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 ) ;
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// skyboxes
typedef struct skybox_t {
handle program ;
mesh_t geometry ;
cubemap_t cubemap ;
int flags ;
2023-09-10 13:03:01 +00:00
// mie
2023-09-10 13:14:34 +00:00
int framebuffers [ 6 ] ;
int textures [ 6 ] ;
2023-09-11 13:22:16 +00:00
float * pixels ;
2023-07-30 19:18:50 +00:00
} 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 ) ;
2023-09-11 13:16:16 +00:00
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 ) ;
2023-07-30 19:18:50 +00:00
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_color ( uint32_t color ) ; // background(uint32_t) instead?
API void viewport_color3 ( vec3 color ) ; // background3(vec3) instead?
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_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 ) ;
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_renderdd.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_scene.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// scene framework
// - rlyeh, public domain
// camera
typedef struct camera_t {
mat44 view , proj ;
vec3 position , up , look ; // position, updir, lookdir
float yaw , pitch , speed ; // mirror_x, mirror_y;
vec3 last_look , last_move ; // used for friction and smoothing
float fov ; // deg(45)
} camera_t ;
API camera_t camera ( ) ;
API void camera_teleport ( camera_t * cam , vec3 pos ) ;
API void camera_move ( camera_t * cam , float incx , float incy , float incz ) ;
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 ( ) ;
// 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
} 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
// scene
enum SCENE_FLAGS {
SCENE_WIREFRAME = 1 ,
SCENE_CULLFACE = 2 ,
SCENE_BACKGROUND = 4 ,
SCENE_FOREGROUND = 8 ,
} ;
typedef struct scene_t {
handle program ;
array ( object_t ) objs ;
// 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 ) ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_script.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_string.h"
2023-07-30 19:18:50 +00:00
// 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 <string.h>
# endif
# define strtok_r strtok_s
# endif
# if 1
# define each_substring(str, delims, keyname) \
( int len_ = strlen ( str ) + 1 ; len_ ; len_ = 0 ) \
for ( char buf_ [ 1024 ] , * ptr_ = len_ < 1024 ? buf_ : REALLOC ( 0 , len_ ) , * lit_ = ( char * ) ( str ) , * _bak = ( snprintf ( ptr_ , len_ , " %s " , lit_ ) , ptr_ ) ; _bak ; _bak = 0 , ( ptr_ = = buf_ ? 0 : REALLOC ( ptr_ , 0 ) ) ) \
for ( char * next_token = 0 , * keyname = strtok_r ( _bak , 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
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_system.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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=value or --arg value
API int optioni ( const char * commalist , int defaults ) ; // argvi() ?
API float optionf ( const char * commalist , float defaults ) ; // app_option?
API void tty_color ( unsigned color ) ;
API void tty_reset ( ) ;
API void tty_attach ( ) ;
2023-08-11 19:59:48 +00:00
API void tty_detach ( ) ;
2023-07-30 19:18:50 +00:00
API const char * app_exec ( const char * command ) ; // returns ("%15d %s", retcode, output_last_line)
API int app_cores ( ) ;
API int app_battery ( ) ; /// return 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 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 ) ;
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 ( const char * optional_reason ) ;
API bool has_debugger ( ) ;
API void signal_hooks ( void ) ;
API void signal_handler_ignore ( int signal ) ;
API void signal_handler_quit ( int signal ) ;
API void signal_handler_abort ( int signal ) ;
API void signal_handler_debug ( int signal ) ;
API const char * signal_name ( int signal ) ; // helper util
API uint16_t lil16 ( uint16_t n ) ; // swap16 as lil
API uint32_t lil32 ( uint32_t n ) ; // swap32 as lil
API float lil32f ( float n ) ; // swap32 as lil
API uint64_t lil64 ( uint64_t n ) ; // swap64 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 float big32f ( float n ) ; // swap32 as big
API uint64_t big64 ( uint64_t n ) ; // swap64 as big
API double big64f ( double n ) ; // swap64 as big
API uint16_t * lil16p ( void * n , int sz ) ;
API uint32_t * lil32p ( void * n , int sz ) ;
API float * lil32pf ( void * n , int sz ) ;
API uint64_t * lil64p ( void * n , int sz ) ;
API double * lil64pf ( void * n , int sz ) ;
API uint16_t * big16p ( void * n , int sz ) ;
API uint32_t * big32p ( void * n , int sz ) ;
API float * big32pf ( void * n , int sz ) ;
API uint64_t * big64p ( void * n , int sz ) ;
API double * big64pf ( void * n , int sz ) ;
# define PANIC(...) PANIC(va(__VA_ARGS__), __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) : "", __FILE__, __LINE__, __FUNCTION__)
API int ( PRINTF ) ( const char * text , const char * stack , const char * file , int line , const char * function ) ;
# line 0
2023-08-10 14:30:56 +00:00
# line 1 "v4k_ui.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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_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_bits8 ( const char * label , uint8_t * bits ) ;
API int ui_bits16 ( 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_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_const_bool ( const char * label , const double value ) ;
API int ui_const_float ( const char * label , const double value ) ;
API int ui_const_string ( const char * label , const char * value ) ;
API int ui_contextual_end ( ) ;
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_visible ( const char * panel_or_window_title ) ; // @todo: include ui_collapse() items that are open as well?
API int ui_enable ( ) ;
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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_video.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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 = 1 ,
VIDEO_AUDIO = 0 ,
VIDEO_NO_AUDIO = 2 ,
} ;
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
2023-08-10 14:30:56 +00:00
# line 1 "v4k_window.h"
2023-07-30 19:18:50 +00:00
// -----------------------------------------------------------------------------
// 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_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_icon ( const char * file_icon ) ;
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 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
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 <GL/glew.h>
# include <GLFW/glfw3.h>
# include <emscripten.h>
# include <emscripten/html5.h>
# define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK)
# else
2023-08-10 14:30:56 +00:00
# if is(win32) /*&& is(tcc)*/ // && WITH_DLL
2023-07-30 19:18:50 +00:00
# ifdef GLAD_API_CALL
# undef GLAD_API_CALL
# endif
# define GLAD_API_CALL extern API
# endif
# ifndef GLAD_GL_H_
2023-08-10 14:30:56 +00:00
# include "v4k"
2023-07-30 19:18:50 +00:00
# endif
# endif
2023-08-10 14:30:56 +00:00
# endif // V4K_H