From ff46b21e1175e3edb51cca90ffb4320260a65eb5 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Sun, 17 Nov 2024 19:27:42 -0700 Subject: [PATCH] Seperate engine and app logic, and moved editor to different build target/source file --- .gitignore | 1 + client/Makefile | 18 +- client/include/engine.h | 87 ++ client/include/ui.h | 8 +- client/src/editor.c | 1203 ++++++++++++++++++++++++++++ client/src/engine.c | 432 ++++++++++ client/src/main.c | 1655 +-------------------------------------- 7 files changed, 1742 insertions(+), 1662 deletions(-) create mode 100644 client/include/engine.h create mode 100644 client/src/editor.c create mode 100644 client/src/engine.c diff --git a/.gitignore b/.gitignore index 154d693..f642358 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ compile_commands.json *.dSYM roleplay +editor .cache diff --git a/client/Makefile b/client/Makefile index 29ea8db..e6c802f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -2,10 +2,13 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) CFLAGS = -I $(ROOT_DIR)/include -I/usr/local/include -O0 -g -Wall -Wextra LDFLAGS = -lfreetype -lz -lglfw -lvulkan -ldl -Xlinker -rpath -Xlinker /opt/homebrew/lib -SOURCES = src/draw.c src/ui.c src/gpu.c src/hex.c src/hsv.h lib/spng.c lib/vma.cpp -APP_SOURCES = src/main.c $(SOURCES) -TEST_SOURCES = test/hsv.c $(SOURCES) +ENGINE_SOURCES = src/engine.c src/draw.c src/ui.c src/gpu.c src/hex.c src/hsv.c lib/spng.c lib/vma.cpp +APP_SOURCES = src/main.c $(ENGINE_SOURCES) +EDITOR_SOURCES = src/editor.c $(ENGINE_SOURCES) +TEST_SOURCES = test/hsv.c $(ENGINE_SOURCES) + APP_OBJECTS = $(addsuffix .o, $(basename $(APP_SOURCES))) +EDITOR_OBJECTS = $(addsuffix .o, $(basename $(EDITOR_SOURCES))) TEST_OBJECTS = $(addsuffix .o, $(basename $(TEST_SOURCES))) VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader/*.vert))) @@ -36,6 +39,9 @@ all: roleplay $(SPV_FILES) roleplay: $(APP_OBJECTS) $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^ +editor: $(EDITOR_OBJECTS) + $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^ + test/test_hsv: $(TEST_OBJECTS) $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^ @@ -43,14 +49,13 @@ test/test_hsv: $(TEST_OBJECTS) test: test/test_hsv ./test/test_hsv - %.o: %.cpp $(CXX) $(CFLAGS) -std=c++17 -Wno-nullability-completeness -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-private-field -Wno-unused-variable -c -o $@ $< %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -.PHONY: clean clean_compdb run +.PHONY: clean clean_compdb run run_editor clean: rm -f $(SPV_FILES) @@ -66,6 +71,9 @@ clean_compdb: run: roleplay $(SPV_FILES) ./roleplay +run_editor: editor $(SPV_FILES) + ./editor + .PHONY: debug-sign debug-sign: codesign --entitlements ./ent.plist -f -s "fake-apple-signing" ./roleplay diff --git a/client/include/engine.h b/client/include/engine.h new file mode 100644 index 0000000..cb45372 --- /dev/null +++ b/client/include/engine.h @@ -0,0 +1,87 @@ +#ifndef ENGINE_H +#define ENGINE_H + +#include "GLFW/glfw3.h" +#include "gpu.h" +#include "ui.h" +#include "hex.h" + +typedef struct ClientContextStruct ClientContext; + +typedef bool (*app_text_callback)( + ClientContext* context, + unsigned int codepoint); + +typedef bool (*app_key_callback)( + ClientContext* context, + int key, + int action, + int mods); + +typedef bool (*app_button_callback)( + ClientContext* context, + float x, + float y, + int button, + int action, + int mods); + +typedef bool (*app_scroll_callback)( + ClientContext* context, + double x, + double y); + +typedef bool (*app_cursor_callback)( + ClientContext* context, + float x, + float y); + +typedef void (*app_frame_function)( + ClientContext* context); + +typedef void (*app_startup_function)( + ClientContext* context); + +struct ClientContextStruct { + GLFWwindow* window; + + RenderContext render; + UIContext ui; + HexContext hex; + + vec3 position; + vec3 velocity; + + vec2 rotation; + int32_t key_spin[2]; + vec2 cur_spin; + + double distance; + int32_t zoom; + + bool camera_mode; + float key_spin_speed; + float cur_spin_speed; + float zoom_speed; + float move_speed; + + void* app_data; + app_frame_function app_frame; + app_text_callback app_text; + app_key_callback app_key; + app_button_callback app_button; + app_scroll_callback app_scroll; + app_cursor_callback app_cursor; +}; + +int run_app( + void* app_data, + app_startup_function app_startup, + app_frame_function app_frame, + app_text_callback app_text, + app_key_callback app_key, + app_button_callback app_button, + app_scroll_callback app_scroll, + app_cursor_callback app_cursor); + +#endif diff --git a/client/include/ui.h b/client/include/ui.h index 74f8ca9..86f0bf1 100644 --- a/client/include/ui.h +++ b/client/include/ui.h @@ -145,11 +145,11 @@ typedef struct GPUContainerStruct { typedef struct UIContextStruct UIContext; -typedef void (*ui_text_callback)(void* data, UIContext* ui, RenderContext* gpu, unsigned int codepoint); +typedef bool (*ui_text_callback)(void* data, UIContext* ui, RenderContext* gpu, unsigned int codepoint); typedef bool (*ui_key_callback)(void* data, UIContext* ui, RenderContext* gpu, int key, int action, int mods); -typedef void (*ui_button_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods); -typedef void (*ui_scroll_callback)(void* data, UIContext* ui, RenderContext* gpu, double x, double y); -typedef void (*ui_cursor_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y); +typedef bool (*ui_button_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods); +typedef bool (*ui_scroll_callback)(void* data, UIContext* ui, RenderContext* gpu, double x, double y); +typedef bool (*ui_cursor_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y); typedef void (*ui_deselect_callback)(void* data, UIContext* ui, RenderContext* gpu); typedef struct UICallbacksStruct { diff --git a/client/src/editor.c b/client/src/editor.c new file mode 100644 index 0000000..49cc329 --- /dev/null +++ b/client/src/editor.c @@ -0,0 +1,1203 @@ +#include +#include "hsv.h" +#include "engine.h" + +#include +#include + +#define COLOR_PICK_CONTAINER_ID 0x03 +typedef struct EditorDataStruct { + uint32_t selected_region; + uint32_t last_selected_region; + + uint32_t last_clicked_region; + uint32_t last_clicked_hex; + uint32_t last_clicked_vertex; + + double current_hsv[3]; + vec4 current; + vec4 saved[12]; + char string[10]; + int string_len; +} EditorData; + + +uint32_t hex_color(vec4 color) { + return ((lrint(color[0]*255.0) & 0xFF) << 24) + + ((lrint(color[1]*255.0) & 0xFF) << 16) + + ((lrint(color[2]*255.0) & 0xFF) << 8) + + ((lrint(color[3]*255.0) & 0xFF) << 0); +} + +uint32_t add_hex_region(ClientContext* context) { + HexRegion* region; + + allocate_hex_region(0, 0, 0, context->hex.data.current_map, ®ion, &context->hex, &context->render); + + for(uint32_t hex = 0; hex < REGION_HEX_COUNT; hex++) { + region->data.hexes[hex].color[0] = 0xFFFFFFFF; + region->data.hexes[hex].color[1] = 0xFFFFFFFF; + region->data.hexes[hex].color[2] = 0xFFFFFFFF; + region->data.hexes[hex].color[3] = 0xFFFFFFFF; + region->data.hexes[hex].color[4] = 0xFFFFFFFF; + region->data.hexes[hex].color[5] = 0xFFFFFFFF; + region->data.hexes[hex].color[6] = 0xFFFFFFFF; + + region->data.hexes[hex].height[0] = 0; + region->data.hexes[hex].height[1] = 0; + region->data.hexes[hex].height[2] = 0; + region->data.hexes[hex].height[3] = 0; + region->data.hexes[hex].height[4] = 0; + region->data.hexes[hex].height[5] = 0; + } + + set_hex_region(region, &context->hex, &context->render); + + uint32_t i = 0; + for(; i < MAX_LOADED_REGIONS; i++) { + if(region == context->hex.regions[i]) { + break; + } + } + + return i; +} + +void update_hex_string(UIContext* ui, RenderContext* gpu, EditorData* data) { + snprintf(data->string, 10, "#%02X%02X%02X%02X", + (uint)rintf(data->current[0]*255), + (uint)rintf(data->current[1]*255), + (uint)rintf(data->current[2]*255), + (uint)rintf(data->current[3]*255)); + data->string_len = 8; + update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); +} + +void sv_square_pick(UIContext* ui, RenderContext* gpu, EditorData* data, float s, float v) { + if(s < 0) s = 0; + if(s > 1) s = 1; + + if(v < 0) v = 0; + if(v > 1) v = 1; + + data->current_hsv[1] = s; + data->current_hsv[2] = v; + + Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); + Layer* layer = &container->layers[0]; + GPUDrawable* select_outline = &layer->drawables_buffer[3]; + GPUDrawable* select = &layer->drawables_buffer[4]; + + select->pos[0] = s*130 - 2; + select->pos[1] = 130 - v*130 - 2; + + select->color[0][1] = s; + select->color[0][2] = v; + + select->color[1][1] = s; + select->color[1][2] = v; + + select->color[2][1] = s; + select->color[2][2] = v; + + select->color[3][1] = s; + select->color[3][2] = v; + + select_outline->pos[0] = s*130 - 3; + select_outline->pos[1] = 130 - v*130 - 3; + + add_transfers( + &select_outline->pos[0], + layer->drawables, + 3*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos), + 1*sizeof(vec2), + gpu); + + add_transfers( + &select->pos[0], + layer->drawables, + 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos), + 1*sizeof(vec2), + gpu); + + add_transfers( + &select->color[0], + layer->drawables, + 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), + 4*sizeof(vec4), + gpu); + + hsv_to_rgb(data->current_hsv, data->current); + update_hex_string(ui, gpu, data); +} + +bool sv_square_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { + (void)mods; + (void)x; + + if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { + set_active_element(COLOR_PICK_CONTAINER_ID, 0, 1, ui); + sv_square_pick(ui, gpu, data, x, 1-y); + } else if(action == GLFW_RELEASE && button == GLFW_MOUSE_BUTTON_LEFT) { + clear_active_element(ui, gpu); + } + + return true; +} + +bool sv_square_cursor_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y) { + if(ui->active_element == 1 + && ui->active_layer == 0 + && ui->active_container == COLOR_PICK_CONTAINER_ID) { + sv_square_pick(ui, gpu, data, x, 1-y); + } + + return true; +} + +void hue_bar_set(UIContext* ui, RenderContext* gpu, EditorData* data, float y) { + if(y < 0) y = 0; + if(y > 1) y = 1; + + data->current_hsv[0] = y; + + Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); + Layer* layer = &container->layers[0]; + GPUDrawable* sv_square = &layer->drawables_buffer[1]; + GPUDrawable* sv_select = &layer->drawables_buffer[4]; + GPUDrawable* hue_select = &layer->drawables_buffer[6]; + + sv_square->color[0][0] = y; + sv_square->color[1][0] = y; + sv_square->color[2][0] = y; + sv_square->color[3][0] = y; + + sv_select->color[0][0] = y; + sv_select->color[1][0] = y; + sv_select->color[2][0] = y; + sv_select->color[3][0] = y; + + hue_select->pos[1] = 2 + y*130; + + add_transfers( + &sv_square->color[0], + layer->drawables, + 1*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), + 4*sizeof(vec4), + gpu); + + add_transfers( + &sv_select->color[0], + layer->drawables, + 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), + 4*sizeof(vec4), + gpu); + + add_transfers( + &hue_select->pos[1], + layer->drawables, + 6*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos) + sizeof(float), + 1*sizeof(float), + gpu); + + hsv_to_rgb(data->current_hsv, data->current); + update_hex_string(ui, gpu, data); +} + +bool hue_bar_scroll_callback(void* data, UIContext* ui, RenderContext* gpu, double x, double y) { + (void)x; + + Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); + hue_bar_set(ui, gpu, data, y*0.01 + container->layers[0].drawables_buffer[1].color[0][0]); + + return true; +} + +bool hue_bar_cursor_callback(void*data, UIContext* ui, RenderContext* gpu, float x, float y) { + (void)x; + + if(ui->active_element == 2 + && ui->active_layer == 0 + && ui->active_container == COLOR_PICK_CONTAINER_ID) { + hue_bar_set(ui, gpu, data, y); + } + + return true; +} + +bool hue_bar_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { + (void)mods; + (void)x; + + if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { + set_active_element(COLOR_PICK_CONTAINER_ID, 0, 2, ui); + hue_bar_set(ui, gpu, data, y); + } else if(action == GLFW_RELEASE && button == GLFW_MOUSE_BUTTON_LEFT) { + clear_active_element(ui, gpu); + } + + return true; +} + +void hex_string_set_color(UIContext* ui, RenderContext* gpu, float color) { + Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); + container->layers[0].drawables_buffer[5].color[0][2] = color; + container->layers[0].drawables_buffer[5].color[0][3] = color; + + container->layers[0].drawables_buffer[5].color[1][2] = color; + container->layers[0].drawables_buffer[5].color[1][3] = color; + + container->layers[0].drawables_buffer[5].color[2][2] = color; + container->layers[0].drawables_buffer[5].color[2][3] = color; + + container->layers[0].drawables_buffer[5].color[3][2] = color; + container->layers[0].drawables_buffer[5].color[3][3] = color; + + add_transfers( + &container->layers[0].drawables_buffer[5].color[0], + container->layers[0].drawables, + 5*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), + 4*sizeof(vec4), + gpu); +} + +bool hex_string_text_callback(void* ptr, UIContext* ui, RenderContext* gpu, unsigned int codepoint) { + EditorData* data = ptr; + + if(codepoint >= 'a' && codepoint <= 'f') { + codepoint += 'A' - 'a'; + } else if(!((codepoint >= 'A' && codepoint <= 'F') || (codepoint >= '0' && codepoint <= '9'))) { + return true; + } + + if(data->string_len < 8) { + data->string_len += 1; + data->string[data->string_len] = codepoint; + update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); + } + + return true; +} + +bool hex_string_key_callback(void* ptr, UIContext* ui, RenderContext* gpu, int key, int action, int mods) { + (void)mods; + EditorData* data = ptr; + char tmp[3]; + + if(action == GLFW_PRESS) { + switch(key) { + case GLFW_KEY_ESCAPE: + hsv_to_rgb(data->current_hsv, data->current); + update_hex_string(ui, gpu, data); + clear_active_element(ui, gpu); + break; + case GLFW_KEY_ENTER: + // TODO: validate hex string and reset or set hsv + tmp[0] = data->string[1]; + tmp[1] = data->string[2]; + tmp[2] = 0; + data->current[0] = strtol(tmp, NULL, 16)/255.0; + + tmp[0] = data->string[3]; + tmp[1] = data->string[4]; + tmp[2] = 0; + data->current[1] = strtol(tmp, NULL, 16)/255.0; + + tmp[0] = data->string[5]; + tmp[1] = data->string[6]; + tmp[2] = 0; + data->current[2] = strtol(tmp, NULL, 16)/255.0; + + tmp[0] = data->string[7]; + tmp[1] = data->string[8]; + tmp[2] = 0; + data->current[3] = strtol(tmp, NULL, 16)/255.0; + + rgb_to_hsv(data->current, data->current_hsv); + hue_bar_set(ui, gpu, data, data->current_hsv[0]); + sv_square_pick(ui, gpu, data, data->current_hsv[1], data->current_hsv[2]); + + clear_active_element(ui, gpu); + break; + case GLFW_KEY_BACKSPACE: + if(data->string_len > 0) { + data->string[data->string_len] = '\0'; + data->string_len -= 1; + update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); + } + break; + } + } + + return true; +} + +bool hex_string_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { + (void)data; + (void)mods; + (void)x; + (void)y; + + if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { + set_active_element(COLOR_PICK_CONTAINER_ID, 0, 5, ui); + hex_string_set_color(ui, gpu, 1); + } + + return true; +} + +void hex_string_deselect_callback(void* data, UIContext* ui, RenderContext* gpu) { + (void)data; + hex_string_set_color(ui, gpu, 0); +} + +void set_saved_color(UIContext* ui, RenderContext* gpu, EditorData* data, uint32_t index, vec4 color) { + data->saved[index][0] = color[0]; + data->saved[index][1] = color[1]; + data->saved[index][2] = color[2]; + data->saved[index][3] = color[3]; + + Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); + Layer* layer = &container->layers[0]; + GPUDrawable* saved_color = &layer->drawables_buffer[7 + index]; + + saved_color->color[0][0] = data->current[0]; + saved_color->color[0][1] = data->current[1]; + saved_color->color[0][2] = data->current[2]; + + saved_color->color[1][0] = data->current[0]; + saved_color->color[1][1] = data->current[1]; + saved_color->color[1][2] = data->current[2]; + + saved_color->color[2][0] = data->current[0]; + saved_color->color[2][1] = data->current[1]; + saved_color->color[2][2] = data->current[2]; + + saved_color->color[3][0] = data->current[0]; + saved_color->color[3][1] = data->current[1]; + saved_color->color[3][2] = data->current[2]; + + add_transfers( + &saved_color->color[0], + layer->drawables, + (7+index)*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), + 4*sizeof(vec4), + gpu); +} + +bool saved_color_button_callback( + void* ptr, + UIContext* ui, + RenderContext* gpu, + float x, float y, + int button, int action, int mods, + uint32_t index) { + (void)x; + (void)y; + (void)mods; + + EditorData* data = ptr; + + if(action == GLFW_PRESS) { + if(button == GLFW_MOUSE_BUTTON_LEFT) { + data->current[0] = data->saved[index][0]; + data->current[1] = data->saved[index][1]; + data->current[2] = data->saved[index][2]; + data->current[3] = data->saved[index][3]; + rgb_to_hsv(data->current, data->current_hsv); + hue_bar_set(ui, gpu, data, data->current_hsv[0]); + sv_square_pick(ui, gpu, data, data->current_hsv[1], data->current_hsv[2]); + update_hex_string(ui, gpu, data); + } else if(button == GLFW_MOUSE_BUTTON_RIGHT) { + set_saved_color(ui, gpu, data, index, data->current); + } else if (button == GLFW_MOUSE_BUTTON_MIDDLE) { + vec4 clear = {0, 0, 0, 0}; + set_saved_color(ui, gpu, data, index, clear); + } + } + + return true; +} + +#define SAVED_COLOR_BUTTON_CALLBACK(n) \ +bool saved_color_button_callback_##n(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { \ + return saved_color_button_callback(data, ui, gpu, x, y, button, action, mods, n); \ +} + +SAVED_COLOR_BUTTON_CALLBACK( 0); +SAVED_COLOR_BUTTON_CALLBACK( 1); +SAVED_COLOR_BUTTON_CALLBACK( 2); +SAVED_COLOR_BUTTON_CALLBACK( 3); +SAVED_COLOR_BUTTON_CALLBACK( 4); +SAVED_COLOR_BUTTON_CALLBACK( 5); +SAVED_COLOR_BUTTON_CALLBACK( 6); +SAVED_COLOR_BUTTON_CALLBACK( 7); +SAVED_COLOR_BUTTON_CALLBACK( 8); +SAVED_COLOR_BUTTON_CALLBACK( 9); +SAVED_COLOR_BUTTON_CALLBACK(10); +SAVED_COLOR_BUTTON_CALLBACK(11); + +#define SAVED_COLOR_CALLBACK_ENTRY(n) \ + { \ + .layer = 0, \ + .element = 7 + n, \ + .data = data, \ + .button = saved_color_button_callback_##n, \ + } + +VkResult color_ui(ClientContext* context) { + GPUString strings[] = { + { + .pos = {2, 150}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 0, + .length = 9, + .font = 0, + }, + }; + + GPUDrawable drawables[] = { + { + .pos = {0, 0}, + .size = {190, 150}, + .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, + }, + { + .type = DRAWABLE_TYPE_RECT_HSV, + .pos = {2, 2}, + .size = {130, 130}, + .color = {{0, 0, 1, 1}, {0, 1, 1, 1}, {0, 0, 0, 1}, {0, 1, 0, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .type = DRAWABLE_TYPE_RECT_HSV, + .pos = {134, 2}, + .size = {10, 130}, + .color = {{0, 1, 1, 1}, {0, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON | UI_EVENT_SCROLL, + }, + { + .pos = {130-4, 130-4}, + .size = {7, 7}, + .color = {{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}}, + }, + { + .type = DRAWABLE_TYPE_RECT_HSV, + .pos = {130-3, 130-3}, + .size = {5, 5}, + .color = {{1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}}, + }, + { + .pos = {20, 134}, + .size = {95, 15}, + .events = UI_EVENT_BUTTON | UI_EVENT_CURSOR, + }, + { + .pos = {134, 2}, + .size = {10, 1}, + .color = {{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}}, + }, + { + .pos = {146, 2}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 2}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {146, 24}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 24}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {146, 46}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 46}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {146, 68}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 68}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {146, 90}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 90}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {146, 112}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + { + .pos = {168, 112}, + .size = {20, 20}, + .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, + .events = UI_EVENT_BUTTON, + }, + }; + + uint32_t codes[9]; + VkResult result; + VK_RESULT(map_string("#00000000", codes, 0, 0, &context->ui)); + + LayerInput layer = { + .strings = strings, + .num_strings = sizeof(strings)/sizeof(GPUString), + .codes = codes, + .num_codes = sizeof(codes)/sizeof(uint32_t), + .drawables = drawables, + .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), + }; + + EditorData* data = context->app_data; + data->string_len = 8; + data->string[0] = '#'; + data->string[1] = '0'; + data->string[2] = '0'; + data->string[3] = '0'; + data->string[4] = '0'; + data->string[5] = '0'; + data->string[6] = '0'; + data->string[7] = '0'; + data->string[8] = '0'; + data->string[9] = '\0'; + data->current[0] = 0; + data->current[1] = 0; + data->current[2] = 0; + data->current[3] = 0; + + UICallbacks callbacks[] = { + { + .layer = 0, + .element = 1, + .data = context->app_data, + .button = sv_square_button_callback, + .cursor = sv_square_cursor_callback, + }, + { + .layer = 0, + .element = 2, + .data = context->app_data, + .button = hue_bar_button_callback, + .cursor = hue_bar_cursor_callback, + .scroll = hue_bar_scroll_callback, + }, + { + .layer = 0, + .element = 5, + .data = context->app_data, + .button = hex_string_button_callback, + .key = hex_string_key_callback, + .text = hex_string_text_callback, + .deselect = hex_string_deselect_callback, + }, + SAVED_COLOR_CALLBACK_ENTRY( 0), + SAVED_COLOR_CALLBACK_ENTRY( 1), + SAVED_COLOR_CALLBACK_ENTRY( 2), + SAVED_COLOR_CALLBACK_ENTRY( 3), + SAVED_COLOR_CALLBACK_ENTRY( 4), + SAVED_COLOR_CALLBACK_ENTRY( 5), + SAVED_COLOR_CALLBACK_ENTRY( 6), + SAVED_COLOR_CALLBACK_ENTRY( 7), + SAVED_COLOR_CALLBACK_ENTRY( 8), + SAVED_COLOR_CALLBACK_ENTRY( 9), + SAVED_COLOR_CALLBACK_ENTRY(10), + SAVED_COLOR_CALLBACK_ENTRY(11), + }; + + ContainerInput container = { + .layers = &layer, + .layer_count = 1, + .anchor = ANCHOR_BOTTOM_LEFT, + .id = COLOR_PICK_CONTAINER_ID, + .offset = {0, 0}, + .size = {190, 150}, + .callbacks = callbacks, + .callback_count = sizeof(callbacks)/sizeof(UICallbacks), + }; + + return create_container(&container, &context->render, &context->ui); +} + +VkResult hex_info_ui(ClientContext* context) { + GPUString strings[] = { + { + .pos = {0, 33}, + .color = {1, 1, 1, 1}, + .size = 32, + .offset = 0, + .length = 0, + .font = 0, + }, + { + .pos = {2, 50}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 20, + .length = 0, + .font = 0, + }, + { + .pos = {2, 73}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 40, + .length = 0, + .font = 0, + }, + { + .pos = {2, 93}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 60, + .length = 0, + .font = 0, + }, + { + .pos = {2, 113}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 80, + .length = 0, + .font = 0, + }, + { + .pos = {2, 133}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 100, + .length = 0, + .font = 0, + }, + { + .pos = {2, 153}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 120, + .length = 0, + .font = 0, + }, + { + .pos = {2, 173}, + .color = {1, 1, 1, 1}, + .size = 16, + .offset = 140, + .length = 0, + .font = 0, + }, + + }; + + GPUDrawable drawables[] = { + { + .pos = {0, 0}, + .size = {150, 175}, + .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, + }, + }; + + LayerInput layer = { + .strings = strings, + .num_strings = sizeof(strings)/sizeof(GPUString), + .max_strings = sizeof(strings)/sizeof(GPUString) + 4, + .max_codes = 200, + .drawables = drawables, + .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), + }; + + ContainerInput container = { + .id = 0x02, + .size = {150, 175}, + .offset = {0, 0}, + .anchor = ANCHOR_BOTTOM_RIGHT, + .layers = &layer, + .layer_count = 1, + }; + + return create_container(&container, &context->render, &context->ui); +} + +VkResult region_info_ui(ClientContext* context) { + + GPUString strings[] = { + { + .pos = {0, 33}, + .color = {1, 1, 1, 1}, + .size = 32, + .offset = 0, + .length = 0, + .font = 0, + }, + { + .pos = {0, 33 + 1*40}, + .color = {1, 1, 1, 1}, + .size = 32, + .offset = 11, + .length = 0, + .font = 0, + }, + { + .pos = {0, 33 + 2*40}, + .color = {1, 1, 1, 1}, + .size = 32, + .offset = 18, + .length = 0, + .font = 0, + }, + { + .pos = {0, 33 + 3*40}, + .color = {1, 1, 1, 1}, + .size = 32, + .offset = 25, + .length = 0, + .font = 0, + }, + }; + + GPUDrawable drawables[] = { + { + .pos = {0, 0}, + .size = {225, 155}, + .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, + }, + }; + + LayerInput layer = { + .strings = strings, + .num_strings = sizeof(strings)/sizeof(GPUString), + .max_strings = sizeof(strings)/sizeof(GPUString) + 4, + .max_codes = 100, + .drawables = drawables, + .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), + }; + + ContainerInput container = { + .id = 0x01, + .size = {225, 155}, + .offset = {0, 0}, + .anchor = ANCHOR_TOP_RIGHT, + .layers = &layer, + .layer_count = 1, + }; + + return create_container(&container, &context->render, &context->ui); +} + +VkResult update_region_info_ui(ClientContext* context) { + char temp[20]; + VkResult result; + EditorData* data = context->app_data; + HexRegion* selected_region = context->hex.regions[data->selected_region]; + + snprintf(temp, + sizeof(temp), + "Region %4d", data->selected_region); + VK_RESULT(update_ui_string(temp, 0x01, 0, 0, &context->ui, &context->render)); + + if(selected_region == NULL) { + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x01, 0, 1, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x01, 0, 2, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x01, 0, 3, &context->ui, &context->render)); + } else { + snprintf( + temp, + sizeof(temp), + "Q: %4d", selected_region->data.q); + VK_RESULT(update_ui_string(temp, 0x01, 0, 1, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "R: %4d", selected_region->data.r); + VK_RESULT(update_ui_string(temp, 0x01, 0, 2, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "Y: %4d", selected_region->data.y); + VK_RESULT(update_ui_string(temp, 0x01, 0, 3, &context->ui, &context->render)); + } + + return VK_SUCCESS; +} + +VkResult update_hex_info_ui(ClientContext* context) { + char temp[20]; + VkResult result; + HexRegion* region = context->hex.regions[context->hex.data.clicked_region]; + + + if(region == NULL) { + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 0, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 1, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 2, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 3, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 4, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 5, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 6, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + ""); + VK_RESULT(update_ui_string(temp, 0x02, 0, 7, &context->ui, &context->render)); + } else { + GPUHex* hex = ®ion->data.hexes[context->hex.data.clicked_hex]; + snprintf(temp, + sizeof(temp), + "%d-%d", + context->hex.data.clicked_region, + context->hex.data.clicked_hex); + VK_RESULT(update_ui_string(temp, 0x02, 0, 0, &context->ui, &context->render)); + + int32_t hex_index = context->hex.data.clicked_hex; + + float radius = 0; + float ring = 0; + int side = 0; + if(hex_index != 0) { + radius = floor(0.5 + sqrt(12*hex_index-3)/6); + ring = hex_index - (3*radius*radius - 3*radius + 1); + side = floor(ring/radius); + } + + // TODO: fix, these are wrong lmao + int32_t hex_q = hex_starts_qr[side][0]*radius + hex_directions_qr[side][0]*(ring-(radius*side)); + int32_t hex_r = hex_starts_qr[side][1]*radius + hex_directions_qr[side][1]*(ring-(radius*side)); + + int32_t world_q = hex_q + region->data.q*(REGION_SIZE*2 + 1) + region->data.r*REGION_SIZE; + int32_t world_r = hex_r + region->data.q*(REGION_SIZE + 0.5) + region->data.r*(REGION_SIZE*2+1); + + snprintf( + temp, + sizeof(temp), + "%d, %d, %d, %d", + world_q, + world_r, + region->data.y, + context->hex.data.clicked_vertex); + VK_RESULT(update_ui_string(temp, 0x02, 0, 1, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%02.02f %02.02f %02.02f", + hex->height[0], hex->height[1], hex->height[2]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 2, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%02.02f %02.02f %02.02f", + hex->height[3], hex->height[4], hex->height[5]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 3, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%08X", + hex->color[0]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 4, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%08X %08X", + hex->color[1], hex->color[2]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 5, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%08X %08X", + hex->color[3], hex->color[4]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 6, &context->ui, &context->render)); + + snprintf( + temp, + sizeof(temp), + "%08X %08X", + hex->color[5], hex->color[6]); + VK_RESULT(update_ui_string(temp, 0x02, 0, 7, &context->ui, &context->render)); + } + + return VK_SUCCESS; +} + +bool editor_key_callback(ClientContext* context, int key, int action, int mods) { + (void)mods; + + if(action != GLFW_PRESS) return false; + + EditorData* data = context->app_data; + HexRegion* region = NULL; + + switch(key) { + case GLFW_KEY_EQUAL: + data->selected_region = add_hex_region(context); + break; + + case GLFW_KEY_LEFT_BRACKET: + data->selected_region -= 1; + if(data->selected_region > MAX_LOADED_REGIONS) { + data->selected_region = MAX_LOADED_REGIONS; + } + break; + case GLFW_KEY_RIGHT_BRACKET: + data->selected_region += 1; + if(data->selected_region > MAX_LOADED_REGIONS) { + data->selected_region = 0; + } + break; + + case GLFW_KEY_I: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.q += 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.q, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, q), + sizeof(uint32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + case GLFW_KEY_K: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.q -= 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.q, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, q), + sizeof(uint32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + case GLFW_KEY_J: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.r += 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.r, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, r), + sizeof(uint32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + case GLFW_KEY_L: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.r -= 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.r, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, r), + sizeof(uint32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + case GLFW_KEY_O: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.y += 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.y, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, y), + sizeof(int32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + case GLFW_KEY_U: + if(context->hex.regions[data->selected_region] != NULL) { + context->hex.regions[data->selected_region]->data.y -= 1; + add_transfer( + &context->hex.regions[data->selected_region]->data.y, + context->hex.regions[data->selected_region]->region, + offsetof(GPUHexRegion, y), + sizeof(int32_t), + context->render.current_frame, + &context->render); + } + update_region_info_ui(context); + break; + + case GLFW_KEY_Y: + region = context->hex.regions[context->hex.data.clicked_region]; + if(region != NULL) { + region->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1] += 0.1; + add_transfer( + ®ion->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1], + region->region, + offsetof(GPUHexRegion, hexes) + + sizeof(GPUHex)*context->hex.data.clicked_hex + + offsetof(GPUHex, height) + + sizeof(float)*(context->hex.data.clicked_vertex-1), + sizeof(float), + context->render.current_frame, + &context->render); + update_hex_info_ui(context); + } + break; + case GLFW_KEY_H: + region = context->hex.regions[context->hex.data.clicked_region]; + if(region != NULL) { + region->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1] -= 0.1; + add_transfer( + ®ion->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1], + region->region, + offsetof(GPUHexRegion, hexes) + + sizeof(GPUHex)*context->hex.data.clicked_hex + + offsetof(GPUHex, height) + + sizeof(float)*(context->hex.data.clicked_vertex-1), + sizeof(float), + context->render.current_frame, + &context->render); + update_hex_info_ui(context); + } + break; + + case GLFW_KEY_E: + region = context->hex.regions[context->hex.data.clicked_region]; + if(region != NULL) { + region->data.hexes[context->hex.data.clicked_hex].color[context->hex.data.clicked_vertex] = hex_color(data->current); + add_transfer( + ®ion->data.hexes[context->hex.data.clicked_hex].color[context->hex.data.clicked_vertex], + region->region, + offsetof(GPUHexRegion, hexes) + + sizeof(GPUHex)*context->hex.data.clicked_hex + + offsetof(GPUHex, color) + + sizeof(uint32_t)*(context->hex.data.clicked_vertex), + sizeof(uint32_t), + context->render.current_frame, + &context->render); + update_hex_info_ui(context); + } + break; + } + + return false; +} + +void editor_frame(ClientContext* context) { + EditorData* data = context->app_data; + if(data->last_clicked_region != context->hex.data.clicked_region || + data->last_clicked_hex != context->hex.data.clicked_hex || + data->last_clicked_vertex != context->hex.data.clicked_vertex) { + data->last_clicked_region = context->hex.data.clicked_region; + data->last_clicked_hex = context->hex.data.clicked_hex; + data->last_clicked_vertex = context->hex.data.clicked_vertex; + update_hex_info_ui(context); + } + + if(data->selected_region != data->last_selected_region) { + data->last_selected_region = data->selected_region; + update_region_info_ui(context); + } +} + +void editor_startup(ClientContext* context) { + region_info_ui(context); + hex_info_ui(context); + color_ui(context); +} + +int main() { + EditorData* data = malloc(sizeof(EditorData)); + memset(data, 0, sizeof(EditorData)); + data->selected_region = MAX_LOADED_REGIONS; + data->last_clicked_region = MAX_LOADED_REGIONS; + + return run_app(data, editor_startup, editor_frame, NULL, editor_key_callback, NULL, NULL, NULL); +} diff --git a/client/src/engine.c b/client/src/engine.c new file mode 100644 index 0000000..90106ef --- /dev/null +++ b/client/src/engine.c @@ -0,0 +1,432 @@ +#include "engine.h" +#include "gpu.h" +#include "draw.h" + +void text_callback(GLFWwindow* window, unsigned int codepoint) { + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + if(context->ui.active_callbacks != NULL + && context->ui.active_callbacks->text != NULL + && context->ui.active_callbacks->text( + context->ui.active_callbacks->data, + &context->ui, + &context->render, + codepoint)) return; + + if(context->app_text != NULL && context->app_text(context, codepoint)) return; +} + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + (void)scancode; + (void)mods; + + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + + if(context->ui.active_callbacks != NULL + && context->ui.active_callbacks->key != NULL + && context->ui.active_callbacks->key( + context->ui.active_callbacks->data, + &context->ui, + &context->render, + key, action, mods)) return; + + if(context->app_key != NULL && context->app_key(context, key, action, mods)) return; + + switch(key) { + case GLFW_KEY_A: + if(action == GLFW_PRESS) { + context->key_spin[0] -= 1; + } else if(action == GLFW_RELEASE) { + context->key_spin[0] += 1; + } + break; + case GLFW_KEY_D: + if(action == GLFW_PRESS) { + context->key_spin[0] += 1; + } else if(action == GLFW_RELEASE) { + context->key_spin[0] -= 1; + } + break; + + case GLFW_KEY_W: + if(action == GLFW_PRESS) { + context->key_spin[1] += 1; + } else if(action == GLFW_RELEASE) { + context->key_spin[1] -= 1; + } + break; + case GLFW_KEY_S: + if(action == GLFW_PRESS) { + context->key_spin[1] -= 1; + } else if(action == GLFW_RELEASE) { + context->key_spin[1] += 1; + } + break; + + case GLFW_KEY_UP: + if(action == GLFW_PRESS) { + context->velocity[2] += 1; + } else if(action == GLFW_RELEASE) { + context->velocity[2] -= 1; + } + break; + case GLFW_KEY_DOWN: + if(action == GLFW_PRESS) { + context->velocity[2] -= 1; + } else if(action == GLFW_RELEASE) { + context->velocity[2] += 1; + } + break; + + case GLFW_KEY_LEFT: + if(action == GLFW_PRESS) { + context->velocity[0] -= 1; + } else if(action == GLFW_RELEASE) { + context->velocity[0] += 1; + } + break; + case GLFW_KEY_RIGHT: + if(action == GLFW_PRESS) { + context->velocity[0] += 1; + } else if(action == GLFW_RELEASE) { + context->velocity[0] -= 1; + } + break; + + case GLFW_KEY_LEFT_SHIFT: + if(action == GLFW_PRESS) { + context->velocity[1] -= 1; + } else if(action == GLFW_RELEASE) { + context->velocity[1] += 1; + } + break; + case GLFW_KEY_SPACE: + if(action == GLFW_PRESS) { + context->velocity[1] += 1; + } else if(action == GLFW_RELEASE) { + context->velocity[1] -= 1; + } + break; + } +} + +void button_callback(GLFWwindow* window, int button, int action, int mods) { + double cursor[2]; + uint32_t container; + uint32_t layer; + uint32_t element; + vec2 position; + + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + + glfwGetCursorPos(window, &cursor[0], &cursor[1]); + + if(context->ui.active_callbacks != NULL && context->ui.active_callbacks->button != NULL) { + Container* container_ptr = context_container(context->ui.active_container, &context->ui); + GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui.active_layer].drawables_buffer[context->ui.active_element]; + vec2 element_pos = { + drawable_ptr->pos[0] + container_ptr->data.offset[0], + drawable_ptr->pos[1] + container_ptr->data.offset[1], + }; + anchor_offset(&context->render, container_ptr, element_pos); + vec2 element_size = { + drawable_ptr->size[0], + drawable_ptr->size[1], + }; + + vec2 point = { + (cursor[0] - element_pos[0])/element_size[0], + (cursor[1] - element_pos[1])/element_size[1], + }; + + if((point[0] <= 1 && point[0] >= 0 && point[1] <= 1 && point[1] >= 0) || action == GLFW_RELEASE) { + context->ui.active_callbacks->button( + context->ui.active_callbacks->data, + &context->ui, + &context->render, + point[0], + point[1], + button, + action, + mods); + return; + } else { + clear_active_element(&context->ui, &context->render); + } + } + + if(context->app_button != NULL && context->app_button(context, cursor[0], cursor[1], button, action, mods)) return; + + if(ui_intersect(cursor, &context->render, &context->ui, UI_EVENT_BUTTON, &container, &layer, &element, position)) { + Container* container_ptr = context_container(container, &context->ui); + for(uint32_t c = 0; c < container_ptr->callback_count; c++) { + if(container_ptr->callbacks[c].element == element) { + if(container_ptr->callbacks[c].button != NULL) { + if(container_ptr->callbacks[c].button( + container_ptr->callbacks[c].data, + &context->ui, + &context->render, + position[0], + position[1], + button, + action, + mods)) return; + } + break; + } + } + } + + update_hex_click(cursor, &context->hex, &context->render); + if(button == GLFW_MOUSE_BUTTON_MIDDLE) { + if(action == GLFW_PRESS) { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + context->camera_mode = true; + } else { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + context->camera_mode = false; + } + } +} + +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { + (void)xoffset; + uint32_t container; + uint32_t layer; + uint32_t element; + vec2 position; + + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + if(context->ui.active_callbacks != NULL + && context->ui.active_callbacks->scroll != NULL + && context->ui.active_callbacks->scroll( + context->ui.active_callbacks->data, + &context->ui, + &context->render, + xoffset, yoffset)) return; + + if(context->app_scroll != NULL && context->app_scroll(context, xoffset, yoffset)) return; + + if(ui_intersect( + context->ui.cursor, + &context->render, + &context->ui, + UI_EVENT_SCROLL, + &container, + &layer, + &element, + position)) { + Container* container_ptr = context_container(container, &context->ui); + for(uint32_t c = 0; c < container_ptr->callback_count; c++) { + if(container_ptr->callbacks[c].element == element) { + if(container_ptr->callbacks[c].scroll != NULL) { + container_ptr->callbacks[c].scroll( + container_ptr->callbacks[c].data, + &context->ui, + &context->render, + xoffset, + yoffset); + } + break; + } + } + } else { + context->zoom = -yoffset; + } +} + +void cursor_callback(GLFWwindow* window, double xpos, double ypos) { + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + uint32_t container; + uint32_t element; + uint32_t layer; + vec2 position; + vec2 last_cursor = { + context->ui.cursor[0], + context->ui.cursor[1], + }; + + context->ui.cursor[0] = xpos; + context->ui.cursor[1] = ypos; + + if(context->camera_mode == true) { + context->cur_spin[0] = (xpos - last_cursor[0])/context->render.swapchain_extent.width*-100; + context->cur_spin[1] = (ypos - last_cursor[1])/context->render.swapchain_extent.height*100; + } else { + if(context->ui.active_callbacks != NULL && context->ui.active_callbacks->cursor != NULL) { + Container* container_ptr = context_container(context->ui.active_container, &context->ui); + GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui.active_layer].drawables_buffer[context->ui.active_element]; + vec2 element_pos = { + drawable_ptr->pos[0] + container_ptr->data.offset[0], + drawable_ptr->pos[1] + container_ptr->data.offset[1], + }; + anchor_offset(&context->render, container_ptr, element_pos); + vec2 element_size = { + drawable_ptr->size[0], + drawable_ptr->size[1], + }; + if(context->ui.active_callbacks->cursor( + context->ui.active_callbacks->data, + &context->ui, + &context->render, + (context->ui.cursor[0] - element_pos[0])/element_size[0], + (context->ui.cursor[1] - element_pos[1])/element_size[1])) return; + } + + if(context->app_cursor != NULL && context->app_cursor(context, xpos, ypos)) return; + + if(ui_intersect(context->ui.cursor, &context->render, &context->ui, UI_EVENT_CURSOR, &container, &layer, &element, position)) { + Container* container_ptr = context_container(container, &context->ui); + for(uint32_t c = 0; c < container_ptr->callback_count; c++) { + if(container_ptr->callbacks[c].element == element) { + if(container_ptr->callbacks[c].cursor != NULL) { + container_ptr->callbacks[c].cursor( + container_ptr->callbacks[c].data, + &context->ui, + &context->render, + position[0], + position[1]); + } + break; + } + } + } else { + update_hex_hover(context->ui.cursor, &context->hex, &context->render); + } + } +} + +int app_main(ClientContext* context) { + VkResult result; + + // + double last_frame_time = 0; + while(glfwWindowShouldClose(context->window) == 0) { + double frame_time = glfwGetTime(); + double delta_time = (frame_time - last_frame_time); + + // Reset callback variables + context->zoom = 0; + context->cur_spin[0] = 0; + context->cur_spin[1] = 0; + + glfwPollEvents(); + if(context->app_frame != NULL) context->app_frame(context); + + if((context->key_spin[0] != 0 || context->key_spin[1] != 0 || + context->velocity[0] != 0 || context->velocity[1] != 0 || context->velocity[2] != 0 || + context->zoom != 0 || + context->cur_spin[0] != 0 || context->cur_spin[1] != 0 || + context->render.framebuffer_recreated == true)) { + + + if(context->render.framebuffer_recreated == true) { + context->render.framebuffer_recreated = false; + VK_RESULT(update_hex_proj(&context->render, &context->hex)); + VK_RESULT(update_ui_context_resolution(&context->ui, &context->render)); + } + + context->rotation[0] += (float)context->key_spin[0]*delta_time*context->key_spin_speed; + context->rotation[0] += (float)context->cur_spin[0]*delta_time*context->cur_spin_speed; + if(context->rotation[0] > 2*M_PI) { + context->rotation[0] -= 2*M_PI; + } else if(context->rotation[0] < 0) { + context->rotation[0] += 2*M_PI; + } + + context->rotation[1] += (float)context->key_spin[1]*delta_time*context->key_spin_speed; + context->rotation[1] += (float)context->cur_spin[1]*delta_time*context->cur_spin_speed; + if(context->rotation[1] > (M_PI/2 - 0.1)) { + context->rotation[1] = (M_PI/2 - 0.1); + } else if(context->rotation[1] < 0) { + context->rotation[1] = 0; + } + + context->position[0] += - context->velocity[2]*context->move_speed*cos(context->rotation[0]) + - context->velocity[0]*context->move_speed*sin(context->rotation[0]); + + context->position[2] += context->velocity[0]*context->move_speed*cos(context->rotation[0]) + - context->velocity[2]*context->move_speed*sin(context->rotation[0]); + + context->position[1] += context->velocity[1]*context->move_speed; + + context->distance += context->zoom*delta_time*context->zoom_speed; + if(context->distance < 1) { + context->distance = 1; + } + + VK_RESULT(update_hex_view( + context->position, + context->rotation, + context->distance, + &context->render, + &context->hex)); + } + // + + VkResult result = draw_frame(&context->render, &context->ui, &context->hex, frame_time); + if(result != VK_SUCCESS) { + fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); + glfwDestroyWindow(context->window); + } + + last_frame_time = frame_time; + } + + return 0; +} + +int run_app( + void* app_data, + app_startup_function app_startup, + app_frame_function app_frame, + app_text_callback app_text, + app_key_callback app_key, + app_button_callback app_button, + app_scroll_callback app_scroll, + app_cursor_callback app_cursor) { + ClientContext* context = malloc(sizeof(ClientContext)); + if(context == NULL) { + return -1; + } + + memset(context, 0, sizeof(ClientContext)); + + context->window = init_window(); + + context->rotation[0] = 3*M_PI/2; + context->rotation[1] = M_PI/4; + context->distance = 25; + context->key_spin_speed = 1.0; + context->cur_spin_speed = 1.0; + context->zoom_speed = 1.0; + context->move_speed = 0.1; + + memset(&context->render, 0, sizeof(RenderContext)); + memset(&context->ui, 0, sizeof(UIContext)); + memset(&context->hex, 0, sizeof(HexContext)); + + context->app_data = app_data; + context->app_frame = app_frame; + context->app_text = app_text; + context->app_key = app_key; + context->app_button = app_button; + context->app_scroll = app_scroll; + context->app_cursor = app_cursor; + + glfwSetWindowUserPointer(context->window, context); + glfwSetKeyCallback(context->window, key_callback); + glfwSetMouseButtonCallback(context->window, button_callback); + glfwSetScrollCallback(context->window, scroll_callback); + glfwSetCursorPosCallback(context->window, cursor_callback); + glfwSetCharCallback(context->window, text_callback); + + if(init_vulkan(context->window, &context->render) != VK_SUCCESS) return -2; + + // TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary + if(create_ui_context(10, 10, 10, &context->render, &context->ui) != VK_SUCCESS) return -3; + if(create_hex_context(&context->render, &context->hex) != VK_SUCCESS) return -4; + + if(app_startup != NULL) app_startup(context); + + return app_main(context); +} diff --git a/client/src/main.c b/client/src/main.c index 9837402..943e394 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1,1656 +1,5 @@ -#include "GLFW/glfw3.h" -#include -#define CGLM_PRINT_PRECISION 10 -#define CGLM_DEFINE_PRINTS 1 -#include "ui.h" -#include "gpu.h" -#include "draw.h" -#include "hex.h" -#include "hsv.h" - -#include "arpa/inet.h" -#include "vk_mem_alloc.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vulkan_core.h" -#include "pthread.h" -#include -#include - -typedef struct EditorDataStruct { - uint32_t selected_region; - uint32_t last_selected_region; - - uint32_t last_clicked_region; - uint32_t last_clicked_hex; - uint32_t last_clicked_vertex; -} EditorData; - -#define COLOR_PICK_CONTAINER_ID 0x03 -typedef struct ColorUIDataStruct { - double current_hsv[3]; - vec4 current; - vec4 saved[12]; - char string[10]; - int string_len; -} ColorUIData; - -typedef struct ClientContextStruct { - GLFWwindow* window; - RenderContext* render; - UIContext* ui; - HexContext* hex; - - vec3 position; - - vec3 velocity; - - vec2 rotation; - int32_t key_spin[2]; - vec2 cur_spin; - - double distance; - int32_t zoom; - - bool camera_mode; - float key_spin_speed; - float cur_spin_speed; - float zoom_speed; - float move_speed; - - EditorData editor; - ColorUIData color; -} ClientContext; - -void* network_thread(void* data) { - ClientContext* context = (ClientContext*)data; - (void)context; - - return NULL; -} - -uint32_t hex_color(vec4 color) { - // TODO: implement vec4 -> uint32 color conversion - return 0x0000000; -} - -uint32_t add_hex_region(ClientContext* context) { - HexRegion* region; - - allocate_hex_region(0, 0, 0, context->hex->data.current_map, ®ion, context->hex, context->render); - - for(uint32_t hex = 0; hex < REGION_HEX_COUNT; hex++) { - region->data.hexes[hex].color[0] = 0xFFFFFFFF; - region->data.hexes[hex].color[1] = 0xFFFFFFFF; - region->data.hexes[hex].color[2] = 0xFFFFFFFF; - region->data.hexes[hex].color[3] = 0xFFFFFFFF; - region->data.hexes[hex].color[4] = 0xFFFFFFFF; - region->data.hexes[hex].color[5] = 0xFFFFFFFF; - region->data.hexes[hex].color[6] = 0xFFFFFFFF; - - region->data.hexes[hex].height[0] = 0; - region->data.hexes[hex].height[1] = 0; - region->data.hexes[hex].height[2] = 0; - region->data.hexes[hex].height[3] = 0; - region->data.hexes[hex].height[4] = 0; - region->data.hexes[hex].height[5] = 0; - } - - set_hex_region(region, context->hex, context->render); - - uint32_t i = 0; - for(; i < MAX_LOADED_REGIONS; i++) { - if(region == context->hex->regions[i]) { - break; - } - } - - return i; -} - -void update_hex_string(UIContext* ui, RenderContext* gpu, ColorUIData* data) { - snprintf(data->string, 10, "#%02X%02X%02X%02X", - (uint)rintf(data->current[0]*255), - (uint)rintf(data->current[1]*255), - (uint)rintf(data->current[2]*255), - (uint)rintf(data->current[3]*255)); - data->string_len = 8; - update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); -} - -void sv_square_pick(UIContext* ui, RenderContext* gpu, ColorUIData* data, float s, float v) { - if(s < 0) s = 0; - if(s > 1) s = 1; - - if(v < 0) v = 0; - if(v > 1) v = 1; - - data->current_hsv[1] = s; - data->current_hsv[2] = 1-v; - - Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); - Layer* layer = &container->layers[0]; - GPUDrawable* select_outline = &layer->drawables_buffer[3]; - GPUDrawable* select = &layer->drawables_buffer[4]; - - select->pos[0] = s*130 - 2; - select->pos[1] = v*130 - 2; - - select->color[0][1] = s; - select->color[0][2] = 1-v; - - select->color[1][1] = s; - select->color[1][2] = 1-v; - - select->color[2][1] = s; - select->color[2][2] = 1-v; - - select->color[3][1] = s; - select->color[3][2] = 1-v; - - select_outline->pos[0] = s*130 - 3; - select_outline->pos[1] = v*130 - 3; - - add_transfers( - &select_outline->pos[0], - layer->drawables, - 3*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos), - 1*sizeof(vec2), - gpu); - - add_transfers( - &select->pos[0], - layer->drawables, - 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos), - 1*sizeof(vec2), - gpu); - - add_transfers( - &select->color[0], - layer->drawables, - 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), - 4*sizeof(vec4), - gpu); - - hsv_to_rgb(data->current_hsv, data->current); - update_hex_string(ui, gpu, data); -} - -void sv_square_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { - (void)mods; - (void)x; - - if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { - set_active_element(COLOR_PICK_CONTAINER_ID, 0, 1, ui); - sv_square_pick(ui, gpu, data, x, y); - } else if(action == GLFW_RELEASE && button == GLFW_MOUSE_BUTTON_LEFT) { - clear_active_element(ui, gpu); - } -} - -void sv_square_cursor_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y) { - if(ui->active_element == 1 - && ui->active_layer == 0 - && ui->active_container == COLOR_PICK_CONTAINER_ID) { - sv_square_pick(ui, gpu, data, x, y); - } -} - -void hue_bar_set(UIContext* ui, RenderContext* gpu, ColorUIData* data, float y) { - if(y < 0) y = 0; - if(y > 1) y = 1; - - data->current_hsv[0] = y; - - Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); - Layer* layer = &container->layers[0]; - GPUDrawable* sv_square = &layer->drawables_buffer[1]; - GPUDrawable* sv_select = &layer->drawables_buffer[4]; - GPUDrawable* hue_select = &layer->drawables_buffer[6]; - - sv_square->color[0][0] = y; - sv_square->color[1][0] = y; - sv_square->color[2][0] = y; - sv_square->color[3][0] = y; - - sv_select->color[0][0] = y; - sv_select->color[1][0] = y; - sv_select->color[2][0] = y; - sv_select->color[3][0] = y; - - hue_select->pos[1] = 2 + y*130; - - add_transfers( - &sv_square->color[0], - layer->drawables, - 1*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), - 4*sizeof(vec4), - gpu); - - add_transfers( - &sv_select->color[0], - layer->drawables, - 4*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), - 4*sizeof(vec4), - gpu); - - add_transfers( - &hue_select->pos[1], - layer->drawables, - 6*sizeof(GPUDrawable) + offsetof(GPUDrawable, pos) + sizeof(float), - 1*sizeof(float), - gpu); - - hsv_to_rgb(data->current_hsv, data->current); - update_hex_string(ui, gpu, data); -} - -void hue_bar_scroll_callback(void* data, UIContext* ui, RenderContext* gpu, double x, double y) { - (void)x; - - Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); - hue_bar_set(ui, gpu, data, y*0.01 + container->layers[0].drawables_buffer[1].color[0][0]); -} - -void hue_bar_cursor_callback(void*data, UIContext* ui, RenderContext* gpu, float x, float y) { - (void)x; - - if(ui->active_element == 2 - && ui->active_layer == 0 - && ui->active_container == COLOR_PICK_CONTAINER_ID) { - hue_bar_set(ui, gpu, data, y); - } -} - -void hue_bar_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { - (void)mods; - (void)x; - - if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { - set_active_element(COLOR_PICK_CONTAINER_ID, 0, 2, ui); - hue_bar_set(ui, gpu, data, y); - } else if(action == GLFW_RELEASE && button == GLFW_MOUSE_BUTTON_LEFT) { - clear_active_element(ui, gpu); - } -} - -void hex_string_set_color(UIContext* ui, RenderContext* gpu, float color) { - Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); - container->layers[0].drawables_buffer[5].color[0][2] = color; - container->layers[0].drawables_buffer[5].color[0][3] = color; - - container->layers[0].drawables_buffer[5].color[1][2] = color; - container->layers[0].drawables_buffer[5].color[1][3] = color; - - container->layers[0].drawables_buffer[5].color[2][2] = color; - container->layers[0].drawables_buffer[5].color[2][3] = color; - - container->layers[0].drawables_buffer[5].color[3][2] = color; - container->layers[0].drawables_buffer[5].color[3][3] = color; - - add_transfers( - &container->layers[0].drawables_buffer[5].color[0], - container->layers[0].drawables, - 5*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), - 4*sizeof(vec4), - gpu); -} - -void hex_string_text_callback(void* ptr, UIContext* ui, RenderContext* gpu, unsigned int codepoint) { - ColorUIData* data = ptr; - - if(codepoint >= 'a' && codepoint <= 'f') { - codepoint += 'A' - 'a'; - } else if(!((codepoint >= 'A' && codepoint <= 'F') || (codepoint >= '0' && codepoint <= '9'))) { - return; - } - - if(data->string_len < 8) { - data->string_len += 1; - data->string[data->string_len] = codepoint; - update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); - } -} - -bool hex_string_key_callback(void* ptr, UIContext* ui, RenderContext* gpu, int key, int action, int mods) { - (void)mods; - ColorUIData* data = ptr; - char tmp[3]; - - if(action == GLFW_PRESS) { - switch(key) { - case GLFW_KEY_ESCAPE: - hsv_to_rgb(data->current_hsv, data->current); - update_hex_string(ui, gpu, data); - clear_active_element(ui, gpu); - break; - case GLFW_KEY_ENTER: - // TODO: validate hex string and reset or set hsv - tmp[0] = data->string[1]; - tmp[1] = data->string[2]; - tmp[2] = 0; - data->current[0] = strtol(tmp, NULL, 16)/255.0; - - tmp[0] = data->string[3]; - tmp[1] = data->string[4]; - tmp[2] = 0; - data->current[1] = strtol(tmp, NULL, 16)/255.0; - - tmp[0] = data->string[5]; - tmp[1] = data->string[6]; - tmp[2] = 0; - data->current[2] = strtol(tmp, NULL, 16)/255.0; - - tmp[0] = data->string[7]; - tmp[1] = data->string[8]; - tmp[2] = 0; - data->current[3] = strtol(tmp, NULL, 16)/255.0; - - rgb_to_hsv(data->current, data->current_hsv); - hue_bar_set(ui, gpu, data, data->current_hsv[0]); - sv_square_pick(ui, gpu, data, data->current_hsv[1], 1-data->current_hsv[2]); - - clear_active_element(ui, gpu); - break; - case GLFW_KEY_BACKSPACE: - if(data->string_len > 0) { - data->string[data->string_len] = '\0'; - data->string_len -= 1; - update_ui_string(data->string, COLOR_PICK_CONTAINER_ID, 0, 0, ui, gpu); - } - break; - } - } - - return true; -} - -void hex_string_button_callback(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { - (void)data; - (void)mods; - (void)x; - (void)y; - - if(action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { - set_active_element(COLOR_PICK_CONTAINER_ID, 0, 5, ui); - hex_string_set_color(ui, gpu, 1); - } -} - -void hex_string_deselect_callback(void* data, UIContext* ui, RenderContext* gpu) { - (void)data; - hex_string_set_color(ui, gpu, 0); -} - -void set_saved_color(UIContext* ui, RenderContext* gpu, ColorUIData* data, uint32_t index, vec4 color) { - data->saved[index][0] = color[0]; - data->saved[index][1] = color[1]; - data->saved[index][2] = color[2]; - data->saved[index][3] = color[3]; - - Container* container = context_container(COLOR_PICK_CONTAINER_ID, ui); - Layer* layer = &container->layers[0]; - GPUDrawable* saved_color = &layer->drawables_buffer[7 + index]; - - saved_color->color[0][0] = data->current[0]; - saved_color->color[0][1] = data->current[1]; - saved_color->color[0][2] = data->current[2]; - - saved_color->color[1][0] = data->current[0]; - saved_color->color[1][1] = data->current[1]; - saved_color->color[1][2] = data->current[2]; - - saved_color->color[2][0] = data->current[0]; - saved_color->color[2][1] = data->current[1]; - saved_color->color[2][2] = data->current[2]; - - saved_color->color[3][0] = data->current[0]; - saved_color->color[3][1] = data->current[1]; - saved_color->color[3][2] = data->current[2]; - - add_transfers( - &saved_color->color[0], - layer->drawables, - (7+index)*sizeof(GPUDrawable) + offsetof(GPUDrawable, color), - 4*sizeof(vec4), - gpu); -} - -void saved_color_button_callback( - void* ptr, - UIContext* ui, - RenderContext* gpu, - float x, float y, - int button, int action, int mods, - uint32_t index) { - (void)x; - (void)y; - (void)mods; - - ColorUIData* data = ptr; - - if(action == GLFW_PRESS) { - if(button == GLFW_MOUSE_BUTTON_LEFT) { - data->current[0] = data->saved[index][0]; - data->current[1] = data->saved[index][1]; - data->current[2] = data->saved[index][2]; - data->current[3] = data->saved[index][3]; - rgb_to_hsv(data->current, data->current_hsv); - hue_bar_set(ui, gpu, data, data->current_hsv[0]); - sv_square_pick(ui, gpu, data, data->current_hsv[1], data->current_hsv[2]); - update_hex_string(ui, gpu, data); - } else if(button == GLFW_MOUSE_BUTTON_RIGHT) { - set_saved_color(ui, gpu, data, index, data->current); - } else if (button == GLFW_MOUSE_BUTTON_MIDDLE) { - vec4 clear = {0, 0, 0, 0}; - set_saved_color(ui, gpu, data, index, clear); - } - } -} - -#define SAVED_COLOR_BUTTON_CALLBACK(n) \ -void saved_color_button_callback_##n(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods) { \ - saved_color_button_callback(data, ui, gpu, x, y, button, action, mods, n); \ -} - -SAVED_COLOR_BUTTON_CALLBACK( 0); -SAVED_COLOR_BUTTON_CALLBACK( 1); -SAVED_COLOR_BUTTON_CALLBACK( 2); -SAVED_COLOR_BUTTON_CALLBACK( 3); -SAVED_COLOR_BUTTON_CALLBACK( 4); -SAVED_COLOR_BUTTON_CALLBACK( 5); -SAVED_COLOR_BUTTON_CALLBACK( 6); -SAVED_COLOR_BUTTON_CALLBACK( 7); -SAVED_COLOR_BUTTON_CALLBACK( 8); -SAVED_COLOR_BUTTON_CALLBACK( 9); -SAVED_COLOR_BUTTON_CALLBACK(10); -SAVED_COLOR_BUTTON_CALLBACK(11); - -#define SAVED_COLOR_CALLBACK_ENTRY(n) \ - { \ - .layer = 0, \ - .element = 7 + n, \ - .data = data, \ - .button = saved_color_button_callback_##n, \ - } - -VkResult color_ui(ClientContext* context) { - GPUString strings[] = { - { - .pos = {2, 150}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 0, - .length = 9, - .font = 0, - }, - }; - - GPUDrawable drawables[] = { - { - .pos = {0, 0}, - .size = {190, 150}, - .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, - }, - { - .type = DRAWABLE_TYPE_RECT_HSV, - .pos = {2, 2}, - .size = {130, 130}, - .color = {{0, 0, 1, 1}, {0, 1, 1, 1}, {0, 0, 0, 1}, {0, 1, 0, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .type = DRAWABLE_TYPE_RECT_HSV, - .pos = {134, 2}, - .size = {10, 130}, - .color = {{0, 1, 1, 1}, {0, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON | UI_EVENT_SCROLL, - }, - { - .pos = {130-4, 130-4}, - .size = {7, 7}, - .color = {{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}}, - }, - { - .type = DRAWABLE_TYPE_RECT_HSV, - .pos = {130-3, 130-3}, - .size = {5, 5}, - .color = {{1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}}, - }, - { - .pos = {20, 134}, - .size = {95, 15}, - .events = UI_EVENT_BUTTON | UI_EVENT_CURSOR, - }, - { - .pos = {134, 2}, - .size = {10, 1}, - .color = {{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}}, - }, - { - .pos = {146, 2}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 2}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {146, 24}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 24}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {146, 46}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 46}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {146, 68}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 68}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {146, 90}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 90}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {146, 112}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - { - .pos = {168, 112}, - .size = {20, 20}, - .color = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, - .events = UI_EVENT_BUTTON, - }, - }; - - uint32_t codes[9]; - VkResult result; - VK_RESULT(map_string("#00000000", codes, 0, 0, context->ui)); - - LayerInput layer = { - .strings = strings, - .num_strings = sizeof(strings)/sizeof(GPUString), - .codes = codes, - .num_codes = sizeof(codes)/sizeof(uint32_t), - .drawables = drawables, - .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), - }; - - ColorUIData* data = &context->color; - data->string_len = 8; - data->string[0] = '#'; - data->string[1] = '0'; - data->string[2] = '0'; - data->string[3] = '0'; - data->string[4] = '0'; - data->string[5] = '0'; - data->string[6] = '0'; - data->string[7] = '0'; - data->string[8] = '0'; - data->string[9] = '\0'; - data->current[0] = 0; - data->current[1] = 0; - data->current[2] = 0; - data->current[3] = 0; - - UICallbacks callbacks[] = { - { - .layer = 0, - .element = 1, - .data = data, - .button = sv_square_button_callback, - .cursor = sv_square_cursor_callback, - }, - { - .layer = 0, - .element = 2, - .data = data, - .button = hue_bar_button_callback, - .cursor = hue_bar_cursor_callback, - .scroll = hue_bar_scroll_callback, - }, - { - .layer = 0, - .element = 5, - .data = data, - .button = hex_string_button_callback, - .key = hex_string_key_callback, - .text = hex_string_text_callback, - .deselect = hex_string_deselect_callback, - }, - SAVED_COLOR_CALLBACK_ENTRY( 0), - SAVED_COLOR_CALLBACK_ENTRY( 1), - SAVED_COLOR_CALLBACK_ENTRY( 2), - SAVED_COLOR_CALLBACK_ENTRY( 3), - SAVED_COLOR_CALLBACK_ENTRY( 4), - SAVED_COLOR_CALLBACK_ENTRY( 5), - SAVED_COLOR_CALLBACK_ENTRY( 6), - SAVED_COLOR_CALLBACK_ENTRY( 7), - SAVED_COLOR_CALLBACK_ENTRY( 8), - SAVED_COLOR_CALLBACK_ENTRY( 9), - SAVED_COLOR_CALLBACK_ENTRY(10), - SAVED_COLOR_CALLBACK_ENTRY(11), - }; - - ContainerInput container = { - .layers = &layer, - .layer_count = 1, - .anchor = ANCHOR_BOTTOM_LEFT, - .id = COLOR_PICK_CONTAINER_ID, - .offset = {0, 0}, - .size = {190, 150}, - .callbacks = callbacks, - .callback_count = sizeof(callbacks)/sizeof(UICallbacks), - }; - - return create_container(&container, context->render, context->ui); -} - -VkResult hex_info_ui(ClientContext* context) { - GPUString strings[] = { - { - .pos = {0, 33}, - .color = {1, 1, 1, 1}, - .size = 32, - .offset = 0, - .length = 0, - .font = 0, - }, - { - .pos = {2, 50}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 20, - .length = 0, - .font = 0, - }, - { - .pos = {2, 73}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 40, - .length = 0, - .font = 0, - }, - { - .pos = {2, 93}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 60, - .length = 0, - .font = 0, - }, - { - .pos = {2, 113}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 80, - .length = 0, - .font = 0, - }, - { - .pos = {2, 133}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 100, - .length = 0, - .font = 0, - }, - { - .pos = {2, 153}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 120, - .length = 0, - .font = 0, - }, - { - .pos = {2, 173}, - .color = {1, 1, 1, 1}, - .size = 16, - .offset = 140, - .length = 0, - .font = 0, - }, - - }; - - GPUDrawable drawables[] = { - { - .pos = {0, 0}, - .size = {150, 175}, - .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, - }, - }; - - LayerInput layer = { - .strings = strings, - .num_strings = sizeof(strings)/sizeof(GPUString), - .max_strings = sizeof(strings)/sizeof(GPUString) + 4, - .max_codes = 200, - .drawables = drawables, - .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), - }; - - ContainerInput container = { - .id = 0x02, - .size = {150, 175}, - .offset = {0, 0}, - .anchor = ANCHOR_BOTTOM_RIGHT, - .layers = &layer, - .layer_count = 1, - }; - - return create_container(&container, context->render, context->ui); -} - -VkResult region_info_ui(ClientContext* context) { - - GPUString strings[] = { - { - .pos = {0, 33}, - .color = {1, 1, 1, 1}, - .size = 32, - .offset = 0, - .length = 0, - .font = 0, - }, - { - .pos = {0, 33 + 1*40}, - .color = {1, 1, 1, 1}, - .size = 32, - .offset = 11, - .length = 0, - .font = 0, - }, - { - .pos = {0, 33 + 2*40}, - .color = {1, 1, 1, 1}, - .size = 32, - .offset = 18, - .length = 0, - .font = 0, - }, - { - .pos = {0, 33 + 3*40}, - .color = {1, 1, 1, 1}, - .size = 32, - .offset = 25, - .length = 0, - .font = 0, - }, - }; - - GPUDrawable drawables[] = { - { - .pos = {0, 0}, - .size = {225, 155}, - .color = {{0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}, {0.4, 0.4, 0.4, 0.4}}, - }, - }; - - LayerInput layer = { - .strings = strings, - .num_strings = sizeof(strings)/sizeof(GPUString), - .max_strings = sizeof(strings)/sizeof(GPUString) + 4, - .max_codes = 100, - .drawables = drawables, - .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), - }; - - ContainerInput container = { - .id = 0x01, - .size = {225, 155}, - .offset = {0, 0}, - .anchor = ANCHOR_TOP_RIGHT, - .layers = &layer, - .layer_count = 1, - }; - - return create_container(&container, context->render, context->ui); -} - -VkResult update_region_info_ui(ClientContext* context) { - char temp[20]; - VkResult result; - HexRegion* selected_region = context->hex->regions[context->editor.selected_region]; - - snprintf(temp, - sizeof(temp), - "Region %4d", context->editor.selected_region); - VK_RESULT(update_ui_string(temp, 0x01, 0, 0, context->ui, context->render)); - - if(selected_region == NULL) { - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x01, 0, 1, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x01, 0, 2, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x01, 0, 3, context->ui, context->render)); - } else { - snprintf( - temp, - sizeof(temp), - "Q: %4d", selected_region->data.q); - VK_RESULT(update_ui_string(temp, 0x01, 0, 1, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "R: %4d", selected_region->data.r); - VK_RESULT(update_ui_string(temp, 0x01, 0, 2, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "Y: %4d", selected_region->data.y); - VK_RESULT(update_ui_string(temp, 0x01, 0, 3, context->ui, context->render)); - } - - return VK_SUCCESS; -} - -VkResult update_hex_info_ui(ClientContext* context) { - char temp[20]; - VkResult result; - HexRegion* region = context->hex->regions[context->hex->data.clicked_region]; - - - if(region == NULL) { - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 0, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 1, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 2, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 3, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 4, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 5, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 6, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - ""); - VK_RESULT(update_ui_string(temp, 0x02, 0, 7, context->ui, context->render)); - } else { - GPUHex* hex = ®ion->data.hexes[context->hex->data.clicked_hex]; - snprintf(temp, - sizeof(temp), - "%d-%d", - context->hex->data.clicked_region, - context->hex->data.clicked_hex); - VK_RESULT(update_ui_string(temp, 0x02, 0, 0, context->ui, context->render)); - - int32_t hex_index = context->hex->data.clicked_hex; - - float radius = 0; - float ring = 0; - int side = 0; - if(hex_index != 0) { - radius = floor(0.5 + sqrt(12*hex_index-3)/6); - ring = hex_index - (3*radius*radius - 3*radius + 1); - side = floor(ring/radius); - } - - // TODO: fix, these are wrong lmao - int32_t hex_q = hex_starts_qr[side][0]*radius + hex_directions_qr[side][0]*(ring-(radius*side)); - int32_t hex_r = hex_starts_qr[side][1]*radius + hex_directions_qr[side][1]*(ring-(radius*side)); - - int32_t world_q = hex_q + region->data.q*(REGION_SIZE*2 + 1) + region->data.r*REGION_SIZE; - int32_t world_r = hex_r + region->data.q*(REGION_SIZE + 0.5) + region->data.r*(REGION_SIZE*2+1); - - snprintf( - temp, - sizeof(temp), - "%d, %d, %d, %d", - world_q, - world_r, - region->data.y, - context->hex->data.clicked_vertex); - VK_RESULT(update_ui_string(temp, 0x02, 0, 1, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%02.02f %02.02f %02.02f", - hex->height[0], hex->height[1], hex->height[2]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 2, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%02.02f %02.02f %02.02f", - hex->height[3], hex->height[4], hex->height[5]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 3, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%08X", - hex->color[0]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 4, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%08X %08X", - hex->color[1], hex->color[2]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 5, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%08X %08X", - hex->color[3], hex->color[4]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 6, context->ui, context->render)); - - snprintf( - temp, - sizeof(temp), - "%08X %08X", - hex->color[5], hex->color[6]); - VK_RESULT(update_ui_string(temp, 0x02, 0, 7, context->ui, context->render)); - } - - return VK_SUCCESS; -} - -VkResult main_thread(ClientContext* context) { - VkResult result; - - VK_RESULT(region_info_ui(context)); - VK_RESULT(hex_info_ui(context)); - VK_RESULT(color_ui(context)); - - // - double last_frame_time = 0; - while(glfwWindowShouldClose(context->window) == 0) { - double frame_time = glfwGetTime(); - double delta_time = (frame_time - last_frame_time); - - // Reset callback variables - context->zoom = 0; - context->cur_spin[0] = 0; - context->cur_spin[1] = 0; - - glfwPollEvents(); - - if(context->editor.last_clicked_region != context->hex->data.clicked_region || - context->editor.last_clicked_hex != context->hex->data.clicked_hex || - context->editor.last_clicked_vertex != context->hex->data.clicked_vertex) { - context->editor.last_clicked_region = context->hex->data.clicked_region; - context->editor.last_clicked_hex = context->hex->data.clicked_hex; - context->editor.last_clicked_vertex = context->hex->data.clicked_vertex; - update_hex_info_ui(context); - } - - if(context->editor.selected_region != context->editor.last_selected_region) { - context->editor.last_selected_region = context->editor.selected_region; - update_region_info_ui(context); - } - - if((context->key_spin[0] != 0 || context->key_spin[1] != 0 || - context->velocity[0] != 0 || context->velocity[1] != 0 || context->velocity[2] != 0 || - context->zoom != 0 || - context->cur_spin[0] != 0 || context->cur_spin[1] != 0 || - context->render->framebuffer_recreated == true)) { - - - if(context->render->framebuffer_recreated == true) { - context->render->framebuffer_recreated = false; - VK_RESULT(update_hex_proj(context->render, context->hex)); - VK_RESULT(update_ui_context_resolution(context->ui, context->render)); - } - - context->rotation[0] += (float)context->key_spin[0]*delta_time*context->key_spin_speed; - context->rotation[0] += (float)context->cur_spin[0]*delta_time*context->cur_spin_speed; - if(context->rotation[0] > 2*M_PI) { - context->rotation[0] -= 2*M_PI; - } else if(context->rotation[0] < 0) { - context->rotation[0] += 2*M_PI; - } - - context->rotation[1] += (float)context->key_spin[1]*delta_time*context->key_spin_speed; - context->rotation[1] += (float)context->cur_spin[1]*delta_time*context->cur_spin_speed; - if(context->rotation[1] > (M_PI/2 - 0.1)) { - context->rotation[1] = (M_PI/2 - 0.1); - } else if(context->rotation[1] < 0) { - context->rotation[1] = 0; - } - - context->position[0] += - context->velocity[2]*context->move_speed*cos(context->rotation[0]) - - context->velocity[0]*context->move_speed*sin(context->rotation[0]); - - context->position[2] += context->velocity[0]*context->move_speed*cos(context->rotation[0]) - - context->velocity[2]*context->move_speed*sin(context->rotation[0]); - - context->position[1] += context->velocity[1]*context->move_speed; - - context->distance += context->zoom*delta_time*context->zoom_speed; - if(context->distance < 1) { - context->distance = 1; - } - - VK_RESULT(update_hex_view( - context->position, - context->rotation, - context->distance, - context->render, - context->hex)); - } - // - - VkResult result = draw_frame(context->render, context->ui, context->hex, frame_time); - if(result != VK_SUCCESS) { - fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); - glfwDestroyWindow(context->window); - } - - last_frame_time = frame_time; - } - - return 0; -} - -void text_callback(GLFWwindow* window, unsigned int codepoint) { - ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); - if(context->ui->active_callbacks != NULL && context->ui->active_callbacks->text != NULL) { - context->ui->active_callbacks->text( - context->ui->active_callbacks->data, - context->ui, - context->render, - codepoint); - } -} - -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - (void)scancode; - (void)mods; - - ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); - if(context->ui->active_callbacks != NULL && context->ui->active_callbacks->key != NULL) { - if(context->ui->active_callbacks->key( - context->ui->active_callbacks->data, - context->ui, - context->render, - key, - action, - mods)) { - return; - } - } - - switch(key) { - case GLFW_KEY_A: - if(action == GLFW_PRESS) { - context->key_spin[0] -= 1; - } else if(action == GLFW_RELEASE) { - context->key_spin[0] += 1; - } - break; - case GLFW_KEY_D: - if(action == GLFW_PRESS) { - context->key_spin[0] += 1; - } else if(action == GLFW_RELEASE) { - context->key_spin[0] -= 1; - } - break; - - case GLFW_KEY_W: - if(action == GLFW_PRESS) { - context->key_spin[1] += 1; - } else if(action == GLFW_RELEASE) { - context->key_spin[1] -= 1; - } - break; - case GLFW_KEY_S: - if(action == GLFW_PRESS) { - context->key_spin[1] -= 1; - } else if(action == GLFW_RELEASE) { - context->key_spin[1] += 1; - } - break; - - case GLFW_KEY_UP: - if(action == GLFW_PRESS) { - context->velocity[2] += 1; - } else if(action == GLFW_RELEASE) { - context->velocity[2] -= 1; - } - break; - case GLFW_KEY_DOWN: - if(action == GLFW_PRESS) { - context->velocity[2] -= 1; - } else if(action == GLFW_RELEASE) { - context->velocity[2] += 1; - } - break; - - case GLFW_KEY_LEFT: - if(action == GLFW_PRESS) { - context->velocity[0] -= 1; - } else if(action == GLFW_RELEASE) { - context->velocity[0] += 1; - } - break; - case GLFW_KEY_RIGHT: - if(action == GLFW_PRESS) { - context->velocity[0] += 1; - } else if(action == GLFW_RELEASE) { - context->velocity[0] -= 1; - } - break; - - case GLFW_KEY_LEFT_SHIFT: - if(action == GLFW_PRESS) { - context->velocity[1] -= 1; - } else if(action == GLFW_RELEASE) { - context->velocity[1] += 1; - } - break; - case GLFW_KEY_SPACE: - if(action == GLFW_PRESS) { - context->velocity[1] += 1; - } else if(action == GLFW_RELEASE) { - context->velocity[1] -= 1; - } - break; - - case GLFW_KEY_EQUAL: - if(action == GLFW_PRESS) { - context->editor.selected_region = add_hex_region(context); - } - break; - - case GLFW_KEY_LEFT_BRACKET: - if(action == GLFW_PRESS) { - context->editor.selected_region -= 1; - if(context->editor.selected_region > MAX_LOADED_REGIONS) { - context->editor.selected_region = MAX_LOADED_REGIONS; - } - } - break; - case GLFW_KEY_RIGHT_BRACKET: - if(action == GLFW_PRESS) { - context->editor.selected_region += 1; - if(context->editor.selected_region > MAX_LOADED_REGIONS) { - context->editor.selected_region = 0; - } - } - break; - - case GLFW_KEY_I: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.q += 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.q, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, q), - sizeof(uint32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - case GLFW_KEY_K: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.q -= 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.q, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, q), - sizeof(uint32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - case GLFW_KEY_J: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.r += 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.r, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, r), - sizeof(uint32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - case GLFW_KEY_L: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.r -= 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.r, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, r), - sizeof(uint32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - case GLFW_KEY_O: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.y += 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.y, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, y), - sizeof(int32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - case GLFW_KEY_U: - if(action == GLFW_PRESS) { - if(context->hex->regions[context->editor.selected_region] != NULL) { - context->hex->regions[context->editor.selected_region]->data.y -= 1; - add_transfer( - &context->hex->regions[context->editor.selected_region]->data.y, - context->hex->regions[context->editor.selected_region]->region, - offsetof(GPUHexRegion, y), - sizeof(int32_t), - context->render->current_frame, - context->render); - } - update_region_info_ui(context); - } - break; - - case GLFW_KEY_Y: - if(action == GLFW_PRESS) { - HexRegion* region = context->hex->regions[context->hex->data.clicked_region]; - if(region != NULL) { - region->data.hexes[context->hex->data.clicked_hex].height[context->hex->data.clicked_vertex-1] += 0.1; - add_transfer( - ®ion->data.hexes[context->hex->data.clicked_hex].height[context->hex->data.clicked_vertex-1], - region->region, - offsetof(GPUHexRegion, hexes) - + sizeof(GPUHex)*context->hex->data.clicked_hex - + offsetof(GPUHex, height) - + sizeof(float)*(context->hex->data.clicked_vertex-1), - sizeof(float), - context->render->current_frame, - context->render); - update_hex_info_ui(context); - } - } - break; - case GLFW_KEY_H: - if(action == GLFW_PRESS) { - HexRegion* region = context->hex->regions[context->hex->data.clicked_region]; - if(region != NULL) { - region->data.hexes[context->hex->data.clicked_hex].height[context->hex->data.clicked_vertex-1] -= 0.1; - add_transfer( - ®ion->data.hexes[context->hex->data.clicked_hex].height[context->hex->data.clicked_vertex-1], - region->region, - offsetof(GPUHexRegion, hexes) - + sizeof(GPUHex)*context->hex->data.clicked_hex - + offsetof(GPUHex, height) - + sizeof(float)*(context->hex->data.clicked_vertex-1), - sizeof(float), - context->render->current_frame, - context->render); - update_hex_info_ui(context); - } - } - break; - - case GLFW_KEY_E: - if(action == GLFW_PRESS) { - HexRegion* region = context->hex->regions[context->hex->data.clicked_region]; - if(region != NULL) { - region->data.hexes[context->hex->data.clicked_hex].color[context->hex->data.clicked_vertex] = hex_color(context->color.current); - add_transfer( - ®ion->data.hexes[context->hex->data.clicked_hex].color[context->hex->data.clicked_vertex], - region->region, - offsetof(GPUHexRegion, hexes) - + sizeof(GPUHex)*context->hex->data.clicked_hex - + offsetof(GPUHex, color) - + sizeof(uint32_t)*(context->hex->data.clicked_vertex), - sizeof(uint32_t), - context->render->current_frame, - context->render); - update_hex_info_ui(context); - } - } - break; - } -} - -void button_callback(GLFWwindow* window, int button, int action, int mods) { - double cursor[2]; - uint32_t container; - uint32_t layer; - uint32_t element; - vec2 position; - - ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); - - glfwGetCursorPos(window, &cursor[0], &cursor[1]); - - if(context->ui->active_callbacks != NULL && context->ui->active_callbacks->button != NULL) { - Container* container_ptr = context_container(context->ui->active_container, context->ui); - GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui->active_layer].drawables_buffer[context->ui->active_element]; - vec2 element_pos = { - drawable_ptr->pos[0] + container_ptr->data.offset[0], - drawable_ptr->pos[1] + container_ptr->data.offset[1], - }; - anchor_offset(context->render, container_ptr, element_pos); - vec2 element_size = { - drawable_ptr->size[0], - drawable_ptr->size[1], - }; - - vec2 point = { - (cursor[0] - element_pos[0])/element_size[0], - (cursor[1] - element_pos[1])/element_size[1], - }; - - if((point[0] <= 1 && point[0] >= 0 && point[1] <= 1 && point[1] >= 0) || action == GLFW_RELEASE) { - context->ui->active_callbacks->button( - context->ui->active_callbacks->data, - context->ui, - context->render, - point[0], - point[1], - button, - action, - mods); - return; - } else { - clear_active_element(context->ui, context->render); - } - } - - if(ui_intersect(cursor, context->render, context->ui, UI_EVENT_BUTTON, &container, &layer, &element, position)) { - Container* container_ptr = context_container(container, context->ui); - for(uint32_t c = 0; c < container_ptr->callback_count; c++) { - if(container_ptr->callbacks[c].element == element) { - if(container_ptr->callbacks[c].button != NULL) { - container_ptr->callbacks[c].button( - container_ptr->callbacks[c].data, - context->ui, - context->render, - position[0], - position[1], - button, - action, - mods); - } - break; - } - } - } else { - } - - update_hex_click(cursor, context->hex, context->render); - if(button == GLFW_MOUSE_BUTTON_MIDDLE) { - if(action == GLFW_PRESS) { - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - context->camera_mode = true; - } else { - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - context->camera_mode = false; - } - } -} - -void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - (void)xoffset; - uint32_t container; - uint32_t layer; - uint32_t element; - vec2 position; - - ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); - if(context->ui->active_callbacks != NULL && context->ui->active_callbacks->scroll != NULL) { - context->ui->active_callbacks->scroll( - context->ui->active_callbacks->data, - context->ui, - context->render, - xoffset, - yoffset); - } else if(ui_intersect( - context->ui->cursor, - context->render, - context->ui, - UI_EVENT_SCROLL, - &container, - &layer, - &element, - position)) { - Container* container_ptr = context_container(container, context->ui); - for(uint32_t c = 0; c < container_ptr->callback_count; c++) { - if(container_ptr->callbacks[c].element == element) { - if(container_ptr->callbacks[c].scroll != NULL) { - container_ptr->callbacks[c].scroll( - container_ptr->callbacks[c].data, - context->ui, - context->render, - xoffset, - yoffset); - } - break; - } - } - } else { - context->zoom = -yoffset; - } -} - -void cursor_callback(GLFWwindow* window, double xpos, double ypos) { - ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); - uint32_t container; - uint32_t element; - uint32_t layer; - vec2 position; - vec2 last_cursor = { - context->ui->cursor[0], - context->ui->cursor[1], - }; - - context->ui->cursor[0] = xpos; - context->ui->cursor[1] = ypos; - - if(context->camera_mode == true) { - context->cur_spin[0] = (xpos - last_cursor[0])/context->render->swapchain_extent.width*-100; - context->cur_spin[1] = (ypos - last_cursor[1])/context->render->swapchain_extent.height*100; - } else { - if(context->ui->active_callbacks != NULL && context->ui->active_callbacks->cursor != NULL) { - Container* container_ptr = context_container(context->ui->active_container, context->ui); - GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui->active_layer].drawables_buffer[context->ui->active_element]; - vec2 element_pos = { - drawable_ptr->pos[0] + container_ptr->data.offset[0], - drawable_ptr->pos[1] + container_ptr->data.offset[1], - }; - anchor_offset(context->render, container_ptr, element_pos); - vec2 element_size = { - drawable_ptr->size[0], - drawable_ptr->size[1], - }; - context->ui->active_callbacks->cursor( - context->ui->active_callbacks->data, - context->ui, - context->render, - (context->ui->cursor[0] - element_pos[0])/element_size[0], - (context->ui->cursor[1] - element_pos[1])/element_size[1]); - } else if(ui_intersect(context->ui->cursor, context->render, context->ui, UI_EVENT_CURSOR, &container, &layer, &element, position)) { - Container* container_ptr = context_container(container, context->ui); - for(uint32_t c = 0; c < container_ptr->callback_count; c++) { - if(container_ptr->callbacks[c].element == element) { - if(container_ptr->callbacks[c].cursor != NULL) { - container_ptr->callbacks[c].cursor( - container_ptr->callbacks[c].data, - context->ui, - context->render, - position[0], - position[1]); - } - break; - } - } - } else { - update_hex_hover(context->ui->cursor, context->hex, context->render); - } - } -} +#include "engine.h" int main() { - ClientContext context = { - .render = malloc(sizeof(RenderContext)), - .ui = malloc(sizeof(UIContext)), - .hex = malloc(sizeof(HexContext)), - .window = init_window(), - - .position = {0, 0, 0}, - .rotation = {3*M_PI/2, M_PI/4}, - .distance = 25, - .key_spin_speed = 1.0, - .cur_spin_speed = 1.0, - .zoom_speed = 1.0, - .move_speed = 0.1, - - .editor = { - .selected_region = MAX_LOADED_REGIONS, - .last_selected_region = 0, - - .last_clicked_region = MAX_LOADED_REGIONS, - }, - }; - if(context.window == NULL || context.render == NULL || context.ui == NULL || context.hex == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - - memset(context.render, 0, sizeof(RenderContext)); - memset(context.ui, 0, sizeof(UIContext)); - memset(context.hex, 0, sizeof(HexContext)); - - glfwSetWindowUserPointer(context.window, &context); - glfwSetKeyCallback(context.window, key_callback); - glfwSetMouseButtonCallback(context.window, button_callback); - glfwSetScrollCallback(context.window, scroll_callback); - glfwSetCursorPosCallback(context.window, cursor_callback); - glfwSetCharCallback(context.window, text_callback); - - int error; - VkResult result; - VK_RESULT(init_vulkan(context.window, context.render)); - - - // TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary - VK_RESULT(create_ui_context(10, 10, 10, context.render, context.ui)); - VK_RESULT(create_hex_context(context.render, context.hex)); - - pthread_t network_thread_handle; - - error = pthread_create(&network_thread_handle, NULL, &network_thread, &context); - if(error != 0) { - return error; - } - - error = main_thread(&context); - if(error != 0) { - return error; - } - - error = pthread_join(network_thread_handle, NULL); - if(error != 0) { - return error; - } - - return 0; + return run_app(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); }