Skip to content

Instantly share code, notes, and snippets.

@heisters
Created November 18, 2011 18:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heisters/1377406 to your computer and use it in GitHub Desktop.
Save heisters/1377406 to your computer and use it in GitHub Desktop.
ofxFenster helper for rendering a single "canvas" across multiple screens
#include "Canvas.h"
Canvas * Canvas::p_Instance = NULL;
Canvas * Canvas::Instance(){
if(!p_Instance) p_Instance = new Canvas();
return p_Instance;
}
Canvas::Canvas(){
rect.x = 0;
rect.y = 0;
rect.width = 0;
rect.height = 0;
};
void Canvas::setScreenIndices(Screen * screen, int index){
screen->index.x = index % columns;
screen->index.y = floor(index / columns);
}
void Canvas::setup(ofxFensterListener * listener, int _columns, int _rows){
setup(listener, _columns, _rows, 0, 0);
}
void Canvas::setup(ofxFensterListener * listener, int _columns, int _rows, int width, int height){
columns = _columns, rows = _rows;
ofxFensterManagerPtr fenster = ofxFensterManager::get();
ofxDisplayList displays = ofxDisplayManager::get()->getDisplays();
ofLogNotice() << "Found" << displays.size() << "displays";
ofxFenster * bootstrapWin = fenster->getActiveWindow();
int canvasWidth = 0;
int canvasHeight = 0;
list<Screen *>::iterator sit;
ofxDisplayList::iterator dit;
for(dit = displays.begin(); dit < displays.end(); dit++){
Screen * screen = new Screen();
screen->display = *dit;
fenster->setActiveDisplay(screen->display);
int w, h;
if(width > 0 && height > 0){
w = width, h = height;
} else {
w = screen->display->width, h = screen->display->height;
}
screen->window = fenster->createFenster(0, 0, w, h, OF_FULLSCREEN);
screen->window->addListener(listener);
for(sit = screens.begin(); sit != screens.end(); sit++){
if((*sit)->display->x > screen->display->x) {
setScreenIndices(*sit, std::distance(screens.begin(), sit) + 1);
break;
}
}
setScreenIndices(screen, std::distance(screens.begin(), sit));
screens.insert(sit, screen);
canvasWidth += screen->window->getWidth();
canvasHeight += screen->window->getHeight();
}
fenster->deleteFenster(bootstrapWin);
if(columns * rows != screens.size()){
ofLogError() << "Expected" << columns * rows << "screens, but found" << screens.size();
ofExit();
}
for(sit = screens.begin(); sit != screens.end(); sit++){
// it's tacky to iterate again just for logging, but this is the only
// way to ensure the log is accurate due to the sorting in the first
// iteration (above).
ofLogNotice() << "Set up display" << (*sit)->display->id << ": at" << (*sit)->index.x << "," << (*sit)->index.y << ", display" << (*sit)->display->width << "x" << (*sit)->display->height << ", window" << (*sit)->window->getWidth() << "x" << (*sit)->window->getHeight();
}
setWidth(canvasWidth / rows);
setHeight(canvasHeight / columns);
}
Screen * Canvas::getActiveScreen(){
ofxFenster * win = ofxFensterManager::get()->getActiveWindow();
Screen * screen;
list<Screen *>::iterator sit;
for(sit = screens.begin(); sit != screens.end(); sit++){
if((*sit)->window == win){
screen = *sit;
break;
}
}
return screen;
}
void Canvas::setupPerspectiveForActiveScreen(){
Screen * screen = getActiveScreen();
ofPoint size = screen->window->getWindowSize();
float halfFovTan = tanf(PI * 60 / 360.0);
float baseDist = (getHeight() / 2) / halfFovTan;
float near = baseDist / 10.f;
float far = baseDist * 10.f;
float aspect = (float) getWidth() / getHeight();
float wholeMaxY = near * halfFovTan;
float wholeMaxX = aspect * wholeMaxY;
float width = (wholeMaxX / columns) * 2;
float height = (wholeMaxY / rows) * 2;
float minX = -wholeMaxX + (width * screen->index.x);
float minY = -wholeMaxY + (height * ((rows - 1) - screen->index.y));
float maxX = minX + width;
float maxY = minY + height;
//ofLogNotice() << Canvas::Instance()->getWidth() << Canvas::Instance()->getHeight() << wholeMaxX << wholeMaxY;
//ofLogNotice() << screen->xIndex << screen->yIndex << minX << minY << maxX << maxY;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(minX, maxX, minY, maxY, near / rows, far / rows);
glMatrixMode(GL_MODELVIEW);
// FIXME: this doesn't work when the screens are different sizes
int originalWidth = getWidth() / columns;
int originalHeight = getHeight() / rows;
glTranslatef(-(getWidth() - originalWidth) / 2, -(getHeight() - originalHeight) / 2, 0);
}
int Canvas::getWidth(){
return rect.width;
}
int Canvas::getHeight(){
return rect.height;
}
void Canvas::setWidth(int w){
rect.width = w;
}
void Canvas::setHeight(int h){
rect.height = h;
}
ofPoint Canvas::getCanvasPosition(){
return ofPoint(rect.x, rect.y);
}
#pragma once
#include "ofMain.h"
#include "ofxFensterManager.h"
typedef struct {
int x;
int y;
} ScreenIndex;
typedef struct {
ofxDisplay * display;
ofxFenster * window;
ScreenIndex index;
} Screen;
class Canvas {
public:
static Canvas * Instance();
int getWidth();
int getHeight();
ofPoint getCanvasPosition();
void setup(ofxFensterListener * listener, int _columns, int _rows);
void setup(ofxFensterListener * listener, int _columns, int _rows, int width, int height);
Screen * getActiveScreen();
void setupPerspectiveForActiveScreen();
list<Screen *> screens;
int rows, columns;
private:
Canvas();
Canvas(Canvas const&){};
Canvas& operator=(Canvas const&){};
static Canvas * p_Instance;
void setScreenIndices(Screen * screen, int index);
void setWidth(int w);
void setHeight(int h);
ofRectangle rect;
};
#include "Canvas.h"
void testApp::setup(){
Canvas::Instance()->setup(this, 3, 2);
// ... which is equivalent to:
//Canvas::Instance()->setup(this, 3, 2, 0, 0);
// or, if you want to force the resolutions of the screens:
//Canvas::Instance()->setup(this, 3, 2, 1920, 1080);
// set the backgrounds of all the screens
list<Screen *>::iterator sit;
for(sit = Canvas::Instance()->screens.begin(); sit != Canvas::Instance()->screens.end(); sit++){
(*sit)->window->setBackgroundColor(255, 0, 0);
}
}
// ...
void testApp::draw(){
Canvas::Instance()->setupPerspectiveForActiveScreen();
// the rest of your draw() goes here
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment