#ifndef K3DSDK_IGL_H
#define K3DSDK_IGL_H

// K-3D
// Copyright (c) 1995-2006, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// 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 for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
		\brief Declares abstract interfaces for drawing the document using OpenGL
		\author Tim Shead (tshead@k-3d.com)
*/

#include "iunknown.h"
#include "signal_system.h"

namespace k3d
{

class icamera;
class iprojection;
class rectangle;

namespace gl
{

/// Abstract interface for objects that can render the document using OpenGL
class irender_engine :
	public virtual iunknown
{
public:
	/// Returns the normalized device coordinates for the viewport, allowing for mismatches between the aspect ratio of the window and the camera
	virtual bool get_ndc(icamera& Camera, const unsigned long PixelWidth, const unsigned long PixelHeight, rectangle& CameraRect, rectangle& WindowRect) = 0;

	/** \brief Redraws the document
	    \note The caller must setup an OpenGL render context before calling this method, and must call glFlush() after it returns */
	virtual void redraw(icamera& Camera, const unsigned long PixelWidth, const unsigned long PixelHeight, const unsigned long FontListBase, double ViewMatrix[16], double ProjectionMatrix[16], int Viewport[4]) = 0;

	/// Enumerates redraw request types
	typedef enum
	{
		SYNCHRONOUS,
		ASYNCHRONOUS
	} redraw_type_t;

	/// Used to signal any connected user interface components that a redraw is requested
	typedef sigc::signal1<void, redraw_type_t> redraw_request_signal_t;
	virtual redraw_request_signal_t& redraw_request_signal() = 0;

protected:
	irender_engine() {}
	irender_engine(const irender_engine&) {}
	irender_engine& operator=(const irender_engine&) { return *this; }
	virtual ~irender_engine() {}
};

/// Used to pass selection bitmask for any combination of primitives
struct select_state
{
	select_state() :
		exclude_unselected_nodes(false),
		select_points(false),
		select_point_groups(false),
		select_edges(false),
		select_faces(false),
		select_linear_curves(false),
		select_cubic_curves(false),
		select_nucurves(false),
		select_bilinear_patches(false),
		select_bicubic_patches(false),
		select_nupatches(false),
		select_blobbies(false)
	{
	}

	bool exclude_unselected_nodes;
	bool select_points;
	bool select_point_groups;
	bool select_edges;
	bool select_faces;
	bool select_linear_curves;
	bool select_cubic_curves;
	bool select_nucurves;
	bool select_bilinear_patches;
	bool select_bicubic_patches;
	bool select_nupatches;
	bool select_blobbies;
};

/// Abstract interface for returning selection data
class iselection_engine :
	public virtual iunknown
{
public:
	/**
	  \brief Draws the document in OpenGL selection mode, so selection "hits" can be extracted
	  \param SelectionState The geometry components to be drawn
	  \param PixelWidth The width of the viewport in pixels
	  \param PixelHeight The width of the viewport in pixels
	  \param FontListBase
	  \param Rectangle Defines the selection region as a rectangle in screen (pixel coordinates)
	  \param ViewMatrix Returns the OpenGL view matrix used for drawing (the camera-to-world matrix)
	  \param ProjectionMatrix Returns the OpenGL projection matrix used for drawing
	  \param Viewport Returns the OpenGL viewport used for drawing
	  \note The caller must setup the OpenGL render context, allocate the selection buffer, put OpenGL in selection mode, and call glFlush() when done
	*/
	virtual void select(const select_state& SelectionState, icamera& Camera, const unsigned long PixelWidth, const unsigned long PixelHeight, const unsigned long FontListBase, const rectangle& Rectangle, double ViewMatrix[16], double ProjectionMatrix[16], int Viewport[4]) = 0;

protected:
	iselection_engine() {}
	iselection_engine(const iselection_engine&) {}
	iselection_engine& operator=(const iselection_engine&) { return *this; }
	virtual ~iselection_engine() {}
};

/// Abstract interface for objects that act as a light source while drawing OpenGL graphics
class ilight :
	public virtual iunknown
{
public:
	virtual void setup_gl_light(const unsigned long LightNumber) = 0;

protected:
	ilight() {}
	ilight(const ilight&) {}
	ilight& operator=(const ilight&) { return *this; }
	virtual ~ilight() {}
};

/// Abstract interface for objects that act as a material while drawing OpenGL graphics
class imaterial :
	public virtual iunknown
{
public:
	virtual void setup_gl_material() = 0;

protected:
	imaterial() {}
	imaterial(const imaterial&) {}
	imaterial& operator=(const imaterial&) { return *this; }
	virtual ~imaterial() {}
};

/// Used to pass (potentially) useful rendering state from the engine to the object being rendered
struct render_state
{
	render_state(icamera& Camera) :
		camera(Camera)
	{
	}

	bool draw_points;
	bool draw_edges;
	bool draw_faces;
	bool draw_linear_curves;
	bool draw_cubic_curves;
	bool draw_nucurves;
	bool draw_bilinear_patches;
	bool draw_bicubic_patches;
	bool draw_nupatches;
	bool draw_blobbies;
	bool draw_two_sided;

	/// Stores the camera used for drawing
	icamera& camera;

	/// Set to true iff the OpenGL viewing frustum used for drawing is orthographic
	bool orthographic;
	
	//@{
	/** Stores the OpenGL viewing frustum used for drawing (perspective or orthographic).
	 * Note: these are the actual values passed to glFrustum() or glOrtho() to fill the
	 * render window, in general they will be different from the viewing frustum defined
	 * by the camera for rendering. */
	double gl_window_frustum_left;
	double gl_window_frustum_right;
	double gl_window_frustum_top;
	double gl_window_frustum_bottom;
	double gl_window_frustum_near;
	double gl_window_frustum_far;
	//@}
	
	//@{
	/** Stores an imaginary OpenGL viewing frustum that represents the viewing frustum
	 * defined by the camera for rendering.  Note that the values may not be the same
	 * as those returned by the camera object.  */
	double gl_camera_frustum_left;
	double gl_camera_frustum_right;
	double gl_camera_frustum_top;
	double gl_camera_frustum_bottom;
	double gl_camera_frustum_near;
	double gl_camera_frustum_far;
	//@}
	
	/// Stores the current OpenGL projection matrix
	float gl_projection_matrix[16];
	/// Stores the current OpenGL viewport
	int gl_viewport[4];
	/// Stores an OpenGL call list index for an ASCII font
	unsigned int gl_ascii_font_list_base;
};

/// Abstract interface implemented by objects that can draw themselves using OpenGL
class idrawable :
	public virtual iunknown
{
public:
	virtual void gl_draw(const render_state& State) = 0;
	virtual void gl_select(const render_state& State, const select_state& SelectState) = 0;

protected:
	idrawable() {}
	idrawable(const idrawable&) {}
	idrawable& operator=(const idrawable&) { return *this; }
	virtual ~idrawable() {}
};

} // namespace gl

} // namespace k3d

#endif // K3DSDK_IGL_H

