|
|
|
@ -1,6 +1,8 @@
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "hex.h"
|
|
|
|
|
#include "hsv.h"
|
|
|
|
|
#include "engine.h"
|
|
|
|
|
#include "vulkan/vulkan_core.h"
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
@ -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];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(selected_region == NULL) {
|
|
|
|
|
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),
|
|
|
|
@ -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));
|
|
|
|
|