diff --git a/client/include/hex.h b/client/include/hex.h index b0c557a..3ac8117 100644 --- a/client/include/hex.h +++ b/client/include/hex.h @@ -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[]; @@ -76,14 +79,39 @@ typedef struct HexPushConstantStruct { } HexPushConstant; VkResult create_hex_context( - RenderContext* gpu, - HexContext* context); + RenderContext* gpu, + HexContext* context); VkResult set_hex_region( - int32_t q, int32_t r, int32_t y, - uint32_t map, - HexRegion** region, - HexContext* hex, - RenderContext* gpu); + 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 diff --git a/client/src/hex.c b/client/src/hex.c index 98c2236..5fac138 100644 --- a/client/src/hex.c +++ b/client/src/hex.c @@ -163,7 +163,7 @@ VkResult create_ray_pipeline( .minSampleShading = 1.0f, .pSampleMask = 0, .alphaToCoverageEnable = VK_FALSE, - .alphaToOneEnable = VK_FALSE, +.alphaToOneEnable = VK_FALSE, }; VkPipelineDepthStencilStateCreateInfo depth_info = { @@ -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( + ®ion->data.hexes, + region->region, + offsetof(GPUHexRegion, hexes), + sizeof(GPUHex)*REGION_HEX_COUNT, + gpu->current_frame, + gpu)); + + return add_transfers( + ®ion->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 = ®ion->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); +} diff --git a/client/src/main.c b/client/src/main.c index ae32ea5..8e50b96 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -17,9 +17,6 @@ #include #include -#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 = ®ion->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, ®ions[region], context->hex, context->render)); + VK_RESULT(allocate_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))]; @@ -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(®ions[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; }