diff mbox

[Branch,~afrantzis/glmark2/trunk] Rev 97: Merge refactoring of Mesh class.

Message ID 20110704132820.21943.83721.launchpad@loganberry.canonical.com
State Accepted
Headers show

Commit Message

alexandros.frantzis@linaro.org July 4, 2011, 1:28 p.m. UTC
Merge authors:
  Alexandros Frantzis (afrantzis)
------------------------------------------------------------
revno: 97 [merge]
committer: Alexandros Frantzis <alexandros.frantzis@linaro.org>
branch nick: trunk
timestamp: Mon 2011-07-04 13:34:07 +0300
message:
  Merge refactoring of Mesh class.
modified:
  src/mesh.cpp
  src/mesh.h
  src/model.cpp
  src/model.h
  src/scene-build.cpp
  src/scene-shading.cpp
  src/scene-texture.cpp
  src/scene.h


--
lp:glmark2
https://code.launchpad.net/~afrantzis/glmark2/trunk

You are subscribed to branch lp:glmark2.
To unsubscribe from this branch go to https://code.launchpad.net/~afrantzis/glmark2/trunk/+edit-subscription
diff mbox

Patch

=== modified file 'src/mesh.cpp'
--- src/mesh.cpp	2011-06-21 12:38:07 +0000
+++ src/mesh.cpp	2011-07-04 10:33:31 +0000
@@ -22,12 +22,11 @@ 
  *  Alexandros Frantzis (glmark2)
  */
 #include "mesh.h"
+#include "log.h"
 
 
 Mesh::Mesh() :
-    mVertexQty(0), mPolygonQty(0),
-    mMode(GL_TRIANGLES), mVertex(0),
-    mVBOVertices(0), mVBONormals(0), mVBOTexCoords(0)
+    vertex_size_(0)
 {
 }
 
@@ -36,189 +35,341 @@ 
     reset();
 }
 
+/*
+ * Sets the vertex format for this mesh.
+ *
+ * The format consists of a vector of integers, each
+ * specifying the size in floats of each vertex attribute.
+ *
+ * e.g. {4, 3, 2} => 3 attributes vec4, vec3, vec2
+ */
+void
+Mesh::set_vertex_format(const std::vector<int> &format)
+{
+    int pos = 0;
+    vertex_format_.clear();
+
+    for (std::vector<int>::const_iterator iter = format.begin();
+         iter != format.end();
+         iter++)
+    {
+        int n = *iter;
+        vertex_format_.push_back(std::pair<int,int>(n, pos));
+
+        pos += n;
+    }
+
+    vertex_size_ = pos;
+}
+
+/*
+ * Sets the attribute locations.
+ *
+ * These are the locations used in glEnableVertexAttribArray()
+ * and other related functions.
+ */
+void
+Mesh::set_attrib_locations(const std::vector<int> &locations)
+{
+    if (locations.size() != vertex_format_.size())
+        Log::error("Trying to set attribute locations using wrong size\n");
+    attrib_locations_ = locations;
+}
+
+
+bool
+Mesh::check_attrib(int pos, int size)
+{
+    if (pos > (int)vertex_format_.size()) {
+        Log::error("Trying to set non-existent attribute\n");
+        return false;
+    }
+
+    if (vertex_format_[pos].first != size) {
+        Log::error("Trying to set attribute with value of invalid type\n");
+        return false;
+    }
+
+    return true;
+}
+
+
+std::vector<float> &
+Mesh::ensure_vertex()
+{
+    if (vertices_.empty())
+        next_vertex();
+
+    return vertices_.back();
+}
+
+/*
+ * Sets the value of an attribute in the current vertex.
+ *
+ * The pos parameter refers to the position of the attribute
+ * as specified indirectly when setting the format using
+ * set_vertex_format(). e.g. 0 = first attribute, 1 = second
+ * etc
+ */
+void
+Mesh::set_attrib(int pos, const LibMatrix::vec2 &v, std::vector<float> *vertex)
+{
+    if (!check_attrib(pos, 2))
+        return;
+
+    std::vector<float> &vtx = !vertex ? ensure_vertex() : *vertex;
+
+    int offset = vertex_format_[pos].second;
+
+    vtx[offset] = v.x();
+    vtx[offset + 1] = v.y();
+}
+
+void
+Mesh::set_attrib(int pos, const LibMatrix::vec3 &v, std::vector<float> *vertex)
+{
+    if (!check_attrib(pos, 3))
+        return;
+
+    std::vector<float> &vtx = !vertex ? ensure_vertex() : *vertex;
+
+    int offset = vertex_format_[pos].second;
+
+    vtx[offset] = v.x();
+    vtx[offset + 1] = v.y();
+    vtx[offset + 2] = v.z();
+}
+
+void
+Mesh::set_attrib(int pos, const LibMatrix::vec4 &v, std::vector<float> *vertex)
+{
+    if (!check_attrib(pos, 4))
+        return;
+
+    std::vector<float> &vtx = !vertex ? ensure_vertex() : *vertex;
+
+    int offset = vertex_format_[pos].second;
+
+    vtx[offset] = v.x();
+    vtx[offset + 1] = v.y();
+    vtx[offset + 2] = v.z();
+    vtx[offset + 3] = v.w();
+}
+
+/*
+ * Adds a new vertex to the list and makes it current.
+ */
+void
+Mesh::next_vertex()
+{
+    vertices_.push_back(std::vector<float>(vertex_size_));
+}
+
 void
 Mesh::reset()
 {
-    delete [] mVertex;
-
+    delete_array();
     delete_vbo();
 
-    mPolygonQty = 0;
-    mVertexQty = 0;
-    mMode = GL_TRIANGLES;
-    mVertex = 0;
-}
-
-void Mesh::make_cube()
-{
-    fprintf(stderr, "Warning: %s: Not implemented\n", __FUNCTION__);
-}
-
-void Mesh::make_torus()
-{
-    unsigned wraps_qty = 64;
-    unsigned per_wrap_qty = 64;
-    float major_radius = 0.8;
-    float minor_radius = 0.4;
-    unsigned i, j;
-    unsigned k = 0;
-
-    LibMatrix::vec3 a, b, c, d, n;
-
-    mMode = GL_TRIANGLES;
-    mVertexQty = wraps_qty * per_wrap_qty * 6;
-    mVertex = new Vertex[mVertexQty];
-
-    for(i = 0; i < wraps_qty; i++)
-        for(j = 0; j < per_wrap_qty; j++)
-        {
-            float wrap_frac = j / (float)per_wrap_qty;
-            float phi = 2 * M_PI * wrap_frac;
-            float theta = 2 * M_PI * (i + wrap_frac) / (float)wraps_qty;
-            float r = major_radius + minor_radius * (float)cos(phi);
-            a.x((float)sin(theta) * r);
-            a.y(minor_radius * (float)sin(phi));
-            a.z((float)cos(theta) * r);
-
-            theta = 2 * M_PI * (i + wrap_frac + 1) / (float)wraps_qty;
-            b.x((float)sin(theta) * r);
-            b.y(minor_radius * (float)sin(phi));
-            b.z((float)cos(theta) * r);
-
-            wrap_frac = (j + 1) / (float)per_wrap_qty;
-            phi = 2 * M_PI * wrap_frac;
-            theta = 2 * M_PI * (i + wrap_frac) / (float)wraps_qty;
-            r = major_radius + minor_radius * (float)cos(phi);
-            c.x((float)sin(theta) * r);
-            c.y(minor_radius * (float)sin(phi));
-            c.z((float)cos(theta) * r);
-
-            theta = 2 * M_PI * (i + wrap_frac + 1) / (float)wraps_qty;
-            d.x((float)sin(theta) * r);
-            d.y(minor_radius * (float)sin(phi));
-            d.z((float)cos(theta) * r);
-
-            n = LibMatrix::vec3::cross(b - a, c - a);
-            n.normalize();
-            mVertex[k].n = n;   mVertex[k].v = a;   k++;
-            mVertex[k].n = n;   mVertex[k].v = b;   k++;
-            mVertex[k].n = n;   mVertex[k].v = c;   k++;
-            n = LibMatrix::vec3::cross(c - b, d - b);
-            n.normalize();
-            mVertex[k].n = n;   mVertex[k].v = b;   k++;
-            mVertex[k].n = n;   mVertex[k].v = c;   k++;
-            mVertex[k].n = n;   mVertex[k].v = d;   k++;
-        }
-}
-
-void Mesh::render_array(int vertex_loc, int normal_loc, int texcoord_loc)
-{
-    // 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(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(vertex_loc);
-    glDisableVertexAttribArray(normal_loc);
-    if (texcoord_loc >= 0)
-        glDisableVertexAttribArray(texcoord_loc);
-}
-
-void Mesh::build_vbo()
-{
-    float *vertex;
-    float *texel;
-    float *normal;
-
-    vertex = new float[mVertexQty * 3];
-    texel = new float[mVertexQty * 2];
-    normal = new float[mVertexQty * 3];
-
-    for(unsigned i = 0; i < mVertexQty; i++)
-    {
-        vertex[3 * i] = mVertex[i].v.x();
-        vertex[3 * i + 1] = mVertex[i].v.y();
-        vertex[3 * i + 2] = mVertex[i].v.z();
-        texel[2 * i] = mVertex[i].t.x();
-        texel[2 * i + 1] = mVertex[i].t.y();
-        normal[3 * i] = mVertex[i].n.x();
-        normal[3 * i + 1] = mVertex[i].n.y();
-        normal[3 * i + 2] = mVertex[i].n.z();
-    }
-
-    // Generate And Bind The Vertex Buffer
-    glGenBuffers(1, &mVBOVertices);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBOVertices);
-    // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 3 * sizeof(float), vertex, GL_STATIC_DRAW);
-
-    // Generate And Bind The normal Buffer
-    glGenBuffers(1, &mVBONormals);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBONormals);
-    // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 3 * sizeof(float), normal, GL_STATIC_DRAW);
-
-    // Generate And Bind The Texture Coordinate Buffer
-    glGenBuffers(1, &mVBOTexCoords);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
-    // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 2 * sizeof(float), texel, GL_STATIC_DRAW);
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-    delete [] vertex;
-    delete [] texel;
-    delete [] normal;
+    vertices_.clear();
+    vertex_format_.clear();
+    attrib_locations_.clear();
+    attrib_data_ptr_.clear();
+    vertex_size_ = 0;
+    vertex_stride_ = 0;
+}
+
+void
+Mesh::build_array(bool interleaved)
+{
+    int nvertices = vertices_.size();
+
+    if (!interleaved) {
+        /* Create an array for each attribute */
+        for (std::vector<std::pair<int, int> >::const_iterator ai = vertex_format_.begin();
+             ai != vertex_format_.end();
+             ai++)
+        {
+            float *array = new float[nvertices * ai->first];
+            float *cur = array;
+
+            /* Fill in the array */
+            for (std::vector<std::vector<float> >::const_iterator vi = vertices_.begin();
+                    vi != vertices_.end();
+                    vi++)
+            {
+                for (int i = 0; i < ai->first; i++)
+                    *cur++ = (*vi)[ai->second + i];
+            }
+
+            vertex_arrays_.push_back(array);
+            attrib_data_ptr_.push_back(array);
+        }
+        vertex_stride_ = 0;
+    }
+    else {
+        float *array = new float[nvertices * vertex_size_];
+        float *cur = array;
+
+        for (std::vector<std::vector<float> >::const_iterator vi = vertices_.begin();
+             vi != vertices_.end();
+             vi++)
+        {
+            /* Fill in the array */
+            for (int i = 0; i < vertex_size_; i++)
+                *cur++ = (*vi)[i];
+        }
+
+        for (size_t i = 0; i < vertex_format_.size(); i++)
+            attrib_data_ptr_.push_back(array + vertex_format_[i].second);
+
+        vertex_arrays_.push_back(array);
+        vertex_stride_ = vertex_size_ * sizeof(float);
+    }
+}
+
+void
+Mesh::build_vbo(bool interleave)
+{
+    delete_array();
+    build_array(interleave);
+
+    int nvertices = vertices_.size();
+
+    attrib_data_ptr_.clear();
+
+    if (!interleave) {
+        /* Create a vbo for each attribute */
+        for (std::vector<std::pair<int, int> >::const_iterator ai = vertex_format_.begin();
+             ai != vertex_format_.end();
+             ai++)
+        {
+            float *data = vertex_arrays_[ai - vertex_format_.begin()];
+            GLuint vbo;
+
+            glGenBuffers(1, &vbo);
+            glBindBuffer(GL_ARRAY_BUFFER, vbo);
+            glBufferData(GL_ARRAY_BUFFER, nvertices * ai->first * sizeof(float),
+                         data, GL_STATIC_DRAW);
+
+            vbos_.push_back(vbo);
+            attrib_data_ptr_.push_back(0);
+        }
+
+        vertex_stride_ = 0;
+    }
+    else {
+        GLuint vbo;
+        /* Create a single vbo to store all attribute data */
+        glGenBuffers(1, &vbo);
+        glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+        glBufferData(GL_ARRAY_BUFFER, nvertices * vertex_size_ * sizeof(float),
+                     vertex_arrays_[0], GL_STATIC_DRAW);
+
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+        for (size_t i = 0; i < vertex_format_.size(); i++) {
+            attrib_data_ptr_.push_back(reinterpret_cast<float *>(sizeof(float) * vertex_format_[i].second));
+            vbos_.push_back(vbo);
+        }
+        vertex_stride_ = vertex_size_ * sizeof(float);
+    }
+
+    delete_array();
+}
+
+void
+Mesh::delete_array()
+{
+    for (size_t i = 0; i < vertex_arrays_.size(); i++) {
+        delete [] vertex_arrays_[i];
+    }
+
+    vertex_arrays_.clear();
 }
 
 void
 Mesh::delete_vbo()
 {
-    glDeleteBuffers(1, &mVBOVertices);
-    glDeleteBuffers(1, &mVBONormals);
-    glDeleteBuffers(1, &mVBOTexCoords);
-
-    mVBOVertices = 0;
-    mVBONormals = 0;
-    mVBOTexCoords = 0;
-}
-
-void Mesh::render_vbo(int vertex_loc, int normal_loc, int texcoord_loc)
-{
-    // 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(vertex_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBONormals);
-    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(vertex_loc);
-    glDisableVertexAttribArray(normal_loc);
-    if (texcoord_loc >= 0)
-        glDisableVertexAttribArray(texcoord_loc);
+    for (size_t i = 0; i < vbos_.size(); i++) {
+        GLuint vbo = vbos_[i];
+        glDeleteBuffers(1, &vbo);
+    }
+
+    vbos_.clear();
+}
+
+
+void
+Mesh::render_array()
+{
+    for (size_t i = 0; i < vertex_format_.size(); i++) {
+        glEnableVertexAttribArray(attrib_locations_[i]);
+        glVertexAttribPointer(attrib_locations_[i], vertex_format_[i].first,
+                              GL_FLOAT, GL_FALSE, vertex_stride_,
+                              attrib_data_ptr_[i]);
+    }
+
+    glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
+
+    for (size_t i = 0; i < vertex_format_.size(); i++) {
+        glDisableVertexAttribArray(attrib_locations_[i]);
+    }
+}
+
+void
+Mesh::render_vbo()
+{
+    for (size_t i = 0; i < vertex_format_.size(); i++) {
+        glEnableVertexAttribArray(attrib_locations_[i]);
+        glBindBuffer(GL_ARRAY_BUFFER, vbos_[i]);
+        glVertexAttribPointer(attrib_locations_[i], vertex_format_[i].first,
+                              GL_FLOAT, GL_FALSE, vertex_stride_,
+                              attrib_data_ptr_[i]);
+    }
+
+    glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
+
+    for (size_t i = 0; i < vertex_format_.size(); i++) {
+        glDisableVertexAttribArray(attrib_locations_[i]);
+    }
+}
+
+void
+Mesh::make_grid(int n_x, int n_y, double width, double height,
+                double spacing, grid_configuration_func conf_func)
+{
+    double side_width = (width - (n_x - 1) * spacing) / n_x;
+    double side_height = (height - (n_y - 1) * spacing) / n_y;
+
+    for (int i = 0; i < n_x; i++) {
+        for (int j = 0; j < n_y; j++) {
+            LibMatrix::vec3 a(-width / 2 + i * (side_width + spacing),
+                              height / 2 - j * (side_height + spacing), 0);
+            LibMatrix::vec3 b(a.x(), a.y() - side_height, 0);
+            LibMatrix::vec3 c(a.x() + side_width, a.y(), 0);
+            LibMatrix::vec3 d(a.x() + side_width, a.y() - side_height, 0);
+
+            std::vector<float> ul(vertex_size_);
+            std::vector<float> ur(vertex_size_);
+            std::vector<float> ll(vertex_size_);
+            std::vector<float> lr(vertex_size_);
+
+            set_attrib(0, a, &ul);
+            set_attrib(0, c, &ur);
+            set_attrib(0, b, &ll);
+            set_attrib(0, d, &lr);
+
+            if (conf_func != 0)
+                conf_func(*this, i, j, n_x, n_y, ul, ur, lr, ll);
+
+            next_vertex(); vertices_.back() = ul;
+            next_vertex(); vertices_.back() = ll;
+            next_vertex(); vertices_.back() = ur;
+            next_vertex(); vertices_.back() = ll;
+            next_vertex(); vertices_.back() = lr;
+            next_vertex(); vertices_.back() = ur;
+        }
+    }
 }

=== modified file 'src/mesh.h'
--- src/mesh.h	2011-06-30 08:38:35 +0000
+++ src/mesh.h	2011-07-04 10:33:31 +0000
@@ -29,37 +29,54 @@ 
 
 #include <stdio.h>
 #include <math.h>
-
-struct Vertex {
-    LibMatrix::vec3 v;
-    LibMatrix::vec3 n;
-    LibMatrix::vec2 t;
-};
-
-// Data for a mesh to be rendered by vertex arrays' or vbos' has 3 verticies per
-// polygon and no polygonal data
+#include <vector>
+
 class Mesh
 {
 public:
-    unsigned mVertexQty;         // Quantity of Verticies
-    unsigned mPolygonQty;        // Quantity of polygons, not really needed
-    GLenum mMode;           // Polygon mode, eg GL_QUADS, GL_TRIANGLES etc...
-    Vertex *mVertex;        // Storage for the verticies
-
-    GLuint mVBOVertices;    // Vertex VBO name
-    GLuint mVBONormals;     // Texture coordinate VBO name
-    GLuint mVBOTexCoords;   // Texture coordinate VBO name
-
-    Mesh();                 // Default Constructor, should set pointers to null
+    Mesh();
     ~Mesh();
 
+    void set_vertex_format(const std::vector<int> &format);
+    void set_attrib_locations(const std::vector<int> &locations);
+
+    void set_attrib(int pos, const LibMatrix::vec2 &v, std::vector<float> *vertex = 0);
+    void set_attrib(int pos, const LibMatrix::vec3 &v, std::vector<float> *vertex = 0);
+    void set_attrib(int pos, const LibMatrix::vec4 &v, std::vector<float> *vertex = 0);
+    void next_vertex();
+
     void reset();
-    void make_cube();
-    void make_torus();
-    void render_array(int vertex_loc, int normal_loc, int texcoord_loc);
-    void build_vbo();
+    void build_array(bool interleaved = false);
+    void build_vbo(bool interleaved = false);
+    void delete_array();
     void delete_vbo();
-    void render_vbo(int vertex_loc, int normal_loc, int texcoord_loc);
+
+    void render_array();
+    void render_vbo();
+
+    typedef void (*grid_configuration_func)(Mesh &mesh, int x, int y, int n_x, int n_y,
+                                            std::vector<float> &upper_left,
+                                            std::vector<float> &upper_right,
+                                            std::vector<float> &lower_right,
+                                            std::vector<float> &lower_left);
+
+    void make_grid(int n_x, int n_y, double width, double height,
+                   double spacing, grid_configuration_func conf_func = 0);
+
+private:
+    bool check_attrib(int pos, int size);
+    std::vector<float> &ensure_vertex();
+
+    std::vector<std::pair<int, int> > vertex_format_;
+    std::vector<int> attrib_locations_;
+    int vertex_size_;
+
+    std::vector<std::vector<float> > vertices_;
+
+    std::vector<float *> vertex_arrays_;
+    std::vector<GLuint> vbos_;
+    std::vector<float *> attrib_data_ptr_;
+    int vertex_stride_;
 };
 
 #endif

=== modified file 'src/model.cpp'
--- src/model.cpp	2011-06-24 09:24:40 +0000
+++ src/model.cpp	2011-07-01 15:31:27 +0000
@@ -46,29 +46,67 @@ 
     delete [] mPolygon;
 }
 
-void Model::convert_to_mesh(Mesh *pMesh)
-{
-    pMesh->reset();
-
-    pMesh->mVertexQty = 3 * mPolygonQty;
-    pMesh->mPolygonQty = mPolygonQty;
-    pMesh->mMode = GL_TRIANGLES;
-
-    pMesh->mVertex = new Vertex[pMesh->mVertexQty];
-
-    for(unsigned i = 0; i < pMesh->mVertexQty; i += 3)
-    {
-        pMesh->mVertex[i + 0].v = mVertex[mPolygon[i / 3].mA].v;
-        pMesh->mVertex[i + 1].v = mVertex[mPolygon[i / 3].mB].v;
-        pMesh->mVertex[i + 2].v = mVertex[mPolygon[i / 3].mC].v;
-
-        pMesh->mVertex[i + 0].n = mVertex[mPolygon[i / 3].mA].n;
-        pMesh->mVertex[i + 1].n = mVertex[mPolygon[i / 3].mB].n;
-        pMesh->mVertex[i + 2].n = mVertex[mPolygon[i / 3].mC].n;
-
-        pMesh->mVertex[i + 0].t = mVertex[mPolygon[i / 3].mA].t;
-        pMesh->mVertex[i + 1].t = mVertex[mPolygon[i / 3].mB].t;
-        pMesh->mVertex[i + 2].t = mVertex[mPolygon[i / 3].mC].t;
+void Model::convert_to_mesh(Mesh &mesh)
+{
+    std::vector<std::pair<AttribType, int> > attribs;
+
+    attribs.push_back(std::pair<AttribType, int>(AttribTypePosition, 3));
+    attribs.push_back(std::pair<AttribType, int>(AttribTypeNormal, 3));
+    attribs.push_back(std::pair<AttribType, int>(AttribTypeTexcoord, 2));
+
+    convert_to_mesh(mesh, attribs);
+}
+
+void Model::convert_to_mesh(Mesh &mesh,
+                            const std::vector<std::pair<AttribType, int> > &attribs)
+{
+    std::vector<int> format;
+    int p_pos = -1;
+    int n_pos = -1;
+    int t_pos = -1;
+
+    mesh.reset();
+
+    for (std::vector<std::pair<AttribType, int> >::const_iterator ai = attribs.begin();
+         ai != attribs.end();
+         ai++)
+    {
+        format.push_back(ai->second);
+        if (ai->first == AttribTypePosition)
+            p_pos = ai - attribs.begin();
+        else if (ai->first == AttribTypeNormal)
+            n_pos = ai - attribs.begin();
+        else if (ai->first == AttribTypeTexcoord)
+            t_pos = ai - attribs.begin();
+    }
+
+    mesh.set_vertex_format(format);
+
+    for(unsigned i = 0; i < 3 * mPolygonQty; i += 3)
+    {
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, mVertex[mPolygon[i / 3].mA].v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, mVertex[mPolygon[i / 3].mA].n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, mVertex[mPolygon[i / 3].mA].t);
+
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, mVertex[mPolygon[i / 3].mB].v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, mVertex[mPolygon[i / 3].mB].n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, mVertex[mPolygon[i / 3].mB].t);
+
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, mVertex[mPolygon[i / 3].mC].v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, mVertex[mPolygon[i / 3].mC].n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, mVertex[mPolygon[i / 3].mC].t);
     }
 }
 

=== modified file 'src/model.h'
--- src/model.h	2011-01-25 15:06:04 +0000
+++ src/model.h	2011-07-01 15:31:27 +0000
@@ -29,6 +29,7 @@ 
 #include <sys/stat.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <vector>
 
 class Polygon
 {
@@ -37,6 +38,13 @@ 
     unsigned short mFaceFlags;
 };
 
+struct Vertex {
+    LibMatrix::vec3 v;
+    LibMatrix::vec3 n;
+    LibMatrix::vec2 t;
+};
+
+
 // A model as loaded from a 3ds file
 class Model
 {
@@ -47,6 +55,13 @@ 
     Polygon *mPolygon;
     char mName[20];
 
+    typedef enum {
+        AttribTypePosition = 1,
+        AttribTypeNormal = 2,
+        AttribTypeTexcoord = 4,
+        AttribTypeCustom = 8
+    } AttribType;
+
     Model();
     ~Model();
 
@@ -54,7 +69,9 @@ 
     void calculate_normals();
     void center();
     void scale(GLfloat pAmount);
-    void convert_to_mesh(Mesh *pMesh);
+    void convert_to_mesh(Mesh &mesh);
+    void convert_to_mesh(Mesh &mesh, 
+                         const std::vector<std::pair<AttribType, int> > &attribs);
 };
 
 #endif

=== modified file 'src/scene-build.cpp'
--- src/scene-build.cpp	2011-06-30 15:07:34 +0000
+++ src/scene-build.cpp	2011-07-01 16:56:27 +0000
@@ -32,6 +32,8 @@ 
 {
     mOptions["use-vbo"] = Scene::Option("use-vbo", "true",
                                         "Whether to use VBOs for rendering [true,false]");
+    mOptions["interleave"] = Scene::Option("interleave", "false",
+                                           "Whether to interleave vertex attribute data [true,false]");
 }
 
 SceneBuild::~SceneBuild()
@@ -48,14 +50,21 @@ 
         return 0;
 
     model.calculate_normals();
-    model.convert_to_mesh(&mMesh);
+
+    /* Tell the converter that we only care about position and normal attributes */
+    std::vector<std::pair<Model::AttribType, int> > attribs;
+    attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
+    attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
+
+    model.convert_to_mesh(mMesh, attribs);
 
     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");
+    std::vector<GLint> attrib_locations;
+    attrib_locations.push_back(mProgram.getAttribIndex("position"));
+    attrib_locations.push_back(mProgram.getAttribIndex("normal"));
+    mMesh.set_attrib_locations(attrib_locations);
 
     mRotationSpeed = 36.0f;
 
@@ -82,9 +91,12 @@ 
     static const LibMatrix::vec4 materialColor(1.0f, 1.0f, 1.0f, 1.0f);
 
     mUseVbo = (mOptions["use-vbo"].value == "true");
+    bool interleave = (mOptions["interleave"].value == "true");
 
     if (mUseVbo)
-        mMesh.build_vbo();
+        mMesh.build_vbo(interleave);
+    else
+        mMesh.build_array(interleave);
 
     mProgram.start();
 
@@ -108,6 +120,8 @@ 
 
     if (mUseVbo)
         mMesh.delete_vbo();
+    else
+        mMesh.delete_array();
 
     Scene::teardown();
 }
@@ -150,14 +164,10 @@ 
     mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
     if (mUseVbo) {
-        mMesh.render_vbo(mVertexAttribLocation,
-                         mNormalAttribLocation,
-                         mTexcoordAttribLocation);
+        mMesh.render_vbo();
     }
     else {
-        mMesh.render_array(mVertexAttribLocation,
-                           mNormalAttribLocation,
-                           mTexcoordAttribLocation);
+        mMesh.render_array();
     }
 }
 

=== modified file 'src/scene-shading.cpp'
--- src/scene-shading.cpp	2011-06-30 15:07:34 +0000
+++ src/scene-shading.cpp	2011-07-01 15:31:27 +0000
@@ -48,7 +48,13 @@ 
         return 0;
 
     model.calculate_normals();
-    model.convert_to_mesh(&mMesh);
+
+    /* Tell the converter that we only care about position and normal attributes */
+    std::vector<std::pair<Model::AttribType, int> > attribs;
+    attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
+    attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
+
+    model.convert_to_mesh(mMesh, attribs);
 
     mMesh.build_vbo();
 
@@ -96,9 +102,10 @@ 
 
     mProgram.start();
 
-    mVertexAttribLocation = mProgram.getAttribIndex("position");
-    mNormalAttribLocation = mProgram.getAttribIndex("normal");
-    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
+    std::vector<GLint> attrib_locations;
+    attrib_locations.push_back(mProgram.getAttribIndex("position"));
+    attrib_locations.push_back(mProgram.getAttribIndex("normal"));
+    mMesh.set_attrib_locations(attrib_locations);
 
     // Load lighting and material uniforms
     mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
@@ -169,9 +176,7 @@ 
     normal_matrix.inverse().transpose();
     mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
-    mMesh.render_vbo(mVertexAttribLocation,
-                     mNormalAttribLocation,
-                     mTexcoordAttribLocation);
+    mMesh.render_vbo();
 }
 
 Scene::ValidationResult

=== modified file 'src/scene-texture.cpp'
--- src/scene-texture.cpp	2011-06-30 15:07:34 +0000
+++ src/scene-texture.cpp	2011-07-01 14:25:12 +0000
@@ -51,15 +51,17 @@ 
         return 0;
 
     model.calculate_normals();
-    model.convert_to_mesh(&mCubeMesh);
+    model.convert_to_mesh(mCubeMesh);
     mCubeMesh.build_vbo();
 
     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");
+    std::vector<GLint> attrib_locations;
+    attrib_locations.push_back(mProgram.getAttribIndex("position"));
+    attrib_locations.push_back(mProgram.getAttribIndex("normal"));
+    attrib_locations.push_back(mProgram.getAttribIndex("texcoord"));
+    mCubeMesh.set_attrib_locations(attrib_locations);
 
     mRotationSpeed = LibMatrix::vec3(36.0f, 36.0f, 36.0f);
 
@@ -170,9 +172,7 @@ 
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture);
 
-    mCubeMesh.render_vbo(mVertexAttribLocation,
-                         mNormalAttribLocation,
-                         mTexcoordAttribLocation);
+    mCubeMesh.render_vbo();
 }
 
 Scene::ValidationResult

=== modified file 'src/scene.h'
--- src/scene.h	2011-06-30 13:33:37 +0000
+++ src/scene.h	2011-07-01 14:23:43 +0000
@@ -148,9 +148,6 @@ 
 
 protected:
     Program mProgram;
-    int mVertexAttribLocation;
-    int mNormalAttribLocation;
-    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;
@@ -174,9 +171,6 @@ 
 
 protected:
     Program mProgram;
-    int mVertexAttribLocation;
-    int mNormalAttribLocation;
-    int mTexcoordAttribLocation;
 
     Mesh mCubeMesh;
     GLuint mTexture;
@@ -200,9 +194,6 @@ 
 
 protected:
     Program mProgram;
-    int mVertexAttribLocation;
-    int mNormalAttribLocation;
-    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;