/*  $Id: gl_state_checker.h,v 1.30 2004/04/23 15:47:49 sphair Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library 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 2.1 of the License, or (at your option) any later version.
**
**  This library 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 library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

#ifndef header_gl_state_checker
#define header_gl_state_checker

#if _MSC_VER > 1000
#pragma once
#endif

#include "API/GL/opengl_state_data.h"
#include "API/Display/stencil_func.h"

#ifdef WIN32
#include <windows.h>
#endif 

#include <stack>
#include "gl_state.h"
#ifndef WIN32
#include <GL/glx.h>
#endif

class CL_Quad;
class CL_Rect;
class CL_Rectf;
class CL_Pointf;
class CL_Color;
class CL_GraphicContext;
class CL_OpenGLState;
class CL_GraphicContext_OpenGL;

class CL_GLStateChecker : private CL_OpenGLStateData
{
//! Construction:
public:
	CL_GLStateChecker(CL_GraphicContext_OpenGL *gc_opengl);

	~CL_GLStateChecker();

//! Attributes:
public:
	CL_OpenGLState *opengl_state;

	CL_GraphicContext_OpenGL *gc_opengl;

	CLint stencil_op_pass;
	CLint stencil_op_fail;
	CLint stencil_func_write;
	CLint stencil_write_ref;

//! Operations:
public:
	static CL_GLStateChecker *from_gc(CL_GraphicContext *gc);

	//: Adds a clear screen.
	void add_clear(
		const CL_Color &color);

	//: Adds drawal of a pixel to the state tree.
	void add_pixel(
		const CL_GLState &state,
		int x, int y);

	//: Adds drawal of a line to the state tree.
	void add_line(
		const CL_GLState &state,
		int x1, int y1, int x2, int y2);

	//: Adds drawal of a gradient filled rectangle to the state tree.
	void add_gradient(
		const CL_GLState &state,
		const CL_Rectf &position,
		const CL_Gradient &gradient);
	
	//: Adds drawal of a gradient filled quad to the state tree.
	void add_gradient(
		const CL_GLState &state,
		const CL_Quad &quad,
		const CL_Gradient &gradient);

	//: Adds drawal of a textured quad to the state tree.
	void add_quad(
		const CL_GLState &state,
		float px1,
		float py1,
		float px2,
		float py2,
		int tx1,
		int ty1,
		int tx2,
		int ty2);

	//: Adds drawal of a textured quad to the state tree.
	void add_quad(
		const CL_GLState &state,
		double destX[4],
		double destY[4],
		int tx[4],
		int ty[4]);

	//: Renders state tree objects.
	void flush(bool rebind_texture=false) const;

	//: Reads a pixel from opengl context.
	CL_Color get_pixel(int x, int y) const;

	//: Clears the Stencil buffer
	void clear_stencil(int value);

	//: Enable writing to stencil buffer
	void enable_stencil_write(bool enabled, bool visible, float alpha_limit);

	//: Enable testing pixels to be drawn with stencil buffer
	void enable_stencil_test(bool enabled, CL_StencilFunc func, int ref);


//! CL_OpenGLStateData:
private:
	//: Save state information needed to restore this OpenGL state.
	virtual void on_save();

	//: Load state information and setup OpenGL to this state.
	virtual void on_load();

	//: Flush current rendering batch.
	virtual void on_flush();

//! Implementation:
private:
	inline void add_quad_vertices(const CL_GLState &state, float px1, float py1, float px2, float py2 );
	
	inline void add_quad_vertices(const CL_GLState &state, float px1, float py1, float px2, float py2, float px3, float py3, float px4, float py4 );

	void set_state(const CL_GLState &state, CLenum primitive);

	//: set_state helper.
	void set_blendfunc(const CL_GLState &state);

	void set_fillmode(const CL_GLState &state);

	mutable CL_GLState internal_state;

	mutable CLenum primitive;

	// Number of quads that can be drawn at once.
	// If more are drawn, a flush() will take place.
	#define MAX_QUAD_COUNT 256

	// Need to distinguish gradients from plain quads.
	// This can be whatever except CL_QUADS, CL_LINES or CL_POINTS.
	#define CL_GRADIENT 0x1337

	//: keep track of how many primitives to draw.
	mutable int primitive_count;

	CLfloat vertex_array[MAX_QUAD_COUNT*3*4];

	CLint texcoord_array[MAX_QUAD_COUNT*2*4];

	CLfloat color_array[MAX_QUAD_COUNT*4*4];

	bool first_call;
};

#endif
