Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision 0ecab17653797998628eabc3abec8b34f7362450)
+++ graphics-pipeline_vulkan.hpp	(revision a52ba8741a9a401499b6ca8a1b53d3da6a461384)
@@ -32,4 +32,5 @@
 };
 
+// TODO: Use this struct for uniform buffers as well (maybe move it to VulkanUtils)
 struct StorageBufferSet {
    vector<VkBuffer> buffers;
@@ -61,5 +62,5 @@
       void addAttribute(VkFormat format, size_t offset);
 
-      void addStorageDescriptor();
+      void addStorageDescriptor(VkShaderStageFlags stageFlags);
 
       void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, vector<VkDescriptorBufferInfo>* bufferData);
@@ -77,4 +78,7 @@
 
       void updateObject(size_t objIndex, SSBOType& ssbo);
+
+      void updateObjectVertices(size_t objIndex, const vector<VertexType>& vertices, VkCommandPool commandPool,
+         VkQueue graphicsQueue);
 
       void cleanup();
@@ -214,9 +218,10 @@
 }
 
-template<class VertexType, class SSBOType>
-void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addStorageDescriptor() {
+// TODO: The SSBOType check isn't really needed since I call this function in VulkanGame explicitly
+template<class VertexType, class SSBOType>
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::addStorageDescriptor(VkShaderStageFlags stageFlags) {
    if (!is_same_v<SSBOType, void*>) {
       addDescriptorInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
-         VK_SHADER_STAGE_VERTEX_BIT, &storageBufferSet.infoSet);
+         stageFlags, &storageBufferSet.infoSet);
    }
 }
@@ -495,17 +500,17 @@
    //    - don't resize, but rewrite data in the buffer to only have non-deleted objects
 
-   if (numVertices + vertices.size() > vertexCapacity) {
+   if (this->numVertices + vertices.size() > this->vertexCapacity) {
       resizeVertexBuffer(commandPool, graphicsQueue);
    }
-   VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, vertices, vertexBuffer, numVertices,
-      graphicsQueue);
-   numVertices += vertices.size();
-
-   if (numIndices + indices.size() > indexCapacity) {
+   VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, vertices,
+      this->vertexBuffer, this->numVertices, graphicsQueue);
+   this->numVertices += vertices.size();
+
+   if (this->numIndices + indices.size() > this->indexCapacity) {
       resizeIndexBuffer(commandPool, graphicsQueue);
    }
-   VulkanUtils::copyDataToBuffer(device, physicalDevice, commandPool, indices, indexBuffer, numIndices,
-      graphicsQueue);
-   numIndices += indices.size();
+   VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, indices,
+      this->indexBuffer, this->numIndices, graphicsQueue);
+   this->numIndices += indices.size();
 
    bool resizedStorageBuffer = false;
@@ -540,7 +545,15 @@
    if (!is_same_v<SSBOType, void*>) {
       for (size_t i = 0; i < storageBufferSet.memory.size(); i++) {
-         VulkanUtils::copyDataToMemory(device, storageBufferSet.memory[i], objIndex, ssbo);
+         VulkanUtils::copyDataToMemory(this->device, storageBufferSet.memory[i], objIndex, ssbo);
       }
    }
+}
+
+// Should only be used if the number of vertices has not changed
+template<class VertexType, class SSBOType>
+void GraphicsPipeline_Vulkan<VertexType, SSBOType>::updateObjectVertices(size_t objIndex,
+      const vector<VertexType>& vertices, VkCommandPool commandPool, VkQueue graphicsQueue) {
+   VulkanUtils::copyDataToBuffer(this->device, this->physicalDevice, commandPool, vertices,
+      this->vertexBuffer, objIndex * vertices.size(), graphicsQueue);
 }
 
