//------------------------------------------------- void ofThread::run(){ #ifdef TARGET_ANDROID JNIEnv * env; jint attachResult = ofGetJavaVMPtr()->AttachCurrentThread(&env,NULL); if(attachResult!=0){ ofLogWarning() << "couldn't attach new thread to java vm"; } #endif // user function // should loop endlessly. try{ threadedFunction(); }catch(const Poco::Exception& exc){ ofLogFatalError("ofThreadErrorLogger::exception") << exc.displayText(); }catch(const std::exception& exc){ ofLogFatalError("ofThreadErrorLogger::exception") << exc.what(); }catch(...){ ofLogFatalError("ofThreadErrorLogger::exception") << "Unknown exception."; } _threadRunning = false; #if !defined(TARGET_WIN32) // FIXME: this won't be needed once we update POCO https://github.com/pocoproject/poco/issues/79 if(!threadBeingWaitedFor){ //if threadedFunction() ended and the thread is not being waited for, detach it before exiting. pthread_detach(pthread_self()); } #endif #ifdef TARGET_ANDROID attachResult = ofGetJavaVMPtr()->DetachCurrentThread(); #endif }
//------------------------------------------------- void ofThread::run(){ #ifdef TARGET_ANDROID JNIEnv * env; jint attachResult = ofGetJavaVMPtr()->AttachCurrentThread(&env,nullptr); if(attachResult!=0){ ofLogWarning() << "couldn't attach new thread to java vm"; } #endif // user function // should loop endlessly. try{ threadedFunction(); }catch(const std::exception& exc){ ofLogFatalError("ofThreadErrorLogger::exception") << exc.what(); }catch(...){ ofLogFatalError("ofThreadErrorLogger::exception") << "Unknown exception."; } thread.detach(); #ifdef TARGET_ANDROID attachResult = ofGetJavaVMPtr()->DetachCurrentThread(); #endif std::unique_lock<std::mutex> lck(mutex); threadRunning = false; threadDone = true; condition.notify_all(); }
//======================================================================== int main( ){ #ifdef USE_PROGRAMMABLE_GL // we are using the programmable gl renderer. ofPtr<ofBaseRenderer> renderer(new ofGLProgrammableRenderer(false)); ofSetCurrentRenderer(renderer, false); ofSetupOpenGL(1280,720,OF_WINDOW); // <-------- setup the GL context #else // we are not using the progammable gl renderer. // when we are not using the programmable gl renderer it is not safe to assume // out current gl context provides us with the necessary openGL extensions to // run this example. // let's check if the current openGL context provides us with glDrawElementsInstanced // we do this after we have initialised our openGL context. ofSetupOpenGL(1280,720,OF_WINDOW); // <-------- setup the GL context ostringstream extStr; extStr << (char*)glGetString(GL_EXTENSIONS); // first get all available extensions. string extensionsAvailable = extStr.str(); if (ofStringTimesInString(extensionsAvailable, "GL_ARB_draw_instanced") == 0) { ofLogFatalError("App") << " GL_ARB_draw_instanced is needed for this example but it is not supported by your graphics card. Exiting App."; return -1; } else { // GL_ARB_draw_instanced is available... so far so good. // either one of these is needed, too: if (ofStringTimesInString(extensionsAvailable, "GL_EXT_gpu_shader4") == 0 && ofStringTimesInString(extensionsAvailable, "NV_vertex_program4") == 0 ) { ofLogFatalError("App") << " GL_EXT_gpu_shader4 or NV_vertex_program4 is needed for this example but it is not supported by your graphics card. Exiting App."; return -1; } } #endif // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp(new ofApp()); }
//======================================================================== int main( ){ // ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context ofGLWindowSettings settings; settings.setGLVersion(3, 2); // Programmable pipeline settings.width = 1024; settings.height = 768; ofCreateWindow(settings); if(!ofGLCheckExtension("GL_ARB_geometry_shader4") && !ofGLCheckExtension("GL_EXT_geometry_shader4") && !ofIsGLProgrammableRenderer()){ ofLogFatalError() << "geometry shaders not supported on this graphics card"; return 1; } GLint major; GLint minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); ofLogNotice() << "opengl: " << major << "." << minor; // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp(new ofApp()); }
void MediaServer::unloadVideo(string& path) { VideoSource* videoSource = static_cast<VideoSource*>(getSourceByPath(path)); // Decrease reference count of the video //referenceCount[path]--; videoSource->referenceCount--; // Unload only if reference count is less or equal to 0 if (videoSource->referenceCount > 0) { ofLogNotice("MediaServer") << "Not unloading video as it is being referenced elsewhere"; return; } // Reference count 0 or less, let's unload the video ofLogNotice("MediaServer") << "Removing video " << path; // Distroy video source if (loadedSources.count(path)) { ofLogNotice("MediaServer") << "Source count before video removal: " << loadedSources.size() << endl; videoSource->clear(); std::map<std::string, BaseSource*>::iterator it = loadedSources.find(path); delete it->second; loadedSources.erase(it); ofLogNotice("MediaServer") << "Source count after video removal: " << loadedSources.size() << endl; ofNotifyEvent(onVideoUnloaded, path, this); return; } // Something wrong here, we should be out of the routine by now std::stringstream failss; failss << "Failed to remove video source: " << path; ofLogFatalError("MediaServer") << failss.str(); std::exit(EXIT_FAILURE); }
void MediaServer::unloadImage(string& path) { ImageSource* source = static_cast<ImageSource*>(getSourceByPath(path)); ofLogNotice("MediaServer") << "Unload image, current reference count: " << source->referenceCount; source->referenceCount--; // Unload only if reference count is less or equal to 0 ofLogNotice("MediaServer") << "New reference count: " << source->referenceCount; if (source->referenceCount > 0) { ofLogNotice("MediaServer") << "Not unloading image as it is being referenced elsewhere"; return; } // Reference count 0 or less, unload image std::stringstream ss; ss << "Removing image " << path; ofLogNotice("MediaServer") << ss.str(); // Destroy image source if (loadedSources.count(path)) { ofLogNotice("MediaServer") << "Source count BEFORE image removal: " << loadedSources.size() << endl; loadedSources[path]->clear(); std::map<std::string, BaseSource*>::iterator it = loadedSources.find(path); delete it->second; loadedSources.erase(it); ofLogNotice("MediaServer") << "Source count AFTER image removal: " << loadedSources.size() << endl; ofNotifyEvent(onImageUnloaded, path, this); return; } // Something wrong here, we should be out of the routine by now std::stringstream failss; failss << "Failed to remove image source: " << path; ofLogFatalError("MediaServer") << failss.str(); std::exit(EXIT_FAILURE); }
void SurfaceManager::saveXmlSettings(string fileName){ if(mediaServer == 0){ ofLogFatalError("SurfaceManager") << "Media server not set"; exit(EXIT_FAILURE); } SettingsLoader::instance()->save(_surfaces, fileName); }
bool SurfaceManager::loadXmlSettings(string fileName){ if(mediaServer == 0){ ofLogFatalError("SurfaceManager") << "Media server not set"; exit(EXIT_FAILURE); } return SettingsLoader::instance()->load(_surfaces, *mediaServer, fileName); }
void assertFileExists(const std::string & path){ if(!ofFile::doesFileExist(path)){ const std::string msg = "Required asset not present: '" + path + "'"; ofLogFatalError("ofxApp") << msg; ofxApp::utils::terminateApp("ofxApp", msg); }else{ //ofLogVerbose("ofxApp") << "Confirmed asset is present: '" << path << "'"; } }
void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle _viewport){ if( _viewport.width == 0 || _viewport.height == 0 ){ _viewport.set(0, 0, ofGetWidth(), ofGetHeight()); } filename = _filename; type = _type; streamBuffer.clear(); if(type == FROM_FILE_EXTENSION){ string ext = ofFilePath::getFileExt(filename); if(ofToLower(ext)=="svg"){ type = SVG; }else if(ofToLower(ext)=="pdf"){ type = PDF; }else{ // default to image type = IMAGE; } } switch(type){ case PDF: if(filename==""){ surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); }else{ surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); } break; case SVG: if(filename==""){ surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); }else{ surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); } break; case IMAGE: imageBuffer.allocate(_viewport.width, _viewport.height, 4); surface = cairo_image_surface_create_for_data(imageBuffer.getPixels(),CAIRO_FORMAT_ARGB32,_viewport.width, _viewport.height,_viewport.width*4); break; case FROM_FILE_EXTENSION: ofLogFatalError("ofCairoRenderer") << "Type not determined from file extension!"; break; default: ofLogError("ofCairoRenderer") << "Unknown type encountered!"; break; } cr = cairo_create(surface); cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL); viewportRect = _viewport; viewport(viewportRect); page = 0; b3D = b3D_; multiPage = multiPage_; setStyle(ofGetStyle()); }
// TODO: getLoadedSourceByPath BaseSource* MediaServer::getSourceByPath(std::string& mediaPath) { if (loadedSources.count(mediaPath)) { return loadedSources[mediaPath]; } // Source not found, exit with error std::stringstream ss; ss << "Could not find source by path: " << mediaPath; ofLogFatalError("MediaServer") << ss.str(); std::exit(EXIT_FAILURE); }
void print_fatal(std::string inp) { #ifdef ROS_BUILD ROS_FATAL("%s", inp.c_str()); ros::shutdown(); #else //printf("FATAL: %s\n", inp.c_str()); ofLogFatalError(MODULE_NAME, "%s\n", inp.c_str()); // exit(1); #endif }
std::string MediaServer::getDefaultMediaDir(int sourceType) { if (sourceType == SourceType::SOURCE_TYPE_IMAGE) { return getDefaultImageDir(); } else if (sourceType == SourceType::SOURCE_TYPE_VIDEO) { return getDefaultVideoDir(); } else { std::stringstream ss; ss << "Could not get default media dir. Unknown source type: " << sourceType; ofLogFatalError("MediaServer") << ss.str(); std::exit(EXIT_FAILURE); } }
void logParagraph(const std::string & moduleName, ofLogLevel lev, const std::string & text){ vector<std::string> jsonLines = ofSplitString(text, "\n"); for (auto & l : jsonLines) { switch(lev){ case OF_LOG_VERBOSE: ofLogVerbose(moduleName) << l; break; case OF_LOG_NOTICE: ofLogNotice(moduleName) << l; break; case OF_LOG_WARNING: ofLogWarning(moduleName) << l; break; case OF_LOG_ERROR: ofLogError(moduleName) << l; break; case OF_LOG_FATAL_ERROR: ofLogFatalError(moduleName) << l; break; default: break; } } }
//======================================================================== int main( ){ ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context if(!ofGLCheckExtension("GL_ARB_geometry_shader4") && !ofGLCheckExtension("GL_EXT_geometry_shader4") && !ofIsGLProgrammableRenderer()){ ofLogFatalError() << "geometry shaders not supported on this graphics card"; return 1; } // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp( new testApp()); }
void ofApp::setup() { ofSetDataPathRoot( __data_path__ ); ofSetFrameRate(30); ofSetVerticalSync(true); ofSetLogLevel(OF_LOG_NOTICE); if ( !settings.open( "config/settings.json" ) ) { ofLogFatalError() << "error opening settings.json"; ofExit(); return; } rgb_cam_name = settings["params"]["calib_kinect_rgb_stereo"]["rgb_cam_name"].asString(); rgb_device_id = settings["params"]["calib_kinect_rgb_stereo"]["rgb_device_id"].asInt(); rgb_width = settings["params"]["calib_kinect_rgb_stereo"]["rgb_width"].asInt(); rgb_height = settings["params"]["calib_kinect_rgb_stereo"]["rgb_height"].asInt(); rgb_width_draw = rgb_width / 2; rgb_height_draw = rgb_height / 2; ofLog() << "rgb size " << rgb_width << " x " << rgb_height; rgb_cam.setDeviceID( rgb_device_id ); rgb_cam.initGrabber( rgb_width, rgb_height, true ); kinect.setRegistration(true); // ir, rgb, texture kinect.init(false, true, true); kinect.open(); kinect.update(); rgb_cam.update(); pix_kinect_rgb = kinect.getPixelsRef(); //copy pix_rgb = rgb_cam.getPixelsRef(); //copy calibration.init( settings["params"]["calib_kinect_rgb_stereo"]["cam_pattern_path"].asString(), "kinect", pix_kinect_rgb, rgb_cam_name, pix_rgb, //load calibrated kinect intrinsics settings["params"]["calib_kinect_rgb_stereo"]["calib_kinect_path"].asString() ); //window setup ofSetWindowShape( kinect.width + rgb_width_draw, rgb_height > kinect.height ? rgb_height : kinect.height ); ofSetWindowPosition( 0, 0 ); }
BaseSource* MediaServer::loadMedia(string &path, int mediaType) { // Chose load method depending on type if (mediaType == SourceType::SOURCE_TYPE_IMAGE) { return loadImage(path); } else if (mediaType == SourceType::SOURCE_TYPE_VIDEO) { return loadVideo(path); } else if (mediaType == SourceType::SOURCE_TYPE_FBO) { return loadFboSource(path); } else { std::stringstream ss; ss << "Can not load media of unknown type: " << mediaType; ofLogFatalError("MediaServer") << ss.str(); std::exit(EXIT_FAILURE); } return NULL; }
void MediaServer::unloadMedia(string &path) { if (loadedSources.count(path)) { BaseSource* mediaSource = getSourceByPath(path); if (mediaSource->getType() == SourceType::SOURCE_TYPE_IMAGE) { unloadImage(path); } else if (mediaSource->getType() == SourceType::SOURCE_TYPE_VIDEO) { unloadVideo(path); } else if (mediaSource->getType() == SourceType::SOURCE_TYPE_FBO) { unloadFboSource(path); } else { // Oh my god, what to do!? Relax and exit. ofLogFatalError("MediaServer") << "Attempt to unload media of unknown type"; std::exit(EXIT_FAILURE); } } else { ofLogNotice("MediaServer") << "Nothing to unload"; } }
void ofxEasyFft::setup(int bufferSize, fftWindowType windowType, fftImplementation implementation, int audioBufferSize, int audioSampleRate) { if(bufferSize < audioBufferSize) { ofLogFatalError() << "ofxEasyFft bufferSize (" << bufferSize << ") must be less than the audioBufferSize (" << audioBufferSize << ")"; } fft = ofxFft::create(bufferSize, windowType, implementation); bins.resize(fft->getBinSize()); audioFront.resize(bufferSize); audioMiddle.resize(bufferSize); audioBack.resize(bufferSize); audioRaw.resize(bufferSize); stream.listDevices(); stream.setup(0, 1, audioSampleRate, audioBufferSize, 2); stream.setInput(this); }
//======================================================================== int main( ){ if( glDrawElementsInstanced == 0 ){ ofLogFatalError("App") << " glDrawElementsInstanced is needed for this example but it is not supported by your graphics card. Exiting App."; return -1; } #ifdef USE_PROGRAMMABLE_GL ofPtr<ofBaseRenderer> renderer(new ofGLProgrammableRenderer(false)); ofSetCurrentRenderer(renderer, false); #endif ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp(new testApp()); }
void WeightedObjectManager::objectExitedScreen(Weightable* o){ if (find(allWeightedObjects.begin(), allWeightedObjects.end(), o) != allWeightedObjects.end()){ map<Weightable*, int>::iterator it; it = screenObjectCounter.find(o); if (it != screenObjectCounter.end()){ it->second = it->second - 1; if(it->second == 0){ vector<Weightable*>::iterator it2 = find(onScreenObjects.begin(), onScreenObjects.end(), o); onScreenObjects.erase(it2); } if(it->second < 0){ it->second = 0; ofLogFatalError("WeightedObjectManager") << "negative object count"; } } }else{ ofLogError("WeightedObjectManager") << "this object is not weighted"; } }
void Creatures::generateTentacles() { unsigned numTentacles = 0; for (unsigned i = 0; i < jellies.size(); ++i) numTentacles += jellies[i]->getNumTentacles(); tentacles.init(TENTACLE_NUM_SECTIONS, numTentacles, OF_PRIMITIVE_LINES, false); if (numTentacles * TENTACLE_NUM_SECTIONS * 4 != tentacles.getNumFloats()) ofLogFatalError() << "tentacle texture size error"; float* particlePosns = new float[tentacles.getNumFloats()]; unsigned tentacleIdx = 0; ofVboMesh& tentacleMesh = tentacles.getMeshRef(); for (unsigned i = 0; i < jellies.size(); ++i) { vector<ofVec3f> deformed = jellies[i]->getDeformedTentaclePosns(); ofVec3f step = -1.5f * TENTACLE_SECTION_LENGTH * jellies[i]->getZAxis(); for (unsigned j = 0; j < deformed.size(); ++j) { for (unsigned x = 0; x < TENTACLE_NUM_SECTIONS; ++x) { unsigned idx = tentacleIdx * TENTACLE_NUM_SECTIONS + x; particlePosns[idx * 4] = deformed[j].x + x * step.x; particlePosns[idx * 4 + 1] = deformed[j].y + x * step.y; particlePosns[idx * 4 + 2] = deformed[j].z + x * step.z; particlePosns[idx * 4 + 3] = 0.f; ofFloatColor col = jellies[i]->getTentacleColour(); col.a = .5f * (1.f - x / (float)TENTACLE_NUM_SECTIONS); tentacleMesh.addColor(col); if (x > 0) { tentacleMesh.addIndex(TENTACLE_NUM_SECTIONS * tentacleIdx + x - 1); tentacleMesh.addIndex(TENTACLE_NUM_SECTIONS * tentacleIdx + x); } } ++tentacleIdx; } } tentacles.loadDataTexture(ofxGpuParticles::POSITION, particlePosns); delete[] particlePosns; tentacles.zeroDataTexture(ofxGpuParticles::VELOCITY); tentaclePosns.resize(numTentacles); }
void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle _viewport){ if( _viewport.width == 0 || _viewport.height == 0 ){ _viewport.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight()); } filename = _filename; type = _type; streamBuffer.clear(); if(type == FROM_FILE_EXTENSION){ string ext = ofFilePath::getFileExt(filename); if(ofToLower(ext)=="svg"){ type = SVG; }else if(ofToLower(ext)=="pdf"){ type = PDF; }else{ // default to image type = IMAGE; } } if(filename != "") { switch(type) { case PDF: case SVG: case IMAGE: ofFilePath::createEnclosingDirectory(filename); case FROM_FILE_EXTENSION: break; } } switch(type){ case PDF: if(filename==""){ surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); }else{ surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); } break; case SVG: if(filename==""){ surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); }else{ surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); } break; case IMAGE: imageBuffer.allocate(_viewport.width, _viewport.height, OF_PIXELS_BGRA); imageBuffer.set(0); surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,_viewport.width, _viewport.height,_viewport.width*4); break; case FROM_FILE_EXTENSION: ofLogFatalError("ofCairoRenderer") << "setup(): couldn't determine type from extension for filename: \"" << _filename << "\"!"; break; default: ofLogError("ofCairoRenderer") << "setup(): encountered unknown type for filename \"" << _filename << "\""; break; } cr = cairo_create(surface); cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL); viewportRect = _viewport; originalViewport = _viewport; viewport(viewportRect); page = 0; b3D = b3D_; multiPage = multiPage_; }
//-------------------------------------------------------------- void ofApp::setup(){ //Screen, visual setup ofSetWindowTitle("Morph OpenCL example"); ofSetFrameRate( 60 ); ofSetVerticalSync(false); signalParticleSpeed = 0.10; spectrumParticleSpeed = 0.20; faceParticleSpeed = 0.04; cubeParticleSpeed = 0.04; ySpectrumVerticalShift = 170; ignoreFFTbelow = .01; portionOfSpecToDraw = 1.0; freqScalingExponent = 1.4; amplitudeScalingExponent = 1.7; signalAmplitudeScale = 3000.0; spectrumAmplitudeScale = 400.0; yFaceWave = 0; yFaceWaveDelta = 1; if(portionOfSpecToDraw > 1.0 || portionOfSpecToDraw <= 0.0) { ofLogFatalError() << "invalid portionOfSpecToDraw, should be in range (0, 1.0] "; } // Audio setup soundStream.listDevices(); soundStream.setDeviceID(1); nOutputChannels = 0; nInputChannels = 2; sampleRate = 44100; bufferSize = 512; nBuffers = 4; fft = ofxFft::create(bufferSize, OF_FFT_WINDOW_HAMMING, OF_FFT_FFTW); drawFFTBins.resize(fft->getBinSize() * portionOfSpecToDraw); middleFFTBins.resize(fft->getBinSize()); audioFFTBins.resize(fft->getBinSize()); drawSignal.resize(bufferSize); middleSignal.resize(bufferSize); audioSignal.resize(bufferSize); soundStream.setup(this, nOutputChannels, nInputChannels, sampleRate, bufferSize, nBuffers); //Camera setup cam.setGlobalPosition(0, 0, 800); cam.setFov(60.0); cam.enableMouseInput(); //OpenCL opencl.setupFromOpenGL(); opencl.loadProgramFromFile("Particle.cl"); opencl.loadKernel("updateParticle"); //create vbo which holds particles positions - particlePos, for drawing glGenBuffersARB(1, &vbo); glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float4) * N, 0, GL_DYNAMIC_COPY_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); // init host and CL buffers particles.initBuffer( N ); particlePos.initFromGLObject( vbo, N ); // load the face const char* imageName = "ksenia256.jpg"; loadImage(imageName); downsampledBins.resize(faceMatrix.size(), 0); // setup the draw mode faceWave = false; instructionsHidden = false; suspended = false; drawMode = TIME; ratchetness = 0.9; }
void terminateApp(const std::string & module, const std::string & reason, float secondsOnScreen){ ofLogFatalError("ofxApp") << "terminateApp()!"; ofxSimpleHttp::destroySslContext(); ofLogFatalError("ofxApp") << ""; ofLogFatalError("ofxApp") << "-----------------------------------------------------------------------------------------------------------"; ofLogFatalError("ofxApp") << ""; ofLogFatalError("ofxApp") << "ofxApp is terminating because the module \"" << module << "\" found an unrecoverable error."; ofLogFatalError("ofxApp") << "\"" << reason << "\""; ofLogFatalError("ofxApp") << "This message will be on screen for " << (int)secondsOnScreen << " seconds, then the app will quit."; ofLogFatalError("ofxApp") << ""; ofLogFatalError("ofxApp") << "-----------------------------------------------------------------------------------------------------------"; ofLogFatalError("ofxApp") << ""; ofxThreadSafeLog::one()->close(); if(ofxApp::get().isWindowSetup()){ ofxSuperLog::getLogger()->setScreenLoggingEnabled(true); //show log if json error ofxSuperLog::getLogger()->getDisplayLogger().setPanelWidth(1.0); int numFrames = secondsOnScreen * 1000 / 16; //stay up a bit so that you can read logs on screen OFXAPP_REPORT("ofxAppTerminate_" + module, reason, 2); //hijack OF and refresh screen & events by hand at ~60fps if(ofGetWindowPtr()){ for(int i = 0; i < numFrames; i++ ){ ofSetupScreen(); ofClear(0,0,0,255); ofxSuperLog::getLogger()->getDisplayLogger().draw(ofGetWidth(), ofGetHeight()); ofGetMainLoop()->pollEvents(); if(ofGetWindowPtr()->getWindowShouldClose()){ ofLogFatalError("ofxApp") << "Quitting by user action"; std::exit(-1); } ofGetWindowPtr()->swapBuffers(); ofSleepMillis(16); } } }else{ ofLogFatalError("ofxApp") << "Terminating ofxApp before the app window is setup."; } std::exit(0); };