Added highlight of clicked tile

main
noah metz 2024-11-05 16:34:10 -07:00
parent c5d88f03d5
commit ba4bd9bc85
4 changed files with 211 additions and 39 deletions

@ -3,9 +3,15 @@
#include "gpu.h" #include "gpu.h"
#define REGION_SIZE (10) #define REGION_SIZE 10
#define REGION_HEX_COUNT (3*REGION_SIZE*(REGION_SIZE-1)+1) #define REGION_HEX_COUNT (3*REGION_SIZE*(REGION_SIZE-1)+1)
#define MAX_LOADED_REGIONS (51*51) #define MAX_LOADED_REGIONS (51*51)
#define HEX_X 0.75
#define SQRT3 1.732050807568877193176604123436845839023590087890625
#define HEX_Z (SQRT3/2)
#define REGION_DIAMETER (2*REGION_SIZE-1)
#define REGION_WIDTH (HEX_X*REGION_DIAMETER)
#define REGION_HEIGHT (HEX_Z*REGION_DIAMETER)
typedef struct GPUHexStruct { typedef struct GPUHexStruct {
float height[6]; float height[6];
@ -53,7 +59,7 @@ typedef struct HexContextStruct {
GraphicsPipeline ray_pipeline; GraphicsPipeline ray_pipeline;
GraphicsPipeline highlight_pipeline; GraphicsPipeline highlight_pipeline;
HexRegion regions[MAX_LOADED_REGIONS]; HexRegion* regions[MAX_LOADED_REGIONS];
GPUHexContext data; GPUHexContext data;
} HexContext; } HexContext;

@ -33,7 +33,7 @@ void main() {
if(hex_index != 0) { if(hex_index != 0) {
radius = floor(0.5 + sqrt(12*hex_index-3)/6); radius = floor(0.5 + sqrt(12*hex_index-3)/6);
ring = hex_index - (3*radius*radius - 3*radius + 1); ring = hex_index - (3*radius*radius - 3*radius + 1);
side = int(floor(ring/(radius))); side = int(floor(ring/radius));
} }
vec4 position = vertices[indices[gl_VertexIndex]] vec4 position = vertices[indices[gl_VertexIndex]]

@ -497,8 +497,9 @@ VkResult set_hex_region(int32_t q, int32_t r, int32_t y, uint32_t map, HexRegion
uint32_t i = 0; uint32_t i = 0;
for(; i < MAX_LOADED_REGIONS; i++) { for(; i < MAX_LOADED_REGIONS; i++) {
if(hex->regions[i].address == 0) { if(hex->regions[i] == NULL) {
*region = &hex->regions[i]; hex->regions[i] = malloc(sizeof(GPUHexRegion));
*region = hex->regions[i];
break; break;
} }
} }

@ -18,6 +18,7 @@
#include <stdlib.h> #include <stdlib.h>
#define max(a, b) ((a > b) ? a : b) #define max(a, b) ((a > b) ? a : b)
#define min(a, b) ((a < b) ? a : b)
typedef struct ClientContextStruct { typedef struct ClientContextStruct {
GLFWwindow* window; GLFWwindow* window;
@ -55,7 +56,157 @@ void* network_thread(void* data) {
return NULL; return NULL;
} }
vec3 zero = {0, 0, 0}; // 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 = &region->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}; vec3 up = {0, 1, 0};
VkResult main_thread(ClientContext* context) { VkResult main_thread(ClientContext* context) {
@ -103,20 +254,18 @@ VkResult main_thread(ClientContext* context) {
add_transfer(&context->hex->data.current_map, context->hex->context, offsetof(GPUHexContext, current_map), sizeof(uint32_t), context->render->current_frame, context->render); 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; uint32_t region = 0;
for(int32_t y = -2; y < 2; y++) { for(int32_t q = -5; q < 5; q++) {
for(int32_t q = -5; q < 5; q++) { for(int32_t r = -5; r < 5; r++) {
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(set_hex_region(q, r, y, 0x01, &regions[region], context->hex, context->render)); for(uint32_t i = 0; i < REGION_HEX_COUNT; i++) {
for(uint32_t i = 0; i < REGION_HEX_COUNT; i++) { for(uint32_t h = 0; h < 6; h++) {
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].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].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(&regions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, 0, context->render)); regions[region]->data.hexes[i].color[6] = colors[(q+r+50) % (sizeof(colors)/sizeof(uint32_t))];
region++;
} }
VK_RESULT(add_transfer(&regions[region]->data.hexes, regions[region]->region, offsetof(GPUHexRegion, hexes), sizeof(GPUHex)*REGION_HEX_COUNT, 0, context->render));
region++;
} }
} }
@ -127,7 +276,6 @@ VkResult main_thread(ClientContext* context) {
int frame = 0; int frame = 0;
double last_frame_time = 0; double last_frame_time = 0;
double test = glfwGetTime();
while(glfwWindowShouldClose(context->window) == 0) { while(glfwWindowShouldClose(context->window) == 0) {
double frame_time = glfwGetTime(); double frame_time = glfwGetTime();
double delta_time = (frame_time - last_frame_time); double delta_time = (frame_time - last_frame_time);
@ -140,19 +288,7 @@ VkResult main_thread(ClientContext* context) {
context->zoom = 0; context->zoom = 0;
context->cur_spin[0] = 0; context->cur_spin[0] = 0;
context->cur_spin[1] = 0; context->cur_spin[1] = 0;
glfwPollEvents(); glfwPollEvents();
if((frame_time - test) > 0.05) {
test = frame_time;
context->hex->data.clicked_region = 210;
context->hex->data.hovered_region = 210;
context->hex->data.hovered_hex = context->hex->data.clicked_hex;
context->hex->data.clicked_hex += 1;
if(context->hex->data.clicked_hex >= REGION_HEX_COUNT) {
context->hex->data.clicked_hex = 0;
}
add_transfer(&context->hex->data.clicked_region, context->hex->context, offsetof(GPUHexContext, clicked_region), 2*sizeof(uint32_t) + 2*sizeof(int32_t), context->render->current_frame, context->render);
}
if((context->key_spin[0] != 0 || context->key_spin[1] != 0 || if((context->key_spin[0] != 0 || context->key_spin[1] != 0 ||
context->zoom != 0 || context->zoom != 0 ||
@ -292,16 +428,21 @@ bool contains(double* point, GPUContainer* container, GPUDrawable* rect) {
} }
void cursor_to_world_ray(ClientContext* context, double cursor[2], vec4 start, vec4 end) { 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 = { vec4 transformed_start = {
cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1, cursor_scaled[0],
cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1, cursor_scaled[1],
0, PERSPECTIVE_NEARZ,
1.0 1.0,
}; };
vec4 transformed_end = { vec4 transformed_end = {
PERSPECTIVE_FARZ*(cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1), PERSPECTIVE_FARZ*cursor_scaled[0],
PERSPECTIVE_FARZ*(cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1), PERSPECTIVE_FARZ*cursor_scaled[1],
PERSPECTIVE_FARZ, PERSPECTIVE_FARZ,
PERSPECTIVE_FARZ, PERSPECTIVE_FARZ,
}; };
@ -333,7 +474,25 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
cursor_to_world_ray(context, cursor, context->hex->data.click_start, context->hex->data.click_end); 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); add_transfer(&context->hex->data.click_start, context->hex->context, offsetof(GPUHexContext, click_start), sizeof(vec4)*2, context->render->current_frame, context->render);
for(int32_t c = context->ui->max_containers - 1; c >= 0; c--) { // 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) { if(context->ui->containers[c].id == 0x00000000) {
continue; continue;
} }
@ -375,6 +534,7 @@ void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
context->cursor[1] = ypos; context->cursor[1] = ypos;
cursor_to_world_ray(context, context->cursor, context->hex->data.hover_start, context->hex->data.hover_end); 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); add_transfer(&context->hex->data.hover_start, context->hex->context, offsetof(GPUHexContext, hover_start), sizeof(vec4)*2, context->render->current_frame, context->render);
} }
int main() { int main() {
@ -395,6 +555,10 @@ int main() {
return VK_ERROR_OUT_OF_HOST_MEMORY; 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); glfwSetWindowUserPointer(context.window, &context);
glfwSetKeyCallback(context.window, key_callback); glfwSetKeyCallback(context.window, key_callback);
glfwSetMouseButtonCallback(context.window, mouse_button_callback); glfwSetMouseButtonCallback(context.window, mouse_button_callback);
@ -404,7 +568,8 @@ int main() {
int error; int error;
VkResult result; VkResult result;
VK_RESULT(init_vulkan(context.window, context.render)); VK_RESULT(init_vulkan(context.window, context.render));
// TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary // 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_ui_context(10, 10, 10, context.render, context.ui));
VK_RESULT(create_hex_context(context.render, context.hex)); VK_RESULT(create_hex_context(context.render, context.hex));