Scaling entire application?

Hey,

I’m totally new on OF, coming from Processing. I’m wondering if there’s a sort of best practice way of scaling an entire application up and down?

The thing is that I frequently develop applications for very large screens (lots of pixels), but I have to be able to do so on much smaller screens, such as my laptop. So what I do in Processing is simply to have a global scale variable that I multiply with all the relevevant variables (position and size) throughout the code.

This works but it’s not ideal, so I’m wondering if there’s a better way to do this in OF?

Hi,

You can scale everything drawn in the ofApp::update() function like this:

virtual void draw0(ofEventArgs & args){
    ofPushMatrix();
    ofScale( scale, scale, 1.f );

    // all your drawings go here

    ofPopMatrix();
}

Simple! But this approach have some drawbacks.
One of them is that the x and y values in the mouse functions will be incorrect. Of course it’s possible to modify them:

void ofApp::mouseMoved(int x, int y ){
    x /= scale;
    y /= scale;
    // the rest of your code go here
}

Another one is that some draws could be done outside of the draw() function, by some other classes which listen the ofEvents().draw event. The content drawn by these classes will not be scaled.
Same thing for the mouse events. The mouse position will not be scaled outside of the ofApp mouse functions.

So I played a little to figure how to resolve these problems, and here’s a class ScaledApp, to use in replacement of ofBaseApp, which seems to do the job:

#include "ScaledApp.h"
class ofApp : public ScaledApp { 

ScaledApp.h (2.0 KB)

I tested it with the guiExample exemple. I just replaced:

class ofApp : public ofBaseApp { 

by

class ofApp : public ScaledApp { 

and write

setScale(0.5f);

in the setup.
The rest of the code is the guiExample code.
It seems to work.
I guess some problems can appear with some functions. Especially for the ones who deal with the screen size, and call ofGetWidth() and ofGetHeight(). For example, ofBackgroundGradient() fail.

example.zip (56.7 KB)

Thanks a lot for this! I’m still too new to all this to actually be able to run or completely understand your code, but I’ll dig into it. Thanks again, I really appreciate the effort you put into this.

My pleasure. It was a little challenge for me to try some things I’ve never tried with OF.

My code has issues, it works fine in some cases, and fails in others.
I think it can be used to scale apps, as long as they don’t use ofGetMouseX() and ofGetMouseY(), because these values are not scaled. The scaled app must use the x and y mouse coords received in the mousedMoved(), mouseDragged(), etc, functions, not ofGetMouseX() and ofGetMouseY(). Perhaps this issue can be fixed…

The use of ofGetWidth() and ofGetHeight() can raise problems too, depending on what is done with their return values.

So this code has serious limitations for now.
But it’s possible to write an app without using these four functions.

If you want to test yourself to scale an existing app, one of yours or one of the OF examples, it’s simple:

  • Add the ScaledApp.h file to the project

  • Replace

    class ofApp : public ofBaseApp {

by

class ofApp : public ScaledApp {

in ofApp.h

And in setup() choose the scale with:

setScale(0.5f);

(Coming from as3/AIR apps here) I went a different way with this. I put

float scale(float val = 1.0);

in my ofApp.h, then added

float ofApp::scale(float val){
	return 	(val * (ofGetViewportHeight() / DESIRED_HEIGHT));
}

to my ofApp.cpp, put this up at the top (it’s based on my target screen resolution):

#define DESIRED_WIDTH		1920.0
#define DESIRED_HEIGHT		1080.0
#define DESIRED_ASPECT		DESIRED_WIDTH / DESIRED_HEIGHT

Now I can do this in ofApp::draw():

ofCircle(scale((float)myCircleX), scale((float)myCircleY), scale((float)60));

and this in ofApp::mousePressed():

Tweener.addTween(myCircleX, x / scale(), 0.3, &ofxTransitions::easeInQuint);

I also wanted to make sure that when I resized my window during testing, it was maintaining the correct aspect ratio for my target device so I wrote this (called at app launch and on window resize):

void ofApp::checkAspect(){
	int newW;
	int newH;
	
	if ((ofGetViewportWidth() / DESIRED_ASPECT) > (ofGetViewportHeight() * DESIRED_ASPECT)) {
		// preserve Width
		newW = ofGetViewportWidth();
		newH = newW / DESIRED_ASPECT;
	} else {
		// preserve Height
		newH = ofGetViewportHeight();
		newW = newH * DESIRED_ASPECT;
	}
	ofSetWindowShape(newW, newH);
}

That function doesn’t seem quite right to me but it always resizes to 16:9. I might mess with it more later because it seems to prefer responding to height changes over width changes.