Tuesday 21 February 2012

A bit of Parsing

In yesterdays post I taked about some updates to the ShaderLib to allow registering of the uniforms, and as I was driving into work I decided to add some more code to parse the shader source and look for any lines containing the word uniform and automatically add it to the uniforms list.

The glsl spec contains a full list of the grammar for glsl, and we can break down the declaration of uniforms to the following
// easy case
// uniform type name;
uniform vec3 position;

// more difficult case
// uniform type name[ ];

#define numLights 10
uniform Lights lights[numLights];

//or

uniform Lights lights[3];

The simple case of a single uniform is easy to parse and can be accomplished by reading the shader source and looking for lines containing the uniform keyword.

The array version however is more complex as we need to determine if we have one of two different cases. Either a hard coded array value or a constant defined by a #define statement.

The lucky thing is that the #define must always be executed before it is used, so we can store these values and do a lookup on them.

The downside of this is the fact that each element of the array must be registered.

This is further compounded by the fact that the data type may be a structure. I'm not going to worry about the structure side of things and only worry with accessing normal arrays of the type uniform vec3 points[3] for example.

Lets get a boost++
In general C++ string processing is not that good, however there are several really good libraries in boost that allow loads of different string processing. For this example I'm going to use boost::tokenizer ,boost::formatboost::split and boost::lexical_cast, all of these are header only templated classes so don't require external compiled libs and all work well with the usual stl containers.

Overview of the process
I've created a new method for the ShaderProgram class which will loop for each attached shader and grab the shader source code string (the whole shader is stored as a single std::string ) this is then split based on the tokens \n\r and a space.
Each line is then searched to find the following keywords "uniform" and "#define". The code to do this is as follows.
void ShaderProgram::autoRegisterUniforms()
{

  unsigned int size=m_shaders.size();
  const std::string *source;
  std::vector<std::string> lines;

  boost::char_separator<char> sep(" \t\r\n");
  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;

  for(unsigned int i=0; i<size; ++i)
  {
   /// first grab all of the shader source for this program
    source=m_shaders[i]->getShaderSource();
    // and split on new lines
    boost::split(lines, *source, boost::is_any_of("\n\r"));

    // now we loop for the strings and tokenize looking for the uniform keyword
   // or the #define keyword
   std::vector<std::string>::iterator start=lines.begin();
    std::vector<std::string>::iterator end=lines.end();
    std::map<std::string,int> defines;

    while(start!=end)
    {
      if(start->find("#define") !=std::string::npos)
      {
        int value;
        std::string define;
        if( parseHashDefine(*start,define,value) )
         {
          defines[define]=value;
        }
      }
      // see if we have uniform in the string
      else if (start->find("uniform") !=std::string::npos)
      {
        parseUniform(*start,defines);
      }
      // got to the next line
      ++start;
     }
  }
}
To find if the string contains our keywords we use the std::string find method which will return a value not equal to std::string::npos if found (basically the index but we don't need that).

If this is found we can process the respective values.
Parsing #define
To store any #define values I'm going to use a std::map<std::string, int>  to store the value, and also make the assumption that we will always have the form #define name [int]. This is a very safe assumption as array subscripts must always be positive and in the case of glsl most implementations only allow very small arrays.

The overall process is quite simple, I tokenise the string as above, however now we copy this to a std::vector <std::string>  using the assign method and then use the subscript to access the elements we want, as shown below

bool ShaderProgram::parseHashDefine(
                                    const std::string &_s,
                                    std::string &o_name,
                                    int &o_value
                                    ) const
{
  // typedef our tokenizer for speed and clarity
  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  // these are the separators we are looking for (not droids ;-)
  boost::char_separator<char> sep(" \t\r\n");
  // generate our tokens based on the separators above
  tokenizer tokens(_s, sep);
  // now we will copy them into a std::vector to process
  std::vector <std::string> data;
  // we do this as the tokenizer just does that so we can't get size etc
  data.assign(tokens.begin(),tokens.end());
  // we are parsing #define name value so check we have this format
  // we should as the glsl compiler will fail if we don't but best to be sure
  if(data.size() !=3)
  {
    return false;
  }
  else
  {
    //            data [0]     [1]   [2]
    // we are parsing #define name value
    o_name=data[1];
    o_value=boost::lexical_cast<int> (data[2]);
    // all was good so return true
    return true;
  }
}
You will notice that the boost::lexical_cast is used to convert the string into an integer, and that both the values are returned to the main program and stored in the defines map ready to be passed into the next function to process the uniforms.
ParseUniform method
The parseUniform method is split into two sections, we first check to see if the string has a [ or not as this will depend upon the parse method. If no [] is present we can process in a similar way to above, however if there is an array we need to further refine the parse, and then loop and register all the uniforms. For example the following glsl code
#define numIndices 4
int indices[numIndices];
would need all the uniforms registered so we would register
indices[0]
indices[1]
indices[2]
indices[3]
The following code shows the complete method
void ShaderProgram::parseUniform(
                                  const std::string &_s,
                                  const std::map <std::string,int> &_defines
                                )
{
 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;

 // first lets see what we need to parse
 if(_s.find("[") ==std::string::npos)
 {
   boost::char_separator<char> sep(" \t\r\n;");
   // generate our tokens based on the seperators above
   tokenizer tokens(_s, sep);
   // now we will copy them into a std::vector to process
   std::vector <std::string> data;
   // we do this as the tokenizer just does that so we can't get size etc
   data.assign(tokens.begin(),tokens.end());
   // uniform type name
   // we should as the glsl compiler will fail if we don't but best to be sure
   if(data.size() >=3)
   {
     registerUniform(data[2]);
   }
 }
 else
 {
   boost::char_separator<char> sep(" []\t\r\n;");
   // generate our tokens based on the separators above
   tokenizer tokens(_s, sep);
   // now we will copy them into a std::vector to process
   std::vector <std::string> data;
   // we do this as the tokenizer just does that so we can't get size etc
   data.assign(tokens.begin(),tokens.end());
   // uniform type name
   // we should as the glsl compiler will fail if we don't but best to be sure
   if(data.size() >=3)
   {
     // so in this case data[3] is either a number or a constant
     int arraySize=0;
     // so we try and convert it if it's not a number
     try
     {
       arraySize=boost::lexical_cast<int> (data[3]);
     }
     // catch and lookup in the uniform array
     catch(boost::bad_lexical_cast)
     {
       std::map <std::string, int >::const_iterator def=_defines.find(data[3]);
       if(def !=_defines.end())
       {
         arraySize=def->second;
       }
     } // end catch
    // now loop and register each of the uniforms
     for(int i=0; i<arraySize; ++i)
     {
       // convert our uniform and register
       std::string uniform=boost::str(boost::format("%s[%d]") %data[2] %i);
       registerUniform(uniform);
     }
   }

 }
}
Most of the code is similar to the other parse methods, however we use the fact that boost::lexical_cast throws and exception to check to see if we have a number or a string as the size of the array, first I try the cast, if this throws a boost::bad_lexical_cast exception we look to see if we have the value stored in our defines list.
Conclusions and Future work
This works quite well and is fairly robust (as the glsl compiler will fail if the code is wrong anyway), however as mentioned above it doesn't cope with registering uniforms which have structures. I may refine this at a later date to cope with these but it would require storing each structure and element of that structure and registering each element.

This will eventually be made redundant due to the use of the new glsl Uniform Buffer Objects however at present my mac doesn't support them so will have to wait.

I may also just write a full glsl parser using the excellent boost::spirit library one day as an exercise in  parser writing (as I quite enjoy writing parsers)

This code has been integrated into ngl and the latest source tree has been updated to inclue it all.

Monday 20 February 2012

ngl::ShaderLib update

Just a quick post to explain some updates to the ngl::ShaderLib sub-system. First of all this doesn't break any existing code, but has in some situations increased frame rate by 10-15%.

First a bit of background, all of the shader lib functions use the getUniformLocation function to query the location of the uniform in the current program and use this GLuint offset to load the values to the uniform in the shader.

This works ok, and generally this only called at the start of the program so doesn't cause too much of a bottleneck. However in most of the demos we load the Model/View/Projection matrix to the Shader each time we move something, and the MVP value will be loaded using the following code (from the ngl:: source)

void ShaderProgram::setUniformMatrix4fv(
                                          const char* _varname,
                                          size_t _count,
                                          bool _transpose,
                                          const float* _value
                                        ) const
{
  glUniformMatrix4fv(getUniformLocation(_varname),_count,_transpose,_value);
}
Here the getUniformLocation is called and doesn't need to be if we pre-cache the value. To do this ngl::ShaderProgram has a new attribute added to it as follows
std::map <std::string, GLuint> m_registeredUniforms;
To use this, once the shader is loaded, compiled and linked we must set it to be active and we can then register the uniform as follows (this will usually be done in the GLWindow::initalizeGL method)
(*shader)["MultipleLights"]->use();
shader->setShaderParam1f("Normalize",1);
shader->registerUniform("MultipleLights","MVP");
shader->registerUniform("MultipleLights","MV");
shader->registerUniform("MultipleLights","M");
shader->registerUniform("MultipleLights","normalMatrix");
shader->registerUniform("MultipleLights","viewerPos");

This will register the uniforms, now when we load the matrix values to the shaders, we can use the "registered" versions of the functions which will look up the values in the map and use the uniform's stored there. This will work unless the shader source is changed and re-compiled. In that case they will need to be re-registered.

void GLWindow::loadMatricesToShader(
                                     ngl::TransformStack &_tx
                                   )
{
  ngl::ShaderLib *shader=ngl::ShaderLib::instance();
  (*shader)["MultipleLights"]->use();
  ngl::Matrix MV;
  ngl::Matrix MVP;
  ngl::Mat3x3 normalMatrix;
  ngl::Matrix M;
  M=_tx.getCurrentTransform().getMatrix();
  MV=_tx.getCurrAndGlobal().getMatrix()*m_cam->getViewMatrix() ;
  MVP=MV*m_cam->getProjectionMatrix();
  normalMatrix=MV;
  normalMatrix.inverse();
  normalMatrix.transpose();
  shader->setRegisteredUniformFromMatrix("MV",MV);
  shader->setRegisteredUniformFromMatrix("M",M);
  shader->setRegisteredUniformFromMatrix("MVP",MVP);
  shader->setRegisteredUniformFromMat3x3("normalMatrix",normalMatrix);
  shader->setRegisteredUniformVec3("viewerPos",m_cam->getEye().toVec3());
}

Operator Overloading in C++ Part 4

previously we have discussed the different types of operator overloading and the differences between the Member operators and Free operators. In this part we are going to implement a basic * Scalar operator which will multiply each of the Vec3 components by a floating point scalar value. In the .h file we can implement the following definition for the operator
/// @brief * float operator
Vec3  operator*(float _rhs) const;
and for the .cpp file the following
/// @brief * float operator
Vec3 Vec3::operator*(float _rhs) const
{
  return Vec3(m_x*_rhs,m_y*_rhs,m_z*_rhs);
}
Testing this using the following code results in
std::cout<<"b*2== "<<b*2<<"\n";
b*2== [4,6,8] 
However if we try to write the following
std::cout<<"2*a ="<<2*a<<" b*2== "<<b*2<<"\n";
We get the following compiler error error: no match for 'operator*' in '2 * a' This is due to the fact that we have no operator for scalar * Vec3. To solve this problem we can generate a Free function version of the operator and a scale method to scale the vector by a scalar value.
/// @param[in} _s the value to scale components by
Vec3 scale(float _s) const;

Vec3 operator *(float _lhs, const Vec3 &_rhs);

/// in the .cpp file
Vec3 operator *(float _lhs, const Vec3 &_rhs)
{
  return _rhs.scale(_lhs);
}
In most cases it will be best to implement both operators as free functions so we would have the following extra methods
Vec3 operator *(float _lhs, const Vec3 &_rhs)
{
  return _rhs.scale(_lhs);
}

Vec3 operator *(const Vec3 &_lhs,float _rhs)
{
  return _lhs.scale(_rhs);
}
As you can see both methods require the extra scale method, however if we use the free function version we can remove the member operator. In some cases this will not be required (for example if the operands are of the same type)

Operator Overloading in C++ Part 3

In the previous post we looked at the mandated member operators, for this part I'm going to look at the different types of operators we can generate and provide examples of each.

For ease I will split this section into relational operators and arithmetic operators. We can represent the relational operators using the following diagram


These operators will always return a boolean value which will be the result of some form of comparison. 


Arithmetic operators will return an object of some type which depending upon the context may be either the same object or a new type of object.  Later we will also add the += style operators which will mutate the current object rather than returning a value.
Equality Operators
In the case of the Vec3 class there are only two equality operator which make sense to implement, these are the == and != operators. Also we must ensure that we are doing correct comparison as we are storing floating point values. ( see here for an in depth discussion of floating point comparison ). For this example I'm going to generate a very simple FCompare macro which will be used to do a comparison via a simple epsilon error value.


//----------------------------------------------------------------------------------------------------------------------
/// @brief define EPSILON for floating point comparison
//----------------------------------------------------------------------------------------------------------------------
#ifndef EPSILON
  const float EPSILON = 0.001f;
#endif

//----------------------------------------------------------------------------------------------------------------------
/// @brief FCompare macro used for floating point comparison functions
//----------------------------------------------------------------------------------------------------------------------
  #define FCompare(a,b) \
      ( ((a)-EPSILON)<(b) && ((a)+EPSILON)>(b) )
In the first example I will produce a "Member operator" for the equality operator, first in the .h file we declare the operator
bool Vec3::operator==(const Vec3 &_rhs)
{
  return FCompare(m_x,_rhs.m_x) &&
         FCompare(m_y,_rhs.m_y) &&
         FCompare(m_z,_rhs.m_z);
}
As you can see in this case we do a component wise FCompare with the current object and the rhs value. We can test this using the following code from the previous examples
if(b==c)
 std::cout<<"b==c is true\n";
else
 std::cout<<"b!=c \n";
if(a==fromFloat)
 std::cout<<"a==fromFloat\n";
else
 std::cout<<"a!=fromFloat\n";
Which gives the following output
testing equality operators 
b==c is true
a!=fromFloat
To generate the != method we do the following

/// in .h
/// @brief != operator
bool operator!=(const Vec3 &_rhs);
/// in .cpp
bool Vec3::operator!=(const Vec3 &_rhs)
{
  return !(*this==_rhs);
}
For the free function operator we have to write some additional code again to allow the free function access to the attributes. In this case we are going to write a method called isEqual ( note that my coding standard says this kind of method should be formed as a question as it returns a bool)
/// @brief function to test equality
bool isEqual(const Vec3 &_rhs) const;
The actual code for this class method will use the same FCompare macro as above and looks like this
bool Vec3::isEqual(const Vec3 &_rhs) const
{
  return FCompare(m_x,_rhs.m_x) &&
         FCompare(m_y,_rhs.m_y) &&
         FCompare(m_z,_rhs.m_z);
}
The free function definitions of the == and != methods are now declared outside of the class but still in the .h file as follows
/// @brief free operator for equality testing
bool operator ==(const Vec3 &_lhs, const Vec3 &_rhs);
/// @brief free operator for equality testing
bool operator !=(const Vec3 &_lhs, const Vec3 &_rhs);
Finally we write the main function code, not that as they are no longer class methods it is no longer valid to mark the methods as const (in fact you get the following error with g++ error: non-member function 'bool operator==(const Vec3&, const Vec3&)' cannot have cv-qualifier )
bool operator ==(const Vec3 &_lhs, const Vec3 &_rhs) const
{
  return _lhs.isEqual(_rhs);
}

bool operator !=(const Vec3 &_lhs, const Vec3 &_rhs)
{
  return !_lhs.isEqual(_rhs);
}

Friday 17 February 2012

Operator Overloading in C++ Part 2

In the previous post I discussed some of the basics of operator overloading and the difference between "Free Operators" and "Member Operators" and we overloaded the << insertion operator so we could use our Vec3 class with the std::cout method, in this section I'm going to start with the assignment operator which is one of the operators which must be a Member operator.

The assignment Operator
The assignment operator must be a member operator to ensure that they receive an lvalue (basically an expression that refers to the object) as the first operand, also if we follow the "rule of three" we should define a copy constructor as well, in this case we could get away without writing an assignment operator as we don't create any dynamic memory in the class, however good practice dictates it's best to always do this. If we did any dynamic allocation in this class we would need to do a "deep copy". The following code is added to both version of the project code to add the copy constructor and assignment operator.

/// @brief a copy ctor
Vec3(const Vec3 &_v);

/// @brief assignment operator
Vec3 & operator=(const Vec3 &_rhs);
In the body code I've explicitly made calls to print out which method is being called so we can see the order of the operations
Vec3::Vec3(const Vec3 &_v)
{
  std::cout<<"copy ctor called\n";
  m_x=_v.m_x;
  m_y=_v.m_y;
  m_z=_v.m_z;
}

Vec3 & Vec3::operator=(const Vec3 &_rhs)
{
  std::cout<<"assignment operator called\n";
  m_x=_rhs.m_x;
  m_y=_rhs.m_y;
  m_z=_rhs.m_z;
  return *this;
}
We can now run the following code and see them being run
Vec3 a(1,2,3);
Vec3 b;
Vec3 c(2,3,4);
std::cout<<"a "<<a<<" b "<<b<<" c "<<c<<"\n";
std::cout<<"testing the assignment operator\n";
b=c;
std::cout<<b<<"\n";
std::cout<<"testing the copy ctor\n";
Vec3 copy(a);
std::cout<<copy<<"\n";
Which gives the following output
a [1,2,3] b [0,0,0] c [2,3,4]
assignment operator called
[2,3,4]
copy ctor called
[1,2,3]
We can also create more than one assignment operator passing in different types to the right hand side parameter, for example if we had a 4x4 matrix class we could call Mat4x4 v=1.0 to set the values to the identity matrix. The following example will set all of the Vec3 components to the floating point value passed in
/// @brief assignment operator from float
Vec3 & operator=(float _rhs);

in .cpp

Vec3 & Vec3::operator=(float _rhs)
{
  std::cout<<"assignment operator from float called\n";
  m_x=_rhs;
  m_y=_rhs;
  m_z=_rhs;
  return *this;
}
We can now use this to assign our Vec3 from a single float value as shown
Vec3 fromFloat;
fromFloat=0.5;
std::cout<<fromFloat<<"\n";
fromFloat=0.0;
std::cout<<fromFloat<<"\n";
Which gives the following output
assignment operator from float called
[0.5,0.5,0.5]
assignment operator from float called
[0,0,0]
Obviously caution should be applied to this approach in your design, however it is quite common in graphical applications to be able to do this (for example renderman tuple types and glsl Vec types both support this type of assignment so I have used it in ngl)
The [] operator
The [] subscript operator is a useful operator to overload as it will allow assignment and access to the internal elements of the class. This does however have the side effect of exposing these private attributes and break encapsulation.

To access the data we really need to have an array as well as the individual m_x style elements, to do this we can use a union however this will effectively make things public anyway (see this post about how g++ does this but not clang ).  The following code will modify the class so we have a union

union
{
 struct
 {
  float m_x;
  float m_y;
  float m_z; 
 };
 float m_array[3];
};
To write the subscript operator we use the following operator syntax
/// @brief [] operator
float & operator[](unsigned int _index);
And in the .cpp file we add
/// @brief [] operator
float & Vec3::operator[](unsigned int _index)
{
  assert(_index<3 );
  return m_array[_index];
}
You will notice in the above example the use of the assert function (from #include <cassert>) this will abort the program if the index is out of range, in this example as we are using an unsigned int for the index we only need to check for the higher bound as the index can never be negative. However our client code could use an int for the index which we should also check the negative bound, to make a fully safe version we should really write both [int] and [unsigned int] versions of the code. Testin this code with the following program
std::cout<<"testing the  [] operator \n";
fromFloat[1]=99.0;
fromFloat[0]=2;
fromFloat[2]=3;
std::cout<<fromFloat[0]<<" "<<fromFloat[1]<<" "<<fromFloat[2] <<"\n";
fromFloat[5]=2;
Which will give the following output (and abort due to the assert)
testing the  [] operator 
2 99 3
Assertion failed: (_index<3), function operator[], file Vec3.cpp, line 42.
The program has unexpectedly finished.
Note : it is also possible to write the same operator without the union, by using the following code
 return &m_x[_index];
Whilst this will work it does make several assumptions on how the data is packed in your header,in this case we assume packed alignment and that m_x m_y and m_z are contiguous, while this is generally the case it is not the safest way of accessing the data and the union should always ensue that the correct data packing is in place.

Thursday 16 February 2012

Operator Overloading in C++ Part 1

We introduced the concept of operator overloading today in the first year lecture / lab session and there was quite a lot of confusion, so I've decided to do a more in depth article about it here.

There is a wealth of knowledge online about operator overloading and a good starting point is this article as well as the venerable c++ faq, however I'm going to use the excellent book by Martin Reddy "API Design for C++" as he discusses some interesting differences between the ways we can implement Operator Overloading.

All of the code mentioned in this article can be downloaded from here

So what is Operator Overloading
The main reason to overload operators in your own class design is to make them behave like the built in types (intrinsic types). It can also make things more intuitive when writing our own classes, especially if they are representing something mathematical. For example imagine the following class

We have three attributes of type float in the private section, and (assuming a constructor has been written )  we could write the following code
Vec3 a,b,c;
add(add(mul(a,b), mul(c,d)), mul(a,c))
But that is almost unreadable and the actual mathematic being implemented is $$ a*b+c*d+a*c $$ which is much more readable, and when trying to implement a mathematical function from a paper much easier to check when debugging.

So we can use operator overloading to make our classes work like mathematical data types even when they are not.

However, it is important to only overload operators which seem natural to do so and follow the semantic you would expect. For example it is natural to overload the plus + operator to meen addition or for string based objects concatenation.

Vec3 Class
For the purpose of this discussion I will be using a simple floating point Vec3 class which represents a three tuple vector and will be used to perform mathematical calculations and comparison operations. The basic header file we will be using is
#ifndef VEC3_H_
#define VEC3_H_

class Vec3
{
  public :
  Vec3(
        float _x=0.0f,
        float _y=0.0f,
        float _z=0.0
      ) :
          m_x(_x),
          m_y(_y),
          m_z(_z){;}

  private :
    /// @brief the x element
    float m_x;
    /// @brief the y element
    float m_y;
    /// @brief the z element
    float m_z;
};

#endif
This will allow us to create simple Vec3 classes like this
#include "Vec3.h"

int main()
{
  Vec3 a(1,2,3);
  Vec3 b;
  // use the compilers built in assignment operator
  b=a;

}
In the above example we construct a Vec3 a and assign it some values, and be will be constructed using the default parameter values 0,0,0. By default the compiler will implement a simple assignment operator for us and a==b. (don't worry we will create our own soon).

Free Operators vs Member Operators
Reddy defines two different types of operator, "Free Operators" and "Member Operators" Member operators are members of the class, and as such have full access to the private data areas of the class, there are some operators that can only be implemented using Member Operators ( = [] -> ->* () (T) new / delete) however all the other operators can be implemented in both ways. In this example I'm going to implement both type using two different project files (which can be downloaded from the link at the top of the page).

Free Operators are not part of the class, and are declared as functions separate to the class, this means that the function doesn't have access to the class private data area so we must write some form of accesors for the attributes for it to work, however this does have the advantage of allow us to reduce the coupling of the Vec3 class to our other implementation.

The other advantage of Free Operators is that they give us better symmetry and allow us to do something like 2*V and V*2 in the same code.

Insertion Operator
The first operator I'm going to implement is the << insertion operator, this will allow us to use std::cout to print the contents of our class, this is perhaps not the best one to start with as it actually add extra complication to what we are doing as we need to send data to the std::ostream class and it will need to know about the internal structure of our Vec3 class. The easiest way of doing this, and in most texts the way shown, is by using the friend prefix this indicates that the method is a friend of the class and it can access the private data. This does however break encapsulation and promotes many coding arguments.

The following code will implement the << operator as a member operator in is placed in the Vec3.h
friend std::ostream& operator<<(std::ostream& _output, const Vec3& _v); 
We can now write the implementation code in the Vec3.cpp file
std::ostream& operator<<(
                         std::ostream& _output,
                         const Vec3 & _v
                        )
{
  return _output<<"["<<_v.m_x<<","<<_v.m_y<<","<<_v.m_z<<"]";
}
This will format the string and return it to the ostream object, we can use the code in the following way
#include "Vec3.h"
#include <iostream>

int main()
{
  Vec3 a(1,2,3);
  Vec3 b;
  Vec3 c(2,3,4);

  std::cout<<"a "<<a<<" b "<<b<<" c "<<c<<"\n";
}
And will give the output
a [1,2,3] b [0,0,0] c [2,3,4]
To generate the free operator version we actually have to write a lot more code in the Vec3 Class. As I mentioned earlier the free operator version is defined outside of the class definition, usually I still prefer to keep the definition and the code in the same .h and .cpp files however this is not mandatory anymore as the free operators are not part of the class. The following code shows the prototype of the free operator
std::ostream& operator<<(std::ostream& _output, const Vec3& _v);
Now as this is no longer a friend to our Vec3 class we need to implement a method to gather the data we require and return it to the free operator in this case I'm going to implement the member function getString() as follows
/// @brief a method to get the data as a string
std::string getString() const;
And the code to format the string and return it
#include <sstream>

std::string Vec3::getString() const
{
  std::stringstream string;
  string<<"["<<m_x<<","<<m_y<<","<<m_z<<"]";
  return string.str();
}
Here we construct a stringstream object and pass the formatted data to it. This is then converted to a string and returned from the method. Finally the free operator can access the data from the class as follows
std::ostream& operator<<(
                         std::ostream& _output,
                         const Vec3 &_v
                        )
{
  return _output<<_v.getString();
}
The client program to use the operator will be exactly the same.

Tuesday 14 February 2012

Getting Started with the Programming Assignment Pt 5 A starmap

In the previous pos I got the ship moving, and on the way to work I decided it would be good to make a better background to the game, so I created a very simple StarMap class which loads two textures and creates two rotating sphere with alpha blended textures. This is shown in the following video and I will write a more detailed explanation when I get a chance. I've also got a new model form Turbo Squid until I get a better one.

The star map image is from here and I recommend this site in general especially the cool geometry stuff here. The planets were taken from here

Monday 13 February 2012

Getting Started with the Programming Assignment Pt 4 Moving the Ship

In the previous post we designed different ways of linking our objects together, now to get the basic movement of the ship going I decided to modify the Advanced Game Key control demo from the ngl:: demos, I was originally going to use the format described in this post however the method I'm going to use here is a lot more flexible and is based on some code written by Rob the Bloke

This video shows the code in action

This code is spread amongst several classes but the main control codes are stored in the following structures in the file GameControls.h

enum GameControls
{
  kUp = 1 << 0,
  kDown = 1 << 1,
  kLeft = 1 << 2,
  kRight = 1 << 3,

  kUpLeft = kUp | kLeft,
  kUpRight = kUp | kRight,
  kDownLeft = kDown | kLeft,
  kDownRight = kDown | kRight,

  // nonsense controls
  kUpDown = kUp | kDown,
  kLeftRight = kRight | kLeft
};
This enum allows us to create a simple bit mask for each of the keys we require, in this case we define the main up/down & left right keys, then using a logical or we can create valid key combinations such as up and left etc. Next we are going to define a structure to contain the movement values for each key combination, for now these will be the x,y movement and rotation values in x,y and z
// motion of a spaceship for a given key combo.
struct SpaceShipMotion
{
  float offsetX;
  float offsetY;
  float rotX;
  float rotY;
  float rotZ;
};
Finally we build up a table of key combination / motion values as shown here
static const SpaceShipMotion g_motionTable[] =
{
  { 0.0f, 0.0f, 0.0f ,0.0f,0.0f}, // 0
  { 0.0f, 1.0f, -1.0f,0.0f,0.0f}, // kUp
  { 0.0f,-1.0f, 1.0f,0.0f,0.0f }, // kDown
  { 0.0f, 0.0f, 0.0f,0.0f,0.0f }, // kUpDown (nonsense)

  {-1.0f, 0.0f, 0.0f,0.0f,-1.0f }, // kLeft
  {-0.707f, 0.707f, -0.707f,0.707f,-0.707f }, // kUpLeft
  {-0.707f,-0.707f, 0.707f,0.707f,0.707f }, // kDownLeft
  {-1.0f, 0.0f, 0.0f,0.0f,0.0f }, // kUpDown (nonsense) & kLeft

  { 1.0f, 0.0f, 0.0f,0.0f,1.0f }, // kRight
  { 0.707f, 0.707f, -0.707f,-0.707f,0.707f }, // kUpRight
  { 0.707f,-0.707f, 0.707f,-0.707f,0.707f }, // kDownRight
  { 1.0f, 0.0f, 0.0f,0.0f,0.0f }, // kUpDown (nonsense) & kRight

  { 0.0f, 0.0f, 0.0f,0.0f,0.0f }, // kLeftRight (nonsense)
  { 0.0f, 1.0f, 0.0f,0.0f,0.0f }, // kUp & kLeftRight (nonsense)
  { 0.0f,-1.0f, 0.0f,0.0f,0.0f }, // kDown & kLeftRight (nonsense)
  { 0.0f, 0.0f, 0.0f,0.0f,0.0f }, // kUpDown (nonsense) & kLeftRight (nonsense)

};
This structure is very useful as we can tweak the position and rotation values for each of the movements and it is easy to update the key combinations to add more. The next stage of the code is to combine this with the SpaceShip class, the class used in the previous versions of the code have been modified to remove the move and rotate methods and been modified to use the following method
void SpaceShip::move(uint8_t _keysPressed)
{
  // note we flip the offset to reverse the key direction here
  m_pos.m_x += -g_motionTable[_keysPressed].offsetX;
  m_pos.m_y += g_motionTable[_keysPressed].offsetY;
  const static float s_rotationUpdate=20.0;
  m_rotation.m_x=s_rotationUpdate*g_motionTable[_keysPressed].rotX;
  m_rotation.m_y=s_rotationUpdate*g_motionTable[_keysPressed].rotY;
  m_rotation.m_z=s_rotationUpdate*g_motionTable[_keysPressed].rotZ;

  // clamp
  m_pos.m_x = std::max(-s_xExtents, m_pos.m_x);
  m_pos.m_y = std::max(-s_yExtents, m_pos.m_y);
  m_pos.m_x = std::min(s_xExtents, m_pos.m_x);
  m_pos.m_y = std::min(s_yExtents, m_pos.m_y);
}
The key combinations set in the GLWindow class are passed to this method as a uint8_t data type, we then uses this value to find the index into the motion table and set the SpaceShip position and rotation values. Finally the values are clamped to ensure the ship stays within the visibile area of the screen (this may change once I get some more of the game developed)
Setting the Key Values
To set the key values we add a new attribute to the GLWindow.h class
/// @brief the keys being pressed
uint8_t m_keysPressed;
Now when the keyPress and release method are called in the GLWindow class we set / free the m_keysPressed attribute to the key combinations in the GameControl.h file as shown
void GLWindow::processKeyDown(
                               QKeyEvent *_event
                              )
{
  switch(_event->key())
  {
    case Qt::Key_Up: m_keysPressed |= kUp; break;
    case Qt::Key_Down: m_keysPressed |= kDown; break;
    case Qt::Key_Left: m_keysPressed |= kLeft; break;
    case Qt::Key_Right: m_keysPressed |= kRight; break;
  }
}
When any of the keys are pressed the m_keysPressed attribute will set the correct key flag in the data structure by using a logical or. This means that if the flag is not set it will be set, however if already set it will remain active. When the key is released we need to turn this flag off, which can be done as follows
void GLWindow::processKeyUp(
                             QKeyEvent *_event
                           )
{
  switch(_event->key())
  {
    case Qt::Key_Up: m_keysPressed &= ~kUp; break;
    case Qt::Key_Down: m_keysPressed &= ~kDown; break;
    case Qt::Key_Left: m_keysPressed &= ~kLeft; break;
    case Qt::Key_Right: m_keysPressed &= ~kRight; break;
  }
}
In this case we use the logical not ~ and the logical and to turn the bit flag off. Finally we call the move method of the SpaceShip before we draw as shown in the following method
void GLWindow::paintGL()
{
  // clear the screen and depth buffer
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  m_spaceShip.move(m_keysPressed);
  m_spaceShip.draw();
 
}
The code for this can be found here

Getting Started with the Programming Assignment Pt 3 Linking Things Together

In the previous post I created a simple SpaceShip class, to contain the state data for the Ship, I also outlined different  methods. In this post I'm going to discuss different ways of associating the classes with each other. In this case we have the SpaceShip class which contains the state data, and the Models class which will contain the actual Mesh to be draw.

I'm going to then highlight three different ways of associating the classes so the SpaceShip class can access the model and draw.

In all these version we will have an instance of the SpaceShip class created in the GLWindow class called m_spaceShip, and we need to pass the global ngl::Camera to the SpaceShip class as well as the instance of the Model class.

Pass By Reference version
In this version we are going to pass into the draw method both the model and the camera, we declare the draw prototype as follows
/// @brief draw the ship
/// @param[in] _model a reference to the model loader
/// @param[in] _cam a reference to the global camera
void draw(
          const Models &_model,
          const ngl::Camera &_cam
         );
You will now note that this method is no longer marked as const, this is because in the loadMatricesToShader method we need to access the m_transform object and grab the current matrix. This will force the transform object to calculate the transforms and mutate itself, and hence is now a non const method.
/// @brief load our matrices to OpenGL shader
/// @param[in] _cam a reference to the camera use to grab the 
/// VP part of the Matrix for drawing
void loadMatricesToShader(
                           const ngl::Camera &_cam
                         );
So the draw method will basically load the Model View Projection matrix to the shader by calling the method above we then need to access the model and call the draw method, this is shown in the following code
void SpaceShip::draw(const Models &_model, const ngl::Camera &_cam)
{
  loadMatricesToShader(_cam);
  _model.draw("spaceship");

}

void SpaceShip::loadMatricesToShader(const ngl::Camera &_cam)
{
  ngl::ShaderLib *shader=ngl::ShaderLib::instance();
  (*shader)["TextureShader"]->use();
  const ngl::Matrix MVP=m_transform.getMatrix()*_cam.getVPMatrix();
  shader->setShaderParamFromMatrix("MVP",MVP);
}
In the loadMatricesToShader method we have already loaded the shaders to the ShaderLib class and we then just call it when required. We can now use the following code in the GLWindow class to draw our SpaceShip
m_spaceShip.draw(m_model,*m_cam);
Which gives us the following
As you can see the orientation is wrong at present but I will fix that later.

Class Global Pointer Version
The next version is going to have two global pointers one for the Camera and one for the Models, these will be set in the spaceship class on construction and then used in the draw methods.

Firstly we need to add them to the SpaceShip class as follows
/// @brief the global camera
const ngl::Camera *m_camera;
/// @brief the global model store
const Models *m_models;
We now need to set these value, the best way to do this is by using the constructor, as we can guarantee that this will always be called.
/// @brief the ctor
/// @param[in] _cam the global camera
/// @param[in] _m the models 
SpaceShip(
           const ngl::Camera *_cam,
           const Models *_m
         );
If we only implement the parameterized constructor above we will force the object to be constructed using these values. In the constructor we just need to copy these values
SpaceShip::SpaceShip(
                      const ngl::Camera *_cam,
                      const Models *_m
                     )
{
  m_camera=_cam;
  m_models=_m;
  m_pos.set(0,0,0);
  m_rotation.set(0,0,0);
  m_numLives=3;
  m_shieldStrength=100;
}
Now the draw and loadMatrices to shader method signatures can change to have no parameters as shown
void SpaceShip::draw()
{
  loadMatricesToShader();
  m_models->draw("spaceship");

}

void SpaceShip::loadMatricesToShader()
{
  ngl::ShaderLib *shader=ngl::ShaderLib::instance();
  (*shader)["TextureShader"]->use();
  const ngl::Matrix MVP=m_transform.getMatrix()*m_camera->getVPMatrix();
  shader->setShaderParamFromMatrix("MVP",MVP);
}
The code to generate the Ship is now different, firstly the SpaceShip class in GLWindow.h must now be a pointer and we need to build the object once we have created our camera and models as shown below
m_cam= new ngl::Camera(From,To,Up,ngl::PERSPECTIVE);
// set the shape using FOV 45 Aspect Ratio based on Width and Height
// The final two are near and far clipping planes of 0.5 and 10
m_cam->setShape(45,(float)720.0/576.0,0.05,350,ngl::PERSPECTIVE);
 

m_model.addModel("bigrock","models/RockBig.obj","textures/rock_texture.bmp");
m_model.addModel("spike","models/RockSpike.obj","textures/rock_texture.bmp");
m_model.addModel("spaceship","models/SpaceShip.obj","textures/spaceship.bmp");


m_spaceShip = new SpaceShip(m_cam,&m_model);
Both these methods work in more or less the same way, not passing the parameters to the draw method does reduce some of the stack overhead with accessing the data however simple timing tests give both methods the same speed of approximately 60FPS
Game State Object
The final method I'm going to describe is going to use a global game object. This object will be a singleton class, it will have public attributes for the camera and the models, which must be set when the class is first used.
The SpaceShip class will then access this when required.
#ifndef __GLOBALGAMEOBJECT_H__
#define __GLOBALGAMEOBJECT_H__

#include "Models.h"
#include <ngl/Camera.h>

/// @file GlobalGameObject.h
/// @brief we use this object to pass around global game data this is a singleton
/// @author Jonathan Macey
/// @version 1.0
/// @date 13/2/12
/// @class Models
/// @brief we only put const global references in this class to pass around data used
/// by the game


class GlobalGameObject
{
  public :
    /// @brief this is a singleton class this get the current instance
    static GlobalGameObject * instance();
    /// @brief our model made public for ease of access
    const Models *m_models;
    /// @brief the global camera made public for ease of access
    const ngl::Camera *m_camera;
  private :
    /// @brief hide away the ctor as this is a singleton
    GlobalGameObject(){;}
    /// @brief hide the copy ctor
    GlobalGameObject(const GlobalGameObject &_g){Q_UNUSED(_g);}
    /// @brief hide the dtor
    ~GlobalGameObject();
    /// @brief hide the assignment operator
    GlobalGameObject operator =(const GlobalGameObject &_r){Q_UNUSED(_r);}
    /// @brief our instance pointer
    static GlobalGameObject *m_instance;
};
#endif
The main C++ code looks like this and is a standard singleton, in this case we don't have to worry about managing the lifetime of the class as it will only contain const pointers and the other classes will manage their own lifetimes
#include "GlobalGameObject.h"

GlobalGameObject* GlobalGameObject::m_instance = 0;// initialize pointer

GlobalGameObject* GlobalGameObject::instance()
{
  if (m_instance == 0)  // is it the first call?
  {
    m_instance = new GlobalGameObject; // create sole instance
  }
  return m_instance; // address of sole instance
}
To use this class we must create it in GLWindow and attach the pointers as shown
GlobalGameObject *game=GlobalGameObject::instance();
game->m_camera=m_cam;
game->m_models=&m_model;
Now in the SpaceShip class we use the following to access the models and the camera
void SpaceShip::draw()
{
  loadMatricesToShader();
  GlobalGameObject *game=GlobalGameObject::instance();
  game->m_models->draw("spaceship");
}

void SpaceShip::loadMatricesToShader()
{
  GlobalGameObject *game=GlobalGameObject::instance();
  ngl::ShaderLib *shader=ngl::ShaderLib::instance();
  (*shader)["TextureShader"]->use();
  const ngl::Matrix MVP=m_transform.getMatrix()*game->m_camera->getVPMatrix();
  shader->setShaderParamFromMatrix("MVP",MVP);
}
As you can see this method breaks some of the OO rules about encapsulation but will require less re-working of the code if we wish to change game elements or add / remove elements to be shared with the rest of the game objects. Another speed test puts this at about the same speed as the others. So there is no clear winner at present for any of the methods. All of the code for the three examples can be found here, for now I think I'm going to use the GlobalGame object method as it will make the development cycle quicker as I only need to add things to the singleton class.

Next how to move the ship

Getting Started with the Programming Assignment Pt 2 The SpaceShip

For part one see here

The main premise of the game is we are going to have a read view of a SpaceShip which the player can move around the screen in x and y. The user can also rotate the ship around the different axis.

The sketch above shows the view of the ship and the axis of rotation, the class sketch below show the initial design of the SpaceShip class

The SpaceShip will have a shield with initial value of 100% which will be changed based on the game play mechanic (for example collisions will reduce the shield and I may update the value based on collecting assets)

By default the player will have 3 ships which will be decreased based on gameplay / collisions and there will be opportunities to add more ships based on score etc.

The following class diagram is a more formal version of the above
And in code looks like this
#ifndef __SPACESHIP_H__
#define __SPACESHIP_H__

#include <ngl/Vec3.h>
#include <ngl/Transformation.h>


/// @file SpaceShip.h
/// @brief the basic spaceship class used for the game
/// @author Jonathan Macey
/// @version 1.0
/// @date 13/2/12
/// @class SpaceShip
/// @brief this class encapsulates the spaceship state, and also controls, it does
/// not have a mesh assosiated with it this is stored in the Models class

class SpaceShip
{
  public :
    /// @brief the ctor
    SpaceShip();
    /// @brief the dtor
    ~SpaceShip();
    /// @brief move this will set the position of the ship
    /// @param[in] _dx the change in the x position
    /// @param[in] _dy the change in the y position
    void move(
               float _dx,
               float _dy
             );
    /// @brief rotate the ship in the three axis
    /// @param[in] _dx the change in the x rotation
    /// @param[in] _dy the change in the y rotation
    /// @param[in] _dz the change in the z rotation
    void rotate(
                 float _dx,
                 float _dy,
                 float _dz
                );
    /// @brief draw the ship
    void draw() const;
    /// @brief get the life value
    inline int getLife() const {return m_numLives;}
    /// @brief remove life
    inline void removeLife(){m_numLives-=1;}
    /// @brief get the sheild strength
    inline int getShieldStrength()const {return m_shieldStrength;}
    /// @brief reduce the sheild strength
    inline void reduceShieldStrength(int _s){ m_shieldStrength-=_s;}

  private :
    /// @brief the position of the ship
    ngl::Vec3 m_pos;
    /// @brief the x,y,z rotation values of the ship
    ngl::Vec3 m_rotation;
    /// @brief our transformation used to load to the matrix
    ngl::Transformation m_transform;
    /// @brief load our matrices to OpenGL shader
    void loadMatricesToShader();
    /// @brief the number of lives for the ship
    /// this is set to 3 initially and will then change as the game progresses
    int m_numLives;
    /// @brief the strength of the sheild starts at 100% and reduces during the game
    /// based on collisions
    int m_shieldStrength;
};


#endif
We can now write most of the methods if we ignore the drawing elements of the class. These are as follows
SpaceShip::SpaceShip()
{
  m_pos.set(0,0,0);
  m_rotation.set(0,0,0);
  m_numLives=3;
  m_shieldStrength=100;
}


SpaceShip::~SpaceShip()
{

}

void SpaceShip::move(float _dx, float _dy)
{
  m_pos.m_x+=_dx;
  m_pos.m_y+=_dy;
}

void SpaceShip::rotate(float _dx, float _dy, float _dz)
{
  m_rotation.m_x+=_dx;
  m_rotation.m_y+=_dy;
  m_rotation.m_z+=_dz;
}
It is now possible to construct a simple SpaceShip class in the main GLWindow and use it for storing the data values for the ship However drawing the mesh for the class is going to be a lot more complex and this will be put into the next post. For now here is the basic code and part three is here

Getting Started with the Programming Assignment Pt 1

It's programming assignment time again, and I've decided this year to write a simple game to demonstrate some of the features of NGL and to show you how to go from the initial design stuff into code.

For this game I've decided to do a simple 3D style asteroid game which uses a number of obj meshes to draw the different asteroids and the ship.

The main focus on these blog posts will be the sharing of data across different classes and the stepwise refinement from the class design to writing the code.

My initial design for the system is shown below


I'm going to concentrate of the basic design of each of these classes, then implement and test them separately. The first class will be the models class.

Models
The models class is a container for the meshes, and allows us to share meshes for each of the other classes. For example in this game we will have a number of Asteroid objects, however each one will only have a single mesh. We could load a mesh for each Asteroid object we create, however this is going to be slow and wasteful of resources as we only have a limited amount of GPU memory and texture memory. Using the Models class we load all our models and textures at program startup, then each of our classes that need access to the models will have a pointer to this class and access models via it.

To store the Obj meshes I decided to use std::string name lookup and the easiest way of implementing this is to use the std::map container and use the build in iterators to access things. Another concern when designing is to ensue we have const correctness built in from the outset. In this case as we only have one method that doesn't mutate the class (the draw method) it is quite easy to do this. 

Finally I wish to ensure full documentation of the class, I will be using Doxygen to comment everything and as usual it is best to write this at the time of creating the class. The code below shows the fully .h file for the class
#ifndef __MODELS_H__
#define __MODELS_H__

#include <string>
#include <map>
#include <ngl/Obj.h>

/// @file Models.h
/// @brief a class to contain all models used in game
/// @author Jonathan Macey
/// @version 1.0
/// @date 10/2/12
/// @class Models
/// @brief this class contains all meshes required for the game level
/// we use this as we only need to load meshes once but may need to attach
/// to many objects in our game

class Models
{
public :
  /// @brief our ctor
  Models(){;}
  /// @brief our dtor this will clear the models and remove
  /// all of the meshes created
  ~Models();
  /// @brief add a mesh with no texture
  /// @param[in] the name of the model we wish to use for lookup
  /// @param[in] the path / name of the mesh
  void addModel(
                const std::string &_name,
                const std::string &_mesh
              );
  /// @brief add a mesh with a texture
  /// @param[in] the name of the model we wish to use for lookup
  /// @param[in] the path / name of the mesh
  /// @param[in] the path / name of the texture
  void addModel(
                  const std::string &_name,
                  const std::string &_mesh,
                  const std::string &_texture
               );
  /// @brief accesor to the model, incase the caller
  /// wishes to modify the mesh etc
  ngl::Obj *getModel(std::string _name);
  /// @brief method to draw the mesh, all tx must be executed before
  /// the call to draw
  /// @param[in] the name of the mesh to draw
  void draw(std::string _name) const;
private :
  /// @brief a map to hold our meshes by name
  std::map < std::string, ngl::Obj *>m_models;

};


#endif
As you can see the constructor doesn't do anything in the class, however we need to implement a destructor to call the ngl::Obj destructor and clear out all the mesh data etc.
Models::~Models()
{
  std::map <std::string,ngl::Obj *>::iterator pbegin=m_models.begin();
  std::map <std::string,ngl::Obj *>::iterator pend=m_models.end();
  while(pbegin != pend)
  {
    std::cout <<"deleting "<<pbegin->first<<"\n";
    delete pbegin->second;
    ++pbegin;
  }
}
The destructor uses the std::map::iterator to grab the front and the back of the map, we then loop through and use the ->second accessor to delete the ngl::Obj * class. The rest of the class is fairly simple, to add a mesh we use the following code
void Models::addModel(
                       const std::string &_name,
                       const std::string &_mesh,
                       const std::string &_texture
                      )
{
  ngl::Obj *mesh = new ngl::Obj(_mesh,_texture);
  mesh->createVAO(GL_STATIC_DRAW);
  mesh->calcBoundingSphere();
  m_models[_name]=mesh;
}
Finally as the draw method is const we need to use a std::map::const_iterator to access the data for drawing
void Models::draw(std::string _name) const
{
  std::map <std::string,ngl::Obj *>::const_iterator pbegin=m_models.begin();
  std::map <std::string,ngl::Obj *>::const_iterator model=m_models.find(_name);

  if(pbegin!=m_models.end() && model !=m_models.end())
  {
    model->second->draw();
  }
}
Testing
To test the class I've used one of the basic ngl:: demo programs, and added to the GLWindow.h class a simple Models m_model; object.

To load the meshes we need to first have a valid OpenGL context
m_model.addModel("bigrock","models/RockBig.obj","textures/rock_texture.bmp");
m_model.addModel("spike","models/RockSpike.obj","textures/rock_texture.bmp");
m_model.addModel("ship","models/SpaceShip.obj","textures/spaceship.bmp");
Then to draw we can use the following
switch (m_whichModel)
{
  case 0 : m_model.draw("bigrock"); break;
  case 1 : m_model.draw("spike"); break;
  case 2 : m_model.draw("ship"); break;
}
Which gives us the following


You can download the test code and class here 

Reflections on initial design
It has occurred to me, whilst writing this up that using a std::map may not be the fasted way of using this  class as we need to iterate to search by name. It may actually be better to use a std::vector and have some form of index based enumerated type to search for the models. Once I start testing the rest of the classes I will do some comparisons for speed, which will test this.