Donations

Today we are opening the openFrameworks donations page!

For years we’ve developed openFrameworks through the voluntary, non-paid contributions of many people around the world.

These contributions are often part of the process of people using openFrameworks for their work or practice. As they discover bugs or need new features, they contribute these changes back to openFrameworks, benefiting the community and project as whole.

This workflow has worked fairly well for openFrameworks up to this point. However it means that the growth of the project is limited by the particular interests and available time of contributors and has meant that some areas of the project have fallen behind.

We are opening up the donations page to fund some of these areas and to help OF continue forward in a more sustainable way. Your donations will contribute to the following:

Documentation

Documentation is one of the main areas that has been behind the rest of the project. We think that it could be that the users who are confident enough to contribute to the openFrameworks codebase don’t rely as much on the the documentation and the people who do rely on it and run into unclear or missing documentation usually don’t feel confident enough to contribute to it.

We’ve organized documentation sprints which has been helpful in the short term, but it doesn’t take long for the documentation to begin to drift out of sync with this codebase and as it is an area where there isn’t active ongoing contributions we believe it needs us to take a different approach.

With financial contributions from individuals, companies and institutions we would be able to fund a team, over the long term to work on the documentation, make sure it was up to date with the API and provide good examples and tutorials for all areas of the project.

Infrastructure

As the openFrameworks project has grown we are relying on wide range of services and infrastructure to keep the project running. We have a distributed build system, continuous integration services ( CI ) that allow us to check that changes don’t break the codebase and a tool for compiling all the libraries for the many different platforms OF supports ( Apothecary ).

There is also a lot of work that needs to be done not directly related to using OF itself, like maintaining the forum, updating the CI or fixing the multiple servers we use when something breaks, as well as keeping them up to date. Maintaining these services and development systems is something we’ve been doing up until now unpaid, but the amount of time it requires isn’t sustainable to continue in the long term.

Diversity

Making openFrameworks more accessible and the community of users more diverse is another big goal of the project that we think we can really improve if we have a significant and ongoing financial contribution.

Until now we’ve been relying on a community of contributors who had enough free time to work on the project but we’ve come to realize that because of very different factors like for example, wages inequality, it is much harder for some people like women, people of color or people living in developing countries to work without being paid in their free time. By being able to pay for some contributions we expect to help overcome that barrier and increase range of people contributing and shaping the future of openFrameworks.

A more sustainable model

Opening up the donations page is only a first step. We are currently working on the outline for a more sustainable model for openFrameworks, which would allow the project to get broader, institutional level funding. Individual donations in the meantime will help immensely with us moving quicker towards our goals, offloading work onto a more diverse group of contributors and help achieve more regular, higher quality and better documented releases.

To donate

If you have used openFrameworks in your personal practice, or you represent a studio or company that has used openFrameworks in your work and you would like to financially support the project, please do so now at the donations link below.

Thanks for your support!

glm

OpenGL Mathematics

OpenGL Mathematics GLM has become the defacto standard for graphics vector math in C++ in the latest years. It’s syntax mimics that of glsl so working with it while working with OpenGL, shaders… makes things easier cause the syntax is almost the same across the different languages.

openFrmaeworks, since version 0.10 uses GLM as it’s default vector math library in the core and although old projects using ofVec* classes should work with minimal changes, if you are starting a new project we recomend to use GLM instead.

Namespace

GLM classes and functions are in the glm namespace so to use them you need to either prefix them with glm:::

glm::vec3 v(2.f, 2.f, 2.f);
float l = glm::length(v);

Or in your .cpp files import the glm namespace at the very beginning:

using namespace glm;

And then use the classes and functions without prefix:

vec3 v(2.f, 2.f, 2.f);
float l = length(v);

Functions not methods

GLM classes like vectors, matrices or quaternions don’t have methods. Instead glm uses functions to operate on those classes so if you want to for example normalize a vector you would do:

glm::vec3 v(2.f, 2.f, 2.f);
glm::vec3 n = glm::normalize(v);

The only exceptions to this rule are operators which you don’t use directly but instead allow to do arithmetic operations so you can do things like:

glm::vec3 v1(1.f, 1.f, 1.f);
glm::vec3 v2(2.f, 2.f, 2.f);
glm::vec3 v3 = v1 + v2;

Warning

GLM vector have a static length function which returns the dimension of the vector type, so glm::vec2::length() returns 2, glm::vec3::length() returns 3…

Because C++ allows to call static methods on instances of that class you can make the error of calling:

glm::vec3 v(2.f, 2.f, 2.f);
float length = v.length();

To try and get the length of the vector instead of the number of dimensions of the type. The correct way of doing that would be:

glm::vec3 v(2.f, 2.f, 2.f);
float length = glm::length(v);

Mostly when porting old code form ofVec to glm, because ofVec included such a method, it’s easy to try and call that function which will compile without errors but won’t do what you expect.

When doing that, most modern compilers should show a warning because of calling a static method on an instance instead of a class, so be on the look for those when porting old code to GLM.

Type strictness

glm has a strict type system, similar to how things work in glsl, meaning that you can’t autoconvert from one type to another automatically as it was the case with ofVectorMath.

For example:

glm::vec2 v2(2.f, 2.f);
glm::vec3 v3 = v2;

Won’t work anymore, you need to do now:

glm::vec3 v3 = glm::vec3(v2, 0.f);

Or in the oposite case:

glm::vec3 v3(2.f, 2.f, 2.f);
glm::vec2 v2 = glm::vec2(v3)

or even:

glm::vec2 v2(v3)

Constants

GLM has some useful constants but the way to use them might be a little bit weird at first. The main problem comes from the fact that this constants are defined as templated functions so to call them you need to specify the type as in:

float p = glm::pi<float>();
double dp = glm::pi<double>();

Multiplication order

Finally, if you are used to the old openFrameworks vector math classes you would multiply vector and matrices like:

ofVec3 v;
ofVec3f projected = v * model * view * projection;

with glm as in glsl the multiplication order is the oposite so now you would do:

glm::vec3 v;
glm::vec3 projected = projection * view * model * v;

Android refactoring

Many OpenFrameworks Android apps are composed from a single activity, which derives from OFActivity and allow you to draw GL content in a canvas. This fits most cases. However, sometimes you need multiple activities, some with GL drawing and some without. OpenFrameworks Android supports such cases.

Add application initialization code

We can distinguish between application initialization and gl initialization. There are two methods in main.cpp, one for each. In most cases, there’s nothing to do in ‘ofAndroidApplicationInit’, and in ‘ofAndroidActivityInit’ we initialize the ofApp class.

‘ofAndroidApplicationInit’ allow you to do some initialization when the cpp side is created, even if the first activity is not a gl activity (for example, a completely native splash activity).

‘ofAndroidActivityInit’ is called when the gl canvas is initialized. This happens when the first OFActivity is created. Notice that if a second OFActivity is created on top of it, the canvas is recycled and this initialization code is not called again. However, if all OFActivites are destroyed, the canvas is indeed destroyed so when a new OFActivity is created, ‘ofAndroidActivityInit’ will be called again. The default implementation for this method instantiates the ofApp class, but you can add more code to it as needed.

Note that due to current architectural constraints, all activities share a single ofApp class and a single canvas. You cannot switch to different ofApp classes for drawing different activities as OpenFrameworks cannot currently hold multiple instances of the ofApp class in memory. It is up to you to signal the cpp side when a different activity is shown (when onResume is called on that activity), and perform different update/draw code to draw different content on the canvas.

Customizing the Android activity

OpenFrameworks supplies a base activity called OFActivity when the following conditions suits the project:

1) The first activity is this activity, meaning, the first activity in the application shows a gl canvas. 2) You want your activity to inherit from regular Android Activity class.

However, OpenFrameworks allows for more complicated scenarios, like having the first activity initializing the cpp side, but not the gl drawing (the first activity doesn’t draw gl at all, for example, a simple splash activity) or inheriting your activities from other classes, for example AppCompatActivity.

In order to achieve one or both the objectives above, you need to notify OpenFrameworks yourself on certain events, just like the original OFActivity does it:

In ANY activity in the application:

1) Whenever ANY activity is created OR resumed, you need to notify OpenFrameworks about it by calling OFAndroidLifeCycle.setActivity with this activity. 2) On the first activity created, you need to call OFAndroidLifeCycle.init() in order to initialize the cpp side. If this activity SHOULD NOT draw GL, you should call it with the parameter false in order to postpone canvas initialization.

In gl drawing activities:

1) in onCreate, call OFAndroidLifeCycle.glCreate() 2) in onResume, call OFAndroidLifeCycle.glResume() 3) in onPause, call OFAndroidLifeCycle.glPause() 4) in onDestroy, call OFAndroidLifeCycle.glDestroy()

You can look at the original OFActivity as a reference, and there’s also a detailed example with multiple activities in the android examples folder, called androidMultiOFActivityExample.

Tal Lavi & Artem Pyatishev.

ofxGui new features

The first post in the series about the new features in the 0.10.0 release, is going to be a short one about the gui.

Color picker

Up until 0.9.8 editing colors in the gui could only be done by adjusting the different rgb values using individual sliders which was not very intuitive:

In 0.10.0 it looks like this:

The new color picker is based on ofxColorPicker by Lukasz Karluk adapted to work with ofxGui and ofParameter

Text fields

In 0.10.0 ofxGui will add a text field for any ofParameter or you can create it manually using ofxInputField.

This new control is based on the original ofxInputField by Felix Lange with additions to better support selection, utf8 and clipboard.

Additionally any slider can be turned into an input field temporarily by right clicking on it, allowing for much more precise input.

Apart from this, one can now add an ofParameter<void> in a parameter group to get a button, add listeners to the save and load buttons to override the default save and load behavior:

panel.savePressedE.addListener([this]{
    // custom save

    return true; // to mark the event as attended 
                 // so the gui doesn't do the default save
});

panel.loadPressedE.addListener([this]{
    // custom load

    return true; // to mark the event as attended 
                 // so the gui doesn't do the default load
});

Also specifying a “.json” file when creating a panel instead of an “.xml” will load and save from json.

Arturo