Index: graphics-pipeline_vulkan.cpp
===================================================================
--- graphics-pipeline_vulkan.cpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ graphics-pipeline_vulkan.cpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -4,6 +4,4 @@
 #include <stdexcept>
 #include <iostream>
-
-#include "vulkan-utils.hpp"
 
 using namespace std;
Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ graphics-pipeline_vulkan.hpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -4,7 +4,14 @@
 #include "graphics-pipeline.hpp"
 
+#include <iostream>
 #include <vector>
 
 #include <vulkan/vulkan.h>
+
+#include "vulkan-utils.hpp"
+
+using namespace std;
+
+// TODO: Remove any instances of cout and instead throw exceptions
 
 // TODO: Maybe change the name of this struct so I can call the list something other than descriptorInfoList
@@ -26,6 +33,6 @@
       void updateRenderPass(VkRenderPass renderPass);
 
-      template<class VertexType, class IndexType>
-      void bindData(const vector<VertexType>& vertices, const vector<IndexType>& indices,
+      template<class VertexType>
+      void bindData(const vector<VertexType>& vertices, const vector<uint16_t>& indices,
          VkCommandPool commandPool, VkQueue graphicsQueue);
 
@@ -48,4 +55,8 @@
 
       void createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage);
+
+      template<class VertexType>
+      bool addObject(const vector<VertexType>& vertices, vector<uint16_t>& indices, VkCommandPool commandPool,
+         VkQueue graphicsQueue);
 
       void cleanup();
@@ -83,8 +94,10 @@
 };
 
-// TODO: Probably better to template the whole class and to also combine this function
-// and the constructor since I call this right after the constructor anyway
-template<class VertexType, class IndexType>
-void GraphicsPipeline_Vulkan::bindData(const vector<VertexType>& vertices, const vector<IndexType>& indices,
+// TODO: Probably better to template the whole class
+// TODO: Change the index type to uint32_t and check the Vulkan Tutorial loading model section as a reference
+
+// TODO: combine this function and the constructor since I call this right after the constructor anyway
+template<class VertexType>
+void GraphicsPipeline_Vulkan::bindData(const vector<VertexType>& vertices, const vector<uint16_t>& indices,
       VkCommandPool commandPool, VkQueue graphicsQueue) {
    numVertices = vertices.size();
@@ -94,5 +107,35 @@
    numIndices = indices.size();
    indexCapacity = numIndices * 2;
-   createIndexBuffer(indices.data(), sizeof(IndexType), commandPool, graphicsQueue);
+   createIndexBuffer(indices.data(), sizeof(uint16_t), commandPool, graphicsQueue);
+}
+
+template<class VertexType>
+bool GraphicsPipeline_Vulkan::addObject(const vector<VertexType>& vertices, vector<uint16_t>& indices,
+      VkCommandPool commandPool, VkQueue graphicsQueue) {
+   cout << "Adding object to pipeline..." << endl;
+
+   if (numVertices + vertices.size() > vertexCapacity) {
+      cout << "ERROR: Need to resize vertex buffers" << endl;
+   } else if (numIndices + indices.size() > indexCapacity) {
+      cout << "ERROR: Need to resize index buffers" << endl;
+   } else {
+      cout << "Added object to scene" << endl;
+
+      for (uint16_t& idx : indices) {
+         idx += numVertices;
+      }
+
+      VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, vertices, vertexBuffer, numVertices,
+         graphicsQueue);
+      numVertices += vertices.size();
+
+      VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, indices, indexBuffer, numIndices,
+         graphicsQueue);
+      numIndices += indices.size();
+
+      return true;
+   }
+
+   return false;
 }
 
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ vulkan-game.cpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -254,4 +254,6 @@
 
    cout << "Created " << graphicsPipelines.size() << " graphics pipelines" << endl;
+
+   numPlanes = 2;
 
    createCommandBuffers();
@@ -281,7 +283,26 @@
                framebufferResized = true;
                break;
-            case UI_EVENT_KEY:
+            case UI_EVENT_KEYDOWN:
                if (e.key.keycode == SDL_SCANCODE_ESCAPE) {
                   quit = true;
+               } else if (e.key.keycode == SDL_SCANCODE_SPACE) {
+                  cout << "Adding a plane" << endl;
+                  float zOffset = -0.5f + (0.5f * numPlanes);
+                  vector<Vertex> vertices = {
+                     {{-0.5f, -0.5f,  zOffset}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
+                     {{ 0.5f, -0.5f,  zOffset}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
+                     {{ 0.5f,  0.5f,  zOffset}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
+                     {{-0.5f,  0.5f,  zOffset}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}
+                  };
+                  vector<uint16_t> indices = {
+                     0, 1, 2, 2, 3, 0
+                  };
+
+                  if (graphicsPipelines[0].addObject(vertices, indices, commandPool, graphicsQueue)) {
+                     vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
+                     createCommandBuffers();
+
+                     numPlanes++;
+                  }
                } else {
                   cout << "Key event detected" << endl;
@@ -943,4 +964,5 @@
 }
 
+// TODO: Fix the crash that happens when alt-tabbing
 void VulkanGame::recreateSwapChain() {
    cout << "Recreating swap chain" << endl;
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ vulkan-game.hpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -97,4 +97,5 @@
 
       size_t currentFrame;
+      size_t numPlanes = 0; // temp
 
       bool framebufferResized;
Index: vulkan-ref.cpp
===================================================================
--- vulkan-ref.cpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ vulkan-ref.cpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -27,5 +27,4 @@
 using namespace glm;
 
-/*** START OF REFACTORED CODE ***/
 const int SCREEN_WIDTH = 800;
 const int SCREEN_HEIGHT = 600;
@@ -217,9 +216,6 @@
 
       size_t currentFrame = 0;
-/*** END OF REFACTORED CODE ***/
-
       size_t numPlanes = 0; // temp
 
-/*** START OF REFACTORED CODE ***/
       bool framebufferResized = false;
 
@@ -1465,5 +1461,4 @@
          vkBindBufferMemory(device, buffer, bufferMemory, 0);
       }
-/*** END OF REFACTORED CODE ***/
 
       void copyDataToBuffer(const void* srcData, VkBuffer dst, VkDeviceSize dstOffset, VkDeviceSize dataSize) {
@@ -1485,5 +1480,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset,
             VkDeviceSize size) {
@@ -1689,5 +1683,4 @@
          }
       }
-/*** END OF REFACTORED CODE ***/
 
       bool addObjectToScene(GraphicsPipelineInfo& info,
@@ -1722,5 +1715,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       void mainLoop() {
          // TODO: Create some generic event-handling functions in game-gui-*
@@ -2075,3 +2067,2 @@
    return EXIT_SUCCESS;
 }
-/*** END OF REFACTORED CODE ***/
Index: vulkan-utils.hpp
===================================================================
--- vulkan-utils.hpp	(revision 5a232772bc90d0e1c1c036fc2cadf724cf049bab)
+++ vulkan-utils.hpp	(revision e3bef3a2058476813ba097faca8f7f9e5175d1e6)
@@ -87,4 +87,8 @@
             uint32_t width, uint32_t height, VkQueue graphicsQueue);
 
+      template<class DataType>
+      static void copyDataToBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool,
+            const vector<DataType>& srcData, VkBuffer dstBuffer, size_t dstVertexOffset, VkQueue graphicsQueue);
+
       static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkBuffer srcBuffer, VkBuffer dstBuffer,
             VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size, VkQueue graphicsQueue);
@@ -95,3 +99,26 @@
 };
 
+template<class DataType>
+void VulkanUtils::copyDataToBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool,
+      const vector<DataType>& srcData, VkBuffer dstBuffer, size_t dstVertexOffset, VkQueue graphicsQueue) {
+   VkDeviceSize srcDataSize = srcData.size() * sizeof(DataType);
+
+   VkBuffer stagingBuffer;
+   VkDeviceMemory stagingBufferMemory;
+   createBuffer(device, physicalDevice, srcDataSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+      stagingBuffer, stagingBufferMemory);
+
+   void* data;
+   vkMapMemory(device, stagingBufferMemory, 0, srcDataSize, 0, &data);
+   memcpy(data, srcData.data(), (size_t)srcDataSize);
+   vkUnmapMemory(device, stagingBufferMemory);
+
+   copyBuffer(device, commandPool, stagingBuffer, dstBuffer, 0, dstVertexOffset * sizeof(DataType), srcDataSize,
+      graphicsQueue);
+
+   vkDestroyBuffer(device, stagingBuffer, nullptr);
+   vkFreeMemory(device, stagingBufferMemory, nullptr);
+}
+
 #endif // _VULKAN_UTILS_H
