void ShaderToyApp::loader( gl::ContextRef ctx ) { // This only works if we can make the render context current. ctx->makeCurrent(); // Loading loop. while( !mThreadAbort ) { // Wait for a request. if( mRequests->isNotEmpty() ) { // Take the request from the buffer. LoaderData data; mRequests->popBack( &data ); // Try to load, parse and compile the shader. try { std::string vs = loadString( loadAsset( "common/shadertoy.vert" ) ); std::string fs = loadString( loadAsset( "common/shadertoy.inc" ) ) + loadString( loadFile( data.path ) ); data.shader = gl::GlslProg::create( gl::GlslProg::Format().vertex( vs ).fragment( fs ) ); // If the shader compiled successfully, pass it to the main thread. mResponses->pushFront( data ); } catch( const std::exception& e ) { // Uhoh, something went wrong, but it's not fatal. CI_LOG_EXCEPTION( "Failed to compile the shader: ", e ); } } else { // Allow the CPU to do other things for a while. std::chrono::milliseconds duration( 100 ); std::this_thread::sleep_for( duration ); } } }
void ShaderToyApp::fileDrop( FileDropEvent event ) { // Send all file requests to the loading thread. size_t count = event.getNumFiles(); for( size_t i = 0; i < count && mRequests->isNotFull(); ++i ) mRequests->pushFront( event.getFile( i ) ); }
void FlickrTestMTApp::update() { double timeSinceLastImage = getElapsedSeconds() - mLastTime; if( ( timeSinceLastImage > 2.5 ) && mImages->isNotEmpty() ) { mLastTexture = mTexture; // the "last" texture is now the current text mImages->popBack( &mTexture ); mLastTime = getElapsedSeconds(); // blend from 0 to 1 over 1.5sec timeline().apply( &mFade, 0.0f, 1.0f, 1.5f ); } }
void ShaderToyApp::setup() { // Create our thread communication buffers. mRequests = new ConcurrentCircularBuffer<LoaderData>( 100 ); mResponses = new ConcurrentCircularBuffer<LoaderData>( 100 ); // Start the loading thread. if( !setupLoader() ) { CI_LOG_E( "Failed to create the loader thread and context." ); quit(); return; } // Load our textures and transition shader in the main thread. try { gl::Texture::Format fmt; fmt.setWrap( GL_REPEAT, GL_REPEAT ); mChannel0 = gl::Texture::create( loadImage( loadAsset( "presets/tex16.png" ) ), fmt ); mChannel1 = gl::Texture::create( loadImage( loadAsset( "presets/tex06.jpg" ) ), fmt ); mChannel2 = gl::Texture::create( loadImage( loadAsset( "presets/tex09.jpg" ) ), fmt ); mChannel3 = gl::Texture::create( loadImage( loadAsset( "presets/tex02.jpg" ) ), fmt ); mShaderTransition = gl::GlslProg::create( loadAsset( "common/shadertoy.vert" ), loadAsset( "common/shadertoy.frag" ) ); } catch( const std::exception& e ) { // Quit if anything went wrong. CI_LOG_EXCEPTION( "Failed to load common textures and shaders:", e ); quit(); return; } // Tell our loading thread to load the first shader. The path is converted to LoaderData implicitly. mRequests->pushFront( getAssetPath( "hell.frag" ) ); }
void FlickrTestMTApp::loadImagesThreadFn( gl::ContextRef context ) { ci::ThreadSetup threadSetup; // instantiate this if you're talking to Cinder from a secondary thread // we received as a parameter a gl::Context we can use safely that shares resources with the primary Context context->makeCurrent(); vector<Url> urls; // parse the image URLS from the XML feed and push them into 'urls' const Url sunFlickrGroup = Url( "https://api.flickr.com/services/feeds/groups_pool.gne?id=52242317293@N01&format=rss_200" ); const XmlTree xml( loadUrl( sunFlickrGroup ) ); for( auto item = xml.begin( "rss/channel/item" ); item != xml.end(); ++item ) { const XmlTree &urlXml = ( ( *item / "media:content" ) ); urls.push_back( Url( urlXml["url"] ) ); } // load images as Textures into our ConcurrentCircularBuffer while( ( ! mShouldQuit ) && ( ! urls.empty() ) ) { try { // we need to wait on a fence before alerting the primary thread that the Texture is ready auto fence = gl::Sync::create(); auto tex = gl::Texture::create( loadImage( loadUrl( urls.back() ) ) ); // wait on the fence fence->clientWaitSync(); mImages->pushFront( tex ); urls.pop_back(); } catch( ci::Exception &exc ) { console() << "failed to create texture, what: " << exc.what() << std::endl; } } }
void ShaderToyApp::update() { LoaderData data; // If we are ready for the next shader, take it from the buffer. if( !mShaderNext && mResponses->isNotEmpty() ) { mResponses->popBack( &data ); mPathNext = data.path; mShaderNext = data.shader; // Start the transition. mTransitionTime = getElapsedSeconds(); mTransitionDuration = 2.0; // Update the window title. getWindow()->setTitle( std::string( "ShaderToyApp - Fading from " ) + mPathCurrent.filename().string() + " to " + mPathNext.filename().string() ); } }
void ShaderToyApp::loader( HDC hdc, HGLRC renderContext ) { // This only works if we can make the render context current. if( !SUCCEEDED(::wglMakeCurrent( hdc, renderContext )) ) return; // Loading loop. while(!mThreadAbort) { // Wait for a request. if(mRequests->isNotEmpty()) { // Take the request from the buffer. LoaderData data; mRequests->popBack(&data); // Try to load, parse and compile the shader. try { std::string vs = loadString( loadAsset("common/shadertoy.vert") ); std::string fs = loadString( loadAsset("common/shadertoy.inc") ) + loadString( loadFile( data.path ) ); data.shader = gl::GlslProg::create( vs.c_str(), fs.c_str() ); // If the shader compiled successfully, pass it to the main thread. mResponses->pushFront( data ); } catch( const std::exception& e ) { // Uhoh, something went wrong, but it's not fatal. console() << "Failed to compile the shader: " << e.what() << endl; } } else { // Allow the CPU to do other things for a while. std::chrono::milliseconds duration( 100 ); std::this_thread::sleep_for( duration ); } } // Delete render context when done. ::wglDeleteContext( renderContext ); renderContext = NULL; }
void ShaderToyApp::random() { const fs::path assets = getAssetPath( "" ); // Find all *.frag files. std::vector<fs::path> shaders; for( fs::recursive_directory_iterator it( assets ), end; it != end; ++it ) { if( fs::is_regular_file( it->path() ) ) if( it->path().extension() == ".frag" ) shaders.push_back( it->path() ); } if( shaders.empty() ) return; // Load random *.frag file, but make sure it is different from the current shader. size_t idx = getElapsedFrames() % shaders.size(); if( shaders.at( idx ) == mPathCurrent ) idx = ( idx + 1 ) % shaders.size(); if( mRequests->isNotFull() ) mRequests->pushFront( shaders.at( idx ) ); }