demotool/ui-texture.cc

341 lines
7.7 KiB
C++
Raw Normal View History

2017-09-30 12:59:04 +02:00
#include "externals.hh"
#include "ui.hh"
#include "ui-odbg.hh"
#include "ui-texture.hh"
#include "ui-utilities.hh"
2017-09-30 12:59:04 +02:00
2017-10-02 10:42:06 +02:00
/*==============================================================================*/
2017-09-30 12:59:04 +02:00
T_Texture::T_Texture(
2017-11-03 09:08:19 +01:00
const uint32_t width ,
const uint32_t height ,
const E_TexType type ,
const uint32_t levels )
: levels_( levels ) , width_( width ) , height_( height ) ,
debugIndex_( -1 )
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;
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;
}
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( )
{
if ( debugIndex_ != -1 ) {
auto& odbg( UI::ODbg( ) );
assert( odbg.outputs_[ debugIndex_ ].id == id_ );
assert( odbg.nRegistered_ > 0 );
odbg.outputs_[ debugIndex_ ].id = 0;
odbg.nRegistered_ --;
}
2017-09-30 12:59:04 +02:00
glDeleteTextures( 1 , &id_ );
}
T_Texture& T_Texture::samplingMode(
2017-11-03 09:08:19 +01:00
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(
2017-11-03 09:08:19 +01:00
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(
2017-11-03 09:08:19 +01:00
T_TextureSampler&& other ) noexcept
2017-10-02 10:42:06 +02:00
{
2017-11-03 09:08:19 +01:00
swap( id_ , other.id_ );
swap( sampling_ , other.sampling_ );
swap( lodSampling_ , other.lodSampling_ );
swap( hasLOD_ , other.hasLOD_ );
2017-10-02 10:42:06 +02:00
setSamplingMode( );
}
T_TextureSampler& T_TextureSampler::operator =(
2017-11-03 09:08:19 +01:00
T_TextureSampler&& other ) noexcept
2017-10-02 10:42:06 +02:00
{
2017-11-03 09:08:19 +01:00
swap( id_ , other.id_ );
swap( sampling_ , other.sampling_ );
swap( lodSampling_ , other.lodSampling_ );
swap( hasLOD_ , other.hasLOD_ );
2017-10-02 10:42:06 +02:00
return *this;
}
T_TextureSampler::~T_TextureSampler( )
{
if ( id_ != 0 ) {
glDeleteSamplers( 1 , &id_ );
}
}
/*----------------------------------------------------------------------------*/
T_TextureSampler& T_TextureSampler::sampling(
2017-11-03 09:08:19 +01:00
const E_TexSampling mode )
2017-10-02 10:42:06 +02:00
{
sampling_ = mode;
setSamplingMode( );
return *this;
}
T_TextureSampler& T_TextureSampler::noMipmap( )
{
hasLOD_ = false;
setSamplingMode( );
return *this;
}
T_TextureSampler& T_TextureSampler::mipmap(
2017-11-03 09:08:19 +01:00
const E_TexSampling mode )
2017-10-02 10:42:06 +02:00
{
hasLOD_ = true;
lodSampling_ = mode;
setSamplingMode( );
return *this;
}
T_TextureSampler& T_TextureSampler::wrap(
2017-11-03 09:08:19 +01:00
const E_TexWrap mode )
2017-10-02 10:42:06 +02:00
{
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(
2017-11-03 09:08:19 +01:00
const float min ,
const float max )
2017-10-02 10:42:06 +02:00
{
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
/*============================================================================*/
constexpr uint32_t T_TextureManager::MaxUnits;
2017-09-30 12:59:04 +02:00
T_TextureManager::T_TextureManager( )
2017-09-30 12:59:04 +02:00
{
2017-11-03 09:08:19 +01:00
T_SharedPtr< T_TextureSampler > tsam;
2017-10-02 10:57:51 +02:00
2017-11-03 09:08:19 +01:00
tsam = NewShared< T_TextureSampler >( );
tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::NEAREST );
2017-11-03 09:08:19 +01:00
samplers_.add( T_String::Pooled( "nearest-edge" ) , std::move( tsam ) );
2017-10-02 10:57:51 +02:00
2017-11-03 09:08:19 +01:00
tsam = NewShared< T_TextureSampler >( );
tsam->wrap( E_TexWrap::CLAMP_EDGE ).sampling( E_TexSampling::LINEAR );
2017-11-03 09:08:19 +01:00
samplers_.add( T_String::Pooled( "linear-edge" ) , std::move( tsam ) );
2017-10-02 10:57:51 +02:00
2017-11-03 09:08:19 +01:00
tsam = NewShared< T_TextureSampler >( );
tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::NEAREST );
2017-11-03 09:08:19 +01:00
samplers_.add( T_String::Pooled( "nearest-border" ) , std::move( tsam ) );
2017-11-03 09:08:19 +01:00
tsam = NewShared< T_TextureSampler >( );
tsam->wrap( E_TexWrap::CLAMP_BORDER ).sampling( E_TexSampling::LINEAR );
2017-11-03 09:08:19 +01:00
samplers_.add( T_String::Pooled( "linear-border" ) , std::move( tsam ) );
}
T_TextureSampler const* T_TextureManager::sampler(
2017-11-03 09:08:19 +01:00
T_String const& name ) const
{
2017-11-03 09:08:19 +01:00
auto const* t( samplers_.get( name ) );
return t ? ( (T_TextureSampler const*) *t ) : nullptr;
}
2017-10-02 10:57:51 +02:00
void T_TextureManager::bind(
2017-11-03 09:08:19 +01:00
const uint32_t unit ,
T_Texture const& texture )
2017-10-02 10:57:51 +02:00
{
assert( unit < MaxUnits );
auto& u( bindings_[ unit ] );
if ( u.texture == texture.id( ) && !u.sampler ) {
2017-10-02 10:57:51 +02:00
return;
}
u.texture = texture.id( );
u.sampler = 0;
glBindTextureUnit( unit , texture.id( ) );
glBindSampler( unit , 0 );
2017-10-02 10:57:51 +02:00
}
void T_TextureManager::bind(
2017-11-03 09:08:19 +01:00
const uint32_t unit ,
T_Texture const& texture ,
T_TextureSampler const& sampler )
2017-10-02 10:57:51 +02:00
{
assert( unit < MaxUnits );
auto& u( bindings_[ unit ] );
if ( u.texture == texture.id( ) && u.sampler == sampler.id( ) ) {
2017-10-02 10:57:51 +02:00
return;
}
u.texture = texture.id( );
u.sampler = sampler.id( );
glBindTextureUnit( unit , texture.id( ) );
glBindSampler( unit , sampler.id( ) );
2017-10-02 10:57:51 +02:00
}
void T_TextureManager::reset( )
2017-10-02 10:57:51 +02:00
{
for ( auto i = 0u ; i < MaxUnits ; i ++ ) {
auto& u( bindings_[ i ] );
u.texture = 0;
u.sampler = 0;
glBindTextureUnit( i , 0 );
glBindSampler( i , 0 );
2017-10-02 10:57:51 +02:00
}
}