#include "externals.hh"
#include "texture.hh"


T_Texture::T_Texture(
		__rd__ const uint32_t width ,
		__rd__ const uint32_t height ,
		__rd__ const E_TexType type ,
		__rd__ const uint32_t levels )
	: width_( width ) , height_( height )
{
	assert( levels > 0 );

	glGenTextures( 1 , &id_ );
	glBindTexture( GL_TEXTURE_2D , id_ );

	GLenum ifmt , fmt , dt;
	switch ( type ) {
		case E_TexType::RGBA8:
			ifmt = GL_RGBA8;
			fmt = GL_RGBA;
			dt = GL_UNSIGNED_BYTE;
			break;

		case E_TexType::RGBA16F:
			ifmt = GL_RGBA16F;
			fmt = GL_RGBA;
			dt = GL_FLOAT;
			break;

		case E_TexType::R8:
			ifmt = GL_R8;
			fmt = GL_RED;
			dt = GL_UNSIGNED_BYTE;
			break;

		case E_TexType::R16F:
			ifmt = GL_R16F;
			fmt = GL_RED;
			dt = GL_FLOAT;
			break;
	}

	glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_LOD , 0 );
	glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAX_LOD , levels - 1 );

	uint32_t w = width , h = height;
	for ( auto i = 0u ; i < levels ; i ++ ) {
		glTexImage2D( GL_TEXTURE_2D , i , ifmt , w , h , 0 , fmt , dt , nullptr );
		w >>= 1;
		h >>= 1;
		assert( w && h );
	}

	assert( glGetError( ) == GL_NO_ERROR );

	glBindTexture( GL_TEXTURE_2D , 0 );
}

T_Texture::~T_Texture( )
{
	glDeleteTextures( 1 , &id_ );
}


/*============================================================================*/


T_TextureBinding::T_TextureBinding(
		__rd__ const uint32_t binding )
	: binding_( binding ) , uniform_( 0 ) , texture_( nullptr )
{ }

void T_TextureBinding::clear( )
{
	uniform_ = 0;
	texture_ = nullptr;
}

void T_TextureBinding::set(
		__rd__ const uint32_t uniform ,
		__rd__ T_Texture const& texture )
{
	uniform_ = uniform;
	texture_ = &texture;
}

void T_TextureBinding::bind( ) const
{
	glActiveTexture( GL_TEXTURE0 + binding_ );
	glBindTexture( GL_TEXTURE_2D , texture_ ? texture_->id( ) : 0 );
	glUniform1i( uniform_ , binding_ );
	assert( glGetError( ) == GL_NO_ERROR );
}