text: #include "Texture.h"
  #include <GL/glew.h>
  #include <assert.h>
  #include "Image.h"
  
  namespace sgl {
  
  	Texture::Texture(
  		const std::string& file, 
  		const PixelElementSize pixel_element_size /*= PixelElementSize::BYTE*/, 
  		const PixelStructure pixel_structure /*= PixelStructure::RGB_ALPHA*/) :
  		pixel_element_size_(pixel_element_size),
  		pixel_structure_(pixel_structure)
  	{
  		Image img(file, pixel_element_size_, pixel_structure_);
  		size_ = img.GetSize();
  
  		glGenTextures(1, &texture_id_);
  		glBindTexture(GL_TEXTURE_2D, texture_id_);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  		glTexImage2D(
  			GL_TEXTURE_2D,
  			0,
  			ConvertToGLType(pixel_element_size_, pixel_structure_),
  			static_cast<GLsizei>(size_.first),
  			static_cast<GLsizei>(size_.second),
  			0,
  			ConvertToGLType(pixel_structure_),
  			ConvertToGLType(pixel_element_size_),
  			img.Data());
  		glGenerateMipmap(GL_TEXTURE_2D);
  
  	}
  
  	Texture::~Texture()
  	{
  		glDeleteTextures(1, &texture_id_);
  	}
  
  	void Texture::Bind(const unsigned int slot /*= 0*/) const
  	{
  		glActiveTexture(GL_TEXTURE0 + slot);
  		glBindTexture(GL_TEXTURE_2D, texture_id_);
  	}
  
  	void Texture::UnBind() const
  	{
  		glBindTexture(GL_TEXTURE_2D, 0);
  	}
  
  	TextureManager::~TextureManager()
  	{
  		DisableAll();
  	}
  
  	bool TextureManager::AddTexture(
  		const std::string& name, 
  		const std::shared_ptr<sgl::Texture>& texture)
  	{
  		auto ret = name_texture_map_.insert({ name, texture });
  		return ret.second;
  	}
  
  	bool TextureManager::RemoveTexture(const std::string& name)
  	{
  		auto it = name_texture_map_.find(name);
  		if (it == name_texture_map_.end())
  		{
  			return false;
  		}
  		name_texture_map_.erase(it);
  		return true;
  	}
  
  	const int TextureManager::EnableTexture(const std::string& name) const
  	{
  		auto it1 = name_texture_map_.find(name);
  		if (it1 == name_texture_map_.end())
  		{
  			throw std::runtime_error("try to enable a texture: " + name);
  		}
  		for (int i = 0; i < name_array_.size(); ++i)
  		{
  			if (name_array_[i].empty())
  			{
  				name_array_[i] = name;
  				it1->second->Bind(i);
  				return i;
  			}
  		}
  		throw std::runtime_error("No free slots!");
  	}
  
  	void TextureManager::DisableTexture(const std::string& name) const
  	{
  		auto it1 = name_texture_map_.find(name);
  		if (it1 == name_texture_map_.end())
  		{
  			throw std::runtime_error("no texture named: " + name);
  		}
  		auto it2 = std::find_if(
  			name_array_.begin(),
  			name_array_.end(),
  			[name](const std::string& value)
  		{
  			return value == name;
  		});
  		if (it2 != name_array_.end())
  		{
  			*it2 = "";
  			it1->second->UnBind();
  		}
  		else
  		{
  			throw std::runtime_error("No slot bind to: " + name);
  		}
  	}
  
  	void TextureManager::DisableAll() const
  	{
  		for (int i = 0; i < 32; ++i)
  		{
  			if (!name_array_[i].empty())
  			{
  				DisableTexture(name_array_[i]);
  			}
  		}
  	}
  
  	TextureCubeMap::TextureCubeMap(
  		const std::array<std::string, 6>& cube_file, 
  		const PixelElementSize pixel_element_size /*= PixelElementSize::BYTE*/, 
  		const PixelStructure pixel_structure /*= PixelStructure::RGB_ALPHA*/) :
  		Texture(pixel_element_size, pixel_structure)
  	{
  		CreateCubeMap();
  
  		for (int i = 0; i < 6; i++) {
  			Image img(cube_file[i], pixel_element_size_, pixel_structure_);
  			size_ = img.GetSize();
  
  			glTexImage2D(
  				GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
  				0,
  				ConvertToGLType(pixel_element_size_, pixel_structure_),
  				static_cast<GLsizei>(size_.first),
  				static_cast<GLsizei>(size_.second),
  				0,
  				ConvertToGLType(pixel_structure_),
  				ConvertToGLType(pixel_element_size_),
  				img.Data());
  			glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
  		}
  	}
  
  	void TextureCubeMap::CreateCubeMap()
  	{
  		glGenTextures(1, &texture_id_);
  		glBindTexture(GL_TEXTURE_CUBE_MAP, texture_id_);
  		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  	}
  
  } // End namespace sgl.
  