Overview of App Framework and Libraries
The OpenGL sample applications all leverage a cross-platform application framework and helper libraries in order to streamline and unify the sample code, and offer ease-of-use to developers.
This document covers the following:
The framework consists of a few libraries that each implement a particular reusable feature area:
Provides the raw application structure, with needed methods, callbacks, and event loop to execute on various platforms. It also includes abstractions for timing, mouse/touch input, keyboard input, gamepad control, and logging.
Provides basic file reading functionality. On Android, also supports reading files from the AssetManager.
Provides abstraction of gamepad input across platforms -- specifically, it implements support for Windows XInput and Android gamepad devices at this time.
Provides a number of helper classes for managing GL-related data -- including a GLSL program loader, and an Image loader focused on DDS files/data.
Provides a number of helper classes for loading and managing geometric model files -- including loading simple OBJ files, rendering, transforming and optimizing the content.
Provides a user interface framework for many standard 2D widgets, as well as the specific "TweakBar" UI used in the sample applications.
The following sections introduce the classes that are provided in each library.
The NVAppBase library exports a set of classes that make it easy to create simple OpenGL (and ES) applications that run on Windows, Android and Linux from a single source base. The basic functionalities of application lifecycle, input handling and mapping, window handling, file loading OpenGL context creation and interactive mainloop are all in place, leaving the application author to focus on the content of the application itself.
NvAppBase serves as a base class for applications and a base implementation of core application functionality. It includes callback functions for all forms of user input, rendering, initialization and shutdown. It provides access to platform functionalities like the OpenGL context, the game controllers (if any) and status information.
Most applications will not subclass NvAppBase directly, as far more functionality is available via the subclass NvSampleApp.
NvAppBase exposes the key startup function that all applications must define and implement: NvAppFactory. This function is declared and called in the NvAppBase library, but must be defined by the application. Each application creates an instance of itself in this function and returns it to the caller. This is how the application framework bootstraps itself.
NvSampleApp inherits from NvAppBase and adds a host of functionalities that are used by all of the sample applications in the samples pack. These include built-in:
- NvInputTransformer object and update calls to the object so that the application can implement a user-controlled object or camera by simply setting the desired interaction mode and querying the latest transform matrices.
- Extension and GL API minspec requirement functions to enforce base specs for an application and exit with a dialog if not met.
- NvTweakBar UI for easy creation of basic "parameter tuning" dialogs.
- Framerate counter for displaying the mean frame rate in the UI.
- Test mode to allow for unattended application testing and reporting.
All of the sample applications are subclasses of NvSampleApp, adding as needed to the initialization, rendering, update and input-handling functions. However, the availability of the built-in UI and input mapping objects means that extremely few (if any) samples need to explicitly override the input handling.
NvPlatformContext exports important platform functionalities to be used by both the framework and the app itself, including:
- Flags indicating whether the application should exit, whether it is the currently-focused application, whether the app has lost its GL context, etc.
- The ability to request that the app exit.
- The gamepad object (if gamepads are supported on the platform).
- The command-line arguments or properties used to launch the application.
NvGLAppContext provides cross-platform access to the GL-related functionalities and queries. These include:
- Binding and unbinding the context to/from the current thread.
- Swapping (presenting).
- Querying the width and height of the main window surface.
- Querying extension support and extension function pointers.
- Querying platform capabilities.
NvStopWatch provides cross-platform timer functionalities for timing application operations and doing animations based on wall-clock time.
NvFramerateCounter provides and easy encapsulation for measuring and computing the mean frame rate of an application over an adjustable window of frames and time. The application need do no more than signal the end of each frame.
NvInputTransformer automatically maps touch, mouse and gamepad input events into OpenGL-ready transform matrices. It can generate different interaction paradigms, such as "camera orbits object (virtual trackball)", "First-person shooter" and "2D pan-and-zoom". The functions in NvInputTransformer that accept input events filter them and will return whether the event should be "eaten" by the interaction method, or whether the events were ignored and should be passed on for further processing. Methods also allow the application to define starting location and orientation, as well as initial rotational and linear velocities.
NvAssetLoader provides functions that allow applications to load asset files into memory on all supported platforms. On Windows and Linux, assets are read from directories on the local filesystem, while on Android, the assets are ready from the application's APK pack.
NvGamepad is a cross-platform gamepad class that makes it easy for applications to query the status of connected gamepads. This support includes digital buttons as well as analog axes. A logical clock is implemented per gamepad to allow applications to quickly determine if any gamepad axes or buttons have changed since the last query. NvGamepad is abstract and serves as the client-side interface for using gamepads.
NvGamepadAndroid and NvGamepadXInput are concrete implementations of NvGamepad for Android and XINPUT-supporting (Win32) platforms. Applications using a cross-platform app framework will likely never deal with these subclasses directly. They will be given pointers to them, cast to the base NvGamepad class. The only interfaces these subclasses add are platform-specific methods of passing input events so that the current gamepad status is kept up-to-date.
The NvGLUtils package is a collection of classes designed to simplify common rendering-related operations without attempting to "abstract away" OpenGL.
NvGLSLProgram supports loading and binding of GLSL shader programs as well as common uniform and attribute operations. GLSL shaders can be loaded from asset files or strings; there are convenience functions for the common vertex-plus-fragment shader case, but all forms of shaders can be loaded, including extensions such as Compute Shadrs. While not the top performance, for simple samples, uniforms and attributes can be set by string name as well as by index.
NvImage supports loading of images from DDS files as well as the creation of OpenGL textures from the resulting image objects. 2D textures, mipmapping, cube maps, 3D textures and 2D array textures are also supported on platforms with support.
NvSimpleFBO wraps framebuffer object creation with some simple APIs and makes it easy to create and bind FBOs. Both color and depth texture buffers are supported.
NvModel includes lightweight geometry loaders and optimizers designed to load OBJ files for rendering under OpenGL.
NvGLModel loads OBJ data from asset files or from memory blocks. It formats them for rendering via OpenGL and provides functions to render the objects using the application's own shaders.
NvShapes includes simple functions to draw basic primitives like rectangles, points and lines using the applications own shaders.
NvUI is a cross-platform, GL/GLES-based user interface widget framework. It includes support for typical elements like icons/graphics, frames, text, buttons, progress bars and sliders, and popup menus, handling user interaction with widgets and rendering of their visuals. The primary use of NvUI in the sample applications is the construction and handling of the NvTweakBar interface.
NvSampleApp-based Application Flow
At a high level, NvSampleApp-based samples are initialized and run in the following manner:
- The platform's "main" function (built into the NvAppBase library) is started
- The main function calls NvAppFactory to create an instance of NvAppBase. This call is actually defined in the derived application itself and returns a pointer to an object that is an instance of the application class itself (e.g. MyApp), cast to the base class NvAppBase.
- The main function sets up the OpenGL system or wrapper and creates the application window on windowed platforms.
- The main function calls the application object's mainLoop, function. This is normally the implementation in NvSampleApp. This function will loop and not return to main until the application exits.
- The NvSampleApp::mainLoop function loops:
- mainLoop tests if the platform context indicates that it is still running. If not, the mainLoop returns
- mainLoop polls for events from the platform context
- The platform context queries the platform-specific input system (this code is in the NvAppBase library). Any input events are passed to the NvAppBase instance's input functions.
- NvSampleApp's implementation of the NvAppBase input functions:
- Passes the input the NvTweakUI
- If not handled, then the input is passed to the specific app's "handle*Input" and "handleGamepad*" functions
- If not handled, the the input is passed to the NvInputTransformer
- mainLoop calls the app's update function.
- If the GL context is not yet set up, the mainLoop attempts to set it up via the platform GL context
- If the setup succeeds, mainLoop calls the app's initRendering function
- mainLoop then creates the NvTweakUI
- mainLoop calls the app's initUI
- If the GL context is set up, the mainLoop calls the app's render function.
- mainLoop calls the renderUI function
- Main shuts down all instances and exits
The framework relies on a few external, third-party libraries to provide particular functionality:
Provides easier access to OpenGL extensions.
Provides a base cross-platform framework, supplying windowing, GL setup, and input support. Used for all platforms other than Android, where we have custom code.