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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkActorPipeline.h
	Version:		$Revision: 1821 $
	Date:			$Date: 2011-10-02 15:41:17 +0200 (So, 02 Okt 2011) $

	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 ACTORPIPELINE_H__
#define ACTORPIPELINE_H__

#include "ritkVTK.h"

#include <vtkMutexLock.h>
#include <vtkActor.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkSmartPointer.h>


namespace ritk
{

/**	@ingroup	ritkVTK
 *	@class		ActorPipeline
 *	@author		Jakob Wasza
 *	@brief		Class that encapsulates a VTK actor pipeline and ensures thread safe rendering
 *
 *	@details
 *	This class encapsulates a VTK actor pipeline (i.e. PolyData->Mapper->Actor) to be used in a VTK renderer.
 *	The purpose of this class is twofold: Firstly, it is provided for convenience to omit a manual set up 
 *	of the actor pipeline that is the same for all actors. As the ActorPipeline is derived from vtkActor
 *	it can be passed to a VTK renderer directly. \n
 *	Secondly, an interface for thread safe rendering is provided. The need for a thread safe rendering interface 
 *	arises from the fact that the actor is eventually rendered in a QVTKWidget which comes along with temporal 
 *	arbitrary repaint events and, thus, temporal arbitrary access to the actor and its associated data that is 
 *	often managed by a different thread. \n
 *	Thread safe rendering is realized by deriving from vtkActor and overriding it's Render() method. The actual
 *	rendering is then locked by a mutex. The same mutex is used to lock the ActorPipeline's SetData() method that 
 *	takes a flag that indicates whether a deep copy of the data should be performed (data consistency is ensured by
 *	this class) or the caller takes full responsibility of data consistency. In addition, the ActorPipeline can be
 *	locked manually. \n
 *	Note: Tests revealed that additional methods are invoked during a repaint event, (e.g. GetBounds(), SetMapper()).
 *	All of them have to be identified and overridden. In case of a crash please report the corresponding vtkActor() 
 *	method that eventually triggered the crash.
 */
class RITKVTK_EXPORT ActorPipeline : public vtkActor
{
public:
	/// Casting
	vtkTypeMacro(ActorPipeline,vtkActor);

	/// Object creation
	static ActorPipeline *New();

	/**	@name	Typedefs for the pipeline elements */
	//@{
	typedef vtkSmartPointer<vtkPolyData>		PolyDataPointer;
	typedef vtkSmartPointer<vtkPolyDataMapper>	PolyDataMapperPointer;
	//@}

	/**	@brief	Set the data
	 *	@param	Data		The data
	 *	@param	DeepCopy	Whether to perform a deep copy of the given data
	 *
	 *	@details
	 *	Will set the data for this actor pipeline. The ActorPipeline will be locked
	 *	during this operation. If the deep copy flag is set the data will be updated
	 *	before the copy operation.
	 *	@sa Render()
	 */
	virtual void SetData(PolyDataPointer Data, bool DeepCopy=true);

	/**	@brief	Get the data
	 *	@param	DeepCopy	Whether the returned data is a deep copy (true) or just a reference (false) to the actual data
	 *	@return	The poly data used by this actor
	 *
	 *	@details
	 *	Returns the polydata used by this actor.
	 *	@sa	SetData()
	 */
	virtual PolyDataPointer GetData(bool DeepCopy=false);

	/**	@brief	Set the mapper
	 *	@param	Mapper		The mapper to be used
	 *
	 *	@details
	 *	This method will set the mapper for the actor pipeline. The pipeline
	 *	will therefore be locked to ensure thread safety.
	 */
	virtual void SetMapper(PolyDataMapperPointer Mapper);

	/**	@brief	Overloaded rendering routine
	 *	@param	Renderer	Renderer
	 *	@param	Mapper		Mapper
	 *	
	 *	@details
	 *	This method realizes a thread safe rendering routine. During rendering
	 *	the ActorPipeline is locked.
	 *	@sa SetData();
	 */
	virtual void Render(vtkRenderer *Renderer, vtkMapper *Mapper);

	/// Lock the ActorPipeline manually
	void Lock();

	/// Unlock the ActorPipeine manually
	void Unlock();

	/// Overloaded to enforce thread safety. Note: We should buffer the returned values!
	virtual double *GetBounds();

	/// Overloaded to enforce thread safety
	virtual int RenderOpaqueGeometry(vtkViewport *viewport);

	/// Set the wrapped actor to modified
	void Modified();

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

protected:
	/// Mutex used to lock the ActorPipeline.
	vtkSmartPointer<vtkMutexLock> m_Mutex;
	/// Device
	vtkSmartPointer<vtkActor> m_Device;
	/// The data
	PolyDataPointer m_Data;
	/// The mapper
	PolyDataMapperPointer m_Mapper;

private:
	ActorPipeline(const ActorPipeline&);  // Not implemented.
	void operator=(const ActorPipeline&);  // Not implemented.
};

} // end namespace ritk

#endif // ACTORPIPELINE_H__