Windowless OF

Hi,
With the new window management in of006 it’s possible to change from GLUT to any other handler - or to not use any. Here is some simple code that implements this in a ofAppNoWindow class.

What it does is that it starts OF with only the console, no graphics at all. This means only the update callback is used and anything in draw functions are ignored. This is good when doing a separate video tracking app for example: you can use GLUT to develop/configure the tracking and then use the NoWindow app to let it run much faster in the background. I’m sure there are other situations too where you might want to work without a window in a live situation too.

The only user interface I’ve implemented is hitting ESC in the console to quit the app properly, and that’s only for Windows at the moment. Does anyone know how to do this in linux and osx? Then please let me know and i’ll add it.

This is what the section in ofAppNoWindow::runAppViaInfiniteLoop looks like:

  
  
        ...  
  
        /// listen for escape  
        #ifdef TARGET_WIN32  
        if (GetAsyncKeyState(VK_ESCAPE))  
            OF_EXIT_APP(0);  
        #endif  
  
        #ifdef TARGET_OSX  
             /// listen for esc on osx  
        #endif  
  
        #ifdef TARGET_LINUX  
             /// listen for esc on linux  
        #endif  
  
        ...  
  

An example and the source (ofAppNoWindow.h/.cpp) can be downloaded here: http://www.carljohanrosen.com/share/NoWindowExample-v0.01.zip

looking forward to some feedback!
cj

Was looking for this! Works great! Thanks!

I have found one problem with the windowless app… The path to the data folder on the mac doesnt work… Apparently the app is running from another folder the the window’ed version does, so the path will screw up…

Jonas

Hi Jonas,
Glad you’re trying out the Windowless app. I don’t work too much with the mac, but if you didn’t figure it out yet i’ll have a look at it in the next few weeks. I know this with the path has been discussed earlier on the forum. Let me know if you have any success!

/cj

try calling

  
ofSetDataPath("data/");  
  

in your testApp::setup function

Theo

I was trying to use your example to create a headless OF app–but I need to use OpenCV libs. I’m new to OF in general, and I’m not sure if I can accomplish what I want without use a GLUT/window. If I try to use the ofAppNoWindow instead of the ofAppGlutWindow, I get a “bus error” reported from the command line. Any thoughts?

I think you should try:

setUseTexture(false);

before you allocate every object that can draw itself (an ofVideoPlayer, ofxCvGrayscaleimage, etc).

ie,

myVideoPlayer.setUseTexture(false);
myVideoPlayer.initGrabber(320,240);

myGrayCvImage.setUseTexture(false);
myGrayCvImage.allocate(320,240);

etc…

if not, you are calling opengl commands (essentially allocating a texture), that could (?) crash without an open opengl context…

hope the helps!
zach

Zach, that certainly did the trick. The only problem I have left with my windowless OF app is exiting—I’m getting an error in Windows XP whenever I try to call ofAppNoWindow::exitApp() _after_ I’m done using ofVideoPlayer and openCV to analyze a video file. What should I do to “clean up” properly with the following references?

  
ofVideoPlayer video;  
ofxCvGrayscaleImage cvThresh;  
ofxCvGrayscaleImage cvPrevFrame;  
ofxCvGrayscaleImage cvGray;  
ofxCvColorImage cvColor;  
ofxCvContourFinder contourFinder;  

Right now, I’m trying this code when I’m done processing the video file:

  
  
    cvColor.clear();  
    cvThresh.clear();  
    cvGray.clear();  
    cvPrevFrame.clear();  
  
    cvColor.~ofxCvImage();  
    cvThresh.~ofxCvImage();  
    cvGray.~ofxCvImage();  
    cvPrevFrame.~ofxCvImage();  
  
    contourFinder.~ofxCvContourFinder();  
  
    video.closeMovie();  
  
    video.~ofVideoPlayer();  

The error is a ntdll.dll error. But I can’t gleam much useful information from the error itself.

Many thanks in advance for any suggestions!

I’d start by poking around what happens when you comment certain things out. For example, if you comment out the opencv but leave in the video player, or if you comment out the video player and leave in the opencv.

then, I’d check to make sure I have setUseTexture(false) everywhere - since there is no opengl context, these things might be mucking around with textures that could be a problem. call that before their “setup / load” functions to be sure.

then, I’d put printfs through the full OF exit app process to find what exactly is causing it. it’s hard to say but if you can say, destructing x, y or z is, then it’s easier to find out.

look at the internal OF stuff too for closing out the OF app – does something get closed that hasn’t been opened because of the windowing system?

hope that helps
zach

Since I’m a newbie to C++, it’s not clear to me how pointers are created and then destroyed in OF. It turns out that by not using a pointer to ofVideoPlayer and other classes in the ofxCv package, I was not able to “clear” them before exit. So, I just made pointers (ofVideoPlayer * video, instead of just ofVideoPlayer video) in the header file, and then referenced the ofVideoPlayer in an array reference, where it could be destroyed on exit. Worked just fine after I did that to all of the OF classes I was using.

if anyone else needs it, here’s a keyboard-input version of ofAppNoWindow.cpp for OSX/Linux:

  
  
#include "ofAppNoWindow.h"  
#include "ofBaseApp.h"  
#include "ofMain.h"  
  
  
  
#if defined TARGET_OSX || defined TARGET_LINUX  
#include <stdlib.h>  
#include <string.h>  
#include <sys/select.h>  
#include <termios.h>  
  
struct termios orig_termios;  
struct sigaction act_open;  
  
void reset_terminal_mode()  
{  
    tcsetattr(0, TCSANOW, &orig_termios);  
}  
  
  
void set_conio_terminal_mode()  
{  
    struct termios new_termios;  
	  
    /* take two copies - one for now, one for later */  
    tcgetattr(0, &orig_termios);  
    memcpy(&new_termios, &orig_termios, sizeof(new_termios));  
	  
    /* register cleanup handler, and set the new terminal mode */  
    atexit(reset_terminal_mode);  
    cfmakeraw(&new_termios);  
    tcsetattr(0, TCSANOW, &new_termios);  
}  
  
int kbhit()  
{  
    struct timeval tv = { 0L, 0L };  
    fd_set fds;  
    FD_SET(0, &fds);  
    return select(1, &fds, NULL, NULL, &tv);  
}  
  
int getch()  
{  
    int r;  
    unsigned char c;  
    if ((r = read(0, &c, sizeof(c))) < 0) {  
        return r;  
    } else {  
        return c;  
    }  
}  
  
#endif  
  
  
//----------------------------------------------------------  
ofAppNoWindow::ofAppNoWindow(){  
	timeNow				= 0;  
	timeThen			= 0;  
	fps					= 60; //give a realistic starting value - win32 issues  
	nFramesForFPS		= 0;  
	nFrameCount			= 0;  
	bFrameRateSet		= false;  
	millisForFrame		= 0;  
	prevMillis			= 0;  
	diffMillis			= 0;  
	frameRate			= 0;  
}  
  
//------------------------------------------------------------  
void ofAppNoWindow::runAppViaInfiniteLoop(ofBaseApp * appPtr){  
	static ofEventArgs voidEventArgs;  
  
	ofAppPtr = appPtr;  
  
	if(ofAppPtr){  
		ofAppPtr->setup();  
		ofAppPtr->update();  
	}  
  
	#if defined TARGET_OSX || defined TARGET_LINUX  
	// for keyboard  
	set_conio_terminal_mode();  
	#endif  
  
	#ifdef OF_USING_POCO  
		ofNotifyEvent( ofEvents.setup, voidEventArgs );  
		ofNotifyEvent( ofEvents.update, voidEventArgs );  
	#endif  
  
    printf("starting main loop\n");  
	while (true)  
	{  
	    if (nFrameCount != 0 && bFrameRateSet == true){  
            diffMillis = ofGetElapsedTimeMillis() - prevMillis;  
            if (diffMillis > millisForFrame){  
                ; // we do nothing, we are already slower than target frame  
            } else {  
                int waitMillis = millisForFrame - diffMillis;  
                #ifdef TARGET_WIN32  
                    Sleep(waitMillis);         //windows sleep in milliseconds  
                #else  
                    usleep(waitMillis * 1000);   //mac sleep in microseconds - cooler :)  
                #endif  
            }  
        }  
        prevMillis = ofGetElapsedTimeMillis(); // you have to measure here  
  
  
        /// listen for escape  
        #ifdef TARGET_WIN32  
        if (GetAsyncKeyState(VK_ESCAPE))  
            OF_EXIT_APP(0);  
        #endif  
  
		#if defined TARGET_OSX || defined TARGET_LINUX  
		while ( kbhit() )  
		{  
			int key = getch();  
			if ( key == 27 )  
			{  
				OF_EXIT_APP(0);  
			}  
			else  
			{  
				ofAppPtr->keyPressed( key );  
			}  
		}  
		#endif  
  
  
        /// update  
        if (ofAppPtr)  
            ofAppPtr->update();  
  
		#ifdef OF_USING_POCO  
		ofNotifyEvent( ofEvents.update, voidEventArgs);  
		#endif  
  
  
  
        // -------------- fps calculation:  
        timeNow = ofGetElapsedTimef();  
        if( (timeNow-timeThen) > 0.05f || nFramesForFPS == 0 ) {  
            fps = (double)nFramesForFPS / (timeNow-timeThen);  
            timeThen = timeNow;  
            nFramesForFPS = 0;  
  
            //hack for windows - was getting NAN - maybe unitialized vars???  
            if( nFrameCount < 5) frameRate = fps;  
            else frameRate = 0.9f * frameRate + 0.1f * fps;  
        }  
        nFramesForFPS++;  
        // --------------  
  
        nFrameCount++;		// increase the overall frame count  
  
	}  
}  
  
//------------------------------------------------------------  
void ofAppNoWindow::exitApp(){  
  
//  -- This already exists in ofExitCallback  
  
//	static ofEventArgs voidEventArgs;  
//  
//	if(ofAppPtr)ofAppPtr->exit();  
//  
//	#ifdef OF_USING_POCO  
//		ofNotifyEvent( ofEvents.exit, voidEventArgs );  
//	#endif  
  
	ofLog(OF_LOG_VERBOSE,"No Window OF app is being terminated!");  
  
	reset_terminal_mode();  
	OF_EXIT_APP(0);  
}  
  
//------------------------------------------------------------  
float ofAppNoWindow::getFrameRate(){  
	return frameRate;  
}  
  
//------------------------------------------------------------  
int ofAppNoWindow::getFrameNum(){  
	return nFrameCount;  
}  
  
//------------------------------------------------------------  
void ofAppNoWindow::setFrameRate(float targetRate){  
	// given this FPS, what is the amount of millis per frame  
	// that should elapse?  
  
	// --- > f / s  
  
	if (targetRate == 0){  
		bFrameRateSet = false;  
		return;  
	}  
  
	bFrameRateSet 			= true;  
	float durationOfFrame 	= 1.0f / (float)targetRate;  
	millisForFrame 			= (int)(1000.0f * durationOfFrame);  
  
	frameRate				= targetRate;  
  
}  
  

Nice! thanks damian, that could be super useful…

Hi all,

What are the experiences with this class? I’ve just tried to simply replace

ofAppGlutWindow window;

with

ofAppNoWindow window;

But it seems it’s eating my CPU much more than with the regular window.
(Ubuntu 10.04 OF 007 (github))

Rg,

Arnaud

don’t know if it’s implemented but try setting a fixed framerate like:

  
  
ofSetFramerate(30)  

if not the app will try to run as fast as it can and not having to draw it will probably consume a lot of cpu

That was too easy, I should have thought of that myself. Thanks :slight_smile:

Rg,

Arnaud

Hi,

Just tried to get a simple app running with ofAppNoWindow based on the example. It builds but crashes

Exception Type: EXC_BAD_ACCESS (SIGBUS)

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libGL.dylib 0x98939fb7 glGetString + 12
1 com.yourcompany.openFrameworks 0x00033f3e glewInit + 30
2 com.yourcompany.openFrameworks 0x00147410 ofSetupOpenGL(ofPtr, int, int, int) + 98
3 com.yourcompany.openFrameworks 0x00147519 ofSetupOpenGL(ofAppBaseWindow*, int, int, int) + 76
4 com.yourcompany.openFrameworks 0x0000267c main + 62 (main.cpp:17)
5 com.yourcompany.openFrameworks 0x00002635 start + 53

System: os x lion,
OF: current master branch
compiled against base sdk 10.6, 32bit

am i missing something, or can somebody help to understand what is happening here?

best,
silvan

It seems like the EXC_BAD_ACCESS (SIGBUS) error comes from an incompletely setup opengl context. I could get it to work by porting ofAppGlutWindow::setupOpenGL() to ofAppNoWindow.

best,
silvan

Hi, does anyone have a working Xcode stub project for headless OF?

I’ve tried a bunch of permutations, including reimplementing setupOpenGL() without luck.

I always get an EXC_BAD_ACCESS at glewInit(); in ofAppRunner.cpp.

I found Damian’s headless projects on GitHub and tried compiling those as well, but I’m getting the same error in the same spot.

I’m on Xcode 4.2.1, latest OF Master, tried both 10.6 and 10.7 SDKs.

Thanks!

Apologies for the thread necromancy, but I recently had to revisit this problem. Here’s what I found out:

Changes to ofAppRunner.cpp in newer versions of OF dropped some extra stuff at the end of the ofSetupOpenGL method.

Previous versions looked like this:

  
void ofSetupOpenGL(ofPtr<ofAppBaseWindow> windowPtr, int w, int h, int screenMode){  
	window = windowPtr;  
	window->setupOpenGL(w, h, screenMode);  
}  

Recent versions look like this:

  
void ofSetupOpenGL(ofPtr<ofAppBaseWindow> windowPtr, int w, int h, int screenMode){  
	window = windowPtr;  
	window->setupOpenGL(w, h, screenMode);  
  
		#ifndef TARGET_OPENGLES  
			glewExperimental = GL_TRUE;  
			GLenum err = glewInit();  
			if (GLEW_OK != err)  
			{  
				/* Problem: glewInit failed, something is seriously wrong. */  
				ofLog(OF_LOG_ERROR, "Error: %s\n", glewGetErrorString(err));  
			}  
		#endif  
			ofSetCurrentRenderer(ofPtr<ofBaseRenderer>(new ofGLRenderer(false)));  
			//Default colors etc are now in ofGraphics - ofSetupGraphicDefaults  
			//ofSetupGraphicDefaults();  
}  

That extra stuff at the end ends up invoking glewInit() which creates the the EXC_BAD_ACCESS errors. For now I just modified core to get the headless code working, but in the longer run does anyone have advice as to what would be the most elegant way to get around this call to glewInit()? I couldn’t see any reasonable place to override it, short of extending ofAppRunner.

Thanks again, headless mode is super useful.

I just added to my github a working branch with an example of an headless app
https://github.com/roymacdonald/openFrameworks/tree/headlessApp