/*
								+--------------------------------+
								|                                |
								|     ***   OpenGL 3.0   ***     |
								|                                |
								|  Copyright © -tHE SWINe- 2009  |
								|                                |
								|           Texture.h            |
								|                                |
								+--------------------------------+
*/

#pragma once
#ifndef __TEXTURE_MANAGER3_INCLUDED
#define __TEXTURE_MANAGER3_INCLUDED

/**
 *	@file gl3/Texture.h
 *	@author -tHE SWINe-
 *	@date 2009
 *	@brief OpenGL 3.0 textures
 *
 *	@todo Write documentation for this, make sure all useful extensions are implemented.
 *	@todo Implement GL_ARB_texture_multisample, GL_ARB_texture_cube_map_array, GL_EXT_texture_array, GL_EXT_texture_buffer_object.
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#include "OpenGL30.h"

class CGLTexture {
protected:
	GLuint m_n_id;
	GLenum m_n_internal_format; // GL_RGB8
	GLenum m_n_target; // GL_TEXTURE_2D

public:
	/*
	 *	CGLTexture::CGLTexture(GLenum n_internal_format, GLenum n_target)
	 *		- constructor accepting some of texture properties
	 *		- creates no texture object
	 */
	CGLTexture(GLenum n_internal_format, GLenum n_target);

	/*
	 *	CGLTexture::~CGLTexture()
	 *		- default destructor
	 *		- deletes OpenGL texture object in case it was created
	 */
	~CGLTexture();

	/*
	 *	bool CGLTexture::b_Status() const
	 *		- returns true in case texture was successfuly created and can be used for texturing
	 */
	bool b_Status() const;

	inline void Bind() const { glBindTexture(m_n_target, m_n_id); }

	inline GLenum n_Pixel_Format() const { return m_n_internal_format; }

	inline GLenum n_Target() const { return m_n_target; }

	// texture parameter getters; texture must be bound to use them
	GLenum n_Get_Texture_Wrap_S() const;
	GLenum n_Get_Texture_Wrap_T() const;
	GLenum n_Get_Texture_Wrap_R() const;
	GLenum n_Get_Texture_Min_Filter() const;
	GLenum n_Get_Texture_Mag_Filter() const;
	float f_Get_Texture_Min_LOD() const;
	float f_Get_Texture_Max_LOD() const;
	float f_Get_Texture_LOD_Bias() const;
	int n_Get_Texture_Base_Level() const;
	int n_Get_Texture_Max_Level() const;
	GLenum n_Get_Texture_Compare_Mode() const;
	GLenum n_Get_Texture_Compare_Func() const;
	float f_Get_Texture_Anisotropy() const;

	// texture parameter setters; texture must be bound to use them
	// note those involve calling glGetIntegerv() / glGetFloatv(),
	// and possibly unwanted GPU / CPU synchronisation
	void Set_Texture_Wrap_S(GLenum n_wrap_mode);
	void Set_Texture_Wrap_T(GLenum n_wrap_mode);
	void Set_Texture_Wrap_R(GLenum n_wrap_mode);
	void Set_Texture_Min_Filter(GLenum n_minify_filter);
	void Set_Texture_Mag_Filter(GLenum n_magnify_filter);
	void Set_Texture_Min_LOD(float f_min_lod);
	void Set_Texture_Max_LOD(float f_max_lod);
	void Set_Texture_LOD_Bias(float f_lod_bias);
	void Set_Texture_Base_Level(int n_base_level);
	void Set_Texture_Max_Level(int n_max_level);
	void Set_Texture_Compare_Mode(GLenum n_compare_mode);
	void Set_Texture_Compare_Func(GLenum n_compare_func);
	void Set_Texture_Anisotropy(float f_anisotropy);

	/**
	 *	@brief gets maximal texture size
	 *
	 *	@return Returns maximal texture size.
	 *
	 *	@note This involves calling glGetIntegerv(), and possibly unwanted GPU / CPU synchronisation.
	 */
	static int n_Max_Size();

	/**
	 *	@brief gets maximal texture anisotropy
	 *
	 *	@return Returns maximal texture anisotropy.
	 *
	 *	@note This involves calling glGetFloatv(), and possibly unwanted GPU / CPU synchronisation.
	 */
	static float f_Max_Anisotropy();

private:
	friend class CGLFrameBufferObject;

	/*
	 *	inline GLuint n_Id() const
	 *		- for use within CGLTexture_Friend inheritants
	 *		- do not free the texture nor change it's parameters, purpose is
	 *		  to enable access to texture id to functions needing it (such as
	 *		  framebuffer object texture binding, etc)
	 */
	inline GLuint n_Id() const { return m_n_id; }
};

class CGLTexture_1D : public CGLTexture {
protected:
	int m_n_width;

public:
	/*
	 *	CGLTexture_1D::CGLTexture_1D(CGLState *p_state, int n_width, GLenum n_internal_format,
	 *		bool b_create_mipmaps = true, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates one-dimensional texture of size n_width and color format n_internal format
	 *		  with border n_border_width pixels wide
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_1D(int n_width, GLenum n_internal_format,
		bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
};

class CGLTexture_2D : public CGLTexture {
protected:
	int m_n_width;
	int m_n_height;

public:
	/*
	 *	CGLTexture_2D::CGLTexture_2D(CGLState *p_state, int n_width, int n_height,
	 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates two-dimensional texture of size n_width per n_height and color format
	 *		  n_internal format with border n_border_width pixels wide
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_2D(int n_width, int n_height, GLenum n_internal_format,
		bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
};

class CGLTexture_Rect : public CGLTexture {
protected:
	int m_n_width;
	int m_n_height;

public:
	/*
	 *	CGLTexture_Rect::CGLTexture_Rect(CGLState *p_state, int n_width, int n_height,
	 *		GLenum n_internal_format, GLenum n_format = GL_RGB,
	 *		GLenum n_data_type = GL_UNSIGNED_BYTE, const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates two-dimensional texture of size n_width per n_height and color format
	 *		  n_internal format (no border and no mip-mapping allowed for rectangle textures)
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_Rect(int n_width, int n_height, GLenum n_internal_format,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
};

class CGLTexture_3D : public CGLTexture {
protected:
	int m_n_width;
	int m_n_height;
	int m_n_depth;

public:
	/*
	 *	CGLTexture_3D::CGLTexture_3D(CGLState *p_state, int n_width, int n_height, int n_depth,
	 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates three-dimensional texture of size n_width per n_height per n_depth
	 *		  and color format n_internal format with border n_border_width pixels wide
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_3D(int n_width, int n_height, int n_depth,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
	inline int n_Depth() const { return m_n_depth; }
};

class CGLTexture_1D_Array : public CGLTexture {
protected:
	int m_n_width;
	int m_n_layer_num;

public:
	/*
	 *	CGLTexture_3D::CGLTexture_3D(CGLState *p_state, int n_width, int n_height, int n_depth,
	 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates three-dimensional texture of size n_width per n_height per n_depth
	 *		  and color format n_internal format with border n_border_width pixels wide
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_1D_Array(int n_width, int n_layer_num,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Layer_Num() const { return m_n_layer_num; }
};

class CGLTexture_2D_Array : public CGLTexture {
protected:
	int m_n_width;
	int m_n_height;
	int m_n_layer_num;

public:
	/*
	 *	CGLTexture_3D::CGLTexture_3D(CGLState *p_state, int n_width, int n_height, int n_depth,
	 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates three-dimensional texture of size n_width per n_height per n_depth
	 *		  and color format n_internal format with border n_border_width pixels wide
	 *		- texture can be initialized with image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_2D_Array(int n_width, int n_height, int n_layer_num,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
	inline int n_Layer_Num() const { return m_n_layer_num; }
};

class CGLTexture_Cube : public CGLTexture {
protected:
	static const GLenum p_cube_face[6];
	int m_n_width;

public:
	/*
	 *	CGLTexture_Cube::CGLTexture_Cube(CGLState *p_state, int n_width, GLenum n_internal_format,
	 *		bool b_create_mipmaps = true, bool b_software_mipmaps = false, int n_border_width = 0,
	 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
	 *		const void *p_src_data[6] = 0)
	 *		- default constructor
	 *		- p_state is OpenGL state guard
	 *		- creates cube-map texture of size n_width per n_width per n_width
	 *		  and color format n_internal format with border n_border_width pixels wide
	 *		- texture can be initialized with six images image of color format n_format stored in
	 *		  data type n_data_type in array p_src_data (in order x- x+ y- y+ z- z+)
	 *		- call b_Status() to find out wheter constructor succeeded
	 *		- note this calls glGetError() and so it fails in case there are some
	 *		  uncaught errors despite texture creation is successful
	 */
	CGLTexture_Cube(int n_width, GLenum n_internal_format,
		bool b_create_mipmaps = true, bool b_software_mipmaps = false,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data[6] = 0);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_width; }
	inline int n_Depth() const { return m_n_width; }
};

#endif // !__TEXTURE_MANAGER3_INCLUDED
