diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 150: Model: Add support for glmark2-extras and handle model loading more cleanly.

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

Commit Message

alexandros.frantzis@linaro.org Oct. 11, 2011, 9:58 a.m. UTC
Merge authors:
  Jesse Barker (jesse-barker)
Related merge proposals:
  https://code.launchpad.net/~jesse-barker/glmark2/extra-support/+merge/78655
  proposed by: Jesse Barker (jesse-barker)
  review: Approve - Alexandros Frantzis (afrantzis)
------------------------------------------------------------
revno: 150 [merge]
author: Jesse Barker <jesse.barker@linaro.org>
committer: Alexandros Frantzis <alexandros.frantzis@linaro.org>
branch nick: trunk
timestamp: Tue 2011-10-11 12:46:59 +0300
message:
  Model: Add support for glmark2-extras and handle model loading more cleanly.
  
  The addition of support for the optional additional large models begged a
  slight revamp of the handling of models in general. Included in this branch:
  
  - Addition of a "--extras-path" option to the configure phase of the build.
    This enables the inclusion of optional data from a non-default location (e.g.,
    in a situation where a developer wants temporary access to the data without
    tainting their installation).
  
  - Model class gets a class method called "find_models()" to scan both the "data
    path" as well as the "extras path" (if configured). This method builds a
    database of available models in the form of a std::map with the model "name"
    (filename with no extension) as key and a pointer to a new ModelDescriptor
    object as value. ModelDescriptor contains the model name, format (3ds, obj),
    and full pathname to the model file.
  
  - Model class gets a new object method called "load()". This takes only the
    model name (as described above), and uses the map to look up the additional
    details it needs to load the model without the calling scene needing to know
    anything about the format of the model. The format-specific load methods are
    now private and all calling scenes have been updated to call the new method.
  
  - Model class gets updated with some additional comments to clarify what has
    been done and how the object is meant to be used.
modified:
  src/model.cpp
  src/model.h
  src/scene-build.cpp
  src/scene-bump.cpp
  src/scene-shading.cpp
  src/scene-texture.cpp
  src/scene.h
  wscript


--
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-09-16 11:49:39 +0000
+++ src/model.cpp	2011-10-07 18:19:11 +0000
@@ -27,7 +27,7 @@ 
 #include "options.h"
 #include "util.h"
 #include "float.h"
-
+#include <dirent.h>
 #include <fstream>
 #include <sstream>
 #include <memory>
@@ -600,3 +600,119 @@ 
         object.vertices.size(), object.faces.size());
     return true;
 }
+
+namespace ModelPrivate
+{
+
+void
+list_files(const string& dirName, vector<string>& fileVec)
+{
+    DIR* dir = opendir(dirName.c_str());
+    if (!dir)
+    {
+        Log::error("Failed to open models directory '%s'\n", dirName.c_str());
+        return;
+    }
+
+    struct dirent* entry = readdir(dir);
+    while (entry)
+    {
+        string pathname(dirName + "/");
+        pathname += string(entry->d_name);
+        // Skip '.' and '..'
+        if (entry->d_name[0] != '.')
+        {
+            fileVec.push_back(pathname);
+        }
+        entry = readdir(dir);
+    }
+    closedir(dir);
+}
+
+ModelMap modelMap;
+
+}
+
+const ModelMap&
+Model::find_models()
+{
+    if (!ModelPrivate::modelMap.empty())
+    {
+        return ModelPrivate::modelMap;
+    }
+    vector<string> pathVec;
+    string dataDir(GLMARK_DATA_PATH"/models");
+    ModelPrivate::list_files(dataDir, pathVec);
+#ifdef GLMARK_EXTRAS_PATH
+    string extrasDir(GLMARK_EXTRAS_PATH"/models");
+    ModelPrivate::list_files(extrasDir, pathVec);
+#endif
+
+    // Now that we have a list of all of the model files available to us,
+    // let's go through and pull out the names and what format they're in
+    // so the scene can decide which ones to use.
+    for(vector<string>::const_iterator pathIt = pathVec.begin();
+        pathIt != pathVec.end();
+        pathIt++)
+    {
+        const string& curPath = *pathIt;
+        string::size_type namePos(0);
+        string::size_type slashPos = curPath.rfind("/");
+        if (slashPos != string::npos)
+        {
+            // Advance to the first character after the last slash
+            namePos = slashPos + 1;
+        }
+
+        ModelFormat format(MODEL_INVALID);
+        string::size_type extPos = curPath.rfind(".3ds");
+        if (extPos == string::npos)
+        {
+            // It's not a 3ds model
+            extPos = curPath.rfind(".obj");
+            if (extPos == string::npos)
+            {
+                // It's not an obj model either, so skip it.
+                continue;
+            }
+            format = MODEL_OBJ;
+        }
+        else
+        {
+            // It's a 3ds model
+            format = MODEL_3DS;
+        }
+
+        string name(curPath, namePos, extPos - namePos);
+        ModelDescriptor* desc = new ModelDescriptor(name, format, curPath);
+        ModelPrivate::modelMap.insert(std::make_pair(name, desc));
+    }
+
+    return ModelPrivate::modelMap;
+}
+
+bool
+Model::load(const string& modelName)
+{
+    bool retVal(false);
+    ModelMap::const_iterator modelIt = ModelPrivate::modelMap.find(modelName);
+    if (modelIt == ModelPrivate::modelMap.end())
+    {
+        return retVal;
+    }
+
+    ModelDescriptor* desc = modelIt->second;
+    switch (desc->format())
+    {
+        case MODEL_INVALID:
+            break;
+        case MODEL_3DS:
+            retVal = load_3ds(desc->pathname());
+            break;
+        case MODEL_OBJ:
+            retVal = load_obj(desc->pathname());
+            break;
+    }
+
+    return retVal;
+}

=== modified file 'src/model.h'
--- src/model.h	2011-09-16 11:49:39 +0000
+++ src/model.h	2011-10-07 18:39:57 +0000
@@ -30,9 +30,35 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 #include <vector>
-
-
-// A model as loaded from a 3ds file
+#include <map>
+
+enum ModelFormat
+{
+    MODEL_INVALID,
+    MODEL_3DS,
+    MODEL_OBJ
+};
+
+class ModelDescriptor
+{
+    std::string name_;
+    std::string pathname_;
+    ModelFormat format_;
+    ModelDescriptor();
+public:
+    ModelDescriptor(const std::string& name, ModelFormat format, 
+                    const std::string& pathname) :
+        name_(name),
+        pathname_(pathname),
+        format_(format) {}
+    ~ModelDescriptor() {}
+    const std::string& pathname() const { return pathname_; }
+    ModelFormat format() const { return format_; }
+};
+
+typedef std::map<std::string, ModelDescriptor*> ModelMap;
+
+// A model as loaded from a 3D object data file
 class Model
 {
 public:
@@ -47,14 +73,21 @@ 
     Model() {}
     ~Model() {}
 
-    bool load_3ds(const std::string &filename);
-    bool load_obj(const std::string &filename);
+    // Load a named model from the ModelMap.
+    bool load(const std::string& name);
+
     void calculate_normals();
     void convert_to_mesh(Mesh &mesh);
     void convert_to_mesh(Mesh &mesh, 
                          const std::vector<std::pair<AttribType, int> > &attribs);
     const LibMatrix::vec3& minVec() const { return minVec_; }
     const LibMatrix::vec3& maxVec() const { return maxVec_; }
+    // Scan the built-in data paths and build a database of usable models
+    // available to scenes.  Map is available on a read-only basis to scenes
+    // that might find it useful for listing models, etc.
+    //
+    // NOTE: This must be called before load().
+    static const ModelMap& find_models();
 private:
     struct Face {
         uint32_t a, b, c;
@@ -76,6 +109,8 @@ 
 
     void append_object_to_mesh(const Object &object, Mesh &mesh,
                                int p_pos, int n_pos, int t_pos);
+    bool load_3ds(const std::string &filename);
+    bool load_obj(const std::string &filename);
 
     // 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	2011-10-05 16:42:33 +0000
+++ src/scene-build.cpp	2011-10-11 09:46:59 +0000
@@ -29,14 +29,31 @@ 
 #include <cmath>
 
 SceneBuild::SceneBuild(Canvas &pCanvas) :
-    Scene(pCanvas, "build")
+    Scene(pCanvas, "build"),
+    mOrientModel(false)
 {
+    const ModelMap& modelMap = Model::find_models();
+    std::string optionDesc("Which model to use [");
+    for (ModelMap::const_iterator modelIt = modelMap.begin();
+         modelIt != modelMap.end();
+         modelIt++)
+    {
+        static bool doSeparator(false);
+        if (doSeparator)
+        {
+            optionDesc += ", ";
+        }
+        const std::string& curName = modelIt->first;
+        optionDesc += curName;
+        doSeparator = true;
+    }
+    optionDesc += "]";
     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]");
     mOptions["model"] = Scene::Option("model", "horse",
-                                      "Which model to use [horse, bunny]");
+                                      optionDesc);
 }
 
 SceneBuild::~SceneBuild()
@@ -83,24 +100,34 @@ 
     }
 
     Model model;
-    bool modelLoaded(false);
     const std::string& whichModel(mOptions["model"].value);
-
-    if (whichModel == "bunny")
-    {
-        // Bunny rotates around the Y axis
-        modelLoaded = model.load_obj(GLMARK_DATA_PATH"/models/bunny.obj");
-    }
-    else
-    {
-        // Default is "horse", so we don't need to look further
-        // Horse rotates around the Y axis
-        modelLoaded = model.load_3ds(GLMARK_DATA_PATH"/models/horse.3ds");
-    }
+    bool modelLoaded = model.load(whichModel);
 
     if(!modelLoaded)
         return;
 
+    // Now that we're successfully loaded, there are a few quirks about
+    // some of the known models that we need to account for.  The draw
+    // logic for the scene wants to rotate the model around the Y axis.
+    // Most of our models are described this way.  Some need adjustment
+    // (an additional rotation that gets the model into the correct
+    // orientation).
+    //
+    // Here's a summary:
+    //
+    // Angel rotates around the Y axis
+    // Armadillo rotates around the Y axis
+    // Buddha rotates around the X axis
+    // Bunny rotates around the Y axis
+    // Dragon rotates around the X axis
+    // Horse rotates around the Y axis
+    if (whichModel == "buddha" || whichModel == "dragon")
+    {
+        mOrientModel = true;
+        mOrientationAngle = -90.0;
+        mOrientationVec = vec3(1.0, 0.0, 0.0);
+    }
+
     model.calculate_normals();
 
     /* Tell the converter that we only care about position and normal attributes */
@@ -187,6 +214,10 @@ 
     LibMatrix::mat4 model_view_proj(mPerspective);
     model_view.translate(-mCenterVec.x(), -mCenterVec.y(), -(mCenterVec.z() + 2.0 + mRadius));
     model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
+    if (mOrientModel)
+    {
+        model_view.rotate(mOrientationAngle, mOrientationVec.x(), mOrientationVec.y(), mOrientationVec.z());
+    }
     model_view_proj *= model_view.getCurrent();
 
     mProgram["ModelViewProjectionMatrix"] = model_view_proj;

=== modified file 'src/scene-bump.cpp'
--- src/scene-bump.cpp	2011-08-31 21:22:27 +0000
+++ src/scene-bump.cpp	2011-10-07 18:35:47 +0000
@@ -56,8 +56,8 @@ 
 {
     static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/bump-poly.vert");
     static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/bump-poly.frag");
-    static const std::string low_poly_filename(GLMARK_DATA_PATH"/models/asteroid-low.3ds");
-    static const std::string high_poly_filename(GLMARK_DATA_PATH"/models/asteroid-high.3ds");
+    static const std::string low_poly_filename("asteroid-low");
+    static const std::string high_poly_filename("asteroid-high");
     static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
     Model model;
 
@@ -70,7 +70,7 @@ 
     std::string poly_filename = type == "high-poly" ?
                                 high_poly_filename : low_poly_filename;
 
-    if(!model.load_3ds(poly_filename))
+    if(!model.load(poly_filename))
         return;
 
     model.calculate_normals();
@@ -110,7 +110,7 @@ 
     static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
     Model model;
 
-    if(!model.load_3ds(GLMARK_DATA_PATH"/models/asteroid-low.3ds"))
+    if(!model.load("asteroid-low"))
         return;
 
     /* Calculate the half vector */
@@ -158,6 +158,7 @@ 
 
     const std::string &bump_render = mOptions["bump-render"].value;
 
+    Model::find_models();
     if (bump_render == "normals")
         setup_model_normals();
     else if (bump_render == "off" || bump_render == "high-poly")

=== modified file 'src/scene-shading.cpp'
--- src/scene-shading.cpp	2011-09-21 14:29:29 +0000
+++ src/scene-shading.cpp	2011-10-07 18:35:47 +0000
@@ -67,9 +67,10 @@ 
 
 int SceneShading::load()
 {
+    Model::find_models();
     Model model;
 
-    if(!model.load_3ds(GLMARK_DATA_PATH"/models/cat.3ds"))
+    if(!model.load("cat"))
         return 0;
 
     model.calculate_normals();

=== modified file 'src/scene-texture.cpp'
--- src/scene-texture.cpp	2011-09-14 16:44:46 +0000
+++ src/scene-texture.cpp	2011-10-07 18:35:47 +0000
@@ -44,9 +44,10 @@ 
 
 int SceneTexture::load()
 {
+    Model::find_models();
     Model model;
 
-    if(!model.load_3ds(GLMARK_DATA_PATH"/models/cube.3ds"))
+    if(!model.load("cube"))
         return 0;
 
     model.calculate_normals();

=== modified file 'src/scene.h'
--- src/scene.h	2011-10-08 12:30:54 +0000
+++ src/scene.h	2011-10-11 09:46:59 +0000
@@ -159,6 +159,9 @@ 
     LibMatrix::vec3 mCenterVec;
     float mRadius;
     Mesh mMesh;
+    bool mOrientModel;
+    float mOrientationAngle;
+    LibMatrix::vec3 mOrientationVec;
     float mRotation;
     float mRotationSpeed;
     bool mUseVbo;

=== modified file 'wscript'
--- wscript	2011-09-21 15:01:11 +0000
+++ wscript	2011-10-07 18:17:20 +0000
@@ -25,6 +25,8 @@ 
                    default = True, help='disable compiler optimizations')
     opt.add_option('--data-path', action='store', dest = 'data_path',
                    help='the path to install the data to')
+    opt.add_option('--extras-path', action='store', dest = 'extras_path',
+                   help='path to additional data (models, shaders, textures)')
 
 def configure(ctx):
     if not Options.options.gl and not Options.options.glesv2:
@@ -75,6 +77,12 @@ 
     if Options.options.data_path is None:
         Options.options.data_path = os.path.join(ctx.env.PREFIX, 'share/glmark2')
 
+    ctx.env.HAVE_EXTRAS = False
+    if Options.options.extras_path is not None:
+        ctx.env.HAVE_EXTRAS = True
+        ctx.env.append_unique('GLMARK_EXTRAS_PATH', Options.options.extras_path)
+        ctx.env.append_unique('DEFINES', 'GLMARK_EXTRAS_PATH="%s"' % Options.options.extras_path)
+
     ctx.env.append_unique('GLMARK_DATA_PATH', Options.options.data_path)
     ctx.env.append_unique('DEFINES', 'GLMARK_DATA_PATH="%s"' % Options.options.data_path)
     ctx.env.append_unique('DEFINES', 'GLMARK_VERSION="%s"' % VERSION)
@@ -85,6 +93,10 @@ 
 
     ctx.msg("Prefix", ctx.env.PREFIX, color = 'PINK')
     ctx.msg("Data path", Options.options.data_path, color = 'PINK')
+    ctx.msg("Including extras", "Yes" if ctx.env.HAVE_EXTRAS else "No",
+            color = 'PINK');
+    if ctx.env.HAVE_EXTRAS:
+        ctx.msg("Extras path", Options.options.extras_path, color = 'PINK')
     ctx.msg("Building GL2 version", "Yes" if ctx.env.USE_GL else "No",
             color = 'PINK')
     ctx.msg("Building GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No",