#pragma once

#include "../graph/RawImage.h"

#include "TextureTypes.h"


namespace lib_gl
{


//! 2Dテクスチャクラス
template<typename T>
class Texture2D : public lgr::RawImage<T>
{
public:
	Texture2D(void)
		: lgr::RawImage<T>()
	{
		ClearTextureParameters( *this );
	}
	
	Texture2D(size_t num_x, size_t num_y)
		: lgr::RawImage<T>( num_x , num_y )
	{
		ClearTextureParameters( *this );
	}

	Texture2D(size_t num_x, size_t num_y, const T& initial_value)
		: lgr::RawImage<T>( num_x , num_y , initial_value )
	{
		ClearTextureParameters( *this );
	}

	//! コピーコンストラクタ.
	Texture2D(const Texture2D<T>& m) : lgr::RawImage<T>( m )
	{
		m_MipmapLevel    = m.m_MipmapLevel;
		m_BorderSize     = m.m_BorderSize;
		m_InternalFormat = m.m_InternalFormat;
		m_PixelFormat    = m.m_PixelFormat;
		m_PixelDataType  = m.m_PixelDataType;
	}

	//! 2Dテクスチャバッファを生成
	void Attach( lib_gl::TEXTURE_MODE i_Mode = TEXTURE_NORMAL );

	//! テクスチャフォーマットをセットする.
	void SetTexelFormats( GLint i_InternalFormat , GLenum i_PixelFormat , GLenum i_PixelDataType );
	void SetTexelFormats( GLenum i_PixelFormat , GLenum i_PixelDataType );

	//! テクスチャパラメータのクリア
	void ClearTextureParameters(void);


protected:
	static void ClearTextureParameters( Texture2D<T>& o_texture );

	// テクセル型に対する適切なアライメント(テクスチャ1行のバイト数の最大約数) を求める.
	// 基本的には, RGB * byte の組み合わせのみ1, それ以外は4.
	template<typename T>
	static GLint GetAlignmentLength(void) { return 4; }
	template<>
	static GLint GetAlignmentLength< lgr::color3b >(void) { return 1; }


public:
	GLint  m_MipmapLevel;    //!< ミップマップレベル
	GLint  m_BorderSize;     //!< 境界線の幅

	GLint  m_InternalFormat; //!< OpenGL内部のテクセル形式
	GLenum m_PixelFormat;    //!< 入力バッファのテクセル形式
	GLenum m_PixelDataType;  //!< テクセルの各チャンネルのデータ型
};


// typedef
typedef Texture2D<lgr::color3b> Texture2D3b;
typedef Texture2D<lgr::color3f> Texture2D3f;
typedef Texture2D<lgr::color3i> Texture2D3i;
typedef Texture2D<lgr::color3d> Texture2D3d;
typedef Texture2D<lgr::color4b> Texture2D4b;
typedef Texture2D<lgr::color4f> Texture2D4f;
typedef Texture2D<lgr::color4i> Texture2D4i;
typedef Texture2D<lgr::color4d> Texture2D4d;



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

//! OpenGLのカレントテクスチャに割り当てる.
template<typename T> inline
void Texture2D<T>::Attach( lib_gl::TEXTURE_MODE i_Mode )
{
	// フォーマットが設定されているか確認.
	_ASSERTE( m_InternalFormat != 0 );
	if( m_InternalFormat == 0 )
		return;

	_ASSERTE( m_PixelFormat != 0 );
	if( m_PixelFormat == 0 )
		return;

	_ASSERTE( m_PixelDataType != 0 );
	if( m_PixelDataType == 0 )
		return;

	if( i_Mode == TEXTURE_NORMAL )
	{
		glPixelStorei( GL_UNPACK_ALIGNMENT , GetAlignmentLength<T>() );

		glTexImage2D( GL_TEXTURE_2D
	              , m_MipmapLevel
	              , m_InternalFormat
	              , size_x() , size_y()
	              , m_BorderSize
	              , m_PixelFormat , m_PixelDataType
	              , v()
	              );
	}
	else if( i_Mode == TEXTURE_MIPMAP )
	{
		glPixelStorei( GL_UNPACK_ALIGNMENT , GetAlignmentLength<T>() );

		gluBuild2DMipmaps( GL_TEXTURE_2D
		                 , m_InternalFormat
		                 , size_x() , size_y()
		                 , m_PixelFormat , m_PixelDataType
		                 , v()
		                 );
	}
	else
	{
		_ASSERT( false );
	}
}

//! テクスチャフォーマットをセットする.
//! @param[in] i_InternalFormat - OpenGL内で保持するテクセルの型  (GL_RGB,GL_RGBA...)
//! @param[in] i_PixelFormat    - このクラスで保持するテクセルの型  (GL_RGB,GL_RGBA...)
//! @param[in] i_PixelDataType  - １つの色要素のデータ型  (GL_UNSIGNED_BYTE...)
template<typename T> inline
void Texture2D<T>::SetTexelFormats( GLint i_InternalFormat , GLenum i_PixelFormat , GLenum i_PixelDataType )
{
	m_InternalFormat = i_InternalFormat;
	m_PixelFormat    = i_PixelFormat;
	m_PixelDataType  = i_PixelDataType;
}

//! テクスチャフォーマットをセットする.
//! @param[in] i_PixelFormat   - テクセルの型  (GL_RGB,GL_RGBA...)
//! @param[in] i_PixelDataType - １つの色要素のデータ型  (GL_UNSIGNED_BYTE...)
template<typename T> inline
void Texture2D<T>::SetTexelFormats( GLenum i_PixelFormat , GLenum i_PixelDataType )
{
	SetTexelFormats( i_PixelFormat , i_PixelFormat , i_PixelDataType );
}


template<typename T> inline
void Texture2D<T>::ClearTextureParameters(void)
{
	ClearTextureParameters( *this );
}

template<typename T> inline
void Texture2D<T>::ClearTextureParameters( Texture2D<T>& o_texture )
{
	o_texture.m_MipmapLevel    = 0;
	o_texture.m_BorderSize     = 0;

	o_texture.m_InternalFormat = 0;
	o_texture.m_PixelFormat    = 0;
	o_texture.m_PixelDataType  = 0;
}


}
