Thursday, 13 December 2012

In one of my previous posts I talked about how to install your own versions of a library when you don't have root access.

In this post I will show you how to install a cmake style project in the same way.

For this example I'm going to use alembic as the target library to build and it will be installed in the directory $(HOME)/

First we will download the alembic source

hg clone https://code.google.com/p/alembic/
cd alembic

Now we need to configure cmake to use the correct path for our local install this is done with the -DCMAKE_INSTALL_PREFIX:PATH= command as follows where the = is followed by where you want to install alembic

In the university labs most of these libs will be in the paths but you will need to change the ALEMBIC_DIR to the correct path for your install.
Finally the LD_LIBRARY_PATH needed to be amended to point to the correct OpenEXR files by adding the following export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ to my .bashrc, this may not be needed on your own versions.

Thursday, 29 November 2012

SDL is a very good library for games development and very useful for cross platform development. In this post I will explain how to install and configure SDL 2.0 (HG) for use with OpenGL and my NGL:: library. The source code can be downloaded using bzr branch http://nccastaff.bournemouth.ac.uk/jmacey/Code/SDLNGL from here

SDL installation

The latest version of SDL handles creating "core profile" OpenGL contexts on mac so this will be required. Earlier version of SDL will not work as they do not support the creation of the correct context for OpenGL under the mac. I decided to do a local install of SDL and if you wish to use this in the Labs at the University you will have to do the same thing as you don't have root permission to install the libs. The process of installation is similar to the one outlined here and I'm going to install the libraries in a directory called $(HOME)/SDL2.0 this is important as the makefile will also use this location to find the sdl2-config script at a later date.

The following commands will download and install the libraries and build it into the correct directory.

SDL NGL Demo

The demo is split into two main modules. The main.cpp file will create the SDL and OpenGL context, and handle the processing of events. The NGLDraw class will contain all OpenGL setup and drawing routines.

Setup and basic SDL

To use SDL we need to include the <SDL.h> header, this will be placed in the path by the following command in the Qt .pro file.

Next we create the basic window, in this case I get the size of the screen and configure the screen to be centred and half max screen width and height

// now get the size of the display and create a window we need to init the video
SDL_Rect rect;
SDL_GetDisplayBounds(0,&rect);
// now create our window
SDL_Window *window=SDL_CreateWindow("SDLNGL",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,
rect.w/2,rect.h/2,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
// check to see if that worked or exit
if (!window)
{
SDLErrorExit("Unable to create window");
}

Creating an OpenGL context

SDL 2.0 uses a SDL_GLContext to hold the information about the current GL context. There are many flags we need to setup our context and these are handled using the SDL_GL_SetAttribute function. I've also discovered on my linux build that some of these flags don't work and cause crashes (particularly creating a core profile context). To overcome this conditional compilation is used as shown in the following function.

SDL_GLContext createOpenGLContext(SDL_Window *window)
{
// Request an opengl 3.2 context first we setup our attributes, if you need any
// more just add them here before the call to create the context
// SDL doesn't have the ability to choose which profile at this time of writing,
// but it should default to the core profile
// for some reason we need this for mac but linux crashes on the latest nvidia drivers
// under centos
#ifdef DARWIN
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
#endif
// set multi sampling else we get really bad graphics that alias
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,4);
// Turn on double buffering with a 24bit Z buffer.
// You may need to change this to 16 or 32 for your system
// on mac up to 32 will work but under linux centos build only 16
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
// enable double buffering (should be on by default)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//
return SDL_GL_CreateContext(window);
}

Care must be taken with setting the depth size, under mac osx it works with 32 bit, under linux I set to 16 and on some machines 24 will work.
The following code configures the GL context and clears the screen.

SDL_GLContext glContext=createOpenGLContext(window);
if(!glContext)
{
SDLErrorExit("Problem creating OpenGL context");
}
// make this our current GL context (we can have more than one window but in this case not)
SDL_GL_MakeCurrent(window, glContext);
/* This makes our buffer swap syncronized with the monitor's vertical refresh */
SDL_GL_SetSwapInterval(1);
// now clear the screen and swap whilst NGL inits (which may take time)
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);

Now this has been done we can use NGL and create our graphics. In this case the NGLDraw class is a re-working of the SimpleNGL demo, it initialises GLEW if required. The following code shows the creation of the NGLDraw class and the key and mouse processing.

The most important call here is the SDL_GL_SwapWindow call which tells SDL to swap the buffers and re-draw.

NGLDraw class

Most of the NGLDraw class is basic ngl code, the constructor is used to initialise ngl and create the camera, light and materials. The draw method grabs and instance of the primitives class and draws the teapot, both of which are similar to the Qt NGL demos. The main difference is the processing of the mouse input. I still use the same flags and attributes to store the rotations and position data, however the SDL mouse data is used to grab x,y and button values. This is shown in the following code.

Thursday, 22 November 2012

I've been getting a few mails about installing libraries on the Lab machines and also where to find certain things. This post will explain a few things about how to setup your build environment to allow you to install different libs in your home directories and use them your self. It will also help people who wish to install / setup a build environment when you don't have root on the machine you are using.

Getting Started

First are you sure the library is not installed? On the lab centos machine we have installed most libraries you may need for doing computer graphics work. You can list the currently installed libs by using the ldconfig -p command. If you feed this into grep you can filter the results. For example to search for the location of the iMath library we can do the following

You can see the path of the library from this ( /usr/lib64 ) and this can be added to the link path using the -L command on the compiler (more on this later).

If this doesn't find what you are looking for, the package may not be a dynamic library. We can search for static libs using the locate command as follows

locate libode
/usr/local/lib/libode.a
/usr/local/lib/libode.la

If you can confirm that the library is installed the next thing is to find the headers, again we can use the locate command. The following will find a specific header file (usually we will get a compile message saying can't find xxx.h).

You will see that in this case it is in several locations as some of the packages installed have included it. It is best to always use the /usr paths as these will correspond to the installed libraries. In this case we can add the include path -I/usr/local/include/

Setting things in Qt Creator

Qt creator uses qmake to configure the projects and the project locations. In particular there are two flags we need to set to add libraries and include paths as follows.

Using the += option we can concatenate to the INCLUDEPATH keyword and absolute path to search for the libs, this will be translated to a -I flag in the compiler command line.
The LIBS flag is passed verbatim to the linker so we need to use the correct commands in this case we use -L to indicate a library search path and -l for the library to be included. Note that the -l flag ignores the prefix lib and the postfix .so.x.x etc.

Once this is done your projects should be fine to run. You can also build and include libs in your own directories and link them using the project paths similar to above. If the lib created is a .a file it is a static lib it will be included in the build of the program. If you are linking to a dynamic lib (.so) you will need to tell the runtime linker where to find the library by setting the LD_LIBRARY_PATH environment variable (this is how the NGL lib is configured).

An Example

This example will show how to install a source package in a custom location (your home dir) using a typical automake style project found in most linux source packages.

Typically now you would run ./configure; make; sudo make install; however as most users do not have access to sudo this will not work as the install will attempt to write files in the /usr file system which you don't have permission to.
Instead we can ask the configure script to use another custom location which we do have permission to. In this case I'm going to use /home/jmacey/myOde as follows

./configure --prefix /home/jmacey/myOde
make
make install

The install will now place all the files in the directory $(HOME)/myOde and we can adjust our build paths accordingly, the following list shows what has been installed.

The newmtl keyword is used to indicate that a new material is being specified and the rest of the elements are part of that material. To store this information I decided to use a std::map using a std::string as the key which will be the name following the newmtl (in the above example this is "leaf"). The map will then store the following structure.

You will notice that this replicates the mtl format shown above and also have several extra items which have the extra postfix ID, these will be used to store the OpenGL texture ID's of the textures once loaded. I also made the design decision not to follow my usual coding standard for the structure as this would make it easier to follow what is happening in the mtl file.

Class functional design

The main elements of the class are shown in the following class diagram.

The main functional design of the Mtl class is split into two areas, first the loading and parsing of the original mtl file. This can either be done in the constructor or using the load method. Next is the actual use of the class data. To allow easy access to this data iterators have been exposed for the std::map as well as other methods. Finally we have the ability to save and load the data in a binary format to save the parse time of reading the original files.

Parsing the mtl file

As the structure of the mtl file is quite simple I decided a full blown parser was not required. Instead I decided to use the boost::tokenizer template to process the data. The file is opened and the data read a line at a time. The tokenizer splits the data and looks for the keywords, which are then processed one at a time. This is shown in the following code.

// this is the line we wish to parse
std::string lineBuffer;
// say which separators should be used in this
// case Spaces, Tabs and return \ new line
boost::char_separator<char> sep(" \t\r\n");
// loop through the file
while(!fileIn.eof())
{
// grab a line from the input
getline(fileIn,lineBuffer,'\n');
// make sure it's not an empty line
if(lineBuffer.size() >1)
{
// now tokenize the line
tokenizer tokens(lineBuffer, sep);
// and get the first token
tokenizer::iterator firstWord = tokens.begin();
// now see if it's a valid one and call the correct function
if( *firstWord =="newmtl")
{
// add to our map it is possible that a badly formed file would not have an mtl
// def first however this is so unlikely I can't be arsed to handle that case.
// If it does crash it could be due to this code.
//std::cout<<"found "<<m_currentName<<"\n";
parseString(firstWord,m_currentName);
m_current= new mtlItem;
// These are the OpenGL texture ID's so set to zero first (for no texture)
m_current->map_KaId=0;
m_current->map_KdId=0;
m_current->map_dId=0;
m_current->map_bumpId=0;
m_current->bumpId=0;
m_materials[m_currentName]=m_current;
}
else if(*firstWord =="Ns")
{
parseFloat(firstWord,m_current->Ns);
}
else if(*firstWord =="Ni")
{
parseFloat(firstWord,m_current->Ni);
}
else if(*firstWord =="d")
{
parseFloat(firstWord,m_current->d);
}
else if(*firstWord =="Tr")
{
parseFloat(firstWord,m_current->Tr);
}
else if(*firstWord =="Tf")
{
parseVec3(firstWord,m_current->Tf);
}
else if(*firstWord =="illum")
{
parseInt(firstWord,m_current->illum);
}
else if(*firstWord =="Ka")
{
parseVec3(firstWord,m_current->Ka);
}
else if(*firstWord =="Kd")
{
parseVec3(firstWord,m_current->Kd);
}
else if(*firstWord =="Ks")
{
parseVec3(firstWord,m_current->Ks);
}
else if(*firstWord =="Ke")
{
parseVec3(firstWord,m_current->Ke);
}
else if(*firstWord == "map_Ka")
{
parseString(firstWord,m_current->map_Ka);
}
else if(*firstWord == "map_Kd")
{
parseString(firstWord,m_current->map_Kd);
}
else if(*firstWord == "map_d")
{
parseString(firstWord,m_current->map_d);
}
else if(*firstWord == "map_bump")
{
parseString(firstWord,m_current->map_bump);
}
else if(*firstWord == "bump")
{
parseString(firstWord,m_current->bump);
}
} // end zero line
} // end while
// as the trigger for putting the meshes back is the newmtl we will always have a hanging one
// this adds it to the list
m_materials[m_currentName]=m_current;

The individual parse functions then use the boost::lexical_cast template to convert the values as shown in the following example

A Subtle Bug

On problem I had when initially using this system was that the texture files were not found when loading. It turned out that as this was a windows mtl file it was using \ in the file names and I was running under mac osx and linux which expected /. To overcome this problem the filename paths are parsed and / converted to \ and visa-versa depending upon operating system.

Designing for efficiency

One of the many things to think about when designing the class is the efficiency of the data storage / texture usage. It is quite possible that the maps used are loaded by several materials and only the multipliers are changed. To ensure that the data is not replicated, the textures are processed when loaded. First I step through each of the materials and load them into a std::list. then the std::list::unique method is called to remove any duplicates. Once this is done the textures are loaded and the ID's stored in a std::vector. Finally these are re-associated with the mtlItem data to store all the values.

Serialisation

Whilst the parsing of the mtl file is relatively quick it was decided to allow for both binary read and write of the data. As there is a lot of text data to save the process is not quite as simple as it could be. For most of the data we need to determine the length of the string to write out then I write out the size of the string followed by the string data. I also decided to write out a unique ID for the file header so we can check that the file being loaded is the correct one.

Loading in the data is almost the reverse of writing it, we first read in the header bytes and check to see if it is the correct file type then read in the data re-sizing the strings to we have enough room to read the data into it.

The Sponza model is quite popular for real-time graphics visualisation, It can be downloaded from the CryTek website, and you can see many demos of it being used for different lighting tests on youtube.

I decided it would be a good example to use in a bigger system of how to load and process meshes / textures in OpenGL and also as part of a bigger modelling / game pipeline.

The main model comes in two parts, a wavefront obj file (obj) and a Material template library file (mtl). These files are simple text files and can be exported from all major animation packages.

Initial Design
My initial design for the program is as follows

I will split the Mtl and Obj files into two different classes, the Mtl class will be responsible for loading the textures and storing OpenGL texture ID's. The ObjG (GroupedObj) class will load the Obj and then determine and process the groups in the file and store all the information required to draw all the individual grouped elements.

The mesh itself will be uploaded as a single OpenGL Vertex Array Object (VAO) and elements will be drawn as sub meshes with the correct textures enabled.

I decided to design / write the Mtl class first. This design can be seen in the next post.

Friday, 19 October 2012

The following video gives one solution to the creation of the generic polygon class exercise from the ASD lecture.
I will add some more features after next week's lab session and do another video post.

Thursday, 4 October 2012

I did a quick google search for this and didn't find anything so I thought I would figure it out myself.
It is actually quite easy, you need to use the $$system() function in qmake to run the sdl-config script (which should be in your path) and then assign it to the correct qmake variables.
The following code snippet shows what to add

Monday, 24 September 2012

In the last post we talked about how to install SDL in this post we will create a simple program to create initialise SDL and create a simple window.

All the code for this post can be found here and downloaded via version control using bzr

SDL.h

The first thing we need to do when using SDL is to include the SDL.h header file. This is done using the following line

#include <SDL/SDL.h>

Note that the directory prefix SDL/ is part of this path, as we shall see later the sdl-config script will give us the correct include paths when we compile the program relative to this directory.

SDL_main

Depending upon the operating system, SDL uses different native code to generate the window / interactions with the operating system. Under linux this is done be default, however under Mac OSX and Windows we need to include a different version of main. To allow this and make the code portable we can use the C/C++ conditional compilation pre-processor. To do this we use the following code

/// note that under mac osx (and windows) there is a different
/// way to build SDL so we need to use SDL_main under linux
/// normal main is fine so we use this conditional compilation
/// to incude the correct version (DARWIN being mac os x)
#if defined (DARWIN) || defined (WIN32)
int SDL_main(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif

SDL_Init

The first thing we need to do when using SDL is to initialise the library, to do this we use the SDL_Init function, this is passed one parameter which is a flag to indicate which sub-systems should be initialised. These values are combined together using a logical or ( | ). The subsystems available are as follows

For example if we wish to initialise both the video and joystick sub sytems we would use the following code

SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);

In the following examples we will use just the video subsystem but we will also check to see if the initialisation actually worked by checking the return value from SDL_init and making sure it's a zero

Setting Video mode

To give us a video surface we use the SDL_SetVideoMode function, it has 4 parameters width and height, bits per pixel (bpp) and flags.

If the bpp value is set to 0 it will attempt to use the system value for the current display, the flags parameter can be a logical or combination of the values below, however some of these flags will cancel each other out.

SDL_SWSURFACE

Surface is stored in system memory

SDL_HWSURFACE

Surface is stored in video memory

SDL_ASYNCBLIT

Surface uses asynchronous blits if possible

SDL_ANYFORMAT

Allows any pixel-format (Display surface)

SDL_HWPALETTE

Surface has exclusive palette

SDL_DOUBLEBUF

Surface is double buffered (Display surface)

SDL_FULLSCREEN

Surface is full screen (Display Surface)

SDL_OPENGL

Surface has an OpenGL context (Display Surface)

SDL_OPENGLBLIT

Surface supports OpenGL blitting (Display Surface)

SDL_RESIZABLE

Surface is resizable (Display Surface)

SDL_HWACCEL

Surface blit uses hardware acceleration

SDL_SRCCOLORKEY

Surface use colorkey blitting

SDL_RLEACCEL

Colorkey blitting is accelerated with RLE

SDL_SRCALPHA

Surface blit uses alpha blending

SDL_PREALLOC

Surface uses preallocated memory

This function will return an SDL_Surface structure if successful which will be referred to in other drawing functions. If this fails NULL will be returned to we can check if there was an error.

In this example we are setting the video to be a Hardware surface (in GPU memory) and to use double buffering which should give use better graphics performance in the later examples.

Setting the window caption

To set the text in the titlebar of the window created by SDL we can use the following code

// next we set the window bar caption to the text 2nd param is for an icon
// this is a char * to a pixmap data but if we use 0 none is loaded
SDL_WM_SetCaption( "A Simple SDL Window", 0 );

Event processing

SDL uses an event structure called SDL_Event to store all the information about the various events the host system / Windows manager is passing. This structure is actually a structure or many other structures and we can process the information in a number of ways. For these first simple examples we are going to look for a key down press and the windows system passing a Quit message. The structure of this is a continuous while loop, where we check a flag to see if we should exit.

SDL is an ideal cross platform API for basic games development and other non GUI graphics systems. To quote the website above

"Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. It is used by MPEG playback software, emulators, and many popular games, including the award winning Linux port of "Civilization: Call To Power."
In this series of blog posts I will look at the basic use of SDL with a focus on using it on the Raspberry Pi, however all the code should work under all linux distributions as well as Mac OSX ( Windows should also just work, however I don't have a windows machine to test against).

Installing SDL using apt-get

The easiest way to install SDL on the rpi is to use apt-get and install the pre-build development packages. To do this use the following commands

sudo apt-get install libsdl1.2-dev

To check that this has been successful we can now execute the sdl-config script as follows

Installing from Source

The source code for SDL is available from this link http://www.libsdl.org/download-1.2.php. This is the easiest way to get SDL working on Linux system without apt as well as for Mac OSX. To build from the .tgz version do the following

Once this is done we can again check to ensure that things are working by testing the sdl-config program above.

Raspberry Pi user config for the console

If you intend to use SDL on the raspberry pi without using X windows the SDL library will attempt to access the framebuffer directly. By default only the root user has access to the framebuffer device so we need to add the current user (i.e. what you logged in as) to this group. To do this we need to add the user to the group video, input and audio groups (audio if we use it later) for a minimum you must have video and input.

sudo usermod -a -G video,input,audio [your username]

Once this is done logout and the user will be added to the group on the next login.

Monday, 9 July 2012

There are several forum posts asking if the Raspberry Pi could be used with the kinect so I decided to give it a try. It is important to note that you will need a powered USB hub, as whilst the kinect does have a PSU this is only used for the motor, the Camera and Audio sub systems still need more power than the Pi can produce.

First you will need to get a couple of libraries, first off libusb is required, I downloaded the latest 1.0.9 tarball and built it using the following commands

This should work fine for both of the debian versions and this will install the developer libraries and headers for libusb.
Next I downloaded the OpenKinect source code from git hub unzip this file and change into the source directory.

You may need to install cmake if you have not already done so, this can be done by using sudo apt-get install cmake. Next we need to edit some of the cmake files as for this example I don't want to build the demos which require libraries which will not work properly on the pi.

If you edit the CMakeLists.txt file and search for the following line

OPTION(BUILD_EXAMPLES "Build example programs" ON)

And change the ON to OFF
you should now be able to build by typing the following

cmake CMakeLists.txt
make
sudo make install

This will then install the following files

ls /usr/local/include/libfreenect/
libfreenect.h

libfreenect-registration.h

libfreenect_sync.h

and

ls /usr/local/lib/libfree*
/usr/local/lib/libfreenect.a

/usr/local/lib/libfreenect.so.0.1

/usr/local/lib/libfreenect_sync.a

/usr/local/lib/libfreenect_sync.so.0.1
/usr/local/lib/libfreenect.so

/usr/local/lib/libfreenect.so.0.1.2

The first demo I've tried is a modified version of the tiltdemo.c There are reports of this working fine for some people, however it didn't for me under the latest wheezy build so I investigated more and found that the sync library wasn't working for me. The following program uses the Normal freenect library calls instead.

Thursday, 21 June 2012

In my feedback for the MSc project proposals I suggested it would be a good idea to embed some form of interpreter for the crowd / multi agent systems instead of hard coding them in C++. This allows for a quicker development cycle and a more flexible tool. In this video tutorial I explain the example code (here) and the basic design behind it. For more details I would read this

Wednesday, 20 June 2012

In the previous post I discussed the EGLWindow class, this class is designed as a framework for the user of the library to create consistent windows. This post will look at how we can use the EGLWindow class and extend it.

MyEGLWindow

This class is going to inherit from the main EGLWindow class then implement the two methods initializeGL and paintGL.

#ifndef MYGLWINDOW_H__
#define MYGLWINDOW_H__
#include "EGLWindow.h"
/// @brief this class create our window by inheriting the features of the EGL Window
class MyGLWindow : public EGLWindow
{
public :
/// @brief ctor
/// @param[in] _config an optional configuration for the buffers etc
MyGLWindow(EGLconfig *_config=0);
/// @brief dtor will close down the vc and re-set EGL
~MyGLWindow();
/// @brief the is the main drawing function should only be called once initalizeGL has
/// been called
virtual void paintGL();
protected :
/// @brief one time OpenGL initialisation
virtual void initializeGL();
};

When using the class the constructor must always call the initializeGL method, as the EGLWindow class is called first this will mean that we have a valid OpenGL context and any GL calls are going to be associated with this context. In this example we just print out that the ctor has been called and then init gl.

The next stage is to implement the initializeGL function, this is where you should do any one off configuration for OpenGL, in this case I'm just going to set the clear colour (which will change later in the draw function)

Next the we will create the paintGL method, this is designed to be called within our main look each time the screen needs to be updated. In this case I'm going to set the screen clear colour and clear the screen.

Once drawing is complete the swapBuffers() method must be called to tell OpenGL to swap the back buffer with the front to show the re-drawn surface.

Using the window

The following code will create an instance of the MyGLWindow class and execute a loop calling draw.

#include <iostream>
#include "MyGLWindow.h"
#include "bcm_host.h"
int main()
{
atexit( bcm_host_deinit);
std::cout<<"starting GL test\n";
bcm_host_init();
std::cout<<"done bcm init\n";
// here I create a config with RGB bit size 5,6,5 and no alpha
EGLconfig *config = new EGLconfig();
config->setRGBA(5,6,5,0);
// set the depth buffer
config->setDepth(16);
// now create a new window using the default config
MyGLWindow win(config);
// now set the size of the screen in this case I'm going to do a
// rectangle in the middle (if you don't call this you would get a full
// screen rect by default)
uint32_t w=win.getMaxWidth();
uint32_t h=win.getMaxHeight();
// set this to true to upscale the dst rect
win.setUpscale(false);
win.setScreen(w/4,h/4,w/2,h/2);
int x,y;
while(1)
{
win.paintGL();
sleep(1);
}
}

In this example we create a custom config with R/B of bit depth 5 and green bit depth 6 and a depth buffer of 16 bits. This is then passed to the MyGLWindow ctor and used as the config when creating the EGL window.
Next we re-size the screen so that is is half the screen dimensions and centred. (This will call the destroySurface method mentioned in the previous post).
Finally we loop calling paintGL for each update and sleeping for 1ms (use ctrl + C to exit the program). We need a Makefile to build this program and it needs to include several libraries to get it working, for more details on this see the blog post here For the full code grab this

In the previous post I created an EGLconfig class to allow the creation of an eglConfig for raspberry pi. In this post I will talk about the design and implementation of an EGLWindow class which allows the user to create a window and then extend the basic window for their own drawing.

EGLWindow

This class will implement various functions to setup and create an OpenGL drawing context for the user. It is then the users responsibility to implement certain methods in the sub-class to do the basic initialisation of the OpenGL functions, then a drawing class which will be called each frame in the client program.

You will notice from the class diagram there are a number of methods and attributes which are either protected or private, along with several methods which are "pure virtual" this is to force the user of the class to implement them. Full source code for the .h file is here

The constructor takes an EGLConfig class as the main parameter, this by default is set to 0 so if one is not passed a default one will be created. This is shown in the following code

EGLWindow::EGLWindow(EGLconfig *_config)
{
// toggle we don't yet have an active surface
m_activeSurface=false;
// set default to not upscale the screen resolution
m_upscale=false;
// set our display values to 0 (not once ported to cx11 will use nullptr but
// current pi default compiler doesn't support it yet
m_display=0;
m_context=0;
m_surface=0;
// now find the max display size (we will use this later to assert if the user
// defined sizes are in the correct bounds
int32_t success = 0;
success = graphics_get_display_size(0 , &m_width, &m_height);
assert( success >= 0 );
std::cout<<"max width and height "<<m_width<<" "<<m_height<<"\n";
m_maxWidth=m_width;
m_maxHeight=m_height;
// if we have a user defined config we will use that else we need to create one
if (_config == 0)
{
std::cout<<"making new config\n";
m_config= new EGLconfig();
}
else
{
m_config=_config;
}
}

The core method to this class is the makeSurface method. It will create our surface and configure internal class attributes to hold values needed for the drawing etc. It also calls the initializeGL method once the surface has been created to do one off configuration of OpenGL / class attributes.

void EGLWindow::makeSurface(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h)
{
// this code does the main window creation
EGLBoolean result;
static EGL_DISPMANX_WINDOW_T nativeWindow;
// our source and destination rect for the screen
VC_RECT_T dstRect;
VC_RECT_T srcRect;
// config you use OpenGL ES2.0 by default
static const EGLint contextAttributes[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
// get an EGL display connection
m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(m_display == EGL_NO_DISPLAY)
{
std::cerr<<"error getting display\n";
exit(EXIT_FAILURE);
}
// initialize the EGL display connection
int major,minor;
result = eglInitialize(m_display, &major, &minor);
std::cout<<"EGL init version "<<major<<"."<<minor<<"\n";
if(result == EGL_FALSE)
{
std::cerr<<"error initialising display\n";
exit(EXIT_FAILURE);
}
// get our config from the config class
m_config->chooseConfig(m_display);
EGLConfig config=m_config->getConfig();
// bind the OpenGL API to the EGL
result = eglBindAPI(EGL_OPENGL_ES_API);
if(result ==EGL_FALSE)
{
std::cerr<<"error binding API\n";
exit(EXIT_FAILURE);
}
// create an EGL rendering context
m_context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, contextAttributes);
if(m_context ==EGL_NO_CONTEXT)
{
std::cerr<<"couldn't get a valid context\n";
exit(EXIT_FAILURE);
}
// create an EGL window surface the way this works is we set the dimensions of the srec
// and destination rectangles.
// if these are the same size there is no scaling, else the window will auto scale
dstRect.x = _x;
dstRect.y = _y;
if(m_upscale == false)
{
dstRect.width = _w;
dstRect.height = _h;
}
else
{
dstRect.width = m_maxWidth;
dstRect.height = m_maxHeight;
}
srcRect.x = 0;
srcRect.y = 0;
srcRect.width = _w << 16;
srcRect.height = _h << 16;
// whilst this is mostly taken from demos I will try to explain what it does
// there are very few documents on this ;-0
// open our display with 0 being the first display, there are also some other versions
// of this function where we can pass in a mode however the mode is not documented as
// far as I can see
m_dispmanDisplay = vc_dispmanx_display_open(0);
// now we signal to the video core we are going to start updating the config
m_dispmanUpdate = vc_dispmanx_update_start(0);
// this is the main setup function where we add an element to the display, this is filled in
// to the src / dst rectangles
m_dispmanElement = vc_dispmanx_element_add ( m_dispmanUpdate, m_dispmanDisplay,
0, &dstRect, 0,&srcRect, DISPMANX_PROTECTION_NONE, 0 ,0,DISPMANX_NO_ROTATE);
// now we have created this element we pass it to the native window structure ready
// no create our new EGL surface
nativeWindow.element = m_dispmanElement;
nativeWindow.width =_w;
nativeWindow.height =_h;
// we now tell the vc we have finished our update
vc_dispmanx_update_submit_sync( m_dispmanUpdate );
// finally we can create a new surface using this config and window
m_surface = eglCreateWindowSurface( m_display, config, &nativeWindow, NULL );
assert(m_surface != EGL_NO_SURFACE);
// connect the context to the surface
result = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
assert(EGL_FALSE != result);
m_activeSurface=true;
initializeGL();
}

The rest of the class is fairy straight forward, however it is worth mentioning the destroySurface method as it is used to allow re-creation / re-size of the window created. This is a private method and is used by the destructor and the resizeScreen method

I've finally ported my graphics library ngl to the raspberry pi and I've released the source on google code. This post is going to be an introduction on getting started with the EGL window and the basic design behind the classes that have been added to pingl to facilitate this window creation.

Initial Design

As most of my desktop NGL demos are based on using Qt, I decided to make the config and running on NGL on the pi to be similar. To that ends I decided to design the EGLWindow class along the same lines as the QGLWidget class in Qt, this would require the splitting of the configuration and the window creation, as well as using inheritance to allow the user a common interface when writing client programs.

I also initially decided to write my own Mouse and Keyboard events stack but in the end decided against this as there are many pre-existing libraries around that allow the user to access this information. An in my case I will be using SDL.

EGLconfig class

The EGLconfig class is used to store the different attributes that may be set for an EGLConfig structure. (for more details see this blog post) The class will by default setup some useable parameters and also allow the user to set their own.

As you can see from the class diagram I use a std::map to store key value pairs for the attributes which will be turned into the appropriate structure when required. The full source for the header file can be seen here

The assert is based on the values of the attribute defines in the egl.h file. This is a hard coded value and will need to be checked from time to time if the egl.h file changes and new attributes are added / removed (this is why enums should be used!)
For convenience methods have been added for the most used attributes as shown below

Finally to choose the correct config we need to pass a constructed EGLDisplay to the class. We then build from our attribute list an array of key value pairs into a std::vector terminating the list with an EGL_NONE token. This is then passed to the eglChooseConfig function to setup the correct values.

Tuesday, 5 June 2012

I've just written a simple wrapper for the Raspberry Pi EGL Window / Config and the video core functions, it is a simple set of C++ classes which allows the creation of windows and setting of size etc. I will write a fuller post soon, but I thought I would upload the code and a simple video now.

Saturday, 2 June 2012

I did some kernel tinkering earlier today and broke my main config so I decided to build two images on SD cards so I could have a stable vs un-stable boot image. The following discusses how to build an image using a mac book pro and the usual tools.

Initial SD image

I'm going to use the debian "squeeze" image from here and the terminal on the mac.

First it is easier if we do these operations as root so in the shell type sudo su and enter your password. Next we need to identify the disk in the card reader. In my case I did this using the following commands

In my case the disk in /Volumes/UNTITLED which is the device /dev/disk3s1, this is a mounted device so the first thing we need to do is unmount the partition so we can write to it. To do this we use the following

diskutil unmount /dev/disk3s1

Now we can proceed to write the disk image. This is a long process and it doesn't give any feedback whilst it is operating, however at the end it will report how many block written

Now this is done we should be able to put it into the pi and boot (username pi password raspberry)

Disk size

If we look at the partition on the disk we have just made you will see the following

As you can see there is quite a bit of space not allocated and this is a bit of a problem if you want to install lots of software to the pi. There are a number of options we can take such as creating a new partition on the spare space and use this for home, or resize the DISK3S2 partition to a larger size.

I want to re-size the partition for ease of having a large home / root partition. The simplest method I've found for doing this is by using the linux gui but as I'm trying to keep this to mac / pi only I will use the method outlined here basically if you follow these instructions it works fine.

Getting updated

One of the first things you should do is update the packages installed. To do this we need to run the apt package manager. In the shell execute the following command

sudo apt-get update

I also decided to update my kernel to the latest version. The good news is that there is a really simple tool to do this, here I had to do the following to get it working

sudo apt-get install ca-certificates
sudo apt-get install git

Once this is done follow the instructions on the link

Adding a user

To add a user we use the unix adduser command. In my case I wanted to use jmacey as my username to sync with all of my other machines at home and work

adduser jmacey

By default this user doesn't have access to the administrator (root) account, so we need to add it to the sudoers file. This is done by using the visudo tool. This will open up an editor and we can add our new user as shown

pi ALL=(ALL) ALL
jmacey ALL=(ALL) ALL

In my case I've placed my username below the pi username, whilst I've left the pi user in, for security you may wish to remove this as it is a well known and documented username / password. To exit the editor use ctrl+k x to save and exit.

You should now be able to login as the new user and become root.

GPM

If you are used to other linux distros, you may be used to using the mouse in the terminal, this is done using the gpm package. You can install it using

Friday, 1 June 2012

My usual development cycle using the raspberry pi is to use the mac and BBEdit via SSH to edit files and iTerm to ssh to get a shell. Whilst by default you can ssh from the pi, you need to enable ssh properly to work both ways.

The following will install and enable ssh on the debian "squeeze" build.

sudo apt-get install ssh
sudo update-rc.d ssh defaults

On a re-boot the ssh server will now be active. To make life easier on the pi you can follow this tutorial to not require a password.

Thursday, 31 May 2012

So i finally go my raspberry pi and my plan is to port my NGL library to it, the main difference is that NGL is using Qt and OpenGL 3.2 core profile and the pi will use OpenGL ES and EGL. Having never used EGL I decides to do a bit of rtfm and read the spec as well as some of the demo programs that come with the pi. The following is a basic introduction to getting started with EGL and using the pi in general. All the code for this post can be found here

EGL getting started

EGL is used as an interface between OpenGL (and other Khronos API's) and the base system (in this case the pi). It is responsible for accessing the display hardware and other synchronisation of the display / graphics context. In the case of the pi we use it to access the display hardware and use OpenGL or OpenVG with it.

All of the functions for this are stored in the header file egl.h as shown below

#include <EGL/egl.h>

On the debian "squeeze" image of the OS these headers can be found in /opt/vc/include, we also need to add the EGL library to our build using the flags -L/opt/vc/lib -lEGL (more on this later in the Makefile section).

Accessing the display

Almost all the EGL functions require a valid display pointer to do their work, this is stored using the EGLDisplay typedef (it's actually a void * ).

Configurations

Now we have initialised EGL we can query the different configurations available to use. This is done using the eglGetConfigs function which works in two different modes. The first mode will allow us to get how many configs there are, and the second will fill a buffer with all of the different configs. This is done in the the following code

EGLint numConfigs;
// first we call getConfigs with a NULL to see how many configs we have
result=eglGetConfigs(display,NULL,0,&numConfigs);
assert(result != EGL_FALSE );
std::cout<< "number of configs found "<<numConfigs<<"\n";
// now we create a buffer to store all our configs
EGLConfig *configs = new EGLConfig[numConfigs];
// and copy them into our buffer (don't forget to delete once done)
result=eglGetConfigs(display,configs,numConfigs,&numConfigs);
assert(result != EGL_FALSE );
......
// don't forget to delete once done
delete [] configs;

We can now gather the information from each of the configs using the eglGetConfigAttrib function. This requires you to pass in the attribute you wish to query and will return the value if set. The following code queries the attributes available on the pi (some that are in the spec are not on the pi)