/********************************************************************/
/* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/

/**
 * @file Texture.h
 * @brief クラス MGGridCursor の宣言
 */
#ifndef _mgTexture_HH
#define _mgTexture_HH

#include "mg/MGCL.h"

class MGImage;
class mgGLSLProgram;

// @class mgTexture Texture.h "mgGL/Texture.h"

///Texture definition class.

///Before use of mgTexture, set_image must be invoked, and
///set_sampler is optionally invoked. If set_sampler is not invoked,
///uniform of spampler2D  "texture1" is assumed.
///Since mgTexture does not invoke glUseProgram(mgGLSLProgram's use() function)
///the current program's uniform variable texture1(or the variable set by set_sampler)
///must be spamler2D.
///When set_textureUnit is not invoked, unit number 0 is assumed.
class MG_DLL_DECLR mgTexture{

public:

	/// デフォルトコンストラクター
	///Before use of mgTexture, set_image and set_sampler must be invoked.
	mgTexture(
		GLenum target=GL_TEXTURE_2D///Currently only GL_TEXTURE_2D is allowed.
	);

	~mgTexture();

	///Set the glsl program and sampler variable name of 
	///*****glUseProgram() is not invoked, glsl must be the current program.
	void set_sampler(mgGLSLProgram* glsl, const std::string& samplerName);

	const std::string& getDefaultSamplerVariable()const;


	///image データをtextureにセットする
	/// @note pixelsピクセルデータのフォーマットについて説明すると、
	/// GLuint 型の配列を利用し、各 4 バイトを 1 ピクセルの色に対応させている。
	/// 整数の上位バイトから A, B, G, R の順に格納されていることを前提とする。
	/// 例えば値 0xFF000000, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF はそれぞれ
	/// 黒、青、緑、赤を意味する。
	///Set the image data. set_image() invokes:
	///1. glGenTextures(if m_textureID was 0)
	///2. glBindTexture
	///3. glTexImage2D or glTexStorege2D
	///4. glTexSubImage2D
	///*******After set_image is invoked, image data is unnecessary since the data 
	///is transfered to GPU.
	void set_image(
		GLsizei width ///< ビットマップデータの横幅。ピクセル幅
		,GLsizei height///< ビットマップデータの縦幅。
		,const GLuint* pixels///< RGBA バイト列。各整数の上位バイトが A 値。
		,bool mutableTexture=true///<true if mutable, false, if immutable.
		,bool isPointSprite = false///<true if point sprite.
		,GLint wrap=GL_REPEAT///<GL_TEXTURE_WRAP_S&GL_TEXTURE_WRAP_Tに指定するparameterを指定
			///<GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_MIRRORED_REPEAT,
            ///<or GL_MIRROR_CLAMP_TO_EDGEGL_REPEAT.
		,GLint magminFilter=GL_LINEAR///<GL_TEXTURE_MAG_FILTER&GL_TEXTURE_MIN_FILTERに
			///<指定するparameterを指定する:GL_NEAREST,GL_LINEAR,GL_NEAREST_MIPMAP_NEAREST,
			///<GL_LINEAR_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_LINEAR
			///<いずれか。GL_TEXTURE_MAG_FILTER&GL_TEXTURE_MIN_FILTER双方に同じ値がセットされる。
	);

	///Set the image data from other MGImage. This type of set_image uses image.width(), .height(),
	///and .image(), and invoke above set_image.
	///set_image() invokes:
	///1. glGenTextures(if m_textureIDwas 0),
	///2. glBindTexture
	///3. glTexImage2D or  glTexStorege2D
	///4. glTexSubImage2D
	///*******After set_image is invoked, image data is unnecessary since teh data 
	///is transfered to GPU.
	void set_image(
		const MGImage& image///<Original image.
		,bool mutableTexture=true///<true if mutable, false, if immutable.
		,bool isPointSprite=false///<true if point sprite.
		,GLint wrap=GL_REPEAT///GL_TEXTURE_WRAP_S&GL_TEXTURE_WRAP_Tに指定するparameterを指定
			///GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_MIRRORED_REPEAT,
            ///or GL_MIRROR_CLAMP_TO_EDGEGL_REPEAT.
		,GLint magminFilter=GL_LINEAR///GL_TEXTURE_MAG_FILTER&GL_TEXTURE_MIN_FILTERに
			///指定するparameterを指定する:GL_NEAREST,GL_LINEAR,GL_NEAREST_MIPMAP_NEAREST,
			///GL_LINEAR_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_LINEAR
			///いずれか。GL_TEXTURE_MAG_FILTER&GL_TEXTURE_MIN_FILTER双方に同じ値がセットされる。
	);

	///When set_textureUnit is not invoked, m_textureUnit=0 is assumed.
	void set_textureUnit(int textureUnit){m_textureUnit=textureUnit;};

	///get texture ID
	GLuint getTextureID()const{return m_textureID;};

	///Use this texture after set_image and set_sampler are invoked.
	///Use() will invoke OpenGL:
	///1. glActiveTexture()
	///2. glBindTexture()
	///4. glSetUniform1i(m_samplerLocation).
	///*****glUseProgram() is not invoked, m_samplerLocation must be 
	///the current program's.
	void use()const;

	GLsizei width()const{return m_width;};
	GLsizei height()const{return m_height;};

private:
	GLsizei m_numberOfTextureLevels;//Currently this is set to 1.
	GLsizei m_width, m_height;///Width and height of the texture.
	GLenum m_target;///Specifies texture target.
		///Must be GL_TEXTURE_XX(GLTEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, or etc.)

	int m_textureUnit;///Texture unit numger(Input of setUnifrom).
		///Input of glActiveTexture is GL_TEXTURE0+m_textureUnit(note that this is int).
	
	GLuint m_textureID;///Texture object id generated by glGenTextures.

	mutable int m_samplerLocation;///m_glsl's uniform sampler(2D?) location..
		///mgTexture will invoke glSetUniform1i(m_samplerLocation);
};///_mgTexture_HH
#endif