#include "externals.hh" #include "odbg.hh" #include "globals.hh" namespace { const std::string 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; } auto const& dspSize( ImGui::GetIO( ).DisplaySize ); ImGui::SetNextWindowSize( ImVec2( 300 , dspSize.y - 300 ) , ImGuiSetCond_Once ); ImGui::SetNextWindowPos( ImVec2( 0 , 150 ) , ImGuiSetCond_Once ); ImGui::Begin( "Output debugger" ); // 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 ( ImGui::Combo( "Output" , &csi , selectorItems_ ) ) { selected_ = selectorMapping_[ csi ]; } if ( selected_ == -1 ) { ImGui::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; ImGui::Combo( "Level" , &t.lod , lodCombo ); } // Submode selector ImGui::Combo( "Display" , &t.submode , smCombo_[ int( t.mode ) ] ); ImGui::End( ); } void T_OutputDebugger::registerTexture( __rw__ T_Texture& texture , __rd__ const E_ODbgMode mode , __rd__ std::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( __rd__ const E_ODbgMode mode , __rd__ std::string const& name , __rd__ std::string const& shader , __rd__ F_SubmodeSetup setup ) { assert( mode != E_ODbgMode::__COUNT__ ); submodes_[ int( mode ) ].add( T_Submode_{ name , Globals::Shaders( ).pipeline({ "fullscreen.v.glsl" , "debug/" + shader + ".glsl" }) , setup } ); } void T_OutputDebugger::initSubmodeCombo( ) { for ( auto sm = 0u ; sm < int( E_ODbgMode::__COUNT__ ) ; sm ++ ) { size_t reqSize = 1; for ( auto const& m : submodes_[ sm ] ) { reqSize += 1 + m.name.length( ); } assert( reqSize > 1 ); smCombo_[ sm ] = new char[ reqSize ]; char* ptr = smCombo_[ sm ]; for ( auto const& m : submodes_[ sm ] ) { strcpy( ptr , m.name.c_str( ) ); ptr += 1 + m.name.length( ); } *ptr = 0; } } /*----------------------------------------------------------------------------*/ int32_t T_OutputDebugger::registerTexture( __rd__ const GLuint id , __rd__ const uint32_t levels , __rd__ const E_ODbgMode mode , __rd__ std::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( __rd__ 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( ) { size_t requiredSize = 2 + NormalOutput_.length( ); uint32_t nrLeft = nRegistered_, i = 0; selectorMapping_.add( -1 ); while ( nrLeft ) { assert( i < outputs_.size( ) ); if ( outputs_[ i ].id != 0 ) { requiredSize += 1 + outputs_[ i ].name.length( ); selectorMapping_.add( i ); nrLeft --; } i ++; } assert( selectorMapping_.size( ) == 1 + nRegistered_ ); assert( requiredSize >= 2 + NormalOutput_.length( ) + 2 * nRegistered_ ); selectorItems_ = new char[ requiredSize ]; char* ptr = selectorItems_; strcpy( ptr , NormalOutput_.c_str( ) ); ptr += NormalOutput_.length( ) + 1; for ( i = 1 ; i < selectorMapping_.size( ) ; i ++ ) { auto const& name( outputs_[ selectorMapping_[ i ] ].name ); strcpy( ptr , name.c_str( ) ); ptr += name.length( ) + 1; } *ptr = 0; }