=== added file 'src/benchmark.cpp'
--- src/benchmark.cpp	1970-01-01 00:00:00 +0000
+++ src/benchmark.cpp	2011-06-09 14:07:23 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+ *
+ * glmark2 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * glmark2.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis (glmark2)
+ */
+
+#include "benchmark.h"
+#include "log.h"
+#include <sstream>
+
+using std::string;
+using std::vector;
+using std::map;
+
+std::map<string, Scene *> Benchmark::mSceneMap;
+
+static void
+split(const string &s, char delim, vector<string> &elems)
+{
+    std::stringstream ss(s);
+
+    string item;
+    while(std::getline(ss, item, delim))
+        elems.push_back(item);
+}
+
+static Scene &
+get_scene_from_description(const string &s)
+{
+    vector<string> elems;
+
+    split(s, ':', elems);
+
+    const string &name = !elems.empty() ? elems[0] : ""; 
+
+    return Benchmark::get_scene_by_name(name);
+}
+
+static vector<Benchmark::OptionPair>
+get_options_from_description(const string &s)
+{
+    vector<Benchmark::OptionPair> options;
+    vector<string> elems;
+
+    split(s, ':', elems);
+
+    for (vector<string>::const_iterator iter = ++elems.begin();
+         iter != elems.end();
+         iter++)
+    {
+        vector<string> opt;
+
+        split(*iter, '=', opt);
+        if (opt.size() == 2)
+            options.push_back(Benchmark::OptionPair(opt[0], opt[1]));
+        else
+            Log::info("Warning: ignoring invalid option string '%s' "
+                      "in benchmark description\n",
+                      iter->c_str());
+    }
+
+    return options;
+}
+
+void
+Benchmark::register_scene(Scene &scene)
+{
+    mSceneMap[scene.name()] = &scene;
+}
+
+Scene &
+Benchmark::get_scene_by_name(const string &name)
+{
+    map<string, Scene *>::const_iterator iter;
+
+    if ((iter = mSceneMap.find(name)) != mSceneMap.end())
+        return *(iter->second);
+    else
+        return Scene::dummy();
+}
+
+Benchmark::Benchmark(Scene &scene, const vector<OptionPair> &options) :
+    mScene(scene), mOptions(options)
+{
+}
+
+Benchmark::Benchmark(const string &name, const vector<OptionPair> &options) :
+    mScene(Benchmark::get_scene_by_name(name)), mOptions(options)
+{
+}
+
+Benchmark::Benchmark(const string &s) :
+    mScene(get_scene_from_description(s)),
+    mOptions(get_options_from_description(s))
+{
+}
+
+Scene &
+Benchmark::setup_scene()
+{
+    mScene.reset_options();
+    load_options();
+
+    mScene.load();
+    mScene.setup();
+
+    return mScene;
+}
+
+void
+Benchmark::teardown_scene()
+{
+    mScene.teardown();
+    mScene.unload();
+}
+
+void
+Benchmark::load_options()
+{
+    for (vector<OptionPair>::iterator iter = mOptions.begin();
+         iter != mOptions.end();
+         iter++)
+    {
+        mScene.set_option(iter->first, iter->second);
+    }
+}
+

=== added file 'src/benchmark.h'
--- src/benchmark.h	1970-01-01 00:00:00 +0000
+++ src/benchmark.h	2011-06-09 14:07:23 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+ *
+ * glmark2 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * glmark2.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis (glmark2)
+ */
+#ifndef GLMARK2_BENCHMARK_H_
+#define GLMARK2_BENCHMARK_H_
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "scene.h"
+
+class Benchmark
+{
+public:
+    typedef std::pair<std::string, std::string> OptionPair;
+
+    Benchmark(Scene &scene, const std::vector<OptionPair> &options);
+    Benchmark(const std::string &name, const std::vector<OptionPair> &options);
+    // Create a benchmark from a description string of the form:
+    // scene[:opt1=val1:opt2=val2...]
+    Benchmark(const std::string &s);
+
+    Scene &setup_scene();
+    void teardown_scene();
+
+    static void register_scene(Scene &scene);
+    static Scene &get_scene_by_name(const std::string &name);
+    static const std::map<std::string, Scene *> &scenes() { return mSceneMap; }
+
+private:
+    Scene &mScene;
+    std::vector<OptionPair> mOptions;
+
+    void load_options();
+
+    static std::map<std::string, Scene *> mSceneMap;
+};
+
+#endif

=== added file 'src/log.cpp'
--- src/log.cpp	1970-01-01 00:00:00 +0000
+++ src/log.cpp	2011-06-08 11:24:18 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of glcompbench.
+ *
+ * glcompbench is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * glcompbench is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with glcompbench.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ *  Jesse Barker <jesse.barker@linaro.org>
+ */
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "options.h"
+#include "log.h"
+
+void
+Log::info(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stdout, fmt, ap);
+    va_end(ap);
+}
+
+void
+Log::debug(const char *fmt, ...)
+{
+    if (!Options::show_debug)
+        return;
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stdout, fmt, ap);
+    va_end(ap);
+}
+
+void
+Log::error(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+

=== added file 'src/log.h'
--- src/log.h	1970-01-01 00:00:00 +0000
+++ src/log.h	2011-06-08 11:24:18 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of glcompbench.
+ *
+ * glcompbench is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * glcompbench is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with glcompbench.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ *  Jesse Barker <jesse.barker@linaro.org>
+ */
+
+#ifndef LOG_H_
+#define LOG_H_
+
+class Log
+{
+public:
+    static void info(const char *fmt, ...);
+    static void debug(const char *fmt, ...);
+    static void error(const char *fmt, ...);
+};
+
+#endif /* LOG_H_ */

=== modified file 'src/main.cpp'
--- src/main.cpp	2011-01-25 15:00:12 +0000
+++ src/main.cpp	2011-06-10 11:27:56 +0000
@@ -23,6 +23,11 @@
  */
 #include "oglsdl.h"
 #include "scene.h"
+#include "benchmark.h"
+#include "options.h"
+#include "log.h"
+
+#include <iostream>
 
 #if USE_GL
 #include "screen-sdl-gl.h"
@@ -30,16 +35,101 @@
 #include "screen-sdl-glesv2.h"
 #endif
 
-#define UNUSED_PARAM(x) (void)(x)
+using std::vector;
+using std::map;
+using std::string;
+
+static const char *default_benchmarks[] = {
+    "build:use-vbo=false",
+    "build:use-vbo=true",
+    "texture:texture-filter=nearest",
+    "texture:texture-filter=linear",
+    "texture:texture-filter=mipmap",
+    "shading:shading=gouraud",
+    "shading:shading=phong",
+    NULL
+};
+
+bool should_keep_running()
+{
+    bool running = true;
+    SDL_Event event;
+
+    while(SDL_PollEvent(&event))
+    {
+        switch(event.type)
+        {
+            case SDL_QUIT:
+                running = false;
+                break;
+            case SDL_KEYDOWN:
+                if(event.key.keysym.sym == SDLK_ESCAPE)
+                    running = false;
+                break;
+        }
+    }
+
+    return running;
+}
+
+void
+add_default_benchmarks(vector<Benchmark *> &benchmarks)
+{
+    for (const char **s = default_benchmarks; *s != NULL; s++)
+        benchmarks.push_back(new Benchmark(*s));
+}
+
+void
+add_custom_benchmarks(vector<Benchmark *> &benchmarks)
+{
+    for (vector<string>::const_iterator iter = Options::benchmarks.begin();
+         iter != Options::benchmarks.end();
+         iter++)
+    {
+        benchmarks.push_back(new Benchmark(*iter));
+    }
+}
+
+static void
+list_scenes()
+{
+    const map<string, Scene *> &scenes = Benchmark::scenes();
+
+    for (map<string, Scene *>::const_iterator scene_iter = scenes.begin();
+         scene_iter != scenes.end();
+         scene_iter++)
+    {
+        Scene *scene = scene_iter->second;
+        Log::info("[Scene] %s\n", scene->name().c_str());
+
+        const map<string, Scene::Option> &options = scene->options();
+
+        for (map<string, Scene::Option>::const_iterator opt_iter = options.begin();
+             opt_iter != options.end();
+             opt_iter++)
+        {
+            const Scene::Option &opt = opt_iter->second;
+            Log::info("  [Option] %s\n"
+                      "    Description  : %s\n"
+                      "    Default Value: %s\n",
+                      opt.name.c_str(), 
+                      opt.description.c_str(),
+                      opt.default_value.c_str());
+        }
+    }
+}
 
 int main(int argc, char *argv[])
 {
-    UNUSED_PARAM(argc);
-    UNUSED_PARAM(argv);
-
-    SDL_Event event;
-    int running = 1;
-    unsigned current_scene = 0;
+    unsigned score = 0;
+
+    if (!Options::parse_args(argc, argv))
+        return 1;
+
+    if (Options::show_help) {
+        Options::print_help();
+        return 0;
+    }
 
     // Create the screen
 #if USE_GL
@@ -53,80 +143,63 @@
         return 1;
     }
 
+    // Register the scenes, so they can be looked-up by name
+    Benchmark::register_scene(*new SceneBuild(screen));
+    Benchmark::register_scene(*new SceneTexture(screen));
+    Benchmark::register_scene(*new SceneShading(screen));
+
+    if (Options::list_scenes) {
+        list_scenes();
+        return 0;
+    }
+
+    // Add the benchmarks to run
+    vector<Benchmark *> benchmarks;
+
+    if (Options::benchmarks.empty())
+        add_default_benchmarks(benchmarks);
+    else
+        add_custom_benchmarks(benchmarks);
+
     printf("=======================================================\n");
     printf("    glmark2 %s\n", GLMARK_VERSION);
     printf("=======================================================\n");
     screen.print_info();
     printf("=======================================================\n");
 
-    // Create the scenes.
-    Scene *scene[] = {
-        new SceneBuild(screen),
-        new SceneTexture(screen),
-        new SceneShading(screen),
-    };
-
-    unsigned num_scenes = sizeof(scene) / sizeof(*scene);
-
-    // Load the first scene
-    if (!scene[current_scene]->load())
-        return 1;
-    scene[current_scene]->start();
-
-    while(running)
+    // Run the benchmarks
+    for (vector<Benchmark *>::iterator bench_iter = benchmarks.begin();
+         bench_iter != benchmarks.end();
+         bench_iter++)
     {
-        while(SDL_PollEvent(&event))
+        bool keep_running = true;
+        Benchmark *bench = *bench_iter;
+        Scene &scene = bench->setup_scene();
+        std::cout << scene.info_string() << std::flush;
+
+        while (scene.is_running() &&
+               (keep_running = should_keep_running()))
         {
-            switch(event.type)
-            {
-            case SDL_QUIT:
-                running = 0;
-                break;
-            case SDL_KEYDOWN:
-                if(event.key.keysym.sym == SDLK_ESCAPE)
-                    running = 0;
-                break;
-            }
-        }
-
-        screen.clear();
-
-        // Update the state of the current scene
-        scene[current_scene]->update();
-
-        // If the current scene is still running then draw it,
-        // otherwise move to the next scene
-        if (scene[current_scene]->is_running()) {
-            scene[current_scene]->draw();
-        }
-        else {
-            // Unload the current scene
-            scene[current_scene]->unload();
-
-            current_scene++;
-
-            // Do we have another scene?
-            if (current_scene < num_scenes) {
-                // Load and start next scene
-                if (!scene[current_scene]->load())
-                    return 1;
-                scene[current_scene]->start();
-            }
-            else
-                running = false;
-        }
-
-
-        screen.update();
+            screen.clear();
+
+            scene.draw();
+            scene.update();
+
+            screen.update();
+        }
+
+        std::cout << " FPS: " << scene.average_fps() << std::endl;
+        score += scene.average_fps();
+
+        bench->teardown_scene();
+
+        if (!keep_running)
+            break;
     }
 
-    unsigned score = 0;
-    for (unsigned i = 0; i < num_scenes; i++)
-        score += scene[i]->calculate_score();
-
     printf("=======================================================\n");
     printf("                                  glmark2 Score: %u \n", score);
-	printf("=======================================================\n");
+    printf("=======================================================\n");
 
     return 0;
 }

=== modified file 'src/mesh.cpp'
--- src/mesh.cpp	2011-01-25 15:00:12 +0000
+++ src/mesh.cpp	2011-06-07 09:40:55 +0000
@@ -44,8 +44,20 @@
 
 Mesh::~Mesh()
 {
+    reset();
+}
+
+void
+Mesh::reset()
+{
     delete [] mVertex;
-    //deleteArray
+
+    delete_vbo();
+
+    mPolygonQty = 0;
+    mVertexQty = 0;
+    mMode = GL_TRIANGLES;
+    mVertex = 0;
 }
 
 void Mesh::make_cube()
@@ -180,6 +192,14 @@
 #endif
 }
 
+void
+Mesh::delete_vbo()
+{
+    glDeleteBuffers(1, &mVBOVertices);
+    glDeleteBuffers(1, &mVBONormals);
+    glDeleteBuffers(1, &mVBOTexCoords);
+}
+
 void Mesh::render_vbo()
 {
     // Enable the attributes

=== modified file 'src/mesh.h'
--- src/mesh.h	2011-01-25 15:06:04 +0000
+++ src/mesh.h	2011-06-07 09:40:55 +0000
@@ -64,10 +64,12 @@
     Mesh();                 // Default Constructor, should set pointers to null
     ~Mesh();
 
+    void reset();
     void make_cube();
     void make_torus();
     void render_array();
     void build_vbo();
+    void delete_vbo();
     void render_vbo();
 };
 

=== modified file 'src/model.cpp'
--- src/model.cpp	2011-01-25 15:00:12 +0000
+++ src/model.cpp	2011-06-07 09:40:55 +0000
@@ -49,6 +49,8 @@
 #ifdef _DEBUG
     printf("Converting model to mesh...      ");
 #endif
+    pMesh->reset();
+
     pMesh->mVertexQty = 3 * mPolygonQty;
     pMesh->mPolygonQty = mPolygonQty;
     pMesh->mMode = GL_TRIANGLES;

=== added file 'src/options.cpp'
--- src/options.cpp	1970-01-01 00:00:00 +0000
+++ src/options.cpp	2011-06-09 14:54:24 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of glcompbench.
+ *
+ * glcompbench is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * glcompbench is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with glcompbench.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ *  Jesse Barker <jesse.barker@linaro.org>
+ */
+
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+#include <getopt.h>
+
+#include "options.h"
+
+std::vector<std::string> Options::benchmarks;
+bool Options::swap_buffers = true;
+bool Options::list_scenes = false;
+bool Options::show_debug = false;
+bool Options::show_help = false;
+
+static struct option long_options[] = {
+    {"benchmark", 1, 0, 0},
+    {"no-swap-buffers", 0, 0, 0},
+    {"list-scenes", 0, 0, 0},
+    {"debug", 0, 0, 0},
+    {"help", 0, 0, 0},
+    {0, 0, 0, 0}
+};
+
+void
+Options::print_help()
+{
+    printf("A benchmark for Open GL (ES) 2.0\n"
+           "\n"
+           "Options:\n"
+           "  -b, --benchmark BENCH  A benchmark to run: 'scene(:opt1=val1)*'\n"
+           "                         (the option can be used multiple times)\n"
+           "      --no-swap-buffers  Don't update the screen by swapping the front and\n"
+           "                         back buffer, use glFinish() instead\n"
+           "  -l, --list-scenes      Display information about the available scenes\n"
+           "                         and their options\n"
+           "  -d, --debug            Display debug messages\n"
+           "  -h, --help             Display help\n");
+}
+
+bool
+Options::parse_args(int argc, char **argv)
+{
+    while (1) {
+        int option_index = -1;
+        int c;
+        const char *optname = "";
+
+        c = getopt_long(argc, argv, "b:ldh",
+                        long_options, &option_index);
+        if (c == -1)
+            break;
+        if (c == ':' || c == '?')
+            return false;
+
+        if (option_index != -1)
+            optname = long_options[option_index].name;
+
+        if (c == 'b' || !strcmp(optname, "benchmark"))
+            Options::benchmarks.push_back(optarg);
+        else if (!strcmp(optname, "no-swap-buffers"))
+            Options::swap_buffers = false;
+        else if (c == 'l' || !strcmp(optname, "list-scenes"))
+            Options::list_scenes = true;
+        else if (c == 'd' || !strcmp(optname, "debug"))
+            Options::show_debug = true;
+        else if (c == 'h' || !strcmp(optname, "help"))
+            Options::show_help = true;
+    }
+
+    return true;
+}

=== added file 'src/options.h'
--- src/options.h	1970-01-01 00:00:00 +0000
+++ src/options.h	2011-06-09 14:24:50 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2011 Linaro Limited
+ *
+ * This file is part of glcompbench.
+ *
+ * glcompbench is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * glcompbench is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with glcompbench.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ *  Jesse Barker <jesse.barker@linaro.org>
+ */
+
+#ifndef OPTIONS_H_
+#define OPTIONS_H_
+
+#include <string>
+#include <vector>
+
+struct Options {
+    static bool parse_args(int argc, char **argv);
+    static void print_help();
+
+    static std::vector<std::string> benchmarks;
+    static bool swap_buffers;
+    static bool list_scenes;
+    static bool show_debug;
+    static bool show_help;
+};
+
+#endif /* OPTIONS_H_ */

=== modified file 'src/scene.cpp'
--- src/scene.cpp	2011-01-25 15:00:12 +0000
+++ src/scene.cpp	2011-06-07 21:06:38 +0000
@@ -22,32 +22,23 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "scene.h"
-
-Scene::Scene(Screen &pScreen) :
-    mScreen(pScreen)
+#include <sstream>
+
+using std::stringstream;
+using std::string;
+using std::map;
+
+Scene::Scene(Screen &pScreen, const string &name) :
+    mScreen(pScreen), mName(name),
+    mStartTime(0), mLastUpdateTime(0), mCurrentFrame(0), mAverageFPS(0), 
+    mRunning(0), mDuration(0)
 {
-    mPartsQty = 0;
-    mCurrentPart = 0;
-    mPartDuration = 0;
-
-    mLastTime = 0;
-    mCurrentTime = 0;
-    mDt = 0;
-    mCurrentFrame = 0;
-    mRunning = false;
-
-    mAverageFPS = 0;
-    mScoreScale = 0;
-
-    mStartTime = 0;
-    mElapsedTime = 0;
+    mOptions["duration"] = Scene::Option("duration", "10.0",
+                                         "The duration of each benchmark in seconds");
 }
 
 Scene::~Scene()
 {
-    delete [] mPartDuration;
-    delete [] mAverageFPS;
-    delete [] mScoreScale;
 }
 
 int Scene::load()
@@ -59,7 +50,13 @@
 {
 }
 
-void Scene::start()
+void Scene::setup()
+{
+    stringstream ss(mOptions["duration"].value);
+    ss >> mDuration;
+}
+
+void Scene::teardown()
 {
 }
 
@@ -71,14 +68,19 @@
 {
 }
 
-unsigned Scene::calculate_score()
-{
-    unsigned mScore = 0;
-
-    for(unsigned i = 0; i < mPartsQty; i++)
-        mScore += mAverageFPS[i] * mScoreScale[i];
-
-    return mScore;
+string
+Scene::info_string(const string &title)
+{
+    stringstream ss;
+
+    ss << "[" << mName << "] " << Scene::construct_title(title) << " ";
+
+    return ss.str();
+}
+
+unsigned Scene::average_fps()
+{
+    return mAverageFPS;
 }
 
 
@@ -86,3 +88,49 @@
 {
     return mRunning;
 }
+
+bool
+Scene::set_option(const string &opt, const string &val)
+{ 
+    map<string, Option>::iterator iter = mOptions.find(opt);
+
+    if (iter == mOptions.end())
+        return false;
+
+    iter->second.value = val;
+
+    return true;
+}
+
+void
+Scene::reset_options()
+{
+    for (map<string, Option>::iterator iter = mOptions.begin();
+         iter != mOptions.end();
+         iter++)
+    {
+        Option &opt = iter->second;
+
+        opt.value = opt.default_value;
+    }
+}
+
+
+string
+Scene::construct_title(const string &title)
+{
+    stringstream ss;
+
+    if (title == "") {
+        for (map<string, Option>::iterator iter = mOptions.begin();
+             iter != mOptions.end();
+             iter++)
+        {
+            ss << iter->first << "=" << iter->second.value << ":";
+        }
+    }
+    else
+        ss << title;
+
+    return ss.str();
+}

=== modified file 'src/scene.h'
--- src/scene.h	2011-01-25 15:06:04 +0000
+++ src/scene.h	2011-06-09 13:07:57 +0000
@@ -33,46 +33,80 @@
 
 #include <math.h>
 
+#include <string>
+#include <map>
+
 class Scene
 {
 public:
-    Scene(Screen &pScreen);
     ~Scene();
 
+    struct Option {
+        Option(const std::string &nam, const std::string &val, const std::string &desc) :
+            name(nam), value(val), default_value(val), description(desc) {}
+        Option() {}
+        std::string name;
+        std::string value;
+        std::string default_value;
+        std::string description;
+    };
+
+    // load() and unload() handle option-independent configuration.
+    // It should be safe to call these only once per program execution,
+    // although you may choose to do so more times to better manage
+    // resource consumption.
     virtual int load();
     virtual void unload();
-    virtual void start();
+
+    // setup() and teardown() handle option-dependent configuration and
+    // also prepare a scene for a benchmark run.
+    // They should be called just before and after running a scene/benchmark.
+    virtual void setup();
+    virtual void teardown();
+
     virtual void update();
     virtual void draw();
+    virtual std::string info_string(const std::string &title = "");
 
-    unsigned calculate_score();
+    unsigned average_fps();
     bool is_running();
 
+    const std::string &name() { return mName; }
+    bool set_option(const std::string &opt, const std::string &val);
+    void reset_options();
+    const std::map<std::string, Option> &options() { return mOptions; }
+
+    static Scene &dummy()
+    {
+        static Scene dummy_scene(Screen::dummy(), "");
+        return dummy_scene;
+    }
+
 protected:
-    unsigned mPartsQty;         // How many parts for the scene
-    unsigned mCurrentPart;      // The current part being rendered
-    double *mPartDuration;      // Duration per part in seconds
-
-    double mLastTime, mCurrentTime, mDt;
+    Scene(Screen &pScreen, const std::string &name);
+    std::string construct_title(const std::string &title);
+
+    Screen &mScreen;
+    std::string mName;
+    std::map<std::string, Option> mOptions;
+
+    double mStartTime;
+    double mLastUpdateTime;
     unsigned mCurrentFrame;
+    unsigned mAverageFPS;      // Average FPS of run
+
     bool mRunning;
-
-    unsigned *mAverageFPS;      // Average FPS per part
-    float *mScoreScale;
-
-    double mStartTime;
-    double mElapsedTime;
-
-    Screen &mScreen;
+    double mDuration;      // Duration of run in seconds
 };
 
 class SceneBuild : public Scene
 {
 public:
-    SceneBuild(Screen &pScreen) : Scene(pScreen) {}
+    SceneBuild(Screen &pScreen);
     int load();
     void unload();
-    void start();
+    void setup();
+    void teardown();
     void update();
     void draw();
 
@@ -84,15 +118,17 @@
     Mesh mMesh;
     float mRotation;
     float mRotationSpeed;
+    bool mUseVbo;
 };
 
 class SceneTexture : public Scene
 {
 public:
-    SceneTexture(Screen &pScreen) : Scene(pScreen) {}
+    SceneTexture(Screen &pScreen);
     int load();
     void unload();
-    void start();
+    void setup();
+    void teardown();
     void update();
     void draw();
 
@@ -102,7 +138,7 @@
     Shader mShader;
 
     Mesh mCubeMesh;
-    GLuint mTexture[3];
+    GLuint mTexture;
     Vector3f mRotation;
     Vector3f mRotationSpeed;
 };
@@ -110,17 +146,18 @@
 class SceneShading : public Scene
 {
 public:
-    SceneShading(Screen &pScreen) : Scene(pScreen) {}
+    SceneShading(Screen &pScreen);
     int load();
     void unload();
-    void start();
+    void setup();
+    void teardown();
     void update();
     void draw();
 
     ~SceneShading();
 
 protected:
-    Shader mShader[2];
+    Shader mShader;
 
     Mesh mMesh;
     float mRotation;

=== modified file 'src/scenebuild.cpp'
--- src/scenebuild.cpp	2011-01-25 15:00:12 +0000
+++ src/scenebuild.cpp	2011-06-07 14:36:16 +0000
@@ -23,6 +23,13 @@
  */
 #include "scene.h"
 
+SceneBuild::SceneBuild(Screen &pScreen) :
+    Scene(pScreen, "build")
+{
+    mOptions["use-vbo"] = Scene::Option("use-vbo", "true",
+                                        "Whether to use VBOs for rendering [true,false]");
+}
+
 SceneBuild::~SceneBuild()
 {
 }
@@ -37,47 +44,38 @@
     model.calculate_normals();
     model.convert_to_mesh(&mMesh);
 
-    mMesh.build_vbo();
-
     mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
                  GLMARK_DATA_PATH"/shaders/light-basic.frag");
 
     mRotationSpeed = 36.0f;
-    mRotation = 0.0;
 
     mRunning = false;
 
-    mPartsQty = 2;
-    mPartDuration = new double[mPartsQty];
-    mAverageFPS = new unsigned[mPartsQty];
-    mScoreScale = new float[mPartsQty];
-
-    mScoreScale[0] = 1.0f / mPartsQty;
-    mScoreScale[1] = 1.0f / mPartsQty;
-
-    mPartDuration[0] = 10.0;
-    mPartDuration[1] = 10.0;
-
-    memset(mAverageFPS, 0, mPartsQty * sizeof(*mAverageFPS));
-
-    mCurrentPart = 0;
-
     return 1;
 }
 
 void SceneBuild::unload()
 {
+    mMesh.reset();
     mShader.remove();
     mShader.unload();
 }
 
-void SceneBuild::start()
+void SceneBuild::setup()
 {
+    Scene::setup();
+
     GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
     GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
     GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
 
+
+    mUseVbo = (mOptions["use-vbo"].value == "true");
+
+    if (mUseVbo)
+        mMesh.build_vbo();
+
     mShader.use();
 
     // Load lighting and material uniforms
@@ -89,43 +87,37 @@
     glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
 
     mCurrentFrame = 0;
+    mRotation = 0.0;
     mRunning = true;
     mStartTime = SDL_GetTicks() / 1000.0;
-    mLastTime = mStartTime;
-
-    if (mCurrentPart == 0)
-        printf("[Suite] Precompilation\n");
+    mLastUpdateTime = mStartTime;
+}
+
+void
+SceneBuild::teardown()
+{
+    mShader.remove();
+
+    if (mUseVbo)
+        mMesh.delete_vbo();
+
+    Scene::teardown();
 }
 
 void SceneBuild::update()
 {
-    mCurrentTime = SDL_GetTicks() / 1000.0;
-    mDt = mCurrentTime - mLastTime;
-    mLastTime = mCurrentTime;
-
-    mElapsedTime = mCurrentTime - mStartTime;
-
-    if(mElapsedTime >= mPartDuration[mCurrentPart])
-    {
-        mAverageFPS[mCurrentPart] = mCurrentFrame / mElapsedTime;
-
-        switch(mCurrentPart)
-        {
-        case 0:
-            printf("    [Benchmark] Vertex array                FPS: %u\n", mAverageFPS[mCurrentPart]);
-            break;
-        case 1:
-            printf("    [Benchmark] Vertex buffer object        FPS: %u\n", mAverageFPS[mCurrentPart]);
-            break;
-        }
-        mCurrentPart++;
-        if(mCurrentPart >= mPartsQty)
-            mRunning = false;
-        else
-            start();
+    double current_time = SDL_GetTicks() / 1000.0;
+    double dt = current_time - mLastUpdateTime;
+    double elapsed_time = current_time - mStartTime;
+
+    mLastUpdateTime = current_time;
+
+    if (elapsed_time >= mDuration) {
+        mAverageFPS = mCurrentFrame / elapsed_time;
+        mRunning = false;
     }
 
-    mRotation += mRotationSpeed * mDt;
+    mRotation += mRotationSpeed * dt;
 
     mCurrentFrame++;
 }
@@ -149,13 +141,8 @@
     glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
                        GL_FALSE, model_view.m);
 
-    switch(mCurrentPart)
-    {
-    case 0:
+    if (mUseVbo)
+        mMesh.render_vbo();
+    else
         mMesh.render_array();
-        break;
-    case 1:
-        mMesh.render_vbo();
-        break;
-    }
 }

=== modified file 'src/sceneshading.cpp'
--- src/sceneshading.cpp	2011-01-25 15:00:12 +0000
+++ src/sceneshading.cpp	2011-06-07 21:06:38 +0000
@@ -24,6 +24,13 @@
 #include "scene.h"
 #include "matrix.h"
 
+SceneShading::SceneShading(Screen &pScreen) :
+    Scene(pScreen, "shading")
+{
+    mOptions["shading"] = Scene::Option("shading", "gouraud",
+                                        "[gouraud, phong]");
+}
+
 SceneShading::~SceneShading()
 {
 }
@@ -40,44 +47,22 @@
 
     mMesh.build_vbo();
 
-    mShader[0].load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                    GLMARK_DATA_PATH"/shaders/light-basic.frag");
-    mShader[1].load(GLMARK_DATA_PATH"/shaders/light-advanced.vert",
-                    GLMARK_DATA_PATH"/shaders/light-advanced.frag");
-
     mRotationSpeed = 36.0f;
-    mRotation = 0.0f;
 
     mRunning = false;
 
-    mPartsQty = 2;
-    mPartDuration = new double[mPartsQty];
-    mAverageFPS = new unsigned[mPartsQty];
-    mScoreScale = new float[mPartsQty];
-
-    mScoreScale[0] = 1.0f / mPartsQty;
-    mScoreScale[1] = 1.0f / mPartsQty;
-
-    mPartDuration[0] = 10.0;
-    mPartDuration[1] = 10.0;
-
-    memset(mAverageFPS, 0, mPartsQty * sizeof(*mAverageFPS));
-
-    mCurrentPart = 0;
-
     return 1;
 }
 
 void SceneShading::unload()
 {
-    for(unsigned i = 0; i < mPartsQty; i++) {
-        mShader[i].remove();
-        mShader[i].unload();
-    }
+    mMesh.reset();
 }
 
-void SceneShading::start()
+void SceneShading::setup()
 {
+    Scene::setup();
+
     GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 1.0f};
     GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
     GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
@@ -88,67 +73,68 @@
     float materialSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
     float materialColor[] = {0.0f, 0.0f, 1.0f, 1.0f};
 
-    mShader[mCurrentPart].use();
+    const std::string &shading = mOptions["shading"].value;
+
+    if (shading == "gouraud") {
+        mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
+                     GLMARK_DATA_PATH"/shaders/light-basic.frag");
+    }
+    else if (shading == "phong") {
+        mShader.load(GLMARK_DATA_PATH"/shaders/light-advanced.vert",
+                     GLMARK_DATA_PATH"/shaders/light-advanced.frag");
+    }
+
+    mShader.use();
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader[mCurrentPart].mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader[mCurrentPart].mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader[mCurrentPart].mLocations.LightSourceDiffuse, 1, lightDiffuse);
-    glUniform3fv(mShader[mCurrentPart].mLocations.LightSourceSpecular, 1, lightSpecular);
-
-    glUniform3fv(mShader[mCurrentPart].mLocations.MaterialAmbient, 1, materialAmbient);
-    glUniform3fv(mShader[mCurrentPart].mLocations.MaterialDiffuse, 1, materialDiffuse);
-    glUniform3fv(mShader[mCurrentPart].mLocations.MaterialSpecular, 1, materialSpecular);
-    glUniform4fv(mShader[mCurrentPart].mLocations.MaterialColor, 1, materialColor);
+    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
+
+    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
+    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
+    glUniform3fv(mShader.mLocations.LightSourceSpecular, 1, lightSpecular);
+
+    glUniform3fv(mShader.mLocations.MaterialAmbient, 1, materialAmbient);
+    glUniform3fv(mShader.mLocations.MaterialDiffuse, 1, materialDiffuse);
+    glUniform3fv(mShader.mLocations.MaterialSpecular, 1, materialSpecular);
+    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
 
     // Calculate and load the half vector
     Vector3f halfVector = Vector3f(lightPosition[0], lightPosition[1], lightPosition[2]);
     halfVector.normalize();
     halfVector += Vector3f(0.0, 0.0, 1.0);
     halfVector.normalize();
-    glUniform3fv(mShader[mCurrentPart].mLocations.LightSourceHalfVector, 1,
+    glUniform3fv(mShader.mLocations.LightSourceHalfVector, 1,
                  (GLfloat *)&halfVector);
 
     mCurrentFrame = 0;
+    mRotation = 0.0f;
     mRunning = true;
     mStartTime = SDL_GetTicks() / 1000.0;
-    mLastTime = mStartTime;
-
-    if (mCurrentPart == 0)
-        printf("[Suite] Shading\n");
+    mLastUpdateTime = mStartTime;
+}
+
+void SceneShading::teardown()
+{
+    mShader.remove();
+    mShader.unload();
+
+    Scene::teardown();
 }
 
 void SceneShading::update()
 {
-    mCurrentTime = SDL_GetTicks() / 1000.0;
-    mDt = mCurrentTime - mLastTime;
-    mLastTime = mCurrentTime;
-
-    mElapsedTime = mCurrentTime - mStartTime;
-
-    if(mElapsedTime >= mPartDuration[mCurrentPart])
-    {
-        mAverageFPS[mCurrentPart] = mCurrentFrame / mElapsedTime;
-
-        switch(mCurrentPart) {
-            case 0:
-                printf("    [Benchmark] GLSL per vertex lighting    FPS: %u\n",
-                       mAverageFPS[mCurrentPart]);
-                break;
-            case 1:
-                printf("    [Benchmark] GLSL per pixel lighting     FPS: %u\n",
-                       mAverageFPS[mCurrentPart]);
-                break;
-        }
-        mCurrentPart++;
-        if(mCurrentPart >= mPartsQty)
-            mRunning = false;
-        else
-            start();
+    double current_time = SDL_GetTicks() / 1000.0;
+    double dt = current_time - mLastUpdateTime;
+    double elapsed_time = current_time - mStartTime;
+
+    mLastUpdateTime = current_time;
+
+    if (elapsed_time >= mDuration) {
+        mAverageFPS = mCurrentFrame / elapsed_time;
+        mRunning = false;
     }
 
-    mRotation += mRotationSpeed * mDt;
+    mRotation += mRotationSpeed * dt;
 
     mCurrentFrame++;
 }
@@ -163,13 +149,13 @@
     model_view.rotate(2 * M_PI * mRotation / 360.0, 0.0f, 1.0f, 0.0f);
     model_view_proj *= model_view;
 
-    glUniformMatrix4fv(mShader[mCurrentPart].mLocations.ModelViewProjectionMatrix, 1,
+    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
                        GL_FALSE, model_view_proj.m);
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
     model_view.invert().transpose();
-    glUniformMatrix4fv(mShader[mCurrentPart].mLocations.NormalMatrix, 1,
+    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
                        GL_FALSE, model_view.m);
 
     mMesh.render_vbo();

=== modified file 'src/scenetexture.cpp'
--- src/scenetexture.cpp	2011-01-25 15:00:12 +0000
+++ src/scenetexture.cpp	2011-06-07 21:06:38 +0000
@@ -24,10 +24,15 @@
 #include "scene.h"
 #include "matrix.h"
 
+SceneTexture::SceneTexture(Screen &pScreen) :
+    Scene(pScreen, "texture")
+{
+    mOptions["texture-filter"] = Scene::Option("texture-filter", "nearest",
+                                               "[nearest, linear, mipmap]");
+}
+
 SceneTexture::~SceneTexture()
 {
-    for(unsigned i = 0; i < 3; i++)
-        glDeleteTextures(1, &mTexture[i]);
 }
 
 int SceneTexture::load()
@@ -37,9 +42,6 @@
     if(!model.load_3ds(GLMARK_DATA_PATH"/models/cube.3ds"))
         return 0;
 
-    if(!load_texture(GLMARK_DATA_PATH"/textures/crate-base.bmp", mTexture))
-        return 0;
-
     model.calculate_normals();
     model.convert_to_mesh(&mCubeMesh);
     mCubeMesh.build_vbo();
@@ -51,39 +53,45 @@
 
     mRunning = false;
 
-    mPartsQty = 3;
-    mPartDuration = new double[mPartsQty];
-    mAverageFPS = new unsigned[mPartsQty];
-    mScoreScale = new float[mPartsQty];
-
-    mScoreScale[0] = 1.0f / mPartsQty;
-    mScoreScale[1] = 1.0f / mPartsQty;
-    mScoreScale[2] = 1.0f / mPartsQty;
-
-    mPartDuration[0] = 10.0;
-    mPartDuration[1] = 10.0;
-    mPartDuration[2] = 10.0;
-
-    memset(mAverageFPS, 0, mPartsQty * sizeof(*mAverageFPS));
-
-    mCurrentPart = 0;
-
     return 1;
 }
 
 void SceneTexture::unload()
 {
-    mShader.remove();
+    mCubeMesh.reset();
     mShader.unload();
 }
 
-void SceneTexture::start()
+void SceneTexture::setup()
 {
+    Scene::setup();
+
     GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
     GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
     GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
 
+    // Create texture according to selected filtering
+    GLint min_filter = GL_NONE;
+    GLint mag_filter = GL_NONE;
+    const std::string &filter = mOptions["texture-filter"].value;
+
+    if (filter == "nearest") {
+        min_filter = GL_NEAREST;
+        mag_filter = GL_NEAREST;
+    }
+    else if (filter == "linear") {
+        min_filter = GL_LINEAR;
+        mag_filter = GL_LINEAR;
+    }
+    else if (filter == "mipmap") {
+        min_filter = GL_LINEAR_MIPMAP_LINEAR;
+        mag_filter = GL_LINEAR;
+    }
+
+    Texture::load(GLMARK_DATA_PATH"/textures/crate-base.bmp", &mTexture,
+                  min_filter, mag_filter, 0);
+
     mShader.use();
 
     // Load lighting and material uniforms
@@ -95,45 +103,34 @@
     glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
 
     mCurrentFrame = 0;
+    mRotation = Vector3f();
     mRunning = true;
     mStartTime = SDL_GetTicks() / 1000.0;
-    mLastTime = mStartTime;
-
-    if (mCurrentPart == 0)
-        printf("[Suite] Texture filtering\n");
+    mLastUpdateTime = mStartTime;
+}
+
+void SceneTexture::teardown()
+{
+    mShader.remove();
+    glDeleteTextures(1, &mTexture);
+
+    Scene::teardown();
 }
 
 void SceneTexture::update()
 {
-    mCurrentTime = SDL_GetTicks() / 1000.0;
-    mDt = mCurrentTime - mLastTime;
-    mLastTime = mCurrentTime;
-
-    mElapsedTime = mCurrentTime - mStartTime;
-
-    if(mElapsedTime >= mPartDuration[mCurrentPart])
-    {
-        mAverageFPS[mCurrentPart] = mCurrentFrame / mElapsedTime;
-
-        switch(mCurrentPart) {
-            case 0:
-                printf("    [Benchmark] Nearest                     FPS: %u\n",  mAverageFPS[mCurrentPart]);
-                break;
-            case 1:
-                printf("    [Benchmark] Linear                      FPS: %u\n",  mAverageFPS[mCurrentPart]);
-                break;
-            case 2:
-                printf("    [Benchmark] Mipmapped                   FPS: %u\n",  mAverageFPS[mCurrentPart]);
-                break;
-        }
-        mCurrentPart++;
-        if(mCurrentPart >= mPartsQty)
-            mRunning = false;
-        else
-            start();
+    double current_time = SDL_GetTicks() / 1000.0;
+    double dt = current_time - mLastUpdateTime;
+    double elapsed_time = current_time - mStartTime;
+
+    mLastUpdateTime = current_time;
+
+    if (elapsed_time >= mDuration) {
+        mAverageFPS = mCurrentFrame / elapsed_time;
+        mRunning = false;
     }
 
-    mRotation += mRotationSpeed * mDt;
+    mRotation += mRotationSpeed * dt;
 
     mCurrentFrame++;
 }
@@ -160,7 +157,7 @@
                        GL_FALSE, model_view.m);
 
     glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, mTexture[mCurrentPart]);
+    glBindTexture(GL_TEXTURE_2D, mTexture);
 
     mCubeMesh.render_vbo();
 }

=== modified file 'src/screen-sdl-gl.cpp'
--- src/screen-sdl-gl.cpp	2011-01-25 15:00:12 +0000
+++ src/screen-sdl-gl.cpp	2011-06-09 10:13:18 +0000
@@ -22,6 +22,7 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "screen-sdl-gl.h"
+#include "options.h"
 
 ScreenSDLGL::ScreenSDLGL(int pWidth, int pHeight, int pBpp, int pFullScreen, int pFlags)
     : ScreenSDL(pWidth, pHeight, pBpp, pFullScreen, pFlags | SDL_OPENGL)
@@ -50,7 +51,10 @@
 
 void ScreenSDLGL::update()
 {
-    SDL_GL_SwapBuffers();
+    if (Options::swap_buffers)
+        SDL_GL_SwapBuffers();
+    else
+        glFinish();
 }
 
 void ScreenSDLGL::print_info()

=== modified file 'src/screen-sdl-glesv2.cpp'
--- src/screen-sdl-glesv2.cpp	2011-04-15 18:20:15 +0000
+++ src/screen-sdl-glesv2.cpp	2011-06-09 10:13:18 +0000
@@ -23,6 +23,7 @@
  */
 #include "screen-sdl-glesv2.h"
 #include "sdlgles/SDL_gles.h"
+#include "options.h"
 
 ScreenSDLGLESv2::ScreenSDLGLESv2(int pWidth, int pHeight, int pBpp, int pFullScreen, int pFlags)
     : ScreenSDL(pWidth, pHeight, pBpp, pFullScreen, pFlags)
@@ -96,7 +97,10 @@
 
 void ScreenSDLGLESv2::update()
 {
-    SDL_GLES_SwapBuffers();
+    if (Options::swap_buffers)
+        SDL_GLES_SwapBuffers();
+    else
+        glFinish();
 }
 
 void ScreenSDLGLESv2::print_info()

=== modified file 'src/screen.h'
--- src/screen.h	2011-01-25 15:06:04 +0000
+++ src/screen.h	2011-06-09 13:07:57 +0000
@@ -32,6 +32,8 @@
 class Screen
 {
 public:
+    ~Screen() {}
+
     int mWidth;
     int mHeight;
     int mBpp;
@@ -39,9 +41,18 @@
     Matrix4f mProjection;
     int mInitSuccess;
 
-    virtual void clear() = 0;
-    virtual void update() = 0;
-    virtual void print_info() = 0;
+    virtual void clear() {}
+    virtual void update() {}
+    virtual void print_info() {}
+
+    static Screen &dummy()
+    {
+        static Screen dummy_screen;
+        return dummy_screen;
+    }
+
+protected:
+    Screen() {}
 };
 
 #endif

=== modified file 'src/texture.cpp'
--- src/texture.cpp	2011-01-25 15:00:12 +0000
+++ src/texture.cpp	2011-06-08 08:44:03 +0000
@@ -23,13 +23,32 @@
  */
 #include "texture.h"
 
-int load_texture(const char pFilename[], GLuint *pTexture)
+static void
+setup_texture(GLuint *tex, GLenum format, SDL_Surface *surface,
+              GLint min_filter, GLint mag_filter)
+{
+    glGenTextures(1, tex);
+    glBindTexture(GL_TEXTURE_2D, *tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
+    glTexImage2D(GL_TEXTURE_2D, 0, format, surface->w, surface->h, 0,
+                 format, GL_UNSIGNED_BYTE, surface->pixels);
+
+    if ((min_filter != GL_NEAREST && min_filter != GL_LINEAR) ||
+        (mag_filter != GL_NEAREST && mag_filter != GL_LINEAR))
+    {
+        glGenerateMipmap(GL_TEXTURE_2D);
+    }
+}
+
+int
+Texture::load(const std::string &filename, GLuint *pTexture, ...)
 {
     SDL_Surface *surface;
     GLenum texture_format = GL_RGB;
     GLint  nOfColors;
 
-    if ((surface = SDL_LoadBMP(pFilename))) {
+    if ((surface = SDL_LoadBMP(filename.c_str()))) {
         if ((surface->w & (surface->w - 1)) != 0)
             printf("warning: image.bmp's width is not a power of 2\n");
 
@@ -79,29 +98,17 @@
             printf("warning: the image is not truecolor..  this will probably break\n");
         }
 
-        glGenTextures(3, pTexture);
-
-        // Create Nearest Filtered Texture
-        glBindTexture(GL_TEXTURE_2D, pTexture[0]);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface->w, surface->h, 0,
-                     texture_format, GL_UNSIGNED_BYTE, surface->pixels);
-
-        // Create Linear Filtered Texture
-        glBindTexture(GL_TEXTURE_2D, pTexture[1]);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface->w, surface->h, 0,
-                     texture_format, GL_UNSIGNED_BYTE, surface->pixels);
-
-        // Create trilinear filtered mipmapped texture
-        glBindTexture(GL_TEXTURE_2D, pTexture[2]);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-        glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface->w, surface->h, 0,
-                     texture_format, GL_UNSIGNED_BYTE, surface->pixels);
-        glGenerateMipmap(GL_TEXTURE_2D);
+        va_list ap;
+        va_start(ap, pTexture);
+        GLint arg;
+
+        while ((arg = va_arg(ap, GLint)) != 0) {
+            GLint arg2 = va_arg(ap, GLint);
+            setup_texture(pTexture, texture_format, surface, arg, arg2);
+            pTexture++;
+        }
+
+        va_end(ap);
     }
     else {
         fprintf(stderr, "SDL could not load image.bmp: %s\n", SDL_GetError());

=== modified file 'src/texture.h'
--- src/texture.h	2011-01-25 15:06:04 +0000
+++ src/texture.h	2011-06-08 08:44:03 +0000
@@ -26,8 +26,12 @@
 
 #include "oglsdl.h"
 
-#include <stdio.h>
+#include <string>
 
-int load_texture(const char pFilename[], GLuint *pTexture);
+class Texture
+{
+public:
+    static int load(const std::string &filename, GLuint *pTexture, ...);
+};
 
 #endif

