//          Copyright Jean Pierre Cimalando 2019.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE.md or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#pragma once
#include "configuration.h"
#include "utility/geometry.h"
#include "utility/SDL++.h"
#include <SDL.h>
#include <gsl/gsl>
#include <mutex>
#include <vector>
#include <memory>
class File_Browser;
class File_Entry;
class Metadata_Display;
class Level_Meter;
class Modal_Box;
class Player;
struct Player_State;
class Main_Layout;
struct Midi_Output;

class Application
{
public:
    static const Point size_;

    Application();
    ~Application();

    SDL_Window *init_window();
    SDL_Renderer *init_renderer();
    void exec();

    void set_scale_factor(SDL_Window *win, unsigned sf);
    void paint(SDL_Renderer *rr, int paint);
    void paint_scaled(SDL_Renderer *rr, int paint, unsigned scale);
    void paint_cached_background(SDL_Renderer *rr);
    bool handle_key_pressed(const SDL_KeyboardEvent &event);
    bool handle_key_released(const SDL_KeyboardEvent &event);
    bool handle_mouse_pressed(const SDL_MouseButtonEvent &event);
    bool handle_mouse_released(const SDL_MouseButtonEvent &event);
    bool handle_text_input(const SDL_TextInputEvent &event);

    void play_file(const std::string &dir, const File_Entry *entries, size_t index, size_t count);
    void play_random(const std::string &dir, const File_Entry &entry);
    void set_current_path(const std::string &path);
    static bool filter_file_name(const std::string &name);
    static bool filter_file_entry(const File_Entry &ent);

    void request_update();
    void update_modals();
    void open_help_dialog();
    void open_fx_dialog();
    void choose_midi_output(bool ask, gsl::cstring_span choice);
    void choose_synth(bool ask, gsl::cstring_span choice);
    void get_midi_outputs(std::vector<Midi_Output> &outputs);

    void choose_theme(gsl::cstring_span choice);
    void get_themes(std::vector<std::string> &themes);

    void load_theme(gsl::cstring_span theme);
    void load_default_theme();
    void load_theme_configuration(const CSimpleIniA &ini);
    void get_fx_parameters(const CSimpleIniA &ini, int *values) const;

    void engage_shutdown();
    void engage_shutdown_if_esc_key();
    void advance_shutdown();
    bool should_quit() const;

private:
    std::unique_ptr<CSimpleIniA> initialize_config();

private:
    void receive_state_in_other_thread(const Player_State &ps);

private:
    SDLpp_Window_u window_;
    SDLpp_Renderer_u renderer_;

    SDL_TimerID update_timer_ = 0;

    std::unique_ptr<Main_Layout> layout_;
    std::vector<std::unique_ptr<Modal_Box>> modal_;
    SDLpp_Texture_u cached_background_;

    SDLpp_Surface_u logo_image_;
    SDLpp_Surface_u wallpaper_image_;

    bool fadeout_engaged_ = false;
    int fadeout_time_ = 0;

    uint32_t esc_key_timer_ = 0;

    unsigned scale_factor_ = 1;
    std::unique_ptr<File_Browser> file_browser_;
    std::unique_ptr<Metadata_Display> metadata_display_;
    std::unique_ptr<Level_Meter> level_meter_[10];
    std::unique_ptr<Player> player_;

    std::string last_midi_output_choice_;
    std::string last_synth_choice_;
    std::string last_theme_choice_;

    std::unique_ptr<Player_State> ps_;
    std::mutex ps_mutex_;

    enum Info_Mode {
        Info_File,
        Info_Metadata,
        Info_Mode_Count,
    };
    Info_Mode info_mode_ = Info_File;
};


#ifndef DART_POINTERS_H
#define DART_POINTERS_H

/*----- System Includes -----*/

#include <atomic>
#include <memory>
#include <gsl/gsl>
#include <stdint.h>
#include <functional>
#include <type_traits>

/*----- System Includes -----*/

#include "../refcount_traits.h"

/*----- Type Declarations -----*/

namespace dart {

  namespace detail {

    template <class T>
    struct managed_ptr_deleter {
      void operator ()(T ptr);
    };

    template <class T>
    struct managed_ptr_deleter<T[]> {
      void operator ()(std::remove_extent_t<T>* ptr);
    };

    // Type-erasure mechanism for counted_ptr_base.
    template <class Counter>
    struct managed_ptr {
      managed_ptr(void* ptr, int64_t use_count) : ptr(ptr), use_count(use_count) {}
      virtual ~managed_ptr() = default;
      virtual void destroy() = 0;

      void* ptr;
      Counter use_count;
    };
    template <class Counter, class PtrType, class Deleter>
    struct managed_ptr_eraser : managed_ptr<Counter> {
      managed_ptr_eraser(void const* ptr, int64_t use_count) : managed_ptr<Counter>(const_cast<void*>(ptr), use_count) {}
      managed_ptr_eraser(void const* ptr, int64_t use_count, Deleter const& deleter) :
        managed_ptr<Counter>(const_cast<void*>(ptr), use_count),
        deleter(deleter)
      {}
      managed_ptr_eraser(void const* ptr, int64_t use_count, Deleter&& deleter) :
        managed_ptr<Counter>(const_cast<void*>(ptr), use_count),
        deleter(std::move(deleter))
      {}
      virtual void destroy() override;

      Deleter deleter;
    };

    template <class T, class Counter>
    class counted_ptr_base {

      public:

        /*----- Public Types -----*/

        using element_type = T;
        using counter_type = Counter;
        template <class U>
        using ptr_type = std::conditional_t<std::is_array<U>::value, U, U*>;

        /*----- Lifecycle Functions -----*/

        counted_ptr_base() noexcept : value(nullptr) {}
        counted_ptr_base(std::nullptr_t) noexcept : value(nullptr) {}
        explicit counted_ptr_base(ptr_type<T> ptr) :
          value(new managed_ptr_eraser<counter_type, ptr_type<T>, managed_ptr_deleter<ptr_type<T>>>(ptr, 1))
        {}
        template <class Deleter>
        counted_ptr_base(ptr_type<T> ptr, Deleter&& deleter) :
          value(new managed_ptr_eraser<counter_type, ptr_type<T>, Deleter>(ptr, 1, std::move(deleter)))
        {}
        template <class U, class EnableIf =
          std::enable_if_t<
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base(counted_ptr_base<U, counter_type> const& other) noexcept;
        template <class U, class EnableIf =
          std::enable_if_t<
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base(counted_ptr_base<U, counter_type>&& other) noexcept;
        template <class U, class Deleter, class EnableIf =
          std::enable_if_t<
            std::is_same<ptr_type<U>, ptr_type<T>>::value
            ||
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base(std::unique_ptr<U, Deleter>&& ptr);
        counted_ptr_base(counted_ptr_base const& other) noexcept;
        counted_ptr_base(counted_ptr_base&& other) noexcept;
        ~counted_ptr_base() noexcept;

        /*----- Operators -----*/

        // Assignment.
        template <class U, class EnableIf =
          std::enable_if_t<
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base& operator =(counted_ptr_base<U, counter_type> const& other) noexcept;
        template <class U, class EnableIf =
          std::enable_if_t<
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base& operator =(counted_ptr_base<U, counter_type>&& other) noexcept;
        counted_ptr_base& operator =(counted_ptr_base const& other) noexcept;
        counted_ptr_base& operator =(counted_ptr_base&& other) noexcept;
        template <class U, class Deleter, class EnableIf =
          std::enable_if_t<
            std::is_convertible<ptr_type<U>, ptr_type<T>>::value
          >
        >
        counted_ptr_base& operator =(std::unique_ptr<U, Deleter>&& ptr)
          noexcept(std::is_nothrow_move_constructible<Deleter>::value);

        // Comparison.
        bool operator ==(counted_ptr_base const& other) const noexcept;
        bool operator !=(counted_ptr_base const& other) const noexcept;
        bool operator <(counted_ptr_base const& other) const noexcept;
        bool operator <=(counted_ptr_base const& other) const noexcept;
        bool operator >(counted_ptr_base const& other) const noexcept;
        bool operator >=(counted_ptr_base const& other) const noexcept;

        // Conversion.
        explicit operator bool() const noexcept;

        /*----- Public API -----*/

        // Accessors.
        std::remove_extent_t<element_type>* get() const noexcept;
        bool unique() const noexcept;
        int64_t use_count() const noexcept;

        // Mutators.
        void reset() noexcept;
        template <class U, class EnableIf =
          std::enable_if_t<
            std::is_convertible<U, ptr_type<T>>::value
          >
        >
        void reset(U ptr);
        template <class U, class Deleter, class EnableIf =
          std::enable_if_t<
            std::is_convertible<U, ptr_type<T>>::value
          >
        >
        void reset(U ptr, Deleter&& deleter);

      protected:

        /*----- Protected Members -----*/

        gsl::owner<managed_ptr<counter_type>*> value;

        /*----- Friends -----*/

        template <class U, class C>
        friend class counted_ptr_base;

    };

    template <class T, class Counter>
    struct counted_ptr_impl : counted_ptr_base<T, Counter> {

      /*----- Types -----*/

      using typename counted_ptr_base<T, Counter>::element_type;

      /*----- Lifecycle Functions -----*/

      using counted_ptr_base<T, Counter>::counted_ptr_base;

      /*----- Operators -----*/

      // Dereference.
      auto operator *() const noexcept -> element_type&;
      auto operator ->() const noexcept -> element_type*;

      // Comparison.
      using counted_ptr_base<T, Counter>::operator ==;
      using counted_ptr_base<T, Counter>::operator !=;
      using counted_ptr_base<T, Counter>::operator <;
      using counted_ptr_base<T, Counter>::operator <=;
      using counted_ptr_base<T, Counter>::operator >;
      using counted_ptr_base<T, Counter>::operator >=;
      using counted_ptr_base<T, Counter>::operator bool;

    };

    template <class T, class Counter>
    struct counted_array_ptr_impl : counted_ptr_base<T, Counter> {

      /*----- Types -----*/

      using index_type = std::ptrdiff_t;
      using element_type = std::remove_extent_t<typename counted_ptr_base<T, Counter>::element_type>;

      /*----- Lifecycle Functions -----*/

      using counted_ptr_base<T, Counter>::counted_ptr_base;

      /*----- Operators -----*/

      // Derefence.
      element_type& operator [](index_type idx) const noexcept;

      // Comparison.
      using counted_ptr_base<T, Counter>::operator ==;
      using counted_ptr_base<T, Counter>::operator !=;
      using counted_ptr_base<T, Counter>::operator <;
      using counted_ptr_base<T, Counter>::operator <=;
      using counted_ptr_base<T, Counter>::operator >;
      using counted_ptr_base<T, Counter>::operator >=;
      using counted_ptr_base<T, Counter>::operator bool;

    };

  }

  template <class T>
  class shareable_ptr {

    public:

      /*----- Public Types -----*/

      using value_type = T;
      using element_type = typename refcount_traits<T>::element_type;

    private:

      struct is_nothrow_assignable :
        meta::conjunction<
          typename refcount_traits<T>::is_nothrow_copyable,
          typename refcount_traits<T>::is_nothrow_moveable
        >
      {};

      // XXX: MSVC gets confused if this is used directly in a noexcept specification.
      struct is_nothrow_default_constructible :
        std::integral_constant<bool,
          refcount_traits<T>::template can_nothrow_take<element_type*, std::default_delete<element_type>>::value
        >
      {};

    public:

      /*----- Lifecycle Functions -----*/

      // Converting constructors.
      shareable_ptr(std::nullptr_t)
          noexcept(is_nothrow_default_constructible::value) :
        shareable_ptr()
      {}
      template <class U, class D, class EnableIf =
        std::enable_if_t<
          refcount::can_take<T, U*, D>::value
        >
      >
      explicit shareable_ptr(std::unique_ptr<U, D>&& ptr)
          noexcept(refcount_traits<T>::template can_nothrow_take<U*, D>::value);
      shareable_ptr(T const& other) noexcept(refcount_traits<T>::is_nothrow_copyable::value);
      shareable_ptr(T&& other) noexcept(refcount_traits<T>::is_nothrow_moveable::value);

      // Ownership transfer constructors.
      template <class U, class =
        std::enable_if_t<
          refcount::can_take<T, U*, std::default_delete<U>>::value
        >
      >
      explicit shareable_ptr(U* owner)
          noexcept(refcount_traits<T>::template can_nothrow_take<U*, std::default_delete<U>>::value) :
        shareable_ptr(owner, std::default_delete<U> {})
      {}
      template <class U, class D, class EnableIf =
        std::enable_if_t<
          refcount::can_take<T, U*, D>::value
        >
      >
      explicit shareable_ptr(U* owner, D&& del)
          noexcept(refcount_traits<T>::template can_nothrow_take<U*, D>::value);

      // Special Constructors.
      shareable_ptr() noexcept(is_nothrow_default_constructible::value);
      shareable_ptr(shareable_ptr const& other) noexcept(refcount_traits<T>::is_nothrow_copyable::value);
      shareable_ptr(shareable_ptr&& other) noexcept(refcount_traits<T>::is_nothrow_moveable::value);
      ~shareable_ptr() noexcept;

      /*----- Operators -----*/

      // Assignment.
      template <class U, class D, class EnableIf =
        std::enable_if_t<
          refcount::can_take<T, U*, D>::value
        >
      >
      shareable_ptr& operator =(std::unique_ptr<U, D>&& ptr)
          noexcept(refcount_traits<T>::template can_nothrow_take<U*, D>::value);
      shareable_ptr& operator =(T const& other) noexcept(is_nothrow_assignable::value);
      shareable_ptr& operator =(T&& other) noexcept;
      shareable_ptr& operator =(std::nullptr_t) noexcept(is_nothrow_default_constructible::value);
      shareable_ptr& operator =(shareable_ptr const& other) noexcept(is_nothrow_assignable::value);
      shareable_ptr& operator =(shareable_ptr&& other) noexcept;

      // Dereference.
      auto operator *() const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value) -> element_type&;
      auto operator ->() const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value) -> element_type*;

      // Comparison.
      bool operator ==(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);
      bool operator !=(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);
      bool operator <(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);
      bool operator <=(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);
      bool operator >(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);
      bool operator >=(shareable_ptr const& other) const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);

      // Conversion.
      explicit operator bool() const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value);

      /*----- Public API -----*/

      // Accessors.
      auto get() const noexcept(refcount_traits<T>::is_nothrow_unwrappable::value) -> element_type*;
      bool unique() const noexcept(refcount_traits<T>::has_nothrow_use_count::value);
      int64_t use_count() const noexcept(refcount_traits<T>::has_nothrow_use_count::value);

      // Mutators.
      void reset() noexcept(refcount_traits<T>::has_nothrow_reset::value);

      // Extremely awkward "copy-constructor" that allows us to copy our
      // wrapped value into a raw instance of T.
      // Function has to be written this way since we can't assume T is copyable/moveable
      // The only thing we can definitely do with T is pass it into dart::refcount_traits::copy.
      void share(T& ptr) const noexcept(refcount_traits<T>::is_nothrow_copyable::value);

      // Extremely awkward "move-constructor" that allows us to move our
      // wrapped value into a raw instance of T.
      // Function has to be written this way since we can't assume T is copyable/moveable
      // The only thing we can definitely do with T is pass it into dart::refcount_traits::move.
      void transfer(T& ptr) && noexcept(refcount_traits<T>::is_nothrow_moveable::value);

      auto raw() noexcept -> value_type&;
      auto raw() const noexcept -> value_type const&;

    private:

      /*----- Private Types -----*/

      struct partial_construction_tag {};

      /*----- Private Lifecycle Functions -----*/

      shareable_ptr(partial_construction_tag) {}

      /*----- Private Members -----*/

      union {
        value_type impl;
      };

      /*----- Friends -----*/

      template <class U, class... Args>
      friend shareable_ptr<U> make_shareable(Args&&...);

  };

  template <template <class> class RefCount>
  struct view_ptr_context {

    template <class T>
    class view_ptr {

      public:

        /*----- Public Types -----*/

        using refcount_type = RefCount<T>;
        using is_nonowning = refcount_type;
        using element_type = typename refcount_traits<refcount_type>::element_type;

        // XXX: Necessary to make logic in refcount_traits work.
        template <template <template <class> class> class Binder>
        using refcount_rebind = Binder<RefCount>;

        /*----- Lifecycle Functions -----*/

        // Functions must exist for refcount concept, but will throw if called
        // as view_ptr doesn't have ownership semantics
        explicit view_ptr(T*);
        template <class Del>
        explicit view_ptr(T*, Del&&);

        // I'm not currently disallowing construction from temporaries
        // I can imagine scenarios where it could be useful, and generally,
        // you'll need to know what you're doing to work with the view types
        view_ptr(std::nullptr_t) noexcept : view_ptr() {}
        view_ptr(refcount_type const& owner) noexcept : impl(&owner) {}

        // Lifecycle functions mostly do nothing
        view_ptr() noexcept : impl(nullptr) {}
        view_ptr(view_ptr const&) = default;
        view_ptr(view_ptr&& other) noexcept;
        ~view_ptr() = default;

        /*----- Operators -----*/

        auto operator =(refcount_type const& owner) noexcept -> view_ptr&;

        auto operator =(view_ptr const&) -> view_ptr& = default;
        auto operator =(view_ptr&& other) noexcept -> view_ptr&;

        auto operator *() const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value) -> element_type&;
        auto operator ->() const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value) -> element_type*;

        bool operator ==(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);
        bool operator !=(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);
        bool operator <(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);
        bool operator <=(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);
        bool operator >(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);
        bool operator >=(view_ptr const& other) const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);

        explicit operator bool() const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value);

        operator refcount_type const&() const;

        /*----- Public API -----*/

        auto get() const noexcept(refcount_traits<refcount_type>::is_nothrow_unwrappable::value) -> element_type*;
        size_t use_count() const noexcept(refcount_traits<refcount_type>::has_nothrow_use_count::value);

        void reset() noexcept;

        auto raw() const noexcept -> refcount_type const&;

      private:

        /*----- Private Members -----*/

        refcount_type const* impl;

    };

  };

  template <class T>
  using unsafe_ptr = std::conditional_t<
    std::is_same<
      std::remove_extent_t<T>,
      T
    >::value,
    detail::counted_ptr_impl<T, int64_t>,
    detail::counted_array_ptr_impl<T, int64_t>
  >;

  template <class T, class EnableIf =
    std::enable_if_t<
      std::is_array<T>::value
    >
  >
  unsafe_ptr<T> make_unsafe(size_t idx);

  template <class T, class... Args>
  std::enable_if_t<!std::is_array<T>::value, unsafe_ptr<T>> make_unsafe(Args&&... the_args);

  template <class T>
  using skinny_ptr = std::conditional_t<
    std::is_same<
      std::remove_extent_t<T>,
      T
    >::value,
    detail::counted_ptr_impl<T, std::atomic<int64_t>>,
    detail::counted_array_ptr_impl<T, std::atomic<int64_t>>
  >;

  template <class T, class EnableIf =
    std::enable_if_t<
      std::is_array<T>::value
    >
  >
  skinny_ptr<T> make_skinny(size_t idx);

  template <class T, class... Args>
  std::enable_if_t<!std::is_array<T>::value, skinny_ptr<T>> make_skinny(Args&&... the_args);

}

/*----- Template Implementations -----*/

#include "ptrs.tcc"

#endif


#pragma once
#include <exception>
#include <iostream>
#include <cstdlib>
#include <functional>
#include <memory>
#include <vector>
#include <gsl/gsl>

#define VK_USE_PLATFORM_WIN32_KHR
#include <vulkan/vulkan.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>

#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

/*
We define this in case we want to use VulkanMemoryAllocator's
allocators.

	- https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator

Currently we are using the allocator by default so allocation of
buffers and images without VMA_USE_ALLOCATOR could not be fully supported.
*/
#define VMA_USE_ALLOCATOR

#include "../utils/Utils.h"
#include "./RenderUtils.h"
#include "../Configuration.h"
#include "RenderData.h"

/**
Used for managing all the rendering logic of the application.

Manages creation, destruction and use of all the resources necessary
to render to the screen using the Vulkan API.
*/
class Renderer
{
private:
	using WindowPtr = std::unique_ptr<GLFWwindow, GLFWWindowDestroyer>;

public:
	/**
	Default Constructor.
	Since we tie a lot of the resources to this instance and we need to
	manage them only from here the copy and move functionalities are not allowed.
	*/
	[[gsl::suppress(26439)]] Renderer();
	Renderer(const Renderer&) = delete;
	Renderer& operator=(const Renderer&) = delete;
	Renderer(Renderer&&) = delete;
	Renderer& operator=(Renderer&&) = delete;
	~Renderer();

	/* --------------------------------------------------------------------------------------------------------- */
	/* ---------------------------------------- PUBLIC FUNCTION MEMBERS ---------------------------------------- */
	/* --------------------------------------------------------------------------------------------------------- */

	/**
	Updates the uniform buffer for the object being rendered

	@TODO: Reformat this function out of the renderer.

	@see m_uniform_buffer
	*/
	auto updateRotateTestUniformBuffer() ->void;

	/**
	Sets up the beggining of a frame. Setting up the recording of a
	one time command buffer to submit to the rendering queue.
	*/
	auto beginFrame() -> void;

	/**
	Finishes the rendering stages and submits all the necessary information
	to the graphics card for rendering.
	*/
	auto endFrame() -> void;

	/**
	Returns true when we should close the application as far as the render manager
	is concerned. Currently it deals with the user closing the window itself.

	@return true if the window has been closed or we should end the application.
	*/
	auto shouldClose() const noexcept -> bool;

private:

	/* ---------------------------------------------------------------------------------------------------------- */
	/* ---------------------------------------- PRIVATE FUNCTION MEMBERS ---------------------------------------- */
	/* ---------------------------------------------------------------------------------------------------------- */

	/**
	Initializes the physical window shown by the operating system

	@see m_window
	*/
	auto initWindow() noexcept -> void;

	/**
	Initializes all the Vulkan related components necessary for rendering to
	the screen.
	*/
	auto initVulkan() -> void;

	/**
	Recreates all the necessary members to create a new swap chain, for example
	when resizing the window.
	*/
	auto recreateSwapChain() -> void;

	/**
	Cleans up all the resources that need to be explicitly cleaned up,
	mostly related to the Vulkan API and its resources.
	*/
	auto cleanup() noexcept -> void;

	/**
	Cleans up all the resources related to the swap chain, this is useful when
	recreating the swap chain to be sure we are not leaking memory and resources.
	*/
	auto cleanupSwapChain() noexcept -> void;

	/**
	Creates a Vulkan instance based on the current configuration parameters.

	@see m_instance
	@return A Valid Vulkan Instance
	*/
	auto createInstance()->VkInstance;

	/**
	Prints to standard output all the extension names of all the extensions provided.

	@param a vector with the extensions you would like to print
	*/
	auto printInstanceExtensions(const std::vector<VkExtensionProperties>& extensions)
		const -> void;

	/**
	Checks and prints if all the required extensions provided are available within the available ones.

	@param The vector of the names of the required extensions
	@param The vector of the struct with the properties of the available extensions
	@return true if all the required extensions are within the available ones, false otherwise.
	*/
	[[gsl::suppress(bounds.3)]] auto checkInstanceExtensionsNamesAvailable(
		const std::vector<const char*>& required_extensions,
		const std::vector<VkExtensionProperties>& available_extensions)
		const -> bool;

	/**
	Checks and prints if all the required validation layers in the conficuration are available.

	@return true if all the required validation layers are within the available ones, false otherwise.
	*/
	[[gsl::suppress(bounds.3)]] auto checkValidationLayerSupport() const noexcept -> bool;

	/**
	Calculates and returns the necessary Vulkan extensions for this application based
	on configuration.

	@return A vector with the names of the required extensions
	*/
	auto getRequiredExtensions() const noexcept->std::vector<const char*>;

	/**
	Callback function called to receive messages from the validation layers when
	enabled (in debug mode).

	It follows the parameters of the vulkan PFN_vkDebugReportCallbackEXT function

	@see PFN_vkDebugReportCallbackEXT
	@return VK_FALSE to indicate that the Vulkan call should NOT be aborted.
	*/
#pragma warning( push )
#pragma warning( disable : 4229)
	auto static VKAPI_ATTR VKAPI_CALL debugReportCallback(
		VkDebugReportFlagsEXT                       flags,
		VkDebugReportObjectTypeEXT                  object_type,
		uint64_t                                    object,
		size_t                                      location,
		int32_t                                     msg_code,
		const char*                                 layer_prefix,
		const char*                                 msg,
		void*                                       user_data
	)->VkBool32;
#pragma warning( pop )

	/**
	Sets up the callback function to receive debug information from
	the debug report validation layer.

	@see debugReportCallback
	@see m_debug_callback
	*/
	auto setupDebugCallback() -> void;

	/**
	Creates the window surface to which we will render to.

	@see m_surface
	*/
	auto createSurface() -> void;

	/**
	Interface to the vulkan function "vkCreateDebugReportCallbackEXT" to create
	the debug function callback.

	@see vkCreateDebugReportCallbackEXT
	@return the result of vkCreateDebugReportCallbackEXT or VK_ERROR_EXTENSION_NOT_PRESENT if
	we can't find the function pointer.
	*/
	auto createDebugReportCallbackEXT(
		const VkInstance& instance,
		const VkDebugReportCallbackCreateInfoEXT * create_info,
		const VkAllocationCallbacks* allocator,
		VkDebugReportCallbackEXT* callback
	) noexcept->VkResult;

	/**
	Interface to the vulkan function "vkDestroyDebugReportCallbackEXT" to destroy
	the debug function callback.

	@see vkDestroyDebugReportCallbackEXT
	*/
	auto destroyDebugReportCallbackEXT(
		const VkInstance& instance,
		const VkDebugReportCallbackEXT& callback,
		const VkAllocationCallbacks* allocator
	) noexcept -> void;

	/**
	Iterates and picks the most suitable physical device
	available on the system for this application.

	@see m_physical_device
	@see m_physical_device_properties
	@see m_physical_device_features
	*/
	auto pickPhysicalDevice() -> void;

	/**
	Checks if the physical device is suitable for the application
	and gives it a score based on how suitable it is based on configuration.

	@param the physical device to rate
	@return a tuple with a bool representing that is true when the device is valid
	and an int representing the score, the higher the better.
	*/
	auto physicalDeviceSuitability(
		const VkPhysicalDevice& device
	) const noexcept->std::tuple<bool, int>;

	/**
	Checks the queue families supported by the provided device and returns the indices for the
	required ones in the struct QueueFamilyIndices (graphics and present queues right now).

	@see QueueFamilyIndices
	@see m_queue_family_indices
	@see PrintOptions
	@param The physical device to retrieve the queue families from
	@param The print options for the function to indicate the output desired to standard output
	@return The struct with the family queue indices required or -1 if they haven't been found
	*/
	auto findQueueFamilies(
		const VkPhysicalDevice& physical_device,
		PrintOptions print_options
	) const->QueueFamilyIndices;

	/**
	Creates the vulkan logical device we are going to use and retrieves the graphics and present
	queues from it.

	@see m_device
	@see m_graphics_queue
	@see m_present_queue
	*/
	auto createLogicalDevice() -> void;

	/**
	Creates the allocator used to reserve memory in vulkan

	@see m_vma_allocator
	*/
	auto createAllocator() noexcept ->void;

	/**
	Checks if the physical device provided supports all the extensions required by our configuration

	@param The physical device to check for extension support
	@return true if all the extensions are supported, false otherwise
	*/
	[[gsl::suppress(bounds.3)]]
	auto checkDeviceExtensionSupport(
		const VkPhysicalDevice& device
	) const -> bool;

	/**
	Checks and retrieves information about the swap chain capabilities of a physical device.
	Fills up said information in the SwapChainSupportDetails struct

	@see SwapChainSupportDetails
	@param The physical device to check for swap chain support
	@return A SwapChainSupportDetails filled with swap chain support information
	*/
	auto querySwapChainSupport(
		const VkPhysicalDevice& device
	) const->SwapChainSupportDetails;

	/**
	Checks and returns the best available surface chain format from the provided ones
	prioritizing the ones that fit us best.

	@param A vector with the surface formats to check
	@return The best surface format for our application
	*/
	auto pickSurfaceChainFormat(
		const std::vector<VkSurfaceFormatKHR>& available_formats
	) const->VkSurfaceFormatKHR;

	/**
	Checks and returns the best available present mode from the provided ones
	prioritizing the ones that fit us best.

	@param A vector with the present modes to check
	@return The best present mode for our application
	*/
	auto pickSurfacePresentMode(
		const std::vector<VkPresentModeKHR>& available_modes
	)  const noexcept->VkPresentModeKHR;

	/**
	Checks and returns the best available extent for the images in the
	swap chain based on its capabilities.

	@param The capabilities of the surface
	@return The best possible extent (width, height) for our application
	*/
	auto pickSwapExtent(
		const VkSurfaceCapabilitiesKHR& capabilities
	)  const noexcept->VkExtent2D;

	/**
	Creates the vulkan swap chain required for rendering.
	Prioritizes a triple buffering implementation if possible.

	@see m_swap_chain
	*/
	auto createSwapChain() -> void;

	/**
	Creates an image view for each image in the swap chain so
	we can use them as color targets later.

	@see m_swap_chain_image_views
	*/
	auto createSwapChainImageViews() -> void;

	/**
	Creates the render pass that will be used to then create
	the graphics pipeline.

	@see m_render_pass
	*/
	auto createRenderPass() -> void;

	/**
	Creates the descriptor set layout that we will set in
	the pipeline.

	@see m_descriptor_set_layout;
	*/
	auto createDescriptorSetLayout() -> void;

	/**
	Creates the graphics pipeline (or pipelines) that will be used to render
	our scene.

	@see m_pipeline_layout
	@see m_pipeline
	*/
	auto createGraphicsPipeline() -> void;

	/**
	Creates a shader module based on the code provided and wraps it up
	in the VkShaderModule struct

	@see VkShaderModule
	@param An array of characters with the code for the shader
	@return The shader module created based on the shader code
	*/
	auto createShaderModule(const std::vector<char>& code) const->VkShaderModule;

	/**
	Creates the framebuffersto draw to during render time

	@see m_swap_chain_framebuffers
	*/
	auto createFramebuffers() ->  void;

	/**
	Creates the command pool that contains the command buffers to
	draw to during render time.

	@see m_graphics_command_pool
	*/
	auto createGraphicsCommandPool() ->  void;

	/**
	Creates the command pool that contains the command buffers to
	execute transfer memory commands.

	@see m_transfer_command_pool
	*/
	auto createTransferCommandPool() ->  void;

	/**
	Helper function that creates a vulkan image in a general way

	@param Width of the image
	@param Height of the image
	@param Vulkan Format of the image
	@param Tiling Options for the image
	@param Usage flags that the image will need
	@param Usage type for allocation
	@param Flags necessary for allocation
	@param The image to be populated
	@param The sharing mode for the image (Concurrent or exclusive)
	@param The family indices when sharing mode is concurrent (or nullptr otherwise)
	@param The sample count for the image, 1 sample by default (used on images meant for multisampling)
	*/
	auto createImage(
		uint width,
		uint height,
		VkFormat format,
		VkImageTiling tiling,
		VkImageUsageFlags flags,
		VmaMemoryUsage allocation_usage,
		VmaAllocationCreateFlags allocation_flags,
		AllocatedImage& image,
		VkSharingMode sharing_mode,
		const std::vector<uint>* queue_family_indices,
		short samples = 1
	) -> void;

	/**
	Destroys the image provided and frees its memory

	@param The image to destroy
	*/
	auto destroyImage(AllocatedImage& image) noexcept -> void;

	/**
	Creates the necessary resources for the implementation
	of a depth buffer

	@ m_depth_image
	@ m_depth_image_view
	*/
	auto createDepthResources() -> void;

	/**
	Creates a texture image with the data loaded from a file

	@param the path of th texture
	@return The allocated image with the texture
	*/
	auto createTextureImage(std::string path) -> AllocatedImage;

	/**
	Creates a texture image view into the texture image

	@param The image to create the view from
	@return An image view for the provided image.
	*/
	auto createTextureImageView(AllocatedImage image) -> VkImageView;

	/**
	Loads the scene with the provided object (.obj) and texture paths

	@param The path to the .obj model
	@param The path to the texture for the model
	@see m_scene
	*/
	auto loadScene(std::string object_path, std::string texture_path) -> void;

	/**
	Creates a sampler to sample the textures
	used in the rendering phase.

	@see m_texture_sampler
	*/
	auto createTextureSampler() -> void;

	/**
	Helper function that creates a vulkan buffer in a general way.

	@param The size of the memory to be allocated
	@param The usage flags necessary for the memory we are allocating
	@param The allocation usage that the buffer will have
	@param The flags for the allocator to use during creating of the buffer.
	@param The handle to the buffer to create
	@param The sharing mode of the buffer (VK_SHARING_MODE_(EXCLUSIVE/CONCURRENT))
	@param The family indices of the queues this buffer will be shared between if CONCURRENT, nullptr otherwise
	*/
	auto createBuffer(
		VkDeviceSize size,
		VkBufferUsageFlags usage,
#ifdef VMA_USE_ALLOCATOR
		VmaMemoryUsage allocation_usage,
		VmaAllocationCreateFlags allocation_flags,
#else
		VkMemoryPropertyFlags properties,
#endif
		AllocatedBuffer& allocated_buffer,
		VkSharingMode sharing_mode,
		const std::vector<uint>* queue_family_indices
	) -> void;

	/**
	Destroys the buffer provided and frees its memory

	@param The Buffer to destroy
	*/
	auto destroyBuffer(
		AllocatedBuffer& allocated_buffer
	) noexcept -> void;

	/**
	Creates the vertex buffer that will hold the vertices to render.

	@see m_vertex_buffer
	*/
	auto createVertexBuffer() -> void;

	/**
	Creates the index buffer that will hold the indexes in order to render.

	@see m_index_buffer
	*/
	auto createIndexBuffer() -> void;

	/**
	Creates the uniform buffer that will hold the object data to render.

	@see m_uniform_buffer
	*/
	auto createUniformBuffer() -> void;

	/**
	Creates the descriptor pool that will hold the descriptors sets that will
	be used during rendering.

	@see m_descriptor_pool
	*/
	auto createDescriptorPool() -> void;

	/**
	Creates the descriptor set that will hold the descriptors
	used during rendering.

	@see m_descriptor_set
	*/
	auto createDescriptorSet() -> void;

	/**
	Helper function that finds the appropriate format for a depth attachment.

	@return Format that supports usage as a depth attachment
	*/
	auto findDepthFormat()->VkFormat;

	/**
	Checks if a given format has a stencil component in it.

	@param The format to check
	@return True if it has a stencil component, false otherwise
	*/
	auto hasStencilComponent(VkFormat format) const noexcept -> bool;

	/**
	Helper function that finds the post appropriate format for an image given
	the desired features and candidates.

	@param The possible formats to choose from
	@param The tiling options of the image
	@param The features desired
	@return The most appropriate format
	*/
	auto findSupportedFormat(
		const std::vector<VkFormat>& candidates,
		VkImageTiling tiling,
		VkFormatFeatureFlags features
	)->VkFormat;

	/**
	Helper function that calculates the required memory types given the input properties.

	@param Flags that indicate the types of memories that we can consider
	@param Properties of the memory we need
	@param A reference to a boolean that will indicate if we have found an appropriate type
	@return Appropriate flags of the memory we can use.
	*/
	auto findMemoryType(
		uint type_filter,
		VkMemoryPropertyFlags properties,
		VkBool32 *found = nullptr
	)->uint;

	/**
	Copies the contents from one VkBuffer to another.

	@param The source buffer
	@param The destination buffer
	@param The size of the memory to be copied
	*/
	auto copyBuffer(
		VkBuffer src,
		VkBuffer dst,
		VkDeviceSize size
	) noexcept -> void;

	/**
	Creates the command buffers that contain the commands to
	draw to during render time.

	@see m_command_buffers
	*/
	auto createCommandBuffers() ->  void;

	/**
	Creates the drawing commands into the command buffers

	@see m_command_buffers
	*/
	auto recordCommandBuffers() -> void;

	/**
	Creates the semaphores and fences necessary for synchronization of
	the rendering phase.

	@see m_image_available_semaphores
	@see m_render_finished_semaphores
	@see m_command_buffer_fences
	*/
	auto createSemaphoresAndFences() -> void;

	/**
	Handles the event of resizing the window to set up the appropriate
	rendering parameters accordingly.

	@param Reference to the window that has been resized
	@param New width of the window
	@param New height of the window
	*/
	auto static onWindowsResized(
		GLFWwindow * window,
		int width,
		int heigth) -> void;

	/**
	Creates a single use command buffer and starts recording to it

	@param the type of commands that will be used (graphics also allows transfer)
	@return The command buffer we are recording to
	*/
	auto beginSingleTimeCommands(
		CommandType command_type = CommandType::graphics
	) noexcept->WrappedCommandBuffer;

	/**
	End recording to a particulaar command buffer and submits it to the queue

	@param The command buffer to submit to the queue
	*/
	auto endSingleTimeCommands(
		WrappedCommandBuffer& command_buffer
	) noexcept ->void;

	/**
	Helper function that changes the image layout to a new one

	@param The image to change the layout to
	@param The format of the image
	@param The old layout of the image
	@param The new layout for the image
	*/
	auto changeImageLayout(
		VkImage& image,
		VkFormat format,
		VkImageLayout old_layout,
		VkImageLayout new_layout)->void;

	/**
	Helper function that copies a buffer with image data into
	a vulkan image structure.

	@param The buffer to read the data from
	@param The image to write de data into
	@param Width of the image
	@param Height of the image
	*/
	auto copyBufferToImage(
		VkBuffer buffer,
		VkImage image,
		uint width,
		uint heigth) noexcept -> void;

	/**
	Helped function that creates an image view to the
	provided image.

	@param The image to create a view from
	@param The format of the view
	@param The aspect mast to create the image view regarding its use
	@return An image view into the provided image
	*/
	auto createImageView(
		VkImage image,
		VkFormat format,
		VkImageAspectFlags aspect_flags
	)->VkImageView;

	/**
	Helper function that calculates the required flags to
	set up an especific amount of samples.

	@param The number of samples required (power of 2 up to 64)
	@return The required vulkan flag for the number of samples
	*/
	auto getSampleBits(short samples)->VkSampleCountFlagBits;

	/**
	Creates a render target for multisampling. This includes, the image,
	its memory and a view to it.

	@param Width of the render target
	@param Height of the render target
	@param Desired format of the render target
	@param The usage flags for the render target
	@param The aspect flags for the image view of the render target
	@return The render target struct with all the relevant info
	*/
	auto createMultisampleRenderTarget(
		uint width,
		uint height,
		VkFormat format,
		VkImageUsageFlags usage,
		VkImageAspectFlags aspect_mask)->WrappedRenderTarget;

	/* ---------------------------------------------------------------------------------------------- */
	/* ---------------------------------------- DATA MEMBERS ---------------------------------------- */
	/* ---------------------------------------------------------------------------------------------- */

	RenderConfiguration config{};

#ifdef VMA_USE_ALLOCATOR
	VmaAllocator m_vma_allocator{};
#endif

	WindowPtr m_window{};

	VkInstance m_instance{};

	VkDebugReportCallbackEXT m_debug_callback{};

	VkSurfaceKHR m_surface{};

	QueueFamilyIndices m_queue_family_indices{};

	VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;

	VkPhysicalDeviceProperties m_physical_device_properties{};

	VkPhysicalDeviceFeatures m_physical_device_features{};

	VkDevice m_device{};

	VkQueue m_graphics_queue{};

	VkQueue m_present_queue{};

	VkQueue m_transfer_queue{};

	WrappedRenderTarget m_render_target{};

	WrappedRenderTarget m_depth_target{};

	VkFormat m_depth_format{};

	VkSwapchainKHR m_swap_chain{};

	uint m_current_swapchain_buffer{};

	std::vector<VkImage> m_swap_chain_images{};

	VkFormat m_swap_chain_image_format{};

	VkExtent2D m_swap_chain_extent{};

	std::vector<VkImageView> m_swap_chain_image_views{};

	VkRenderPass m_render_pass{};

	VkPipelineLayout m_pipeline_layout{};

	SimpleObjScene m_scene{};

	VkDescriptorSetLayout m_descriptor_set_layout{};

	VkPipeline m_pipeline{};

	std::vector<VkFramebuffer> m_swap_chain_framebuffers{};

	VkCommandPool m_graphics_command_pool{};

	VkCommandPool m_transfer_command_pool{};

	AllocatedBuffer m_vertex_buffer{};

	AllocatedBuffer m_index_buffer{};

	AllocatedBuffer m_uniform_buffer{};

	AllocatedImage m_depth_image{};

	VkImageView m_depth_image_view{};

	VkSampler m_texture_sampler{};

	VkDescriptorPool m_descriptor_pool{};

	VkDescriptorSet m_descriptor_set{};

	std::vector<VkCommandBuffer> m_command_buffers{};

	uint m_current_command_buffer{};

	std::vector<bool> m_command_buffer_submitted{};

	std::vector<VkSemaphore> m_image_available_semaphores{};

	std::vector<VkSemaphore> m_render_finished_semaphores{};

	std::vector<VkFence> m_command_buffer_fences{};

};


/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#pragma once

#include <mcbp/protocol/status.h>
#include <stdint.h>
#include <gsl/gsl>

struct EngineIface;

/**
 * Callback for any function producing stats.
 *
 * @param key the stat's key
 * @param klen length of the key
 * @param val the stat's value in an ascii form (e.g. text form of a number)
 * @param vlen length of the value
 * @param cookie magic callback cookie
 */
typedef void (*ADD_STAT)(const char* key,
                         const uint16_t klen,
                         const char* val,
                         const uint32_t vlen,
                         gsl::not_null<const void*> cookie);

/**
 * Callback for adding a response backet
 * @param key The key to put in the response
 * @param keylen The length of the key
 * @param ext The data to put in the extended field in the response
 * @param extlen The number of bytes in the ext field
 * @param body The data body
 * @param bodylen The number of bytes in the body
 * @param datatype This is currently not used and should be set to 0
 * @param status The status code of the return packet (see in protocol_binary
 *               for the legal values)
 * @param cas The cas to put in the return packet
 * @param cookie The cookie provided by the frontend
 * @return true if return message was successfully created, false if an
 *              error occured that prevented the message from being sent
 */
typedef bool (*ADD_RESPONSE)(const void* key,
                             uint16_t keylen,
                             const void* ext,
                             uint8_t extlen,
                             const void* body,
                             uint32_t bodylen,
                             uint8_t datatype,
                             cb::mcbp::Status status,
                             uint64_t cas,
                             const void* cookie);


#pragma once
#include "halley/support/logger.h"
#include "halley/net/connection/network_message.h"
#include <gsl/gsl>

namespace Halley
{
	class Serializer;
	class String;
	class MessageQueue;

	namespace DevCon
	{
		void setupMessageQueue(MessageQueue& queue);

		enum class MessageType
		{
			Log,
			ReloadAssets
		};

		class DevConMessage : public NetworkMessage
		{
		public:
			virtual ~DevConMessage() = default;
			virtual MessageType getMessageType() const = 0;
		};

		class LogMsg : public DevConMessage
		{
		public:
			LogMsg(gsl::span<const gsl::byte> data);
			LogMsg(LoggerLevel level, const String& msg);

			void serialize(Serializer& s) const override;

			LoggerLevel getLevel() const;
			const String& getMessage() const;
			MessageType getMessageType() const override;

		private:
			LoggerLevel level;
			String msg;
		};

		class ReloadAssetsMsg : public DevConMessage
		{
		public:
			ReloadAssetsMsg(gsl::span<const gsl::byte> data);
			ReloadAssetsMsg(std::vector<String> ids);

			void serialize(Serializer& s) const override;

			std::vector<String> getIds() const;

			MessageType getMessageType() const override;

		private:
			std::vector<String> ids;
		};
	}
}


/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#pragma once

#ifndef utilities_9904f6c1_3075_4335_b065_c7099f52e80b_h
#define utilities_9904f6c1_3075_4335_b065_c7099f52e80b_h

#include <ariel/type.h>
#include <gslib/std.h>
#include <gslib/string.h>
#include <gslib/file.h>

__ariel_begin__

/*
 * Text format elements:
 *  [section] { ... }
 *  [section]:[notation] { ... }
 *
 * where sections could be nested
 */

extern bool io_bad_eof(const string& src, int32 curr);
extern int32 io_skip_blank_charactors(const string& src, int32 start);
extern int32 io_read_section_name(const string& src, string& name, int32 start);
extern int32 io_read_notation(const string& src, string& notation, int32 start);
extern int32 io_skip_section(const string& src, int32 start);
extern int32 io_enter_section(const string& src, int32 start, gchar st = _t('{'));
extern int32 io_read_line_of_section(const string& src, string& line, int32 start);

/*
 * Binary format elements:
 *  #[uint32][string]@[uint32]      section about length(in bytes)
 *  $[uint32][string]               notation string(ASCII only)
 */

using gs::file;

class __gs_novtable io_binary_stream abstract
{
public:
    typedef vector<int32> section_stack;

    enum control_type
    {
        ctl_unknown,
        ctl_section,
        ctl_notation,
        ctl_counter,
        ctl_byte_stream_field,
        ctl_word_stream_field,
        ctl_dword_stream_field,
        ctl_qword_stream_field,
    };

public:
    io_binary_stream(int32 size);
    virtual ~io_binary_stream() {}
    control_type read_control_type();
    bool next_byte_valid() const { return next_n_bytes_valid(1); }
    bool next_word_valid() const { return next_n_bytes_valid(2); }
    bool next_dword_valid() const { return next_n_bytes_valid(4); }
    bool next_qword_valid() const { return next_n_bytes_valid(8); }
    bool next_n_bytes_valid(int32 bytes) const;
    void seek_to(int32 bytes);
    void seek_by(int32 bytes);
    float read_float();
    double read_double();
    int32 read_nstring(string& str);
    int32 read_string(string& str, const string& stopch);
    void enter_section(int32 size) { _section_stack.push_back(size); }
    bool exit_section();
    bool skip_current_section();
    bool skip_next_section();

protected:
    int32                   _size;
    int32                   _current;
    section_stack           _section_stack;

public:
    virtual byte read_byte() = 0;
    virtual word read_word() = 0;
    virtual dword read_dword() = 0;
    virtual qword read_qword() = 0;
    virtual bool read_field_to_buf(void* ptr, int32 bytes) = 0;
    virtual void rewind_to(int32 bytes) = 0;
    virtual int32 current_dev_pos() const = 0;

protected:
    void rewind_by(int32 bytes);
    void take_next_n_bytes(int32 n);
    bool section_stack_valid(int32 bytes) const;
};

class io_binary_memory:
    public io_binary_stream
{
public:
    io_binary_memory(const void* ptr, int32 size);
    virtual byte read_byte() override;
    virtual word read_word() override;
    virtual dword read_dword() override;
    virtual qword read_qword() override;
    virtual bool read_field_to_buf(void* ptr, int32 bytes) override;
    virtual void rewind_to(int32 bytes) override {}
    virtual int32 current_dev_pos() const override { return _current; }

protected:
    const byte*             _mem;
};

class io_binary_file:
    public io_binary_stream
{
public:
    io_binary_file(file& pf);
    virtual byte read_byte() override;
    virtual word read_word() override;
    virtual dword read_dword() override;
    virtual qword read_qword() override;
    virtual bool read_field_to_buf(void* ptr, int32 bytes) override;
    virtual void rewind_to(int32 bytes) override { _file.seek(bytes, SEEK_SET); }
    virtual int32 current_dev_pos() const override { return _file.current(); }

protected:
    file&                   _file;
};

__ariel_end__

#endif


#ifndef S3D_VIDEO_FILE_PARSER_FFMPEG_SEEKER_H
#define S3D_VIDEO_FILE_PARSER_FFMPEG_SEEKER_H

#include <chrono>

#include <gsl/gsl>

struct AVFormatContext;

namespace s3d {

class Seeker {
 public:
  Seeker(gsl::not_null<AVFormatContext*> formatContext, int streamIndex);

  void seekTo(std::chrono::microseconds timestamp);

 private:
  AVFormatContext* formatContext_;
  int streamIndex_;
};

}  // namespace s3d

#endif  // S3D_VIDEO_FILE_PARSER_FFMPEG_SEEKER_H


#ifndef S3D_VIDEO_STEREO_DEMUXER_STEREO_DEMUXER_H
#define S3D_VIDEO_STEREO_DEMUXER_STEREO_DEMUXER_H

#include "s3d/utilities/rule_of_five.h"

#include "s3d/video/capture/video_capture_types.h"
#include "s3d/video/video_types.h"

#include <gsl/gsl>

#include <cstdint>
#include <vector>

namespace s3d {

class StereoDemuxer : public rule_of_five_interface<StereoDemuxer> {
 public:
  using InputImageData = gsl::span<const uint8_t>;
  using OutputImageData = std::vector<uint8_t>;
  virtual void demux(const InputImageData& image,
                     OutputImageData* leftImage,
                     OutputImageData* rightImage) = 0;
  virtual Size demuxedSize() const = 0;
  virtual Stereo3DFormat getStereoFormat() const = 0;
  virtual void setSize(Size size) = 0;
  virtual void setPixelFormat(VideoPixelFormat format) = 0;
};
}  // namespace s3d

#endif  // S3D_VIDEO_STEREO_DEMUXER_STEREO_DEMUXER_H


#pragma once
#include "iparam.h"
#include "iparamlist.h"
#include "iflag.h"
#include "iarg.h"
#include "iarglist.h"
#include "icommand.h"
#include "optioninfo.h"
#include "format.h"
#include <sfun/string_utils.h>
#include <cmdlime/usageinfoformat.h>
#include <gsl/gsl>
#include <utility>
#include <vector>
#include <memory>
#include <algorithm>
#include <iomanip>

namespace cmdlime::detail{
using namespace gsl;
namespace str = sfun::string_utils;

inline std::string adjustedToLineBreak(std::string line, std::string& text)
{
    if (!text.empty() && !isspace(text.front())){
        auto trimmedLine = str::trimFront(line);
        if (std::find_if(trimmedLine.begin(), trimmedLine.end(), [](auto ch){return std::isspace(ch);}) == trimmedLine.end())
            return line;
        while(!isspace(line.back())){
            text.insert(text.begin(), 1, line.back());
            line.pop_back();
        }
    }
    return line;
}

inline std::string popLine(std::string& text, std::size_t width, bool firstLine = false)
{
    auto newLinePos = text.find('\n');
    if (newLinePos != std::string::npos && newLinePos <= width){
        auto line = text.substr(0, newLinePos);
        text.erase(text.begin(), text.begin() + static_cast<int>(newLinePos + 1));
        if (!firstLine)
            line = str::trimFront(line);
        return line;
    }

    auto line = text.substr(0, width);
    if (text.size() < width)
        text.clear();
    else
        text.erase(text.begin(), text.begin() + static_cast<int>(width));
    if (!firstLine)
        line = str::trimFront(line);
    return adjustedToLineBreak(line, text);
}

template <typename T>
inline std::vector<not_null<T*>> getParamsByOptionality(const std::vector<not_null<T*>>& params, bool isOptional)
{
    auto result = std::vector<not_null<T*>>{};
    std::copy_if(params.begin(), params.end(), std::back_inserter(result),
                 [isOptional](auto param){return param->isOptional() == isOptional;});
    return result;
}

template <typename T>
const std::string& getName(T& option)
{
    return option.info().name();
}

template <typename T>
const std::string& getType(T& option)
{
    return option.info().type();
}

template <typename T>
const std::string& getDescription(T& option)
{
    return option.info().description();
}

template <FormatType formatType>
class UsageInfoCreator{
public:
    UsageInfoCreator(std::string programName,
                     UsageInfoFormat outputSettings,
                     const std::vector<not_null<IParam*>>& params,
                     const std::vector<not_null<IParamList*>>& paramLists,
                     std::vector<not_null<IFlag*>> flags,
                     std::vector<not_null<IArg*>> args,
                     IArgList* argList,
                     std::vector<not_null<ICommand*>> commands)
    : programName_(std::move(programName))
    , params_(getParamsByOptionality(params, false))
    , optionalParams_(getParamsByOptionality(params, true))
    , paramLists_(getParamsByOptionality(paramLists, false))
    , optionalParamLists_(getParamsByOptionality(paramLists, true))
    , flags_(std::move(flags))
    , args_(std::move(args))
    , argList_(argList)
    , commands_(std::move(commands))
    , outputSettings_(outputSettings)
    , maxOptionNameSize_(maxOptionNameLength() + outputSettings.columnsSpacing)
    {
    }

    std::string createDetailed()
    {
        return minimizedUsageInfo() +
               argsInfo() +
               paramsInfo() +
               paramListsInfo() +
               optionsInfo() +
               optionalParamListsInfo() +
               flagsInfo() +
               commandsInfo();
    }

    std::string create()
    {
        return usageInfo();
    }

private:
    using OutputFormatter = typename Format<formatType>::outputFormatter;

    std::string usageInfo()
    {
        auto result = "Usage: " + programName_ + " ";
        if (!commands_.empty())
            result += "[commands] ";

        for (auto arg : args_)
            result += OutputFormatter::argUsageName(*arg) + " ";

        for (auto param : params_)
            result += OutputFormatter::paramUsageName(*param) + " ";
        for (auto paramList : paramLists_)
            result += OutputFormatter::paramListUsageName(*paramList) + " ";
        for (auto param : optionalParams_)
           result += OutputFormatter::paramUsageName(*param) + " ";
        for (auto paramList : optionalParamLists_)
           result += OutputFormatter::paramListUsageName(*paramList) + " ";

        for (auto flag : flags_)
            result += OutputFormatter::flagUsageName(*flag) + " ";

        if (argList_)
            result += OutputFormatter::argListUsageName(*argList_);

        result += "\n";
        return result;
    }

    std::string minimizedUsageInfo()
    {
        auto result = "Usage: " + programName_ + " ";

        if (!commands_.empty())
            result += "[commands] ";

        for (auto arg : args_)
            result += OutputFormatter::argUsageName(*arg) + " ";

        for (auto param : params_)
            result += OutputFormatter::paramUsageName(*param) + " ";

        for (auto paramList : paramLists_)
            result += OutputFormatter::paramListUsageName(*paramList) + " ";

        if (!optionalParams_.empty() || !optionalParamLists_.empty())
            result += "[params] ";

        if (!flags_.empty())
            result += "[flags] ";

        if (argList_)
            result += OutputFormatter::argListUsageName(*argList_);

        result += "\n";
        return result;
    }

    std::string paramsInfo()
    {
        auto result = std::string{"Parameters:\n"};
        if (params_.empty())
            return result;
        for (const auto& param : params_){
            const auto name = OutputFormatter::paramDescriptionName(*param, outputSettings_.nameIndentation) + "\n";
            result += makeConfigFieldInfo(name, getDescription(*param));
        }
        return result;
    }

    std::string paramListsInfo()
    {
        auto result = std::string{};
        if (paramLists_.empty())
            return result;
        for (const auto paramList : paramLists_){
            const auto name = OutputFormatter::paramListDescriptionName(*paramList, outputSettings_.nameIndentation) + "\n";
            auto description = getDescription(*paramList);
            if (!description.empty())
                description += "\n(multi-value)";
            else
                description += "multi-value";
            result += makeConfigFieldInfo(name, description);
        }
        return result;
    }

    std::string optionsInfo()
    {
        if (optionalParams_.empty())
            return {};
        auto result = std::string{};
        for (const auto option : optionalParams_){
            auto description = getDescription(*option);
            if (!description.empty()){
                if (!option->defaultValue().empty())
                    description += "\n(optional, default: " + option->defaultValue() + ")";
                else
                    description += "\n(optional)";
            }
            else{
                if (!option->defaultValue().empty())
                    description += "optional, default: " + option->defaultValue();
                else
                    description += "optional";
            }
            result += makeConfigFieldInfo(OutputFormatter::paramDescriptionName(*option, outputSettings_.nameIndentation) + "\n", description);
        }
        return result;
    }

    std::string optionalParamListsInfo()
    {
        if (optionalParamLists_.empty())
            return {};
        auto result = std::string{};
        for (const auto option : optionalParamLists_){
            auto description = getDescription(*option);
            if (!description.empty()){
                description += "\n(multi-value, ";
                if (!option->defaultValue().empty())
                    description += "optional, default: " + option->defaultValue() + ")";
                else
                    description += "optional)";
            }
            else{
                description += "multi-value, ";
                if (!option->defaultValue().empty())
                    description += "optional, default: " + option->defaultValue();
                else
                    description += "optional";
            }
            result += makeConfigFieldInfo(OutputFormatter::paramListDescriptionName(*option, outputSettings_.nameIndentation) + "\n", description);
        }
        return result;
    }

    std::string argsInfo()
    {
        if (args_.empty() && !argList_)
            return {};
        auto result = std::string{"Arguments:\n"};
        for (const auto arg : args_)
            result += makeConfigFieldInfo(OutputFormatter::argDescriptionName(*arg, outputSettings_.nameIndentation) + "\n", getDescription(*arg));

        if (argList_){
            auto description = getDescription(*argList_);
            if (!description.empty()){
                description += "\n(multi-value";
                if (argList_->isOptional()){
                    if (!argList_->defaultValue().empty())
                        description += ", optional, default: " + argList_->defaultValue() + ")";
                    else
                        description +=  ", optional)";
                }
                else
                    description += ")";
            }
            else{
                description += "multi-value";
                if (argList_->isOptional()){
                    if (!argList_->defaultValue().empty())
                        description += ", optional, default: " + argList_->defaultValue();
                    else
                        description +=  ", optional";
                }
            }
            result += makeConfigFieldInfo(OutputFormatter::argListDescriptionName(*argList_, outputSettings_.nameIndentation) + "\n", description);
        }
        return result;
    }

    std::string flagsInfo()
    {
        if (flags_.empty())
            return {};
        auto result = std::string{"Flags:\n"};
        for (const auto flag : flags_)
            result += makeConfigFieldInfo(OutputFormatter::flagDescriptionName(*flag, outputSettings_.nameIndentation) + "\n", getDescription(*flag));
        return result;
    }

    std::string commandsInfo()
    {
        if (commands_.empty())
            return {};
        auto result = std::string{"Commands:\n"};
        for (const auto command : commands_){
            auto nameStream = std::stringstream{};
            if (outputSettings_.nameIndentation)
                nameStream << std::setw(outputSettings_.nameIndentation) << " ";
            nameStream << getName(*command)
                       << " [options]";
            result += makeConfigFieldInfo(nameStream.str(), getDescription(*command));
        }
        return result;
    }

    int maxOptionNameLength()
    {
        auto length = 0;
        auto updateLength = [&length](std::string name)
        {
            auto firstLine = true;
            do {
               auto nameLine = popLine(name, 100, firstLine);
               length = std::max(length, static_cast<int>(nameLine.size()));
               firstLine = false;
            } while(!name.empty());
        };

        for (auto param : params_)
            updateLength(OutputFormatter::paramDescriptionName(*param, outputSettings_.nameIndentation));
        for (auto option : optionalParams_)
            updateLength(OutputFormatter::paramDescriptionName(*option, outputSettings_.nameIndentation));
        for (auto flag : flags_)
            updateLength(OutputFormatter::flagDescriptionName(*flag, outputSettings_.nameIndentation));
        for (auto arg : args_)
            updateLength(OutputFormatter::argDescriptionName(*arg, outputSettings_.nameIndentation));
        if (argList_)
            updateLength(OutputFormatter::argListDescriptionName(*argList_, outputSettings_.nameIndentation));
        return length;
    }

    std::string makeConfigFieldInfo(std::string name, std::string description)
    {
        auto maxNameWidth = std::min(outputSettings_.maxNameColumnWidth, maxOptionNameSize_);
        const auto columnSeparatorWidth = 1;
        const auto leftColumnWidth = columnSeparatorWidth + maxNameWidth;
        const auto rightColumnWidth = static_cast<std::size_t>(outputSettings_.terminalWidth - leftColumnWidth);
        const auto descriptionWidth = rightColumnWidth - 2;
        auto stream = std::stringstream{};
        auto firstLine = true;
        while (!name.empty()){
            auto nameLine = popLine(name, static_cast<std::size_t>(maxNameWidth), firstLine);
            const auto descriptionLine = popLine(description, descriptionWidth, firstLine);
            if (firstLine)
                stream << std::setw(maxNameWidth) << std::left << nameLine << " " << descriptionLine << std::endl;
            else
                stream << std::setw(maxNameWidth) << std::left << nameLine << "   " << descriptionLine << std::endl;
            firstLine = false;
        }
        while(!description.empty()){
            auto descriptionLine = popLine(description, descriptionWidth);
            stream << std::setw(leftColumnWidth) << " " << "  " << descriptionLine << std::endl;
        }
        return stream.str();
    }

private:
    std::string programName_;
    std::vector<not_null<IParam*>> params_;
    std::vector<not_null<IParam*>> optionalParams_;
    std::vector<not_null<IParamList*>> paramLists_;
    std::vector<not_null<IParamList*>> optionalParamLists_;
    std::vector<not_null<IFlag*>> flags_;
    std::vector<not_null<IArg*>> args_;
    IArgList* argList_;
    std::vector<not_null<ICommand*>> commands_;
    UsageInfoFormat outputSettings_;
    int maxOptionNameSize_;
};

}


//------------------------------------------------------------------------------
// Util.h
// Various utility functions and basic types used throughout the library.
//
// File is under the MIT license; see LICENSE for details.
//------------------------------------------------------------------------------
#pragma once

#include <climits>     // for type size macros
#include <cstddef>     // for std::byte
#include <cstdint>     // for sized integer types
#include <new>         // for placement new
#include <optional>    // for std::optional
#include <string_view> // for std::string_view
#include <utility>     // for many random utility functions
#include <variant>     // for std::variant

using std::byte;
using std::int16_t;
using std::int32_t;
using std::int64_t;
using std::int8_t;
using std::intptr_t;
using std::nullptr_t;
using std::optional;
using std::ptrdiff_t;
using std::size_t;
using std::string_view;
using std::uint16_t;
using std::uint32_t;
using std::uint64_t;
using std::uint8_t;
using std::uintptr_t;

using namespace std::literals;

#if !defined(ASSERT_ENABLED)
#    if !defined(NDEBUG)
#        define ASSERT_ENABLED 1
#    endif
#endif

#if ASSERT_ENABLED
#    if defined(__GNUC__) || defined(__clang__)
#        define ASSERT_FUNCTION __PRETTY_FUNCTION__
#    elif defined(_MSC_VER)
#        define ASSERT_FUNCTION __FUNCSIG__
#    elif defined(__SUNPRO_CC)
#        define ASSERT_FUNCTION __func__
#    else
#        define ASSERT_FUNCTION __FUNCTION__
#    endif
#    define ASSERT(cond)                                                                 \
        do {                                                                             \
            if (!(cond))                                                                 \
                slang::assert::assertFailed(#cond, __FILE__, __LINE__, ASSERT_FUNCTION); \
        } while (false)

#else
#    define ASSERT(cond)        \
        do {                    \
            (void)sizeof(cond); \
        } while (false)
#endif

#define THROW_UNREACHABLE                                                                  \
    throw std::logic_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + ": " + \
                           "Default case should be unreachable!")

#define __ENUM_ELEMENT(x) x,
#define __ENUM_STRING(x) #x,
#define ENUM(name, elements)                                          \
    enum class name { elements(__ENUM_ELEMENT) };                     \
    inline string_view toString(name e) {                             \
        static const char* strings[] = { elements(__ENUM_STRING) };   \
        return strings[static_cast<std::underlying_type_t<name>>(e)]; \
    }                                                                 \
    inline std::ostream& operator<<(std::ostream& os, name e) { return os << toString(e); }

#define ENUM_MEMBER(name, elements)                                   \
    enum name { elements(__ENUM_ELEMENT) };                           \
    friend string_view toString(name e) {                             \
        static const char* strings[] = { elements(__ENUM_STRING) };   \
        return strings[static_cast<std::underlying_type_t<name>>(e)]; \
    }

#include <gsl/gsl>

using gsl::finally;
using gsl::make_span;
using gsl::not_null;
using gsl::span;

// Compiler-specific macros for warnings and suppressions
#ifdef __clang__
#    define NO_SANITIZE(warningName) __attribute__((no_sanitize(warningName)))
#else
#    define NO_SANITIZE(warningName)
#endif

#include <bitmask.hpp>
using bitmask_lib::bitmask;

#include <nlohmann/json_fwd.hpp>
using json = nlohmann::json;

#define HAS_METHOD_TRAIT(name)                                                               \
    template<typename, typename T>                                                           \
    struct has_##name {                                                                      \
        static_assert(always_false<T>::value,                                                \
                      "Second template parameter needs to be of function type.");            \
    };                                                                                \
    template<typename C, typename Ret, typename... Args>                                     \
    struct has_##name<C, Ret(Args...)> {                                                     \
    private:                                                                                \
        template<typename T>                                                                 \
        static constexpr auto check(T*) ->                                                   \
            typename std::is_same<decltype(std::declval<T>().name(std::declval<Args>()...)), \
                                  Ret>::type;                                                \
        template<typename>                                                                   \
        static constexpr std::false_type check(...);                                         \
        typedef decltype(check<C>(0)) type;                                                  \
                                                                                \
    public:                                                                                \
        static constexpr bool value = type::value;                                           \
    };                                                                                \
    template<typename C, typename Ret, typename... Args>                                     \
    static constexpr bool has_##name##_v = has_##name<C, Ret(Args...)>::value

namespace slang {

template<typename T>
struct always_false : std::false_type {};

/// Converts a span of characters into a string_view.
inline string_view to_string_view(span<char> text) {
    return string_view(text.data(), (size_t)text.size());
}

inline void hash_combine(size_t&) {
}

/// Hash combining function, based on the function from Boost.
template<typename T, typename... Rest>
inline void hash_combine(size_t& seed, const T& v, Rest... rest) {
    std::hash<T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    hash_combine(seed, rest...);
}

namespace assert {

class AssertionException : public std::logic_error {
public:
    AssertionException(const std::string& message) : std::logic_error(message) {}
};

[[noreturn]] void assertFailed(const char* expr, const char* file, int line, const char* func);

} // namespace assert

} // namespace slang

namespace detail {

template<typename Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
struct HashValueImpl {
    static void apply(size_t& seed, const Tuple& tuple) {
        HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
        slang::hash_combine(seed, std::get<Index>(tuple));
    }
};

template<typename Tuple>
struct HashValueImpl<Tuple, 0> {
    static void apply(size_t& seed, const Tuple& tuple) {
        slang::hash_combine(seed, std::get<0>(tuple));
    }
};

} // namespace detail

namespace std {

template<typename... TT>
struct hash<std::tuple<TT...>> {
    size_t operator()(const std::tuple<TT...>& tt) const {
        size_t seed = 0;
        ::detail::HashValueImpl<std::tuple<TT...>>::apply(seed, tt);
        return seed;
    }
};

} // namespace std


#pragma once

#include <gsl/gsl>

#include <memory>
#include <atlcomcli.h>

#include "textures.h"

struct ID3D11Texture2D;
struct ID3D11DeviceContext;
struct ID3D11RenderTargetView;
struct ID3D11ShaderResourceView;
struct ID3D11DepthStencilView;

namespace gfx {

	enum class BufferFormat;

	class DynamicTexture : public Texture {
		friend class RenderingDevice;
	public:
		DynamicTexture(ID3D11DeviceContext *context,
			ID3D11Texture2D *texture,
			ID3D11ShaderResourceView *resourceView,
			const Size &size,
			uint32_t bytesPerPixel);

		int GetId() const override;

		const std::string& GetName() const;

		const ContentRect& GetContentRect() const override {
			return mContentRect;
		}

		const Size& GetSize() const override {
			return mSize;
		}

		TextureType GetType() const override {
			return TextureType::Dynamic;
		}

		// Unloads the device texture (does't prevent it from being loaded again later)
		void FreeDeviceTexture() override;

		ID3D11ShaderResourceView* GetResourceView() override {
			return mResourceView;
		}

		uint32_t GetBytesPerPixel() const {
			return mBytesPerPixel;
		}

		template<typename T>
		void Update(gsl::span<T> data) {
			UpdateRaw(
				gsl::span(reinterpret_cast<uint8_t*>(&data[0]), data.size_bytes()),
				mSize.width * sizeof(T)
			);
		}

	private:

		void UpdateRaw(gsl::span<uint8_t> data, size_t pitch);

		CComPtr<ID3D11DeviceContext> mContext;
		CComPtr<ID3D11Texture2D> mTexture;
		CComPtr<ID3D11ShaderResourceView> mResourceView;
		Size mSize;
		size_t mBytesPerPixel;
		ContentRect mContentRect;

	};

	using DynamicTexturePtr = std::shared_ptr<DynamicTexture>;

	class RenderTargetTexture : public Texture {
	friend class RenderingDevice;
	public:

		RenderTargetTexture(ID3D11Texture2D *texture,
			ID3D11RenderTargetView *rtView,
			ID3D11Texture2D *resolvedTexture,
			ID3D11ShaderResourceView *resourceView,
			const Size &size,
			bool multiSampled);

		int GetId() const override;

		const std::string& GetName() const;

		const ContentRect& GetContentRect() const override {
			return mContentRect;
		}

		const Size& GetSize() const override {
			return mSize;
		}

		TextureType GetType() const override {
			return TextureType::RenderTarget;
		}

		// Unloads the device texture (does't prevent it from being loaded again later)
		void FreeDeviceTexture() override;

		/**
		 * Only valid for MSAA targets. Will return the texture used to resolve the multisampling
		 * so it can be used as a shader resource.
		 */
		ID3D11Texture2D* GetResolvedTexture() const {
			return mResolvedTexture;
		}

		/**
		 * For MSAA targets, this will return the resolvedTexture, while for normal targets,
		 * this will just be the texture itself.
		 */
		ID3D11ShaderResourceView* GetResourceView() override {
			return mResourceView;
		}

		bool IsMultiSampled() const {
			return mMultiSampled;
		}

		gfx::BufferFormat GetFormat() const;

	private:
		CComPtr<ID3D11RenderTargetView> mRtView;
		CComPtr<ID3D11Texture2D> mTexture;
		CComPtr<ID3D11Texture2D> mResolvedTexture;
		CComPtr<ID3D11ShaderResourceView> mResourceView;
		Size mSize;
		ContentRect mContentRect;
		bool mMultiSampled;

	};

	using RenderTargetTexturePtr = std::shared_ptr<RenderTargetTexture>;

	class RenderTargetDepthStencil {
		friend class RenderingDevice;
	public:

		RenderTargetDepthStencil(ID3D11Texture2D *textureNew,
			ID3D11DepthStencilView *dsView,
			const Size &size);

		const Size& GetSize() const {
			return mSize;
		}

	private:

		CComPtr<ID3D11DepthStencilView> mDsView;
		CComPtr<ID3D11Texture2D> mTextureNew;
		Size mSize;

	};

	using RenderTargetDepthStencilPtr = std::shared_ptr<RenderTargetDepthStencil>;

}


#ifndef cloptions_h
#define cloptions_h

#include <petsc.h>
#include "../include/structs.h"

// Process general command line options
PetscErrorCode ProcessCommandLineOptions(MPI_Comm comm, AppCtx app_ctx);

#endif // cloptions_h


/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#pragma once

#ifndef typeof_027722a0_eb51_4e04_8f59_b9299ee17be6_h
#define typeof_027722a0_eb51_4e04_8f59_b9299ee17be6_h

#include <gslib/type.h>

__gslib_begin__

#define gs_register_typeof_bs(t) \
    template<> \
    struct typeof<t*> { typedef t type; }; \
    template<> \
    struct typeof<const t*> { typedef t type; };

#define gs_register_typeof(q, t) \
    q t; /* for announcement. */ \
    gs_register_typeof_bs(t);

#define gs_register_typeof_ns(ns, q, t) \
    namespace ns { \
        q t; /* for announcement. */ \
    }; \
    gs_register_typeof_bs(ns::t);

/* all pointer typeof operator should be registered here. */
gs_register_typeof_bs(int8);
gs_register_typeof_bs(int16);
gs_register_typeof_bs(int);
gs_register_typeof_bs(int64);
gs_register_typeof_bs(wchar);
gs_register_typeof_bs(real32);
gs_register_typeof_bs(real);
gs_register_typeof_bs(byte);
gs_register_typeof_bs(word);
gs_register_typeof_bs(dword);
gs_register_typeof_bs(qword);
gs_register_typeof_ns(rathen, struct, ps_data);
gs_register_typeof_ns(rathen, struct, ps_ref);
gs_register_typeof_ns(rathen, struct, ps_stdata);
gs_register_typeof_ns(rathen, struct, ps_stref);
gs_register_typeof_ns(ariel, class, button);
/* more to come ... */

__gslib_end__

#endif


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <gsl/gsl>

#include "core/optimizer/graph_transformer.h"
#include "core/optimizer/rule_based_graph_transformer.h"
#include "core/optimizer/rewrite_rule.h"

namespace onnxruntime {
struct FreeDimensionOverride;

namespace transformer_utils {

/** Generates all predefined rules for this level.
   If rules_to_enable is not empty, it returns the intersection of predefined rules and rules_to_enable.
   TODO: This is visible for testing at the moment, but we should rather make it private. */
std::vector<std::unique_ptr<RewriteRule>> GenerateRewriteRules(TransformerLevel level,
                                                               const std::vector<std::string>& rules_to_enable = {});

/** Generates all predefined (both rule-based and non-rule-based) transformers for this level.
    If transformers_and_rules_to_enable is not empty, it returns the intersection between the predefined transformers/rules
	and the transformers_and_rules_to_enable. */
std::vector<std::unique_ptr<GraphTransformer>> GenerateTransformers(TransformerLevel level,
                                                                    gsl::span<const FreeDimensionOverride> free_dimension_overrides,
                                                                    const std::vector<std::string>& rules_and_transformers_to_enable = {});

/** Given a TransformerLevel, this method generates a name for the rule-based graph transformer of that level. */
std::string GenerateRuleBasedTransformerName(TransformerLevel level);

}  // namespace transformer_utils
}  // namespace onnxruntime


#pragma once

#include "Cesium3DTilesReader/Library.h"

#include <Cesium3DTiles/Tileset.h>
#include <CesiumJsonReader/ExtensionReaderContext.h>

#include <gsl/span>

#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

namespace Cesium3DTilesReader {

/**
 * @brief The result of reading a tileset with
 * {@link TilesetReader::readTileset}.
 */
struct CESIUM3DTILESREADER_API TilesetReaderResult {
  /**
   * @brief The read tileset, or std::nullopt if the tileset could not be read.
   */
  std::optional<Cesium3DTiles::Tileset> tileset;

  /**
   * @brief Errors, if any, that occurred during the load process.
   */
  std::vector<std::string> errors;

  /**
   * @brief Warnings, if any, that occurred during the load process.
   */
  std::vector<std::string> warnings;
};

/**
 * @brief Options for how to read a tileset.
 */
struct CESIUM3DTILESREADER_API ReadTilesetOptions {};

/**
 * @brief Reads tilesets.
 */
class CESIUM3DTILESREADER_API TilesetReader {
public:
  /**
   * @brief Constructs a new instance.
   */
  TilesetReader();

  /**
   * @brief Gets the context used to control how extensions are loaded from a
   * tileset.
   */
  CesiumJsonReader::ExtensionReaderContext& getExtensions();

  /**
   * @brief Gets the context used to control how extensions are loaded from a
   * tileset.
   */
  const CesiumJsonReader::ExtensionReaderContext& getExtensions() const;

  /**
   * @brief Reads a tileset.
   *
   * @param data The buffer from which to read the tileset.
   * @param options Options for how to read the tileset.
   * @return The result of reading the tileset.
   */
  TilesetReaderResult readTileset(
      const gsl::span<const std::byte>& data,
      const ReadTilesetOptions& options = ReadTilesetOptions()) const;

private:
  CesiumJsonReader::ExtensionReaderContext _context;
};

} // namespace Cesium3DTilesReader


#ifndef PARALLEL_PROCESSING_H_2FVRLMCH
#define PARALLEL_PROCESSING_H_2FVRLMCH

#include <chrono>
#include <gsl/gsl>
#include <iomanip>
#include <ios>
#include <iostream>
#include <sens_loc/util/console.h>
#include <sens_loc/util/progress_bar_observer.h>
#include <taskflow/taskflow.hpp>
#include <type_traits>

namespace sens_loc::apps {

/// Helper function that processes a range of files based on index.
/// The boolean function \c f is applied to each function. Error handling
/// and reporting is done if \c f returns \c false.
///
/// \tparam BoolFunction Apply this functor for each index.
/// \param start,end inclusive range of integers for the files
/// \param f functor that is applied for each index
template <typename BoolFunction>
bool parallel_indexed_file_processing(int          start,
                                      int          end,
                                      BoolFunction f) noexcept {
    static_assert(std::is_nothrow_invocable_r_v<bool, BoolFunction, int>,
                  "Functor needs to be noexcept callable and return bool!");

    try {
        if (start > end)
            std::swap(start, end);

        int total_tasks = end - start + 1;

        tf::Executor executor;
        executor.make_observer<util::progress_bar_observer>(total_tasks);
        tf::Taskflow tf;

        bool batch_success = true;
        int  fails         = 0;

        tf.parallel_for(
            start, end + 1, 1, [&batch_success, &fails, &f](int idx) {
                const bool success = f(idx);
                if (!success) {
                    auto s = synced();
                    fails++;
                    std::cerr << util::err{};
                    std::cerr << "Could not process index \""
                              << rang::style::bold << idx << "\""
                              << rang::style::reset << "!" << std::endl;
                    batch_success = false;
                }
            });

        const auto before = std::chrono::steady_clock::now();
        executor.run(tf).wait();
        const auto after = std::chrono::steady_clock::now();
        const auto dur_deci_seconds =
            std::chrono::duration_cast<std::chrono::duration<long, std::centi>>(
                after - before);
        std::cout << std::endl;

        Ensures(fails >= 0);

        using namespace std::chrono;
        {
            auto s = synced();
            std::cerr << util::info{};
            std::cerr << "Processing " << rang::style::bold
                      << std::abs(end - start) + 1 - fails << rang::style::reset
                      << " images took " << rang::style::bold << std::fixed
                      << std::setprecision(2)
                      << (dur_deci_seconds.count() / 100.) << rang::style::reset
                      << " seconds!\n";
        }

        if (fails > 0) {
            auto s = synced();
            std::cerr << util::warn{} << "Encountered " << rang::style::bold
                      << fails << rang::style::reset << " problematic files!\n";
        }

        return batch_success;
    } catch (...) {
        auto s = synced();
        std::cerr << util::err{} << "System error in batch processing!\n";
        return false;
    }
}

}  // namespace sens_loc::apps

#endif /* end of include guard: PARALLEL_PROCESSING_H_2FVRLMCH */


#ifndef ADD_TO_TASK_INCLUDE
#define ADD_TO_TASK_INCLUDE

#include <functional>
#include <initializer_list>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include <gsl/pointers>

#include "base-utils/nonEmptyString.h"
#include "core/task.h"

namespace execHelper::test {
using AddToTaskFunction = std::function<core::TaskCollection(std::string)>;

inline void addToTask(const std::string& value, gsl::not_null<core::Task*> task,
                      AddToTaskFunction func) {
    task->append(func(value));
}

inline void addToTask(const NonEmptyString& value,
                      gsl::not_null<core::Task*> task, AddToTaskFunction func) {
    task->append(func(*value));
}

inline void addToTask(bool value, gsl::not_null<core::Task*> task,
                      AddToTaskFunction func) {
    if(value) {
        task->append(func("true"));
    } else {
        task->append(func("false"));
    }
}

inline void addToTask(const std::vector<std::string>& value,
                      gsl::not_null<core::Task*> task, AddToTaskFunction func) {
    std::for_each(
        value.begin(), value.end(),
        [&task, func](const auto& element) { task->append(func(element)); });
}

inline void addToTask(const std::pair<std::string, std::string>& value,
                      gsl::not_null<core::Task*> task, AddToTaskFunction func) {
    task->append(func(value.first + "=" + value.second));
}

template <typename T>
inline void addToTask(const std::optional<T>& value,
                      gsl::not_null<core::Task*> task, AddToTaskFunction func) {
    if(value) {
        addToTask(*value, task, func);
    }
}

template <typename T>
inline void addToTask(const std::optional<T>& value,
                      gsl::not_null<core::Task*> task, AddToTaskFunction func,
                      const T& defaultValue) {
    if(value) {
        addToTask(*value, task, func);
    } else {
        addToTask(defaultValue, task, func);
    }
}
} // namespace execHelper::test

#endif /* ADD_TO_TASK_INCLUDE */


/* vector/gsl_check_range.h
 *
 * Copyright (C) 2003, 2004, 2007 Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_CHECK_RANGE_H__
#define __GSL_CHECK_RANGE_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

GSL_VAR int gsl_check_range;

/* Turn range checking on by default, unless the user defines
   GSL_RANGE_CHECK_OFF, or defines GSL_RANGE_CHECK to 0 explicitly */

#ifdef GSL_RANGE_CHECK_OFF
# ifndef GSL_RANGE_CHECK
#  define GSL_RANGE_CHECK 0
# else
#  error "cannot set both GSL_RANGE_CHECK and GSL_RANGE_CHECK_OFF"
# endif
#else
# ifndef GSL_RANGE_CHECK
#  define GSL_RANGE_CHECK 1
# endif
#endif

__END_DECLS

#endif /* __GSL_CHECK_RANGE_H__ */


#pragma once
#include "utility/types.h"
#include <gsl/gsl>
#include <memory>

struct nk_context;
struct nk_user_font;
struct nk_buffer;

///
namespace cws80 {

class GraphicsDevice;
struct FontRequest;

//
class NkScreen {
public:
    NkScreen();
    ~NkScreen();

    void init(GraphicsDevice &gdev, uint w, uint h, gsl::span<const FontRequest> fontreqs);
    void clear();
    bool should_render() const;
    void render(void *draw_context);
    void update();
    nk_context *context() const;
    nk_user_font *font(uint id) const;

    uint width() const;
    uint height() const;

private:
    struct Impl;
    std::unique_ptr<Impl> P;
};

}  // namespace cws80


#pragma once

#include <type_traits>
#include <gsl/gsl>

#include "sly/macros.h"
#include "sly/types.h"

template <class T>
struct is_unique_ptr : std::false_type
{};

template <class T, class D>
struct is_unique_ptr<std::unique_ptr<T, D>> : std::true_type
{};

template <class T>
struct unique_ptr_type
{};

template <class T, class D>
struct unique_ptr_type<std::unique_ptr<T, D>>
{
    using type = std::unique_ptr<T, D>;
    using underlying_type = T;
    using delete_type = D;
};

template <class T>
struct is_shared_ptr : std::false_type
{};

template <class T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type
{};

template <typename T>
struct is_indexable  : std::false_type
{ };

template <typename T, typename A>
struct is_indexable<std::vector<T, A>> : std::true_type
{ };

template <typename T, std::size_t N>
struct is_indexable<std::array<T, N>> : std::true_type
{ };

namespace sly {
    typedef s32 StatusCode;
    typedef const char* ErrorMessage;

    static const StatusCode SUCCESS = (StatusCode)0;
    static const StatusCode UNKNOWN = (StatusCode)-1;

    template <typename T, typename = typename std::is_reference<T>::type>
    struct retval { };

    template <typename T>
    struct retval<T, std::false_type> {
    public:

        using type = T;
        using type_pointer = typename std::remove_reference<T>::type*;
        using type_reference = typename std::remove_reference<T>::type&;

        //using unique_ptr = typename is_unique_ptr<T>::value;

        retval(T value) :
            _value(std::move(value)),
            _statusCode(SUCCESS) {}

        retval(StatusCode code) : _statusCode(code) {}

        //retval(const retval&) = delete;
        retval& operator =(const retval&) = delete;
        ~retval() = default;

        template <class V, typename Y = T, typename std::enable_if_t<is_unique_ptr<Y>::value || is_shared_ptr<Y>::value>* = nullptr>
        V to() const {
            return reinterpret_cast<V>(_value.get());
        }

        template <class V, typename Y = T, typename std::enable_if_t<!is_unique_ptr<Y>::value && !is_shared_ptr<Y>::value>* = nullptr>
        V to() const {
            return reinterpret_cast<V>(_value);
        }

        template<typename V>
        operator V() const {
            return to<V>();
        }

        type result() { return _value; }
        type_reference ref() { return _value; }

        template <typename Y = T, typename std::enable_if_t<is_unique_ptr<Y>::value || is_shared_ptr<Y>::value>* = nullptr>
        operator type_reference() const {
            return *_value.get();
        }

        template <typename Y = T, typename std::enable_if_t<is_unique_ptr<Y>::value || is_shared_ptr<Y>::value>* = nullptr>
        operator typename unique_ptr_type<Y>::underlying_type&() {
            return *_value.get();
        }

        template <typename Y = T, typename std::enable_if_t<!is_unique_ptr<Y>::value && !is_shared_ptr<Y>::value>* = nullptr>
        operator type() { return result(); }

        template <typename Y = T, typename std::enable_if_t<std::is_pointer<Y>::value || is_unique_ptr<Y>::value || is_shared_ptr<Y>::value>* = nullptr>
        type_reference operator->() { return _value; }

        template <typename Y = T, typename std::enable_if_t<!std::is_pointer<Y>::value && !is_unique_ptr<Y>::value && !is_shared_ptr<Y>::value>* = nullptr>
        type_pointer operator->() { return &_value; }

        //template <typename N, typename Y = T, typename std::enable_if_t<std::is_pointer<Y>::value || is_unique_ptr<Y>::value || is_shared_ptr<Y>::value || is_indexable<Y>::value>* = nullptr>
        template<typename N>
        auto operator[](const N index) { return _value[index]; }

        StatusCode statusCode() const { return _statusCode; }

        bool_t succeeded() { return statusCode() == SUCCESS; }
        bool_t failed() { return statusCode() != SUCCESS; }

        template<typename X>
        X as() {
            return (X)result;
        }

    private:
        StatusCode _statusCode;
        T _value;
    };

    template <typename T>
    struct retval<T, std::true_type> {
    public:

        using type = T;
        using type_pointer = typename std::remove_reference<T>::type*;

        retval(T value) :
            _value(std::addressof(value)),
            _statusCode(SUCCESS) {}

        retval(StatusCode code) : _statusCode(code), _value(nullptr) {}

        retval(const retval&) = delete;
        retval& operator =(const retval&) = delete;
        ~retval() = default;

        T result() { return *_value; }
        operator T() { return result(); }
        type_pointer operator->() { return _value; }

        StatusCode statusCode() const { return _statusCode; }

        bool_t succeeded() { return statusCode() == SUCCESS; }
        bool_t failed() { return statusCode() != SUCCESS; }

        template<typename X>
        X as() {
            return (X)result();
        }

    private:
        StatusCode _statusCode;
        type_pointer _value;
    };

    template <>
    struct retval<void, std::false_type> {
    public:
        retval() : _statusCode(SUCCESS) {}
        retval(StatusCode code) : _statusCode(code) {}

        retval(const retval&) = delete;
        retval& operator =(const retval&) = delete;
        ~retval() = default;

        void value() const { }

        StatusCode statusCode() const { return _statusCode; }

        bool_t succeeded() { return statusCode() == SUCCESS; }
        bool_t failed() { return statusCode() != SUCCESS; }

        template<typename X>
        X as() {
            return (X)result;
        }

    private:
        StatusCode _statusCode;
    };

    template <typename T>
    retval<T> value(const T& value) {
        auto result = retval<T> ( std::move(value) ) ;
        return result;
    }

    template <typename T>
    retval<T&> reference(T& value) {
        return retval<T&> ( value );
    }

    retval<void> success();
    retval<void> failed();

    template <typename T>
    retval<T> failed(StatusCode statusCode, ErrorMessage message) {

        Expects(statusCode != SUCCESS);
        return retval<T> { statusCode };
    }

    template <typename T>
    retval<T> failed() {
        return retval<T> { UNKNOWN };
    }
}