#pragma once

#include "QtViewBase.h"

#include "SceneMain.h"
#include "Camera.h"
#include "GeometryRender.h"
#include "View3DConfig.h"
#include "CloseVertInfo.h"
#include "Modifier.h"
#include "GLWidgetList.h"
#include "CameraRecords.h"
#include "SelRange.h"
#include "Cursor3D.h"
#include "PostProcBuffer.h"

#include "ShaderLibrary.h"
#include "Shader/ShaderInterface.h"

#include "PostprocLibrary.h"
#include "Postproc/PostprocInterface.h"

#include <C2/gl/Projection.h>
#include <C2/gl/Manipulator.h>
#include <C2/gl/Light.h>

#include <C2/util/optional.h>

#include <QGestureEvent>

using namespace gl;



class View3D :
	public QtViewBase,
	public SceneObserver
{
	Q_OBJECT

public:
	View3D(void);

	virtual bool InitializeView(MyGLWidget* ParentWidget);
	void RegisterScene(SceneMain* scene);

	void SetLightStrengthByStdRatio(float rat);

	virtual void FinalizeView(void);

	void BeginRender(void);
	void EndRender(void);

	virtual void OnPaint(void);
	virtual void OnResize(int width, int height);

	virtual void OnMousePress(QMouseEvent *e);
	virtual void OnMouseRelease(QMouseEvent *e);
	virtual void OnMouseDoubleClick(QMouseEvent *e);
	virtual void OnMouseMove(QMouseEvent *e);

	virtual void OnWheel(QWheelEvent *e);

	virtual void OnGesturePan(QPanGesture *gesture);
	virtual void OnGesturePinch(QPinchGesture *gesture);

	virtual void OnKeyPress(QKeyEvent *e);
	bool KeyPressOnRotCamera(QKeyEvent *e, const Modifier& m);

	// SceneObserver通知イベント
	virtual void OnGeometryBuild(const SceneMain& scene);

	void ReleaseRenderbuffer(GeomObject* obj);

	void RecordCamera(void);
	void MoveToRecordedCamera(int camera_idx, bool animation);
	void RemoveRecordedCamera(int camera_idx);
	void ClearRecordedCamera(void);

	void ResetPrimaryObjectLists(void);
	void ReleaseAllRenderBuffer(void);

	void DrawCloseVertInfo(void);

	void DrawCutPlane(void) const;
	void DrawObjectsBBox(void) const;

	void RepaintParent(void);

	std::vector<int> PickObjectAroundMouse(const QPoint& pos, int sel_range);
	bool IsInRange(int x, int y, const QImage& bmp) const;
	int QColorToIndex(const QColor& c) const;

	float GetGeomDepth(int x, int y);
	util::Optional<lm::vec3f> GetGeomDepht3DPos(int x, int y);

	void LookDepth(void);
	bool LookPixelDepth(int x, int y);
	void Look3DCursor(void);
	void ResetCursorMeasure(void);
	void UpdateCursorCutNormal(void);

	void MoveCaemraTo(ViewPoint vp);
	void MoveLookPosToCenter(void);
	void MoveLookPosToOrigin(void);
	void AdjustCameraDistAuto(void);

protected:
	void PaintMain(bool showOnlyGeom);
	void Render3D(Camera& camera, bool showOnlyGeom);
	void Render3DScene(Camera& camera, bool showOnlyGeom);
	void Render3DWithPostproc(Camera& camera);
	void UpdatePostProcContext(Camera& camera);
	void RenderClipRange(void);

	void RenderBillboard(void);
	void RenderSelRange(void);
	void RenderShadowmapBuf(void);
	void RenderCameraMeasure(void);
	void RenderCameraMeasureAxis(const lm::vec2f& axis_a, const lm::vec2f& axis_b, float abs_len);

	void ClearRenderBuffer(void);
	void SetDefalutLightState(const Camera& camera);
	void SetDefalutCullState(void);

	void DrawAllGeom(bool UseShader);
	void DrawAllGeomMeshStd(bool UseShader);
	void DrawAllGeomPolyline(void);
	void DrawPolyline(GeomObject& obj);
	void DrawPolylineHighlight(GeomObject& obj);
	void DrawPolylineGeom(const GeomObject& obj, const lib_geo::BasePolyline& pl);
	void DrawAllGeomMeshIndexColor(int index_offset);

	void DrawOptions_Before(void);
	void DrawOptions_After(void);

	void DrawGeomMeshHighlight(void);
	void DrawSelVert(GeomObject& obj, int vert_idx);
	void PickMouseClosePoint(int x, int y);
	void PickMouseClosePointMain(Camera& camera, bool scissor, int x, int y);
	void DrawVertexLinker(GeomObject& obj);
	void DrawLookPos(void);

	void DrawEnvImage(Camera& camera);
	void DrawGround(void);
	void DrawAxis(void);
	void DrawMiniAxis(void);
	void Draw3DCursor(void);
	void Draw3DCursorAxis(const lm::vec3f& p, const lm::vec3f& c);
	void Draw3DCursorCoord(const lm::vec3f& p);
	void Draw3DCursorMeasure(void);
	void Draw3DCursorBary(void);
	void DrawBmpCross(const lm::vec3f& p);

	void DrawAllGeomCrossSection(void);
	void DrawAllGeomCrossSectionLine(std::vector<GeomObject*>& objects);
	void DrawAllGeomCsConvexHull(std::vector<GeomObject*>& objects);
	void DrawAllGeomCsLengthInfo(std::vector<GeomObject*>& objects);

	void DrawCrossSectinPath(const lib_geo::CrossSection& cs);
	void DrawCsConvexHull(const lib_geo::CrossSection& cs);
	void DrawCsLengthInfo(const lib_geo::CrossSection& cs);

	void BeginClipPlaneConfig(void);
	void EndClipPlaneConfig(void);

	void BeginCutPlaneConfig(void);
	void EndCutPlaneConfig(void);

	void DrawClipRangeGraph(Camera& camera);

	void GetClipLimit(float& t, float& b) const;

	void DrawRenderTime(void);

	// mouse events
	bool MouseMove_OnSelRange        (QMouseEvent* e, QPointF& diff);
	bool MouseMove_OnZoomSelRange    (QMouseEvent* e, QPointF& diff);
	bool MouseMove_OnUpdateCloseVert (QMouseEvent* e, QPointF& diff);
	bool MouseMove_OnCameraControl   (QMouseEvent* e, QPointF& diff);
	bool MouseMove_OnLightControl    (QMouseEvent* e, QPointF& diff);
	bool MouseMove_OnCursorControl   (QMouseEvent* e);

	lm::vec3f Move3DCursor(lm::vec3f& cp, double px, double py);

	bool UpdateCloseVert(QMouseEvent* e);

	void DrawCenterCross(void);

	bool IsRequireUpdateShadowmap(void);

	ShaderInterface* GetPrimaryShader(void);
	void SetShaderResources(void);

	void UpdateShadowmap(void);
	void DrawAllGeomForShadowbuf(void);

	void SelectVertsSelRange(bool select_add);

	void DrawLightPos(const lib_gl::Light& light);

	void PushAndIdentityGLModelProjMatrix(void);
	void PushAndIdentityGLAllMatrix(void);
	void PopGLModelProjMatrix(void);
	void PopGLAllMatrix(void);

	void SelectClosestVertOnMouseDown(QMouseEvent *e);
	void SelectObjectOnMouseDown(QMouseEvent *e);

	bool CheckCameraIsReverse(void) const;

private:
	GeometryRender& GetRender(const GeomObject* geom);

	void RenderCurrentTextureToBillboard(int left, int top, int width, int height);

	void ZoomSelRange(void);

	bool IsVisibleObject(const GeomObject& obj) const;
	std::vector<GeomObject*> GetVisibleObjects(void);

signals:
	void SelectedObjectChanged(int sel_idx);

	void CameraMoved(void);


public:
	GLWidgetList* m_Widgets;

	Camera m_Camera;
	bool m_CameraReverse;

	CameraRecords m_CameraRecord;

	lib_gl::Light m_HeadLight;    //!< カメラと同位置にある, 車のヘッドライト状のライト
	lib_gl::Light m_ControlLight; //!< マウスで操作するライト

	View3DConfig m_Config;

	SceneMain* m_Scene;

	ShaderLibrary m_ShaderLib;
	ShaderContext m_ShaderContext;

	PosprocLibrary m_PPLib;
	PostprocContext m_PPContext;
	MultPathRenderBuf m_PPBuf;

	lib_graph::color4f m_BGColor;

	float m_GridAxisScale;

	bool m_FpsMode;


private:
	boost::ptr_map<const GeomObject*, GeometryRender> m_RenderMap;

	bool m_GlewInitialized;

	int m_LastRenderTime;

	SelRange m_SelRange;
	SelRange m_ZoomSelRange;

	CloseVertInfo m_CloseVertInfo;

	QPointF m_LastMousePos;
};
