#ifndef K3DSDK_IVIEWPORT_H
#define K3DSDK_IVIEWPORT_H

// K-3D
// Copyright (c) 1995-2004, 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 k3d::iviewport, an abstract interface for an object that can draw the document using OpenGL
		\author Tim Shead (tshead@k-3d.com)
*/

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

#include <sdpgl/sdpgl.h>
#include <vector>

namespace k3d
{

// Forward declarations
class iprojection;
class iviewport_host;
class rectangle;

/// Abstract interface for objects that can draw the document using OpenGL
class iviewport :
	public virtual iunknown
{
public:
	/// Gives the viewport/host a chance to (optionally) constrain the requested screen aspect ratio
	virtual void constrain_screen_aspect_ratio(double& Ratio) = 0;
	/// Returns the current 3D-to-2D projection for this viewport
	virtual iprojection& projection() = 0;

	/// Sets the current viewport host for this viewport
	virtual void set_host(iviewport_host* Host) = 0;
	/// Returns the current viewport host for this viewport
	virtual iviewport_host* host() = 0;
	/// Defines a signal that will be emitted whenever the host for this viewport changes
	typedef SigC::Signal0<void> host_changed_signal_t;
	virtual host_changed_signal_t& host_changed_signal() = 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(const unsigned long PixelWidth, const unsigned long PixelHeight, const unsigned long FontListBase) = 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;

	/// Defines a signal that will be emitted if the requested screen aspect ratio changes
	typedef SigC::Signal0<void> aspect_ratio_changed_signal_t;
	virtual aspect_ratio_changed_signal_t& aspect_ratio_changed_signal() = 0;

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

namespace viewport
{

/// 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 Rectangle Defines the selection region as a rectangle in screen (pixel coordinates)
	  \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 unsigned long PixelWidth, const unsigned long PixelHeight, const unsigned long FontListBase, const rectangle& Rectangle) = 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 during viewport rendering
class ilight :
	public virtual iunknown
{
public:
	virtual void setup_viewport_light(const unsigned long LightNumber) = 0;

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

/// Abstract interface for objects that act a material during editor-mode rendering
class imaterial :
	public virtual iunknown
{
public:
	virtual void setup_viewport_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
{
	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_face_orientations;
	bool draw_two_sided;

	/// Stores the current OpenGL projection matrix
	GLfloat gl_projection_matrix[16];
	/// Stores the current OpenGL viewport
	GLint gl_viewport[4];
	/// Stores an OpenGL call list index for an ASCII font
	GLuint gl_ascii_font_list_base;
};

/// Abstract interface implemented by objects that can draw themselves during viewport rendering
class idrawable :
	public virtual k3d::iunknown
{
public:
	virtual void viewport_draw(const render_state& State) = 0;
	virtual void viewport_select(const render_state& State) = 0;

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

} // namespace viewport

} // namespace k3d

#endif // K3DSDK_IVIEWPORT_H
