612 lines
19 KiB
C
612 lines
19 KiB
C
#include "GLFW/glfw3.h"
|
|
#define CGLM_PRINT_PRECISION 10
|
|
#define CGLM_DEFINE_PRINTS 1
|
|
#include "cglm/cam.h"
|
|
#include "cglm/mat4.h"
|
|
#include "cglm/io.h"
|
|
#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>
|
|
|
|
#define max(a, b) ((a > b) ? a : b)
|
|
#define min(a, b) ((a < b) ? a : b)
|
|
|
|
typedef struct ClientContextStruct {
|
|
GLFWwindow* window;
|
|
RenderContext* render;
|
|
UIContext* ui;
|
|
HexContext* hex;
|
|
|
|
uint32_t clicked_container;
|
|
uint32_t clicked_element;
|
|
int32_t clicked_hex[2];
|
|
|
|
double cursor[2];
|
|
|
|
vec3 position;
|
|
|
|
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;
|
|
|
|
mat4 inverse;
|
|
} ClientContext;
|
|
|
|
void* network_thread(void* data) {
|
|
ClientContext* context = (ClientContext*)data;
|
|
(void)context;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// cos(I*PI/3)/2, sin(I*PI/3)/2
|
|
vec3 hex_vertices[] = {
|
|
{ 1.0/2, 0, 0},
|
|
{ 1.0/4, 0, SQRT3/4},
|
|
{-1.0/4, 0, SQRT3/4},
|
|
{-1.0/2, 0, 0},
|
|
{-1.0/4, 0, -SQRT3/4},
|
|
{ 1.0/4, 0, -SQRT3/4},
|
|
};
|
|
|
|
vec3 hex_starts[] = {
|
|
{ 0, 0, HEX_Z},
|
|
{-HEX_X, 0, HEX_Z/2},
|
|
{-HEX_X, 0, -HEX_Z/2},
|
|
{ 0, 0, -HEX_Z},
|
|
{ HEX_X, 0, -HEX_Z/2},
|
|
{ HEX_X, 0, HEX_Z/2},
|
|
};
|
|
|
|
vec3 hex_directions[] = {
|
|
{-HEX_X, 0, -HEX_Z/2},
|
|
{ 0, 0, -HEX_Z},
|
|
{ HEX_X, 0, -HEX_Z/2},
|
|
{ HEX_X, 0, HEX_Z/2},
|
|
{ 0, 0, HEX_Z},
|
|
{-HEX_X, 0, HEX_Z/2},
|
|
};
|
|
|
|
int hex_indices[] = {
|
|
0, 2, 1,
|
|
0, 3, 2,
|
|
0, 4, 3,
|
|
0, 5, 4,
|
|
0, 6, 5,
|
|
0, 1, 6,
|
|
};
|
|
|
|
bool ray_hex_intersect(float* distance, vec4 ray_start, vec4 ray_end, uint32_t region_index, uint32_t hex_index, HexContext* context) {
|
|
/*
|
|
Ray-hexagon intersection
|
|
1. For each triangle in the hexagon, check for intersection
|
|
2. If intersections, return the closest along the ray
|
|
*/
|
|
GPUHexRegion* region = &context->regions[region_index]->data;
|
|
GPUHex* hex = ®ion->hexes[hex_index];
|
|
|
|
vec3 start;
|
|
start[0] = ray_start[0]/ray_start[3];
|
|
start[1] = ray_start[1]/ray_start[3];
|
|
start[2] = ray_start[2]/ray_start[3];
|
|
|
|
vec3 end;
|
|
end[0] = ray_end[0]/ray_end[3];
|
|
end[1] = ray_end[1]/ray_end[3];
|
|
end[2] = ray_end[2]/ray_end[3];
|
|
|
|
vec3 dir;
|
|
dir[0] = end[0] - start[0];
|
|
dir[1] = end[1] - start[1];
|
|
dir[2] = end[2] - start[2];
|
|
|
|
|
|
float dir_len = glm_vec3_norm(dir);
|
|
glm_vec3_divs(dir, dir_len, dir);
|
|
|
|
vec3 region_offset = {
|
|
((float)region->q + (float)region->r/2)*REGION_WIDTH - region->r*HEX_X/2,
|
|
0,
|
|
0.75*region->r*REGION_HEIGHT + 0.25*region->r*HEX_Z + 0.5*region->q*HEX_Z,
|
|
};
|
|
|
|
float center_height = (hex->height[0]
|
|
+ hex->height[1]
|
|
+ hex->height[2]
|
|
+ hex->height[3]
|
|
+ hex->height[4]
|
|
+ hex->height[5])/6;
|
|
|
|
vec3 vertices[7] = {
|
|
{0, 0, 0},
|
|
};
|
|
glm_vec3_add(vertices[0], region_offset, vertices[0]);
|
|
glm_vec3_add(hex_vertices[0], region_offset, vertices[1]);
|
|
glm_vec3_add(hex_vertices[1], region_offset, vertices[2]);
|
|
glm_vec3_add(hex_vertices[2], region_offset, vertices[3]);
|
|
glm_vec3_add(hex_vertices[3], region_offset, vertices[4]);
|
|
glm_vec3_add(hex_vertices[4], region_offset, vertices[5]);
|
|
glm_vec3_add(hex_vertices[5], region_offset, vertices[6]);
|
|
|
|
vertices[0][1] += center_height;
|
|
vertices[1][1] += hex->height[0];
|
|
vertices[2][1] += hex->height[1];
|
|
vertices[3][1] += hex->height[2];
|
|
vertices[4][1] += hex->height[3];
|
|
vertices[5][1] += hex->height[4];
|
|
vertices[6][1] += hex->height[5];
|
|
|
|
vec3 hex_offset = {0, 0, 0};
|
|
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);
|
|
}
|
|
|
|
glm_vec3_muladds(hex_starts[side], radius, hex_offset);
|
|
glm_vec3_muladds(hex_directions[side], ring-(radius*side), hex_offset);
|
|
for(uint32_t vertex = 0; vertex < 7; vertex++) {
|
|
glm_vec3_add(vertices[vertex], hex_offset, vertices[vertex]);
|
|
}
|
|
|
|
*distance = INFINITY;
|
|
bool intersect = false;
|
|
|
|
for(uint32_t triangle = 0; triangle < 6; triangle++) {
|
|
vec3 vert[3];
|
|
for(int v_i = 0; v_i < 3; v_i++) {
|
|
vert[v_i][0] = vertices[hex_indices[triangle*3+v_i]][0];
|
|
vert[v_i][1] = vertices[hex_indices[triangle*3+v_i]][1];
|
|
vert[v_i][2] = vertices[hex_indices[triangle*3+v_i]][2];
|
|
}
|
|
|
|
vec3 v0v1;
|
|
glm_vec3_sub(vert[1], vert[0], v0v1);
|
|
vec3 v0v2;
|
|
glm_vec3_sub(vert[2], vert[0], v0v2);
|
|
vec3 pvec;
|
|
glm_vec3_cross(dir, v0v2, pvec);
|
|
float det = glm_vec3_dot(v0v1, pvec);
|
|
|
|
float det_inv = 1/det;
|
|
|
|
vec3 t;
|
|
glm_vec3_sub(start, vert[0], t);
|
|
float u = glm_vec3_dot(t, pvec) * det_inv;
|
|
if(u < 0 || u > 1) continue;
|
|
|
|
vec3 q;
|
|
glm_vec3_cross(t, v0v1, q);
|
|
float v = glm_vec3_dot(dir, q) * det_inv;
|
|
if(v < 0 || (u+v) > 1) continue;
|
|
|
|
intersect = true;
|
|
*distance = min(*distance, glm_vec3_dot(v0v2, q) * det_inv);
|
|
}
|
|
|
|
return intersect;
|
|
}
|
|
|
|
vec3 up = {0, 1, 0};
|
|
|
|
VkResult main_thread(ClientContext* context) {
|
|
VkResult result;
|
|
|
|
GPUString strings[] = {
|
|
{
|
|
.pos = {0, 32},
|
|
.size = 32,
|
|
.color = {1.0, 1.0, 1.0, 1.0},
|
|
.offset = 0,
|
|
.length = 0,
|
|
.font = 0,
|
|
},
|
|
};
|
|
|
|
GPUDrawable drawables[] = {};
|
|
|
|
LayerInput layer = {
|
|
.strings = strings,
|
|
.num_strings = sizeof(strings)/sizeof(GPUString),
|
|
.max_codes = 50,
|
|
|
|
.drawables = drawables,
|
|
.num_drawables = sizeof(drawables)/sizeof(GPUDrawable),
|
|
};
|
|
|
|
ContainerInput container = {
|
|
.id = 1,
|
|
.size = {WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT},
|
|
.layer_count = 1,
|
|
.layers = &layer,
|
|
};
|
|
|
|
create_container(&container, context->render, context->ui);
|
|
|
|
HexRegion* regions[MAX_LOADED_REGIONS];
|
|
uint32_t colors[] = {
|
|
0xFF0000FF,
|
|
0x00FF00FF,
|
|
0x0000FFFF,
|
|
};
|
|
|
|
context->hex->data.current_map = 0x01;
|
|
add_transfer(&context->hex->data.current_map, context->hex->context, offsetof(GPUHexContext, current_map), sizeof(uint32_t), context->render->current_frame, context->render);
|
|
|
|
uint32_t region = 0;
|
|
for(int32_t q = -5; q < 5; q++) {
|
|
for(int32_t r = -5; r < 5; r++) {
|
|
VK_RESULT(set_hex_region(q, r, 0, 0x01, ®ions[region], context->hex, context->render));
|
|
for(uint32_t i = 0; i < REGION_HEX_COUNT; i++) {
|
|
for(uint32_t h = 0; h < 6; h++) {
|
|
regions[region]->data.hexes[i].color[h] = colors[(q+r+50) % (sizeof(colors)/sizeof(uint32_t))];
|
|
regions[region]->data.hexes[i].height[h] = (float)i/REGION_HEX_COUNT;
|
|
}
|
|
regions[region]->data.hexes[i].color[6] = colors[(q+r+50) % (sizeof(colors)/sizeof(uint32_t))];
|
|
}
|
|
VK_RESULT(add_transfer(®ions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, 0, context->render));
|
|
region++;
|
|
}
|
|
}
|
|
|
|
//
|
|
uint32_t* mapped_codes = context->ui->containers[0].layers[0].codes_buffer;
|
|
GPUString* mapped_string = context->ui->containers[0].layers[0].strings_buffer;
|
|
char str[51];
|
|
|
|
int frame = 0;
|
|
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->clicked_hex[0] = 0;
|
|
context->clicked_hex[1] = 0;
|
|
context->zoom = 0;
|
|
context->cur_spin[0] = 0;
|
|
context->cur_spin[1] = 0;
|
|
|
|
glfwPollEvents();
|
|
if((context->key_spin[0] != 0 || context->key_spin[1] != 0 ||
|
|
context->zoom != 0 ||
|
|
context->cur_spin[0] != 0 || context->cur_spin[1] != 0 ||
|
|
context->render->framebuffer_recreated == true) && frame > 0) {
|
|
if(context->render->framebuffer_recreated == true) {
|
|
context->render->framebuffer_recreated = false;
|
|
glm_perspective(
|
|
PERSPECTIVE_FOVY,
|
|
(float)context->render->swapchain_extent.width/(float)context->render->swapchain_extent.height,
|
|
PERSPECTIVE_NEARZ,
|
|
PERSPECTIVE_FARZ,
|
|
context->hex->data.proj);
|
|
VK_RESULT(add_transfer(
|
|
&context->hex->data.proj,
|
|
context->hex->context,
|
|
offsetof(GPUHexContext, proj),
|
|
sizeof(mat4),
|
|
context->render->current_frame,
|
|
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->distance += context->zoom*delta_time*context->zoom_speed;
|
|
if(context->distance < 1) {
|
|
context->distance = 1;
|
|
}
|
|
|
|
vec3 camera = {};
|
|
camera[0] = context->position[0] + context->distance*cos(context->rotation[1])*cos(context->rotation[0]);
|
|
camera[1] = context->position[1] + context->distance*sin(context->rotation[1]);
|
|
camera[2] = context->position[2] + context->distance*cos(context->rotation[1])*sin(context->rotation[0]);
|
|
|
|
glm_lookat(camera, context->position, up, context->hex->data.view);
|
|
|
|
mat4 regular;
|
|
glm_mat4_mul(context->hex->data.proj, context->hex->data.view, regular);
|
|
glm_mat4_inv(regular, context->inverse);
|
|
|
|
add_transfer(&context->hex->data, context->hex->context, 0, 2*sizeof(mat4), context->render->current_frame, context->render);
|
|
}
|
|
|
|
if(context->clicked_hex[0] != 0 || context->clicked_hex[1] != 0) {
|
|
snprintf(str, 50, "Clicked: (%d,%d)", context->clicked_hex[0], context->clicked_hex[1]);
|
|
map_string(str, mapped_codes, 0, 0, context->ui);
|
|
VK_RESULT(add_transfers(
|
|
context->ui->containers[0].layers[0].codes_buffer,
|
|
context->ui->containers[0].layers[0].codes,
|
|
0,
|
|
strlen(str)*sizeof(uint32_t),
|
|
context->render));
|
|
mapped_string->length = strlen(str);
|
|
VK_RESULT(add_transfers(
|
|
&context->ui->containers[0].layers[0].strings_buffer[0].length,
|
|
context->ui->containers[0].layers[0].strings,
|
|
offsetof(GPUString, length),
|
|
sizeof(uint32_t),
|
|
context->render));
|
|
|
|
}
|
|
//
|
|
|
|
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);
|
|
}
|
|
frame += 1;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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 cursor_to_world_ray(ClientContext* context, double cursor[2], vec4 start, vec4 end) {
|
|
double cursor_scaled[2] = {
|
|
2*(cursor[0]*context->render->window_scale[0]/context->render->swapchain_extent.width - 0.5),
|
|
2*(cursor[1]*context->render->window_scale[1]/context->render->swapchain_extent.height - 0.5),
|
|
};
|
|
|
|
vec4 transformed_start = {
|
|
cursor_scaled[0],
|
|
cursor_scaled[1],
|
|
PERSPECTIVE_NEARZ,
|
|
1.0,
|
|
};
|
|
|
|
vec4 transformed_end = {
|
|
PERSPECTIVE_FARZ*cursor_scaled[0],
|
|
PERSPECTIVE_FARZ*cursor_scaled[1],
|
|
PERSPECTIVE_FARZ,
|
|
PERSPECTIVE_FARZ,
|
|
};
|
|
|
|
glm_mat4_mulv(context->inverse, transformed_start, start);
|
|
glm_mat4_mulv(context->inverse, transformed_end, end);
|
|
}
|
|
|
|
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) {
|
|
cursor_to_world_ray(context, cursor, context->hex->data.click_start, context->hex->data.click_end);
|
|
add_transfer(&context->hex->data.click_start, context->hex->context, offsetof(GPUHexContext, click_start), sizeof(vec4)*2, context->render->current_frame, context->render);
|
|
|
|
// Hex intersections
|
|
float distance;
|
|
for(uint32_t r = 0; r < MAX_LOADED_REGIONS; r++) {
|
|
if(context->hex->regions[r] == NULL) {
|
|
continue;
|
|
} else if(context->hex->regions[r]->data.map != context->hex->data.current_map) {
|
|
continue;
|
|
}
|
|
for(uint32_t h = 0; h < REGION_HEX_COUNT; h++) {
|
|
if(ray_hex_intersect(&distance, context->hex->data.click_start, context->hex->data.click_end, r, h, context->hex)) {
|
|
context->hex->data.clicked_region = r;
|
|
context->hex->data.clicked_hex = h;
|
|
add_transfer(&context->hex->data.clicked_region, context->hex->context, offsetof(GPUHexContext, clicked_region), sizeof(uint32_t)*2, context->render->current_frame, 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// NOTE: this logic is the same as it would be for right-click(just with different outcomes), so dont repeat yourself
|
|
// 1. Search through the UI context for the first element that the contains the mouse point
|
|
// 2. If no UI element intersection, cast a ray through the world scene to find the "clicked entity"
|
|
// 3. Based on what was clicked, start the mouse click animation at the target area
|
|
}
|
|
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;
|
|
cursor_to_world_ray(context, context->cursor, context->hex->data.hover_start, context->hex->data.hover_end);
|
|
add_transfer(&context->hex->data.hover_start, context->hex->context, offsetof(GPUHexContext, hover_start), sizeof(vec4)*2, context->render->current_frame, context->render);
|
|
|
|
// Hex intersections
|
|
float distance;
|
|
for(uint32_t r = 0; r < MAX_LOADED_REGIONS; r++) {
|
|
if(context->hex->regions[r] == NULL) {
|
|
continue;
|
|
} else if(context->hex->regions[r]->data.map != context->hex->data.current_map) {
|
|
continue;
|
|
}
|
|
for(uint32_t h = 0; h < REGION_HEX_COUNT; h++) {
|
|
if(ray_hex_intersect(&distance, context->hex->data.hover_start, context->hex->data.hover_end, r, h, context->hex)) {
|
|
context->hex->data.hovered_region = r;
|
|
context->hex->data.hovered_hex = h;
|
|
add_transfer(&context->hex->data.hovered_region, context->hex->context, offsetof(GPUHexContext, hovered_region), sizeof(uint32_t)*2, context->render->current_frame, 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,
|
|
};
|
|
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;
|
|
}
|