diff --git a/Makefile b/Makefile index eeda30c..f44f3b4 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,8 @@ OBJS = \ src/minecraft/world.o \ src/minecraft/entry_table.o \ src/minecraft/vulkan.o \ - src/minecraft/vulkan/per_world.o + src/minecraft/vulkan/per_world.o \ + src/font/outline.o WORLDS = \ data/minecraft/midnightmeadow/inthash.o \ diff --git a/data/font/outline/uncial_antiqua_36.data b/data/font/outline/uncial_antiqua_36.data new file mode 100644 index 0000000..90e468e Binary files /dev/null and b/data/font/outline/uncial_antiqua_36.data differ diff --git a/filenames.txt b/filenames.txt index fb4c619..de3e097 100644 --- a/filenames.txt +++ b/filenames.txt @@ -35,3 +35,6 @@ data/minecraft/midnightmeadow/global.dump data/minecraft/midnightmeadow/global.lights.vtx data/minecraft/terrain2.dds + +shader/font.spv +data/font/outline/uncial_antiqua_36.data diff --git a/include/font/outline.h b/include/font/outline.h new file mode 100644 index 0000000..7295189 --- /dev/null +++ b/include/font/outline.h @@ -0,0 +1,79 @@ +#pragma once + +#include "outline_types.h" +#include "vulkan_helper.h" + +namespace font::outline { + + struct font_desc { + char const * const path; + }; + + font_desc const uncial_antiqua[] = { + { + .path = "data/font/outline/uncial_antiqua_36.data", + }, + }; + int const uncial_antiqua_length = (sizeof (uncial_antiqua)) / (sizeof (font_desc)); + + struct AllocatedImage { + VkImage image; + VkDeviceMemory memory; + VkImageView imageView; + }; + + struct LoadedFont { + types::font * font; + types::glyph * glyphs; + AllocatedImage allocatedImage; + }; + + struct font { + static constexpr int perVertexSize = (4) * 2; + static constexpr int perInstanceSize = (0) * 2; + + VkInstance instance; + VkDevice device; + VkQueue queue; + VkCommandPool commandPool; + VkPhysicalDeviceProperties physicalDeviceProperties; + VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; + VkFormat colorFormat; + VkFormat depthFormat; + VkSampler linearSampler; + + // font-specific state + VkPipelineLayout pipelineLayout; + VkShaderModule shaderModule; + VkPipeline pipeline; + VertexIndex vertexIndex; + LoadedFont loadedFont; + + VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; + static constexpr int descriptorSetLayoutCount = 1; + VkDescriptorSetLayout descriptorSetLayouts[descriptorSetLayoutCount]; // unrelated to maxFrames, unrelated to descriptorCount + VkDescriptorSet descriptorSet0; + + void initial_state(VkInstance instance, + VkDevice device, + VkQueue queue, + VkCommandPool commandPool, + VkPhysicalDeviceProperties physicalDeviceProperties, + VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, + VkFormat colorFormat, + VkFormat depthFormat, + VkSampler linearSampler); + + void init(); + + void load_vertex_index_buffer(); + void load_shader(); + void create_descriptor_sets(); + void write_descriptor_sets(VkImageView fontImageView); + void create_pipeline(); + void draw(VkCommandBuffer commandBuffer, + uint32_t frameIndex); + + LoadedFont load_font(font_desc const& desc); + }; +} diff --git a/include/font/outline_types.h b/include/font/outline_types.h new file mode 100644 index 0000000..de4a3c7 --- /dev/null +++ b/include/font/outline_types.h @@ -0,0 +1,49 @@ +// this file is designed to be platform-agnostic +#pragma once + +#include + +namespace font::outline::types { + + // metrics are 26.6 fixed point + struct glyph_metrics { + int32_t horiBearingX; + int32_t horiBearingY; + int32_t horiAdvance; + }; + + static_assert((sizeof (struct glyph_metrics)) == ((sizeof (int32_t)) * 3)); + + struct glyph_bitmap { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + }; + + static_assert((sizeof (struct glyph_bitmap)) == ((sizeof (uint16_t)) * 4)); + + struct glyph { + struct glyph_bitmap bitmap; + struct glyph_metrics metrics; + }; + + static_assert((sizeof (struct glyph)) == ((sizeof (struct glyph_bitmap)) + (sizeof (struct glyph_metrics)))); + + struct font { + uint32_t first_char_code; + uint32_t last_char_code; + struct face_metrics { + int32_t height; // 26.6 fixed point + int32_t max_advance; // 26.6 fixed point + } face_metrics; + uint16_t glyph_count; + uint16_t _texture_stride; + uint16_t texture_width; + uint16_t texture_height; + uint32_t max_z_curve_ix; + }; + + static_assert((sizeof (struct font)) == ((sizeof (uint32_t)) * 7)); + +} diff --git a/include/minecraft/vulkan.h b/include/minecraft/vulkan.h index 46b2625..83c11db 100644 --- a/include/minecraft/vulkan.h +++ b/include/minecraft/vulkan.h @@ -3,6 +3,7 @@ #include "directxmath/directxmath.h" #include "volk/volk.h" +#include "vulkan_helper.h" #include "minecraft/vulkan/per_world.h" namespace minecraft::vulkan { @@ -24,12 +25,7 @@ namespace minecraft::vulkan { static constexpr int perVertexSize = (3 + 3 + 2) * 2; static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2; - struct { - VkDeviceSize jointWeightOffset; - VkDeviceSize indexOffset; - VkBuffer buffer; - VkDeviceMemory memory; - } vertexIndex; + VertexIndex vertexIndex; // externally initialized, opaque handle VkInstance instance; diff --git a/include/vulkan_helper.h b/include/vulkan_helper.h index 9b3be79..78e3f0e 100644 --- a/include/vulkan_helper.h +++ b/include/vulkan_helper.h @@ -73,3 +73,42 @@ void createImageFromFilenameTGA(VkDevice device, VkImage * outImage, VkDeviceMemory * outMemory, VkImageView * outImageView); + +void createImage(VkDevice device, + VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + VkFormat format, + uint32_t width, + uint32_t height, + uint32_t levelCount, + VkImage * outImage, + VkDeviceMemory * outMemory, + VkImageView * outImageView); + +void textureTransfer(VkDevice device, + VkQueue queue, + VkCommandBuffer commandBuffer, + VkFence fence, + VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + uint32_t imageDataSize, + void * imageData, + VkImage image, + uint32_t width, + uint32_t height, + uint32_t levelCount, + uint32_t * levelOffsets); + +struct VertexIndex { + VkDeviceSize indexOffset; + VkBuffer buffer; + VkDeviceMemory memory; +}; + +VertexIndex createVertexIndexBuffer(VkDevice device, + VkPhysicalDeviceProperties const& physicalDeviceProperties, + VkPhysicalDeviceMemoryProperties const& physicalDeviceMemoryProperties, + void const * vertexStart, + uint32_t vertexSize, + void const * indexStart, + uint32_t indexSize); diff --git a/shader/font.hlsl b/shader/font.hlsl new file mode 100644 index 0000000..035e729 --- /dev/null +++ b/shader/font.hlsl @@ -0,0 +1,32 @@ +// set 1: constant +[[vk::binding(0, 0)]] SamplerState ClosestSampler; +[[vk::binding(1, 0)]] Texture2D FontTexture; + +struct VSInput +{ + float2 Position : POSITION0; + float2 Texture : TEXCOORD0; +}; + +struct VSOutput +{ + float4 Position : SV_POSITION; + float2 Texture : NORMAL0; +}; + +[shader("vertex")] +VSOutput VSMain(VSInput input) +{ + VSOutput output = (VSOutput)0; + output.Position = float4(input.Position, 0, 1); + output.Texture = input.Texture; + + return output; +} + +[shader("pixel")] +float4 PSMain(VSOutput input) : SV_TARGET +{ + float4 color = FontTexture.Sample(ClosestSampler, input.Texture); + return float4(color.xxx, 1.0); +} diff --git a/src/font/outline.cpp b/src/font/outline.cpp new file mode 100644 index 0000000..27defea --- /dev/null +++ b/src/font/outline.cpp @@ -0,0 +1,481 @@ +#include +#include +#include + +#include "volk/volk.h" +#include "vulkan/vk_enum_string_helper.h" + +#include "directxmath/directxmath.h" +#include "vulkan_helper.h" +#include "check.h" +#include "file.h" + +#include "font/outline.h" +#include "font/outline_types.h" + +namespace font::outline { + static const _Float16 vertexData[] = { + // x y u v + (_Float16)-1.0, (_Float16)-1.0, (_Float16)0.0, (_Float16)0.0, + (_Float16)1.0, (_Float16)-1.0, (_Float16)1.0, (_Float16)0.0, + (_Float16)-1.0, (_Float16)1.0, (_Float16)0.0, (_Float16)1.0, + (_Float16)1.0, (_Float16)1.0, (_Float16)1.0, (_Float16)1.0, + }; + static const uint32_t vertexSize = (sizeof (vertexData)); + + static const uint16_t indexData[] = { + 0, 1, 2, 3, + }; + static const uint32_t indexSize = (sizeof (indexData)); + + void font::initial_state(VkInstance instance, + VkDevice device, + VkQueue queue, + VkCommandPool commandPool, + VkPhysicalDeviceProperties physicalDeviceProperties, + VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, + VkFormat colorFormat, + VkFormat depthFormat, + VkSampler linearSampler) + { + this->instance = instance; + this->device = device; + this->queue = queue; + this->commandPool = commandPool; + + this->physicalDeviceProperties = physicalDeviceProperties; + this->physicalDeviceMemoryProperties = physicalDeviceMemoryProperties; + + this->colorFormat = colorFormat; + this->depthFormat = depthFormat; + + this->linearSampler = linearSampler; + } + + void font::init() + { + load_vertex_index_buffer(); + load_shader(); + create_descriptor_sets(); + loadedFont = load_font(uncial_antiqua[0]); + write_descriptor_sets(loadedFont.allocatedImage.imageView); + create_pipeline(); + } + + ////////////////////////////////////////////////////////////////////// + // vertex index buffer + ////////////////////////////////////////////////////////////////////// + + void font::load_vertex_index_buffer() + { + void const * vertexStart = (void const *)vertexData; + void const * indexStart = (void const *)indexData; + + vertexIndex = createVertexIndexBuffer(device, + physicalDeviceProperties, + physicalDeviceMemoryProperties, + vertexStart, vertexSize, + indexStart, indexSize); + } + + ////////////////////////////////////////////////////////////////////// + // shader + ////////////////////////////////////////////////////////////////////// + + void font::load_shader() + { + uint32_t shaderSize; + void const * shaderStart = file::open("shader/font.spv", &shaderSize); + + VkShaderModuleCreateInfo shaderModuleCreateInfo{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = shaderSize, + .pCode = (uint32_t *)shaderStart + }; + VK_CHECK(vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &shaderModule)); + } + + ////////////////////////////////////////////////////////////////////// + // pipeline + ////////////////////////////////////////////////////////////////////// + + void font::create_pipeline() + { + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = descriptorSetLayoutCount, + .pSetLayouts = descriptorSetLayouts, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr + }; + VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP + }; + + VkPipelineShaderStageCreateInfo shaderStages[2]{ + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = shaderModule, + .pName = "VSMain" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = shaderModule, + .pName = "PSMain" + } + }; + + VkPipelineViewportStateCreateInfo viewportState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .scissorCount = 1 + }; + + constexpr uint32_t dynamicStateCount = 2; + VkDynamicState dynamicStates[dynamicStateCount]{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + VkPipelineDynamicStateCreateInfo dynamicState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = dynamicStateCount, + .pDynamicStates = dynamicStates + }; + + VkPipelineDepthStencilStateCreateInfo depthStencilState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_FALSE, + .depthWriteEnable = VK_FALSE, + .depthCompareOp = VK_COMPARE_OP_ALWAYS, + .stencilTestEnable = VK_FALSE, + .front = { + .failOp = VK_STENCIL_OP_REPLACE, + .passOp = VK_STENCIL_OP_REPLACE, + .depthFailOp = VK_STENCIL_OP_REPLACE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .compareMask = 0x01, + .writeMask = 0x01, + .reference = 1, + }, + .back = { + .failOp = VK_STENCIL_OP_REPLACE, + .passOp = VK_STENCIL_OP_REPLACE, + .depthFailOp = VK_STENCIL_OP_REPLACE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .compareMask = 0x01, + .writeMask = 0x01, + .reference = 1, + }, + }; + + VkPipelineRenderingCreateInfo renderingCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &colorFormat, + .depthAttachmentFormat = depthFormat, + .stencilAttachmentFormat = depthFormat + }; + + VkPipelineColorBlendAttachmentState blendAttachment{ + .colorWriteMask = 0xF + }; + VkPipelineColorBlendStateCreateInfo colorBlendState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &blendAttachment + }; + VkPipelineRasterizationStateCreateInfo rasterizationState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + //.cullMode = VK_CULL_MODE_BACK_BIT, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .lineWidth = 1.0f + }; + VkPipelineMultisampleStateCreateInfo multisampleState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT + }; + + VkVertexInputBindingDescription vertexBindingDescriptions[2]{ + { + .binding = 0, + .stride = perVertexSize, + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX + }, + { + .binding = 1, + .stride = perInstanceSize, + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + + VkVertexInputAttributeDescription vertexAttributeDescriptions[2]{ + // per-vertex + { // position + .location = 0, + .binding = 0, + .format = VK_FORMAT_R16G16_SFLOAT, + .offset = 0, + }, + { // texture + .location = 1, + .binding = 0, + .format = VK_FORMAT_R16G16_SFLOAT, + .offset = 4, + }, + }; + + VkPipelineVertexInputStateCreateInfo vertexInputState{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + //.vertexBindingDescriptionCount = 2, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = 2, + .pVertexAttributeDescriptions = vertexAttributeDescriptions, + }; + + VkGraphicsPipelineCreateInfo pipelineCreateInfos[1]{ + { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &renderingCreateInfo, + .stageCount = 2, + .pStages = shaderStages, + .pVertexInputState = &vertexInputState, + .pInputAssemblyState = &inputAssemblyState, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizationState, + .pMultisampleState = &multisampleState, + .pDepthStencilState = &depthStencilState, + .pColorBlendState = &colorBlendState, + .pDynamicState = &dynamicState, + .layout = pipelineLayout + }, + }; + + VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, pipelineCreateInfos, nullptr, &pipeline)); + } + + ////////////////////////////////////////////////////////////////////// + // load font + ////////////////////////////////////////////////////////////////////// + + LoadedFont font::load_font(font_desc const& desc) + { + uint32_t font_data_size; + void const * font_data = file::open(desc.path, &font_data_size); + assert(font_data != nullptr); + + types::font * font = (types::font *)font_data; + types::glyph * glyphs = (types::glyph *)(((ptrdiff_t)font_data) + (sizeof (types::font))); + + void * texture_data = (void *)(((ptrdiff_t)glyphs) + (sizeof (types::glyph)) * font->glyph_count); + + ptrdiff_t font_end = ((ptrdiff_t)font_data) + font_data_size; + int texture_size = font->texture_width * font->texture_height; + assert(font_end - ((ptrdiff_t)texture_data) == texture_size); + + // transfer texture + + VkCommandBuffer commandBuffer{}; + VkCommandBufferAllocateInfo commandBufferAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = commandPool, + .commandBufferCount = 1 + }; + VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, &commandBuffer)); + + VkFenceCreateInfo fenceCreateInfo{ + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO + }; + VkFence fence{}; + VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + + void * imageData = texture_data; + uint32_t imageDataSize = texture_size; + VkFormat format = VK_FORMAT_R8_UNORM; + uint32_t width = font->texture_width; + uint32_t height = font->texture_height; + uint32_t levelCount = 1; + uint32_t levelOffset = 0; + VkImage outImage; + VkDeviceMemory outMemory; + VkImageView outImageView; + + createImage(device, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + format, + width, + height, + levelCount, + &outImage, + &outMemory, + &outImageView); + + textureTransfer(device, + queue, + commandBuffer, + fence, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + imageDataSize, + imageData, + outImage, + width, + height, + levelCount, + &levelOffset); + + vkDestroyFence(device, fence, nullptr); + vkFreeCommandBuffers(device, + commandPool, + 1, + &commandBuffer); + + // return + return { + .font = font, + .glyphs = glyphs, + .allocatedImage = { + .image = outImage, + .memory = outMemory, + .imageView = outImageView, + }, + }; + } + + ////////////////////////////////////////////////////////////////////// + // descriptor sets + ////////////////////////////////////////////////////////////////////// + + void font::create_descriptor_sets() + { + // + // pool + // + constexpr int descriptorPoolSizesCount = 2; + VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{ + { // linear sampler + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + } + }; + VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 1, + .poolSizeCount = descriptorPoolSizesCount, + .pPoolSizes = descriptorPoolSizes + }; + VK_CHECK(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool)); + + // + // (set 0, constant) + // + { + constexpr int bindingCount = 2; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, + { // font image + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + } + }; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = bindingCount, + .pBindings = descriptorSetLayoutBindings + }; + VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[0])); + + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &descriptorSetLayouts[0] + }; + VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet0)); + } + } + + ////////////////////////////////////////////////////////////////////// + // descriptor set writes + ////////////////////////////////////////////////////////////////////// + + void font::write_descriptor_sets(VkImageView fontImageView) + { + constexpr uint32_t writeCount = 2; + VkWriteDescriptorSet writeDescriptorSets[writeCount]; + uint32_t writeIndex = 0; + + // set1 bindings + VkDescriptorImageInfo samplerDescriptorImageInfo = { + .sampler = linearSampler, + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet0, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .pImageInfo = &samplerDescriptorImageInfo + }; + VkDescriptorImageInfo terrainDescriptorImageInfo = { + .imageView = fontImageView, + .imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet0, + .dstBinding = 1, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = &terrainDescriptorImageInfo + }; + + assert(writeIndex == writeCount); + vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr); + } + + ////////////////////////////////////////////////////////////////////// + // draw + ////////////////////////////////////////////////////////////////////// + + void font::draw(VkCommandBuffer commandBuffer, + uint32_t frameIndex) + { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + VkDescriptorSet descriptorSets[1] = { + descriptorSet0, + }; + vkCmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout, + 0, 1, descriptorSets, + 0, nullptr); + + vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16); + + VkDeviceSize vertexOffset{ 0 }; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndex.buffer, &vertexOffset); + + vkCmdDrawIndexed(commandBuffer, 4, 1, 0, 0, 0); + } +} diff --git a/src/main.cpp b/src/main.cpp index 2c72290..d4e59af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,7 @@ #include "collada/scene/vulkan.h" #include "minecraft/vulkan.h" +#include "font/outline.h" #include "scenes/shadow_test/shadow_test.h" #include "scenes/eidelwind/eidelwind.h" @@ -678,6 +679,22 @@ int main() shadowDepthImageViewDepth); minecraft_state.init(); + ////////////////////////////////////////////////////////////////////// + // initialize font + ////////////////////////////////////////////////////////////////////// + + font::outline::font font_state; + font_state.initial_state(instance, + device, + queue, + commandPool, + physicalDeviceProperties, + physicalDeviceMemoryProperties, + surfaceFormat.format, + depthFormat, + textureSamplers[2]); + font_state.init(); + ////////////////////////////////////////////////////////////////////// // initialize view ////////////////////////////////////////////////////////////////////// @@ -798,7 +815,7 @@ int main() // transfer ////////////////////////////////////////////////////////////////////// - { + if (0) { collada_state.vulkan.change_frame(commandBuffer, frameIndex); XMMATRIX projection = currentProjection(); @@ -901,7 +918,7 @@ int main() collada_state.vulkan.excludeMaterialIndex = lightMaterialIndex; collada_state.vulkan.pipelineIndex = 0; // shadow pipeline - collada_state.draw(); + //collada_state.draw(); vkCmdEndRendering(commandBuffer); @@ -1022,11 +1039,13 @@ int main() collada_state.vulkan.excludeMaterialIndex = -1; collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline - collada_state.draw(); + //collada_state.draw(); //collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline //collada_state.draw(); - minecraft_state.draw(commandBuffer, frameIndex); + //minecraft_state.draw(commandBuffer, frameIndex); + + font_state.draw(commandBuffer, frameIndex); vkCmdEndRendering(commandBuffer); diff --git a/src/minecraft/vulkan.cpp b/src/minecraft/vulkan.cpp index db390a7..163bfe8 100644 --- a/src/minecraft/vulkan.cpp +++ b/src/minecraft/vulkan.cpp @@ -72,54 +72,11 @@ namespace minecraft::vulkan { uint32_t indexSize; void const * indexStart = file::open(index_filename, &indexSize); - vertexIndex.indexOffset = vertexSize; - - // create buffer - - VkDeviceSize bufferSize{ vertexSize + indexSize }; - VkBufferCreateInfo vertexIndexBufferCreateInfo{ - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = bufferSize, - .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - VK_CHECK(vkCreateBuffer(device, &vertexIndexBufferCreateInfo, nullptr, &vertexIndex.buffer)); - - // allocate memory - - VkMemoryRequirements memoryRequirements; - vkGetBufferMemoryRequirements(device, vertexIndex.buffer, &memoryRequirements); - VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; - VkMemoryAllocateFlags memoryAllocateFlags{}; - VkDeviceSize stride; - allocateFromMemoryRequirements(device, - physicalDeviceProperties.limits.nonCoherentAtomSize, - physicalDeviceMemoryProperties, - memoryRequirements, - memoryPropertyFlags, - memoryAllocateFlags, - 1, - &vertexIndex.memory, - &stride); - - VK_CHECK(vkBindBufferMemory(device, vertexIndex.buffer, vertexIndex.memory, 0)); - - // copy data - - void * vertexIndexMappedData; - VK_CHECK(vkMapMemory(device, vertexIndex.memory, 0, VK_WHOLE_SIZE, 0, &vertexIndexMappedData)); - memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + 0), vertexStart, vertexSize); - memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize), indexStart, indexSize); - - VkMappedMemoryRange mappedMemoryRange{ - .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, - .memory = vertexIndex.memory, - .offset = 0, - .size = VK_WHOLE_SIZE, - }; - vkFlushMappedMemoryRanges(device, 1, &mappedMemoryRange); - - vkUnmapMemory(device, vertexIndex.memory); + vertexIndex = createVertexIndexBuffer(device, + physicalDeviceProperties, + physicalDeviceMemoryProperties, + vertexStart, vertexSize, + indexStart, indexSize); } ////////////////////////////////////////////////////////////////////// diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index 7669599..824fa67 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -418,3 +418,65 @@ void createImageFromFilenameTGA(VkDevice device, free(imageStart); } + +VertexIndex createVertexIndexBuffer(VkDevice device, + VkPhysicalDeviceProperties const& physicalDeviceProperties, + VkPhysicalDeviceMemoryProperties const& physicalDeviceMemoryProperties, + void const * vertexStart, + uint32_t vertexSize, + void const * indexStart, + uint32_t indexSize) +{ + VertexIndex vertexIndex{}; + + vertexIndex.indexOffset = vertexSize; + + // create buffer + + VkDeviceSize bufferSize{ vertexSize + indexSize }; + VkBufferCreateInfo vertexIndexBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = bufferSize, + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + VK_CHECK(vkCreateBuffer(device, &vertexIndexBufferCreateInfo, nullptr, &vertexIndex.buffer)); + + // allocate memory + + VkMemoryRequirements memoryRequirements; + vkGetBufferMemoryRequirements(device, vertexIndex.buffer, &memoryRequirements); + VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; + VkMemoryAllocateFlags memoryAllocateFlags{}; + VkDeviceSize stride; + allocateFromMemoryRequirements(device, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + memoryRequirements, + memoryPropertyFlags, + memoryAllocateFlags, + 1, + &vertexIndex.memory, + &stride); + + VK_CHECK(vkBindBufferMemory(device, vertexIndex.buffer, vertexIndex.memory, 0)); + + // copy data + + void * vertexIndexMappedData; + VK_CHECK(vkMapMemory(device, vertexIndex.memory, 0, VK_WHOLE_SIZE, 0, &vertexIndexMappedData)); + memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + 0), vertexStart, vertexSize); + memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize), indexStart, indexSize); + + VkMappedMemoryRange mappedMemoryRange{ + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = vertexIndex.memory, + .offset = 0, + .size = VK_WHOLE_SIZE, + }; + vkFlushMappedMemoryRanges(device, 1, &mappedMemoryRange); + + vkUnmapMemory(device, vertexIndex.memory); + + return vertexIndex; +}