diff --git a/engine/editor.c b/engine/editor.c index c74a773..80a21ae 100644 --- a/engine/editor.c +++ b/engine/editor.c @@ -93,6 +93,122 @@ TODO("bug: missing code completions popup") // https://github.com/rxi/lite/commit/236a585756cb9fa70130eee6c9a604780aced424 > suru.png // https://github.com/rxi/lite/commit/f90b00748e1fe1cd2340aaa06d2526a1b2ea54ec +#if 0 // good UI/UX blender ideas +ui density is perfect: font face, font size and icon sizes are perfect even in a low res 1366x768 scenario +viewport: not cluttered at all. vertical floating toolbar on the left, floating icons on the right +left icons are tools related to current edition mode, right icons are camera only. +left icons can be long pressed for a hovered submenu, right icons can be clicked or dragged. +non-matching text filtering works by disabling widgets, not by hiding them +window contents can be promoted to any display any other window content by clicking their [icon V] +there are no windows or minimize/maximize buttons +windows are grouped with a vertical toolbar inside the right bar docked section +you can only display 1 window at time. +panels can be dragged within a window and make much more sense than our approach +scene tree: can make collections/groups +widget tree drawing is much simpler than us, just a vertical parent line per collection and indented arrows per child +context menus are always like: optional icon (white), text (white), either optional input binding (gray) or submenu arrow +input boxes are super reactive +< > are hidden unless hovered +< > can be clicked to de/increment (release) +< > can be horizontally dragged to de/increment larger quantities (hold) +< > can be vertically dragged to include other Y,Z properties in the selection (hold) +0.53m can be clicked (release) or dragged (<-> hovered icon) (hold). +0.53m whole text is automatically selected when clicked. +you can enter units when entering values 350m, 350km, 12mi +you can enter math values: 30+20+sin(1) +numeric: units always specified: 0 m, 90o, 1.25x +numeric: epsilons (non-zero) displayed as -0.00000 even if digits cannot fit widget rect + +operation context is split into different sections in menu bar: modeling, sculpting, uv editing, shading, anim, etc +cam 3d orientation gizmo top right: can be dragged (orbit cam) or clicked (reposition) +rotation gizmo: anchor can be positioned within world +gizmo: will display always initial position while dragging, and tape distance so far +right floating icons can be dragged: cam orientation, cam panning, cam zooming, cam iso/dimetric +ctrl-z undo, ctrl-shift-z redo +#endif + +static const char* codepoint_to_utf8_(unsigned c) { //< @r-lyeh + static char s[4+1]; + memset(s, 0, 5); + /**/ if (c < 0x80) s[0] = c, s[1] = 0; + else if (c < 0x800) s[0] = 0xC0 | ((c >> 6) & 0x1F), s[1] = 0x80 | ( c & 0x3F), s[2] = 0; + else if (c < 0x10000) s[0] = 0xE0 | ((c >> 12) & 0x0F), s[1] = 0x80 | ((c >> 6) & 0x3F), s[2] = 0x80 | ( c & 0x3F), s[3] = 0; + else if (c < 0x110000) s[0] = 0xF0 | ((c >> 18) & 0x07), s[1] = 0x80 | ((c >> 12) & 0x3F), s[2] = 0x80 | ((c >> 6) & 0x3F), s[3] = 0x80 | (c & 0x3F), s[4] = 0; + return s; +} +bool is_hovering(vec4 rect, vec2 mouse) { // rect(x,y,x2,y2) + if( mouse.x < rect.x ) return 0; + if( mouse.x > rect.z ) return 0; + if( mouse.y < rect.y ) return 0; + if( mouse.y > rect.w ) return 0; + return 1; +} +vec4 editor_toolbar_drag; // xy mouse, z time +vec4 editor_toolbar_rect; +int editor_toolbar_hovered() { + return is_hovering(editor_toolbar_rect, vec2(input(MOUSE_X),input(MOUSE_Y))); +} +vec2 editor_toolbar_dragged() { + return vec2( editor_toolbar_drag.x, editor_toolbar_drag.y ); +} +int editor_toolbar(int x, int y, int incw, int inch, const char *sym) { + array(uint32_t) codepoints = string32(sym); + if( incw < 0 ) return editor_toolbar(x + incw * (array_count(codepoints)-1), y, -incw, inch, sym); + if( inch < 0 ) return editor_toolbar(x, y + inch * (array_count(codepoints)-1), incw, -inch, sym); + + int mx = input(MOUSE_X); + int my = input(MOUSE_Y); + int inc = maxi(incw, inch); + + static int ox = 0, oy = 0, dragging = 0; // drag origin + + editor_toolbar_rect = vec4(x,y,x + (incw ? incw * array_count(codepoints) : inch), y + (inch ? inch * array_count(codepoints) : incw) ); + int oo = is_hovering(editor_toolbar_rect, vec2(ox,oy)); + + int ix = x, iy = y; + for each_array(codepoints, uint32_t, g) { + int selected = oo ? is_hovering(vec4(ix,iy,ix+inc,iy+inc),vec2(ox,oy)) : 0; + int hovering = dragging ? 0 : is_hovering(vec4(ix,iy,ix+inc,iy+inc), vec2(mx,my)); + const char *str8 = va("%s%s", selected || hovering ? FONT_COLOR1 : FONT_COLOR2, codepoint_to_utf8_(g)); + editor_symbol(ix + inc/8, iy + inc/3 + 2, str8); + ix += incw; + iy += inch; + } +// debug: +// ddraw_push_2d(); +// ddraw_aabb(vec3(editor_toolbar_rect.x,editor_toolbar_rect.y,0),vec3(editor_toolbar_rect.z,editor_toolbar_rect.w,0)); +// ddraw_pop_2d(); + if( 1 ) // is_hovering(editor_toolbar_rect, vec2(mx,my)) ) + { + if( input_down(MOUSE_L) && editor_toolbar_hovered() ) { + window_cursor_shape(0); + editor_toolbar_drag = vec4(0,0, mx,my); + ox = mx, oy = my, dragging = 1; + int mcx = ((ox - x) / inc) + 1, mcy = ((oy - y) / inc) + 1; // mouse cells + return incw ? -mcx : -mcy; + } + if( input(MOUSE_L) && dragging ) { + int mcx = ((ox - x) / inc) + 1, mcy = ((oy - y) / inc) + 1; // mouse cells + editor_toolbar_drag.x = mx - editor_toolbar_drag.z; + editor_toolbar_drag.y = my - editor_toolbar_drag.w; + API void editor_cursorpos(int x, int y); + editor_cursorpos(ox, oy); + editor_toolbar_drag.z = ox; + editor_toolbar_drag.w = oy; + return incw ? -mcx : -mcy; + } + if( input_up(MOUSE_L) && dragging ) { + int mcx = ((ox - x) / inc) + 1, mcy = ((oy - y) / inc) + 1; // mouse cells + window_cursor_shape(CURSOR_SW_AUTO); + ox = oy = 0, dragging = 0; + return incw ? mcx : mcy; + } + } + editor_toolbar_drag = vec4(0,0,0,0); + return 0; +} + + // ---------------------------------------------------------------------------- // demo @@ -327,13 +443,14 @@ void game(unsigned frame, float dt, double t) { window_cursor( !active ); 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); - 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 * active); camera_moveby(&cam, wasdecq); camera_fps(&cam, mouse.x,mouse.y); // draw world ddraw_ontop_push(0); - ddraw_grid(0); + ddraw_grid(0); // 1+10+100 + ddraw_grid(1000); ddraw_ontop_pop(); ddraw_flush(); @@ -344,6 +461,8 @@ void game(unsigned frame, float dt, double t) { } int main(){ + argvadd("--cook-on-demand"); + // borderless, see: // https://github.com/glfw/glfw/pull/1420 // https://github.com/glfw/glfw/pull/987 @@ -351,14 +470,27 @@ int main(){ // https://github.com/glfw/glfw/pull/990 window_title("Editor " EDITOR_VERSION); - if( flag("--transparent") ) - window_create(101, 0); - else - window_create(80, flag("--windowed") ? 0 : WINDOW_BORDERLESS); + window_create( flag("--transparent") ? 101 : 80, flag("--windowed") ? 0 : WINDOW_BORDERLESS); window_icon("scale-ruler-icon.png"); while( window_swap() ) { editor_frame(game); editor_gizmos(2); + + int choice1 = editor_toolbar(window_width()-32, ui_has_menubar() ? 34 : 0, 0, 32, ICON_MD_VISIBILITY ICON_MD_360 ICON_MD_ZOOM_OUT_MAP ICON_MD_GRID_ON ); // ICON_MDI_ORBIT ICON_MDI_LOUPE ICON_MDI_GRID ); + //int choice2 = editor_toolbar(window_width()-32*2, ui_has_menubar() ? 34 : 0, -32, 0, ICON_MD_360 ICON_MD_ZOOM_OUT_MAP ICON_MD_GRID_ON ); // ICON_MDI_ORBIT ICON_MDI_LOUPE ICON_MDI_GRID ); + + if( choice1 > 0 ) { // clicked[>0] + camera_t *cam = camera_get_active(); + if( choice1 == 4 ) cam->orthographic ^= 1, camera_fps(cam, 0, 0); + } + if( choice1 < 0 ) { // dragged[<0] + vec2 mouse_sensitivity = vec2(0.1, -0.1); // sensitivity + polarity + vec2 drag = mul2( editor_toolbar_dragged(), mouse_sensitivity ); + camera_t *cam = camera_get_active(); + if( choice1 == -1 ) camera_fps(cam, drag.x, drag.y ); + if( choice1 == -2 ) camera_orbit(cam, drag.x, drag.y, 0); //len3(cam->position) ); + if( choice1 == -3 ) camera_fov(cam, cam->fov += drag.y - drag.x); + } } } diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index f8c1a71..7a68c7e 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -14331,12 +14331,6 @@ extern "C" { static void fn(void) #endif -#if 0 // autorun demo -void byebye(void) { puts("seen after main()"); } -AUTORUN { puts("seen before main()"); } -AUTORUN { puts("seen before main() too"); atexit( byebye ); } -#endif - // ----------------------------------------------------------------------------- // build info @@ -15334,32 +15328,32 @@ void* obj_free(void *o); #define obj_vtable(method,RC,...) RC macro(obj_##method)(){ __VA_ARGS__ }; RC (*obj_##method[256])() = { REPEAT256(macro(obj_##method)) }; #define obj_vtable_null(method,RC) RC (*obj_##method[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed -#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f -#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) -#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) +#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f ///- +#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) ///- +#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) ///- #undef EXTEND #define EXTEND(...) EXPAND(EXTEND, __VA_ARGS__) -#define EXTEND2(o,F1) obj_extend(o,F1) -#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) -#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) -#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) -#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) -#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) -#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) -#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) -#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) +#define EXTEND2(o,F1) obj_extend(o,F1) ///- +#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) ///- +#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) ///- +#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) ///- +#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) ///- +#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) ///- +#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) ///- +#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) ///- +#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) ///- #define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__) -#define EXTEND_T2(o,F1) obj_extend_t(o,F1) -#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) -#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) -#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) -#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) -#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) -#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) -#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) -#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) +#define EXTEND_T2(o,F1) obj_extend_t(o,F1) ///- +#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) ///- +#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) ///- +#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) ///- +#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) ///- +#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) ///- +#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) ///- +#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) ///- +#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) ///- // --- declare vtables @@ -17694,6 +17688,12 @@ API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int s API void ddraw_demo(); API void ddraw_flush(); API void ddraw_flush_projview(mat44 proj, mat44 view); + +// transform gizmos + +API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); +API bool gizmo_active(); +API bool gizmo_hover(); #line 0 #line 1 "v4k_scene.h" @@ -17713,6 +17713,11 @@ typedef struct camera_t { float look_friction, look_damping; vec2 last_look; vec3 last_move; // used for friction and damping bool damping; + + bool orthographic; // 0 perspective, 1 orthographic; when ortho: dimetric[if pitch == -30o], isometric[if pitch == 35.264o] + float distance; // distance to pivot, when orbiting + // vec2 polarity = { +1,-1 }; // @todo + // vec2 sensitivity = { 2,2 }; // @todo } camera_t; API camera_t camera(); @@ -18118,6 +18123,7 @@ API void thread_destroy( void *thd ); API int argc(); API char* argv(int); +API void argvadd(const char *arg); API int flag(const char *commalist); // --arg // app_flag? API const char* option(const char *commalist, const char *defaults); // --arg=string or --arg string @@ -18600,6 +18606,7 @@ API void window_setclipboard(const char *text); #define EDITOR_VERSION "2023.10" // ---------------------------------------------------------------------------- +// editor bindings typedef struct editor_bind_t { const char *command; @@ -18613,6 +18620,7 @@ API void editor_addbind(editor_bind_t bind); void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); } // ---------------------------------------------------------------------------- +// editor properties #define EDITOR_PROPERTYDEF(T,property_name) \ typedef map(void*,T) editor_##property_name##_map_t; \ @@ -18622,25 +18630,26 @@ API void editor_set##property_name(const void *obj, T value); \ API void editor_alt##property_name(const void *obj); \ API void editor_no##property_name(void *obj); -EDITOR_PROPERTYDEF(int, open); // whether object is tree opened in tree editor -EDITOR_PROPERTYDEF(int, selected); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, changed); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, popup); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, bookmarked); -EDITOR_PROPERTYDEF(int, visible); -EDITOR_PROPERTYDEF(int, script); -EDITOR_PROPERTYDEF(int, event); -EDITOR_PROPERTYDEF(char*,iconinstance); -EDITOR_PROPERTYDEF(char*,iconclass); -EDITOR_PROPERTYDEF(int, treeoffsety); +EDITOR_PROPERTYDEF(int, open); ///- whether object is tree opened in tree editor +EDITOR_PROPERTYDEF(int, selected); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, changed); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, popup); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, bookmarked); ///- +EDITOR_PROPERTYDEF(int, visible); ///- +EDITOR_PROPERTYDEF(int, script); ///- +EDITOR_PROPERTYDEF(int, event); ///- +EDITOR_PROPERTYDEF(char*,iconinstance); ///- +EDITOR_PROPERTYDEF(char*,iconclass); ///- +EDITOR_PROPERTYDEF(int, treeoffsety); ///- API void editor_destroy_properties(void *o); API void editor_load_on_boot(void); API void editor_save_on_quit(void); // ---------------------------------------------------------------------------- +// editor ui -enum { +enum EDITOR_MODE { EDITOR_PANEL, EDITOR_WINDOW, EDITOR_WINDOW_NK, @@ -18650,6 +18659,9 @@ enum { API int editor_begin(const char *title, int mode); API int editor_end(int mode); +// ---------------------------------------------------------------------------------------- +// editor selection + API int editor_filter(); API void editor_select(const char *mask); API void editor_unselect(); // same than editor_select("!**"); @@ -18660,6 +18672,7 @@ API void* editor_first_selected(); API void* editor_last_selected(); // ---------------------------------------------------------------------------------------- +// editor instancing API void editor_addtoworld(obj *o); API void editor_watch(const void *o); @@ -18670,44 +18683,34 @@ API void editor_destroy_selected(); API void editor_inspect(obj *o); // ---------------------------------------------------------------------------------------- -// tty - -API int editor_send(const char *cmd); // return job-id -API const char* editor_recv(int jobid, double timeout_ss); -API void editor_pump(); - -// ---------------------------------------------------------------------------------------- - -API void editor_symbol(int x, int y, const char *sym); -API void editor_frame( void (*game)(unsigned, float, double) ); -API void editor_gizmos(int dim); - -// ---------------------------------------------------------------------------------------- - -API int editor_send(const char *command); +// editor utils //API void editor(); //API bool editor_active(); API vec3 editor_pick(float mouse_x, float mouse_y); API char* editor_path(const char *path); +API void editor_symbol(int x, int y, const char *sym); +API void editor_gizmos(int dim); + +// ---------------------------------------------------------------------------------------- +// editor loop + +API int editor_send(const char *cmd); // returns job-id +API const char* editor_recv(int jobid, double timeout_ss); + +API void editor_pump(); +API void editor_frame( void (*game)(unsigned, float, double) ); + +// ---------------------------------------------------------------------------------------- +// engine section: @todo: expand me + API float* engine_getf(const char *key); API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); -API int ui_debug(); - -// open file dialog - -API char* dialog_load(); -API char* dialog_save(); - -// transform gizmos - -API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); -API bool gizmo_active(); -API bool gizmo_hover(); +API int ui_engine(); #line 0 // ---- @@ -18722,13 +18725,13 @@ API bool gizmo_hover(); #include #include #include - #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) + #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) ///- #else #if is(win32) /*&& is(tcc)*/ // && ENABLE_DLL #ifdef GLAD_API_CALL #undef GLAD_API_CALL #endif - #define GLAD_API_CALL extern API + #define GLAD_API_CALL extern API ///- #endif #ifndef GLAD_GL_H_ #include "v4k" @@ -346213,8 +346216,12 @@ static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int act event->type = GLEQ_KEY_REPEATED; } +static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0; static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint) { + if( gleq_char_callback_prev ) + gleq_char_callback_prev(window, codepoint); + GLEQevent* event = gleq_new_event(); event->type = GLEQ_CODEPOINT_INPUT; event->window = window; @@ -346303,6 +346310,7 @@ GLEQDEF void gleqTrackWindow(GLFWwindow* window) glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback); glfwSetScrollCallback(window, gleq_scroll_callback); glfwSetKeyCallback(window, gleq_key_callback); + gleq_char_callback_prev = //< @r-lyeh glfwSetCharCallback(window, gleq_char_callback); #if GLFW_VERSION_MINOR >= 1 glfwSetDropCallback(window, gleq_file_drop_callback); @@ -349124,6 +349132,10 @@ static int ui_using_v2_menubar = 0; #define UI_FONT_TERMINAL_SIZE UI_FONT_ENUM(14,14) #endif + #define UI_FONT_REGULAR_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_HEADING_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_TERMINAL_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #if UI_ICONS_SMALL #define UI_ICON_FONTSIZE UI_FONT_ENUM(16.5f,16.5f) #define UI_ICON_SPACING_X UI_FONT_ENUM(-2,-2) @@ -349162,8 +349174,12 @@ static void nk_config_custom_fonts() { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) { float font_size = UI_FONT_REGULAR_SIZE; struct nk_font_config cfg = nk_font_config(font_size); - cfg.oversample_v = 2; - cfg.pixel_snap = 0; + cfg.oversample_h = UI_FONT_REGULAR_SAMPLING.x; + cfg.oversample_v = UI_FONT_REGULAR_SAMPLING.y; + cfg.pixel_snap = UI_FONT_REGULAR_SAMPLING.z; + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font; @@ -349171,10 +349187,10 @@ static void nk_config_custom_fonts() { // ...with icons embedded on it. static struct icon_font { - const char *file; int yspacing; nk_rune range[3]; + const char *file; int yspacing; vec3 sampling; nk_rune range[3]; } icons[] = { - {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" - {"materialdesignicons-webfont.ttf", 2, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, + {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {1,1,1}, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" + {"materialdesignicons-webfont.ttf", 2, {1,1,1}, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, }; for( int f = 0; f < countof(icons); ++f ) for( char *data = vfs_load(icons[f].file, &datalen); data; data = 0 ) { @@ -349187,9 +349203,13 @@ static void nk_config_custom_fonts() { // cfg.font->ascent += ICON_ASCENT; // cfg.font->height += ICON_HEIGHT; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = icons[f].sampling.x; + cfg.oversample_v = icons[f].sampling.y; + cfg.pixel_snap = icons[f].sampling.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg); } @@ -349197,15 +349217,19 @@ static void nk_config_custom_fonts() { // Monospaced font. Used in terminals or consoles. for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) { - const float font_size = UI_FONT_REGULAR_SIZE; + const float font_size = UI_FONT_TERMINAL_SIZE; static const nk_rune icon_range[] = {32, 127, 0}; struct nk_font_config cfg = nk_font_config(font_size); cfg.range = icon_range; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = UI_FONT_TERMINAL_SAMPLING.x; + cfg.oversample_v = UI_FONT_TERMINAL_SAMPLING.y; + cfg.pixel_snap = UI_FONT_TERMINAL_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); @@ -349214,7 +349238,17 @@ static void nk_config_custom_fonts() { // Extra optional fonts from here... for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) { - struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; + struct nk_font_config cfg = nk_font_config(UI_FONT_HEADING_SIZE); + cfg.oversample_h = UI_FONT_HEADING_SAMPLING.x; + cfg.oversample_v = UI_FONT_HEADING_SAMPLING.y; + cfg.pixel_snap = UI_FONT_HEADING_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif + + struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, &cfg); + // font = bold ? bold : font; } nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); @@ -349369,7 +349403,7 @@ int ui_menu_editbox(char *buf, int bufcap) { } int ui_has_menubar() { - return ui_using_v2_menubar || !!ui_items; // array_count(ui_items) > 0; + return ui_using_v2_menubar || !!ui_items; // ? UI_MENUROW_HEIGHT + 8 : 0; // array_count(ui_items) > 0; } static @@ -354872,9 +354906,8 @@ static void *xml_path(struct xml *node, char *path, int down) { const char *(xml_string)(char *key) { struct xml *node = xml_path(*array_back(xml_docs), key, 0); - if( !node ) return ""; - if( strchr(key, '@') ) return (const char *)node; - if( strchr(key, '$') ) return (const char *)node; + if( node && strchr(key, '@') ) return (const char *)node; + if( node && strchr(key, '$') ) return (const char *)node; return ""; } unsigned (xml_count)(char *key) { @@ -355461,7 +355494,10 @@ array(char*) file_list(const char *pathmasks) { ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); - dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); + int recurse = strstr(cwd, "**") || strstr(masks, "**"); + strswap(cwd, "**", "./"); + + dir *d = dir_open(cwd, recurse ? "r" : ""); if( d ) { for( int i = 0; i < dir_count(d); ++i ) { if( dir_file(d,i) ) { @@ -355825,8 +355861,6 @@ static bool vfs_mount_hints(const char *path); void vfs_reload() { const char *app = app_name(); - dir_cache = 0; // @leak - array_resize(vfs_hints, 0); // @leak array_resize(vfs_entries, 0); // @leak @@ -358455,6 +358489,8 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // convert to vbo data int cp = ch; // f->cp2iter[ch]; //if(cp == 0xFFFD) continue; + //if(cp > f->num_glyphs) cp = 0xFFFD; + *t++ = X; *t++ = Y; *t++ = f->cp2iter[cp]; @@ -366575,6 +366611,13 @@ int fx_load(const char *filemask) { set_insert(added, name); (void)postfx_load_from_mem(&fx, file_name(name), vfs_read(name)); } + if( 1 ) + for each_array( file_list(filemask), char*, list ) { + if( set_find(added, list) ) continue; + char *name = STRDUP(list); // @leak + set_insert(added, name); + (void)postfx_load_from_mem(&fx, file_name(name), file_read(name)); + } return 1; } void fx_begin() { @@ -368738,6 +368781,117 @@ void ddraw_demo() { ddraw_color_pop(); } + +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; +} #line 0 #line 1 "v4k_scene.c" @@ -368755,6 +368909,8 @@ camera_t camera() { cam.position = vec3(10,10,10); cam.updir = vec3(0,1,0); cam.fov = 45; + cam.orthographic = false; + cam.distance = 3; // len3(cam.position); cam.damping = false; cam.move_friction = 0.09f; @@ -368846,19 +369002,18 @@ void camera_enable(camera_t *cam) { void camera_fov(camera_t *cam, float fov) { last_camera = cam; -#if 0 // isometric/dimetric - #define orthogonal(proj, fov, aspect, znear, zfar) \ - ortho44((proj), -(fov) * (aspect), (fov) * (aspect), -(fov), (fov), (znear), (zfar)) - - float DIMETRIC = 30.000f; - float ISOMETRIC = 35.264f; float aspect = window_width() / ((float)window_height()+!window_height()); - orthogonal(cam->proj, 45, aspect, -1000, 1000); // why -1000? - // cam->yaw = 45; - cam->pitch = -ISOMETRIC; -#endif + cam->fov = fov; - perspective44(cam->proj, cam->fov, window_width() / ((float)window_height()+!window_height()), 0.01f, 1000.f); + + if( cam->orthographic ) { + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png + // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric + // cam->pitch = -pitch; // quickly reorient towards origin + } else { + perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + } } void camera_fps(camera_t *cam, float yaw, float pitch) { @@ -368889,34 +369044,21 @@ void camera_fps(camera_t *cam, float yaw, float pitch) { void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { last_camera = cam; - vec2 inc_mouse = vec2(yaw, pitch); - - // @todo: worth moving all these members into camera_t ? - static vec2 _mouse = {0,0}; - static vec2 _polarity = { +1,-1 }; - static vec2 _sensitivity = { 2,2 }; - static float _friction = 0.75; //99; - static float _distance; do_once _distance = len3(cam->position); - // update dummy state camera_fps(cam, 0,0); - // add smooth input - _mouse = mix2(_mouse, add2(_mouse, mul2(mul2(inc_mouse,_sensitivity),_polarity)), _friction); - _distance = mixf(_distance, _distance+inc_distance, _friction); + // @todo: add damping + vec3 _mouse = vec3(yaw, pitch, inc_distance); + cam->yaw += _mouse.x; + cam->pitch += _mouse.y; + cam->distance += _mouse.z; - // look: update angles - vec2 offset = sub2( _mouse, ptr2(&cam->last_move.x) ); - if( 1 ) { // if _enabled - cam->yaw += offset.x; - cam->pitch += offset.y; // look: limit pitch angle [-89..89] cam->pitch = cam->pitch > 89 ? 89 : cam->pitch < -89 ? -89 : cam->pitch; - } // compute view matrix - float x = rad(cam->yaw), y = rad(cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); - lookat44(cam->view, vec3( cx*cy*_distance, sy*_distance, sx*cy*_distance ), vec3(0,0,0), vec3(0,1,0) ); + float x = rad(cam->yaw), y = rad(-cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); + lookat44(cam->view, vec3( cx*cy*cam->distance, sy*cam->distance, sx*cy*cam->distance ), vec3(0,0,0), vec3(0,1,0) ); // save for next call cam->last_move.x = _mouse.x; @@ -368925,6 +369067,7 @@ void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { int ui_camera( camera_t *cam ) { int changed = 0; + changed |= ui_bool("Orthographic", &cam->orthographic); changed |= ui_bool("Damping", &cam->damping); if( !cam->damping ) ui_disable(); changed |= ui_slider2("Move friction", &cam->move_friction, va("%5.3f", cam->move_friction)); @@ -368942,6 +369085,7 @@ int ui_camera( camera_t *cam ) { ui_enable(); ui_separator(); changed |= ui_float("FOV (degrees)", &cam->fov); + changed |= ui_float("Orbit distance", &cam->distance); ui_disable(); changed |= ui_mat44("Projection matrix", cam->proj); ui_enable(); @@ -370833,6 +370977,16 @@ __attribute__((constructor)) void init_argcv(int argc, char **argv) { __argc = a #endif #endif +void argvadd(const char *arg) { + char **argv = MALLOC( sizeof(char*) * (__argc+1) ); + for( int i = 0; i < __argc; ++i ) { + argv[i] = __argv[i]; + } + argv[__argc] = STRDUP(arg); + __argv = argv; + ++__argc; +} + const char *app_path() { // @fixme: should return absolute path always. see tcc -g -run static char buffer[1024] = {0}; if( buffer[0] ) return buffer; @@ -373268,8 +373422,7 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - API int ui_debug(); - ui_debug(); + ui_engine(); (has_menu ? ui_window_end : ui_panel_end)(); } @@ -375858,7 +376011,7 @@ int engine_tick() { return 0; } -int ui_debug() { +int ui_engine() { static int time_factor = 0; static int playing = 0; static int paused = 0; @@ -376086,118 +376239,6 @@ int ui_debug() { return 0; } - -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; -} - #line 0 #line 1 "v4k_main.c" @@ -376804,21 +376845,22 @@ void editor_pump() { // ---------------------------------------------------------------------------------------- +API void editor_cursorpos(int x, int y); +void editor_cursorpos(int x, int y) { + glfwSetCursorPos( window_handle(), x, y ); +} + void editor_symbol(int x, int y, const char *sym) { - #define FONT_SYMBOLS FONT_FACE2 - #define FONT_WHITE FONT_COLOR1 - #define FONT_YELLOW FONT_COLOR2 - #define FONT_ORANGE FONT_COLOR3 - #define FONT_CYAN FONT_COLOR4 // style: atlas size, unicode ranges and 6 font faces max - do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); + do_once font_face(FONT_FACE2, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); // style: 10 colors max - do_once font_color(FONT_WHITE, WHITE); - do_once font_color(FONT_YELLOW, YELLOW); - do_once font_color(FONT_CYAN, CYAN); - do_once font_color(FONT_ORANGE, ORANGE); + do_once font_color(FONT_COLOR1, WHITE); + do_once font_color(FONT_COLOR2, RGBX(0xE8F1FF,128)); // GRAY); + do_once font_color(FONT_COLOR3, YELLOW); + do_once font_color(FONT_COLOR4, ORANGE); + do_once font_color(FONT_COLOR5, CYAN); font_goto(x,y); - font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym)); + font_print(va(FONT_FACE2 /*FONT_WHITE*/ FONT_H1 "%s", sym)); } void editor_frame( void (*game)(unsigned, float, double) ) { @@ -376831,7 +376873,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { window_cursor_shape(CURSOR_SW_AUTO); editor.hz_high = window_fps_target(); - fx_load("editorOutline.fs"); + fx_load("**/editorOutline.fs"); fx_enable(0, 1); obj_setname(editor.root = obj_new(obj), "Signals"); @@ -376887,26 +376929,27 @@ void editor_frame( void (*game)(unsigned, float, double) ) { int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED); int ingame = !editor.active; static double clicked_titlebar = 0; - UI_MENU(14+is_borderless, \ + UI_MENU(14+2*is_borderless, \ if(ingame) ui_disable(); \ - UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ + UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_engine()) \ if(ingame) ui_enable(); \ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \ - UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \ + UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+32 + 32*2*is_borderless + 10, clicked_titlebar = time_ms()) \ if(ingame) ui_disable(); \ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \ + UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \ - UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \ - UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \ + UI_MENU_ITEM(ICON_MDI_MAGNIFY, editor_send("filter")) /*MD_SEARCH*/ \ if(ingame) ui_enable(); \ - UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \ + UI_MENU_ITEM(window_has_maximize() ? ICON_MDI_WINDOW_MINIMIZE : ICON_MDI_WINDOW_MAXIMIZE, window_maximize(1 ^ window_has_maximize())) \ + UI_MENU_ITEM(ICON_MDI_CLOSE, editor_send("quit")) \ ); if( is_borderless ) { @@ -376951,7 +376994,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { fx_end(); // draw box selection - if( !ui_active() ) { //< check that we're not moving a window + if( !ui_active() && window_has_cursor() && cursorshape ) { //< check that we're not moving a window + not in fps cam static vec2 from = {0}, to = {0}; if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to; if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)); diff --git a/engine/split/3rd_lite_sys_gleq.h b/engine/split/3rd_lite_sys_gleq.h index 105431e..88cbb9d 100644 --- a/engine/split/3rd_lite_sys_gleq.h +++ b/engine/split/3rd_lite_sys_gleq.h @@ -286,8 +286,12 @@ static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int act event->type = GLEQ_KEY_REPEATED; } +static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0; static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint) { + if( gleq_char_callback_prev ) + gleq_char_callback_prev(window, codepoint); + GLEQevent* event = gleq_new_event(); event->type = GLEQ_CODEPOINT_INPUT; event->window = window; @@ -376,6 +380,7 @@ GLEQDEF void gleqTrackWindow(GLFWwindow* window) glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback); glfwSetScrollCallback(window, gleq_scroll_callback); glfwSetKeyCallback(window, gleq_key_callback); + gleq_char_callback_prev = //< @r-lyeh glfwSetCharCallback(window, gleq_char_callback); #if GLFW_VERSION_MINOR >= 1 glfwSetDropCallback(window, gleq_file_drop_callback); diff --git a/engine/split/v4k.h.inl b/engine/split/v4k.h.inl index bd8593d..43bfeb7 100644 --- a/engine/split/v4k.h.inl +++ b/engine/split/v4k.h.inl @@ -172,13 +172,13 @@ extern "C" { #include #include #include - #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) + #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) ///- #else #if is(win32) /*&& is(tcc)*/ // && ENABLE_DLL #ifdef GLAD_API_CALL #undef GLAD_API_CALL #endif - #define GLAD_API_CALL extern API + #define GLAD_API_CALL extern API ///- #endif #ifndef GLAD_GL_H_ #include "v4k" diff --git a/engine/split/v4k_config.h b/engine/split/v4k_config.h index 5d703a4..9d42e20 100644 --- a/engine/split/v4k_config.h +++ b/engine/split/v4k_config.h @@ -300,12 +300,6 @@ static void fn(void) #endif -#if 0 // autorun demo -void byebye(void) { puts("seen after main()"); } -AUTORUN { puts("seen before main()"); } -AUTORUN { puts("seen before main() too"); atexit( byebye ); } -#endif - // ----------------------------------------------------------------------------- // build info diff --git a/engine/split/v4k_data.c b/engine/split/v4k_data.c index 70eae12..de1da1f 100644 --- a/engine/split/v4k_data.c +++ b/engine/split/v4k_data.c @@ -153,9 +153,8 @@ static void *xml_path(struct xml *node, char *path, int down) { const char *(xml_string)(char *key) { struct xml *node = xml_path(*array_back(xml_docs), key, 0); - if( !node ) return ""; - if( strchr(key, '@') ) return (const char *)node; - if( strchr(key, '$') ) return (const char *)node; + if( node && strchr(key, '@') ) return (const char *)node; + if( node && strchr(key, '$') ) return (const char *)node; return ""; } unsigned (xml_count)(char *key) { diff --git a/engine/split/v4k_editor.c b/engine/split/v4k_editor.c index 1b10364..927e134 100644 --- a/engine/split/v4k_editor.c +++ b/engine/split/v4k_editor.c @@ -507,21 +507,22 @@ void editor_pump() { // ---------------------------------------------------------------------------------------- +API void editor_cursorpos(int x, int y); +void editor_cursorpos(int x, int y) { + glfwSetCursorPos( window_handle(), x, y ); +} + void editor_symbol(int x, int y, const char *sym) { - #define FONT_SYMBOLS FONT_FACE2 - #define FONT_WHITE FONT_COLOR1 - #define FONT_YELLOW FONT_COLOR2 - #define FONT_ORANGE FONT_COLOR3 - #define FONT_CYAN FONT_COLOR4 // style: atlas size, unicode ranges and 6 font faces max - do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); + do_once font_face(FONT_FACE2, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); // style: 10 colors max - do_once font_color(FONT_WHITE, WHITE); - do_once font_color(FONT_YELLOW, YELLOW); - do_once font_color(FONT_CYAN, CYAN); - do_once font_color(FONT_ORANGE, ORANGE); + do_once font_color(FONT_COLOR1, WHITE); + do_once font_color(FONT_COLOR2, RGBX(0xE8F1FF,128)); // GRAY); + do_once font_color(FONT_COLOR3, YELLOW); + do_once font_color(FONT_COLOR4, ORANGE); + do_once font_color(FONT_COLOR5, CYAN); font_goto(x,y); - font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym)); + font_print(va(FONT_FACE2 /*FONT_WHITE*/ FONT_H1 "%s", sym)); } void editor_frame( void (*game)(unsigned, float, double) ) { @@ -534,7 +535,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { window_cursor_shape(CURSOR_SW_AUTO); editor.hz_high = window_fps_target(); - fx_load("editorOutline.fs"); + fx_load("**/editorOutline.fs"); fx_enable(0, 1); obj_setname(editor.root = obj_new(obj), "Signals"); @@ -590,26 +591,27 @@ void editor_frame( void (*game)(unsigned, float, double) ) { int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED); int ingame = !editor.active; static double clicked_titlebar = 0; - UI_MENU(14+is_borderless, \ + UI_MENU(14+2*is_borderless, \ if(ingame) ui_disable(); \ - UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ + UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_engine()) \ if(ingame) ui_enable(); \ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \ - UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \ + UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+32 + 32*2*is_borderless + 10, clicked_titlebar = time_ms()) \ if(ingame) ui_disable(); \ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \ + UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \ - UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \ - UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \ + UI_MENU_ITEM(ICON_MDI_MAGNIFY, editor_send("filter")) /*MD_SEARCH*/ \ if(ingame) ui_enable(); \ - UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \ + UI_MENU_ITEM(window_has_maximize() ? ICON_MDI_WINDOW_MINIMIZE : ICON_MDI_WINDOW_MAXIMIZE, window_maximize(1 ^ window_has_maximize())) \ + UI_MENU_ITEM(ICON_MDI_CLOSE, editor_send("quit")) \ ); if( is_borderless ) { @@ -654,7 +656,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { fx_end(); // draw box selection - if( !ui_active() ) { //< check that we're not moving a window + if( !ui_active() && window_has_cursor() && cursorshape ) { //< check that we're not moving a window + not in fps cam static vec2 from = {0}, to = {0}; if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to; if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)); diff --git a/engine/split/v4k_editor.h b/engine/split/v4k_editor.h index 3e12382..d6271e6 100644 --- a/engine/split/v4k_editor.h +++ b/engine/split/v4k_editor.h @@ -5,6 +5,7 @@ #define EDITOR_VERSION "2023.10" // ---------------------------------------------------------------------------- +// editor bindings typedef struct editor_bind_t { const char *command; @@ -18,6 +19,7 @@ API void editor_addbind(editor_bind_t bind); void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); } // ---------------------------------------------------------------------------- +// editor properties #define EDITOR_PROPERTYDEF(T,property_name) \ typedef map(void*,T) editor_##property_name##_map_t; \ @@ -27,25 +29,26 @@ API void editor_set##property_name(const void *obj, T value); \ API void editor_alt##property_name(const void *obj); \ API void editor_no##property_name(void *obj); -EDITOR_PROPERTYDEF(int, open); // whether object is tree opened in tree editor -EDITOR_PROPERTYDEF(int, selected); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, changed); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, popup); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, bookmarked); -EDITOR_PROPERTYDEF(int, visible); -EDITOR_PROPERTYDEF(int, script); -EDITOR_PROPERTYDEF(int, event); -EDITOR_PROPERTYDEF(char*,iconinstance); -EDITOR_PROPERTYDEF(char*,iconclass); -EDITOR_PROPERTYDEF(int, treeoffsety); +EDITOR_PROPERTYDEF(int, open); ///- whether object is tree opened in tree editor +EDITOR_PROPERTYDEF(int, selected); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, changed); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, popup); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, bookmarked); ///- +EDITOR_PROPERTYDEF(int, visible); ///- +EDITOR_PROPERTYDEF(int, script); ///- +EDITOR_PROPERTYDEF(int, event); ///- +EDITOR_PROPERTYDEF(char*,iconinstance); ///- +EDITOR_PROPERTYDEF(char*,iconclass); ///- +EDITOR_PROPERTYDEF(int, treeoffsety); ///- API void editor_destroy_properties(void *o); API void editor_load_on_boot(void); API void editor_save_on_quit(void); // ---------------------------------------------------------------------------- +// editor ui -enum { +enum EDITOR_MODE { EDITOR_PANEL, EDITOR_WINDOW, EDITOR_WINDOW_NK, @@ -55,6 +58,9 @@ enum { API int editor_begin(const char *title, int mode); API int editor_end(int mode); +// ---------------------------------------------------------------------------------------- +// editor selection + API int editor_filter(); API void editor_select(const char *mask); API void editor_unselect(); // same than editor_select("!**"); @@ -65,6 +71,7 @@ API void* editor_first_selected(); API void* editor_last_selected(); // ---------------------------------------------------------------------------------------- +// editor instancing API void editor_addtoworld(obj *o); API void editor_watch(const void *o); @@ -75,41 +82,31 @@ API void editor_destroy_selected(); API void editor_inspect(obj *o); // ---------------------------------------------------------------------------------------- -// tty - -API int editor_send(const char *cmd); // return job-id -API const char* editor_recv(int jobid, double timeout_ss); -API void editor_pump(); - -// ---------------------------------------------------------------------------------------- - -API void editor_symbol(int x, int y, const char *sym); -API void editor_frame( void (*game)(unsigned, float, double) ); -API void editor_gizmos(int dim); - -// ---------------------------------------------------------------------------------------- - -API int editor_send(const char *command); +// editor utils //API void editor(); //API bool editor_active(); API vec3 editor_pick(float mouse_x, float mouse_y); API char* editor_path(const char *path); +API void editor_symbol(int x, int y, const char *sym); +API void editor_gizmos(int dim); + +// ---------------------------------------------------------------------------------------- +// editor loop + +API int editor_send(const char *cmd); // returns job-id +API const char* editor_recv(int jobid, double timeout_ss); + +API void editor_pump(); +API void editor_frame( void (*game)(unsigned, float, double) ); + +// ---------------------------------------------------------------------------------------- +// engine section: @todo: expand me + API float* engine_getf(const char *key); API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); -API int ui_debug(); - -// open file dialog - -API char* dialog_load(); -API char* dialog_save(); - -// transform gizmos - -API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); -API bool gizmo_active(); -API bool gizmo_hover(); +API int ui_engine(); diff --git a/engine/split/v4k_editor0.c b/engine/split/v4k_editor0.c index 08289a3..a93723b 100644 --- a/engine/split/v4k_editor0.c +++ b/engine/split/v4k_editor0.c @@ -190,7 +190,7 @@ int engine_tick() { return 0; } -int ui_debug() { +int ui_engine() { static int time_factor = 0; static int playing = 0; static int paused = 0; @@ -418,115 +418,3 @@ int ui_debug() { return 0; } - -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; -} - diff --git a/engine/split/v4k_file.c b/engine/split/v4k_file.c index 68d4730..7f427ef 100644 --- a/engine/split/v4k_file.c +++ b/engine/split/v4k_file.c @@ -221,7 +221,10 @@ array(char*) file_list(const char *pathmasks) { ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); - dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); + int recurse = strstr(cwd, "**") || strstr(masks, "**"); + strswap(cwd, "**", "./"); + + dir *d = dir_open(cwd, recurse ? "r" : ""); if( d ) { for( int i = 0; i < dir_count(d); ++i ) { if( dir_file(d,i) ) { @@ -585,8 +588,6 @@ static bool vfs_mount_hints(const char *path); void vfs_reload() { const char *app = app_name(); - dir_cache = 0; // @leak - array_resize(vfs_hints, 0); // @leak array_resize(vfs_entries, 0); // @leak diff --git a/engine/split/v4k_font.c b/engine/split/v4k_font.c index 858915c..de1e183 100644 --- a/engine/split/v4k_font.c +++ b/engine/split/v4k_font.c @@ -2060,6 +2060,8 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // convert to vbo data int cp = ch; // f->cp2iter[ch]; //if(cp == 0xFFFD) continue; + //if(cp > f->num_glyphs) cp = 0xFFFD; + *t++ = X; *t++ = Y; *t++ = f->cp2iter[cp]; diff --git a/engine/split/v4k_obj.h b/engine/split/v4k_obj.h index 3384876..d8efb20 100644 --- a/engine/split/v4k_obj.h +++ b/engine/split/v4k_obj.h @@ -168,32 +168,32 @@ void* obj_free(void *o); #define obj_vtable(method,RC,...) RC macro(obj_##method)(){ __VA_ARGS__ }; RC (*obj_##method[256])() = { REPEAT256(macro(obj_##method)) }; #define obj_vtable_null(method,RC) RC (*obj_##method[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed -#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f -#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) -#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) +#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f ///- +#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) ///- +#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) ///- #undef EXTEND #define EXTEND(...) EXPAND(EXTEND, __VA_ARGS__) -#define EXTEND2(o,F1) obj_extend(o,F1) -#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) -#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) -#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) -#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) -#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) -#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) -#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) -#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) +#define EXTEND2(o,F1) obj_extend(o,F1) ///- +#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) ///- +#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) ///- +#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) ///- +#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) ///- +#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) ///- +#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) ///- +#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) ///- +#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) ///- #define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__) -#define EXTEND_T2(o,F1) obj_extend_t(o,F1) -#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) -#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) -#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) -#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) -#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) -#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) -#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) -#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) +#define EXTEND_T2(o,F1) obj_extend_t(o,F1) ///- +#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) ///- +#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) ///- +#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) ///- +#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) ///- +#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) ///- +#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) ///- +#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) ///- +#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) ///- // --- declare vtables diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 80d2db6..414d192 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -2390,6 +2390,13 @@ int fx_load(const char *filemask) { set_insert(added, name); (void)postfx_load_from_mem(&fx, file_name(name), vfs_read(name)); } + if( 1 ) + for each_array( file_list(filemask), char*, list ) { + if( set_find(added, list) ) continue; + char *name = STRDUP(list); // @leak + set_insert(added, name); + (void)postfx_load_from_mem(&fx, file_name(name), file_read(name)); + } return 1; } void fx_begin() { diff --git a/engine/split/v4k_renderdd.c b/engine/split/v4k_renderdd.c index 10474c1..179c734 100644 --- a/engine/split/v4k_renderdd.c +++ b/engine/split/v4k_renderdd.c @@ -843,3 +843,114 @@ void ddraw_demo() { ddraw_color_pop(); } + +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; +} diff --git a/engine/split/v4k_renderdd.h b/engine/split/v4k_renderdd.h index 278d95f..7f088a4 100644 --- a/engine/split/v4k_renderdd.h +++ b/engine/split/v4k_renderdd.h @@ -62,3 +62,9 @@ API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int s API void ddraw_demo(); API void ddraw_flush(); API void ddraw_flush_projview(mat44 proj, mat44 view); + +// transform gizmos + +API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); +API bool gizmo_active(); +API bool gizmo_hover(); diff --git a/engine/split/v4k_scene.c b/engine/split/v4k_scene.c index b1dfba6..526ad99 100644 --- a/engine/split/v4k_scene.c +++ b/engine/split/v4k_scene.c @@ -12,6 +12,8 @@ camera_t camera() { cam.position = vec3(10,10,10); cam.updir = vec3(0,1,0); cam.fov = 45; + cam.orthographic = false; + cam.distance = 3; // len3(cam.position); cam.damping = false; cam.move_friction = 0.09f; @@ -103,19 +105,18 @@ void camera_enable(camera_t *cam) { void camera_fov(camera_t *cam, float fov) { last_camera = cam; -#if 0 // isometric/dimetric - #define orthogonal(proj, fov, aspect, znear, zfar) \ - ortho44((proj), -(fov) * (aspect), (fov) * (aspect), -(fov), (fov), (znear), (zfar)) - - float DIMETRIC = 30.000f; - float ISOMETRIC = 35.264f; float aspect = window_width() / ((float)window_height()+!window_height()); - orthogonal(cam->proj, 45, aspect, -1000, 1000); // why -1000? - // cam->yaw = 45; - cam->pitch = -ISOMETRIC; -#endif + cam->fov = fov; - perspective44(cam->proj, cam->fov, window_width() / ((float)window_height()+!window_height()), 0.01f, 1000.f); + + if( cam->orthographic ) { + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png + // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric + // cam->pitch = -pitch; // quickly reorient towards origin + } else { + perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + } } void camera_fps(camera_t *cam, float yaw, float pitch) { @@ -146,34 +147,21 @@ void camera_fps(camera_t *cam, float yaw, float pitch) { void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { last_camera = cam; - vec2 inc_mouse = vec2(yaw, pitch); - - // @todo: worth moving all these members into camera_t ? - static vec2 _mouse = {0,0}; - static vec2 _polarity = { +1,-1 }; - static vec2 _sensitivity = { 2,2 }; - static float _friction = 0.75; //99; - static float _distance; do_once _distance = len3(cam->position); - // update dummy state camera_fps(cam, 0,0); - // add smooth input - _mouse = mix2(_mouse, add2(_mouse, mul2(mul2(inc_mouse,_sensitivity),_polarity)), _friction); - _distance = mixf(_distance, _distance+inc_distance, _friction); + // @todo: add damping + vec3 _mouse = vec3(yaw, pitch, inc_distance); + cam->yaw += _mouse.x; + cam->pitch += _mouse.y; + cam->distance += _mouse.z; - // look: update angles - vec2 offset = sub2( _mouse, ptr2(&cam->last_move.x) ); - if( 1 ) { // if _enabled - cam->yaw += offset.x; - cam->pitch += offset.y; // look: limit pitch angle [-89..89] cam->pitch = cam->pitch > 89 ? 89 : cam->pitch < -89 ? -89 : cam->pitch; - } // compute view matrix - float x = rad(cam->yaw), y = rad(cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); - lookat44(cam->view, vec3( cx*cy*_distance, sy*_distance, sx*cy*_distance ), vec3(0,0,0), vec3(0,1,0) ); + float x = rad(cam->yaw), y = rad(-cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); + lookat44(cam->view, vec3( cx*cy*cam->distance, sy*cam->distance, sx*cy*cam->distance ), vec3(0,0,0), vec3(0,1,0) ); // save for next call cam->last_move.x = _mouse.x; @@ -182,6 +170,7 @@ void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { int ui_camera( camera_t *cam ) { int changed = 0; + changed |= ui_bool("Orthographic", &cam->orthographic); changed |= ui_bool("Damping", &cam->damping); if( !cam->damping ) ui_disable(); changed |= ui_slider2("Move friction", &cam->move_friction, va("%5.3f", cam->move_friction)); @@ -199,6 +188,7 @@ int ui_camera( camera_t *cam ) { ui_enable(); ui_separator(); changed |= ui_float("FOV (degrees)", &cam->fov); + changed |= ui_float("Orbit distance", &cam->distance); ui_disable(); changed |= ui_mat44("Projection matrix", cam->proj); ui_enable(); diff --git a/engine/split/v4k_scene.h b/engine/split/v4k_scene.h index 1952a8a..f17e8d9 100644 --- a/engine/split/v4k_scene.h +++ b/engine/split/v4k_scene.h @@ -14,6 +14,11 @@ typedef struct camera_t { float look_friction, look_damping; vec2 last_look; vec3 last_move; // used for friction and damping bool damping; + + bool orthographic; // 0 perspective, 1 orthographic; when ortho: dimetric[if pitch == -30o], isometric[if pitch == 35.264o] + float distance; // distance to pivot, when orbiting + // vec2 polarity = { +1,-1 }; // @todo + // vec2 sensitivity = { 2,2 }; // @todo } camera_t; API camera_t camera(); diff --git a/engine/split/v4k_system.c b/engine/split/v4k_system.c index bb4f446..80c8208 100644 --- a/engine/split/v4k_system.c +++ b/engine/split/v4k_system.c @@ -5,6 +5,16 @@ __attribute__((constructor)) void init_argcv(int argc, char **argv) { __argc = a #endif #endif +void argvadd(const char *arg) { + char **argv = MALLOC( sizeof(char*) * (__argc+1) ); + for( int i = 0; i < __argc; ++i ) { + argv[i] = __argv[i]; + } + argv[__argc] = STRDUP(arg); + __argv = argv; + ++__argc; +} + const char *app_path() { // @fixme: should return absolute path always. see tcc -g -run static char buffer[1024] = {0}; if( buffer[0] ) return buffer; diff --git a/engine/split/v4k_system.h b/engine/split/v4k_system.h index 697ac72..8e206b4 100644 --- a/engine/split/v4k_system.h +++ b/engine/split/v4k_system.h @@ -10,6 +10,7 @@ API void thread_destroy( void *thd ); API int argc(); API char* argv(int); +API void argvadd(const char *arg); API int flag(const char *commalist); // --arg // app_flag? API const char* option(const char *commalist, const char *defaults); // --arg=string or --arg string diff --git a/engine/split/v4k_ui.c b/engine/split/v4k_ui.c index ae60b9f..f595cf0 100644 --- a/engine/split/v4k_ui.c +++ b/engine/split/v4k_ui.c @@ -149,6 +149,10 @@ static int ui_using_v2_menubar = 0; #define UI_FONT_TERMINAL_SIZE UI_FONT_ENUM(14,14) #endif + #define UI_FONT_REGULAR_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_HEADING_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_TERMINAL_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #if UI_ICONS_SMALL #define UI_ICON_FONTSIZE UI_FONT_ENUM(16.5f,16.5f) #define UI_ICON_SPACING_X UI_FONT_ENUM(-2,-2) @@ -187,8 +191,12 @@ static void nk_config_custom_fonts() { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) { float font_size = UI_FONT_REGULAR_SIZE; struct nk_font_config cfg = nk_font_config(font_size); - cfg.oversample_v = 2; - cfg.pixel_snap = 0; + cfg.oversample_h = UI_FONT_REGULAR_SAMPLING.x; + cfg.oversample_v = UI_FONT_REGULAR_SAMPLING.y; + cfg.pixel_snap = UI_FONT_REGULAR_SAMPLING.z; + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font; @@ -196,10 +204,10 @@ static void nk_config_custom_fonts() { // ...with icons embedded on it. static struct icon_font { - const char *file; int yspacing; nk_rune range[3]; + const char *file; int yspacing; vec3 sampling; nk_rune range[3]; } icons[] = { - {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" - {"materialdesignicons-webfont.ttf", 2, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, + {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {1,1,1}, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" + {"materialdesignicons-webfont.ttf", 2, {1,1,1}, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, }; for( int f = 0; f < countof(icons); ++f ) for( char *data = vfs_load(icons[f].file, &datalen); data; data = 0 ) { @@ -212,9 +220,13 @@ static void nk_config_custom_fonts() { // cfg.font->ascent += ICON_ASCENT; // cfg.font->height += ICON_HEIGHT; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = icons[f].sampling.x; + cfg.oversample_v = icons[f].sampling.y; + cfg.pixel_snap = icons[f].sampling.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg); } @@ -222,15 +234,19 @@ static void nk_config_custom_fonts() { // Monospaced font. Used in terminals or consoles. for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) { - const float font_size = UI_FONT_REGULAR_SIZE; + const float font_size = UI_FONT_TERMINAL_SIZE; static const nk_rune icon_range[] = {32, 127, 0}; struct nk_font_config cfg = nk_font_config(font_size); cfg.range = icon_range; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = UI_FONT_TERMINAL_SAMPLING.x; + cfg.oversample_v = UI_FONT_TERMINAL_SAMPLING.y; + cfg.pixel_snap = UI_FONT_TERMINAL_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); @@ -239,7 +255,17 @@ static void nk_config_custom_fonts() { // Extra optional fonts from here... for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) { - struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; + struct nk_font_config cfg = nk_font_config(UI_FONT_HEADING_SIZE); + cfg.oversample_h = UI_FONT_HEADING_SAMPLING.x; + cfg.oversample_v = UI_FONT_HEADING_SAMPLING.y; + cfg.pixel_snap = UI_FONT_HEADING_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif + + struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, &cfg); + // font = bold ? bold : font; } nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); @@ -394,7 +420,7 @@ int ui_menu_editbox(char *buf, int bufcap) { } int ui_has_menubar() { - return ui_using_v2_menubar || !!ui_items; // array_count(ui_items) > 0; + return ui_using_v2_menubar || !!ui_items; // ? UI_MENUROW_HEIGHT + 8 : 0; // array_count(ui_items) > 0; } static diff --git a/engine/split/v4k_window.c b/engine/split/v4k_window.c index 1a21661..5f6331e 100644 --- a/engine/split/v4k_window.c +++ b/engine/split/v4k_window.c @@ -539,8 +539,7 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - API int ui_debug(); - ui_debug(); + ui_engine(); (has_menu ? ui_window_end : ui_panel_end)(); } diff --git a/engine/v4k b/engine/v4k index 31575c0..98bdb88 100644 --- a/engine/v4k +++ b/engine/v4k @@ -327473,8 +327473,12 @@ static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int act event->type = GLEQ_KEY_REPEATED; } +static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0; static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint) { + if( gleq_char_callback_prev ) + gleq_char_callback_prev(window, codepoint); + GLEQevent* event = gleq_new_event(); event->type = GLEQ_CODEPOINT_INPUT; event->window = window; @@ -327563,6 +327567,7 @@ GLEQDEF void gleqTrackWindow(GLFWwindow* window) glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback); glfwSetScrollCallback(window, gleq_scroll_callback); glfwSetKeyCallback(window, gleq_key_callback); + gleq_char_callback_prev = //< @r-lyeh glfwSetCharCallback(window, gleq_char_callback); #if GLFW_VERSION_MINOR >= 1 glfwSetDropCallback(window, gleq_file_drop_callback); diff --git a/engine/v4k.c b/engine/v4k.c index 2b61870..88a02ec 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -1343,6 +1343,10 @@ static int ui_using_v2_menubar = 0; #define UI_FONT_TERMINAL_SIZE UI_FONT_ENUM(14,14) #endif + #define UI_FONT_REGULAR_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_HEADING_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #define UI_FONT_TERMINAL_SAMPLING UI_FONT_ENUM(vec3(1,1,1),vec3(1,1,1)) + #if UI_ICONS_SMALL #define UI_ICON_FONTSIZE UI_FONT_ENUM(16.5f,16.5f) #define UI_ICON_SPACING_X UI_FONT_ENUM(-2,-2) @@ -1381,8 +1385,12 @@ static void nk_config_custom_fonts() { for( char *data = vfs_load(UI_FONT_REGULAR, &datalen); data; data = 0 ) { float font_size = UI_FONT_REGULAR_SIZE; struct nk_font_config cfg = nk_font_config(font_size); - cfg.oversample_v = 2; - cfg.pixel_snap = 0; + cfg.oversample_h = UI_FONT_REGULAR_SAMPLING.x; + cfg.oversample_v = UI_FONT_REGULAR_SAMPLING.y; + cfg.pixel_snap = UI_FONT_REGULAR_SAMPLING.z; + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // win32: struct nk_font *arial = nk_font_atlas_add_from_file(atlas, va("%s/fonts/arial.ttf",getenv("windir")), font_size, &cfg); font = arial ? arial : font; // struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "nuklear/extra_font/DroidSans.ttf", font_size, &cfg); font = droid ? droid : font; struct nk_font *regular = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); font = regular ? regular : font; @@ -1390,10 +1398,10 @@ static void nk_config_custom_fonts() { // ...with icons embedded on it. static struct icon_font { - const char *file; int yspacing; nk_rune range[3]; + const char *file; int yspacing; vec3 sampling; nk_rune range[3]; } icons[] = { - {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" - {"materialdesignicons-webfont.ttf", 2, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, + {"MaterialIconsSharp-Regular.otf", UI_ICON_SPACING_Y, {1,1,1}, {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" + {"materialdesignicons-webfont.ttf", 2, {1,1,1}, {0xF68C /*ICON_MIN_MDI*/, 0xF1CC7/*ICON_MAX_MDI*/, 0}}, }; for( int f = 0; f < countof(icons); ++f ) for( char *data = vfs_load(icons[f].file, &datalen); data; data = 0 ) { @@ -1406,9 +1414,13 @@ static void nk_config_custom_fonts() { // cfg.font->ascent += ICON_ASCENT; // cfg.font->height += ICON_HEIGHT; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = icons[f].sampling.x; + cfg.oversample_v = icons[f].sampling.y; + cfg.pixel_snap = icons[f].sampling.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif struct nk_font *icons = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_ICON_FONTSIZE, &cfg); } @@ -1416,15 +1428,19 @@ static void nk_config_custom_fonts() { // Monospaced font. Used in terminals or consoles. for( char *data = vfs_load(UI_FONT_TERMINAL, &datalen); data; data = 0 ) { - const float font_size = UI_FONT_REGULAR_SIZE; + const float font_size = UI_FONT_TERMINAL_SIZE; static const nk_rune icon_range[] = {32, 127, 0}; struct nk_font_config cfg = nk_font_config(font_size); cfg.range = icon_range; - cfg.oversample_h = 1; - cfg.oversample_v = 1; - cfg.pixel_snap = 1; + cfg.oversample_h = UI_FONT_TERMINAL_SAMPLING.x; + cfg.oversample_v = UI_FONT_TERMINAL_SAMPLING.y; + cfg.pixel_snap = UI_FONT_TERMINAL_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif // struct nk_font *proggy = nk_font_atlas_add_default(atlas, font_size, &cfg); struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, font_size, &cfg); @@ -1433,7 +1449,17 @@ static void nk_config_custom_fonts() { // Extra optional fonts from here... for( char *data = vfs_load(UI_FONT_HEADING, &datalen); data; data = 0 ) { - struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, 0); // font = bold ? bold : font; + struct nk_font_config cfg = nk_font_config(UI_FONT_HEADING_SIZE); + cfg.oversample_h = UI_FONT_HEADING_SAMPLING.x; + cfg.oversample_v = UI_FONT_HEADING_SAMPLING.y; + cfg.pixel_snap = UI_FONT_HEADING_SAMPLING.z; + + #if UI_LESSER_SPACING + cfg.spacing.x -= 1.0; + #endif + + struct nk_font *bold = nk_font_atlas_add_from_memory(atlas, data, datalen, UI_FONT_HEADING_SIZE, &cfg); + // font = bold ? bold : font; } nk_glfw3_font_stash_end(&nk_glfw); // nk_sdl_font_stash_end(); @@ -1588,7 +1614,7 @@ int ui_menu_editbox(char *buf, int bufcap) { } int ui_has_menubar() { - return ui_using_v2_menubar || !!ui_items; // array_count(ui_items) > 0; + return ui_using_v2_menubar || !!ui_items; // ? UI_MENUROW_HEIGHT + 8 : 0; // array_count(ui_items) > 0; } static @@ -7091,9 +7117,8 @@ static void *xml_path(struct xml *node, char *path, int down) { const char *(xml_string)(char *key) { struct xml *node = xml_path(*array_back(xml_docs), key, 0); - if( !node ) return ""; - if( strchr(key, '@') ) return (const char *)node; - if( strchr(key, '$') ) return (const char *)node; + if( node && strchr(key, '@') ) return (const char *)node; + if( node && strchr(key, '$') ) return (const char *)node; return ""; } unsigned (xml_count)(char *key) { @@ -7680,7 +7705,10 @@ array(char*) file_list(const char *pathmasks) { ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); - dir *d = dir_open(cwd, strstr(masks,"**") ? "r" : ""); + int recurse = strstr(cwd, "**") || strstr(masks, "**"); + strswap(cwd, "**", "./"); + + dir *d = dir_open(cwd, recurse ? "r" : ""); if( d ) { for( int i = 0; i < dir_count(d); ++i ) { if( dir_file(d,i) ) { @@ -8044,8 +8072,6 @@ static bool vfs_mount_hints(const char *path); void vfs_reload() { const char *app = app_name(); - dir_cache = 0; // @leak - array_resize(vfs_hints, 0); // @leak array_resize(vfs_entries, 0); // @leak @@ -10674,6 +10700,8 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // convert to vbo data int cp = ch; // f->cp2iter[ch]; //if(cp == 0xFFFD) continue; + //if(cp > f->num_glyphs) cp = 0xFFFD; + *t++ = X; *t++ = Y; *t++ = f->cp2iter[cp]; @@ -18794,6 +18822,13 @@ int fx_load(const char *filemask) { set_insert(added, name); (void)postfx_load_from_mem(&fx, file_name(name), vfs_read(name)); } + if( 1 ) + for each_array( file_list(filemask), char*, list ) { + if( set_find(added, list) ) continue; + char *name = STRDUP(list); // @leak + set_insert(added, name); + (void)postfx_load_from_mem(&fx, file_name(name), file_read(name)); + } return 1; } void fx_begin() { @@ -20957,6 +20992,117 @@ void ddraw_demo() { ddraw_color_pop(); } + +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; +} #line 0 #line 1 "v4k_scene.c" @@ -20974,6 +21120,8 @@ camera_t camera() { cam.position = vec3(10,10,10); cam.updir = vec3(0,1,0); cam.fov = 45; + cam.orthographic = false; + cam.distance = 3; // len3(cam.position); cam.damping = false; cam.move_friction = 0.09f; @@ -21065,19 +21213,18 @@ void camera_enable(camera_t *cam) { void camera_fov(camera_t *cam, float fov) { last_camera = cam; -#if 0 // isometric/dimetric - #define orthogonal(proj, fov, aspect, znear, zfar) \ - ortho44((proj), -(fov) * (aspect), (fov) * (aspect), -(fov), (fov), (znear), (zfar)) - - float DIMETRIC = 30.000f; - float ISOMETRIC = 35.264f; float aspect = window_width() / ((float)window_height()+!window_height()); - orthogonal(cam->proj, 45, aspect, -1000, 1000); // why -1000? - // cam->yaw = 45; - cam->pitch = -ISOMETRIC; -#endif + cam->fov = fov; - perspective44(cam->proj, cam->fov, window_width() / ((float)window_height()+!window_height()), 0.01f, 1000.f); + + if( cam->orthographic ) { + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png + // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric + // cam->pitch = -pitch; // quickly reorient towards origin + } else { + perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + } } void camera_fps(camera_t *cam, float yaw, float pitch) { @@ -21108,34 +21255,21 @@ void camera_fps(camera_t *cam, float yaw, float pitch) { void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { last_camera = cam; - vec2 inc_mouse = vec2(yaw, pitch); - - // @todo: worth moving all these members into camera_t ? - static vec2 _mouse = {0,0}; - static vec2 _polarity = { +1,-1 }; - static vec2 _sensitivity = { 2,2 }; - static float _friction = 0.75; //99; - static float _distance; do_once _distance = len3(cam->position); - // update dummy state camera_fps(cam, 0,0); - // add smooth input - _mouse = mix2(_mouse, add2(_mouse, mul2(mul2(inc_mouse,_sensitivity),_polarity)), _friction); - _distance = mixf(_distance, _distance+inc_distance, _friction); + // @todo: add damping + vec3 _mouse = vec3(yaw, pitch, inc_distance); + cam->yaw += _mouse.x; + cam->pitch += _mouse.y; + cam->distance += _mouse.z; - // look: update angles - vec2 offset = sub2( _mouse, ptr2(&cam->last_move.x) ); - if( 1 ) { // if _enabled - cam->yaw += offset.x; - cam->pitch += offset.y; // look: limit pitch angle [-89..89] cam->pitch = cam->pitch > 89 ? 89 : cam->pitch < -89 ? -89 : cam->pitch; - } // compute view matrix - float x = rad(cam->yaw), y = rad(cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); - lookat44(cam->view, vec3( cx*cy*_distance, sy*_distance, sx*cy*_distance ), vec3(0,0,0), vec3(0,1,0) ); + float x = rad(cam->yaw), y = rad(-cam->pitch), cx = cosf(x), cy = cosf(y), sx = sinf(x), sy = sinf(y); + lookat44(cam->view, vec3( cx*cy*cam->distance, sy*cam->distance, sx*cy*cam->distance ), vec3(0,0,0), vec3(0,1,0) ); // save for next call cam->last_move.x = _mouse.x; @@ -21144,6 +21278,7 @@ void camera_orbit( camera_t *cam, float yaw, float pitch, float inc_distance ) { int ui_camera( camera_t *cam ) { int changed = 0; + changed |= ui_bool("Orthographic", &cam->orthographic); changed |= ui_bool("Damping", &cam->damping); if( !cam->damping ) ui_disable(); changed |= ui_slider2("Move friction", &cam->move_friction, va("%5.3f", cam->move_friction)); @@ -21161,6 +21296,7 @@ int ui_camera( camera_t *cam ) { ui_enable(); ui_separator(); changed |= ui_float("FOV (degrees)", &cam->fov); + changed |= ui_float("Orbit distance", &cam->distance); ui_disable(); changed |= ui_mat44("Projection matrix", cam->proj); ui_enable(); @@ -23052,6 +23188,16 @@ __attribute__((constructor)) void init_argcv(int argc, char **argv) { __argc = a #endif #endif +void argvadd(const char *arg) { + char **argv = MALLOC( sizeof(char*) * (__argc+1) ); + for( int i = 0; i < __argc; ++i ) { + argv[i] = __argv[i]; + } + argv[__argc] = STRDUP(arg); + __argv = argv; + ++__argc; +} + const char *app_path() { // @fixme: should return absolute path always. see tcc -g -run static char buffer[1024] = {0}; if( buffer[0] ) return buffer; @@ -25487,8 +25633,7 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - API int ui_debug(); - ui_debug(); + ui_engine(); (has_menu ? ui_window_end : ui_panel_end)(); } @@ -28077,7 +28222,7 @@ int engine_tick() { return 0; } -int ui_debug() { +int ui_engine() { static int time_factor = 0; static int playing = 0; static int paused = 0; @@ -28305,118 +28450,6 @@ int ui_debug() { return 0; } - -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; -} - #line 0 #line 1 "v4k_main.c" @@ -29023,21 +29056,22 @@ void editor_pump() { // ---------------------------------------------------------------------------------------- +API void editor_cursorpos(int x, int y); +void editor_cursorpos(int x, int y) { + glfwSetCursorPos( window_handle(), x, y ); +} + void editor_symbol(int x, int y, const char *sym) { - #define FONT_SYMBOLS FONT_FACE2 - #define FONT_WHITE FONT_COLOR1 - #define FONT_YELLOW FONT_COLOR2 - #define FONT_ORANGE FONT_COLOR3 - #define FONT_CYAN FONT_COLOR4 // style: atlas size, unicode ranges and 6 font faces max - do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); + do_once font_face(FONT_FACE2, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048); // style: 10 colors max - do_once font_color(FONT_WHITE, WHITE); - do_once font_color(FONT_YELLOW, YELLOW); - do_once font_color(FONT_CYAN, CYAN); - do_once font_color(FONT_ORANGE, ORANGE); + do_once font_color(FONT_COLOR1, WHITE); + do_once font_color(FONT_COLOR2, RGBX(0xE8F1FF,128)); // GRAY); + do_once font_color(FONT_COLOR3, YELLOW); + do_once font_color(FONT_COLOR4, ORANGE); + do_once font_color(FONT_COLOR5, CYAN); font_goto(x,y); - font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym)); + font_print(va(FONT_FACE2 /*FONT_WHITE*/ FONT_H1 "%s", sym)); } void editor_frame( void (*game)(unsigned, float, double) ) { @@ -29050,7 +29084,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { window_cursor_shape(CURSOR_SW_AUTO); editor.hz_high = window_fps_target(); - fx_load("editorOutline.fs"); + fx_load("**/editorOutline.fs"); fx_enable(0, 1); obj_setname(editor.root = obj_new(obj), "Signals"); @@ -29106,26 +29140,27 @@ void editor_frame( void (*game)(unsigned, float, double) ) { int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED); int ingame = !editor.active; static double clicked_titlebar = 0; - UI_MENU(14+is_borderless, \ + UI_MENU(14+2*is_borderless, \ if(ingame) ui_disable(); \ - UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ + UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_engine()) \ if(ingame) ui_enable(); \ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \ - UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \ + UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+32 + 32*2*is_borderless + 10, clicked_titlebar = time_ms()) \ if(ingame) ui_disable(); \ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \ + UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \ - UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \ - UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \ + UI_MENU_ITEM(ICON_MDI_MAGNIFY, editor_send("filter")) /*MD_SEARCH*/ \ if(ingame) ui_enable(); \ - UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \ + UI_MENU_ITEM(window_has_maximize() ? ICON_MDI_WINDOW_MINIMIZE : ICON_MDI_WINDOW_MAXIMIZE, window_maximize(1 ^ window_has_maximize())) \ + UI_MENU_ITEM(ICON_MDI_CLOSE, editor_send("quit")) \ ); if( is_borderless ) { @@ -29170,7 +29205,7 @@ void editor_frame( void (*game)(unsigned, float, double) ) { fx_end(); // draw box selection - if( !ui_active() ) { //< check that we're not moving a window + if( !ui_active() && window_has_cursor() && cursorshape ) { //< check that we're not moving a window + not in fps cam static vec2 from = {0}, to = {0}; if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to; if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)); diff --git a/engine/v4k.h b/engine/v4k.h index a688ba1..34f089e 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -398,12 +398,6 @@ extern "C" { static void fn(void) #endif -#if 0 // autorun demo -void byebye(void) { puts("seen after main()"); } -AUTORUN { puts("seen before main()"); } -AUTORUN { puts("seen before main() too"); atexit( byebye ); } -#endif - // ----------------------------------------------------------------------------- // build info @@ -1401,32 +1395,32 @@ void* obj_free(void *o); #define obj_vtable(method,RC,...) RC macro(obj_##method)(){ __VA_ARGS__ }; RC (*obj_##method[256])() = { REPEAT256(macro(obj_##method)) }; #define obj_vtable_null(method,RC) RC (*obj_##method[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed -#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f -#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) -#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) +#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f ///- +#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) ///- +#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) ///- #undef EXTEND #define EXTEND(...) EXPAND(EXTEND, __VA_ARGS__) -#define EXTEND2(o,F1) obj_extend(o,F1) -#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) -#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) -#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) -#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) -#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) -#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) -#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) -#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) +#define EXTEND2(o,F1) obj_extend(o,F1) ///- +#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) ///- +#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) ///- +#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) ///- +#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) ///- +#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) ///- +#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) ///- +#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) ///- +#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) ///- #define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__) -#define EXTEND_T2(o,F1) obj_extend_t(o,F1) -#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) -#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) -#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) -#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) -#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) -#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) -#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) -#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) +#define EXTEND_T2(o,F1) obj_extend_t(o,F1) ///- +#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) ///- +#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) ///- +#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) ///- +#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) ///- +#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) ///- +#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) ///- +#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) ///- +#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) ///- // --- declare vtables @@ -3761,6 +3755,12 @@ API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int s API void ddraw_demo(); API void ddraw_flush(); API void ddraw_flush_projview(mat44 proj, mat44 view); + +// transform gizmos + +API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); +API bool gizmo_active(); +API bool gizmo_hover(); #line 0 #line 1 "v4k_scene.h" @@ -3780,6 +3780,11 @@ typedef struct camera_t { float look_friction, look_damping; vec2 last_look; vec3 last_move; // used for friction and damping bool damping; + + bool orthographic; // 0 perspective, 1 orthographic; when ortho: dimetric[if pitch == -30o], isometric[if pitch == 35.264o] + float distance; // distance to pivot, when orbiting + // vec2 polarity = { +1,-1 }; // @todo + // vec2 sensitivity = { 2,2 }; // @todo } camera_t; API camera_t camera(); @@ -4185,6 +4190,7 @@ API void thread_destroy( void *thd ); API int argc(); API char* argv(int); +API void argvadd(const char *arg); API int flag(const char *commalist); // --arg // app_flag? API const char* option(const char *commalist, const char *defaults); // --arg=string or --arg string @@ -4667,6 +4673,7 @@ API void window_setclipboard(const char *text); #define EDITOR_VERSION "2023.10" // ---------------------------------------------------------------------------- +// editor bindings typedef struct editor_bind_t { const char *command; @@ -4680,6 +4687,7 @@ API void editor_addbind(editor_bind_t bind); void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); } // ---------------------------------------------------------------------------- +// editor properties #define EDITOR_PROPERTYDEF(T,property_name) \ typedef map(void*,T) editor_##property_name##_map_t; \ @@ -4689,25 +4697,26 @@ API void editor_set##property_name(const void *obj, T value); \ API void editor_alt##property_name(const void *obj); \ API void editor_no##property_name(void *obj); -EDITOR_PROPERTYDEF(int, open); // whether object is tree opened in tree editor -EDITOR_PROPERTYDEF(int, selected); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, changed); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, popup); // whether object is displaying a contextual popup or not -EDITOR_PROPERTYDEF(int, bookmarked); -EDITOR_PROPERTYDEF(int, visible); -EDITOR_PROPERTYDEF(int, script); -EDITOR_PROPERTYDEF(int, event); -EDITOR_PROPERTYDEF(char*,iconinstance); -EDITOR_PROPERTYDEF(char*,iconclass); -EDITOR_PROPERTYDEF(int, treeoffsety); +EDITOR_PROPERTYDEF(int, open); ///- whether object is tree opened in tree editor +EDITOR_PROPERTYDEF(int, selected); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, changed); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, popup); ///- whether object is displaying a contextual popup or not +EDITOR_PROPERTYDEF(int, bookmarked); ///- +EDITOR_PROPERTYDEF(int, visible); ///- +EDITOR_PROPERTYDEF(int, script); ///- +EDITOR_PROPERTYDEF(int, event); ///- +EDITOR_PROPERTYDEF(char*,iconinstance); ///- +EDITOR_PROPERTYDEF(char*,iconclass); ///- +EDITOR_PROPERTYDEF(int, treeoffsety); ///- API void editor_destroy_properties(void *o); API void editor_load_on_boot(void); API void editor_save_on_quit(void); // ---------------------------------------------------------------------------- +// editor ui -enum { +enum EDITOR_MODE { EDITOR_PANEL, EDITOR_WINDOW, EDITOR_WINDOW_NK, @@ -4717,6 +4726,9 @@ enum { API int editor_begin(const char *title, int mode); API int editor_end(int mode); +// ---------------------------------------------------------------------------------------- +// editor selection + API int editor_filter(); API void editor_select(const char *mask); API void editor_unselect(); // same than editor_select("!**"); @@ -4727,6 +4739,7 @@ API void* editor_first_selected(); API void* editor_last_selected(); // ---------------------------------------------------------------------------------------- +// editor instancing API void editor_addtoworld(obj *o); API void editor_watch(const void *o); @@ -4737,44 +4750,34 @@ API void editor_destroy_selected(); API void editor_inspect(obj *o); // ---------------------------------------------------------------------------------------- -// tty - -API int editor_send(const char *cmd); // return job-id -API const char* editor_recv(int jobid, double timeout_ss); -API void editor_pump(); - -// ---------------------------------------------------------------------------------------- - -API void editor_symbol(int x, int y, const char *sym); -API void editor_frame( void (*game)(unsigned, float, double) ); -API void editor_gizmos(int dim); - -// ---------------------------------------------------------------------------------------- - -API int editor_send(const char *command); +// editor utils //API void editor(); //API bool editor_active(); API vec3 editor_pick(float mouse_x, float mouse_y); API char* editor_path(const char *path); +API void editor_symbol(int x, int y, const char *sym); +API void editor_gizmos(int dim); + +// ---------------------------------------------------------------------------------------- +// editor loop + +API int editor_send(const char *cmd); // returns job-id +API const char* editor_recv(int jobid, double timeout_ss); + +API void editor_pump(); +API void editor_frame( void (*game)(unsigned, float, double) ); + +// ---------------------------------------------------------------------------------------- +// engine section: @todo: expand me + API float* engine_getf(const char *key); API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); -API int ui_debug(); - -// open file dialog - -API char* dialog_load(); -API char* dialog_save(); - -// transform gizmos - -API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); -API bool gizmo_active(); -API bool gizmo_hover(); +API int ui_engine(); #line 0 // ---- @@ -4789,13 +4792,13 @@ API bool gizmo_hover(); #include #include #include - #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) + #define gladLoadGL(func) (glewExperimental = true, glewInit() == GLEW_OK) ///- #else #if is(win32) /*&& is(tcc)*/ // && ENABLE_DLL #ifdef GLAD_API_CALL #undef GLAD_API_CALL #endif - #define GLAD_API_CALL extern API + #define GLAD_API_CALL extern API ///- #endif #ifndef GLAD_GL_H_ #include "v4k"