roleplay/client/src/hex.c

1112 lines
31 KiB
C

#include "hex.h"
#include "gpu.h"
#include "vulkan/vulkan_core.h"
#include <stdio.h>
#include <string.h>
// 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,
};
VkResult create_point_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
VkResult result;
VkShaderModule vert_shader = load_shader_file("shader/point.vert.spv", gpu->device);
VkShaderModule frag_shader = load_shader_file("shader/point.frag.spv", gpu->device);
VkPipelineShaderStageCreateInfo stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.pName = "main",
.module = vert_shader,
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.pName = "main",
.module = frag_shader,
},
};
VkPushConstantRange push = {
.size = sizeof(HexPushConstant),
.offset = 0,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pPushConstantRanges = &push,
.pushConstantRangeCount = 1,
};
VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout));
VkPipelineVertexInputStateCreateInfo vertex_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
};
VkPipelineInputAssemblyStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkViewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = (float)(100),
.height = (float)(100),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
VkRect2D scissor = {
.offset = {
.x = 0,
.y = 0,
},
.extent = {
.width = 100,
.height = 100,
},
};
VkPipelineViewportStateCreateInfo viewport_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
VkPipelineRasterizationStateCreateInfo raster_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
};
VkPipelineColorBlendAttachmentState blend_attachments = {
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
};
VkPipelineColorBlendStateCreateInfo blend_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &blend_attachments,
};
VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
VkPipelineDynamicStateCreateInfo dynamic_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState),
.pDynamicStates = dynamic_states,
};
VkPipelineMultisampleStateCreateInfo multisample_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = 0,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineDepthStencilStateCreateInfo depth_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE,
.depthCompareOp = VK_COMPARE_OP_LESS,
};
VkGraphicsPipelineCreateInfo graphics_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.layout = pipeline->layout,
.stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo),
.pStages = stages,
.pVertexInputState = &vertex_info,
.pInputAssemblyState = &input_info,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_info,
.pColorBlendState = &blend_info,
.pDynamicState = &dynamic_info,
.pMultisampleState = &multisample_info,
.pDepthStencilState = &depth_info,
.renderPass = gpu->render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
VkResult create_ray_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
VkResult result;
VkShaderModule vert_shader = load_shader_file("shader/ray.vert.spv", gpu->device);
VkShaderModule frag_shader = load_shader_file("shader/ray.frag.spv", gpu->device);
VkPipelineShaderStageCreateInfo stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.pName = "main",
.module = vert_shader,
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.pName = "main",
.module = frag_shader,
},
};
VkPushConstantRange push = {
.size = sizeof(HexPushConstant),
.offset = 0,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pPushConstantRanges = &push,
.pushConstantRangeCount = 1,
};
VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout));
VkPipelineVertexInputStateCreateInfo vertex_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
};
VkPipelineInputAssemblyStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkViewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = (float)(100),
.height = (float)(100),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
VkRect2D scissor = {
.offset = {
.x = 0,
.y = 0,
},
.extent = {
.width = 100,
.height = 100,
},
};
VkPipelineViewportStateCreateInfo viewport_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
VkPipelineRasterizationStateCreateInfo raster_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
};
VkPipelineColorBlendAttachmentState blend_attachments = {
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
};
VkPipelineColorBlendStateCreateInfo blend_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &blend_attachments,
};
VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
VkPipelineDynamicStateCreateInfo dynamic_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState),
.pDynamicStates = dynamic_states,
};
VkPipelineMultisampleStateCreateInfo multisample_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = 0,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineDepthStencilStateCreateInfo depth_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE,
.depthCompareOp = VK_COMPARE_OP_LESS,
};
VkGraphicsPipelineCreateInfo graphics_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.layout = pipeline->layout,
.stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo),
.pStages = stages,
.pVertexInputState = &vertex_info,
.pInputAssemblyState = &input_info,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_info,
.pColorBlendState = &blend_info,
.pDynamicState = &dynamic_info,
.pMultisampleState = &multisample_info,
.pDepthStencilState = &depth_info,
.renderPass = gpu->render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
VkResult create_hex_highlight_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
VkResult result;
VkShaderModule vert_shader = load_shader_file("shader/hex_highlight.vert.spv", gpu->device);
VkShaderModule frag_shader = load_shader_file("shader/hex_highlight.frag.spv", gpu->device);
VkPipelineShaderStageCreateInfo stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.pName = "main",
.module = vert_shader,
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.pName = "main",
.module = frag_shader,
},
};
VkPushConstantRange push = {
.size = sizeof(HexPushConstant),
.offset = 0,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pPushConstantRanges = &push,
.pushConstantRangeCount = 1,
};
VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout));
VkPipelineVertexInputStateCreateInfo vertex_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
};
VkPipelineInputAssemblyStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkViewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = (float)(100),
.height = (float)(100),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
VkRect2D scissor = {
.offset = {
.x = 0,
.y = 0,
},
.extent = {
.width = 100,
.height = 100,
},
};
VkPipelineViewportStateCreateInfo viewport_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
VkPipelineRasterizationStateCreateInfo raster_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
};
VkPipelineColorBlendAttachmentState blend_attachments = {
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
};
VkPipelineColorBlendStateCreateInfo blend_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &blend_attachments,
};
VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
VkPipelineDynamicStateCreateInfo dynamic_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState),
.pDynamicStates = dynamic_states,
};
VkPipelineMultisampleStateCreateInfo multisample_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = 0,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineDepthStencilStateCreateInfo depth_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE,
.depthCompareOp = VK_COMPARE_OP_LESS,
};
VkGraphicsPipelineCreateInfo graphics_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.layout = pipeline->layout,
.stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo),
.pStages = stages,
.pVertexInputState = &vertex_info,
.pInputAssemblyState = &input_info,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_info,
.pColorBlendState = &blend_info,
.pDynamicState = &dynamic_info,
.pMultisampleState = &multisample_info,
.pDepthStencilState = &depth_info,
.renderPass = gpu->render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
VkResult create_hex_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
VkResult result;
VkShaderModule vert_shader = load_shader_file("shader/hex.vert.spv", gpu->device);
VkShaderModule frag_shader = load_shader_file("shader/hex.frag.spv", gpu->device);
VkPipelineShaderStageCreateInfo stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.pName = "main",
.module = vert_shader,
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.pName = "main",
.module = frag_shader,
},
};
VkPushConstantRange push = {
.size = sizeof(HexPushConstant),
.offset = 0,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pPushConstantRanges = &push,
.pushConstantRangeCount = 1,
};
VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout));
VkPipelineVertexInputStateCreateInfo vertex_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
};
VkPipelineInputAssemblyStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkViewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = (float)(100),
.height = (float)(100),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
VkRect2D scissor = {
.offset = {
.x = 0,
.y = 0,
},
.extent = {
.width = 100,
.height = 100,
},
};
VkPipelineViewportStateCreateInfo viewport_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
VkPipelineRasterizationStateCreateInfo raster_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
};
VkPipelineColorBlendAttachmentState blend_attachments = {
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
};
VkPipelineColorBlendStateCreateInfo blend_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &blend_attachments,
};
VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
VkPipelineDynamicStateCreateInfo dynamic_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState),
.pDynamicStates = dynamic_states,
};
VkPipelineMultisampleStateCreateInfo multisample_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = 0,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineDepthStencilStateCreateInfo depth_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE,
.depthCompareOp = VK_COMPARE_OP_LESS,
};
VkGraphicsPipelineCreateInfo graphics_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.layout = pipeline->layout,
.stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo),
.pStages = stages,
.pVertexInputState = &vertex_info,
.pInputAssemblyState = &input_info,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_info,
.pColorBlendState = &blend_info,
.pDynamicState = &dynamic_info,
.pMultisampleState = &multisample_info,
.pDepthStencilState = &depth_info,
.renderPass = gpu->render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
VkResult create_hex_context(
RenderContext* gpu,
HexContext* context) {
VkResult result;
VK_RESULT(create_hex_pipeline(gpu, &context->graphics));
#ifdef DRAW_HEX_RAYS
VK_RESULT(create_ray_pipeline(gpu, &context->ray_pipeline));
#endif
VK_RESULT(create_hex_highlight_pipeline(gpu, &context->highlight_pipeline));
VK_RESULT(create_point_pipeline(gpu, &context->point_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_mat4_identity(context->data.view);
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VK_RESULT(create_storage_buffer(
gpu->allocator,
0,
sizeof(GPUHexContext),
&context->context[i],
&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));
return VK_SUCCESS;
}
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;
for(; i < MAX_LOADED_REGIONS; i++) {
if(hex->regions[i] == NULL) {
hex->regions[i] = malloc(sizeof(HexRegion));
*region = hex->regions[i];
break;
}
}
if(*region == NULL) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
(*region)->data.q = q;
(*region)->data.r = r;
(*region)->data.y = y;
(*region)->data.map = map;
VK_RESULT(create_storage_buffer(
gpu->allocator,
0,
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));
(*region)->address = buffer_address(gpu->device, (*region)->region);
return VK_SUCCESS;
}
bool ray_hex_intersect(
float* distance,
uint32_t* vertex,
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]);
}
bool intersect = false;
vec3 t;
glm_vec3_sub(start, vertices[0], t);
for(uint32_t triangle = 0; triangle < 6; triangle++) {
vec3 vert[2];
for(int v_i = 0; v_i < 2; v_i++) {
vert[v_i][0] = vertices[hex_indices[triangle*3+v_i + 1]][0];
vert[v_i][1] = vertices[hex_indices[triangle*3+v_i + 1]][1];
vert[v_i][2] = vertices[hex_indices[triangle*3+v_i + 1]][2];
}
vec3 v0v1;
glm_vec3_sub(vert[0], vertices[0], v0v1);
vec3 v0v2;
glm_vec3_sub(vert[1], vertices[0], v0v2);
vec3 pvec;
glm_vec3_cross(dir, v0v2, pvec);
float det = glm_vec3_dot(v0v1, pvec);
float u = glm_vec3_dot(t, pvec) / det;
if(u < 0 || u > 1) continue;
vec3 q;
glm_vec3_cross(t, v0v1, q);
float v = glm_vec3_dot(dir, q) / det;
if(v < 0 || (u+v) > 1) continue;
intersect = true;
float intersect_distance = glm_vec3_dot(v0v2, q) / det;
if(intersect_distance < *distance) {
*distance = intersect_distance;
*vertex = (u > v) ? ((triangle+1) % 6)+1 : triangle+1;
}
}
return intersect;
}
bool ray_region_intersect(
float* distance,
uint32_t* vertex,
uint32_t* hid,
vec3 start,
vec3 dir,
HexRegion* region) {
bool intersect = false;
float intersect_distance = INFINITY;
uint32_t intersection_vertex = 0;
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 intersect_hid = 0; intersect_hid < REGION_HEX_COUNT; intersect_hid++) {
if(ray_hex_intersect(&intersect_distance, &intersection_vertex, start, dir, region_offset, intersect_hid, region)) {
if(intersect_distance < *distance) {
intersect = true;
*hid = intersect_hid;
*distance = intersect_distance;
*vertex = intersection_vertex;
}
}
}
return intersect;
}
bool ray_world_intersect(
float* distance,
uint32_t* vertex,
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 intersect_distance = INFINITY;
uint32_t intersection_vertex = 0;
uint32_t intersect_hid;
*distance = INFINITY;
for(uint32_t intersect_rid = 0; intersect_rid < MAX_LOADED_REGIONS; intersect_rid++) {
HexRegion* region = context->regions[intersect_rid];
if(region == NULL) {
continue;
} else if(region->data.map != context->data.current_map) {
continue;
}
if(ray_region_intersect(&intersect_distance, &intersection_vertex, &intersect_hid, start, dir, region)) {
if(intersect_distance < *distance) {
intersect = true;
*hid = intersect_hid;
*rid = intersect_rid;
*vertex = intersection_vertex;
*distance = intersect_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,
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, hex->inverse);
return add_transfers(&hex->data, hex->context, 0, 2*sizeof(mat4), gpu);
}
void cursor_to_world_ray(RenderContext* gpu, mat4 inverse, double cursor[2], vec4 start, vec4 end) {
double cursor_scaled[2] = {
2*(cursor[0]*gpu->window_scale[0]/gpu->swapchain_extent.width - 0.5),
2*(cursor[1]*gpu->window_scale[1]/gpu->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(inverse, transformed_start, start);
glm_mat4_mulv(inverse, transformed_end, end);
}
VkResult update_hex_hover(
double cursor[2],
HexContext* hex,
RenderContext* gpu) {
cursor_to_world_ray(
gpu,
hex->inverse,
cursor,
hex->data.hover_start,
hex->data.hover_end);
add_transfers(
&hex->data.hover_start,
hex->context,
offsetof(GPUHexContext, hover_start),
sizeof(vec4)*2,
gpu);
float distance;
if(ray_world_intersect(
&distance,
&hex->data.hovered_vertex,
&hex->data.hovered_region,
&hex->data.hovered_hex,
hex->data.hover_start,
hex->data.hover_end,
hex)) {
add_transfers(
&hex->data.hovered_region,
hex->context,
offsetof(GPUHexContext, hovered_region),
sizeof(uint32_t)*3,
gpu);
}
return VK_SUCCESS;
}
VkResult update_hex_click(
double cursor[2],
HexContext* hex,
RenderContext* gpu) {
VkResult result;
float distance;
cursor_to_world_ray(
gpu,
hex->inverse,
cursor,
hex->data.click_start,
hex->data.click_end);
VK_RESULT(add_transfers(
&hex->data.click_start,
hex->context,
offsetof(GPUHexContext, click_start),
sizeof(vec4)*2,
gpu));
if(ray_world_intersect(
&distance,
&hex->data.clicked_vertex,
&hex->data.clicked_region,
&hex->data.clicked_hex,
hex->data.click_start,
hex->data.click_end,
hex)) {
VK_RESULT(add_transfers(
&hex->data.clicked_region,
hex->context,
offsetof(GPUHexContext, clicked_region),
sizeof(uint32_t)*3,
gpu));
}
return VK_SUCCESS;
}