// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2018-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// Copyright (C) 2021 coolsoft.rf <coolsoft.rf@gmail.com>
// Copyright (C) 2022 lainon <GermanAizek@yandex.ru>
// AUTOGENERATED COPYRIGHT HEADER END

#pragma once
#include "common.hpp"
#include "gfx/gfx-util.hpp"
#include "gfx/shader/gfx-shader-param.hpp"
#include "obs/gs/gs-effect.hpp"
#include "obs/gs/gs-rendertarget.hpp"

#include "warning-disable.hpp"
#include <filesystem>
#include <list>
#include <map>
#include <random>
#include "warning-enable.hpp"

namespace streamfx::gfx {
	namespace shader {
		enum class size_type {
			Pixel,
			Percent,
		};

		enum class shader_mode {
			Source,
			Filter,
			Transition,
		};

		typedef std::map<std::string_view, std::shared_ptr<parameter>> shader_param_map_t;

		class shader {
			obs_source_t* _self;

			std::shared_ptr<streamfx::gfx::util> _gfx_util;

			// Inputs
			shader_mode _mode;
			uint32_t    _base_width;
			uint32_t    _base_height;
			bool        _active;
			bool        _visible;

			// Shader
			streamfx::obs::gs::effect       _shader;
			std::filesystem::path           _shader_file;
			std::string                     _shader_tech;
			std::filesystem::file_time_type _shader_file_mt;
			uintmax_t                       _shader_file_sz;
			float                         _shader_file_tick;
			shader_param_map_t              _shader_params;

			// Options
			size_type _width_type;
			double_t  _width_value;
			size_type _height_type;
			double_t  _height_value;

			// Cache
			bool            _have_current_params;
			float         _time;
			float         _time_loop;
			int32_t         _loops;
			std::mt19937_64 _random;
			int32_t         _random_seed;
			float         _random_values[16]; // 0..4 Per-Instance-Random, 4..8 Per-Activation-Random 9..15 Per-Frame-Random

			// Rendering
			bool                                             _rt_up_to_date;
			std::shared_ptr<streamfx::obs::gs::rendertarget> _rt;

			public:
			shader(obs_source_t* self, shader_mode mode);
			~shader();

			bool is_shader_different(const std::filesystem::path& file);

			bool is_technique_different(std::string_view tech);

			bool load_shader(const std::filesystem::path& file, std::string_view tech, bool& shader_dirty, bool& param_dirty);

			static void defaults(obs_data_t* data);

			void properties(obs_properties_t* props);

			bool on_refresh_properties(obs_properties_t* props, obs_property_t* prop);

			bool on_shader_or_technique_modified(obs_properties_t* props, obs_property_t* prop, obs_data_t* data);

			bool update_shader(obs_data_t* data, bool& shader_dirty, bool& param_dirty);

			void update(obs_data_t* data);

			uint32_t width();

			uint32_t height();

			uint32_t base_width();

			uint32_t base_height();

			bool tick(float time);

			void prepare_render();

			void render(gs_effect* effect);

			obs_source_t* get();

			std::filesystem::path get_shader_file();

			public:
			void set_size(uint32_t w, uint32_t h);

			void set_input_a(std::shared_ptr<streamfx::obs::gs::texture> tex, bool srgb = false);

			void set_input_b(std::shared_ptr<streamfx::obs::gs::texture> tex, bool srgb = false);

			void set_transition_time(float t);

			void set_transition_size(uint32_t w, uint32_t h);

			void set_visible(bool visible);

			void set_active(bool active);
		};
	} // namespace shader
} // namespace streamfx::gfx
