/*======================================================================================

Program:		Range Imaging Toolkit (RITK)
Module:			ritkOpenGLVisualizationWidget.h
Version:		$Revision: 2869 $
Date:			$Date: 2012-03-30 16:27:19 +0200 (Fr, 30 Mrz 2012) $

Copyright (c) 2010-2011
Pattern Recognition Lab, 
University Erlangen-Nuremberg, Germany
All rights reserved.

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 RITKCopyright.txt for more information.

http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef OPENGLVISUALIZATIONWIDGET_H__
#define OPENGLVISUALIZATIONWIDGET_H__

#include "ritkVisualization.h"

#include <QtOpenGL>
#include <QGLWidget>
#include <QMutex>

#include "ritkOpenGLEntity.h"
#include "ritkOpenGLCamera.h"

namespace ritk
{

/**	@ingroup	Visualization
 *	@class		OpenGLVisualizationWidget
 *	@author		Jakob Wasza
 *	@brief		A visualization widget that uses OpenGL
 *
 *	@details
 *	Press r to reset the camera, press w to toggle wire-frame mode.
 *	@todo	More detailed description
 */
class VISUALIZATION_EXPORT OpenGLVisualizationWidget : public QGLWidget
{
	Q_OBJECT

public:
	/**	@brief	Get the global OpenGL context
	 *	@return	the global context
	 *	
	 *	@details
	 *	@todo detailed documentation
	 */
	static QGLContext* GetGLContext();

	/**	@brief	Get the global QGLWidget to share contexts and display lists
	 *	@return	The global QGLWidget
	 *
	 *	@details
	 *	@todo detailed documentation
	 */
	static QGLWidget* GetGlobalQGLWidget();

	/// Constructor
	OpenGLVisualizationWidget(QWidget *parent=0);
	/// Destructor
	~OpenGLVisualizationWidget();

	/**	@name	Camera */
	//@{
	typedef OpenGLCamera				CameraType;
	typedef CameraType::Pointer			CameraPointer;
	typedef CameraType::ConstPointer	CameraConstPointer;
	void SetCamera(CameraPointer Camera);
	CameraPointer GetCamera();
	CameraConstPointer GetCamera() const;
	//@}

	/**	@name Add/remove entities. An entity's StatusChanged() signal will be automatically (dis)connected to indicate the need for a redraw */
	//@{
	bool AddEntity(OpenGLEntity *e, bool lock = true);
	bool RemoveEntity(OpenGLEntity *e, bool lock = true);
	bool SetPrimaryEntity(OpenGLEntity *e);
	bool RemovePrimaryEntity();
	const OpenGLEntity *GetPrimaryEntity();
	//@}

	/**	@name Get the entities in this visualization widget */
	//@{
	typedef std::list<OpenGLEntity*> EntityContainerType;
	const EntityContainerType& GetEntities() const;
	EntityContainerType& GetEntities();
	//@}

	virtual void SetRender3D(bool enabled);
	virtual void SetRenderModeFixed(bool enabled);

public slots:
	/// Will update (i.e. paint) the widget and is connected to the widget's StatusChanged() signals
	void Update();

signals:
	/// Signal to establish communication with the ResetCamera method
	void ResetCameraSignal();

protected:
	/**	@name	Does the OpenGL part */
	//@{
	void initializeGL();
	void resizeGL(int width, int height);
	void paintGL();
	void closeGL();
	//@}

	/**	@name	Intercept mouse events */
	//@{
	void mouseMoveEvent(QMouseEvent *e);
	void mousePressEvent(QMouseEvent *e);
	void mouseReleaseEvent(QMouseEvent *e);
	void wheelEvent(QWheelEvent*);
	//@}

	/**	@name	Keyboard events */
	//@{
	void keyPressEvent(QKeyEvent *e);
	//@}
	
protected slots:
	/// Reset the camera
	void ResetCamera();

protected:
	/// Flag that indicates whether this widget (in particular the OpenGL extensions) are initialized
	bool m_InitFlag;

	/**	@name  Width and height of the drawing area */
	//@{
	int m_Width;
	int m_Height;
	//@}

	/// draw wireframe or faces
	bool m_DrawWire;

	/// render 2D or 3D
	bool m_Render3D;
	bool m_RenderModeFixed;

	/// Our camera
	CameraPointer m_Camera;

	/// Primary Entity; should be RImageEntity. Used by PointPicker to get 2D-3D conversion
	OpenGLEntity *m_PrimaryEntity;

	/// Managed entities
	EntityContainerType m_Entities;
	
	/// Last mouse point
	QPoint m_LastMousePos;

	/// Mutex used to synchronize rendering and data update
	QMutex m_Mutex;

	GLuint m_BackGroundTexture;

private:
	/// The global OpenGL context
	static QGLContext *s_GLContext;

	/// The global QGLWidget
	static QGLWidget *s_QGLWidget;

};

} // end namespace ritk

#endif // OPENGLVISUALIZATIONWIDGET_H__
