/* -*- mia-c++ -*-
 *
 * This file is part of viewitgui - a library and program for the
 * visualization of 3D data sets. 
 *
 * Copyright (c) Leipzig, Madrid 1999-2013 Mirco Hellmann, Gert Wollny
 *
 * viewitgui 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 3 of the License, or
 * (at your option) any later version.
 *
 * viewitgui 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with viewitgui; if not, see <http://www.gnu.org/licenses/>.
 */


#ifndef __planeexpose_h
#define __planeexpose_h

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <list>
#include <vector>

#include <GL/gl.h>

#include <mia.hh>
using namespace mia; 


#include <viewit/texture.hh>

class BasePlaneExpose {

	static float deform_thresh;
	static unsigned int max_objs;
	
	struct GLTexPoint {
		T2DVector<GLfloat> tex;
		T3DVector<GLfloat> normal;
		T3DVector<GLfloat> loc;
	};

	class  TPoint{
		C2DFVector tex;
		C3DFVector normal;
		C3DFVector deform;
	public:	
		TPoint() {};
		TPoint(const C3DFVector& d,float tx,float ty):
			tex(tx,ty),normal(0.0,0.0,0.0),deform(d){
		};
		const C3DFVector& GetDeform() const {
			return deform;
		}
		C3DFVector& normal_ref() {
			return normal;
		}
		C3DFVector& deform_ref() {
			return deform;
		}
		C2DFVector tex_ref() {
			return tex;
		}
		
		void GetTexPoint(GLTexPoint *retval) const{
			retval->tex = tex;
			GLfloat normal_norm = normal.norm();
			assert(normal_norm > 0.0);
			retval->normal = normal/normal_norm;
			retval->loc = deform;
		}
	};
	
	struct TQuad {
		int xa_ya_idx,xe_ya_idx,xe_ye_idx,xa_ye_idx;
	};
	
	struct TWorkObject {
		float priority;
		int xa,xe,ya,ye;
		TQuad quad;
		bool operator < (const TWorkObject& other)const {
			return priority < other.priority;
		}
	};
	
	enum plane_type {plane_xy, plane_xz, plane_yz};
	
	int obj_size;
	const GL2DTexture& Texture;	
	GLuint *ObjIndexArray;
	GLTexPoint *PointArray;
	GLTexPoint *fine_point_array;
protected:	
	typedef T2DDatafield<C3DFVector> T3DVector2DField;
private:	
	T3DVector2DField m_coordinates;
	bool fine_display;
public:
	BasePlaneExpose(const GL2DTexture& Texture);
	virtual ~BasePlaneExpose();
	void draw() const;
	void set_fine_display(bool fine);
	bool get_fine_display()const; 
protected:		
	void set_coordinates(T3DVector2DField c) {
		m_coordinates = c; 
	};
	void create_point_table();
private:
	float get_deform(const std::vector<BasePlaneExpose::TPoint>& Points,const TWorkObject& wo);
	int generate_map(std::vector<BasePlaneExpose::TPoint> *Points,std::list<BasePlaneExpose::TQuad> *objs);
	C3DFVector get_quad_normal(int x,int y,int xe,int ye)const;
	void draw_point(const GLTexPoint& pPoint)const; 
	
};


class XYPlaneExpose: public BasePlaneExpose {
public:	
	XYPlaneExpose(const GL2DTexture& _Texture,const C3DTransformation& Deform,int plane);
};

class XZPlaneExpose: public BasePlaneExpose {
public:	
	XZPlaneExpose(const GL2DTexture& _Texture,const C3DTransformation& Deform,int plane);
};

class YZPlaneExpose: public BasePlaneExpose {
public:	
	YZPlaneExpose(const GL2DTexture& _Texture,const C3DTransformation& Deform,int plane);
};


template <class In> 
inline In bilin_interpol(const In& xa_ya,const In& xe_ya,const In& xa_ye,const In& xe_ye,
				float dx,float mx,float dy,float my) 
{
	return  ( (my * mx) * xa_ya + (my * dx) * xe_ya ) + 
		( (dy * mx) * xa_ye + (dy * dx) * xe_ye ) ;
}

inline bool BasePlaneExpose::get_fine_display()const
{
	return fine_display; 
}

#endif

