From: hgn Date: Tue, 30 Jan 2024 20:59:33 +0000 (+0000) Subject: add colour picker to imgui X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=commitdiff_plain;h=b37cac2c8562dd54066162cbbab359937d5399b1 add colour picker to imgui --- diff --git a/vg_imgui.h b/vg_imgui.h index 19f4d78..32fab49 100644 --- a/vg_imgui.h +++ b/vg_imgui.h @@ -225,6 +225,8 @@ struct{ SDL_Cursor *cursor_map[ k_ui_cursor_max ]; v4f colour; + + f32 hue; /* lol this sucks */ } static vg_ui = { .scheme = { @@ -383,9 +385,56 @@ static struct vg_shader _shader_ui_image = { } }; +static struct vg_shader _shader_ui_hsv = { + .name = "[vg] ui_hsv", + .link = NULL, + .vs = { + .orig_file = NULL, + .static_src = + "layout (location=0) in vec2 a_co;" + "layout (location=1) in vec2 a_uv;" + "layout (location=2) in vec4 a_colour;" + "uniform mat3 uPv;" + + "out vec2 aTexCoords;" + "out vec4 aColour;" + "out vec2 aWsp;" + + "void main()" + "{" + "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );" + "aTexCoords = a_uv * 0.00390625;" + "aColour = a_colour;" + + "aWsp = a_co;" + "}", + }, + .fs = + { + .orig_file = NULL, + .static_src = + "uniform float uHue;" + "out vec4 FragColor;" + + "in vec2 aTexCoords;" + "in vec4 aColour;" + "in vec2 aWsp;" + + "void main()" + "{" + "vec3 c = vec3( uHue, aTexCoords );" + "vec4 K = vec4(1.0,2.0/3.0,1.0/3.0,3.0);" + "vec3 p = abs(fract(c.xxx+K.xyz)*6.0 - K.www);" + "vec3 colour = c.z*mix(K.xxx,clamp(p-K.xxx,0.0,1.0),c.y);" + "FragColor = vec4( colour, 1.0 );" + "}" + } +}; + static void _vg_ui_init(void){ if( !vg_shader_compile( &_shader_ui ) || - !vg_shader_compile( &_shader_ui_image ) ){ + !vg_shader_compile( &_shader_ui_image ) || + !vg_shader_compile( &_shader_ui_hsv ) ){ vg_fatal_error( "Failed to compile ui shader" ); } @@ -493,7 +542,8 @@ static void _vg_ui_init(void){ enum ui_shader { k_ui_shader_colour, - k_ui_shader_image + k_ui_shader_image, + k_ui_shader_hsv, }; static void rect_copy( ui_rect a, ui_rect b ){ @@ -561,6 +611,12 @@ static void ui_flush( enum ui_shader shader, f32 w, f32 h ){ glUniform4fv( glGetUniformLocation( _shader_ui_image.id, "uColour" ), 1, vg_ui.colour ); } + else if( shader == k_ui_shader_hsv ){ + glUseProgram( _shader_ui_hsv.id ); + glUniformMatrix3fv( glGetUniformLocation( _shader_ui_hsv.id, "uPv" ), 1, + GL_FALSE, (float *)view ); + glUniform1f( glGetUniformLocation(_shader_ui_hsv.id,"uHue"), vg_ui.hue ); + } else vg_fatal_error( "Invalid UI shader (%d)\n", shader ); @@ -1070,10 +1126,12 @@ enum ui_button_state { k_ui_button_hover = 0x8 }; +/* TODO: split this out into a formatless button and one that auto fills */ static enum ui_button_state ui_colourbutton( ui_rect rect, enum ui_scheme_colour colour, enum ui_scheme_colour hover_colour, - enum ui_scheme_colour hi_colour ){ + enum ui_scheme_colour hi_colour, + bool const fill ){ int clickup= ui_click_up(UI_MOUSE_LEFT), click = ui_clicking(UI_MOUSE_LEFT) | clickup, target = ui_inside_rect( rect, vg_ui.mouse_click ) && click, @@ -1099,41 +1157,43 @@ static enum ui_button_state ui_colourbutton( ui_rect rect, if( target ){ if( hover ){ if( clickup ){ - ui_fill( rect, col_highlight ); vg_ui.ignore_input_frames = 2; - rect_copy( rect, vg_ui.click_fader ); + ui_defocus_all(); - rect_copy( rect, vg_ui.click_fader_end ); - vg_ui.click_fader_end[3] = 0; - ui_rect_center( rect, vg_ui.click_fader_end ); + if( fill ) { + ui_fill( rect, col_highlight ); + rect_copy( rect, vg_ui.click_fader ); + rect_copy( rect, vg_ui.click_fader_end ); + vg_ui.click_fader_end[3] = 0; + ui_rect_center( rect, vg_ui.click_fader_end ); + vg_ui.click_fade_opacity = 1.0f; + } - vg_ui.click_fade_opacity = 1.0f; - ui_defocus_all(); return k_ui_button_click; } else{ - ui_fill( rect, col_highlight ); + if( fill ) ui_fill( rect, col_highlight ); return k_ui_button_holding_inside; } } else{ - ui_fill( rect, col_base ); + if( fill ) ui_fill( rect, col_base ); ui_outline( rect, 1, col_highlight, 0 ); return k_ui_button_holding_outside; } } else{ - ui_fill( rect, col_base ); + if( fill ) ui_fill( rect, col_base ); return k_ui_button_none; } } else{ if( hover ){ - ui_fill( rect, col_hover ); + if( fill ) ui_fill( rect, col_hover ); return k_ui_button_hover; } else{ - ui_fill( rect, col_base ); + if( fill ) ui_fill( rect, col_base ); return k_ui_button_none; } } @@ -1142,7 +1202,7 @@ static enum ui_button_state ui_colourbutton( ui_rect rect, static enum ui_button_state ui_colourbutton_text( ui_rect rect, const char *string, ui_px scale, enum ui_scheme_colour colour ){ - enum ui_button_state state = ui_colourbutton( rect, colour, 0, 0 ); + enum ui_button_state state = ui_colourbutton( rect, colour, 0, 0, 1 ); ui_rect t = { 0,0, ui_text_line_width( string )*scale, 14*scale }; ui_rect_center( rect, t ); @@ -1263,7 +1323,7 @@ static int ui_checkbox( ui_rect inout_panel, const char *str_label, i32 *data ){ ui_split( rect, k_ui_axis_v, -rect[3], 0, label, box ); ui_text( label, str_label, k_ui_scale, k_ui_align_middle_left, 0 ); - int changed = ui_colourbutton( box, k_ui_bg, 0, 0 )==1; + int changed = ui_colourbutton( box, k_ui_bg, 0, 0, 1 )==1; if( changed ) *data = (*data) ^ 0x1; @@ -1356,12 +1416,8 @@ static void ui_enum_post(void){ * ----------------------------------------------------------------------------- */ -static void ui_slider( ui_rect inout_panel, const char *str_label, - f32 min, f32 max, f32 *value, const char *format ){ - ui_rect rect, label, box; - ui_standard_widget( inout_panel, rect, 1 ); - ui_label( rect, str_label, k_ui_scale, 0, box ); - +static void _ui_slider( ui_rect box, + f32 min, f32 max, f32 *value, const char *format ){ f32 t; enum ui_button_state @@ -1371,7 +1427,7 @@ static void ui_slider( ui_rect inout_panel, const char *str_label, k_ui_button_click, mask_brighter = mask_using | k_ui_button_hover, - state = ui_colourbutton( box, k_ui_bg, k_ui_bg+2, k_ui_bg+3 ); + state = ui_colourbutton( box, k_ui_bg, k_ui_bg+2, k_ui_bg+3, 1 ); if( state & mask_using ){ t = vg_clampf( (f32)(vg_ui.mouse[0] - box[0]) / (f32)( box[2] ), @@ -1392,6 +1448,103 @@ static void ui_slider( ui_rect inout_panel, const char *str_label, ui_text( box, buf, 1, k_ui_align_middle_center, 0 ); } +static void ui_slider( ui_rect inout_panel, const char *str_label, + f32 min, f32 max, f32 *value, const char *format ){ + ui_rect rect, label, box; + ui_standard_widget( inout_panel, rect, 1 ); + ui_label( rect, str_label, k_ui_scale, 0, box ); + _ui_slider( box, min, max, value, format ); +} + +/* + * Colour picker + * ----------------------------------------------------------------------------- + */ + +static void ui_colourpicker( ui_rect inout_panel, const char *str_label, + v4f value ){ + ui_rect widget, left, right; + ui_standard_widget( inout_panel, widget, 8 ); + ui_split_ratio( widget, k_ui_axis_v, 0.5f, 8, left, right ); + + ui_rect sliders[4]; + ui_split_ratio( right, k_ui_axis_h, 0.5f, 2, sliders[0], sliders[2] ); + ui_split_ratio( sliders[0], k_ui_axis_h, 0.5f, 2, sliders[0], sliders[1] ); + ui_split_ratio( sliders[2], k_ui_axis_h, 0.5f, 2, sliders[2], sliders[3] ); + + for( u32 i=0; i<4; i ++ ){ + _ui_slider( sliders[i], 0.0f, 1.0f, value+i, + (const char *[]){ "hue %.2f", + "sat %.2f", + "lum %.2f", + "alpha %.2f" }[i] ); + } + + ui_rect preview, square; + ui_split_ratio( left, k_ui_axis_v, 0.8f, 8, square, preview ); + + u32 state = ui_colourbutton( square, 0, 0, 0, 0 ); + + enum ui_button_state + mask_using = + k_ui_button_holding_inside | + k_ui_button_holding_outside | + k_ui_button_click; + + if( state & mask_using ){ + for( u32 i=0; i<2; i ++ ){ + value[1+i] = vg_clampf( + (f32)(vg_ui.mouse[i] - square[i]) / (f32)(square[2+i]), + 0.0f, 1.0f ); + } + + value[2] = 1.0f-value[2]; + } + + ui_outline( square, 1, ui_colour( state? k_ui_fg+3: k_ui_bg+3 ), 0 ); + + /* preview colour */ + i32 i = floorf( value[0]*6.0f ); + f32 v = value[2], + f = value[0] * 6.0f - (f32)i, + p = v * (1.0f-value[1]), + q = v * (1.0f-f*value[1]), + t = v * (1.0f-(1.0f-f)*value[1]); + + v4f colour; + + switch( i % 6 ){ + case 0: colour[0] = v; colour[1] = t; colour[2] = p; break; + case 1: colour[0] = q; colour[1] = v; colour[2] = p; break; + case 2: colour[0] = p; colour[1] = v; colour[2] = t; break; + case 3: colour[0] = p; colour[1] = q; colour[2] = v; break; + case 4: colour[0] = t; colour[1] = p; colour[2] = v; break; + case 5: colour[0] = v; colour[1] = p; colour[2] = q; break; + } + colour[3] = 1.0f; + ui_fill( preview, v4f_u32_colour( colour ) ); + + /* Draw hsv shader thingy */ + ui_flush( k_ui_shader_colour, vg.window_x, vg.window_y ); + ui_fill_rect( square, 0xffffffff, (ui_px[4]){ 0,256,256,0 } ); + vg_ui.hue = value[0]; + ui_flush( k_ui_shader_hsv, vg.window_x, vg.window_y ); + + ui_rect marker = { square[0] + value[1] * (f32)square[2] - 4, + square[1] + (1.0f-value[2]) * (f32)square[3] - 4, + 8, 8 }, + lx = { square[0], + square[1] + (1.0f-value[2]) * (f32)square[3], + square[2], 1 }, + ly = { square[0] + value[1] * (f32)square[2], + square[1], + 1, square[3] }; + + ui_fill( marker, ui_colour( k_ui_fg ) ); + ui_fill( lx, ui_colour( k_ui_fg ) ); + ui_fill( ly, ui_colour( k_ui_fg ) ); +} + /* * Textbox chaos * -----------------------------------------------------------------------------