#pragma once

#include "volumeshop.h"

#include "Environment.h"
#include "Volume.h"
#include "Renderer.h"
#include "Vector.h"
#include "Quaternion.h"
#include "Matrix.h"
#include "Shader.h"
#include "Color.h"
#include "Timer.h"
#include "Label.h"
#include "ColorTransferFunction.h"
#include "LightingTransferFunction.h"
#include "Exception.h"

class RendererVolumeBooster : public Renderer
{
public:

	RendererVolumeBooster(Environment & envEnvironment) : m_envEnvironment(envEnvironment), m_uWidth(32), m_uHeight(32),
		m_uGeometryFrameBuffer(0), m_uGhostCutoutFrameBuffer(0), m_uSelectionCutoutFrameBuffer(0), m_uTemporaryFrameBuffer(0), m_uGeometryColorTexture(0), m_uGeometryDepthTexture(0), m_uTemporaryDepthTexture(0), m_uImageColorTexture(0), 	m_uGhostCutoutDepthTexture(0), m_uSelectionCutoutDepthTexture(0), m_uCutoutColorRenderBuffer(0), 
		m_proBackgroundDisplay(VertexShader("RendererVolumeBoosterBackgroundDisplayVertex.glsl"),FragmentShader("RendererVolumeBoosterBackgroundDisplayFragment.glsl")),
		m_proGhostDisplay(VertexShader("RendererVolumeBoosterGhostDisplayVertex.glsl"),FragmentShader("RendererVolumeBoosterGhostDisplayFragment.glsl")),
		m_proSelectionDisplay(VertexShader("RendererVolumeBoosterSelectionDisplayVertex.glsl"),FragmentShader("RendererVolumeBoosterSelectionDisplayFragment.glsl")),
		m_proCutoutGenerationPass1(VertexShader("RendererVolumeBoosterCutoutGenerationVertex.glsl"),FragmentShader("RendererVolumeBoosterCutoutGenerationPass1Fragment.glsl")),
		m_proCutoutGenerationPass2(VertexShader("RendererVolumeBoosterCutoutGenerationVertex.glsl"),FragmentShader("RendererVolumeBoosterCutoutGenerationPass2Fragment.glsl"))
	{
		if (!GLEW_ARB_fragment_shader)
		{
			std::cerr << "GL_ARB_fragment_shader is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_ARB_fragment_shader is not supported by your hardware or driver.");
		}

		if (!GLEW_ARB_vertex_shader)
		{
			std::cerr << "GL_ARB_fragment_shader is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_ARB_fragment_shader is not supported by your hardware or driver.");
		}

		if (!GLEW_ARB_texture_non_power_of_two)
		{
			std::cerr << "GL_ARB_texture_non_power_of_two is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_ARB_texture_non_power_of_two is not supported by your hardware or driver.");
		}

		if (!GLEW_ARB_texture_rectangle)
		{
			std::cerr << "GL_ARB_texture_rectangle is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_ARB_texture_rectangle is not supported by your hardware or driver.");
		}		

		if (!GLEW_EXT_framebuffer_object)
		{
			std::cerr << "GL_EXT_framebuffer_object is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_EXT_framebuffer_object is not supported by your hardware or driver.");
		}


	/*
		glGenBuffers( 1, &m_uVertexBuffer );
		glGenBuffers( 1, &m_uIndexBuffer );

		//create the points used to draw the slices
		unsigned int i,j;
		Vector vvVertices[64];

		for (j=0;j < 8; j++)
		{
			for (i=0; i < 8; i++)
			{
				const unsigned int uVertex = j*8+i;
				vvVertices[uVertex].SetX(float(i) / 7.0f - 0.5f);
				vvVertices[uVertex].SetY(float(j) / 7.0f - 0.5f);
				vvVertices[uVertex].SetZ(-0.5f);
				vvVertices[uVertex].normalize();

				vvVertices[uVertex].SetX(vvVertices[uVertex].GetX() * 2.0f);
				vvVertices[uVertex].SetY(vvVertices[uVertex].GetY() * 2.0f);
				vvVertices[uVertex].SetZ(vvVertices[uVertex].GetZ() + 1.0f);
			}
		}

		glBindBuffer(GL_ARRAY_BUFFER, m_uVertexBuffer);
		glBufferData(GL_ARRAY_BUFFER, 64*sizeof(Vector), (void*)&vvVertices[0], GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		unsigned int vuIndices[196];
		unsigned int uIndex = 0;

		for(j=0;j<7;j++)
		{
			for(i=0;i<7;i++)
			{
				vuIndices[uIndex++] = j*8+i;
				vuIndices[uIndex++] = j*8+i+1;
				vuIndices[uIndex++] = (j+1)*8+i+1;
				vuIndices[uIndex++] = (j+1)*8+i;
			}
		}

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uIndexBuffer);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, 196*sizeof(unsigned int), (void*)&vuIndices[0], GL_STATIC_DRAW);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
*/		
		glGenFramebuffersEXT(1, &m_uGeometryFrameBuffer);
		glGenFramebuffersEXT(1, &m_uGhostCutoutFrameBuffer);
		glGenFramebuffersEXT(1, &m_uSelectionCutoutFrameBuffer);
		glGenFramebuffersEXT(1, &m_uTemporaryFrameBuffer);

		glGenTextures(1,&m_uImageColorTexture);
		glGenTextures(1,&m_uGeometryColorTexture);
		glGenTextures(1,&m_uGeometryDepthTexture);
		glGenTextures(1,&m_uTemporaryDepthTexture);
	
		glGenRenderbuffersEXT(1, &m_uCutoutColorRenderBuffer);  
		glGenTextures(1,&m_uGhostCutoutDepthTexture);
		glGenTextures(1,&m_uSelectionCutoutDepthTexture);
	};

	virtual ~RendererVolumeBooster()
	{
		if (m_uSelectionCutoutDepthTexture)
			glDeleteTextures(1,&m_uSelectionCutoutDepthTexture);

		if (m_uGhostCutoutDepthTexture)
			glDeleteTextures(1,&m_uGhostCutoutDepthTexture);

		if (m_uCutoutColorRenderBuffer)
			glDeleteRenderbuffersEXT(1, &m_uCutoutColorRenderBuffer);

		if (m_uTemporaryFrameBuffer)
			glDeleteFramebuffersEXT(1, &m_uTemporaryFrameBuffer);

		if (m_uSelectionCutoutFrameBuffer)
			glDeleteFramebuffersEXT(1, &m_uSelectionCutoutFrameBuffer);

		if (m_uGhostCutoutFrameBuffer)
			glDeleteFramebuffersEXT(1, &m_uGhostCutoutFrameBuffer);

		if (m_uGeometryFrameBuffer)
			glDeleteFramebuffersEXT(1, &m_uGeometryFrameBuffer);
/*
		if (m_uIndexBuffer)
			glDeleteBuffers( 1, &m_uIndexBuffer );

		if (m_uVertexBuffer)
			glDeleteBuffers( 1, &m_uVertexBuffer );
*/
	};

	Environment & GetEnvironment()
	{
		return m_envEnvironment;
	};

	virtual void idle()
	{
	};

	virtual void underlay()
	{
	};

	virtual void display()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		generateGeometryTexture();	

		float vfLightDirection[4] = {-0.25f,0.5f,-1.0f,0.0};
		glLightfv(GL_LIGHT0,GL_POSITION,vfLightDirection);

		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetProjectionTransformation().Get());
		
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetViewingTransformation().Get());

		generateGhostStandardCutoutTexture();
		generateSelectionStandardCutoutTexture();

		if (GetEnvironment().IsGhostCutoutEnabled())
			generateGhostSmoothCutoutTexture();

		if (GetEnvironment().IsSelectionCutoutEnabled())
			generateSelectionSmoothCutoutTexture();

		Volume<DataVoxel>::Octree::Iterator i(GetEnvironment().GetDataVolume().GetOctree());
		Volume<SelectionVoxel>::Octree::Iterator j(GetEnvironment().GetSelectionVolume().GetOctree());

		float fMinimumBackground = std::numeric_limits<float>::max();
		float fMaximumBackground = -std::numeric_limits<float>::max();

		float fMinimumGhost = std::numeric_limits<float>::max();
		float fMaximumGhost = -std::numeric_limits<float>::max();

		float fMinimumSelection = std::numeric_limits<float>::max();
		float fMaximumSelection = -std::numeric_limits<float>::max();

		Matrix matViewingDataTransformation = GetEnvironment().GetViewingTransformation() * GetEnvironment().GetDataTransformation();
		Matrix matViewingSelectionTransformation = GetEnvironment().GetViewingTransformation() * GetEnvironment().GetSelectionTransformation();

		for (unsigned int k=0;k<8;k++)
		{
			const Vector vecCornerBackground = matViewingDataTransformation  * (*i).GetBounds().GetTranslated((*i).GetPosition()).GetCorner(k);
			const Vector vecCornerGhost = matViewingDataTransformation  * (*j).GetBounds().GetTranslated((*j).GetPosition()).GetCorner(k);
			const Vector vecCornerSelection = matViewingSelectionTransformation  * (*j).GetBounds().GetTranslated((*j).GetPosition()).GetCorner(k);

			fMinimumBackground = std::min(fMinimumBackground,vecCornerBackground.GetZ());
			fMaximumBackground = std::max(fMaximumBackground,vecCornerBackground.GetZ());

			fMinimumGhost = std::min(fMinimumGhost,vecCornerBackground.GetZ());
			fMaximumGhost = std::max(fMaximumGhost,vecCornerBackground.GetZ());

			fMinimumSelection = std::min(fMinimumSelection,vecCornerSelection.GetZ());
			fMaximumSelection = std::max(fMaximumSelection,vecCornerSelection.GetZ());
		}

		fMaximumGhost = std::max(fMaximumBackground,fMaximumGhost);
		fMaximumSelection = std::max(fMaximumGhost,fMaximumSelection);

		if (GetEnvironment().GetQuality() == Environment::QUALITY_LOW)
			glViewport(0,0,256,256);		

		if (!(*i).GetBounds().IsEmpty())
			displaySlicesSelection(fMinimumSelection,fMaximumSelection);

		if (!(*j).GetBounds().IsEmpty())
			displaySlicesGhost(fMinimumGhost,fMaximumGhost);

		displaySlicesBackground(fMinimumBackground,fMaximumBackground);

		if (GetEnvironment().GetQuality() == Environment::QUALITY_LOW)
		{
			glViewport(0,0,m_uWidth,m_uHeight);

			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D,m_uImageColorTexture);
			glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,256,256);

			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();

			glBegin(GL_QUADS);

			glTexCoord2f(0.0f,0.0f);
			glVertex2f(-1.0f,-1.0f);

			glTexCoord2f(1.0f,0.0f);
			glVertex2f(1.0f,-1.0f);

			glTexCoord2f(1.0f,1.0f);
			glVertex2f(1.0f,1.0f);

			glTexCoord2f(0.0f,1.0f);
			glVertex2f(-1.0f,1.0f);

			glEnd();

			glBindTexture(GL_TEXTURE_2D,0);

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();

			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();
		}

		displayGeometryTexture();

		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();

		glMatrixMode(GL_PROJECTION);
		glPopMatrix();

		glPopAttrib();
	};

	virtual void overlay()
	{
	};

	virtual void reshape(const unsigned int uWidth, const unsigned int uHeight)
	{
		GLenum glStatus;

		m_uWidth = uWidth;
		m_uHeight = uHeight;

		//////////////////////////////////////////////////////////////////////////
		glBindTexture(GL_TEXTURE_2D,m_uImageColorTexture);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,256,256,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_2D,0);
		//////////////////////////////////////////////////////////////////////////
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryColorTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGBA,uWidth,uHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		//////////////////////////////////////////////////////////////////////////		
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_DEPTH_COMPONENT,uWidth,uHeight,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		//////////////////////////////////////////////////////////////////////////
		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_uCutoutColorRenderBuffer);
		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_RGBA, uWidth, uHeight);  
		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////		
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGhostCutoutDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_DEPTH_COMPONENT,uWidth,uHeight,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		//////////////////////////////////////////////////////////////////////////
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uSelectionCutoutDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_DEPTH_COMPONENT,uWidth,uHeight,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		//////////////////////////////////////////////////////////////////////////
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uTemporaryDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_DEPTH_COMPONENT,uWidth,uHeight,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,NULL);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		//////////////////////////////////////////////////////////////////////////
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uGeometryFrameBuffer);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_RECTANGLE_ARB, m_uGeometryColorTexture, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_RECTANGLE_ARB, m_uGeometryDepthTexture, 0);

		glStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		if (glStatus  != GL_FRAMEBUFFER_COMPLETE_EXT)
		{
			std::cerr << "Error initializing geometry framebuffer." << std::endl << std::endl;
			throw Exception("Error initializing geometry framebuffer.");
		}

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uGhostCutoutFrameBuffer);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_RENDERBUFFER_EXT, m_uCutoutColorRenderBuffer);  
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_RECTANGLE_ARB, m_uGhostCutoutDepthTexture, 0);

		glStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		if (glStatus  != GL_FRAMEBUFFER_COMPLETE_EXT)
		{
			std::cerr << "Error initializing ghost cutout framebuffer." << std::endl << std::endl;
			throw Exception("Error initializing ghost cutout framebuffer.");
		}

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////				
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uSelectionCutoutFrameBuffer);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_RENDERBUFFER_EXT, m_uCutoutColorRenderBuffer);  
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_RECTANGLE_ARB, m_uSelectionCutoutDepthTexture, 0);

		glStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		if (glStatus  != GL_FRAMEBUFFER_COMPLETE_EXT)
		{
			std::cerr << "Error initializing selection cutout framebuffer." << std::endl << std::endl;
			throw Exception("Error initializing selection cutout framebuffer.");
		}

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////				
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uTemporaryFrameBuffer);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_RENDERBUFFER_EXT, m_uCutoutColorRenderBuffer);  
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_RECTANGLE_ARB, m_uTemporaryDepthTexture, 0);

		glStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		if (glStatus  != GL_FRAMEBUFFER_COMPLETE_EXT)
		{
			std::cerr << "Error initializing temporary framebuffer." << std::endl << std::endl;
			throw Exception("Error initializing temporary framebuffer.");
		}

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////				
	};


	virtual void mousePress(const MouseEvent & mouEvent)
	{
	};

	virtual void mouseRelease(const MouseEvent & mouEvent)
	{	
	};

	virtual void mouseMove(const MouseEvent & mouEvent)
	{
	};

	virtual void keyboardPress(const KeyboardEvent & keyEvent)
	{
	};

	virtual void keyboardRelease(const KeyboardEvent & keyEvent)
	{
	};

protected:

	virtual void displaySlicesBindTextures()
	{
		//////////////////////////////////////////////////////////////////////////		

		const Vector vecTexture(float((GetEnvironment().GetDataVolume().GetBlocksX()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksY()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksZ()*BLOCKDIMENSION)));
		const float vfPlaneX[] = {1.0f / vecTexture.GetX(), 0.0f, 0.0f, 0.5f*(1.0f / vecTexture.GetX())};
		const float vfPlaneY[] = {0.0f, 1.0f / vecTexture.GetY(), 0.0f, 0.5f*(1.0f / vecTexture.GetY())};
		const float vfPlaneZ[] = {0.0f, 0.0f, 1.0f / vecTexture.GetZ(), 0.5f*(1.0f / vecTexture.GetZ())};

		//////////////////////////////////////////////////////////////////////////

		// Set up volume texture
		glActiveTexture(GL_TEXTURE0);
		GetEnvironment().GetDataVolume().bind();
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetDataTransformation().Get());
		glTexGenfv(GL_S,GL_EYE_PLANE,vfPlaneX);
		glTexGenfv(GL_T,GL_EYE_PLANE,vfPlaneY);
		glTexGenfv(GL_R,GL_EYE_PLANE,vfPlaneZ);
		glPopMatrix();

		// Set up selection texture
		glActiveTexture(GL_TEXTURE1);
		//GetEnvironment().GetSelectionVolume().bind(0);
		GetEnvironment().GetSelectionVolume().bind(1);
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetSelectionTransformation().Get());		
		glTexGenfv(GL_S,GL_EYE_PLANE,vfPlaneX);
		glTexGenfv(GL_T,GL_EYE_PLANE,vfPlaneY);
		glTexGenfv(GL_R,GL_EYE_PLANE,vfPlaneZ);
		glPopMatrix();

		// Set up background/selection scalar transfer function texture
		glActiveTexture(GL_TEXTURE2);
		GetEnvironment().GetBackgroundSelectionColorTransferFunction().bind();

		// Set up ghost/selection scalar transfer function texture
		glActiveTexture(GL_TEXTURE3);
		GetEnvironment().GetGhostSelectionColorTransferFunction().bind();

		// Set up background lighting transfer function
		glActiveTexture(GL_TEXTURE4);
		GetEnvironment().GetBackgroundLightingTransferFunction().bind();

		// Set up ghost lighting transfer function
		glActiveTexture(GL_TEXTURE5);
		GetEnvironment().GetGhostLightingTransferFunction().bind();

		// Set up selection lighting transfer function
		glActiveTexture(GL_TEXTURE6);
		GetEnvironment().GetSelectionLightingTransferFunction().bind();

		// Set up geometry depth texture
		glActiveTexture(GL_TEXTURE7);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE); 
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_FUNC,GL_GEQUAL);

		// Set up ghost cutout depth texture
		glActiveTexture(GL_TEXTURE8);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGhostCutoutDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE); 
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);

		// Set up selection cutout depth texture
		glActiveTexture(GL_TEXTURE9);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uSelectionCutoutDepthTexture);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE); 
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);


		//////////////////////////////////////////////////////////////////////////
	};

	virtual void displaySlicesReleaseTextures()
	{
		//////////////////////////////////////////////////////////////////////////

		glActiveTexture(GL_TEXTURE9);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

		glActiveTexture(GL_TEXTURE8);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

		glActiveTexture(GL_TEXTURE7);
		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

		glActiveTexture(GL_TEXTURE6);
		GetEnvironment().GetSelectionLightingTransferFunction().release();

		glActiveTexture(GL_TEXTURE5);
		GetEnvironment().GetGhostLightingTransferFunction().release();

		glActiveTexture(GL_TEXTURE4);
		GetEnvironment().GetBackgroundLightingTransferFunction().release();

		glActiveTexture(GL_TEXTURE3);
		GetEnvironment().GetGhostSelectionColorTransferFunction().release();

		glActiveTexture(GL_TEXTURE2);
		GetEnvironment().GetBackgroundSelectionColorTransferFunction().release();

		glActiveTexture(GL_TEXTURE1);
		GetEnvironment().GetSelectionVolume().release();

		glActiveTexture(GL_TEXTURE0);
		GetEnvironment().GetDataVolume().release();

		//////////////////////////////////////////////////////////////////////////
	};

	virtual void displaySlices(const float fMinimum, const float fMaximum)
	{
		const float fDistance = GetEnvironment().GetViewingTransformation().GetTranslation().GetMagnitude();

		const float fLength = (GetEnvironment().GetViewingTransformation()*Vector(0.0f,0.0f,fDistance)-GetEnvironment().GetViewingTransformation()*Vector(0.0f,0.0f,0.0f)).GetMagnitude();
/*
		glBindBuffer(GL_ARRAY_BUFFER, m_uVertexBuffer);
		glVertexPointer( 3, GL_FLOAT, 0, NULL);
		glEnableClientState(GL_VERTEX_ARRAY);	

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uIndexBuffer);
		glIndexPointer(GL_INT,0,NULL);
		glEnableClientState(GL_INDEX_ARRAY);
*/
		glEnable(GL_BLEND);
//		glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
		glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);

		glPushMatrix();
		glLoadIdentity();
		//glTranslatef(0.0f,0.0f,fMaximum);		

		//const float fDimension = float(std::max(GetEnvironment().GetDataVolume().GetSizeX(),std::max(GetEnvironment().GetDataVolume().GetSizeY(),GetEnvironment().GetDataVolume().GetSizeZ())));
		//const float fDiagonal = 2.0f*fDimension*sqrtf(3.0f);

		const unsigned int uSlices = 512;
		const float fStep = fLength / float (uSlices);

		glBegin(GL_QUADS);

		float fTranslation = fMaximum;

		unsigned int k=0;

		while (fTranslation >= fMinimum)
		{
			fTranslation -= fStep;

			glVertex3f(-1.0f,-1.0f,fTranslation);
			glVertex3f(1.0f,-1.0f,fTranslation);
			glVertex3f(1.0f,1.0f,fTranslation);
			glVertex3f(-1.0f,1.0f,fTranslation);

	
			//glTranslatef(0.0f,0.0f,fTranslation);
//			glDrawElements(GL_QUADS,196,GL_UNSIGNED_INT,NULL);
			//glTranslatef(0.0f,0.0f,-fTranslation);

			k++;
		}		

		glEnd();

		glPopMatrix();

		glDisableClientState( GL_VERTEX_ARRAY );	
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		glDisableClientState(GL_INDEX_ARRAY);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	};

	virtual void displaySlicesBackground(const float fMinimum, const float fMaximum)
	{	
		if (fMinimum >= fMaximum)
			return;

		//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uVolumeFrameBuffer);
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		displayBackgroundBounds();

		glDepthMask(GL_FALSE);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_GREATER);

		// bind textures
		displaySlicesBindTextures();

		m_proBackgroundDisplay.bind();

		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samDataVolume"), 0);
		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samBackgroundSelectionColorTransferFunction"), 2);
		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samBackgroundLightingTransferFunction"), 4);
		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samGeometryDepth"), 7);
		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samGhostCutoutDepth"), 8);
		glUniform1iARB(m_proBackgroundDisplay.GetUniformLocation("samSelectionCutoutDepth"), 9);

		const Vector vecStart(0.0f,0.0f,-1.0f);
		const Vector vecEnd(0.0f,0.0f,1.0f);
		const Matrix matTransformation = (GetEnvironment().GetProjectionTransformation() * (GetEnvironment().GetViewingTransformation() * GetEnvironment().GetDataTransformation())).GetInverse();
		const Matrix matInverseTransformation = matTransformation.GetInverse();
		const Vector vecRayStart = matInverseTransformation * vecStart;
		const Vector vecRayEnd = matInverseTransformation * vecEnd;
		const Vector vecTexture(float((GetEnvironment().GetDataVolume().GetBlocksX()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksY()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksZ()*BLOCKDIMENSION)));
		const Vector vecDirection = (vecRayEnd-vecRayStart).GetNormalized() / (vecTexture*1.0f);
		glUniform3fARB(m_proBackgroundDisplay.GetUniformLocation("vecDirection"), vecDirection.GetX(), vecDirection.GetY(), vecDirection.GetZ());

		if (GetEnvironment().GetQuality() == Environment::QUALITY_LOW)
			glUniform3fARB(m_proBackgroundDisplay.GetUniformLocation("vecScale"), float(m_uWidth)/(256.0f), float(m_uHeight)/(256.0f), 1.0f);
		else
			glUniform3fARB(m_proBackgroundDisplay.GetUniformLocation("vecScale"), 1.0f, 1.0f, 1.0f);

		displaySlices(fMinimum,fMaximum);

		m_proBackgroundDisplay.release();

		// release textures
		displaySlicesReleaseTextures();

		glPopAttrib();
	};

	virtual void displaySlicesGhost(const float fMinimum, const float fMaximum)
	{	
		if (fMinimum >= fMaximum)
			return;

		glPushAttrib(GL_ALL_ATTRIB_BITS);

		displayGhostBounds();

		glDepthMask(GL_FALSE);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);

		// bind textures
		displaySlicesBindTextures();

		m_proGhostDisplay.bind();

		glUniform1fARB(m_proGhostDisplay.GetUniformLocation("fCutoutGhost"), GetEnvironment().IsGhostCutoutEnabled() ? GetEnvironment().GetGhostGhosting() : 0.0f);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samDataVolume"), 0);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samSelectionVolume"), 1);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samBackgroundSelectionColorTransferFunction"), 2);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samGhostSelectionColorTransferFunction"), 3);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samBackgroundLightingTransferFunction"), 4);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samGhostLightingTransferFunction"), 5);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samGeometryDepth"), 7);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samGhostCutoutDepth"), 8);
		glUniform1iARB(m_proGhostDisplay.GetUniformLocation("samSelectionCutoutDepth"), 9);

		const Vector vecStart(0.0f,0.0f,-1.0f);
		const Vector vecEnd(0.0f,0.0f,1.0f);
		const Matrix matTransformation = (GetEnvironment().GetProjectionTransformation() * (GetEnvironment().GetViewingTransformation() * GetEnvironment().GetDataTransformation())).GetInverse();
		const Matrix matInverseTransformation = matTransformation.GetInverse();
		const Vector vecRayStart = matInverseTransformation * vecStart;
		const Vector vecRayEnd = matInverseTransformation * vecEnd;
		const Vector vecTexture(float((GetEnvironment().GetDataVolume().GetBlocksX()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksY()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksZ()*BLOCKDIMENSION)));
		const Vector vecDirection = (vecRayEnd-vecRayStart).GetNormalized() / (vecTexture*1.0f);
		glUniform3fARB(m_proGhostDisplay.GetUniformLocation("vecDirection"), vecDirection.GetX(), vecDirection.GetY(), vecDirection.GetZ());

		if (GetEnvironment().GetQuality() == Environment::QUALITY_LOW)
			glUniform3fARB(m_proGhostDisplay.GetUniformLocation("vecScale"), float(m_uWidth)/(256.0f), float(m_uHeight)/(256.0f), 1.0f);
		else
			glUniform3fARB(m_proGhostDisplay.GetUniformLocation("vecScale"), 1.0f, 1.0f, 1.0f);

		displaySlices(fMinimum,fMaximum);

		m_proGhostDisplay.release();

		// release textures
		displaySlicesReleaseTextures();

		glPopAttrib();
	};

	virtual void displaySlicesSelection(const float fMinimum, const float fMaximum)
	{	
		if (fMinimum >= fMaximum)
			return;

		glPushAttrib(GL_ALL_ATTRIB_BITS);

		displaySelectionBounds();

		glDepthMask(GL_FALSE);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);

		// bind textures
		displaySlicesBindTextures();

		m_proSelectionDisplay.bind();

		glUniform1fARB(m_proSelectionDisplay.GetUniformLocation("fCutoutGhost"), GetEnvironment().IsGhostCutoutEnabled() ? GetEnvironment().GetGhostGhosting() : 0.0f);
		glUniform1fARB(m_proSelectionDisplay.GetUniformLocation("fCutoutSelection"), GetEnvironment().IsSelectionCutoutEnabled() ? GetEnvironment().GetSelectionGhosting() : 0.0f);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samDataVolume"), 0);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samSelectionVolume"), 1);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samBackgroundSelectionColorTransferFunction"), 2);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samGhostSelectionColorTransferFunction"), 3);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samBackgroundLightingTransferFunction"), 4);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samGhostLightingTransferFunction"), 5);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samSelectionLightingTransferFunction"), 6);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samGeometryDepth"), 7);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samGhostCutoutDepth"), 8);
		glUniform1iARB(m_proSelectionDisplay.GetUniformLocation("samSelectionCutoutDepth"), 9);

		const Vector vecStart(0.0f,0.0f,-1.0f);
		const Vector vecEnd(0.0f,0.0f,1.0f);
		const Matrix matTransformation = GetEnvironment().GetProjectionTransformation() * (GetEnvironment().GetViewingTransformation() * GetEnvironment().GetDataTransformation());
		const Matrix matInverseTransformation = matTransformation.GetInverse();
		const Vector vecRayStart = matInverseTransformation * vecStart;
		const Vector vecRayEnd = matInverseTransformation * vecEnd;
		const Vector vecTexture(float((GetEnvironment().GetDataVolume().GetBlocksX()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksY()*BLOCKDIMENSION)),float((GetEnvironment().GetDataVolume().GetBlocksZ()*BLOCKDIMENSION)));
		const Vector vecDirection = (vecRayEnd-vecRayStart).GetNormalized() / (vecTexture*1.0f);
		glUniform3fARB(m_proSelectionDisplay.GetUniformLocation("vecDirection"), vecDirection.GetX(), vecDirection.GetY(), vecDirection.GetZ());

		if (GetEnvironment().GetQuality() == Environment::QUALITY_LOW)
			glUniform3fARB(m_proSelectionDisplay.GetUniformLocation("vecScale"), float(m_uWidth)/(256.0f), float(m_uHeight)/(256.0f), 1.0f);
		else
			glUniform3fARB(m_proSelectionDisplay.GetUniformLocation("vecScale"), 1.0f, 1.0f, 1.0f);

		displaySlices(fMinimum,fMaximum);

		m_proSelectionDisplay.release();

		// release textures
		displaySlicesReleaseTextures();

		glPopAttrib();
	};


	virtual void displayBackgroundBounds()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Draw bounding geometry
		//////////////////////////////////////////////////////////////////////////		
		glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
		glDepthMask(GL_TRUE);

		glClearDepth(1.0f);		
		glClear(GL_DEPTH_BUFFER_BIT);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LESS);

		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetDataTransformation().Get());
		Volume<DataVoxel>::Octree::Iterator iter(GetEnvironment().GetDataVolume().GetOctree());
		displayBackgroundBounds(iter);
		glPopMatrix();
		//////////////////////////////////////////////////////////////////////////

		glPopAttrib();
	};

	void displayBackgroundBounds(const Volume<DataVoxel>::Octree::Iterator & iter)
	{
		if (GetEnvironment().GetBackgroundSelectionColorTransferFunction().IsVisble(0,(*iter).GetMinimum().GetValue(),(*iter).GetMaximum().GetValue()))
		{
			if (iter.IsLeaf())
			{
				const Vector & vecPosition((*iter).GetPosition());
				glTranslatef(vecPosition.GetX(),vecPosition.GetY(),vecPosition.GetZ());
				displayBlock();
				glTranslatef(-vecPosition.GetX(),-vecPosition.GetY(),-vecPosition.GetZ());
			}
			else
			{
				for (unsigned int i=0;i<8;i++)
					displayBackgroundBounds(iter[i]);
			}
		}
	};

	virtual void displayGhostBounds()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Draw bounding geometry
		//////////////////////////////////////////////////////////////////////////		
		glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
		glDepthMask(GL_TRUE);

		glClearDepth(0.0f);		
		glClear(GL_DEPTH_BUFFER_BIT);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_GREATER);

		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetDataTransformation().Get());
		Volume<SelectionVoxel>::Octree::Iterator iter(GetEnvironment().GetSelectionVolume().GetOctree());

		if (GetEnvironment().IsGhostCutoutEnabled())
			displayGhostSpheres(iter);
		else
			displayGhostBounds(iter);

		glPopMatrix();
		//////////////////////////////////////////////////////////////////////////

		glPopAttrib();
	};

	void displayGhostBounds(const Volume<SelectionVoxel>::Octree::Iterator & iter)
	{
		if (!(*iter).GetBounds().IsEmpty())
		{
			if (iter.IsLeaf())
			{
				const Vector & vecPosition((*iter).GetPosition());
				glTranslatef(vecPosition.GetX(),vecPosition.GetY(),vecPosition.GetZ());
				displayBlock();
				glTranslatef(-vecPosition.GetX(),-vecPosition.GetY(),-vecPosition.GetZ());
			}
			else
			{
				for (unsigned int i=0;i<8;i++)
					displayGhostBounds(iter[i]);
			}
		}
	};

	void displayGhostSpheres(const Volume<SelectionVoxel>::Octree::Iterator & iter)
	{
		if (!(*iter).GetBounds().IsEmpty())
		{
			if (iter.IsLeaf())
			{
				const Vector vecPosition((*iter).GetPosition()+(*iter).GetBounds().GetCenter());
				const float fScale = sqrtf(2.0f)*2.0f*(*iter).GetBounds().GetRadius();

				glPushMatrix();
				glTranslatef(vecPosition.GetX(),vecPosition.GetY(),vecPosition.GetZ());
				glScalef(fScale,fScale,fScale);
				displayIcosahedreon();
				glPopMatrix();
			}
			else
			{
				for (unsigned int i=0;i<8;i++)
					displayGhostSpheres(iter[i]);
			}
		}
	};

	virtual void displaySelectionBounds()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Draw bounding geometry
		//////////////////////////////////////////////////////////////////////////		
		glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
		glDepthMask(GL_TRUE);

		glClearDepth(0.0f);		
		glClear(GL_DEPTH_BUFFER_BIT);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_GREATER);

		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetSelectionTransformation().Get());
		Volume<SelectionVoxel>::Octree::Iterator iter(GetEnvironment().GetSelectionVolume().GetOctree());

		if (GetEnvironment().IsSelectionCutoutEnabled())
			displaySelectionSpheres(iter);
		else
			displaySelectionBounds(iter);

		glPopMatrix();
		//////////////////////////////////////////////////////////////////////////		

		glPopAttrib();
	};

	void displaySelectionBounds(const Volume<SelectionVoxel>::Octree::Iterator & iter)
	{
		if ((*iter).GetMaximum().Get() > 0.0f)
		{
			if (iter.IsLeaf())
			{
				if (!(*iter).GetBounds().IsEmpty())
				{
					const Vector & vecPosition((*iter).GetPosition());
					glTranslatef(vecPosition.GetX(),vecPosition.GetY(),vecPosition.GetZ());
					displayBlock();
					glTranslatef(-vecPosition.GetX(),-vecPosition.GetY(),-vecPosition.GetZ());
				}
			}
			else
			{
				for (unsigned int i=0;i<8;i++)
					displaySelectionBounds(iter[i]);
			}
		}
	};

	void displaySelectionSpheres(const Volume<SelectionVoxel>::Octree::Iterator & iter)
	{
		if ((*iter).GetMaximum().Get() > 0.0f)
		{
			if (iter.IsLeaf())
			{
				if (!(*iter).GetBounds().IsEmpty())
				{
					const Vector vecPosition((*iter).GetPosition()+(*iter).GetBounds().GetCenter());
					const float fScale = sqrtf(2.0f)*2.0f*(*iter).GetBounds().GetRadius();

					glPushMatrix();
					glTranslatef(vecPosition.GetX(),vecPosition.GetY(),vecPosition.GetZ());
					glScalef(fScale,fScale,fScale);
					displayIcosahedreon();
					glPopMatrix();
				}
			}
			else
			{
				for (unsigned int i=0;i<8;i++)
					displaySelectionSpheres(iter[i]);
			}
		}
	};

	virtual void displayGeometryTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Display geometry texture
		//////////////////////////////////////////////////////////////////////////		
		glDepthMask(GL_FALSE);
		glDepthFunc(GL_ALWAYS);

		glEnable(GL_BLEND);
//		glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
		glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);


		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glLoadIdentity();
		glEnable(GL_TEXTURE_RECTANGLE_ARB);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryColorTexture);
		glBegin(GL_QUADS);
		glTexCoord2i(0,0);
		glVertex2f(-1.0f,-1.0f);
		glTexCoord2i(m_uWidth,0);
		glVertex2f(1.0f,-1.0f);
		glTexCoord2i(m_uWidth,m_uHeight);
		glVertex2f(1.0f,1.0f);
		glTexCoord2i(0,m_uHeight);
		glVertex2f(-1.0f,1.0f);
		glEnd();
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
		//////////////////////////////////////////////////////////////////////////

		glPopAttrib();
	};

	virtual void generateGeometryTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryColorTexture);
		glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGBA,0,0,m_uWidth,m_uHeight,0);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGeometryDepthTexture);
		glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_DEPTH_COMPONENT,0,0,m_uWidth,m_uHeight,0);
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glPopAttrib();
	};

	virtual void generateGhostStandardCutoutTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Make cutout depth texture
		//////////////////////////////////////////////////////////////////////////
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uGhostCutoutFrameBuffer);
		{
			glDepthMask(GL_TRUE);

			glClearColor(0.0,0.0,0.0,0.0);
			glClearDepth(0.0f);

			glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_GREATER);
			

			glPushMatrix();
			glMultMatrixf(GetEnvironment().GetDataTransformation().Get());		
			Volume<SelectionVoxel>::Octree::Iterator iter(GetEnvironment().GetSelectionVolume().GetOctree());

			if (GetEnvironment().IsGhostCutoutEnabled())
				displayGhostSpheres(iter);
			else
				displayGhostBounds(iter);

			glPopMatrix();

			glClearColor(1.0,1.0,1.0,0.0);
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////

		glPopAttrib();
	};

	virtual void generateSelectionStandardCutoutTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		//////////////////////////////////////////////////////////////////////////
		// Make cutout depth texture
		//////////////////////////////////////////////////////////////////////////
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uSelectionCutoutFrameBuffer);
		{
			glDepthMask(GL_TRUE);

			glClearColor(0.0,0.0,0.0,0.0);
			glClearDepth(0.0f);

			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_GREATER);

			glPushMatrix();
			glMultMatrixf(GetEnvironment().GetSelectionTransformation().Get());		
			Volume<SelectionVoxel>::Octree::Iterator iter(GetEnvironment().GetSelectionVolume().GetOctree());

			if (GetEnvironment().IsSelectionCutoutEnabled())
				displaySelectionSpheres(iter);
			else
				displaySelectionBounds(iter);

			glPopMatrix();

			glClearColor(1.0,1.0,1.0,0.0);
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		//////////////////////////////////////////////////////////////////////////

		glPopAttrib();
	};

	virtual void generateGhostSmoothCutoutTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		Volume<DataVoxel>::Octree::Iterator iterDataVolume(GetEnvironment().GetDataVolume().GetOctree());
		const Matrix matTransformation = (GetEnvironment().GetProjectionTransformation() * (GetEnvironment().GetViewingTransformation()*GetEnvironment().GetDataTransformation()));
		const Box boxBlock = Box(Vector(0.0f,0.0f,0.0f),Vector(float(BLOCKDIMENSION),float(BLOCKDIMENSION),float(BLOCKDIMENSION)));//(*iterDataVolume).GetBounds().GetTranslated((*iterDataVolume).GetPosition());
	
		Vector vecMinimum( std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
		Vector vecMaximum(-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max());

		
		for (unsigned int i=0;i<8;i++)
		{
			const Vector vecCorner = matTransformation * boxBlock.GetCorner(i);
			
			vecMinimum.SetX(std::min(vecCorner.GetX(),vecMinimum.GetX()));
			vecMinimum.SetY(std::min(vecCorner.GetY(),vecMinimum.GetY()));
			vecMinimum.SetZ(std::min(vecCorner.GetZ(),vecMinimum.GetZ()));

			vecMaximum.SetX(std::max(vecCorner.GetX(),vecMaximum.GetX()));
			vecMaximum.SetY(std::max(vecCorner.GetY(),vecMaximum.GetY()));
			vecMaximum.SetZ(std::max(vecCorner.GetZ(),vecMaximum.GetZ()));
		}

		const Box boxTransformed(vecMinimum,vecMaximum);
		const float fRadius = 0.33f*boxTransformed.GetRadius()*float(std::max(m_uWidth,m_uHeight));
		const int iRadius = int(fRadius);

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uTemporaryFrameBuffer);
		{
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();

			glDepthMask(GL_TRUE);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_ALWAYS);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uGhostCutoutDepthTexture);
			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 

			m_proCutoutGenerationPass1.bind();
			glUniform1iARB(m_proCutoutGenerationPass1.GetUniformLocation("samTexture"), 0);
			glUniform1iARB(m_proCutoutGenerationPass1.GetUniformLocation("iRadius"), iRadius);

			glBegin(GL_QUADS);

			glTexCoord2i(0,0);
			glVertex2f(-1.0f,-1.0f);

			glTexCoord2i(m_uWidth,0);
			glVertex2f(1.0f,-1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(1.0f,1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(-1.0f,1.0f);

			glEnd();

			m_proCutoutGenerationPass1.release();

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uGhostCutoutFrameBuffer);
		{
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();

			glDepthMask(GL_TRUE);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_ALWAYS);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uTemporaryDepthTexture);
			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 

			m_proCutoutGenerationPass2.bind();
			glUniform1iARB(m_proCutoutGenerationPass2.GetUniformLocation("samTexture"), 0);
			glUniform1iARB(m_proCutoutGenerationPass2.GetUniformLocation("iRadius"), iRadius);

			glBegin(GL_QUADS);

			glTexCoord2i(0,0);
			glVertex2f(-1.0f,-1.0f);

			glTexCoord2i(m_uWidth,0);
			glVertex2f(1.0f,-1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(1.0f,1.0f);

			glTexCoord2i(0.0f,m_uHeight);
			glVertex2f(-1.0f,1.0f);

			glEnd();

			m_proCutoutGenerationPass2.release();

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

		glPopAttrib();
	};

	virtual void generateSelectionSmoothCutoutTexture()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		Volume<DataVoxel>::Octree::Iterator iterDataVolume(GetEnvironment().GetDataVolume().GetOctree());
		const Matrix matTransformation = (GetEnvironment().GetProjectionTransformation() * (GetEnvironment().GetViewingTransformation()*GetEnvironment().GetDataTransformation()));
		const Box boxBlock = Box(Vector(0.0f,0.0f,0.0f),Vector(float(BLOCKDIMENSION),float(BLOCKDIMENSION),float(BLOCKDIMENSION)));//(*iterDataVolume).GetBounds().GetTranslated((*iterDataVolume).GetPosition());

		Vector vecMinimum( std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
		Vector vecMaximum(-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max());


		for (unsigned int i=0;i<8;i++)
		{
			const Vector vecCorner = matTransformation * boxBlock.GetCorner(i);

			vecMinimum.SetX(std::min(vecCorner.GetX(),vecMinimum.GetX()));
			vecMinimum.SetY(std::min(vecCorner.GetY(),vecMinimum.GetY()));
			vecMinimum.SetZ(std::min(vecCorner.GetZ(),vecMinimum.GetZ()));

			vecMaximum.SetX(std::max(vecCorner.GetX(),vecMaximum.GetX()));
			vecMaximum.SetY(std::max(vecCorner.GetY(),vecMaximum.GetY()));
			vecMaximum.SetZ(std::max(vecCorner.GetZ(),vecMaximum.GetZ()));
		}

		const Box boxTransformed(vecMinimum,vecMaximum);
		const float fRadius = 0.33f*boxTransformed.GetRadius()*float(std::max(m_uWidth,m_uHeight));
		const int iRadius = int(fRadius);

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uTemporaryFrameBuffer);
		{
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();

			glDepthMask(GL_TRUE);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_ALWAYS);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uSelectionCutoutDepthTexture);
			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 

			m_proCutoutGenerationPass1.bind();
			glUniform1iARB(m_proCutoutGenerationPass1.GetUniformLocation("samTexture"), 0);
			glUniform1iARB(m_proCutoutGenerationPass1.GetUniformLocation("iRadius"), iRadius);

			glBegin(GL_QUADS);

			glTexCoord2i(0,0);
			glVertex2f(-1.0f,-1.0f);

			glTexCoord2i(m_uWidth,0);
			glVertex2f(1.0f,-1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(1.0f,1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(-1.0f,1.0f);

			glEnd();

			m_proCutoutGenerationPass1.release();

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_uSelectionCutoutFrameBuffer);
		{
			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			glLoadIdentity();

			glDepthMask(GL_TRUE);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_ALWAYS);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,m_uTemporaryDepthTexture);
			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_COMPARE_MODE,GL_NONE); 

			m_proCutoutGenerationPass2.bind();
			glUniform1iARB(m_proCutoutGenerationPass2.GetUniformLocation("samTexture"), 0);
			glUniform1iARB(m_proCutoutGenerationPass2.GetUniformLocation("iRadius"), iRadius);

			glBegin(GL_QUADS);

			glTexCoord2i(0,0);
			glVertex2f(-1.0f,-1.0f);

			glTexCoord2i(m_uWidth,0);
			glVertex2f(1.0f,-1.0f);

			glTexCoord2i(m_uWidth,m_uHeight);
			glVertex2f(1.0f,1.0f);

			glTexCoord2i(0.0f,m_uHeight);
			glVertex2f(-1.0f,1.0f);

			glEnd();

			m_proCutoutGenerationPass2.release();

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_RECTANGLE_ARB,0);

			glMatrixMode(GL_MODELVIEW);
			glPopMatrix();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
		}
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

		glPopAttrib();
	};

	virtual void displayIcosahedreon()
	{
		static const float fX = 0.525731112119133606f;
		static const float fZ = 0.850650808352039932f;

		static const float vfData[12][3] =
		{
			{-fX, 0.0, fZ}, {fX, 0.0, fZ}, {-fX, 0.0, -fZ}, {fX, 0.0, -fZ},
			{0.0, fZ, fX}, {0.0, fZ, -fX}, {0.0, -fZ, fX}, {0.0, -fZ, -fX},
			{fZ, fX, 0.0}, {-fZ, fX, 0.0}, {fZ, -fX, 0.0}, {-fZ, -fX, 0.0}
		};

		static const unsigned int vuIndices[20][3] =
		{
			{1, 4, 0}, {4, 9, 0}, {4, 5, 9}, {8, 5, 4}, {1, 8, 4},
			{1, 10, 8}, {10, 3, 8}, {8, 3, 5}, {3, 2, 5}, {3, 7, 2},
			{3, 10, 7}, {10, 6, 7}, {6, 11, 7}, {6, 0, 11}, {6, 1, 0},
			{10, 1, 6}, {11, 0, 9}, {2, 11, 9}, {5, 2, 9}, {11, 2, 7}
		};

		glBegin(GL_TRIANGLES);

		for (unsigned int i = 0; i < 20; i++)
		{
			glNormal3fv(&vfData[vuIndices[i][0]][0]);
			glVertex3fv(&vfData[vuIndices[i][0]][0]);
			
			glNormal3fv(&vfData[vuIndices[i][1]][0]);
			glVertex3fv(&vfData[vuIndices[i][1]][0]);
				
			glNormal3fv(&vfData[vuIndices[i][2]][0]);
			glVertex3fv(&vfData[vuIndices[i][2]][0]);

		}

		glEnd();
	};

	virtual void displayBlock(const Box & boxBounds)
	{
		if (boxBounds.IsEmpty())
			return;

		const float fStartX = boxBounds.GetMinimum().GetX();
		const float fStartY = boxBounds.GetMinimum().GetY();
		const float fStartZ = boxBounds.GetMinimum().GetZ();

		const float fEndX = boxBounds.GetMaximum().GetX();
		const float fEndY = boxBounds.GetMaximum().GetY();
		const float fEndZ = boxBounds.GetMaximum().GetZ();

		const float vfCube[2][4][3] =
		{
			// Left
			{
				{ fStartX,fEndY,fEndZ }, 
				{ fStartX,fEndY,fStartZ }, 
				{ fStartX,fStartY,fStartZ }, 
				{ fStartX,fStartY,fEndZ }, 
			},

			// Right
			{
				{ fEndX,fEndY,fStartZ }, 
				{ fEndX,fEndY,fEndZ }, 
				{ fEndX,fStartY,fEndZ }, 
				{ fEndX,fStartY,fStartZ }, 
			},
		};

		const float vfCubeStrips[10][3] =
		{
			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 

			{ fStartX,fEndY,fStartZ }, 
			{ fEndX,fEndY,fStartZ }, 

			{ fStartX,fStartY,fStartZ }, 
			{ fEndX,fStartY,fStartZ }, 

			{ fStartX,fStartY,fEndZ}, 
			{ fEndX,fStartY,fEndZ}, 

			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 
		};

		glBegin(GL_QUADS);

		glVertex3fv(vfCube[0][0]);
		glVertex3fv(vfCube[0][1]);
		glVertex3fv(vfCube[0][2]);
		glVertex3fv(vfCube[0][3]);

		glVertex3fv(vfCube[1][0]);
		glVertex3fv(vfCube[1][1]);
		glVertex3fv(vfCube[1][2]);
		glVertex3fv(vfCube[1][3]);

		glEnd();

		glBegin(GL_QUAD_STRIP);

		glVertex3fv(vfCubeStrips[0]);
		glVertex3fv(vfCubeStrips[1]);
		glVertex3fv(vfCubeStrips[2]);
		glVertex3fv(vfCubeStrips[3]);
		glVertex3fv(vfCubeStrips[4]);
		glVertex3fv(vfCubeStrips[5]);
		glVertex3fv(vfCubeStrips[6]);
		glVertex3fv(vfCubeStrips[7]);
		glVertex3fv(vfCubeStrips[8]);
		glVertex3fv(vfCubeStrips[9]);

		glEnd();
	};

	virtual void displayBlock() const
	{
		const float fSizeX = float(BLOCKDIMENSION);
		const float fSizeY = float(BLOCKDIMENSION);
		const float fSizeZ = float(BLOCKDIMENSION);

		const float fStartX = -fSizeX*0.5f;
		const float fStartY = -fSizeY*0.5f;
		const float fStartZ = -fSizeZ*0.5f;

		const float fEndX = fStartX + fSizeX;
		const float fEndY = fStartY + fSizeY;
		const float fEndZ = fStartZ + fSizeZ;

		const float vfCube[2][4][3] =
		{
			// Left
			{
				{ fStartX,fEndY,fEndZ }, 
				{ fStartX,fEndY,fStartZ }, 
				{ fStartX,fStartY,fStartZ }, 
				{ fStartX,fStartY,fEndZ }, 
			},

			// Right
			{
				{ fEndX,fEndY,fStartZ }, 
				{ fEndX,fEndY,fEndZ }, 
				{ fEndX,fStartY,fEndZ }, 
				{ fEndX,fStartY,fStartZ }, 
			},
		};

		const float vfCubeStrips[10][3] =
		{
			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 

			{ fStartX,fEndY,fStartZ }, 
			{ fEndX,fEndY,fStartZ }, 

			{ fStartX,fStartY,fStartZ }, 
			{ fEndX,fStartY,fStartZ }, 

			{ fStartX,fStartY,fEndZ}, 
			{ fEndX,fStartY,fEndZ}, 

			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 
		};

		glBegin(GL_QUADS);

		glVertex3fv(vfCube[0][0]);
		glVertex3fv(vfCube[0][1]);
		glVertex3fv(vfCube[0][2]);
		glVertex3fv(vfCube[0][3]);

		glVertex3fv(vfCube[1][0]);
		glVertex3fv(vfCube[1][1]);
		glVertex3fv(vfCube[1][2]);
		glVertex3fv(vfCube[1][3]);

		glEnd();

		glBegin(GL_QUAD_STRIP);

		glVertex3fv(vfCubeStrips[0]);
		glVertex3fv(vfCubeStrips[1]);
		glVertex3fv(vfCubeStrips[2]);
		glVertex3fv(vfCubeStrips[3]);
		glVertex3fv(vfCubeStrips[4]);
		glVertex3fv(vfCubeStrips[5]);
		glVertex3fv(vfCubeStrips[6]);
		glVertex3fv(vfCubeStrips[7]);
		glVertex3fv(vfCubeStrips[8]);
		glVertex3fv(vfCubeStrips[9]);

		glEnd();
	};

private:
	
	Environment & m_envEnvironment;
	unsigned int m_uWidth;
	unsigned int m_uHeight;

	/*
	unsigned int m_uVertexBuffer;
	unsigned int m_uIndexBuffer;
	*/

	unsigned int m_uGeometryFrameBuffer;
	unsigned int m_uGhostCutoutFrameBuffer;
	unsigned int m_uSelectionCutoutFrameBuffer;
	unsigned int m_uTemporaryFrameBuffer;

	unsigned int m_uGeometryColorTexture;
	unsigned int m_uGeometryDepthTexture;

	unsigned int m_uTemporaryDepthTexture;

	unsigned int m_uImageColorTexture;
	unsigned int m_uGhostCutoutDepthTexture;
	unsigned int m_uSelectionCutoutDepthTexture;
	unsigned int m_uCutoutColorRenderBuffer;

	Program m_proBackgroundDisplay;
	Program m_proGhostDisplay;
	Program m_proSelectionDisplay;
	Program m_proCutoutGenerationPass1;
	Program m_proCutoutGenerationPass2;
};