#include "hex.h" #include "gpu.h" #include "vulkan/vulkan_core.h" #include #include // 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( ®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; 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 = ®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; *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; }