1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
10 #include "vg/vg_shader.h"
12 static struct vg_shader _shader_ui
=
20 "layout (location=0) in vec2 a_co;"
21 "layout (location=1) in vec2 a_uv;"
22 "layout (location=2) in vec4 a_colour;"
23 "layout (location=3) in vec4 a_clip;"
26 "out vec2 aTexCoords;"
33 "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );"
34 "aTexCoords = a_uv * 0.0078125;"
45 "uniform sampler2D uTexGlyphs;"
56 "float clip_blend = step( aWsp.x, aClip.z ) *"
57 "step( aWsp.y, aClip.w ) *"
58 "step( aClip.x, aWsp.x ) *"
59 "step( aClip.y, aWsp.y ); "
61 "vec4 glyph = vec4(1.0,1.0,1.0,1.0);"
63 "if( aColour.a == 0.0 )"
65 "glyph = texture( uTexGlyphs, aTexCoords );"
66 "glyph.a = smoothstep( 0.47, 0.53, glyph.r );"
70 "glyph.a = aColour.a;"
73 "FragColor = vec4( aColour.rgb, glyph.a*clip_blend );"
78 static struct vg_shader _shader_ui_image
=
80 .name
= "[vg] ui_image",
86 "layout (location=0) in vec2 a_co;"
87 "layout (location=1) in vec2 a_uv;"
88 "layout (location=2) in vec4 a_colour;"
89 "layout (location=3) in vec4 a_clip;"
92 "out vec2 aTexCoords;"
99 "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );"
100 "aTexCoords = a_uv * 0.0078125;"
101 "aColour = a_colour;"
111 "uniform sampler2D uTexImage;"
112 "out vec4 FragColor;"
114 "in vec2 aTexCoords;"
122 "float clip_blend = step( aWsp.x, aClip.z ) *"
123 "step( aWsp.y, aClip.w ) *"
124 "step( aClip.x, aWsp.x ) *"
125 "step( aClip.y, aWsp.y ); "
127 "vec4 colour = texture( uTexImage, aTexCoords );"
128 "float value = dot(vec4(1.0),colour)*0.25;"
130 "vec3 col = vec3(pow(cos(value*3.14159265*2.0)*0.5+0.5,0.5))"
131 "* vec3(step(value,0.5),0.3,step(1.0-value,0.5));"
133 "FragColor = vec4( col*4.0, clip_blend );"
139 typedef u32 ui_colour
;
140 typedef ui_px ui_rect
[4];
141 typedef struct ui_colourset ui_colourset
;
143 /* Relative to cursor p0 */
146 k_text_align_left
= 0,
147 k_text_align_right
= 1,
148 k_text_align_center
= 2
163 ui_colour background
;
193 struct ui_vert
*vertex_buffer
;
195 u32 max_verts
, max_indices
, cur_vert
, cur_indice
;
200 u32 capture_mouse_id
;
205 int click_state
; /* 0: released, 1: on down, 2: pressed, 3: on release */
207 ui_colourset
*colours
;
223 #define UI_GLYPH_SPACING_X 8
225 static GLuint ui_glyph_texture
= 0;
226 static ui_colourset ui_default_colours
= {
232 VG_STATIC
void _vg_ui_init(void)
234 if( !vg_shader_compile( &_shader_ui
) ||
235 !vg_shader_compile( &_shader_ui_image
) )
236 vg_fatal_error( "Failed to compile ui shader" );
240 * ----------------------------------------
243 vg_uictx
.max_indices
= 20000;
244 vg_uictx
.max_verts
= 30000;
245 vg_uictx
.colours
= &ui_default_colours
;
247 /* Generate the buffer we are gonna be drawing to */
248 glGenVertexArrays( 1, &vg_uictx
.vao
);
249 glGenBuffers( 1, &vg_uictx
.vbo
);
250 glGenBuffers( 1, &vg_uictx
.ebo
);
252 glBindVertexArray( vg_uictx
.vao
);
253 glBindBuffer( GL_ARRAY_BUFFER
, vg_uictx
.vbo
);
255 glBufferData( GL_ARRAY_BUFFER
,
256 vg_uictx
.max_verts
* sizeof( struct ui_vert
),
257 NULL
, GL_DYNAMIC_DRAW
);
258 glBindVertexArray( vg_uictx
.vao
);
260 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, vg_uictx
.ebo
);
261 glBufferData( GL_ELEMENT_ARRAY_BUFFER
,
262 vg_uictx
.max_indices
* sizeof( u16
), NULL
, GL_DYNAMIC_DRAW
);
267 u32
const stride
= sizeof( struct ui_vert
);
270 glVertexAttribPointer( 0, 2, GL_SHORT
, GL_FALSE
,
271 stride
, (void *)offsetof( struct ui_vert
, co
) );
272 glEnableVertexAttribArray( 0 );
275 glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE
, GL_FALSE
,
276 stride
, (void *)offsetof( struct ui_vert
, uv
) );
277 glEnableVertexAttribArray( 1 );
280 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE
, GL_TRUE
, stride
,
281 (void *)offsetof( struct ui_vert
, colour
) );
282 glEnableVertexAttribArray( 2 );
285 glVertexAttribPointer( 3, 4, GL_SHORT
, GL_FALSE
, stride
,
286 (void *)offsetof( struct ui_vert
, clip
) );
287 glEnableVertexAttribArray( 3 );
291 /* Alloc RAM default context */
292 u32 vert_size
= vg_uictx
.max_verts
*sizeof(struct ui_vert
),
293 inds_size
= vg_align8( vg_uictx
.max_indices
*sizeof(u16
) );
295 vg_uictx
.vertex_buffer
= vg_linear_alloc( vg_mem
.rtmemory
, vert_size
);
296 vg_uictx
.indice_buffer
= vg_linear_alloc( vg_mem
.rtmemory
, inds_size
);
299 * -----------------------------------------------------
302 /* Load default font */
304 #include "vg/vg_pxfont_thin.h"
307 u32 pixels
= 0, total
= 256*256, data
= 0;
310 while( pixels
< total
){
311 for( int b
= 31; b
>= 0; b
-- ){
312 image
[ pixels
++ ] = (compressed
[data
] & (0x1u
<< b
))? 0xffu
: 0x00u
;
314 if( pixels
>= total
){
322 glGenTextures( 1, &ui_glyph_texture
);
323 glBindTexture( GL_TEXTURE_2D
, ui_glyph_texture
);
324 glTexImage2D( GL_TEXTURE_2D
, 0, GL_R8
, 256, 256, 0,
325 GL_RED
, GL_UNSIGNED_BYTE
, image
);
328 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
329 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
330 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
331 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
334 static struct ui_vert
*ui_fill_rect_uv( ui_rect rect
, u32 colour
, ui_px uv
[4] );
336 VG_STATIC
void ui_draw( m3x3f view_override
)
338 u32 num_indices_normal
= vg_uictx
.cur_indice
;
340 /* Append images to back of buffer */
341 for( int i
= 0; i
< vg_uictx
.image_count
; i
++ )
343 ui_fill_rect_uv( vg_uictx
.images
[i
].rc
, 0xffffffff,
344 (ui_px
[4]){0,0,128,128} );
347 glBindVertexArray( vg_uictx
.vao
);
349 glBindBuffer( GL_ARRAY_BUFFER
, vg_uictx
.vbo
);
350 glBufferSubData( GL_ARRAY_BUFFER
, 0,
351 vg_uictx
.cur_vert
* sizeof( struct ui_vert
),
352 vg_uictx
.vertex_buffer
);
354 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, vg_uictx
.ebo
);
355 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER
, 0,
356 vg_uictx
.cur_indice
* sizeof( u16
),
357 vg_uictx
.indice_buffer
);
360 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
361 glBlendEquation(GL_FUNC_ADD
);
363 glUseProgram( _shader_ui
.id
);
365 m3x3f view
= M3X3_IDENTITY
;
369 view_override
= view
;
371 m3x3_translate( view
, (v3f
){ -1.0f
, 1.0f
, 0.0f
} );
372 m3x3_scale( view
, (v3f
){ 1.0f
/((float)vg
.window_x
*0.5f
),
373 -1.0f
/((float)vg
.window_y
*0.5f
), 1.0f
} );
377 glUniformMatrix3fv( glGetUniformLocation( _shader_ui
.id
, "uPv" ), 1,
378 GL_FALSE
, (float *)view_override
);
380 glActiveTexture( GL_TEXTURE0
);
381 glBindTexture( GL_TEXTURE_2D
, ui_glyph_texture
);
382 glUniform1i( glGetUniformLocation( _shader_ui
.id
, "uTexGlyphs" ), 0 );
384 glDrawElements( GL_TRIANGLES
, num_indices_normal
,
385 GL_UNSIGNED_SHORT
, (void*)(0) );
389 glUseProgram( _shader_ui_image
.id
);
390 glUniformMatrix3fv( glGetUniformLocation( _shader_ui_image
.id
, "uPv" ), 1,
391 GL_FALSE
, (float *)view_override
);
393 glActiveTexture( GL_TEXTURE1
);
394 glUniform1i( glGetUniformLocation( _shader_ui_image
.id
, "uTexImage" ), 1 );
396 /* Draw image elements */
397 for( int i
= 0; i
< vg_uictx
.image_count
; i
++ )
399 struct ui_image
*img
= &vg_uictx
.images
[i
];
401 glBindTexture( GL_TEXTURE_2D
, img
->image
);
402 glDrawElements( GL_TRIANGLES
, 6, GL_UNSIGNED_SHORT
,
403 (void*)( (num_indices_normal
+ 6*i
)*sizeof(u16
) ) );
412 VG_STATIC
void ui_rect_copy( ui_rect src
, ui_rect dst
)
420 VG_STATIC
void ui_rect_pad( ui_rect rect
, ui_px pad
)
431 static struct ui_qnode
*ui_current(void)
433 return &vg_uictx
.stack
[ vg_uictx
.stack_count
-1 ];
436 VG_STATIC
void ui_new_node(void)
438 if( vg_uictx
.stack_count
== vg_list_size( vg_uictx
.stack
) )
440 vg_error( "[UI] Stack overflow while creating box!" );
444 struct ui_qnode
*parent
= &vg_uictx
.stack
[ vg_uictx
.stack_count
-1 ];
445 struct ui_qnode
*node
= &vg_uictx
.stack
[ vg_uictx
.stack_count
++ ];
446 ui_rect_copy( vg_uictx
.cursor
, node
->rect
);
448 if( parent
->mouse_over
)
450 if( vg_uictx
.mouse
[0] >= node
->rect
[0] &&
451 vg_uictx
.mouse
[0] < node
->rect
[0]+node
->rect
[2] &&
452 vg_uictx
.mouse
[1] >= node
->rect
[1] &&
453 vg_uictx
.mouse
[1] < node
->rect
[1]+node
->rect
[3] )
454 node
->mouse_over
= 1;
456 node
->mouse_over
= 0;
460 node
->mouse_over
= 0;
464 static int ui_hasmouse(void)
466 struct ui_qnode
*node
= ui_current();
467 return (node
->mouse_over
&& (node
->capture_id
== vg_uictx
.capture_mouse_id
));
470 VG_STATIC
void ui_end(void)
472 struct ui_qnode
*node
= &vg_uictx
.stack
[ --vg_uictx
.stack_count
];
473 ui_rect_copy( node
->rect
, vg_uictx
.cursor
);
476 VG_STATIC
void ui_end_down(void)
478 ui_px height
= ui_current()->rect
[3];
480 vg_uictx
.cursor
[1] += height
;
483 VG_STATIC
void ui_end_right(void)
485 ui_px width
= ui_current()->rect
[2];
487 vg_uictx
.cursor
[0] += width
;
490 VG_STATIC
void ui_fill_y(void)
492 struct ui_qnode
*node
= ui_current();
493 vg_uictx
.cursor
[3] = node
->rect
[3] - (vg_uictx
.cursor
[1]-node
->rect
[1]);
496 VG_STATIC
void ui_fill_x(void)
498 struct ui_qnode
*node
= ui_current();
499 vg_uictx
.cursor
[2] = node
->rect
[2] - (vg_uictx
.cursor
[0]-node
->rect
[0]);
502 VG_STATIC
void ui_align_bottom(void)
504 struct ui_qnode
*node
= ui_current();
505 vg_uictx
.cursor
[1] = node
->rect
[1] + node
->rect
[3] - vg_uictx
.cursor
[3];
508 VG_STATIC
void ui_align_right(void)
510 struct ui_qnode
*node
= ui_current();
511 vg_uictx
.cursor
[0] = node
->rect
[0] + node
->rect
[2] - vg_uictx
.cursor
[2];
514 VG_STATIC
void ui_align_top(void)
516 vg_uictx
.cursor
[1] = ui_current()->rect
[1];
519 VG_STATIC
void ui_align_left(void)
521 vg_uictx
.cursor
[0] = ui_current()->rect
[0];
524 VG_STATIC
void ui_clamp_rect( ui_rect parent
, ui_rect dest
)
526 dest
[0] = vg_min( parent
[0] + parent
[2] - dest
[2], dest
[0] );
527 dest
[1] = vg_min( parent
[1] + parent
[3] - dest
[3], dest
[1] );
528 dest
[0] = vg_max( parent
[0], dest
[0] );
529 dest
[1] = vg_max( parent
[1], dest
[1] );
532 VG_STATIC
void ui_capture_mouse( u32 id
)
534 struct ui_qnode
*node
= &vg_uictx
.stack
[ vg_uictx
.stack_count
-1 ];
535 node
->capture_id
= id
;
537 if( !vg_uictx
.capture_lock
&& node
->mouse_over
)
539 vg_uictx
.capture_mouse_id
= id
;
543 static int ui_want_mouse(void)
545 return vg_uictx
.capture_mouse_id
== 0? 0: 1;
548 VG_STATIC
void ui_set_clip( ui_rect clip
)
550 vg_uictx
.clipping
[0] = clip
[0];
551 vg_uictx
.clipping
[1] = clip
[1];
552 vg_uictx
.clipping
[2] = clip
[0] + clip
[2];
553 vg_uictx
.clipping
[3] = clip
[1] + clip
[3];
556 VG_STATIC
void ui_release_clip(void)
558 vg_uictx
.clipping
[0] = -32000;
559 vg_uictx
.clipping
[1] = -32000;
560 vg_uictx
.clipping
[2] = 32000;
561 vg_uictx
.clipping
[3] = 32000;
564 static struct ui_vert
*ui_fill_rect_uv( ui_rect rect
, u32 colour
, ui_px uv
[4] )
566 /* this if far from ideal but stops us from crashing */
567 if( (vg_uictx
.cur_vert
+ 6 > vg_uictx
.max_verts
) ||
568 (vg_uictx
.cur_indice
+ 4 > vg_uictx
.max_indices
))
569 return vg_uictx
.vertex_buffer
;
571 struct ui_vert
*vertices
= &vg_uictx
.vertex_buffer
[ vg_uictx
.cur_vert
];
572 u16
*indices
= &vg_uictx
.indice_buffer
[ vg_uictx
.cur_indice
];
574 vertices
[0].co
[0] = rect
[0];
575 vertices
[0].co
[1] = rect
[1];
576 vertices
[0].uv
[0] = uv
[0];
577 vertices
[0].uv
[1] = uv
[1];
578 vertices
[0].colour
= colour
;
579 vertices
[1].co
[0] = rect
[0]+rect
[2];
580 vertices
[1].co
[1] = rect
[1];
581 vertices
[1].uv
[0] = uv
[2];
582 vertices
[1].uv
[1] = uv
[1];
583 vertices
[1].colour
= colour
;
584 vertices
[2].co
[0] = rect
[0]+rect
[2];
585 vertices
[2].co
[1] = rect
[1]+rect
[3];
586 vertices
[2].uv
[0] = uv
[2];
587 vertices
[2].uv
[1] = uv
[3];
588 vertices
[2].colour
= colour
;
589 vertices
[3].co
[0] = rect
[0];
590 vertices
[3].co
[1] = rect
[1]+rect
[3];
591 vertices
[3].uv
[0] = uv
[0];
592 vertices
[3].uv
[1] = uv
[3];
593 vertices
[3].colour
= colour
;
594 u16 ind_start
= vg_uictx
.cur_vert
;
596 ui_rect_copy( vg_uictx
.clipping
, vertices
[0].clip
);
597 ui_rect_copy( vg_uictx
.clipping
, vertices
[1].clip
);
598 ui_rect_copy( vg_uictx
.clipping
, vertices
[2].clip
);
599 ui_rect_copy( vg_uictx
.clipping
, vertices
[3].clip
);
601 indices
[0] = ind_start
+0;
602 indices
[1] = ind_start
+2;
603 indices
[2] = ind_start
+1;
605 indices
[3] = ind_start
+0;
606 indices
[4] = ind_start
+3;
607 indices
[5] = ind_start
+2;
609 vg_uictx
.cur_indice
+= 6;
610 vg_uictx
.cur_vert
+= 4;
615 static struct ui_vert
*ui_fill_rect( ui_rect rect
, u32 colour
)
617 return ui_fill_rect_uv( rect
, colour
, (ui_px
[4]){ 4,4, 4,4 } );
620 static ui_px
ui_text_line_offset( const char *str
, ui_px scale
,
621 enum ui_text_align align
)
623 if( align
== k_text_align_left
)
627 const char *_c
= str
;
630 while( (c
= *(_c
++)) )
631 if( c
>= 32 && c
<= 126 )
636 if( align
== k_text_align_right
)
637 return -length
* scale
*8;
639 return (-length
* scale
*8) / 2;
642 VG_STATIC
void ui_text( ui_px pos
[2],
643 const char *str
, ui_px scale
, enum ui_text_align align
)
646 u32 current_colour
= 0x00ffffff;
648 const char *_c
= str
;
651 text_cursor
[0] = pos
[0] + ui_text_line_offset( str
, scale
, align
);
652 text_cursor
[1] = pos
[1];
653 text_cursor
[2] = 8*scale
;
654 text_cursor
[3] = 14*scale
;
656 while( (c
= *(_c
++)) ){
658 text_cursor
[1] += 14*scale
;
659 text_cursor
[0] = pos
[0] + ui_text_line_offset( _c
, scale
, align
);
665 glyph_base
[0] = glyph_index
& 0xf;
666 glyph_base
[1] = (glyph_index
-glyph_base
[0])>>4;
671 ui_fill_rect_uv( text_cursor
, current_colour
, (ui_px
[4])
679 else if( c
== '\x1B' ){
682 for( int i
= 0; i
< 3; i
++ ){
688 case '0': current_colour
= 0x00ffffff; break;
689 case '3'|'1'<<8: current_colour
= 0x00201fee; break;
690 case '3'|'2'<<8: current_colour
= 0x0037e420; break;
691 case '3'|'3'<<8: current_colour
= 0x000ed8e2; break;
692 case '3'|'4'<<8: current_colour
= 0x00f15010; break;
693 case '3'|'5'<<8: current_colour
= 0x00ee20ee; break;
694 case '3'|'6'<<8: current_colour
= 0x00eeee20; break;
695 case '3'|'7'<<8: current_colour
= 0x00ffffff; break;
701 colour_id
|= _c
[i
] << (i
*8);
711 else if( c
== '\t' ){
712 text_cursor
[0] += UI_GLYPH_SPACING_X
*scale
*4;
716 text_cursor
[0] += UI_GLYPH_SPACING_X
*scale
;
723 VG_STATIC
void ui_begin( ui_px res_x
, ui_px res_y
)
725 vg_uictx
.cursor
[0] = 0;
726 vg_uictx
.cursor
[1] = 0;
727 vg_uictx
.cursor
[2] = res_x
;
728 vg_uictx
.cursor
[3] = res_y
;
730 ui_rect_copy( vg_uictx
.cursor
, vg_uictx
.stack
[0].rect
);
731 vg_uictx
.stack
[0].mouse_over
= 1;
733 vg_uictx
.stack_count
= 1;
735 vg_uictx
.cur_vert
= 0;
736 vg_uictx
.cur_indice
= 0;
740 if( vg_uictx
.click_state
== 0 )
741 vg_uictx
.capture_mouse_id
= 0;
743 vg_uictx
.image_count
= 0;
746 VG_STATIC
void ui_resolve(void)
748 if( vg_uictx
.stack_count
-1 )
750 vg_error( "[UI] Mismatched node create/drestroy!" );
754 if( vg_uictx
.click_state
== 3 || vg_uictx
.click_state
== 0 )
756 vg_uictx
.capture_lock
= 0;
760 VG_STATIC
void ui_set_mouse( int x
, int y
, int click_state
)
762 vg_uictx
.mouse
[0] = x
;
763 vg_uictx
.mouse
[1] = y
;
765 vg_uictx
.click_state
= click_state
;
769 * High level controls
777 ui_px drag_offset
[2];
782 k_button_released
= 0,
783 k_button_start_click
,
788 static int ui_button(void)
790 u32 uid
= vg_uictx
.control_id
++;
794 ui_capture_mouse( uid
);
798 ui_fill_rect( vg_uictx
.cursor
, vg_uictx
.colours
->hover
);
800 if( vg_uictx
.click_state
== 1 )
802 vg_uictx
.capture_lock
= 1;
803 return k_button_start_click
;
805 else if( vg_uictx
.capture_lock
&& vg_uictx
.click_state
== 3 )
806 return k_button_click
;
807 else if( vg_uictx
.capture_lock
&& vg_uictx
.click_state
== 2 )
808 return k_button_hold
;
810 return k_button_click
;
813 ui_fill_rect( vg_uictx
.cursor
, vg_uictx
.colours
->main
);
816 return k_button_released
;
819 static int ui_window( struct ui_window
*window
, u32 control_group
)
823 window
->transform
[0] = vg_uictx
.mouse
[0]+window
->drag_offset
[0];
824 window
->transform
[1] = vg_uictx
.mouse
[1]+window
->drag_offset
[1];
826 ui_clamp_rect( vg_uictx
.stack
[0].rect
, window
->transform
);
828 if( vg_uictx
.click_state
== 0 || vg_uictx
.click_state
== 3 )
834 ui_rect_copy( window
->transform
, vg_uictx
.cursor
);
838 ui_capture_mouse( vg_uictx
.control_id
++ );
841 vg_uictx
.cursor
[3] = 25;
844 ui_capture_mouse( vg_uictx
.control_id
++ );
846 struct ui_vert
*drag_bar
= ui_fill_rect( vg_uictx
.cursor
, 0xff555555 );
849 vg_uictx
.cursor
[0] += 2;
850 vg_uictx
.cursor
[1] += 2;
851 ui_text( vg_uictx
.cursor
, window
->title
, 2, 0 );
854 vg_uictx
.cursor
[3] = 25;
855 vg_uictx
.cursor
[2] = 25;
858 ui_rect_pad( vg_uictx
.cursor
, 4 );
862 vg_info( "Click clacked\n" );
864 vg_uictx
.cursor
[0] += 2;
865 ui_text( vg_uictx
.cursor
, "x", 2, 0 );
870 drag_bar
[0].colour
= 0xff777777;
871 drag_bar
[1].colour
= 0xff777777;
872 drag_bar
[2].colour
= 0xff777777;
873 drag_bar
[3].colour
= 0xff777777;
876 if( vg_uictx
.click_state
== 1 )
879 window
->drag_offset
[0] = window
->transform
[0]-vg_uictx
.mouse
[0];
880 window
->drag_offset
[1] = window
->transform
[1]-vg_uictx
.mouse
[1];
890 VG_STATIC
void ui_push_image( ui_rect rc
, GLuint image
)
892 struct ui_image
*img
= &vg_uictx
.images
[ vg_uictx
.image_count
++ ];
893 ui_rect_copy( rc
, img
->rc
);
903 struct ui_slider_vector
905 float *data
, min
, max
;
906 struct ui_slider sub
[4];
915 VG_STATIC
void ui_slider( struct ui_slider
*slider
)
919 ui_px slider_start
= vg_uictx
.cursor
[0];
921 float const ftotal
= vg_uictx
.cursor
[2],
922 fwidth
= ftotal
*0.25f
,
923 fmove
= ftotal
- fwidth
,
924 fstart
= fwidth
*0.5f
,
925 frange
= slider
->max
-slider
->min
,
926 fpos
= (*slider
->data
- slider
->min
) / frange
;
928 ui_fill_rect( vg_uictx
.cursor
, 0xff111111 );
929 vg_uictx
.cursor
[2] = fwidth
;
930 vg_uictx
.cursor
[0] = slider_start
+ fpos
* fmove
;
932 u32 uid
= vg_uictx
.control_id
++;
933 int status
= ui_button();
934 if( vg_uictx
.capture_lock
&& (vg_uictx
.capture_mouse_id
== uid
))
936 float ui_new
= vg_uictx
.mouse
[0],
937 local
= ui_new
- (slider_start
+ fstart
),
938 zo
= vg_clampf(local
/ fmove
,0.0f
,1.0f
);
940 *slider
->data
= vg_lerpf( slider
->min
, slider
->max
, zo
);
943 vg_uictx
.cursor
[0] += 4;
944 vg_uictx
.cursor
[1] += 4;
947 snprintf( buf
, 12, "%.2f", *slider
->data
);
948 ui_text( vg_uictx
.cursor
, buf
, 1, 0 );
953 VG_STATIC
void ui_slider_vector( struct ui_slider_vector
*slider
)
955 for( int i
=0; i
<slider
->len
; i
++ )
957 slider
->sub
[i
].data
= &slider
->data
[i
];
958 slider
->sub
[i
].min
= slider
->min
;
959 slider
->sub
[i
].max
= slider
->max
;
960 ui_slider( &slider
->sub
[i
] );
964 VG_STATIC
void ui_checkbox( struct ui_checkbox
*cb
)
966 if( ui_button() == k_button_click
)
970 ui_rect_pad( vg_uictx
.cursor
, 4 );
972 ui_fill_rect( vg_uictx
.cursor
, 0xff00e052 );
974 ui_fill_rect( vg_uictx
.cursor
, 0xff0052e0 );