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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkOpenGLVolumeRayCastEntity.h
	Version:		$Revision: 2908 $
	Date:			$Date: 2012-04-03 22:28:42 +0200 (Di, 03 Apr 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 RITKOPENGLVOLUMERAYCASTENTITY_H__
#define RITKOPENGLVOLUMERAYCASTENTITY_H__

#include "ritkVisualization.h"
#include "ritkOpenGLEntity.h"
#include "ritkRayCasterBase.h"

#include <itkObject.h>
#include <itkObjectFactory.h>
#include <itkSimpleFastMutexLock.h>


#include <QMutex>


namespace ritk
{

/**	@ingroup	Visualization
 *	@class		OpenGLVolumeRayCastEntity
 *	@author		Jakob Wasza
 *	@brief		Interface for volume ray casting and visualization in OpenGL
 *
 *	@details
 *	This class provides the basic interface for ray casting in RITK for utilizing the ritk::OpenGLEntity concept.
 *	This abstract base class provides implementations for several sub tasks in ray casting, in particular computing the projection matrix from the OpenGL state.\n
 *	Note that this class does not provide a concrete ray caster as this heavily depends on the actual volume and desired output type.
 *	Providing a ray caster is the task of subclasses via the corresponding member.
 *	In the Render3D method, the subclass' raycaster is then feeded with the volume and projection matrix and eventually updated. \n
 *	However, besides rendering the bounding box, it is the task of subclasses to do the actual OpenGL stuff.
 *	This is necessary, as the actual type of the projection image (float, RGBA) implies different OpenGL calls and LUT operations. 
 *	Therefore, all subclasses have to implement the PostProcessAndRender() method that will be called during this class implementation of Render3D(). \n
 */
template<class TVolume, class TOutputImage>
class OpenGLVolumeRayCastEntity : public ritk::OpenGLEntity, public itk::Object
{
public:
	/**	@name	Standard ITK typedefs */
	//@{
	typedef OpenGLVolumeRayCastEntity			Self;
	typedef itk::Object							Superclass;
	typedef itk::SmartPointer<Self>				Pointer;
	typedef itk::SmartPointer<const Self>		ConstPointer;
	//@}

	/**	@name	Volume and image typedefs */
	//@{
	typedef TVolume										VolumeType;
	typedef typename VolumeType::Pointer				VolumePointer;
	typedef typename VolumeType::ConstPointer			VolumeConstPointer;
	typedef TOutputImage								OutputImageType;
	typedef typename OutputImageType::Pointer			OutputImagePointer;
	typedef typename OutputImageType::ConstPointer		OutputImageConstPointer;
	//@}

	/// RTTI
	itkTypeMacro(OpenGLVolumeRayCastEntity, itk::Object);


	/// Set the volume to render
	virtual void SetVolume(const VolumeType *Volume);

	/**	@name Rendering */
	//@{
	virtual void Render3D(const ritk::OpenGLVisualizationWidget *Widget); 
	virtual void Render2D(const ritk::OpenGLVisualizationWidget *Widget, QVector2D ImgDimensions); // not supported atm
	//@}

	/// Bounding box
	virtual BoundingBoxType GetBoundingBox() const;

	/// The controlunit of this entity. This base class returns NULL
	virtual QDockWidget* GetControlUnit() const;

protected:
	/// Constructor
	OpenGLVolumeRayCastEntity();
	/// Destructor
	virtual ~OpenGLVolumeRayCastEntity();

	/// Print the camera to the given stream
	virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;

	/// Initialize all OpenGL related members
	virtual void InitGL();
	/// Release all OpenGL related members
	virtual void CloseGL();

	/// Must be implemented by all subclasses and has to do the actual rendering
	virtual void PostProcessAndRender()=0;

	/**	@name	Create the ray caster. Must be implemented by subclasses */
	//@{
	typedef RayCasterBase<VolumeType,OutputImageType> RayCasterType;
	typedef typename RayCasterType::Pointer RayCasterPointer;
	//@}

protected:
	/// Enable/disable rendering of the bounding box
	void SetRenderBoundingBox(bool b);

protected:
	/// General purpose mutex for synchronization
	QMutex m_Mutex;

	/// Whether to render the bounding box
	bool m_RenderBoundingBox;

	/// The actual volume to render
	VolumeConstPointer m_Volume;

	/// The actual ray caster. Is created via CreateRayCaster()
	RayCasterPointer m_RayCaster;

private:
	/// purposely not implemented
	OpenGLVolumeRayCastEntity(Self&); 
	/// purposely not implemented
	void operator=(const Self&); 

};

} // ritk

#endif // OPENGLVOLUMERAYCASTENTITY_H__
