#include "externals.hh" #include "ui.hh" #include "ui-odbg.hh" #include "ui-texture.hh" #include "ui-utilities.hh" /*==============================================================================*/ T_Texture::T_Texture( const uint32_t width , const uint32_t height , const E_TexType type , const uint32_t levels ) : levels_( levels ) , width_( width ) , height_( height ) , debugIndex_( -1 ) { assert( levels > 0 ); glGenTextures( 1 , &id_ ); glBindTexture( GL_TEXTURE_2D , id_ ); 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::RGB8: ifmt_ = GL_RGB8; fmt_ = GL_RGB; dt_ = GL_UNSIGNED_BYTE; break; case E_TexType::RGB16F: ifmt_ = GL_RGB16F; fmt_ = GL_RGB; 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_BASE_LEVEL , 0 ); glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , levels - 1 ); glTexParameterf( GL_TEXTURE_2D , GL_TEXTURE_MIN_LOD , 0 ); glTexParameterf( GL_TEXTURE_2D , GL_TEXTURE_MAX_LOD , levels - 1 ); glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ); uint32_t w = width , h = height; for ( auto i = 0u ; i < levels ; i ++ ) { #ifdef INTRUSIVE_TRACES printf( "init %p txid %d lv %d sz %dx%d\n" , this , id_ , i , w , h ); #endif glTexImage2D( GL_TEXTURE_2D , i , ifmt_ , w , h , 0 , fmt_ , dt_ , nullptr ); w >>= 1; h >>= 1; assert( w && h ); } // GL_ASSERT( ); } T_Texture::~T_Texture( ) { if ( debugIndex_ != -1 ) { auto& odbg( UI::ODbg( ) ); assert( odbg.outputs_[ debugIndex_ ].id == id_ ); assert( odbg.nRegistered_ > 0 ); odbg.outputs_[ debugIndex_ ].id = 0; odbg.nRegistered_ --; } glDeleteTextures( 1 , &id_ ); } T_Texture& T_Texture::samplingMode( const E_TexSampling mode ) { glBindTexture( GL_TEXTURE_2D , id_ ); GLenum min , max; switch ( mode ) { case E_TexSampling::NEAREST: min = levels_ > 1 ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; max = GL_NEAREST; break; case E_TexSampling::LINEAR: min = levels_ > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; max = GL_LINEAR; break; } glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , min ); glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , max ); return *this; } T_Texture& T_Texture::wrap( const E_TexWrap mode ) { GLenum gm; switch ( mode ) { case E_TexWrap::REPEAT: gm = GL_REPEAT; break; case E_TexWrap::CLAMP_EDGE: gm = GL_CLAMP_TO_EDGE; break; case E_TexWrap::CLAMP_BORDER: gm = GL_CLAMP_TO_BORDER; break; } glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , gm ); glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , gm ); return *this; } /*==============================================================================*/ T_TextureSampler::T_TextureSampler( ) { glGenSamplers( 1 , &id_ ); //GL_ASSERT( ); } T_TextureSampler::T_TextureSampler( T_TextureSampler&& other ) noexcept { swap( id_ , other.id_ ); swap( sampling_ , other.sampling_ ); swap( lodSampling_ , other.lodSampling_ ); swap( hasLOD_ , other.hasLOD_ ); setSamplingMode( ); } T_TextureSampler& T_TextureSampler::operator =( T_TextureSampler&& other ) noexcept { swap( id_ , other.id_ ); swap( sampling_ , other.sampling_ ); swap( lodSampling_ , other.lodSampling_ ); swap( hasLOD_ , other.hasLOD_ ); return *this; } T_TextureSampler::~T_TextureSampler( ) { if ( id_ != 0 ) { glDeleteSamplers( 1 , &id_ ); } } /*----------------------------------------------------------------------------*/ T_TextureSampler& T_TextureSampler::sampling( const E_TexSampling mode ) { sampling_ = mode; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::noMipmap( ) { hasLOD_ = false; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::mipmap( const E_TexSampling mode ) { hasLOD_ = true; lodSampling_ = mode; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::wrap( const E_TexWrap mode ) { GLenum gm; switch ( mode ) { case E_TexWrap::REPEAT: gm = GL_REPEAT; break; case E_TexWrap::CLAMP_EDGE: gm = GL_CLAMP_TO_EDGE; break; case E_TexWrap::CLAMP_BORDER: gm = GL_CLAMP_TO_BORDER; break; } glSamplerParameteri( id_ , GL_TEXTURE_WRAP_S , gm ); glSamplerParameteri( id_ , GL_TEXTURE_WRAP_T , gm ); //GL_ASSERT( ); return *this; } T_TextureSampler& T_TextureSampler::lod( const float min , const float max ) { glSamplerParameterf( id_ , GL_TEXTURE_MIN_LOD , min ); glSamplerParameterf( id_ , GL_TEXTURE_MAX_LOD , max ); //GL_ASSERT( ); return *this; } /*----------------------------------------------------------------------------*/ void T_TextureSampler::setSamplingMode( ) const { GLenum min , max; if ( hasLOD_ ) { switch ( sampling_ ) { case E_TexSampling::NEAREST: min = lodSampling_ == E_TexSampling::LINEAR ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; max = GL_NEAREST; break; case E_TexSampling::LINEAR: min = lodSampling_ == E_TexSampling::LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST; max = GL_LINEAR; break; } } else { min = ( sampling_ == E_TexSampling::LINEAR ) ? GL_LINEAR : GL_NEAREST; max = min; } glSamplerParameteri( id_ , GL_TEXTURE_MIN_FILTER , min ); glSamplerParameteri( id_ , GL_TEXTURE_MAG_FILTER , max ); //GL_ASSERT( ); } /*============================================================================*/ constexpr uint32_t T_TextureManager::MaxUnits; T_TextureManager::T_TextureManager( ) { T_SharedPtr< T_TextureSampler > tsam; tsam = NewShared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::NEAREST ); samplers_.add( T_String::Pooled( "nearest-edge" ) , std::move( tsam ) ); tsam = NewShared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::LINEAR ); samplers_.add( T_String::Pooled( "linear-edge" ) , std::move( tsam ) ); tsam = NewShared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::NEAREST ); samplers_.add( T_String::Pooled( "nearest-border" ) , std::move( tsam ) ); tsam = NewShared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::LINEAR ); samplers_.add( T_String::Pooled( "linear-border" ) , std::move( tsam ) ); } T_TextureSampler const* T_TextureManager::sampler( T_String const& name ) const { auto const* t( samplers_.get( name ) ); return t ? ( (T_TextureSampler const*) *t ) : nullptr; } void T_TextureManager::bind( const uint32_t unit , T_Texture const& texture ) { assert( unit < MaxUnits ); auto& u( bindings_[ unit ] ); if ( u.texture == texture.id( ) && !u.sampler ) { return; } u.texture = texture.id( ); u.sampler = 0; glBindTextureUnit( unit , texture.id( ) ); glBindSampler( unit , 0 ); } void T_TextureManager::bind( const uint32_t unit , T_Texture const& texture , T_TextureSampler const& sampler ) { assert( unit < MaxUnits ); auto& u( bindings_[ unit ] ); if ( u.texture == texture.id( ) && u.sampler == sampler.id( ) ) { return; } u.texture = texture.id( ); u.sampler = sampler.id( ); glBindTextureUnit( unit , texture.id( ) ); glBindSampler( unit , sampler.id( ) ); } void T_TextureManager::reset( ) { for ( auto i = 0u ; i < MaxUnits ; i ++ ) { auto& u( bindings_[ i ] ); u.texture = 0; u.sampler = 0; glBindTextureUnit( i , 0 ); glBindSampler( i , 0 ); } }