Port all benchmarks and infrastructure to the Program object.
diff --git a/src/mesh.cpp b/src/mesh.cpp
index c5dd5c0..5ff62f0 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -22,7 +22,6 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "mesh.h"
-#include "shader.h"
 
 
 Mesh::Mesh()
@@ -113,27 +112,31 @@
         }
 }
 
-void Mesh::render_array()
+void Mesh::render_array(int vertex_loc, int normal_loc, int texcoord_loc)
 {
-    // Enable the attributes
-    glEnableVertexAttribArray(OldShader::VertexAttribLocation);
-    glEnableVertexAttribArray(OldShader::NormalAttribLocation);
-    glEnableVertexAttribArray(OldShader::TexCoordAttribLocation);
+    // Enable the attributes (texcoord is optional)
+    glEnableVertexAttribArray(vertex_loc);
+    glEnableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glEnableVertexAttribArray(texcoord_loc);
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glVertexAttribPointer(OldShader::VertexAttribLocation, 3, GL_FLOAT,
-                          GL_FALSE, 8 * sizeof(float), mVertex[0].v);
-    glVertexAttribPointer(OldShader::NormalAttribLocation, 3, GL_FLOAT,
-                          GL_FALSE, 8 * sizeof(float), mVertex[0].n);
-    glVertexAttribPointer(OldShader::TexCoordAttribLocation, 2, GL_FLOAT,
-                          GL_FALSE, 8 * sizeof(float), mVertex[0].t);
+    glVertexAttribPointer(vertex_loc, 3, GL_FLOAT, GL_FALSE,
+                          8 * sizeof(float), mVertex[0].v);
+    glVertexAttribPointer(normal_loc, 3, GL_FLOAT, GL_FALSE,
+                          8 * sizeof(float), mVertex[0].n);
+    if (texcoord_loc >= 0) {
+        glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE,
+                              8 * sizeof(float), mVertex[0].t);
+    }
 
     glDrawArrays(GL_TRIANGLES, 0, mVertexQty);
 
     // Disable the attributes
-    glDisableVertexAttribArray(OldShader::TexCoordAttribLocation);
-    glDisableVertexAttribArray(OldShader::NormalAttribLocation);
-    glDisableVertexAttribArray(OldShader::VertexAttribLocation);
+    glDisableVertexAttribArray(vertex_loc);
+    glDisableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glDisableVertexAttribArray(texcoord_loc);
 }
 
 void Mesh::build_vbo()
@@ -198,24 +201,28 @@
     glDeleteBuffers(1, &mVBOTexCoords);
 }
 
-void Mesh::render_vbo()
+void Mesh::render_vbo(int vertex_loc, int normal_loc, int texcoord_loc)
 {
-    // Enable the attributes
-    glEnableVertexAttribArray(OldShader::VertexAttribLocation);
-    glEnableVertexAttribArray(OldShader::NormalAttribLocation);
-    glEnableVertexAttribArray(OldShader::TexCoordAttribLocation);
+    // Enable the attributes (texcoord is optional)
+    glEnableVertexAttribArray(vertex_loc);
+    glEnableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glEnableVertexAttribArray(texcoord_loc);
 
     glBindBuffer(GL_ARRAY_BUFFER, mVBOVertices);
-    glVertexAttribPointer(OldShader::VertexAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
+    glVertexAttribPointer(vertex_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
     glBindBuffer(GL_ARRAY_BUFFER, mVBONormals);
-    glVertexAttribPointer(OldShader::NormalAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
-    glVertexAttribPointer(OldShader::TexCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
+    glVertexAttribPointer(normal_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
+    if (texcoord_loc >= 0) {
+        glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
+        glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
+    }
 
     glDrawArrays(GL_TRIANGLES, 0, mVertexQty);
 
     // Disable the attributes
-    glDisableVertexAttribArray(OldShader::TexCoordAttribLocation);
-    glDisableVertexAttribArray(OldShader::NormalAttribLocation);
-    glDisableVertexAttribArray(OldShader::VertexAttribLocation);
+    glDisableVertexAttribArray(vertex_loc);
+    glDisableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glDisableVertexAttribArray(texcoord_loc);
 }
diff --git a/src/mesh.h b/src/mesh.h
index 49b3cd8..9a793bb 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -56,10 +56,10 @@
     void reset();
     void make_cube();
     void make_torus();
-    void render_array();
+    void render_array(int vertex_loc, int normal_loc, int texcoord_loc);
     void build_vbo();
     void delete_vbo();
-    void render_vbo();
+    void render_vbo(int vertex_loc, int normal_loc, int texcoord_loc);
 };
 
 #endif
diff --git a/src/scene.cpp b/src/scene.cpp
index 7b12c67..828a768 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -22,6 +22,7 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "scene.h"
+#include "log.h"
 #include <sstream>
 #include <cmath>
 
@@ -154,3 +155,50 @@
 
     return std::sqrt(s);
 }
+
+bool
+Scene::load_shaders(Program &program,
+                    const std::string &vtx_shader_filename,
+                    const std::string &frg_shader_filename)
+{
+    std::string vtx_shader;
+    std::string frg_shader;
+
+    if (!gotSource(vtx_shader_filename, vtx_shader))
+        return false;
+
+    if (!gotSource(frg_shader_filename, frg_shader))
+        return false;
+
+    program.init();
+
+    program.addShader(GL_VERTEX_SHADER, vtx_shader);
+    if (!program.valid()) {
+        Log::error("Failed to add vertex shader from file %s:\n  %s\n",
+                   vtx_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    program.addShader(GL_FRAGMENT_SHADER, frg_shader);
+    if (!program.valid()) {
+        Log::error("Failed to add fragment shader from file %s:\n  %s\n",
+                   frg_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    program.build();
+    if (!program.ready()) {
+        Log::error("Failed to link program created from files %s and %s:  %s\n",
+                   vtx_shader_filename.c_str(),
+                   frg_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/scene.h b/src/scene.h
index 5ba06e0..fd98855 100644
--- a/src/scene.h
+++ b/src/scene.h
@@ -29,8 +29,8 @@
 #include "mesh.h"
 #include "model.h"
 #include "texture.h"
-#include "shader.h"
 #include "vec.h"
+#include "program.h"
 
 #include <math.h>
 
@@ -91,6 +91,10 @@
 
     virtual ValidationResult validate() { return ValidationUnknown; }
 
+    static bool load_shaders(Program &program,
+                             const std::string &vtx_shader_filename,
+                             const std::string &frg_shader_filename);
+
 protected:
     Scene(Screen &pScreen, const std::string &name);
     std::string construct_title(const std::string &title);
@@ -125,7 +129,10 @@
     ~SceneBuild();
 
 protected:
-    OldShader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;
@@ -148,7 +155,10 @@
     ~SceneTexture();
 
 protected:
-    OldShader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mCubeMesh;
     GLuint mTexture;
@@ -171,7 +181,10 @@
     ~SceneShading();
 
 protected:
-    OldShader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;
diff --git a/src/scenebuild.cpp b/src/scenebuild.cpp
index b1df9bb..c8ed676 100644
--- a/src/scenebuild.cpp
+++ b/src/scenebuild.cpp
@@ -40,6 +40,8 @@
 
 int SceneBuild::load()
 {
+    static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert");
+    static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.frag");
     Model model;
 
     if(!model.load_3ds(GLMARK_DATA_PATH"/models/horse.3ds"))
@@ -48,8 +50,12 @@
     model.calculate_normals();
     model.convert_to_mesh(&mMesh);
 
-    mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                 GLMARK_DATA_PATH"/shaders/light-basic.frag");
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return 0;
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
 
     mRotationSpeed = 36.0f;
 
@@ -61,34 +67,32 @@
 void SceneBuild::unload()
 {
     mMesh.reset();
-    mShader.remove();
-    mShader.unload();
+
+    mProgram.stop();
+    mProgram.release();
 }
 
 void SceneBuild::setup()
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
-    GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
-
+    static const LibMatrix::vec4 lightAmbient(0.0f, 0.0f, 0.0f, 1.0f);
+    static const LibMatrix::vec4 lightDiffuse(0.8f, 0.8f, 0.8f, 1.0f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(1.0f, 1.0f, 1.0f, 1.0f);
 
     mUseVbo = (mOptions["use-vbo"].value == "true");
 
     if (mUseVbo)
         mMesh.build_vbo();
 
-    mShader.use();
+    mProgram.start();
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     mCurrentFrame = 0;
     mRotation = 0.0;
@@ -100,7 +104,7 @@
 void
 SceneBuild::teardown()
 {
-    mShader.remove();
+    mProgram.stop();
 
     if (mUseVbo)
         mMesh.delete_vbo();
@@ -137,20 +141,24 @@
     model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
     model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
     LibMatrix::mat4 normal_matrix(model_view.getCurrent());
     normal_matrix.inverse().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, normal_matrix);
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
-    if (mUseVbo)
-        mMesh.render_vbo();
-    else
-        mMesh.render_array();
+    if (mUseVbo) {
+        mMesh.render_vbo(mVertexAttribLocation,
+                         mNormalAttribLocation,
+                         mTexcoordAttribLocation);
+    }
+    else {
+        mMesh.render_array(mVertexAttribLocation,
+                           mNormalAttribLocation,
+                           mTexcoordAttribLocation);
+    }
 }
 
 Scene::ValidationResult
diff --git a/src/sceneshading.cpp b/src/sceneshading.cpp
index cea69da..307d7cf 100644
--- a/src/sceneshading.cpp
+++ b/src/sceneshading.cpp
@@ -68,47 +68,55 @@
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
+    static const LibMatrix::vec3 lightAmbient(0.1f, 0.1f, 0.1f);
+    static const LibMatrix::vec3 lightDiffuse(0.8f, 0.8f, 0.8f);
+    static const LibMatrix::vec3 lightSpecular(0.8f, 0.8f, 0.8f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
 
-    float materialAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialColor[] = {0.0f, 0.0f, 1.0f, 1.0f};
+    static const LibMatrix::vec3 materialAmbient(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec3 materialDiffuse(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec3 materialSpecular(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(0.0f, 0.0f, 1.0f, 1.0f);
 
+    std::string vtx_shader_filename;
+    std::string frg_shader_filename;
     const std::string &shading = mOptions["shading"].value;
 
     if (shading == "gouraud") {
-        mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                     GLMARK_DATA_PATH"/shaders/light-basic.frag");
+        vtx_shader_filename = GLMARK_DATA_PATH"/shaders/light-basic.vert";
+        frg_shader_filename = GLMARK_DATA_PATH"/shaders/light-basic.frag";
     }
     else if (shading == "phong") {
-        mShader.load(GLMARK_DATA_PATH"/shaders/light-advanced.vert",
-                     GLMARK_DATA_PATH"/shaders/light-advanced.frag");
+        vtx_shader_filename = GLMARK_DATA_PATH"/shaders/light-advanced.vert";
+        frg_shader_filename = GLMARK_DATA_PATH"/shaders/light-advanced.frag";
     }
 
-    mShader.use();
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return;
+
+    mProgram.start();
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(lightSpecular, "LightSourceSpecular");
 
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-    glUniform3fv(mShader.mLocations.LightSourceSpecular, 1, lightSpecular);
-
-    glUniform3fv(mShader.mLocations.MaterialAmbient, 1, materialAmbient);
-    glUniform3fv(mShader.mLocations.MaterialDiffuse, 1, materialDiffuse);
-    glUniform3fv(mShader.mLocations.MaterialSpecular, 1, materialSpecular);
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(materialAmbient, "MaterialAmbient");
+    mProgram.loadUniformVector(materialDiffuse, "MaterialDiffuse");
+    mProgram.loadUniformVector(materialSpecular, "MaterialSpecular");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     // Calculate and load the half vector
     LibMatrix::vec3 halfVector(lightPosition[0], lightPosition[1], lightPosition[2]);
     halfVector.normalize();
     halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
     halfVector.normalize();
-    glUniform3fv(mShader.mLocations.LightSourceHalfVector, 1, halfVector);
+    mProgram.loadUniformVector(halfVector, "LightSourceHalfVector");
 
     mCurrentFrame = 0;
     mRotation = 0.0f;
@@ -119,8 +127,8 @@
 
 void SceneShading::teardown()
 {
-    mShader.remove();
-    mShader.unload();
+    mProgram.stop();
+    mProgram.release();
 
     Scene::teardown();
 }
@@ -153,17 +161,17 @@
     model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
     model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
     LibMatrix::mat4 normal_matrix(model_view.getCurrent());
     normal_matrix.inverse().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, normal_matrix);
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
-    mMesh.render_vbo();
+    mMesh.render_vbo(mVertexAttribLocation,
+                     mNormalAttribLocation,
+                     mTexcoordAttribLocation);
 }
 
 Scene::ValidationResult
diff --git a/src/scenetexture.cpp b/src/scenetexture.cpp
index 0701450..9d7b0fe 100644
--- a/src/scenetexture.cpp
+++ b/src/scenetexture.cpp
@@ -27,6 +27,7 @@
 #include "vec.h"
 #include "log.h"
 
+#include "program.h"
 #include <cmath>
 
 SceneTexture::SceneTexture(Screen &pScreen) :
@@ -42,6 +43,8 @@
 
 int SceneTexture::load()
 {
+    static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert");
+    static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic-tex.frag");
     Model model;
 
     if(!model.load_3ds(GLMARK_DATA_PATH"/models/cube.3ds"))
@@ -51,8 +54,12 @@
     model.convert_to_mesh(&mCubeMesh);
     mCubeMesh.build_vbo();
 
-    mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                 GLMARK_DATA_PATH"/shaders/light-basic-tex.frag");
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return 0;
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
 
     mRotationSpeed = LibMatrix::vec3(36.0f, 36.0f, 36.0f);
 
@@ -64,17 +71,19 @@
 void SceneTexture::unload()
 {
     mCubeMesh.reset();
-    mShader.unload();
+
+    mProgram.stop();
+    mProgram.release();
 }
 
 void SceneTexture::setup()
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
-    GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
+    static const LibMatrix::vec4 lightAmbient(0.0f, 0.0f, 0.0f, 1.0f);
+    static const LibMatrix::vec4 lightDiffuse(0.8f, 0.8f, 0.8f, 1.0f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(1.0f, 1.0f, 1.0f, 1.0f);
 
     // Create texture according to selected filtering
     GLint min_filter = GL_NONE;
@@ -97,15 +106,13 @@
     Texture::load(GLMARK_DATA_PATH"/textures/crate-base.bmp", &mTexture,
                   min_filter, mag_filter, 0);
 
-    mShader.use();
+    mProgram.start();
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     mCurrentFrame = 0;
     mRotation = LibMatrix::vec3();
@@ -116,7 +123,7 @@
 
 void SceneTexture::teardown()
 {
-    mShader.remove();
+    mProgram.stop();
     glDeleteTextures(1, &mTexture);
 
     Scene::teardown();
@@ -152,20 +159,20 @@
     model_view.rotate(mRotation.z(), 0.0f, 0.0f, 1.0f);
     model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
     LibMatrix::mat4 normal_matrix(model_view.getCurrent());
     normal_matrix.inverse().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, normal_matrix);
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture);
 
-    mCubeMesh.render_vbo();
+    mCubeMesh.render_vbo(mVertexAttribLocation,
+                         mNormalAttribLocation,
+                         mTexcoordAttribLocation);
 }
 
 Scene::ValidationResult