/*
 * This code should be used to set OpenGL state, such as: 
 * blending, depth testing, current color etc etc.
 *
 * The reason for this is that OpenGL is a huge mess of global variables,
 * most of which you can write but not read (not quickly, anyway). In addition
 * openGL doesn't allow you to push/pop most of these, leading to very ugly
 * code and/or all kind of side effects when you set something in one proc and
 * forget to restore it.
 *
 * I've made this a class so we can have a separate state for the main
 * render context and for the render-to-texture context.
 */

#pragma once

class OGLState
{
public:

	// constructor
	OGLState();
	~OGLState();

	static void SetState(OGLState* inState);

/////////////////////////////////////////////////////////////////////////////////////////////
//			Blending
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetBlend(bool inEnable);
static bool GetBlend();
static void PushBlend(bool inEnable);
static void PopBlend();

static void SetBlendFunc(GLenum inBlendSource, GLenum inBlendDest);
static void GetBlendFunc(GLenum& outBlendSource, GLenum& outBlendDest);
static void PushBlendFunc(GLenum inBlendSource, GLenum inBlendDest);
static void PopBlendFunc();

/////////////////////////////////////////////////////////////////////////////////////////////
//			BGColor
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetBGColor(int inAlpha, int inRed, int inGreen, int inBlue);
static void GetBGColor(int& outAlpha, int& outRed, int& outGreen, int& outBlue);
static void PushBGColor(int inAlpha, int inRed, int inGreen, int inBlue);
static void PopBGColor();

/////////////////////////////////////////////////////////////////////////////////////////////
//			Depth
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetDepth(bool inEnable);
static bool GetDepth();
static void PushDepth(bool inEnable);
static void PopDepth();

/////////////////////////////////////////////////////////////////////////////////////////////
//			Textures
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetTexture2D(bool inEnable);
static bool GetTexture2D();
static void PushTexture2D(bool inEnable);
static void PopTexture2D();

static void SetTextureUsed(GLuint inTexture);
static GLuint GetTextureUsed();
static void PushTextureUsed(GLuint inTexture);
static void PopTextureUsed();

/////////////////////////////////////////////////////////////////////////////////////////////
//			ColorMask
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetColorMask(bool inAlpha, bool inRed, bool inGreen, bool inBlue );
static void GetColorMask(bool& outAlpha, bool& outRed, bool& outGreen, bool& outBlue);
static void PushColorMask(bool inAlpha, bool inRed, bool inGreen, bool inBlue);
static void PopColorMask();

/////////////////////////////////////////////////////////////////////////////////////////////
//			MatrixMode
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetMatrixMode(GLenum inMatrixMode );
static GLenum GetMatrixMode();
static void PushMatrixMode(GLenum inMatrixMode);
static void PopMatrixMode();

/////////////////////////////////////////////////////////////////////////////////////////////
//			ShadeModel
/////////////////////////////////////////////////////////////////////////////////////////////

static void SetShadeModel(GLenum inShadeModel );
static GLenum GetShadeModel();
static void PushShadeModel(GLenum inShadeModel);
static void PopShadeModel();

private:
	static OGLState* gState;

	enum { MAX_STACK = 32 }; // please don't push more than this...

	bool	mBlendEnable[MAX_STACK];
	int		mBlendEnableCurrent;

	GLenum	mBlendSourceFunc[MAX_STACK];
	GLenum	mBlendDestFunc[MAX_STACK];
	int		mBlendFuncCurrent;

	unsigned long mBGColor[MAX_STACK];
	int		mBGColorCurrent;

	bool	mDepthEnable[MAX_STACK];
	int		mDepthEnableCurrent;

	bool	mTexture2DEnable[MAX_STACK];
	int		mTexture2DEnableCurrent;

	GLuint	mTexture2D[MAX_STACK];
	int		mTexture2DCurrent;

	char	mColorMask[MAX_STACK];
	int		mColorMaskCurrent;

	GLenum	mMatrixMode[MAX_STACK];
	int		mMatrixModeCurrent;

	GLenum	mShadeModel[MAX_STACK];
	int		mShadeModelCurrent;
};

