diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 260: Merge of lp:~glmark2-dev/glmark2/obj-update

Message ID 20130201172711.3242.68696.launchpad@ackee.canonical.com
State Accepted
Headers show

Commit Message

Jesse Barker Feb. 1, 2013, 5:27 p.m. UTC
Merge authors:
  Jesse Barker (jesse-barker)
Related merge proposals:
  https://code.launchpad.net/~glmark2-dev/glmark2/obj-update/+merge/145746
  proposed by: Jesse Barker (jesse-barker)
  review: Approve - Alexandros Frantzis (afrantzis)
------------------------------------------------------------
revno: 260 [merge]
committer: Jesse Barker <jesse.barker@linaro.org>
branch nick: trunk
timestamp: Fri 2013-02-01 09:21:16 -0800
message:
  Merge of lp:~glmark2-dev/glmark2/obj-update
  
  Model: Adds more general support of the Wavefront .obj file format.  We still
  only support triangular faces (the format itself allows for arbitrary polygonal
  faces), however, we now support vertex normals and texcoords supplied with the
  object, and the format actually allows for separate indexing into each of those
  attribute lists, so those must be tracked and represented separately by Model
  (both loading and when converting to Mesh).  We do not support any of the more
  complex features of the file format like curves, free-form surfaces, and the
  various material description options (separate file load and file format).
modified:
  src/model.cpp
  src/model.h
  src/scene-build.cpp
  src/scene-bump.cpp
  src/scene-refract.cpp
  src/scene-shading.cpp
  src/scene-shadow.cpp
  src/scene-texture.cpp


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

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

Patch

=== modified file 'src/model.cpp'
--- src/model.cpp	2012-07-05 17:22:16 +0000
+++ src/model.cpp	2013-01-30 23:07:13 +0000
@@ -35,6 +35,7 @@ 
 
 using std::string;
 using std::vector;
+using LibMatrix::vec2;
 using LibMatrix::vec3;
 using LibMatrix::uvec3;
 
@@ -108,50 +109,65 @@ 
                              int p_pos, int n_pos, int t_pos,
                              int nt_pos, int nb_pos)
 {
-    size_t face_count = object.faces.size();
-
-    for(size_t i = 0; i < 3 * face_count; i += 3)
+    for (vector<Face>::const_iterator faceIt = object.faces.begin();
+         faceIt != object.faces.end();
+         faceIt++)
     {
-        const Face &face = object.faces[i / 3];
-        const Vertex &a = object.vertices[face.a];
-        const Vertex &b = object.vertices[face.b];
-        const Vertex &c = object.vertices[face.c];
-
-        mesh.next_vertex();
-        if (p_pos >= 0)
-            mesh.set_attrib(p_pos, a.v);
-        if (n_pos >= 0)
-            mesh.set_attrib(n_pos, a.n);
-        if (t_pos >= 0)
-            mesh.set_attrib(t_pos, a.t);
-        if (nt_pos >= 0)
-            mesh.set_attrib(nt_pos, a.nt);
-        if (nb_pos >= 0)
-            mesh.set_attrib(nb_pos, a.nb);
-
-        mesh.next_vertex();
-        if (p_pos >= 0)
-            mesh.set_attrib(p_pos, b.v);
-        if (n_pos >= 0)
-            mesh.set_attrib(n_pos, b.n);
-        if (t_pos >= 0)
-            mesh.set_attrib(t_pos, b.t);
-        if (nt_pos >= 0)
-            mesh.set_attrib(nt_pos, b.nt);
-        if (nb_pos >= 0)
-            mesh.set_attrib(nb_pos, b.nb);
-
-        mesh.next_vertex();
-        if (p_pos >= 0)
-            mesh.set_attrib(p_pos, c.v);
-        if (n_pos >= 0)
-            mesh.set_attrib(n_pos, c.n);
-        if (t_pos >= 0)
-            mesh.set_attrib(t_pos, c.t);
-        if (nt_pos >= 0)
-            mesh.set_attrib(nt_pos, c.nt);
-        if (nb_pos >= 0)
-            mesh.set_attrib(nb_pos, c.nb);
+        // In some model file formats (OBJ in particular), the face description
+        // may contain separate indices per-attribute.  So, we need to allow
+        // for this when adding each vertex attribute to the mesh.
+        const Face &face = *faceIt;
+        const Vertex &v1 = object.vertices[face.v.x()];
+        const Vertex &v2 = object.vertices[face.v.y()];
+        const Vertex &v3 = object.vertices[face.v.z()];
+
+        bool separate_t(face.which & Face::OBJ_FACE_T);
+
+        const Vertex &t1 = object.vertices[separate_t ? face.t.x() : face.v.x()];
+        const Vertex &t2 = object.vertices[separate_t ? face.t.y() : face.v.y()];
+        const Vertex &t3 = object.vertices[separate_t ? face.t.z() : face.v.z()];
+
+        bool separate_n(face.which & Face::OBJ_FACE_N);
+
+        const Vertex &n1 = object.vertices[separate_n ? face.n.x() : face.v.x()];
+        const Vertex &n2 = object.vertices[separate_n ? face.n.y() : face.v.y()];
+        const Vertex &n3 = object.vertices[separate_n ? face.n.z() : face.v.z()];
+
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, v1.v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, n1.n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, t1.t);
+        if (nt_pos >= 0)
+            mesh.set_attrib(nt_pos, v1.nt);
+        if (nb_pos >= 0)
+            mesh.set_attrib(nb_pos, v1.nb);
+
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, v2.v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, n2.n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, t2.t);
+        if (nt_pos >= 0)
+            mesh.set_attrib(nt_pos, v2.nt);
+        if (nb_pos >= 0)
+            mesh.set_attrib(nb_pos, v2.nb);
+
+        mesh.next_vertex();
+        if (p_pos >= 0)
+            mesh.set_attrib(p_pos, v3.v);
+        if (n_pos >= 0)
+            mesh.set_attrib(n_pos, n3.n);
+        if (t_pos >= 0)
+            mesh.set_attrib(t_pos, t3.t);
+        if (nt_pos >= 0)
+            mesh.set_attrib(nt_pos, v3.nt);
+        if (nb_pos >= 0)
+            mesh.set_attrib(nb_pos, v3.nb);
     }
 }
 
@@ -225,6 +241,9 @@ 
 void
 Model::calculate_texcoords()
 {
+    if (gotTexcoords_)
+        return;
+
     // Since the model didn't come with texcoords, and we don't actually know
     // if it came with normals, either, we'll use positional spherical mapping
     // to generate texcoords for the model.  See:
@@ -248,6 +267,8 @@ 
             curVertex.t.y(asinf(vnorm.y()) / M_PI + 0.5);
         }
     }
+
+    gotTexcoords_ = true;
 }
 
 /**
@@ -256,6 +277,9 @@ 
 void
 Model::calculate_normals()
 {
+    if (gotNormals_)
+        return;
+
     LibMatrix::vec3 n;
 
     for (std::vector<Object>::iterator iter = objects_.begin();
@@ -269,9 +293,9 @@ 
              f_iter++)
         {
             const Face &face = *f_iter;
-            Vertex &a = object.vertices[face.a];
-            Vertex &b = object.vertices[face.b];
-            Vertex &c = object.vertices[face.c];
+            Vertex &a = object.vertices[face.v.x()];
+            Vertex &b = object.vertices[face.v.y()];
+            Vertex &c = object.vertices[face.v.z()];
 
             /* Calculate normal */
             n = LibMatrix::vec3::cross(b.v - a.v, c.v - a.v);
@@ -318,8 +342,9 @@ 
             v.nt.normalize();
             v.nb.normalize();
         }
-
     }
+
+    gotNormals_ = true;
 }
 
 /**
@@ -425,9 +450,10 @@ 
                 for (uint16_t i = 0; i < qty; i++) {
                     float f[3];
                     read_or_fail(input_file, f, sizeof(float) * 3);
-                    object->vertices[i].v.x(f[0]);
-                    object->vertices[i].v.y(f[1]);
-                    object->vertices[i].v.z(f[2]);
+                    vec3& vertex = object->vertices[i].v;
+                    vertex.x(f[0]);
+                    vertex.y(f[1]);
+                    vertex.z(f[2]);
                 }
                 }
                 break;
@@ -445,10 +471,12 @@ 
                 read_or_fail(input_file, &qty, sizeof(uint16_t));
                 object->faces.resize(qty);
                 for (uint16_t i = 0; i < qty; i++) {
-                    read_or_fail(input_file, &object->faces[i].a, sizeof(uint16_t));
-                    read_or_fail(input_file, &object->faces[i].b, sizeof(uint16_t));
-                    read_or_fail(input_file, &object->faces[i].c, sizeof(uint16_t));
-                    read_or_fail(input_file, &object->faces[i].face_flags, sizeof(uint16_t));
+                    uint16_t f[4];
+                    read_or_fail(input_file, f, sizeof(uint16_t) * 4);
+                    uvec3& face = object->faces[i].v;
+                    face.x(f[0]);
+                    face.y(f[1]);
+                    face.z(f[2]);
                 }
                 }
                 break;
@@ -467,8 +495,9 @@ 
                 for (uint16_t i = 0; i < qty; i++) {
                     float f[2];
                     read_or_fail(input_file, f, sizeof(float) * 2);
-                    object->vertices[i].t.x(f[0]);
-                    object->vertices[i].t.y(f[1]);
+                    vec2& texcoord = object->vertices[i].t;
+                    texcoord.x(f[0]);
+                    texcoord.y(f[1]);
                 }
                 }
                 gotTexcoords_ = true;
@@ -500,118 +529,144 @@ 
     return true;
 }
 
-/**
- * Parse vec3 values from an OBJ file.
+
+const unsigned int Model::Face::OBJ_FACE_V = 0x1;
+const unsigned int Model::Face::OBJ_FACE_T = 0x2;
+const unsigned int Model::Face::OBJ_FACE_N = 0x4;
+
+/**
+ * Parse 2-element vertex attribute from an OBJ file.
+ *
+ * @param source the source line to parse
+ * @param v the vec2 to populate
+ */
+void
+Model::obj_get_attrib(const string& source, vec2& v)
+{
+    // Our attribs are whitespace separated, so use a fuzzy split.
+    vector<string> elements;
+    Util::split(source, ' ', elements, Util::SplitModeFuzzy);
+
+    // Find the first value...
+    float x = Util::fromString<float>(elements[0]);
+    // And the second value (there might be a third, but we don't care)...
+    float y = Util::fromString<float>(elements[1]);
+    v.x(x);
+    v.y(y);
+}
+
+/**
+ * Parse 3-element vertex attribute from an OBJ file.
  *
  * @param source the source line to parse
  * @param v the vec3 to populate
  */
-static void
-obj_get_values(const string& source, vec3& v)
+void
+Model::obj_get_attrib(const string& source, vec3& v)
 {
-    // Skip the definition type...
-    string::size_type endPos = source.find(" ");
-    string::size_type startPos(0);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
+    // Our attribs are whitespace separated, so use a fuzzy split.
+    vector<string> elements;
+    Util::split(source, ' ', elements, Util::SplitModeFuzzy);
+
     // Find the first value...
-    startPos = endPos + 1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
-    string::size_type numChars(endPos - startPos);
-    string xs(source, startPos, numChars);
-    float x = Util::fromString<float>(xs);
+    float x = Util::fromString<float>(elements[0]);
     // Then the second value...
-    startPos = endPos + 1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
-    numChars = endPos - startPos;
-    string ys(source, startPos, numChars);
-    float y = Util::fromString<float>(ys);
+    float y = Util::fromString<float>(elements[1]);
     // And the third value (there might be a fourth, but we don't care)...
-    startPos = endPos + 1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        numChars = endPos;
-    }
-    else
-    {
-        numChars = endPos - startPos;
-    }
-    string zs(source, startPos, endPos - startPos);
-    float z = Util::fromString<float>(zs);
+    float z = Util::fromString<float>(elements[2]);
     v.x(x);
     v.y(y);
     v.z(z);
 }
 
+
+void
+Model::obj_face_get_index(const string& tuple, unsigned int& which,
+    unsigned int& v, unsigned int& t, unsigned int& n)
+{
+    // We can use a normal split here as syntax requires no spaces around
+    // the '/' delimiter for a face description.
+    vector<string> elements;
+    Util::split(tuple, '/', elements, Util::SplitModeNormal);
+
+    if (elements.empty())
+    {
+        which = 0;
+        return;
+    }
+
+    which = Face::OBJ_FACE_V;
+    v = Util::fromString<unsigned int>(elements[0]);
+
+    unsigned int num_elements = elements.size();
+
+    if (num_elements > 1 && !elements[1].empty())
+    {
+        which |= Face::OBJ_FACE_T;
+        t = Util::fromString<unsigned int>(elements[1]);
+    }
+
+    if (num_elements > 2 && !elements[2].empty())
+    {
+        which |= Face::OBJ_FACE_N;
+        n = Util::fromString<unsigned int>(elements[2]);
+    }
+
+    return;
+}
+
 /**
- * Parse uvec3 values from an OBJ file.
+ * Parse a face description from an OBJ file.
+ * Faces always specify position, but optionally can also contain separate
+ * indices for texcoords and normals.
  *
  * @param source the source line to parse
  * @param v the uvec3 to populate
  */
-static void
-obj_get_values(const string& source, uvec3& v)
+void
+Model::obj_get_face(const string& source, Face& f)
 {
-    // Skip the definition type...
-    string::size_type endPos = source.find(" ");
-    string::size_type startPos(0);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
+    // Our indices are whitespace separated, so use a fuzzy split.
+    vector<string> elements;
+    Util::split(source, ' ', elements, Util::SplitModeFuzzy);
+
     // Find the first value...
-    startPos = endPos + 1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
-    string::size_type numChars(endPos - startPos);
-    string xs(source, startPos, numChars);
-    unsigned int x = Util::fromString<unsigned int>(xs);
+    unsigned int which(0);
+    unsigned int vx(0);
+    unsigned int tx(0);
+    unsigned int nx(0);
+    obj_face_get_index(elements[0], which, vx, tx, nx);
+
     // Then the second value...
-    startPos = endPos+1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        Log::error("Bad element '%s'\n", source.c_str());
-        return;
-    }
-    numChars = endPos - startPos;
-    string ys(source, startPos, numChars);
-    unsigned int y = Util::fromString<unsigned int>(ys);
+    unsigned int vy(0);
+    unsigned int ty(0);
+    unsigned int ny(0);
+    obj_face_get_index(elements[1], which, vy, ty, ny);
+
     // And the third value (there might be a fourth, but we don't care)...
-    startPos = endPos + 1;
-    endPos = source.find(" ", startPos);
-    if (endPos == string::npos)
-    {
-        numChars = endPos;
-    }
-    else
-    {
-        numChars = endPos - startPos;
-    }
-    string zs(source, startPos, numChars);
-    unsigned int z = Util::fromString<unsigned int>(zs);
-    v.x(x);
-    v.y(y);
-    v.z(z);
+    unsigned int vz(0);
+    unsigned int tz(0);
+    unsigned int nz(0);
+    obj_face_get_index(elements[2], which, vz, tz, nz);
+
+    // OBJ models start absoluted indices at '1', so subtract to re-base to
+    // '0'.  We do not handle relative indexing (negative indices).  
+    f.which = which;
+    f.v.x(vx - 1);
+    f.v.y(vy - 1);
+    f.v.z(vz - 1);
+    if (which & Face::OBJ_FACE_T)
+    {
+        f.t.x(tx - 1);
+        f.t.y(ty - 1);
+        f.t.z(tz - 1);
+    }
+    if (which & Face::OBJ_FACE_N)
+    {
+        f.n.x(nx - 1);
+        f.n.y(ny - 1);
+        f.n.z(nz - 1);
+    }
 }
 
 /**
@@ -642,59 +697,98 @@ 
     }
 
     // Give ourselves an object to populate.
-    objects_.push_back(Object(filename));
+    objects_.push_back(Object(string()));
     Object& object(objects_.back());
 
+    static const string object_definition("o");
     static const string vertex_definition("v");
     static const string normal_definition("vn");
     static const string texcoord_definition("vt");
     static const string face_definition("f");
+    vector<vec3> positions;
+    vector<vec3> normals;
+    vector<vec2> texcoords;
     for (vector<string>::const_iterator lineIt = sourceVec.begin();
          lineIt != sourceVec.end();
          lineIt++)
     {
         const string& curSrc = *lineIt;
         // Is it a vertex attribute, a face description, comment or other?
-        // We only care about the first two, we ignore comments, object names,
-        // group names, smoothing groups, etc.
+        // We only care about the first two, we ignore comments, group names,
+        // smoothing groups, etc.
         string::size_type startPos(0);
         string::size_type spacePos = curSrc.find(" ", startPos);
-        string definitionType(curSrc, startPos, spacePos - startPos);
+        string::size_type num_chars(string::npos);
+        string definition;
+        if (spacePos != string::npos)
+        {
+            // Could be arbitrary whitespace between description type and
+            // the data
+            string::size_type defPos = curSrc.find_first_not_of(' ', spacePos);
+            definition = string(curSrc, defPos);
+            num_chars = spacePos - startPos;
+        }
+        string definitionType(curSrc, startPos, num_chars);
+
         if (definitionType == vertex_definition)
         {
-            Vertex v;
-            obj_get_values(curSrc, v.v);
-            object.vertices.push_back(v);
+            vec3 p;
+            obj_get_attrib(definition, p);
+            positions.push_back(p);
         }
         else if (definitionType == normal_definition)
         {
-            // If we encounter an OBJ model with normals, we can update this
-            // to update object.vertices.n directly
-            Log::debug("We got a normal...\n");
+            vec3 n;
+            obj_get_attrib(definition, n);
+            normals.push_back(n);
         }
         else if (definitionType == texcoord_definition)
         {
-            // If we encounter an OBJ model with normals, we can update this
-            // to update object.vertices.t directly
-            Log::debug("We got a texcoord...\n");
+            vec2 t;
+            obj_get_attrib(definition, t);
+            texcoords.push_back(t);
         }
         else if (definitionType == face_definition)
         {
-            uvec3 v;
-            obj_get_values(curSrc, v);
             Face f;
-            // OBJ models index from '1'.
-            f.a = v.x() - 1;
-            f.b = v.y() - 1;
-            f.c = v.z() - 1;
+            obj_get_face(definition, f);
             object.faces.push_back(f);
         }
-    }
+        else if (definitionType == object_definition)
+        {
+            object.name = definition;
+        }
+    }
+
+    if (!texcoords.empty())
+    {
+        gotTexcoords_ = true;
+    }
+    if (!normals.empty())
+    {
+        gotNormals_ = true;
+    }
+    unsigned int numVertices = positions.size();
+    object.vertices.resize(numVertices);
+    for (unsigned int i = 0; i < numVertices; i++)
+    {
+        Vertex& curVertex = object.vertices[i];
+        curVertex.v = positions[i];
+        if (gotTexcoords_)
+        {
+            curVertex.t = texcoords[i];
+        }
+        if (gotNormals_)
+        {
+            curVertex.n = normals[i];
+        }
+    }
+
     // Compute bounding box for perspective projection
     compute_bounding_box(object);
 
-    Log::debug("Object populated with %u vertices and %u faces.\n",
-        object.vertices.size(), object.faces.size());
+    Log::debug("Object name: %s Vertex count: %u Face count: %u\n",
+        object.name.empty() ? "(none)" : object.name.c_str(), object.vertices.size(), object.faces.size());
     return true;
 }
 

=== modified file 'src/model.h'
--- src/model.h	2012-07-27 09:11:50 +0000
+++ src/model.h	2013-01-29 16:55:36 +0000
@@ -78,12 +78,13 @@ 
         AttribTypeCustom
     } AttribType;
 
-    Model() : gotTexcoords_(false) {}
+    Model() : gotTexcoords_(false), gotNormals_(false) {}
     ~Model() {}
 
     bool load(const std::string& name);
 
     bool needTexcoords() const { return !gotTexcoords_; }
+    bool needNormals() const { return !gotNormals_; }
     void calculate_texcoords();
     void calculate_normals();
     void convert_to_mesh(Mesh &mesh);
@@ -93,11 +94,18 @@ 
     const LibMatrix::vec3& maxVec() const { return maxVec_; }
     static const ModelMap& find_models();
 private:
-    // If the model we loaded contained texcoord data...
+    // If the model we loaded contained texcoord or normal data...
     bool gotTexcoords_;
+    bool gotNormals_;
+
     struct Face {
-        uint32_t a, b, c;
-        uint16_t face_flags;
+        LibMatrix::uvec3 v;
+        LibMatrix::uvec3 n;
+        LibMatrix::uvec3 t;
+        unsigned int which; // mask of which values are relevant for this face.
+        static const unsigned int OBJ_FACE_V;
+        static const unsigned int OBJ_FACE_T;
+        static const unsigned int OBJ_FACE_N;
     };
 
     struct Vertex {
@@ -120,6 +128,11 @@ 
                                int nt_pos, int nb_pos);
     bool load_3ds(const std::string &filename);
     bool load_obj(const std::string &filename);
+    void obj_get_attrib(const std::string& description, LibMatrix::vec2& v);
+    void obj_get_attrib(const std::string& description, LibMatrix::vec3& v);
+    void obj_face_get_index(const std::string& tuple, unsigned int& which,
+        unsigned int& v, unsigned int& t, unsigned int& n);
+    void obj_get_face(const std::string& description, Face& face);
 
     // For vertices of the bounding box for this model.
     void compute_bounding_box(const Object& object);

=== modified file 'src/scene-build.cpp'
--- src/scene-build.cpp	2012-08-15 09:45:06 +0000
+++ src/scene-build.cpp	2013-01-29 17:17:28 +0000
@@ -141,7 +141,8 @@ 
         orientationVec_ = vec3(0.0, 1.0, 0.0);
     }
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     /* Tell the converter that we only care about position and normal attributes */
     std::vector<std::pair<Model::AttribType, int> > attribs;

=== modified file 'src/scene-bump.cpp'
--- src/scene-bump.cpp	2012-08-15 09:45:06 +0000
+++ src/scene-bump.cpp	2013-01-29 17:17:28 +0000
@@ -80,7 +80,8 @@ 
     if(!model.load(poly_filename))
         return false;
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     /* Tell the converter that we only care about position and normal attributes */
     std::vector<std::pair<Model::AttribType, int> > attribs;
@@ -177,7 +178,8 @@ 
     if(!model.load("asteroid-low"))
         return false;
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     /* Calculate the half vector */
     LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
@@ -234,7 +236,8 @@ 
     if(!model.load("asteroid-low"))
         return false;
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     /* Calculate the half vector */
     LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());

=== modified file 'src/scene-refract.cpp'
--- src/scene-refract.cpp	2012-12-15 09:46:12 +0000
+++ src/scene-refract.cpp	2013-01-29 17:17:28 +0000
@@ -322,7 +322,8 @@ 
         orientationVec_ = vec3(0.0, 1.0, 0.0);
     }
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     // Mesh setup
     vector<std::pair<Model::AttribType, int> > attribs;

=== modified file 'src/scene-shading.cpp'
--- src/scene-shading.cpp	2012-08-15 09:45:06 +0000
+++ src/scene-shading.cpp	2013-01-29 17:17:28 +0000
@@ -220,7 +220,8 @@ 
         orientationVec_ = vec3(0.0, 1.0, 0.0);
     }
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     /* Tell the converter that we only care about position and normal attributes */
     std::vector<std::pair<Model::AttribType, int> > attribs;

=== modified file 'src/scene-shadow.cpp'
--- src/scene-shadow.cpp	2012-12-17 16:08:05 +0000
+++ src/scene-shadow.cpp	2013-01-29 17:17:28 +0000
@@ -324,7 +324,8 @@ 
         return false;
     }
 
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
 
     // Mesh setup
     vector<std::pair<Model::AttribType, int> > attribs;

=== modified file 'src/scene-texture.cpp'
--- src/scene-texture.cpp	2012-08-15 09:45:06 +0000
+++ src/scene-texture.cpp	2013-01-29 17:17:28 +0000
@@ -208,7 +208,9 @@ 
 
     if (model.needTexcoords())
         model.calculate_texcoords();
-    model.calculate_normals();
+    if (model.needNormals())
+        model.calculate_normals();
+
     // Tell the converter which attributes we care about
     std::vector<std::pair<Model::AttribType, int> > attribs;
     attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));