/*
    QGLView
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef RENDERER_H
#define RENDERER_H

#include "renderer_base.h"
#include "renderer_material.h"
#include "renderer_service.h"
#include "renderer_selection.h"
#include "tonemapping_proc.h"
#include "glcubemap.h"
#include <QQueue>


class Renderer: public RendererBase {
	friend class QGLView;
	friend class MouseController;
	friend class RendererBase;
	friend class RendererMaterial;
	friend class RendererService;
	friend class RendererSelection;
	friend class TonemappingProc;
	enum ShaderRole {
		// Selection
		srSelectionFill,
		srSelectionHalo,
		srSelectionApply,
		srSelectionFrame,

		// Service
		srServiceFill,
		srServiceFrame,
		srServiceLine,

		// Deferred shading
		srGeometryPass,
		srLightOmniPass,
		srLightSpotPass,
		srFinalPass,
		srTonemapPass,
	};
	enum DeferredBufferRole {
		dbrDiffuse,
		dbrNormalZ,
		dbrSpecularReflect,
		dbrEmissionRough,
		dbrSpeedBitangXY,

		dbrBuffersCount,
	};
	enum OutBufferRole {
		obrTonemap,
		obrSum,
		obrSolidOmni,
		obrSolidSpot,
		obrTransparentOmni,
		obrTransparentSpot,

		obrBuffersCount,
	};

public:
	Renderer(QGLView * view_);
	virtual ~Renderer();

	void init(int width, int height);
	void resize(int width, int height);
	void reloadShaders();
	void renderScene();
	void setCameraLightMode(int m);
	int cameraLightMode() const {return camera_light_mode;}

	QImage materialThumbnail(Material * m) {return rend_mat.materialThumbnail(m);}
	void recreateMaterialThumbnails(bool force_all = false) {rend_mat.recreateMaterialThumbnails(force_all);}

protected:
	void fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass);
	void reloadObjects();
	void renderObjects(Scene & scene, RenderPass pass);
	void renderLight(int first_wr_buff, bool clear_only);

	bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0);
	bool bindShader(QOpenGLShaderProgram * sp);
	void initShaders();
	void releaseShader();

private:
	float gamma_;
	int camera_light_mode;
	bool edit_mode, need_init_shaders, need_render_sum;
	Framebuffer fbo_ds, fbo_out;
	/*QOpenGLShaderProgram * shader_fxaa, * shader_ds_0, * shader_ds_1, * shader_hdr, * shader_small;
	QOpenGLShaderProgram * shader_bloom_0, * shader_bloom_1, * shader_motion_blur, * shader_fbo_add;
	QOpenGLShaderProgram * shader_shadow, * shader_ssr, * shader_ssr_blur, * shader_ssr_merge;
	QOpenGLShaderProgram * shader_ssao_blur, * shader_ssao_merge, * shader_dof;*/
	QMap<ShaderRole, QString> shader_files;
	QMap<ShaderRole, QStringList> shader_defines;
	QMap<ShaderRole, QOpenGLShaderProgram*> shaders;
	QOpenGLShaderProgram * shader_fxaa;

	RendererMaterial rend_mat;
	RendererService rend_service;
	RendererSelection rend_selection;
	TonemappingProc tone_proc;

	Mesh * quad;
	Light * cam_light;
	CubeTexture tex_env;

	QPoint mouse_pos;
	QRect mouse_rect;
	QMatrix4x4 prev_view, prev_proj;
	QMatrix3x3 nm;
	QVector4D corner_dirs[4];
	QVector<QVector3D> hcontent;
	QMap<int, QList<Light*>> cur_lights;

};

#endif // RENDERER_H
