Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 7297892d3ee9f767f9adec44726c263f23bbb4da)
+++ vulkan-game.cpp	(revision 845a2cb7a34c5349a49ed51c2b9111b3eba65572)
@@ -3,4 +3,5 @@
 #include <array>
 #include <iostream>
+#include <numeric>
 #include <set>
 
@@ -28,4 +29,5 @@
    this->asteroid_VP_mats = {};
    this->laser_VP_mats = {};
+   this->explosion_UBO = {};
 }
 
@@ -519,4 +521,9 @@
       }, false);
 
+   ship.model_base =
+      translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f)) *
+      scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
+   ship.modified = true;
+
    shipPipeline.createDescriptorSetLayout();
    shipPipeline.createPipeline("shaders/ship-vert.spv", "shaders/ship-frag.spv");
@@ -559,4 +566,20 @@
    laserPipeline.createDescriptorSets(swapChainImages);
 
+   explosionPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ExplosionVertex::particleStartVelocity));
+   explosionPipeline.addAttribute(VK_FORMAT_R32_SFLOAT, offset_of(&ExplosionVertex::particleStartTime));
+   explosionPipeline.addAttribute(VK_FORMAT_R32_UINT, offset_of(&ExplosionVertex::objIndex));
+
+   createBufferSet(sizeof(UBO_Explosion), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_explosionPipeline, uniformBuffersMemory_explosionPipeline, uniformBufferInfoList_explosionPipeline);
+
+   explosionPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+      VK_SHADER_STAGE_VERTEX_BIT, &uniformBufferInfoList_explosionPipeline);
+   explosionPipeline.addStorageDescriptor(VK_SHADER_STAGE_VERTEX_BIT);
+
+   explosionPipeline.createDescriptorSetLayout();
+   explosionPipeline.createPipeline("shaders/explosion-vert.spv", "shaders/explosion-frag.spv");
+   explosionPipeline.createDescriptorPool(swapChainImages);
+   explosionPipeline.createDescriptorSets(swapChainImages);
+
    cout << "Created all the graphics pipelines" << endl;
 
@@ -564,26 +587,31 @@
 
    createSyncObjects();
-
-   ship.model_base =
-      translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f)) *
-      scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
-   ship.modified = true;
 }
 
 void VulkanGame::initGraphicsPipelines() {
-   overlayPipeline = GraphicsPipeline_Vulkan<OverlayVertex, void*>(physicalDevice, device, renderPass,
+   overlayPipeline = GraphicsPipeline_Vulkan<OverlayVertex, void*>(
+      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 4, 6, 0);
 
-   modelPipeline = GraphicsPipeline_Vulkan<ModelVertex, SSBO_ModelObject>(physicalDevice, device, renderPass,
+   modelPipeline = GraphicsPipeline_Vulkan<ModelVertex, SSBO_ModelObject>(
+      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 16, 24, 10);
 
-   shipPipeline = GraphicsPipeline_Vulkan<ShipVertex, SSBO_ModelObject>(physicalDevice, device, renderPass,
+   shipPipeline = GraphicsPipeline_Vulkan<ShipVertex, SSBO_ModelObject>(
+      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 138, 138, 10);
 
-   asteroidPipeline = GraphicsPipeline_Vulkan<AsteroidVertex, SSBO_Asteroid>(physicalDevice, device, renderPass,
+   asteroidPipeline = GraphicsPipeline_Vulkan<AsteroidVertex, SSBO_Asteroid>(
+      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 24, 36, 10);
 
-   laserPipeline = GraphicsPipeline_Vulkan<LaserVertex, SSBO_Laser>(physicalDevice, device, renderPass,
+   laserPipeline = GraphicsPipeline_Vulkan<LaserVertex, SSBO_Laser>(
+      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 8, 18, 2);
+
+   explosionPipeline = GraphicsPipeline_Vulkan<ExplosionVertex, SSBO_Explosion>(
+      VK_PRIMITIVE_TOPOLOGY_POINT_LIST, physicalDevice, device, renderPass,
+      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height },
+      swapChainImages, EXPLOSION_PARTICLE_COUNT, EXPLOSION_PARTICLE_COUNT, 2);
 }
 
@@ -616,4 +644,7 @@
    laser_VP_mats.view = viewMat;
    laser_VP_mats.proj = projMat;
+
+   explosion_UBO.view = viewMat;
+   explosion_UBO.proj = projMat;
 }
 
@@ -732,5 +763,5 @@
                break;
             case UI_EVENT_UNKNOWN:
-               cout << "Unknown event type: 0x" << hex << e.unknown.eventType << dec << endl;
+               //cout << "Unknown event type: 0x" << hex << e.unknown.eventType << dec << endl;
                break;
             default:
@@ -813,8 +844,18 @@
          vec3 objCenter = vec3(viewMat * vec4(asteroid.center, 1.0f));
 
-         if ((objCenter.z - asteroid.radius) > -NEAR_CLIP || asteroid.ssbo.hp <= 0.0f) {
+         if (asteroid.ssbo.hp <= 0.0f) {
             asteroid.ssbo.deleted = true;
 
-            // TODO: Create explosion here
+            // TODO: Optimize this so I don't recalculate the camera rotation every time
+            // TODO: Also, avoid re-declaring cam_pitch
+            float cam_pitch = -50.0f;
+            mat4 pitch_mat = rotate(mat4(1.0f), radians(cam_pitch), vec3(1.0f, 0.0f, 0.0f));
+            mat4 model_mat = translate(mat4(1.0f), asteroid.center) * pitch_mat;
+
+            addExplosion(model_mat, 0.5f, curTime);
+
+            // TODO: Increment player's score here
+         } else if ((objCenter.z - asteroid.radius) > -NEAR_CLIP) {
+            asteroid.ssbo.deleted = true;
          } else {
             asteroid.model_transform =
@@ -933,4 +974,12 @@
    }
 
+   for (size_t i = 0; i < explosionObjects.size(); i++) {
+      if (explosionObjects[i].modified) {
+         updateObject(explosionObjects, explosionPipeline, i);
+      }
+   }
+
+   explosion_UBO.cur_time = curTime;
+
    VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_modelPipeline[currentImage], 0, object_VP_mats);
 
@@ -940,4 +989,6 @@
 
    VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_laserPipeline[currentImage], 0, laser_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_explosionPipeline[currentImage], 0, explosion_UBO);
 }
 
@@ -1046,4 +1097,5 @@
    asteroidPipeline.cleanupBuffers();
    laserPipeline.cleanupBuffers();
+   explosionPipeline.cleanupBuffers();
 
    for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
@@ -1538,4 +1590,5 @@
       asteroidPipeline.createRenderCommands(commandBuffers[i], i);
       laserPipeline.createRenderCommands(commandBuffers[i], i);
+      explosionPipeline.createRenderCommands(commandBuffers[i], i);
 
       // Always render this pipeline last
@@ -1571,5 +1624,5 @@
 }
 
-void VulkanGame::addLaser( vec3 start, vec3 end, vec3 color, float width) {
+void VulkanGame::addLaser(vec3 start, vec3 end, vec3 color, float width) {
    vec3 ray = end - start;
    float length = glm::length(ray);
@@ -1792,4 +1845,41 @@
 }
 
+void VulkanGame::addExplosion(mat4 model_mat, float duration, float cur_time) {
+   cout << "Adding explosion..." << endl;
+
+   vector<ExplosionVertex> vertices;
+   vertices.reserve(EXPLOSION_PARTICLE_COUNT);
+
+   float particlestart_time = 0.0f;
+
+   for (int i = 0; i < EXPLOSION_PARTICLE_COUNT; i++) {
+      float randx = ((float)rand() / (float)RAND_MAX) - 0.5f;
+      float randy = ((float)rand() / (float)RAND_MAX) - 0.5f;
+
+      vertices.push_back({ vec3(randx, randy, 0.0f), particlestart_time});
+
+      particlestart_time += 0.01f;
+   }
+
+   // Fill the indices with the the first EXPLOSION_PARTICLE_COUNT ints
+   vector<uint16_t> indices(EXPLOSION_PARTICLE_COUNT);
+   iota(indices.begin(), indices.end(), 0);
+
+   SceneObject<ExplosionVertex, SSBO_Explosion>& explosion = addObject(
+      explosionObjects, explosionPipeline,
+      addObjectIndex(explosionObjects.size(), vertices),
+      indices, {
+         mat4(1.0f),
+         cur_time,
+         duration,
+         false
+      }, true);
+
+   explosion.model_base = model_mat;
+   explosion.model_transform = mat4(1.0f);
+
+   explosion.modified = true;
+}
+
 // TODO: Fix the crash that happens when alt-tabbing
 void VulkanGame::recreateSwapChain() {
@@ -1853,4 +1943,12 @@
    laserPipeline.createDescriptorPool(swapChainImages);
    laserPipeline.createDescriptorSets(swapChainImages);
+
+   createBufferSet(sizeof(UBO_Explosion), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_explosionPipeline, uniformBuffersMemory_explosionPipeline, uniformBufferInfoList_explosionPipeline);
+
+   explosionPipeline.updateRenderPass(renderPass);
+   explosionPipeline.createPipeline("shaders/explosion-vert.spv", "shaders/explosion-frag.spv");
+   explosionPipeline.createDescriptorPool(swapChainImages);
+   explosionPipeline.createDescriptorSets(swapChainImages);
 
    createCommandBuffers();
@@ -1871,4 +1969,5 @@
    asteroidPipeline.cleanup();
    laserPipeline.cleanup();
+   explosionPipeline.cleanup();
 
    for (size_t i = 0; i < uniformBuffers_modelPipeline.size(); i++) {
@@ -1892,4 +1991,9 @@
    }
 
+   for (size_t i = 0; i < uniformBuffers_explosionPipeline.size(); i++) {
+      vkDestroyBuffer(device, uniformBuffers_explosionPipeline[i], nullptr);
+      vkFreeMemory(device, uniformBuffersMemory_explosionPipeline[i], nullptr);
+   }
+
    vkDestroyRenderPass(device, renderPass, nullptr);
 
