text: #pragma once
  
  #include "Keyboard.h"
  
  #define GLFW_INCLUDE_VULKAN
  #include <GLFW/glfw3.h>
  
  #define GLM_FORCE_RADIANS
  #define GLM_FORCE_DEPTH_ZERO_TO_ONE
  #define GLM_ENABLE_EXPERIMENTAL
  #include <glm/glm.hpp>
  #include <glm/gtc/matrix_transform.hpp>
  #include <glm/gtx/hash.hpp>
  
  #include <iostream>
  #include <fstream>
  #include <stdexcept>
  #include <algorithm>
  #include <chrono>
  #include <vector>
  #include <cstring>
  #include <cstdlib>
  #include <cstdint>
  #include <array>
  #include <optional>
  #include <set>
  #include <unordered_map>
  
  const uint32_t WIDTH = 800;
  const uint32_t HEIGHT = 600;
  
  const int MAX_FRAMES_IN_FLIGHT = 2;
  
  VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger);
  
  void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator);
  
  struct QueueFamilyIndices {
      std::optional<uint32_t> graphicsFamily;
      std::optional<uint32_t> presentFamily;
  
      bool isComplete();
  };
  
  struct SwapChainSupportDetails {
      VkSurfaceCapabilitiesKHR capabilities;
      std::vector<VkSurfaceFormatKHR> formats;
      std::vector<VkPresentModeKHR> presentModes;
  };
  
  const std::vector<const char*> validationLayers = {
      "VK_LAYER_KHRONOS_validation"
  };
  
  const std::vector<const char*> deviceExtensions = {
      VK_KHR_SWAPCHAIN_EXTENSION_NAME
  };
  
  const std::vector<uint16_t> recIindices = {
      0, 1, 2, 2, 3, 0
  };
  
  struct Vertex {
      glm::vec3 pos;
      glm::vec4 color;
      glm::vec2 texCoord;
  
      static VkVertexInputBindingDescription getBindingDescription() {
          VkVertexInputBindingDescription bindingDescription{};
          bindingDescription.binding = 0;
          bindingDescription.stride = sizeof(Vertex);
          bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
  
          return bindingDescription;
      }
  
      static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
          std::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;
      }
  
      bool operator==(const Vertex& other) const {
          return pos == other.pos && color == other.color && texCoord == other.texCoord;
      }
  };
  
  namespace std {
      template<> struct hash<Vertex> {
          size_t operator()(Vertex const& vertex) const {
              return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^ (hash<glm::vec2>()(vertex.texCoord) << 1);
          }
      };
  }
  
  static Keyboard* keyboard = Keyboard::getInstance();
  
  static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  {
      if (action == GLFW_PRESS) {
          keyboard->addKey(key);
      }
      else if (action == GLFW_RELEASE) {
          keyboard->removeKey(key);
      }
  }
  