main
Dominik Madarász 2023-10-13 12:59:44 +02:00
parent fb2aefca71
commit 3da7b6dc9a
43 changed files with 9189 additions and 392 deletions

View File

@ -19,8 +19,10 @@ if "%1"=="help" (
echo %0 [web] ; run Python webserver in html5 dir echo %0 [web] ; run Python webserver in html5 dir
echo %0 [pull] ; pull changes from origin echo %0 [pull] ; pull changes from origin
echo %0 [push] ; prepare for commit, stage changes and commit them echo %0 [push] ; prepare for commit, stage changes and commit them
echo %0 [dstat] ; show depot changes
echo %0 [dpush] ; push depot changes echo %0 [dpush] ; push depot changes
echo %0 [depot] ; sync depot changes echo %0 [depot] ; sync depot changes
echo %0 [fuse] ; fuse all binaries and cooked zipfiles found together
echo %0 [git] ; prepare for commit echo %0 [git] ; prepare for commit
echo %0 [vps] ; upload the release to VPS echo %0 [vps] ; upload the release to VPS
echo %0 [tidy] ; clean up temp files echo %0 [tidy] ; clean up temp files
@ -138,7 +140,7 @@ if "%1"=="git" (
rem call make.bat docs rem call make.bat docs
call make.bat amalgamation call make.bat amalgamation
call make.bat split rem call make.bat split
rem rd /q /s engine\split rem rd /q /s engine\split
rem md engine\split rem md engine\split
@ -227,6 +229,17 @@ if "%1"=="join" (
exit /b exit /b
) )
rem fuse binaries and zipfiles
if "%1"=="fuse" (
setlocal enableDelayedExpansion
if "%2"=="cook" (
del *.zip 2> nul 1> nul & tools\cook --cook-jobs=1
)
for %%i in (*.exe) do set "var=%%i" && if not "!var:~0,6!"=="fused_" ( copy /y !var! fused_!var! 2>nul 1>nul & tools\ark fused_!var! *.zip )
endlocal
exit /b
)
rem check memory api calls rem check memory api calls
if "%1"=="checkmem" ( if "%1"=="checkmem" (
findstr /RNC:"[^_xv]realloc[(]" engine\v4k.c engine\split\v4k* findstr /RNC:"[^_xv]realloc[(]" engine\v4k.c engine\split\v4k*

@ -1 +1 @@
Subproject commit 18db6da2d1c9b1dbf954be2692f289ca54ec81d8 Subproject commit b82b5ab54dae8de6498e566956b6163b3f4c27cd

View File

@ -1902,6 +1902,8 @@ typedef struct audio_handle* audio_t;
float audio_volume_clip(float gain); float audio_volume_clip(float gain);
float audio_volume_stream(float gain); float audio_volume_stream(float gain);
float audio_volume_master(float gain); float audio_volume_master(float gain);
int audio_mute(int mute);
int audio_muted();
int ui_audio(); int ui_audio();
enum AUDIO_FLAGS { enum AUDIO_FLAGS {
AUDIO_1CH = 0, AUDIO_1CH = 0,
@ -2103,6 +2105,10 @@ typedef union json_t { char* s; double f; int64_t i; uintptr_t p; union json_t*
void* dll(const char *filename, const char *symbol); void* dll(const char *filename, const char *symbol);
vec3 editor_pick(float mouse_x, float mouse_y); vec3 editor_pick(float mouse_x, float mouse_y);
char* editor_path(const char *path); char* editor_path(const char *path);
float* editor_getf(const char *key);
int* editor_geti(const char *key);
char** editor_gets(const char *key);
int editor_send(const char *cmd, const char *optional_value);
char* dialog_load(); char* dialog_load();
char* dialog_save(); char* dialog_save();
int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
@ -3069,6 +3075,8 @@ typedef vec3i guid;
void app_crash(); void app_crash();
void app_singleton(const char *guid); void app_singleton(const char *guid);
bool app_open(const char *folder_file_or_url); bool app_open(const char *folder_file_or_url);
const char* app_loadfile();
const char* app_savefile();
char* callstack( int traces ); char* callstack( int traces );
int callstackf( FILE *fp, int traces ); int callstackf( FILE *fp, int traces );
void die(const char *message); void die(const char *message);
@ -3140,7 +3148,7 @@ PANEL_OPEN = 1,
int ui_label2_toolbar(const char *label, const char *icons); int ui_label2_toolbar(const char *label, const char *icons);
int ui_slider(const char *label, float *value); int ui_slider(const char *label, float *value);
int ui_slider2(const char *label, float *value, const char *caption); int ui_slider2(const char *label, float *value, const char *caption);
int ui_contextual_end(); int ui_contextual_end(int close);
int ui_collapse_clicked(); int ui_collapse_clicked();
int ui_collapse_end(); int ui_collapse_end();
int ui_panel_end(); int ui_panel_end();

View File

@ -15292,9 +15292,12 @@ API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch
API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ ); API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ );
API int audio_stop( audio_t a ); API int audio_stop( audio_t a );
API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. return current fx volume in any case API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case
API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. return current bgm volume in any case API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case
API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. return current master volume in any case API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case
API int audio_mute(int mute);
API int audio_muted();
API int ui_audio(); API int ui_audio();
@ -15683,6 +15686,11 @@ API void* dll(const char *filename, const char *symbol);
API vec3 editor_pick(float mouse_x, float mouse_y); API vec3 editor_pick(float mouse_x, float mouse_y);
API char* editor_path(const char *path); API char* editor_path(const char *path);
API float* editor_getf(const char *key);
API int* editor_geti(const char *key);
API char** editor_gets(const char *key);
API int editor_send(const char *cmd, const char *optional_value);
// open file dialog // open file dialog
API char* dialog_load(); API char* dialog_load();
@ -16520,7 +16528,9 @@ extern API int profiler_enabled; ///-
// @todo: nested structs? pointers in members? // @todo: nested structs? pointers in members?
// @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/)
#ifndef ifdef_objapi
#define ifdef_objapi(T,...) __VA_ARGS__ #define ifdef_objapi(T,...) __VA_ARGS__
#endif
typedef struct reflected_t { typedef struct reflected_t {
unsigned id, objtype; unsigned id, objtype;
@ -17519,9 +17529,10 @@ char* strtok_s(char* str,const char* delimiters,char** context); // tcc misses t
#if 1 #if 1
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( int len_ = strlen(str) + 1; len_; len_ = 0 ) \ ( char *str_ = (char*)(str); str_; str_ = 0 ) \
for( char buf_[1024], *ptr_ = len_ < 1024 ? buf_ : REALLOC(0, len_), *lit_ = (char*)(str), *_bak = (snprintf(ptr_, len_, "%s", lit_), ptr_); _bak; _bak = 0, (ptr_ == buf_ ? 0 : REALLOC(ptr_, 0)) ) \ for( int len_ = strlen(str_) + 1, heap_ = len_ < 1024; len_ > 1; len_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(_bak, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) ) for( char *ptr_ = (heap_ ? REALLOC(0, len_) : ALLOCA(len_)), *cpy_ = (snprintf(ptr_, len_, "%s", str_), ptr_); ptr_; (heap_ ? REALLOC(ptr_, 0) : 0), ptr_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(cpy_, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) )
#else #else
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \ ( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \
@ -17676,6 +17687,10 @@ API void app_crash();
API void app_singleton(const char *guid); API void app_singleton(const char *guid);
API bool app_open(const char *folder_file_or_url); API bool app_open(const char *folder_file_or_url);
API const char* app_loadfile();
API const char* app_savefile();
API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free(). API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free().
API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order. API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order.
@ -17775,7 +17790,7 @@ API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons); API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value); API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption); API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_contextual_end(); API int ui_contextual_end(int close);
API int ui_collapse_clicked(); API int ui_collapse_clicked();
API int ui_collapse_end(); API int ui_collapse_end();
API int ui_panel_end(); API int ui_panel_end();
@ -252217,6 +252232,7 @@ unsigned file_decode(FILE* in, FILE* out, FILE *logfile) { // multi decoder
typedef struct zip zip; typedef struct zip zip;
zip* zip_open(const char *file, const char *mode /*r,w,a*/); zip* zip_open(const char *file, const char *mode /*r,w,a*/);
zip* zip_open_handle(FILE*fp, const char *mode /*r,w,a*/);
// only for (w)rite or (a)ppend mode // only for (w)rite or (a)ppend mode
bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level); bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level);
@ -252432,7 +252448,7 @@ int jzReadEndRecord(FILE *fp, JZEndRecord *endRecord) {
// Read ZIP file global directory. Will move within file. Returns Z_OK, or error code // Read ZIP file global directory. Will move within file. Returns Z_OK, or error code
// Callback is called for each record, until callback returns zero // Callback is called for each record, until callback returns zero
int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data) { int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data, void *user_data2) {
JZGlobalFileHeader fileHeader; JZGlobalFileHeader fileHeader;
if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) { if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) {
@ -252447,6 +252463,8 @@ int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback ca
return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i); return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i);
} }
fileHeader.relativeOffsetOflocalHeader += (uintptr_t)user_data2;
JZGlobalFileHeader *g = &fileHeader, copy = *g; JZGlobalFileHeader *g = &fileHeader, copy = *g;
FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50 FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50
FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported
@ -252939,11 +252957,7 @@ common:;
// zip common // zip common
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open_handle(FILE *fp, const char *mode) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
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 fclose(fp), ERR(NULL, "out of mem"); else *z = zero;
@ -252954,12 +252968,17 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; z->in = fp;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file end record.");
} }
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z) != JZ_OK) {
jzEndRecord.centralDirectoryOffset += seekcur;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory.");
} }
@ -252987,6 +253006,14 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return fclose(fp), ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode);
}
void zip_close(zip* z) { void zip_close(zip* z) {
if( z->out && z->count ) { if( z->out && z->count ) {
// prepare end record // prepare end record
@ -253166,8 +253193,7 @@ tar *tar_open(const char *filename, const char *mode) {
*t = zero; *t = zero;
t->in = in; t->in = in;
tar__parse(in, tar__push_entry, t); return tar__parse(in, tar__push_entry, t) ? t : NULL;
return t;
} }
int tar_find(tar *t, const char *entryname) { int tar_find(tar *t, const char *entryname) {
@ -331461,16 +331487,26 @@ char* tempvl(const char *fmt, va_list vl) {
int reqlen = sz; int reqlen = sz;
#if 0 #if 0
int heap = 0;
enum { STACK_ALLOC = 16384 }; enum { STACK_ALLOC = 16384 };
static __thread char buf[STACK_ALLOC]; static __thread char buf[STACK_ALLOC];
#else #else
enum { STACK_ALLOC = 128*1024 }; int heap = 1;
static __thread int STACK_ALLOC = 128*1024;
static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak
#endif #endif
static __thread int cur = 0, len = STACK_ALLOC - 1; //printf("string stack %d/%d\n", cur, STACK_ALLOC); static __thread int cur = 0; //printf("string stack %d/%d\n", cur, STACK_ALLOC);
assert(reqlen < STACK_ALLOC && "no stack enough, increase STACK_ALLOC variable above"); if( reqlen >= STACK_ALLOC ) {
char* ptr = buf + (cur *= (cur+reqlen) < len, (cur += reqlen) - reqlen); tty_color(RED);
printf("no stack enough, increase STACK_ALLOC variable above (reqlen:%d) (fmt: %s)\n", reqlen, fmt);
tty_color(0);
//assert(reqlen < STACK_ALLOC);
STACK_ALLOC = reqlen * 2;
buf = REALLOC(0, STACK_ALLOC);
}
char* ptr = buf + (cur *= (cur+reqlen) < (STACK_ALLOC - 1), (cur += reqlen) - reqlen);
/*stbsp_*/vsnprintf( ptr, sz, fmt, vl ); /*stbsp_*/vsnprintf( ptr, sz, fmt, vl );
return (char *)ptr; return (char *)ptr;
@ -332366,10 +332402,17 @@ float audio_volume_master(float gain) {
mixer.gain = volume_master; mixer.gain = volume_master;
return sqrt( volume_master ); return sqrt( volume_master );
} }
int audio_mute(int mute) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if( mute >= 0 && mute <= 1 ) muted = mute;
return muted;
}
int audio_muted() {
return audio_mute(-1);
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) { int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted"); if(audio_muted()) return 1;
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) { if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is // do nothing, gain used as-is
@ -335115,7 +335158,7 @@ array(struct fs) zipscan_filter(int threadid, int numthreads) {
// skip if list item does not belong to this thread bucket // skip if list item does not belong to this thread bucket
uint64_t hash = hash_str(fname); uint64_t hash = hash_str(fname);
unsigned bucket = (hash >> 32) % numthreads; unsigned bucket = (hash /*>> 32*/) % numthreads;
if(bucket != threadid) continue; if(bucket != threadid) continue;
array_push(fs, fs_now[i]); array_push(fs, fs_now[i]);
@ -335372,10 +335415,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
char *s = strchr( ART, ';' ); if(s) *s = 0; char *s = strchr( ART, ';' ); if(s) *s = 0;
char *w = strchr( ART, ' ' ); if(w) *w = 0; char *w = strchr( ART, ' ' ); if(w) *w = 0;
char *out = 0; const char *sep = ""; char *out = 0; const char *sep = "";
const char *v4k_title = getenv("V4K_TITLE");
for each_substring(ART, ",", t) { for each_substring(ART, ",", t) {
char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN; char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN;
PRINTF("ART mount+=%s\n", tmp);
for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/'; for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/';
strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/"); strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/");
assert( out[strlen(out) - 1] == '/' ); assert( out[strlen(out) - 1] == '/' );
@ -336162,7 +336203,7 @@ bool file_delete(const char *pathfile) {
} }
bool file_copy(const char *src, const char *dst) { bool file_copy(const char *src, const char *dst) {
int ok = 0, BUFSIZE = 1 << 20; // 1 MiB int ok = 0, BUFSIZE = 1 << 20; // 1 MiB
static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); // @leak
for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) { for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) {
for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) { for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) {
for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){ for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){
@ -336487,6 +336528,8 @@ void vfs_reload() {
#if defined(EMSCRIPTEN) #if defined(EMSCRIPTEN)
vfs_mount("index.zip"); vfs_mount("index.zip");
#else #else
// mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way /* // old way
for( int i = 0; i < JOBS_MAX; ++i) { for( int i = 0; i < JOBS_MAX; ++i) {
if( vfs_mount(va(".art[%02x].zip", i)) ) continue; if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
@ -336506,6 +336549,34 @@ void vfs_reload() {
} }
} }
#define ARK1 'ArK\x1'
#define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x)
#define ARK_SWAP64(x) (x)
#define ARK_REALLOC REALLOC
static uint64_t ark_fget64( FILE *in ) { uint64_t v; fread( &v, 1, 8, in ); return ARK_SWAP64(v); }
void ark_list( const char *infile, zip **z ) {
for( FILE *in = fopen(infile, "rb"); in; fclose(in), in = 0 )
while(!feof(in)) {
if( 0 != (ftell(in) % ARK1_PADDING) ) fseek(in, ARK1_PADDING - (ftell(in) % ARK1_PADDING), SEEK_CUR);
ARK_PRINTF("Reading at #%d\n", (int)ftell(in));
uint64_t mark = ark_fget64(in);
if( mark != ARK1 ) continue;
uint64_t stamp = ark_fget64(in);
uint64_t datalen = ark_fget64(in);
uint64_t datahash = ark_fget64(in);
uint64_t namelen = ark_fget64(in);
*z = zip_open_handle(in, "rb");
return;
}
}
static static
bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) { bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL; zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL;
@ -336515,6 +336586,7 @@ bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
if( !is_folder ) z = zip_open(path, "rb"); if( !is_folder ) z = zip_open(path, "rb");
if( !is_folder && !z ) t = tar_open(path, "rb"); if( !is_folder && !z ) t = tar_open(path, "rb");
if( !is_folder && !z && !t ) p = pak_open(path, "rb"); if( !is_folder && !z && !t ) p = pak_open(path, "rb");
if( !is_folder && !z && !t && !p ) ark_list(path, &z); // last resort. try as .ark
if( !is_folder && !z && !t && !p ) return 0; if( !is_folder && !z && !t && !p ) return 0;
// normalize input -> "././" to "" // normalize input -> "././" to ""
@ -336699,9 +336771,9 @@ if( found && *found == 0 ) {
const char *lookup_id = /*file_normalize_with_folder*/(pathfile); const char *lookup_id = /*file_normalize_with_folder*/(pathfile);
// search (last item) // search (last item)
static char last_item[256] = { 0 }; static __thread char last_item[256] = { 0 };
static void *last_ptr = 0; static __thread void *last_ptr = 0;
static int last_size = 0; static __thread int last_size = 0;
if( !strcmpi(lookup_id, last_item)) { if( !strcmpi(lookup_id, last_item)) {
ptr = last_ptr; ptr = last_ptr;
size = last_size; size = last_size;
@ -336858,6 +336930,10 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
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
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &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;
*(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero; *(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero;
@ -336867,7 +336943,8 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
dir_cache->data = REALLOC(0, size+1); dir_cache->data = REALLOC(0, size+1);
memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator
// keep cached files within limits void *found = 0;
static int added = 0; static int added = 0;
if( added < MAX_CACHED_FILES ) { if( added < MAX_CACHED_FILES ) {
++added; ++added;
@ -336876,15 +336953,18 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) { for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) {
if( !dir->next ) { if( !dir->next ) {
prev->next = 0; // break link prev->next = 0; // break link
void *data = dir->data; found = dir->data;
dir->path = REALLOC(dir->path, 0); dir->path = REALLOC(dir->path, 0);
dir->data = REALLOC(dir->data, 0); dir->data = REALLOC(dir->data, 0);
dir = REALLOC(dir, 0); dir = REALLOC(dir, 0);
return data; break;
} }
} }
} }
return 0;
thread_mutex_unlock(&mutex);
return found;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -343657,8 +343737,8 @@ static map(unsigned, reflected_t) reflects;
static map(unsigned, array(reflected_t)) members; static map(unsigned, array(reflected_t)) members;
void reflected_printf(reflected_t *r) { void reflected_printf(reflected_t *r) {
printf("id:%u objtype:%u sz:%u name:%s info:%s addr:%p parent:%u type:%s", printf("name:%s info:'%s' id:%u objtype:%u sz:%u addr:%p parent:%u type:%s",
r->id, r->objtype, r->sz, r->name ? r->name : "", r->info ? r->info : "", r->addr, r->parent, r->type ? r->type : ""); r->name ? r->name : "", r->info ? r->info : "", r->id, r->objtype, r->sz, r->addr, r->parent, r->type ? r->type : "");
} }
void reflected_printf_all() { void reflected_printf_all() {
for each_map_ptr(reflects, unsigned, k, reflected_t, p) { for each_map_ptr(reflects, unsigned, k, reflected_t, p) {
@ -351231,6 +351311,26 @@ bool app_open(const char *link) {
return app_open_url(link); return app_open_url(link);
} }
const char* app_loadfile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
const char* app_savefile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests // tests
@ -352817,11 +352917,12 @@ int ui_collapse_end() {
int ui_contextual() { int ui_contextual() {
struct nk_rect bounds = nk_widget_bounds(ui_ctx); struct nk_rect bounds = nk_widget_bounds(ui_ctx); // = nk_window_get_bounds(ui_ctx);
bounds.y -= 25; bounds.y -= 25;
return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds); return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds);
} }
int ui_contextual_end() { int ui_contextual_end(int close) {
if(close) nk_contextual_close(ui_ctx);
nk_contextual_end(ui_ctx); nk_contextual_end(ui_ctx);
return 1; return 1;
} }
@ -352832,7 +352933,7 @@ int ui_submenu(const char *options) {
for( int i = 0; i < array_count(tokens) ; ++i ) { for( int i = 0; i < array_count(tokens) ; ++i ) {
if( ui_button_transparent(tokens[i]) ) choice = i + 1; if( ui_button_transparent(tokens[i]) ) choice = i + 1;
} }
ui_contextual_end(); ui_contextual_end(0);
} }
return choice; return choice;
} }
@ -352966,8 +353067,10 @@ int ui_label(const char *text) {
int ui_label2(const char *label, const char *text_) { int ui_label2(const char *label, const char *text_) {
nk_layout_row_dynamic(ui_ctx, 0, 2); nk_layout_row_dynamic(ui_ctx, 0, 2);
int align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align1 = NK_TEXT_LEFT;
int align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align2 = NK_TEXT_LEFT;
if( label ) align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
if( text_ ) align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
ui_label_(label, align1); ui_label_(label, align1);
const struct nk_input *input = &ui_ctx->input; const struct nk_input *input = &ui_ctx->input;
@ -354702,12 +354805,38 @@ int window_frame_begin() {
if( may_render_stats ) { if( may_render_stats ) {
if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) {
#if 1 static int time_factor = 0;
static char *filter = 0; static int playing = 0;
static int paused = 0;
int advance_frame = 0;
static int do_filter = 0; static int do_filter = 0;
static int do_profile = 0;
static int do_extra = 0;
char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
ICON_MD_PLAY_ARROW,
paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
ICON_MD_FAST_FORWARD,
ICON_MD_STOP,
ICON_MD_REPLAY,
ICON_MD_FACE,
ICON_MD_MENU
);
if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
int choice = ui_toolbar(ICON_MD_SEARCH ";"); int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
if( choice == 1 ) do_filter = 1; if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
if( choice == 2 ) playing = 1, paused = 0;
if( choice == 3 ) advance_frame = !!paused, paused = 1;
if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
if( choice == 6 ) window_reload();
if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
static char *filter = 0;
if( do_filter ) { if( do_filter ) {
ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
@ -354717,13 +354846,44 @@ int window_frame_begin() {
if( filter ) filter[0] = '\0'; if( filter ) filter[0] = '\0';
} }
char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
#endif
static char *username = 0;
static char *userpass = 0;
if( do_profile ) {
ui_string(ICON_MD_FACE " Username", &username);
ui_string(ICON_MD_FACE " Password", &userpass);
}
if( do_extra ) {
int choice2 = ui_label2_toolbar(NULL,
ICON_MD_VIEW_IN_AR
ICON_MD_MESSAGE
ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
);
}
int open = 0, clicked_or_toggled = 0; int open = 0, clicked_or_toggled = 0;
#define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id))
for( int p = (open = ui_collapse_filtered(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { #define EDITOR_UI_COLLAPSE(f,...) \
for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
// @todo. parse /bugs.ini, includes saved screenshots & videos.
// @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
}
// Art and bookmarks
EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
bool inlined = true; bool inlined = true;
const char *file = 0; const char *file = 0;
if( ui_browse(&file, &inlined) ) { if( ui_browse(&file, &inlined) ) {
@ -354731,47 +354891,78 @@ int window_frame_begin() {
app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
// E,C,S,W
EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
//node_edit(editor.edit.down,&editor.edit);
}
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
// node_edit(&editor.init,&editor.init);
// node_edit(&editor.draw,&editor.draw);
// node_edit(&editor.tick,&editor.tick);
// node_edit(&editor.edit,&editor.edit);
// node_edit(&editor.quit,&editor.quit);
}
EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
// @todo // @todo
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VOLUME_UP " Audio", "Debug.Audio")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
ui_audio(); ui_audio();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIDEOCAM " Camera", "Debug.Camera")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
ui_camera( camera_get_active() ); ui_camera( camera_get_active() );
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_BUILD " Cook", "Debug.Cook")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
// @todo // @todo: fps lock, fps target, aspect ratio, fullscreen
char *text = va("%s;%s;%s",
window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
ICON_MD_PHOTO_CAMERA,
record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
);
int choice = ui_toolbar(text);
if( choice == 1 ) editor_send("key_fullscreen",0);
if( choice == 2 ) editor_send("key_screenshot",0);
if( choice == 3 ) editor_send("key_record",0);
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_SIGNAL_CELLULAR_ALT " Network", "Debug.Network")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_MOVIE " FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_SPEED " Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_keyboard(); ui_keyboard();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_MOUSE " Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
ui_mouse(); ui_mouse();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
for( int q = 0; q < 4; ++q ) { for( int q = 0; q < 4; ++q ) {
for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
ui_gamepad(q); ui_gamepad(q);
} }
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIEW_QUILT " UI", "Debug.UI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
// @todo
}
EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
ui_shaders();
}
EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
ui_fxs();
}
EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") {
int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout");
if( choice == 1 ) ui_layout_all_reset("*"); if( choice == 1 ) ui_layout_all_reset("*");
if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
@ -354784,8 +354975,61 @@ int window_frame_begin() {
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
// @todo. // mem,fps,gfx,net,hdd,... also logging
}
EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
// @todo
// SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
}
EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%d", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
ui_profiler();
}
EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
// @todo
}
// logic: either plug icon (power saving off) or one of the following ones (power saving on):
// if 0% batt (no batt): battery alert
// if discharging: battery levels [alert,0..6,full]
// if charging: battery charging
int battery_read = app_battery();
int battery_level = abs(battery_read);
int battery_discharging = battery_read < 0 && battery_level < 100;
const char *power_icon_label = ICON_MD_POWER " Power";
if( battery_level ) {
const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
};
power_icon_label = (const char*)va("%s Power %d%%",
battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
battery_level);
}
EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
if( choice == 1 ) editor_send("key_battery","0");
if( choice == 2 ) editor_send("key_battery","1");
}
EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
// @todo. include VCS
EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
// @todo
}
}
(has_menu ? ui_window_end : ui_panel_end)(); (has_menu ? ui_window_end : ui_panel_end)();
} }
API int editor_tick();
editor_tick();
} }
#if 0 // deprecated #if 0 // deprecated
@ -356186,6 +356430,61 @@ int ui_bt(bt_t *b) {
// editing: // editing:
// nope > functions: add/rem property // nope > functions: add/rem property
#define ICON_PLAY ICON_MD_PLAY_ARROW
#define ICON_PAUSE ICON_MD_PAUSE
#define ICON_STOP ICON_MD_STOP
#define ICON_CANCEL ICON_MD_CLOSE
#define ICON_WARNING ICON_MD_WARNING
#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
#define ICON_OUTLINER ICON_MD_VIEW_IN_AR
#define ICON_BUILD ICON_MD_BUILD
#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
#define ICON_CAMERA_ON ICON_MD_VIDEOCAM
#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
#define ICON_AUDIO_ON ICON_MD_VOLUME_UP
#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
#define ICON_FULLSCREEN ICON_MD_FULLSCREEN
#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
#define ICON_DISK ICON_MD_STORAGE
#define ICON_RATE ICON_MD_SPEED
#define ICON_CLOCK ICON_MD_TODAY
#define ICON_CHRONO ICON_MD_TIMELAPSE
#define ICON_SETTINGS ICON_MD_SETTINGS
#define ICON_LANGUAGE ICON_MD_G_TRANSLATE
#define ICON_PERSONA ICON_MD_FACE
#define ICON_SOCIAL ICON_MD_MESSAGE
#define ICON_GAME ICON_MD_ROCKET_LAUNCH
#define ICON_KEYBOARD ICON_MD_KEYBOARD
#define ICON_MOUSE ICON_MD_MOUSE
#define ICON_GAMEPAD ICON_MD_GAMEPAD
#define ICON_MONITOR ICON_MD_MONITOR
#define ICON_WIFI ICON_MD_WIFI
#define ICON_BUDGET ICON_MD_SAVINGS
#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
#define ICON_PLUGIN ICON_MD_EXTENSION
#define ICON_RESTART ICON_MD_REPLAY
#define ICON_QUIT ICON_MD_CLOSE
#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
#define ICON_BATTERY_LEVELS \
ICON_MD_BATTERY_ALERT, \
ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
char *editor_path(const char *path) { char *editor_path(const char *path) {
return va("%s/%s", EDITOR, path); return va("%s/%s", EDITOR, path);
} }
@ -356250,6 +356549,75 @@ int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate
return clicked | (copy ^ *enabled); return clicked | (copy ^ *enabled);
} }
typedef union editor_var {
int i;
float f;
char *s;
} editor_var;
static map(char*,editor_var) editor_vars;
float *editor_getf(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->f;
}
int *editor_geti(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->i;
}
char **editor_gets(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
if(!found->s) found->s = stringf("%s","");
return &found->s;
}
int editor_send(const char *cmd, const char *optional_value) {
unsigned *gamepads = editor_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
unsigned *renders = editor_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
float *speed = editor_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
unsigned *powersave = editor_geti("powersave");
char *name;
/**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
else if( !strcmp(cmd, "key_stop" )) window_pause(1);
else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
else if( !strcmp(cmd, "key_reload" )) window_reload();
else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(); else
name = file_counter(va("%s.mp4",app_name())), window_record(name), ui_notify(va("Video capturing: %s", name), date_string());
else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
else alert(va("editor could not handle `%s` command.", cmd));
return 0;
}
int editor_tick() {
enum { editor_hz = 60 };
enum { editor_hz_mid = 18 };
enum { editor_hz_low = 5 };
if( *editor_geti("powersave") ) {
// adaptive framerate
int app_on_background = !window_has_focus();
int hz = app_on_background ? editor_hz_low : editor_hz_mid;
window_fps_lock( hz < 5 ? 5 : hz );
} else {
// window_fps_lock( editor_hz );
}
return 0;
}
static int gizmo__mode; static int gizmo__mode;
static int gizmo__active; static int gizmo__active;
static int gizmo__hover; static int gizmo__hover;
@ -356361,26 +356729,6 @@ int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
return modified; return modified;
} }
char* dialog_load() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
char* dialog_save() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// -- localization kit // -- localization kit
static const char *kit_lang = "enUS", *kit_langs = static const char *kit_lang = "enUS", *kit_langs =
@ -356554,18 +356902,20 @@ static void v4k_pre_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
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point // init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for #pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ui_init(), 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 ) 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 == 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 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
else if( i == 2 ) script_init(), kit_init(), midi_init(); else if( i == 2 ) script_init(), kit_init(), midi_init();
else if( i == 3 ) input_init(), network_init(); else if( i == 3 ) input_init(), network_init();

View File

@ -31,6 +31,7 @@
typedef struct zip zip; typedef struct zip zip;
zip* zip_open(const char *file, const char *mode /*r,w,a*/); zip* zip_open(const char *file, const char *mode /*r,w,a*/);
zip* zip_open_handle(FILE*fp, const char *mode /*r,w,a*/);
// only for (w)rite or (a)ppend mode // only for (w)rite or (a)ppend mode
bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level); bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level);
@ -246,7 +247,7 @@ int jzReadEndRecord(FILE *fp, JZEndRecord *endRecord) {
// Read ZIP file global directory. Will move within file. Returns Z_OK, or error code // Read ZIP file global directory. Will move within file. Returns Z_OK, or error code
// Callback is called for each record, until callback returns zero // Callback is called for each record, until callback returns zero
int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data) { int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data, void *user_data2) {
JZGlobalFileHeader fileHeader; JZGlobalFileHeader fileHeader;
if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) { if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) {
@ -261,6 +262,8 @@ int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback ca
return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i); return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i);
} }
fileHeader.relativeOffsetOflocalHeader += (uintptr_t)user_data2;
JZGlobalFileHeader *g = &fileHeader, copy = *g; JZGlobalFileHeader *g = &fileHeader, copy = *g;
FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50 FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50
FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported
@ -753,11 +756,7 @@ common:;
// zip common // zip common
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open_handle(FILE *fp, const char *mode) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
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 fclose(fp), ERR(NULL, "out of mem"); else *z = zero;
@ -768,12 +767,17 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; z->in = fp;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file end record.");
} }
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z) != JZ_OK) {
jzEndRecord.centralDirectoryOffset += seekcur;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory.");
} }
@ -801,6 +805,14 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return fclose(fp), ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode);
}
void zip_close(zip* z) { void zip_close(zip* z) {
if( z->out && z->count ) { if( z->out && z->count ) {
// prepare end record // prepare end record
@ -980,8 +992,7 @@ tar *tar_open(const char *filename, const char *mode) {
*t = zero; *t = zero;
t->in = in; t->in = in;
tar__parse(in, tar__push_entry, t); return tar__parse(in, tar__push_entry, t) ? t : NULL;
return t;
} }
int tar_find(tar *t, const char *entryname) { int tar_find(tar *t, const char *entryname) {

View File

@ -385,10 +385,17 @@ float audio_volume_master(float gain) {
mixer.gain = volume_master; mixer.gain = volume_master;
return sqrt( volume_master ); return sqrt( volume_master );
} }
int audio_mute(int mute) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if( mute >= 0 && mute <= 1 ) muted = mute;
return muted;
}
int audio_muted() {
return audio_mute(-1);
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) { int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted"); if(audio_muted()) return 1;
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) { if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is // do nothing, gain used as-is

View File

@ -24,9 +24,12 @@ API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch
API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ ); API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ );
API int audio_stop( audio_t a ); API int audio_stop( audio_t a );
API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. return current fx volume in any case API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case
API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. return current bgm volume in any case API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case
API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. return current master volume in any case API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case
API int audio_mute(int mute);
API int audio_muted();
API int ui_audio(); API int ui_audio();

View File

@ -364,7 +364,7 @@ array(struct fs) zipscan_filter(int threadid, int numthreads) {
// skip if list item does not belong to this thread bucket // skip if list item does not belong to this thread bucket
uint64_t hash = hash_str(fname); uint64_t hash = hash_str(fname);
unsigned bucket = (hash >> 32) % numthreads; unsigned bucket = (hash /*>> 32*/) % numthreads;
if(bucket != threadid) continue; if(bucket != threadid) continue;
array_push(fs, fs_now[i]); array_push(fs, fs_now[i]);
@ -621,10 +621,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
char *s = strchr( ART, ';' ); if(s) *s = 0; char *s = strchr( ART, ';' ); if(s) *s = 0;
char *w = strchr( ART, ' ' ); if(w) *w = 0; char *w = strchr( ART, ' ' ); if(w) *w = 0;
char *out = 0; const char *sep = ""; char *out = 0; const char *sep = "";
const char *v4k_title = getenv("V4K_TITLE");
for each_substring(ART, ",", t) { for each_substring(ART, ",", t) {
char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN; char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN;
PRINTF("ART mount+=%s\n", tmp);
for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/'; for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/';
strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/"); strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/");
assert( out[strlen(out) - 1] == '/' ); assert( out[strlen(out) - 1] == '/' );

View File

@ -1,6 +1,61 @@
// editing: // editing:
// nope > functions: add/rem property // nope > functions: add/rem property
#define ICON_PLAY ICON_MD_PLAY_ARROW
#define ICON_PAUSE ICON_MD_PAUSE
#define ICON_STOP ICON_MD_STOP
#define ICON_CANCEL ICON_MD_CLOSE
#define ICON_WARNING ICON_MD_WARNING
#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
#define ICON_OUTLINER ICON_MD_VIEW_IN_AR
#define ICON_BUILD ICON_MD_BUILD
#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
#define ICON_CAMERA_ON ICON_MD_VIDEOCAM
#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
#define ICON_AUDIO_ON ICON_MD_VOLUME_UP
#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
#define ICON_FULLSCREEN ICON_MD_FULLSCREEN
#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
#define ICON_DISK ICON_MD_STORAGE
#define ICON_RATE ICON_MD_SPEED
#define ICON_CLOCK ICON_MD_TODAY
#define ICON_CHRONO ICON_MD_TIMELAPSE
#define ICON_SETTINGS ICON_MD_SETTINGS
#define ICON_LANGUAGE ICON_MD_G_TRANSLATE
#define ICON_PERSONA ICON_MD_FACE
#define ICON_SOCIAL ICON_MD_MESSAGE
#define ICON_GAME ICON_MD_ROCKET_LAUNCH
#define ICON_KEYBOARD ICON_MD_KEYBOARD
#define ICON_MOUSE ICON_MD_MOUSE
#define ICON_GAMEPAD ICON_MD_GAMEPAD
#define ICON_MONITOR ICON_MD_MONITOR
#define ICON_WIFI ICON_MD_WIFI
#define ICON_BUDGET ICON_MD_SAVINGS
#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
#define ICON_PLUGIN ICON_MD_EXTENSION
#define ICON_RESTART ICON_MD_REPLAY
#define ICON_QUIT ICON_MD_CLOSE
#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
#define ICON_BATTERY_LEVELS \
ICON_MD_BATTERY_ALERT, \
ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
char *editor_path(const char *path) { char *editor_path(const char *path) {
return va("%s/%s", EDITOR, path); return va("%s/%s", EDITOR, path);
} }
@ -65,6 +120,75 @@ int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate
return clicked | (copy ^ *enabled); return clicked | (copy ^ *enabled);
} }
typedef union editor_var {
int i;
float f;
char *s;
} editor_var;
static map(char*,editor_var) editor_vars;
float *editor_getf(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->f;
}
int *editor_geti(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->i;
}
char **editor_gets(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
if(!found->s) found->s = stringf("%s","");
return &found->s;
}
int editor_send(const char *cmd, const char *optional_value) {
unsigned *gamepads = editor_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
unsigned *renders = editor_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
float *speed = editor_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
unsigned *powersave = editor_geti("powersave");
char *name;
/**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
else if( !strcmp(cmd, "key_stop" )) window_pause(1);
else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
else if( !strcmp(cmd, "key_reload" )) window_reload();
else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(); else
name = file_counter(va("%s.mp4",app_name())), window_record(name), ui_notify(va("Video capturing: %s", name), date_string());
else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
else alert(va("editor could not handle `%s` command.", cmd));
return 0;
}
int editor_tick() {
enum { editor_hz = 60 };
enum { editor_hz_mid = 18 };
enum { editor_hz_low = 5 };
if( *editor_geti("powersave") ) {
// adaptive framerate
int app_on_background = !window_has_focus();
int hz = app_on_background ? editor_hz_low : editor_hz_mid;
window_fps_lock( hz < 5 ? 5 : hz );
} else {
// window_fps_lock( editor_hz );
}
return 0;
}
static int gizmo__mode; static int gizmo__mode;
static int gizmo__active; static int gizmo__active;
static int gizmo__hover; static int gizmo__hover;
@ -176,26 +300,6 @@ int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
return modified; return modified;
} }
char* dialog_load() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
char* dialog_save() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// -- localization kit // -- localization kit
static const char *kit_lang = "enUS", *kit_langs = static const char *kit_lang = "enUS", *kit_langs =

View File

@ -9,6 +9,11 @@
API vec3 editor_pick(float mouse_x, float mouse_y); API vec3 editor_pick(float mouse_x, float mouse_y);
API char* editor_path(const char *path); API char* editor_path(const char *path);
API float* editor_getf(const char *key);
API int* editor_geti(const char *key);
API char** editor_gets(const char *key);
API int editor_send(const char *cmd, const char *optional_value);
// open file dialog // open file dialog
API char* dialog_load(); API char* dialog_load();

View File

@ -257,7 +257,7 @@ bool file_delete(const char *pathfile) {
} }
bool file_copy(const char *src, const char *dst) { bool file_copy(const char *src, const char *dst) {
int ok = 0, BUFSIZE = 1 << 20; // 1 MiB int ok = 0, BUFSIZE = 1 << 20; // 1 MiB
static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); // @leak
for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) { for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) {
for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) { for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) {
for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){ for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){
@ -582,6 +582,8 @@ void vfs_reload() {
#if defined(EMSCRIPTEN) #if defined(EMSCRIPTEN)
vfs_mount("index.zip"); vfs_mount("index.zip");
#else #else
// mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way /* // old way
for( int i = 0; i < JOBS_MAX; ++i) { for( int i = 0; i < JOBS_MAX; ++i) {
if( vfs_mount(va(".art[%02x].zip", i)) ) continue; if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
@ -601,6 +603,34 @@ void vfs_reload() {
} }
} }
#define ARK1 'ArK\x1'
#define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x)
#define ARK_SWAP64(x) (x)
#define ARK_REALLOC REALLOC
static uint64_t ark_fget64( FILE *in ) { uint64_t v; fread( &v, 1, 8, in ); return ARK_SWAP64(v); }
void ark_list( const char *infile, zip **z ) {
for( FILE *in = fopen(infile, "rb"); in; fclose(in), in = 0 )
while(!feof(in)) {
if( 0 != (ftell(in) % ARK1_PADDING) ) fseek(in, ARK1_PADDING - (ftell(in) % ARK1_PADDING), SEEK_CUR);
ARK_PRINTF("Reading at #%d\n", (int)ftell(in));
uint64_t mark = ark_fget64(in);
if( mark != ARK1 ) continue;
uint64_t stamp = ark_fget64(in);
uint64_t datalen = ark_fget64(in);
uint64_t datahash = ark_fget64(in);
uint64_t namelen = ark_fget64(in);
*z = zip_open_handle(in, "rb");
return;
}
}
static static
bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) { bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL; zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL;
@ -610,6 +640,7 @@ bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
if( !is_folder ) z = zip_open(path, "rb"); if( !is_folder ) z = zip_open(path, "rb");
if( !is_folder && !z ) t = tar_open(path, "rb"); if( !is_folder && !z ) t = tar_open(path, "rb");
if( !is_folder && !z && !t ) p = pak_open(path, "rb"); if( !is_folder && !z && !t ) p = pak_open(path, "rb");
if( !is_folder && !z && !t && !p ) ark_list(path, &z); // last resort. try as .ark
if( !is_folder && !z && !t && !p ) return 0; if( !is_folder && !z && !t && !p ) return 0;
// normalize input -> "././" to "" // normalize input -> "././" to ""
@ -794,9 +825,9 @@ if( found && *found == 0 ) {
const char *lookup_id = /*file_normalize_with_folder*/(pathfile); const char *lookup_id = /*file_normalize_with_folder*/(pathfile);
// search (last item) // search (last item)
static char last_item[256] = { 0 }; static __thread char last_item[256] = { 0 };
static void *last_ptr = 0; static __thread void *last_ptr = 0;
static int last_size = 0; static __thread int last_size = 0;
if( !strcmpi(lookup_id, last_item)) { if( !strcmpi(lookup_id, last_item)) {
ptr = last_ptr; ptr = last_ptr;
size = last_size; size = last_size;
@ -953,6 +984,10 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
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
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &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;
*(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero; *(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero;
@ -962,7 +997,8 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
dir_cache->data = REALLOC(0, size+1); dir_cache->data = REALLOC(0, size+1);
memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator
// keep cached files within limits void *found = 0;
static int added = 0; static int added = 0;
if( added < MAX_CACHED_FILES ) { if( added < MAX_CACHED_FILES ) {
++added; ++added;
@ -971,15 +1007,18 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) { for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) {
if( !dir->next ) { if( !dir->next ) {
prev->next = 0; // break link prev->next = 0; // break link
void *data = dir->data; found = dir->data;
dir->path = REALLOC(dir->path, 0); dir->path = REALLOC(dir->path, 0);
dir->data = REALLOC(dir->data, 0); dir->data = REALLOC(dir->data, 0);
dir = REALLOC(dir, 0); dir = REALLOC(dir, 0);
return data; break;
} }
} }
} }
return 0;
thread_mutex_unlock(&mutex);
return found;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -19,18 +19,20 @@ static void v4k_pre_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
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point // init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for #pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ui_init(), 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 ) 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 == 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 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
else if( i == 2 ) script_init(), kit_init(), midi_init(); else if( i == 2 ) script_init(), kit_init(), midi_init();
else if( i == 3 ) input_init(), network_init(); else if( i == 3 ) input_init(), network_init();

View File

@ -8,8 +8,8 @@ static map(unsigned, reflected_t) reflects;
static map(unsigned, array(reflected_t)) members; static map(unsigned, array(reflected_t)) members;
void reflected_printf(reflected_t *r) { void reflected_printf(reflected_t *r) {
printf("id:%u objtype:%u sz:%u name:%s info:%s addr:%p parent:%u type:%s", printf("name:%s info:'%s' id:%u objtype:%u sz:%u addr:%p parent:%u type:%s",
r->id, r->objtype, r->sz, r->name ? r->name : "", r->info ? r->info : "", r->addr, r->parent, r->type ? r->type : ""); r->name ? r->name : "", r->info ? r->info : "", r->id, r->objtype, r->sz, r->addr, r->parent, r->type ? r->type : "");
} }
void reflected_printf_all() { void reflected_printf_all() {
for each_map_ptr(reflects, unsigned, k, reflected_t, p) { for each_map_ptr(reflects, unsigned, k, reflected_t, p) {

View File

@ -4,7 +4,9 @@
// @todo: nested structs? pointers in members? // @todo: nested structs? pointers in members?
// @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/)
#ifndef ifdef_objapi
#define ifdef_objapi(T,...) __VA_ARGS__ #define ifdef_objapi(T,...) __VA_ARGS__
#endif
typedef struct reflected_t { typedef struct reflected_t {
unsigned id, objtype; unsigned id, objtype;

View File

@ -8,16 +8,26 @@ char* tempvl(const char *fmt, va_list vl) {
int reqlen = sz; int reqlen = sz;
#if 0 #if 0
int heap = 0;
enum { STACK_ALLOC = 16384 }; enum { STACK_ALLOC = 16384 };
static __thread char buf[STACK_ALLOC]; static __thread char buf[STACK_ALLOC];
#else #else
enum { STACK_ALLOC = 128*1024 }; int heap = 1;
static __thread int STACK_ALLOC = 128*1024;
static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak
#endif #endif
static __thread int cur = 0, len = STACK_ALLOC - 1; //printf("string stack %d/%d\n", cur, STACK_ALLOC); static __thread int cur = 0; //printf("string stack %d/%d\n", cur, STACK_ALLOC);
assert(reqlen < STACK_ALLOC && "no stack enough, increase STACK_ALLOC variable above"); if( reqlen >= STACK_ALLOC ) {
char* ptr = buf + (cur *= (cur+reqlen) < len, (cur += reqlen) - reqlen); tty_color(RED);
printf("no stack enough, increase STACK_ALLOC variable above (reqlen:%d) (fmt: %s)\n", reqlen, fmt);
tty_color(0);
//assert(reqlen < STACK_ALLOC);
STACK_ALLOC = reqlen * 2;
buf = REALLOC(0, STACK_ALLOC);
}
char* ptr = buf + (cur *= (cur+reqlen) < (STACK_ALLOC - 1), (cur += reqlen) - reqlen);
/*stbsp_*/vsnprintf( ptr, sz, fmt, vl ); /*stbsp_*/vsnprintf( ptr, sz, fmt, vl );
return (char *)ptr; return (char *)ptr;

View File

@ -21,9 +21,10 @@ char* strtok_s(char* str,const char* delimiters,char** context); // tcc misses t
#if 1 #if 1
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( int len_ = strlen(str) + 1; len_; len_ = 0 ) \ ( char *str_ = (char*)(str); str_; str_ = 0 ) \
for( char buf_[1024], *ptr_ = len_ < 1024 ? buf_ : REALLOC(0, len_), *lit_ = (char*)(str), *_bak = (snprintf(ptr_, len_, "%s", lit_), ptr_); _bak; _bak = 0, (ptr_ == buf_ ? 0 : REALLOC(ptr_, 0)) ) \ for( int len_ = strlen(str_) + 1, heap_ = len_ < 1024; len_ > 1; len_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(_bak, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) ) for( char *ptr_ = (heap_ ? REALLOC(0, len_) : ALLOCA(len_)), *cpy_ = (snprintf(ptr_, len_, "%s", str_), ptr_); ptr_; (heap_ ? REALLOC(ptr_, 0) : 0), ptr_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(cpy_, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) )
#else #else
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \ ( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \

View File

@ -850,6 +850,26 @@ bool app_open(const char *link) {
return app_open_url(link); return app_open_url(link);
} }
const char* app_loadfile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
const char* app_savefile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests // tests

View File

@ -38,6 +38,10 @@ API void app_crash();
API void app_singleton(const char *guid); API void app_singleton(const char *guid);
API bool app_open(const char *folder_file_or_url); API bool app_open(const char *folder_file_or_url);
API const char* app_loadfile();
API const char* app_savefile();
API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free(). API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free().
API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order. API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order.

View File

@ -1401,11 +1401,12 @@ int ui_collapse_end() {
int ui_contextual() { int ui_contextual() {
struct nk_rect bounds = nk_widget_bounds(ui_ctx); struct nk_rect bounds = nk_widget_bounds(ui_ctx); // = nk_window_get_bounds(ui_ctx);
bounds.y -= 25; bounds.y -= 25;
return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds); return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds);
} }
int ui_contextual_end() { int ui_contextual_end(int close) {
if(close) nk_contextual_close(ui_ctx);
nk_contextual_end(ui_ctx); nk_contextual_end(ui_ctx);
return 1; return 1;
} }
@ -1416,7 +1417,7 @@ int ui_submenu(const char *options) {
for( int i = 0; i < array_count(tokens) ; ++i ) { for( int i = 0; i < array_count(tokens) ; ++i ) {
if( ui_button_transparent(tokens[i]) ) choice = i + 1; if( ui_button_transparent(tokens[i]) ) choice = i + 1;
} }
ui_contextual_end(); ui_contextual_end(0);
} }
return choice; return choice;
} }
@ -1550,8 +1551,10 @@ int ui_label(const char *text) {
int ui_label2(const char *label, const char *text_) { int ui_label2(const char *label, const char *text_) {
nk_layout_row_dynamic(ui_ctx, 0, 2); nk_layout_row_dynamic(ui_ctx, 0, 2);
int align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align1 = NK_TEXT_LEFT;
int align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align2 = NK_TEXT_LEFT;
if( label ) align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
if( text_ ) align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
ui_label_(label, align1); ui_label_(label, align1);
const struct nk_input *input = &ui_ctx->input; const struct nk_input *input = &ui_ctx->input;

View File

@ -60,7 +60,7 @@ API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons); API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value); API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption); API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_contextual_end(); API int ui_contextual_end(int close);
API int ui_collapse_clicked(); API int ui_collapse_clicked();
API int ui_collapse_end(); API int ui_collapse_end();
API int ui_panel_end(); API int ui_panel_end();

View File

@ -536,12 +536,38 @@ int window_frame_begin() {
if( may_render_stats ) { if( may_render_stats ) {
if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) {
#if 1 static int time_factor = 0;
static char *filter = 0; static int playing = 0;
static int paused = 0;
int advance_frame = 0;
static int do_filter = 0; static int do_filter = 0;
static int do_profile = 0;
static int do_extra = 0;
char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
ICON_MD_PLAY_ARROW,
paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
ICON_MD_FAST_FORWARD,
ICON_MD_STOP,
ICON_MD_REPLAY,
ICON_MD_FACE,
ICON_MD_MENU
);
if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
int choice = ui_toolbar(ICON_MD_SEARCH ";"); int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
if( choice == 1 ) do_filter = 1; if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
if( choice == 2 ) playing = 1, paused = 0;
if( choice == 3 ) advance_frame = !!paused, paused = 1;
if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
if( choice == 6 ) window_reload();
if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
static char *filter = 0;
if( do_filter ) { if( do_filter ) {
ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
@ -551,13 +577,44 @@ int window_frame_begin() {
if( filter ) filter[0] = '\0'; if( filter ) filter[0] = '\0';
} }
char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
#endif
static char *username = 0;
static char *userpass = 0;
if( do_profile ) {
ui_string(ICON_MD_FACE " Username", &username);
ui_string(ICON_MD_FACE " Password", &userpass);
}
if( do_extra ) {
int choice2 = ui_label2_toolbar(NULL,
ICON_MD_VIEW_IN_AR
ICON_MD_MESSAGE
ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
);
}
int open = 0, clicked_or_toggled = 0; int open = 0, clicked_or_toggled = 0;
#define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id))
for( int p = (open = ui_collapse_filtered(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { #define EDITOR_UI_COLLAPSE(f,...) \
for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
// @todo. parse /bugs.ini, includes saved screenshots & videos.
// @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
}
// Art and bookmarks
EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
bool inlined = true; bool inlined = true;
const char *file = 0; const char *file = 0;
if( ui_browse(&file, &inlined) ) { if( ui_browse(&file, &inlined) ) {
@ -565,47 +622,78 @@ int window_frame_begin() {
app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
// E,C,S,W
EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
//node_edit(editor.edit.down,&editor.edit);
}
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
// node_edit(&editor.init,&editor.init);
// node_edit(&editor.draw,&editor.draw);
// node_edit(&editor.tick,&editor.tick);
// node_edit(&editor.edit,&editor.edit);
// node_edit(&editor.quit,&editor.quit);
}
EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
// @todo // @todo
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VOLUME_UP " Audio", "Debug.Audio")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
ui_audio(); ui_audio();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIDEOCAM " Camera", "Debug.Camera")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
ui_camera( camera_get_active() ); ui_camera( camera_get_active() );
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_BUILD " Cook", "Debug.Cook")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
// @todo // @todo: fps lock, fps target, aspect ratio, fullscreen
char *text = va("%s;%s;%s",
window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
ICON_MD_PHOTO_CAMERA,
record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
);
int choice = ui_toolbar(text);
if( choice == 1 ) editor_send("key_fullscreen",0);
if( choice == 2 ) editor_send("key_screenshot",0);
if( choice == 3 ) editor_send("key_record",0);
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_SIGNAL_CELLULAR_ALT " Network", "Debug.Network")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_MOVIE " FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_SPEED " Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_keyboard(); ui_keyboard();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_MOUSE " Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
ui_mouse(); ui_mouse();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
for( int q = 0; q < 4; ++q ) { for( int q = 0; q < 4; ++q ) {
for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
ui_gamepad(q); ui_gamepad(q);
} }
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIEW_QUILT " UI", "Debug.UI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
// @todo
}
EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
ui_shaders();
}
EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
ui_fxs();
}
EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") {
int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout");
if( choice == 1 ) ui_layout_all_reset("*"); if( choice == 1 ) ui_layout_all_reset("*");
if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
@ -618,8 +706,61 @@ int window_frame_begin() {
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
// @todo. // mem,fps,gfx,net,hdd,... also logging
}
EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
// @todo
// SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
}
EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%d", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
ui_profiler();
}
EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
// @todo
}
// logic: either plug icon (power saving off) or one of the following ones (power saving on):
// if 0% batt (no batt): battery alert
// if discharging: battery levels [alert,0..6,full]
// if charging: battery charging
int battery_read = app_battery();
int battery_level = abs(battery_read);
int battery_discharging = battery_read < 0 && battery_level < 100;
const char *power_icon_label = ICON_MD_POWER " Power";
if( battery_level ) {
const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
};
power_icon_label = (const char*)va("%s Power %d%%",
battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
battery_level);
}
EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
if( choice == 1 ) editor_send("key_battery","0");
if( choice == 2 ) editor_send("key_battery","1");
}
EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
// @todo. include VCS
EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
// @todo
}
}
(has_menu ? ui_window_end : ui_panel_end)(); (has_menu ? ui_window_end : ui_panel_end)();
} }
API int editor_tick();
editor_tick();
} }
#if 0 // deprecated #if 0 // deprecated

View File

@ -234245,6 +234245,7 @@ unsigned file_decode(FILE* in, FILE* out, FILE *logfile) { // multi decoder
typedef struct zip zip; typedef struct zip zip;
zip* zip_open(const char *file, const char *mode /*r,w,a*/); zip* zip_open(const char *file, const char *mode /*r,w,a*/);
zip* zip_open_handle(FILE*fp, const char *mode /*r,w,a*/);
// only for (w)rite or (a)ppend mode // only for (w)rite or (a)ppend mode
bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level); bool zip_append_file(zip*, const char *entryname, const char *comment, FILE *in, unsigned compress_level);
@ -234460,7 +234461,7 @@ int jzReadEndRecord(FILE *fp, JZEndRecord *endRecord) {
// Read ZIP file global directory. Will move within file. Returns Z_OK, or error code // Read ZIP file global directory. Will move within file. Returns Z_OK, or error code
// Callback is called for each record, until callback returns zero // Callback is called for each record, until callback returns zero
int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data) { int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback callback, void *user_data, void *user_data2) {
JZGlobalFileHeader fileHeader; JZGlobalFileHeader fileHeader;
if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) { if(fseek(fp, endRecord->centralDirectoryOffset, SEEK_SET)) {
@ -234475,6 +234476,8 @@ int jzReadCentralDirectory(FILE *fp, JZEndRecord *endRecord, JZRecordCallback ca
return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i); return ERR(JZ_ERRNO, "Couldn't read file header #%d!", i);
} }
fileHeader.relativeOffsetOflocalHeader += (uintptr_t)user_data2;
JZGlobalFileHeader *g = &fileHeader, copy = *g; JZGlobalFileHeader *g = &fileHeader, copy = *g;
FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50 FPRINTF(stdout, "\tsignature: %u %#x\n", g->signature, g->signature); // 0x02014B50
FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported FPRINTF(stdout, "\tversionMadeBy: %u %#x\n", g->versionMadeBy, g->versionMadeBy); // unsupported
@ -234967,11 +234970,7 @@ common:;
// zip common // zip common
zip* zip_open(const char *file, const char *mode /*r,w,a*/) { zip* zip_open_handle(FILE *fp, const char *mode) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
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 fclose(fp), ERR(NULL, "out of mem"); else *z = zero;
@ -234982,12 +234981,17 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
if( mode[0] == 'r' || mode[0] == 'a' ) { if( mode[0] == 'r' || mode[0] == 'a' ) {
z->in = fp; z->in = fp;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file end record.");
} }
if(jzReadCentralDirectory(fp, &jzEndRecord, zip__callback, z) != JZ_OK) {
jzEndRecord.centralDirectoryOffset += seekcur;
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 fclose(fp), ERR(NULL, "Couldn't read ZIP file central directory.");
} }
@ -235015,6 +235019,14 @@ zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
return fclose(fp), ERR(NULL, "Unknown open mode %s", mode); return fclose(fp), ERR(NULL, "Unknown open mode %s", mode);
} }
zip* zip_open(const char *file, const char *mode /*r,w,a*/) {
struct stat buffer;
int exists = (stat(file, &buffer) == 0);
if( mode[0] == 'a' && !exists ) mode = "wb";
FILE *fp = fopen(file, mode[0] == 'w' ? "wb" : mode[0] == 'a' ? "a+b" : "rb");
return zip_open_handle(fp, mode);
}
void zip_close(zip* z) { void zip_close(zip* z) {
if( z->out && z->count ) { if( z->out && z->count ) {
// prepare end record // prepare end record
@ -235194,8 +235206,7 @@ tar *tar_open(const char *filename, const char *mode) {
*t = zero; *t = zero;
t->in = in; t->in = in;
tar__parse(in, tar__push_entry, t); return tar__parse(in, tar__push_entry, t) ? t : NULL;
return t;
} }
int tar_find(tar *t, const char *entryname) { int tar_find(tar *t, const char *entryname) {

View File

@ -525,16 +525,26 @@ char* tempvl(const char *fmt, va_list vl) {
int reqlen = sz; int reqlen = sz;
#if 0 #if 0
int heap = 0;
enum { STACK_ALLOC = 16384 }; enum { STACK_ALLOC = 16384 };
static __thread char buf[STACK_ALLOC]; static __thread char buf[STACK_ALLOC];
#else #else
enum { STACK_ALLOC = 128*1024 }; int heap = 1;
static __thread int STACK_ALLOC = 128*1024;
static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak static __thread char *buf = 0; if(!buf) buf = REALLOC(0, STACK_ALLOC); // @leak
#endif #endif
static __thread int cur = 0, len = STACK_ALLOC - 1; //printf("string stack %d/%d\n", cur, STACK_ALLOC); static __thread int cur = 0; //printf("string stack %d/%d\n", cur, STACK_ALLOC);
assert(reqlen < STACK_ALLOC && "no stack enough, increase STACK_ALLOC variable above"); if( reqlen >= STACK_ALLOC ) {
char* ptr = buf + (cur *= (cur+reqlen) < len, (cur += reqlen) - reqlen); tty_color(RED);
printf("no stack enough, increase STACK_ALLOC variable above (reqlen:%d) (fmt: %s)\n", reqlen, fmt);
tty_color(0);
//assert(reqlen < STACK_ALLOC);
STACK_ALLOC = reqlen * 2;
buf = REALLOC(0, STACK_ALLOC);
}
char* ptr = buf + (cur *= (cur+reqlen) < (STACK_ALLOC - 1), (cur += reqlen) - reqlen);
/*stbsp_*/vsnprintf( ptr, sz, fmt, vl ); /*stbsp_*/vsnprintf( ptr, sz, fmt, vl );
return (char *)ptr; return (char *)ptr;
@ -1430,10 +1440,17 @@ float audio_volume_master(float gain) {
mixer.gain = volume_master; mixer.gain = volume_master;
return sqrt( volume_master ); return sqrt( volume_master );
} }
int audio_mute(int mute) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if( mute >= 0 && mute <= 1 ) muted = mute;
return muted;
}
int audio_muted() {
return audio_mute(-1);
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) { int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted"); if(audio_muted()) return 1;
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) { if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is // do nothing, gain used as-is
@ -4179,7 +4196,7 @@ array(struct fs) zipscan_filter(int threadid, int numthreads) {
// skip if list item does not belong to this thread bucket // skip if list item does not belong to this thread bucket
uint64_t hash = hash_str(fname); uint64_t hash = hash_str(fname);
unsigned bucket = (hash >> 32) % numthreads; unsigned bucket = (hash /*>> 32*/) % numthreads;
if(bucket != threadid) continue; if(bucket != threadid) continue;
array_push(fs, fs_now[i]); array_push(fs, fs_now[i]);
@ -4436,10 +4453,8 @@ bool cook_start( const char *cook_ini, const char *masks, int flags ) {
char *s = strchr( ART, ';' ); if(s) *s = 0; char *s = strchr( ART, ';' ); if(s) *s = 0;
char *w = strchr( ART, ' ' ); if(w) *w = 0; char *w = strchr( ART, ' ' ); if(w) *w = 0;
char *out = 0; const char *sep = ""; char *out = 0; const char *sep = "";
const char *v4k_title = getenv("V4K_TITLE");
for each_substring(ART, ",", t) { for each_substring(ART, ",", t) {
char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN; char *tmp = file_pathabs(va("%s%s", HOME, t)) + ART_LEN;
PRINTF("ART mount+=%s\n", tmp);
for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/'; for(int i = 0; tmp[i]; ++i) if(tmp[i]=='\\') tmp[i] = '/';
strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/"); strcatf(&out, "%s%s%s", sep, tmp, strendi(tmp, "/") ? "" : "/");
assert( out[strlen(out) - 1] == '/' ); assert( out[strlen(out) - 1] == '/' );
@ -5226,7 +5241,7 @@ bool file_delete(const char *pathfile) {
} }
bool file_copy(const char *src, const char *dst) { bool file_copy(const char *src, const char *dst) {
int ok = 0, BUFSIZE = 1 << 20; // 1 MiB int ok = 0, BUFSIZE = 1 << 20; // 1 MiB
static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); static __thread char *buffer = 0; do_once buffer = REALLOC(0, BUFSIZE); // @leak
for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) { for( FILE *in = fopen(src, "rb"); in; fclose(in), in = 0) {
for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) { for( FILE *out = fopen(dst, "wb"); out; fclose(out), out = 0, ok = 1) {
for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){ for( int n; !!(n = fread( buffer, 1, BUFSIZE, in )); ){
@ -5551,6 +5566,8 @@ void vfs_reload() {
#if defined(EMSCRIPTEN) #if defined(EMSCRIPTEN)
vfs_mount("index.zip"); vfs_mount("index.zip");
#else #else
// mount fused executables
vfs_mount(va("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")));
/* // old way /* // old way
for( int i = 0; i < JOBS_MAX; ++i) { for( int i = 0; i < JOBS_MAX; ++i) {
if( vfs_mount(va(".art[%02x].zip", i)) ) continue; if( vfs_mount(va(".art[%02x].zip", i)) ) continue;
@ -5570,6 +5587,34 @@ void vfs_reload() {
} }
} }
#define ARK1 'ArK\x1'
#define ARK1_PADDING (512 - 40) // 472
#define ARK_PRINTF(f,...) 0 // printf(f,__VA_ARGS__)
#define ARK_SWAP32(x) (x)
#define ARK_SWAP64(x) (x)
#define ARK_REALLOC REALLOC
static uint64_t ark_fget64( FILE *in ) { uint64_t v; fread( &v, 1, 8, in ); return ARK_SWAP64(v); }
void ark_list( const char *infile, zip **z ) {
for( FILE *in = fopen(infile, "rb"); in; fclose(in), in = 0 )
while(!feof(in)) {
if( 0 != (ftell(in) % ARK1_PADDING) ) fseek(in, ARK1_PADDING - (ftell(in) % ARK1_PADDING), SEEK_CUR);
ARK_PRINTF("Reading at #%d\n", (int)ftell(in));
uint64_t mark = ark_fget64(in);
if( mark != ARK1 ) continue;
uint64_t stamp = ark_fget64(in);
uint64_t datalen = ark_fget64(in);
uint64_t datahash = ark_fget64(in);
uint64_t namelen = ark_fget64(in);
*z = zip_open_handle(in, "rb");
return;
}
}
static static
bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) { bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL; zip *z = NULL; tar *t = NULL; pak *p = NULL; dir *d = NULL;
@ -5579,6 +5624,7 @@ bool vfs_mount_(const char *path, array(struct vfs_entry) *entries) {
if( !is_folder ) z = zip_open(path, "rb"); if( !is_folder ) z = zip_open(path, "rb");
if( !is_folder && !z ) t = tar_open(path, "rb"); if( !is_folder && !z ) t = tar_open(path, "rb");
if( !is_folder && !z && !t ) p = pak_open(path, "rb"); if( !is_folder && !z && !t ) p = pak_open(path, "rb");
if( !is_folder && !z && !t && !p ) ark_list(path, &z); // last resort. try as .ark
if( !is_folder && !z && !t && !p ) return 0; if( !is_folder && !z && !t && !p ) return 0;
// normalize input -> "././" to "" // normalize input -> "././" to ""
@ -5763,9 +5809,9 @@ if( found && *found == 0 ) {
const char *lookup_id = /*file_normalize_with_folder*/(pathfile); const char *lookup_id = /*file_normalize_with_folder*/(pathfile);
// search (last item) // search (last item)
static char last_item[256] = { 0 }; static __thread char last_item[256] = { 0 };
static void *last_ptr = 0; static __thread void *last_ptr = 0;
static int last_size = 0; static __thread int last_size = 0;
if( !strcmpi(lookup_id, last_item)) { if( !strcmpi(lookup_id, last_item)) {
ptr = last_ptr; ptr = last_ptr;
size = last_size; size = last_size;
@ -5922,6 +5968,10 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
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
static thread_mutex_t mutex, *init = 0; if(!init) thread_mutex_init(init = &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;
*(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero; *(dir_cache = REALLOC(0, sizeof(archive_dir))) = zero;
@ -5931,7 +5981,8 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
dir_cache->data = REALLOC(0, size+1); dir_cache->data = REALLOC(0, size+1);
memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator memcpy(dir_cache->data, ptr, size); size[(char*)dir_cache->data] = 0; // copy+terminator
// keep cached files within limits void *found = 0;
static int added = 0; static int added = 0;
if( added < MAX_CACHED_FILES ) { if( added < MAX_CACHED_FILES ) {
++added; ++added;
@ -5940,15 +5991,18 @@ void* cache_insert(const char *pathfile, void *ptr, int size) { // append key/va
for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) { for( archive_dir *prev = dir_cache, *dir = prev; dir ; prev = dir, dir = dir->next ) {
if( !dir->next ) { if( !dir->next ) {
prev->next = 0; // break link prev->next = 0; // break link
void *data = dir->data; found = dir->data;
dir->path = REALLOC(dir->path, 0); dir->path = REALLOC(dir->path, 0);
dir->data = REALLOC(dir->data, 0); dir->data = REALLOC(dir->data, 0);
dir = REALLOC(dir, 0); dir = REALLOC(dir, 0);
return data; break;
} }
} }
} }
return 0;
thread_mutex_unlock(&mutex);
return found;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -12721,8 +12775,8 @@ static map(unsigned, reflected_t) reflects;
static map(unsigned, array(reflected_t)) members; static map(unsigned, array(reflected_t)) members;
void reflected_printf(reflected_t *r) { void reflected_printf(reflected_t *r) {
printf("id:%u objtype:%u sz:%u name:%s info:%s addr:%p parent:%u type:%s", printf("name:%s info:'%s' id:%u objtype:%u sz:%u addr:%p parent:%u type:%s",
r->id, r->objtype, r->sz, r->name ? r->name : "", r->info ? r->info : "", r->addr, r->parent, r->type ? r->type : ""); r->name ? r->name : "", r->info ? r->info : "", r->id, r->objtype, r->sz, r->addr, r->parent, r->type ? r->type : "");
} }
void reflected_printf_all() { void reflected_printf_all() {
for each_map_ptr(reflects, unsigned, k, reflected_t, p) { for each_map_ptr(reflects, unsigned, k, reflected_t, p) {
@ -20295,6 +20349,26 @@ bool app_open(const char *link) {
return app_open_url(link); return app_open_url(link);
} }
const char* app_loadfile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
const char* app_savefile() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests // tests
@ -21881,11 +21955,12 @@ int ui_collapse_end() {
int ui_contextual() { int ui_contextual() {
struct nk_rect bounds = nk_widget_bounds(ui_ctx); struct nk_rect bounds = nk_widget_bounds(ui_ctx); // = nk_window_get_bounds(ui_ctx);
bounds.y -= 25; bounds.y -= 25;
return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds); return ui_popups() ? 0 : nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 300), bounds);
} }
int ui_contextual_end() { int ui_contextual_end(int close) {
if(close) nk_contextual_close(ui_ctx);
nk_contextual_end(ui_ctx); nk_contextual_end(ui_ctx);
return 1; return 1;
} }
@ -21896,7 +21971,7 @@ int ui_submenu(const char *options) {
for( int i = 0; i < array_count(tokens) ; ++i ) { for( int i = 0; i < array_count(tokens) ; ++i ) {
if( ui_button_transparent(tokens[i]) ) choice = i + 1; if( ui_button_transparent(tokens[i]) ) choice = i + 1;
} }
ui_contextual_end(); ui_contextual_end(0);
} }
return choice; return choice;
} }
@ -22030,8 +22105,10 @@ int ui_label(const char *text) {
int ui_label2(const char *label, const char *text_) { int ui_label2(const char *label, const char *text_) {
nk_layout_row_dynamic(ui_ctx, 0, 2); nk_layout_row_dynamic(ui_ctx, 0, 2);
int align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align1 = NK_TEXT_LEFT;
int align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT; int align2 = NK_TEXT_LEFT;
if( label ) align1 = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
if( text_ ) align2 = text_[0] == '>' ? (text_++, NK_TEXT_RIGHT) : text_[0] == '=' ? (text_++, NK_TEXT_CENTERED) : text_[0] == '<' ? (text_++, NK_TEXT_LEFT) : NK_TEXT_LEFT;
ui_label_(label, align1); ui_label_(label, align1);
const struct nk_input *input = &ui_ctx->input; const struct nk_input *input = &ui_ctx->input;
@ -23766,12 +23843,38 @@ int window_frame_begin() {
if( may_render_stats ) { if( may_render_stats ) {
if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) {
#if 1 static int time_factor = 0;
static char *filter = 0; static int playing = 0;
static int paused = 0;
int advance_frame = 0;
static int do_filter = 0; static int do_filter = 0;
static int do_profile = 0;
static int do_extra = 0;
char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
ICON_MD_PLAY_ARROW,
paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
ICON_MD_FAST_FORWARD,
ICON_MD_STOP,
ICON_MD_REPLAY,
ICON_MD_FACE,
ICON_MD_MENU
);
if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
int choice = ui_toolbar(ICON_MD_SEARCH ";"); int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
if( choice == 1 ) do_filter = 1; if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
if( choice == 2 ) playing = 1, paused = 0;
if( choice == 3 ) advance_frame = !!paused, paused = 1;
if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
if( choice == 6 ) window_reload();
if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
static char *filter = 0;
if( do_filter ) { if( do_filter ) {
ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
@ -23781,13 +23884,44 @@ int window_frame_begin() {
if( filter ) filter[0] = '\0'; if( filter ) filter[0] = '\0';
} }
char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
#endif
static char *username = 0;
static char *userpass = 0;
if( do_profile ) {
ui_string(ICON_MD_FACE " Username", &username);
ui_string(ICON_MD_FACE " Password", &userpass);
}
if( do_extra ) {
int choice2 = ui_label2_toolbar(NULL,
ICON_MD_VIEW_IN_AR
ICON_MD_MESSAGE
ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
);
}
int open = 0, clicked_or_toggled = 0; int open = 0, clicked_or_toggled = 0;
#define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id))
for( int p = (open = ui_collapse_filtered(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { #define EDITOR_UI_COLLAPSE(f,...) \
for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
// @todo. parse /bugs.ini, includes saved screenshots & videos.
// @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
}
// Art and bookmarks
EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
bool inlined = true; bool inlined = true;
const char *file = 0; const char *file = 0;
if( ui_browse(&file, &inlined) ) { if( ui_browse(&file, &inlined) ) {
@ -23795,47 +23929,78 @@ int window_frame_begin() {
app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
// E,C,S,W
EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
//node_edit(editor.edit.down,&editor.edit);
}
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
// node_edit(&editor.init,&editor.init);
// node_edit(&editor.draw,&editor.draw);
// node_edit(&editor.tick,&editor.tick);
// node_edit(&editor.edit,&editor.edit);
// node_edit(&editor.quit,&editor.quit);
}
EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
// @todo // @todo
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VOLUME_UP " Audio", "Debug.Audio")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
ui_audio(); ui_audio();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIDEOCAM " Camera", "Debug.Camera")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
ui_camera( camera_get_active() ); ui_camera( camera_get_active() );
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_BUILD " Cook", "Debug.Cook")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
// @todo // @todo: fps lock, fps target, aspect ratio, fullscreen
char *text = va("%s;%s;%s",
window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
ICON_MD_PHOTO_CAMERA,
record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
);
int choice = ui_toolbar(text);
if( choice == 1 ) editor_send("key_fullscreen",0);
if( choice == 2 ) editor_send("key_screenshot",0);
if( choice == 3 ) editor_send("key_record",0);
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_SIGNAL_CELLULAR_ALT " Network", "Debug.Network")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
// @todo
}
for( int p = (open = ui_collapse_filtered(ICON_MD_MOVIE " FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_SPEED " Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse_filtered(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_keyboard(); ui_keyboard();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_MOUSE " Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
ui_mouse(); ui_mouse();
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) { EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
for( int q = 0; q < 4; ++q ) { for( int q = 0; q < 4; ++q ) {
for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
ui_gamepad(q); ui_gamepad(q);
} }
} }
} }
for( int p = (open = ui_collapse_filtered(ICON_MD_VIEW_QUILT " UI", "Debug.UI")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
// @todo
}
EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
ui_shaders();
}
EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
ui_fxs();
}
EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") {
int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout");
if( choice == 1 ) ui_layout_all_reset("*"); if( choice == 1 ) ui_layout_all_reset("*");
if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
@ -23848,8 +24013,61 @@ int window_frame_begin() {
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
// @todo. // mem,fps,gfx,net,hdd,... also logging
}
EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
// @todo
// SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
}
EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%d", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
ui_profiler();
}
EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
// @todo
}
// logic: either plug icon (power saving off) or one of the following ones (power saving on):
// if 0% batt (no batt): battery alert
// if discharging: battery levels [alert,0..6,full]
// if charging: battery charging
int battery_read = app_battery();
int battery_level = abs(battery_read);
int battery_discharging = battery_read < 0 && battery_level < 100;
const char *power_icon_label = ICON_MD_POWER " Power";
if( battery_level ) {
const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
};
power_icon_label = (const char*)va("%s Power %d%%",
battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
battery_level);
}
EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
if( choice == 1 ) editor_send("key_battery","0");
if( choice == 2 ) editor_send("key_battery","1");
}
EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
// @todo. include VCS
EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
// @todo
}
}
(has_menu ? ui_window_end : ui_panel_end)(); (has_menu ? ui_window_end : ui_panel_end)();
} }
API int editor_tick();
editor_tick();
} }
#if 0 // deprecated #if 0 // deprecated
@ -25250,6 +25468,61 @@ int ui_bt(bt_t *b) {
// editing: // editing:
// nope > functions: add/rem property // nope > functions: add/rem property
#define ICON_PLAY ICON_MD_PLAY_ARROW
#define ICON_PAUSE ICON_MD_PAUSE
#define ICON_STOP ICON_MD_STOP
#define ICON_CANCEL ICON_MD_CLOSE
#define ICON_WARNING ICON_MD_WARNING
#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
#define ICON_OUTLINER ICON_MD_VIEW_IN_AR
#define ICON_BUILD ICON_MD_BUILD
#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
#define ICON_CAMERA_ON ICON_MD_VIDEOCAM
#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
#define ICON_AUDIO_ON ICON_MD_VOLUME_UP
#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
#define ICON_FULLSCREEN ICON_MD_FULLSCREEN
#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
#define ICON_DISK ICON_MD_STORAGE
#define ICON_RATE ICON_MD_SPEED
#define ICON_CLOCK ICON_MD_TODAY
#define ICON_CHRONO ICON_MD_TIMELAPSE
#define ICON_SETTINGS ICON_MD_SETTINGS
#define ICON_LANGUAGE ICON_MD_G_TRANSLATE
#define ICON_PERSONA ICON_MD_FACE
#define ICON_SOCIAL ICON_MD_MESSAGE
#define ICON_GAME ICON_MD_ROCKET_LAUNCH
#define ICON_KEYBOARD ICON_MD_KEYBOARD
#define ICON_MOUSE ICON_MD_MOUSE
#define ICON_GAMEPAD ICON_MD_GAMEPAD
#define ICON_MONITOR ICON_MD_MONITOR
#define ICON_WIFI ICON_MD_WIFI
#define ICON_BUDGET ICON_MD_SAVINGS
#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
#define ICON_PLUGIN ICON_MD_EXTENSION
#define ICON_RESTART ICON_MD_REPLAY
#define ICON_QUIT ICON_MD_CLOSE
#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
#define ICON_BATTERY_LEVELS \
ICON_MD_BATTERY_ALERT, \
ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
char *editor_path(const char *path) { char *editor_path(const char *path) {
return va("%s/%s", EDITOR, path); return va("%s/%s", EDITOR, path);
} }
@ -25314,6 +25587,75 @@ int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate
return clicked | (copy ^ *enabled); return clicked | (copy ^ *enabled);
} }
typedef union editor_var {
int i;
float f;
char *s;
} editor_var;
static map(char*,editor_var) editor_vars;
float *editor_getf(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->f;
}
int *editor_geti(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
return &found->i;
}
char **editor_gets(const char *key) {
if(!editor_vars) map_init_str(editor_vars);
editor_var *found = map_find_or_add(editor_vars, (char*)key, ((editor_var){0}) );
if(!found->s) found->s = stringf("%s","");
return &found->s;
}
int editor_send(const char *cmd, const char *optional_value) {
unsigned *gamepads = editor_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
unsigned *renders = editor_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
float *speed = editor_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
unsigned *powersave = editor_geti("powersave");
char *name;
/**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
else if( !strcmp(cmd, "key_stop" )) window_pause(1);
else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
else if( !strcmp(cmd, "key_reload" )) window_reload();
else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(); else
name = file_counter(va("%s.mp4",app_name())), window_record(name), ui_notify(va("Video capturing: %s", name), date_string());
else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
else alert(va("editor could not handle `%s` command.", cmd));
return 0;
}
int editor_tick() {
enum { editor_hz = 60 };
enum { editor_hz_mid = 18 };
enum { editor_hz_low = 5 };
if( *editor_geti("powersave") ) {
// adaptive framerate
int app_on_background = !window_has_focus();
int hz = app_on_background ? editor_hz_low : editor_hz_mid;
window_fps_lock( hz < 5 ? 5 : hz );
} else {
// window_fps_lock( editor_hz );
}
return 0;
}
static int gizmo__mode; static int gizmo__mode;
static int gizmo__active; static int gizmo__active;
static int gizmo__hover; static int gizmo__hover;
@ -25425,26 +25767,6 @@ int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
return modified; return modified;
} }
char* dialog_load() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
int allowMultipleSelections = 0;
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_openFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints, allowMultipleSelections );
}
char* dialog_save() {
const char *windowTitle = NULL;
const char *defaultPathFile = NULL;
const char *filterHints = NULL; // "image files"
const char *filters[] = { "*.*" };
tinyfd_assumeGraphicDisplay = 1;
return tinyfd_saveFileDialog( windowTitle, defaultPathFile, countof(filters), filters, filterHints );
}
// -- localization kit // -- localization kit
static const char *kit_lang = "enUS", *kit_langs = static const char *kit_lang = "enUS", *kit_langs =
@ -25618,18 +25940,20 @@ static void v4k_pre_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
ui_init();
// init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point // init more subsystems; beware of VFS mounting, as some of these may need cooked assets at this point
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for #pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ui_init(), 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 ) 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 == 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 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
else if( i == 2 ) script_init(), kit_init(), midi_init(); else if( i == 2 ) script_init(), kit_init(), midi_init();
else if( i == 3 ) input_init(), network_init(); else if( i == 3 ) input_init(), network_init();

View File

@ -1359,9 +1359,12 @@ API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch
API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ ); API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ );
API int audio_stop( audio_t a ); API int audio_stop( audio_t a );
API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. return current fx volume in any case API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case
API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. return current bgm volume in any case API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case
API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. return current master volume in any case API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case
API int audio_mute(int mute);
API int audio_muted();
API int ui_audio(); API int ui_audio();
@ -1750,6 +1753,11 @@ API void* dll(const char *filename, const char *symbol);
API vec3 editor_pick(float mouse_x, float mouse_y); API vec3 editor_pick(float mouse_x, float mouse_y);
API char* editor_path(const char *path); API char* editor_path(const char *path);
API float* editor_getf(const char *key);
API int* editor_geti(const char *key);
API char** editor_gets(const char *key);
API int editor_send(const char *cmd, const char *optional_value);
// open file dialog // open file dialog
API char* dialog_load(); API char* dialog_load();
@ -2587,7 +2595,9 @@ extern API int profiler_enabled; ///-
// @todo: nested structs? pointers in members? // @todo: nested structs? pointers in members?
// @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/)
#ifndef ifdef_objapi
#define ifdef_objapi(T,...) __VA_ARGS__ #define ifdef_objapi(T,...) __VA_ARGS__
#endif
typedef struct reflected_t { typedef struct reflected_t {
unsigned id, objtype; unsigned id, objtype;
@ -3586,9 +3596,10 @@ char* strtok_s(char* str,const char* delimiters,char** context); // tcc misses t
#if 1 #if 1
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( int len_ = strlen(str) + 1; len_; len_ = 0 ) \ ( char *str_ = (char*)(str); str_; str_ = 0 ) \
for( char buf_[1024], *ptr_ = len_ < 1024 ? buf_ : REALLOC(0, len_), *lit_ = (char*)(str), *_bak = (snprintf(ptr_, len_, "%s", lit_), ptr_); _bak; _bak = 0, (ptr_ == buf_ ? 0 : REALLOC(ptr_, 0)) ) \ for( int len_ = strlen(str_) + 1, heap_ = len_ < 1024; len_ > 1; len_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(_bak, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) ) for( char *ptr_ = (heap_ ? REALLOC(0, len_) : ALLOCA(len_)), *cpy_ = (snprintf(ptr_, len_, "%s", str_), ptr_); ptr_; (heap_ ? REALLOC(ptr_, 0) : 0), ptr_ = 0 ) \
for( char *next_token = 0, *keyname = strtok_r(cpy_, delims, &next_token); keyname; keyname = strtok_r(NULL, delims, &next_token) )
#else #else
#define each_substring(str, delims, keyname) \ #define each_substring(str, delims, keyname) \
( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \ ( char** tokens_ = strsplit((str), (delims)), *keyname = 0; tokens_; tokens_ = 0) \
@ -3743,6 +3754,10 @@ API void app_crash();
API void app_singleton(const char *guid); API void app_singleton(const char *guid);
API bool app_open(const char *folder_file_or_url); API bool app_open(const char *folder_file_or_url);
API const char* app_loadfile();
API const char* app_savefile();
API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free(). API char* callstack( int traces ); // write callstack into a temporary string. <0 traces to invert order. do not free().
API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order. API int callstackf( FILE *fp, int traces ); // write callstack to file. <0 traces to invert order.
@ -3842,7 +3857,7 @@ API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons); API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value); API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption); API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_contextual_end(); API int ui_contextual_end(int close);
API int ui_collapse_clicked(); API int ui_collapse_clicked();
API int ui_collapse_end(); API int ui_collapse_end();
API int ui_panel_end(); API int ui_panel_end();

138
tools/ark.c 100644
View File

@ -0,0 +1,138 @@
// ARK: lightweight, append-only, header-less journaling file format specification.
// - rlyeh, public domain.
// Features:
// - [x] Journaling support: data can be rolled back to an earlier state to retrieve older versions of files.
// - [x] Append-only format: create or update new entries just by appending stuff to the journal file.
// - [x] Compaction support: compact archives by keeping, for each duplicated file, its latest revision only.
// - [x] Concat friendly: journals can be glued together, and the result will still be a valid journey file.
// - [x] Foreign support: append random data to a foreign file and result will still be a valid journey file.
// - [x] Always aligned: file data is always 512-byte aligned for safe/fast memory access.
// - [x] Simple, tiny, portable, cross-platform, header-only.
// - [x] Public domain, CC0, 0-BSD, unlicensed (pick one).
// Extension:
// .ark
// File format:
// [foreign data]
// [...]
// [archive-entry #1]
// [archive-entry #2]
// [...]
// [archive-entry #N]
// [EOF]
//
// Where, each archive-entry is {
// [zero] 472-byte aligned zero padding
// [mark] 64-bit magic id 'Ark\x1' (if \1krA is found, swap endianness)
// [time] 64-bit time stamp in seconds (unix epoch)
// [dlen] 64-bit data length
// [hash] 64-bit data hash
// [nlen] 64-bit name length+1
// [data] file data (512-byte aligned)
// [name] file name+NUL
// }
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define ARK1 'ArK\x1'
#define ARK1_PADDING (512 - 40) // 472
#ifndef ARK_PRINTF
#define ARK_PRINTF printf
#endif
#ifndef ARK_SWAP32
#define ARK_SWAP32(x) x
#define ARK_SWAP64(x) x
#endif
#ifndef ARK_REALLOC
#define ARK_REALLOC realloc
#endif
static int ark_fput64( FILE *out, uint64_t v ) { return fwrite( (v = ARK_SWAP64(v), &v), 1, 8, out); }
static uint64_t ark_fget64( FILE *in ) { uint64_t v; fread( &v, 1, 8, in ); return ARK_SWAP64(v); }
static const char ark1_zero[ARK1_PADDING] = {0};
// `outfile` must be fopen("file.ark", "a+b") beforehand
int ark_append_mem( FILE *out, const char *name, const void *data, int datalen, uint64_t stamp ) {
fseek( out, 0L, SEEK_END );
while( 0 != (ftell(out) % ARK1_PADDING) ) fwrite(ark1_zero, 1, ARK1_PADDING - (ftell(out) % ARK1_PADDING), out);
ARK_PRINTF("Writing %s at #%d\n", name, (int)ftell(out));
int namelen = strlen(name) + 1;
uint64_t mark = ARK1;
ark_fput64(out, mark);
ark_fput64(out, stamp);
ark_fput64(out, datalen);
ark_fput64(out, 0ULL/*hash*/);
ark_fput64(out, namelen);
fwrite(data, 1, datalen, out);
fwrite(name, 1, namelen, out);
return 1;
}
// `outfile` must be fopen("file.ark", "a+b") beforehand
int ark_append_file( FILE *out, const char *name ) {
FILE *in = fopen(name, "rb");
if( in ) {
fseek(in, 0L, SEEK_END);
size_t sz = ftell(in);
fseek(in, 0L, SEEK_SET);
char *buffer = ARK_REALLOC(0, sz);
if( !buffer ) return fclose(in), 0;
fread(buffer, 1, sz, in);
fclose(in);
int rc = ark_append_mem(out, name, buffer, sz, 0ULL);
ARK_REALLOC(buffer, 0);
return rc;
}
return 0;
}
void ark_list( FILE *in, void *yield_fn ) {
int (*ark_yield_fn)() = yield_fn;
while( !feof(in) ) {
while( 0 != (ftell(in) % ARK1_PADDING) && !feof(in) ) fseek(in, ARK1_PADDING - (ftell(in) % ARK1_PADDING), SEEK_CUR);
ARK_PRINTF("Reading at #%d\n", (int)ftell(in));
uint64_t mark = ark_fget64(in);
if( mark != ARK1 ) continue;
uint64_t stamp = ark_fget64(in);
uint64_t datalen = ark_fget64(in);
uint64_t datahash = ark_fget64(in);
uint64_t namelen = ark_fget64(in);
char *data = ARK_REALLOC(0, datalen);
fread(data, 1, datalen, in);
char *name = ARK_REALLOC(0, namelen);
fread(name, 1, namelen, in);
if( yield_fn == printf ) {
printf("Found %s (%d bytes)\n", name, (int)datalen );
ARK_REALLOC(name, 0);
ARK_REALLOC(data, 0);
}
else {
if( !ark_yield_fn(name, data, datalen, datahash, stamp) )
return;
}
}
}
int main(int argc, char **argv) {
if( argc > 2 ) {
FILE *ark = fopen(argv[1], "a+b");
if( ark ) for( int i = 2; i < argc; ++i) ark_append_file( ark, argv[i] );
if( ark ) fclose(ark);
}
else if( argc == 2 ) {
FILE *ark = fopen(argv[1], "rb");
if( ark ) ark_list(ark, printf), fclose(ark);
}
else printf("%s infile.ark\n%s outfile.ark infile1 [infile2...]\n", argv[0], argv[0]);
}
// cl ark.c /MT /O2 /DNDEBUG /link setargv.obj

BIN
tools/ark.exe 100644

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
Pictogrammers Free License
--------------------------
This icon collection is released as free, open source, and GPL friendly by
the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it
for commercial projects, open source projects, or anything really.
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
Some of the icons are redistributed under the Apache 2.0 license. All other
icons are either redistributed under their respective licenses or are
distributed under the Apache 2.0 license.
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
All web and desktop fonts are distributed under the Apache 2.0 license. Web
and desktop fonts contain some icons that are redistributed under the Apache
2.0 license. All other icons are either redistributed under their respective
licenses or are distributed under the Apache 2.0 license.
# Code: MIT (https://opensource.org/licenses/MIT)
The MIT license applies to all non-font and non-icon files.

View File

@ -61,7 +61,7 @@
// ### editor (v4) // ### editor (v4)
// Bring in remote datas into the editor. // Bring in remote datas into the editor.
// Go social & marketplace. Allow others to expand, share, publish, subscribe, discuss their sub-editors within a small community. // Go social & marketplace. Allow others to expand, share, publish, subscribe, discuss their sub-editors within a small community.
// I really like the way the way OpenFrameworks.cc does their addons, and I think we should do same: just discover and monitor github repos, and list everything on a website (v4k- prefix?). // I really like the way the way OpenFrameworks.cc does their addons, and I think we should do same: just discover and monitor github repos, and list everything on a website (fwk- prefix?).
// Wishlist for a github-based community flow: discovery, transparent installs, publish on github, star there, watch commits & releases, track issues+discussions, etc // Wishlist for a github-based community flow: discovery, transparent installs, publish on github, star there, watch commits & releases, track issues+discussions, etc
// //
// We should have a generic, extensible, script/plugin-driven, working editor at this point (hopefully) that does not require maintenance. // We should have a generic, extensible, script/plugin-driven, working editor at this point (hopefully) that does not require maintenance.
@ -153,7 +153,7 @@
// - ecs: sys are modules, ecs: char *messaging, ecs: filesystem (e/dir,c/files,s/dll) // - ecs: sys are modules, ecs: char *messaging, ecs: filesystem (e/dir,c/files,s/dll)
// - world: streaming, migration // - world: streaming, migration
#include "v4k.h" #include "fwk.h"
// #include "labs.vm/ecs.c" // #include "labs.vm/ecs.c"
@ -839,10 +839,10 @@ void editor_obj_render_max_properties(void *obj, const char *mask) { // headless
// main editor interface // main editor interface
void editor_render_menubar() { void editor_render_menubar() {
int alts = input(KEY_LALT) || input(KEY_RALT); // @todo: move to v4k.c int alts = input(KEY_LALT) || input(KEY_RALT); // @todo: move to fwk.c
int ctrls = input(KEY_LCTRL) || input(KEY_RCTRL); // @todo: move to v4k.c int ctrls = input(KEY_LCTRL) || input(KEY_RCTRL); // @todo: move to fwk.c
int shifts = input(KEY_LSHIFT) || input(KEY_RSHIFT); // @todo: move to v4k.c int shifts = input(KEY_LSHIFT) || input(KEY_RSHIFT); // @todo: move to fwk.c
int mods = alts || ctrls || shifts; // @todo: move to v4k.c int mods = alts || ctrls || shifts; // @todo: move to fwk.c
if( input_down(KEY_F5) ) editor_key = key_reload; if( input_down(KEY_F5) ) editor_key = key_reload;
if( input_down(KEY_F11) ) editor_key = key_fullscreen; if( input_down(KEY_F11) ) editor_key = key_fullscreen;
if( input_down(KEY_PAUSE) ) editor_key = key_pause; if( input_down(KEY_PAUSE) ) editor_key = key_pause;
@ -1046,7 +1046,7 @@ void editor_obj_render_properties_recursively(void *obj, const char *mask) {
if( ui_button_transparent("<Cut" ) ) do_context_obj = obj, do_context_cmd = cc3(c,u,t); if( ui_button_transparent("<Cut" ) ) do_context_obj = obj, do_context_cmd = cc3(c,u,t);
if( ui_button_transparent("<Copy" ) ) do_context_obj = obj, do_context_cmd = cc4(c,o,p,y); if( ui_button_transparent("<Copy" ) ) do_context_obj = obj, do_context_cmd = cc4(c,o,p,y);
if( ui_button_transparent("<Paste") ) do_context_obj = obj, do_context_cmd = cc5(p,a,s,t,e); if( ui_button_transparent("<Paste") ) do_context_obj = obj, do_context_cmd = cc5(p,a,s,t,e);
ui_contextual_end(); ui_contextual_end(0);
} }
for( int i = 0; i < num_subobjects; ++i ) { for( int i = 0; i < num_subobjects; ++i ) {
@ -1067,7 +1067,7 @@ void editor_obj_render_properties_recursively(void *obj, const char *mask) {
if( ui_button_transparent("<Cut" ) ) do_context_obj = obj, do_context_cmd = cc3(c,u,t); if( ui_button_transparent("<Cut" ) ) do_context_obj = obj, do_context_cmd = cc3(c,u,t);
if( ui_button_transparent("<Copy" ) ) do_context_obj = obj, do_context_cmd = cc4(c,o,p,y); if( ui_button_transparent("<Copy" ) ) do_context_obj = obj, do_context_cmd = cc4(c,o,p,y);
if( ui_button_transparent("<Paste") ) do_context_obj = obj, do_context_cmd = cc5(p,a,s,t,e); if( ui_button_transparent("<Paste") ) do_context_obj = obj, do_context_cmd = cc5(p,a,s,t,e);
ui_contextual_end(); ui_contextual_end(0);
} }
if( clicked_or_toggled & 1 ) { if( clicked_or_toggled & 1 ) {

View File

@ -13,7 +13,7 @@
- [ ] Editor: GUI pass: timeline and data tracks, node graphs. <!-- worthy: will be reused into materials, animgraphs and blueprints --> - [ ] Editor: GUI pass: timeline and data tracks, node graphs. <!-- worthy: will be reused into materials, animgraphs and blueprints -->
*/ */
#include "v4k.c" #include "fwk.c"
#include "editor2.h" // old editor interface #include "editor2.h" // old editor interface
#define ui_push_hspace(px) \ #define ui_push_hspace(px) \
@ -28,8 +28,6 @@
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
#include "labs.meta/meta_reflect.c"
int *meta_changed(void *value) { int *meta_changed(void *value) {
static map(void*,int) changes = 0; static map(void*,int) changes = 0;
do_once map_init_ptr(changes); do_once map_init_ptr(changes);
@ -37,20 +35,20 @@ int *meta_changed(void *value) {
return map_find_or_add(changes, value, 0); return map_find_or_add(changes, value, 0);
} }
void reflect_ui( const reflect *r, void *value, void *userdata ) { void reflect_ui( const char *type, const char *name, const char *info, void *value ) {
ui_label_icon_highlight = *meta_changed(value); // @hack: remove ui_label_icon_highlight hack ui_label_icon_highlight = *meta_changed(value); // @hack: remove ui_label_icon_highlight hack
char *title = va(ICON_MD_UNDO "%s", r->info); char *title = va(ICON_MD_UNDO "%s", info);
int changed = 0; int changed = 0;
/**/ if( !strcmp(r->type, "int") ) changed = ui_int(title, (int*)value); /**/ if( !strcmp(type, "int") ) changed = ui_int(title, (int*)value);
else if( !strcmp(r->type, "char") && r->is_ptr ) changed = ui_buffer(title, (char*)value, strlen((char*)value)+1); else if( !strcmp(type, "char*") ) changed = ui_buffer(title, (char*)value, strlen((char*)value)+1);
else if( !strcmp(r->type, "string") ) changed = ui_string(title, (char**)value); else if( !strcmp(type, "string") ) changed = ui_string(title, (char**)value);
else if( !strcmp(r->type, "float") ) changed = ui_float(title, (float*)value); else if( !strcmp(type, "float") ) changed = ui_float(title, (float*)value);
else if( !strcmp(r->type, "double") ) changed = ui_double(title, (double*)value); else if( !strcmp(type, "double") ) changed = ui_double(title, (double*)value);
else if( !strcmp(r->type, "unsigned") ) changed = ui_unsigned(title, (unsigned*)value); else if( !strcmp(type, "unsigned") ) changed = ui_unsigned(title, (unsigned*)value);
else if( !strcmp(r->type, "color") ) changed = ui_color4(va("%s #%02X%02X%02X%02X", title, (int)(0[(float*)value]),(int)(1[(float*)value]),(int)(2[(float*)value]),(int)(3[(float*)value])), (float*)value); else if( !strcmp(type, "color") ) changed = ui_color4(va("%s #%02X%02X%02X%02X", title, (int)(0[(float*)value]),(int)(1[(float*)value]),(int)(2[(float*)value]),(int)(3[(float*)value])), (float*)value);
// else if( !strcmp(type, "vec3") ) ; // not supported. decays to 3 floats // else if( !strcmp(type, "vec3") ) ; // not supported. decays to 3 floats
else ui_label2(title, va("(%s)%s", r->type, r->name)); else ui_label2(title, va("(%s)%s", type, name));
if( changed ) { if( changed ) {
*meta_changed(value) = 1; *meta_changed(value) = 1;
@ -62,7 +60,7 @@ void reflect_ui( const reflect *r, void *value, void *userdata ) {
} }
bool reflect_parse(void *obj, const char *type, const char *val) { bool reflect_parse(void *obj, const char *type, const char *val) {
/**/ if( !strcmp(type, "int") ) *((int*)obj) = eval(val); /**/ if( !strcmp(type, "int") ) *((int*)obj) = eval(val);
// else if( !strcmp(r->type, "char") && r->is_ptr ) ; // @fixme: not supported, unless we do strncpy() or similar. // else if( !strcmp(type, "char*") ) ; // @fixme: not supported, unless we do strncpy() or similar.
else if( !strcmp(type, "string") ) *((char**)obj) = stringf("%s", val); else if( !strcmp(type, "string") ) *((char**)obj) = stringf("%s", val);
else if( !strcmp(type, "float") ) *((float*)obj) = eval(val); // = v[0] == '~' ? (float)~atoi(val+1) : atof(val); // = atof(val); else if( !strcmp(type, "float") ) *((float*)obj) = eval(val); // = v[0] == '~' ? (float)~atoi(val+1) : atof(val); // = atof(val);
else if( !strcmp(type, "double") ) *((double*)obj) = eval(val); // = v[0] == '~' ? (float)~atoi(val+1) : atof(val); // = atof(val); else if( !strcmp(type, "double") ) *((double*)obj) = eval(val); // = v[0] == '~' ? (float)~atoi(val+1) : atof(val); // = atof(val);
@ -73,42 +71,6 @@ bool reflect_parse(void *obj, const char *type, const char *val) {
return 1; return 1;
} }
// ----------------------------------------------------------------------------------------
typedef void(*obj_ctor)(void*);
static map(char*, obj_ctor) obj_ctors;
#define STRUCT_CTOR(type, ctor) STRUCT_CTOR(#type, (obj_ctor)ctor)
void (STRUCT_CTOR)( const char *type, obj_ctor ctor ) {
do_once map_init_str(obj_ctors);
map_find_or_add(obj_ctors, STRDUP(type), ctor);
}
bool obj_make(void *obj, const char *ini_data) { // initialize object from ini datas
char *hint = 0;
for( ini_t read = ini_from_mem(ini_data); !!read; map_free(read), read = 0) {
for each_map(read, char*, k, char*, v) {
array(char*) tokens = strsplit(k, ".");
if( array_count(tokens) != 2 ) continue;
const char *type = 0;
void *found = reflect_field( tokens[0], obj, tokens[1], &type );
if( !found ) continue;
if( reflect_parse(found, type, v) ) {
hint = tokens[0];
}
}
// constructor (post-init call)
obj_ctor *ctor = map_find(obj_ctors, hint);
if( ctor ) (*ctor)( obj );
}
return hint != 0;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#define POD_TYPES \ #define POD_TYPES \
@ -223,9 +185,9 @@ void node_edit(node *n, node *root) {
if( ui_collapse(va("%s %s (%u)", n->down ? ICON_MD_SOURCE : ICON_MD_FOLDER, node_name(n), node_children(n)), va("%p%p",root,n->v.ptr)) ) { // @fixme v.ptr if( ui_collapse(va("%s %s (%u)", n->down ? ICON_MD_SOURCE : ICON_MD_FOLDER, node_name(n), node_children(n)), va("%p%p",root,n->v.ptr)) ) { // @fixme v.ptr
if( n->down ) node_edit(n->down,root); if( n->down ) node_edit(n->down,root);
if( reflect_has_fields( node_type(n), n->v.ptr ) ) { if( 1 ) { // reflect_has_fields( node_type(n), n->v.ptr ) ) {
for ui_push_hspace( 4 ) { for ui_push_hspace( 4 ) {
#define ICON_DOT ICON_CANCEL // ICON_MD_WIFI_1_BAR // ICON_MD_RADIO_BUTTON_UNCHECKED // ICON_MD_LENS_BLUR #define ICON_DOT " · " // ICON_CANCEL // ICON_MD_WIFI_1_BAR // ICON_MD_RADIO_BUTTON_UNCHECKED // ICON_MD_LENS_BLUR
static int flags[4] = {0}; static int flags[4] = {0};
char *toolbar = va("%s%s%s%s", char *toolbar = va("%s%s%s%s",
flags[3] ? ICON_MD_STAR : ICON_MD_STAR_OUTLINE, // ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER, // flags[3] == 0 ? ICON_MD_STAR_OUTLINE : flags[3] == 1 ? ICON_MD_STAR_HALF : ICON_MD_STAR, flags[3] ? ICON_MD_STAR : ICON_MD_STAR_OUTLINE, // ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER, // flags[3] == 0 ? ICON_MD_STAR_OUTLINE : flags[3] == 1 ? ICON_MD_STAR_HALF : ICON_MD_STAR,
@ -239,7 +201,10 @@ void node_edit(node *n, node *root) {
int choice = ui_label2_toolbar(section, toolbar); int choice = ui_label2_toolbar(section, toolbar);
if( choice ) flags[ choice - 1 ] = (flags[ choice - 1 ] + 1 ) % ( choice == 4 ? 2/*3*/ : 2); if( choice ) flags[ choice - 1 ] = (flags[ choice - 1 ] + 1 ) % ( choice == 4 ? 2/*3*/ : 2);
reflect_iterate_fields( node_type(n), n->v.ptr, reflect_ui, NULL ); // @fixme v.ptr
for each_member( node_type(n), R ) {
reflect_ui(R->type, R->name, R->info, n->v.ptr); // @fixme v.ptr
}
} }
} }
@ -269,7 +234,7 @@ void editor_reset() {
} }
void editor_frame() { void editor_frame() {
editor_init(); // old editor interface editor_init(); // old editor interface
editor_tick(); // old editor interface editor_tick_(); // old editor interface
editor_menubar(); // old editor interface editor_menubar(); // old editor interface
if( input_down(KEY_F5) ) { if( input_down(KEY_F5) ) {
@ -422,42 +387,42 @@ int main() {
STRUCT( my_sprite, vec3, position, "Position" ); STRUCT( my_sprite, vec3, position, "Position" );
STRUCT( my_sprite, float, tilt, "Tilt degrees" ); STRUCT( my_sprite, float, tilt, "Tilt degrees" );
STRUCT( my_sprite, color, tint, "Tint color" ); STRUCT( my_sprite, color, tint, "Tint color" );
STRUCT_CTOR( my_sprite, my_sprite_ctor );
PRINTF("pod:%d, var:%d, node:%d warn\n", (int)sizeof(pod), (int)sizeof(var), (int)sizeof(node)); PRINTF("pod:%d, var:%d, node:%d warn\n", (int)sizeof(pod), (int)sizeof(var), (int)sizeof(node));
PRINTF("reflected:%d bytes vs real:%d bytes warn\n", reflect_sizeof("my_sprite"), (int)sizeof(my_sprite)); // PRINTF("reflected:%d bytes vs real:%d bytes warn\n", reflect_sizeof("my_sprite"), (int)sizeof(my_sprite));
// cook_config("../../tools/cook.ini"); // cook_config("../../tools/cook.ini");
window_create(0.80, 0); window_create(0.80, 0);
struct my_sprite spr1 = {0}, spr2 = {0}, spr3 = {0}; struct my_sprite
obj_make(&spr1, spr1 = {
"[my_sprite]\n" .filename="cat.png",
"filename=cat.png\n" .position = vec3(5, 2, 100),
"position=5 2 100\n" .tilt=45 + 45 -90,
"tilt=45 + 45 -90\n" .tint=vec4(255, 255, 0, 255)
"tint=255 255 0\n" },
); spr2 = {
obj_make(&spr2, .filename="cat.png",
"[my_sprite]\n" .position = vec3(1, 2, 100),
"filename=cat.png\n" .tilt=45 + 45 -90,
"position=1 2 100\n" .tint=vec4(255, 0, 0, 255)
"tilt=45 + 45 -90\n" },
"tint=255 0 0\n" spr3 = {
); .filename="cat.png",
obj_make(&spr3, .position = vec3(1, 2, 100),
"[my_sprite]\n" .tilt=45,
"filename=cat.png\n" .tint=vec4(0, 0, 255, 255)
"position=1 2 100\n" };
"tilt=45\n"
"tint=0 0 255\n" my_sprite_ctor(&spr1);
); my_sprite_ctor(&spr2);
my_sprite_ctor(&spr3);
int hero1 = editor_spawn("/hero1", "my_sprite", &spr1); int hero1 = editor_spawn("/hero1", "my_sprite", &spr1);
int hero2 = editor_spawn("/hero2", "my_sprite", &spr2); int hero2 = editor_spawn("/hero2", "my_sprite", &spr2);
int hero3 = editor_spawn("/hero1/heroB", "my_sprite", &spr3); int hero3 = editor_spawn("/hero1/heroB", "my_sprite", &spr3);
camera_t cam = camera(); camera_t cam = camera();
camera_enable(&cam);
while( window_swap() ) { while( window_swap() ) {
editor_frame(); editor_frame();

View File

@ -102,12 +102,12 @@ void editor_init() {
map_init_ptr(editor_dicts); map_init_ptr(editor_dicts);
set_init_ptr(editor_world); set_init_ptr(editor_world);
set_init_ptr(editor_selection); set_init_ptr(editor_selection);
profile_enable( false ); profiler_enable( false );
window_pause( true ); window_pause( true );
} }
} }
void editor_tick() { void editor_tick_() {
// timing // timing
editor_dt = window_delta() * !window_has_pause(); if(editor_dt > 1/60.f) editor_dt = 1/60.f; editor_dt = window_delta() * !window_has_pause(); if(editor_dt > 1/60.f) editor_dt = 1/60.f;
} }
@ -155,10 +155,10 @@ enum editor_keys {
void editor_menubar() { void editor_menubar() {
do_once editor_init(); do_once editor_init();
int alts = input(KEY_LALT) || input(KEY_RALT); // @todo: move to v4k.c int alts = input(KEY_LALT) || input(KEY_RALT); // @todo: move to fwk.c
int ctrls = input(KEY_LCTRL) || input(KEY_RCTRL); // @todo: move to v4k.c int ctrls = input(KEY_LCTRL) || input(KEY_RCTRL); // @todo: move to fwk.c
int shifts = input(KEY_LSHIFT) || input(KEY_RSHIFT); // @todo: move to v4k.c int shifts = input(KEY_LSHIFT) || input(KEY_RSHIFT); // @todo: move to fwk.c
int mods = alts || ctrls || shifts; // @todo: move to v4k.c int mods = alts || ctrls || shifts; // @todo: move to fwk.c
if( input_down(KEY_F5) ) editor_key = key_reload; if( input_down(KEY_F5) ) editor_key = key_reload;
if( input_down(KEY_F11) ) editor_key = key_fullscreen; if( input_down(KEY_F11) ) editor_key = key_fullscreen;
if( input_down(KEY_PAUSE) ) editor_key = key_pause; if( input_down(KEY_PAUSE) ) editor_key = key_pause;
@ -332,7 +332,7 @@ void editor_menubar() {
break; case key_outliner: ui_show("Outliner", ui_visible("Outliner") ^ true); break; case key_outliner: ui_show("Outliner", ui_visible("Outliner") ^ true);
break; case key_recording: name = file_counter(va("%s.mp4",app_name())), window_record(name), ui_notify(va("Video capturing: %s", name), date_string()); break; case key_recording: name = file_counter(va("%s.mp4",app_name())), window_record(name), ui_notify(va("Video capturing: %s", name), date_string());
break; case key_screenshot: name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); break; case key_screenshot: name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
break; case key_profiler: ui_show("Profiler", profile_enable(ui_visible("Profiler") ^ true)); break; case key_profiler: ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
break; case key_fullscreen: record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand break; case key_fullscreen: record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
break; case key_gamepad: editor_gamepad ^= 1; break; case key_gamepad: editor_gamepad ^= 1;
break; case key_lit: editor_lit ^= 1; break; case key_lit: editor_lit ^= 1;

View File

@ -1,6 +1,6 @@
//#define META_DEMO //#define META_DEMO
#include "v4k.h" #include "fwk.h"
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>

View File

@ -1,5 +1,5 @@
#define V4K_C #define FWK_C
#include "v4k.h" #include "fwk.h"
bool parse_struct(const char *line) { bool parse_struct(const char *line) {
return strstr(line, "s""truct "); return strstr(line, "s""truct ");

View File

@ -21,9 +21,9 @@ cl ..\editor2.c -I ..\..\tools -DCOOK_ON_DEMAND
pushd ..\.. && call make amalgamation && popd pushd ..\.. && call make amalgamation && popd
taskkill /im "oscedit.exe" > nul 2> nul taskkill /im "oscedit.exe" > nul 2> nul
call ..\..\tools\tcc oscgame.c -I ..\.. -DV4K_IMPLEMENTATION -DCOOK_ON_DEMAND %* call ..\..\tools\tcc oscgame.c -I ..\.. -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
call ..\..\tools\tcc oscsend.c -I ..\.. -DV4K_IMPLEMENTATION -DCOOK_ON_DEMAND %* call ..\..\tools\tcc oscsend.c -I ..\.. -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
call ..\..\tools\tcc oscedit.c -I ..\.. -DV4K_IMPLEMENTATION -DCOOK_ON_DEMAND %* && start oscedit.exe call ..\..\tools\tcc oscedit.c -I ..\.. -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %* && start oscedit.exe
timeout 3 timeout 3

View File

@ -1,4 +1,4 @@
#include "v4k.h" #include "fwk.h"
#include "oscedit.h" #include "oscedit.h"
// demo // demo

View File

@ -1,4 +1,4 @@
#include "v4k.h" #include "fwk.h"
#include "oscedit.h" #include "oscedit.h"
// game // game

View File

@ -1,4 +1,4 @@
#include "v4k.h" #include "fwk.h"
#define OSCPACK_C #define OSCPACK_C
#define OSCRECV_C #define OSCRECV_C

View File

@ -1,7 +1,7 @@
// networked gui demo // networked gui demo
// - rlyeh, public domain // - rlyeh, public domain
#include "v4k.h" #include "fwk.h"
#define OSCPACK_C #define OSCPACK_C
#define OSCRECV_C #define OSCRECV_C
@ -46,7 +46,6 @@ int main() {
// camera // camera
camera_t cam = camera(); camera_t cam = camera();
cam.speed = 0.2f;
// demo loop // demo loop
while (window_swap()) while (window_swap())
@ -61,7 +60,7 @@ int main() {
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f); if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed); vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z); camera_moveby(&cam, wasdecq);
camera_fps(&cam, mouse.x,mouse.y); camera_fps(&cam, mouse.x,mouse.y);
// queue model scale bounces // queue model scale bounces

View File

@ -1,4 +1,4 @@
#include "v4k.h" #include "fwk.h"
#include "oscsend.h" #include "oscsend.h"
#include "oscedit.h" #include "oscedit.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {

View File

@ -0,0 +1,86 @@
given a string A, we want it to be B.
A: hello world and thanks for the fish.
B: hello cruel o_o world and thanks for the fish!
however, the instructions to reconstruct B must be as small as possible, to minimize transmission costs. this is why we dont send B entirely.
different algorithms as follow:
## ALGORITHM 1
- identify the first mismatching character (S).
v-- 6(S)
A: hello world and thanks for the fish.
B: hello cruel o_o world and thanks for the fish!
- identify the last mismatch character (E).
v-- 0(E)
A: hello world and thanks for the fish.
B: hello cruel o_o world and thanks for the fish!
- we construct the patch now with 3 numbers:
- number of bytes to copy from beginning(A) till S(A)
- number of bytes to copy from S(B) till E(B). plus the substring that is get copied.
- number of bytes to copy from E(A) till end of string.
6 40 "cruel o_o world and thanks for the fish!" 0
- total patch size is 3 control bytes + 40 (string) = 43 bytes
## ALGORITHM 2
- We delta every character in both strings, from beginning to end, and from end to beginning.
A: hello world and thanks for the fish.0000000000
B: hello cruel o_o world and thanks for the fish!
C: 000000XXXXX0XXX0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (-)
A: 0000000000hello world and thanks for the fish.
B: hello cruel o_o world and thanks for the fish!
C: XXXXXXXXXXXXXX0000000000000000000000000000000X (-)
- Pick the option with most zeros (2nd). Aka, select the option with less Xs.
do { Encode every XXXX island in C as a positive operation indicating how many bytes to copy from.
Run-length the number of zeros into a negative operation.
} repeat till lane is exhausted.
XXXXXXXXXXXXXXX: +14 "hello cruel o_"
0000000000000000000000000000000: -29
X: +1 "!"
- Patch size is 3 control bytes + 14 (string) + 1 (string) = 18 bytes
## ALGORITHM 3
- start source (A) and target (B) strings. start with A:
- select how many bytes to copy (positive), how many to skip (negative), or switch A<-->B lanes (zero).
- repeat previous step over and over until both lanes do reach their respective string ends.
A: hello world and thanks for the fish.
B: hello cruel o_o world and thanks for the fish!
A: +6 0 >> hello
B: -6 +10 0 >> hello cruel o_o
A: +24 -1 0 >> hello cruel o_o world and thanks for the fish
B: -29 +1 >> hello cruel o_o world and thanks for the fish!
(10 bytes)
what if we always specify a dual +/- operation per lane?
lanes changed automatically after every tuple. in this case a 0 shall indicate a no op.
A: +6 0 >> hello
B: -6 +10 >> hello cruel o_o
A: +24 -1 >> hello cruel o_o world and thanks for the fish
B: -29 +1 >> hello cruel o_o world and thanks for the fish!
(8 bytes)
- we construct the patch now. a substring excerpt must come after any positive operations on lane B.
+6 0 -6 +10 "cruel o_o " +24 -1 -29 +1 "!"
- total patch size is 8 control bytes + 10 (string) + 1 (string) = 19 bytes

View File

@ -0,0 +1,193 @@
// object: method dispatch tables
#define ctor(obj) obj_method0(obj, ctor) // ctor[obj_typeid(obj)](obj)
#define dtor(obj) obj_method0(obj, dtor) // dtor[obj_typeid(obj)](obj)
API extern void (*ctor[256])(); ///-
API extern void (*dtor[256])(); ///-
const char *obj_typeof( const void *obj ) {
int obj_typeeq(a,b)
// ---
// ---
void *obj_copy(void **dst, const void *src) {
if(!*dst) return *dst = obj_clone(src);
if( obj_typeeq(*dst, src) ) {
return memcpy(*dst, src, obj_sizeof(src));
}
return NULL;
}
void *obj_mutate(void **dst_, const void *src) {
// mutate a class. ie, convert a given object class into a different one,
// while preserving the original metas and references as much as possible.
//
// @fixme: systems might be tracking objects in the future. the fact that we
// can reallocate a pointer (and hence, change its address) seems way too dangerous,
// as the tracking systems could crash when referencing a mutated object.
// solutions: do not reallocate if sizeof(new_class) > sizeof(old_class) maybe? good enough?
// also, optimization hint: no need to reallocate if both sizes matches, just copy contents.
if(!*dst_) return *dst_ = obj_clone(src);
void *dst = *dst_;
dtor(dst);
unsigned src_sz = obj_sizeof(src);
unsigned src_id = obj_typeid(src);
void *dst_ptr = *((void**)dst - 1);
unsigned payload = (OBJPAYLOAD16(dst_ptr) & 255) | src_id << 8;
FREE( OBJUNBOX(dst_ptr) );
*((void**)dst - 1) = OBJBOX( STRDUP( OBJUNBOX(*((void**)src - 1)) ), payload);
void *base = (void*)((void**)dst - 1);
base = REALLOC(base, src_sz + sizeof(void*));
*dst_ = (char*)base + sizeof(void*);
dst = (char*)base + sizeof(void*);
memcpy(dst, src, src_sz);
ctor(dst);
return dst;
}
#ifdef OBJ_DEMO
typedef struct MyObject {
char* id;
int x,y;
float rotation;
struct MyObject *next;
} MyObject;
void tests1() {
// Construct two objects
MyObject *root = obj_new(MyObject, 0);
MyObject *obj = obj_new(MyObject, "An identifier!", 0x11, 0x22, 3.1415f, root );
// Dump contents of our objects
obj_hexdump(root);
obj_hexdump(obj);
// Save to mem
char* buffer = obj_save(obj);
printf("%d bytes\n", (int)strlen(buffer));
// Clear
obj_zero( obj );
obj_hexdump( obj );
// Reload
obj_load( obj, buffer );
obj_hexdump( obj );
// Copy tests
{
MyObject *clone = obj_clone(obj);
obj_hexdump(clone);
obj_del(clone);
}
{
MyObject *copy = 0;
obj_copy(&copy, obj);
obj_hexdump(copy);
obj_del(copy);
}
{
MyObject *copy = obj_new(MyObject, "A different identifier!", 0x33, 0x44, 0.0f, root );
obj_copy(&copy, obj);
obj_hexdump(copy);
obj_del(copy);
}
{
void *copy = obj_malloc(100, "an untyped class" );
obj_mutate(&copy, obj);
obj_hexdump(copy);
obj_copy(&copy, obj);
obj_hexdump(copy);
obj_del(copy);
}
// Benchmarking call overhead.
// We're here using dtor as a method to test. Since there is actually no
// destructor associated to this class, it will be safe to call it extensively (no double frees).
//
// results:
// 427 million calls/s @ old i5-4300/1.90Ghz laptop. compiled with "cl /Ox /Os /MT /DNDEBUG /GL /GF /arch:AVX2"
#ifndef N
#define N (INT32_MAX-1)
#endif
double t = (puts("benchmarking..."), -clock() / (double)CLOCKS_PER_SEC);
for( int i = 0; i < N; ++i ) {
dtor(root);
}
t += clock() / (double)CLOCKS_PER_SEC;
printf("Benchmark: %5.2f objcalls/s %5.2fM objcalls/s\n", N/(t), (N/1000)/(t*1000)); // ((N+N)*5) / (t) );
}
void tests2() {
REGISTER_BOX
REGISTER_RECT
box *b = obj_new(box, 100);
rect *r = obj_new(rect, 100, 200);
dump(b);
dump(r);
printf("%f\n", area(b));
printf("%f\n", area(r));
obj_del(b);
obj_ref(r); obj_unref(r); //obj_del(r);
int *untyped = obj_malloc( sizeof(int) );
int *my_number = obj_malloc( sizeof(int), "a comment about my_number" );
char *my_text = obj_malloc( 32, "some debug info here" );
*untyped = 100;
*my_number = 123;
sprintf( my_text, "hello world" );
struct my_bitmap { int w, h, bpp; const char *pixels; };
struct my_bitmap *my_bitmap = obj_new(struct my_bitmap, 2,2,8, "\1\2\3\4");
printf( "%p(%s,%u)\n", my_bitmap, obj_typeof(my_bitmap), obj_typeid(my_bitmap) );
printf( "%d(%s,%d)\n", *untyped, obj_typeof(untyped), obj_typeid(untyped) );
printf( "%d(%s,%d)\n", *my_number, obj_typeof(my_number), obj_typeid(my_number) );
printf( "%s(%s,%d)\n", my_text, obj_typeof(my_text), obj_typeid(my_text) );
obj_printf(my_text, "hello world #1\n");
obj_printf(my_text, "hello world #2\n");
puts(obj_output(my_text));
printf( "%s(%s,%d)\n", my_text, obj_typeof(my_text), obj_typeid(my_text) );
printf( "equal?:%d\n", obj_typeeq(my_number, untyped) );
printf( "equal?:%d\n", obj_typeeq(my_number, my_number) );
printf( "equal?:%d\n", obj_typeeq(my_number, my_text) );
printf( "equal?:%d\n", obj_typeeq(my_number, my_bitmap) );
obj_free( untyped );
obj_free( my_text );
obj_free( my_bitmap );
obj_del( my_number ); // should not crash, even if allocated with obj_malloc()
}

View File

@ -0,0 +1,18 @@
[myWindow]
x=0.166667
y=0.194444
w=0.666667
h=0.666667
visible=1
[Outliner]
x=-0.000000
y=0.107495
w=0.249929
h=0.333728
visible=1
[Properties]
x=0.749973
y=0.052117
w=0.250028
h=0.333860
visible=1