Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision 2d8729794fc0b2af68f5b1a9b152e2e96258b598)
+++ graphics-pipeline_vulkan.hpp	(revision 860a0da7bda4763e3a1be95cfde80564e1cc9319)
@@ -5,4 +5,5 @@
 
 #include <fstream>
+#include <iostream>
 #include <stdexcept>
 #include <vector>
@@ -31,10 +32,21 @@
 };
 
+struct StorageBufferSet {
+   vector<VkBuffer> buffers;
+   vector<VkDeviceMemory> memory;
+   vector<VkDescriptorBufferInfo> infoSet;
+};
+
 template<class VertexType, class SSBOType>
 class GraphicsPipeline_Vulkan : public GraphicsPipeline {
    public:
       GraphicsPipeline_Vulkan();
+
+      // TODO: swapChainImages is only ever used to get its size. Check how that is determined and,
+      // if it will never change, just pass it in the constructor and save it
+      // If it does change, I could add an updateSwapchainImageCount() function
       GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device, VkRenderPass renderPass,
-         Viewport viewport, size_t vertexCapacity, size_t indexCapacity);
+         Viewport viewport, vector<VkImage>& swapChainImages,
+         size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity);
       ~GraphicsPipeline_Vulkan();
 
@@ -46,4 +58,6 @@
 
       void addAttribute(VkFormat format, size_t offset);
+
+      void addStorageDescriptor();
 
       void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData);
@@ -62,4 +76,6 @@
       void cleanup();
       void cleanupBuffers();
+
+      StorageBufferSet storageBufferSet;
    
    private:
@@ -90,4 +106,7 @@
       VkDeviceMemory indexBufferMemory;
 
+      size_t numObjects;
+      size_t objectCapacity;
+
       VkShaderModule createShaderModule(const vector<char>& code);
       vector<char> readFile(const string& filename);
@@ -107,5 +126,6 @@
 GraphicsPipeline_Vulkan<VertexType, SSBOType>::GraphicsPipeline_Vulkan(
       VkPhysicalDevice physicalDevice, VkDevice device,
-      VkRenderPass renderPass, Viewport viewport, size_t vertexCapacity, size_t indexCapacity) {
+      VkRenderPass renderPass, Viewport viewport, vector<VkImage>& swapChainImages,
+      size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity) {
    this->physicalDevice = physicalDevice;
    this->device = device;
@@ -133,6 +153,32 @@
       VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
-}
-
+
+   this->numObjects = 0;
+   this->objectCapacity = objectCapacity;
+
+   // Hacky way to allow an SSBO to be optional
+   // Specifying void* as the SSBOType will skip allocating the related buffers
+   if (!is_same_v<SSBOType, void*>) {
+      VkDeviceSize bufferSize = objectCapacity * sizeof(SSBOType);
+      cout << "NUM SWAP CHAIN IMAGES: " << swapChainImages.size() << endl;
+
+      storageBufferSet.buffers.resize(swapChainImages.size());
+      storageBufferSet.memory.resize(swapChainImages.size());
+      storageBufferSet.infoSet.resize(swapChainImages.size());
+
+      for (size_t i = 0; i < swapChainImages.size(); i++) {
+         VulkanUtils::createBuffer(this->device, this->physicalDevice, bufferSize,
+            VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+            storageBufferSet.buffers[i], storageBufferSet.memory[i]);
+
+         storageBufferSet.infoSet[i].buffer = storageBufferSet.buffers[i];
+         storageBufferSet.infoSet[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
+         storageBufferSet.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
+      }
+   }
+}
+
+// TODO: Move as much cleanup as I can into the destructor
 template<class VertexType, class SSBOType>
 GraphicsPipeline_Vulkan<VertexType, SSBOType>::~GraphicsPipeline_Vulkan() {
@@ -162,10 +208,20 @@
 
 template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData) {
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addStorageDescriptor() {
+   if (!is_same_v<SSBOType, void*>) {
+      addDescriptorInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+         VK_SHADER_STAGE_VERTEX_BIT, &storageBufferSet.infoSet);
+   }
+}
+
+template<class VertexType, class SSBOType>
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type,
+      VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData) {
    this->descriptorInfoList.push_back({ type, stageFlags, bufferData, nullptr });
 }
 
 template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData) {
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addDescriptorInfo(VkDescriptorType type,
+      VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData) {
    this->descriptorInfoList.push_back({ type, stageFlags, nullptr, imageData });
 }
@@ -351,4 +407,5 @@
 }
 
+// TODO: Since I only need the size of the swapChainImages array, I should just pass that in instead of the whole array
 template<class VertexType, class SSBOType>
 void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createDescriptorSets(vector<VkImage>& swapChainImages) {
@@ -398,5 +455,6 @@
 
 template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createRenderCommands(VkCommandBuffer& commandBuffer, uint32_t currentImage) {
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::createRenderCommands(VkCommandBuffer& commandBuffer,
+      uint32_t currentImage) {
    vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
    vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
@@ -436,4 +494,7 @@
    vkDestroyPipeline(device, pipeline, nullptr);
    vkDestroyDescriptorPool(device, descriptorPool, nullptr);
+
+   // TODO: I read that the pipeline layout does not have to be recreated every time
+   // Try only creating it once
    vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
 }
@@ -447,4 +508,11 @@
    vkDestroyBuffer(device, indexBuffer, nullptr);
    vkFreeMemory(device, indexBufferMemory, nullptr);
+
+   if (!is_same_v<SSBOType, void*>) {
+      for (size_t i = 0; i < storageBufferSet.buffers.size(); i++) {
+         vkDestroyBuffer(device, storageBufferSet.buffers[i], nullptr);
+         vkFreeMemory(device, storageBufferSet.memory[i], nullptr);
+      }
+   }
 }
 
@@ -486,17 +554,18 @@
 
 template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeVertexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue) {
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeVertexBuffer(VkCommandPool commandPool,
+      VkQueue graphicsQueue) {
    VkBuffer newVertexBuffer;
    VkDeviceMemory newVertexBufferMemory;
-   vertexCapacity *= 2;
-
-   VulkanUtils::createBuffer(device, physicalDevice, vertexCapacity * sizeof(VertexType),
+   this->vertexCapacity *= 2;
+
+   VulkanUtils::createBuffer(this->device, this->physicalDevice, this->vertexCapacity * sizeof(VertexType),
       VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newVertexBuffer, newVertexBufferMemory);
 
-   VulkanUtils::copyBuffer(device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
-
-   vkDestroyBuffer(device, vertexBuffer, nullptr);
-   vkFreeMemory(device, vertexBufferMemory, nullptr);
+   VulkanUtils::copyBuffer(this->device, commandPool, vertexBuffer, newVertexBuffer, 0, 0, numVertices * sizeof(VertexType), graphicsQueue);
+
+   vkDestroyBuffer(this->device, vertexBuffer, nullptr);
+   vkFreeMemory(this->device, vertexBufferMemory, nullptr);
 
    vertexBuffer = newVertexBuffer;
@@ -505,17 +574,18 @@
 
 template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeIndexBuffer(VkCommandPool commandPool, VkQueue graphicsQueue) {
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::resizeIndexBuffer(VkCommandPool commandPool,
+      VkQueue graphicsQueue) {
    VkBuffer newIndexBuffer;
    VkDeviceMemory newIndexBufferMemory;
-   indexCapacity *= 2;
-
-   VulkanUtils::createBuffer(device, physicalDevice, indexCapacity * sizeof(uint16_t),
+   this->indexCapacity *= 2;
+
+   VulkanUtils::createBuffer(this->device, this->physicalDevice, this->indexCapacity * sizeof(uint16_t),
       VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newIndexBuffer, newIndexBufferMemory);
 
-   VulkanUtils::copyBuffer(device, commandPool, indexBuffer, newIndexBuffer, 0, 0, numIndices * sizeof(uint16_t), graphicsQueue);
-
-   vkDestroyBuffer(device, indexBuffer, nullptr);
-   vkFreeMemory(device, indexBufferMemory, nullptr);
+   VulkanUtils::copyBuffer(this->device, commandPool, indexBuffer, newIndexBuffer, 0, 0, numIndices * sizeof(uint16_t), graphicsQueue);
+
+   vkDestroyBuffer(this->device, indexBuffer, nullptr);
+   vkFreeMemory(this->device, indexBufferMemory, nullptr);
 
    indexBuffer = newIndexBuffer;
