#include "externals.hh" #include "utilities.hh" #include "texture.hh" #include "globals.hh" #include "odbg.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 ) : levels_( levels ) , width_( width ) , height_( height ) , debugIndex_( -1 ) { 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::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( Globals::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( __rd__ 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( __rd__ 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( __rw__ T_TextureSampler&& other ) noexcept { std::swap( id_ , other.id_ ); std::swap( sampling_ , other.sampling_ ); std::swap( lodSampling_ , other.lodSampling_ ); std::swap( hasLOD_ , other.hasLOD_ ); setSamplingMode( ); } T_TextureSampler& T_TextureSampler::operator =( __rw__ T_TextureSampler&& other ) noexcept { std::swap( id_ , other.id_ ); std::swap( sampling_ , other.sampling_ ); std::swap( lodSampling_ , other.lodSampling_ ); std::swap( hasLOD_ , other.hasLOD_ ); return *this; } T_TextureSampler::~T_TextureSampler( ) { if ( id_ != 0 ) { glDeleteSamplers( 1 , &id_ ); } } /*----------------------------------------------------------------------------*/ T_TextureSampler& T_TextureSampler::sampling( __rd__ const E_TexSampling mode ) { sampling_ = mode; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::noMipmap( ) { hasLOD_ = false; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::mipmap( __rd__ const E_TexSampling mode ) { hasLOD_ = true; lodSampling_ = mode; setSamplingMode( ); return *this; } T_TextureSampler& T_TextureSampler::wrap( __rd__ 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( __rd__ const float min , __rd__ 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( ) { std::shared_ptr< T_TextureSampler > tsam; tsam = std::make_shared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::NEAREST ); samplers_[ "nearest-edge" ] = tsam; tsam = std::make_shared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::LINEAR ); samplers_[ "linear-edge" ] = tsam; tsam = std::make_shared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::NEAREST ); samplers_[ "nearest-border" ] = tsam; tsam = std::make_shared< T_TextureSampler >( ); tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::LINEAR ); samplers_[ "linear-border" ] = tsam; } T_TextureSampler const* T_TextureManager::sampler( __rd__ std::string const& name ) const { auto pos( samplers_.find( name ) ); if ( pos == samplers_.end( ) ) { return nullptr; } return (*pos).second.get( ); } void T_TextureManager::bind( __rd__ const uint32_t unit , __rd__ 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( __rd__ const uint32_t unit , __rd__ T_Texture const& texture , __rd__ 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 ); } }