#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>

#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>

#include "types.hpp"

// Vertex data for the model
struct Vertex {
  // Position of the vertex
  glm::vec3 pos;
  // Color of the vertex (in RGB)
  glm::vec3 color;
  // Texture coordinates of the vertex
  glm::vec2 tex_coord;

  // Returns the binding description for the vertex
  static fn getBindingDescription() -> vk::VertexInputBindingDescription {
    return { .binding = 0, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex };
  }

  // Returns the attribute descriptions for the vertex
  static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 3> {
    return {
      // Position attribute
      vk::VertexInputAttributeDescription { 0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex,       pos) },
      // Color attribute
      vk::VertexInputAttributeDescription { 1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex,     color) },
      // Texture coordinate attribute
      vk::VertexInputAttributeDescription { 2, 0,    vk::Format::eR32G32Sfloat, offsetof(Vertex, tex_coord) }
    };
  }

  // Overload the equality operator for the vertex
  fn operator==(const Vertex& other) const->bool {
    return pos == other.pos && color == other.color && tex_coord == other.tex_coord;
  }
};

// Hash function for the vertex
namespace std {
  template <>
  struct hash<Vertex> {
    fn operator()(Vertex const& vertex) const->size_t {
      return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
             (hash<glm::vec2>()(vertex.tex_coord) << 1);
    }
  };
}