#pragma once	
/****************************************************************************
* VCGLib                                                            o o     *
* Visual and Computer Graphics Library                            o     o   *
*                                                                _   O  _   *
* Copyright(C) 2004                                                \/)\/    *
* Visual Computing Lab                                            /\/|      *
* ISTI - Italian National Research Council                           |      *
*                                                                    \      *
* All rights reserved.                                                      *
*                                                                           *
* This program is free software; you can redistribute it and/or modify      *   
* it under the terms of the GNU General Public License as published by      *
* the Free Software Foundation; either version 2 of the License, or         *
* (at your option) any later version.                                       *
*                                                                           *
* 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 the             *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
* for more details.                                                         *
*                                                                           *
****************************************************************************/
/****************************************************************************
This file contains two function providing the standard way to do picking using opendgl:
- using the SELECT mode (first function)
- using the depth buffer and gluUnproject (second function)

  History
$Log: not supported by cvs2svn $
****************************************************************************/


#include <algorithm>
#include <GL/glut.h>

template <class TO_PICK_CONT_TYPE>
int Pick(	const int & x, const int &y, 
					TO_PICK_CONT_TYPE &m, 
					std::vector<typename TO_PICK_CONT_TYPE::value_type*> &result, 
					void (draw_func)(typename TO_PICK_CONT_TYPE::value_type &),
					int width=4, 
					int height=4)
	{
		result.clear();
		long hits;	
		int sz=m.size()*5;
		unsigned int *selectBuf =new unsigned int[sz];
		glSelectBuffer(sz, selectBuf);
		glRenderMode(GL_SELECT);
		glInitNames();

		/* Because LoadName() won't work with no names on the stack */
		glPushName(-1);
		double mp[16];

		int viewport[4];
		glGetIntegerv(GL_VIEWPORT,viewport);
		glMatrixMode(GL_PROJECTION);
		glGetDoublev(GL_PROJECTION_MATRIX ,mp);
		glPushMatrix();
		glLoadIdentity();
		//gluPickMatrix(x, viewport[3]-y, 4, 4, viewport);
		gluPickMatrix(x, y, width, height, viewport);
		glMultMatrixd(mp);

		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		int cnt=0; 
		typename TO_PICK_CONT_TYPE::iterator  ei;
		for(ei=m.begin();ei!=m.end();++ei)
		{

				glLoadName(cnt);
				draw_func(*ei);
				cnt++;
		}

		glPopMatrix();
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		hits = glRenderMode(GL_RENDER);
		
		if (hits <= 0)     return 0;
		std::vector< std::pair<double,unsigned int> > H;
		for(int ii=0;ii<hits;ii++){
			H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
		}
		std::sort(H.begin(),H.end());

		result.resize(H.size());
		for(ii=0;ii<hits;ii++){
			typename TO_PICK_CONT_TYPE::iterator ei=m.begin();
			advance(ei ,H[ii].second);
			result[ii]=&*ei;
		}

		delete [] selectBuf;
		return result.size();
	}

template <class PointType>
PointType Pick(const int & x, const int &y){
	double res[3];
	GLdouble mm[16],pm[16]; GLint vp[4];
	glGetDoublev(GL_MODELVIEW_MATRIX,mm);
	glGetDoublev(GL_PROJECTION_MATRIX,pm);
	glGetIntegerv(GL_VIEWPORT,vp);
	
	float   pix;
	glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&pix);
	gluUnProject(x,y,pix,mm,pm,vp,&res[0],&res[1],&res[2]);
	return PointType (res[0],res[1],res[2]);
	}