fixed bug in ui.h causing 0 height, got ui rects rendering heck yea

main
Patrick Cleavelin 2024-03-20 19:50:01 -05:00
parent 6e0d5d58d2
commit e941db978c
4 changed files with 136 additions and 19 deletions

View File

@ -65,3 +65,69 @@ fragment float4 fs_main(VertexOutput in [[stage_in]],
return float4(text_color * float3(1,1,1), text_color);
}
struct UiRect {
float2 position;
float2 size;
float2 border_size;
};
struct UiRectFragment {
float4 device_position [[position]];
float2 position;
float2 size;
float2 border_size;
float2 screen_size;
float2 tex_coord;
};
vertex UiRectFragment
ui_rect_vs(
uint vertex_id [[vertex_id]],
uint rect_id [[instance_id]],
constant VertexInput *vertices [[buffer(0)]],
constant UiRect *rects [[buffer(1)]],
constant UniformParams &params [[buffer(2)]]
)
{
UiRect rect = rects[rect_id];
return UiRectFragment {
float4(vertices[vertex_id].position, 1, 1),
rect.position,
rect.size,
rect.border_size,
params.screen_size,
vertices[vertex_id].tex_coord,
};
}
float rect_sdf(
float2 absolute_pixel_position,
float2 origin,
float2 size,
float corner_radius
) {
float2 half_size = size / 2;
float2 rect_center = origin + half_size;
float2 pixel_position = abs(absolute_pixel_position - rect_center);
float2 shrunk_corner_position = half_size - corner_radius;
float2 pixel_to_shrunk_corner = max(float2(0), pixel_position - shrunk_corner_position);
float distance_to_shrunk_corner = length(pixel_to_shrunk_corner);
float distance = distance_to_shrunk_corner - corner_radius;
return distance;
}
fragment float4 ui_rect_fs(UiRectFragment in [[stage_in]])
{
float2 pixel_pos = in.tex_coord.xy * in.screen_size;
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);
} else {
return float4(0);
}
}

View File

@ -170,7 +170,6 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width, uint32_t heigh
[view.layer addSublayer:metal_layer];
view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
NSError *libraryError = NULL;
NSURL *libraryURL = [[NSBundle mainBundle] URLForResource:@"./shaders" withExtension:@"metallib"];
if (libraryURL == NULL) {
@ -191,6 +190,8 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width, uint32_t heigh
id<MTLCommandQueue> command_queue = [device newCommandQueue];
id<MTLFunction> vertex_func = [library newFunctionWithName:@"vs_main"];
id<MTLFunction> fragment_func = [library newFunctionWithName:@"fs_main"];
id<MTLFunction> ui_rect_vertex_func = [library newFunctionWithName:@"ui_rect_vs"];
id<MTLFunction> ui_rect_fragment_func = [library newFunctionWithName:@"ui_rect_fs"];
MTLRenderPipelineDescriptor *pipeline_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
[pipeline_descriptor setVertexFunction:vertex_func];
@ -203,9 +204,28 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width, uint32_t heigh
pipeline_descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipeline_descriptor.colorAttachments[0].blendingEnabled = true;
MTLRenderPipelineDescriptor *ui_rect_pipeline_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
[ui_rect_pipeline_descriptor setVertexFunction:ui_rect_vertex_func];
[ui_rect_pipeline_descriptor setFragmentFunction:ui_rect_fragment_func];
ui_rect_pipeline_descriptor.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
ui_rect_pipeline_descriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
ui_rect_pipeline_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].blendingEnabled = true;
NSError *pipeline_error = NULL;
array(_MTLRenderPipelineState) pipelines = newArray(_MTLRenderPipelineState, 2);
pushArray(_MTLRenderPipelineState, &pipelines, [device newRenderPipelineStateWithDescriptor:pipeline_descriptor error:&pipeline_error]);
if (pipeline_error != NULL) {
if (pipeline_error.description != NULL) {
NSLog(@"Error description: %@\n", pipeline_error.description);
}
exit(1);
}
pushArray(_MTLRenderPipelineState, &pipelines, [device newRenderPipelineStateWithDescriptor:ui_rect_pipeline_descriptor error:&pipeline_error]);
array(_MTLBuffer) buffers = newArray(_MTLBuffer, 8);
array(_MTLTexture) textures = newArray(_MTLTexture, 8);
@ -255,16 +275,27 @@ void _metal_gfx_present(_metal_gfx_context *cx) {
render_pass_desc.colorAttachments[0].storeAction = MTLStoreActionStore;
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];
[encoder setVertexBuffer:cx->buffers.data[2] offset:0 atIndex:1];
[encoder setVertexBuffer:cx->buffers.data[3] offset:0 atIndex:2];
[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];
[encoder endEncoding];
// 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];
[encoder endEncoding];
[command_buffer presentDrawable:drawable];
[command_buffer commit];

View File

@ -73,6 +73,16 @@ void queue_text(string text, float position[2]) {
}
}
void queue_ui_rect(uint32_t position[2], uint32_t size[2], uint32_t 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 },
};
pushArray(GpuUiRect, &state.gpu_ui_rects, rect);
}
void ed_init(_gfx_frame_func frame_func) {
state.gfx_cx = gfx_init_context(frame_func, 640, 480);
state.ui_cx = ui_init_context();
@ -96,6 +106,7 @@ void ed_init(_gfx_frame_func frame_func) {
gfx_allocate_vertex_buffer(state.gfx_cx, state.gpu_glyphs.capacity * sizeof(GpuGlyph));
gfx_allocate_vertex_buffer(state.gfx_cx, sizeof(GpuUniformParams));
gfx_allocate_vertex_buffer(state.gfx_cx, state.gpu_ui_rects.capacity * sizeof(GpuUiRect));
uint8_t ttf_buffer[1<<20];
// TODO: grab default font from the system
@ -178,11 +189,15 @@ void ed_frame() {
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_update_cache(&state.ui_cx, 0);
@ -193,6 +208,10 @@ void ed_frame() {
fprintf(stderr, "updated glyph buffer: %zu\n", state.gpu_glyphs.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));
}
GpuUniformParams gpu_uniform_params = {
.screen_size = {
(float)state.gfx_cx->frame_width,

View File

@ -155,7 +155,7 @@ size_t ui_element(ui_context *cx, string label) {
.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_FILL,
.size.semantic_size[1].type = UI_SEMANTIC_SIZE_FIT_TEXT,
};
// Get cached element data
@ -210,7 +210,7 @@ static void _ui_compute_simple_layout(ui_context *cx, ui_element_frame_data *elm
if (axis == UI_AXIS_HORIZONTAL) {
elm->size.computed_size[axis] = elm->label.len * _FONT_WIDTH;
} else if (axis == UI_AXIS_VERTICAL) {
elm->size.computed_size[axis] = _FONT_WIDTH;
elm->size.computed_size[axis] = _FONT_HEIGHT;
}
break;
@ -236,13 +236,13 @@ static void _ui_compute_simple_layout(ui_context *cx, ui_element_frame_data *elm
}
static void _ui_compute_children_layout(ui_context *cx, ui_element_frame_data *elm) {
uint32_t child_size[2] = { 0 };
uint32_t child_size[2] = { 0, 0 };
// NOTE: the number of fills for the opposite axis of this box needs to be 1
// because it will never get incremented in the loop below and cause a divide by zero
// and the number of fills for the axis of the box needs to start at zero or else it will
// be n+1 causing incorrect sizes
uint32_t num_fills[2] = { 1 };
uint32_t num_fills[2] = { 1, 1 };
num_fills[elm->size.axis] = 0;
// TODO: maybe just use the actual data instead of copying?
@ -302,7 +302,9 @@ void ui_compute_layout(ui_context *cx, size_t element_index) {
bool post_compute[2] = { false, false };
// only compute layout for children of root
if (elm->index > 0) {
_ui_compute_simple_layout(cx, elm, axis, post_compute);
for (int i=0; i<2; ++i) {
_ui_compute_simple_layout(cx, elm, i, post_compute);
}
}
_ui_compute_children_layout(cx, elm);
@ -382,14 +384,6 @@ void ui_update_cache(ui_context *cx, size_t element_index) {
ui_update_cache(cx, child_index);
} while ((child_index = _next(child_index)) < SIZE_MAX);
}
cx->frame_elements.size = 1;
cx->frame_elements.data[0].first = SIZE_MAX;
cx->frame_elements.data[0].prev = SIZE_MAX;
cx->frame_elements.data[0].next = SIZE_MAX;
cx->frame_elements.data[0].last = SIZE_MAX;
cx->frame_elements.data[0].parent = SIZE_MAX;
cx->current_parent = 0;
}
void ui_prune(ui_context *cx) {
@ -408,6 +402,13 @@ void ui_prune(ui_context *cx) {
}
cx->frame_index += 1;
cx->frame_elements.size = 1;
cx->frame_elements.data[0].first = SIZE_MAX;
cx->frame_elements.data[0].prev = SIZE_MAX;
cx->frame_elements.data[0].next = SIZE_MAX;
cx->frame_elements.data[0].last = SIZE_MAX;
cx->frame_elements.data[0].parent = SIZE_MAX;
cx->current_parent = 0;
}
#endif