1058 lines
29 KiB
C
1058 lines
29 KiB
C
#include "GLFW/glfw3.h"
|
|
#include <stdio.h>
|
|
#define CGLM_PRINT_PRECISION 10
|
|
#define CGLM_DEFINE_PRINTS 1
|
|
#include "ui.h"
|
|
#include "gpu.h"
|
|
#include "draw.h"
|
|
#include "hex.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 <math.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef struct EditorContextStruct {
|
|
uint32_t selected_region;
|
|
uint32_t last_selected_region;
|
|
|
|
uint32_t last_clicked_region;
|
|
uint32_t last_clicked_hex;
|
|
uint32_t last_clicked_vertex;
|
|
} EditorContext;
|
|
|
|
typedef struct ClientContextStruct {
|
|
GLFWwindow* window;
|
|
RenderContext* render;
|
|
UIContext* ui;
|
|
HexContext* hex;
|
|
|
|
uint32_t clicked_container;
|
|
uint32_t clicked_element;
|
|
|
|
double cursor[2];
|
|
|
|
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;
|
|
|
|
EditorContext editor;
|
|
} ClientContext;
|
|
|
|
void* network_thread(void* data) {
|
|
ClientContext* context = (ClientContext*)data;
|
|
(void)context;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
VkResult color_ui(ClientContext* context) {
|
|
GPUString strings[] = {
|
|
{
|
|
.pos = {-2, 168},
|
|
.color = {1, 1, 1, 1},
|
|
.size = 32,
|
|
.offset = 0,
|
|
.length = 9,
|
|
.font = 0,
|
|
},
|
|
};
|
|
|
|
GPUDrawable drawables[] = {
|
|
{
|
|
.pos = {0, 0},
|
|
.size = {178, 168},
|
|
.color = {0.4, 0.4, 0.4, 0.4},
|
|
},
|
|
{
|
|
.pos = {2, 2},
|
|
.size = {130, 130},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x01,
|
|
},
|
|
{
|
|
.pos = {36, 136},
|
|
.size = {140, 30},
|
|
.color = {0, 0, 1, 0.4},
|
|
.id = 0x02,
|
|
},
|
|
{
|
|
.pos = {134, 2},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x03,
|
|
},
|
|
{
|
|
.pos = {156, 2},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x04,
|
|
},
|
|
{
|
|
.pos = {134, 24},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x05,
|
|
},
|
|
{
|
|
.pos = {156, 24},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x06,
|
|
},
|
|
{
|
|
.pos = {134, 46},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x07,
|
|
},
|
|
{
|
|
.pos = {156, 46},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x08,
|
|
},
|
|
{
|
|
.pos = {134, 68},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x09,
|
|
},
|
|
{
|
|
.pos = {156, 68},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x0A,
|
|
},
|
|
{
|
|
.pos = {134, 90},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x0B,
|
|
},
|
|
{
|
|
.pos = {156, 90},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x0C,
|
|
},
|
|
{
|
|
.pos = {134, 112},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x0D,
|
|
},
|
|
{
|
|
.pos = {156, 112},
|
|
.size = {20, 20},
|
|
.color = {1, 1, 1, 1},
|
|
.id = 0x0E,
|
|
},
|
|
};
|
|
|
|
uint32_t codes[9];
|
|
VkResult result;
|
|
VK_RESULT(map_string("#FFFFFFFF", 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),
|
|
};
|
|
|
|
ContainerInput container = {
|
|
.layers = &layer,
|
|
.layer_count = 1,
|
|
.anchor = ANCHOR_BOTTOM_LEFT,
|
|
.id = 0x03,
|
|
.offset = {0, 0},
|
|
.size = {178, 168},
|
|
};
|
|
|
|
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},
|
|
},
|
|
};
|
|
|
|
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},
|
|
},
|
|
};
|
|
|
|
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, 0, 0, 0, context->ui, context->render));
|
|
|
|
if(selected_region == NULL) {
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 0, 0, 1, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 0, 0, 2, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 0, 0, 3, context->ui, context->render));
|
|
} else {
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"Q: %4d", selected_region->data.q);
|
|
VK_RESULT(update_ui_string(temp, 0, 0, 1, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"R: %4d", selected_region->data.r);
|
|
VK_RESULT(update_ui_string(temp, 0, 0, 2, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"Y: %4d", selected_region->data.y);
|
|
VK_RESULT(update_ui_string(temp, 0, 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, 1, 0, 0, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 1, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 2, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 3, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 4, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 5, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 6, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"");
|
|
VK_RESULT(update_ui_string(temp, 1, 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, 1, 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);
|
|
}
|
|
|
|
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, 1, 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, 1, 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, 1, 0, 3, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"%08X",
|
|
hex->color[0]);
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 4, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"%08X %08X",
|
|
hex->color[1], hex->color[2]);
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 5, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"%08X %08X",
|
|
hex->color[3], hex->color[4]);
|
|
VK_RESULT(update_ui_string(temp, 1, 0, 6, context->ui, context->render));
|
|
|
|
snprintf(
|
|
temp,
|
|
sizeof(temp),
|
|
"%08X %08X",
|
|
hex->color[5], hex->color[6]);
|
|
VK_RESULT(update_ui_string(temp, 1, 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->clicked_element = 0x00000000;
|
|
context->clicked_container = 0x00000000;
|
|
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 key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
|
|
(void)scancode;
|
|
(void)mods;
|
|
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;
|
|
}
|
|
}
|
|
|
|
bool contains(double* point, GPUContainer* container, GPUDrawable* rect) {
|
|
vec2 pos = {
|
|
container->offset[0] + rect->pos[0],
|
|
container->offset[1] + rect->pos[1],
|
|
};
|
|
return (point[0] >= pos[0] && point[0] <= pos[0] + rect->size[0]) &&
|
|
(point[1] >= pos[1] && point[1] <= pos[1] + rect->size[1]) &&
|
|
(point[0] >= container->offset[0] && point[0] <= container->offset[0] + container->size[0]) &&
|
|
(point[1] >= container->offset[1] && point[1] <= container->offset[1] + container->size[1]);
|
|
}
|
|
|
|
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
|
|
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
|
|
|
|
(void)mods;
|
|
(void)context;
|
|
double cursor[2];
|
|
glfwGetCursorPos(window, &cursor[0], &cursor[1]);
|
|
switch(button) {
|
|
// Handle camera hover
|
|
case GLFW_MOUSE_BUTTON_RIGHT:
|
|
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;
|
|
}
|
|
break;
|
|
case GLFW_MOUSE_BUTTON_LEFT:
|
|
if(action == GLFW_PRESS) {
|
|
// Hex intersection
|
|
update_hex_click(cursor, context->hex, context->render);
|
|
|
|
// UI intersections
|
|
for(uint32_t c = 0; c < context->ui->max_containers; c++) {
|
|
if(context->ui->containers[c].id == 0x00000000) {
|
|
continue;
|
|
}
|
|
|
|
for(uint32_t l = 0; l < context->ui->containers[c].layer_count; l++) {
|
|
for(uint32_t d = 0; d < context->ui->containers[c].layers[l].data.num_drawables; d++) {
|
|
if(context->ui->containers[c].layers[l].drawables_buffer[d].id == 0x00000000) {
|
|
continue;
|
|
}
|
|
if(contains(
|
|
cursor,
|
|
&context->ui->containers[c].data,
|
|
&context->ui->containers[c].layers[l].drawables_buffer[d])) {
|
|
context->clicked_container = context->ui->containers[c].id;
|
|
context->clicked_element = context->ui->containers[c].layers[l].drawables_buffer[d].id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
|
|
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
|
|
(void)xoffset;
|
|
context->zoom = -yoffset;
|
|
}
|
|
|
|
void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
|
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
|
|
if(context->camera_mode == true) {
|
|
context->cur_spin[0] = (xpos - context->cursor[0])/context->render->swapchain_extent.width*-100;
|
|
context->cur_spin[1] = (ypos - context->cursor[1])/context->render->swapchain_extent.height*100;
|
|
|
|
context->cursor[0] = xpos;
|
|
context->cursor[1] = ypos;
|
|
} else {
|
|
context->cursor[0] = xpos;
|
|
context->cursor[1] = ypos;
|
|
update_hex_hover(context->cursor, context->hex, context->render);
|
|
}
|
|
}
|
|
|
|
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, mouse_button_callback);
|
|
glfwSetScrollCallback(context.window, scroll_callback);
|
|
glfwSetCursorPosCallback(context.window, cursor_pos_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;
|
|
}
|