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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkActorPipeline.cxx
	Version:		$Revision: 1980 $
	Date:			$Date: 2011-10-27 17:44:49 +0200 (Do, 27 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

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

#include "ritkActorPipeline.h"

#include <vtkObjectFactory.h>
#include <vtkProperty.h>
#include <vtkGraphicsFactory.h>
#include <vtkMatrix4x4.h>
#include <vtkTexture.h>

namespace ritk
{

// Implements static ActorPipeline *New();
vtkStandardNewMacro(ActorPipeline);

//----------------------------------------------------------------------------
ActorPipeline::ActorPipeline()
{
	// Initialize the mutex
	m_Mutex = vtkSmartPointer<vtkMutexLock>::New();

	// Initialize the device
	m_Device = vtkSmartPointer<vtkActor>::New();
	vtkMatrix4x4 *m = vtkMatrix4x4::New();
	this->m_Device->SetUserMatrix(m);
	m->Delete();

	// Set up the pipeline
	m_Data = PolyDataPointer::New();
	m_Mapper = PolyDataMapperPointer::New();
	m_Mapper->SetInput(m_Data);
	Superclass::SetMapper(m_Mapper);
}


//----------------------------------------------------------------------------
ActorPipeline::~ActorPipeline()
{
}


//----------------------------------------------------------------------------
void
ActorPipeline::SetData(PolyDataPointer Data, bool DeepCopy)
{
	// Lock the pipeline
	Lock();

	// Set the data to the pipeline
	if ( DeepCopy )
	{
		Data->Update();
		m_Data->DeepCopy(Data);
		m_Mapper->SetInput(m_Data);
		Superclass::SetMapper(m_Mapper);
		m_Device->SetMapper(m_Mapper);
		m_Mapper->Update();
	}

	else
	{
		m_Data = Data;
		m_Mapper->SetInput(m_Data);
		Superclass::SetMapper(m_Mapper);
		m_Device->SetMapper(m_Mapper);
		m_Mapper->Update();
	}

	// Modified (not sure about the benifit from these calls)
	this->Modified();
	m_Device->Modified();

	// Unlock the pipeline
	Unlock();
}


//----------------------------------------------------------------------------
ActorPipeline::PolyDataPointer
ActorPipeline::GetData(bool DeepCopy)
{
	if ( !DeepCopy )
		return m_Data;
	else
	{
		// Lock the pipeline
		Lock();
		PolyDataPointer Result = PolyDataPointer::New();
		Result->DeepCopy(m_Data);
		// Unlock the pipeline
		Unlock();
		return Result;
	}
}


//----------------------------------------------------------------------------
void
ActorPipeline::SetMapper(PolyDataMapperPointer Mapper)
{
	// Lock the pipeline
	Lock();

	// Insert the mapper into the pipeline
	m_Mapper = Mapper;
	m_Mapper->SetInput(m_Data);
	Superclass::SetMapper(m_Mapper);
	m_Device->SetMapper(m_Mapper);
	m_Mapper->Update();

	// Modified (not sure about the benifit from these calls)
	this->Modified();
	m_Device->Modified();

	// Unlock the pipeline
	Unlock();
}


//----------------------------------------------------------------------------
void
ActorPipeline::Render(vtkRenderer *Renderer, vtkMapper *Mapper)
{
	// Lock the pipeline
	Lock();

	// render the property
	if ( !this->Property )
    	{
    		// force creation of a property
    		this->GetProperty();
    	}
  	this->Property->Render(this, Renderer);
  	if ( this->BackfaceProperty )
    	{
    		this->BackfaceProperty->BackfaceRender(this, Renderer);
		this->m_Device->SetBackfaceProperty(this->BackfaceProperty);
	}
 	this->m_Device->SetProperty(this->Property);
  
  
  	// render the texture
	if ( this->Texture )
	{
		this->Texture->Render(Renderer);
	}

	// make sure the device has the same matrix
	this->GetMatrix(m_Device->GetUserMatrix());

	// The actual rendering
	m_Device->Render(Renderer,Mapper);

	// Unlock the pipeline
	Unlock();
}


//----------------------------------------------------------------------------
void
ActorPipeline::Lock()
{
	// @todo 
	m_Mutex->Lock();
}


//----------------------------------------------------------------------------
void
ActorPipeline::Unlock()
{
	// @todo
	m_Mutex->Unlock();
}


//----------------------------------------------------------------------------
void 
ActorPipeline::Modified()
{
	if ( this->m_Device ) // Will be NULL only during destruction of this class.
	{
	this->m_Device->Modified();
	}
	this->vtkActor::Modified();
}


//----------------------------------------------------------------------------
double*
ActorPipeline::GetBounds()
{
	double *d;
	Lock();
	d = Superclass::GetBounds();
	//d = m_Device->GetBounds();
	Unlock();
	return d;
}


//----------------------------------------------------------------------------
int
ActorPipeline::RenderOpaqueGeometry(vtkViewport *viewport)
{
	int i;
	Lock();
	i = Superclass::RenderOpaqueGeometry(viewport);
	Unlock();
	return i;
}
		


} // end namespace ritk
