diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 105: Refactor Model class to correctly read 3ds files with multiple objects.

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

Commit Message

alexandros.frantzis@linaro.org July 21, 2011, 12:36 p.m. UTC
------------------------------------------------------------
revno: 105
committer: Alexandros Frantzis <alexandros.frantzis@linaro.org>
timestamp: Tue 2011-07-12 12:05:53 +0300
message:
  Refactor Model class to correctly read 3ds files with multiple objects.
modified:
  src/model.cpp
  src/model.h


--
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	2011-07-01 15:31:27 +0000
+++ src/model.cpp	2011-07-12 09:05:53 +0000
@@ -24,29 +24,63 @@ 
 #include "model.h"
 #include "vec.h"
 #include "log.h"
-
-long filelength(int f)
-{
-    struct stat buf;
-    fstat(f, &buf);
-    return(buf.st_size);
-}
-
-Model::Model()
-{
-    mPolygonQty = 0;
-    mVertexQty = 0;
-    mVertex = 0;        // Set pointer to null
-    mPolygon = 0;       // Set pointer to null
-}
-
-Model::~Model()
-{
-    delete [] mVertex;
-    delete [] mPolygon;
-}
-
-void Model::convert_to_mesh(Mesh &mesh)
+#include "options.h"
+
+#include <fstream>
+#include <sstream>
+
+#define read_or_fail(file, dst, size) do { \
+    file.read(reinterpret_cast<char *>((dst)), (size)); \
+    if (file.gcount() < (std::streamsize)(size)) { \
+        Log::error("%s: %d: Failed to read %zd bytes from 3ds file (read %zd)\n", \
+                   __FUNCTION__, __LINE__, \
+                   (size_t)(size), file.gcount()); \
+        return false; \
+    } \
+} while(0);
+
+void
+Model::append_object_to_mesh(const Object &object, Mesh &mesh,
+                             int p_pos, int n_pos, int t_pos)
+{
+    size_t face_count = object.faces.size();
+
+    for(size_t i = 0; i < 3 * face_count; i += 3)
+    {
+        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);
+
+        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);
+
+        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);
+    }
+
+}
+
+void
+Model::convert_to_mesh(Mesh &mesh)
 {
     std::vector<std::pair<AttribType, int> > attribs;
 
@@ -57,8 +91,9 @@ 
     convert_to_mesh(mesh, attribs);
 }
 
-void Model::convert_to_mesh(Mesh &mesh,
-                            const std::vector<std::pair<AttribType, int> > &attribs)
+void
+Model::convert_to_mesh(Mesh &mesh,
+                       const std::vector<std::pair<AttribType, int> > &attribs)
 {
     std::vector<int> format;
     int p_pos = -1;
@@ -82,115 +117,79 @@ 
 
     mesh.set_vertex_format(format);
 
-    for(unsigned i = 0; i < 3 * mPolygonQty; i += 3)
+    for (std::vector<Object>::const_iterator iter = objects_.begin();
+         iter != objects_.end();
+         iter++)
     {
-        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);
+        append_object_to_mesh(*iter, mesh, p_pos, n_pos, t_pos);
     }
 }
 
-void Model::calculate_normals()
+void
+Model::calculate_normals()
 {
     LibMatrix::vec3 n;
 
-    for(unsigned i = 0; i < mPolygonQty; i++)
-    {
-        n = LibMatrix::vec3::cross(mVertex[mPolygon[i].mB].v - mVertex[mPolygon[i].mA].v,
-                                   mVertex[mPolygon[i].mC].v - mVertex[mPolygon[i].mA].v);
-        n.normalize();
-        mVertex[mPolygon[i].mA].n += n;
-        mVertex[mPolygon[i].mB].n += n;
-        mVertex[mPolygon[i].mC].n += n;
-    }
-
-    for(unsigned i = 0; i < mVertexQty; i++)
-        mVertex[i].n.normalize();
-}
-
-void Model::center()
-{
-    LibMatrix::vec3 max(mVertex[0].v);
-    LibMatrix::vec3 min(mVertex[0].v);
-
-    for(unsigned i = 1; i < mVertexQty; i++)
-    {
-        if(mVertex[i].v.x() > max.x()) max.x(mVertex[i].v.x());
-        if(mVertex[i].v.y() > max.y()) max.y(mVertex[i].v.y());
-        if(mVertex[i].v.z() > max.z()) max.z(mVertex[i].v.z());
-
-        if(mVertex[i].v.x() < min.x()) min.x(mVertex[i].v.x());
-        if(mVertex[i].v.y() < min.y()) min.y(mVertex[i].v.y());
-        if(mVertex[i].v.z() < min.z()) min.z(mVertex[i].v.z());
-    }
-
-    LibMatrix::vec3 center(max + min);
-    center /= 2.0f;
-
-    for(unsigned i = 0; i < mVertexQty; i++)
-        mVertex[i].v -= center;
-}
-
-void Model::scale(GLfloat pAmount)
-{
-    for(unsigned i = 1; i < mVertexQty; i++)
-        mVertex[i].v *= pAmount;
-}
-
-#define fread_or_fail(a, b, c, d) do { \
-    size_t nread_; \
-    nread_ = fread((a), (b), (c), (d));\
-    if (nread_ < (c)) { \
-        Log::error("Failed to read %zd bytes from 3ds file (read %zd)\n", \
-                   (size_t)((c) * (b)), nread_ * (b)); \
-        return 0; \
-    } \
-} while(0);
-
-int Model::load_3ds(const char *pFileName)
-{
-    int i;
-    FILE *l_file;
-    unsigned short l_chunk_id;
-    unsigned int l_chunk_length;
-    unsigned char l_char;
-    unsigned short l_qty;
-
-    Log::debug("Loading model from 3ds file '%s'\n", pFileName);
-
-    if ((l_file = fopen (pFileName, "rb")) == NULL) {
-        Log::error("Could not open 3ds file '%s'\n", pFileName);
-        return 0;
+    for (std::vector<Object>::iterator iter = objects_.begin();
+         iter != objects_.end();
+         iter++)
+    {
+        Object &object = *iter;
+        size_t face_count = object.faces.size();
+        size_t vertex_count = object.vertices.size();
+
+        for(unsigned i = 0; i < face_count; i++)
+        {
+            const Face &face = object.faces[i];
+            Vertex &a = object.vertices[face.a];
+            Vertex &b = object.vertices[face.b];
+            Vertex &c = object.vertices[face.c];
+
+            n = LibMatrix::vec3::cross(b.v - a.v, c.v - a.v);
+            n.normalize();
+            a.n += n;
+            b.n += n;
+            c.n += n;
+        }
+
+        for(unsigned i = 0; i < vertex_count; i++)
+            object.vertices[i].n.normalize();
+    }
+}
+
+bool
+Model::load_3ds(const std::string &filename)
+{
+    Object *object;
+
+    Log::debug("Loading model from 3ds file '%s'\n", filename.c_str());
+
+    std::fstream input_file(filename.c_str());
+    if (!input_file) {
+        Log::error("Could not open 3ds file '%s'\n", filename.c_str());
+        return false;
     }
 
     // Loop to scan the whole file
-    while (ftell (l_file) < filelength (fileno (l_file))) {
+    while (!input_file.eof()) {
+        uint16_t chunk_id;
+        uint32_t chunk_length;
+
         // Read the chunk header
-        fread_or_fail (&l_chunk_id, 2, 1, l_file);
+        input_file.read(reinterpret_cast<char *>(&chunk_id), 2);
+        if (input_file.gcount() == 0) {
+            continue;
+        }
+        else if (input_file.gcount() < 2) {
+            Log::error("%s: %d: Failed to read %zd bytes from 3ds file (read %zd)\n",
+                       __FUNCTION__, __LINE__, 2, input_file.gcount());
+            return false;
+        }
+
         //Read the lenght of the chunk
-        fread_or_fail (&l_chunk_length, 4, 1, l_file);
+        read_or_fail(input_file, &chunk_length, 4);
 
-        switch (l_chunk_id)
+        switch (chunk_id)
         {
             //----------------- MAIN3DS -----------------
             // Description: Main chunk, contains all the other chunks
@@ -214,12 +213,18 @@ 
             // Chunk Lenght: len(object name) + sub chunks
             //-------------------------------------------
             case 0x4000:
-                i = 0;
-                do {
-                    fread_or_fail (&l_char, 1, 1, l_file);
-                    mName[i] = l_char;
-                    i++;
-                } while(l_char != '\0' && i<20);
+                {
+                std::stringstream ss;
+                unsigned char c = 1;
+
+                for (int i = 0; i < 20 && c != '\0'; i++) {
+                    read_or_fail(input_file, &c, 1);
+                    ss << c;
+                }
+
+                objects_.push_back(Object(ss.str()));
+                object = &objects_.back();
+                }
                 break;
 
             //--------------- OBJ_TRIMESH ---------------
@@ -238,15 +243,18 @@ 
             //             + sub chunks
             //-------------------------------------------
             case 0x4110:
-                fread_or_fail (&l_qty, sizeof (unsigned short), 1, l_file);
-                mVertexQty = l_qty;
-                mVertex = new Vertex[mVertexQty];
-                for (i = 0; i < l_qty; i++) {
+                {
+                uint16_t qty;
+                read_or_fail(input_file, &qty, sizeof(uint16_t));
+                object->vertices.resize(qty);
+
+                for (uint16_t i = 0; i < qty; i++) {
                     float f[3];
-                    fread_or_fail (f, sizeof(float), 3, l_file);
-                    mVertex[i].v.x(f[0]);
-                    mVertex[i].v.y(f[1]);
-                    mVertex[i].v.z(f[2]);
+                    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]);
+                }
                 }
                 break;
 
@@ -258,14 +266,16 @@ 
             //             + sub chunks
             //-------------------------------------------
             case 0x4120:
-                fread_or_fail (&l_qty, sizeof (unsigned short), 1, l_file);
-                mPolygonQty = l_qty;
-                mPolygon = new Polygon[mPolygonQty];
-                for (i = 0; i < l_qty; i++) {
-                    fread_or_fail (&mPolygon[i].mA, sizeof (unsigned short), 1, l_file);
-                    fread_or_fail (&mPolygon[i].mB, sizeof (unsigned short), 1, l_file);
-                    fread_or_fail (&mPolygon[i].mC, sizeof (unsigned short), 1, l_file);
-                    fread_or_fail (&mPolygon[i].mFaceFlags, sizeof (unsigned short), 1, l_file);
+                {
+                uint16_t qty;
+                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));
+                }
                 }
                 break;
 
@@ -277,12 +287,15 @@ 
             //             + sub chunks
             //-------------------------------------------
             case 0x4140:
-                fread_or_fail (&l_qty, sizeof (unsigned short), 1, l_file);
-                for (i = 0; i < l_qty; i++) {
+                {
+                uint16_t qty;
+                read_or_fail(input_file, &qty, sizeof(uint16_t));
+                for (uint16_t i = 0; i < qty; i++) {
                     float f[2];
-                    fread_or_fail (f, sizeof(float), 2, l_file);
-                    mVertex[i].t.x(f[0]);
-                    mVertex[i].t.y(f[1]);
+                    read_or_fail(input_file, f, sizeof(float) * 2);
+                    object->vertices[i].t.x(f[0]);
+                    object->vertices[i].t.y(f[1]);
+                }
                 }
                 break;
 
@@ -292,15 +305,19 @@ 
             //to the same level next chunk
             //-------------------------------------------
             default:
-                fseek(l_file, l_chunk_length - 6, SEEK_CUR);
-        }
-    }
-    fclose(l_file); // Closes the file stream
-
-    Log::debug("    Model Information\n"
-               "    Name:          %s\n"
-               "    Vertex count:  %d\n"
-               "    Polygon count: %d\n",
-               mName, mVertexQty, mPolygonQty);
-    return 1;
+                input_file.seekg(chunk_length - 6, std::ios::cur);
+        }
+    }
+
+    if (Options::show_debug) {
+        for (std::vector<Object>::const_iterator iter = objects_.begin();
+             iter != objects_.end();
+             iter++)
+        {
+            Log::debug("    Object name: %s Vertex count: %d Face count: %d\n",
+                       iter->name.c_str(), iter->vertices.size(), iter->faces.size());
+        }
+    }
+
+    return true;
 }

=== modified file 'src/model.h'
--- src/model.h	2011-07-01 15:31:27 +0000
+++ src/model.h	2011-07-12 09:05:53 +0000
@@ -31,29 +31,11 @@ 
 #include <stdlib.h>
 #include <vector>
 
-class Polygon
-{
-public:
-    unsigned short mA, mB, mC;
-    unsigned short mFaceFlags;
-};
-
-struct Vertex {
-    LibMatrix::vec3 v;
-    LibMatrix::vec3 n;
-    LibMatrix::vec2 t;
-};
-
 
 // A model as loaded from a 3ds file
 class Model
 {
 public:
-    unsigned mPolygonQty;
-    unsigned mVertexQty;
-    Vertex *mVertex;
-    Polygon *mPolygon;
-    char mName[20];
 
     typedef enum {
         AttribTypePosition = 1,
@@ -62,16 +44,37 @@ 
         AttribTypeCustom = 8
     } AttribType;
 
-    Model();
-    ~Model();
+    Model() {}
+    ~Model() {}
 
-    int load_3ds(const char *pFileName);
+    bool load_3ds(const std::string &filename);
     void calculate_normals();
-    void center();
-    void scale(GLfloat pAmount);
     void convert_to_mesh(Mesh &mesh);
     void convert_to_mesh(Mesh &mesh, 
                          const std::vector<std::pair<AttribType, int> > &attribs);
+private:
+    struct Face {
+        uint16_t a, b, c;
+        uint16_t face_flags;
+    };
+
+    struct Vertex {
+        LibMatrix::vec3 v;
+        LibMatrix::vec3 n;
+        LibMatrix::vec2 t;
+    };
+
+    struct Object {
+        Object(const std::string &name) : name(name) {}
+        std::string name;
+        std::vector<Vertex> vertices;
+        std::vector<Face> faces;
+    };
+
+    void append_object_to_mesh(const Object &object, Mesh &mesh,
+                               int p_pos, int n_pos, int t_pos);
+
+    std::vector<Object> objects_;
 };
 
 #endif