Index: graphics-pipeline_vulkan.cpp
===================================================================
--- graphics-pipeline_vulkan.cpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ graphics-pipeline_vulkan.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -263,4 +263,21 @@
 }
 
+void GraphicsPipeline_Vulkan::createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage) {
+   vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+   vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
+      &descriptorSets[currentImage], 0, nullptr);
+
+   // TODO: Implement once I add vertex and index buffers to the pipeline
+   /*
+   VkBuffer vertexBuffers[] = { info.vertexBuffer };
+   VkDeviceSize offsets[] = { 0 };
+   vkCmdBindVertexBuffers(commandBuffers[currentImage], 0, 1, vertexBuffers, offsets);
+
+   vkCmdBindIndexBuffer(commandBuffers[currentImage], info.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
+
+   vkCmdDrawIndexed(commandBuffers[currentImage], static_cast<uint32_t>(info.numIndices), 1, 0, 0, 0);
+   */
+}
+
 VkShaderModule GraphicsPipeline_Vulkan::createShaderModule(const vector<char>& code) {
    VkShaderModuleCreateInfo createInfo = {};
Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ graphics-pipeline_vulkan.hpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -35,4 +35,6 @@
       void createDescriptorSets(vector<VkImage>& swapChainImages);
 
+      void createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage);
+
       void cleanup();
       void cleanupBuffers();
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ vulkan-game.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -133,7 +133,11 @@
    createCommandPool();
 
-   createVulkanResources();
-
-   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass, viewport, sizeof(Vertex)));
+   createImageResources();
+
+   createFramebuffers();
+   createUniformBuffers();
+
+   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass,
+      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, sizeof(Vertex)));
 
    graphicsPipelines.back().addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::pos));
@@ -151,5 +155,6 @@
    graphicsPipelines.back().createDescriptorSets(swapChainImages);
 
-   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass, viewport, sizeof(OverlayVertex)));
+   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass,
+      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, sizeof(OverlayVertex)));
 
    graphicsPipelines.back().addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));
@@ -163,4 +168,9 @@
    graphicsPipelines.back().createDescriptorPool(swapChainImages);
    graphicsPipelines.back().createDescriptorSets(swapChainImages);
+
+   createCommandBuffers();
+
+   // TODO: Creating the descriptor pool and descriptor sets might need to be redone when the
+   // swap chain is recreated
 
    cout << "Created " << graphicsPipelines.size() << " graphics pipelines" << endl;
@@ -496,5 +506,5 @@
 
    swapChainImageFormat = surfaceFormat.format;
-   viewport = { 0, 0, (int)extent.width, (int)extent.height };
+   swapChainExtent = extent;
 }
 
@@ -588,13 +598,12 @@
 }
 
-void VulkanGame::createVulkanResources() {
+void VulkanGame::createImageResources() {
+   VulkanUtils::createDepthImage(device, physicalDevice, commandPool, findDepthFormat(), swapChainExtent,
+      depthImage, graphicsQueue);
+
    createTextureSampler();
-   createUniformBuffers();
-
-   // TODO: Make sure that Vulkan complains about these images not being destroyed and then destroy them
 
    VulkanUtils::createVulkanImageFromFile(device, physicalDevice, commandPool, "textures/texture.jpg",
       floorTextureImage, graphicsQueue);
-   VulkanUtils::createVulkanImageFromSDLTexture(device, physicalDevice, uiOverlay, sdlOverlayImage);
 
    floorTextureImageDescriptor = {};
@@ -602,4 +611,6 @@
    floorTextureImageDescriptor.imageView = floorTextureImage.imageView;
    floorTextureImageDescriptor.sampler = textureSampler;
+
+   VulkanUtils::createVulkanImageFromSDLTexture(device, physicalDevice, uiOverlay, sdlOverlayImage);
 
    sdlOverlayImageDescriptor = {};
@@ -635,4 +646,28 @@
 }
 
+void VulkanGame::createFramebuffers() {
+   swapChainFramebuffers.resize(swapChainImageViews.size());
+
+   for (size_t i = 0; i < swapChainImageViews.size(); i++) {
+      array<VkImageView, 2> attachments = {
+         swapChainImageViews[i],
+         depthImage.imageView
+      };
+
+      VkFramebufferCreateInfo framebufferInfo = {};
+      framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+      framebufferInfo.renderPass = renderPass;
+      framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
+      framebufferInfo.pAttachments = attachments.data();
+      framebufferInfo.width = swapChainExtent.width;
+      framebufferInfo.height = swapChainExtent.height;
+      framebufferInfo.layers = 1;
+
+      if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
+         throw runtime_error("failed to create framebuffer!");
+      }
+   }
+}
+
 void VulkanGame::createUniformBuffers() {
    VkDeviceSize bufferSize = sizeof(UniformBufferObject);
@@ -653,5 +688,66 @@
 }
 
+void VulkanGame::createCommandBuffers() {
+   commandBuffers.resize(swapChainImages.size());
+
+   VkCommandBufferAllocateInfo allocInfo = {};
+   allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+   allocInfo.commandPool = commandPool;
+   allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+   allocInfo.commandBufferCount = (uint32_t) commandBuffers.size();
+
+   if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
+      throw runtime_error("failed to allocate command buffers!");
+   }
+
+   for (size_t i = 0; i < commandBuffers.size(); i++) {
+      VkCommandBufferBeginInfo beginInfo = {};
+      beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+      beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+      beginInfo.pInheritanceInfo = nullptr;
+
+      if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
+         throw runtime_error("failed to begin recording command buffer!");
+      }
+
+      VkRenderPassBeginInfo renderPassInfo = {};
+      renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+      renderPassInfo.renderPass = renderPass;
+      renderPassInfo.framebuffer = swapChainFramebuffers[i];
+      renderPassInfo.renderArea.offset = { 0, 0 };
+      renderPassInfo.renderArea.extent = swapChainExtent;
+
+      array<VkClearValue, 2> clearValues = {};
+      clearValues[0].color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
+      clearValues[1].depthStencil = { 1.0f, 0 };
+
+      renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
+      renderPassInfo.pClearValues = clearValues.data();
+
+      vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+      // reateGraphicsPipelineCommands(scenePipeline, i);
+      // createGraphicsPipelineCommands(overlayPipeline, i);
+      for (GraphicsPipeline_Vulkan pipeline : graphicsPipelines) {
+         pipeline.createRenderCommands(commandBuffers[i], i);
+      }
+
+      vkCmdEndRenderPass(commandBuffers[i]);
+
+      if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
+         throw runtime_error("failed to record command buffer!");
+      }
+   }
+}
+
 void VulkanGame::cleanupSwapChain() {
+   VulkanUtils::destroyVulkanImage(device, depthImage);
+
+   for (VkFramebuffer framebuffer : swapChainFramebuffers) {
+      vkDestroyFramebuffer(device, framebuffer, nullptr);
+   }
+
+   vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
+
    for (GraphicsPipeline_Vulkan pipeline : graphicsPipelines) {
       pipeline.cleanup();
@@ -666,5 +762,5 @@
    vkDestroySwapchainKHR(device, swapChain, nullptr);
 
-   for (size_t i = 0; i < swapChainImages.size(); i++) {
+   for (size_t i = 0; i < uniformBuffers.size(); i++) {
       vkDestroyBuffer(device, uniformBuffers[i], nullptr);
       vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ vulkan-game.hpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -37,5 +37,4 @@
    private:
       GameGui* gui;
-      Viewport viewport;
 
       vector<GraphicsPipeline_Vulkan> graphicsPipelines;
@@ -59,13 +58,13 @@
       vector<VkImage> swapChainImages;
       VkFormat swapChainImageFormat;
+      VkExtent2D swapChainExtent;
       vector<VkImageView> swapChainImageViews;
+      vector<VkFramebuffer> swapChainFramebuffers;
 
       VkRenderPass renderPass;
       VkCommandPool commandPool;
+      vector<VkCommandBuffer> commandBuffers;
 
-      // TODO: Create these (and wrap them inside a VulkanImage)
-      VkImage depthImage;
-      VkDeviceMemory depthImageMemory;
-      VkImageView depthImageView;
+      VulkanImage depthImage;
 
       VkSampler textureSampler;
@@ -109,7 +108,10 @@
       VkFormat findDepthFormat();
       void createCommandPool();
-      void createVulkanResources();
+      void createImageResources();
+
       void createTextureSampler();
+      void createFramebuffers();
       void createUniformBuffers();
+      void createCommandBuffers();
 
       void cleanupSwapChain();
Index: vulkan-ref.cpp
===================================================================
--- vulkan-ref.cpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ vulkan-ref.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -178,22 +178,13 @@
       vector<VkImage> swapChainImages;
       VkFormat swapChainImageFormat;
-/*** END OF REFACTORED CODE ***/
-      // (This was taken out of vulkan-game for now and replaced with Viewport)
-      // It will definitely be needed when creating command buffers and I could use it in a few other places
-      // TODO: Check above ^
       VkExtent2D swapChainExtent;
-/*** START OF REFACTORED CODE ***/
       vector<VkImageView> swapChainImageViews;
-/*** END OF REFACTORED CODE ***/
       vector<VkFramebuffer> swapChainFramebuffers;
 
-/*** START OF REFACTORED CODE ***/
       VkRenderPass renderPass;
 
       VkCommandPool commandPool;
-/*** END OF REFACTORED CODE ***/
       vector<VkCommandBuffer> commandBuffers;
 
-/*** START OF REFACTORED CODE ***/
       // The images and the sampler are used to store data for specific attributes. I probably
       // want to keep them separate from the GraphicsPipelineInfo objects and start passing
@@ -203,5 +194,4 @@
       VkDeviceMemory depthImageMemory;
       VkImageView depthImageView;
-/*** END OF REFACTORED CODE ***/
 
       VkImage textureImage;
@@ -213,5 +203,4 @@
       VkImageView sdlOverlayImageView;
 
-/*** START OF REFACTORED CODE ***/
       VkSampler textureSampler;
 
@@ -222,15 +211,13 @@
       vector<VkBuffer> uniformBuffers;
       vector<VkDeviceMemory> uniformBuffersMemory;
-/*** END OF REFACTORED CODE ***/
 
       VkDescriptorImageInfo sceneImageInfo;
       VkDescriptorImageInfo overlayImageInfo;
 
-/*** START OF REFACTORED CODE ***/
       vector<VkDescriptorBufferInfo> uniformBufferInfoList;
-/*** END OF REFACTORED CODE ***/
 
       GraphicsPipelineInfo scenePipeline;
       GraphicsPipelineInfo overlayPipeline;
+/*** END OF REFACTORED CODE ***/
 
       vector<VkSemaphore> imageAvailableSemaphores;
@@ -339,8 +326,6 @@
 
          createCommandPool();
-/*** END OF REFACTORED CODE ***/
 
          createImageResources("textures/texture.jpg", textureImage, textureImageMemory, textureImageView);
-/*** START OF REFACTORED CODE ***/
          createImageResourcesFromSDLTexture(uiOverlay, sdlOverlayImage, sdlOverlayImageMemory, sdlOverlayImageView);
          createTextureSampler();
@@ -413,7 +398,7 @@
 
          createDescriptorSetLayout(overlayPipeline);
+
+         createBufferResources();
 /*** END OF REFACTORED CODE ***/
-
-         createBufferResources();
 
          createSyncObjects();
@@ -818,10 +803,8 @@
          }
       }
-/*** END OF REFACTORED CODE ***/
 
       void initGraphicsPipelineInfo(GraphicsPipelineInfo& info,
             const void* vertexData, int vertexSize, size_t numVertices,
             const void* indexData, int indexSize, size_t numIndices) {
-/*** START OF REFACTORED CODE ***/
          // Since there is only one array of vertex data, we use binding = 0
          // I'll probably do that for the foreseeable future
@@ -1015,5 +998,4 @@
          vkDestroyShaderModule(device, fragShaderModule, nullptr);
       }
-/*** END OF REFACTORED CODE ***/
 
       VkShaderModule createShaderModule(const vector<char>& code) {
@@ -1035,5 +1017,5 @@
 
          for (size_t i = 0; i < swapChainImageViews.size(); i++) {
-            array <VkImageView, 2> attachments = {
+            array<VkImageView, 2> attachments = {
                swapChainImageViews[i],
                depthImageView
@@ -1055,5 +1037,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       void createCommandPool() {
          QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
@@ -1100,5 +1081,4 @@
          return indices;
       }
-/*** END OF REFACTORED CODE ***/
 
       void createDepthResources() {
@@ -1112,5 +1092,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       VkFormat findDepthFormat() {
          return findSupportedFormat(
@@ -1239,4 +1218,5 @@
       }
 
+/*** START OF REFACTORED CODE ***/
       void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
             VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
@@ -1364,5 +1344,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) {
          VkImageViewCreateInfo viewInfo = {};
@@ -1649,5 +1628,4 @@
          }
       }
-/*** END OF REFACTORED CODE ***/
 
       void createCommandBuffers() {
@@ -1690,6 +1668,8 @@
             vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
 
+/*** END OF REFACTORED CODE ***/
             createGraphicsPipelineCommands(scenePipeline, i);
             createGraphicsPipelineCommands(overlayPipeline, i);
+/*** START OF REFACTORED CODE ***/
 
             vkCmdEndRenderPass(commandBuffers[i]);
@@ -1705,4 +1685,5 @@
          vkCmdBindDescriptorSets(commandBuffers[currentImage], VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipelineLayout, 0, 1,
             &info.descriptorSets[currentImage], 0, nullptr);
+/*** END OF REFACTORED CODE ***/
 
          VkBuffer vertexBuffers[] = { info.vertexBuffer };
@@ -1713,5 +1694,7 @@
 
          vkCmdDrawIndexed(commandBuffers[currentImage], static_cast<uint32_t>(info.numIndices), 1, 0, 0, 0);
-      }
+/*** START OF REFACTORED CODE ***/
+      }
+/*** END OF REFACTORED CODE ***/
 
       void createSyncObjects() {
@@ -1955,12 +1938,10 @@
       }
 
+/*** START OF REFACTORED CODE ***/
       void createBufferResources() {
-         // TODO: The three functions below will be called in vulkan-game following the
-         // pipeline creation (createDescriptorSets()), and before createCommandBuffers()
          createDepthResources();
          createFramebuffers();
          createUniformBuffers();
 
-/*** START OF REFACTORED CODE ***/
          createGraphicsPipeline("shaders/scene-vert.spv", "shaders/scene-frag.spv", scenePipeline);
          createDescriptorPool(scenePipeline);
@@ -1970,5 +1951,4 @@
          createDescriptorPool(overlayPipeline);
          createDescriptorSets(overlayPipeline);
-/*** END OF REFACTORED CODE ***/
 
          createCommandBuffers();
@@ -1976,5 +1956,4 @@
 
       void cleanup() {
-/*** START OF REFACTORED CODE ***/
          cleanupSwapChain();
 
@@ -2042,5 +2021,4 @@
 
       void cleanupSwapChain() {
-/*** END OF REFACTORED CODE ***/
          vkDestroyImageView(device, depthImageView, nullptr);
          vkDestroyImage(device, depthImage, nullptr);
@@ -2053,5 +2031,4 @@
          vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
 
-/*** START OF REFACTORED CODE ***/
          cleanupPipeline(scenePipeline);
          cleanupPipeline(overlayPipeline);
Index: vulkan-utils.cpp
===================================================================
--- vulkan-utils.cpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ vulkan-utils.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -308,4 +308,14 @@
 
    image.imageView = createImageView(device, image.image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
+}
+
+void VulkanUtils::createDepthImage(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool,
+      VkFormat depthFormat, VkExtent2D extent, VulkanImage& image, VkQueue graphicsQueue) {
+   createImage(device, physicalDevice, extent.width, extent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL,
+      VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
+   image.imageView = createImageView(device, image.image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
+
+   transitionImageLayout(device, commandPool, image.image, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED,
+      VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, graphicsQueue);
 }
 
Index: vulkan-utils.hpp
===================================================================
--- vulkan-utils.hpp	(revision e83b155c9ca795fd8d1ec3852877e07734355307)
+++ vulkan-utils.hpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
@@ -70,4 +70,6 @@
       static void createVulkanImageFromSDLTexture(VkDevice device, VkPhysicalDevice physicalDevice,
             SDL_Texture* texture, VulkanImage& image);
+      static void createDepthImage(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool,
+            VkFormat depthFormat, VkExtent2D extent, VulkanImage& image, VkQueue graphicsQueue);
       static void createImage(VkDevice device, VkPhysicalDevice physicalDevice, uint32_t width, uint32_t height,
             VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties,
