#pragma once

#include <C2/gl/GlDisplayList.h>

#include "View3DConfig.h"

#include "ShaderLibrary.h"
#include "GeometryVBO.h"

#include <LibQtGeoViewerCore/GeomObject.h>
#include <LibQtGeoViewerCore/SceneMain.h>



class GeometryRender
{
private:
	enum MeshRenderMode
	{
		MR_FILL,
		MR_WIRE_SHADE,
		MR_WIRE_OVERLAY,
	};

public:
	GeometryRender(MeshBuf* mbuf);
	virtual ~GeometryRender(void);

	void InitializeGeoRender(View3DConfig* config, ShaderLibrary* shaders, SceneMain* scene);

	void ReleaseAccBuffer(void);
	void ReleaseIndexDispList(void);

	void DrawGeomVertPick(MeshBuf& mbuf, SceneMain& scene);
	void DrawGeomHighlight(MeshBuf& mbuf, SceneMain& scene);

	void DrawFace_WireConstantColor(MeshBuf& mbuf, SceneMain& scene);
	void DrawFace_WireConstantColorForCS(MeshBuf& mbuf, SceneMain& scene);
	void DrawFace_WireConstantColorVBO(MeshBuf& mbuf, SceneMain& scene);
	void DrawFace_WireConstantColorRawOrDispList(MeshBuf& mbuf, SceneMain& scene);
	void DrawFace_Fill(MeshBuf& mbuf, SceneMain& scene, ShaderInterface* shader);

	void DrawMeshMain(SceneMain& scene, ShaderInterface* shader);
	void DrawFaceIndexColor(MeshBuf& mbuf, SceneMain& scene, unsigned int idx);

	void DrawMeshExtAll(void);
	void DrawSelVertAll(void);

private:
	void DrawMeshFaceMain(SceneMain& scene, ShaderInterface* shader, MeshRenderMode mode);

	void DrawMeshFid(lib_geo::BaseMesh& mesh);

	void DrawVert(const lib_geo::BaseMesh& mesh);
	void DrawVertPoint(const lib_geo::BaseMesh& mesh);
	void DrawVertVid(MeshBuf& mbuf);
	void DrawVertNormal(const lib_geo::BaseMesh& mesh);

	void SetGLNormalColor(const lm::vec3f& n) const;

	const lib_graph::Material* GetFaceMaterial(SceneMain& scene, const MeshBuf& mbuf, const lib_geo::BaseFace& f) const;
	void AssignTextures(SceneMain& scene, MeshBuf& mbuf, ShaderInterface* shader, const lib_geo::BaseFace& f) const;
	void AssignMatcap(SceneMain& scene, MeshBuf& mbuf, ShaderInterface* shader, const lib_geo::BaseFace& f) const;
	gl::GlTexture* GetSceneFixedTexture(SceneMain& scene) const;

	void DrawFaceGroupGeometry(lib_geo::BaseMesh& mesh, const FaceGroup& fg, GLenum primitive_type, ShaderInterface* shader);
	void DrawFaceGroupGeometry_VBO(lib_geo::BaseMesh& mesh, const FaceGroup& fg, GLenum primitive_type, ShaderInterface* shader);
	void DrawFaceGroupGeometry_STD(lib_geo::BaseMesh& mesh, const FaceGroup& fg, GLenum primitive_type, ShaderInterface* shader);

	GeometryVBO* GetOrCreateVBO(lib_geo::BaseMesh& mesh, const FaceGroup& fg);

	void SetGlIndexColor(unsigned int idx) const;

	void SetMeshDepthOffset(MeshRenderMode mode);

	void SetMaterialHilight(const lib_graph::Material& m);
	void SetShaderConfig(ShaderInterface* shader);

private:
	GeometryRender(const GeometryRender&) {}
	void operator=(const GeometryRender&) {}

	bool CheckSphereClipUpdated(void);
	void UpdateSphereClipCache(void);

private:
	SceneMain* m_Scene;
	MeshBuf* m_Mesh;
	View3DConfig* m_Config;
	ShaderLibrary* m_Shaders;

	View3DConfig m_LastConfig;
	lib_gl::GlDisplayList m_DispList_FaceWire;
	lib_gl::GlDisplayList m_DispList_Vert;
	lib_gl::GlDisplayList m_DispList_Vid;
	lib_gl::GlDisplayList m_DispList_Fid;

	std::map<int, GeometryVBO> m_FaceGroupVBO;

	SphereClipType m_SphereClipType;
	float m_SphereClipDst;
	lm::vec3f m_CursorPos;
};
