Tech/LxEngine/Tutorials/Tutorial 1

Overview
The objective of this tutorial is to use LxEngine to create a Window that can render with OpenGL. The tutorial will simply clear the screen using the command to demonstrate this.

This is not a very exciting tutorial, but will give a whirlwind tour of the LxEngine architecture and major classes.

Concepts Introduced

 * Engine
 * Document, View, ViewImp
 * lxvar
 * Engine::run
 * Renderer
 * UIBinding

Prerequisites

 * This tutorial assumes you have downloaded and built the LxEngine SDK successfully and are able to execute the samples
 * This tutorial assumes a very basic familiarity with OpenGL and does not explain how OpenGL functions used in the tutorial work

Results
If all goes well, the application should produce a Blue Screen of Success&#0153;.

The Blue Screen of Success&#0153; can be exited by pressing the ESC key.



Tutorial
The code for this tutorial is all contained in a single file,. The full project can be browsed on github.

Since this is one of the first tutorials, a full listing of the file is included at the bottom of this page in. This tutorial itself will be going through the code a bit out of order, so it may be helpful to skim the full source listing first to orient yourself.

(Now would be a good time to click on the full source listing link if you haven't already.)

Headers
Summary: include in order to use LxEngine

Let's look at the first meaningful section of the code: what headers are included.

The lx0 includes

All LxEngine headers are located within the subdirectory to avoid naming collisions and conflicts. All of the "core" or "standard" functionality of LxEngine is included when is included. All LxEngine applications are expected to include

However, any optional or plug-in functionality must be included explicitly via another header. In this case, the plug-in functionality is the "canvas" functionality. Canvas is an optional component included in the standard LxEngine library. It represents a particular type of View, in this case a window that supports OpenGL rendering. Other types of View implementations are possible: such as OGRE-based windows, DirectX-based windows, or custom View implementations. Since not all application will necessarily be using the Canvas implementation, this is an optional component that needs to included explicitly.

Optionally functionality is usually included via a single header included of the. For example, in this case, a "view" is being added, so the type of component is "views". Another component type is "subsystem", which for major subsystems like a physics plug-in, javascript implementation, or the custom LxEngine OpenGL rasterizer. The remaining component-types are currently "util", for collections of utility functionality rather than neatly encapsulated components, and "prototype", for in-development plug-in behavior that is not yet fully usable.

The windows.h and gl.h includes

The next two includes are not directly related to LxEngine: they simply include the standard OpenGL headers so functions like can be used. Note that on Windows, it's still unfortunately necessary to included prior to including  - otherwise, there's nothing Windows specific about this tutorial application!

main
Summary: LxEngine throws exceptions, be ready to catch them on error conditions you wish to handle

Next, let's look at the start of the main function:

(...code here to be discussed later...)

The notable item is that the entire program is enclosed in block. LxEngine does throw exceptions. Exceptions are reserved for conditions that imply an application error has occurred and the application will likely want to close. LxEngine error handling is discussed elsewhere - for now, it's good to know that LxEngine does use exceptions. 

The Engine Singleton
Summary: is where to start

The next important line is the call to. LxEngine uses a Singleton object of the Engine class to orchestrate all the uses of LxEngine within that application. Acquiring the singleton for the first time does some minimal initialization, so it's important that this be the first step of the application before any other LxEngine services are used.

It's also worth noting the LxEngine naming convention:
 * is the class name
 * is a typedef for a

The suffix is used thorough the LxEngine code base, as reference counted pointers are the standard for all LxEngine objects.

Remember that of ? We now register the Canvas functionality with the Engine. Basically, we give the plugin a string name (which we'll use later to identify that plug-in) and provide a function for the Engine for creating instances of that plug-in. Notice that the core Engine object does not know anything about plug-in components, therefore addViewPlugin must be called and must pass in the lambda function telling the Engine object how to create a "Canvas" view.

The Document & View
Summary: LxEngine is an MVC architecture, you'll need a  and   to get going

LxEngine use a Model-View-Controller design pattern for the majority of the architecture. In basic terms, all the application 'data' is stored in a generic  and any sort of view of that data is done via a   object.

The is used to create the Document. Again, remember the Engine's purpose is to orchestrate everything that goes on in the application, so therefore it wants to know about all the major objects in the system.

Sure, this application doesn't have any data, so there's technically no need for a Document: but since the vast majority of applications will, LxEngine does enforce that a View must have a corresponding parent Document - even if it is an empty Document, as in this case.

Next the Document creates a View. This is done via naming the view plugin to use, assigning that view instance a name and lastly connecting the View to Renderer. The View itself is like a blank canvas that gives the application a chance to draw on it. The Renderer is the user-supplied object that does that actual drawing. The instance name is used so other components can get access to the View or Views on a Document without having to explicitly store a pointer to them (another instance of loose coupling in the LxEngine architecture).

We'll skip over the for a moment (it tells the View what to actually draw) in order to finish up looking at the  function.

A bit more Setup
First, we add a UIBinding to the View. What's that? It's a simple class that maps UI events (i.e. key presses, mouse moves, etc.) into 'application' events (e.g. quit, redraw the screen). We'll look into that in a moment. It's fairly straightforward.

Then, we need to show that View we created a moment ago. Since the View has a host of optional parameters, we pass them into the  method using an. What's an lxvar? It's basically a lightweight C++ class for storing JSON-like variant data of ints, floats, booleans, arrays, and/or maps. For non-performance sensitive code, it's very flexible and useful.

Engine::run
Summary: Engine::run is the platform-independent application message loop

What's the big black box inside the method?

The run method essentially wraps up an event loop that handles and dispatches platform messages (e.g. Win32 MSGs), object notifications (e.g. View::update calls), application events (e.g. the "quit" event).

The run method will continue until the Engine is sent a "quit" event. That will never happen by default, but fortunately, the UIBindingImp discussed shortly will map the ESC key to a "quit" event so that we're not trapped in an infinite loop.

Engine::shutdown
Summary: Call Engine::shutdown before closing the application

In C++, aren't the destructors supposed to do all the clean-up?

Yes, they are. However, due to the use of shared pointers, the Engine class requires a shutdown call to make sure all major objects in the system have an opportunity to clean-up nicely in the proper order. The explicit shutdown call also gives the Engine object an opportunity to do some internal memory and consistency checks in a debug environment to help improve the robustness of the application.

Another way to think of the shutdown call: this provides a "root" object from which the clean-up occurs, descending downward to the Document, View, and other major objects in the system. Construction and destruction order of application-wide objects can be a problem in large applications due to dependencies between objects. The method provides a more well-defined process for tearing down those objects.

Be sure to call Engine::shutdown before exiting to avoid some warnings and complaints from the application during the Engine destructor.

UIBindingImp
The UIBindingImp class' purpose is quite simple:

Map device events to application events.

The notion of application events will be discussed in more detail in later tutorials, but for now, the above is hopefully somewhat self explanatory. If the ESCAPE key is down, send a "quit" message to the Engine. If the R key is down, send a "redraw" message to the view. The messages are string-based to allow maximum flexibility in defining custom events (as well as for keeping disparate components only loosely coupled). 

The UIBinding interface provides several virtual functions for responding to various UI / device events. In this case, the code is hooked into the updateFrame method which is called once per "frame" or iteration of the Engine::run loop.

Renderer
The Renderer is another simple interface providing virtual methods that get called by the host View so that the View can render something meaningful. In particular, and  are of interest.

The Canvas ViewImp does all the basic OpenGL functionality such as the context creation, therefore the render only needs to initialize the data it in particular cares about. The Canvas implementation also handles the buffer swap. (Admittedly, what the Canvas class does and doesn't do needs to be documented somewhere other than simply in the source code itself!)

For developers familiar with OpenGL, what's happening here should be quite straightforward:
 * 1) The clear color is initialized once, right after the view is setup
 * 2) Every time the window is redraw, glClear is called to clear the buffer

Additional OpenGL calls can easily be added to the initialize and render methods to provide more intricate drawing than simply clearing the screen.

Conclusion
Even the most basic LxEngine application involves numerous objects:


 * Engine
 * Document
 * View
 * ViewImp
 * Renderer
 * UIBinding
 * lxvar

However, this covers the majority of the entire LxEngine architecture. There are a few other "core" classes such as Element and Controller, but for the most part these are all the core classes that you'll ever need to know to use LxEngine correctly. Individual subsystems and plug-ins introduce variations on these core objects, but for the most part do not introduce any fundamental new concepts.

Yes, this is a fairly long tutorial to display a blank window - but once this is in place, it should be fairly easy to accelerate along to more advanced features and custom behavior.

Appendix A: Feedback, Questions, & Issues
Please provide any feedback, questions, or issues on the forums.

LxEngine is in active development and in need of improvements. Suggestions for making it simpler to use are most welcome!

Appendix B: Full Source Listing
The latest source for this file is located on github here: https://github.com/athile/lxengine/blob/master/lx0/dev/samples/tutorials/tutorial_01/main.cpp