Newer
Older
ForwardPlusRenderer / include / Context.h
#pragma once

#include <stdafx.h>
#define MAX_TEXTURES 1024
#define MAX_MESHES 100000 // 100,000
#include "Device.h"
#include "RenderGraph.h"
#include "IO.h"
#include "VulkanWindow.h"
#include "SwapChain.h"
#include "InputHandler.h"
namespace fpr
{

struct Version
{
  uint32_t m_variant;
  uint32_t m_major;
  uint32_t m_minor;
  uint32_t m_patch;

  Version() = default;
  Version(uint32_t variant, uint32_t major, uint32_t minor, uint32_t patch);

  uint32_t MakeVersion() const FPR_NOEXCEPT;
};

class Context final
{
  static VulkanWindow* s_window;
  static std::string   s_app_name;
  static fpr::Version  s_app_version;
  static std::string   s_engine_name;
  static fpr::Version  s_engine_version;
  static fpr::Version  s_vulkan_version;

#ifdef NDEBUG
  const bool                     validation_layers_enabled = false;
  const std::vector<const char*> m_validation_layers;
#else
  const bool                     validation_layers_enabled = true;
  const std::vector<const char*> m_validation_layers       = { "VK_LAYER_KHRONOS_validation" };

#endif

  vk::UniqueInstance       m_instance;
  std::vector<const char*> m_extensions;

  [[nodiscard]] vk::ApplicationInfo ApplicationInfo(
      const char*    application_name,
      const Version& app_version,
      const char*    engine_name,
      const Version& engine_version,
      const Version& api_version) FPR_NOEXCEPT;

  [[nodiscard]] std::vector<const char*> GetRequiredExtensions(const std::vector<const char*>& validation_layers)
      FPR_NOEXCEPT;

  [[nodiscard]] inline bool IsValidationLayersValid(
      const std::vector<const char*>&         validation_layers,
      const std::vector<vk::LayerProperties>& available_layers) FPR_NOEXCEPT;

  bool IsVulkanSupported() const FPR_NOEXCEPT;

  [[nodiscard]] const vk::Instance& GetVulkanInstance() const FPR_NOEXCEPT;

  InputHandler           m_camera_input_handler;
  vk::UniqueSwapchainKHR m_old_swapchain;
  ;
public:
  // Type, name, settings, parent(optional);
  using PipelineCreationData =
      std::vector<std::tuple<EPipelineType, std::string_view, fpr::PipelineOptions, tl::optional<std::string>>>;
private:

  std::unique_ptr<Device>                   m_device;
  vk::UniqueSurfaceKHR                      m_surface;
  vk::UniqueCommandPool                     m_command_pool;
  vk::UniqueCommandPool                     m_compute_comand_pool;
  std::unique_ptr<SwapChain>                m_swapchain;
  std::function<PipelineCreationData(void)> m_pipeline_creation_fn;

  vk::UniqueDescriptorPool                  m_descriptor_pool;


  vk::UniqueCommandBuffer                   m_single_time_cmd_buffer;

  VulkanWindow*                             m_window;

  uint32_t                                  m_dynamic_alignment = sizeof(glm::mat4);

  static std::function<PipelineCreationData(void)> DEFAULT_PIPELINE_CREATION_CALLBACK;

  Context(
      VulkanWindow*      Window,
      const std::string& app_name,
      fpr::Version       app_version,
      const std::string& engine_name,
      fpr::Version       engine_version,
      fpr::Version       vulkan_version);

  ~Context() = default;

  void CreateSingleTimeCommandBuffer();

  static Context& GetImpl(
      VulkanWindow*      Window         = nullptr,
      const std::string& app_name       = s_app_name,
      fpr::Version       app_version    = s_app_version,
      const std::string& engine_name    = s_engine_name,
      fpr::Version       engine_version = s_engine_version,
      fpr::Version       vulkan_version = s_vulkan_version);




  void CreateModelDescriptorSet();
  void CreateCameraDescriptorSet();
  void CreateCameraDescriptorSetLayout();
  void CreateModelDescriptorSetLayout();

  void CreateDepthSamplerLayout();
  void CreateDepthSamplerDescriptorSet();
public:
  static constexpr glm::vec3 FORWARD_VECTOR = glm::vec3(0, 0, 1);
  static constexpr glm::vec3 UP_VECTOR      = glm::vec3(0, 1, 0);
  static constexpr glm::vec3 RIGHT_VECTOR   = glm::vec3(1, 0, 0);


      void CreateDescriptorSets();

   struct PerModelData
  {
    glm::mat4* model_matrix;
  } PER_MODEL_UBO;

  fpr::Scene* m_loaded_scene;

  static Context& Get();

  static void Init(
      VulkanWindow*      Window,
      const std::string& app_name,
      fpr::Version       app_version,
      const std::string& engine_name,
      fpr::Version       engine_version,
      fpr::Version       vulkan_version);

  std::unique_ptr<RenderGraph> m_render_graph;

  VulkanWindow* GetWindow();
  SwapChain*    GetSwapChain();

  void CreateGraphicsCmdPool();
  void CreateSwapChain();
  void CreateComputeCmdPool();
  void CreateDescriptorPools();
  void CreateTextureSampler();
  void RecreateSwapchain();
  void CreatePipelines(std::function<PipelineCreationData(void)> fn = DEFAULT_PIPELINE_CREATION_CALLBACK);
  void CreateSceneBuffers();

  void LoadScene(const char* file_name);

  vk::CommandPool&       GetGraphicsCmdPool() FPR_NOEXCEPT;
  vk::DescriptorPool&    GetDescriptorPool();
  vk::SurfaceKHR&        GetSurface() FPR_NOEXCEPT;
  [[nodiscard]] Device*  GetDevice() const FPR_NOEXCEPT;
  [[nodiscard]] uint32_t GetRequiredDynamicAlignment() const FPR_NOEXCEPT;

  void SetDynamicAlignment(uint32_t) FPR_NOEXCEPT;

  Context(const Context& other) = delete;
  Context& operator=(const Context& other) = delete;

  vk::Instance&      GetInstance();
  vk::CommandBuffer& BeginSingleTimeCommands();
  void               EndSingleTimeCommands();

  InputHandler& GetCameraInputHandler();
};
} // namespace fpr