// OpenGL API の実行補助機能

#pragma once


void glLight4f(GLenum light, GLenum pname, float param0, float param1, float param2, float param3);
void glLight3f(GLenum light, GLenum pname, float param0, float param1, float param2);

void glMaterial4f(GLenum face, GLenum pname, float param0, float param1, float param2, float param3);
void glMaterial3f(GLenum face, GLenum pname, float param0, float param1, float param2);
void glMaterial1f(GLenum face, GLenum pname, float param0);

void glTexMinMagFilter2D(GLint near_filter, GLint far_filter);
void glTexMinMagFilter2D(GLint near_and_far_filter);

void glTexWrapST2D(GLint wrap_s, GLint wrap_t);
void glTexWrapST2D(GLint wrap_st);

GLboolean  glGetBoolean(GLenum pname);
GLint      glGetInteger(GLenum pname);
GLfloat    glGetFloat(GLenum pname);
GLdouble   glGetDouble(GLenum pname);

void glSetEnable(GLenum pname, bool enable);
bool glGetEnable(GLenum pname);

const char* glGetErrorMessage(void);
const char* glGetErrorMessage(GLenum err);

void glSetPickMatrixProjection(double pick_x, double pick_y, double pick_width, double pick_height);

void glClipPlaneFunc(GLenum plane, GLdouble eq0, GLdouble eq1, GLdouble eq2, GLdouble eq3);
void glClipPlaneFuncX(GLenum plane, bool bFore, GLdouble height);
void glClipPlaneFuncY(GLenum plane, bool bFore, GLdouble height);
void glClipPlaneFuncZ(GLenum plane, bool bFore, GLdouble height);


// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


inline void glLight4f(GLenum light, GLenum pname, float param0, float param1, float param2, float param3)
{
	float v[4] = { param0 , param1 , param2 , param3 };
	glLightfv(light, pname, v);
}

inline void glLight3f(GLenum light, GLenum pname, float param0, float param1, float param2)
{
	float v[3] = { param0 , param1 , param2 };
	glLightfv(light, pname, v);
}


inline void glMaterial4f(GLenum face, GLenum pname, float param0, float param1, float param2, float param3)
{
	float v[4] = { param0 , param1 , param2 , param3 };
	glMaterialfv(face, pname, v);
}

inline void glMaterial3f(GLenum face, GLenum pname, float param0, float param1, float param2)
{
	glMaterial4f(face, pname, param0, param1, param2, 1.0f);
}

inline void glMaterial1f(GLenum face, GLenum pname, float param0)
{
	glMaterialfv(face, pname, &param0);
}


//! テクスチャサンプリングの設定のmin, magフィルタを同時に設定する.
inline void glTexMinMagFilter2D(GLint near_filter, GLint far_filter)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, near_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, far_filter);
}

inline void glTexMinMagFilter2D(GLint near_and_far_filter)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, near_and_far_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, near_and_far_filter);
}


//! テクスチャのWrap形式の設定をs,t方向同時に実行する
inline void glTexWrapST2D(GLint wrap_s, GLint wrap_t)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
}

inline void glTexWrapST2D(GLint wrap_st)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_st);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_st);
}


//! 1パラメータの状態変数を取得する
inline GLboolean glGetBoolean(GLenum pname)
{
	GLboolean b;
	glGetBooleanv(pname, &b);
	return b;
}

//! 1パラメータの状態変数を取得する
inline GLint glGetInteger(GLenum pname)
{
	GLint i;
	glGetIntegerv(pname, &i);
	return i;
}

//! 1パラメータの状態変数を取得する
inline GLfloat glGetFloat(GLenum pname)
{
	GLfloat f;
	glGetFloatv(pname, &f);
	return f;
}

//! 1パラメータの状態変数を取得する
inline GLdouble glGetDouble(GLenum pname)
{
	GLdouble d;
	glGetDoublev(pname, &d);
	return d;
}


//! boolで, glEnable/glDisableをセットする
inline void glSetEnable(GLenum pname, bool enable)
{
	if( enable )
		glEnable(pname);
	else
		glDisable(pname);
}

//! glEnable/glDisableで設定する状態変数の値を取得する
inline bool glGetEnable(GLenum pname)
{
	return ( glGetBoolean(pname) == GL_TRUE );
}


inline const char* glGetErrorMessage(void)
{
	return glGetErrorMessage( glGetError() );
}

inline const char* glGetErrorMessage(GLenum err)
{
	if( err == GL_NO_ERROR          ) return "GL_NO_ERROR";
	if( err == GL_INVALID_ENUM      ) return "GL_INVALID_ENUM";
	if( err == GL_INVALID_VALUE     ) return "GL_INVALID_VALUE";
	if( err == GL_INVALID_OPERATION ) return "GL_INVALID_OPERATION";
	if( err == GL_STACK_OVERFLOW    ) return "GL_STACK_OVERFLOW";
	if( err == GL_STACK_UNDERFLOW   ) return "GL_STACK_UNDERFLOW";
	if( err == GL_OUT_OF_MEMORY     ) return "GL_OUT_OF_MEMORY";
	//if( err == GL_TABLE_TOO_LARGE   ) return "GL_TABLE_TOO_LARGE";

	return "UNKNOWN_ERROR";
}


//! ピック行列を現在の投影行列に反映する
//! ビューの指定範囲をズームしたような状態になる
//! @param[in] pick_x      - ピック範囲中心のスクリーン座標 x
//! @param[in] pick_y      - ピック範囲中心のスクリーン座標 y
//! @param[in] pick_width  - ピック範囲の大きさ(ピクセル数) x方向
//! @param[in] pick_height - ピック範囲の大きさ(ピクセル数) y方向
inline void glSetPickMatrixProjection(double pick_x, double pick_y, double pick_width, double pick_height)
{
	glPushAttrib( GL_TRANSFORM_BIT );

	GLint viewport[4];
	glGetIntegerv( GL_VIEWPORT , viewport );

	GLfloat projection[16];
	glGetFloatv(GL_PROJECTION_MATRIX, projection);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPickMatrix( pick_x , pick_y , pick_width , pick_height , viewport );
	glMultMatrixf( projection );

	glPopAttrib();
}


inline void glClipPlaneFunc(GLenum plane, GLdouble eq0, GLdouble eq1, GLdouble eq2, GLdouble eq3)
{
	GLdouble eq[4] = {eq0, eq1, eq2, eq3};
	glClipPlane(plane, eq);
}

//! x軸方向を垂直なクリッププレーンを設定する
//! bForeにtrueを設定すると正方向, falseを指定すると負方向を隠す.
inline void glClipPlaneFuncX(GLenum plane, bool bFore, GLdouble height)
{
	GLdouble n = bFore ? -1.0 : 1.0;
	GLdouble eq[4] = {n, 0.0, 0.0, -height * n};
	glClipPlane(plane, eq);
}

inline void glClipPlaneFuncY(GLenum plane, bool bFore, GLdouble height)
{
	GLdouble n = bFore ? -1.0 : 1.0;
	GLdouble eq[4] = {0.0, n, 0.0, -height * n};
	glClipPlane(plane, eq);
}

inline void glClipPlaneFuncZ(GLenum plane, bool bFore, GLdouble height)
{
	GLdouble n = bFore ? -1.0 : 1.0;
	GLdouble eq[4] = {0.0, 0.0, n, -height * n};
	glClipPlane(plane, eq);
}
