#include "externals.hh" #include "imgui_impl_sdl.h" #include "utilities.hh" #include "texture.hh" #include "rendertarget.hh" /*= T_Main ===================================================================*/ struct T_Main { T_Main( ); ~T_Main( ); void mainLoop( ); private: const std::string projectFile; SDL_Window * window; SDL_GLContext gl; bool done = false; bool capture = false; ImVec2 mouseInitial; ImVec2 mouseMove; T_Camera camera; T_FilesWatcher watcher; std::unique_ptr< T_ShaderProgram > spRaymarch; std::unique_ptr< T_ShaderProgram > spCopy; std::unique_ptr< T_ShaderProgram > spBloomFilter; std::unique_ptr< T_ShaderProgram > spBlur; std::unique_ptr< T_ShaderProgram > spBloomCombine; std::unique_ptr< T_Texture > txRaymarchOutput; std::unique_ptr< T_Rendertarget > rtRaymarchOutput; std::unique_ptr< T_Texture > txBloomInput; std::unique_ptr< T_Rendertarget > rtBloomInput; std::unique_ptr< T_Texture > txBlur0 , txBlur1; std::vector< std::unique_ptr< T_Rendertarget > > rtBlur0 , rtBlur1; void startIteration( ); void handleCapture( ); void makeUI( ); void render( ); void initProgram( ); }; /*----------------------------------------------------------------------------*/ T_Main::T_Main( ) { SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ); // Setup window SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER , 1 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE , 24 ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE , 8 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION , 2 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION , 2 ); SDL_DisplayMode current; SDL_GetCurrentDisplayMode( 0 , ¤t ); window = SDL_CreateWindow( "DEMO", SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED , 1280 , 720 , SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE ); gl = SDL_GL_CreateContext( window ); glewInit(); ImGui_ImplSdl_Init( window ); initProgram( ); txRaymarchOutput = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F ); rtRaymarchOutput = std::make_unique < T_Rendertarget >( T_RendertargetSetup( ).add( *txRaymarchOutput ).create( ) ); txBloomInput = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F ); txBloomInput->wrap( E_TexWrap::CLAMP_BORDER ).samplingMode( E_TexSampling::LINEAR ); rtBloomInput = std::make_unique < T_Rendertarget >( T_RendertargetSetup( ).add( *txBloomInput ).create( ) ); txBlur0 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); txBlur0->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); txBlur1 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); txBlur1->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); for ( int i = 0 ; i < 5 ; i ++ ) { rtBlur0.push_back( std::make_unique< T_Rendertarget >( T_RendertargetSetup( ).add( *txBlur0 , i ).create( ) ) ); rtBlur1.push_back( std::make_unique< T_Rendertarget >( T_RendertargetSetup( ).add( *txBlur1 , i ).create( ) ) ); } } void T_Main::mainLoop( ) { while ( !done ) { startIteration( ); if ( !done ) { handleCapture( ); makeUI( ); watcher.check( ); render( ); } } } T_Main::~T_Main( ) { ImGui_ImplSdl_Shutdown( ); SDL_GL_DeleteContext( gl ); SDL_DestroyWindow( window ); SDL_Quit( ); } /*----------------------------------------------------------------------------*/ void T_Main::startIteration( ) { SDL_Event event; mouseMove = ImVec2( ); while ( SDL_PollEvent( &event ) ) { ImGui_ImplSdl_ProcessEvent( &event ); if ( event.type == SDL_QUIT ) { done = true; return; } if ( capture && event.type == SDL_MOUSEMOTION ) { mouseMove.x += event.motion.xrel; mouseMove.y += event.motion.yrel; } } ImGui_ImplSdl_NewFrame( window , capture , mouseInitial ); ImGui::GetIO( ).MouseDrawCursor = true; } void T_Main::handleCapture( ) { auto const& io( ImGui::GetIO( ) ); const bool lmb( ImGui::IsMouseDown( 0 ) ); const bool mb( lmb || ImGui::IsMouseDown( 1 ) ); const bool appCanGrab( !( ImGui::IsMouseHoveringAnyWindow( ) || io.WantCaptureMouse || io.WantCaptureKeyboard ) ); const bool shift( io.KeyShift ); const bool ctrl( io.KeyCtrl ); if ( capture && !mb ) { capture = false; ImGui::CaptureMouseFromApp( false ); SDL_SetRelativeMouseMode( SDL_FALSE ); SDL_WarpMouseInWindow( window , int( mouseInitial.x ) , int( mouseInitial.y ) ); ImGui::SetMouseCursor( ImGuiMouseCursor_Arrow ); } else if ( capture ) { ImGui::SetMouseCursor( ImGuiMouseCursor_Move ); camera.handleDND( mouseMove , ctrl , shift , lmb ); } else if ( appCanGrab && mb ) { capture = true; mouseInitial = ImGui::GetMousePos( ); ImGui::CaptureMouseFromApp( true ); SDL_SetRelativeMouseMode( SDL_TRUE ); ImGui::SetMouseCursor( ImGuiMouseCursor_Move ); } if ( ( appCanGrab || capture ) && io.MouseWheel ) { camera.handleWheel( io.MouseWheel , ctrl , shift ); } } void T_Main::makeUI( ) { auto const& dspSize( ImGui::GetIO( ).DisplaySize ); ImGui::SetNextWindowSize( ImVec2( 300 , dspSize.y ) , ImGuiSetCond_Once ); ImGui::SetNextWindowPos( ImVec2( ) , ImGuiSetCond_Once ); ImGui::Begin( "Yay! Demo!" ); camera.makeUI( ); ImGui::End( ); } void T_Main::render( ) { auto const& dspSize( ImGui::GetIO( ).DisplaySize ); if ( spRaymarch->activate( ) && rtRaymarchOutput->activate( ) ) { glClearColor( 0 , 1 , 1 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); enum { U_TIME = 0 , U_RESOLUTION = 1 , U_CAM_POS = 2 , U_LOOK_AT = 3 , U_CAM_UP = 4 , U_NEAR_PLANE = 5 , U_LIGHT_DIR = 6 , U_RENDER = 7 , }; glUniform1f( U_TIME , 0 ); glUniform2f( U_RESOLUTION , dspSize.x , dspSize.y ); glUniform3fv( U_CAM_POS , 1 , &camera.pos.x ); glUniform3fv( U_LOOK_AT , 1 , &camera.lookAt.x ); glUniform3fv( U_CAM_UP , 1 , &camera.up.x ); glUniform1f( U_NEAR_PLANE , camera.np ); glUniform3f( U_LIGHT_DIR , 0 , 1 , 1 ); glUniform4f( U_RENDER , 128 , 0.9 , 0.001 , 100 ); glRectf( -1, -1 , 1 , 1 ); } if ( spBloomFilter->activate( ) ) { enum { U_TEXTURE = 0 , U_LOD = 1 , U_INPUT_SIZE = 2 , U_PARAMS = 3 , }; rtBloomInput->activate( ); T_TextureBinding tb( 0 ); tb.set( U_TEXTURE , *txRaymarchOutput ); tb.bind( ); glUniform1i( U_LOD , 0 ); glUniform2f( U_INPUT_SIZE , txRaymarchOutput->width( ) , txRaymarchOutput->height( ) ); glUniform3f( U_PARAMS , 1.6 , 1.2 , .95 ); glRectf( -1, -1 , 1 , 1 ); } if ( spBlur->activate( ) ) { enum { U_TEXTURE = 0 , U_OUTPUT_SIZE = 1 , U_INPUT_SIZE = 2 , U_SOURCE_LOD = 3 , U_DIRECTION = 4 , U_WEIGHTS = 5 , }; glUniform4f( U_WEIGHTS , 0.324 , 0.232 , 0.0855 , 0.0205 ); for ( int i = 0 ; i < 5 ; i ++ ) { // IB RMO B0 B1 B0 B1 B0 // OB B0/0 B1/0 B0/1 B1/1 B0/2 B1/2 // SLOD: 0 0 0 1 1 2 // IW: W W W W/2 W/2 W/4 // OW: W W W/2 W/2 W/4 W/4 T_TextureBinding tb( 0 ); uint32_t w , h; if ( i == 0 ) { tb.set( U_TEXTURE , *txBloomInput ); w = txRaymarchOutput->width( ); h = txRaymarchOutput->height( ); } else { tb.set( U_TEXTURE , *txBlur1 ); w = txBlur1->width( ) >> ( i - 1 ); h = txBlur1->height( ) >> ( i - 1 ); } const uint32_t slod = i > 0 ? ( i - 1 ) : 0; rtBlur0[ i ]->activate( ); #ifdef INTRUSIVE_TRACES printf( "BLUR %d/H IT %p SLOD %d IS %dx%d OS %dx%d\n" , i , &(*( i == 0 ? txBloomInput : txBlur1 ) ) , slod , w , h , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); #endif glUniform2f( U_OUTPUT_SIZE , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); glUniform1i( U_SOURCE_LOD , slod ); glUniform2f( U_INPUT_SIZE , w , h ); glUniform2f( U_DIRECTION , 1 , 0 ); tb.bind( ); glRectf( -1 , -1 , 1 , 1 ); rtBlur1[ i ]->activate( ); tb.set( U_TEXTURE , *txBlur0 ); tb.bind( ); glUniform2f( U_DIRECTION , 0 , 1 ); glUniform1i( U_SOURCE_LOD , i ); glUniform2f( U_INPUT_SIZE , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); glRectf( -1 , -1 , 1 , 1 ); #ifdef INTRUSIVE_TRACES printf( "BLUR %d/V IT %p SLOD %d IS %dx%d OS %dx%d\n" , i , &(*( txBlur0 ) ) , i , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); #endif } } T_Rendertarget::MainOutput( ); glClearColor( 1 , 0 , 1 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); if ( spBloomCombine->activate( ) ) { T_TextureBinding main( 0 ) , blur( 1 ); main.set( 0 , *txRaymarchOutput ); main.bind( ); blur.set( 1 , *txBlur1 ); blur.bind( ); glUniform2f( 2 , dspSize.x , dspSize.y ); glRectf( -1, -1 , 1 , 1 ); glBindTexture( GL_TEXTURE_2D , 0 ); } glUseProgram( 0 ); ImGui::Render( ); SDL_GL_SwapWindow( window ); } void T_Main::initProgram( ) { spRaymarch = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spRaymarch->addFile( "raymarch-header.glsl" ); spRaymarch->addFile( "map.glsl" ); spRaymarch->addFile( "raymarcher.glsl" ); spRaymarch->load( ); spCopy = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spCopy->addFile( "copy.glsl" ); spCopy->load( ); spBloomFilter = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spBloomFilter->addFile( "bloom-highpass.glsl" ); spBloomFilter->load( ); spBlur = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spBlur->addFile( "blur-pass.glsl" ); spBlur->load( ); spBloomCombine = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spBloomCombine->addFile( "bloom-combine.glsl" ); spBloomCombine->load( ); } /*============================================================================*/ int main( int , char** ) { T_Main m; m.mainLoop( ); #if 0 // Frame time history const int nFrameTimes = 200; float frameTimes[ nFrameTimes ]; memset( frameTimes , 0 , sizeof( float ) * nFrameTimes ); #endif #if 0 // Update frame time history memmove( frameTimes , &frameTimes[ 1 ] , ( nFrameTimes - 1 ) * sizeof( float ) ); frameTimes[ nFrameTimes - 1 ] = 1000.0f / ImGui::GetIO( ).Framerate; #endif return 0; }