Created
November 18, 2011 18:59
-
-
Save heisters/1377406 to your computer and use it in GitHub Desktop.
ofxFenster helper for rendering a single "canvas" across multiple screens
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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