main
Dominik Madarász 2023-10-14 21:47:24 +02:00
parent a9c5d6c269
commit 64a7eade9f
30 changed files with 623 additions and 414 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ demos/ports/*/*.exe
demos/ports/doom/.doomrc demos/ports/doom/.doomrc
*.sublime-workspace *.sublime-workspace
engine/v4k.html engine/v4k.html
*.exe.manifest

View File

@ -395,6 +395,7 @@ if "%1"=="tidy" (
del *.zip > nul 2> nul del *.zip > nul 2> nul
del *.mem > nul 2> nul del *.mem > nul 2> nul
del *.exp > nul 2> nul del *.exp > nul 2> nul
del *.exe.manifest > nul 2> nul
del tools\*.exp > nul 2> nul del tools\*.exp > nul 2> nul
del *.lib > nul 2> nul del *.lib > nul 2> nul
del *.exe > nul 2> nul del *.exe > nul 2> nul

@ -1 +1 @@
Subproject commit 20989f73cd14330b84c627cc1742b63732d67bcb Subproject commit 494a0e216d2b4984065994372960d15f197c1e07

View File

@ -1496,6 +1496,9 @@ ffi.cdef([[
//lcpp INF [0000] vec3: macro name but used as C declaration in: void light_dir(light_t* l, vec3 dir); //lcpp INF [0000] vec3: macro name but used as C declaration in: void light_dir(light_t* l, vec3 dir);
//lcpp INF [0000] vec2i: macro name but used as C declaration in:vec2i* entries; //lcpp INF [0000] vec2i: macro name but used as C declaration in:vec2i* entries;
//lcpp INF [0000] vec3i: macro name but used as C declaration in:typedef vec3i guid; //lcpp INF [0000] vec3i: macro name but used as C declaration in:typedef vec3i guid;
//lcpp INF [0000] test: macro name but used as C declaration in:API int (test)(const char *file, int line, const char *expr, bool result);
//lcpp INF [0000] test: macro name but used as C declaration in:STATIC int (test)(const char *file, int line, const char *expr, bool result);
//lcpp INF [0000] test: macro name but used as C declaration in: int (test)(const char *file, int line, const char *expr, bool result);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 ui_get_dims();
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 ui_get_dims();
//lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 ui_get_dims();
@ -2120,7 +2123,7 @@ typedef union json_t { char* s; double f; int64_t i; uintptr_t p; union json_t*
char* kit_translate( const char *id ); char* kit_translate( const char *id );
char* kit_translate2( const char *id, const char *langcode_iso639_1 ); char* kit_translate2( const char *id, const char *langcode_iso639_1 );
void kit_dump_state( FILE *fp ); void kit_dump_state( FILE *fp );
const char** file_list(const char *path, const char *masks); char** file_list( const char *pathmasks );
bool file_write( const char *file, const void *ptr, int len ); bool file_write( const char *file, const void *ptr, int len );
bool file_append( const char *file, const void *ptr, int len ); bool file_append( const char *file, const void *ptr, int len );
char * file_read(const char *filename); char * file_read(const char *filename);
@ -3088,6 +3091,8 @@ typedef vec3i guid;
void trap_on_abort(int signal); void trap_on_abort(int signal);
void trap_on_debug(int signal); void trap_on_debug(int signal);
int (PANIC)(const char *error, const char *file, int line); int (PANIC)(const char *error, const char *file, int line);
int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function);
int (test)(const char *file, int line, const char *expr, bool result);
enum PANEL_FLAGS { enum PANEL_FLAGS {
PANEL_OPEN = 1, PANEL_OPEN = 1,
}; };
@ -3208,7 +3213,6 @@ WINDOW_VSYNC_DISABLED =8192,
void window_loop(void (*function)(void* loopArg), void* loopArg ); void window_loop(void (*function)(void* loopArg), void* loopArg );
void window_loop_exit(); void window_loop_exit();
void window_title(const char *title); void window_title(const char *title);
void window_icon(const char *file_icon);
void window_color(unsigned color); void window_color(unsigned color);
vec2 window_canvas(); vec2 window_canvas();
void* window_handle(); void* window_handle();
@ -3232,6 +3236,8 @@ WINDOW_VSYNC_DISABLED =8192,
int window_has_maximize(); int window_has_maximize();
void window_transparent(int enabled); void window_transparent(int enabled);
int window_has_transparent(); int window_has_transparent();
void window_icon(const char *file_icon);
int window_has_icon();
double window_aspect(); double window_aspect();
void window_aspect_lock(unsigned numer, unsigned denom); void window_aspect_lock(unsigned numer, unsigned denom);
void window_aspect_unlock(); void window_aspect_unlock();

View File

@ -14056,8 +14056,8 @@ extern "C" {
#define ENABLE_LINUX_CALLSTACKS 0 ///+ #define ENABLE_LINUX_CALLSTACKS 0 ///+
#endif #endif
#ifndef ENABLE_TESTS #ifndef ENABLE_AUTOTESTS
#define ENABLE_TESTS 0 // ifdef(debug, 1, 0) ///+ #define ENABLE_AUTOTESTS ifdef(debug, 1, 0) ///+
#endif #endif
#ifndef ENABLE_RETAIL #ifndef ENABLE_RETAIL
@ -14148,15 +14148,6 @@ extern "C" {
#define ifdef_release ifdef_false #define ifdef_release ifdef_false
#endif #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
#if ENABLE_RETAIL #if ENABLE_RETAIL
#define ifdef_retail ifdef_true #define ifdef_retail ifdef_true
#else #else
@ -14169,6 +14160,37 @@ extern "C" {
#define ifdef_nocook ifdef_false #define ifdef_nocook ifdef_false
#endif #endif
#if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3
#define ifdef_O3 ifdef_true
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 2
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_true
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 1
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_true
#define ifdef_O0 ifdef_false
#else
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_true
#endif
#include <stdint.h>
#if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
#define ifdef_64 ifdef_true
#define ifdef_32 ifdef_false
#else
#define ifdef_64 ifdef_false
#define ifdef_32 ifdef_true
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// new C keywords // new C keywords
@ -14197,8 +14219,13 @@ extern "C" {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// new C macros // new C macros
#if ENABLE_RETAIL
#define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0
#else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT(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 ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
#endif
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_)
#define FILELINE __FILE__ ":" STRINGIZE(__LINE__) #define FILELINE __FILE__ ":" STRINGIZE(__LINE__)
@ -14475,14 +14502,16 @@ static __thread unsigned array_n_;
} while(0) } while(0)
#define array_foreach(t,val_t,v) for each_array(t,val_t,v) #define array_foreach(t,val_t,v) for each_array(t,val_t,v)
#define each_array(t,val_t,v) \ #define each_array(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t v = __it[t], *on__ = &v; on__; on__ = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 )
#define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v) #define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v)
#define each_array_ptr(t,val_t,v) \ #define each_array_ptr(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t *v = (val_t*)&__it[t]; v; v = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t *v = (val_t*)&i_[a_]; v; v = 0 )
#define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \ #define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \
bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn ) bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn )
@ -14498,13 +14527,13 @@ static __thread unsigned array_n_;
} \ } \
} while(0) } while(0)
#define array_copy(t, src) do { /*todo: review old vrealloc call!*/ \ #define array_copy(t, src) do { \
array_free(t); \ array_free(t); \
(t) = array_realloc_( (t), array_count(src)); \ (t) = array_realloc_( (t), array_count(src)); \
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_swapback_and_pop(t, i) do { /*may alter ordering*/ \ #define array_erase_fast(t, i) do { /*may alter ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
@ -15750,7 +15779,7 @@ API void kit_dump_state( FILE *fp );
// physical filesystem. files // physical filesystem. files
API const char** file_list(const char *path, const char *masks); // **.png;*.c API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c
API bool file_write( const char *file, const void *ptr, int len ); API bool file_write( const char *file, const void *ptr, int len );
API bool file_append( 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_read(const char *filename);
@ -17729,18 +17758,13 @@ API void trap_on_debug(int signal); // helper util
#define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ? #define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ?
API int (PANIC)(const char *error, const char *file, int line); API int (PANIC)(const char *error, const char *file, int line);
#if !ENABLE_RETAIL
#define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__) #define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__)
API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function); API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function);
#define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr)) #define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr))
API int (test)(const char *file, int line, const char *expr, bool result); API int (test)(const char *file, int line, const char *expr, bool result);
#else
#define PRINTF(...)
#define test(expr)
#endif
#if ENABLE_TESTS #if ENABLE_AUTOTESTS
#define AUTOTEST AUTORUN #define AUTOTEST AUTORUN
#else #else
#define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)() #define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)()
@ -17748,6 +17772,12 @@ API int (test)(const char *file, int line, const char *expr, bool result);
// AUTOTEST { test(1<2); } // AUTOTEST { test(1<2); }
#if ENABLE_RETAIL
#undef PRINTF
#define PRINTF(...) 0
#undef test
#define test(expr) 0
#endif
#line 0 #line 0
#line 1 "engine/split/v4k_ui.h" #line 1 "engine/split/v4k_ui.h"
@ -17922,7 +17952,6 @@ API void window_loop(void (*function)(void* loopArg), void* loopArg ); // ru
API void window_loop_exit(); // exit from main loop function (emscripten only) API void window_loop_exit(); // exit from main loop function (emscripten only)
API void window_title(const char *title); API void window_title(const char *title);
API void window_icon(const char *file_icon);
API void window_color(unsigned color); API void window_color(unsigned color);
API vec2 window_canvas(); API vec2 window_canvas();
API void* window_handle(); API void* window_handle();
@ -17951,6 +17980,8 @@ API void window_maximize(int enabled);
API int window_has_maximize(); API int window_has_maximize();
API void window_transparent(int enabled); API void window_transparent(int enabled);
API int window_has_transparent(); API int window_has_transparent();
API void window_icon(const char *file_icon);
API int window_has_icon();
API double window_aspect(); API double window_aspect();
API void window_aspect_lock(unsigned numer, unsigned denom); API void window_aspect_lock(unsigned numer, unsigned denom);
@ -240032,8 +240063,8 @@ static void browser_reload_directory_content(struct browser *browser, const char
BROWSER_PRINTF("searching at %s\n", path); BROWSER_PRINTF("searching at %s\n", path);
const char **list = file_list(path, "*"); array(char*) list = file_list(path);
for( int i = 0; list[i]; ++i ) { for( int i = 0, end = array_count(list); i < end; ++i ) {
char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext
BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) );
@ -240577,9 +240608,11 @@ char *json5__parse_value(json5 *obj, char *p, char **err_code) {
*buf++ = *p++; *buf++ = *p++;
} }
obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER; obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER;
long long unsigned int llu;
long long int lli;
/**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real ); /**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real );
else if( is_hex ) sscanf( buffer, "%llx", &obj->integer ); // SCNx64 -> inttypes.h else if( is_hex ) sscanf( buffer, "%llx", &llu ), obj->integer = llu; // SCNx64 -> inttypes.h
else sscanf( buffer, "%lld", &obj->integer ); // SCNd64 -> inttypes.h else sscanf( buffer, "%lld", &lli ), obj->integer = lli; // SCNd64 -> inttypes.h
} }
else { else {
return NULL; return NULL;
@ -240631,7 +240664,7 @@ void json5_write(FILE *fp, const json5 *o) {
} }
/**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null"); /**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null");
else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false"); else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false");
else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", o->integer); else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", (long long int)o->integer);
else if( o->type == JSON5_REAL ) { else if( o->type == JSON5_REAL ) {
/**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" ); /**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" );
else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" ); else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" );
@ -252818,10 +252851,10 @@ bool zip_append_file_timeinfo(zip *z, const char *entryname, const char *comment
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
fseek(in, 0, SEEK_SET); // rewind fseek(in, 0, SEEK_SET); // rewind
@ -252929,10 +252962,10 @@ bool zip_append_mem_timeinfo(zip *z, const char *entryname, const char *comment,
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
size_t bytes = inlen; size_t bytes = inlen;
@ -252980,30 +253013,46 @@ common:;
// zip common // zip common
#if 1
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
#else
# if (defined(__TINYC__) && defined(_WIN32))
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
# elif defined _MSC_VER
# define zip_lockfile(f) _lock_file(f)
# define zip_unlockfile(f) _unlock_file(f)
# else
# define zip_lockfile(f) flockfile(f)
# define zip_unlockfile(f) funlockfile(f)
# endif
#endif
zip* zip_open_handle(FILE *fp, const char *mode) { zip* zip_open_handle(FILE *fp, const char *mode) {
if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode); if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode);
zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip)); zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip));
if( !z ) return fclose(fp), ERR(NULL, "out of mem"); else *z = zero; if( !z ) return ERR(NULL, "out of mem"); else *z = zero;
if( mode[0] == 'w' ) { if( mode[0] == 'w' ) {
z->out = fp; zip_lockfile(z->out = fp);
return z; return z;
} }
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; zip_lockfile(z->in = fp);
unsigned long long seekcur = ftell(z->in); unsigned long long seekcur = ftell(z->in);
JZEndRecord jzEndRecord = {0}; JZEndRecord jzEndRecord = {0};
if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) { if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file end record."); return ERR(NULL, "Couldn't read ZIP file end record.");
} }
jzEndRecord.centralDirectoryOffset += seekcur; jzEndRecord.centralDirectoryOffset += seekcur;
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) { if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory."); return ERR(NULL, "Couldn't read ZIP file central directory.");
} }
if( mode[0] == 'a' ) { if( mode[0] == 'a' ) {
@ -253020,13 +253069,13 @@ zip* zip_open_handle(FILE *fp, const char *mode) {
fseek( fp, 0L, SEEK_END ); fseek( fp, 0L, SEEK_END );
} }
z->out = z->in;
z->in = NULL; z->in = NULL;
z->out = fp;
} }
return z; return z;
} }
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
@ -253034,7 +253083,11 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
int exists = (stat(file, &buffer) == 0); int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb"; if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb"); FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode); if (!fp) return NULL;
if (mode[0] == 'a') fseek(fp, 0L, SEEK_SET);
zip *z = zip_open_handle(fp, mode);
if (!z) return fclose(fp), NULL;
return z;
} }
void zip_close(zip* z) { void zip_close(zip* z) {
@ -253062,8 +253115,8 @@ void zip_close(zip* z) {
// flush end record // flush end record
fwrite(&end, 1, sizeof(end), z->out); fwrite(&end, 1, sizeof(end), z->out);
} }
if( z->out ) fclose(z->out); if( z->out ) zip_unlockfile(z->out), fclose(z->out);
if( z->in ) fclose(z->in); if( z->in ) zip_unlockfile(z->in), fclose(z->in);
// clean up // clean up
for(unsigned i = 0; i < z->count; ++i ) { for(unsigned i = 0; i < z->count; ++i ) {
REALLOC(z->entries[i].filename, 0); REALLOC(z->entries[i].filename, 0);
@ -330573,7 +330626,7 @@ struct xml *xml_parse(char *s, int preserve_white, char **errorp)
static inline void array_find_and_remove(array(int) arr, int v) { static inline void array_find_and_remove(array(int) arr, int v) {
for( int i = 0, end = array_count(arr); i < end; i++ ) for( int i = 0, end = array_count(arr); i < end; i++ )
if( arr[i] == v ) { array_erase(arr, i); --end; break; } if( arr[i] == v ) { array_erase_fast(arr, i); --end; break; }
} }
#include <assert.h> #include <assert.h>
@ -330687,7 +330740,7 @@ static void RemoveIfNonNeighbor_(struct mesh *M, struct vertex *v, int id) {
return; return;
} }
// remove from neighbors // remove from neighbors
array_erase(v->neighbor, i); array_erase_fast(v->neighbor, i);
return; return;
} }
} }
@ -330850,7 +330903,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
} }
array(int) tmp = 0; array(int) tmp = 0;
// make tmp a Array of all the neighbors of u // make tmp a Array of all the neighbors of u
for (int i = 0; i<array_count(u->neighbor); i++) { for (int i = 0; i<array_count(u->neighbor); i++) {
array_push(tmp, u->neighbor[i]); array_push(tmp, u->neighbor[i]);
@ -330870,7 +330923,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
for (int i = 0; i<array_count(tmp); i++) { for (int i = 0; i<array_count(tmp); i++) {
ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i])); ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i]));
} }
array_free(tmp); array_free(tmp);
} }
@ -331954,6 +332007,8 @@ const struct in6_addr in6addr_loopback; /* ::1 */
#define chdir ifdef(cl, _chdir, chdir) #define chdir ifdef(cl, _chdir, chdir)
#if is(cl) || is(tcc) #if is(cl) || is(tcc)
#define ftruncate _chsize_s #define ftruncate _chsize_s
#define flockfile ifdef(cl,_lock_file,(void))
#define funlockfile ifdef(cl,_unlock_file,(void))
#endif #endif
#else // gcc #else // gcc
//#include <alloca.h> // mingw64 does not have it //#include <alloca.h> // mingw64 does not have it
@ -332316,8 +332371,8 @@ int audio_init( int flags ) {
ma_backend_wasapi, // Higest priority. ma_backend_wasapi, // Higest priority.
ma_backend_dsound, ma_backend_dsound,
ma_backend_winmm, ma_backend_winmm,
ma_backend_pulseaudio,
ma_backend_coreaudio, ma_backend_coreaudio,
ma_backend_pulseaudio,
ma_backend_alsa, ma_backend_alsa,
ma_backend_oss, ma_backend_oss,
ma_backend_jack, ma_backend_jack,
@ -335215,7 +335270,7 @@ int zipscan_diff( zip* old, array(struct fs) now ) {
uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found
int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp; int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp;
if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate) if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate)
printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, oldstamp,now[i].stamp); printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, (long long unsigned)oldstamp, (long long unsigned)now[i].stamp);
array_push(changed, STRDUP(now[i].fname)); array_push(changed, STRDUP(now[i].fname));
array_push(uncooked, STRDUP(now[i].fname)); array_push(uncooked, STRDUP(now[i].fname));
} }
@ -335511,8 +335566,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
// scan disk: all subfolders in ART (comma-separated) // scan disk: all subfolders in ART (comma-separated)
static array(char *) list = 0; // @leak static array(char *) list = 0; // @leak
for each_substring(ART, ",", art_folder) { for each_substring(ART, ",", art_folder) {
const char **glob = file_list(art_folder, "**"); array(char *) glob = file_list(va("%s**",art_folder)); // art_folder ends with '/'
for( unsigned i = 0; glob[i]; ++i ) { for( unsigned i = 0, end = array_count(glob); i < end; ++i ) {
const char *fname = glob[i]; const char *fname = glob[i];
if( !strmatchi(fname, masks)) continue; if( !strmatchi(fname, masks)) continue;
@ -335532,8 +335587,13 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
if( !memcmp(header, "\x64\x86", 2) ) continue; if( !memcmp(header, "\x64\x86", 2) ) continue;
if( !memcmp(header, "\x00\x00", 2) ) continue; if( !memcmp(header, "\x00\x00", 2) ) continue;
} }
// exclude vc/gcc files
if( strend(fname, ".a") || strend(fname, ".pdb") || strend(fname, ".lib") || strend(fname, ".ilk") || strend(fname, ".exp") ) { char *dot = strrchr(fname, '.');
if( dot ) {
char extdot[32];
snprintf(extdot, 32, "%s.", dot); // .png -> .png.
// exclude vc/gcc/clang files
if( strstr(fname, ".a.o.pdb.lib.ilk.exp.dSYM.") ) // must end with dot
continue; continue;
} }
@ -335594,8 +335654,7 @@ void cook_stop() {
if(jobs[i].self) thread_join(jobs[i].self); if(jobs[i].self) thread_join(jobs[i].self);
} }
// remove all temporary outfiles // remove all temporary outfiles
const char **temps = file_list("./", "temp_*"); for each_array(file_list("temp_*"), char*, tempfile) unlink(tempfile);
for( int i = 0; temps[i]; ++i ) unlink(temps[i]);
} }
int cook_progress() { int cook_progress() {
@ -336044,7 +336103,8 @@ bool file_append(const char *name, const void *ptr, int len) {
} }
return ok; return ok;
} }
static bool file_stat(const char *fname, struct stat *st) { static // not exposed
bool file_stat(const char *fname, struct stat *st) {
// remove ending slashes. win32+tcc does not like them. // remove ending slashes. win32+tcc does not like them.
int l = strlen(fname), m = l; int l = strlen(fname), m = l;
while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l; while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l;
@ -336165,7 +336225,7 @@ char *ext = strrchr(base, '.'); //if (ext) ext[0] = '\0'; // remove all extensio
} }
return va("%s", buffer); return va("%s", buffer);
} }
const char** file_list(const char *cwds, const char *masks) { array(char*) file_list(const char *pathmasks) {
static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ? static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ?
for( int i = 0; i < array_count(list); ++i ) { for( int i = 0; i < array_count(list); ++i ) {
@ -336173,7 +336233,16 @@ const char** file_list(const char *cwds, const char *masks) {
} }
array_resize(list, 0);//array_free(list); array_resize(list, 0);//array_free(list);
for each_substring(cwds,";",cwd) { for each_substring(pathmasks,";",pathmask) {
char *cwd = 0, *masks = 0;
char *slash = strrchr(pathmask, '/');
if( !slash ) cwd = "./", masks = pathmask;
else {
masks = va("%s", slash+1);
cwd = pathmask, slash[1] = '\0';
}
if( !masks[0] ) masks = "*";
ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd);
dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : "");
@ -336201,8 +336270,7 @@ const char** file_list(const char *cwds, const char *masks) {
} }
} }
array_push(list, 0); // terminator return list;
return (const char**)list;
} }
bool file_move(const char *src, const char *dst) { bool file_move(const char *src, const char *dst) {
@ -336549,15 +336617,8 @@ void vfs_reload() {
#else #else
// mount fused executables // mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""))); vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way // mount all zipfiles
for( int i = 0; i < JOBS_MAX; ++i) { for each_array( file_list("*.zip"), char*, file ) vfs_mount(file);
if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
if( vfs_mount(va("%s[%02x].zip", app, i)) ) continue;
if( vfs_mount(va("%s%02x.zip", app, i)) ) continue;
// if( vfs_mount(va("%s.%02x", app, i)) ) continue;
} */
// faster way
for( const char **file = file_list("./","*.zip"); *file; ++file) vfs_mount(*file);
#endif #endif
// vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress. // vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress.
@ -336570,7 +336631,7 @@ void vfs_reload() {
#define ARK1 'ArK\x1' #define ARK1 0x41724B31 // 'ArK1' in le, 0x314B7241 41 72 4B 31 otherwise
#define ARK1_PADDING (512 - 40) // 472 #define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__) #define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x) #define ARK_SWAP32(x) (x)
@ -336662,9 +336723,9 @@ const char** vfs_list(const char *masks) {
for each_substring(masks,";",it) { for each_substring(masks,";",it) {
if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file
for(const char **items = file_list("./", it); *items; items++) { for each_array(file_list(it), char*, item) {
// insert copy // insert copy
char *copy = STRDUP(*items); char *copy = STRDUP(item);
array_push(list, copy); array_push(list, copy);
} }
@ -336770,8 +336831,8 @@ if( found && *found == 0 ) {
folder = file_path(pathfile); folder = file_path(pathfile);
// ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav // ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav
// or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf // or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf
static array(char*) art_paths = 0; static __thread array(char*) art_paths = 0;
do_once for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem)); if(!art_paths) for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem));
char* pretty_folder = ""; char* pretty_folder = "";
if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) { if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) {
if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; } if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; }
@ -336822,7 +336883,7 @@ if( found && *found == 0 ) {
// this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s) // this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s)
#if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS #if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS
static set(char*) disk = 0; static set(char*) disk = 0;
if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for( const char **list = file_list(art_folder,"**"); *list; ++list) set_insert(disk, STRDUP(*list)); } if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for each_array(file_list(va("%s**", art_folder)), char*, item) set_insert(disk, STRDUP(item)); } // art_folder ends with '/'
int found = !!set_find(disk, (char*)pathfile); int found = !!set_find(disk, (char*)pathfile);
if( found ) if( found )
#endif #endif
@ -336935,23 +336996,28 @@ const char *vfs_extract(const char *pathfile) { // extract a vfs file into the l
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// cache // cache
static thread_mutex_t cache_mutex; AUTORUN{ thread_mutex_init(&cache_mutex); }
void* cache_lookup(const char *pathfile, int *size) { // find key->value void* cache_lookup(const char *pathfile, int *size) { // find key->value
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
void* data = 0;
thread_mutex_lock(&cache_mutex);
for(archive_dir *dir = dir_cache; dir; dir = dir->next) { for(archive_dir *dir = dir_cache; dir; dir = dir->next) {
if( !strcmp(dir->path, pathfile) ) { if( !strcmp(dir->path, pathfile) ) {
if(size) *size = dir->size; if(size) *size = dir->size;
return dir->data; data = dir->data;
break;
} }
} }
return 0; thread_mutex_unlock(&cache_mutex);
return data;
} }
void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
if( !ptr || !size ) return 0; if( !ptr || !size ) return 0;
// keep cached files within limits // keep cached files within limits
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &mutex); thread_mutex_lock(&cache_mutex);
thread_mutex_lock(&mutex);
// append to cache // append to cache
archive_dir zero = {0}, *old = dir_cache; archive_dir zero = {0}, *old = dir_cache;
@ -336981,7 +337047,7 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
} }
} }
thread_mutex_unlock(&mutex); thread_mutex_unlock(&cache_mutex);
return found; return found;
} }
@ -341907,7 +341973,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket >= 0 ) { if( socket >= 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -341924,7 +341990,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket > 0 ) { if( socket > 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -341935,7 +342001,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
} }
} }
PRINTF("Network rank:%lld ip:%s port:%lld\n", network_get(NETWORK_RANK), ip, network_get(NETWORK_PORT)); PRINTF("Network rank:%u ip:%s port:%d\n", (unsigned)network_get(NETWORK_RANK), ip, (int)network_get(NETWORK_PORT));
} }
int64_t network_put(uint64_t key, int64_t value) { int64_t network_put(uint64_t key, int64_t value) {
@ -342068,8 +342134,8 @@ char** server_poll(unsigned timeout_ms) {
*(uint32_t*)&init_msg[0] = MSG_INIT; *(uint32_t*)&init_msg[0] = MSG_INIT;
*(int64_t*)&init_msg[4] = client_id; *(int64_t*)&init_msg[4] = client_id;
server_send_bin(client_id, init_msg, 12); server_send_bin(client_id, init_msg, 12);
PRINTF("Client rank %lld for peer ::%s:%u\n", client_id, ip, event.peer->address.port); PRINTF("Client rank %u for peer ::%s:%u\n", (unsigned)client_id, ip, event.peer->address.port);
msg = va( "%d new client rank:%lld from ::%s:%u", 0, client_id, ip, event.peer->address.port ); msg = va( "%d new client rank:%u from ::%s:%u", 0, (unsigned)client_id, ip, event.peer->address.port );
event.peer->data = (void*)client_id; event.peer->data = (void*)client_id;
break; break;
@ -342125,7 +342191,7 @@ char** server_poll(unsigned timeout_ms) {
msg = va("%d %s", 0, va("%s", ptr)); msg = va("%d %s", 0, va("%s", ptr));
} break; } break;
default: default:
msg = va("%d unk msg len:%u from rank:%lld ::%s:%u", -1, sz, (uint64_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */ msg = va("%d unk msg len:%u from rank:%u ::%s:%u", -1, sz, (unsigned)(uintptr_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */
break; break;
} }
/* Clean up the packet now that we're done using it. */ /* Clean up the packet now that we're done using it. */
@ -342133,7 +342199,7 @@ char** server_poll(unsigned timeout_ms) {
} break; } break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
msg = va( "%d disconnect rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d disconnect rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
/* Reset the peer's client information. */ /* Reset the peer's client information. */
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
@ -342142,7 +342208,7 @@ char** server_poll(unsigned timeout_ms) {
break; break;
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
msg = va( "%d timeout rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d timeout rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
server_drop_client_peer(event.peer); server_drop_client_peer(event.peer);
@ -343850,10 +343916,10 @@ AUTOTEST {
// iterate reflected struct // iterate reflected struct
for each_member("MyVec4", R) { for each_member("MyVec4", R) {
printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info); // printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info);
} }
reflected_printf_all(); // reflected_printf_all();
} }
#line 0 #line 0
@ -343964,9 +344030,10 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
const char *glsl_version = ifdef(ems, "300 es", "150"); const char *glsl_version = ifdef(ems, "300 es", "150");
vs = vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : ""); if(gs)
fs = fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : ""); gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
if (gs) gs = gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : ""); vs = vs && vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : "");
fs = fs && fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : "");
#if is(ems) #if is(ems)
{ {
@ -350498,9 +350565,10 @@ const char *app_path() { // @fixme: should return absolute path always. see tcc
strcat(buffer, "..\\..\\"); strcat(buffer, "..\\..\\");
} }
#else // #elif is(linux) #else // #elif is(linux)
char path[21] = {0}; char path[32] = {0};
sprintf(path, "/proc/%d/exe", getpid()); sprintf(path, "/proc/%d/exe", getpid());
readlink(path, buffer, sizeof(buffer)); readlink(path, buffer, sizeof(buffer));
if(strrchr(buffer,'/')) 1[strrchr(buffer,'/')] = '\0';
#endif #endif
return buffer; return buffer;
} }
@ -351203,15 +351271,15 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line); char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line);
int cols = tty_cols() + 1 - (int)strlen(location); int cols = tty_cols() + 1 - (int)strlen(location);
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock); flockfile(stdout);
thread_mutex_lock( &lock );
tty_color(color); tty_color(color);
printf("\r%*.s%s", cols, "", location); printf("\r%*.s%s", cols, "", location);
printf("\r%07.3fs|%s%s", secs, text, stack); printf("\r%07.3fs|%s%s", secs, text, stack);
tty_color(0); tty_color(0);
thread_mutex_unlock( &lock ); funlockfile(stdout);
return 1; return 1;
} }
@ -351599,20 +351667,20 @@ static void nk_config_custom_fonts() {
nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas); nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas);
// Default font(#1)... // Default font(#1)...
int datalen = 0;
for( char *data = vfs_read(UI_FONT_REGULAR); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) {
float font_size = UI_FONT_REGULAR_SIZE; float font_size = UI_FONT_REGULAR_SIZE;
struct nk_font_config cfg = nk_font_config(font_size); struct nk_font_config cfg = nk_font_config(font_size);
cfg.oversample_v = 2; cfg.oversample_v = 2;
cfg.pixel_snap = 0; cfg.pixel_snap = 0;
// win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font;
// struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font;
struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_REGULAR), font_size, &cfg); font = regular ? regular : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font;
} }
// ...with icons embedded on it. // ...with icons embedded on it.
for( char *data = vfs_read(UI_FONT_ICONS); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_ICONS, &datalen); data; data = 0 ) {
static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}; static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0};
struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE); struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE);
@ -351628,12 +351696,12 @@ static void nk_config_custom_fonts() {
cfg.oversample_v = 1; cfg.oversample_v = 1;
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_ICONS), UI_ICON_FONTSIZE, &cfg); struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg);
} }
// Monospaced font. Used in terminals or consoles. // Monospaced font. Used in terminals or consoles.
for( char *data = vfs_read(UI_FONT_TERMINAL); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) {
const float font_size = UI_FONT_REGULAR_SIZE; const float font_size = UI_FONT_REGULAR_SIZE;
static const nk_rune icon_range[] = {32, 127, 0}; static const nk_rune icon_range[] = {32, 127, 0};
@ -351645,13 +351713,13 @@ static void nk_config_custom_fonts() {
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
// struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg);
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_TERMINAL), font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg);
} }
// Extra optional fonts from here... // Extra optional fonts from here...
for( char *data = vfs_read(UI_FONT_HEADING); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) {
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_HEADING), UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font;
} }
nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end();
@ -355278,11 +355346,16 @@ void window_color(unsigned color) {
unsigned a = (color >> 24) & 255; unsigned a = (color >> 24) & 255;
winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0); winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
} }
static int has_icon;
int window_has_icon() {
return has_icon;
}
void window_icon(const char *file_icon) { void window_icon(const char *file_icon) {
unsigned len = file_size(file_icon); len = len ? len : vfs_size(file_icon); int len = 0;
if( len ) { void *data = vfs_load(file_icon, &len);
void *data = file_read(file_icon); data = data ? data : vfs_read(file_icon); if( !data ) data = file_read(file_icon), len = file_size(file_icon);
if( data ) {
if( data && len ) {
image_t img = image_from_mem(data, len, IMAGE_RGBA); image_t img = image_from_mem(data, len, IMAGE_RGBA);
if( img.w && img.h && img.pixels ) { if( img.w && img.h && img.pixels ) {
GLFWimage images[1]; GLFWimage images[1];
@ -355290,11 +355363,11 @@ void window_icon(const char *file_icon) {
images[0].height = img.h; images[0].height = img.h;
images[0].pixels = img.pixels; images[0].pixels = img.pixels;
glfwSetWindowIcon(window, 1, images); glfwSetWindowIcon(window, 1, images);
has_icon = 1;
return; return;
} }
} }
} #if 0 // is(win32)
#if is(win32)
HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
if( hIcon ) { if( hIcon ) {
HWND hWnd = glfwGetWin32Window(window); HWND hWnd = glfwGetWin32Window(window);
@ -355302,6 +355375,7 @@ void window_icon(const char *file_icon) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
has_icon = 1;
return; return;
} }
#endif #endif
@ -355667,7 +355741,7 @@ vec3 get_voxel_for_boid(float perception_radius, const boid_t *b) { // quantize
static static
void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) { void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) {
for each_array_ptr(voxel_cached, const boid_t*, test) { for each_array_ptr(voxel_cached, boid_t*, test) {
vec3 p1 = b->position; vec3 p1 = b->position;
vec3 p2 = (*test)->position; vec3 p2 = (*test)->position;
vec3 vec = sub3(p2, p1); vec3 vec = sub3(p2, p1);
@ -355680,7 +355754,7 @@ void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_com
compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2); compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2);
} }
if ((&b) != test && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) { if (b != (*test) && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) {
nearby_boid_t nb; nearby_boid_t nb;
nb.boid = (boid_t*)*test; nb.boid = (boid_t*)*test;
nb.distance = distance; nb.distance = distance;
@ -356243,7 +356317,7 @@ int pathfind_astar(int width, int height, const unsigned* map, vec2i src, vec2i
// [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2) // [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2)
// [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false) // [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false)
// [ ] HasTags(names=blank,bAllRequired=true) // [ ] HasTags(names=blank,bAllRequired=true)
// [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesnt exist, and stores it in the passed variable name, and then pushes item object onto it. // [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesn't exist, and stores it in the passed variable name, and then pushes 'item' 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. // [ ] 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. // [ ] 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. // [ ] 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.
@ -356911,48 +356985,41 @@ int main() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static void v4k_pre_init() { static void v4k_pre_init() {
const char *appname = app_name(); window_icon(va("%s%s.png", app_path(), app_name()));
const char *appdir = app_path();
window_icon(va("%s/%s.png", appdir, appname));
ifdef(win32,window_icon(va("%s/%s.ico", appdir, appname)));
glfwPollEvents(); glfwPollEvents();
int i; int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 6; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up /**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init(); else if( i == 1 ) sprite_init();
else if( i == 2 ) profiler_init(); else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
else if( i == 4 ) audio_init(0);
else if( i == 5 ) script_init(), kit_init(), midi_init();
else if( i == 6 ) network_init();
} }
// window_swap(); // window_swap();
} }
static void v4k_post_init(float refresh_rate) { static void v4k_post_init(float refresh_rate) {
int i;
// cook cleanup // cook cleanup
cook_stop(); cook_stop();
vfs_reload(); vfs_reload();
// init subsystems that depend on cooked assets now. ui_init() is special case and needs to be safely in single thread // init subsystems that depend on cooked assets now
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 2; ++i ) {
/**/ if( i == 0 ) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up if(i == 0) ui_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) audio_init(0); // initialize audio after cooking // reasoning for this: do not launch audio threads while cooks are in progress, so there is more cpu for cooking actually if(i == 0) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 2 ) script_init(), kit_init(), midi_init(); if(i == 1) input_init();
else if( i == 3 ) input_init(), network_init(); if(i == 2) window_icon(va("%s.png", app_name()));
} }
const char *appname = app_name();
window_icon(va("%s.png", appname));
window_icon(va("%s.ico", appname));
// display window // display window
glfwShowWindow(window); glfwShowWindow(window);
glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h);

View File

@ -594,10 +594,10 @@ bool zip_append_file_timeinfo(zip *z, const char *entryname, const char *comment
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
fseek(in, 0, SEEK_SET); // rewind fseek(in, 0, SEEK_SET); // rewind
@ -705,10 +705,10 @@ bool zip_append_mem_timeinfo(zip *z, const char *entryname, const char *comment,
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
size_t bytes = inlen; size_t bytes = inlen;
@ -756,30 +756,46 @@ common:;
// zip common // zip common
#if 1
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
#else
# if (defined(__TINYC__) && defined(_WIN32))
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
# elif defined _MSC_VER
# define zip_lockfile(f) _lock_file(f)
# define zip_unlockfile(f) _unlock_file(f)
# else
# define zip_lockfile(f) flockfile(f)
# define zip_unlockfile(f) funlockfile(f)
# endif
#endif
zip* zip_open_handle(FILE *fp, const char *mode) { zip* zip_open_handle(FILE *fp, const char *mode) {
if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode); if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode);
zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip)); zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip));
if( !z ) return fclose(fp), ERR(NULL, "out of mem"); else *z = zero; if( !z ) return ERR(NULL, "out of mem"); else *z = zero;
if( mode[0] == 'w' ) { if( mode[0] == 'w' ) {
z->out = fp; zip_lockfile(z->out = fp);
return z; return z;
} }
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; zip_lockfile(z->in = fp);
unsigned long long seekcur = ftell(z->in); unsigned long long seekcur = ftell(z->in);
JZEndRecord jzEndRecord = {0}; JZEndRecord jzEndRecord = {0};
if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) { if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file end record."); return ERR(NULL, "Couldn't read ZIP file end record.");
} }
jzEndRecord.centralDirectoryOffset += seekcur; jzEndRecord.centralDirectoryOffset += seekcur;
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) { if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory."); return ERR(NULL, "Couldn't read ZIP file central directory.");
} }
if( mode[0] == 'a' ) { if( mode[0] == 'a' ) {
@ -796,13 +812,13 @@ zip* zip_open_handle(FILE *fp, const char *mode) {
fseek( fp, 0L, SEEK_END ); fseek( fp, 0L, SEEK_END );
} }
z->out = z->in;
z->in = NULL; z->in = NULL;
z->out = fp;
} }
return z; return z;
} }
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
@ -810,7 +826,11 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
int exists = (stat(file, &buffer) == 0); int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb"; if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb"); FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode); if (!fp) return NULL;
if (mode[0] == 'a') fseek(fp, 0L, SEEK_SET);
zip *z = zip_open_handle(fp, mode);
if (!z) return fclose(fp), NULL;
return z;
} }
void zip_close(zip* z) { void zip_close(zip* z) {
@ -838,8 +858,8 @@ void zip_close(zip* z) {
// flush end record // flush end record
fwrite(&end, 1, sizeof(end), z->out); fwrite(&end, 1, sizeof(end), z->out);
} }
if( z->out ) fclose(z->out); if( z->out ) zip_unlockfile(z->out), fclose(z->out);
if( z->in ) fclose(z->in); if( z->in ) zip_unlockfile(z->in), fclose(z->in);
// clean up // clean up
for(unsigned i = 0; i < z->count; ++i ) { for(unsigned i = 0; i < z->count; ++i ) {
REALLOC(z->entries[i].filename, 0); REALLOC(z->entries[i].filename, 0);

View File

@ -251,9 +251,11 @@ char *json5__parse_value(json5 *obj, char *p, char **err_code) {
*buf++ = *p++; *buf++ = *p++;
} }
obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER; obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER;
long long unsigned int llu;
long long int lli;
/**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real ); /**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real );
else if( is_hex ) sscanf( buffer, "%llx", &obj->integer ); // SCNx64 -> inttypes.h else if( is_hex ) sscanf( buffer, "%llx", &llu ), obj->integer = llu; // SCNx64 -> inttypes.h
else sscanf( buffer, "%lld", &obj->integer ); // SCNd64 -> inttypes.h else sscanf( buffer, "%lld", &lli ), obj->integer = lli; // SCNd64 -> inttypes.h
} }
else { else {
return NULL; return NULL;
@ -305,7 +307,7 @@ void json5_write(FILE *fp, const json5 *o) {
} }
/**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null"); /**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null");
else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false"); else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false");
else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", o->integer); else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", (long long int)o->integer);
else if( o->type == JSON5_REAL ) { else if( o->type == JSON5_REAL ) {
/**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" ); /**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" );
else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" ); else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" );

View File

@ -117,8 +117,8 @@ static void browser_reload_directory_content(struct browser *browser, const char
BROWSER_PRINTF("searching at %s\n", path); BROWSER_PRINTF("searching at %s\n", path);
const char **list = file_list(path, "*"); array(char*) list = file_list(path);
for( int i = 0; list[i]; ++i ) { for( int i = 0, end = array_count(list); i < end; ++i ) {
char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext
BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) );

View File

@ -12,7 +12,7 @@
static inline void array_find_and_remove(array(int) arr, int v) { static inline void array_find_and_remove(array(int) arr, int v) {
for( int i = 0, end = array_count(arr); i < end; i++ ) for( int i = 0, end = array_count(arr); i < end; i++ )
if( arr[i] == v ) { array_erase(arr, i); --end; break; } if( arr[i] == v ) { array_erase_fast(arr, i); --end; break; }
} }
#include <assert.h> #include <assert.h>
@ -126,7 +126,7 @@ static void RemoveIfNonNeighbor_(struct mesh *M, struct vertex *v, int id) {
return; return;
} }
// remove from neighbors // remove from neighbors
array_erase(v->neighbor, i); array_erase_fast(v->neighbor, i);
return; return;
} }
} }
@ -289,7 +289,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
} }
array(int) tmp = 0; array(int) tmp = 0;
// make tmp a Array of all the neighbors of u // make tmp a Array of all the neighbors of u
for (int i = 0; i<array_count(u->neighbor); i++) { for (int i = 0; i<array_count(u->neighbor); i++) {
array_push(tmp, u->neighbor[i]); array_push(tmp, u->neighbor[i]);
@ -309,7 +309,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
for (int i = 0; i<array_count(tmp); i++) { for (int i = 0; i<array_count(tmp); i++) {
ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i])); ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i]));
} }
array_free(tmp); array_free(tmp);
} }

View File

@ -51,7 +51,7 @@ vec3 get_voxel_for_boid(float perception_radius, const boid_t *b) { // quantize
static static
void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) { void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) {
for each_array_ptr(voxel_cached, const boid_t*, test) { for each_array_ptr(voxel_cached, boid_t*, test) {
vec3 p1 = b->position; vec3 p1 = b->position;
vec3 p2 = (*test)->position; vec3 p2 = (*test)->position;
vec3 vec = sub3(p2, p1); vec3 vec = sub3(p2, p1);
@ -64,7 +64,7 @@ void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_com
compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2); compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2);
} }
if ((&b) != test && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) { if (b != (*test) && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) {
nearby_boid_t nb; nearby_boid_t nb;
nb.boid = (boid_t*)*test; nb.boid = (boid_t*)*test;
nb.distance = distance; nb.distance = distance;

View File

@ -276,8 +276,8 @@ int audio_init( int flags ) {
ma_backend_wasapi, // Higest priority. ma_backend_wasapi, // Higest priority.
ma_backend_dsound, ma_backend_dsound,
ma_backend_winmm, ma_backend_winmm,
ma_backend_pulseaudio,
ma_backend_coreaudio, ma_backend_coreaudio,
ma_backend_pulseaudio,
ma_backend_alsa, ma_backend_alsa,
ma_backend_oss, ma_backend_oss,
ma_backend_jack, ma_backend_jack,

View File

@ -51,7 +51,7 @@
// [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2) // [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2)
// [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false) // [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false)
// [ ] HasTags(names=blank,bAllRequired=true) // [ ] HasTags(names=blank,bAllRequired=true)
// [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesnt exist, and stores it in the passed variable name, and then pushes item object onto it. // [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesn't exist, and stores it in the passed variable name, and then pushes 'item' 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. // [ ] 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. // [ ] 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. // [ ] 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.

View File

@ -31,6 +31,8 @@ const struct in6_addr in6addr_loopback; /* ::1 */
#define chdir ifdef(cl, _chdir, chdir) #define chdir ifdef(cl, _chdir, chdir)
#if is(cl) || is(tcc) #if is(cl) || is(tcc)
#define ftruncate _chsize_s #define ftruncate _chsize_s
#define flockfile ifdef(cl,_lock_file,(void))
#define funlockfile ifdef(cl,_unlock_file,(void))
#endif #endif
#else // gcc #else // gcc
//#include <alloca.h> // mingw64 does not have it //#include <alloca.h> // mingw64 does not have it

View File

@ -25,8 +25,8 @@
#define ENABLE_LINUX_CALLSTACKS 0 ///+ #define ENABLE_LINUX_CALLSTACKS 0 ///+
#endif #endif
#ifndef ENABLE_TESTS #ifndef ENABLE_AUTOTESTS
#define ENABLE_TESTS 0 // ifdef(debug, 1, 0) ///+ #define ENABLE_AUTOTESTS ifdef(debug, 1, 0) ///+
#endif #endif
#ifndef ENABLE_RETAIL #ifndef ENABLE_RETAIL
@ -117,15 +117,6 @@
#define ifdef_release ifdef_false #define ifdef_release ifdef_false
#endif #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
#if ENABLE_RETAIL #if ENABLE_RETAIL
#define ifdef_retail ifdef_true #define ifdef_retail ifdef_true
#else #else
@ -138,6 +129,37 @@
#define ifdef_nocook ifdef_false #define ifdef_nocook ifdef_false
#endif #endif
#if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3
#define ifdef_O3 ifdef_true
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 2
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_true
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 1
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_true
#define ifdef_O0 ifdef_false
#else
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_true
#endif
#include <stdint.h>
#if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
#define ifdef_64 ifdef_true
#define ifdef_32 ifdef_false
#else
#define ifdef_64 ifdef_false
#define ifdef_32 ifdef_true
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// new C keywords // new C keywords
@ -166,8 +188,13 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// new C macros // new C macros
#if ENABLE_RETAIL
#define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0
#else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT(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 ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
#endif
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_)
#define FILELINE __FILE__ ":" STRINGIZE(__LINE__) #define FILELINE __FILE__ ":" STRINGIZE(__LINE__)

View File

@ -398,7 +398,7 @@ int zipscan_diff( zip* old, array(struct fs) now ) {
uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found
int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp; int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp;
if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate) if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate)
printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, oldstamp,now[i].stamp); printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, (long long unsigned)oldstamp, (long long unsigned)now[i].stamp);
array_push(changed, STRDUP(now[i].fname)); array_push(changed, STRDUP(now[i].fname));
array_push(uncooked, STRDUP(now[i].fname)); array_push(uncooked, STRDUP(now[i].fname));
} }
@ -694,8 +694,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
// scan disk: all subfolders in ART (comma-separated) // scan disk: all subfolders in ART (comma-separated)
static array(char *) list = 0; // @leak static array(char *) list = 0; // @leak
for each_substring(ART, ",", art_folder) { for each_substring(ART, ",", art_folder) {
const char **glob = file_list(art_folder, "**"); array(char *) glob = file_list(va("%s**",art_folder)); // art_folder ends with '/'
for( unsigned i = 0; glob[i]; ++i ) { for( unsigned i = 0, end = array_count(glob); i < end; ++i ) {
const char *fname = glob[i]; const char *fname = glob[i];
if( !strmatchi(fname, masks)) continue; if( !strmatchi(fname, masks)) continue;
@ -715,8 +715,13 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
if( !memcmp(header, "\x64\x86", 2) ) continue; if( !memcmp(header, "\x64\x86", 2) ) continue;
if( !memcmp(header, "\x00\x00", 2) ) continue; if( !memcmp(header, "\x00\x00", 2) ) continue;
} }
// exclude vc/gcc files
if( strend(fname, ".a") || strend(fname, ".pdb") || strend(fname, ".lib") || strend(fname, ".ilk") || strend(fname, ".exp") ) { char *dot = strrchr(fname, '.');
if( dot ) {
char extdot[32];
snprintf(extdot, 32, "%s.", dot); // .png -> .png.
// exclude vc/gcc/clang files
if( strstr(fname, ".a.o.pdb.lib.ilk.exp.dSYM.") ) // must end with dot
continue; continue;
} }
@ -777,8 +782,7 @@ void cook_stop() {
if(jobs[i].self) thread_join(jobs[i].self); if(jobs[i].self) thread_join(jobs[i].self);
} }
// remove all temporary outfiles // remove all temporary outfiles
const char **temps = file_list("./", "temp_*"); for each_array(file_list("temp_*"), char*, tempfile) unlink(tempfile);
for( int i = 0; temps[i]; ++i ) unlink(temps[i]);
} }
int cook_progress() { int cook_progress() {

View File

@ -90,14 +90,16 @@ static __thread unsigned array_n_;
} while(0) } while(0)
#define array_foreach(t,val_t,v) for each_array(t,val_t,v) #define array_foreach(t,val_t,v) for each_array(t,val_t,v)
#define each_array(t,val_t,v) \ #define each_array(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t v = __it[t], *on__ = &v; on__; on__ = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 )
#define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v) #define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v)
#define each_array_ptr(t,val_t,v) \ #define each_array_ptr(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t *v = (val_t*)&__it[t]; v; v = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t *v = (val_t*)&i_[a_]; v; v = 0 )
#define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \ #define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \
bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn ) bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn )
@ -113,13 +115,13 @@ static __thread unsigned array_n_;
} \ } \
} while(0) } while(0)
#define array_copy(t, src) do { /*todo: review old vrealloc call!*/ \ #define array_copy(t, src) do { \
array_free(t); \ array_free(t); \
(t) = array_realloc_( (t), array_count(src)); \ (t) = array_realloc_( (t), array_count(src)); \
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_swapback_and_pop(t, i) do { /*may alter ordering*/ \ #define array_erase_fast(t, i) do { /*may alter ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)

View File

@ -79,7 +79,8 @@ bool file_append(const char *name, const void *ptr, int len) {
} }
return ok; return ok;
} }
static bool file_stat(const char *fname, struct stat *st) { static // not exposed
bool file_stat(const char *fname, struct stat *st) {
// remove ending slashes. win32+tcc does not like them. // remove ending slashes. win32+tcc does not like them.
int l = strlen(fname), m = l; int l = strlen(fname), m = l;
while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l; while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l;
@ -200,7 +201,7 @@ char *ext = strrchr(base, '.'); //if (ext) ext[0] = '\0'; // remove all extensio
} }
return va("%s", buffer); return va("%s", buffer);
} }
const char** file_list(const char *cwds, const char *masks) { array(char*) file_list(const char *pathmasks) {
static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ? static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ?
for( int i = 0; i < array_count(list); ++i ) { for( int i = 0; i < array_count(list); ++i ) {
@ -208,7 +209,16 @@ const char** file_list(const char *cwds, const char *masks) {
} }
array_resize(list, 0);//array_free(list); array_resize(list, 0);//array_free(list);
for each_substring(cwds,";",cwd) { for each_substring(pathmasks,";",pathmask) {
char *cwd = 0, *masks = 0;
char *slash = strrchr(pathmask, '/');
if( !slash ) cwd = "./", masks = pathmask;
else {
masks = va("%s", slash+1);
cwd = pathmask, slash[1] = '\0';
}
if( !masks[0] ) masks = "*";
ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd);
dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : "");
@ -236,8 +246,7 @@ const char** file_list(const char *cwds, const char *masks) {
} }
} }
array_push(list, 0); // terminator return list;
return (const char**)list;
} }
bool file_move(const char *src, const char *dst) { bool file_move(const char *src, const char *dst) {
@ -584,15 +593,8 @@ void vfs_reload() {
#else #else
// mount fused executables // mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""))); vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way // mount all zipfiles
for( int i = 0; i < JOBS_MAX; ++i) { for each_array( file_list("*.zip"), char*, file ) vfs_mount(file);
if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
if( vfs_mount(va("%s[%02x].zip", app, i)) ) continue;
if( vfs_mount(va("%s%02x.zip", app, i)) ) continue;
// if( vfs_mount(va("%s.%02x", app, i)) ) continue;
} */
// faster way
for( const char **file = file_list("./","*.zip"); *file; ++file) vfs_mount(*file);
#endif #endif
// vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress. // vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress.
@ -605,7 +607,7 @@ void vfs_reload() {
#define ARK1 'ArK\x1' #define ARK1 0x41724B31 // 'ArK1' in le, 0x314B7241 41 72 4B 31 otherwise
#define ARK1_PADDING (512 - 40) // 472 #define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__) #define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x) #define ARK_SWAP32(x) (x)
@ -697,9 +699,9 @@ const char** vfs_list(const char *masks) {
for each_substring(masks,";",it) { for each_substring(masks,";",it) {
if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file
for(const char **items = file_list("./", it); *items; items++) { for each_array(file_list(it), char*, item) {
// insert copy // insert copy
char *copy = STRDUP(*items); char *copy = STRDUP(item);
array_push(list, copy); array_push(list, copy);
} }
@ -805,8 +807,8 @@ if( found && *found == 0 ) {
folder = file_path(pathfile); folder = file_path(pathfile);
// ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav // ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav
// or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf // or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf
static array(char*) art_paths = 0; static __thread array(char*) art_paths = 0;
do_once for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem)); if(!art_paths) for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem));
char* pretty_folder = ""; char* pretty_folder = "";
if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) { if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) {
if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; } if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; }
@ -857,7 +859,7 @@ if( found && *found == 0 ) {
// this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s) // this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s)
#if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS #if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS
static set(char*) disk = 0; static set(char*) disk = 0;
if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for( const char **list = file_list(art_folder,"**"); *list; ++list) set_insert(disk, STRDUP(*list)); } if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for each_array(file_list(va("%s**", art_folder)), char*, item) set_insert(disk, STRDUP(item)); } // art_folder ends with '/'
int found = !!set_find(disk, (char*)pathfile); int found = !!set_find(disk, (char*)pathfile);
if( found ) if( found )
#endif #endif
@ -970,23 +972,28 @@ const char *vfs_extract(const char *pathfile) { // extract a vfs file into the l
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// cache // cache
static thread_mutex_t cache_mutex; AUTORUN{ thread_mutex_init(&cache_mutex); }
void* cache_lookup(const char *pathfile, int *size) { // find key->value void* cache_lookup(const char *pathfile, int *size) { // find key->value
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
void* data = 0;
thread_mutex_lock(&cache_mutex);
for(archive_dir *dir = dir_cache; dir; dir = dir->next) { for(archive_dir *dir = dir_cache; dir; dir = dir->next) {
if( !strcmp(dir->path, pathfile) ) { if( !strcmp(dir->path, pathfile) ) {
if(size) *size = dir->size; if(size) *size = dir->size;
return dir->data; data = dir->data;
break;
} }
} }
return 0; thread_mutex_unlock(&cache_mutex);
return data;
} }
void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
if( !ptr || !size ) return 0; if( !ptr || !size ) return 0;
// keep cached files within limits // keep cached files within limits
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &mutex); thread_mutex_lock(&cache_mutex);
thread_mutex_lock(&mutex);
// append to cache // append to cache
archive_dir zero = {0}, *old = dir_cache; archive_dir zero = {0}, *old = dir_cache;
@ -1016,7 +1023,7 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
} }
} }
thread_mutex_unlock(&mutex); thread_mutex_unlock(&cache_mutex);
return found; return found;
} }

View File

@ -10,7 +10,7 @@
// physical filesystem. files // physical filesystem. files
API const char** file_list(const char *path, const char *masks); // **.png;*.c API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c
API bool file_write( const char *file, const void *ptr, int len ); API bool file_write( const char *file, const void *ptr, int len );
API bool file_append( 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_read(const char *filename);

View File

@ -1,48 +1,41 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static void v4k_pre_init() { static void v4k_pre_init() {
const char *appname = app_name(); window_icon(va("%s%s.png", app_path(), app_name()));
const char *appdir = app_path();
window_icon(va("%s/%s.png", appdir, appname));
ifdef(win32,window_icon(va("%s/%s.ico", appdir, appname)));
glfwPollEvents(); glfwPollEvents();
int i; int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 6; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up /**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init(); else if( i == 1 ) sprite_init();
else if( i == 2 ) profiler_init(); else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
else if( i == 4 ) audio_init(0);
else if( i == 5 ) script_init(), kit_init(), midi_init();
else if( i == 6 ) network_init();
} }
// window_swap(); // window_swap();
} }
static void v4k_post_init(float refresh_rate) { static void v4k_post_init(float refresh_rate) {
int i;
// cook cleanup // cook cleanup
cook_stop(); cook_stop();
vfs_reload(); vfs_reload();
// init subsystems that depend on cooked assets now. ui_init() is special case and needs to be safely in single thread // init subsystems that depend on cooked assets now
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 2; ++i ) {
/**/ if( i == 0 ) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up if(i == 0) ui_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) audio_init(0); // initialize audio after cooking // reasoning for this: do not launch audio threads while cooks are in progress, so there is more cpu for cooking actually if(i == 0) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 2 ) script_init(), kit_init(), midi_init(); if(i == 1) input_init();
else if( i == 3 ) input_init(), network_init(); if(i == 2) window_icon(va("%s.png", app_name()));
} }
const char *appname = app_name();
window_icon(va("%s.png", appname));
window_icon(va("%s.ico", appname));
// display window // display window
glfwShowWindow(window); glfwShowWindow(window);
glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h);

View File

@ -305,7 +305,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket >= 0 ) { if( socket >= 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -322,7 +322,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket > 0 ) { if( socket > 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -333,7 +333,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
} }
} }
PRINTF("Network rank:%lld ip:%s port:%lld\n", network_get(NETWORK_RANK), ip, network_get(NETWORK_PORT)); PRINTF("Network rank:%u ip:%s port:%d\n", (unsigned)network_get(NETWORK_RANK), ip, (int)network_get(NETWORK_PORT));
} }
int64_t network_put(uint64_t key, int64_t value) { int64_t network_put(uint64_t key, int64_t value) {
@ -466,8 +466,8 @@ char** server_poll(unsigned timeout_ms) {
*(uint32_t*)&init_msg[0] = MSG_INIT; *(uint32_t*)&init_msg[0] = MSG_INIT;
*(int64_t*)&init_msg[4] = client_id; *(int64_t*)&init_msg[4] = client_id;
server_send_bin(client_id, init_msg, 12); server_send_bin(client_id, init_msg, 12);
PRINTF("Client rank %lld for peer ::%s:%u\n", client_id, ip, event.peer->address.port); PRINTF("Client rank %u for peer ::%s:%u\n", (unsigned)client_id, ip, event.peer->address.port);
msg = va( "%d new client rank:%lld from ::%s:%u", 0, client_id, ip, event.peer->address.port ); msg = va( "%d new client rank:%u from ::%s:%u", 0, (unsigned)client_id, ip, event.peer->address.port );
event.peer->data = (void*)client_id; event.peer->data = (void*)client_id;
break; break;
@ -523,7 +523,7 @@ char** server_poll(unsigned timeout_ms) {
msg = va("%d %s", 0, va("%s", ptr)); msg = va("%d %s", 0, va("%s", ptr));
} break; } break;
default: default:
msg = va("%d unk msg len:%u from rank:%lld ::%s:%u", -1, sz, (uint64_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */ msg = va("%d unk msg len:%u from rank:%u ::%s:%u", -1, sz, (unsigned)(uintptr_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */
break; break;
} }
/* Clean up the packet now that we're done using it. */ /* Clean up the packet now that we're done using it. */
@ -531,7 +531,7 @@ char** server_poll(unsigned timeout_ms) {
} break; } break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
msg = va( "%d disconnect rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d disconnect rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
/* Reset the peer's client information. */ /* Reset the peer's client information. */
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
@ -540,7 +540,7 @@ char** server_poll(unsigned timeout_ms) {
break; break;
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
msg = va( "%d timeout rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d timeout rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
server_drop_client_peer(event.peer); server_drop_client_peer(event.peer);

View File

@ -102,8 +102,8 @@ AUTOTEST {
// iterate reflected struct // iterate reflected struct
for each_member("MyVec4", R) { for each_member("MyVec4", R) {
printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info); // printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info);
} }
reflected_printf_all(); // reflected_printf_all();
} }

View File

@ -104,9 +104,10 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
const char *glsl_version = ifdef(ems, "300 es", "150"); const char *glsl_version = ifdef(ems, "300 es", "150");
vs = vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : ""); if(gs)
fs = fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : ""); gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
if (gs) gs = gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : ""); vs = vs && vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : "");
fs = fs && fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : "");
#if is(ems) #if is(ems)
{ {

View File

@ -18,9 +18,10 @@ const char *app_path() { // @fixme: should return absolute path always. see tcc
strcat(buffer, "..\\..\\"); strcat(buffer, "..\\..\\");
} }
#else // #elif is(linux) #else // #elif is(linux)
char path[21] = {0}; char path[32] = {0};
sprintf(path, "/proc/%d/exe", getpid()); sprintf(path, "/proc/%d/exe", getpid());
readlink(path, buffer, sizeof(buffer)); readlink(path, buffer, sizeof(buffer));
if(strrchr(buffer,'/')) 1[strrchr(buffer,'/')] = '\0';
#endif #endif
return buffer; return buffer;
} }
@ -723,15 +724,15 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line); char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line);
int cols = tty_cols() + 1 - (int)strlen(location); int cols = tty_cols() + 1 - (int)strlen(location);
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock); flockfile(stdout);
thread_mutex_lock( &lock );
tty_color(color); tty_color(color);
printf("\r%*.s%s", cols, "", location); printf("\r%*.s%s", cols, "", location);
printf("\r%07.3fs|%s%s", secs, text, stack); printf("\r%07.3fs|%s%s", secs, text, stack);
tty_color(0); tty_color(0);
thread_mutex_unlock( &lock ); funlockfile(stdout);
return 1; return 1;
} }

View File

@ -62,18 +62,13 @@ API void trap_on_debug(int signal); // helper util
#define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ? #define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ?
API int (PANIC)(const char *error, const char *file, int line); API int (PANIC)(const char *error, const char *file, int line);
#if !ENABLE_RETAIL
#define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__) #define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__)
API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function); API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function);
#define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr)) #define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr))
API int (test)(const char *file, int line, const char *expr, bool result); API int (test)(const char *file, int line, const char *expr, bool result);
#else
#define PRINTF(...)
#define test(expr)
#endif
#if ENABLE_TESTS #if ENABLE_AUTOTESTS
#define AUTOTEST AUTORUN #define AUTOTEST AUTORUN
#else #else
#define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)() #define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)()
@ -81,3 +76,9 @@ API int (test)(const char *file, int line, const char *expr, bool result);
// AUTOTEST { test(1<2); } // AUTOTEST { test(1<2); }
#if ENABLE_RETAIL
#undef PRINTF
#define PRINTF(...) 0
#undef test
#define test(expr) 0
#endif

View File

@ -64,20 +64,20 @@ static void nk_config_custom_fonts() {
nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas); nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas);
// Default font(#1)... // Default font(#1)...
int datalen = 0;
for( char *data = vfs_read(UI_FONT_REGULAR); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) {
float font_size = UI_FONT_REGULAR_SIZE; float font_size = UI_FONT_REGULAR_SIZE;
struct nk_font_config cfg = nk_font_config(font_size); struct nk_font_config cfg = nk_font_config(font_size);
cfg.oversample_v = 2; cfg.oversample_v = 2;
cfg.pixel_snap = 0; cfg.pixel_snap = 0;
// win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font;
// struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font;
struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_REGULAR), font_size, &cfg); font = regular ? regular : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font;
} }
// ...with icons embedded on it. // ...with icons embedded on it.
for( char *data = vfs_read(UI_FONT_ICONS); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_ICONS, &datalen); data; data = 0 ) {
static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}; static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0};
struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE); struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE);
@ -93,12 +93,12 @@ static void nk_config_custom_fonts() {
cfg.oversample_v = 1; cfg.oversample_v = 1;
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_ICONS), UI_ICON_FONTSIZE, &cfg); struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg);
} }
// Monospaced font. Used in terminals or consoles. // Monospaced font. Used in terminals or consoles.
for( char *data = vfs_read(UI_FONT_TERMINAL); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) {
const float font_size = UI_FONT_REGULAR_SIZE; const float font_size = UI_FONT_REGULAR_SIZE;
static const nk_rune icon_range[] = {32, 127, 0}; static const nk_rune icon_range[] = {32, 127, 0};
@ -110,13 +110,13 @@ static void nk_config_custom_fonts() {
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
// struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg);
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_TERMINAL), font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg);
} }
// Extra optional fonts from here... // Extra optional fonts from here...
for( char *data = vfs_read(UI_FONT_HEADING); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) {
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_HEADING), UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font;
} }
nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end();

View File

@ -990,11 +990,16 @@ void window_color(unsigned color) {
unsigned a = (color >> 24) & 255; unsigned a = (color >> 24) & 255;
winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0); winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
} }
static int has_icon;
int window_has_icon() {
return has_icon;
}
void window_icon(const char *file_icon) { void window_icon(const char *file_icon) {
unsigned len = file_size(file_icon); len = len ? len : vfs_size(file_icon); int len = 0;
if( len ) { void *data = vfs_load(file_icon, &len);
void *data = file_read(file_icon); data = data ? data : vfs_read(file_icon); if( !data ) data = file_read(file_icon), len = file_size(file_icon);
if( data ) {
if( data && len ) {
image_t img = image_from_mem(data, len, IMAGE_RGBA); image_t img = image_from_mem(data, len, IMAGE_RGBA);
if( img.w && img.h && img.pixels ) { if( img.w && img.h && img.pixels ) {
GLFWimage images[1]; GLFWimage images[1];
@ -1002,11 +1007,11 @@ void window_icon(const char *file_icon) {
images[0].height = img.h; images[0].height = img.h;
images[0].pixels = img.pixels; images[0].pixels = img.pixels;
glfwSetWindowIcon(window, 1, images); glfwSetWindowIcon(window, 1, images);
has_icon = 1;
return; return;
} }
} }
} #if 0 // is(win32)
#if is(win32)
HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
if( hIcon ) { if( hIcon ) {
HWND hWnd = glfwGetWin32Window(window); HWND hWnd = glfwGetWin32Window(window);
@ -1014,6 +1019,7 @@ void window_icon(const char *file_icon) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
has_icon = 1;
return; return;
} }
#endif #endif

View File

@ -36,7 +36,6 @@ API void window_loop(void (*function)(void* loopArg), void* loopArg ); // ru
API void window_loop_exit(); // exit from main loop function (emscripten only) API void window_loop_exit(); // exit from main loop function (emscripten only)
API void window_title(const char *title); API void window_title(const char *title);
API void window_icon(const char *file_icon);
API void window_color(unsigned color); API void window_color(unsigned color);
API vec2 window_canvas(); API vec2 window_canvas();
API void* window_handle(); API void* window_handle();
@ -65,6 +64,8 @@ API void window_maximize(int enabled);
API int window_has_maximize(); API int window_has_maximize();
API void window_transparent(int enabled); API void window_transparent(int enabled);
API int window_has_transparent(); API int window_has_transparent();
API void window_icon(const char *file_icon);
API int window_has_icon();
API double window_aspect(); API double window_aspect();
API void window_aspect_lock(unsigned numer, unsigned denom); API void window_aspect_lock(unsigned numer, unsigned denom);

View File

@ -222022,8 +222022,8 @@ static void browser_reload_directory_content(struct browser *browser, const char
BROWSER_PRINTF("searching at %s\n", path); BROWSER_PRINTF("searching at %s\n", path);
const char **list = file_list(path, "*"); array(char*) list = file_list(path);
for( int i = 0; list[i]; ++i ) { for( int i = 0, end = array_count(list); i < end; ++i ) {
char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext
BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) );
@ -222567,9 +222567,11 @@ char *json5__parse_value(json5 *obj, char *p, char **err_code) {
*buf++ = *p++; *buf++ = *p++;
} }
obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER; obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER;
long long unsigned int llu;
long long int lli;
/**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real ); /**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real );
else if( is_hex ) sscanf( buffer, "%llx", &obj->integer ); // SCNx64 -> inttypes.h else if( is_hex ) sscanf( buffer, "%llx", &llu ), obj->integer = llu; // SCNx64 -> inttypes.h
else sscanf( buffer, "%lld", &obj->integer ); // SCNd64 -> inttypes.h else sscanf( buffer, "%lld", &lli ), obj->integer = lli; // SCNd64 -> inttypes.h
} }
else { else {
return NULL; return NULL;
@ -222621,7 +222623,7 @@ void json5_write(FILE *fp, const json5 *o) {
} }
/**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null"); /**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null");
else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false"); else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false");
else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", o->integer); else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", (long long int)o->integer);
else if( o->type == JSON5_REAL ) { else if( o->type == JSON5_REAL ) {
/**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" ); /**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" );
else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" ); else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" );
@ -234808,10 +234810,10 @@ bool zip_append_file_timeinfo(zip *z, const char *entryname, const char *comment
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
fseek(in, 0, SEEK_SET); // rewind fseek(in, 0, SEEK_SET); // rewind
@ -234919,10 +234921,10 @@ bool zip_append_mem_timeinfo(zip *z, const char *entryname, const char *comment,
// Read whole file and and use compress(). Simple but won't handle GB files well. // Read whole file and and use compress(). Simple but won't handle GB files well.
unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level); unsigned dataSize = e->header.uncompressedSize, compSize = BOUNDS(e->header.uncompressedSize, compress_level);
comp = REALLOC(0, compSize); comp = REALLOC(comp, compSize);
if(comp == NULL) goto cant_compress; if(comp == NULL) goto cant_compress;
data = REALLOC(0, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x) data = REALLOC(data, dataSize + 8); // small excess as some compressors are really wild when reading from buffers (lz4x)
if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8); if(data == NULL) goto cant_compress; else memset((char*)data + dataSize, 0, 8);
size_t bytes = inlen; size_t bytes = inlen;
@ -234970,30 +234972,46 @@ common:;
// zip common // zip common
#if 1
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
#else
# if (defined(__TINYC__) && defined(_WIN32))
# define zip_lockfile(f) (void)(f)
# define zip_unlockfile(f) (void)(f)
# elif defined _MSC_VER
# define zip_lockfile(f) _lock_file(f)
# define zip_unlockfile(f) _unlock_file(f)
# else
# define zip_lockfile(f) flockfile(f)
# define zip_unlockfile(f) funlockfile(f)
# endif
#endif
zip* zip_open_handle(FILE *fp, const char *mode) { zip* zip_open_handle(FILE *fp, const char *mode) {
if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode); if( !fp ) return ERR(NULL, "cannot open file for %s mode", mode);
zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip)); zip zero = {0}, *z = (zip*)REALLOC(0, sizeof(zip));
if( !z ) return fclose(fp), ERR(NULL, "out of mem"); else *z = zero; if( !z ) return ERR(NULL, "out of mem"); else *z = zero;
if( mode[0] == 'w' ) { if( mode[0] == 'w' ) {
z->out = fp; zip_lockfile(z->out = fp);
return z; return z;
} }
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; zip_lockfile(z->in = fp);
unsigned long long seekcur = ftell(z->in); unsigned long long seekcur = ftell(z->in);
JZEndRecord jzEndRecord = {0}; JZEndRecord jzEndRecord = {0};
if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) { if(jzReadEndRecord(fp, &jzEndRecord) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file end record."); return ERR(NULL, "Couldn't read ZIP file end record.");
} }
jzEndRecord.centralDirectoryOffset += seekcur; jzEndRecord.centralDirectoryOffset += seekcur;
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) { if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z, (void*)(uintptr_t)seekcur ) != JZ_OK) {
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory."); return ERR(NULL, "Couldn't read ZIP file central directory.");
} }
if( mode[0] == 'a' ) { if( mode[0] == 'a' ) {
@ -235010,13 +235028,13 @@ zip* zip_open_handle(FILE *fp, const char *mode) {
fseek( fp, 0L, SEEK_END ); fseek( fp, 0L, SEEK_END );
} }
z->out = z->in;
z->in = NULL; z->in = NULL;
z->out = fp;
} }
return z; return z;
} }
REALLOC(z, 0); REALLOC(z, 0);
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
@ -235024,7 +235042,11 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
int exists = (stat(file, &buffer) == 0); int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb"; if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb"); FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode); if (!fp) return NULL;
if (mode[0] == 'a') fseek(fp, 0L, SEEK_SET);
zip *z = zip_open_handle(fp, mode);
if (!z) return fclose(fp), NULL;
return z;
} }
void zip_close(zip* z) { void zip_close(zip* z) {
@ -235052,8 +235074,8 @@ void zip_close(zip* z) {
// flush end record // flush end record
fwrite(&end, 1, sizeof(end), z->out); fwrite(&end, 1, sizeof(end), z->out);
} }
if( z->out ) fclose(z->out); if( z->out ) zip_unlockfile(z->out), fclose(z->out);
if( z->in ) fclose(z->in); if( z->in ) zip_unlockfile(z->in), fclose(z->in);
// clean up // clean up
for(unsigned i = 0; i < z->count; ++i ) { for(unsigned i = 0; i < z->count; ++i ) {
REALLOC(z->entries[i].filename, 0); REALLOC(z->entries[i].filename, 0);
@ -312563,7 +312585,7 @@ struct xml *xml_parse(char *s, int preserve_white, char **errorp)
static inline void array_find_and_remove(array(int) arr, int v) { static inline void array_find_and_remove(array(int) arr, int v) {
for( int i = 0, end = array_count(arr); i < end; i++ ) for( int i = 0, end = array_count(arr); i < end; i++ )
if( arr[i] == v ) { array_erase(arr, i); --end; break; } if( arr[i] == v ) { array_erase_fast(arr, i); --end; break; }
} }
#include <assert.h> #include <assert.h>
@ -312677,7 +312699,7 @@ static void RemoveIfNonNeighbor_(struct mesh *M, struct vertex *v, int id) {
return; return;
} }
// remove from neighbors // remove from neighbors
array_erase(v->neighbor, i); array_erase_fast(v->neighbor, i);
return; return;
} }
} }
@ -312840,7 +312862,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
} }
array(int) tmp = 0; array(int) tmp = 0;
// make tmp a Array of all the neighbors of u // make tmp a Array of all the neighbors of u
for (int i = 0; i<array_count(u->neighbor); i++) { for (int i = 0; i<array_count(u->neighbor); i++) {
array_push(tmp, u->neighbor[i]); array_push(tmp, u->neighbor[i]);
@ -312860,7 +312882,7 @@ static void Collapse(struct mesh *M, int uid, int vid) {
for (int i = 0; i<array_count(tmp); i++) { for (int i = 0; i<array_count(tmp); i++) {
ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i])); ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i]));
} }
array_free(tmp); array_free(tmp);
} }

View File

@ -969,6 +969,8 @@ const struct in6_addr in6addr_loopback; /* ::1 */
#define chdir ifdef(cl, _chdir, chdir) #define chdir ifdef(cl, _chdir, chdir)
#if is(cl) || is(tcc) #if is(cl) || is(tcc)
#define ftruncate _chsize_s #define ftruncate _chsize_s
#define flockfile ifdef(cl,_lock_file,(void))
#define funlockfile ifdef(cl,_unlock_file,(void))
#endif #endif
#else // gcc #else // gcc
//#include <alloca.h> // mingw64 does not have it //#include <alloca.h> // mingw64 does not have it
@ -1331,8 +1333,8 @@ int audio_init( int flags ) {
ma_backend_wasapi, // Higest priority. ma_backend_wasapi, // Higest priority.
ma_backend_dsound, ma_backend_dsound,
ma_backend_winmm, ma_backend_winmm,
ma_backend_pulseaudio,
ma_backend_coreaudio, ma_backend_coreaudio,
ma_backend_pulseaudio,
ma_backend_alsa, ma_backend_alsa,
ma_backend_oss, ma_backend_oss,
ma_backend_jack, ma_backend_jack,
@ -4230,7 +4232,7 @@ int zipscan_diff( zip* old, array(struct fs) now ) {
uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found uint64_t oldstamp = atoi64(zip_modt(old,found)+20); // format is "YYYY/MM/DD hh:mm:ss", then +20 chars later a hidden epoch timestamp in base10 can be found
int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp; int64_t diffstamp = oldstamp < now[i].stamp ? now[i].stamp - oldstamp : oldstamp - now[i].stamp;
if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate) if( oldsize != now[i].bytes || diffstamp > 1 ) { // @fixme: should use hash instead. hashof(tool) ^ hashof(args used) ^ hashof(rawsize) ^ hashof(rawdate)
printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, oldstamp,now[i].stamp); printf("%s:\t%u vs %u, %llu vs %llu\n", now[i].fname, (unsigned)oldsize,(unsigned)now[i].bytes, (long long unsigned)oldstamp, (long long unsigned)now[i].stamp);
array_push(changed, STRDUP(now[i].fname)); array_push(changed, STRDUP(now[i].fname));
array_push(uncooked, STRDUP(now[i].fname)); array_push(uncooked, STRDUP(now[i].fname));
} }
@ -4526,8 +4528,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
// scan disk: all subfolders in ART (comma-separated) // scan disk: all subfolders in ART (comma-separated)
static array(char *) list = 0; // @leak static array(char *) list = 0; // @leak
for each_substring(ART, ",", art_folder) { for each_substring(ART, ",", art_folder) {
const char **glob = file_list(art_folder, "**"); array(char *) glob = file_list(va("%s**",art_folder)); // art_folder ends with '/'
for( unsigned i = 0; glob[i]; ++i ) { for( unsigned i = 0, end = array_count(glob); i < end; ++i ) {
const char *fname = glob[i]; const char *fname = glob[i];
if( !strmatchi(fname, masks)) continue; if( !strmatchi(fname, masks)) continue;
@ -4547,8 +4549,13 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
if( !memcmp(header, "\x64\x86", 2) ) continue; if( !memcmp(header, "\x64\x86", 2) ) continue;
if( !memcmp(header, "\x00\x00", 2) ) continue; if( !memcmp(header, "\x00\x00", 2) ) continue;
} }
// exclude vc/gcc files
if( strend(fname, ".a") || strend(fname, ".pdb") || strend(fname, ".lib") || strend(fname, ".ilk") || strend(fname, ".exp") ) { char *dot = strrchr(fname, '.');
if( dot ) {
char extdot[32];
snprintf(extdot, 32, "%s.", dot); // .png -> .png.
// exclude vc/gcc/clang files
if( strstr(fname, ".a.o.pdb.lib.ilk.exp.dSYM.") ) // must end with dot
continue; continue;
} }
@ -4609,8 +4616,7 @@ void cook_stop() {
if(jobs[i].self) thread_join(jobs[i].self); if(jobs[i].self) thread_join(jobs[i].self);
} }
// remove all temporary outfiles // remove all temporary outfiles
const char **temps = file_list("./", "temp_*"); for each_array(file_list("temp_*"), char*, tempfile) unlink(tempfile);
for( int i = 0; temps[i]; ++i ) unlink(temps[i]);
} }
int cook_progress() { int cook_progress() {
@ -5059,7 +5065,8 @@ bool file_append(const char *name, const void *ptr, int len) {
} }
return ok; return ok;
} }
static bool file_stat(const char *fname, struct stat *st) { static // not exposed
bool file_stat(const char *fname, struct stat *st) {
// remove ending slashes. win32+tcc does not like them. // remove ending slashes. win32+tcc does not like them.
int l = strlen(fname), m = l; int l = strlen(fname), m = l;
while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l; while( l && (fname[l-1] == '/' || fname[l-1] == '\\') ) --l;
@ -5180,7 +5187,7 @@ char *ext = strrchr(base, '.'); //if (ext) ext[0] = '\0'; // remove all extensio
} }
return va("%s", buffer); return va("%s", buffer);
} }
const char** file_list(const char *cwds, const char *masks) { array(char*) file_list(const char *pathmasks) {
static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ? static __thread array(char*) list = 0; // @fixme: should we add 16 slots in here similar to what we do in va() ?
for( int i = 0; i < array_count(list); ++i ) { for( int i = 0; i < array_count(list); ++i ) {
@ -5188,7 +5195,16 @@ const char** file_list(const char *cwds, const char *masks) {
} }
array_resize(list, 0);//array_free(list); array_resize(list, 0);//array_free(list);
for each_substring(cwds,";",cwd) { for each_substring(pathmasks,";",pathmask) {
char *cwd = 0, *masks = 0;
char *slash = strrchr(pathmask, '/');
if( !slash ) cwd = "./", masks = pathmask;
else {
masks = va("%s", slash+1);
cwd = pathmask, slash[1] = '\0';
}
if( !masks[0] ) masks = "*";
ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd);
dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : "");
@ -5216,8 +5232,7 @@ const char** file_list(const char *cwds, const char *masks) {
} }
} }
array_push(list, 0); // terminator return list;
return (const char**)list;
} }
bool file_move(const char *src, const char *dst) { bool file_move(const char *src, const char *dst) {
@ -5564,15 +5579,8 @@ void vfs_reload() {
#else #else
// mount fused executables // mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""))); vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way // mount all zipfiles
for( int i = 0; i < JOBS_MAX; ++i) { for each_array( file_list("*.zip"), char*, file ) vfs_mount(file);
if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
if( vfs_mount(va("%s[%02x].zip", app, i)) ) continue;
if( vfs_mount(va("%s%02x.zip", app, i)) ) continue;
// if( vfs_mount(va("%s.%02x", app, i)) ) continue;
} */
// faster way
for( const char **file = file_list("./","*.zip"); *file; ++file) vfs_mount(*file);
#endif #endif
// vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress. // vfs_resolve() will use these art_folder locations as hints when cook-on-demand is in progress.
@ -5585,7 +5593,7 @@ void vfs_reload() {
#define ARK1 'ArK\x1' #define ARK1 0x41724B31 // 'ArK1' in le, 0x314B7241 41 72 4B 31 otherwise
#define ARK1_PADDING (512 - 40) // 472 #define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__) #define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x) #define ARK_SWAP32(x) (x)
@ -5677,9 +5685,9 @@ const char** vfs_list(const char *masks) {
for each_substring(masks,";",it) { for each_substring(masks,";",it) {
if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file if( COOK_ON_DEMAND ) // edge case: any game using only vfs api + cook-on-demand flag will never find any file
for(const char **items = file_list("./", it); *items; items++) { for each_array(file_list(it), char*, item) {
// insert copy // insert copy
char *copy = STRDUP(*items); char *copy = STRDUP(item);
array_push(list, copy); array_push(list, copy);
} }
@ -5785,8 +5793,8 @@ if( found && *found == 0 ) {
folder = file_path(pathfile); folder = file_path(pathfile);
// ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav // ease folders reading by shortening them: /home/rlyeh/prj/v4k/art/demos/audio/coin.wav -> demos/audio/coin.wav
// or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf // or C:/prj/v4k/engine/art/fonts/B612-BoldItalic.ttf -> fonts/B612-BoldItalic.ttf
static array(char*) art_paths = 0; static __thread array(char*) art_paths = 0;
do_once for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem)); if(!art_paths) for each_substring(ART,",",stem) array_push(art_paths, STRDUP(stem));
char* pretty_folder = ""; char* pretty_folder = "";
if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) { if( folder ) for( int i = 0; i < array_count(art_paths); ++i ) {
if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; } if( strbeg(folder, art_paths[i]) ) { pretty_folder = folder + strlen(art_paths[i]); break; }
@ -5837,7 +5845,7 @@ if( found && *found == 0 ) {
// this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s) // this block saves some boot time (editor --cook-on-demand: boot 1.50s -> 0.90s)
#if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS #if 1 // EXPERIMENTAL_DONT_COOK_NON_EXISTING_ASSETS
static set(char*) disk = 0; static set(char*) disk = 0;
if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for( const char **list = file_list(art_folder,"**"); *list; ++list) set_insert(disk, STRDUP(*list)); } if(!disk) { set_init_str(disk); for each_substring(ART,",",art_folder) for each_array(file_list(va("%s**", art_folder)), char*, item) set_insert(disk, STRDUP(item)); } // art_folder ends with '/'
int found = !!set_find(disk, (char*)pathfile); int found = !!set_find(disk, (char*)pathfile);
if( found ) if( found )
#endif #endif
@ -5950,23 +5958,28 @@ const char *vfs_extract(const char *pathfile) { // extract a vfs file into the l
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// cache // cache
static thread_mutex_t cache_mutex; AUTORUN{ thread_mutex_init(&cache_mutex); }
void* cache_lookup(const char *pathfile, int *size) { // find key->value void* cache_lookup(const char *pathfile, int *size) { // find key->value
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
void* data = 0;
thread_mutex_lock(&cache_mutex);
for(archive_dir *dir = dir_cache; dir; dir = dir->next) { for(archive_dir *dir = dir_cache; dir; dir = dir->next) {
if( !strcmp(dir->path, pathfile) ) { if( !strcmp(dir->path, pathfile) ) {
if(size) *size = dir->size; if(size) *size = dir->size;
return dir->data; data = dir->data;
break;
} }
} }
return 0; thread_mutex_unlock(&cache_mutex);
return data;
} }
void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/value; return LRU or NULL
if( !MAX_CACHED_FILES ) return 0; if( !MAX_CACHED_FILES ) return 0;
if( !ptr || !size ) return 0; if( !ptr || !size ) return 0;
// keep cached files within limits // keep cached files within limits
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &mutex); thread_mutex_lock(&cache_mutex);
thread_mutex_lock(&mutex);
// append to cache // append to cache
archive_dir zero = {0}, *old = dir_cache; archive_dir zero = {0}, *old = dir_cache;
@ -5996,7 +6009,7 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
} }
} }
thread_mutex_unlock(&mutex); thread_mutex_unlock(&cache_mutex);
return found; return found;
} }
@ -10922,7 +10935,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket >= 0 ) { if( socket >= 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -10939,7 +10952,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */ network_put(NETWORK_RANK, -1); /* unassigned until we connect successfully */
int64_t socket = client_join(ip, port); int64_t socket = client_join(ip, port);
if( socket > 0 ) { if( socket > 0 ) {
PRINTF("Client connected, id %lld\n", socket); PRINTF("Client connected, id %d\n", (int)socket);
network_put(NETWORK_LIVE, 1); network_put(NETWORK_LIVE, 1);
network_put(NETWORK_RANK, socket); network_put(NETWORK_RANK, socket);
} else { } else {
@ -10950,7 +10963,7 @@ void network_create(unsigned max_clients, const char *ip, const char *port_, uns
} }
} }
PRINTF("Network rank:%lld ip:%s port:%lld\n", network_get(NETWORK_RANK), ip, network_get(NETWORK_PORT)); PRINTF("Network rank:%u ip:%s port:%d\n", (unsigned)network_get(NETWORK_RANK), ip, (int)network_get(NETWORK_PORT));
} }
int64_t network_put(uint64_t key, int64_t value) { int64_t network_put(uint64_t key, int64_t value) {
@ -11083,8 +11096,8 @@ char** server_poll(unsigned timeout_ms) {
*(uint32_t*)&init_msg[0] = MSG_INIT; *(uint32_t*)&init_msg[0] = MSG_INIT;
*(int64_t*)&init_msg[4] = client_id; *(int64_t*)&init_msg[4] = client_id;
server_send_bin(client_id, init_msg, 12); server_send_bin(client_id, init_msg, 12);
PRINTF("Client rank %lld for peer ::%s:%u\n", client_id, ip, event.peer->address.port); PRINTF("Client rank %u for peer ::%s:%u\n", (unsigned)client_id, ip, event.peer->address.port);
msg = va( "%d new client rank:%lld from ::%s:%u", 0, client_id, ip, event.peer->address.port ); msg = va( "%d new client rank:%u from ::%s:%u", 0, (unsigned)client_id, ip, event.peer->address.port );
event.peer->data = (void*)client_id; event.peer->data = (void*)client_id;
break; break;
@ -11140,7 +11153,7 @@ char** server_poll(unsigned timeout_ms) {
msg = va("%d %s", 0, va("%s", ptr)); msg = va("%d %s", 0, va("%s", ptr));
} break; } break;
default: default:
msg = va("%d unk msg len:%u from rank:%lld ::%s:%u", -1, sz, (uint64_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */ msg = va("%d unk msg len:%u from rank:%u ::%s:%u", -1, sz, (unsigned)(uintptr_t)event.peer->data, ip, event.peer->address.port); /* @TODO: hexdump? */
break; break;
} }
/* Clean up the packet now that we're done using it. */ /* Clean up the packet now that we're done using it. */
@ -11148,7 +11161,7 @@ char** server_poll(unsigned timeout_ms) {
} break; } break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
msg = va( "%d disconnect rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d disconnect rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
/* Reset the peer's client information. */ /* Reset the peer's client information. */
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
@ -11157,7 +11170,7 @@ char** server_poll(unsigned timeout_ms) {
break; break;
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
msg = va( "%d timeout rank:%lld", 0, (uint64_t)event.peer->data); msg = va( "%d timeout rank:%u", 0, (unsigned)(uintptr_t)event.peer->data);
FREE(event.peer->data); FREE(event.peer->data);
event.peer->data = NULL; event.peer->data = NULL;
server_drop_client_peer(event.peer); server_drop_client_peer(event.peer);
@ -12865,10 +12878,10 @@ AUTOTEST {
// iterate reflected struct // iterate reflected struct
for each_member("MyVec4", R) { for each_member("MyVec4", R) {
printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info); // printf("+%s MyVec4.%s // %s\n", R->type, R->name, R->info);
} }
reflected_printf_all(); // reflected_printf_all();
} }
#line 0 #line 0
@ -12979,9 +12992,10 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
const char *glsl_version = ifdef(ems, "300 es", "150"); const char *glsl_version = ifdef(ems, "300 es", "150");
vs = vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : ""); if(gs)
fs = fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : ""); gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
if (gs) gs = gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : ""); vs = vs && vs[0] == '#' && vs[1] == 'v' ? vs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, vs ? vs : "");
fs = fs && fs[0] == '#' && fs[1] == 'v' ? fs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, fs ? fs : "");
#if is(ems) #if is(ems)
{ {
@ -19513,9 +19527,10 @@ const char *app_path() { // @fixme: should return absolute path always. see tcc
strcat(buffer, "..\\..\\"); strcat(buffer, "..\\..\\");
} }
#else // #elif is(linux) #else // #elif is(linux)
char path[21] = {0}; char path[32] = {0};
sprintf(path, "/proc/%d/exe", getpid()); sprintf(path, "/proc/%d/exe", getpid());
readlink(path, buffer, sizeof(buffer)); readlink(path, buffer, sizeof(buffer));
if(strrchr(buffer,'/')) 1[strrchr(buffer,'/')] = '\0';
#endif #endif
return buffer; return buffer;
} }
@ -20218,15 +20233,15 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line); char *location = va("|%s|%s:%d", /*errno?strerror(errno):*/function, file, line);
int cols = tty_cols() + 1 - (int)strlen(location); int cols = tty_cols() + 1 - (int)strlen(location);
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock); flockfile(stdout);
thread_mutex_lock( &lock );
tty_color(color); tty_color(color);
printf("\r%*.s%s", cols, "", location); printf("\r%*.s%s", cols, "", location);
printf("\r%07.3fs|%s%s", secs, text, stack); printf("\r%07.3fs|%s%s", secs, text, stack);
tty_color(0); tty_color(0);
thread_mutex_unlock( &lock ); funlockfile(stdout);
return 1; return 1;
} }
@ -20614,20 +20629,20 @@ static void nk_config_custom_fonts() {
nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas); nk_glfw3_font_stash_begin(&nk_glfw, &atlas); // nk_sdl_font_stash_begin(&atlas);
// Default font(#1)... // Default font(#1)...
int datalen = 0;
for( char *data = vfs_read(UI_FONT_REGULAR); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) {
float font_size = UI_FONT_REGULAR_SIZE; float font_size = UI_FONT_REGULAR_SIZE;
struct nk_font_config cfg = nk_font_config(font_size); struct nk_font_config cfg = nk_font_config(font_size);
cfg.oversample_v = 2; cfg.oversample_v = 2;
cfg.pixel_snap = 0; cfg.pixel_snap = 0;
// win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font;
// struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font;
struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_REGULAR), font_size, &cfg); font = regular ? regular : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font;
} }
// ...with icons embedded on it. // ...with icons embedded on it.
for( char *data = vfs_read(UI_FONT_ICONS); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_ICONS, &datalen); data; data = 0 ) {
static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}; static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0};
struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE); struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE);
@ -20643,12 +20658,12 @@ static void nk_config_custom_fonts() {
cfg.oversample_v = 1; cfg.oversample_v = 1;
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_ICONS), UI_ICON_FONTSIZE, &cfg); struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg);
} }
// Monospaced font. Used in terminals or consoles. // Monospaced font. Used in terminals or consoles.
for( char *data = vfs_read(UI_FONT_TERMINAL); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) {
const float font_size = UI_FONT_REGULAR_SIZE; const float font_size = UI_FONT_REGULAR_SIZE;
static const nk_rune icon_range[] = {32, 127, 0}; static const nk_rune icon_range[] = {32, 127, 0};
@ -20660,13 +20675,13 @@ static void nk_config_custom_fonts() {
cfg.pixel_snap = 1; cfg.pixel_snap = 1;
// struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg);
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_TERMINAL), font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg);
} }
// Extra optional fonts from here... // Extra optional fonts from here...
for( char *data = vfs_read(UI_FONT_HEADING); data; data = 0 ) { for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) {
struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, vfs_size(UI_FONT_HEADING), UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font;
} }
nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end();
@ -24293,11 +24308,16 @@ void window_color(unsigned color) {
unsigned a = (color >> 24) & 255; unsigned a = (color >> 24) & 255;
winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0); winbgcolor = vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
} }
static int has_icon;
int window_has_icon() {
return has_icon;
}
void window_icon(const char *file_icon) { void window_icon(const char *file_icon) {
unsigned len = file_size(file_icon); len = len ? len : vfs_size(file_icon); int len = 0;
if( len ) { void *data = vfs_load(file_icon, &len);
void *data = file_read(file_icon); data = data ? data : vfs_read(file_icon); if( !data ) data = file_read(file_icon), len = file_size(file_icon);
if( data ) {
if( data && len ) {
image_t img = image_from_mem(data, len, IMAGE_RGBA); image_t img = image_from_mem(data, len, IMAGE_RGBA);
if( img.w && img.h && img.pixels ) { if( img.w && img.h && img.pixels ) {
GLFWimage images[1]; GLFWimage images[1];
@ -24305,11 +24325,11 @@ void window_icon(const char *file_icon) {
images[0].height = img.h; images[0].height = img.h;
images[0].pixels = img.pixels; images[0].pixels = img.pixels;
glfwSetWindowIcon(window, 1, images); glfwSetWindowIcon(window, 1, images);
has_icon = 1;
return; return;
} }
} }
} #if 0 // is(win32)
#if is(win32)
HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); HANDLE hIcon = LoadImageA(0, file_icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
if( hIcon ) { if( hIcon ) {
HWND hWnd = glfwGetWin32Window(window); HWND hWnd = glfwGetWin32Window(window);
@ -24317,6 +24337,7 @@ void window_icon(const char *file_icon) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
has_icon = 1;
return; return;
} }
#endif #endif
@ -24682,7 +24703,7 @@ vec3 get_voxel_for_boid(float perception_radius, const boid_t *b) { // quantize
static static
void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) { void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_compare_value, array(boid_t*) voxel_cached, array(nearby_boid_t) *result, const vec3 voxelPos, const boid_t *b) {
for each_array_ptr(voxel_cached, const boid_t*, test) { for each_array_ptr(voxel_cached, boid_t*, test) {
vec3 p1 = b->position; vec3 p1 = b->position;
vec3 p2 = (*test)->position; vec3 p2 = (*test)->position;
vec3 vec = sub3(p2, p1); vec3 vec = sub3(p2, p1);
@ -24695,7 +24716,7 @@ void check_voxel_for_boids(float perception_radius, float blindspot_angledeg_com
compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2); compare_value = dot3(neg3(b->velocity), vec) / (l1 * l2);
} }
if ((&b) != test && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) { if (b != (*test) && distance <= perception_radius && (blindspot_angledeg_compare_value > compare_value || len3(b->velocity) == 0)) {
nearby_boid_t nb; nearby_boid_t nb;
nb.boid = (boid_t*)*test; nb.boid = (boid_t*)*test;
nb.distance = distance; nb.distance = distance;
@ -25258,7 +25279,7 @@ int pathfind_astar(int width, int height, const unsigned* map, vec2i src, vec2i
// [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2) // [ ] CompareKeys(keyVar1, operator < <= > >= == !=, keyVar2)
// [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false) // [ ] SetTags(names=blank,cooldownTime=inf,bIsCooldownAdditive=false)
// [ ] HasTags(names=blank,bAllRequired=true) // [ ] HasTags(names=blank,bAllRequired=true)
// [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesnt exist, and stores it in the passed variable name, and then pushes item object onto it. // [ ] PushToStack(keyVar,itemObj): creates a new stack if one doesn't exist, and stores it in the passed variable name, and then pushes 'item' 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. // [ ] 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. // [ ] 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. // [ ] 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.
@ -25926,48 +25947,41 @@ int main() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static void v4k_pre_init() { static void v4k_pre_init() {
const char *appname = app_name(); window_icon(va("%s%s.png", app_path(), app_name()));
const char *appdir = app_path();
window_icon(va("%s/%s.png", appdir, appname));
ifdef(win32,window_icon(va("%s/%s.ico", appdir, appname)));
glfwPollEvents(); glfwPollEvents();
int i; int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 6; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up /**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init(); else if( i == 1 ) sprite_init();
else if( i == 2 ) profiler_init(); else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
else if( i == 4 ) audio_init(0);
else if( i == 5 ) script_init(), kit_init(), midi_init();
else if( i == 6 ) network_init();
} }
// window_swap(); // window_swap();
} }
static void v4k_post_init(float refresh_rate) { static void v4k_post_init(float refresh_rate) {
int i;
// cook cleanup // cook cleanup
cook_stop(); cook_stop();
vfs_reload(); vfs_reload();
// init subsystems that depend on cooked assets now. ui_init() is special case and needs to be safely in single thread // init subsystems that depend on cooked assets now
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 2; ++i ) {
/**/ if( i == 0 ) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up if(i == 0) ui_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) audio_init(0); // initialize audio after cooking // reasoning for this: do not launch audio threads while cooks are in progress, so there is more cpu for cooking actually if(i == 0) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 2 ) script_init(), kit_init(), midi_init(); if(i == 1) input_init();
else if( i == 3 ) input_init(), network_init(); if(i == 2) window_icon(va("%s.png", app_name()));
} }
const char *appname = app_name();
window_icon(va("%s.png", appname));
window_icon(va("%s.ico", appname));
// display window // display window
glfwShowWindow(window); glfwShowWindow(window);
glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h);

View File

@ -123,8 +123,8 @@ extern "C" {
#define ENABLE_LINUX_CALLSTACKS 0 ///+ #define ENABLE_LINUX_CALLSTACKS 0 ///+
#endif #endif
#ifndef ENABLE_TESTS #ifndef ENABLE_AUTOTESTS
#define ENABLE_TESTS 0 // ifdef(debug, 1, 0) ///+ #define ENABLE_AUTOTESTS ifdef(debug, 1, 0) ///+
#endif #endif
#ifndef ENABLE_RETAIL #ifndef ENABLE_RETAIL
@ -215,15 +215,6 @@ extern "C" {
#define ifdef_release ifdef_false #define ifdef_release ifdef_false
#endif #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
#if ENABLE_RETAIL #if ENABLE_RETAIL
#define ifdef_retail ifdef_true #define ifdef_retail ifdef_true
#else #else
@ -236,6 +227,37 @@ extern "C" {
#define ifdef_nocook ifdef_false #define ifdef_nocook ifdef_false
#endif #endif
#if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3
#define ifdef_O3 ifdef_true
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 2
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_true
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 1
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_true
#define ifdef_O0 ifdef_false
#else
#define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_true
#endif
#include <stdint.h>
#if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
#define ifdef_64 ifdef_true
#define ifdef_32 ifdef_false
#else
#define ifdef_64 ifdef_false
#define ifdef_32 ifdef_true
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// new C keywords // new C keywords
@ -264,8 +286,13 @@ extern "C" {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// new C macros // new C macros
#if ENABLE_RETAIL
#define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0
#else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT(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 ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0)
#endif
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_line_) : !!(EXPR); } macro(static_assert_on_line_)
#define FILELINE __FILE__ ":" STRINGIZE(__LINE__) #define FILELINE __FILE__ ":" STRINGIZE(__LINE__)
@ -542,14 +569,16 @@ static __thread unsigned array_n_;
} while(0) } while(0)
#define array_foreach(t,val_t,v) for each_array(t,val_t,v) #define array_foreach(t,val_t,v) for each_array(t,val_t,v)
#define each_array(t,val_t,v) \ #define each_array(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t v = __it[t], *on__ = &v; on__; on__ = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 )
#define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v) #define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v)
#define each_array_ptr(t,val_t,v) \ #define each_array_ptr(a,val_t,v) \
( int __it = 0, __end = array_count(t); __it < __end; ++__it ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( val_t *v = (val_t*)&__it[t]; v; v = 0 ) for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t *v = (val_t*)&i_[a_]; v; v = 0 )
#define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \ #define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \
bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn ) bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn )
@ -565,13 +594,13 @@ static __thread unsigned array_n_;
} \ } \
} while(0) } while(0)
#define array_copy(t, src) do { /*todo: review old vrealloc call!*/ \ #define array_copy(t, src) do { \
array_free(t); \ array_free(t); \
(t) = array_realloc_( (t), array_count(src)); \ (t) = array_realloc_( (t), array_count(src)); \
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_swapback_and_pop(t, i) do { /*may alter ordering*/ \ #define array_erase_fast(t, i) do { /*may alter ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
@ -1817,7 +1846,7 @@ API void kit_dump_state( FILE *fp );
// physical filesystem. files // physical filesystem. files
API const char** file_list(const char *path, const char *masks); // **.png;*.c API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c
API bool file_write( const char *file, const void *ptr, int len ); API bool file_write( const char *file, const void *ptr, int len );
API bool file_append( 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_read(const char *filename);
@ -3796,18 +3825,13 @@ API void trap_on_debug(int signal); // helper util
#define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ? #define PANIC(...) PANIC(va(__VA_ARGS__), strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__) // die() ?
API int (PANIC)(const char *error, const char *file, int line); API int (PANIC)(const char *error, const char *file, int line);
#if !ENABLE_RETAIL
#define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__) #define PRINTF(...) PRINTF(va(__VA_ARGS__), 1[#__VA_ARGS__] == '!' ? callstack(+48) : "", strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__, __LINE__, __FUNCTION__)
API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function); API int (PRINTF)(const char *text, const char *stack, const char *file, int line, const char *function);
#define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr)) #define test(expr) test(strrchr(__FILE__, '/')?(strrchr(__FILE__, '/')+2):__FILE__,__LINE__,#expr,!!(expr))
API int (test)(const char *file, int line, const char *expr, bool result); API int (test)(const char *file, int line, const char *expr, bool result);
#else
#define PRINTF(...)
#define test(expr)
#endif
#if ENABLE_TESTS #if ENABLE_AUTOTESTS
#define AUTOTEST AUTORUN #define AUTOTEST AUTORUN
#else #else
#define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)() #define AUTOTEST static void concat(concat(concat(disabled_test_, __LINE__), _), __COUNTER__)()
@ -3815,6 +3839,12 @@ API int (test)(const char *file, int line, const char *expr, bool result);
// AUTOTEST { test(1<2); } // AUTOTEST { test(1<2); }
#if ENABLE_RETAIL
#undef PRINTF
#define PRINTF(...) 0
#undef test
#define test(expr) 0
#endif
#line 0 #line 0
#line 1 "engine/split/v4k_ui.h" #line 1 "engine/split/v4k_ui.h"
@ -3989,7 +4019,6 @@ API void window_loop(void (*function)(void* loopArg), void* loopArg ); // ru
API void window_loop_exit(); // exit from main loop function (emscripten only) API void window_loop_exit(); // exit from main loop function (emscripten only)
API void window_title(const char *title); API void window_title(const char *title);
API void window_icon(const char *file_icon);
API void window_color(unsigned color); API void window_color(unsigned color);
API vec2 window_canvas(); API vec2 window_canvas();
API void* window_handle(); API void* window_handle();
@ -4018,6 +4047,8 @@ API void window_maximize(int enabled);
API int window_has_maximize(); API int window_has_maximize();
API void window_transparent(int enabled); API void window_transparent(int enabled);
API int window_has_transparent(); API int window_has_transparent();
API void window_icon(const char *file_icon);
API int window_has_icon();
API double window_aspect(); API double window_aspect();
API void window_aspect_lock(unsigned numer, unsigned denom); API void window_aspect_lock(unsigned numer, unsigned denom);