diff --git a/client/include/hex.h b/client/include/hex.h index c83d052..d56b098 100644 --- a/client/include/hex.h +++ b/client/include/hex.h @@ -34,8 +34,7 @@ typedef struct GPUHexStruct { } GPUHex; typedef struct GPUHexRegionStruct { - int32_t q; - int32_t r; + HexCoord position; int32_t y; uint32_t map; @@ -106,6 +105,11 @@ VkResult allocate_hex_region( HexContext* hex, RenderContext* gpu); +VkResult free_hex_region( + uint32_t region_index, + HexContext* hex, + RenderContext* gpu); + bool ray_world_intersect( float* distance, uint32_t* vertex, @@ -144,4 +148,11 @@ void hex_add(HexCoord from, HexCoord* to); void hex_index(HexCoord world, HexCoord* region, uint32_t* hex); +void hex_vertex_neighbors( + uint32_t vertex, HexCoord hex, + uint32_t n_vertex[2], HexCoord n_region[2], uint32_t n_hex[2]); + +void first_matching_region(HexCoord coord, int y, uint32_t* region, HexContext* context); + + #endif diff --git a/client/src/editor.c b/client/src/editor.c index 8b8070e..1a6c201 100644 --- a/client/src/editor.c +++ b/client/src/editor.c @@ -1,6 +1,8 @@ #include +#include "hex.h" #include "hsv.h" #include "engine.h" +#include "vulkan/vulkan_core.h" #include #include @@ -8,7 +10,6 @@ #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; @@ -29,6 +30,35 @@ uint32_t hex_color(vec4 color) { + ((lrint(color[3]*255.0) & 0xFF) << 0); } +VkResult set_vertex_height(float height, uint32_t region, uint32_t hex, uint32_t vertex, ClientContext* context) { + if(vertex == 0) return VK_ERROR_VALIDATION_FAILED_EXT; + context->hex.regions[region]->data.hexes[hex].height[vertex-1] = height; + return add_transfer( + &context->hex.regions[region]->data.hexes[hex].height[vertex-1], + context->hex.regions[region]->region, + offsetof(GPUHexRegion, hexes) + + sizeof(GPUHex)*hex + + offsetof(GPUHex, height) + + sizeof(float)*(vertex-1), + sizeof(float), + context->render.current_frame, + &context->render); +} + +VkResult set_vertex_color(vec4 color, uint32_t region, uint32_t hex, uint32_t vertex, ClientContext* context) { + context->hex.regions[region]->data.hexes[hex].color[vertex] = hex_color(color); + return add_transfer( + &context->hex.regions[region]->data.hexes[hex].color[vertex], + context->hex.regions[region]->region, + offsetof(GPUHexRegion, hexes) + + sizeof(GPUHex)*hex + + offsetof(GPUHex, color) + + sizeof(uint32_t)*vertex, + sizeof(uint32_t), + context->render.current_frame, + &context->render); +} + uint32_t add_hex_region(ClientContext* context) { HexRegion* region; @@ -834,12 +864,13 @@ VkResult update_region_info_ui(ClientContext* context) { 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, 0, &context->ui, &context->render)); + snprintf( temp, sizeof(temp), @@ -858,16 +889,21 @@ VkResult update_region_info_ui(ClientContext* context) { ""); VK_RESULT(update_ui_string(temp, 0x01, 0, 3, &context->ui, &context->render)); } else { + snprintf(temp, + sizeof(temp), + "Region %4d", data->selected_region); + VK_RESULT(update_ui_string(temp, 0x01, 0, 0, &context->ui, &context->render)); + snprintf( temp, sizeof(temp), - "Q: %4d", selected_region->data.q); + "Q: %4d", selected_region->data.position.q); VK_RESULT(update_ui_string(temp, 0x01, 0, 1, &context->ui, &context->render)); snprintf( temp, sizeof(temp), - "R: %4d", selected_region->data.r); + "R: %4d", selected_region->data.position.r); VK_RESULT(update_ui_string(temp, 0x01, 0, 2, &context->ui, &context->render)); snprintf( @@ -943,14 +979,12 @@ VkResult update_hex_info_ui(ClientContext* context) { context->hex.data.clicked_hex); VK_RESULT(update_ui_string(temp, 0x02, 0, 0, &context->ui, &context->render)); - HexCoord hex_world; hex_qr(context->hex.data.clicked_hex, &hex_world); - - HexCoord region_coord = {region->data.q, region->data.r}; + + HexCoord region_coord = {region->data.position.q, region->data.position.r}; HexCoord region_world; region_qr(region_coord, ®ion_world); - hex_add(region_world, &hex_world); snprintf( @@ -1010,7 +1044,7 @@ VkResult update_hex_info_ui(ClientContext* context) { } bool editor_key_callback(ClientContext* context, int key, int action, int mods) { - (void)mods; + uint32_t start, next_region; if(action != GLFW_PRESS) return false; @@ -1020,28 +1054,59 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) switch(key) { case GLFW_KEY_EQUAL: data->selected_region = add_hex_region(context); + update_region_info_ui(context); + update_hex_info_ui(context); break; - case GLFW_KEY_LEFT_BRACKET: - data->selected_region -= 1; - if(data->selected_region > MAX_LOADED_REGIONS) { + case GLFW_KEY_MINUS: + free_hex_region(data->selected_region, &context->hex, &context->render); + start = data->selected_region; + next_region = start; + do { + next_region -= 1; + if(next_region > MAX_LOADED_REGIONS) next_region = MAX_LOADED_REGIONS; + if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; + } while(next_region != start); + if(next_region == start) { data->selected_region = MAX_LOADED_REGIONS; + } else { + data->selected_region = next_region; } + update_region_info_ui(context); + update_hex_info_ui(context); + break; + + case GLFW_KEY_LEFT_BRACKET: + start = data->selected_region; + next_region = start; + do { + next_region -= 1; + if(next_region > MAX_LOADED_REGIONS) next_region = MAX_LOADED_REGIONS; + if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; + } while(next_region != start); + data->selected_region = next_region; + update_region_info_ui(context); break; + case GLFW_KEY_RIGHT_BRACKET: - data->selected_region += 1; - if(data->selected_region > MAX_LOADED_REGIONS) { - data->selected_region = 0; - } + start = data->selected_region; + next_region = start; + do { + next_region += 1; + if(next_region > MAX_LOADED_REGIONS) next_region = 0; + if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; + } while(next_region != start); + data->selected_region = next_region; + update_region_info_ui(context); break; case GLFW_KEY_I: if(context->hex.regions[data->selected_region] != NULL) { - context->hex.regions[data->selected_region]->data.q += 1; + context->hex.regions[data->selected_region]->data.position.q += 1; add_transfer( - &context->hex.regions[data->selected_region]->data.q, + &context->hex.regions[data->selected_region]->data.position, context->hex.regions[data->selected_region]->region, - offsetof(GPUHexRegion, q), + offsetof(GPUHexRegion, position), sizeof(uint32_t), context->render.current_frame, &context->render); @@ -1050,11 +1115,11 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) break; case GLFW_KEY_K: if(context->hex.regions[data->selected_region] != NULL) { - context->hex.regions[data->selected_region]->data.q -= 1; + context->hex.regions[data->selected_region]->data.position.q -= 1; add_transfer( - &context->hex.regions[data->selected_region]->data.q, + &context->hex.regions[data->selected_region]->data.position.q, context->hex.regions[data->selected_region]->region, - offsetof(GPUHexRegion, q), + offsetof(GPUHexRegion, position) + offsetof(HexCoord, q), sizeof(uint32_t), context->render.current_frame, &context->render); @@ -1063,11 +1128,11 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) break; case GLFW_KEY_J: if(context->hex.regions[data->selected_region] != NULL) { - context->hex.regions[data->selected_region]->data.r += 1; + context->hex.regions[data->selected_region]->data.position.r += 1; add_transfer( - &context->hex.regions[data->selected_region]->data.r, + &context->hex.regions[data->selected_region]->data.position.r, context->hex.regions[data->selected_region]->region, - offsetof(GPUHexRegion, r), + offsetof(GPUHexRegion, position) + offsetof(HexCoord, r), sizeof(uint32_t), context->render.current_frame, &context->render); @@ -1076,11 +1141,11 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) break; case GLFW_KEY_L: if(context->hex.regions[data->selected_region] != NULL) { - context->hex.regions[data->selected_region]->data.r -= 1; + context->hex.regions[data->selected_region]->data.position.r -= 1; add_transfer( - &context->hex.regions[data->selected_region]->data.r, + &context->hex.regions[data->selected_region]->data.position.r, context->hex.regions[data->selected_region]->region, - offsetof(GPUHexRegion, r), + offsetof(GPUHexRegion, position) + offsetof(HexCoord, r), sizeof(uint32_t), context->render.current_frame, &context->render); @@ -1116,35 +1181,54 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) 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); + if(region != NULL && context->hex.data.clicked_vertex != 0) { + float height = region->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1] + 0.1; + + if(~mods & GLFW_MOD_CONTROL) { + uint32_t n_vertex[2], n_hex[2]; + HexCoord n_region[2]; + HexCoord world, region_center; + + region_qr(region->data.position, ®ion_center); + hex_qr(context->hex.data.clicked_hex, &world); + hex_add(region_center, &world); + hex_vertex_neighbors(context->hex.data.clicked_vertex, world, n_vertex, n_region, n_hex); + + uint32_t n0, n1; + first_matching_region(n_region[0], region->data.y, &n0, &context->hex); + first_matching_region(n_region[1], region->data.y, &n1, &context->hex); + + if(n0 != MAX_LOADED_REGIONS) set_vertex_height(height, n0, n_hex[0], n_vertex[0], context); + if(n1 != MAX_LOADED_REGIONS) set_vertex_height(height, n1, n_hex[1], n_vertex[1], context); + } + set_vertex_height(height, context->hex.data.clicked_region, context->hex.data.clicked_hex, context->hex.data.clicked_vertex, context); 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); + if(region != NULL && context->hex.data.clicked_vertex != 0) { + float height = region->data.hexes[context->hex.data.clicked_hex].height[context->hex.data.clicked_vertex-1] - 0.1; + + if(~mods & GLFW_MOD_CONTROL) { + uint32_t n_vertex[2], n_hex[2]; + HexCoord n_region[2]; + HexCoord world, region_center; + + region_qr(region->data.position, ®ion_center); + hex_qr(context->hex.data.clicked_hex, &world); + hex_add(region_center, &world); + hex_vertex_neighbors(context->hex.data.clicked_vertex, world, n_vertex, n_region, n_hex); + + uint32_t n0, n1; + first_matching_region(n_region[0], region->data.y, &n0, &context->hex); + first_matching_region(n_region[1], region->data.y, &n1, &context->hex); + + if(n0 != MAX_LOADED_REGIONS) set_vertex_height(height, n0, n_hex[0], n_vertex[0], context); + if(n1 != MAX_LOADED_REGIONS) set_vertex_height(height, n1, n_hex[1], n_vertex[1], context); + } + set_vertex_height(height, context->hex.data.clicked_region, context->hex.data.clicked_hex, context->hex.data.clicked_vertex, context); update_hex_info_ui(context); } break; @@ -1152,17 +1236,24 @@ bool editor_key_callback(ClientContext* context, int key, int action, int mods) 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); + uint32_t n_vertex[2], n_hex[2]; + HexCoord n_region[2]; + HexCoord world, region_center; + + if(context->hex.data.clicked_vertex != 0) { + region_qr(region->data.position, ®ion_center); + hex_qr(context->hex.data.clicked_hex, &world); + hex_add(region_center, &world); + hex_vertex_neighbors(context->hex.data.clicked_vertex, world, n_vertex, n_region, n_hex); + + uint32_t n0, n1; + first_matching_region(n_region[0], region->data.y, &n0, &context->hex); + first_matching_region(n_region[1], region->data.y, &n1, &context->hex); + + if(n0 != MAX_LOADED_REGIONS) set_vertex_color(data->current, n0, n_hex[0], n_vertex[0], context); + if(n1 != MAX_LOADED_REGIONS) set_vertex_color(data->current, n1, n_hex[1], n_vertex[1], context); + } + set_vertex_color(data->current, context->hex.data.clicked_region, context->hex.data.clicked_hex, context->hex.data.clicked_vertex, context); update_hex_info_ui(context); } break; @@ -1181,11 +1272,6 @@ void editor_frame(ClientContext* context) { 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) { @@ -1194,22 +1280,6 @@ void editor_startup(ClientContext* context) { color_ui(context); } -void hex_vertex_neighbors( - uint32_t vertex, HexCoord region, uint32_t hex, - uint32_t n_vertex[2], HexCoord n_region[2], uint32_t n_hex[2]) { - HexCoord n1 = hex_directions_qr[(vertex+1) % 6]; - HexCoord n2 = hex_directions_qr[(vertex+2) % 6]; - - HexCoord hex_world; - HexCoord region_world; - - region_qr(region, ®ion_world); - hex_qr(hex, &hex_world); - hex_add(region_world, &hex_world); - hex_add(hex_world, &n1); - hex_add(hex_world, &n2); -} - int main() { EditorData* data = malloc(sizeof(EditorData)); memset(data, 0, sizeof(EditorData)); diff --git a/client/src/hex.c b/client/src/hex.c index c05ccd2..ece591c 100644 --- a/client/src/hex.c +++ b/client/src/hex.c @@ -759,6 +759,24 @@ VkResult set_hex_region(HexRegion* region, HexContext* hex, RenderContext* gpu) gpu); } +VkResult free_hex_region( + uint32_t region_index, + HexContext* hex, + RenderContext* gpu) { + if(hex->regions[region_index] == NULL) return VK_ERROR_VALIDATION_FAILED_EXT; + + free(hex->regions[region_index]); + hex->regions[region_index] = NULL; + + VkDeviceAddress null_address = 0x00; + return add_transfers( + &null_address, + hex->context, + offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*region_index, + sizeof(VkDeviceAddress), + gpu); +} + VkResult allocate_hex_region( int32_t q, int32_t r, @@ -782,8 +800,8 @@ VkResult allocate_hex_region( return VK_ERROR_OUT_OF_HOST_MEMORY; } - (*region)->data.q = q; - (*region)->data.r = r; + (*region)->data.position.q = q; + (*region)->data.position.r = r; (*region)->data.y = y; (*region)->data.map = map; VK_RESULT(create_storage_buffer( @@ -793,9 +811,9 @@ VkResult allocate_hex_region( &(*region)->region, &(*region)->region_memory)); VK_RESULT(add_transfer( - &(*region)->data.q, + &(*region)->data.position, (*region)->region, - offsetof(GPUHexRegion, q), + offsetof(GPUHexRegion, position), sizeof(int32_t)*3 + sizeof(uint32_t), gpu->current_frame, gpu)); @@ -920,9 +938,9 @@ bool ray_region_intersect( float intersect_distance = INFINITY; uint32_t intersection_vertex = 0; vec3 region_offset = { - ((float)region->data.q + (float)region->data.r/2)*REGION_WIDTH - region->data.r*HEX_X/2, + ((float)region->data.position.q + (float)region->data.position.r/2)*REGION_WIDTH - region->data.position.r*HEX_X/2, 0, - 0.75*region->data.r*REGION_HEIGHT + 0.25*region->data.r*HEX_Z + 0.5*region->data.q*HEX_Z, + 0.75*region->data.position.r*REGION_HEIGHT + 0.25*region->data.position.r*HEX_Z + 0.5*region->data.position.q*HEX_Z, }; for(uint32_t intersect_hid = 0; intersect_hid < REGION_HEX_COUNT; intersect_hid++) { @@ -1277,3 +1295,30 @@ side_found: *hex = (3*radius*(radius-1) + 1) + radius*side + side_distance; } } + +void hex_vertex_neighbors( + uint32_t vertex, HexCoord hex, + uint32_t n_vertex[2], HexCoord n_region[2], uint32_t n_hex[2]) { + HexCoord n1 = hex_starts_qr[(vertex+3) % 6]; + HexCoord n2 = hex_starts_qr[(vertex+4) % 6]; + + hex_add(hex, &n1); + hex_add(hex, &n2); + + hex_index(n1, &n_region[0], &n_hex[0]); + hex_index(n2, &n_region[1], &n_hex[1]); + + n_vertex[0] = ((vertex + 1) % 6) + 1; + n_vertex[1] = ((vertex + 3) % 6) + 1; +} + +void first_matching_region(HexCoord coord, int y, uint32_t* region, HexContext* context) { + for(*region = 0; *region < MAX_LOADED_REGIONS; (*region)++) { + if(context->regions[*region] != NULL + && context->regions[*region]->data.position.q == coord.q + && context->regions[*region]->data.position.r == coord.r + && context->regions[*region]->data.y == y) { + return; + } + } +}