#include "externals.hh" #include "odbg.hh" #include "globals.hh" namespace { char const NormalOutput_[] = "(DISABLED)"; } /*= T_OutputDebugger =========================================================*/ T_OutputDebugger::T_OutputDebugger( ) : selectorItems_( nullptr ) { using namespace ebcl; registerSubmode( E_ODbgMode::LDR , "Colors" , "copy" ); registerSubmode( E_ODbgMode::LDR_ALPHA , "Colors" , "copy" ); registerSubmode( E_ODbgMode::LDR_ALPHA , "Alpha channel" , "alpha-channel" ); registerSubmode( E_ODbgMode::HDR , "Colors (raw)" , "copy" ); registerSubmode( E_ODbgMode::HDR , "Colors (Reinhart)" , "reinhart" ); registerSubmode( E_ODbgMode::DEPTH , "Depth (linear / 10)" , "depth-linear" , []( uint32_t id ) { glProgramUniform1f( id , 3 , .1 ); } ); registerSubmode( E_ODbgMode::DEPTH , "Depth (linear / 100)" , "depth-linear" , []( uint32_t id ) { glProgramUniform1f( id , 3 , .01 ); } ); registerSubmode( E_ODbgMode::DEPTH , "Depth (Reinhart)" , "depth-reinhart" ); initSubmodeCombo( ); } T_OutputDebugger::~T_OutputDebugger( ) { clearSelectorItems( ); for ( auto ptr : smCombo_ ) { delete[] ptr; } } void T_OutputDebugger::makeUI( ) { if ( !enabled_ ) { return; } using namespace ImGui; auto const& dspSize( GetIO( ).DisplaySize ); SetNextWindowSize( ImVec2( 300 , dspSize.y - 170 ) , ImGuiSetCond_Appearing ); SetNextWindowPos( ImVec2( 0 , 20 ) , ImGuiSetCond_Appearing ); Begin( "Output debugger" , &enabled_ , ImGuiWindowFlags_NoCollapse ); // Main selector if ( selectorItems_ == nullptr ) { makeSelectorItems( ); } int csi = -1; for ( auto i = 0u ; i < selectorMapping_.size( ) ; i ++ ) { if ( selectorMapping_[ i ] == selected_ ) { csi = i; break; } } assert( csi != -1 ); if ( Combo( "Output" , &csi , selectorItems_ ) ) { selected_ = selectorMapping_[ csi ]; } if ( selected_ == -1 ) { End( ); return; } // LOD selector auto& t( outputs_[ selected_ ] ); if ( t.levels > 1 ) { char lodCombo[ t.levels * 4 + 1 ]; char* ptr = lodCombo; for ( auto i = 0u ; i < t.levels ; i ++ ) { ptr += 1 + snprintf( ptr , sizeof( lodCombo ) - ( ptr - lodCombo ) , "%d" , i ); } *ptr = 0; Combo( "Level" , &t.lod , lodCombo ); } // Submode selector Combo( "Display" , &t.submode , smCombo_[ int( t.mode ) ] ); End( ); } void T_OutputDebugger::registerTexture( T_Texture& texture , const E_ODbgMode mode , T_String const& name ) { texture.debugIndex_ = registerTexture( texture.id_ , texture.levels_ , mode , name ); } void T_OutputDebugger::debugOutput( ) { assert( selected_ != -1 ); glClearColor( 0 , 0 , 0 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); auto const& info( outputs_[ selected_ ] ); auto const& sm( submodes_[ int( info.mode ) ][ info.submode ] ); if ( !sm.pipeline.valid( ) ) { return; } auto& tm( Globals::Textures( ) ); glBindTextureUnit( 0 , info.id ); glBindSampler( 0 , tm.sampler( "nearest-border" )->id( ) ); auto const& dspSize( ImGui::GetIO( ).DisplaySize ); auto pid( sm.pipeline.program( E_ShaderType::FRAGMENT ) ); sm.pipeline.enable( ); glProgramUniform1i( pid , 0 , 0 ); glProgramUniform1i( pid , 1 , info.lod ); glProgramUniform2f( pid , 2 , dspSize.x , dspSize.y ); if ( sm.setup ) { sm.setup( pid ); } glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); } /*----------------------------------------------------------------------------*/ void T_OutputDebugger::registerSubmode( const E_ODbgMode mode , T_String const& name , T_String const& shader , F_SubmodeSetup setup ) { assert( mode != E_ODbgMode::__COUNT__ ); ebcl::T_StringBuilder sb( "debug/" ); sb << shader << ".glsl" << '\0'; submodes_[ int( mode ) ].add( T_Submode_{ name , Globals::Shaders( ).pipeline({ "fullscreen.v.glsl" , sb.data( ) }) , setup } ); } void T_OutputDebugger::initSubmodeCombo( ) { for ( auto sm = 0u ; sm < int( E_ODbgMode::__COUNT__ ) ; sm ++ ) { imguiStrings.clear( ); for ( auto const& m : submodes_[ sm ] ) { imguiStrings << m.name << '\0'; } imguiStrings << '\0'; smCombo_[ sm ] = new char[ imguiStrings.size( ) ]; memcpy( smCombo_[ sm ] , imguiStrings.data( ) , imguiStrings.size( ) ); } } /*----------------------------------------------------------------------------*/ int32_t T_OutputDebugger::registerTexture( const GLuint id , const uint32_t levels , const E_ODbgMode mode , T_String const& name ) { assert( mode != E_ODbgMode::__COUNT__ ); assert( id != 0 ); assert( name.length( ) ); nRegistered_ ++; const auto n( outputs_.size( ) ); for ( auto i = 0u ; i < n ; i ++ ) { if ( outputs_[ i ].id == 0 ) { outputs_[ i ] = T_Texture_{ id , levels , mode , name , 0 , 0 }; return i; } } outputs_.add( T_Texture_{ id , levels , mode , name , 0 , 0 } ); return n; } void T_OutputDebugger::unregisterTexture( const uint32_t index ) { assert( index < outputs_.size( ) ); assert( outputs_[ index ].id != 0 ); assert( nRegistered_ > 0 ); outputs_[ index ].id = 0; if ( selected_ >= 0 && index == uint32_t( selected_ ) ) { selected_ = -1; } } /*----------------------------------------------------------------------------*/ void T_OutputDebugger::clearSelectorItems( ) { if ( selectorItems_ != nullptr ) { delete[] selectorItems_; selectorItems_ = nullptr; selectorMapping_.clear( ); } } void T_OutputDebugger::makeSelectorItems( ) { imguiStrings.clear( ); imguiStrings << NormalOutput_ << '\0'; uint32_t nrLeft = nRegistered_, i = 0; selectorMapping_.add( -1 ); while ( nrLeft ) { assert( i < outputs_.size( ) ); if ( outputs_[ i ].id != 0 ) { imguiStrings << outputs_[ i ].name << '\0'; selectorMapping_.add( i ); nrLeft --; } i ++; } imguiStrings << '\0'; assert( selectorMapping_.size( ) == 1 + nRegistered_ ); selectorItems_ = new char[ imguiStrings.size( ) ]; memcpy( selectorItems_ , imguiStrings.data( ) , imguiStrings.size( ) ); }