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.