fixed bug in ui.h causing 0 height, got ui rects rendering heck yea
							parent
							
								
									6e0d5d58d2
								
							
						
					
					
						commit
						e941db978c
					
				| 
						 | 
				
			
			@ -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 ¶ms [[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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								src/gfx.h
								
								
								
								
							
							
						
						
									
										43
									
								
								src/gfx.h
								
								
								
								
							| 
						 | 
				
			
			@ -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];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										19
									
								
								src/main.c
								
								
								
								
							| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								src/ui.h
								
								
								
								
							
							
						
						
									
										27
									
								
								src/ui.h
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue