#pragma once

#include "GlInclude.h"


namespace lib_gl
{


// -----------------------------------------------------------------------------------------------
//! Viewport
class Viewport
{
public:
	Viewport(void) 
		: Left(0) , Bottom(0)
		, Width(0) , Height(0)
		, Visible(true)
	{}

	Viewport( int i_left , int i_bottom , int i_width , int i_height )
		: Left( i_left ) , Bottom( i_bottom )
		, Width( i_width ) , Height( i_height )
		, Visible(true)
	{}

	//! 始点( 左下 ) の位置を設定する.
	void SetLeftBottom( int i_left , int i_bottom );
	//! サイズ( 高さと横幅 ) を設定する.
	void SetWidthHeight( int i_width , int i_height );
	//! 始点とサイズを設定する.
	void SetViewport( int i_left , int i_bottom , int i_width , int i_height );

	//! 始点( 左下 ) の位置を取得する.
	void GetLefBottom( int& o_left , int& o_bottom ) const;
	//! サイズ( 高さと横幅 ) を取得する.
	void GetWidthHeight( int& o_width , int& o_height ) const;
	//! 始点とサイズを取得する.
	void GetViewport( int& o_left , int& o_bottom , int& o_width , int& o_height ) const;

	//! サイズ情報が適正か調べる.
	//! @retval true  - 面積が0以上
	//! @retval false - 面積が0未満
	bool IsValidView(void) const;

	//! アスペクト比を返す ( == GetAspectWH() )
	float GetAspect(void) const;
	//! アスペクト比を返す ( 横幅 / 高さ )
	float GetAspectWH(void) const;
	//! アスペクト比を返す ( 高さ / 横幅 )
	float GetAspectHW(void) const;

	void SetGLViewport(void);
	void SetGLScissor(void);

	//! 現在のビューポートに対するビルボード状の投影行列をセット
	void SetGLBillboardMatrix(bool invert_vertical);

	//! 指定された座標がビューポート内に含まれるかどうか表す
	bool Contains( int i_x , int i_y ) const;

	//! GLint[4]に変換する
	void GetGlArray( GLint* o_array ) const;

	int GetRight(void) const { return Left + Width; }
	int GetTop(void) const { return Bottom + Height; }


public:
	int Left;
	int Bottom;
	int Width;
	int Height;

	bool Visible; //!< 表示、非表示を表す
};



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

inline
void Viewport::SetLeftBottom( int i_left , int i_bottom )
{
	Left    = i_left;
	Bottom  = i_bottom;
}

inline
void Viewport::SetWidthHeight( int i_width , int i_height )
{
	Width  = i_width;
	Height = i_height;
}

inline
void Viewport::SetViewport( int i_left , int i_bottom , int i_width , int i_height )
{
	Left   = i_left;
	Bottom = i_bottom;
	Width  = i_width;
	Height = i_height;
}

inline
void Viewport::GetLefBottom( int& o_left , int& o_bottom ) const
{
	o_left   = Left;
	o_bottom = Bottom;
}

inline
void Viewport::GetWidthHeight( int& o_width , int& o_height ) const
{
	o_width  = Width;
	o_height = Height;
}

inline
void Viewport::GetViewport( int& o_left , int& o_bottom , int& o_width , int& o_height ) const
{
	o_left   = Left;
	o_bottom = Bottom;
	o_width  = Width;
	o_height = Height;
}


inline
bool Viewport::IsValidView(void) const
{
	if( Width  == 0 ) return false;
	if( Height == 0 ) return false;
	return true;
}

inline
float Viewport::GetAspect(void) const
{
	return GetAspectWH();
}

inline
float Viewport::GetAspectWH(void) const
{
	if( Height == 0 ) return 0.0f;
	return static_cast<float>(Width) / static_cast<float>(Height);
}

inline
float Viewport::GetAspectHW(void) const
{
	if( Width == 0 ) return 0.0f;
	return static_cast<float>(Height) / static_cast<float>(Width);
}

inline
void Viewport::SetGLViewport(void)
{
	glViewport( Left , Bottom , Width , Height );
}

inline
void Viewport::SetGLScissor(void)
{
	glScissor( Left , Bottom , Width , Height );
}


inline
void Viewport::SetGLBillboardMatrix(bool invert_vertical)
{
	glPushAttrib( GL_TRANSFORM_BIT );

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	if( invert_vertical )
		glOrtho( 0.0 , (GLdouble)Width , (GLdouble)Height , 0.0 , 1.0 , -1.0 );
	else
		glOrtho( 0.0 , (GLdouble)Width , 0.0 , (GLdouble)Height , 1.0 , -1.0 );

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glPopAttrib();
}


inline
bool Viewport::Contains( int i_x , int i_y ) const
{
	if( i_x < Left   ) return false;
	if( i_y < Bottom ) return false;
	if( i_x > ( Left   + Width - 1 ) ) return false;
	if( i_y > ( Bottom + Height -1 ) ) return false;

	return true;
}


inline
void Viewport::GetGlArray( GLint* o_array ) const
{
	o_array[0] = static_cast<GLint>( Left   );
	o_array[1] = static_cast<GLint>( Bottom );
	o_array[2] = static_cast<GLint>( Width  );
	o_array[3] = static_cast<GLint>( Height );
}


}
