Appendix A. Support Libraries

In this text, we used GLFW as a simple, cross-platform application framework to simplify our examples. Further, we wrapped up the GLFW plumbing behind some of our own frameworks to reduce the amount of boilerplate code in each sample application. In addition, we employed the widely used GL3W OpenGL glue library to provide access to all of OpenGL’s functions on platforms that don’t necessarily expose them directly. This appendix provides a brief overview of both libraries.

This appendix contains the following major sections:

• “Basics of GLFW: The OpenGL Utility Framework

• “Initializing and Creating a Window

• “Handling User Input

• “Controlling the Window

• “Shutting Down Cleanly

• “GL3W: OpenGL Glue

Basics of GLFW: The OpenGL Utility Framework

GLFW is well maintained, lean, and without legacy constraints. It contains more functionality than we used throughout the text. This appendix describes a subset of the functions available in GLFW 3.x, which is the version used in this book. It is certainly not intended as a replacement for GLFW’s excellent online documentation.

GLFW makes the process of creating OpenGL applications simple because in its most basic form, only four steps are required to get the application going.

1. Initialize the GLFW library.

2. Create a GLFW window and OpenGL context.

3. Render your scene.

4. Present the output to the user.

In this appendix, we explain those steps and expand on other options that the GLFW library makes available. For complete details on GLFW, visit its Web site (http://www.glfw.org).

Initializing and Creating a Window

Before doing anything with GLFW, it’s a good idea to set up error handling such that if anything goes wrong, GLFW can tell you about it. Errors are reported to your application using a callback function. This callback function is set using the glfwSetErrorCallback() function, whose prototype is

The error callback function is declared in the following way:

When the error callback function is called, error will be set to the value of a GLFW error code, and description will contain a string describing the cause of the error.

To actually use GLFW for real work, you first need to initialize the library by calling glfwInit(). The prototype of glfwInit() is

Before you can do anything useful with GLFW, you need to create a window and its associated context. The window and its context are created together by the GLFW library. This is accomplished through a single call to glfwCreateWindow():

glfwCreateWindow() creates both the rendering window and a new context with which to render into it. Before you can use that context, however, you need to make it current. This is achieved by calling glfwMakeContextCurrent():

Once the window is created and its context is made current, you are ready to render. This is where the bulk of an OpenGL application lives. This is often referred to as the message loop because many windowing systems are message based, and an application will check for messages inside a tight loop. GLFW-based applications are no different. The main thing to check for is whether the application is supposed to exit. This information is given to you by glfwWindowShouldClose().

A typical GLFW application will execute a while loop, checking each time whether glfwWindowShouldClose() returns GL_TRUE and exiting if it does. Inside this loop, the application will render one frame and present it to the user. This is accomplished by calling glfwSwapBuffers().

Finally, inside this loop, GLFW should be given the opportunity to check its own message queues and synchronize with the operating system and its file system. This is achieved through a call to glfwPollEvents(), the prototype for which is

In applications that need to render continuously because, for example, they display an animation should call glfwPollEvents(). This function returns immediately regardless of whether any events are pending. If an application needs to update the display only when there is user interaction such as clicking a user-interface element or resizing the window, it may be a better idea to call glfwWaitEvents().

Handling User Input

There are two main types of user input that an OpenGL application is likely to be interested in: keyboard and mouse. For the keyboard, GLFW provides two mechanisms for input. The first is to use a callback function, which can be set individually for each window of the application. To set the keyboard callback for a window, call

The callback function you provide is called by GLFW when the user presses keys on the keyboard. In fact, it is called whenever the user presses or releases a key, including special keys such as Shift, Caps Lock, and Esc. The callback function has a prototype that looks like this:

When the callback function is called, window is the window handle to which the keyboard message was directed; key is the keyboard key that was pressed or released; scancode is a platform-dependent scan code for the key; action is one of GLFW_PRESS, GLFW_RELEASE, or GLFW_REPEAT, indicating whether the key was pressed, released or held down, respectively; and mods contains flags describing which modifier keys (such as Shift or Ctrl) were pressed at the same time.

The second method of handling keyboard input is through polling, which means asking the system whether any keys are pressed or, more specifically, whether certain keys are pressed. To do this, call

The glfwGetKey() function allows you to find the instantaneous state of any key. In effect, you can ask “Is this key pressed right now?”

To receive mouse input, you can employ either of two mechanisms similar to that used to handle keyboard input. The first is through a callback, which you can set by calling

After you call glfwSetCursorPosCallback(), the callback function you specify will be called whenever the mouse cursor is moved by the user. The prototype of your callback function should be

This function is called whenever the mouse cursor is moved. The x and y parameters contain the new position of the mouse cursor relative to the top left of the window.

In addition to receiving notification about movement of the mouse, it’s possible to receive notification about the user’s use of the mouse buttons and the scroll wheel. These work similarly to the keyboard and mouse position interfaces. To get the immediate state of the mouse buttons, call

When calling glfwGetMouseButton(), the button argument can be any number, although GLFW has defines for the first eight buttons using the tokens GLFW_MOUSE_BUTTON_1 through GLFW_MOUSE_BUTTON_8. By convention, the left, right and middle mouse buttons are defined as buttons 1, 2, and 3, respectively. The GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_RIGHT, and GLFW_MOUSE_BUTTON_MIDDLE are aliases for these values and should be used in your code.

To receive updates about the state of the mouse buttons as they occur, set a mouse-button callback function by calling

The prototype of the mouse callback function is

Unlike mouse buttons and position, the mouse wheel does not have an instantaneous position that may be queried, and its state is reported only through a callback function that you specify. To get the immediate position of the mouse wheel, your application needs to track the position of the wheel as it moves, using the callback function. To set the callback function, call

The mouse-wheel (scroll) callback is called by GLFW whenever the user moves the mouse wheel. The prototype of the callback function should be

As you might have noticed, the mouse-wheel (scroll) callback function takes both an xoffset and a yoffset parameter. These are the offsets of the movement in x and y axes; therefore, it’s possible to support two-dimensional scrolling in your application.

Controlling the Window

In GLFW, there are two areas where your application has control over the window. First, you can define its parameters before it is created. These parameters persist for the lifetime of the window and can’t be changed without closing and re-creating the window. Second, you have some control over the window after it’s been created.

The first set of parameters are set using hints. These are sticky state within the GLFW library and control features such as the color format used for the window, the OpenGL version requested by GLFW when it creates a rendering context, and so on. These are set using the glfwWindowHint() function, the prototype of which is

Once set, window hints will affect all windows created from then on. To reset all the hints to their defaults quickly, call

It’s a good idea to call this function before setting your own hints and creating new windows, because if any other part of your program has created a window before, the hints it set up might be lingering.

Besides the hints that control window creation and are generally permanent for a given window, certain properties of the window can be controlled by your application or by the user. The two obvious properties are the window’s size and position.

To change the size of a window, call

Likewise, to set the position of a window, call

The current position of the window may be queried at any time by calling

Likewise, the current size of a window may be queried by calling

Both the window position and size can also be reported to your application by GLFW asynchronously via callbacks. The respective functions for setting the position and size callback functions are

and

While glfwGetWindowPos() returns the size of the window in pixels (and the callback function is given this size in pixels), this is not always the real size of its associated framebuffer, especially if the window system is scaling or otherwise processing your application’s output. To retrieve the actual size of the framebuffer, use

As with window position, the size of the window’s framebuffer can also be reported to the application asynchronously by setting the framebuffer-size callback using

You will notice that all of the callback functions mentioned in this guide take a window parameter. This is the GLFW window that’s making the call. In most simple applications, you’re likely to use only a single window, but even so, it’s generally good practice to avoid global variables unless you’re absolutely sure that there will be only a single copy of the data they’re storing. Therefore, GLFW provides a means to associate your own data with a window. To set the window’s data, call

When you’re inside a callback function, you can call glfwGetWindowUserPointer() to get back the pointer you’ve specified. The prototype of glfwGetWindowUserPointer() is

The book’s application framework implements a class that contains the GLFW window along with other application state. It sets up the callbacks for you and sets the window user data pointer to this. Inside the callbacks (which must be static member functions), it calls glfwGetWindowUserPointer() to retrieve the value of this from GLFW and then calls the nonstatic member function, which you can override in your application.

Shutting Down Cleanly

When an application is ready to exit, it should reverse the steps it took to get running in the first place. First, the GLFW application should destroy any windows that it created. This is accomplished through a call to glfwDestroyWindow().

Finally, before exiting, the application should uninitialize GLFW itself. This is achieved with a call to glfwTerminate(), the prototype of which is

That’s it! After you’ve closed down GLFW, your application shouldn’t call any more of its functions (except, perhaps, glfwInit() to restart).

GL3W: OpenGL Glue

On most platforms that support OpenGL, the OpenGL libraries are installed as part of standard software development kits. For those that don’t provide such libraries (or simply to improve the portability of your code), we recommend using the GL3W library (https://github.com/skaslev/gl3w). GL3W is actually a script that generates binding code directly from Khronos’ master header files and so is automatically up to date. In addition to providing your application with access to the core OpenGL APIs, GL3W adds three simple functions, only one of which is really necessary in normal applications.

Before you can call any OpenGL functions when you’re using GL3W, you must call gl3wInit(), the prototype of which is

The other two functions of GL3W allow you to query properties of the OpenGL implementation you’re running on. First, gl3wIsSupported() allows you to determine whether the version of OpenGL supported by the platform is at least a version you ask for. The prototype of gl3wIsSupported() is

Remember, you can query the exact version of OpenGL being used directly from the current context by calling glGet*() with the parameters GL_VERSION_MAJOR and GL_VERSION_MINOR.

Finally, GL3W provides an abstraction of the platform-specific mechanism for getting a pointer to one of OpenGL’s functions. For core functions, this is not necessary because gl3wInit() sets all this up for you. However, if you want to use extensions, the gl3wGetProcAddress() function provides a way to get at the additional functions that they provide. Its prototype is

The GL3W library does not allocate any resources and does not need to be shut down.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.149.168