#pragma once

#include "volumeshop.h"

#include "Matrix.h"
#include "Volume.h"
#include "DataVoxel.h"
#include "SelectionVoxel.h"
#include "ColorTransferFunction.h"
#include "LightingTransferFunction.h"
#include "Element.h"
#include "Attribute.h"

#include <set>
#include <stdio.h>
#include <stdarg.h>
#include <sstream>
#include <iostream>
#include <vector>

class Viewer;

class Environment
{

public:

	enum Quality
	{
		QUALITY_LOW,
		QUALITY_HIGH,
	};


	Environment();
	~Environment();

	void add(Viewer *pViewer);
	void remove(Viewer *pViewer);
	void update();
	void update(const float fX1, const float fY1, const float fX2, const float fY2);

	void SetViewingPreTransformation(const Matrix & matViewingPreTransformation)
	{
		m_matViewingPreTransformation = matViewingPreTransformation;
	};

	const Matrix & GetViewingPreTransformation() const
	{
		return m_matViewingPreTransformation;
	};

	void SetProjectionPreTransformation(const Matrix & matProjectionPreTransformation)
	{
		m_matProjectionPreTransformation = matProjectionPreTransformation;
	};

	const Matrix & GetProjectionPreTransformation() const
	{
		return m_matProjectionPreTransformation;
	};

	void SetViewingUserTransformation(const Matrix & matViewingUserTransformation)
	{
		m_matViewingUserTransformation = matViewingUserTransformation;
	};

	const Matrix & GetViewingUserTransformation() const
	{
		return m_matViewingUserTransformation;
	};

	void SetProjectionUserTransformation(const Matrix & matProjectionUserTransformation)
	{
		m_matProjectionUserTransformation = matProjectionUserTransformation;
	};

	const Matrix & GetProjectionUserTransformation() const
	{
		return m_matProjectionUserTransformation;
	};

	void SetViewingPostTransformation(const Matrix & matViewingPostTransformation)
	{
		m_matViewingPostTransformation = matViewingPostTransformation;
	};

	const Matrix & GetViewingPostTransformation() const
	{
		return m_matViewingPostTransformation;
	};

	void SetProjectionPostTransformation(const Matrix & matProjectionPostTransformation)
	{
		m_matProjectionPostTransformation = matProjectionPostTransformation;
	};

	const Matrix & GetProjectionPostTransformation() const
	{
		return m_matProjectionPostTransformation;
	};

	const Matrix GetViewingTransformation() const
	{
		return (m_matViewingPreTransformation * m_matViewingUserTransformation) * m_matViewingPostTransformation;
	};

	const Matrix GetProjectionTransformation() const
	{
		return (m_matProjectionPreTransformation * m_matProjectionUserTransformation) * m_matProjectionPostTransformation;
	};

	void SetVolumePreTransformation(const Matrix & matVolumePreTransformation)
	{
		m_matVolumePreTransformation = matVolumePreTransformation;
	};

	const Matrix & GetVolumePreTransformation() const
	{
		return m_matVolumePreTransformation;
	};

	void SetVolumePostTransformation(const Matrix & matVolumePostTransformation)
	{
		m_matVolumePostTransformation = matVolumePostTransformation;
	};

	const Matrix & GetVolumePostTransformation() const
	{
		return m_matVolumePostTransformation;
	};

	void resize(const unsigned int uSizeX, const unsigned int uSizeY, const unsigned int uSizeZ)
	{
		GetDataVolume().resize(uSizeX,uSizeY,uSizeZ);
		GetSelectionVolume().resize(uSizeX,uSizeY,uSizeZ);
	};

	const Volume<DataVoxel> & GetDataVolume() const
	{
		return m_vecDataVolumes[m_uActiveData];
	};

	const Volume<DataVoxel> & GetDataVolume(const unsigned int uIndex) const
	{
		return m_vecDataVolumes[uIndex];
	};

	const Volume<SelectionVoxel> & GetSelectionVolume() const
	{
		return m_vecSelectionVolumes[m_uActiveSelection];
	};

	const Volume<SelectionVoxel> & GetSelectionVolume(const unsigned int uIndex) const
	{
		return m_vecSelectionVolumes[uIndex];
	};

	Volume<DataVoxel> & GetDataVolume()
	{
		return m_vecDataVolumes[m_uActiveData];
	};

	Volume<DataVoxel> & GetDataVolume(const unsigned int uIndex)
	{
		return m_vecDataVolumes[uIndex];
	};

	Volume<SelectionVoxel> & GetSelectionVolume()
	{
		return m_vecSelectionVolumes[m_uActiveSelection];
	};

	Volume<SelectionVoxel> & GetSelectionVolume(const unsigned int uIndex)
	{
		return m_vecSelectionVolumes[uIndex];
	};

	void SetDataLabel(const std::string & strLabel)
	{
		m_vecDataLabels[m_uActiveData] = strLabel;
	};

	void SetDataLabel(const unsigned int uIndex, const std::string & strLabel)
	{
		m_vecDataLabels[uIndex] = strLabel;
	};

	const std::string & GetDataLabel() const
	{
		return m_vecDataLabels[m_uActiveData];
	};

	const std::string & GetDataLabel(const unsigned int uIndex) const
	{
		return m_vecDataLabels[uIndex];
	};

	void SetSelectionLabel(const std::string & strLabel)
	{
		m_vecSelectionLabels[m_uActiveSelection] = strLabel;
	};

	void SetSelectionLabel(const unsigned int uIndex, const std::string & strLabel)
	{
		m_vecSelectionLabels[uIndex] = strLabel;
	};

	const std::string & GetSelectionLabel() const
	{
		return m_vecSelectionLabels[m_uActiveSelection];
	};

	const std::string & GetSelectionLabel(const unsigned int uIndex) const
	{
		return m_vecSelectionLabels[uIndex];
	};

	void SetDataUserTransformation(const Matrix & matDataUserTransformation)
	{
		m_vecDataUserTransformations[m_uActiveData] = matDataUserTransformation;
	};

	void SetDataUserTransformation(const unsigned int uIndex, const Matrix & matDataUserTransformation)
	{
		m_vecDataUserTransformations[uIndex] = matDataUserTransformation;
	};

	const Matrix & GetDataUserTransformation() const
	{
		return m_vecDataUserTransformations[m_uActiveData];
	};

	const Matrix & GetDataUserTransformation(const unsigned int uIndex) const
	{
		return m_vecDataUserTransformations[uIndex];
	};

	void SetSelectionUserTransformation(const Matrix & matSelectionUserTransformation)
	{
		m_vecSelectionUserTransformations[m_uActiveSelection] = matSelectionUserTransformation;
	};

	void SetSelectionUserTransformation(const unsigned int uIndex, const Matrix & matSelectionUserTransformation)
	{
		m_vecSelectionUserTransformations[uIndex] = matSelectionUserTransformation;
	};

	const Matrix & GetSelectionUserTransformation() const
	{
		return m_vecSelectionUserTransformations[m_uActiveSelection];
	};

	const Matrix & GetSelectionUserTransformation(const unsigned int uIndex) const
	{
		return m_vecSelectionUserTransformations[uIndex];
	};

	const Matrix GetDataTransformation() const
	{
		return GetDataTransformation(GetActiveData());
	};

	const Matrix GetDataTransformation(const unsigned int uIndex) const
	{
		const Vector vecVolume(float(GetDataVolume().GetSizeX()),float(GetDataVolume().GetSizeY()),float(GetDataVolume().GetSizeZ()));
		const float fMaximumVolume = std::max(vecVolume.GetX(),std::max(vecVolume.GetY(),vecVolume.GetZ()));

		Matrix matVolumeTransformation;
		matVolumeTransformation.scale(Vector(1.0f / fMaximumVolume,1.0f / fMaximumVolume,1.0f / fMaximumVolume));
		matVolumeTransformation.scale(GetDataVolume().GetScale());
		matVolumeTransformation.translate(-vecVolume*0.5);

		return ((m_matVolumePreTransformation * m_vecDataUserTransformations[uIndex]) * m_matVolumePostTransformation) * matVolumeTransformation;
	};

	const Matrix GetSelectionTransformation() const
	{
		if (IsSelectionPinEnabled())
		{
			const Matrix matTransformation = (GetProjectionTransformation() * (GetViewingTransformation()*GetSelectionTransformation(GetActiveSelection()))).GetInverse();
			const Vector vecTransformedPinPosition = matTransformation * m_vecSelectionPinPosition;

			Volume<SelectionVoxel>::Octree::Iterator iterSelectionVolume(GetSelectionVolume().GetOctree());
			const Vector vecCenter = (*iterSelectionVolume).GetBounds().GetTranslated((*iterSelectionVolume).GetPosition()).GetCenter();

			return GetSelectionTransformation(GetActiveSelection()).GetTranslated(vecTransformedPinPosition-vecCenter);
		}

		return GetSelectionTransformation(GetActiveSelection());
	};

	const Matrix GetSelectionTransformation(const unsigned int uIndex) const
	{
		const Vector vecVolume(float(GetSelectionVolume().GetSizeX()),float(GetSelectionVolume().GetSizeY()),float(GetSelectionVolume().GetSizeZ()));
		const float fMaximumVolume = std::max(vecVolume.GetX(),std::max(vecVolume.GetY(),vecVolume.GetZ()));

		Matrix matVolumeTransformation;
		matVolumeTransformation.scale(Vector(1.0f / fMaximumVolume,1.0f / fMaximumVolume,1.0f / fMaximumVolume));
		matVolumeTransformation.scale(GetSelectionVolume().GetScale());
		matVolumeTransformation.translate(-vecVolume*0.5);

		//return ((m_matVolumePreTransformation * m_vecSelectionUserTransformations[uIndex]) * m_matVolumePostTransformation) * matVolumeTransformation;
		//return GetDataTransformation(uIndex) * m_vecSelectionUserTransformations[uIndex];
		return ((m_matVolumePreTransformation * m_vecSelectionUserTransformations[uIndex]) * m_matVolumePostTransformation) * matVolumeTransformation;
	};

	ColorTransferFunction & GetBackgroundSelectionColorTransferFunction()
	{
		return m_colBackgroundSelectionColorTransferFunction;
	};

	ColorTransferFunction & GetGhostSelectionColorTransferFunction()
	{
		return m_colGhostSelectionColorTransferFunction;
	};

	const ColorTransferFunction & GetBackgroundSelectionColorTransferFunction() const
	{
		return m_colBackgroundSelectionColorTransferFunction;
	};

	const ColorTransferFunction & GetGhostSelectionColorTransferFunction() const
	{
		return m_colGhostSelectionColorTransferFunction;
	};

	LightingTransferFunction & GetBackgroundLightingTransferFunction()
	{
		return m_ligBackgroundLightingTransferFunction;
	};

	LightingTransferFunction & GetGhostLightingTransferFunction()
	{
		return m_ligGhostLightingTransferFunction;
	};

	LightingTransferFunction & GetSelectionLightingTransferFunction()
	{
		return m_ligSelectionLightingTransferFunction;
	};

	const LightingTransferFunction & GetBackgroundLightingTransferFunction() const 
	{
		return m_ligBackgroundLightingTransferFunction;
	};

	const LightingTransferFunction & GetGhostLightingTransferFunction() const 
	{
		return m_ligGhostLightingTransferFunction;
	};

	const LightingTransferFunction & GetSelectionLightingTransferFunction() const 
	{
		return m_ligSelectionLightingTransferFunction;
	};

	operator Element() const
	{
		Element eleElement("environment");

		eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("pre")  ][ GetViewingPreTransformation() ];
		eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("user") ][ GetViewingUserTransformation()];
		eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("post") ][ GetViewingPostTransformation() ];

		eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("pre")  ][ GetProjectionPreTransformation() ];
		eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("user")  ][ GetProjectionUserTransformation()];
		eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("post")  ][ GetProjectionPostTransformation() ];

		eleElement[ Element("global") ][ Element("volume") ][ Element("transformation") ][ Element("pre")  ][ GetVolumePreTransformation() ];
		eleElement[ Element("global") ][ Element("volume") ][ Element("transformation") ][ Element("post")  ][ GetVolumePostTransformation() ];

		eleElement[ Element("global") ][ Element("transferfunction") ][ Element("color") ][ Element("backgroundselection") ][ GetBackgroundSelectionColorTransferFunction() ];
		eleElement[ Element("global") ][ Element("transferfunction") ][ Element("color") ][ Element("ghostselection") ][ GetGhostSelectionColorTransferFunction() ];

		for (unsigned int i=0;i<GetDataCount();i++)
		{
			Element eleData("data");
			eleData[ Attribute("index") ] = i;
			eleData[ Attribute("name") ] = GetDataLabel(i);
			eleData[ Element("transformation") ][ Element("user") ] [ GetDataUserTransformation() ];
			eleElement.add(eleData);
		}

		for (unsigned int i=0;i<GetSelectionCount();i++)
		{
			Element eleSelection("selection");
			eleSelection[ Attribute("index") ] = i;
			eleSelection[ Attribute("name") ] = GetSelectionLabel(i);
			eleSelection[ Element("transformation") ][ Element("user") ] [ GetSelectionUserTransformation() ];
			eleElement.add(eleSelection);
		}

		return eleElement;
	};

	Environment & operator=(const Element & eleElement)
	{
		
		m_matViewingPreTransformation = eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("pre")  ][ m_matViewingPreTransformation ];
		m_matViewingUserTransformation = eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("user") ][ m_matViewingUserTransformation ];
		m_matViewingPostTransformation = eleElement[ Element("global") ][ Element("viewing") ][ Element("transformation") ][ Element("post") ][ m_matViewingPostTransformation ];

		m_matProjectionPreTransformation = eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("pre")  ][ m_matProjectionPreTransformation ];
		m_matProjectionUserTransformation = eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("user") ][ m_matProjectionUserTransformation ];
		m_matProjectionPostTransformation = eleElement[ Element("global") ][ Element("projection") ][ Element("transformation") ][ Element("post") ][ m_matProjectionPostTransformation ];
	
		m_matVolumePreTransformation = eleElement[ Element("global") ][ Element("volume") ][ Element("transformation") ][ Element("pre")  ][ m_matVolumePreTransformation ];
		m_matVolumePostTransformation = eleElement[ Element("global") ][ Element("volume") ][ Element("transformation") ][ Element("post") ][ m_matVolumePostTransformation ];

		m_colBackgroundSelectionColorTransferFunction = eleElement[ Element("global") ][ Element("transferfunction") ][ Element("color") ][ Element("backgroundselection") ][ m_colBackgroundSelectionColorTransferFunction ];
		m_colGhostSelectionColorTransferFunction = eleElement[ Element("global") ][ Element("transferfunction") ][ Element("color") ][ Element("ghostselection") ][ m_colGhostSelectionColorTransferFunction ];


		m_vecDataVolumes.clear();
		m_vecDataLabels.clear();
		m_vecDataUserTransformations.clear();

		unsigned int uDataCount = 0; 

		for (Element::ConstantIterator i = eleElement[ Element("data") ]; !i.IsAtEnd(); ++i)
			uDataCount++;

		m_vecDataVolumes.resize(uDataCount);
		m_vecDataLabels.resize(uDataCount);
		m_vecDataUserTransformations.resize(uDataCount);

		for (Element::ConstantIterator i = eleElement[ Element("data") ]; !i.IsAtEnd(); ++i)
		{
			const Element & eleData = (const Element & ) i;
			const unsigned int uIndex = eleData[ Attribute("index") = 0 ];
			m_vecDataLabels[uIndex] = std::string(eleData[ Attribute("name") = std::string("Data") + toString(uIndex)]);
			m_vecDataUserTransformations[uIndex] = eleData[ Element("transformation") ][ Element("user") ][ m_vecDataUserTransformations[uIndex] ];
		}

		m_vecSelectionVolumes.clear();
		m_vecSelectionLabels.clear();
		m_vecSelectionUserTransformations.clear();

		unsigned int uSelectionCount = 0; 

		for (Element::ConstantIterator i = eleElement[ Element("selection") ]; !i.IsAtEnd(); ++i)
			uSelectionCount++;

		m_vecSelectionVolumes.resize(uSelectionCount);
		m_vecSelectionLabels.resize(uSelectionCount);
		m_vecSelectionUserTransformations.resize(uSelectionCount);

		for (Element::ConstantIterator i = eleElement[ Element("selection") ]; !i.IsAtEnd(); ++i)
		{
			const Element & eleSelection = (const Element & ) i;
			const unsigned int uIndex = eleSelection[ Attribute("index") = 0 ];
			m_vecSelectionLabels[uIndex] = std::string(eleSelection[ Attribute("name") = std::string("Selection") + toString(uIndex)]);
			m_vecSelectionUserTransformations[uIndex] = eleSelection[ Element("transformation") ][ Element("user") ] [ m_vecSelectionUserTransformations[uIndex] ];
		}

		update();
		return *this;
	};

	void addData()
	{
		m_vecDataVolumes.push_back(GetDataVolume());
		m_vecDataLabels.push_back(GetDataLabel());
		m_vecDataUserTransformations.push_back(Matrix());
		m_vecDataVolumes.back().clear();

		SetActiveData(unsigned int(m_vecDataVolumes.size()-1));
		SetDataLabel(std::string("Data")+toString(GetActiveSelection()));
	};

	void removeData()
	{
		if (m_vecDataVolumes.size() > 1)
		{
			std::vector< Volume<DataVoxel> >::iterator i = m_vecDataVolumes.begin() + GetActiveData();
			std::vector< Volume<DataVoxel> >::iterator j = m_vecDataVolumes.erase(i);
			m_vecDataLabels.erase(m_vecDataLabels.begin() + GetActiveData());
			m_vecDataUserTransformations.erase(m_vecDataUserTransformations.begin() + GetActiveData());

			if (j == m_vecDataVolumes.end())
				SetActiveData(unsigned int(m_vecDataVolumes.size()-1));
			else
				SetActiveData(unsigned int(j - m_vecDataVolumes.begin()));
		}
	};

	void addSelection()
	{
		m_vecSelectionVolumes.push_back(GetSelectionVolume());
		m_vecSelectionLabels.push_back(GetSelectionLabel());
		m_vecSelectionUserTransformations.push_back(Matrix());
		m_vecSelectionVolumes.back().clear();

		SetActiveSelection(unsigned int(m_vecSelectionVolumes.size()-1));
		SetSelectionLabel(std::string("Selection")+toString(GetActiveSelection()));
	};

	void removeSelection()
	{
		if (m_vecSelectionVolumes.size() > 1)
		{
			std::vector< Volume<SelectionVoxel> >::iterator i = m_vecSelectionVolumes.begin() + GetActiveSelection();
			std::vector< Volume<SelectionVoxel> >::iterator j = m_vecSelectionVolumes.erase(i);
			m_vecSelectionLabels.erase(m_vecSelectionLabels.begin() + GetActiveSelection());
			m_vecSelectionUserTransformations.erase(m_vecSelectionUserTransformations.begin() + GetActiveSelection());

			if (j == m_vecSelectionVolumes.end())
				SetActiveSelection(unsigned int(m_vecSelectionVolumes.size()-1));
			else
				SetActiveSelection(unsigned int(j - m_vecSelectionVolumes.begin()));
		}
	};

	const unsigned int GetDataCount() const
	{
		return unsigned int(m_vecDataVolumes.size());
	};

	const unsigned int GetSelectionCount() const
	{
		return unsigned int(m_vecSelectionVolumes.size());
	};

	void SetActiveData(unsigned int uIndex)
	{
		m_uActiveData = std::min(unsigned int(m_vecDataVolumes.size()-1),uIndex);
//		update();
	};

	void SetActiveSelection(unsigned int uIndex)
	{
		m_uActiveSelection = std::min(unsigned int(m_vecSelectionVolumes.size()-1),uIndex);
//		update();
	};

	const unsigned int GetActiveData() const
	{
		return m_uActiveData;
	};

	const unsigned int GetActiveSelection() const
	{
		return m_uActiveSelection;
	};

	void SetGhostGhosting(const float fGhosting) 
	{
		m_fGhostGhosting = fGhosting;
	};

	const float GetGhostGhosting() const
	{
		return m_fGhostGhosting;
	};

	void SetSelectionGhosting(const float fGhosting)
	{
		m_fSelectionGhosting = fGhosting;
	};

	const float GetSelectionGhosting() const
	{
		return m_fSelectionGhosting;
	};

	void SetGhostCutoutEnabled(const bool bEnabled)
	{
		m_bGhostCutoutEnabled = bEnabled;
	};

	const bool IsGhostCutoutEnabled() const
	{
		return m_bGhostCutoutEnabled;
	};

	void SetSelectionCutoutEnabled(const bool bEnabled)
	{
		m_bSelectionCutoutEnabled = bEnabled;
	};

	const bool IsSelectionCutoutEnabled() const
	{
		return m_bSelectionCutoutEnabled;
	};

	void SetSelectionPinEnabled(bool bEnabled)
	{
		if (!m_bSelectionPinEnabled)
		{
			Volume<SelectionVoxel>::Octree::Iterator iterSelectionVolume(GetSelectionVolume().GetOctree());
			const Vector vecCenter = (*iterSelectionVolume).GetBounds().GetTranslated((*iterSelectionVolume).GetPosition()).GetCenter();

			const Matrix matTransformation = (GetProjectionTransformation() * (GetViewingTransformation()*GetSelectionTransformation(GetActiveSelection())));
			m_vecSelectionPinPosition = matTransformation * vecCenter;
		}
		else
		{
			const Matrix matTransformation = (GetProjectionTransformation() * (GetViewingTransformation()*GetSelectionTransformation(GetActiveSelection()))).GetInverse();
			const Vector vecTransformedPinPosition = matTransformation * m_vecSelectionPinPosition;

			Volume<SelectionVoxel>::Octree::Iterator iterSelectionVolume(GetSelectionVolume().GetOctree());
			const Vector vecCenter = (*iterSelectionVolume).GetBounds().GetTranslated((*iterSelectionVolume).GetPosition()).GetCenter();

			m_vecSelectionUserTransformations[GetActiveSelection()] = (m_vecSelectionUserTransformations[GetActiveSelection()] * GetDataTransformation()).GetTranslated(vecTransformedPinPosition-vecCenter) * GetDataTransformation().GetInverse();
		}

		m_bSelectionPinEnabled = bEnabled;	
	};

	const bool IsSelectionPinEnabled() const
	{
		return m_bSelectionPinEnabled;
	};

	const Vector GetSelectionPinPosition() const
	{
		return m_vecSelectionPinPosition;
	};

	void SetSelectionPinPosition(const Vector & vecPosition)
	{
		m_vecSelectionPinPosition = vecPosition;
	};

	void SetQuality(const Quality & eQuality)
	{
		m_eQuality = eQuality;
	};

	const Quality & GetQuality() const
	{
		return m_eQuality;
	};

private:

	std::multiset<Viewer*> m_mulViewers;

	Matrix m_matViewingPreTransformation;
	Matrix m_matViewingUserTransformation;
	Matrix m_matViewingPostTransformation;

	Matrix m_matProjectionPreTransformation;
	Matrix m_matProjectionUserTransformation;
	Matrix m_matProjectionPostTransformation;

	std::vector<std::string> m_vecDataLabels;
	std::vector<std::string> m_vecSelectionLabels;

	Matrix m_matVolumePreTransformation;
	std::vector<Matrix> m_vecDataUserTransformations;
	std::vector<Matrix> m_vecSelectionUserTransformations;
	Matrix m_matVolumePostTransformation;

	std::vector< Volume<DataVoxel> > m_vecDataVolumes;
	std::vector< Volume<SelectionVoxel> > m_vecSelectionVolumes;

	unsigned int m_uActiveData;
	unsigned int m_uActiveSelection;

	ColorTransferFunction m_colBackgroundSelectionColorTransferFunction;
	ColorTransferFunction m_colGhostSelectionColorTransferFunction;
	
	LightingTransferFunction m_ligBackgroundLightingTransferFunction;
	LightingTransferFunction m_ligGhostLightingTransferFunction;
	LightingTransferFunction m_ligSelectionLightingTransferFunction;

	bool m_bGhostCutoutEnabled;
	bool m_bSelectionCutoutEnabled;

	float m_fGhostGhosting;
	float m_fSelectionGhosting;

	bool m_bSelectionPinEnabled;
	Vector m_vecSelectionPinPosition;
	Quality m_eQuality;
};