2017-09-30 12:59:04 +02:00
|
|
|
#include "externals.hh"
|
2017-10-01 18:51:02 +02:00
|
|
|
#include "utilities.hh"
|
2017-09-30 12:59:04 +02:00
|
|
|
#include "texture.hh"
|
|
|
|
|
|
|
|
|
2017-10-02 10:42:06 +02:00
|
|
|
/*==============================================================================*/
|
|
|
|
|
2017-09-30 12:59:04 +02:00
|
|
|
T_Texture::T_Texture(
|
|
|
|
__rd__ const uint32_t width ,
|
|
|
|
__rd__ const uint32_t height ,
|
|
|
|
__rd__ const E_TexType type ,
|
|
|
|
__rd__ const uint32_t levels )
|
2017-09-30 17:58:48 +02:00
|
|
|
: levels_( levels ) , width_( width ) , height_( height )
|
2017-09-30 12:59:04 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2017-09-30 17:58:48 +02:00
|
|
|
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;
|
|
|
|
|
2017-09-30 12:59:04 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-09-30 17:58:48 +02:00
|
|
|
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 );
|
2017-09-30 12:59:04 +02:00
|
|
|
|
|
|
|
uint32_t w = width , h = height;
|
|
|
|
for ( auto i = 0u ; i < levels ; i ++ ) {
|
2017-10-01 18:51:02 +02:00
|
|
|
#ifdef INTRUSIVE_TRACES
|
|
|
|
printf( "init %p txid %d lv %d sz %dx%d\n" , this , id_ ,
|
|
|
|
i , w , h );
|
|
|
|
#endif
|
2017-09-30 12:59:04 +02:00
|
|
|
glTexImage2D( GL_TEXTURE_2D , i , ifmt , w , h , 0 , fmt , dt , nullptr );
|
2017-09-30 15:28:24 +02:00
|
|
|
w >>= 1;
|
|
|
|
h >>= 1;
|
2017-09-30 12:59:04 +02:00
|
|
|
assert( w && h );
|
|
|
|
}
|
|
|
|
|
2017-10-02 13:51:08 +02:00
|
|
|
GL_ASSERT( );
|
2017-09-30 12:59:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
T_Texture::~T_Texture( )
|
|
|
|
{
|
|
|
|
glDeleteTextures( 1 , &id_ );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-30 17:58:48 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-02 10:42:06 +02:00
|
|
|
/*==============================================================================*/
|
|
|
|
|
|
|
|
T_TextureSampler::T_TextureSampler( )
|
|
|
|
{
|
|
|
|
glGenSamplers( 1 , &id_ );
|
2017-10-02 13:51:08 +02:00
|
|
|
GL_ASSERT( );
|
2017-10-02 10:42:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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 );
|
2017-10-02 13:51:08 +02:00
|
|
|
GL_ASSERT( );
|
2017-10-02 10:42:06 +02:00
|
|
|
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 );
|
2017-10-02 13:51:08 +02:00
|
|
|
GL_ASSERT( );
|
2017-10-02 10:42:06 +02:00
|
|
|
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 );
|
2017-10-02 13:51:08 +02:00
|
|
|
GL_ASSERT( );
|
2017-10-02 10:42:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-30 12:59:04 +02:00
|
|
|
/*============================================================================*/
|
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
constexpr uint32_t T_TextureManagement::MaxUnits;
|
|
|
|
std::unique_ptr< T_TextureManagement > T_TextureManagement::instance_;
|
2017-09-30 12:59:04 +02:00
|
|
|
|
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
T_TextureManagement& T_TextureManagement::TM( )
|
2017-09-30 12:59:04 +02:00
|
|
|
{
|
2017-10-02 14:48:16 +02:00
|
|
|
if ( !instance_ ) {
|
|
|
|
instance_.reset( new T_TextureManagement( ) );
|
|
|
|
}
|
|
|
|
return *instance_;
|
2017-09-30 12:59:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
void T_TextureManagement::Shutdown( )
|
2017-09-30 12:59:04 +02:00
|
|
|
{
|
2017-10-02 14:48:16 +02:00
|
|
|
instance_.reset( );
|
2017-09-30 12:59:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
|
|
|
|
T_TextureManagement::T_TextureManagement( )
|
2017-09-30 12:59:04 +02:00
|
|
|
{
|
2017-10-02 14:48:16 +02:00
|
|
|
std::shared_ptr< T_TextureSampler > tsam;
|
2017-10-02 10:57:51 +02:00
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
tsam = std::make_shared< T_TextureSampler >( );
|
|
|
|
tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::NEAREST );
|
|
|
|
samplers_[ "nearest-edge" ] = tsam;
|
2017-10-02 10:57:51 +02:00
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
tsam = std::make_shared< T_TextureSampler >( );
|
|
|
|
tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::LINEAR );
|
|
|
|
samplers_[ "linear-edge" ] = tsam;
|
2017-10-02 10:57:51 +02:00
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
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_TextureManagement::sampler(
|
|
|
|
__rd__ std::string const& name ) const
|
|
|
|
{
|
|
|
|
auto pos( samplers_.find( name ) );
|
|
|
|
if ( pos == samplers_.end( ) ) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return (*pos).second.get( );
|
|
|
|
}
|
2017-10-02 10:57:51 +02:00
|
|
|
|
|
|
|
void T_TextureManagement::bind(
|
|
|
|
__rd__ const uint32_t unit ,
|
|
|
|
__rd__ T_Texture const& texture )
|
|
|
|
{
|
|
|
|
assert( unit < MaxUnits );
|
|
|
|
auto& u( bindings_[ unit ] );
|
2017-10-02 14:48:16 +02:00
|
|
|
if ( u.texture == texture.id( ) && !u.sampler ) {
|
2017-10-02 10:57:51 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-02 14:48:16 +02:00
|
|
|
u.texture = texture.id( );
|
|
|
|
u.sampler = 0;
|
|
|
|
glBindTextureUnit( unit , texture.id( ) );
|
|
|
|
glBindSampler( unit , 0 );
|
2017-10-02 10:57:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void T_TextureManagement::bind(
|
|
|
|
__rd__ const uint32_t unit ,
|
2017-10-02 14:48:16 +02:00
|
|
|
__rd__ T_Texture const& texture ,
|
|
|
|
__rd__ T_TextureSampler const& sampler )
|
2017-10-02 10:57:51 +02:00
|
|
|
{
|
|
|
|
assert( unit < MaxUnits );
|
|
|
|
auto& u( bindings_[ unit ] );
|
2017-10-02 14:48:16 +02:00
|
|
|
if ( u.texture == texture.id( ) && u.sampler == sampler.id( ) ) {
|
2017-10-02 10:57:51 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-02 14:48:16 +02:00
|
|
|
u.texture = texture.id( );
|
|
|
|
u.sampler = sampler.id( );
|
|
|
|
glBindTextureUnit( unit , texture.id( ) );
|
|
|
|
glBindSampler( unit , sampler.id( ) );
|
2017-10-02 10:57:51 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 14:48:16 +02:00
|
|
|
void T_TextureManagement::reset( )
|
2017-10-02 10:57:51 +02:00
|
|
|
{
|
|
|
|
for ( auto i = 0u ; i < MaxUnits ; i ++ ) {
|
|
|
|
auto& u( bindings_[ i ] );
|
2017-10-02 14:48:16 +02:00
|
|
|
u.texture = 0;
|
|
|
|
u.sampler = 0;
|
|
|
|
glBindTextureUnit( i , 0 );
|
|
|
|
glBindSampler( i , 0 );
|
2017-10-02 10:57:51 +02:00
|
|
|
}
|
|
|
|
}
|