fix view not updating with rendered contents

main
Patrick Cleavelin 2024-04-16 16:14:14 -05:00
parent 0d8b0b738a
commit 2eaca7a4b9
5 changed files with 925 additions and 817 deletions

3
.clang-format Normal file
View File

@ -0,0 +1,3 @@
TabWidth: 4
IndentWidth: 4
UseTab: Never

103
src/gfx.h
View File

@ -16,6 +16,7 @@
bool keep_running = true;
@interface EDGFXView : NSView
@property NSTrackingArea *tracking_area;
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end
@ -58,6 +59,8 @@ typedef struct {
EDGFXView *view;
bool keep_running;
int mouse_x, mouse_y;
// Metal objects
id<MTLDevice> device;
CAMetalLayer *metal_layer;
@ -70,7 +73,7 @@ typedef struct {
} _metal_gfx_context;
#endif
typedef void (*_gfx_frame_func)();
typedef void (*_gfx_frame_func)(int mouse_x, int mouse_y);
typedef struct {
#if defined(__APPLE__)
_metal_gfx_context backend;
@ -152,8 +155,58 @@ void gfx_update_buffer(gfx_context_t *cx, size_t buffer_index, const void *data,
return NSViewLayerContentsRedrawOnSetNeedsDisplay;
}
- (void)insertText:(id)insertString {
NSLog(@"inserting text: %@", insertString);
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
NSRect rect = NSMakeRect(
0, 0,
_gfx_context.frame_width =
_gfx_context.backend.window.contentView.frame.size.width,
_gfx_context.frame_height =
_gfx_context.backend.window.contentView.frame.size.height);
self.tracking_area = [[NSTrackingArea alloc]
initWithRect:rect
options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
NSTrackingActiveInKeyWindow)
owner:self
userInfo:nil];
[self addTrackingArea:self.tracking_area];
return self;
}
- (void)mouseMoved:(NSEvent *)event {
// NSPoint location = NSEvent.mouseLocation;
NSPoint location = [self convertPoint:[event locationInWindow]
fromView:nil];
_gfx_context.backend.mouse_x = location.x;
_gfx_context.backend.mouse_y = location.y;
[self setNeedsDisplay:YES];
[self displayIfNeeded];
[_gfx_context.backend.metal_layer setNeedsDisplay];
[_gfx_context.backend.metal_layer displayIfNeeded];
}
- (void)updateTrackingAreas {
[self removeTrackingArea:self.tracking_area];
[self.tracking_area release];
NSRect rect = NSMakeRect(
0, 0,
_gfx_context.frame_width =
_gfx_context.backend.window.contentView.frame.size.width,
_gfx_context.frame_height =
_gfx_context.backend.window.contentView.frame.size.height);
self.tracking_area = [[NSTrackingArea alloc]
initWithRect:rect
options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
NSTrackingActiveInKeyWindow)
owner:self
userInfo:nil];
[self addTrackingArea:self.tracking_area];
}
@end
@ -168,9 +221,10 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width,
NSString *title = @"chat - [Slack Sux]";
NSRect rect = NSMakeRect(0, 0, width, height);
NSWindow *window = [[NSWindow alloc]
initWithContentRect:rect
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSWindow *window =
[[NSWindow alloc] initWithContentRect:rect
styleMask:NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskResizable
backing:NSBackingStoreBuffered
@ -267,8 +321,8 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width,
MTLBlendOperationAdd;
ui_rect_pipeline_descriptor.colorAttachments[0].sourceAlphaBlendFactor =
MTLBlendFactorSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].destinationAlphaBlendFactor =
MTLBlendFactorOneMinusSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0]
.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].sourceRGBBlendFactor =
MTLBlendFactorSourceAlpha;
ui_rect_pipeline_descriptor.colorAttachments[0].destinationRGBBlendFactor =
@ -288,9 +342,9 @@ static _metal_gfx_context _metal_gfx_init_context(uint32_t width,
exit(1);
}
pushArray(_MTLRenderPipelineState, &pipelines,
[device
newRenderPipelineStateWithDescriptor:ui_rect_pipeline_descriptor
pushArray(
_MTLRenderPipelineState, &pipelines,
[device newRenderPipelineStateWithDescriptor:ui_rect_pipeline_descriptor
error:&pipeline_error]);
array(_MTLBuffer) buffers = newArray(_MTLBuffer, 8);
@ -332,7 +386,8 @@ static void _metal_gfx_send_events(_metal_gfx_context *cx) {
static void _metal_gfx_present(_metal_gfx_context *cx) {
_gfx_context.gpu_glyphs.size = 0;
_gfx_context.gpu_ui_rects.size = 0;
_gfx_context.frame_func();
_gfx_context.frame_func(cx->mouse_x,
_gfx_context.frame_height - cx->mouse_y);
if (_gfx_context.gpu_glyphs.size > 0) {
gfx_update_buffer(&_gfx_context, 2, _gfx_context.gpu_glyphs.data,
@ -354,6 +409,7 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
gfx_update_buffer(&_gfx_context, 3, &gpu_uniform_params,
sizeof(GpuUniformParams));
@autoreleasepool {
id<CAMetalDrawable> drawable = [cx->metal_layer nextDrawable];
id<MTLCommandBuffer> command_buffer = [cx->command_queue commandBuffer];
@ -365,13 +421,14 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
MTLClearColorMake(0, 0, 0, 1);
render_pass_desc.colorAttachments[0].storeAction = MTLStoreActionStore;
id<MTLRenderCommandEncoder> encoder =
[command_buffer renderCommandEncoderWithDescriptor:render_pass_desc];
id<MTLRenderCommandEncoder> encoder = [command_buffer
renderCommandEncoderWithDescriptor:render_pass_desc];
if (_gfx_context.gpu_ui_rects.size > 0) {
// UI Rects
[encoder setRenderPipelineState:cx->pipelines.data[1]];
// FIXME: allow these to be described by the user instead of hardcoded
// FIXME: allow these to be described by the user instead of
// hardcoded
[encoder setVertexBuffer:cx->buffers.data[0]
offset:0
atIndex:0]; // vertices
@ -381,7 +438,6 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
[encoder setVertexBuffer:cx->buffers.data[3]
offset:0
atIndex:2]; // uniforms
// TODO: get instance count properly
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:6
indexType:MTLIndexTypeUInt16
@ -393,7 +449,8 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
if (_gfx_context.gpu_glyphs.size > 0) {
// UI Text
[encoder setRenderPipelineState:cx->pipelines.data[0]];
// FIXME: allow these to be described by the user instead of hardcoded
// FIXME: allow these to be described by the user instead of
// hardcoded
[encoder setVertexBuffer:cx->buffers.data[0]
offset:0
atIndex:0]; // vertices
@ -404,7 +461,6 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
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
@ -414,10 +470,12 @@ static void _metal_gfx_present(_metal_gfx_context *cx) {
}
[encoder endEncoding];
[command_buffer presentDrawable:drawable];
[command_buffer presentDrawable:drawable
afterMinimumDuration:1.0 / 144.0];
[command_buffer commit];
[command_buffer waitUntilScheduled];
}
}
static size_t _metal_gfx_push_texture_buffer(_metal_gfx_context *cx,
@ -496,7 +554,8 @@ void gfx_run_events(gfx_context_t *cx) {
size_t gfx_push_texture_buffer(gfx_context_t *cx, uint32_t width,
uint32_t height, const void *data, size_t len) {
#if defined(__APPLE__)
return _metal_gfx_push_texture_buffer(&cx->backend, width, height, data, len);
return _metal_gfx_push_texture_buffer(&cx->backend, width, height, data,
len);
#else
#error "Unsupported graphics backend"
#endif
@ -596,8 +655,8 @@ void *gfx_init_context(_gfx_frame_func frame_func, uint32_t width,
gfx_allocate_vertex_buffer(&_gfx_context, _gfx_context.gpu_glyphs.capacity *
sizeof(GpuGlyph));
gfx_allocate_vertex_buffer(&_gfx_context, sizeof(GpuUniformParams));
gfx_allocate_vertex_buffer(&_gfx_context, _gfx_context.gpu_ui_rects.capacity *
sizeof(GpuUiRect));
gfx_allocate_vertex_buffer(
&_gfx_context, _gfx_context.gpu_ui_rects.capacity * sizeof(GpuUiRect));
return &_gfx_context;
}

View File

@ -48,7 +48,8 @@ void ed_init(_gfx_frame_func frame_func) {
ttf_buffer));
stbtt_fontinfo font;
stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
stbtt_InitFont(&font, ttf_buffer,
stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
const int font_bitmap_size = 512;
const int rasterized_font_height = _FONT_HEIGHT;
@ -77,8 +78,8 @@ void ed_init(_gfx_frame_func frame_func) {
int y = 0;
for (size_t i = 33; i < 33 + 96; ++i) {
int width, height, xoff, yoff;
uint8_t *bitmap = stbtt_GetCodepointBitmap(&font, scale, scale, (int)i,
&width, &height, &xoff, &yoff);
uint8_t *bitmap = stbtt_GetCodepointBitmap(
&font, scale, scale, (int)i, &width, &height, &xoff, &yoff);
if (x + width >= font_bitmap_size) {
x = 0;
@ -89,7 +90,8 @@ void ed_init(_gfx_frame_func frame_func) {
for (size_t xx = 0; xx < (size_t)width; ++xx) {
size_t yyy = y;
for (size_t yy = 0; yy < (size_t)height; ++yy) {
font_bitmap[xxx + yyy * font_bitmap_size] = bitmap[xx + yy * width];
font_bitmap[xxx + yyy * font_bitmap_size] =
bitmap[xx + yy * width];
yyy += 1;
}
@ -120,16 +122,27 @@ void render_ui_rect(float position[2], float size[2], float color[4]) {
gfx_queue_ui_rect(state.gfx_cx, position, size, 0, color);
}
void ed_frame() {
void ed_frame(int mouse_x, int mouse_y) {
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;
uint8_t buffer[256] = {};
snprintf(buffer, 256, "Mouse X: %d, Mouse Y: %d, Mouse %s", mouse_x,
mouse_y, state.ui_cx.input.mouse_left_down ? "Down" : "Up");
render_ui_rect((float[2]){mouse_x, mouse_y}, (float[2]){32, 32},
(float[4]){1, 1, 1, 1});
ui_element(&state.ui_cx, _String("channel sidebar"), UI_AXIS_VERTICAL,
ui_make_size(ui_children_sum, ui_fill), UI_FLAG_DRAW_BACKGROUND);
ui_push_parent(&state.ui_cx);
{
ui_element(&state.ui_cx, _String(buffer), UI_AXIS_HORIZONTAL,
ui_make_size(ui_fit_text, ui_fit_text),
UI_FLAG_DRAW_BACKGROUND | UI_FLAG_DRAW_TEXT);
ui_element(&state.ui_cx, _String("#dev-general"), UI_AXIS_HORIZONTAL,
ui_make_size(ui_fit_text, ui_fit_text),
UI_FLAG_DRAW_BACKGROUND | UI_FLAG_DRAW_TEXT);
@ -144,6 +157,13 @@ void ed_frame() {
ui_update_cache(&state.ui_cx, 0);
ui_prune(&state.ui_cx);
ui_update_input(&state.ui_cx, (ui_context_input){
.mouse_x = mouse_x,
.mouse_y = mouse_y,
.mouse_left_down = false,
.mouse_right_down = false,
});
}
int main(int argc, char *argv[]) {

View File

@ -1,12 +1,13 @@
#ifndef ED_STRING_INCLUDED
#define ED_STRING_INCLUDED
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#define _String(text) ((string) { .data = (uint8_t*) text, .len = sizeof(text), .owned = false })
#define _String(text) \
((string){.data = (uint8_t *)text, .len = sizeof(text), .owned = false})
typedef struct {
uint8_t *data;
size_t len;
@ -14,13 +15,14 @@ typedef struct {
bool owned;
} string;
#ifdef ED_STRING_IMPLEMENTATION
bool string_eq(string a, string b) {
if (a.len != b.len) return false;
if (a.len != b.len)
return false;
for (size_t i=0; i<a.len; ++i) {
if (a.data[i] != b.data[i]) return false;
for (size_t i = 0; i < a.len; ++i) {
if (a.data[i] != b.data[i])
return false;
}
return true;

View File

@ -69,6 +69,12 @@ typedef struct {
uint32_t computed_pos[2];
} ui_size;
typedef struct {
bool hovering;
bool clicked;
bool dragging;
} ui_interaction;
// UI Element data persisted across frames
typedef struct {
string label;
@ -106,11 +112,22 @@ typedef struct {
} ui_element_frame_data;
arrayTemplate(ui_element_frame_data);
typedef struct {
bool mouse_left_down;
bool mouse_right_down;
uint32_t mouse_x;
uint32_t mouse_y;
} ui_context_input;
typedef struct {
ed_ht cached_elements;
array(ui_element_frame_data) frame_elements;
array(ui_element_frame_data) frame_floating_elements;
ui_context_input input;
ui_context_input last_input;
size_t frame_index;
uint32_t canvas_size[2];
@ -276,9 +293,9 @@ static void _ui_compute_children_layout(ui_context *cx,
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
// 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, 1};
num_fills[elm->size.axis] = 0;
@ -473,11 +490,13 @@ void ui_prune(ui_context *cx) {
if (cx->cached_elements.key_slots[i].key.data != NULL) {
string key = cx->cached_elements.key_slots[i].key;
// if this element hasn't been created in the past 5 frames, remove it
// if this element hasn't been created in the past 5 frames, remove
// it
ui_element_cache_data *cached = ht_get(&cx->cached_elements, key);
if (cached && cached->last_instantiated_index < cx->frame_index - 5) {
// fprintf(stderr, "removing %.*s from cache, cache index: %zu, frame
// index: %zu\n", (int)key.len, key.data,
if (cached &&
cached->last_instantiated_index < cx->frame_index - 5) {
// fprintf(stderr, "removing %.*s from cache, cache index: %zu,
// frame index: %zu\n", (int)key.len, key.data,
// cached->last_instantiated_index, cx->frame_index);
ht_remove(&cx->cached_elements, key);
@ -503,5 +522,10 @@ void ui_prune(ui_context *cx) {
cx->current_parent = 0;
}
void ui_update_input(ui_context *cx, ui_context_input new_input) {
cx->last_input = cx->input;
cx->input = new_input;
}
#endif
#endif