X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fvg%2Fvg_ui.h;h=0c4b4159bc5636419e86f430fe185aac93410adb;hb=3dd767bb10e6fee9cbffeb185d1a9685810c17b5;hp=f7f8a1ca791b8253057714ef262ee789ad04ca1d;hpb=95c9a820474d4974ee394f2fcfae82fbfa367dbd;p=vg.git diff --git a/src/vg/vg_ui.h b/src/vg/vg_ui.h index f7f8a1c..0c4b415 100644 --- a/src/vg/vg_ui.h +++ b/src/vg/vg_ui.h @@ -1,7 +1,20 @@ /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ -SHADER_DEFINE( shader_ui, +#ifndef VG_UI_H +#define VG_UI_H +#include "vg/vg.h" +#include "vg/vg_tex.h" +#include "vg/vg_shader.h" + +static struct vg_shader _shader_ui = +{ + .name = "[vg] ui", + .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;" @@ -22,8 +35,11 @@ SHADER_DEFINE( shader_ui, "aWsp = a_co;" "aClip = a_clip;" "}", - - /* Fragment */ + }, + .fs = + { + .orig_file = NULL, + .static_src = "uniform sampler2D uTexGlyphs;" "out vec4 FragColor;" "" @@ -54,14 +70,12 @@ SHADER_DEFINE( shader_ui, "FragColor = vec4( aColour.rgb, glyph.a*clip_blend );" "}" - , - UNIFORMS({ "uPv", "uTexGlyphs" }) -) + } +}; typedef i16 ui_px; typedef u32 ui_colour; typedef ui_px ui_rect[4]; -typedef struct ui_ctx ui_ctx; typedef struct ui_colourset ui_colourset; /* Relative to cursor p0 */ @@ -91,7 +105,17 @@ struct ui_colourset }; }; -struct ui_ctx +#pragma pack(push,1) +struct ui_vert +{ + ui_px co[2]; + u8 uv[2]; + u32 colour; + ui_rect clip; +}; +#pragma pack(pop) + +struct { struct ui_qnode { @@ -102,29 +126,18 @@ struct ui_ctx } stack[ 32 ]; - #pragma pack(push,1) - struct ui_vert - { - ui_px co[2]; - u8 uv[2]; - u32 colour; - ui_rect clip; - } - *verts; - #pragma pack(pop) - - u32 num_verts; - u16 *indices; - u32 num_indices; + u32 control_id; + + struct ui_vert *vertex_buffer; + u16 *indice_buffer; + u32 max_verts, max_indices, cur_vert, cur_indice; ui_rect clipping; ui_rect cursor; u32 stack_count; u32 capture_mouse_id; int capture_lock; - u32 id_base; - int glyph_base; - + /* User input */ ui_px mouse[2]; int click_state; /* 0: released, 1: on down, 2: pressed, 3: on release */ @@ -142,7 +155,8 @@ struct ui_ctx } images[16]; int image_count; -}; +} +static vg_uictx; #define UI_GLYPH_SPACING_X 9 @@ -153,83 +167,81 @@ static ui_colourset ui_default_colours = { .active = 0xffad9f9e }; -static ui_ctx ui_global_ctx; - -static void ui_init_context( ui_ctx *ctx, int index_buffer_size ) +VG_STATIC void ui_init_context(void) { - u32 vertex_buffer_size = (index_buffer_size+(index_buffer_size/2)); + if( !vg_shader_compile( &_shader_ui ) ) + vg_fatal_exit_loop( "Failed to compile ui shader" ); + + /* + * Vertex buffer + * ---------------------------------------- + */ + + vg_uictx.max_indices = 20000; + vg_uictx.max_verts = 30000; /* Generate the buffer we are gonna be drawing to */ - { - glGenVertexArrays(1, &ctx->vao); - glGenBuffers( 1, &ctx->vbo ); - glGenBuffers( 1, &ctx->ebo ); - glBindVertexArray( ctx->vao ); - - glBindBuffer( GL_ARRAY_BUFFER, ctx->vbo ); - - glBufferData( GL_ARRAY_BUFFER, - vertex_buffer_size * sizeof( struct ui_vert ), - NULL, GL_DYNAMIC_DRAW ); - glBindVertexArray( ctx->vao ); - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ctx->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, - index_buffer_size * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW ); - - u32 const stride = sizeof( struct ui_vert ); - - /* XY */ - glVertexAttribPointer( 0, 2, GL_SHORT, GL_FALSE, - stride, (void *)offsetof( struct ui_vert, co ) ); - glEnableVertexAttribArray( 0 ); - - /* UV */ - glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE, GL_FALSE, - stride, (void *)offsetof( struct ui_vert, uv ) ); - glEnableVertexAttribArray( 1 ); - - /* COLOUR */ - glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, - (void *)offsetof( struct ui_vert, colour ) ); - glEnableVertexAttribArray( 2 ); - - /* CLIPPING */ - glVertexAttribPointer( 3, 4, GL_SHORT, GL_FALSE, stride, - (void *)offsetof( struct ui_vert, clip ) ); - glEnableVertexAttribArray( 3 ); - } - - /* Initialize default context */ - { - ctx->verts = (struct ui_vert *)malloc( - vertex_buffer_size * sizeof(struct ui_vert) ); - ctx->indices = (u16*)malloc( index_buffer_size * sizeof(u16) ); + glGenVertexArrays( 1, &vg_uictx.vao ); + glGenBuffers( 1, &vg_uictx.vbo ); + glGenBuffers( 1, &vg_uictx.ebo ); - if( !ctx->colours ) - ctx->colours = &ui_default_colours; - } -} + glBindVertexArray( vg_uictx.vao ); + glBindBuffer( GL_ARRAY_BUFFER, vg_uictx.vbo ); + + glBufferData( GL_ARRAY_BUFFER, + vg_uictx.max_verts * sizeof( struct ui_vert ), + NULL, GL_DYNAMIC_DRAW ); + glBindVertexArray( vg_uictx.vao ); + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vg_uictx.ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, + vg_uictx.max_indices * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW ); -static void ui_context_free( ui_ctx *ctx ) -{ - glDeleteVertexArrays( 1, &ctx->vao ); - glDeleteBuffers( 1, &ctx->vbo ); - glDeleteBuffers( 1, &ctx->ebo ); - - free( ctx->verts ); - free( ctx->indices ); -} + VG_CHECK_GL_ERR(); -static void ui_default_init(void) -{ + /* Set pointers */ + u32 const stride = sizeof( struct ui_vert ); + + /* XY */ + glVertexAttribPointer( 0, 2, GL_SHORT, GL_FALSE, + stride, (void *)offsetof( struct ui_vert, co ) ); + glEnableVertexAttribArray( 0 ); + + /* UV */ + glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE, GL_FALSE, + stride, (void *)offsetof( struct ui_vert, uv ) ); + glEnableVertexAttribArray( 1 ); + + /* COLOUR */ + glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, + (void *)offsetof( struct ui_vert, colour ) ); + glEnableVertexAttribArray( 2 ); + + /* CLIPPING */ + glVertexAttribPointer( 3, 4, GL_SHORT, GL_FALSE, stride, + (void *)offsetof( struct ui_vert, clip ) ); + glEnableVertexAttribArray( 3 ); + + VG_CHECK_GL_ERR(); + + /* Alloc RAM default context */ + u32 vert_size = vg_uictx.max_verts*sizeof(struct ui_vert), + inds_size = vg_uictx.max_indices*sizeof(u16); + + vg_uictx.vertex_buffer = vg_linear_alloc( vg_mem.rtmemory, vert_size ); + vg_uictx.indice_buffer = vg_linear_alloc( vg_mem.rtmemory, inds_size ); + + /* font + * ----------------------------------------------------- + */ + /* Load default font */ u32 compressed[] = { #include "vg/vg_pxfont.h" }; u32 pixels = 0, total = 256*256, data = 0; - u8 *image = malloc( total ); + u8 image[256*256]; while( pixels < total ) { @@ -248,54 +260,44 @@ static void ui_default_init(void) glGenTextures( 1, &ui_glyph_texture ); glBindTexture( GL_TEXTURE_2D, ui_glyph_texture ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, 256, 256, 0, - GL_RED, GL_UNSIGNED_BYTE, image ); - + GL_RED, GL_UNSIGNED_BYTE, image ); + + VG_CHECK_GL_ERR(); vg_tex2d_clamp(); vg_tex2d_nearest(); - - free( image ); - - SHADER_INIT( shader_ui ); - ui_init_context( &ui_global_ctx, 20000 ); } -static void ui_default_free(void) -{ - glDeleteTextures( 1, &ui_glyph_texture ); - ui_context_free( &ui_global_ctx ); -} - -static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, - u32 colour, ui_px uv[4] ); +static struct ui_vert *ui_fill_rect_uv( ui_rect rect, u32 colour, ui_px uv[4] ); -static void ui_draw( ui_ctx *ctx, m3x3f view_override ) +VG_STATIC void ui_draw( m3x3f view_override ) { - u32 num_indices_normal = ctx->num_indices; + u32 num_indices_normal = vg_uictx.cur_indice; /* Append images to back of buffer */ - for( int i = 0; i < ctx->image_count; i ++ ) + for( int i = 0; i < vg_uictx.image_count; i ++ ) { - ui_fill_rect_uv( ctx, ctx->images[i].rc, - 0xffffffff, (ui_px[4]){0,0,128,128} ); + ui_fill_rect_uv( vg_uictx.images[i].rc, 0xffffffff, + (ui_px[4]){0,0,128,128} ); } - glBindVertexArray( ctx->vao ); + glBindVertexArray( vg_uictx.vao ); - glBindBuffer( GL_ARRAY_BUFFER, ctx->vbo ); + glBindBuffer( GL_ARRAY_BUFFER, vg_uictx.vbo ); glBufferSubData( GL_ARRAY_BUFFER, 0, - ctx->num_verts * sizeof( struct ui_vert ), ctx->verts ); + vg_uictx.cur_vert * sizeof( struct ui_vert ), + vg_uictx.vertex_buffer ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ctx->ebo ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vg_uictx.ebo ); glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, - ctx->num_indices * sizeof( u16 ), ctx->indices ); + vg_uictx.cur_indice * sizeof( u16 ), + vg_uictx.indice_buffer ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); - SHADER_USE( shader_ui ); + glUseProgram( _shader_ui.id ); m3x3f view = M3X3_IDENTITY; @@ -304,24 +306,25 @@ static void ui_draw( ui_ctx *ctx, m3x3f view_override ) view_override = view; m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } ); - m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), - -1.0f/((float)vg_window_y*0.5f), 1.0f } ); + m3x3_scale( view, (v3f){ 1.0f/((float)vg.window_x*0.5f), + -1.0f/((float)vg.window_y*0.5f), 1.0f } ); } - glUniformMatrix3fv( SHADER_UNIFORM( shader_ui, "uPv" ), 1, + /* TODO? */ + glUniformMatrix3fv( glGetUniformLocation( _shader_ui.id, "uPv" ), 1, GL_FALSE, (float *)view_override ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, ui_glyph_texture ); - glUniform1i( SHADER_UNIFORM( shader_ui, "uTexGlyphs" ), 0 ); + glUniform1i( glGetUniformLocation( _shader_ui.id, "uTexGlyphs" ), 0 ); glDrawElements( GL_TRIANGLES, num_indices_normal, GL_UNSIGNED_SHORT, (void*)(0) ); /* Draw image elements */ - for( int i = 0; i < ctx->image_count; i ++ ) + for( int i = 0; i < vg_uictx.image_count; i ++ ) { - struct ui_image *img = &ctx->images[i]; + struct ui_image *img = &vg_uictx.images[i]; glBindTexture( GL_TEXTURE_2D, img->image ); glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, @@ -334,7 +337,7 @@ static void ui_draw( ui_ctx *ctx, m3x3f view_override ) /* * Rect controls */ -static void ui_rect_copy( ui_rect src, ui_rect dst ) +VG_STATIC void ui_rect_copy( ui_rect src, ui_rect dst ) { dst[0] = src[0]; dst[1] = src[1]; @@ -342,7 +345,7 @@ static void ui_rect_copy( ui_rect src, ui_rect dst ) dst[3] = src[3]; } -static void ui_rect_pad( ui_rect rect, ui_px pad ) +VG_STATIC void ui_rect_pad( ui_rect rect, ui_px pad ) { rect[0] += pad; rect[1] += pad; @@ -353,26 +356,29 @@ static void ui_rect_pad( ui_rect rect, ui_px pad ) /* * Stack control */ -static struct ui_qnode *ui_current( ui_ctx *ctx ) +static struct ui_qnode *ui_current(void) { - return &ctx->stack[ ctx->stack_count-1 ]; + return &vg_uictx.stack[ vg_uictx.stack_count-1 ]; } -static void ui_new_node( ui_ctx *ctx ) +VG_STATIC void ui_new_node(void) { - if( ctx->stack_count == vg_list_size( ctx->stack ) ) - vg_exiterr( "[UI] Stack overflow while creating box!" ); + if( vg_uictx.stack_count == vg_list_size( vg_uictx.stack ) ) + { + vg_error( "[UI] Stack overflow while creating box!" ); + return; + } - struct ui_qnode *parent = &ctx->stack[ ctx->stack_count-1 ]; - struct ui_qnode *node = &ctx->stack[ ctx->stack_count++ ]; - ui_rect_copy( ctx->cursor, node->rect ); + struct ui_qnode *parent = &vg_uictx.stack[ vg_uictx.stack_count-1 ]; + struct ui_qnode *node = &vg_uictx.stack[ vg_uictx.stack_count++ ]; + ui_rect_copy( vg_uictx.cursor, node->rect ); if( parent->mouse_over ) { - if( ctx->mouse[0] >= node->rect[0] && - ctx->mouse[0] < node->rect[0]+node->rect[2] && - ctx->mouse[1] >= node->rect[1] && - ctx->mouse[1] < node->rect[1]+node->rect[3] ) + if( vg_uictx.mouse[0] >= node->rect[0] && + vg_uictx.mouse[0] < node->rect[0]+node->rect[2] && + vg_uictx.mouse[1] >= node->rect[1] && + vg_uictx.mouse[1] < node->rect[1]+node->rect[3] ) node->mouse_over = 1; else node->mouse_over = 0; @@ -383,67 +389,67 @@ static void ui_new_node( ui_ctx *ctx ) } } -static int ui_hasmouse( ui_ctx *ctx ) +static int ui_hasmouse(void) { - struct ui_qnode *node = ui_current( ctx ); - return (node->mouse_over && (node->capture_id == ctx->capture_mouse_id)); + struct ui_qnode *node = ui_current(); + return (node->mouse_over && (node->capture_id == vg_uictx.capture_mouse_id)); } -static void ui_end( ui_ctx *ctx ) +VG_STATIC void ui_end(void) { - struct ui_qnode *node = &ctx->stack[ --ctx->stack_count ]; - ui_rect_copy( node->rect, ctx->cursor ); + struct ui_qnode *node = &vg_uictx.stack[ --vg_uictx.stack_count ]; + ui_rect_copy( node->rect, vg_uictx.cursor ); } -static void ui_end_down( ui_ctx *ctx ) +VG_STATIC void ui_end_down(void) { - ui_px height = ui_current( ctx )->rect[3]; - ui_end( ctx ); - ctx->cursor[1] += height; + ui_px height = ui_current()->rect[3]; + ui_end(); + vg_uictx.cursor[1] += height; } -static void ui_end_right( ui_ctx *ctx ) +VG_STATIC void ui_end_right(void) { - ui_px width = ui_current( ctx )->rect[2]; - ui_end( ctx ); - ctx->cursor[0] += width; + ui_px width = ui_current()->rect[2]; + ui_end(); + vg_uictx.cursor[0] += width; } -static void ui_fill_y( ui_ctx *ctx ) +VG_STATIC void ui_fill_y(void) { - struct ui_qnode *node = ui_current( ctx ); - ctx->cursor[3] = node->rect[3] - (ctx->cursor[1]-node->rect[1]); + struct ui_qnode *node = ui_current(); + vg_uictx.cursor[3] = node->rect[3] - (vg_uictx.cursor[1]-node->rect[1]); } -static void ui_fill_x( ui_ctx *ctx ) +VG_STATIC void ui_fill_x(void) { - struct ui_qnode *node = ui_current( ctx ); - ctx->cursor[2] = node->rect[2] - (ctx->cursor[0]-node->rect[0]); + struct ui_qnode *node = ui_current(); + vg_uictx.cursor[2] = node->rect[2] - (vg_uictx.cursor[0]-node->rect[0]); } -static void ui_align_bottom( ui_ctx *ctx ) +VG_STATIC void ui_align_bottom(void) { - struct ui_qnode *node = ui_current( ctx ); - ctx->cursor[1] = node->rect[1] + node->rect[3] - ctx->cursor[3]; + struct ui_qnode *node = ui_current(); + vg_uictx.cursor[1] = node->rect[1] + node->rect[3] - vg_uictx.cursor[3]; } -static void ui_align_right( ui_ctx *ctx ) +VG_STATIC void ui_align_right(void) { - struct ui_qnode *node = ui_current( ctx ); - ctx->cursor[0] = node->rect[0] + node->rect[2] - ctx->cursor[2]; + struct ui_qnode *node = ui_current(); + vg_uictx.cursor[0] = node->rect[0] + node->rect[2] - vg_uictx.cursor[2]; } -static void ui_align_top( ui_ctx *ctx ) +VG_STATIC void ui_align_top(void) { - ctx->cursor[1] = ui_current( ctx )->rect[1]; + vg_uictx.cursor[1] = ui_current()->rect[1]; } -static void ui_align_left( ui_ctx *ctx ) +VG_STATIC void ui_align_left(void) { - ctx->cursor[0] = ui_current( ctx )->rect[0]; + vg_uictx.cursor[0] = ui_current()->rect[0]; } -static void ui_clamp_rect( ui_rect parent, ui_rect dest ) +VG_STATIC void ui_clamp_rect( ui_rect parent, ui_rect dest ) { dest[0] = vg_min( parent[0] + parent[2] - dest[2], dest[0] ); dest[1] = vg_min( parent[1] + parent[3] - dest[3], dest[1] ); @@ -451,49 +457,48 @@ static void ui_clamp_rect( ui_rect parent, ui_rect dest ) dest[1] = vg_max( parent[1], dest[1] ); } -static u32 ui_group_id( ui_ctx *ctx, u32 lesser_unique ) -{ - return ctx->id_base | lesser_unique; -} - -static void ui_capture_mouse( ui_ctx *ctx, u32 id ) +VG_STATIC void ui_capture_mouse( u32 id ) { - u32 group_uid = ui_group_id(ctx,id); - - struct ui_qnode *node = &ctx->stack[ ctx->stack_count-1 ]; - node->capture_id = group_uid; + struct ui_qnode *node = &vg_uictx.stack[ vg_uictx.stack_count-1 ]; + node->capture_id = id; - if( !ctx->capture_lock && node->mouse_over ) + if( !vg_uictx.capture_lock && node->mouse_over ) { - ctx->capture_mouse_id = group_uid; + vg_uictx.capture_mouse_id = id; } } -static int ui_want_mouse( ui_ctx *ctx ) +static int ui_want_mouse(void) { - return ctx->capture_mouse_id == 0? 0: 1; + return vg_uictx.capture_mouse_id == 0? 0: 1; } -static void ui_set_clip( ui_ctx *ctx, ui_rect clip ) +VG_STATIC void ui_set_clip( ui_rect clip ) { - ctx->clipping[0] = clip[0]; - ctx->clipping[1] = clip[1]; - ctx->clipping[2] = clip[0] + clip[2]; - ctx->clipping[3] = clip[1] + clip[3]; + vg_uictx.clipping[0] = clip[0]; + vg_uictx.clipping[1] = clip[1]; + vg_uictx.clipping[2] = clip[0] + clip[2]; + vg_uictx.clipping[3] = clip[1] + clip[3]; } -static void ui_release_clip( ui_ctx *ctx ) +VG_STATIC void ui_release_clip(void) { - ctx->clipping[0] = -32000; - ctx->clipping[1] = -32000; - ctx->clipping[2] = 32000; - ctx->clipping[3] = 32000; + vg_uictx.clipping[0] = -32000; + vg_uictx.clipping[1] = -32000; + vg_uictx.clipping[2] = 32000; + vg_uictx.clipping[3] = 32000; } -static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, - u32 colour, ui_px uv[4] ) +static struct ui_vert *ui_fill_rect_uv( ui_rect rect, u32 colour, ui_px uv[4] ) { - struct ui_vert *vertices = &ctx->verts[ ctx->num_verts ]; + /* this if far from ideal but stops us from crashing */ + if( (vg_uictx.cur_vert + 6 > vg_uictx.max_verts) || + (vg_uictx.cur_indice + 4 > vg_uictx.max_indices)) + return vg_uictx.vertex_buffer; + + struct ui_vert *vertices = &vg_uictx.vertex_buffer[ vg_uictx.cur_vert ]; + u16 *indices = &vg_uictx.indice_buffer[ vg_uictx.cur_indice ]; + vertices[0].co[0] = rect[0]; vertices[0].co[1] = rect[1]; vertices[0].uv[0] = uv[0]; @@ -514,13 +519,12 @@ static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, vertices[3].uv[0] = uv[0]; vertices[3].uv[1] = uv[3]; vertices[3].colour = colour; - u16 ind_start = ctx->num_verts; - u16 *indices = &ctx->indices[ ctx->num_indices ]; + u16 ind_start = vg_uictx.cur_vert; - ui_rect_copy( ctx->clipping, vertices[0].clip ); - ui_rect_copy( ctx->clipping, vertices[1].clip ); - ui_rect_copy( ctx->clipping, vertices[2].clip ); - ui_rect_copy( ctx->clipping, vertices[3].clip ); + ui_rect_copy( vg_uictx.clipping, vertices[0].clip ); + ui_rect_copy( vg_uictx.clipping, vertices[1].clip ); + ui_rect_copy( vg_uictx.clipping, vertices[2].clip ); + ui_rect_copy( vg_uictx.clipping, vertices[3].clip ); indices[0] = ind_start+0; indices[1] = ind_start+2; @@ -530,15 +534,15 @@ static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, indices[4] = ind_start+3; indices[5] = ind_start+2; - ctx->num_indices += 6; - ctx->num_verts += 4; + vg_uictx.cur_indice += 6; + vg_uictx.cur_vert += 4; return vertices; } -static struct ui_vert *ui_fill_rect( ui_ctx *ctx, ui_rect rect, u32 colour ) +static struct ui_vert *ui_fill_rect( ui_rect rect, u32 colour ) { - return ui_fill_rect_uv( ctx, rect, colour, (ui_px[4]){ 4,4, 4,4 } ); + return ui_fill_rect_uv( rect, colour, (ui_px[4]){ 4,4, 4,4 } ); } static ui_px ui_text_line_offset( const char *str, ui_px scale, @@ -563,7 +567,7 @@ static ui_px ui_text_line_offset( const char *str, ui_px scale, return (-length * scale*8) / 2; } -static void ui_text( ui_ctx *ctx, ui_px pos[2], +VG_STATIC void ui_text( ui_px pos[2], const char *str, ui_px scale, enum ui_text_align align ) { ui_rect text_cursor; @@ -595,7 +599,7 @@ static void ui_text( ui_ctx *ctx, ui_px pos[2], glyph_base[0] *= 8; glyph_base[1] *= 8; - ui_fill_rect_uv( ctx, text_cursor, current_colour, (ui_px[4]) + ui_fill_rect_uv( text_cursor, current_colour, (ui_px[4]) { glyph_base[0]+2, glyph_base[1]+1, @@ -654,46 +658,49 @@ static void ui_text( ui_ctx *ctx, ui_px pos[2], /* * API Control */ -static void ui_begin( ui_ctx *ctx, ui_px res_x, ui_px res_y ) +VG_STATIC void ui_begin( ui_px res_x, ui_px res_y ) { - ctx->cursor[0] = 0; - ctx->cursor[1] = 0; - ctx->cursor[2] = res_x; - ctx->cursor[3] = res_y; + vg_uictx.cursor[0] = 0; + vg_uictx.cursor[1] = 0; + vg_uictx.cursor[2] = res_x; + vg_uictx.cursor[3] = res_y; - ui_rect_copy( ctx->cursor, ctx->stack[0].rect ); - ctx->stack[0].mouse_over = 1; + ui_rect_copy( vg_uictx.cursor, vg_uictx.stack[0].rect ); + vg_uictx.stack[0].mouse_over = 1; - ctx->stack_count = 1; + vg_uictx.stack_count = 1; - ctx->num_verts = 0; - ctx->num_indices = 0; + vg_uictx.cur_vert = 0; + vg_uictx.cur_indice = 0; - ui_release_clip( ctx ); + ui_release_clip(); - if( ctx->click_state == 0 ) - ctx->capture_mouse_id = 0; + if( vg_uictx.click_state == 0 ) + vg_uictx.capture_mouse_id = 0; - ctx->image_count = 0; + vg_uictx.image_count = 0; } -static void ui_resolve( ui_ctx *ctx ) +VG_STATIC void ui_resolve(void) { - if( ctx->stack_count-1 ) - vg_exiterr( "[UI] Mismatched node create/drestroy!" ); + if( vg_uictx.stack_count-1 ) + { + vg_error( "[UI] Mismatched node create/drestroy!" ); + return; + } - if( ctx->click_state == 3 || ctx->click_state == 0 ) + if( vg_uictx.click_state == 3 || vg_uictx.click_state == 0 ) { - ctx->capture_lock = 0; + vg_uictx.capture_lock = 0; } } -static void ui_set_mouse( ui_ctx *ctx, int x, int y, int click_state ) +VG_STATIC void ui_set_mouse( int x, int y, int click_state ) { - ctx->mouse[0] = x; - ctx->mouse[1] = y; + vg_uictx.mouse[0] = x; + vg_uictx.mouse[1] = y; - ctx->click_state = click_state; + vg_uictx.click_state = click_state; } /* @@ -716,85 +723,87 @@ enum button_state k_button_hold }; -static int ui_button( ui_ctx *ctx, u32 id ) +static int ui_button(void) { - ui_new_node( ctx ); + u32 uid = vg_uictx.control_id ++; + + ui_new_node(); { - ui_capture_mouse( ctx, id ); + ui_capture_mouse( uid ); - if( ui_hasmouse(ctx) ) + if( ui_hasmouse() ) { - ui_fill_rect( ctx, ctx->cursor, ctx->colours->hover ); + ui_fill_rect( vg_uictx.cursor, vg_uictx.colours->hover ); - if( ctx->click_state == 1 ) + if( vg_uictx.click_state == 1 ) { - ctx->capture_lock = 1; + vg_uictx.capture_lock = 1; return k_button_start_click; } - else if( ctx->capture_lock && ctx->click_state == 3 ) + else if( vg_uictx.capture_lock && vg_uictx.click_state == 3 ) return k_button_click; - else if( ctx->capture_lock && ctx->click_state == 2 ) + else if( vg_uictx.capture_lock && vg_uictx.click_state == 2 ) return k_button_hold; + + return k_button_click; } else - ui_fill_rect( ctx, ctx->cursor, ctx->colours->main ); + ui_fill_rect( vg_uictx.cursor, vg_uictx.colours->main ); } return k_button_released; } -static int ui_window( ui_ctx *ctx, struct ui_window *window, u32 control_group ) +static int ui_window( struct ui_window *window, u32 control_group ) { - ctx->id_base = control_group << 16; - if( window->drag ) { - window->transform[0] = ctx->mouse[0]+window->drag_offset[0]; - window->transform[1] = ctx->mouse[1]+window->drag_offset[1]; + window->transform[0] = vg_uictx.mouse[0]+window->drag_offset[0]; + window->transform[1] = vg_uictx.mouse[1]+window->drag_offset[1]; - ui_clamp_rect( ctx->stack[0].rect, window->transform ); + ui_clamp_rect( vg_uictx.stack[0].rect, window->transform ); - if( ctx->click_state == 0 || ctx->click_state == 3 ) + if( vg_uictx.click_state == 0 || vg_uictx.click_state == 3 ) { window->drag = 0; } } - ui_rect_copy( window->transform, ctx->cursor ); + ui_rect_copy( window->transform, vg_uictx.cursor ); - ui_new_node( ctx ); + ui_new_node(); { - ui_capture_mouse( ctx, __COUNTER__ ); + ui_capture_mouse( vg_uictx.control_id ++ ); /* Drag bar */ - ctx->cursor[3] = 25; - ui_new_node( ctx ); + vg_uictx.cursor[3] = 25; + ui_new_node(); { - ui_capture_mouse( ctx, __COUNTER__ ); + ui_capture_mouse( vg_uictx.control_id ++ ); - struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, 0xff555555 ); + struct ui_vert *drag_bar = ui_fill_rect( vg_uictx.cursor, 0xff555555 ); /* title.. */ - ctx->cursor[0] += 2; - ctx->cursor[1] += 2; - ui_text( ctx, ctx->cursor, window->title, 2, 0 ); + vg_uictx.cursor[0] += 2; + vg_uictx.cursor[1] += 2; + ui_text( vg_uictx.cursor, window->title, 2, 0 ); /* Close button */ - ctx->cursor[3] = 25; - ctx->cursor[2] = 25; - ui_align_right( ctx ); - ui_align_top( ctx ); - ui_rect_pad( ctx->cursor, 4 ); + vg_uictx.cursor[3] = 25; + vg_uictx.cursor[2] = 25; + ui_align_right(); + ui_align_top(); + ui_rect_pad( vg_uictx.cursor, 4 ); - if( ui_button( ctx, __COUNTER__ ) ) + if( ui_button() ) { vg_info( "Click clacked\n" ); } - ctx->cursor[0] += 2; - ui_text( ctx, ctx->cursor, "x", 2, 0 ); - ui_end( ctx ); + vg_uictx.cursor[0] += 2; + ui_text( vg_uictx.cursor, "x", 2, 0 ); + ui_end(); - if( ui_hasmouse( ctx ) ) + if( ui_hasmouse() ) { drag_bar[0].colour = 0xff777777; drag_bar[1].colour = 0xff777777; @@ -802,54 +811,108 @@ static int ui_window( ui_ctx *ctx, struct ui_window *window, u32 control_group ) drag_bar[3].colour = 0xff777777; /* start drag */ - if( ctx->click_state == 1 ) + if( vg_uictx.click_state == 1 ) { window->drag = 1; - window->drag_offset[0] = window->transform[0]-ctx->mouse[0]; - window->drag_offset[1] = window->transform[1]-ctx->mouse[1]; + window->drag_offset[0] = window->transform[0]-vg_uictx.mouse[0]; + window->drag_offset[1] = window->transform[1]-vg_uictx.mouse[1]; } } } - ui_end_down( ctx ); + ui_end_down(); } return 1; } -static void ui_push_image( ui_ctx *ctx, ui_rect rc, GLuint image ) +VG_STATIC void ui_push_image( ui_rect rc, GLuint image ) { - struct ui_image *img = &ctx->images[ ctx->image_count ++ ]; + struct ui_image *img = &vg_uictx.images[ vg_uictx.image_count ++ ]; ui_rect_copy( rc, img->rc ); img->image = image; } -/* Shortnames */ -#define gui_draw(...) ui_draw( &ui_global_ctx, __VA_ARGS__) -#define gui_current(...) ui_current( &ui_global_ctx, __VA_ARGS__) -#define gui_new_node() ui_new_node( &ui_global_ctx ) -#define gui_hasmouse(...) ui_hasmouse( &ui_global_ctx, __VA_ARGS__) -#define gui_end() ui_end( &ui_global_ctx ) -#define gui_end_down() ui_end_down( &ui_global_ctx ) -#define gui_end_right() ui_end_right( &ui_global_ctx ) -#define gui_fill_y() ui_fill_y( &ui_global_ctx) -#define gui_fill_x() ui_fill_x( &ui_global_ctx) -#define gui_align_bottom() ui_align_bottom( &ui_global_ctx ) -#define gui_align_right() ui_align_right( &ui_global_ctx ) -#define gui_align_top() ui_align_top( &ui_global_ctx ) -#define gui_align_left() ui_align_left( &ui_global_ctx ) -#define gui_clamp_rect(...) ui_clamp_rect( &ui_global_ctx, __VA_ARGS__) -#define gui_group_id(...) ui_group_id( &ui_global_ctx, __VA_ARGS__) -#define gui_capture_mouse(...) ui_capture_mouse( &ui_global_ctx, __VA_ARGS__) -#define gui_set_clip(...) ui_set_clip( &ui_global_ctx, __VA_ARGS__) -#define gui_release_clip() ui_release_clip( &ui_global_ctx ) -#define gui_fill_rect_uv(...) ui_fill_rect_uv( &ui_global_ctx, __VA_ARGS__) -#define gui_fill_rect(...) ui_fill_rect( &ui_global_ctx, __VA_ARGS__) -#define gui_text(...) ui_text( &ui_global_ctx, __VA_ARGS__) -#define gui_begin(...) ui_begin( &ui_global_ctx, __VA_ARGS__) -#define gui_resolve(...) ui_resolve( &ui_global_ctx, __VA_ARGS__) -#define gui_set_mouse(...) ui_set_mouse( &ui_global_ctx, __VA_ARGS__) -#define gui_button(...) ui_button( &ui_global_ctx, __VA_ARGS__) -#define gui_window(...) ui_window( &ui_global_ctx, __VA_ARGS__) -#define gui_want_mouse() ui_want_mouse( &ui_global_ctx ) -#define gui_push_image(...) ui_push_image( &ui_global_ctx, __VA_ARGS__ ) -#define gui_reset_colours(...) ui_reset_colours( &ui_global_ctx ) +struct ui_slider +{ + float *data; + float min, max; +}; + +struct ui_slider_vector +{ + float *data, min, max; + struct ui_slider sub[4]; + u32 len; +}; + +struct ui_checkbox +{ + int *data; +}; + +VG_STATIC void ui_slider( struct ui_slider *slider ) +{ + ui_new_node(); + + ui_px slider_start = vg_uictx.cursor[0]; + + float const ftotal = vg_uictx.cursor[2], + fwidth = ftotal*0.25f, + fmove = ftotal - fwidth, + fstart = fwidth*0.5f, + frange = slider->max-slider->min, + fpos = (*slider->data - slider->min) / frange; + + ui_fill_rect( vg_uictx.cursor, 0xff111111 ); + vg_uictx.cursor[2] = fwidth; + vg_uictx.cursor[0] = slider_start + fpos * fmove; + + u32 uid = vg_uictx.control_id ++; + int status = ui_button(); + if( vg_uictx.capture_lock && (vg_uictx.capture_mouse_id == uid)) + { + float ui_new = vg_uictx.mouse[0], + local = ui_new - (slider_start + fstart), + zo = vg_clampf(local / fmove,0.0f,1.0f); + + *slider->data = vg_lerpf( slider->min, slider->max, zo ); + } + + vg_uictx.cursor[0] += 4; + vg_uictx.cursor[1] += 4; + + char buf[12]; + snprintf( buf, 12, "%.2f", *slider->data ); + ui_text( vg_uictx.cursor, buf, 1, 0 ); + ui_end_down(); + ui_end_down(); +} + +VG_STATIC void ui_slider_vector( struct ui_slider_vector *slider ) +{ + for( int i=0; ilen; i++ ) + { + slider->sub[i].data = &slider->data[i]; + slider->sub[i].min = slider->min; + slider->sub[i].max = slider->max; + ui_slider( &slider->sub[i] ); + } +} + +VG_STATIC void ui_checkbox( struct ui_checkbox *cb ) +{ + if( ui_button() == k_button_click ) + *cb->data ^= 0x1; + + ui_new_node(); + ui_rect_pad( vg_uictx.cursor, 4 ); + if( *cb->data ) + ui_fill_rect( vg_uictx.cursor, 0xff00e052 ); + else + ui_fill_rect( vg_uictx.cursor, 0xff0052e0 ); + + ui_end(); + ui_end_down(); +} + +#endif /* VG_UI_H */