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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkOpenGLRGBAVolumeCudaRayCastEntity.cxx
	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

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

// Required for windows
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")


#include <QDataStream>
#include <QVariant>
#include <QDockWidget>
#include <QApplication>
#include <QComboBox>

#include "ritkDebugManager.h"

#include "ThirdParty/GLee.h"
#include "ritkOpenGLRGBAVolumeCudaRayCastEntity.h"

#include <itkImageFileWriter.h>

#include <itkRescaleIntensityImageFilter.h>


// Convenience macro to check for OpenGL errors
#define CHECK_GL_ERROR()												\
{																		\
	GLenum errCode = glGetError();										\
	if ( errCode != GL_NO_ERROR )										\
	{																	\
	std::cout << "An OpenGL error occured: " << errCode << std::endl;	\
	std::cout << gluErrorString(errCode) << std::endl;					\
	std::cout << __FILE__ << " Line " << __LINE__  << std::endl;		\
	}																	\
}


namespace ritk
{

//----------------------------------------------------------------------------
OpenGLRGBAVolumeCudaRayCastEntity::OpenGLRGBAVolumeCudaRayCastEntity()
{
	// Create the raycaster
	Superclass::m_RayCaster = CudaRayCasterType::New();

	// Not initialized by default
	m_InitFlag = false;

	// Create our control unit
	m_ControlUnit = new OpenGLFloatVolumeRayCastControlUnit();

	// Connect our control unit's signals
	connect(m_ControlUnit->m_RenderBBCheckBox, SIGNAL(toggled(bool)), this, SLOT(RenderBoundingBox(bool)));

	// No OpenGL
	m_Texture = 0;
}


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


//----------------------------------------------------------------------------
QDockWidget*
OpenGLRGBAVolumeCudaRayCastEntity::GetControlUnit() const
{
	return m_ControlUnit;	
}


//----------------------------------------------------------------------------
void
OpenGLRGBAVolumeCudaRayCastEntity::RenderBoundingBox(bool b)
{
	Superclass::SetRenderBoundingBox(b);
	emit StatusChanged();
}


//----------------------------------------------------------------------------
void
OpenGLRGBAVolumeCudaRayCastEntity::InitGL()
{
	if ( m_InitFlag )
		return;

	// Create our textures
	glGenTextures(1, &m_Texture);

	m_InitFlag = true;
}


//----------------------------------------------------------------------------
void
OpenGLRGBAVolumeCudaRayCastEntity::CloseGL()
{
	// Delete our texture
	glDeleteTextures(1, &m_Texture);

	m_InitFlag = false;
}


//----------------------------------------------------------------------------
void
OpenGLRGBAVolumeCudaRayCastEntity::PostProcessAndRender()
{
	// Should return immediately once we're initialized
	InitGL();

	// Disable the current state
	glMatrixMode(GL_MODELVIEW); 
	glPushMatrix(); 
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glPushMatrix(); 
	glLoadIdentity();
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);

	// Bind the UC4 image to our texture
	RGBProjectionImagePointer P = Superclass::m_RayCaster->GetOutput();
	glBindTexture(GL_TEXTURE_2D, m_Texture);
	//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, P->GetRequestedRegion().GetSize()[0], P->GetRequestedRegion().GetSize()[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)P->GetBufferPointer());
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, P->GetRequestedRegion().GetSize()[0], P->GetRequestedRegion().GetSize()[1], 0, GL_RGBA, GL_FLOAT, (void*)P->GetBufferPointer());
	
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	CHECK_GL_ERROR();

	glEnable(GL_TEXTURE_2D);

	// Render the projection to the texture
	glColor3f(1,1,1);
	glBegin (GL_QUADS);
		glTexCoord2f(0.0f, 0.0f);
		//glColor3f(1,0,0);
		glVertex3f(-1.0f, -1.0f, -1.0f); 

		glTexCoord2f(1.0f, 0.0f);
		//glColor3f(0,1,0);
		glVertex3f(1.0f, -1.0f, -1.0f); 

		glTexCoord2f(1.0f, 1.0f);
		//glColor3f(0,0,1);
		glVertex3f(1.0f, 1.0f, -1.0f);

		glTexCoord2f(0.0f, 1.0f);
		//glColor3f(1,1,1);
		glVertex3f(-1.0f, 1.0f, -1.0f); 
	glEnd();

	CHECK_GL_ERROR();

	// Restore previous state
	glDisable(GL_TEXTURE_2D);
	glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	glPopMatrix(); 
	glMatrixMode(GL_MODELVIEW); 
	glPopMatrix();

}




} // ritk
