From patchwork Tue Oct 11 09:58:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alexandros.frantzis@linaro.org X-Patchwork-Id: 4614 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id D61F023EF7 for ; Tue, 11 Oct 2011 09:58:17 +0000 (UTC) Received: from mail-wy0-f180.google.com (mail-wy0-f180.google.com [74.125.82.180]) by fiordland.canonical.com (Postfix) with ESMTP id C992DA18301 for ; Tue, 11 Oct 2011 09:58:17 +0000 (UTC) Received: by wyh11 with SMTP id 11so9589200wyh.11 for ; Tue, 11 Oct 2011 02:58:17 -0700 (PDT) Received: by 10.223.17.3 with SMTP id q3mr14473369faa.28.1318327097639; Tue, 11 Oct 2011 02:58:17 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.24.41 with SMTP id r9cs152056laf; Tue, 11 Oct 2011 02:58:17 -0700 (PDT) Received: by 10.216.210.216 with SMTP id u66mr569458weo.49.1318327093258; Tue, 11 Oct 2011 02:58:13 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id v36si15724676weq.134.2011.10.11.02.58.13 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 11 Oct 2011 02:58:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1RDZ6C-0008GF-MY for ; Tue, 11 Oct 2011 09:58:12 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 9BA14E01FB for ; Tue, 11 Oct 2011 09:58:12 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: glmark2 X-Launchpad-Branch: ~glmark2-dev/glmark2/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 150 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [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> Date: Tue, 11 Oct 2011 09:58:12 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="14124"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: 8e47bcbef11e734b3e45cdbcde0684572fe0cb1d 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 committer: Alexandros Frantzis 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 === 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 #include #include #include @@ -600,3 +600,119 @@ object.vertices.size(), object.faces.size()); return true; } + +namespace ModelPrivate +{ + +void +list_files(const string& dirName, vector& 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 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::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 #include #include - - -// A model as loaded from a 3ds file +#include + +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 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 > &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 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",