Index: README.txt
===================================================================
--- README.txt	(revision 8667f76b356145b63b25cb3260e2dcfd293b8c19)
+++ README.txt	(revision 80edd70437ab00d07490dffe468e1b971f7bc630)
@@ -59,4 +59,6 @@
  - Copy the SDL2 include folder into /include and rename it SDL2
  - Add the location of the lib/x64 folder to the VS2019 project properties under Linker/General/Addition Library DIrectories
+ - You can also just copy the contents of that folder to lib
+ - TODO: Figure out how to do static compilation with SDL2
 
 Download the vulkan sdk
Index: VulkanGame.vcxproj
===================================================================
--- VulkanGame.vcxproj	(revision 8667f76b356145b63b25cb3260e2dcfd293b8c19)
+++ VulkanGame.vcxproj	(revision 80edd70437ab00d07490dffe468e1b971f7bc630)
@@ -70,5 +70,8 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
-  <PropertyGroup />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>include;$(IncludePath)</IncludePath>
+    <LibraryPath>lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
@@ -82,6 +85,6 @@
     <Link>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>C:\Users\dportnoy\Desktop\SDL2-2.0.9\lib\x64;D:\VulkanSDK\1.1.108.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-      <AdditionalDependencies>SDL2.lib;SDL2main.lib;vulkan-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>D:\VulkanSDK\1.1.108.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>SDL2.lib;SDL2main.lib;glfw3.lib;vulkan-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
@@ -131,8 +134,10 @@
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="game-gui-glfw.cpp" />
     <ClCompile Include="game-gui-sdl.cpp" />
     <ClCompile Include="vulkan-game.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="game-gui-glfw.hpp" />
     <ClInclude Include="game-gui-sdl.hpp" />
     <ClInclude Include="game-gui.hpp" />
Index: shaders/shader.vert
===================================================================
--- shaders/shader.vert	(revision 8667f76b356145b63b25cb3260e2dcfd293b8c19)
+++ shaders/shader.vert	(revision 80edd70437ab00d07490dffe468e1b971f7bc630)
@@ -1,20 +1,11 @@
 #version 450
+
+layout(location = 0) in vec2 inPosition;
+layout(location = 1) in vec3 inColor;
 
 layout(location = 0) out vec3 fragColor;
 
-vec2 positions[3] = vec2[](
-   vec2(0.0, -0.5),
-   vec2(0.5, 0.5),
-   vec2(-0.5, 0.5)
-);
-
-vec3 colors[3] = vec3[](
-   vec3(1.0, 0.0, 0.0),
-   vec3(0.0, 1.0, 0.0),
-   vec3(0.0, 0.0, 1.0)
-);
-
 void main() {
-   gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
-   fragColor = colors[gl_VertexIndex];
+   gl_Position = vec4(inPosition, 0.0, 1.0);
+   fragColor = inColor;
 }
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 8667f76b356145b63b25cb3260e2dcfd293b8c19)
+++ vulkan-game.cpp	(revision 80edd70437ab00d07490dffe468e1b971f7bc630)
@@ -7,14 +7,15 @@
 #define GLM_FORCE_RADIANS
 #define GLM_FORCE_DEPTH_ZERO_TO_ONE
-#include <glm/vec4.hpp>
-#include <glm/mat4x4.hpp>
-
+#include <glm/glm.hpp>
+
+#include <iostream>
 #include <fstream>
-#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <array>
+#include <set>
 #include <optional>
-#include <set>
 
 using namespace std;
-//using namespace glm;
 
 const int SCREEN_WIDTH = 800;
@@ -50,4 +51,41 @@
     vector<VkSurfaceFormatKHR> formats;
     vector<VkPresentModeKHR> presentModes;
+};
+
+struct Vertex {
+   glm::vec2 pos;
+   glm::vec3 color;
+
+   static VkVertexInputBindingDescription getBindingDescription() {
+      VkVertexInputBindingDescription bindingDescription = {};
+
+      bindingDescription.binding = 0;
+      bindingDescription.stride = sizeof(Vertex);
+      bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+      return bindingDescription;
+   }
+
+   static array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
+      array<VkVertexInputAttributeDescription, 2> attributeDescriptions = {};
+
+      attributeDescriptions[0].binding = 0;
+      attributeDescriptions[0].location = 0;
+      attributeDescriptions[0].format = VK_FORMAT_R32G32_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);
+
+      return attributeDescriptions;
+   }
+};
+
+const vector<Vertex> vertices = {
+   {{ 0.0f, -0.5f}, {1.0f, 1.0f, 1.0f}},
+   {{ 0.5f,  0.5f}, {0.0f, 1.0f, 0.0f}},
+   {{-0.5f,  0.5f}, {0.0f, 0.0f, 1.0f}}
 };
 
@@ -112,4 +150,7 @@
       VkPipeline graphicsPipeline;
       VkCommandPool commandPool;
+
+      VkBuffer vertexBuffer;
+      VkDeviceMemory vertexBufferMemory;
 
       vector<VkFramebuffer> swapChainFramebuffers;
@@ -152,4 +193,5 @@
          createFramebuffers();
          createCommandPool();
+         createVertexBuffer();
          createCommandBuffers();
          createSyncObjects();
@@ -666,6 +708,12 @@
          VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
          vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-         vertexInputInfo.vertexBindingDescriptionCount = 0;
-         vertexInputInfo.vertexAttributeDescriptionCount = 0;
+
+         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();
 
          VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
@@ -808,4 +856,48 @@
       }
 
+      void createVertexBuffer() {
+         VkBufferCreateInfo bufferInfo = {};
+         bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+         bufferInfo.size = sizeof(vertices[0]) * vertices.size();
+         bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+         bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+         if (vkCreateBuffer(device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) {
+            throw runtime_error("failed to create vertex buffer!");
+         }
+
+         VkMemoryRequirements memoryRequirements;
+         vkGetBufferMemoryRequirements(device, vertexBuffer, &memoryRequirements);
+
+         VkMemoryAllocateInfo allocInfo = {};
+         allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+         allocInfo.allocationSize = memoryRequirements.size;
+         allocInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+         if (vkAllocateMemory(device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) {
+            throw runtime_error("failed to allocate vertex buffer memory!");
+         }
+
+         vkBindBufferMemory(device, vertexBuffer, vertexBufferMemory, 0);
+
+         void* data;
+         vkMapMemory(device, vertexBufferMemory, 0, bufferInfo.size, 0, &data);
+         memcpy(data, vertices.data(), (size_t)bufferInfo.size);
+         vkUnmapMemory(device, vertexBufferMemory);
+      }
+
+      uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
+         VkPhysicalDeviceMemoryProperties memProperties;
+         vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
+
+         for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
+            if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
+               return i;
+            }
+         }
+
+         throw runtime_error("failed to find suitable memory type!");
+      }
+
       void createCommandBuffers() {
          commandBuffers.resize(swapChainFramebuffers.size());
@@ -844,5 +936,10 @@
             vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
             vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
-            vkCmdDraw(commandBuffers[i], 3, 1, 0, 0);
+
+            VkBuffer vertexBuffers[] = { vertexBuffer };
+            VkDeviceSize offsets[] = { 0 };
+            vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
+
+            vkCmdDraw(commandBuffers[i], static_cast<uint32_t>(vertices.size()), 1, 0, 0);
             vkCmdEndRenderPass(commandBuffers[i]);
 
@@ -972,4 +1069,7 @@
          cleanupSwapChain();
 
+         vkDestroyBuffer(device, vertexBuffer, nullptr);
+         vkFreeMemory(device, vertexBufferMemory, nullptr);
+
          for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
             vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
@@ -1031,8 +1131,4 @@
 #endif
 
-   glm::mat4 matrix;
-   glm::vec4 vec;
-   glm::vec4 test = matrix * vec;
-
    cout << "Starting Vulkan game..." << endl;
 
