don't hardcode stuff with rendering (sorta), actually use ui flags

main
Patrick Cleavelin 2024-03-20 22:34:56 -05:00
parent e941db978c
commit 2ffbc3a65e
4 changed files with 107 additions and 43 deletions

View File

@ -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); float distance = rect_sdf(pixel_pos, in.position, in.size, in.border_size.x);
if (distance <= 0.0) { if (distance <= 0.0) {
return float4(1,1,1,0.5); return float4(0.2,0.2,0.2,1.0);
} else { } else {
return float4(0); return float4(0);
} }

View File

@ -58,6 +58,9 @@ typedef struct {
uint32_t frame_width; uint32_t frame_width;
uint32_t frame_height; uint32_t frame_height;
_gfx_frame_func frame_func; _gfx_frame_func frame_func;
size_t num_glyphs;
size_t num_ui_rects;
} gfx_context_t; } gfx_context_t;
static gfx_context_t _gfx_context; static gfx_context_t _gfx_context;
@ -88,15 +91,13 @@ static void _metal_gfx_send_events(_metal_gfx_context *cx);
} }
- (void)windowDidResize:(NSNotification *)notification { - (void)windowDidResize:(NSNotification *)notification {
NSLog(@"did resize\n");
_gfx_context.frame_width = _gfx_context.backend.window.contentView.frame.size.width; _gfx_context.frame_width = _gfx_context.backend.window.contentView.frame.size.width;
_gfx_context.frame_height = _gfx_context.backend.window.contentView.frame.size.height; _gfx_context.frame_height = _gfx_context.backend.window.contentView.frame.size.height;
CGFloat scale = _gfx_context.backend.metal_layer.contentsScale; 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)]; [_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 @end
@ -276,24 +277,28 @@ void _metal_gfx_present(_metal_gfx_context *cx) {
id<MTLRenderCommandEncoder> encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_desc]; id<MTLRenderCommandEncoder> encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_desc];
// UI Text if (_gfx_context.num_ui_rects > 0) {
[encoder setRenderPipelineState:cx->pipelines.data[0]]; // UI Rects
// FIXME: allow these to be described by the user instead of hardcoded [encoder setRenderPipelineState:cx->pipelines.data[1]];
[encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices // FIXME: allow these to be described by the user instead of hardcoded
[encoder setVertexBuffer:cx->buffers.data[2] offset:0 atIndex:1]; // glyph data [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices
[encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms [encoder setVertexBuffer:cx->buffers.data[4] offset:0 atIndex:1]; // ui rects
[encoder setFragmentTexture:cx->textures.data[0] atIndex:0]; [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms
// TODO: get instance count properly // TODO: get instance count properly
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:36]; [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:_gfx_context.num_ui_rects];
}
// UI Rects if (_gfx_context.num_glyphs > 0) {
[encoder setRenderPipelineState:cx->pipelines.data[1]]; // UI Text
// FIXME: allow these to be described by the user instead of hardcoded [encoder setRenderPipelineState:cx->pipelines.data[0]];
[encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices // FIXME: allow these to be described by the user instead of hardcoded
[encoder setVertexBuffer:cx->buffers.data[4] offset:0 atIndex:1]; // ui rects [encoder setVertexBuffer:cx->buffers.data[0] offset:0 atIndex:0]; // vertices
[encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms [encoder setVertexBuffer:cx->buffers.data[2] offset:0 atIndex:1]; // glyph data
// TODO: get instance count properly [encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2]; // uniforms
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:6 indexType:MTLIndexTypeUInt16 indexBuffer:cx->buffers.data[1] indexBufferOffset:0 instanceCount:3]; [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]; [encoder endEncoding];
[command_buffer presentDrawable:drawable]; [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_func = frame_func;
_gfx_context.frame_width = width; _gfx_context.frame_width = width;
_gfx_context.frame_height = height; _gfx_context.frame_height = height;
_gfx_context.num_glyphs = 0;
_gfx_context.num_ui_rects = 0;
return &_gfx_context; return &_gfx_context;
} }

View File

@ -66,18 +66,18 @@ void queue_text(string text, float position[2]) {
glyph.position[0] = x+position[0]; glyph.position[0] = x+position[0];
glyph.position[1] = position[1]; glyph.position[1] = position[1];
x += glyph.size[0]/2; x += glyph.size[0]/2+4;
pushArray(GpuGlyph, &state.gpu_glyphs, glyph); 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) { GpuUiRect rect = (GpuUiRect) {
.position = { (float)position[0], (float)position[1] }, .position = { position[0], position[1] },
.size = { (float)size[0], (float)size[1] }, .size = { size[0], size[1] },
.border_size = { (float)border_size, (float)border_size }, .border_size = { border_size, border_size },
}; };
pushArray(GpuUiRect, &state.gpu_ui_rects, rect); 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)); 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() { 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[0] = state.gfx_cx->frame_width;
state.ui_cx.frame_elements.data[0].size.computed_size[1] = state.gfx_cx->frame_height; 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("Number 1"), UI_AXIS_VERTICAL, ui_make_size(ui_fill, ui_fill), 0);
ui_element(&state.ui_cx, _String("ui element 2")); ui_push_parent(&state.ui_cx);
ui_element(&state.ui_cx, _String("ui element 3")); {
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); ui_compute_layout(&state.ui_cx, 0);
state.gpu_glyphs.size = 0; state.gpu_glyphs.size = 0;
state.gpu_ui_rects.size = 0; state.gpu_ui_rects.size = 0;
for (size_t i = 1; i < state.ui_cx.frame_elements.size; ++i) { ui_render(&state.ui_cx, render_ui_text, render_ui_rect);
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_update_cache(&state.ui_cx, 0); ui_update_cache(&state.ui_cx, 0);
ui_prune(&state.ui_cx); ui_prune(&state.ui_cx);
state.gfx_cx->num_glyphs = state.gpu_glyphs.size;
if (state.gpu_glyphs.size > 0) { if (state.gpu_glyphs.size > 0) {
gfx_update_buffer(state.gfx_cx, 2, state.gpu_glyphs.data, state.gpu_glyphs.size * sizeof(GpuGlyph)); 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) { 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)); gfx_update_buffer(state.gfx_cx, 4, state.gpu_ui_rects.data, state.gpu_ui_rects.size * sizeof(GpuUiRect));
} }

View File

@ -52,6 +52,13 @@ typedef struct {
}; };
} ui_semantic_size; } 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 { typedef struct {
ui_axis axis; ui_axis axis;
ui_semantic_size semantic_size[2]; 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) { ui_element_frame_data frame_data = (ui_element_frame_data) {
.index = cx->frame_elements.size, .index = cx->frame_elements.size,
// TODO: don't just set this to label, because then elements // 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, .next = -1,
.prev = cx->frame_elements.data[cx->current_parent].last, .prev = cx->frame_elements.data[cx->current_parent].last,
.parent = cx->current_parent, .parent = cx->current_parent,
.size.semantic_size[0].type = UI_SEMANTIC_SIZE_FILL, .size.axis = axis,
.size.semantic_size[1].type = UI_SEMANTIC_SIZE_FIT_TEXT, .size.semantic_size[0] = size[0],
.size.semantic_size[1] = size[1],
.flags = flags,
}; };
// Get cached element data // Get cached element data
@ -163,7 +184,11 @@ size_t ui_element(ui_context *cx, string label) {
if (cache_data) { if (cache_data) {
cache_data->last_instantiated_index = cx->frame_index; 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 { } else {
assert("couldn't insert into ui element cache" && ht_set(&cx->cached_elements, label, &(ui_element_cache_data) { assert("couldn't insert into ui element cache" && ht_set(&cx->cached_elements, label, &(ui_element_cache_data) {
.label = label, .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) { void ui_prune(ui_context *cx) {
for (size_t i = 0; i < cx->cached_elements.capacity; ++i) { for (size_t i = 0; i < cx->cached_elements.capacity; ++i) {
if (cx->cached_elements.key_slots[i].key.data != NULL) { if (cx->cached_elements.key_slots[i].key.data != NULL) {