From 2ffbc3a65ecef381d45596acfceb91ecd8778c3c Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Wed, 20 Mar 2024 22:34:56 -0500 Subject: [PATCH] don't hardcode stuff with rendering (sorta), actually use ui flags --- shaders/text_atlas.metal | 2 +- src/gfx.h | 47 ++++++++++++++++++-------------- src/main.c | 42 ++++++++++++++++------------ src/ui.h | 59 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 107 insertions(+), 43 deletions(-) diff --git a/shaders/text_atlas.metal b/shaders/text_atlas.metal index 2f95b7d..382b3c5 100644 --- a/shaders/text_atlas.metal +++ b/shaders/text_atlas.metal @@ -126,7 +126,7 @@ fragment float4 ui_rect_fs(UiRectFragment in [[stage_in]]) float distance = rect_sdf(pixel_pos, in.position, in.size, in.border_size.x); if (distance <= 0.0) { - return float4(1,1,1,0.5); + return float4(0.2,0.2,0.2,1.0); } else { return float4(0); } diff --git a/src/gfx.h b/src/gfx.h index 4b4e971..c65d501 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -58,6 +58,9 @@ typedef struct { uint32_t frame_width; uint32_t frame_height; _gfx_frame_func frame_func; + + size_t num_glyphs; + size_t num_ui_rects; } gfx_context_t; static gfx_context_t _gfx_context; @@ -88,15 +91,13 @@ static void _metal_gfx_send_events(_metal_gfx_context *cx); } - (void)windowDidResize:(NSNotification *)notification { - NSLog(@"did resize\n"); - _gfx_context.frame_width = _gfx_context.backend.window.contentView.frame.size.width; _gfx_context.frame_height = _gfx_context.backend.window.contentView.frame.size.height; CGFloat scale = _gfx_context.backend.metal_layer.contentsScale; [_gfx_context.backend.metal_layer setDrawableSize:CGSizeMake(_gfx_context.frame_width * scale, _gfx_context.frame_height * scale)]; - _metal_gfx_present(&_gfx_context.backend); + _gfx_context.backend.view.needsDisplay = true; } @end @@ -276,24 +277,28 @@ void _metal_gfx_present(_metal_gfx_context *cx) { id encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_desc]; - // UI Text - [encoder setRenderPipelineState:cx->pipelines.data[0]]; - // FIXME: allow these to be described by the user instead of hardcoded - [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices - [encoder setVertexBuffer:cx->buffers.data[2] offset:0 atIndex:1]; // glyph data - [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms - [encoder setFragmentTexture:cx->textures.data[0] atIndex:0]; - // TODO: get instance count properly - [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:36]; + if (_gfx_context.num_ui_rects > 0) { + // UI Rects + [encoder setRenderPipelineState:cx->pipelines.data[1]]; + // FIXME: allow these to be described by the user instead of hardcoded + [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices + [encoder setVertexBuffer:cx->buffers.data[4] offset:0 atIndex:1]; // ui rects + [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms + // TODO: get instance count properly + [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:_gfx_context.num_ui_rects]; + } - // UI Rects - [encoder setRenderPipelineState:cx->pipelines.data[1]]; - // FIXME: allow these to be described by the user instead of hardcoded - [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices - [encoder setVertexBuffer:cx->buffers.data[4] offset:0 atIndex:1]; // ui rects - [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms - // TODO: get instance count properly - [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:3]; + if (_gfx_context.num_glyphs > 0) { + // UI Text + [encoder setRenderPipelineState:cx->pipelines.data[0]]; + // FIXME: allow these to be described by the user instead of hardcoded + [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices + [encoder setVertexBuffer:cx->buffers.data[2] offset:0 atIndex:1]; // glyph data + [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms + [encoder setFragmentTexture:cx->textures.data[0] atIndex:0]; + // TODO: get instance count properly + [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:_gfx_context.num_glyphs]; + } [encoder endEncoding]; [command_buffer presentDrawable:drawable]; @@ -355,6 +360,8 @@ void * gfx_init_context(_gfx_frame_func frame_func, uint32_t width, uint32_t hei _gfx_context.frame_func = frame_func; _gfx_context.frame_width = width; _gfx_context.frame_height = height; + _gfx_context.num_glyphs = 0; + _gfx_context.num_ui_rects = 0; return &_gfx_context; } diff --git a/src/main.c b/src/main.c index ef549e9..d1ac154 100644 --- a/src/main.c +++ b/src/main.c @@ -66,18 +66,18 @@ void queue_text(string text, float position[2]) { glyph.position[0] = x+position[0]; glyph.position[1] = position[1]; - x += glyph.size[0]/2; + x += glyph.size[0]/2+4; pushArray(GpuGlyph, &state.gpu_glyphs, glyph); } } } -void queue_ui_rect(uint32_t position[2], uint32_t size[2], uint32_t border_size) { +void queue_ui_rect(float position[2], float size[2], float border_size) { GpuUiRect rect = (GpuUiRect) { - .position = { (float)position[0], (float)position[1] }, - .size = { (float)size[0], (float)size[1] }, - .border_size = { (float)border_size, (float)border_size }, + .position = { position[0], position[1] }, + .size = { size[0], size[1] }, + .border_size = { border_size, border_size }, }; pushArray(GpuUiRect, &state.gpu_ui_rects, rect); @@ -178,36 +178,42 @@ void ed_init(_gfx_frame_func frame_func) { gfx_push_texture_buffer(state.gfx_cx, font_bitmap_size, font_bitmap_size, font_bitmap, font_bitmap_size*font_bitmap_size * sizeof(uint8_t)); } + +void render_ui_text(string text, float position[2]) { + queue_text(text, position); +} +void render_ui_rect(float position[2], float size[2]) { + queue_ui_rect(position, size, 0); +} + void ed_frame() { state.ui_cx.frame_elements.data[0].size.computed_size[0] = state.gfx_cx->frame_width; state.ui_cx.frame_elements.data[0].size.computed_size[1] = state.gfx_cx->frame_height; - ui_element(&state.ui_cx, _String("Number 1")); - ui_element(&state.ui_cx, _String("ui element 2")); - ui_element(&state.ui_cx, _String("ui element 3")); + ui_element(&state.ui_cx, _String("Number 1"), UI_AXIS_VERTICAL, ui_make_size(ui_fill, ui_fill), 0); + ui_push_parent(&state.ui_cx); + { + ui_element(&state.ui_cx, _String("ui element 2"), UI_AXIS_HORIZONTAL, ui_make_size(ui_fit_text, ui_fill), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); + ui_element(&state.ui_cx, _String("ui element 2"), UI_AXIS_HORIZONTAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); + } + ui_pop_parent(&state.ui_cx); + ui_element(&state.ui_cx, _String("Look I don't have to hardcode any values"), UI_AXIS_VERTICAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); ui_compute_layout(&state.ui_cx, 0); state.gpu_glyphs.size = 0; state.gpu_ui_rects.size = 0; - for (size_t i = 1; i < state.ui_cx.frame_elements.size; ++i) { - string text = state.ui_cx.frame_elements.data[i].key; - ui_element_frame_data *elm = &state.ui_cx.frame_elements.data[i]; - - queue_text(text, (float[]){ (float)elm->size.computed_pos[0], (float)elm->size.computed_pos[1] }); - - fprintf(stderr, "size[0]: %d, size[1]: %d\n", elm->size.computed_size[0], elm->size.computed_size[1]); - queue_ui_rect(elm->size.computed_pos, elm->size.computed_size, 16); - } + ui_render(&state.ui_cx, render_ui_text, render_ui_rect); ui_update_cache(&state.ui_cx, 0); ui_prune(&state.ui_cx); + state.gfx_cx->num_glyphs = state.gpu_glyphs.size; if (state.gpu_glyphs.size > 0) { gfx_update_buffer(state.gfx_cx, 2, state.gpu_glyphs.data, state.gpu_glyphs.size * sizeof(GpuGlyph)); - fprintf(stderr, "updated glyph buffer: %zu\n", state.gpu_glyphs.size); } + state.gfx_cx->num_ui_rects = state.gpu_ui_rects.size; if (state.gpu_ui_rects.size > 0) { gfx_update_buffer(state.gfx_cx, 4, state.gpu_ui_rects.data, state.gpu_ui_rects.size * sizeof(GpuUiRect)); } diff --git a/src/ui.h b/src/ui.h index 2c937ce..6e9fcd7 100644 --- a/src/ui.h +++ b/src/ui.h @@ -52,6 +52,13 @@ typedef struct { }; } ui_semantic_size; +#define ui_make_size(horizontal, vertical) ((ui_semantic_size[2]) { horizontal, vertical }) + +#define ui_fit_text ((ui_semantic_size) { .type = UI_SEMANTIC_SIZE_FIT_TEXT }) +#define ui_fill ((ui_semantic_size) { .type = UI_SEMANTIC_SIZE_FILL }) +#define ui_children_sum ((ui_semantic_size) { .type = UI_SEMANTIC_SIZE_CHILDREN_SUM }) +#define ui_exact(value) ((ui_semantic_size) { .type = UI_SEMANTIC_SIZE_EXACT, .integer = value }) + typedef struct { ui_axis axis; ui_semantic_size semantic_size[2]; @@ -142,7 +149,19 @@ ui_context ui_init_context() { }; } -size_t ui_element(ui_context *cx, string label) { +void ui_push_parent(ui_context *cx) { + if (cx->frame_elements.size > 0) { + cx->current_parent = cx->frame_elements.size-1; + } +} + +void ui_pop_parent(ui_context *cx) { + if (_parent(cx->current_parent) < SIZE_MAX) { + cx->current_parent = _parent(cx->current_parent); + } +} + +size_t ui_element(ui_context *cx, string label, ui_axis axis, ui_semantic_size size[2], ui_flags flags) { ui_element_frame_data frame_data = (ui_element_frame_data) { .index = cx->frame_elements.size, // TODO: don't just set this to label, because then elements @@ -154,8 +173,10 @@ size_t ui_element(ui_context *cx, string label) { .next = -1, .prev = cx->frame_elements.data[cx->current_parent].last, .parent = cx->current_parent, - .size.semantic_size[0].type = UI_SEMANTIC_SIZE_FILL, - .size.semantic_size[1].type = UI_SEMANTIC_SIZE_FIT_TEXT, + .size.axis = axis, + .size.semantic_size[0] = size[0], + .size.semantic_size[1] = size[1], + .flags = flags, }; // Get cached element data @@ -163,7 +184,11 @@ size_t ui_element(ui_context *cx, string label) { if (cache_data) { cache_data->last_instantiated_index = cx->frame_index; - frame_data.size = cache_data->size; + frame_data.size.computed_pos[0] = cache_data->size.computed_pos[0]; + frame_data.size.computed_pos[1] = cache_data->size.computed_pos[1]; + + frame_data.size.computed_size[0] = cache_data->size.computed_size[0]; + frame_data.size.computed_size[1] = cache_data->size.computed_size[1]; } else { assert("couldn't insert into ui element cache" && ht_set(&cx->cached_elements, label, &(ui_element_cache_data) { .label = label, @@ -386,6 +411,32 @@ void ui_update_cache(ui_context *cx, size_t element_index) { } } +typedef void (*_ui_render_text_func)(string text, float position[2]); +typedef void (*_ui_render_rect_func)(float position[2], float size[2]); +void ui_render(ui_context *cx, _ui_render_text_func text_func, _ui_render_rect_func rect_func) { + for (size_t i = 1; i < cx->frame_elements.size; ++i) { + string text = cx->frame_elements.data[i].key; + ui_element_frame_data *elm = &cx->frame_elements.data[i]; + + if (_flags(i, UI_FLAG_DRAW_TEXT)) { + text_func(text, (float[]){ (float)elm->size.computed_pos[0], (float)elm->size.computed_pos[1] }); + } + + if (_flags(i, UI_FLAG_DRAW_BACKGROUND)) { + rect_func( + (float[]){ + (float)elm->size.computed_pos[0], + (float)elm->size.computed_pos[1] + }, + (float[]){ + (float)elm->size.computed_size[0], + (float)elm->size.computed_size[1] + } + ); + } + } +} + void ui_prune(ui_context *cx) { for (size_t i = 0; i < cx->cached_elements.capacity; ++i) { if (cx->cached_elements.key_slots[i].key.data != NULL) {