Cleaning up hex functions

main
noah metz 2024-11-06 18:13:32 -07:00
parent f984f245aa
commit 40f388f7b2
3 changed files with 338 additions and 207 deletions

@ -13,6 +13,9 @@
#define REGION_WIDTH (HEX_X*REGION_DIAMETER)
#define REGION_HEIGHT (HEX_Z*REGION_DIAMETER)
#define max(a, b) ((a > b) ? a : b)
#define min(a, b) ((a < b) ? a : b)
extern vec3 hex_vertices[];
extern vec3 hex_starts[];
extern vec3 hex_directions[];
@ -80,10 +83,35 @@ VkResult create_hex_context(
HexContext* context);
VkResult set_hex_region(
HexRegion* region,
HexContext* hex,
RenderContext* gpu);
VkResult allocate_hex_region(
int32_t q, int32_t r, int32_t y,
uint32_t map,
HexRegion** region,
HexContext* hex,
RenderContext* gpu);
bool ray_world_intersect(
float* distance,
uint32_t* rid,
uint32_t* hid,
vec4 ray_start,
vec4 ray_end,
HexContext* context);
VkResult update_hex_proj(
RenderContext* gpu,
HexContext* hex);
VkResult update_hex_view(
vec3 position,
vec2 rotation,
double distance,
mat4 inverse,
RenderContext* gpu,
HexContext* hex);
#endif

@ -192,7 +192,12 @@ VkResult create_ray_pipeline(
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(gpu->device, VK_NULL_HANDLE, 1, &graphics_pipeline_info, NULL, &pipeline->pipeline));
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
@ -347,7 +352,12 @@ VkResult create_hex_highlight_pipeline(
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(gpu->device, VK_NULL_HANDLE, 1, &graphics_pipeline_info, NULL, &pipeline->pipeline));
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
@ -502,7 +512,12 @@ VkResult create_hex_pipeline(
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(gpu->device, VK_NULL_HANDLE, 1, &graphics_pipeline_info, NULL, &pipeline->pipeline));
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
@ -518,7 +533,12 @@ VkResult create_hex_context(
VK_RESULT(create_hex_highlight_pipeline(gpu, &context->highlight_pipeline));
memset(&context->data, 0, sizeof(GPUHexContext));
glm_perspective(PERSPECTIVE_FOVY, (float)gpu->swapchain_extent.width/(float)gpu->swapchain_extent.height, PERSPECTIVE_NEARZ, PERSPECTIVE_FARZ, context->data.proj);
glm_perspective(
PERSPECTIVE_FOVY,
(float)gpu->swapchain_extent.width/(float)gpu->swapchain_extent.height,
PERSPECTIVE_NEARZ,
PERSPECTIVE_FARZ,
context->data.proj);
glm_mat4_identity(context->data.view);
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VK_RESULT(create_storage_buffer(
@ -529,12 +549,53 @@ VkResult create_hex_context(
&context->context_memory[i]));
context->address[i] = buffer_address(gpu->device, context->context[i]);
}
VK_RESULT(add_transfers(&context->data, context->context, 0, sizeof(GPUHexContext), gpu));
VK_RESULT(add_transfers(
&context->data,
context->context,
0,
sizeof(GPUHexContext),
gpu));
return VK_SUCCESS;
}
VkResult set_hex_region(int32_t q, int32_t r, int32_t y, uint32_t map, HexRegion** region, HexContext* hex, RenderContext* gpu) {
VkResult set_hex_region(HexRegion* region, HexContext* hex, RenderContext* gpu) {
uint32_t index = UINT32_MAX;
for(uint32_t i = 0; i < MAX_LOADED_REGIONS; i++) {
if(hex->regions[i] == region) {
index = i;
break;
}
}
if(index == UINT32_MAX) {
return VK_ERROR_UNKNOWN;
}
VkResult result;
VK_RESULT(add_transfer(
&region->data.hexes,
region->region,
offsetof(GPUHexRegion, hexes),
sizeof(GPUHex)*REGION_HEX_COUNT,
gpu->current_frame,
gpu));
return add_transfers(
&region->address,
hex->context,
offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*index,
sizeof(VkDeviceAddress),
gpu);
}
VkResult allocate_hex_region(
int32_t q,
int32_t r,
int32_t y,
uint32_t map,
HexRegion** region,
HexContext* hex,
RenderContext* gpu) {
VkResult result;
uint32_t i = 0;
@ -560,11 +621,221 @@ VkResult set_hex_region(int32_t q, int32_t r, int32_t y, uint32_t map, HexRegion
sizeof(GPUHexRegion),
&(*region)->region,
&(*region)->region_memory));
VK_RESULT(add_transfer(&(*region)->data.q, (*region)->region, offsetof(GPUHexRegion, q), sizeof(int32_t)*3 + sizeof(uint32_t), gpu->current_frame, gpu));
VK_RESULT(add_transfer(
&(*region)->data.q,
(*region)->region,
offsetof(GPUHexRegion, q),
sizeof(int32_t)*3 + sizeof(uint32_t),
gpu->current_frame,
gpu));
(*region)->address = buffer_address(gpu->device, (*region)->region);
// TODO: load hex data before setting address so that data is synchronized
VK_RESULT(add_transfers(&(*region)->address, hex->context, offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*i, sizeof(VkDeviceAddress), gpu));
return VK_SUCCESS;
}
bool ray_hex_intersect(
float* distance,
vec3 start,
vec3 dir,
vec3 region_offset,
uint32_t hex_index,
HexRegion* region) {
GPUHex* hex = &region->data.hexes[hex_index];
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;
}
bool ray_region_intersect(
float* distance,
uint32_t* hid,
vec3 start,
vec3 dir,
HexRegion* region) {
bool intersect = false;
float temp_distance;
*distance = INFINITY;
vec3 region_offset = {
((float)region->data.q + (float)region->data.r/2)*REGION_WIDTH - region->data.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,
};
for(uint32_t temp_hid = 0; temp_hid < REGION_HEX_COUNT; temp_hid++) {
if(ray_hex_intersect(&temp_distance, start, dir, region_offset, temp_hid, region)) {
if(temp_distance < *distance) {
intersect = true;
*hid = temp_hid;
*distance = temp_distance;
}
}
}
return intersect;
}
bool ray_world_intersect(
float* distance,
uint32_t* rid,
uint32_t* hid,
vec4 ray_start,
vec4 ray_end,
HexContext* context) {
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 mdir = glm_vec3_norm(dir);
glm_vec3_divs(dir, mdir, dir);
bool intersect = false;
float temp_distance;
uint32_t temp_hid;
*distance = INFINITY;
for(uint32_t temp_rid = 0; temp_rid < MAX_LOADED_REGIONS; temp_rid++) {
HexRegion* region = context->regions[temp_rid];
if(region == NULL) {
continue;
} else if(region->data.map != context->data.current_map) {
continue;
}
if(ray_region_intersect(&temp_distance, &temp_hid, start, dir, region)) {
if(temp_distance < *distance) {
intersect = true;
*hid = temp_hid;
*rid = temp_rid;
*distance = temp_distance;
}
}
}
return intersect;
}
VkResult update_hex_proj(RenderContext* gpu, HexContext* hex) {
glm_perspective(
PERSPECTIVE_FOVY,
(float)gpu->swapchain_extent.width/(float)gpu->swapchain_extent.height,
PERSPECTIVE_NEARZ,
PERSPECTIVE_FARZ,
hex->data.proj);
return add_transfers(
&hex->data.proj,
hex->context,
offsetof(GPUHexContext, proj),
sizeof(mat4),
gpu);
}
vec3 up = {0, 1, 0};
VkResult update_hex_view(
vec3 position,
vec2 rotation,
double distance,
mat4 inverse,
RenderContext* gpu,
HexContext* hex) {
vec3 camera = {};
camera[0] = position[0] + distance*cos(rotation[1])*cos(rotation[0]);
camera[1] = position[1] + distance*sin(rotation[1]);
camera[2] = position[2] + distance*cos(rotation[1])*sin(rotation[0]);
glm_lookat(camera, position, up, hex->data.view);
mat4 regular;
glm_mat4_mul(hex->data.proj, hex->data.view, regular);
glm_mat4_inv(regular, inverse);
return add_transfers(&hex->data, hex->context, 0, 2*sizeof(mat4), gpu);
}

@ -17,9 +17,6 @@
#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;
@ -56,165 +53,6 @@ void* network_thread(void* data) {
return NULL;
}
bool ray_hex_intersect(float* distance, vec3 start, vec3 dir, vec3 region_offset, uint32_t hex_index, HexRegion* region) {
/*
Ray-hexagon intersection
1. For each triangle in the hexagon, check for intersection
2. If intersections, return the closest along the ray
*/
GPUHex* hex = &region->data.hexes[hex_index];
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;
}
bool ray_region_intersect(float* distance, uint32_t* hid, vec3 start, vec3 dir, HexRegion* region) {
bool intersect = false;
float temp_distance;
*distance = INFINITY;
vec3 region_offset = {
((float)region->data.q + (float)region->data.r/2)*REGION_WIDTH - region->data.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,
};
for(uint32_t temp_hid = 0; temp_hid < REGION_HEX_COUNT; temp_hid++) {
if(ray_hex_intersect(&temp_distance, start, dir, region_offset, temp_hid, region)) {
if(temp_distance < *distance) {
intersect = true;
*hid = temp_hid;
*distance = temp_distance;
}
}
}
return intersect;
}
bool ray_world_intersect(float* distance, uint32_t* rid, uint32_t* hid, vec4 ray_start, vec4 ray_end, HexContext* context) {
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 mdir = glm_vec3_norm(dir);
glm_vec3_divs(dir, mdir, dir);
bool intersect = false;
float temp_distance;
uint32_t temp_hid;
*distance = INFINITY;
for(uint32_t temp_rid = 0; temp_rid < MAX_LOADED_REGIONS; temp_rid++) {
HexRegion* region = context->regions[temp_rid];
if(region == NULL) {
continue;
} else if(region->data.map != context->data.current_map) {
continue;
}
if(ray_region_intersect(&temp_distance, &temp_hid, start, dir, region)) {
if(temp_distance < *distance) {
intersect = true;
*hid = temp_hid;
*rid = temp_rid;
*distance = temp_distance;
}
}
}
return intersect;
}
vec3 up = {0, 1, 0};
VkResult main_thread(ClientContext* context) {
VkResult result;
@ -257,12 +95,17 @@ VkResult main_thread(ClientContext* context) {
};
context->hex->data.current_map = 0x01;
add_transfers(&context->hex->data.current_map, context->hex->context, offsetof(GPUHexContext, current_map), sizeof(uint32_t), context->render);
VK_RESULT(add_transfers(
&context->hex->data.current_map,
context->hex->context,
offsetof(GPUHexContext, current_map),
sizeof(uint32_t),
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, &regions[region], context->hex, context->render));
VK_RESULT(allocate_hex_region(q, r, 0, 0x01, &regions[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))];
@ -270,7 +113,7 @@ VkResult main_thread(ClientContext* context) {
}
regions[region]->data.hexes[i].color[6] = colors[(q+r+50) % (sizeof(colors)/sizeof(uint32_t))];
}
VK_RESULT(add_transfer(&regions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, context->render->current_frame, context->render));
VK_RESULT(set_hex_region(regions[region], context->hex, context->render));
region++;
}
}
@ -302,18 +145,7 @@ VkResult main_thread(ClientContext* context) {
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_transfers(
&context->hex->data.proj,
context->hex->context,
offsetof(GPUHexContext, proj),
sizeof(mat4),
context->render));
VK_RESULT(update_hex_proj(context->render, context->hex));
}
context->rotation[0] += (float)context->key_spin[0]*delta_time*context->key_spin_speed;
@ -337,18 +169,13 @@ VkResult main_thread(ClientContext* context) {
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_transfers(&context->hex->data, context->hex->context, 0, 2*sizeof(mat4), context->render);
VK_RESULT(update_hex_view(
context->position,
context->rotation,
context->distance,
context->inverse,
context->render,
context->hex));
}
if(context->clicked_hex[0] != 0 || context->clicked_hex[1] != 0) {
@ -496,6 +323,8 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
context->hex->data.click_start,
context->hex->data.click_end,
context->hex)) {
context->clicked_hex[0] = context->hex->data.clicked_region;
context->clicked_hex[1] = context->hex->data.clicked_hex;
add_transfers(
&context->hex->data.clicked_region,
context->hex->context,
@ -515,7 +344,10 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
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])) {
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;
}