2017-10-06 14:29:01 +02:00
|
|
|
#include "externals.hh"
|
|
|
|
#include "odbg.hh"
|
|
|
|
#include "globals.hh"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const std::string NormalOutput_ = "(DISABLED)";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*= T_OutputDebugger =========================================================*/
|
|
|
|
|
|
|
|
T_OutputDebugger::T_OutputDebugger( )
|
|
|
|
: selectorItems_( nullptr )
|
|
|
|
{
|
|
|
|
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 );
|
2017-10-06 14:45:00 +02:00
|
|
|
ImGui::SetNextWindowSize( ImVec2( 300 , dspSize.y - 300 ) ,
|
2017-10-06 14:29:01 +02:00
|
|
|
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 ) ].push_back( 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_.push_back( 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_.push_back( -1 );
|
|
|
|
while ( nrLeft ) {
|
|
|
|
assert( i < outputs_.size( ) );
|
|
|
|
if ( outputs_[ i ].id != 0 ) {
|
|
|
|
requiredSize += 1 + outputs_[ i ].name.length( );
|
|
|
|
selectorMapping_.push_back( 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;
|
|
|
|
}
|