//==============================================================================
/*! \file
 * OpenMesh Toolkit for mesh analysis    \n
 * Copyright (c) 2010 by Rostislav Hulik     \n
 *
 * Author:  Rostislav Hulik, rosta.hulik@gmail.com  \n
 * Date:    2010/10/20                          \n
 *
 * This file is part of software developed for support of Rostislav Hulik's dissertation thesis at dcgm-robotics@FIT group.
 *
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This file 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 the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Description:
 * - Class for Visualizing color legend
 */

 
#include <OMToolkitOSG/OMLegendGeo.h>

namespace osg {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor
// @param min Minimum value showed in legend
// @param max Maximum value showed in legend
// @param windowHeight Height of HUD window
// @param windowWidth Height of HUD window
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
OMLegendGeometry::OMLegendGeometry(double min, double max, int windowHeight, int windowWidth)
{
	m_height = windowHeight;
	m_width = windowWidth;
	float step = (max - min) / HUD_SIZE;

	ref_ptr<Vec3Array> HUDBackgroundVertices = new Vec3Array();	
	DrawElementsUInt *HUDBackgroundIndices =new DrawElementsUInt(PrimitiveSet::QUADS, 0);
	ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;

	// set up legend rectangle with specified colors
	for(unsigned int i = 0; i < HUD_SIZE; ++i)
	{
		HUDBackgroundVertices->push_back( Vec3(  i+HUD_MARGIN, m_height-HUD_MARGIN,-1) );		
		HUDBackgroundVertices->push_back( Vec3(i+1+HUD_MARGIN, m_height-HUD_MARGIN,-1) );		
		HUDBackgroundVertices->push_back( Vec3(i+1+HUD_MARGIN, m_height-HUD_MARGIN - HUD_HEIGHT,-1) );		
		HUDBackgroundVertices->push_back( Vec3(  i+HUD_MARGIN, m_height-HUD_MARGIN - HUD_HEIGHT,-1) );		

		HUDBackgroundIndices->push_back(i*4+0);
		HUDBackgroundIndices->push_back(i*4+1);
		HUDBackgroundIndices->push_back(i*4+2);
		HUDBackgroundIndices->push_back(i*4+3);

		OpenMesh::Vec4uc color = OMToolkit::getColor(min + i*step, min, max);

		if (i != 0 && i != HUD_SIZE/2 && i != HUD_SIZE - 1)
			colors->push_back(Vec4f((float)color[0]/255.0, (float)color[1]/255.0, (float)color[2]/255.0, (float)color[3]/255.0));
		else
			colors->push_back(Vec4f(1.0, 1.0, 1.0, 1.0));
	}
	
	// set arrays into this
	ref_ptr<Vec3Array> HUDnormals = new Vec3Array;
	HUDnormals->push_back(Vec3(0.0f,0.0f,1.0f));
	setNormalArray(HUDnormals);
	setNormalBinding(Geometry::BIND_PER_PRIMITIVE_SET);

	setVertexArray(HUDBackgroundVertices);
	addPrimitiveSet(HUDBackgroundIndices);
	setColorArray(colors);
	setColorBinding(Geometry::BIND_PER_PRIMITIVE);

	// set up texts
	for (unsigned int i = 0; i < TEXT_SIZE; ++i)
	{
		text[i] = new osgText::Text();
		text[i]->setCharacterSize(TEXT_CHAR);
		text[i]->setAxisAlignment(osgText::Text::SCREEN);
		text[i]->setColor( osg::Vec4(1, 1, 1, 1) );
	}
	
	std::stringstream strMin, strMax, strMean;	
	strMin << min;
	strMax << max;
	strMean << (min+max)/2;
	text[0]->setPosition( osg::Vec3(HUD_MARGIN,m_height - HUD_MARGIN - HUD_HEIGHT- TEXT_CHAR,-1) );
	text[0]->setText(strMin.str());

	text[1]->setPosition( osg::Vec3(HUD_MARGIN + HUD_SIZE/2,m_height - HUD_MARGIN - HUD_HEIGHT- TEXT_CHAR,-1) );
	text[1]->setText(strMean.str());
	
	text[2]->setPosition( osg::Vec3(HUD_MARGIN + HUD_SIZE,m_height - HUD_MARGIN - HUD_HEIGHT- TEXT_CHAR,-1) );
	text[2]->setText(strMax.str());
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function registers this geometry into osg Group (with all the setup matrices)
// @param parent OSG root group
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OMLegendGeometry::addToGroup(ref_ptr<Group> parent)
{
	// hud projection
	ref_ptr<Projection> HUDProjectionMatrix = new Projection();
	ref_ptr<MatrixTransform> HUDModelViewMatrix = new MatrixTransform();
	ref_ptr<Geode> HUDGeode = new Geode();

	HUDProjectionMatrix->setMatrix(Matrix::ortho2D(0,m_width, 0,m_height));
	HUDModelViewMatrix->setMatrix(Matrix::identity());
	HUDModelViewMatrix->setReferenceFrame(Transform::ABSOLUTE_RF);
	
	for (unsigned int i = 0; i < TEXT_SIZE; ++i)
	{
		HUDGeode->addDrawable(text[i]);
	}

	// set geometry stateset
	ref_ptr<StateSet> HUDStateSet = new osg::StateSet();
	HUDGeode->setStateSet(HUDStateSet);
	HUDStateSet->setMode(GL_BLEND,osg::StateAttribute::ON);
	HUDStateSet->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
	HUDStateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
	HUDStateSet->setRenderBinDetails( 11, "RenderBin");

	// register hierarchy
	parent->addChild(HUDProjectionMatrix);
	HUDProjectionMatrix->addChild(HUDModelViewMatrix);

	HUDModelViewMatrix->addChild( HUDGeode );
	HUDGeode->addDrawable(this);
}
} // namespace osg