typedef i16 ui_px;
typedef ui_px ui_rect[4];
+typedef ui_px ui_point[2];
typedef struct ui_vert ui_vert;
enum ui_axis {
void (*enter)( char *, u32 ),
(*up)( char *, u32 ),
(*down)( char *, u32 ),
- (*change)( char *, u32 );
+ (*change)( char *, u32 ),
+ (*escape)( void );
}
callbacks;
}
}
modal;
- GLuint tex_glyphs, vao, vbo, ebo;
+ GLuint tex_glyphs, vao, vbo, ebo, tex_bg;
+ v2f bg_inverse_ratio;
ui_px mouse[2], mouse_click[2];
u32 mouse_state[2];
ui_rect click_fader, click_fader_end;
float click_fade_opacity;
+ f32 frosting;
ui_scheme scheme;
const ui_font *font;
cursor;
SDL_Cursor *cursor_map[ k_ui_cursor_max ];
+ v4f colour;
}
static vg_ui = {
.scheme = {
[ k_ui_purple + k_ui_brighter ] = UI_RGB( 0xd3869b ),
[ k_ui_gray + k_ui_brighter ] = UI_RGB( 0xa89984 ),
},
- .font = &vg_ui_font_small
+ .font = &vg_ui_font_small,
+ .colour = {1.0f,1.0f,1.0f,1.0f},
+ .bg_inverse_ratio = {1,1}
};
-static struct vg_shader _shader_ui =
-{
- .name = "[vg] ui",
+static struct vg_shader _shader_ui ={
+ .name = "[vg] ui - transparent",
.link = NULL,
- .vs =
- {
+ .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;"
+ "uniform vec2 uBGInverseRatio;"
""
- "out vec2 aTexCoords;"
+ "out vec4 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;" /* TODO: Uniform */
+ "void main(){"
+ "vec4 proj_pos = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );"
+ "gl_Position = proj_pos;"
+ "aTexCoords = vec4( a_uv * 0.00390625, "
+ " (proj_pos.xy*0.5+0.5) * uBGInverseRatio );"
"aColour = a_colour;"
-
- "aWsp = a_co;"
"}",
},
- .fs =
- {
+ .fs = {
.orig_file = NULL,
.static_src =
- "uniform sampler2D uTexGlyphs;"
+ "uniform sampler2D uTexGlyphs;"
+ "uniform sampler2D uTexBG;"
+ "uniform vec4 uColour;"
+ "uniform float uSpread;"
"out vec4 FragColor;"
""
- "in vec2 aTexCoords;"
+ "in vec4 aTexCoords;"
"in vec4 aColour;"
""
- "in vec2 aWsp;"
-
+ "vec2 rand_hash22( vec2 p ){"
+ "vec3 p3 = fract(vec3(p.xyx) * 213.8976123);"
+ "p3 += dot(p3, p3.yzx+19.19);"
+ "return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));"
+ "}"
""
- "void main()"
- "{"
+ "void main(){"
"vec4 diffuse = aColour;"
- "if( diffuse.a == 0.0 )"
- "{"
- "diffuse.a = texture( uTexGlyphs, aTexCoords ).r;"
+ "vec4 avg = vec4(0.0);"
+
+ "if( aColour.a == 0.0 ){"
+ "avg = aColour;"
+ "avg.a = texture( uTexGlyphs, aTexCoords.xy ).r;"
"}"
-
- "FragColor = diffuse;"
+ "else{"
+ "if( uSpread > 0.0001 ){"
+ "for( int i=0; i<4; i ++ ){"
+ "vec2 spread = rand_hash22(aTexCoords.zw+vec2(float(i)));"
+ "avg += texture( uTexBG, aTexCoords.zw + (spread-0.5)*uSpread );"
+ "}"
+ "avg *= 0.25;"
+ "avg.a = 1.0;"
+ "avg.rgb = mix( avg.rgb, aColour.rgb, aColour.a );"
+ "}"
+ "else{"
+ "avg = aColour;"
+ "}"
+ "}"
+
+ "FragColor = avg * uColour;"
"}"
}
};
.orig_file = NULL,
.static_src =
"uniform sampler2D uTexImage;"
+ "uniform vec4 uColour;"
"out vec4 FragColor;"
"in vec2 aTexCoords;"
"void main()"
"{"
"vec4 colour = texture( uTexImage, aTexCoords );"
- "FragColor = colour;"
+ "FragColor = colour * uColour;"
"}"
}
};
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_fatal_error( "Failed to compile ui shader" );
+ }
/*
* Vertex buffer
b[i] = a[i];
}
-static void ui_flush( enum ui_shader shader ){
+static void ui_flush( enum ui_shader shader, f32 w, f32 h ){
u32 vertex_offset = vg_ui.vert_start*sizeof(ui_vert),
vertex_count = vg_ui.cur_vert-vg_ui.vert_start,
vertex_size = vertex_count*sizeof(ui_vert),
m3x3f view = M3X3_IDENTITY;
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/(w*0.5f),
+ -1.0f/(h*0.5f), 1.0f } );
if( shader == k_ui_shader_colour ){
glUseProgram( _shader_ui.id );
glUniformMatrix3fv( glGetUniformLocation( _shader_ui.id, "uPv" ), 1,
GL_FALSE, (float *)view );
+ glUniform4fv( glGetUniformLocation( _shader_ui.id, "uColour" ), 1,
+ vg_ui.colour );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, vg_ui.tex_glyphs );
glUniform1i( glGetUniformLocation( _shader_ui.id, "uTexGlyphs" ), 0 );
+
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_2D, vg_ui.tex_bg );
+ glUniform1i( glGetUniformLocation( _shader_ui.id, "uTexBG" ), 1 );
+ glUniform1f( glGetUniformLocation( _shader_ui.id, "uSpread" ),
+ vg_ui.frosting );
+ glUniform2fv( glGetUniformLocation( _shader_ui.id, "uBGInverseRatio" ),
+ 1, vg_ui.bg_inverse_ratio );
}
else if( shader == k_ui_shader_image ){
glUseProgram( _shader_ui_image.id );
glUniformMatrix3fv( glGetUniformLocation( _shader_ui_image.id, "uPv" ), 1,
GL_FALSE, (float *)view );
glUniform1i( glGetUniformLocation(_shader_ui_image.id,"uTexImage"), 0 );
+ glUniform4fv( glGetUniformLocation( _shader_ui_image.id, "uColour" ), 1,
+ vg_ui.colour );
}
else
vg_fatal_error( "Invalid UI shader (%d)\n", shader );
out_texcoords[3] = out_texcoords[1] + font->glyph_height;
}
+static u32 ui_opacity( u32 colour, f32 opacity ){
+ u32 alpha = opacity * 255.0f;
+ return (colour & 0x00ffffff) | (alpha << 24);
+}
+
static u32 ui_ntext( ui_rect rect, const char *str, u32 len, ui_px scale,
enum ui_align align, u32 colour ){
ui_rect text_cursor;
}
static void ui_image( ui_rect rect, GLuint image ){
- ui_flush( k_ui_shader_colour );
+ ui_flush( k_ui_shader_colour, vg.window_x, vg.window_y );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, image );
ui_fill_rect( rect, 0xffffffff, (ui_px[4]){ 0,256,256,0 } );
- ui_flush( k_ui_shader_image );
+ ui_flush( k_ui_shader_image, vg.window_x, vg.window_y );
}
static u32 v4f_u32_colour( v4f colour ){
static void ui_defocus_all(void){
if( vg_ui.focused_control_type == k_ui_control_textbox ){
SDL_StopTextInput();
+ if( vg_ui.textbox.callbacks.escape )
+ vg_ui.textbox.callbacks.escape();
}
vg_ui.focused_control_id = NULL;
vg_ui.wants_mouse = 1;
}
- ui_flush( k_ui_shader_colour );
+ ui_flush( k_ui_shader_colour, vg.window_x, vg.window_y );
if( !vg_ui.focused_control_hit ){
ui_defocus_all();
static void _ui_textbox_enter(void){
if( vg_ui.focused_control_type == k_ui_control_textbox ){
+ vg_ui.ignore_input_frames = 2;
+
if( vg_ui.textbox.callbacks.enter )
vg_ui.textbox.callbacks.enter( vg_ui.textbuf, vg_ui.textbox.len );