2. Hello oFWorld

Hello and welcome to the world of openFrameworks. We will introduce some key concepts through this sequence of Hello World (actually Hello Space) programs. You can work through the programs by copying parts of the code step by step, or if you feel confident you may be able to come up with parts of the code yourself. Also try tweak the examples to let it do something slightly different.

In this first program we will start with understanding of the basic structure of an openFrameworks program. Most of the action happens in ofApp.cpp so we can focus on that first.

The basic idea is that of a sense - integrate/update state - take action cycle, which keeps repeating. Compare it to an animal sensing the environment, updating its needs and emotional state, and the taking action.

The app is initialized through the setup() method, where you can do some general set up. Then an update() method is called, here you can update any internal state of your app, and in the draw() method you can then define what action to take, and then the app loops back to update(). So you may ask your self, where is the sensing step? This is dealt with through the various events (keypressed(), mousemoved() etc). They will fire immediately when such an event is detected.

In the code below we print statements to a log to just understand how the system works, using the cout command. You could start with just the text in the setup method first, and then extend to the others.

You can start a new program by copying the emptyExample dir in <ofdir>/examples/empty to <ofdir>/apps/myApps, and rename it for example <ofdir>/apps/myApps/myFirstExample, or use the project generator (see 7. Working with openFrameworks).

ofApp.h

 

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:

        void setup();

        void update();

        void draw();

        void keyPressed  (int key);

        void keyReleased(int key);

        void mouseMoved(int x, int y );

        void mouseDragged(int x, int y, int button);

        void mousePressed(int x, int y, int button);

        void mouseReleased(int x, int y, int button);

        void windowResized(int w, int h);

};

#endif

 

ofApp.cpp

 

#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup(){

    cout << "This is ground control to Major Tom, commencing countdown, engines on..." << endl; // just getting started

    ofBackground(0,0,0); // background color

    ofSetColor(255,255,255); // text white

}

//--------------------------------------------------------------

void ofApp::update(){

    cout << "Can you hear me major Tom?" << endl;

}

//--------------------------------------------------------------

void ofApp::draw(){

    ofDrawBitmapString("I am floating in the most peculiar way", mouseX, mouseY);

}

//--------------------------------------------------------------

void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------

void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------

void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------

void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::windowResized(int w, int h){

}

  

HELLO GLOBE

Ok, time to move on to something more interesting. in this program we are introducing our first event to sense input (we have been cheating above by directly referring to mouseX, mouseY), and also learn how to introduce a new variable that we can use across methods.

Let's change our program to draw a circle instead of a bitmap text. We could start with a fixed diameter of 100. Then it would be more interesting to be able to decrease and increase the diameter by pressing a and z respectively. For that we first print they value of a pressed key (cout << key) in the keyPressed() method. You will notice that key contains the ASCII value of the pressed key, and this way we can make sure we are checking for the right number.

The next step is to swap out the fixed diameter of 100 in the circle by a variable that represents the diameter. However if you just replace 100 by a variable diameter you will notice that doesn't work - the variable is not 'declared'. Now within a method (say in draw() alone) we could introduce a variable diameter but that wouldn't work - we need it at the overall App level so that we can increase and decrease it in the keyPressed() event. 

To do this you will need to declare the variable diameter in the ofApp.file, by adding a line int diameter;. Actually ofApp is a class (say an object type) and the ofApp,h file is the so called header file of the ofApp class - it lists what methods and variables are available for the ofApp object. The ofApp.cpp file is the so called implementation of the ofApp class methods; .cpp stands for C++, the program language the openFrameworks is written in.

ofApp.h

 

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:

        void setup();

        void update();

        void draw();

        void keyPressed  (int key);

        void keyReleased(int key);

        void mouseMoved(int x, int y );

        void mouseDragged(int x, int y, int button);

        void mousePressed(int x, int y, int button);

        void mouseReleased(int x, int y, int button);

        void windowResized(int w, int h);

        int diameter;

};

#endif

  

ofApp.cpp

 

#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup(){

    cout << "This is ground control to Major Tom, commencing countdown, engines on..." << endl; // just getting started

    diameter=50;

    ofBackground(0,0,0); // background color

    ofSetColor(255,255,255); // text white

}

//--------------------------------------------------------------

void ofApp::update(){

    // cout << "Can you hear me major Tom?" << endl;

}

//--------------------------------------------------------------

void ofApp::draw(){

    ofCircle(mouseX, mouseY, diameter); // draw circle

}

//--------------------------------------------------------------

void ofApp::keyPressed(int key){

    cout << key << endl; // just for testing purposes

    if(key==97) diameter++; // a pressed

    if(key==122) diameter--; // z pressed

}

//--------------------------------------------------------------

void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------

void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------

void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){

    ofNoFill();

}

//--------------------------------------------------------------

void ofApp::mouseReleased(int x, int y, int button){

    ofFill();

}

//--------------------------------------------------------------

void ofApp::windowResized(int w, int h){

}

HELLO PLANET

As we explained above ofApp is a class, defined by its properties (variables), and methods that describe what you can do with that class. OpenFrameworks comes with many more out of the box classes, and you can also create your own. The instantiations of a class is called an object. In the example below we use image objects, instantiations of the ofImage class, to replace the circle with the image of a planet. Like any other property we declare it first in the .h header file, and we can use the methods that defined for ofImage to take actions. Note: you need to put this picture in your bin/data directory in your project directory and call it planet.png

 

 

 

ofApp.h

 

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:

        void setup();

        void update();

        void draw();

        void keyPressed  (int key);

        void keyReleased(int key);

        void mouseMoved(int x, int y );

        void mouseDragged(int x, int y, int button);

        void mousePressed(int x, int y, int button);

        void mouseReleased(int x, int y, int button);

        void windowResized(int w, int h);

        ofImage planet;

};

#endif

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup(){

    cout << "This is ground control to Major Tom, commencing countdown, engines on..." << endl; // just getting started

    planet.loadImage("planet.png");

    planet.setAnchorPercent(0.5, 0.5); 

    ofBackground(0,0,0); // background color

    ofSetColor(255,255,255); // text white

}

//--------------------------------------------------------------

void ofApp::update(){

    // cout << "Can you hear me major Tom?" << endl;

}

//--------------------------------------------------------------

void ofApp::draw(){

    planet.draw(mouseX, mouseY);

}

//--------------------------------------------------------------

void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------

void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------

void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------

void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::windowResized(int w, int h){

}

 

BOUNCING PLANET

To practice a bit more with C++ syntax we are going to change the program so that it is no longer controlled by the mouse, but let it bounce around on the screen diagonally. Every time we hit the boundary of the screen we need to change either the x or y direction in which the planet travels.

ofApp.h

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:

        void setup();

        void update();

        void draw();

        void keyPressed  (int key);

        void keyReleased(int key);

        void mouseMoved(int x, int y );

        void mouseDragged(int x, int y, int button);

        void mousePressed(int x, int y, int button);

        void mouseReleased(int x, int y, int button);

        void windowResized(int w, int h);

        int x, y, vx, vy;

        ofImage planet;

};

#endif

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup(){

    cout << "This is ground control to Major Tom, commencing countdown, engines on..." << endl; // just getting started

    x=ofGetWidth()/2;

    y=ofGetHeight()/2;

    vx=1;

    vy=1;

    ofBackground(0,0,0); // background color

    ofSetColor(255,255,255); // text white

    planet.loadImage("planet.png");

    planet.setAnchorPercent(0.5, 0.5);

}

//--------------------------------------------------------------

void ofApp::update(){

    x+=vx; y+=vy;

    // if (x < 0) x = ofGetWidth();  // if it drops off, appear on the other side

    // if (y < 0) y = ofGetHeight();

    // if (x > ofGetWidth()) x=0;

    // if (y > ofGetHeight()) y = 0;

    if (x < 0) {

        x = 0;

        vx=-vx;

        }

    if (y < 0) {

        y = 0;

        vy=-vy;

        }

    if (x > ofGetWidth()) {

        x=ofGetWidth();

        vx=-vx;

    }

    if (y > ofGetHeight()) {

        y = ofGetHeight();

        vy=-vy;}

}

//--------------------------------------------------------------

void ofApp::draw(){

    planet.draw(x, y);

}

//--------------------------------------------------------------

void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------

void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------

void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------

void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::windowResized(int w, int h){

}

 

BOUNCING PLANETS

In this final example we are going to use the single bouncing planet by a whole bunch of bouncing planets. To do this we are going to add a property that declares an array of n images. We will also introduce the ofPoint class that represents a point in space, and use this to declare arrays of postions as well as speeds. We will also introduce the ofRandom class to generate random numbers in a particular range.

ofApp.h

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:

        void setup();

        void update();

        void draw();

        void keyPressed  (int key);

        void keyReleased(int key);

        void mouseMoved(int x, int y );

        void mouseDragged(int x, int y, int button);

        void mousePressed(int x, int y, int button);

        void mouseReleased(int x, int y, int button);

        void windowResized(int w, int h);

        int n;

        ofImage planet[10];

        ofPoint pos[10], speed[10];

};

#endif

ofApp.cpp

 

#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup(){

    cout << "This is ground control to Major Tom, commencing countdown, engines on..." << endl; // just getting started

    n=10;

    for(int i=0; i<n; i++) {

        pos[i].x=ofRandom(0,ofGetWidth());

        pos[i].y=ofRandom(0,ofGetHeight());;

        speed[i].x=ofRandom(-0.5, 0.5);

        speed[i].y=ofRandom(-0.5,0.5);

        cout << pos[i].x << ", " << pos[i].y << endl;

        planet[i].loadImage("planet.png");

        planet[i].setAnchorPercent(0.5, 0.5);

        }

}

//--------------------------------------------------------------

void ofApp::update(){

    for(int i=0; i<n; i++) {

        pos[i].x+=speed[i].x;

        pos[i].y+=speed[i].y;

        if (pos[i].x < 0) {

            pos[i].x = 0;

            speed[i].x=-speed[i].x;

            }

        if (pos[i].y < 0) {

            pos[i].y = 0;

            speed[i].y=-speed[i].y;

            }

        if (pos[i].x > ofGetWidth()) {

            pos[i].x=ofGetWidth();

            speed[i].x=-speed[i].x;

        }

        if (pos[i].y > ofGetHeight()) {

            pos[i].y = ofGetHeight();

            speed[i].y=-speed[i].y;}

    }

}

//--------------------------------------------------------------

void ofApp::draw(){

    ofBackground(0,0,0); // background color

    ofSetColor(255,255,255); // text white

    // cout << "Can you hear me major Tom?" << endl;

    for (int i=0; i<n; i++) planet[i].draw(pos[i].x, pos[i].y);

}

//--------------------------------------------------------------

void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------

void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------

void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------

void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------

void ofApp::windowResized(int w, int h){

}