Index: shaders/overlay.frag
===================================================================
--- shaders/overlay.frag	(revision d53ef6a0ec3d80160a2943bdb89e54074dd117ce)
+++ shaders/overlay.frag	(revision f00ee54ef3913ec9cd14069ea55103ceaf8220cc)
@@ -4,7 +4,5 @@
 layout(binding = 0) uniform sampler2D uiTexSampler;
 
-layout(location = 0) in vec3 fragColor;
-layout(location = 1) in vec2 fragTexCoord;
-layout(location = 2) flat in uint isOverlay;
+layout(location = 0) in vec2 fragTexCoord;
 
 layout(location = 0) out vec4 outColor;
@@ -12,9 +10,3 @@
 void main() {
    outColor = texture(uiTexSampler, fragTexCoord);
-
-   if (isOverlay == 1) {
-      outColor = texture(uiTexSampler, fragTexCoord);
-   } else {
-      outColor = vec4(fragColor * texture(uiTexSampler, fragTexCoord).rgb, 1.0);
-   }
 }
Index: shaders/overlay.vert
===================================================================
--- shaders/overlay.vert	(revision d53ef6a0ec3d80160a2943bdb89e54074dd117ce)
+++ shaders/overlay.vert	(revision f00ee54ef3913ec9cd14069ea55103ceaf8220cc)
@@ -3,21 +3,11 @@
 
 layout(location = 0) in vec3 inPosition;
-layout(location = 1) in vec3 inColor;
-layout(location = 2) in vec2 inTexCoord;
+layout(location = 1) in vec2 inTexCoord;
 
-layout(location = 0) out vec3 fragColor;
-layout(location = 1) out vec2 fragTexCoord;
-layout(location = 2) out uint isOverlay;
+layout(location = 0) out vec2 fragTexCoord;
 
 void main() {
-   if (gl_VertexIndex < 0) {
-      fragColor = inColor;
-      isOverlay = 0;
-   } else {
-      fragColor = inColor;
-      isOverlay = 1;
-   }
+   fragTexCoord = inTexCoord;
 
-   fragTexCoord = inTexCoord;
    gl_Position = vec4(inPosition, 1.0);
 }
Index: shaders/scene.frag
===================================================================
--- shaders/scene.frag	(revision d53ef6a0ec3d80160a2943bdb89e54074dd117ce)
+++ shaders/scene.frag	(revision f00ee54ef3913ec9cd14069ea55103ceaf8220cc)
@@ -3,17 +3,11 @@
 
 layout(binding = 1) uniform sampler2D texSampler;
-layout(binding = 2) uniform sampler2D uiTexSampler;
 
 layout(location = 0) in vec3 fragColor;
 layout(location = 1) in vec2 fragTexCoord;
-layout(location = 2) flat in uint isOverlay;
 
 layout(location = 0) out vec4 outColor;
 
 void main() {
-   if (isOverlay == 1) {
-      outColor = texture(uiTexSampler, fragTexCoord);
-   } else {
-      outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
-   }
+   outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
 }
Index: shaders/scene.vert
===================================================================
--- shaders/scene.vert	(revision d53ef6a0ec3d80160a2943bdb89e54074dd117ce)
+++ shaders/scene.vert	(revision f00ee54ef3913ec9cd14069ea55103ceaf8220cc)
@@ -14,17 +14,9 @@
 layout(location = 0) out vec3 fragColor;
 layout(location = 1) out vec2 fragTexCoord;
-layout(location = 2) out uint isOverlay;
 
 void main() {
-   if (gl_VertexIndex < 8) {
-      gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
-      fragColor = inColor;
-      isOverlay = 0;
-   } else {
-      gl_Position = vec4(inPosition, 1.0);
-      fragColor = vec3(1.0, 1.0, 1.0);
-      isOverlay = 1;
-   }
+   fragColor = inColor;
+   fragTexCoord = inTexCoord;
 
-   fragTexCoord = inTexCoord;
+   gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
 }
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision d53ef6a0ec3d80160a2943bdb89e54074dd117ce)
+++ vulkan-game.cpp	(revision f00ee54ef3913ec9cd14069ea55103ceaf8220cc)
@@ -1,13 +1,4 @@
-/*
-DESIGN GUIDE
-
--I should store multiple buffers (e.g. vertex and index buffers) in the same VkBuffer and use offsets into it
--For specifying a separate transform for each model, I can specify a descriptorCount > ` in the ubo layout binding
--Name class instance variables that are pointers (and possibly other pointer variables as well) like pVarName
-*/
-
-#include "game-gui-glfw.hpp"
-
-#include "game-gui-sdl.hpp"
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h" // TODO: Probably switch to SDL_image
 
 //#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
@@ -15,9 +6,7 @@
 #define GLM_FORCE_RADIANS
 #define GLM_FORCE_DEPTH_ZERO_TO_ONE
+
 #include <glm/glm.hpp>
 #include <glm/gtc/matrix_transform.hpp>
-
-#define STB_IMAGE_IMPLEMENTATION
-#include "stb_image.h" // TODO: Probably switch to SDL_image
 
 #include <iostream>
@@ -30,7 +19,11 @@
 #include <chrono>
 
+#include "utils.h"
+
+#include "game-gui-glfw.hpp"
+#include "game-gui-sdl.hpp"
+
 using namespace std;
-
-// TODO: Maybe add asserts for testing
+using namespace glm;
 
 const int SCREEN_WIDTH = 800;
@@ -72,48 +65,15 @@
    glm::vec3 color;
    glm::vec2 texCoord;
-
-   static VkVertexInputBindingDescription getBindingDescription() {
-      VkVertexInputBindingDescription bindingDescription = {};
-
-      // Since there is only one array of vertex data, we use binding = 0
-      // I'll probably do that for the foreseeable future
-      // I can calculate the stride myself given info about all the varying attributes
-
-      // In new-game.cpp, it looks like I had a C++ struct for each shader type anyway,
-      // so I can use the same pattern for this as well probably
-
-      bindingDescription.binding = 0;
-      bindingDescription.stride = sizeof(Vertex);
-      bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
-
-      return bindingDescription;
-   }
-
-   static array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
-      array<VkVertexInputAttributeDescription, 3> attributeDescriptions = {};
-
-      attributeDescriptions[0].binding = 0;
-      attributeDescriptions[0].location = 0;
-      attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
-      attributeDescriptions[0].offset = offsetof(Vertex, pos);
-
-      attributeDescriptions[1].binding = 0;
-      attributeDescriptions[1].location = 1;
-      attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
-      attributeDescriptions[1].offset = offsetof(Vertex, color);
-
-      attributeDescriptions[2].binding = 0;
-      attributeDescriptions[2].location = 2;
-      attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
-      attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
-
-      return attributeDescriptions;
-   }
 };
 
+struct OverlayVertex {
+   glm::vec3 pos;
+   glm::vec2 texCoord;
+};
+
 struct UniformBufferObject {
-   alignas(16) glm::mat4 model;
-   alignas(16) glm::mat4 view;
-   alignas(16) glm::mat4 proj;
+   alignas(16) mat4 model;
+   alignas(16) mat4 view;
+   alignas(16) mat4 proj;
 };
 
@@ -122,15 +82,18 @@
    VkPipeline pipeline;
 
+   VkVertexInputBindingDescription bindingDescription;
+   vector<VkVertexInputAttributeDescription> attributeDescriptions;
+
    VkDescriptorPool descriptorPool;
    VkDescriptorSetLayout descriptorSetLayout;
    vector<VkDescriptorSet> descriptorSets;
 
+   size_t numVertices; // Currently unused
    VkBuffer vertexBuffer;
    VkDeviceMemory vertexBufferMemory;
-   size_t numVertices;
-
+
+   size_t numIndices;
    VkBuffer indexBuffer;
    VkDeviceMemory indexBufferMemory;
-   size_t numIndices;
 };
 
@@ -345,8 +308,5 @@
          createTextureSampler();
 
-         createSceneDescriptorSetLayout(scenePipeline);
-         createOverlayDescriptorSetLayout(overlayPipeline);
-
-         createShaderBuffers(scenePipeline, {
+         vector<Vertex> sceneVertices = {
             {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
             {{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
@@ -358,17 +318,39 @@
             {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
             {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}
-         }, {
+         };
+         vector<uint16_t> sceneIndices = {
             0, 1, 2, 2, 3, 0,
             4, 5, 6, 6, 7, 4
-         });
-
-         createShaderBuffers(overlayPipeline, {
-            {{-1.0f,  1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
-            {{ 1.0f,  1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f}},
-            {{ 1.0f, -1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
-            {{-1.0f, -1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}
-         }, {
-            0, 1, 2, 2,3, 0
-         });
+         };
+
+         initGraphicsPipelineInfo(scenePipeline,
+            sceneVertices.data(), sizeof(Vertex), sceneVertices.size(),
+            sceneIndices.data(), sizeof(uint16_t), sceneIndices.size());
+
+         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::pos));
+         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::color));
+         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32_SFLOAT, offset_of(&Vertex::texCoord));
+
+         createSceneDescriptorSetLayout(scenePipeline);
+
+
+         vector<OverlayVertex> overlayVertices = {
+            {{-1.0f,  1.0f,  0.0f}, {0.0f, 1.0f}},
+            {{ 1.0f,  1.0f,  0.0f}, {1.0f, 1.0f}},
+            {{ 1.0f, -1.0f,  0.0f}, {1.0f, 0.0f}},
+            {{-1.0f, -1.0f,  0.0f}, {0.0f, 0.0f}}
+         };
+         vector<uint16_t> overlayIndices = {
+            0, 1, 2, 2, 3, 0
+         };
+
+         initGraphicsPipelineInfo(overlayPipeline,
+            overlayVertices.data(), sizeof(OverlayVertex), overlayVertices.size(),
+            overlayIndices.data(), sizeof(uint16_t), overlayIndices.size());
+
+         addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));
+         addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32_SFLOAT, offset_of(&OverlayVertex::texCoord));
+
+         createOverlayDescriptorSetLayout(overlayPipeline);
 
          createBufferResources();
@@ -706,6 +688,6 @@
             };
 
-            actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
-            actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
+            actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
+            actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
 
             return actualExtent;
@@ -794,12 +776,5 @@
          samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
 
-         VkDescriptorSetLayoutBinding overlaySamplerLayoutBinding = {};
-         overlaySamplerLayoutBinding.binding = 2;
-         overlaySamplerLayoutBinding.descriptorCount = 1;
-         overlaySamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-         overlaySamplerLayoutBinding.pImmutableSamplers = nullptr;
-         overlaySamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
-
-         array<VkDescriptorSetLayoutBinding, 3> bindings = { uboLayoutBinding, samplerLayoutBinding, overlaySamplerLayoutBinding };
+         array<VkDescriptorSetLayoutBinding, 2> bindings = { uboLayoutBinding, samplerLayoutBinding };
          VkDescriptorSetLayoutCreateInfo layoutInfo = {};
          layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
@@ -831,4 +806,33 @@
       }
 
+      void initGraphicsPipelineInfo(GraphicsPipelineInfo& info,
+            const void* vertexData, int vertexSize, size_t numVertices,
+            const void* indexData, int indexSize, size_t numIndices) {
+         // Since there is only one array of vertex data, we use binding = 0
+         // I'll probably do that for the foreseeable future
+         // I can calculate the stride myself given info about all the varying attributes
+
+         info.bindingDescription.binding = 0;
+         info.bindingDescription.stride = vertexSize;
+         info.bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+         info.numVertices = numVertices;
+         createVertexBuffer(info, vertexData, vertexSize * numVertices);
+
+         info.numIndices = numIndices;
+         createIndexBuffer(info, indexData, indexSize * numIndices);
+      }
+
+      void addAttributeDescription(GraphicsPipelineInfo& info, VkFormat format, size_t offset) {
+         VkVertexInputAttributeDescription attributeDesc = {};
+
+         attributeDesc.binding = 0;
+         attributeDesc.location = info.attributeDescriptions.size();
+         attributeDesc.format = format;
+         attributeDesc.offset = offset;
+
+         info.attributeDescriptions.push_back(attributeDesc);
+      }
+
       void createGraphicsPipeline(string vertShaderFile, string fragShaderFile, GraphicsPipelineInfo& info) {
          auto vertShaderCode = readFile(vertShaderFile);
@@ -855,11 +859,8 @@
          vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
 
-         auto bindingDescription = Vertex::getBindingDescription();
-         auto attributeDescriptions = Vertex::getAttributeDescriptions();
-
          vertexInputInfo.vertexBindingDescriptionCount = 1;
-         vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
-         vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
-         vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
+         vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(info.attributeDescriptions.size());
+         vertexInputInfo.pVertexBindingDescriptions = &info.bindingDescription;
+         vertexInputInfo.pVertexAttributeDescriptions = info.attributeDescriptions.data();
 
          VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
@@ -1147,5 +1148,5 @@
 
       void populateImageFromSDLTexture(SDL_Texture* texture, VkImage& image) {
-         int a, w, h, pitch;
+         int a, w, h;
 
          SDL_QueryTexture(texture, nullptr, &a, &w, &h);
@@ -1365,16 +1366,5 @@
       }
 
-      void createShaderBuffers(GraphicsPipelineInfo& info, const vector<Vertex>& vertices, const vector<uint16_t>& indices) {
-         createVertexBuffer(info.vertexBuffer, info.vertexBufferMemory, vertices);
-         info.numVertices = vertices.size();
-
-         createIndexBuffer(info.indexBuffer, info.indexBufferMemory, indices);
-         info.numIndices = indices.size();
-      }
-
-      void createVertexBuffer(VkBuffer& vertexBuffer, VkDeviceMemory& vertexBufferMemory,
-            const vector<Vertex>& vertices) {
-         VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
-
+      void createVertexBuffer(GraphicsPipelineInfo& info, const void* vertexData, VkDeviceSize bufferSize) {
          VkBuffer stagingBuffer;
          VkDeviceMemory stagingBufferMemory;
@@ -1385,11 +1375,11 @@
          void* data;
          vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
-         memcpy(data, vertices.data(), (size_t) bufferSize);
+         memcpy(data, vertexData, (size_t) bufferSize);
          vkUnmapMemory(device, stagingBufferMemory);
 
          createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
-            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
-
-         copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
+            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, info.vertexBuffer, info.vertexBufferMemory);
+
+         copyBuffer(stagingBuffer, info.vertexBuffer, bufferSize);
 
          vkDestroyBuffer(device, stagingBuffer, nullptr);
@@ -1397,8 +1387,5 @@
       }
 
-      void createIndexBuffer(VkBuffer& indexBuffer, VkDeviceMemory& indexBufferMemory,
-            const vector<uint16_t>& indices) {
-         VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
-
+      void createIndexBuffer(GraphicsPipelineInfo& info, const void* indexData, VkDeviceSize bufferSize) {
          VkBuffer stagingBuffer;
          VkDeviceMemory stagingBufferMemory;
@@ -1409,11 +1396,11 @@
          void* data;
          vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
-         memcpy(data, indices.data(), (size_t) bufferSize);
+         memcpy(data, indexData, (size_t) bufferSize);
          vkUnmapMemory(device, stagingBufferMemory);
 
          createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
-            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
-
-         copyBuffer(stagingBuffer, indexBuffer, bufferSize);
+            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, info.indexBuffer, info.indexBufferMemory);
+
+         copyBuffer(stagingBuffer, info.indexBuffer, bufferSize);
 
          vkDestroyBuffer(device, stagingBuffer, nullptr);
@@ -1517,11 +1504,9 @@
 
       void createSceneDescriptorPool(GraphicsPipelineInfo& info) {
-         array<VkDescriptorPoolSize, 3> poolSizes = {};
+         array<VkDescriptorPoolSize, 2> poolSizes = {};
          poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
          poolSizes[0].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
          poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
          poolSizes[1].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
-         poolSizes[2].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-         poolSizes[2].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
 
          VkDescriptorPoolCreateInfo poolInfo = {};
@@ -1561,10 +1546,5 @@
             imageInfo.sampler = textureSampler;
 
-            VkDescriptorImageInfo overlayImageInfo = {};
-            overlayImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-            overlayImageInfo.imageView = sdlOverlayImageView;
-            overlayImageInfo.sampler = textureSampler;
-
-            array<VkWriteDescriptorSet, 3> descriptorWrites = {};
+            array<VkWriteDescriptorSet, 2> descriptorWrites = {};
 
             descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -1588,14 +1568,4 @@
             descriptorWrites[1].pTexelBufferView = nullptr;
 
-            descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
-            descriptorWrites[2].dstSet = info.descriptorSets[i];
-            descriptorWrites[2].dstBinding = 2;
-            descriptorWrites[2].dstArrayElement = 0;
-            descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-            descriptorWrites[2].descriptorCount = 1;
-            descriptorWrites[2].pBufferInfo = nullptr;
-            descriptorWrites[2].pImageInfo = &overlayImageInfo;
-            descriptorWrites[2].pTexelBufferView = nullptr;
-
             vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
          }
@@ -1685,5 +1655,5 @@
 
             array<VkClearValue, 2> clearValues = {};
-            clearValues[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };
+            clearValues[0].color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
             clearValues[1].depthStencil = { 1.0f, 0 };
 
@@ -1871,7 +1841,7 @@
 
          UniformBufferObject ubo = {};
-         ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
-         ubo.view = glm::lookAt(glm::vec3(0.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
-         ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
+         ubo.model = rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
+         ubo.view = lookAt(glm::vec3(0.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
+         ubo.proj = perspective(radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
          ubo.proj[1][1] *= -1; // flip the y-axis so that +y is up
 
