=== modified file 'src/model.cpp'
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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",