| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -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;
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |