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);
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);
}

View File

@ -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<MTLRenderCommandEncoder> 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;
}

View File

@ -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));
}

View File

@ -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) {