2023-07-30 19:18:50 +00:00
// editing:
// nope > functions: add/rem property
2023-10-13 10:59:44 +00:00
# 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
2023-07-30 19:18:50 +00:00
char * editor_path ( const char * path ) {
return va ( " %s/%s " , EDITOR , path ) ;
}
vec3 editor_pick ( float mouse_x , float mouse_y ) {
2023-10-10 08:52:29 +00:00
#if 0
// unproject 2d coord as 3d coord
camera_t * camera = camera_get_active ( ) ;
vec3 out , xyd = vec3 ( mouse_x , window_height ( ) - mouse_y , 1 ) ; // usually x:mouse_x,y:window_height()-mouse_y,d:0=znear/1=zfar
mat44 mvp , model ; identity44 ( model ) ; multiply44x3 ( mvp , camera - > proj , camera - > view , model ) ;
bool ok = unproject44 ( & out , xyd , vec4 ( 0 , 0 , window_width ( ) , window_height ( ) ) , mvp ) ;
return out ;
# else
2023-07-30 19:18:50 +00:00
// unproject 2d coord as 3d coord
2023-10-11 19:01:06 +00:00
vec2 dpi = ifdef ( osx , window_dpi ( ) , vec2 ( 1 , 1 ) ) ;
2023-07-30 19:18:50 +00:00
camera_t * camera = camera_get_active ( ) ;
2023-10-10 19:10:22 +00:00
float x = ( 2.0f * mouse_x ) / ( dpi . x * window_width ( ) ) - 1.0f ;
float y = 1.0f - ( 2.0f * mouse_y ) / ( dpi . y * window_height ( ) ) ;
2023-10-09 21:47:23 +00:00
float z = 1.0f ;
vec3 ray_nds = vec3 ( x , y , z ) ;
vec4 ray_clip = vec4 ( ray_nds . x , ray_nds . y , - 1.0 , 1.0 ) ;
mat44 inv_proj ; invert44 ( inv_proj , camera - > proj ) ;
mat44 inv_view ; invert44 ( inv_view , camera - > view ) ;
vec4 p = transform444 ( inv_proj , ray_clip ) ;
vec4 eye = vec4 ( p . x , p . y , - 1.0 , 0.0 ) ;
vec4 wld = norm4 ( transform444 ( inv_view , eye ) ) ;
return vec3 ( wld . x , wld . y , wld . z ) ;
2023-10-10 08:52:29 +00:00
# endif
2023-07-30 19:18:50 +00:00
}
2023-10-26 07:27:46 +00:00
#if 0
2023-07-30 19:18:50 +00:00
int editor_ui_bits8 ( const char * label , uint8_t * enabled ) { // @to deprecate
int clicked = 0 ;
uint8_t copy = * enabled ;
// @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive
nk_layout_row_dynamic ( ui_ctx , 1 , 1 ) ;
struct nk_rect bounds = nk_widget_bounds ( ui_ctx ) ;
// actual widget: label + 8 checkboxes
enum { HEIGHT = 18 , BITS = 8 , SPAN = 118 } ; // bits widget below needs at least 118px wide
nk_layout_row_begin ( ui_ctx , NK_STATIC , HEIGHT , 1 + BITS ) ;
int offset = bounds . w > SPAN ? bounds . w - SPAN : 0 ;
nk_layout_row_push ( ui_ctx , offset ) ;
if ( ui_label_ ( label , NK_TEXT_LEFT ) ) clicked = 1 < < 31 ;
for ( int i = 0 ; i < BITS ; + + i ) {
nk_layout_row_push ( ui_ctx , 10 ) ;
// bit
int val = ( * enabled > > i ) & 1 ;
int chg = nk_checkbox_label ( ui_ctx , " " , & val ) ;
* enabled = ( * enabled & ~ ( 1 < < i ) ) | ( ( ! ! val ) < < i ) ;
// tooltip
struct nk_rect bb = { offset + 10 + i * 14 , bounds . y , 14 , HEIGHT } ; // 10:padding,14:width
if ( nk_input_is_mouse_hovering_rect ( & ui_ctx - > input , bb ) & & ! ui_popups ( ) ) {
const char * tips [ BITS ] = { " Init " , " Tick " , " Draw " , " Quit " , " " , " " , " " , " " } ;
if ( tips [ i ] [ 0 ] ) nk_tooltipf ( ui_ctx , " %s " , tips [ i ] ) ;
}
}
nk_layout_row_end ( ui_ctx ) ;
return clicked | ( copy ^ * enabled ) ;
}
2023-10-26 07:27:46 +00:00
# endif
2023-07-30 19:18:50 +00:00
2023-10-13 10:59:44 +00:00
2023-10-26 07:27:46 +00:00
typedef union engine_var {
2023-10-13 10:59:44 +00:00
int i ;
float f ;
char * s ;
2023-10-26 07:27:46 +00:00
} engine_var ;
static map ( char * , engine_var ) engine_vars ;
float * engine_getf ( const char * key ) {
if ( ! engine_vars ) map_init_str ( engine_vars ) ;
engine_var * found = map_find_or_add ( engine_vars , ( char * ) key , ( ( engine_var ) { 0 } ) ) ;
2023-10-13 10:59:44 +00:00
return & found - > f ;
}
2023-10-26 07:27:46 +00:00
int * engine_geti ( const char * key ) {
if ( ! engine_vars ) map_init_str ( engine_vars ) ;
engine_var * found = map_find_or_add ( engine_vars , ( char * ) key , ( ( engine_var ) { 0 } ) ) ;
2023-10-13 10:59:44 +00:00
return & found - > i ;
}
2023-10-26 07:27:46 +00:00
char * * engine_gets ( const char * key ) {
if ( ! engine_vars ) map_init_str ( engine_vars ) ;
engine_var * found = map_find_or_add ( engine_vars , ( char * ) key , ( ( engine_var ) { 0 } ) ) ;
2023-10-13 10:59:44 +00:00
if ( ! found - > s ) found - > s = stringf ( " %s " , " " ) ;
return & found - > s ;
}
2023-10-26 07:27:46 +00:00
int engine_send ( const char * cmd , const char * optional_value ) {
unsigned * gamepads = engine_geti ( " gamepads " ) ; // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
unsigned * renders = engine_geti ( " renders " ) ; // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
float * speed = engine_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 = engine_geti ( " powersave " ) ;
2023-10-13 10:59:44 +00:00
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 ) ;
2023-10-20 17:55:43 +00:00
else if ( ! strcmp ( cmd , " key_record " ) ) if ( record_active ( ) ) record_stop ( ) , ui_notify ( va ( " Video recorded " ) , date_string ( ) ) ; else
app_beep ( ) , name = file_counter ( va ( " %s.mp4 " , app_name ( ) ) ) , window_record ( name ) ;
2023-10-13 10:59:44 +00:00
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 ;
}
2023-10-26 07:27:46 +00:00
int engine_tick ( ) {
enum { engine_hz = 60 } ;
2023-10-29 11:19:16 +00:00
enum { engine_hz_mid = 18 } ;
2023-10-26 07:27:46 +00:00
enum { engine_hz_low = 5 } ;
if ( * engine_geti ( " powersave " ) ) {
2023-10-13 10:59:44 +00:00
// adaptive framerate
int app_on_background = ! window_has_focus ( ) ;
2023-10-26 07:27:46 +00:00
int hz = app_on_background ? engine_hz_low : engine_hz_mid ;
2023-10-13 10:59:44 +00:00
window_fps_lock ( hz < 5 ? 5 : hz ) ;
} else {
// window_fps_lock( editor_hz );
2023-10-28 12:16:41 +00:00
}
return 0 ;
}
int ui_debug ( ) {
static int time_factor = 0 ;
static int playing = 0 ;
static int paused = 0 ;
int advance_frame = 0 ;
#if 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 ;
int choice = ui_toolbar ( EDITOR_TOOLBAR_ICONS ) ;
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 ;
if ( do_filter ) {
char * bak = ui_filter ; ui_filter = 0 ;
ui_string ( ICON_MD_CLOSE " Filter " ICON_MD_SEARCH , & bak ) ;
ui_filter = bak ;
if ( ui_label_icon_clicked_L . x > 0 & & ui_label_icon_clicked_L . x < = 24 ) { // if clicked on CANCEL icon (1st icon)
do_filter = 0 ;
}
} else {
if ( ui_filter ) ui_filter [ 0 ] = ' \0 ' ;
}
char * filter_mask = ui_filter & & ui_filter [ 0 ] ? va ( " *%s* " , ui_filter ) : " * " ;
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
) ;
}
# endif
int open = 0 , clicked_or_toggled = 0 ;
# define EDITOR_UI_COLLAPSE(f,...) \
for ( int macro ( p ) = ( open = ui_collapse ( f , __VA_ARGS__ ) ) , macro ( dummy ) = ( clicked_or_toggled = ui_collapse_clicked ( ) ) ; macro ( p ) ; ui_collapse_end ( ) , macro ( p ) = 0 )
2023-11-01 11:24:16 +00:00
EDITOR_UI_COLLAPSE ( ICON_MD_VIEW_QUILT " Windows " , " Debug.Windows " ) {
int choice = ui_toolbar ( ICON_MD_RECYCLING " @Reset layout; " ICON_MD_SAVE_AS " @Save layout " ) ;
if ( choice = = 1 ) ui_layout_all_reset ( " * " ) ;
if ( choice = = 2 ) file_delete ( WINDOWS_INI ) , ui_layout_all_save_disk ( " * " ) ;
for each_map_ptr_sorted ( ui_windows , char * , k , unsigned , v ) {
bool visible = ui_visible ( * k ) ;
if ( ui_bool ( * k , & visible ) ) {
ui_show ( * k , ui_visible ( * k ) ^ true ) ;
}
}
}
2023-10-28 12:16:41 +00:00
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 ;
const char * file = 0 ;
if ( ui_browse ( & file , & inlined ) ) {
const char * sep = ifdef ( win32 , " \" " , " ' " ) ;
app_exec ( va ( " %s %s%s%s " , ifdef ( win32 , " start \" \" " , ifdef ( osx , " open " , " xdg-open " ) ) , sep , file , sep ) ) ;
}
}
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
}
EDITOR_UI_COLLAPSE ( ICON_MD_VOLUME_UP " Audio " , " Debug.Audio " ) {
ui_audio ( ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_VIDEOCAM " Camera " , " Debug.Camera " ) {
ui_camera ( camera_get_active ( ) ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_MONITOR " Display " , " Debug.Display " ) {
// @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 ) engine_send ( " key_fullscreen " , 0 ) ;
if ( choice = = 2 ) engine_send ( " key_screenshot " , 0 ) ;
if ( choice = = 3 ) engine_send ( " key_record " , 0 ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_KEYBOARD " Keyboard " , " Debug.Keyboard " ) {
ui_keyboard ( ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_MOUSE " Mouse " , " Debug.Mouse " ) {
ui_mouse ( ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_GAMEPAD " Gamepads " , " Debug.Gamepads " ) {
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 ) {
ui_gamepad ( q ) ;
}
}
}
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_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/%dfps " , 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 ) engine_send ( " key_battery " , " 0 " ) ;
if ( choice = = 2 ) engine_send ( " key_battery " , " 1 " ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_WATER " Reflection " , " Debug.Reflect " ) {
ui_reflect ( " * " ) ;
}
EDITOR_UI_COLLAPSE ( ICON_MD_EXTENSION " Plugins " , " Debug.Plugins " ) {
// @todo. include VCS
EDITOR_UI_COLLAPSE ( ICON_MD_BUILD " Cook " , " Debug.Cook " ) {
// @todo
}
2023-10-13 10:59:44 +00:00
}
return 0 ;
}
2023-07-30 19:18:50 +00:00
static int gizmo__mode ;
static int gizmo__active ;
static int gizmo__hover ;
bool gizmo_active ( ) {
return gizmo__active ;
}
bool gizmo_hover ( ) {
return gizmo__hover ;
}
int gizmo ( vec3 * pos , vec3 * rot , vec3 * sca ) {
#if 0
ddraw_flush ( ) ;
mat44 copy ; copy44 ( copy , camera_get_active ( ) - > view ) ;
if ( 1 ) {
float * mv = camera_get_active ( ) - > view ;
float d = sqrt ( mv [ 4 * 0 + 0 ] * mv [ 4 * 0 + 0 ] + mv [ 4 * 1 + 1 ] * mv [ 4 * 1 + 1 ] + mv [ 4 * 2 + 2 ] * mv [ 4 * 2 + 2 ] ) ;
if ( 4 ) mv [ 4 * 0 + 0 ] = d , mv [ 4 * 0 + 1 ] = 0 , mv [ 4 * 0 + 2 ] = 0 ;
if ( 2 ) mv [ 4 * 1 + 0 ] = 0 , mv [ 4 * 1 + 1 ] = d , mv [ 4 * 1 + 2 ] = 0 ;
if ( 1 ) mv [ 4 * 2 + 0 ] = 0 , mv [ 4 * 2 + 1 ] = 0 , mv [ 4 * 2 + 2 ] = d ;
}
# endif
ddraw_color_push ( dd_color ) ;
ddraw_ontop_push ( 1 ) ;
int enabled = ! ui_active ( ) & & ! ui_hover ( ) ;
vec3 mouse = enabled ? vec3 ( input ( MOUSE_X ) , input ( MOUSE_Y ) , input_down ( MOUSE_L ) ) : vec3 ( 0 , 0 , 0 ) ; // x,y,l
vec3 from = camera_get_active ( ) - > position ;
vec3 to = editor_pick ( mouse . x , mouse . y ) ;
ray r = ray ( from , to ) ;
static vec3 src3 , hit3 , off3 ; static vec2 src2 ;
# define on_gizmo_dragged(X,Y,Z,COLOR,DRAWCMD, ...) do { \
vec3 dir = vec3 ( X , Y , Z ) ; \
line axis = { add3 ( * pos , scale3 ( dir , 100 ) ) , add3 ( * pos , scale3 ( dir , - 100 ) ) } ; \
plane ground = { vec3 ( 0 , 0 , 0 ) , vec3 ( Y ? 1 : 0 , Y ? 0 : 1 , 0 ) } ; \
vec3 unit = vec3 ( X + ( 1.0 - X ) * 0.3 , Y + ( 1.0 - Y ) * 0.3 , Z + ( 1.0 - Z ) * 0.3 ) ; \
aabb arrow = { sub3 ( * pos , unit ) , add3 ( * pos , unit ) } ; \
hit * hit_arrow = ray_hit_aabb ( r , arrow ) , * hit_ground = ray_hit_plane ( r , ground ) ; \
ddraw_color ( hit_arrow | | gizmo__active = = ( X * 4 + Y * 2 + Z ) ? gizmo__hover = 1 , YELLOW : COLOR ) ; \
DRAWCMD ; \
if ( ! gizmo__active & & hit_arrow & & mouse . z ) src2 = vec2 ( mouse . x , mouse . y ) , src3 = * pos , hit3 = hit_ground - > p , off3 = mul3 ( sub3 ( src3 , hit3 ) , vec3 ( X , Y , Z ) ) , gizmo__active = X * 4 + Y * 2 + Z ; \
if ( ( gizmo__active & & gizmo__active = = ( X * 4 + Y * 2 + Z ) ) | | ( ! gizmo__active & & hit_arrow ) ) { ddraw_color ( COLOR ) ; ( 1 ? ddraw_line : ddraw_line_dashed ) ( axis . a , axis . b ) ; } \
if ( gizmo__active = = ( X * 4 + Y * 2 + Z ) & & hit_ground ) { { __VA_ARGS__ } ; modified = 1 ; gizmo__active * = ! ! input ( MOUSE_L ) ; } \
} while ( 0 )
# define gizmo_translate(X,Y,Z,COLOR) \
on_gizmo_dragged ( X , Y , Z , COLOR , ddraw_arrow ( * pos , add3 ( * pos , vec3 ( X , Y , Z ) ) ) , { \
* pos = add3 ( line_closest_point ( axis , hit_ground - > p ) , off3 ) ; \
} )
# define gizmo_scale(X,Y,Z,COLOR) \
on_gizmo_dragged ( X , Y , Z , COLOR , ( ddraw_line ( * pos , add3 ( * pos , vec3 ( X , Y , Z ) ) ) , ddraw_sphere ( add3 ( * pos , vec3 ( X - 0.1 * X , Y - 0.1 * Y , Z - 0.1 * Z ) ) , 0.1 ) ) , { /*ddraw_aabb(arrow.min,arrow.max)*/ \
int component = ( X * 1 + Y * 2 + Z * 3 ) - 1 ; \
float mag = len2 ( sub2 ( vec2 ( mouse . x , mouse . y ) , src2 ) ) ; \
float magx = ( mouse . x - src2 . x ) * ( mouse . x - src2 . x ) ; \
float magy = ( mouse . y - src2 . y ) * ( mouse . y - src2 . y ) ; \
float sgn = ( magx > magy ? mouse . x > src2 . x : mouse . y > src2 . y ) ? 1 : - 1 ; \
sca - > v3 [ component ] - = sgn * mag * 0.01 ; \
src2 = vec2 ( mouse . x , mouse . y ) ; \
} )
# define gizmo_rotate(X,Y,Z,COLOR) do { \
vec3 dir = vec3 ( X , Y , Z ) ; \
line axis = { add3 ( * pos , scale3 ( dir , 100 ) ) , add3 ( * pos , scale3 ( dir , - 100 ) ) } ; \
plane ground = { vec3 ( 0 , 0 , 0 ) , vec3 ( 0 , 1 , 0 ) } ; \
vec3 unit = vec3 ( X + ( 1.0 - X ) * 0.3 , Y + ( 1.0 - Y ) * 0.3 , Z + ( 1.0 - Z ) * 0.3 ) ; \
aabb arrow = { sub3 ( * pos , unit ) , add3 ( * pos , unit ) } ; \
hit * hit_arrow = ray_hit_aabb ( r , arrow ) , * hit_ground = ray_hit_plane ( r , ground ) ; \
int hover = ( hit_arrow ? ( X * 4 + Y * 2 + Z ) : 0 ) ; \
if ( gizmo__active = = ( X * 4 + Y * 2 + Z ) ) { ddraw_color ( gizmo__active ? gizmo__hover = 1 , YELLOW : WHITE ) ; ddraw_circle ( * pos , vec3 ( X , Y , Z ) , 1 ) ; } \
else if ( ! gizmo__active & & hover = = ( X * 4 + Y * 2 + Z ) ) { gizmo__hover = 1 ; ddraw_color ( COLOR ) ; ddraw_circle ( * pos , vec3 ( X , Y , Z ) , 1 ) ; } \
else if ( ! gizmo__active ) { ddraw_color ( WHITE ) ; ddraw_circle ( * pos , vec3 ( X , Y , Z ) , 1 ) ; } \
if ( ! gizmo__active & & hit_arrow & & mouse . z ) src2 = vec2 ( mouse . x , mouse . y ) , gizmo__active = hover ; \
if ( ( ! gizmo__active & & hover = = ( X * 4 + Y * 2 + Z ) ) | | gizmo__active = = ( X * 4 + Y * 2 + Z ) ) { gizmo__hover = 1 ; ddraw_color ( COLOR ) ; ( 1 ? ddraw_line_thin : ddraw_line_dashed ) ( axis . a , axis . b ) ; } \
if ( gizmo__active & & gizmo__active = = ( X * 4 + Y * 2 + Z ) & & hit_ground & & enabled ) { \
int component = ( Y * 1 + X * 2 + Z * 3 ) - 1 ; /*pitch,yaw,roll*/ \
float mag = len2 ( sub2 ( vec2 ( mouse . x , mouse . y ) , src2 ) ) ; \
float magx = ( mouse . x - src2 . x ) * ( mouse . x - src2 . x ) ; \
float magy = ( mouse . y - src2 . y ) * ( mouse . y - src2 . y ) ; \
float sgn = ( magx > magy ? mouse . x > src2 . x : mouse . y > src2 . y ) ? 1 : - 1 ; \
rot - > v3 [ component ] + = sgn * mag ; \
/*rot->v3[component] = clampf(rot->v3[component], -360, +360);*/ \
src2 = vec2 ( mouse . x , mouse . y ) ; \
\
} \
gizmo__active * = enabled & & ! ! input ( MOUSE_L ) ; \
} while ( 0 )
gizmo__hover = 0 ;
int modified = 0 ;
if ( enabled & & input_down ( KEY_SPACE ) ) gizmo__active = 0 , gizmo__mode = ( gizmo__mode + 1 ) % 3 ;
if ( gizmo__mode = = 0 ) gizmo_translate ( 1 , 0 , 0 , RED ) ;
if ( gizmo__mode = = 0 ) gizmo_translate ( 0 , 1 , 0 , GREEN ) ;
if ( gizmo__mode = = 0 ) gizmo_translate ( 0 , 0 , 1 , BLUE ) ;
if ( gizmo__mode = = 1 ) gizmo_scale ( 1 , 0 , 0 , RED ) ;
if ( gizmo__mode = = 1 ) gizmo_scale ( 0 , 1 , 0 , GREEN ) ;
if ( gizmo__mode = = 1 ) gizmo_scale ( 0 , 0 , 1 , BLUE ) ;
if ( gizmo__mode = = 2 ) gizmo_rotate ( 1 , 0 , 0 , RED ) ;
if ( gizmo__mode = = 2 ) gizmo_rotate ( 0 , 1 , 0 , GREEN ) ;
if ( gizmo__mode = = 2 ) gizmo_rotate ( 0 , 0 , 1 , BLUE ) ;
#if 0
ddraw_flush ( ) ;
copy44 ( camera_get_active ( ) - > view , copy ) ;
# endif
ddraw_ontop_pop ( ) ;
ddraw_color_pop ( ) ;
return modified ;
}
// -- localization kit
static const char * kit_lang = " enUS " , * kit_langs =
" enUS,enGB, "
" frFR, "
" esES,esAR,esMX, "
" deDE,deCH,deAT, "
" itIT,itCH, "
" ptBR,ptPT, "
" zhCN,zhSG,zhTW,zhHK,zhMO, "
" ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP, "
" koKR,csCZ,huHU,roRO,thTH,bgBG,heIL "
;
static map ( char * , char * ) kit_ids ;
static map ( char * , char * ) kit_vars ;
# ifndef KIT_FMT_ID2
# define KIT_FMT_ID2 "%s.%s"
# endif
void kit_init ( ) {
do_once map_init ( kit_ids , less_str , hash_str ) ;
do_once map_init ( kit_vars , less_str , hash_str ) ;
}
void kit_insert ( const char * id , const char * translation ) {
char * id2 = va ( KIT_FMT_ID2 , kit_lang , id ) ;
char * * found = map_find_or_add_allocated_key ( kit_ids , STRDUP ( id2 ) , NULL ) ;
if ( * found ) FREE ( * found ) ;
* found = STRDUP ( translation ) ;
}
bool kit_merge ( const char * filename ) {
// @todo: xlsx2ini
return false ;
}
void kit_clear ( ) {
map_clear ( kit_ids ) ;
}
bool kit_load ( const char * filename ) {
return kit_clear ( ) , kit_merge ( filename ) ;
}
void kit_set ( const char * key , const char * value ) {
value = value & & value [ 0 ] ? value : " " ;
char * * found = map_find_or_add_allocated_key ( kit_vars , STRDUP ( key ) , NULL ) ;
if ( * found ) FREE ( * found ) ;
* found = STRDUP ( value ) ;
}
void kit_reset ( ) {
map_clear ( kit_vars ) ;
}
char * kit_translate2 ( const char * id , const char * lang ) {
char * id2 = va ( KIT_FMT_ID2 , lang , id ) ;
char * * found = map_find ( kit_ids , id2 ) ;
// return original [[ID]] if no translation is found
if ( ! found ) return va ( " [[%s]] " , id ) ;
// return translation if no {{moustaches}} are found
if ( ! strstr ( * found , " {{ " ) ) return * found ;
// else replace all found {{moustaches}} with context vars
{
// make room
static __thread char * results [ 16 ] = { 0 } ;
static __thread unsigned counter = 0 ; counter = ( counter + 1 ) % 16 ;
char * buffer = results [ counter ] ;
if ( buffer ) FREE ( buffer ) , buffer = 0 ;
// iterate moustaches
const char * begin , * end , * text = * found ;
while ( NULL ! = ( begin = strstr ( text , " {{ " ) ) ) {
end = strstr ( begin + 2 , " }} " ) ;
if ( end ) {
char * var = va ( " %.*s " , ( int ) ( end - ( begin + 2 ) ) , begin + 2 ) ;
char * * found_var = map_find ( kit_vars , var ) ;
if ( found_var & & 0 [ * found_var ] ) {
strcatf ( & buffer , " %.*s%s " , ( int ) ( begin - text ) , text , * found_var ) ;
} else {
strcatf ( & buffer , " %.*s{{%s}} " , ( int ) ( begin - text ) , text , var ) ;
}
text = end + 2 ;
} else {
strcatf ( & buffer , " %.*s " , ( int ) ( begin - text ) , text ) ;
text = begin + 2 ;
}
}
strcatf ( & buffer , " %s " , text ) ;
return buffer ;
}
}
char * kit_translate ( const char * id ) {
return kit_translate2 ( id , kit_lang ) ;
}
void kit_locale ( const char * lang ) {
kit_lang = STRDUP ( lang ) ; // @leak
}
void kit_dump_state ( FILE * fp ) {
for each_map ( kit_ids , char * , k , char * , v ) {
fprintf ( fp , " [ID ] %s=%s \n " , k , v ) ;
}
for each_map ( kit_vars , char * , k , char * , v ) {
fprintf ( fp , " [VAR] %s=%s \n " , k , v ) ;
}
}
/*
int main ( ) {
kit_init ( ) ;
kit_locale ( " enUS " ) ;
kit_insert ( " HELLO_PLAYERS " , " Hi {{PLAYER1}} and {{PLAYER2}}! " ) ;
kit_insert ( " GREET_PLAYERS " , " Nice to meet you. " ) ;
kit_locale ( " esES " ) ;
kit_insert ( " HELLO_PLAYERS " , " Hola {{PLAYER1}} y {{PLAYER2}}! " ) ;
kit_insert ( " GREET_PLAYERS " , " Un placer conoceros. " ) ;
kit_locale ( " enUS " ) ;
printf ( " %s %s \n " , kit_translate ( " HELLO_PLAYERS " ) , kit_translate ( " GREET_PLAYERS " ) ) ; // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
kit_locale ( " esES " ) ;
kit_set ( " PLAYER1 " , " John " ) ;
kit_set ( " PLAYER2 " , " Karl " ) ;
printf ( " %s %s \n " , kit_translate ( " HELLO_PLAYERS " ) , kit_translate ( " GREET_PLAYERS " ) ) ; // Hola John y Karl! Un placer conoceros.
assert ( 0 = = strcmp ( kit_translate ( " NON_EXISTING " ) , " [[NON_EXISTING]] " ) ) ; // [[NON_EXISTING]]
assert ( ~ puts ( " Ok " ) ) ;
}
*/