From 31acdce47dad476bb956ea6e3bd9a8582441141b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Tue, 28 Nov 2023 14:31:56 +0100 Subject: [PATCH] implement sliders and panels --- MAKE.bat | 11 ++- bind/v4k.lua | 34 ++++++-- demos/99-gui.c | 34 +++++--- demos/art/gui/golden.ase | Bin 47515 -> 48629 bytes engine/joint/v4k.h | 172 +++++++++++++++++++++++++++++++++++---- engine/split/v4k_gui.c | 156 ++++++++++++++++++++++++++++++++--- engine/split/v4k_gui.h | 16 +++- engine/v4k.c | 156 ++++++++++++++++++++++++++++++++--- engine/v4k.h | 16 +++- tools/cook.ini | 6 +- v4k.sublime-project | 4 +- 11 files changed, 528 insertions(+), 77 deletions(-) diff --git a/MAKE.bat b/MAKE.bat index 2abae6b..6f2163f 100644 --- a/MAKE.bat +++ b/MAKE.bat @@ -149,7 +149,7 @@ if "%1"=="git" ( call make.bat bind rem call make.bat docs - call make.bat amalgamation + rem call make.bat amalgamation rem call make.bat split rem rd /q /s engine\split @@ -229,7 +229,7 @@ if "%1"=="push" ( ) if "%1"=="prep" ( - call make.bat join + call make.bat split call make.bat amalgamation exit /b ) @@ -311,7 +311,8 @@ if "%1"=="vps" ( if "%1"=="fwk" ( pushd ..\fwk-mirror - call MAKE.bat sync + git fetch + git reset --hard origin/main popd call MAKE.bat fwk_prep start "" fwk_diff.WinMerge @@ -319,6 +320,7 @@ if "%1"=="fwk" ( ) if "%1"=="fwk_prep" ( + call make.bat split if not exist "_fwk" mkdir "_fwk" if not exist "_fwk\demos" mkdir "_fwk\demos" if not exist "_fwk\tools" mkdir "_fwk\tools" @@ -419,6 +421,9 @@ if "%1"=="back" ( rem tools\fwkren.exe tools\cook.ini to + call make.bat join + call make.bat amalgamation + echo All done. endlocal exit /b diff --git a/bind/v4k.lua b/bind/v4k.lua index 6f0593e..7a92c57 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1522,15 +1522,27 @@ ffi.cdef([[ //lcpp INF [0000] vec2: macro name but used as C declaration in:vec2 sca; //lcpp INF [0000] vec4: macro name but used as C declaration in:void (*drawrect)(void* userdata, const char *skin, vec4 rect); //lcpp INF [0000] vec2: macro name but used as C declaration in:void (*getskinsize)(void* userdata, const char *skin, vec2 *size); +//lcpp INF [0000] vec4: macro name but used as C declaration in:void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); +//lcpp INF [0000] vec4: macro name but used as C declaration in:void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); +//lcpp INF [0000] vec4: macro name but used as C declaration in:bool (*ismouseinrect)(void* userdata, const char *skin, vec4 rect); //lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 gui_getskinsize(const char *skin); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 gui_getskinsize(const char *skin); //lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 gui_getskinsize(const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in:API void gui_panel(int id, vec4 rect, const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC void gui_panel(int id, vec4 rect, const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in: void gui_panel(int id, vec4 rect, const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in:API bool gui_button(int id, vec4 rect, const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC bool gui_button(int id, vec4 rect, const char *skin); -//lcpp INF [0000] vec4: macro name but used as C declaration in: bool gui_button(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:API bool gui_ismouseinrect(const char *skin, vec4 rect); +//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC bool gui_ismouseinrect(const char *skin, vec4 rect); +//lcpp INF [0000] vec4: macro name but used as C declaration in: bool gui_ismouseinrect(const char *skin, vec4 rect); +//lcpp INF [0000] vec4: macro name but used as C declaration in:API void gui_panel_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC void gui_panel_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in: void gui_panel_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:API void gui_rect_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC void gui_rect_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in: void gui_rect_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:API bool gui_button_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC bool gui_button_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in: bool gui_button_id(int id, vec4 rect, const char *skin); +//lcpp INF [0000] vec4: macro name but used as C declaration in:API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); +//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); +//lcpp INF [0000] vec4: macro name but used as C declaration in: bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); //lcpp INF [0000] test: macro name but used as C declaration in:API int (test)(const char *file, int line, const char *expr, bool result); //lcpp INF [0000] test: macro name but used as C declaration in:STATIC int (test)(const char *file, int line, const char *expr, bool result); //lcpp INF [0000] test: macro name but used as C declaration in: int (test)(const char *file, int line, const char *expr, bool result); @@ -3306,14 +3318,20 @@ enum { OBJTYPE_sprite_t = 10 }; typedef struct { unsigned static_assert_on typedef struct guiskin_t { void (*drawrect)(void* userdata, const char *skin, vec4 rect); void (*getskinsize)(void* userdata, const char *skin, vec2 *size); +void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); +bool (*ismouseinrect)(void* userdata, const char *skin, vec4 rect); void (*free)(void* userdata); void *userdata; } guiskin_t; void gui_pushskin(guiskin_t skin); void* gui_userdata(); vec2 gui_getskinsize(const char *skin); - void gui_panel(int id, vec4 rect, const char *skin); - bool gui_button(int id, vec4 rect, const char *skin); + bool gui_ismouseinrect(const char *skin, vec4 rect); + void gui_panel_id(int id, vec4 rect, const char *skin); + void gui_rect_id(int id, vec4 rect, const char *skin); + bool gui_button_id(int id, vec4 rect, const char *skin); + bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); + void gui_panel_end(); void gui_popskin(); typedef struct skinned_t { atlas_t atlas; diff --git a/demos/99-gui.c b/demos/99-gui.c index c4157a0..6017ccb 100644 --- a/demos/99-gui.c +++ b/demos/99-gui.c @@ -8,6 +8,9 @@ int main() { vec4 pos = vec4(400,400,100, 30); + float testval=7.5f; + float testval2=7.5f; + while( window_swap() && !input(KEY_ESC) ) { // game loop vec4 panel_pos = vec4(0, 0, window_width(), window_height()); @@ -32,21 +35,26 @@ int main() { } // - gui_panel(panel_pos, 0); - if (gui_button(pos, 0)) { - printf("%s\n", "Button pressed!"); - } + gui_panel(panel_pos, "panel"); + if (gui_button(pos, 0)) { + printf("%s\n", "Button pressed!"); + } - gui_panel(vec4(40,140, 320, 20*skinned->scale), "vial"); - gui_panel(vec4(40,140, 200, 14*skinned->scale), "hp"); - gui_panel(vec4(40,240, 240, 20*skinned->scale), "vial"); - gui_panel(vec4(40,240, 160, 14*skinned->scale), "mp"); + gui_rect(vec4(40,140, 320, 20*skinned->scale), "vial"); + gui_rect(vec4(40,140, 200, 14*skinned->scale), "hp"); + gui_rect(vec4(40,240, 240, 20*skinned->scale), "vial"); + gui_rect(vec4(40,240, 160, 14*skinned->scale), "mp"); - vec2 badge_size = gui_getskinsize("badge"); - badge_size.x += 2; // padding - gui_panel(vec4(60+badge_size.x*0,320, 1, 1), "badge"); - gui_panel(vec4(60+badge_size.x*1,320, 1, 1), "badge"); - gui_panel(vec4(60+badge_size.x*2,320, 1, 1), "badge_empty"); + vec2 badge_size = gui_getskinsize("badge"); + badge_size.x += 2; // padding + gui_rect(vec4(60+badge_size.x*0,320, 1, 1), "badge"); + gui_rect(vec4(60+badge_size.x*1,320, 1, 1), "badge"); + gui_rect(vec4(60+badge_size.x*2,320, 1, 1), "badge_empty"); + + vec2 slider_size = gui_getskinsize("slider"); + gui_slider(vec4(60, 480, 80*skinned->scale, 1), 0, 0.0f, 15.0f, 1.0f, &testval); + gui_slider(vec4(60, 480+slider_size.y+10, 120*skinned->scale, 1), 0, -5.0f, 20.0f, 0.0f, &testval2); + gui_panel_end(); } gui_popskin(); diff --git a/demos/art/gui/golden.ase b/demos/art/gui/golden.ase index 5af71729e8d202b09a47fcbc6b31c89bfa7abf3e..17f0297dd2aa2f54627830a86974888db4082c00 100644 GIT binary patch delta 9205 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

GZkyt?=)=IIGzq*F7v4g|q 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 X3`Q22c|VKY){nj|Q~1+=|GNJR5s*4} delta 8082 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 byd_`!bma)|`_2rf$G^KfDlu6bd1e0xsCyxR diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 54af6e3..62d6a58 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -18119,6 +18119,8 @@ API void sprite_setanim(sprite_t *s, unsigned name); typedef struct guiskin_t { void (*drawrect)(void* userdata, const char *skin, vec4 rect); void (*getskinsize)(void* userdata, const char *skin, vec2 *size); + void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); + bool (*ismouseinrect)(void* userdata, const char *skin, vec4 rect); void (*free)(void* userdata); void *userdata; } guiskin_t; @@ -18126,14 +18128,20 @@ typedef struct guiskin_t { API void gui_pushskin(guiskin_t skin); API void* gui_userdata(); API vec2 gui_getskinsize(const char *skin); +API bool gui_ismouseinrect(const char *skin, vec4 rect); // -- -API void gui_panel(int id, vec4 rect, const char *skin); -API bool gui_button(int id, vec4 rect, const char *skin); +API void gui_panel_id(int id, vec4 rect, const char *skin); +API void gui_rect_id(int id, vec4 rect, const char *skin); +API bool gui_button_id(int id, vec4 rect, const char *skin); +API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); +API void gui_panel_end(); API void gui_popskin(); // helpers -#define gui_panel(...) gui_panel(__LINE__, __VA_ARGS__) -#define gui_button(...) gui_button(__LINE__, __VA_ARGS__) +#define gui_panel(...) gui_panel_id(__LINE__, __VA_ARGS__) +#define gui_rect(...) gui_rect_id(__LINE__, __VA_ARGS__) +#define gui_button(...) gui_button_id(__LINE__, __VA_ARGS__) +#define gui_slider(...) gui_slider_id(__LINE__, __VA_ARGS__) // default renderers @@ -358926,18 +358934,17 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve // ---------------------------------------------------------------------------- // game ui -typedef struct gui_state_t { - union { - struct { - bool held; - bool hover; - }; +typedef union gui_state_t { + struct { + bool held; + bool hover; }; } gui_state_t; static __thread array(guiskin_t) skins=0; static __thread guiskin_t *last_skin=0; static __thread map(int, gui_state_t) ctl_states=0; //@leak +static __thread array(vec4) scissor_rects=0; void gui_pushskin(guiskin_t skin) { array_push(skins, skin); @@ -358961,18 +358968,46 @@ vec2 gui_getskinsize(const char *skin) { return size; } +bool gui_ismouseinrect(const char *skin, vec4 rect) { + if (last_skin->ismouseinrect) return last_skin->ismouseinrect(last_skin->userdata, skin, rect); + return false; +} + static gui_state_t *gui_getstate(int id) { if (!ctl_states) map_init(ctl_states, less_int, hash_int); return map_find_or_add(ctl_states, id, (gui_state_t){0}); } -bool (gui_button)(int id, vec4 r, const char *skin) { +void gui_panel_id(int id, vec4 rect, const char *skin) { + (void)id; + vec4 scissor={0, 0, window_width(), window_height()}; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &scissor); + + if (!array_count(scissor_rects)) + glEnable(GL_SCISSOR_TEST); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + array_push(scissor_rects, scissor); +} + +void gui_panel_end() { + ASSERT(array_count(scissor_rects)); + array_pop(scissor_rects); + if (array_count(scissor_rects)) { + vec4 scissor = *array_back(scissor_rects); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +bool gui_button_id(int id, vec4 r, const char *skin) { gui_state_t *entry = gui_getstate(id); bool was_clicked=0; - entry->hover = false; - if (input(MOUSE_X) > r.x && input(MOUSE_X) < (r.x+r.z) && input(MOUSE_Y) > r.y && input(MOUSE_Y) < (r.y+r.w)) { + char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(btn, r)) { if (input_up(MOUSE_L) && entry->held) { was_clicked=1; } @@ -358983,15 +359018,74 @@ bool (gui_button)(int id, vec4 r, const char *skin) { else if (input_up(MOUSE_L) && entry->held) { entry->held = false; } + else { + entry->hover = false; + } - char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, btn, r); return was_clicked; } -void (gui_panel)(int id, vec4 r, const char *skin) { - if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin?skin:"panel", r); +static +float slider2posx(float min, float max, float value, float step, float w) { + float norm = value - min; + float range = max - min; + float rel = norm / range; + float res = w * rel; + return step==0.0f?res:(round(res/step)*step); +} + +static +float posx2slider(vec4 rect, float min, float max, float xpos, float step) { + xpos = clampf(xpos, rect.x, rect.x+rect.z); + double rel = (xpos - rect.x) / rect.z; + float res = min + (rel * (max - min)); + return step==0.0f?res:(round(res/step)*step); +} + +bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value) { + gui_state_t *entry = gui_getstate(id); + + skin = skin?skin:"slider"; + char *cursorskin = va("%s_cursor%s", skin, entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(skin, rect)) { + entry->held = input_held(MOUSE_L); + entry->hover = true; + } + else if (input_up(MOUSE_L) && entry->held) { + entry->held = false; + } + else { + entry->hover = false; + } + + + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + + vec2 slidersize={0}, cursorsize={0}; + vec4 usablerect=rect; + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &usablerect); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, skin, &slidersize); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, cursorskin, &cursorsize); + if (entry->held) { + *value = posx2slider(usablerect, min, max, input(MOUSE_X), step); + } + float sliderx = slider2posx(min, max, *value, step, usablerect.z); + vec2 cursorpos = vec2(sliderx+usablerect.x*.5f-cursorsize.x*.5f, (slidersize.y*.5f - cursorsize.y*.5f)); + vec4 cursorrect = rect; + cursorrect.x += cursorpos.x; + cursorrect.y += cursorpos.y; + cursorrect.z = cursorsize.x; + cursorrect.w = cursorsize.y; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, cursorskin, cursorrect); + + return false; +} + +void gui_rect_id(int id, vec4 r, const char *skin) { + (void)id; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, r); } /* skinned */ @@ -359008,6 +359102,7 @@ atlas_slice_frame_t *skinned_getsliceframe(atlas_t *a, const char *name) { for (int i = 0; i < array_count(a->slices); i++) if (!strcmp(quark_string(&a->db, a->slices[i].name), name)) return &a->slice_frames[a->slices[i].frames[0]]; + PRINTF("slice name: '%s' is missing in atlas!\n", name); return NULL; } @@ -359017,6 +359112,28 @@ void skinned_draw_missing_rect(vec4 r) { gui_drawrect(texture_checker(), v42v2(size), 0x800080FF, v42v2(r)); } +static +bool skinned_ismouseinrect(void *userdata, const char *skin, vec4 r) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return false; + + vec4 outer = f->bounds; + r.x -= f->pivot.x*a->scale; + r.y -= f->pivot.y*a->scale; + r.z += r.x; + r.w += r.y; + + if ((r.z-r.x) < (outer.z-outer.x) * a->scale) { + r.z = r.x + (outer.z-outer.x) * a->scale; + } + if ((r.w-r.y) < (outer.w-outer.y) * a->scale) { + r.w = r.y + (outer.w-outer.y) * a->scale; + } + + return (input(MOUSE_X) > r.x && input(MOUSE_X) < r.z && input(MOUSE_Y) > r.y && input(MOUSE_Y) < r.w); +} + static void skinned_draw_sprite(float scale, atlas_t *a, atlas_slice_frame_t *f, vec4 r) { vec4 outer = f->bounds; @@ -359099,6 +359216,27 @@ void skinned_getskinsize(void *userdata, const char *skin, vec2 *size) { } } +static +void skinned_getscissorrect(void* userdata, const char *skin, vec4 rect, vec4 *dims) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return; + + *dims = rect; + + if (!f->has_9slice) return; + vec2 skinsize, coresize; + skinsize.x = (f->bounds.z-f->bounds.x)*a->scale; + skinsize.y = (f->bounds.w-f->bounds.y)*a->scale; + coresize.x = (f->core.z-f->core.x)*a->scale; + coresize.y = (f->core.w-f->core.y)*a->scale; + + dims->x += f->core.x*a->scale; + dims->y += f->core.y*a->scale; + dims->z -= (skinsize.x - coresize.x); + dims->w -= (skinsize.y - coresize.y); +} + guiskin_t gui_skinned(const char *inifile, float scale) { skinned_t *a = REALLOC(0, sizeof(skinned_t)); a->atlas = atlas_create(inifile, 0); @@ -359107,6 +359245,8 @@ guiskin_t gui_skinned(const char *inifile, float scale) { skin.userdata = a; skin.drawrect = skinned_draw_rect; skin.getskinsize = skinned_getskinsize; + skin.ismouseinrect = skinned_ismouseinrect; + skin.getscissorrect = skinned_getscissorrect; skin.free = skinned_free; return skin; } diff --git a/engine/split/v4k_gui.c b/engine/split/v4k_gui.c index d70ce81..2811546 100644 --- a/engine/split/v4k_gui.c +++ b/engine/split/v4k_gui.c @@ -89,18 +89,17 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve // ---------------------------------------------------------------------------- // game ui -typedef struct gui_state_t { - union { - struct { - bool held; - bool hover; - }; +typedef union gui_state_t { + struct { + bool held; + bool hover; }; } gui_state_t; static __thread array(guiskin_t) skins=0; static __thread guiskin_t *last_skin=0; static __thread map(int, gui_state_t) ctl_states=0; //@leak +static __thread array(vec4) scissor_rects=0; void gui_pushskin(guiskin_t skin) { array_push(skins, skin); @@ -124,18 +123,46 @@ vec2 gui_getskinsize(const char *skin) { return size; } +bool gui_ismouseinrect(const char *skin, vec4 rect) { + if (last_skin->ismouseinrect) return last_skin->ismouseinrect(last_skin->userdata, skin, rect); + return false; +} + static gui_state_t *gui_getstate(int id) { if (!ctl_states) map_init(ctl_states, less_int, hash_int); return map_find_or_add(ctl_states, id, (gui_state_t){0}); } -bool (gui_button)(int id, vec4 r, const char *skin) { +void gui_panel_id(int id, vec4 rect, const char *skin) { + (void)id; + vec4 scissor={0, 0, window_width(), window_height()}; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &scissor); + + if (!array_count(scissor_rects)) + glEnable(GL_SCISSOR_TEST); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + array_push(scissor_rects, scissor); +} + +void gui_panel_end() { + ASSERT(array_count(scissor_rects)); + array_pop(scissor_rects); + if (array_count(scissor_rects)) { + vec4 scissor = *array_back(scissor_rects); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +bool gui_button_id(int id, vec4 r, const char *skin) { gui_state_t *entry = gui_getstate(id); bool was_clicked=0; - entry->hover = false; - if (input(MOUSE_X) > r.x && input(MOUSE_X) < (r.x+r.z) && input(MOUSE_Y) > r.y && input(MOUSE_Y) < (r.y+r.w)) { + char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(btn, r)) { if (input_up(MOUSE_L) && entry->held) { was_clicked=1; } @@ -146,15 +173,74 @@ bool (gui_button)(int id, vec4 r, const char *skin) { else if (input_up(MOUSE_L) && entry->held) { entry->held = false; } + else { + entry->hover = false; + } - char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, btn, r); return was_clicked; } -void (gui_panel)(int id, vec4 r, const char *skin) { - if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin?skin:"panel", r); +static +float slider2posx(float min, float max, float value, float step, float w) { + float norm = value - min; + float range = max - min; + float rel = norm / range; + float res = w * rel; + return step==0.0f?res:(round(res/step)*step); +} + +static +float posx2slider(vec4 rect, float min, float max, float xpos, float step) { + xpos = clampf(xpos, rect.x, rect.x+rect.z); + double rel = (xpos - rect.x) / rect.z; + float res = min + (rel * (max - min)); + return step==0.0f?res:(round(res/step)*step); +} + +bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value) { + gui_state_t *entry = gui_getstate(id); + + skin = skin?skin:"slider"; + char *cursorskin = va("%s_cursor%s", skin, entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(skin, rect)) { + entry->held = input_held(MOUSE_L); + entry->hover = true; + } + else if (input_up(MOUSE_L) && entry->held) { + entry->held = false; + } + else { + entry->hover = false; + } + + + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + + vec2 slidersize={0}, cursorsize={0}; + vec4 usablerect=rect; + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &usablerect); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, skin, &slidersize); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, cursorskin, &cursorsize); + if (entry->held) { + *value = posx2slider(usablerect, min, max, input(MOUSE_X), step); + } + float sliderx = slider2posx(min, max, *value, step, usablerect.z); + vec2 cursorpos = vec2(sliderx+usablerect.x*.5f-cursorsize.x*.5f, (slidersize.y*.5f - cursorsize.y*.5f)); + vec4 cursorrect = rect; + cursorrect.x += cursorpos.x; + cursorrect.y += cursorpos.y; + cursorrect.z = cursorsize.x; + cursorrect.w = cursorsize.y; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, cursorskin, cursorrect); + + return false; +} + +void gui_rect_id(int id, vec4 r, const char *skin) { + (void)id; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, r); } /* skinned */ @@ -171,6 +257,7 @@ atlas_slice_frame_t *skinned_getsliceframe(atlas_t *a, const char *name) { for (int i = 0; i < array_count(a->slices); i++) if (!strcmp(quark_string(&a->db, a->slices[i].name), name)) return &a->slice_frames[a->slices[i].frames[0]]; + PRINTF("slice name: '%s' is missing in atlas!\n", name); return NULL; } @@ -180,6 +267,28 @@ void skinned_draw_missing_rect(vec4 r) { gui_drawrect(texture_checker(), v42v2(size), 0x800080FF, v42v2(r)); } +static +bool skinned_ismouseinrect(void *userdata, const char *skin, vec4 r) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return false; + + vec4 outer = f->bounds; + r.x -= f->pivot.x*a->scale; + r.y -= f->pivot.y*a->scale; + r.z += r.x; + r.w += r.y; + + if ((r.z-r.x) < (outer.z-outer.x) * a->scale) { + r.z = r.x + (outer.z-outer.x) * a->scale; + } + if ((r.w-r.y) < (outer.w-outer.y) * a->scale) { + r.w = r.y + (outer.w-outer.y) * a->scale; + } + + return (input(MOUSE_X) > r.x && input(MOUSE_X) < r.z && input(MOUSE_Y) > r.y && input(MOUSE_Y) < r.w); +} + static void skinned_draw_sprite(float scale, atlas_t *a, atlas_slice_frame_t *f, vec4 r) { vec4 outer = f->bounds; @@ -262,6 +371,27 @@ void skinned_getskinsize(void *userdata, const char *skin, vec2 *size) { } } +static +void skinned_getscissorrect(void* userdata, const char *skin, vec4 rect, vec4 *dims) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return; + + *dims = rect; + + if (!f->has_9slice) return; + vec2 skinsize, coresize; + skinsize.x = (f->bounds.z-f->bounds.x)*a->scale; + skinsize.y = (f->bounds.w-f->bounds.y)*a->scale; + coresize.x = (f->core.z-f->core.x)*a->scale; + coresize.y = (f->core.w-f->core.y)*a->scale; + + dims->x += f->core.x*a->scale; + dims->y += f->core.y*a->scale; + dims->z -= (skinsize.x - coresize.x); + dims->w -= (skinsize.y - coresize.y); +} + guiskin_t gui_skinned(const char *inifile, float scale) { skinned_t *a = REALLOC(0, sizeof(skinned_t)); a->atlas = atlas_create(inifile, 0); @@ -270,6 +400,8 @@ guiskin_t gui_skinned(const char *inifile, float scale) { skin.userdata = a; skin.drawrect = skinned_draw_rect; skin.getskinsize = skinned_getskinsize; + skin.ismouseinrect = skinned_ismouseinrect; + skin.getscissorrect = skinned_getscissorrect; skin.free = skinned_free; return skin; } diff --git a/engine/split/v4k_gui.h b/engine/split/v4k_gui.h index a95603b..7844a56 100644 --- a/engine/split/v4k_gui.h +++ b/engine/split/v4k_gui.h @@ -4,6 +4,8 @@ typedef struct guiskin_t { void (*drawrect)(void* userdata, const char *skin, vec4 rect); void (*getskinsize)(void* userdata, const char *skin, vec2 *size); + void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); + bool (*ismouseinrect)(void* userdata, const char *skin, vec4 rect); void (*free)(void* userdata); void *userdata; } guiskin_t; @@ -11,14 +13,20 @@ typedef struct guiskin_t { API void gui_pushskin(guiskin_t skin); API void* gui_userdata(); API vec2 gui_getskinsize(const char *skin); +API bool gui_ismouseinrect(const char *skin, vec4 rect); // -- -API void gui_panel(int id, vec4 rect, const char *skin); -API bool gui_button(int id, vec4 rect, const char *skin); +API void gui_panel_id(int id, vec4 rect, const char *skin); +API void gui_rect_id(int id, vec4 rect, const char *skin); +API bool gui_button_id(int id, vec4 rect, const char *skin); +API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); +API void gui_panel_end(); API void gui_popskin(); // helpers -#define gui_panel(...) gui_panel(__LINE__, __VA_ARGS__) -#define gui_button(...) gui_button(__LINE__, __VA_ARGS__) +#define gui_panel(...) gui_panel_id(__LINE__, __VA_ARGS__) +#define gui_rect(...) gui_rect_id(__LINE__, __VA_ARGS__) +#define gui_button(...) gui_button_id(__LINE__, __VA_ARGS__) +#define gui_slider(...) gui_slider_id(__LINE__, __VA_ARGS__) // default renderers diff --git a/engine/v4k.c b/engine/v4k.c index dbaa917..8ff251a 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -11099,18 +11099,17 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve // ---------------------------------------------------------------------------- // game ui -typedef struct gui_state_t { - union { - struct { - bool held; - bool hover; - }; +typedef union gui_state_t { + struct { + bool held; + bool hover; }; } gui_state_t; static __thread array(guiskin_t) skins=0; static __thread guiskin_t *last_skin=0; static __thread map(int, gui_state_t) ctl_states=0; //@leak +static __thread array(vec4) scissor_rects=0; void gui_pushskin(guiskin_t skin) { array_push(skins, skin); @@ -11134,18 +11133,46 @@ vec2 gui_getskinsize(const char *skin) { return size; } +bool gui_ismouseinrect(const char *skin, vec4 rect) { + if (last_skin->ismouseinrect) return last_skin->ismouseinrect(last_skin->userdata, skin, rect); + return false; +} + static gui_state_t *gui_getstate(int id) { if (!ctl_states) map_init(ctl_states, less_int, hash_int); return map_find_or_add(ctl_states, id, (gui_state_t){0}); } -bool (gui_button)(int id, vec4 r, const char *skin) { +void gui_panel_id(int id, vec4 rect, const char *skin) { + (void)id; + vec4 scissor={0, 0, window_width(), window_height()}; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &scissor); + + if (!array_count(scissor_rects)) + glEnable(GL_SCISSOR_TEST); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + array_push(scissor_rects, scissor); +} + +void gui_panel_end() { + ASSERT(array_count(scissor_rects)); + array_pop(scissor_rects); + if (array_count(scissor_rects)) { + vec4 scissor = *array_back(scissor_rects); + glScissor(scissor.x, scissor.y, scissor.z, scissor.w); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +bool gui_button_id(int id, vec4 r, const char *skin) { gui_state_t *entry = gui_getstate(id); bool was_clicked=0; - entry->hover = false; - if (input(MOUSE_X) > r.x && input(MOUSE_X) < (r.x+r.z) && input(MOUSE_Y) > r.y && input(MOUSE_Y) < (r.y+r.w)) { + char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(btn, r)) { if (input_up(MOUSE_L) && entry->held) { was_clicked=1; } @@ -11156,15 +11183,74 @@ bool (gui_button)(int id, vec4 r, const char *skin) { else if (input_up(MOUSE_L) && entry->held) { entry->held = false; } + else { + entry->hover = false; + } - char *btn = va("%s%s", skin?skin:"button", entry->held?"_press":entry->hover?"_hover":""); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, btn, r); return was_clicked; } -void (gui_panel)(int id, vec4 r, const char *skin) { - if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin?skin:"panel", r); +static +float slider2posx(float min, float max, float value, float step, float w) { + float norm = value - min; + float range = max - min; + float rel = norm / range; + float res = w * rel; + return step==0.0f?res:(round(res/step)*step); +} + +static +float posx2slider(vec4 rect, float min, float max, float xpos, float step) { + xpos = clampf(xpos, rect.x, rect.x+rect.z); + double rel = (xpos - rect.x) / rect.z; + float res = min + (rel * (max - min)); + return step==0.0f?res:(round(res/step)*step); +} + +bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value) { + gui_state_t *entry = gui_getstate(id); + + skin = skin?skin:"slider"; + char *cursorskin = va("%s_cursor%s", skin, entry->held?"_press":entry->hover?"_hover":""); + if (gui_ismouseinrect(skin, rect)) { + entry->held = input_held(MOUSE_L); + entry->hover = true; + } + else if (input_up(MOUSE_L) && entry->held) { + entry->held = false; + } + else { + entry->hover = false; + } + + + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, rect); + + vec2 slidersize={0}, cursorsize={0}; + vec4 usablerect=rect; + if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, rect, &usablerect); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, skin, &slidersize); + if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, cursorskin, &cursorsize); + if (entry->held) { + *value = posx2slider(usablerect, min, max, input(MOUSE_X), step); + } + float sliderx = slider2posx(min, max, *value, step, usablerect.z); + vec2 cursorpos = vec2(sliderx+usablerect.x*.5f-cursorsize.x*.5f, (slidersize.y*.5f - cursorsize.y*.5f)); + vec4 cursorrect = rect; + cursorrect.x += cursorpos.x; + cursorrect.y += cursorpos.y; + cursorrect.z = cursorsize.x; + cursorrect.w = cursorsize.y; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, cursorskin, cursorrect); + + return false; +} + +void gui_rect_id(int id, vec4 r, const char *skin) { + (void)id; + if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, r); } /* skinned */ @@ -11181,6 +11267,7 @@ atlas_slice_frame_t *skinned_getsliceframe(atlas_t *a, const char *name) { for (int i = 0; i < array_count(a->slices); i++) if (!strcmp(quark_string(&a->db, a->slices[i].name), name)) return &a->slice_frames[a->slices[i].frames[0]]; + PRINTF("slice name: '%s' is missing in atlas!\n", name); return NULL; } @@ -11190,6 +11277,28 @@ void skinned_draw_missing_rect(vec4 r) { gui_drawrect(texture_checker(), v42v2(size), 0x800080FF, v42v2(r)); } +static +bool skinned_ismouseinrect(void *userdata, const char *skin, vec4 r) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return false; + + vec4 outer = f->bounds; + r.x -= f->pivot.x*a->scale; + r.y -= f->pivot.y*a->scale; + r.z += r.x; + r.w += r.y; + + if ((r.z-r.x) < (outer.z-outer.x) * a->scale) { + r.z = r.x + (outer.z-outer.x) * a->scale; + } + if ((r.w-r.y) < (outer.w-outer.y) * a->scale) { + r.w = r.y + (outer.w-outer.y) * a->scale; + } + + return (input(MOUSE_X) > r.x && input(MOUSE_X) < r.z && input(MOUSE_Y) > r.y && input(MOUSE_Y) < r.w); +} + static void skinned_draw_sprite(float scale, atlas_t *a, atlas_slice_frame_t *f, vec4 r) { vec4 outer = f->bounds; @@ -11272,6 +11381,27 @@ void skinned_getskinsize(void *userdata, const char *skin, vec2 *size) { } } +static +void skinned_getscissorrect(void* userdata, const char *skin, vec4 rect, vec4 *dims) { + skinned_t *a = C_CAST(skinned_t*, userdata); + atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); + if (!f) return; + + *dims = rect; + + if (!f->has_9slice) return; + vec2 skinsize, coresize; + skinsize.x = (f->bounds.z-f->bounds.x)*a->scale; + skinsize.y = (f->bounds.w-f->bounds.y)*a->scale; + coresize.x = (f->core.z-f->core.x)*a->scale; + coresize.y = (f->core.w-f->core.y)*a->scale; + + dims->x += f->core.x*a->scale; + dims->y += f->core.y*a->scale; + dims->z -= (skinsize.x - coresize.x); + dims->w -= (skinsize.y - coresize.y); +} + guiskin_t gui_skinned(const char *inifile, float scale) { skinned_t *a = REALLOC(0, sizeof(skinned_t)); a->atlas = atlas_create(inifile, 0); @@ -11280,6 +11410,8 @@ guiskin_t gui_skinned(const char *inifile, float scale) { skin.userdata = a; skin.drawrect = skinned_draw_rect; skin.getskinsize = skinned_getskinsize; + skin.ismouseinrect = skinned_ismouseinrect; + skin.getscissorrect = skinned_getscissorrect; skin.free = skinned_free; return skin; } diff --git a/engine/v4k.h b/engine/v4k.h index 4be98c5..69e67f4 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -4186,6 +4186,8 @@ API void sprite_setanim(sprite_t *s, unsigned name); typedef struct guiskin_t { void (*drawrect)(void* userdata, const char *skin, vec4 rect); void (*getskinsize)(void* userdata, const char *skin, vec2 *size); + void (*getscissorrect)(void* userdata, const char *skin, vec4 rect, vec4 *dims); + bool (*ismouseinrect)(void* userdata, const char *skin, vec4 rect); void (*free)(void* userdata); void *userdata; } guiskin_t; @@ -4193,14 +4195,20 @@ typedef struct guiskin_t { API void gui_pushskin(guiskin_t skin); API void* gui_userdata(); API vec2 gui_getskinsize(const char *skin); +API bool gui_ismouseinrect(const char *skin, vec4 rect); // -- -API void gui_panel(int id, vec4 rect, const char *skin); -API bool gui_button(int id, vec4 rect, const char *skin); +API void gui_panel_id(int id, vec4 rect, const char *skin); +API void gui_rect_id(int id, vec4 rect, const char *skin); +API bool gui_button_id(int id, vec4 rect, const char *skin); +API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); +API void gui_panel_end(); API void gui_popskin(); // helpers -#define gui_panel(...) gui_panel(__LINE__, __VA_ARGS__) -#define gui_button(...) gui_button(__LINE__, __VA_ARGS__) +#define gui_panel(...) gui_panel_id(__LINE__, __VA_ARGS__) +#define gui_rect(...) gui_rect_id(__LINE__, __VA_ARGS__) +#define gui_button(...) gui_button_id(__LINE__, __VA_ARGS__) +#define gui_slider(...) gui_slider_id(__LINE__, __VA_ARGS__) // default renderers diff --git a/tools/cook.ini b/tools/cook.ini index 862eb39..a599b5d 100644 --- a/tools/cook.ini +++ b/tools/cook.ini @@ -25,9 +25,9 @@ ART=../demos/art/,../engine/art/,../editor/art/ ; comma-separated folder(s) tha ; also, once a symbol is found, it is replaced by its value always. ; some predefined symbols: INPUT (input filename), OUTPUT (output filename), PRETTY (clean input filename), PROGRESS (cook progress). -@windows `echo Cooking PROGRESS% PRETTY...` -@linux `echo "Cooking PROGRESS% PRETTY..."` -@osx `echo "Cooking PROGRESS% PRETTY..."` +;@windows `echo Cooking PROGRESS% PRETTY...` +;@linux `echo "Cooking PROGRESS% PRETTY..."` +;@osx `echo "Cooking PROGRESS% PRETTY..."` ; ------------------------------------------------------------------------------ ; groups below are collection of files that we want to cook, and then package. diff --git a/v4k.sublime-project b/v4k.sublime-project index 2ce1798..ced448a 100644 --- a/v4k.sublime-project +++ b/v4k.sublime-project @@ -3,8 +3,8 @@ [ { "path": ".", - "file_exclude_patterns": ["*.exe.manifest", "*.zip", "*.ilk", "*.exp", "_mirror/", "engine/v4k*", "engine/joint/"], - "index_exclude_patterns": ["engine/joint/v4k.h", "engine/v4k.h", "engine/v4k.c", "_mirror/**"] + "file_exclude_patterns": ["*.exe.manifest", "*.zip", "*.ilk", "*.exp", "_mirror/", "engine/v4k", "engine/joint/", "engine/split/"], + "index_exclude_patterns": ["engine/joint/v4k.h", "engine/split/**", "_mirror/**"] } ], "settings": {