How to split ofFbo between two windows?

Hi,

I’ve spent an entire day trying to accomplish something that ought to be simple… How do I go about splitting up one ofFbo into two screens in my multiwindow app? Currently I’m trying to make it work by rendering to ofImage and cropping like this:

    floor.setFromPixels(pixBuffer);
    floor.update();
    floor.crop(0, h / 2, w, h / 2);
    floor.resize( w, h );

    backWall.setFromPixels(pixBuffer);
    backWall.update();
    backWall.crop(0, 0, w, h / 2);
    backWall.resize( w, h );

where floor and backWall are ofImage and pixBuffer is an ofPixel taken from an ofFbo.
This is happening in a class called Physarum, which has a drawBackWall and a drawFloor function:

void Physarum::drawBackWall(){
    ofSetColor(r, g, b, a);
    backWall.draw(0, 0);
void Physarum::drawFloor(){
    ofSetColor(r, g, b, a);
    floor.draw(0, 0);

In my main.cpp I use Physarum as a shared pointer:

    shared_ptr<Physarum> physarum(new Physarum);
    wallProjection->physarum = physarum;
    floorProjection->physarum = physarum;

and I am calling it in ofApp.cpp like this:

// in update()
        physarum->update();
//in draw()       
 physarum->drawBackWall();

and in FloorProjection.cpp (the second window) like this:

physarum->drawFloor();

The problem I have is that the thing draws fine in the ofApp, but in FloorProjection I only get a black screen.

Any help greatly appreciated! I am also very open for better design principles for this particular problem. I tried my hands a bit on shaders as well for resizing, but my shader fu is not yet up for it…

Hi,

I think the main thing you are missing is the sharing of a GL context between the two windows.
If you do that you can even use the same FBO in both windows.

This is how we setup an App in main.cpp to use a single GL context for both the main window and renderer.

//========================================================================
int main( ){
    
    ofGLFWWindowSettings msettings;
    msettings.setSize( 1600, 900 );
    auto mainWin    = ofCreateWindow( msettings );
    
    ofGLFWWindowSettings rsettings;
    rsettings.setSize( 1920, 1080);
    rsettings.shareContextWith = mainWin; // <<--- this is the missing line you need 

    auto renderWin  = ofCreateWindow( rsettings );
        
    auto app = make_shared<ofApp>();
    
    ofRunApp( mainWin, app );
    ofRunMainLoop();

}

Thank you so much for that pointer! I am still struggling with how exactly to share an ofFbo across the two windows. I can’t find any documentation on how to do that… Right now I have a main.cpp that looks like this:

#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGLFWWindow.h"

int main( ){

    ofGLFWWindowSettings settings;
    settings.setGLVersion(3, 2);
    settings.setSize(1024, 768);
    settings.setPosition( vec2(0, 0) );
    settings.windowMode = OF_WINDOW;
    // settings.windowMode = OF_FULLSCREEN;

    auto wallProjectionWindow = ofCreateWindow(settings);

    settings.setGLVersion(3, 2);
    settings.setSize(1024, 768);
    settings.setPosition( vec2(0, 768) );
    settings.shareContextWith = wallProjectionWindow;
    settings.windowMode = OF_WINDOW;
    // settings.windowMode = OF_FULLSCREEN;

    auto floorProjectionWindow = ofCreateWindow(settings);

    auto app = make_shared<ofApp>();

    ofRunApp(wallProjectionWindow, app);
    ofRunMainLoop();
}

and have zero clue on how to proceed… My usecase is that I have one projector on the backwall and one on the floor, and I want to be able to treat them as a single surface.

Finally I found a solution with a little help from my friends… simply resize the window to spill over to the other screen… puha… With linux and exotic tiling window managers this is obviously not always obvious. What I had to do was this:

    ofGLFWWindowSettings settings;
    settings.setGLVersion(3, 2);
    settings.setPosition( vec2(0, 0) );
    settings.setSize(1920 * 2, 1080);
    settings.title = "singularityVideo";
    settings.windowMode = OF_WINDOW;
    ofCreateWindow( settings );
    ofRunApp( new ofApp() );

and then, in my sway configuration:

for_window [title="singularityVideo"] floating enabled

Not an entirely wasted day of my life, as it provided me with a hell of a lot of study materials. Thanks a lot, still!

Hi, sorry I should have shown you had to get the renderWindow to have a draw() function in ofApp.cpp and also the code I posted wasn’t holding onto the render window.

Taking your example:

#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGLFWWindow.h"

int main( ){

    ofGLFWWindowSettings settings;
    settings.setGLVersion(3, 2);
    settings.setSize(1024, 768);
    settings.setPosition( vec2(0, 0) );
    settings.windowMode = OF_WINDOW;
    // settings.windowMode = OF_FULLSCREEN;

    auto wallProjectionWindow = ofCreateWindow(settings);

    settings.setGLVersion(3, 2);
    settings.setSize(1024, 768);
    settings.setPosition( vec2(0, 768) );
    settings.shareContextWith = wallProjectionWindow;
    settings.windowMode = OF_WINDOW;
    // settings.windowMode = OF_FULLSCREEN;
  
    auto app = make_shared<ofApp>();

   //NEW
    app->floorProjectionWindow = ofCreateWindow(settings); 
    ofAddListener( app->floorProjectionWindow->events().draw, app.get(), &ofApp::onRenderWindowDraw );  // <------  add a draw event to call an ofApp function for the render window 

    ofRunApp(wallProjectionWindow, app); 
    ofRunMainLoop();
}

Now in ofApp.h add ( in the public section ):

    void onRenderWindowDraw( ofEventArgs& args ); 
    shared_ptr<ofAppBaseWindow> floorProjectionWindow;

In ofApp.cpp add:

//--------------------------------------------------------------
void ofApp::onRenderWindowDraw( ofEventArgs& args ) {
  //draw your FBO for your second window here. 
 //eg: you can draw just a subsection of the FBO 
//ofSetColor(255); 
 //fbo.getTexture().drawSubsection(0, 0, croppedW, croppedH, offsetX, offsetY);
}

Hope that helps!

Also for reference there is an example that shows how to do multiple windows from one app in:
examples/window/multiWindowOneAppExample

1 Like

This is absolute gold, thank you so much! Especially the drawSubsection method has eluded me before. Incredibly useful.