diff --git a/src/main.c b/src/main.c index c7c45a0..c4d7d8a 100644 --- a/src/main.c +++ b/src/main.c @@ -52,18 +52,37 @@ typedef struct AllocatedBufferStruct { VkDeviceMemory memory; } AllocatedBuffer; -typedef struct MaterialStruct { - VkPipelineLayout pipeline_layout; - VkPipeline pipeline; -} Material; - typedef struct MeshStruct { uint32_t vertex_count; AllocatedBuffer vertex_buffer; + uint32_t index_count; AllocatedBuffer index_buffer; + + void* data; } Mesh; +typedef void (*MaterialBindFunc)(VkCommandBuffer, void*); +typedef void (*MeshBindFunc)(Mesh, VkCommandBuffer, void*); + +typedef struct MaterialStruct { + VkPipelineLayout pipeline_layout; + VkPipeline pipeline; + + MaterialBindFunc material_bind; + MeshBindFunc mesh_bind; + + void* data; +} Material; + +typedef struct TextureMaterialDataStruct { + // Store pool to allocate new texture descriptor sets +} TextureMaterialData; + +typedef struct TextureMeshDataStruct { + // Store allocated texture descriptor set +} TextureMeshData; + typedef struct VulkanContextStruct { VkInstance instance; VkDebugUtilsMessengerEXT debug_messenger; @@ -190,7 +209,7 @@ GLFWwindow* init_window(int width, int height) { glfwSetErrorCallback(glfw_error); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan window", 0, 0); @@ -1188,18 +1207,84 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) { void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) { VkBuffer vertex_buffers[] = {mesh.vertex_buffer.buffer}; VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets); vkCmdBindIndexBuffer(command_buffer, mesh.index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(command_buffer, mesh.index_count, 1, 0, 0, 0); } +VkResult recreate_swap_chain(VulkanContext* context, VkExtent2D new_extent) { + for(uint32_t i = 0; i < context->swapchain_image_count; i++) { + vkDestroyFramebuffer(context->device, context->swapchain_framebuffers[i], 0); + vkDestroyImageView(context->device, context->swapchain_image_views[i], 0); + } + + vkDestroySwapchainKHR(context->device, context->swapchain, 0); + free(context->swapchain_images); + free(context->swapchain_image_views); + free(context->swapchain_framebuffers); + free(context->swapchain_details.formats); + free(context->swapchain_details.present_modes); + + context->swapchain_extent = new_extent; + + SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface); + if(swapchain_details.formats == 0) { + return 0; + } else { + context->swapchain_details = swapchain_details; + } + + context->swapchain_format = choose_swapchain_format(context->swapchain_details); + context->swapchain_present_mode = choose_present_mode(context->swapchain_details); + context->swapchain_extent = choose_swapchain_extent(context->swapchain_details); + + VkSwapchainKHR swapchain = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->queue_indices, context->swapchain); + if(swapchain == VK_NULL_HANDLE) { + context->swapchain = VK_NULL_HANDLE; + return VK_ERROR_INITIALIZATION_FAILED; + } else { + context->swapchain = swapchain; + } + + SwapchainImages swapchain_images = get_swapchain_images(context->device, context->swapchain); + if(swapchain_images.count == 0) { + return VK_ERROR_INITIALIZATION_FAILED; + } else { + context->swapchain_images = swapchain_images.images; + context->swapchain_image_count = swapchain_images.count; + } + + VkImageView* image_views = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format); + if(image_views == 0) { + return VK_ERROR_INITIALIZATION_FAILED; + } else { + context->swapchain_image_views = image_views; + } + + VkFramebuffer* framebuffers = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->render_pass, context->swapchain_extent); + if(framebuffers == 0) { + return VK_ERROR_INITIALIZATION_FAILED; + } else { + context->swapchain_framebuffers = framebuffers; + } + + return VK_SUCCESS; +} + void record_command_buffer_material(Material material, uint32_t mesh_count, Mesh* meshes, VkDescriptorSet scene_ubo_descriptor, VkCommandBuffer command_buffer) { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline); vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline_layout, 0, 1, &scene_ubo_descriptor, 0, 0); + if(material.material_bind != 0) { + material.material_bind(command_buffer, material.data); + } + for(uint32_t i = 0; i < mesh_count; i++) { + if(material.mesh_bind != 0) { + material.mesh_bind(meshes[i], command_buffer, material.data); + } record_command_buffer_mesh(meshes[i], command_buffer); } } @@ -1341,7 +1426,21 @@ Mesh load_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex* return mesh; } -Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, uint32_t shader_stage_count, VkPipelineShaderStageCreateInfo* shader_stages, VkDescriptorSetLayout scene_ubo_layout, uint32_t set_count, VkDescriptorSetLayout* set_layouts, uint32_t pcr_count, VkPushConstantRange* pcrs) { +Material create_material( + VkDevice device, + VkExtent2D extent, + VkRenderPass render_pass, + uint32_t shader_stage_count, + VkPipelineShaderStageCreateInfo* shader_stages, + VkDescriptorSetLayout scene_ubo_layout, + uint32_t set_count, + VkDescriptorSetLayout* set_layouts, + uint32_t pcr_count, + VkPushConstantRange* pcrs, + MaterialBindFunc material_bind, + MeshBindFunc mesh_bind, + void* data + ) { Material zero_material = { .pipeline = VK_NULL_HANDLE, }; @@ -1372,8 +1471,6 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render free(all_pcrs); return zero_material; } - free(all_layouts); - free(all_pcrs); VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass, shader_stage_count, shader_stages); if(pipeline == VK_NULL_HANDLE) { @@ -1383,6 +1480,9 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render Material material = { .pipeline_layout = pipeline_layout, .pipeline = pipeline, + .material_bind = material_bind, + .mesh_bind = mesh_bind, + .data = data, }; return material; @@ -1637,7 +1737,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { shader_stages[1].module = frag_shader; shader_stages[1].pName = "main"; - Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0); + Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0, 0, 0, 0); if(simple_mesh_material.pipeline == VK_NULL_HANDLE) { fprintf(stderr, "failed to create simple mesh material\n"); return 0; @@ -1666,11 +1766,18 @@ struct { bool down: 1; bool turn_left: 1; bool turn_right: 1; + bool turn_up: 1; + bool turn_down: 1; } key_flags = { .forward = false, .backward = false, .left = false, .right = false, + + .turn_left = false, + .turn_right = false, + .turn_up = false, + .turn_down = false, }; void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { @@ -1742,6 +1849,22 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod key_flags.turn_left = false; } break; + + case GLFW_KEY_UP: + if(action == GLFW_PRESS) { + key_flags.turn_up = true; + } else if(action == GLFW_RELEASE) { + key_flags.turn_up = false; + } + break; + + case GLFW_KEY_DOWN: + if(action == GLFW_PRESS) { + key_flags.turn_down = true; + } else if(action == GLFW_RELEASE) { + key_flags.turn_down = false; + } + break; } } @@ -1801,7 +1924,7 @@ VkResult update_scene_ubo(void** buffers, uint32_t frame_index, vec3 world_posit return VK_SUCCESS; } -VkResult draw_frame(VulkanContext* context) { +VkResult draw_frame(GLFWwindow* window, VulkanContext* context) { update_scene_ubo(context->scene_ubo_ptrs, context->current_frame, world_position, &rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01); VkResult result; @@ -1810,13 +1933,19 @@ VkResult draw_frame(VulkanContext* context) { return result; } - result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]); - if(result != VK_SUCCESS) { + uint32_t image_index; + result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index); + if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + int width, height; + glfwGetWindowSize(window, &width, &height); + VkExtent2D window_extent = {width, height}; + recreate_swap_chain(context, window_extent); + return result; + } else if(result != VK_SUCCESS) { return result; } - uint32_t image_index; - result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index); + result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]); if(result != VK_SUCCESS) { return result; } @@ -1866,7 +1995,7 @@ void main_loop(GLFWwindow* window, VulkanContext* context) { while(!glfwWindowShouldClose(window)) { glfwPollEvents(); - draw_frame(context); + draw_frame(window, context); context->current_frame += 1; if(context->current_frame >= context->max_frames_in_flight) { context->current_frame = 0;