1357 lines
40 KiB
C
1357 lines
40 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},
|
|
};
|
|
|
|
HexCoord hex_starts_qr[] = {
|
|
{ 0, -1},
|
|
{-1, 0},
|
|
{-1, 1},
|
|
{ 0, 1},
|
|
{ 1, 0},
|
|
{ 1, -1},
|
|
};
|
|
|
|
HexCoord hex_directions_qr[] = {
|
|
{-1, 1},
|
|
{ 0, 1},
|
|
{ 1, 0},
|
|
{ 1, -1},
|
|
{ 0, -1},
|
|
{-1, 0},
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
VkPipelineRenderingCreateInfo rendering_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachmentFormats = &gpu->swapchain_format.format,
|
|
.depthAttachmentFormat = gpu->depth_format,
|
|
};
|
|
|
|
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,
|
|
.pNext = &rendering_info,
|
|
.renderPass = VK_NULL_HANDLE,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
VK_RESULT(vkCreateGraphicsPipelines(
|
|
gpu->device,
|
|
VK_NULL_HANDLE,
|
|
1, &graphics_pipeline_info,
|
|
NULL,
|
|
&pipeline->pipeline));
|
|
vkDestroyShaderModule(gpu->device, vert_shader, NULL);
|
|
vkDestroyShaderModule(gpu->device, frag_shader, NULL);
|
|
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,
|
|
};
|
|
|
|
VkPipelineRenderingCreateInfo rendering_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachmentFormats = &gpu->swapchain_format.format,
|
|
.depthAttachmentFormat = gpu->depth_format,
|
|
};
|
|
|
|
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,
|
|
.pNext = &rendering_info,
|
|
.renderPass = VK_NULL_HANDLE,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
VK_RESULT(vkCreateGraphicsPipelines(
|
|
gpu->device,
|
|
VK_NULL_HANDLE,
|
|
1, &graphics_pipeline_info,
|
|
NULL,
|
|
&pipeline->pipeline));
|
|
vkDestroyShaderModule(gpu->device, vert_shader, NULL);
|
|
vkDestroyShaderModule(gpu->device, frag_shader, NULL);
|
|
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,
|
|
};
|
|
|
|
VkPipelineRenderingCreateInfo rendering_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachmentFormats = &gpu->swapchain_format.format,
|
|
.depthAttachmentFormat = gpu->depth_format,
|
|
};
|
|
|
|
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,
|
|
.pNext = &rendering_info,
|
|
.renderPass = VK_NULL_HANDLE,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
VK_RESULT(vkCreateGraphicsPipelines(
|
|
gpu->device,
|
|
VK_NULL_HANDLE,
|
|
1, &graphics_pipeline_info,
|
|
NULL,
|
|
&pipeline->pipeline));
|
|
vkDestroyShaderModule(gpu->device, vert_shader, NULL);
|
|
vkDestroyShaderModule(gpu->device, frag_shader, NULL);
|
|
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,
|
|
};
|
|
|
|
VkPipelineRenderingCreateInfo rendering_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachmentFormats = &gpu->swapchain_format.format,
|
|
.depthAttachmentFormat = gpu->depth_format,
|
|
};
|
|
|
|
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,
|
|
.pNext = &rendering_info,
|
|
.renderPass = VK_NULL_HANDLE,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
VK_RESULT(vkCreateGraphicsPipelines(
|
|
gpu->device,
|
|
VK_NULL_HANDLE,
|
|
1, &graphics_pipeline_info,
|
|
NULL,
|
|
&pipeline->pipeline));
|
|
vkDestroyShaderModule(gpu->device, vert_shader, NULL);
|
|
vkDestroyShaderModule(gpu->device, frag_shader, NULL);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_hex_context(
|
|
RenderContext* gpu,
|
|
HexContext* context) {
|
|
VkResult result;
|
|
|
|
VK_RESULT(create_hex_pipeline(gpu, &context->graphics));
|
|
VK_RESULT(create_ray_pipeline(gpu, &context->ray_pipeline));
|
|
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));
|
|
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(create_storage_buffer(
|
|
gpu->allocator,
|
|
0,
|
|
sizeof(GPURay)*MAX_RAYS,
|
|
&context->rays[i],
|
|
&context->rays_memory[i]));
|
|
|
|
VK_RESULT(create_storage_buffer(
|
|
gpu->allocator,
|
|
0,
|
|
sizeof(GPUPoint)*MAX_POINTS,
|
|
&context->points[i],
|
|
&context->points_memory[i]));
|
|
|
|
VK_RESULT(create_storage_buffer(
|
|
gpu->allocator,
|
|
0,
|
|
sizeof(GPUHighlight)*MAX_HIGHLIGHTS,
|
|
&context->highlights[i],
|
|
&context->highlights_memory[i]));
|
|
}
|
|
|
|
for(uint32_t i = 0; i < MAX_HIGHLIGHTS; i++) {
|
|
uint32_t temp = 0xFFFFFFFF;
|
|
VK_RESULT(add_transfers(
|
|
&temp,
|
|
context->highlights,
|
|
sizeof(GPUHighlight)*i + offsetof(GPUHighlight, hex),
|
|
sizeof(uint32_t),
|
|
gpu));
|
|
}
|
|
|
|
for(uint32_t i = 0; i < MAX_POINTS; i++) {
|
|
uint32_t temp = 0xFFFFFFFF;
|
|
VK_RESULT(add_transfers(
|
|
&temp,
|
|
context->points,
|
|
sizeof(GPUPoint)*i + offsetof(GPUPoint, hex),
|
|
sizeof(uint32_t),
|
|
gpu));
|
|
}
|
|
|
|
VK_RESULT(add_transfers(
|
|
&context->data,
|
|
context->context,
|
|
0,
|
|
sizeof(GPUHexContext),
|
|
gpu));
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
VkDeviceAddress rays, points, highlights;
|
|
rays = buffer_address(gpu->device, context->rays[i]);
|
|
points = buffer_address(gpu->device, context->points[i]);
|
|
highlights = buffer_address(gpu->device, context->highlights[i]);
|
|
|
|
VK_RESULT(add_transfer(
|
|
&rays,
|
|
context->context[i],
|
|
offsetof(GPUHexContext, rays),
|
|
sizeof(VkDeviceAddress),
|
|
i,
|
|
gpu));
|
|
|
|
VK_RESULT(add_transfer(
|
|
&points,
|
|
context->context[i],
|
|
offsetof(GPUHexContext, points),
|
|
sizeof(VkDeviceAddress),
|
|
i,
|
|
gpu));
|
|
|
|
VK_RESULT(add_transfer(
|
|
&highlights,
|
|
context->context[i],
|
|
offsetof(GPUHexContext, highlights),
|
|
sizeof(VkDeviceAddress),
|
|
i,
|
|
gpu));
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void destroy_hex_context(RenderContext* gpu, HexContext* context) {
|
|
vkDestroyPipeline(gpu->device, context->graphics.pipeline, NULL);
|
|
vkDestroyPipelineLayout(gpu->device, context->graphics.layout, NULL);
|
|
vkDestroyPipeline(gpu->device, context->highlight_pipeline.pipeline, NULL);
|
|
vkDestroyPipelineLayout(gpu->device, context->highlight_pipeline.layout, NULL);
|
|
vkDestroyPipeline(gpu->device, context->point_pipeline.pipeline, NULL);
|
|
vkDestroyPipelineLayout(gpu->device, context->point_pipeline.layout, NULL);
|
|
vkDestroyPipeline(gpu->device, context->ray_pipeline.pipeline, NULL);
|
|
vkDestroyPipelineLayout(gpu->device, context->ray_pipeline.layout, NULL);
|
|
|
|
// Direct teardown rather than free_hex_region: its GPU-address-nulling
|
|
// transfer is pointless work when the context's own buffers are about to
|
|
// be destroyed right below, unread.
|
|
for(uint32_t i = 0; i < MAX_LOADED_REGIONS; i++) {
|
|
if(context->regions[i] == NULL) continue;
|
|
vmaDestroyBuffer(gpu->allocator, context->regions[i]->region, context->regions[i]->region_memory);
|
|
free(context->regions[i]);
|
|
context->regions[i] = NULL;
|
|
}
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
vmaDestroyBuffer(gpu->allocator, context->context[i], context->context_memory[i]);
|
|
vmaDestroyBuffer(gpu->allocator, context->rays[i], context->rays_memory[i]);
|
|
vmaDestroyBuffer(gpu->allocator, context->points[i], context->points_memory[i]);
|
|
vmaDestroyBuffer(gpu->allocator, context->highlights[i], context->highlights_memory[i]);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
return add_transfer(
|
|
®ion->data.hexes,
|
|
region->region,
|
|
offsetof(GPUHexRegion, hexes),
|
|
sizeof(GPUHex)*REGION_HEX_COUNT,
|
|
gpu->current_frame,
|
|
gpu);
|
|
}
|
|
|
|
VkResult free_hex_region(
|
|
uint32_t region_index,
|
|
HexContext* hex,
|
|
RenderContext* gpu) {
|
|
if(hex->regions[region_index] == NULL) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
free(hex->regions[region_index]);
|
|
hex->regions[region_index] = NULL;
|
|
|
|
VkDeviceAddress null_address = 0x00;
|
|
return add_transfers(
|
|
&null_address,
|
|
hex->context,
|
|
offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*region_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.position.q = q;
|
|
(*region)->data.position.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.position,
|
|
(*region)->region,
|
|
offsetof(GPUHexRegion, position),
|
|
sizeof(int32_t)*3 + sizeof(uint32_t),
|
|
gpu->current_frame,
|
|
gpu));
|
|
|
|
(*region)->address = buffer_address(gpu->device, (*region)->region);
|
|
|
|
return add_transfers(
|
|
&(*region)->address,
|
|
hex->context,
|
|
offsetof(GPUHexContext, regions) + sizeof(VkDeviceAddress)*i,
|
|
sizeof(VkDeviceAddress),
|
|
gpu);
|
|
}
|
|
|
|
bool ray_hex_intersect(
|
|
float* distance,
|
|
uint32_t* vertex,
|
|
vec3 start,
|
|
vec3 dir,
|
|
vec3 region_offset,
|
|
uint32_t hex_index,
|
|
bool edge_only,
|
|
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]);
|
|
}
|
|
|
|
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;
|
|
if(edge_only) {
|
|
// Never report the hex center (vertex 0) - always snap to whichever
|
|
// of the triangle's two edge vertices is closer, so vertex-mode
|
|
// picking always lands on a real, editable vertex.
|
|
if(u >= v) {
|
|
*vertex = ((triangle + 1) % 6) + 1;
|
|
} else {
|
|
*vertex = triangle + 1;
|
|
}
|
|
} else {
|
|
float w = 1 - u - v;
|
|
if(u >= v && u >= w) {
|
|
*vertex = ((triangle + 1) % 6) + 1;
|
|
} else if(v >= u && v >= w) {
|
|
*vertex = triangle + 1;
|
|
} else {
|
|
*vertex = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return intersect;
|
|
}
|
|
|
|
bool ray_region_intersect(
|
|
float* distance,
|
|
uint32_t* vertex,
|
|
uint32_t* hid,
|
|
vec3 start,
|
|
vec3 dir,
|
|
bool edge_only,
|
|
HexRegion* region) {
|
|
bool intersect = false;
|
|
float intersect_distance = INFINITY;
|
|
uint32_t intersection_vertex = 0;
|
|
vec3 region_offset = {
|
|
((float)region->data.position.q + (float)region->data.position.r/2)*REGION_WIDTH - region->data.position.r*HEX_X/2,
|
|
0,
|
|
0.75*region->data.position.r*REGION_HEIGHT + 0.25*region->data.position.r*HEX_Z + 0.5*region->data.position.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, edge_only, 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,
|
|
bool edge_only,
|
|
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, edge_only, region)) {
|
|
if(intersect_distance < *distance) {
|
|
intersect = true;
|
|
*hid = intersect_hid;
|
|
*rid = intersect_rid;
|
|
*vertex = intersection_vertex;
|
|
*distance = intersect_distance;
|
|
}
|
|
}
|
|
}
|
|
|
|
return intersect;
|
|
}
|
|
|
|
void update_hex_picking_inverse(Camera* camera, HexContext* hex) {
|
|
mat4 regular;
|
|
glm_mat4_mul(camera->proj, camera->view, regular);
|
|
glm_mat4_inv(regular, hex->inverse);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void hex_qr(uint32_t hex, HexCoord* world) {
|
|
float radius = 0;
|
|
float ring = 0;
|
|
int side = 0;
|
|
if(hex != 0) {
|
|
radius = floor(0.5 + sqrt(12*hex-3)/6);
|
|
ring = hex - (3*radius*radius - 3*radius + 1);
|
|
side = floor(ring/radius);
|
|
}
|
|
|
|
world->q = hex_starts_qr[side].q*radius + hex_directions_qr[side].q*(ring-(radius*side));
|
|
world->r = hex_starts_qr[side].r*radius + hex_directions_qr[side].r*(ring-(radius*side));
|
|
}
|
|
|
|
void region_qr(HexCoord region, HexCoord* world) {
|
|
world->q = region.q * REGION_DIAMETER + region.r * (REGION_DIAMETER - 1)/2;
|
|
world->r = -region.r * REGION_DIAMETER - region.q * (REGION_DIAMETER + 1)/2;
|
|
}
|
|
|
|
void hex_add(HexCoord from, HexCoord* to) {
|
|
to->q += from.q;
|
|
to->r += from.r;
|
|
}
|
|
|
|
unsigned int hex_distance(HexCoord a, HexCoord b) {
|
|
return (abs(a.q - b.q) + abs(a.r - b.r) + abs(a.q + a.r - b.q - b.r))/2;
|
|
}
|
|
|
|
unsigned int region_radius_1(HexCoord hex, HexCoord region) {
|
|
return region.q*REGION_DIAMETER + region.r*(REGION_SIZE-1) - hex.q;
|
|
}
|
|
|
|
unsigned int region_radius_2(HexCoord hex, HexCoord region) {
|
|
return -region.r*REGION_DIAMETER - region.q*REGION_SIZE - hex.r;
|
|
}
|
|
|
|
unsigned int region_radius_3(HexCoord hex, HexCoord region) {
|
|
return region.q*(REGION_SIZE-1) - region.r*REGION_SIZE - hex.q - hex.r;
|
|
}
|
|
|
|
void region_1(HexCoord hex, HexCoord* region) {
|
|
region->q = ceil((hex.q*REGION_DIAMETER + hex.r*(REGION_SIZE-1))/(double)REGION_HEX_COUNT);
|
|
region->r = floor((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void region_2(HexCoord hex, HexCoord* region) {
|
|
region->q = ceil((hex.q*REGION_DIAMETER + hex.r*(REGION_SIZE - 1))/(double)REGION_HEX_COUNT);
|
|
region->r = floor((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER + REGION_SIZE*REGION_SIZE - 2*REGION_SIZE + 1)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void region_3(HexCoord hex, HexCoord* region) {
|
|
region->q = ceil((hex.q*REGION_DIAMETER + hex.r*(REGION_SIZE-1) - REGION_SIZE*REGION_SIZE + 2*REGION_SIZE - 1)/(double)REGION_HEX_COUNT);
|
|
region->r = ceil((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void region_4(HexCoord hex, HexCoord* region) {
|
|
region->q = ceil((hex.q*REGION_DIAMETER + hex.r*(REGION_SIZE-1) - REGION_SIZE*REGION_SIZE + REGION_SIZE)/(double)REGION_HEX_COUNT);
|
|
region->r = floor((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void region_5(HexCoord hex, HexCoord* region) {
|
|
region->q = ceil((hex.r*(REGION_SIZE-1) + hex.q*REGION_DIAMETER - 2*REGION_SIZE*REGION_SIZE + 2*REGION_SIZE)/(double)REGION_HEX_COUNT);
|
|
region->r = floor((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER + REGION_SIZE*REGION_SIZE - REGION_SIZE)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void region_6(HexCoord hex, HexCoord* region) {
|
|
region->q = floor((hex.q*REGION_DIAMETER + hex.r*(REGION_SIZE-1))/(double)REGION_HEX_COUNT);
|
|
region->r = ceil((-hex.q*REGION_SIZE - hex.r*REGION_DIAMETER)/(double)REGION_HEX_COUNT);
|
|
}
|
|
|
|
void hex_index(HexCoord world, HexCoord* region, uint32_t* hex) {
|
|
int R1, R2, R3;
|
|
unsigned int side, radius;
|
|
HexCoord side_start, region_center;
|
|
|
|
region_1(world, region);
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (R1 + R2 + R3)/2;
|
|
if(R1 >= 0 && R2 > 0 && radius <= REGION_SIZE - 1) {
|
|
side = 0;
|
|
goto side_found;
|
|
}
|
|
|
|
region_2(world, region);
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (R1 - R2 + R3)/2;
|
|
if(R2 <= 0 && R3 > 0 && radius <= REGION_SIZE - 1) {
|
|
side = 1;
|
|
goto side_found;
|
|
}
|
|
|
|
region_3(world, region);
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (R1 - R2 - R3)/2;
|
|
if(R1 > 0 && R3 <= 0 && radius <= REGION_SIZE - 1) {
|
|
side = 2;
|
|
goto side_found;
|
|
}
|
|
|
|
region_4(world, region);
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (-R1 + R2 + R3)/2;
|
|
if(R1 < 0 && R3 >= 0 && radius <= REGION_SIZE - 1) {
|
|
side = 5;
|
|
goto side_found;
|
|
}
|
|
|
|
region_5(world, region);
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (-R1 + R2 - R3)/2;
|
|
if(R2 >= 0 && R3 < 0 && radius <= REGION_SIZE - 1) {
|
|
side = 4;
|
|
goto side_found;
|
|
}
|
|
|
|
region_6(world, region);
|
|
side = 3;
|
|
R1 = region_radius_1(world, *region);
|
|
R2 = region_radius_2(world, *region);
|
|
R3 = region_radius_3(world, *region);
|
|
radius = (-R1 - R2 -R3)/2;
|
|
|
|
side_found:
|
|
side_start.q = hex_starts_qr[side].q * radius;
|
|
side_start.r = hex_starts_qr[side].r * radius;
|
|
region_qr(*region, ®ion_center);
|
|
hex_add(region_center, &side_start);
|
|
|
|
unsigned int side_distance = hex_distance(world, side_start);
|
|
if(radius == 0) {
|
|
*hex = 0;
|
|
} else {
|
|
*hex = (3*radius*(radius-1) + 1) + radius*side + side_distance;
|
|
}
|
|
}
|
|
|
|
void hex_vertex_neighbors(
|
|
uint32_t vertex, HexCoord hex,
|
|
uint32_t n_vertex[2], HexCoord n_region[2], uint32_t n_hex[2]) {
|
|
HexCoord n1 = hex_starts_qr[(vertex+3) % 6];
|
|
HexCoord n2 = hex_starts_qr[(vertex+4) % 6];
|
|
|
|
hex_add(hex, &n1);
|
|
hex_add(hex, &n2);
|
|
|
|
hex_index(n1, &n_region[0], &n_hex[0]);
|
|
hex_index(n2, &n_region[1], &n_hex[1]);
|
|
|
|
n_vertex[0] = ((vertex + 1) % 6) + 1;
|
|
n_vertex[1] = ((vertex + 3) % 6) + 1;
|
|
}
|
|
|
|
void first_matching_region(HexCoord coord, int y, uint32_t* region, HexContext* context) {
|
|
for(*region = 0; *region < MAX_LOADED_REGIONS; (*region)++) {
|
|
if(context->regions[*region] != NULL
|
|
&& context->regions[*region]->data.position.q == coord.q
|
|
&& context->regions[*region]->data.position.r == coord.r
|
|
&& context->regions[*region]->data.y == y) {
|
|
return;
|
|
}
|
|
}
|
|
}
|