#include #include #include #include #include #include #define STB_TRUETYPE_IMPLEMENTATION #include #define ED_GFX_IMPLEMENTATION #define ED_STRING_IMPLEMENTATION #define ED_HT_IMPLEMENTATION #define ED_UI_IMPLEMENTATION #define ED_BUFFER_IMPLEMENTATION #define ED_FILE_IO_IMPLEMENTATION #define CHAT_SLACK_IMPLEMENTATION #include "ed_array.h" #include "file_io.h" #include "gfx.h" #include "ht.h" #include "slack_api.h" #include "string.h" #include "ui.h" // static Arena default_arena = {0}; // static Arena temporary_arena = {0}; // static Arena *context_arena = &default_arena; void *context_alloc(size_t size) { // assert(context_arena); // return arena_alloc(context_arena, size); return malloc(size); } static struct { bool should_exit; bool show_thing; ui_context ui_cx; gfx_context_t *gfx_cx; } state; void init(_gfx_frame_func frame_func) { state.gfx_cx = gfx_init_context(frame_func, 640, 480); state.ui_cx = ui_init_context(); // TODO: grab default font from the system uint8_t ttf_buffer[1 << 20]; assert("failed to load font" && load_file(_String("./bin/JetBrainsMono-Medium.ttf"), 1 << 20, ttf_buffer)); stbtt_fontinfo font; stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0)); const int font_bitmap_size = 512; const int rasterized_font_height = _FONT_HEIGHT; uint8_t *font_bitmap = context_alloc(font_bitmap_size * font_bitmap_size * sizeof(uint8_t)); int ascent, descent, line_gap; float scale = stbtt_ScaleForPixelHeight(&font, rasterized_font_height * 2); stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); for (size_t xx = 0; xx < rasterized_font_height / 2; ++xx) { for (size_t yy = 0; yy < rasterized_font_height; ++yy) { font_bitmap[xx + yy * font_bitmap_size] = 0; } } // manually add glyph for SPACE pushArray(GpuGlyph, &state.gfx_cx->glyph_cache, ((GpuGlyph){ .atlas_position = {0}, .size = {rasterized_font_height / 4, 1}, .position = {0}, .y_offset = -rasterized_font_height, })); int x = rasterized_font_height / 4; 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); if (x + width >= font_bitmap_size) { x = 0; y += (int)((float)(ascent - descent + line_gap) * scale); } size_t xxx = x; 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]; yyy += 1; } xxx += 1; } pushArray(GpuGlyph, &state.gfx_cx->glyph_cache, ((GpuGlyph){ .atlas_position = {(float)(x), (float)(y)}, .size = {(float)width, (float)height}, .position = {(float)x, (float)y}, .y_offset = (float)(yoff), })); x += width; } 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]) { gfx_queue_text(state.gfx_cx, text, position); } 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(int mouse_x, int mouse_y, bool mouse_left_down, bool mouse_right_down) { 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, mouse_left_down ? "Down" : "Up"); ui_update_input(&state.ui_cx, (ui_context_input){ .mouse_x = mouse_x, .mouse_y = mouse_y, .mouse_left_down = mouse_left_down, .mouse_right_down = mouse_right_down, }); 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); if (ui_button(&state.ui_cx, _String("#dev-general")).clicked) { printf("you clicked the dev-general button\n"); state.show_thing = !state.show_thing; } if (ui_button(&state.ui_cx, _String("#dev-help")).clicked) { printf("you clicked the dev-help button\n"); } if (state.show_thing) { ui_interaction interaction = _ui_test_interaction( &state.ui_cx, ui_element(&state.ui_cx, _String("thread list"), UI_AXIS_VERTICAL, ui_make_size(ui_children_sum, ui_children_sum), UI_FLAG_DRAW_BACKGROUND)); ui_push_parent(&state.ui_cx); ui_element(&state.ui_cx, _String("List of Threads"), UI_AXIS_VERTICAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_BACKGROUND | UI_FLAG_DRAW_TEXT | UI_FLAG_HOVERABLE); if (interaction.hovering) { if (ui_button(&state.ui_cx, _String("Thread 1")).clicked) { printf("thread 1\n"); } if (ui_button(&state.ui_cx, _String("Thread 2")).clicked) { printf("thread 2\n"); } if (ui_button(&state.ui_cx, _String("Thread 3")).clicked) { printf("thread 3\n"); } if (ui_button(&state.ui_cx, _String("Thread 4")).clicked) { printf("thread 4\n"); } } ui_pop_parent(&state.ui_cx); } } ui_pop_parent(&state.ui_cx); ui_compute_layout(&state.ui_cx, 0); ui_render(&state.ui_cx, render_ui_text, render_ui_rect); ui_update_cache(&state.ui_cx, 0); ui_prune(&state.ui_cx); } int main(int argc, char *argv[]) { /* curl_global_init(CURL_GLOBAL_ALL); slack_client client = slack_init_client(_String("test token"), _String("Cookie: test_cookie=hello")); _slack_debug_print_auth_test(&client, _String("test token"), _String("Cookie: test_cookie=hello")); curl_global_cleanup(); return 0; */ init(ed_frame); while (keep_running) { gfx_run_events(state.gfx_cx); } }