//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007-2008)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: d3d9_graphicDriver.hpp
//      Краткое описание: графический драйвер Direct3D9
//

#ifdef GD_D3D9

#ifndef DSE_GS_DIRECT3D_D3D9_GRAPHICDRIVER_HPP
#define DSE_GS_DIRECT3D_D3D9_GRAPHICDRIVER_HPP

#include <Darkstar/common.hpp>
#include <Darkstar/Graphic System/window.hpp>
#include <Darkstar/Kernel/Misc/singleton.hpp>
#include <Darkstar/Graphic System/Direct3D/direct3d_include.hpp>
#include <Darkstar/Graphic System/render_target_main.hpp>
#include <Darkstar/Graphic System/Direct3D/display_mode.hpp>
#include <Darkstar/Resource System/rs_common.hpp>
#include <Darkstar/math.hpp>

namespace gs
{
	class GraphicDriver : public ker::SingletonHolder<GraphicDriver>
	{
	private:
		IDirect3DDevice9* device;
		IDirect3D9* d3d;

		unsigned int back_buffer_count;
		DRTAATYPE current_aa_mode;
		HWND output_window;
		bool is_fullscreen;

		shared_ptr<RenderTarget> backBuffer, depthBuffer;

		std::vector<shared_ptr<DisplayMode> > supported_modes_32bit;
		shared_ptr<DisplayMode> current_display_mode;

		unsigned int cur_color_rt_layer;
		shared_ptr<RenderTarget> cur_color;
		shared_ptr<RenderTarget> cur_depth;

		rs::DEViewport cur_viewport;

		std::vector<boost::function2<void, const unsigned int, const unsigned int> > resize_message_listeners;

		void onResizeBuffers();
		bool change_display_mode_on;

		bool _setBackAndDepthBuffers();

		rs::DE_PRIMITIVE_TOPOLOGY current_primitive_topology;
	public:
		GraphicDriver();
		~GraphicDriver();

		IDirect3DDevice9* getDevice() const;

		bool init(HWND hwnd, const shared_ptr<DisplayMode>& display_mode, const bool is_windowed = false, 
			const DRTAATYPE& aa_type = WITHOUT_AA, const unsigned int back_buffer_count = 2);
		void present();

		const shared_ptr<RenderTarget>& getBackBuffer() const;
		const shared_ptr<RenderTarget>& getDepthStencilSurface() const;

		const shared_ptr<RenderTarget>& getCurrentColorRenderTarget() const;
		const shared_ptr<RenderTarget>& getCurrentDepthStencilRenderTarget() const;
		unsigned int getCurrentColorRTLayer() const;

		// if width == 0 && height == 0 then setViewport set width and height of new viewport
		// exactly as width and height of current_display_mode
		void setViewport(const unsigned int width, const unsigned int height, const unsigned int topx = 0, const unsigned int topy = 0, const float min_depth = 0.0f, const float max_depth = 1.0f);
		void setViewport(const rs::DEViewport& new_viewport);
		const rs::DEViewport& getCurViewport() const;
		void resizeBuffers(unsigned int new_width, unsigned int new_height);
		void addMessageListenerOnResize(const boost::function2<void, const unsigned int, const unsigned int>& new_listener);

		void begin(const shared_ptr<RenderTarget>& color, const shared_ptr<RenderTarget>& depth);
		void begin(const shared_ptr<RenderTarget>& color, const shared_ptr<RenderTarget>& depth, const unsigned int color_rt_layer);
		void beginWithColor(const shared_ptr<RenderTarget>& color, const unsigned int color_rt_layer);
		void beginWithColor(const shared_ptr<RenderTarget>& color);
		void end();

		const shared_ptr<DisplayMode>& getCurrentDisplayMode() const;
		const std::vector<shared_ptr<DisplayMode> >& getSupported32BitDisplayMode() const;
		// change to new full screen display mode
		bool changeDisplayMode(const shared_ptr<DisplayMode>& new_mode, const DRTAATYPE& new_aa_type, const DISPLAY_MODE& dipslay_mode = DDM_WITHOUT_CHANGE);
		// new display mode, old antialising mode
		bool changeDisplayMode(const shared_ptr<DisplayMode>& new_mode, const DISPLAY_MODE& dipslay_mode = DDM_WITHOUT_CHANGE);
		// new antialising mode, old display mode
		bool changeDisplayMode(const DRTAATYPE& new_aa_type, const DISPLAY_MODE& dipslay_mode = DDM_WITHOUT_CHANGE);
		// change full screen and windowed mode
		bool changeDisplayMode(const DISPLAY_MODE& display_mode);

		void unsetAll();

		void setPrimitiveTopology(const rs::DE_PRIMITIVE_TOPOLOGY& prim_topl);

		void clear(const math::Vect4& color = math::vect4_zero, const float depth_value = 1, const unsigned int stencil_value = 0);
	};
};

#endif


#endif