You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
367 lines
12 KiB
367 lines
12 KiB
/*! |
|
|
|
@page quick_guide Getting started |
|
|
|
@tableofcontents |
|
|
|
This guide takes you through writing a small application using GLFW 3. The |
|
application will create a window and OpenGL context, render a rotating triangle |
|
and exit when the user closes the window or presses _Escape_. This guide will |
|
introduce a few of the most commonly used functions, but there are many more. |
|
|
|
This guide assumes no experience with earlier versions of GLFW. If you |
|
have used GLFW 2 in the past, read @ref moving_guide, as some functions |
|
behave differently in GLFW 3. |
|
|
|
|
|
@section quick_steps Step by step |
|
|
|
@subsection quick_include Including the GLFW header |
|
|
|
In the source files of your application where you use GLFW, you need to include |
|
its header file. |
|
|
|
@code{.c} |
|
#include <GLFW/glfw3.h> |
|
@endcode |
|
|
|
This header provides all the constants, types and function prototypes of the |
|
GLFW API. |
|
|
|
By default it also includes the OpenGL header from your development environment. |
|
On some platforms this header only supports older versions of OpenGL. The most |
|
extreme case is Windows, where it typically only supports OpenGL 1.2. |
|
|
|
Most programs will instead use an |
|
[extension loader library](@ref context_glext_auto) and include its header. |
|
This example uses files generated by [glad](https://gen.glad.sh/). The GLFW |
|
header can detect most such headers if they are included first and will then not |
|
include the one from your development environment. |
|
|
|
@code{.c} |
|
#include <glad/gl.h> |
|
#include <GLFW/glfw3.h> |
|
@endcode |
|
|
|
To make sure there will be no header conflicts, you can define @ref |
|
GLFW_INCLUDE_NONE before the GLFW header to explicitly disable inclusion of the |
|
development environment header. This also allows the two headers to be included |
|
in any order. |
|
|
|
@code{.c} |
|
#define GLFW_INCLUDE_NONE |
|
#include <GLFW/glfw3.h> |
|
#include <glad/gl.h> |
|
@endcode |
|
|
|
|
|
@subsection quick_init_term Initializing and terminating GLFW |
|
|
|
Before you can use most GLFW functions, the library must be initialized. On |
|
successful initialization, `GLFW_TRUE` is returned. If an error occurred, |
|
`GLFW_FALSE` is returned. |
|
|
|
@code{.c} |
|
if (!glfwInit()) |
|
{ |
|
// Initialization failed |
|
} |
|
@endcode |
|
|
|
Note that `GLFW_TRUE` and `GLFW_FALSE` are and will always be one and zero. |
|
|
|
When you are done using GLFW, typically just before the application exits, you |
|
need to terminate GLFW. |
|
|
|
@code{.c} |
|
glfwTerminate(); |
|
@endcode |
|
|
|
This destroys any remaining windows and releases any other resources allocated by |
|
GLFW. After this call, you must initialize GLFW again before using any GLFW |
|
functions that require it. |
|
|
|
|
|
@subsection quick_capture_error Setting an error callback |
|
|
|
Most events are reported through callbacks, whether it's a key being pressed, |
|
a GLFW window being moved, or an error occurring. Callbacks are C functions (or |
|
C++ static methods) that are called by GLFW with arguments describing the event. |
|
|
|
In case a GLFW function fails, an error is reported to the GLFW error callback. |
|
You can receive these reports with an error callback. This function must have |
|
the signature below but may do anything permitted in other callbacks. |
|
|
|
@code{.c} |
|
void error_callback(int error, const char* description) |
|
{ |
|
fprintf(stderr, "Error: %s\n", description); |
|
} |
|
@endcode |
|
|
|
Callback functions must be set, so GLFW knows to call them. The function to set |
|
the error callback is one of the few GLFW functions that may be called before |
|
initialization, which lets you be notified of errors both during and after |
|
initialization. |
|
|
|
@code{.c} |
|
glfwSetErrorCallback(error_callback); |
|
@endcode |
|
|
|
|
|
@subsection quick_create_window Creating a window and context |
|
|
|
The window and its OpenGL context are created with a single call to @ref |
|
glfwCreateWindow, which returns a handle to the created combined window and |
|
context object |
|
|
|
@code{.c} |
|
GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); |
|
if (!window) |
|
{ |
|
// Window or OpenGL context creation failed |
|
} |
|
@endcode |
|
|
|
This creates a 640 by 480 windowed mode window with an OpenGL context. If |
|
window or OpenGL context creation fails, `NULL` will be returned. You should |
|
always check the return value. While window creation rarely fails, context |
|
creation depends on properly installed drivers and may fail even on machines |
|
with the necessary hardware. |
|
|
|
By default, the OpenGL context GLFW creates may have any version. You can |
|
require a minimum OpenGL version by setting the `GLFW_CONTEXT_VERSION_MAJOR` and |
|
`GLFW_CONTEXT_VERSION_MINOR` hints _before_ creation. If the required minimum |
|
version is not supported on the machine, context (and window) creation fails. |
|
|
|
You can select the OpenGL profile by setting the `GLFW_OPENGL_PROFILE` hint. |
|
This program uses the core profile as that is the only profile macOS supports |
|
for OpenGL 3.x and 4.x. |
|
|
|
@code{.c} |
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); |
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); |
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); |
|
GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); |
|
if (!window) |
|
{ |
|
// Window or context creation failed |
|
} |
|
@endcode |
|
|
|
When a window and context is no longer needed, destroy it. |
|
|
|
@code{.c} |
|
glfwDestroyWindow(window); |
|
@endcode |
|
|
|
Once this function is called, no more events will be delivered for that window |
|
and its handle becomes invalid. |
|
|
|
|
|
@subsection quick_context_current Making the OpenGL context current |
|
|
|
Before you can use the OpenGL API, you must have a current OpenGL context. |
|
|
|
@code{.c} |
|
glfwMakeContextCurrent(window); |
|
@endcode |
|
|
|
The context will remain current until you make another context current or until |
|
the window owning the current context is destroyed. |
|
|
|
If you are using an [extension loader library](@ref context_glext_auto) to |
|
access modern OpenGL then this is when to initialize it, as the loader needs |
|
a current context to load from. This example uses |
|
[glad](https://github.com/Dav1dde/glad), but the same rule applies to all such |
|
libraries. |
|
|
|
@code{.c} |
|
gladLoadGL(glfwGetProcAddress); |
|
@endcode |
|
|
|
|
|
@subsection quick_window_close Checking the window close flag |
|
|
|
Each window has a flag indicating whether the window should be closed. |
|
|
|
When the user attempts to close the window, either by pressing the close widget |
|
in the title bar or using a key combination like Alt+F4, this flag is set to 1. |
|
Note that __the window isn't actually closed__, so you are expected to monitor |
|
this flag and either destroy the window or give some kind of feedback to the |
|
user. |
|
|
|
@code{.c} |
|
while (!glfwWindowShouldClose(window)) |
|
{ |
|
// Keep running |
|
} |
|
@endcode |
|
|
|
You can be notified when the user is attempting to close the window by setting |
|
a close callback with @ref glfwSetWindowCloseCallback. The callback will be |
|
called immediately after the close flag has been set. |
|
|
|
You can also set it yourself with @ref glfwSetWindowShouldClose. This can be |
|
useful if you want to interpret other kinds of input as closing the window, like |
|
for example pressing the _Escape_ key. |
|
|
|
|
|
@subsection quick_key_input Receiving input events |
|
|
|
Each window has a large number of callbacks that can be set to receive all the |
|
various kinds of events. To receive key press and release events, create a key |
|
callback function. |
|
|
|
@code{.c} |
|
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) |
|
{ |
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) |
|
glfwSetWindowShouldClose(window, GLFW_TRUE); |
|
} |
|
@endcode |
|
|
|
The key callback, like other window related callbacks, are set per-window. |
|
|
|
@code{.c} |
|
glfwSetKeyCallback(window, key_callback); |
|
@endcode |
|
|
|
In order for event callbacks to be called when events occur, you need to process |
|
events as described below. |
|
|
|
|
|
@subsection quick_render Rendering with OpenGL |
|
|
|
Once you have a current OpenGL context, you can use OpenGL normally. In this |
|
tutorial, a multicolored rotating triangle will be rendered. The framebuffer |
|
size needs to be retrieved for `glViewport`. |
|
|
|
@code{.c} |
|
int width, height; |
|
glfwGetFramebufferSize(window, &width, &height); |
|
glViewport(0, 0, width, height); |
|
@endcode |
|
|
|
You can also set a framebuffer size callback using @ref |
|
glfwSetFramebufferSizeCallback and be notified when the size changes. |
|
|
|
The details of how to render with OpenGL is outside the scope of this tutorial, |
|
but there are many excellent resources for learning modern OpenGL. Here are |
|
a few of them: |
|
|
|
- [Anton's OpenGL 4 Tutorials](https://antongerdelan.net/opengl/) |
|
- [Learn OpenGL](https://learnopengl.com/) |
|
- [Open.GL](https://open.gl/) |
|
|
|
These all happen to use GLFW, but OpenGL itself works the same whatever API you |
|
use to create the window and context. |
|
|
|
|
|
@subsection quick_timer Reading the timer |
|
|
|
To create smooth animation, a time source is needed. GLFW provides a timer that |
|
returns the number of seconds since initialization. The time source used is the |
|
most accurate on each platform and generally has micro- or nanosecond |
|
resolution. |
|
|
|
@code{.c} |
|
double time = glfwGetTime(); |
|
@endcode |
|
|
|
|
|
@subsection quick_swap_buffers Swapping buffers |
|
|
|
GLFW windows by default use double buffering. That means that each window has |
|
two rendering buffers; a front buffer and a back buffer. The front buffer is |
|
the one being displayed and the back buffer the one you render to. |
|
|
|
When the entire frame has been rendered, the buffers need to be swapped with one |
|
another, so the back buffer becomes the front buffer and vice versa. |
|
|
|
@code{.c} |
|
glfwSwapBuffers(window); |
|
@endcode |
|
|
|
The swap interval indicates how many frames to wait until swapping the buffers, |
|
commonly known as _vsync_. By default, the swap interval is zero, meaning |
|
buffer swapping will occur immediately. On fast machines, many of those frames |
|
will never be seen, as the screen is still only updated typically 60-75 times |
|
per second, so this wastes a lot of CPU and GPU cycles. |
|
|
|
Also, because the buffers will be swapped in the middle the screen update, |
|
leading to [screen tearing](https://en.wikipedia.org/wiki/Screen_tearing). |
|
|
|
For these reasons, applications will typically want to set the swap interval to |
|
one. It can be set to higher values, but this is usually not recommended, |
|
because of the input latency it leads to. |
|
|
|
@code{.c} |
|
glfwSwapInterval(1); |
|
@endcode |
|
|
|
This function acts on the current context and will fail unless a context is |
|
current. |
|
|
|
|
|
@subsection quick_process_events Processing events |
|
|
|
GLFW needs to communicate regularly with the window system both in order to |
|
receive events and to show that the application hasn't locked up. Event |
|
processing must be done regularly while you have visible windows and is normally |
|
done each frame after buffer swapping. |
|
|
|
There are two methods for processing pending events; polling and waiting. This |
|
example will use event polling, which processes only those events that have |
|
already been received and then returns immediately. |
|
|
|
@code{.c} |
|
glfwPollEvents(); |
|
@endcode |
|
|
|
This is the best choice when rendering continually, like most games do. If |
|
instead you only need to update your rendering once you have received new input, |
|
@ref glfwWaitEvents is a better choice. It waits until at least one event has |
|
been received, putting the thread to sleep in the meantime, and then processes |
|
all received events. This saves a great deal of CPU cycles and is useful for, |
|
for example, many kinds of editing tools. |
|
|
|
|
|
@section quick_example Putting it together |
|
|
|
Now that you know how to initialize GLFW, create a window and poll for |
|
keyboard input, it's possible to create a small program. |
|
|
|
This program creates a 640 by 480 windowed mode window and starts a loop that |
|
clears the screen, renders a triangle and processes events until the user either |
|
presses _Escape_ or closes the window. |
|
|
|
@snippet triangle-opengl.c code |
|
|
|
The program above can be found in the |
|
[source package](https://www.glfw.org/download.html) as |
|
`examples/triangle-opengl.c` and is compiled along with all other examples when |
|
you build GLFW. If you built GLFW from the source package then you already have |
|
this as `triangle-opengl.exe` on Windows, `triangle-opengl` on Linux or |
|
`triangle-opengl.app` on macOS. |
|
|
|
This tutorial used only a few of the many functions GLFW provides. There are |
|
guides for each of the areas covered by GLFW. Each guide will introduce all the |
|
functions for that category. |
|
|
|
- @ref intro_guide |
|
- @ref window_guide |
|
- @ref context_guide |
|
- @ref monitor_guide |
|
- @ref input_guide |
|
|
|
You can access reference documentation for any GLFW function by clicking it and |
|
the reference for each function links to related functions and guide sections. |
|
|
|
The tutorial ends here. Once you have written a program that uses GLFW, you |
|
will need to compile and link it. How to do that depends on the development |
|
environment you are using and is best explained by the documentation for that |
|
environment. To learn about the details that are specific to GLFW, see |
|
@ref build_guide. |
|
|
|
*/
|
|
|