LEO - Leadwerks Engine Objects

From Leadwerks Developer Wiki

Jump to: navigation, search

Contents

Introduction

LEO - Leadwerks Engine Objects
LEO - Leadwerks Engine Objects
LEO stands for Leadwerks Engine Objects, which is an extension to the

object Oriented Programming of C++ with the Leadwerks Engine functions.
As a complement to the plain C API that engine.h offers, LEO features
class wrappers as a thin C++ interface where most things are implemented
as classes.

All classes are declared within a namespace 'LEO' to avoid naming confusion.

If you have questions, suggestions or want to make bug reports please use
the Leadwerks forum and start the subject with "LEO:".

What is LEO?

LEO stands for Leadwerks Engine Objects, which is an extension to the
object Oriented Programming of C++ with the Leadwerks Engine functions.

As a complement to the plain C API that engine.h offers, LEO features
class wrappers as a thin C++ interface where most things are implemented
as classes.

All classes are declared within a namespace 'LEO' to avoid naming confusion.

If you have questions, suggestions or want to make bug reports please use
the Leadwerks forum and start the subject with "LEO:".

Latest version

Latest version is 2.28.0

Does LEO add new functions to the engine ?

LEO does not add any new functionality to the engine, its just a pure,
thin class representation of the C API.

Why use LEO?

Why use LEO instead of the standard C API when it doesn't add any functionality?
LEO brings a more object oriented approach to the engine and make life more
easy when adding special functionality to existing entities.

I have written my own wrapper so why use the LEO?
It's great if you have the knowledge to write your own class API to the engine,
but using a common class API has some advantages.

Some of the benefits of using LEO are:

  • It will be updated as the C API changes
  • A common base for new classes that may be shared within the community
  • Others will find errors that you missed.

Installation

LEO is included in the SDK and can be found in directory CPP/LEO

How to use

Using the LEO classes is easy and can be mixed with using the normal C API.

Add CPP and CPP/LEO to your compiler include path
Then add the file leo.cpp to your project

Add following two lines to your cpp file(s)

#include "leo.h"
using namespace LEO;

Naming conventions

When LEO was designed, following four simple rules was used for naming class methods

  • SetXXXX for changing attribute values
  • GetXXXX for reading attribute values
  • IsXXXX for reading class states
  • If a C function is member of a class (like they all are), then class name is removed from function name

Class diagram

The class diagram can be downloaded here

Tutorials


The Engine class

All classes in LEO have their counterpart in Nodes or Entity's in the C-API except one
and that is the Engine class. This class handles initialization and termination of the engine,
and also has a number of static methods which do not have to be called directly from an instance.
There should not be more than one instance of this class anyways.

It's commands other than creation and destruction can be referred static:

e.g.
Engine::SetShadowQuality()

Example

#include "leo.h"
using namespace LEO ;
 
int main( int argn, char* args[] ) 
{
      Engine engine( "A Test" , 800, 600 ) ;
 
      // Leadwerks Engine is now loaded and graphic's is initialized
 
      // other program code 
 
      // done
      return engine.Free() ;
}

A quick crash course

When using classes you are using the files in CPP/LEO
which a C++ class wrappers for the standard C-API in CPP/engine.h

Lets try to explain things with a small application which just shows
a rotating cube on screen. I will explain each line even If I guess you
are familiar to most of them

So lets get started. This is a simple example that can be used
for further questions.

Adding the LEO header

First we need to include the definitions for all the classes and declare that they are in a separate namespace called LEO.

#include "leo.h"

Writing main

Next we need out main program function which is always the same
for console programs. This 'main' is called by the operative system
when program starts.

#include "leo.h"
 
int main( int argn,  char* argv[] )
{
      return 0 ;
}

Initializing the engine

Ok. This was really basic stuff. Now we are going to use a LEO class to initialize the Leadwerks Engine and graphics

The Wiki gives

C++:
Engine::Engine( void )
Engine::Engine( const std::string& appTitle, int width, int height, int depth = 0, int hertz = 0, int flags = GRAPHICS_BACKBUFFER| GRAPHICS_DEPTHBUFFER )
int Engine::Create( const std::string&r appTitle, int width, int height, int depth = 0, int hertz = 0, int flags = GRAPHICS_BACKBUFFER| GRAPHICS_DEPTHBUFFER )

Where Engine::Engine is a class constructor. This means that each time an instance of the Engine class is created
the code in its constructor will be executed. As you see there are two different constructors here and also a method
called Create.

This is because you have two different options to use the Engine class.

One is to use the Engine::Engine constructor which only creates an instance of Engine and nothing more. 
To really start things you have to call the Create method.
Another way is tho use the Engine::Engine( const std::string& appTitle, int width, int height, ----- )
constructor which both creates the instance of the Engine and also internally calls Create for you.

We can use any of those methods to create the Engine instance.
First I will show an example of using the Engine::Engine constructor

#include "leo.h"
 
int main( int argn,  char* argv[] )
{
      LEO::Engine  engine ;     // create an  instance of Engine
      engine.Create( "Learning C++", 800, 600 ) ; // Start it 
 
     // fill with game code here 
 
      return engine.Free() ; // close (free) the engine and exit program
}

How to deal with namespace LEO

First you may wonder where the LEO:: comes from.
As all classes are defined in a separate namespace called LEO
we have to tell the compiler about that by prepending the class name by LEO::
This can be tiresome. So to make things more easy we can tell the compiler
that we are using the namespace LEO in this file with a using statement.
Then we don't have to specify LEO everywhere.

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine ;     // create an  instance of Engine
      engine.Create( "Learning C++", 800, 600 ) ; // Start it 
 
     // fill with game code here 
 
      return engine.Free() ; // close (free) the engine and exit program
}

Another more compact way to initialize the engine

A more compact way to do this is to use the other Engine constructor which both creates the instance and starts the engine

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; // Create instance and start it 
 
     // fill with game code here 
 
      return engine.Free() ; // close (free) the engine and exit program
}

Adding a world

Next thing is to add a world to our little program using the World class. Wiki gives.

C++:
World::World( const CreateMode& mode = CREATELATER ) Set mode = CREATENOW for instant creation<br>
virtual void World::Create( void )

So. Either we can create a World directly by giving the argument CREATENOW in the constructor or create the
instance giving no argument (or CREATELATER) in the constructor (in this case we can create the world later
by a call to Create)

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; 
      World   world( CREATENOW ) ;  // Create and initialize a world
 
      return engine.Free() ; 
}

Adding a camera

In order to see anything we need a Camera (Yes here it comes:).
Again we can look in the Wiki.

C++:
Camera::Camera( const TEntity = 0 ) Create has to be called
Camera::Camera( const CreateMode& createMode, const TEntity = 0 ) Where createMode is either CREATENOW or CREATELATER
virtual void Camera::Create( Entity parent=NULL )

Seems familiar to Engine and World. In fact almost all LEO classes builds on the strategy of having two constructors
and a Create method. Normally its most handy to use the constructor which both creates the instance and initializes it,
but when using LEO classes as members of other classes this is not always possible, so in such cases the 'empty'
constructor is used together with the Create call.

Ok. Lets create the camera and position it ( 5 meters backwards and at 1 meter height )

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; 
      World    world( CREATENOW ) ;
 
      Camera cam( CREATENOW ) ;
      cam.SetPosition( 0, 1, -5 ) ;      
 
      return engine.Free() ;
}

Adding a cube

We now got one more thing to create and that is the cube.
Checking the Wiki gives no surprises.

C++:
Cube::Cube( const CreateMode& createMode, const TEntity parent = 0 ) Set createMode = CREATENOW for immediate creation
virtual void Cube::Create( const TEntity parent = 0 )


So, as with the other LEO objects... just create it and there you are

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; 
      World    world( CREATENOW ) ;
 
      Camera cam( CREATENOW ) ;
      cam.SetPosition( 0, 1, -5 ) ;      
 
      Cube  cube( CREATENOW ) ; // creates and initializes a cube at position 0,0,0
 
      return engine.Free() ;
}

Writing the game loop

We also needs a game loop, that checks for user Escape and other terminating events.
Its also good to only render when the program is in focus. This can be achieved by using
some static methods ( methods that can be called without having an instance of a class)
in the Keyboard and Engine class.

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; 
      World    world( CREATENOW ) ;
 
      Camera cam( CREATENOW ) ;
      cam.SetPosition( 0, 1, -5 ) ;      
 
      Cube  cube( CREATENOW ) ; // creates and initializes a cube at position 0,0,0
 
      while(   !Keyboard::IsHit( KEY_ESCAPE )    // while user didn't hit Escape
      &&       !Engine::IsTerminated() )   // and the engine wasn't terminated of some other reason
      {
            if( !Engine::IsSuspended() )    // don't do things if we are suspended (not current window)
            {
                   // things will happen here ... .
           }
      }
      return engine.Free() ;
}

Adding rendering code

Almost there now.... Some rendering and were done
Rendering code for this sample is simple. First rotate the cube,
then update and render the World. Last send it to the screen.
No new classes used here.

#include "leo.h"
using namespace LEO ;
 
int main( int argn,  char* argv[] )
{
      Engine  engine( "Learning C++", 800, 600 ) ; 
      World    world( CREATENOW ) ;
 
      Camera cam( CREATENOW ) ;
      cam.SetPosition( 0, 1, -5 ) ;      
 
      Cube  cube( CREATENOW ) ; 
 
      while(   !Keyboard::IsHit( KEY_ESCAPE )    
      &&       !Engine::IsTerminated() )   
      {
            if( !Engine::IsSuspended() )    
            {
                  cube.Turn( Vec3( 1 ) ) ; // Rotate the cube
 
                  World::Update() ;   // calling static update method in world. 
                                               // This works on current world
                  World::Render() ;    // Render world
 
                  Engine::Flip();       // Send to screen calling Engine static method.
                                               // Note. As we have an engine instance here we could
                                               // have called engine.Flip(). The result would have been the same.
                                               // But note that calling methods like ClassName::Method(.... ) is only
                                               // possible for static methods.
            }
      }
      return engine.Free() ;
}

Done. Compile and run.

Finally done! Compile and run...you should get something like this:

Image:Whitecube.png

ProjectWizard

ProjectWizard is a project generator tool for Visual Studio that creates
a default project for you. This project is in fact same as shown above.
So if you have any problems setting this up I recommend you to download
ProjectWizard and generate a LEO project and you will have a program that
generates the same things as shown here.

ProjectWizard is included in the SDK


Written by rstralberg