Professional Documents
Culture Documents
Introduction
This tutorial is not about OpenGL itself, but rather how to use SFML as an
environment for OpenGL, and how to mix them together.
As you know, one of the most important features of OpenGL is portability. But
OpenGL alone won't be enough to create complete programs: you need a
window, a rendering context, user input, etc. You would have no choice but to
write OS-specific code to handle this stuff on your own. That's where the sfml-
window module comes into play. Let's see how it allows you to play with
OpenGL.
#include <SFML/OpenGL.hpp>
This header includes OpenGL functions, and nothing else. People sometimes
think that SFML automatically includes OpenGL extension headers because
SFML loads extensions itself, but it's an implementation detail. From the
user's point of view, OpenGL extension loading must be handled like any
other external library.
You will then need to link your program to the OpenGL library. Unlike what it
does with the headers, SFML can't provide a unified way of linking OpenGL.
Therefore, you need to know which library to link to according to what
operating system you're using ("opengl32" on Windows, "GL" on Linux, etc.).
OpenGL functions start with the "gl" prefix. Remember this when you get
linker errors, it will help you find which library you forgot to link.
1
Since SFML is based on OpenGL, its windows are ready for OpenGL calls
without any extra effort.
glEnable(GL_TEXTURE_2D);
...
o depthBits is the number of bits per pixel to use for the depth buffer (0 to
disable it)
o stencilBits is the number of bits per pixel to use for the stencil buffer (0
to disable it)
o antialiasingLevel is the multisampling level
o majorVersion and minorVersion comprise the requested version of
OpenGL
sf::ContextSettings settings;
settings.depthBits = 24;
settings.stencilBits = 8;
settings.antialiasingLevel = 4;
settings.majorVersion = 3;
settings.minorVersion = 0;
settings);
If any of these settings is not supported by the graphics card, SFML tries to
find the closest valid match. For example, if 4x anti-aliasing is too high, it tries
2
2x and then falls back to 0.
In any case, you can check what settings SFML actually used with
the getSettings function:
OpenGL versions above 3.0 are supported by SFML (as long as your graphics
driver can handle them). Support for selecting the profile of 3.2+ contexts and
whether the context debug flag is set was added in SFML 2.3. The forward
compatibility flag is not supported. By default, SFML creates 3.2+ contexts
using the compatibility profile because the graphics module makes use of
legacy OpenGL functionality. If you intend on using the graphics module,
make sure to create your context without the core profile setting or the
graphics module will not function correctly. On OS X, SFML supports creating
OpenGL 3.2+ contexts using the core profile only. If you want to use the
graphics module on OS X, you are limited to using a legacy context which
implies OpenGL version 2.1.
#include <SFML/Window.hpp>
#include <SFML/OpenGL.hpp>
int main()
3
sf::Window window(sf::VideoMode( 800, 600), "OpenGL", sf::Style::Default,
sf::ContextSettings(32));
window.setVerticalSyncEnabled( true);
window.setActive( true);
while (running)
// handle events
sf::Event event;
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
running = false;
4
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw...
// end the current frame (internally swaps the front and back buffers)
window.display();
// release resources...
return 0;
Don't hesitate to have a look at the "OpenGL" and "Window" examples in the
SFML SDK if you have further problems, they are more complete and most
likely contain solutions to your problems.
5
active will result in the currently active one being implicitly deactivated before
the new one is activated. In order to explicitly deactivate a window's context,
use window.setActive(false). This is required if the context is to be activated
on another thread as explained later on. Generally however, it is
recommended to simply deactivate the context every time you are done with a
batch of OpenGL operations. Following this advice, each batch of operations
would be visibly wrapped between activation and deactivation calls. A RAII
helper class can be written for this purpose.
window.setActive( true);
// clear framebuffers
window.setActive( false);
When debugging issues with OpenGL in SFML, the first step is always to
make sure a context is active when OpenGL functions are called. Do not
assume that SFML will implicitly activate a context or that SFML will preserve
the currently active context when calling into the library. The only guarantee
provided is that the context active on the current thread will not change
between calls to window.setActive(true) and window.setActive(false) as long
as no other calls are made into the library in between. In all other cases, it has
to be assumed that the current context might have changed, so explicitly
reactivating the previously active context is required to guarantee the
previously active context is once again active. Also ensure that the right
context is active when an OpenGL function is called. The active context not
only provides an execution environment for OpenGL operations, it also
designates the destination framebuffer of any draw commands. Calling
OpenGL draw functions while a context without a visible framebuffer is active
will result in those draw commands not producing any visible output. Splitting
OpenGL operations among multiple contexts will also result in the state
changes being spread across the contexts. If any subsequent draw operation
6
assumes that certain states are set, it will not produce the correct results in
this case.
Depending on the version and capabilities of the context available, care has to
be taken to only call functions that are actually valid within the current context.
Doing otherwise will often result in
the GL_INVALID_OPERATION or GL_INVALID_ENUM errors being generated. To query
the actual version and capabilities of a context created with a window or
separately, use window.getSettings() or context.getSettings() respectively. Be
aware that these settings might differ from the settings passed during creation
of the context if the OpenGL implementation was not able to meet all the
requirements. It is recommended to always check if the context created
actually provides the functionality required by the OpenGL code to be
executed. This can become confusing when loading OpenGL extensions in a
more capable context and trying to use them in a less capable context or vice
versa.
OpenGL calls are made on the active context (thus the active window).
Therefore if you want to draw to two different windows within the same
program, you have to select which window is active before drawing
something. This can be done with the setActive function:
window1.setActive( true);
7
// activate the second window
window2.setActive( true);
Only one context (window) can be active in a thread, so you don't need to
deactivate a window before activating another one, it is deactivated
automatically. This is how OpenGL works.
Another thing to know is that all the OpenGL contexts created by SFML share
their resources. This means that you can create a texture or vertex buffer with
any context active, and use it with any other. This also means that you don't
have to reload all your OpenGL resources when you recreate your window.
Only shareable OpenGL resources can be shared among contexts. An
example of an unshareable resource is a vertex array object.
int main()
sf::Context context;
...
return 0;
8
}
window->setActive( true);
while (window->isOpen())
// draw...
window->display();
int main()
// create the window (remember: it's safer to create it in the main thread
due to OS limitations)
9
sf::Window window(sf::VideoMode( 800, 600), "OpenGL");
window.setActive( false);
thread.launch();
while (window.isOpen())
...
return 0;
If you don't know the graphics module yet, all you have to know is that
the sf::Window class is replaced with sf::RenderWindow, which inherits all its
functions and adds features to draw SFML specific entities.
The only way to avoid conflicts between SFML and your own OpenGL states,
is to save/restore them every time you switch from OpenGL to SFML.
10
- save OpenGL states
...
glDraw...
window.pushGLStates();
window.draw(...);
window.popGLStates();
glDraw...
Since it has no knowledge about your OpenGL code, SFML can't optimize
these steps and as a result it saves/restores all available OpenGL states and
matrices. This may be acceptable for small projects, but it might also be too
slow for bigger programs that require maximum performance. In this case, you
can handle saving and restoring the OpenGL states yourself,
with glPushAttrib/glPopAttrib, glPushMatrix/glPopMatrix, etc.
If you do this, you'll still need to restore SFML's own states before drawing.
This is done with the resetGLStates function.
glDraw...
glPush...
window.resetGLStates();
11
window.draw(...);
glPop...
glDraw...
By saving and restoring OpenGL states yourself, you can manage only the
ones that you really need which leads to reducing the number of unnecessary
driver calls.
12