// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#pragma once

#ifndef __RENDER_BGFX__
#define __RENDER_BGFX__

#include <bgfx/bgfx.h>

#include <map>
#include <vector>

#include "binpacker.h"
#include "bgfx/vertex.h"
#include "bgfx/chain.h"
#include "bgfx/chainmanager.h"
#include "sliderdirtynotifier.h"

class texture_manager;
class target_manager;
class shader_manager;
class effect_manager;
class chain_manager;
class bgfx_texture;
class bgfx_effect;
class bgfx_target;
class bgfx_chain;
class osd_options;
class avi_write;

/* sdl_info is the information about SDL for the current screen */
class renderer_bgfx : public osd_renderer, public slider_dirty_notifier
{
public:
	renderer_bgfx(std::shared_ptr<osd_window> w);
	virtual ~renderer_bgfx();

	static void init(running_machine &machine) { }
	static void exit();

	virtual int create() override;
	virtual int draw(const int update) override;

	virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) override;
	virtual std::vector<ui_menu_item> get_slider_list() override;
	virtual void set_sliders_dirty() override;

#ifdef OSD_SDL
	virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
#endif

	virtual void save() override { }
	virtual void record() override;
	virtual void toggle_fsfx() override { }

	virtual render_primitive_list *get_primitives() override
	{
		auto win = try_getwindow();
		if (win == nullptr)
			return nullptr;

		// determines whether the screen container is transformed by the chain's shaders
		bool chain_transform = false;

		// check the first chain
		bgfx_chain* chain = this->m_chains->screen_chain(0);
		if (chain != nullptr)
		{
			chain_transform = chain->transform();
		}

		osd_dim wdim = win->get_size();
		win->target()->set_bounds(wdim.width(), wdim.height(), win->pixel_aspect());
		win->target()->set_transform_container(!chain_transform);
		return &win->target()->get_primitives();
	}

	static const char* WINDOW_PREFIX;

private:
	void vertex(ScreenVertex* vertex, float x, float y, float z, uint32_t rgba, float u, float v);
	void render_avi_quad();
	void update_recording();

	bool update_dimensions();

	void setup_view(uint32_t view_index, bool screen);
	void init_ui_view();

	void setup_matrices(uint32_t view_index, bool screen);

	void allocate_buffer(render_primitive *prim, UINT32 blend, bgfx::TransientVertexBuffer *buffer);
	enum buffer_status
	{
		BUFFER_PRE_FLUSH,
		BUFFER_FLUSH,
		BUFFER_SCREEN,
		BUFFER_EMPTY,
		BUFFER_DONE
	};
	buffer_status buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);

	void render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer);
	void render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);

	void put_packed_quad(render_primitive *prim, UINT32 hash, ScreenVertex* vertex);
	void put_polygon(const float* coords, UINT32 num_coords, float r, UINT32 rgba, ScreenVertex* vertex);
	void put_line(float x0, float y0, float x1, float y1, float r, UINT32 rgba, ScreenVertex* vertex, float fth = 1.0f);

	void set_bgfx_state(UINT32 blend);

	static uint32_t u32Color(uint32_t r, uint32_t g, uint32_t b, uint32_t a);

	bool check_for_dirty_atlas();
	bool update_atlas();
	void process_atlas_packs(std::vector<std::vector<rectangle_packer::packed_rectangle>>& packed);
	UINT32 get_texture_hash(render_primitive *prim);

	osd_options& m_options;

	bgfx_target* m_framebuffer;
	bgfx_texture* m_texture_cache;

	// Original display_mode
	osd_dim m_dimensions;

	texture_manager* m_textures;
	target_manager* m_targets;
	shader_manager* m_shaders;
	effect_manager* m_effects;
	chain_manager* m_chains;

	bgfx_effect* m_gui_effect[4];
	bgfx_effect* m_screen_effect[4];
	std::vector<uint32_t> m_seen_views;

	std::map<UINT32, rectangle_packer::packed_rectangle> m_hash_to_entry;
	std::vector<rectangle_packer::packable_rectangle> m_texinfo;
	rectangle_packer m_packer;

	uint32_t m_width[16];
	uint32_t m_height[16];
	uint32_t m_white[16*16];
	int32_t m_ui_view;
	uint32_t m_max_view;

	avi_write* m_avi_writer;
	bgfx_target* m_avi_target;
	bgfx::TextureHandle m_avi_texture;
	bitmap_rgb32 m_avi_bitmap;
	uint8_t* m_avi_data;

	static const uint16_t CACHE_SIZE;
	static const uint32_t PACKABLE_SIZE;
	static const uint32_t WHITE_HASH;

	static bool s_window_set;
	static uint32_t s_current_view;
};

#endif
