Thursday, 13 December 2012

Creating a local cmake library install

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
cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/jmacey/
make -j 4
make install
In the case of the current version of Alembic this will install to the directory alembic-1.1.2

Testing

A simple test program to read alembic files from the command line and write out the contents has been created as follows
#include <Alembic/AbcGeom/All.h>
#include <Alembic/AbcCoreAbstract/All.h>
#include <Alembic/AbcCoreHDF5/All.h>
#include <Alembic/Abc/ErrorHandler.h>
#include <iostream>
#include <cstdlib>


using namespace Alembic::AbcGeom; // Contains Abc, AbcCoreAbstract


int main(int argc, char **argv)
{
  if(argc <2 )
  {
    std::cerr <<"usage Alembic [filename]\n";
    exit(EXIT_FAILURE);
  }

  IArchive  archive( Alembic::AbcCoreHDF5::ReadArchive(),
                          argv[1] );


  std::cout<<"traversing archive for elements\n";
  IObject obj=archive.getTop();
  unsigned int numChildren=obj.getNumChildren();
  std::cout<< "found "<<numChildren<<" children in file\n";

  for(int i=0; i<numChildren; ++i)
  {
    std::cout<<obj.getChildHeader(i).getFullName()<<"\n";
    IObject child(obj,obj.getChildHeader(i).getName());

    std::cout<<"Children "<<child.getNumChildren()<<"\n";
    const MetaData &md = child.getMetaData();
    std::cout<<md.serialize() <<"\n";

    for(int x=0; x<child.getNumChildren(); x++)
    {
      IObject child2(child,child.getChildHeader(x).getName());
      const MetaData &md2 = child2.getMetaData();
      if( IPolyMeshSchema::matches( md2 ) || ISubDSchema::matches( md2 ))
      {
        std::cout<<"Found a mesh "<<child2.getName()<<"\n";

      }
    }
  }

  return EXIT_SUCCESS;
}
To compile this I have created a QMAKE project which sets the paths to point to the correct install of alembic
TARGET=Alembic
DESTDIR=./
CONFIG += console
CONFIG -= app_bundle

SOURCES+=read.cpp
INCLUDEPATH+=/home/jmacey/alembic-1.1.2/include/
INCLUDEPATH+=/usr/local/include/OpenEXR

ALEMBIC_DIR=/home/jmacey/alembic-1.1.2
ALEMBIC_LIB=/home/jmacey/alembic-1.1.2/lib/static

LIBS+= -L$$ALEMBIC_LIB
LIBS+= -lAbcWFObjConvert
LIBS+= -lAlembicAbcCollection
LIBS+= -lAlembicAbcCoreHDF5
LIBS+= -lAlembicAbc
LIBS+= -lAlembicAbcCoreAbstract
LIBS+= -lAlembicAbcGeom
LIBS+= -lAlembicUtil

LIBS+=-lImath
LIBS+=-lHalf
LIBS+=-lIex
LIBS+=-lhdf5
LIBS+=-lhdf5_hl
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

Using NGL with SDL

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.
mkdir SDL2.0
tar vfxz SDL-2.0.tar.gz 
cd SDL-2.0.0-6673/
./configure --prefix=/home/jmacey/SDL2.0 (change to your home dir)
make -j 8
make install
This will install everything into the SDL2 directory and you will have a structure like this
bin include lib share
To test this is working do the following
cd ~/SDL2.0/bin
./sdl2-config --cflags --libs
-I/Volumes/home/jmacey/SDL2.0/include/SDL2 -D_THREAD_SAFE
-L/Volumes/home/jmacey/SDL2.0/lib -lSDL2

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.
QMAKE_CXXFLAGS+=$$system($$(HOME)/SDL2.0/bin/sdl2-config  --cflags)
message(output from sdl2-config --cflags added to CXXFLAGS= $$QMAKE_CXXFLAGS)

LIBS+=$$system($$(HOME)/SDL2.0/bin/sdl2-config  --libs)
message(output from sdl2-config --libs added to LIB=$$LIBS)
For more info see this post

First we need to initialise the SDL video subsystem using the following command

// Initialize SDL's Video subsystem
if (SDL_Init(SDL_INIT_VIDEO) < 0 )
{
  // Or die on error
  SDLErrorExit("Unable to initialize SDL");
}
There is also a helper function to exit SDL gracefully
void SDLErrorExit(const std::string &_msg)
{
  std::cerr<<_msg<<"\n";
  std::cerr<<SDL_GetError()<<"\n";
  SDL_Quit();
  exit(EXIT_FAILURE);
}
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.
NGLDraw ngl;
// resize the ngl to set the screen size and camera stuff
ngl.resize(rect.w,rect.h);
while(!quit)
{

 while ( SDL_PollEvent(&event) )
 {
  switch (event.type)
  {
   // this is the window x being clicked.
   case SDL_QUIT : quit = true; break;
   // process the mouse data by passing it to ngl class
   case SDL_MOUSEMOTION : ngl.mouseMoveEvent(event.motion); break;
   case SDL_MOUSEBUTTONDOWN : ngl.mousePressEvent(event.button); break;
   case SDL_MOUSEBUTTONUP : ngl.mouseReleaseEvent(event.button); break;
   case SDL_MOUSEWHEEL : ngl.wheelEvent(event.wheel);
   // if the window is re-sized pass it to the ngl class to change gl viewport
   // note this is slow as the context is re-create by SDL each time
   case SDL_WINDOWEVENT :
    int w,h;
    // get the new window size
    SDL_GetWindowSize(window,&w,&h);
    ngl.resize(w,h);
   break;

   // now we look for a keydown event
   case SDL_KEYDOWN:
   {
    switch( event.key.keysym.sym )
    {
     // if it's the escape key quit
     case SDLK_ESCAPE :  quit = true; break;
     case SDLK_w : glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); break;
     case SDLK_s : glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); break;
     case SDLK_f :
     SDL_SetWindowFullscreen(window,SDL_TRUE);
     glViewport(0,0,rect.w,rect.h);
     break;

     case SDLK_g : SDL_SetWindowFullscreen(window,SDL_FALSE); break;
     default : break;
    } // end of key process
   } // end of keydown

   default : break;
  } // end of event switch
 } // end of poll events

 // now we draw ngl
 ngl.draw();
 // swap the buffers
 SDL_GL_SwapWindow(window);

}
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.
void NGLDraw::mouseMoveEvent (const SDL_MouseMotionEvent &_event)
{
  if(m_rotate && _event.state &SDL_BUTTON_LMASK)
  {
    int diffx=_event.x-m_origX;
    int diffy=_event.y-m_origY;
    m_spinXFace += (float) 0.5f * diffy;
    m_spinYFace += (float) 0.5f * diffx;
    m_origX = _event.x;
    m_origY = _event.y;
    this->draw();

  }
  // right mouse translate code
  else if(m_translate && _event.state &SDL_BUTTON_RMASK)
  {
    int diffX = (int)(_event.x - m_origXPos);
    int diffY = (int)(_event.y - m_origYPos);
    m_origXPos=_event.x;
    m_origYPos=_event.y;
    m_modelPos.m_x += INCREMENT * diffX;
    m_modelPos.m_y -= INCREMENT * diffY;
    this->draw();
  }
}


void NGLDraw::mousePressEvent (const SDL_MouseButtonEvent &_event)
{
  // this method is called when the mouse button is pressed in this case we
  // store the value where the maouse was clicked (x,y) and set the Rotate flag to true
  if(_event.button == SDL_BUTTON_LEFT)
  {
    m_origX = _event.x;
    m_origY = _event.y;
    m_rotate =true;
  }
  // right mouse translate mode
  else if(_event.button == SDL_BUTTON_RIGHT)
  {
    m_origXPos = _event.x;
    m_origYPos = _event.y;
    m_translate=true;
  }
}

void NGLDraw::mouseReleaseEvent (const SDL_MouseButtonEvent &_event)
{
  // this event is called when the mouse button is released
  // we then set Rotate to false
  if (_event.button == SDL_BUTTON_LEFT)
  {
    m_rotate=false;
  }
  // right mouse translate mode
  if (_event.button == SDL_BUTTON_RIGHT)
  {
    m_translate=false;
  }
}

void NGLDraw::wheelEvent(const SDL_MouseWheelEvent &_event)
{

  // check the diff of the wheel position (0 means no change)
  if(_event.y > 0)
  {
    m_modelPos.m_z+=ZOOM;
    this->draw();
  }
  else if(_event.y <0 )
  {
    m_modelPos.m_z-=ZOOM;
    this->draw();
  }

  // check the diff of the wheel position (0 means no change)
  if(_event.x > 0)
  {
    m_modelPos.m_x-=ZOOM;
    this->draw();
  }
  else if(_event.x <0 )
  {
    m_modelPos.m_x+=ZOOM;
    this->draw();
  }
}
The rest of the code is fairly self explanatory if you've use NGL before.

Thursday, 22 November 2012

Libraries, Include paths and other Linux fun

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

ldconfig -p | grep -i imath
libImath.so.6 (libc6,x86-64) => /usr/lib64/libImath.so.6

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).

locate ImathColor.h
/opt/autodesk/maya2012-x64/devkit/Alembic/include/AlembicPrivate/OpenEXR/ImathColor.h
/opt/hfs12.1.77/toolkit/include/OpenEXR/ImathColor.h
/usr/local/include/OpenEXR/ImathColor.h
/usr/local/include/OpenEXR/PyImathColor.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.

INCLUDEPATH+=/usr/local/include/collada-dom2.4/
LIBS+=-L/usr/lib   -lcolladadom150
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. 

First I'm going to download the ode source and extract it.
wget http://sourceforge.net/projects/opende/files/latest/download?source=files
tar vfxj ode-0.12.tar.bz2 
cd ode-0.12
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.
find .
.
./include
./include/ode
./include/ode/error.h
./include/ode/odeconfig.h
./include/ode/timer.h
./include/ode/odemath.h
./include/ode/contact.h
./include/ode/odeinit.h
./include/ode/rotation.h
./include/ode/memory.h
./include/ode/collision.h
./include/ode/objects.h
./include/ode/collision_space.h
./include/ode/collision_trimesh.h
./include/ode/compatibility.h
./include/ode/common.h
./include/ode/mass.h
./include/ode/ode.h
./include/ode/export-dif.h
./include/ode/odemath_legacy.h
./include/ode/odecpp.h
./include/ode/matrix.h
./include/ode/misc.h
./include/ode/odecpp_collision.h
./lib
./lib/libode.la
./lib/pkgconfig
./lib/pkgconfig/ode.pc
./lib/libode.a
./bin
./bin/ode-config

Monday, 12 November 2012

Sponza Demo Pt 3 The GroupedObj class

In the previous post I described the Mtl class. This video blog will show the design and ideas behind the the GroupedObj class as shown in the following diagram










You can get the code from here

Sponza Demo Pt 2 Mtl class

In the previous post I discussed the basic overview of the system this post will explain how the Mtl class works and how is was developed.

The mtl file has the following basic structure, where each element may or may not be present.

newmtl leaf
  Ns 10.0000
  Ni 1.5000
  d 1.0000
  Tr 0.0000
  Tf 1.0000 1.0000 1.0000
  illum 2
  Ka 0.5880 0.5880 0.5880
  Kd 0.5880 0.5880 0.5880
  Ks 0.0000 0.0000 0.0000
  Ke 0.0000 0.0000 0.0000
  map_Ka textures\sponza_thorn_diff.tga
  map_Kd textures\sponza_thorn_diff.tga
  map_d textures\sponza_thorn_mask.tga
  map_bump textures\sponza_thorn_ddn.tga
  bump textures\sponza_thorn_ddn.tga

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.
typedef struct
{
  float Ns;
  float Ni;
  float d;
  float Tr;
  int illum;
  ngl::Vec3 Tf;
  ngl::Vec3 Ka;
  ngl::Vec3 Kd;
  ngl::Vec3 Ks;
  ngl::Vec3 Ke;
  std::string map_Ka;
  std::string map_Kd;
  std::string map_d;
  std::string map_bump;
  std::string bump;
  GLuint map_KaId;
  GLuint map_KdId;
  GLuint map_dId;
  GLuint map_bumpId;
  GLuint bumpId;
}mtlItem;
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
void Mtl::parseFloat(tokenizer::iterator &_firstWord, float &io_f)
{
  // skip first token
    ++_firstWord;
    // use lexical cast to convert to float then increment the itor
    io_f=boost::lexical_cast<float>(*_firstWord++);
}

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.

void Mtl::parseString(tokenizer::iterator &_firstWord, std::string &io_s)
{
  ++_firstWord;
  // there is a chance that we have either windows or linux slashes
  // need to process file name for either
  io_s=*_firstWord;

  #ifdef WIN32
  std::replace(io_s.begin(), io_s.end(), '/', '\\');
  #else
    std::replace(io_s.begin(), io_s.end(), '\\', '/');
  #endif
}

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.
void Mtl::loadTextures()
{
  m_textureID.clear();
  std::cout<<"loading textures this may take some time\n";
  // first loop and store all the texture names in the container
  std::list <std::string> names;
  std::map<std::string, mtlItem *>::const_iterator end=m_materials.end();
  std::map<std::string, mtlItem *>::const_iterator i = m_materials.begin();
  for( ; i != end; ++i )
  {
    if(i->second->map_Ka.size() !=0)
      names.push_back(i->second->map_Ka);
    if(i->second->map_Kd.size() !=0)
      names.push_back(i->second->map_Kd);
    if(i->second->map_d.size() !=0)
      names.push_back(i->second->map_d);
    if(i->second->map_bump.size() !=0)
      names.push_back(i->second->map_bump);
    if(i->second->map_bump.size() !=0)
      names.push_back(i->second->bump);
  }

  std::cout<<"we have this many textures "<<names.size()<<"\n";
  // now remove duplicates
  names.unique();
  std::cout<<"we have "<<names.size()<<" unique textures to load\n";
  // now we load the textures and get the GL id
  // now we associate the ID with the mtlItem

  BOOST_FOREACH(std::string name , names)
  {
    std::cout<<"loading texture "<<name<<"\n";
    ngl::Texture t(name);
    GLuint textureID=t.setTextureGL();
    m_textureID.push_back(textureID);
    std::cout<<"processing "<<name<<"\n";
    i=m_materials.begin();
    for( ; i != end; ++i )
    {
      if(i->second->map_Ka == name)
        i->second->map_KaId=textureID;
      if(i->second->map_Kd == name)
        i->second->map_KdId=textureID;
      if(i->second->map_d == name)
        i->second->map_dId=textureID;
      if(i->second->map_bump == name)
        i->second->map_bumpId=textureID;
      if(i->second->bump == name)
        i->second->bumpId=textureID;
    }
  }
  std::cout <<"done \n";
}

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.

The code to write the data is as follows

bool Mtl::saveBinary(const std::string &_fname) const
{
  std::ofstream fileOut;
  fileOut.open(_fname.c_str(),std::ios::out | std::ios::binary);
  if (!fileOut.is_open())
  {
    std::cout <<"File : "<<_fname<<" could not be written for output"<<std::endl;
    return false;
  }
  // write our own id into the file so we can check we have the correct type
  // when loading
  const std::string header("ngl::mtlbin");
  fileOut.write(header.c_str(),header.length());

  unsigned int size=m_materials.size();
  fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
  std::map<std::string, mtlItem *>::const_iterator start=m_materials.begin();
  std::map<std::string, mtlItem *>::const_iterator end=m_materials.end();
  for(; start!=end; ++start)
  {
    //std::cout<<"writing out "<<start->first<<"\n";
    // first write the length of the string
    size=start->first.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->first.c_str()),size);
    // now we do the different data elements of the mtlItem.
    fileOut.write(reinterpret_cast<char *>(&start->second->Ns),sizeof(float));
    fileOut.write(reinterpret_cast<char *>(&start->second->Ni),sizeof(float));
    fileOut.write(reinterpret_cast<char *>(&start->second->d),sizeof(float));
    fileOut.write(reinterpret_cast<char *>(&start->second->Tr),sizeof(float));
    fileOut.write(reinterpret_cast<char *>(&start->second->illum),sizeof(int));

    fileOut.write(reinterpret_cast<char *>(&start->second->Tf),sizeof(ngl::Vec3));
    fileOut.write(reinterpret_cast<char *>(&start->second->Ka),sizeof(ngl::Vec3));
    fileOut.write(reinterpret_cast<char *>(&start->second->Kd),sizeof(ngl::Vec3));
    fileOut.write(reinterpret_cast<char *>(&start->second->Ks),sizeof(ngl::Vec3));
    fileOut.write(reinterpret_cast<char *>(&start->second->Ke),sizeof(ngl::Vec3));

    // first write the length of the string
    size=start->second->map_Ka.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->second->map_Ka.c_str()),size);

    // first write the length of the string
    size=start->second->map_Kd.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->second->map_Kd.c_str()),size);

    // first write the length of the string
    size=start->second->map_d.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->second->map_d.c_str()),size);

    // first write the length of the string
    size=start->second->map_bump.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->second->map_bump.c_str()),size);

    // first write the length of the string
    size=start->second->bump.length();
    fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string
    fileOut.write(reinterpret_cast<const char *>(start->second->bump.c_str()),size);
  }


  fileOut.close();
  return true;
}
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.
bool Mtl::loadBinary(const std::string &_fname)
{
  std::ifstream fileIn;
  fileIn.open(_fname.c_str(),std::ios::in | std::ios::binary);
  if (!fileIn.is_open())
  {
    std::cout <<"File : "<<_fname<<" could not be opened for reading"<<std::endl;
    return false;
  }
  // clear out what we already have.
  clear();
  unsigned int mapsize;


  char header[12];
  fileIn.read(header,11*sizeof(char));
  header[11]=0; // for strcmp we need \n
  // basically I used the magick string ngl::bin (I presume unique in files!) and
  // we test against it.
  if(strcmp(header,"ngl::mtlbin"))
  {
    // best close the file and exit
    fileIn.close();
    std::cout<<"this is not an ngl::mtlbin file "<<std::endl;
    return false;
  }


  fileIn.read(reinterpret_cast<char *>(&mapsize),sizeof(mapsize));
  unsigned int size;
  std::string materialName;
  std::string s;
  for(unsigned int i=0; i<mapsize; ++i)
  {
    mtlItem *item = new mtlItem;

    fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
    // now the string we first need to allocate space then copy in
    materialName.resize(size);
   fileIn.read(reinterpret_cast<char *>(&materialName[0]),size);
    // now we do the different data elements of the mtlItem.
   fileIn.read(reinterpret_cast<char *>(&item->Ns),sizeof(float));
   fileIn.read(reinterpret_cast<char *>(&item->Ni),sizeof(float));
   fileIn.read(reinterpret_cast<char *>(&item->d),sizeof(float));
   fileIn.read(reinterpret_cast<char *>(&item->Tr),sizeof(float));
   fileIn.read(reinterpret_cast<char *>(&item->illum),sizeof(int));

   fileIn.read(reinterpret_cast<char *>(&item->Tf),sizeof(ngl::Vec3));
   fileIn.read(reinterpret_cast<char *>(&item->Ka),sizeof(ngl::Vec3));
   fileIn.read(reinterpret_cast<char *>(&item->Kd),sizeof(ngl::Vec3));
   fileIn.read(reinterpret_cast<char *>(&item->Ks),sizeof(ngl::Vec3));
   fileIn.read(reinterpret_cast<char *>(&item->Ke),sizeof(ngl::Vec3));
  // more strings
   fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
   // now the string we first need to allocate space then copy in
   s.resize(size);
   fileIn.read(reinterpret_cast<char *>(&s[0]),size);
   item->map_Ka=s;

   fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
   // now the string we first need to allocate space then copy in
   s.resize(size);
   fileIn.read(reinterpret_cast<char *>(&s[0]),size);
   item->map_Kd=s;

   fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
   // now the string we first need to allocate space then copy in
   s.resize(size);
   fileIn.read(reinterpret_cast<char *>(&s[0]),size);
   item->map_d=s;

   fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
   // now the string we first need to allocate space then copy in
   s.resize(size);
   fileIn.read(reinterpret_cast<char *>(&s[0]),size);
   item->map_bump=s;

   fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
   // now the string we first need to allocate space then copy in
   s.resize(size);
   fileIn.read(reinterpret_cast<char *>(&s[0]),size);
   item->bump=s;

   m_materials[materialName]=item;
  }
  m_loadTextures=true;
  loadTextures();
  return true;
}

Using the class

It is quite easy to use the class as the following code demonstrates

Mtl *m_mtl = new Mtl("models/sponza.mtl",true);
m_mtl->saveBinary("sponzaMtl.bin");

bool loaded=m_mtl->loadBinary("sponzaMtl.bin");
if(loaded == false)
{
 std::cerr<<"error loading mtl file ";
 exit(EXIT_FAILURE);
}

m_mtl->debugPrint();

That is about it for the Mtl class, the next post will describe the design of the GroupedObj class.

Sponza Demo Pt 1 Initial Design

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

Generic Polygon Class

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

How to run sdl-config in a Qt Project

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

LIBS+=$$system(sdl-config  --libs)
message(output from sdl-config --libs added to LIBS =$$LIBS)
CXX_FLAGS+=$$system(sdl-config  --cflags)
message(output from sdl-config --cflags added to CXX_FLAGS= $$CXX_FLAGS)
The message calls are there to display the output for debug and can be removed. This will output the following (on my mac)
Project MESSAGE: output from sdl-config --libs added to LIBS =-L/usr/local/lib -lSDLmain -lSDL -Wl,-framework,Cocoa
Project MESSAGE: output from sdl-config --cflags added to CXX_FLAGS= -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_THREAD_SAFE

Monday, 24 September 2012

Getting Started with SDL (Part 2 A Simple Window)

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
SDL_INIT_TIMER Initializes the timer sub system.
SDL_INIT_AUDIO Initializes the audio sub system.
SDL_INIT_VIDEO Initializes the video sub system.
SDL_INIT_CDROM Initializes the cdrom sub system.
SDL_INIT_JOYSTICK Initializes the joystick sub system.
SDL_INIT_EVERYTHING Initialize all of the above.
SDL_INIT_NOPARACHUTE Prevents SDL from catching fatal signals.
SDL_INIT_EVENTTHREAD
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
if (SDL_Init( SDL_INIT_VIDEO ) !=0)
{
    std::cerr <<"error initialising SDL exiting\n";
    exit(EXIT_FAILURE);
}

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.

/// @brief the width of the window
const int WINDOW_WIDTH = 1024;
/// @brief the height of the window
const int WINDOW_HEIGHT = 720;
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 
                                        0,SDL_HWSURFACE | SDL_DOUBLEBUF );
if( screen == NULL)
{
  std::cerr<<"error setting SDL Video Mode\n";
  exit(EXIT_FAILURE);
}

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_Event event;
bool quit=false;
// now we loop until the quit flag is set to true
while(!quit)
{
 // process SDL events, in this case we are looking for keys
  while ( SDL_PollEvent(&event) )  
  {
    switch (event.type)
    {
    // this is the window x being clicked.
    case SDL_QUIT : quit = true; break;

    // now we look for a keydown event
    case SDL_KEYDOWN:
    {
      switch( event.key.keysym.sym )
      {
        // if it's the escape key quit
        case SDLK_ESCAPE :  quit = true; break;
        default : break;
      }
    }

    default : break;
  }
 }
} // end processing loop

Exiting SDL

Once processing has finished it is important to shutdown SDL as it may have grabbed resources that other programs need access. To do this we use the SDL_Quit function.

Compiling the program

To compile our completed program we need to pass several flags to the c++ compiler we are using, this is what the sdl-config program is for. If we run sdl-config we get the following 
sdl-config --cflags --libs
-I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
-L/usr/lib/arm-linux-gnueabihf -lSDL
We can combine this into the call to g++ by using the single back quotes as follows
g++ InitSDL.cpp -o InitSDL `sdl-config --cflags --libs`
The full listing of the program can be downloaded from the bzr repository at the top of the page, however here is the source for the basic demo (without comments)
#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>

const int WINDOW_WIDTH = 1024;
const int WINDOW_HEIGHT = 720;

#if defined (DARWIN) || defined (WIN32)
  int SDL_main(int argc, char **argv)
#else
  int main(int argc, char **argv)
#endif
{
 if (SDL_Init( SDL_INIT_VIDEO ) !=0)
 {
  std::cerr <<"error initialising SDL exiting\n";
  exit(EXIT_FAILURE);
 }
 SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0,SDL_HWSURFACE | SDL_DOUBLEBUF );
 if( screen == NULL)
 {
  std::cerr<<"error setting SDL Video Mode\n";
  exit(EXIT_FAILURE);
 }
 SDL_WM_SetCaption( "A Simple SDL Window", 0 );

 SDL_Event event;
 bool quit=false;
 while(!quit)
 {
  while ( SDL_PollEvent(&event) )
  {
   switch (event.type)
   {
    case SDL_QUIT : quit = true; break;

    case SDL_KEYDOWN:
    {
     switch( event.key.keysym.sym )
     {
      case SDLK_ESCAPE :  quit = true; break;
      default : break;
     }
    }

    default : break;
   }
  }
 } // end processing loop

 SDL_Quit();

 return EXIT_SUCCESS;
}

Getting Started with SDL (Part 1 installation)

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

sdl-config 
Usage: sdl-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs] [--static-libs]

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

tar vfxz SDL-1.2.15.tar.gz
cd SDL-1.2.15
./configure
make
sudo make install

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.
part 2

Monday, 9 July 2012

Raspberry Pi and the Kinect

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

tar vfxj libusb-1.0.9.tar.bz2
cd libusb-1.0.9/
./configure
make
sudo make install
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.
#include "libfreenect.h"
#include <cstdlib>
#include <ctime>
#include <iostream>

int main(int argc, char *argv[])
{
 // seed rng generator
 srand(time(0));
 // pointer to the freenect context
 freenect_context *ctx;
 // pointer to the device
 freenect_device *dev;


 if (freenect_init(&ctx, NULL) < 0)
 {
  std::cout<<"freenect_init() failed\n";
   exit(EXIT_FAILURE);
 }
 // set the highest log level so we can see what is going on
 freenect_set_log_level(ctx, FREENECT_LOG_SPEW);

 int nr_devices = freenect_num_devices (ctx);
 std::cout<<"Number of devices found: "<<nr_devices<<"\n";
 // I only have one kinect so open device 0
 if (freenect_open_device(ctx, &dev, 0) < 0)
 {
  std::cout<<"could not open device error\n";
  freenect_shutdown(ctx);
  exit(EXIT_FAILURE);
 }
 // now I'm going to loop and set random value
 // these are basically from the tiltdemo.c that comes with
 // the freenect lib modified not to use the sync lib
 while (1)
 {
  // Pick a random tilt and a random LED state
  freenect_led_options led = (freenect_led_options) (rand() % 6); // explicit cast
  int tilt = (rand() % 30)-15;
  freenect_raw_tilt_state *state = 0;
  double dx, dy, dz;
  // Set the LEDs to one of the possible states
  freenect_set_led(dev,led);
  // Set the tilt angle (in degrees)
  freenect_set_tilt_degs(dev,tilt);

  // Get the raw accelerometer values and tilt data
  state=freenect_get_tilt_state(dev);

  std::cout<<"led["<<led<<"] tilt["<<tilt<<"]\r" ;
  std::cout.flush();
  sleep(1);
 }
}

To build this I used the following makefile
CC=g++
CFLAGS=-c -Wall -O3 -I/usr/local/include/libfreenect
LDFLAGS=-L/usr/local/lib -lfreenect
SOURCES=tiltdemo.cpp
OBJECTS=$(SOURCES:%.cpp=%.o)
EXECUTABLE=tiltdemo

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
 $(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
 $(CC) $(CFLAGS) $< -o $@

clean :
 rm -f *.o $(EXECUTABLE)

A video of it in action can be seen here

Thursday, 21 June 2012

Embedding a Python interpreter in C++

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

OpenGL ES on the raspberry pi Pt 3 Creating a window

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.
MyGLWindow::MyGLWindow(EGLconfig *_config) : EGLWindow(_config)
{
std::cout<<"My GL Window Ctor\n";
srand(time(NULL));
// init GL in this case we are going to create some render buffers
// for colour and depth
initializeGL();
}
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)
void MyGLWindow::initializeGL()
{
 // set the clear colour
 glClearColor(1,1,1,1);
}
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.
void MyGLWindow::paintGL()
{
 // scale the colour based on the width
 float r=(float)rand()/(float)RAND_MAX;
 float g=(float)rand()/(float)RAND_MAX;
 float b=(float)rand()/(float)RAND_MAX;
 // set the clear colour
 glClearColor(r,g,b,1);
 // clear screen
 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 // to update we need to swap the buffers
 swapBuffers();
}
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

OpenGL ES on the raspberry pi Pt 2 EGLWindow Class

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
void EGLWindow::destroySurface()
{
 if(m_activeSurface == true)
 {
  eglSwapBuffers(m_display, m_surface);
  // here we free up the context and display we made earlier
  eglMakeCurrent( m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
  eglDestroySurface( m_display, m_surface );
  eglDestroyContext( m_display, m_context );
  eglTerminate( m_display );
  m_activeSurface=false;
 }
}
The next post will show how these classes can be used to create a simple OpenGL window.

OpenGL ES on the raspberry pi Pt 1 EGLconfig Class

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

By default the constructor creates the following attributes
EGLconfig::EGLconfig()
{
  m_attributes[EGL_RED_SIZE]=8;
  m_attributes[EGL_GREEN_SIZE]=8;
  m_attributes[EGL_BLUE_SIZE]=8;
  m_attributes[EGL_ALPHA_SIZE]=8;
  m_attributes[EGL_SURFACE_TYPE]=EGL_WINDOW_BIT;
}
To set one of the attributes by value the following code is used
void EGLconfig::setAttribute(EGLint _attrib,EGLint _value)
{
  assert(_attrib >= 0x3020 && _attrib <=0x3042);
  m_attributes[_attrib]=_value;
}
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
void EGLconfig::setRGBA(EGLint _r,EGLint _g, EGLint _b, EGLint _a)
{
  m_attributes[EGL_RED_SIZE]=_r;
  m_attributes[EGL_GREEN_SIZE]=_g;
  m_attributes[EGL_BLUE_SIZE]=_b;
  m_attributes[EGL_ALPHA_SIZE]=_a;
}
void EGLconfig::setDepth(EGLint _d)
{
  m_attributes[EGL_DEPTH_SIZE]=_d;
}

void EGLconfig::setSurface(EGLint _s)
{
  m_attributes[EGL_SURFACE_TYPE]=_s;
}
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.

void EGLconfig::chooseConfig(EGLDisplay _display)
{
  std::map<EGLint,EGLint>::const_iterator it;

  std::vector <EGLint> attribs;
  for ( it=m_attributes.begin() ; it != m_attributes.end(); it++ )
  {
    attribs.push_back((*it).first);
    attribs.push_back((*it).second);
  }
  attribs.push_back(EGL_NONE);

  EGLBoolean result;
  EGLint numConfig;

  // get an appropriate EGL frame buffer configuration
  result = eglChooseConfig(_display, &attribs[0], &m_config, 1, &numConfig);
  std::cout<<"got numCofig ="<<numConfig<<"\n";
  if( result==EGL_FALSE )
  {
  std::cerr<<"error setting config check your setting or if you have a valid display\n";
  exit(EXIT_FAILURE);
  }
  std::cout<<"choosing config\n";
}
The full source for the cpp file can be seen here In the next post we will create an EGLWindow class to use this.

Tuesday, 5 June 2012

An EGLWindow class

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.

The design is based in part on how the Qt QGLWidget works.

You can grab the code from here

video

Saturday, 2 June 2012

Building a Raspberry PI Image Mac osx

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

mount

/dev/disk0s2 on / (hfs, local, journaled, noatime)
devfs on /dev (devfs, local, nobrowse)
/dev/disk1s2 on /Volumes/home (hfs, local, journaled)
/dev/disk1s3 on /Volumes/spare (hfs, local, journaled)
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
map auto_home on /home (autofs, automounted, nobrowse)
localhost:/udRZrWiR2BXDgRrkJFCx2X on /Volumes/MobileBackups (mtmfs, nosuid, read-only, nobrowse)
/dev/disk3s1 on /Volumes/UNTITLED (msdos, local, nodev, nosuid, noowners)

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

dd bs=1m if=debian6-19-04-2012.img of=/dev/disk3
1859+1 records in
1859+1 records out
1950000000 bytes transferred in 1349.801573 secs (1444657 bytes/sec)
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
sudo apt-get install gpm
We now need to edit the config file to get the correct mouse device.
sudo vi /etc/gpm.conf
# now change the device line to
device=/dev/input/mouse0
# save then
sudo  /etc/init.d/gpm restart 
This should now give you a mouse in the terminal

Friday, 1 June 2012

Enable SSH on Boot for Raspberry PI

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

Getting Started with EGL on the Raspberry pi

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 * ).

We can get one of these using the following code
EGLDisplay display;
// get an EGL display connection
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert(display !=EGL_NO_DISPLAY);
If this is successful it should return a valid display, else the EGL_NO_DISPLAY value will be returned.

EGL initialisation 

Now we have a valid display connection we can initialise EGL and query what version we have, this is done with the following code.
// now lets initialise EGL and get the versions
int major;
int minor;
EGLBoolean result;

result = eglInitialize(display, &major, &minor);
assert(result != EGL_FALSE );
std::cout<<"Major version "<<major<<" minor "<<minor<<"\n";
On my version of the pi it gives the following output
Major version 1 minor 4

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)

for(int i=0; i<numConfigs; ++i)
{
 std::cout<<"Config #"<<i<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_BUFFER_SIZE,&value);
 std::cout<<"Buffer Size "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_RED_SIZE,&value);
 std::cout<<"Red Size "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_GREEN_SIZE,&value);
 std::cout<<"Green Size "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_BLUE_SIZE,&value);
 std::cout<<"Blue Size "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_ALPHA_SIZE,&value);
 std::cout<<"Alpha Size "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_CONFIG_CAVEAT,&value);
 switch(value)
 {
  case  EGL_NONE : std::cout<<"EGL_CONFIG_CAVEAT EGL_NONE\n"; break;
  case  EGL_SLOW_CONFIG : std::cout<<"EGL_CONFIG_CAVEAT EGL_SLOW_CONFIG\n"; break;
 }
 eglGetConfigAttrib(display,configs[i],EGL_CONFIG_ID,&value);
 std::cout<<"Config ID "<<value<<"\n";

 eglGetConfigAttrib(display,configs[i],EGL_DEPTH_SIZE,&value);
 std::cout<<"Depth size "<<value<<"\n";

 eglGetConfigAttrib(display,configs[i],EGL_MAX_PBUFFER_WIDTH,&value);
 std::cout<<"Max pbuffer width "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_MAX_PBUFFER_HEIGHT,&value);
 std::cout<<"Max pbuffer height "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_MAX_PBUFFER_PIXELS,&value);
 std::cout<<"Max pbuffer pixels "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_NATIVE_RENDERABLE,&value);
 std::cout<<"Native renderable "<<std::string(value ? "true" : "false")<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_NATIVE_VISUAL_ID,&value);
 std::cout<<"Native visual ID "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_NATIVE_VISUAL_TYPE,&value);
 std::cout<<"Native visual type "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_SAMPLE_BUFFERS,&value);
 std::cout<<"Sample Buffers "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_SAMPLES,&value);
 std::cout<<"Samples "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_SURFACE_TYPE,&value);
 std::cout<<"Surface type "<<value<<"\n";
 eglGetConfigAttrib(display,configs[i],EGL_TRANSPARENT_TYPE,&value);

}
This give a sample output like this (a full listing can be seen here or in the file output.txt in the code bundle)
Config #0
Buffer Size 32
Red Size 8
Green Size 8
Blue Size 8
Alpha Size 8
EGL_CONFIG_CAVEAT EGL_NONE
Config ID 1
Depth size 24
Max pbuffer width 2048
Max pbuffer height 2048
Max pbuffer pixels 4194304
Native renderable true
Native visual ID 37928
Native visual type 12344
Sample Buffers 0
Samples 0
Surface type 1639

Makefile

To build the program the following makefile was used, it includes the correct paths and libs
CC=g++
CFLAGS=-c -Wall -O3 -I/usr/local/include -I/opt/vc/include -Iinclude/ngl -Isrc/ngl -Isrc/shaders -DNGL_DEBUG
LDFLAGS=-L/opt/vc/lib -lEGL
SOURCES=$(shell find ./ -name *.cpp)
OBJECTS=$(SOURCES:%.cpp=%.o)
EXECUTABLE=EGLgetConfig

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
 $(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
 $(CC) $(CFLAGS) $< -o $@

clean :
 rm -f *.o $(EXECUTABLE)

That it for now but here is a sneak preview of NGL almost working