]> git.tdb.fi Git - libs/gl.git/blobdiff - demos/desertpillars.cpp
Rename Pipeline to Sequence
[libs/gl.git] / demos / desertpillars.cpp
index b5cdde063b7b62b674177f71694abe0a3b52a73b..d741beea5390b0eb8307fdb78d401fb47c62b314 100644 (file)
@@ -5,6 +5,7 @@
 #include <msp/gl/animatedobject.h>
 #include <msp/gl/bloom.h>
 #include <msp/gl/box.h>
+#include <msp/gl/colorcurve.h>
 #include <msp/gl/cylinder.h>
 #include <msp/gl/environmentmap.h>
 #include <msp/gl/framebuffer.h>
 #include <msp/gl/instancescene.h>
 #include <msp/gl/light.h>
 #include <msp/gl/lighting.h>
-#include <msp/gl/material.h>
+#include <msp/gl/basicmaterial.h>
 #include <msp/gl/mesh.h>
 #include <msp/gl/meshbuilder.h>
 #include <msp/gl/object.h>
-#include <msp/gl/pipeline.h>
+#include <msp/gl/sequence.h>
 #include <msp/gl/program.h>
-#include <msp/gl/programbuilder.h>
 #include <msp/gl/renderer.h>
+#include <msp/gl/resources.h>
 #include <msp/gl/shader.h>
 #include <msp/gl/shadowmap.h>
 #include <msp/gl/simplescene.h>
 #include <msp/gl/technique.h>
 #include <msp/gl/tests.h>
 #include <msp/gl/texturecube.h>
+#include <msp/gl/windowview.h>
 #include <msp/graphics/simplewindow.h>
 #include <msp/input/keyboard.h>
 #include <msp/input/keys.h>
 #include <msp/time/timestamp.h>
-#include <msp/time/units.h>
+#include <msp/time/timedelta.h>
 #include <msp/time/utils.h>
 
 using namespace std;
@@ -44,7 +46,7 @@ including:
 - Shadow mapping
 - Environment mapped reflections
 - Skybox using a cube map texture
-- Nested scenes and pipelines
+- Effects with nested sequences
 - Complex multitexturing
 - Shader-based deformations
 - Creating a normalmapped texture through rendering
@@ -95,13 +97,15 @@ private:
        Msp::Graphics::Window window;
        Msp::Graphics::GLContext gl_context;
        Msp::Input::Keyboard keyboard;
+       GL::Resources resources;
 
        GL::Program skybox_shprog;
        GL::Technique skybox_tech;
        GL::TextureCube skybox_tex;
+       GL::Sampler linear_clamped_sampler;
        ObjectData skybox_data;
 
-       GL::Program shadow_shprog;
+       const GL::Program &shadow_shprog;
 
        GL::Program ground_shprog;
        GL::ProgramData ground_shdata;
@@ -109,24 +113,26 @@ private:
        GL::Texture2D tiles_normalmap;
        GL::Texture2D sand_texture;
        GL::Texture2D sand_normalmap;
+       GL::Sampler linear_sampler;
+       GL::Sampler mipmap_sampler;
        GL::Technique ground_tech;
        ObjectData ground_data;
 
-       GL::Program pillar_shprog;
-       GL::Material pillar_material;
+       GL::BasicMaterial pillar_material;
        GL::Technique pillar_tech;
        std::vector<ObjectData> pillar_data;
        std::vector<GL::AnimatedObject *> pillars;
 
        GL::Program cube_shprog;
        GL::Program cube_shadow_shprog;
-       GL::Material cube_material;
+       GL::BasicMaterial cube_material;
        GL::Technique cube_tech;
        ObjectData cube_data;
        Cube *cube;
        GL::EnvironmentMap *env_cube;
 
-       GL::Pipeline pipeline;
+       GL::WindowView view;
+       GL::Sequence sequence;
        GL::Camera camera;
        GL::SimpleScene sky_scene;
        GL::InstanceScene scene;
@@ -134,8 +140,9 @@ private:
        GL::Light light;
        GL::ShadowMap shadow_scene;
        GL::Bloom bloom;
+       GL::ColorCurve colorcurve;
 
-       GL::Pipeline env_pipeline;
+       GL::Sequence env_sequence;
 
        Time::TimeStamp last_tick;
        float camera_angle;
@@ -146,12 +153,11 @@ private:
        float cube_phase;
        bool cube_frozen;
 
-       static const char texture_vertex_src[];
-       static const char texture_fragment_src[];
-       static const char skybox_vertex_src[];
-       static const char skybox_fragment_src[];
-       static const char ground_variables[];
-       static const char cube_variables[];
+       static const char texture_src[];
+       static const char skybox_src[];
+       static const char ground_src[];
+       static const char cube_src[];
+       static const char cube_shadow_src_tail[];
        static const float cube_shapes[];
 
 public:
@@ -159,7 +165,8 @@ public:
        ~DesertPillars();
 
 private:
-       void create_pipeline();
+       void setup_view();
+       void create_sequence();
        void create_skybox();
        static void create_skybox_face(GL::TextureCube &, GL::TextureCubeFace);
        void create_tiles_texture();
@@ -180,68 +187,83 @@ private:
        void key_press(unsigned);
 };
 
-const char DesertPillars::texture_vertex_src[] =
-       "#version 130\n"
-       "in vec3 vertex;\n"
-       "in vec3 normal;\n"
-       "in vec3 color;\n"
-       "out vec3 v_normal;\n"
-       "out vec3 v_color;\n"
+const char DesertPillars::texture_src[] =
+       "import msp_interface;\n"
+       "#pragma MSP stage(vertex)\n"
        "void main()\n"
        "{\n"
        "       gl_Position = vec4(vertex.xy*2.0-1.0, -vertex.z*2.0, 1.0);\n"
-       "       v_normal = normal;\n"
-       "       v_color = color.rgb;\n"
-       "}\n";
-
-const char DesertPillars::texture_fragment_src[] =
-       "#version 130\n"
-       "in vec3 v_normal;\n"
-       "in vec3 v_color;\n"
-       "out vec4 frag_color;\n"
-       "out vec4 frag_normal;\n"
+       "       passthrough;\n"
+       "}\n"
+       "#pragma MSP stage(fragment)\n"
+       "layout(location=1) out vec4 frag_normal;\n"
        "void main()\n"
        "{\n"
-       "       frag_color = vec4(v_color, 1.0);\n"
-       "       frag_normal = vec4(v_normal*0.5+0.5, 1.0);\n"
+       "       frag_color = color;\n"
+       "       frag_normal = vec4(normal*0.5+0.5, 1.0);\n"
        "}\n";
 
-const char DesertPillars::skybox_vertex_src[] =
-       "#version 130\n"
-       "uniform mat4 projection_matrix;\n"
-       "uniform mat4 eye_obj_matrix;\n"
-       "in vec3 vertex;\n"
-       "out vec3 v_texcoord;\n"
+const char DesertPillars::skybox_src[] =
+       "import msp_interface;\n"
+       "uniform samplerCube sky;\n"
+       "#pragma MSP stage(vertex)\n"
        "void main()\n"
        "{\n"
-       "       gl_Position = projection_matrix*vec4(mat3(eye_obj_matrix)*vertex, 1.0);\n"
-       "       v_texcoord = vertex;\n"
-       "}";
-
-const char DesertPillars::skybox_fragment_src[] =
-       "#version 130\n"
-       "uniform samplerCube sky;\n"
-       "in vec3 v_texcoord;\n"
-       "out vec4 frag_color;\n"
+       "       gl_Position = projection_matrix*vec4(mat3(eye_obj_matrix)*vertex.xyz, 1.0);\n"
+       "       passthrough;\n"
+       "}\n"
+       "#pragma MSP stage(fragment)\n"
        "void main()\n"
        "{\n"
-       "       frag_color = textureCube(sky, v_texcoord);\n"
-       "}";
+       "       frag_color = texture(sky, vertex.xyz);\n"
+       "}\n";
 
-const char DesertPillars::ground_variables[] =
+const char DesertPillars::ground_src[] =
+       "import phong;\n"
        "uniform sampler2D texture1;\n"
        "uniform sampler2D normalmap1;\n"
        "uniform sampler2D texture2;\n"
        "uniform sampler2D normalmap2;\n"
-       "attribute float ground_type;\n"
-       "fragment vec4 tex_sample = mix(texture2D(texture1, texture_coord*3.0), texture2D(texture2, texture_coord), ground_type);\n"
-       "fragment vec3 normal_sample = mix(texture2D(normalmap1, texture_coord*3.0).rgb, texture2D(normalmap2, texture_coord).rgb, ground_type);\n";
+       "const bool use_normal_map = true;\n"
+       "const bool use_shadow_map = true;\n"
+       "#pragma MSP stage(vertex)\n"
+       "layout(location=11) in float ground_type;\n"
+       "void custom_transform() override\n"
+       "{\n"
+       "       passthrough;\n"
+       "}\n"
+       "#pragma MSP stage(fragment)\n"
+       "vec4 get_diffuse_color() override\n"
+       "{\n"
+       "       return mix(texture(texture1, texcoord.xy*3.0), texture(texture2, texcoord.xy), ground_type);\n"
+       "}\n"
+       "vec3 get_fragment_normal() override\n"
+       "{\n"
+       "       return mix(texture(normalmap1, texcoord.xy*3.0).rgb, texture(normalmap2, texcoord.xy).rgb, ground_type);\n"
+       "}\n";
 
-const char DesertPillars::cube_variables[] =
+const char DesertPillars::cube_src[] =
+       "import phong;\n"
+       "const bool use_specular = true;\n"
+       "const bool use_reflectivity = true;\n"
        "uniform float spherify;\n"
-       "attribute vec3 sphere_coord;\n"
-       "vertex vec3 eye_normal = eye_obj_normal_matrix*normalize(mix(normal, normalize(sphere_coord), spherify));\n"
-       "vertex vec4 eye_vertex = eye_obj_matrix*vec4(mix(vertex.xyz, sphere_coord, spherify), 1.0);\n";
+       "#pragma MSP stage(vertex)\n"
+       "layout(location=11) in vec3 sphere_coord;\n"
+       "vec4 transform_position(vec4 pos) override\n"
+       "{\n"
+       "       return eye_obj_matrix*vec4(mix(vertex.xyz, sphere_coord, spherify), 1.0);\n"
+       "}\n"
+       "vec3 transform_normal(vec3 pos) override\n"
+       "{\n"
+       "       return eye_obj_normal_matrix*normalize(mix(normal, normalize(sphere_coord), spherify));\n"
+       "}\n";
+
+const char DesertPillars::cube_shadow_src_tail[] =
+       "#pragma MSP stage(fragment)\n"
+       "void main()\n"
+       "{\n"
+       "       frag_color = vec4(1.0);\n"
+       "}\n";
 
 const float DesertPillars::cube_shapes[] = { -0.4, 0.5, 1.0, 0.3 };
 
@@ -271,11 +293,17 @@ DesertPillars::DesertPillars(int argc, char **argv):
        window(display, options.window_opts),
        gl_context(window),
        keyboard(window),
-       shadow_shprog(GL::ProgramBuilder::StandardFeatures()),
-       pipeline(window.get_width(), window.get_height()),
-       shadow_scene(2048, scene, light),
-       bloom(window.get_width(), window.get_height()),
-       env_pipeline(512, 512),
+       skybox_shprog(skybox_src),
+       shadow_shprog(resources.get<GL::Program>("_occluder.glsl.shader")),
+       ground_shprog(ground_src),
+       cube_shprog(cube_src),
+       cube_shadow_shprog(string(cube_src)+cube_shadow_src_tail),
+       view(window, gl_context),
+       sequence(view),
+       shadow_scene(resources, 2048, scene, light),
+       bloom(resources, window.get_width(), window.get_height()),
+       colorcurve(resources),
+       env_sequence(512, 512),
        camera_angle(0),
        camera_stopped(false),
        cube_angle(0),
@@ -290,7 +318,8 @@ DesertPillars::DesertPillars(int argc, char **argv):
                window.show_cursor(false);
        keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &DesertPillars::key_press), false));
 
-       create_pipeline();
+       setup_view();
+       create_sequence();
        create_skybox();
        create_ground();
        create_pillars();
@@ -305,66 +334,69 @@ DesertPillars::~DesertPillars()
                delete *i;
 }
 
-void DesertPillars::create_pipeline()
+void DesertPillars::setup_view()
 {
-       pipeline.set_multisample(8);
-
-       camera.set_aspect(float(window.get_width())/window.get_height());
+       camera.set_aspect_ratio(float(window.get_width())/window.get_height());
        camera.set_up_direction(GL::Vector3(0, 0, 1));
        camera.set_depth_clip(1, 50);
-       pipeline.set_camera(&camera);
+       view.set_camera(&camera);
+       view.set_content(&sequence);
+}
+
+void DesertPillars::create_sequence()
+{
+       sequence.set_multisample(8);
+       sequence.set_hdr(true);
 
        /* The shadow map is focused on the part of the scene that contains the
        pillars and the cube.  Making the ground cast shadows as well would result
        either in a very low spatial resolution of the shadow map, or ugly artifacts
        as the ground crosses the shadow map boundary. */
        shadow_scene.set_target(GL::Vector3(0, 0, 0), 10);
-       sky_scene.add(shadow_scene);
-       pipeline.add_renderable(sky_scene);
+       shadow_scene.set_darkness(1);
 
        // Put the sun pretty high in the sky
+       light.set_diffuse(GL::Color(2.0));
        light.set_position(GL::Vector4(0.5, -2, 3, 0));
        lighting.attach(0, light);
-       lighting.set_ambient(GL::Color(0.5));
+       lighting.set_ambient(GL::Color(0.2));
 
        // The skybox is rendered first
-       pipeline.add_pass("sky");
+       sequence.add_pass(0, sky_scene);
 
-       GL::Pipeline::Pass *pass = &pipeline.add_pass(0);
+       GL::Sequence::Pass *pass = &sequence.add_pass(0, shadow_scene);
        pass->set_lighting(&lighting);
        pass->set_depth_test(&GL::DepthTest::lequal());
 
        /* A bloom filter enhances the realism of bright surfaces, even if there
        isn't anything really glowy in the scene. */
        bloom.set_strength(0.3);
-       pipeline.add_postprocessor(bloom);
+       sequence.add_postprocessor(bloom);
 
-       /* Initialize a second pipeline to render the environment map.  It has the
+       /* Lighting calculations are best done in linear color space, so the final
+       image must be converted to srgb for display. */
+       colorcurve.set_srgb();
+       sequence.add_postprocessor(colorcurve);
+
+       /* Initialize a second sequence to render the environment map.  It has the
        same renderables and passes, but no postprocessors or camera. */
-       env_pipeline.add_renderable(sky_scene);
-       env_pipeline.add_pass("sky");
-       pass = &env_pipeline.add_pass(0);
+       env_sequence.add_pass(0, sky_scene);
+       pass = &env_sequence.add_pass(0, shadow_scene);
        pass->set_lighting(&lighting);
        pass->set_depth_test(&GL::DepthTest::lequal());
 }
 
 void DesertPillars::create_skybox()
 {
-       skybox_tex.storage(GL::RGB, 128);
-       skybox_tex.set_min_filter(GL::LINEAR);
-       skybox_tex.set_wrap(GL::CLAMP_TO_EDGE);
+       skybox_tex.storage(GL::SRGB8, 128, 1);
+       linear_clamped_sampler.set_min_filter(GL::LINEAR);
+       linear_clamped_sampler.set_wrap(GL::CLAMP_TO_EDGE);
        for(unsigned i=0; i<6; ++i)
                create_skybox_face(skybox_tex, skybox_tex.enumerate_faces(i));
 
-       skybox_shprog.attach_shader_owned(new GL::VertexShader(skybox_vertex_src));
-       skybox_shprog.attach_shader_owned(new GL::FragmentShader(skybox_fragment_src));
-       skybox_shprog.bind_attribute(GL::VERTEX3, "vertex");
-       skybox_shprog.bind_fragment_data(0, "frag_color");
-       skybox_shprog.link();
-
-       GL::RenderPass &pass = skybox_tech.add_pass("sky");
+       GL::RenderPass &pass = skybox_tech.add_pass(0);
        pass.set_shader_program(&skybox_shprog, 0);
-       pass.set_texture(0, &skybox_tex);
+       pass.set_texture(0, &skybox_tex, &linear_clamped_sampler);
 
        // The shader will use the vertex coordinates to initialize texture coordinates as well
        skybox_data.mesh = new GL::Mesh(GL::VERTEX3);
@@ -398,7 +430,7 @@ void DesertPillars::create_skybox_face(GL::TextureCube &texture, GL::TextureCube
                                pixels[i+2] = 160;
                        }
                }
-       texture.image(face, 0, GL::RGB, GL::UNSIGNED_BYTE, pixels);
+       texture.image(face, 0, pixels);
        delete[] pixels;
 }
 
@@ -406,10 +438,9 @@ void DesertPillars::create_tiles_texture()
 {
        unsigned width = 256;
        unsigned height = 256;
-       tiles_texture.storage(GL::RGB, width, height);
-       tiles_texture.set_min_filter(GL::LINEAR);
-       tiles_normalmap.storage(GL::RGB, width, height);
-       tiles_normalmap.set_min_filter(GL::LINEAR);
+       tiles_texture.storage(GL::RGB8, width, height, 1);
+       tiles_normalmap.storage(GL::RGB8, width, height, 1);
+       linear_sampler.set_min_filter(GL::LINEAR);
 
        GL::Mesh tiles((GL::VERTEX3, GL::NORMAL3, GL::COLOR4_UBYTE));
 
@@ -424,6 +455,7 @@ void DesertPillars::create_tiles_texture()
                4, 4, 3, 3, 4, 1, 3, 2,
                2, 3, 2, 2, 3, 3, 3, 2 };
 
+       {
        GL::MeshBuilder bld(tiles);
 
        // Create a dark background
@@ -437,7 +469,7 @@ void DesertPillars::create_tiles_texture()
        bld.end();
 
        // Create the four tiles
-       bld.color(0.95f, 0.8f, 0.65f);
+       bld.color(GL::Color(0.95f, 0.8f, 0.65f).to_linear());
        for(unsigned i=0; i<2; ++i)
                for(unsigned j=0; j<2; ++j)
                {
@@ -460,21 +492,16 @@ void DesertPillars::create_tiles_texture()
                                bld.vertex(coords[i*4+order[32+l*2]], coords[j*4+order[32+l*2+1]], bevel);
                        bld.end();
                }
+       }
 
-       GL::Program shprog(texture_vertex_src, texture_fragment_src);
-       shprog.bind_attribute(GL::VERTEX3, "vertex");
-       shprog.bind_attribute(GL::NORMAL3, "normal");
-       shprog.bind_attribute(GL::COLOR4_UBYTE, "color");
-       shprog.bind_fragment_data(0, "frag_color");
-       shprog.bind_fragment_data(1, "frag_normal");
-       shprog.link();
+       GL::Program shprog(texture_src);
 
        // Use an FBO to turn the geometry into a normalmapped texture
        GL::Framebuffer fbo;
        fbo.attach(GL::COLOR_ATTACHMENT0, tiles_texture);
        fbo.attach(GL::COLOR_ATTACHMENT1, tiles_normalmap);
        GL::Bind bind_fbo(fbo);
-       GL::Renderer renderer(0);
+       GL::Renderer renderer;
        renderer.set_shader_program(&shprog, 0);
        tiles.draw(renderer);
 }
@@ -484,14 +511,12 @@ void DesertPillars::create_sand_texture()
        unsigned width = 512;
        unsigned height = 512;
 
-       sand_texture.storage(GL::RGB, width/16, height/16);
-       sand_texture.set_min_filter(GL::LINEAR_MIPMAP_LINEAR);
-       sand_texture.set_max_anisotropy(4);
-       sand_texture.set_generate_mipmap(true);
-       sand_normalmap.storage(GL::RGB, width, height);
-       sand_normalmap.set_min_filter(GL::LINEAR_MIPMAP_LINEAR);
-       sand_normalmap.set_max_anisotropy(4);
-       sand_normalmap.set_generate_mipmap(true);
+       sand_texture.storage(GL::SRGB8, width/16, height/16);
+       sand_texture.set_auto_generate_mipmap(true);
+       sand_normalmap.storage(GL::RGB8, width, height);
+       sand_normalmap.set_auto_generate_mipmap(true);
+       mipmap_sampler.set_min_filter(GL::LINEAR_MIPMAP_LINEAR);
+       mipmap_sampler.set_max_anisotropy(4);
 
        unsigned char *pixels = new unsigned char[width*height*3];
        unsigned char *bump = new unsigned char[width*height];
@@ -505,10 +530,10 @@ void DesertPillars::create_sand_texture()
                        pixels[i+2] = 160;
                        bump[x+y*width] = rand();
                }
-       sand_texture.image(0, GL::RGB, GL::UNSIGNED_BYTE, pixels);
+       sand_texture.image(0, pixels);
        gaussian_blur(bump, width, height);
        create_normalmap(bump, pixels, width, height, 4);
-       sand_normalmap.image(0, GL::RGB, GL::UNSIGNED_BYTE, pixels);
+       sand_normalmap.image(0, pixels);
        delete[] pixels;
        delete[] bump;
 }
@@ -573,16 +598,6 @@ void DesertPillars::create_ground()
        create_tiles_texture();
        create_sand_texture();
 
-       GL::ProgramBuilder::StandardFeatures features;
-       features.lighting = true;
-       features.shadow = true;
-       features.texture = true;
-       features.normalmap = true;
-       features.custom = ground_variables;
-       GL::ProgramBuilder(features).add_shaders(ground_shprog);
-       ground_shprog.bind_attribute(7, "ground_type");
-       ground_shprog.link();
-
        ground_shdata.uniform("texture1", 0);
        ground_shdata.uniform("normalmap1", 1);
        ground_shdata.uniform("texture2", 2);
@@ -590,15 +605,15 @@ void DesertPillars::create_ground()
 
        GL::RenderPass *pass = &ground_tech.add_pass(0);
        pass->set_shader_program(&ground_shprog, &ground_shdata);
-       pass->set_texture(0, &tiles_texture);
-       pass->set_texture(1, &tiles_normalmap);
-       pass->set_texture(2, &sand_texture);
-       pass->set_texture(3, &sand_normalmap);
+       pass->set_texture(0, &tiles_texture, &linear_sampler);
+       pass->set_texture(1, &tiles_normalmap, &linear_sampler);
+       pass->set_texture(2, &sand_texture, &mipmap_sampler);
+       pass->set_texture(3, &sand_normalmap, &mipmap_sampler);
 
        /* No shadow pass here; the ground only receives shadows, but doesn't cast
        them. */
 
-       GL::VertexFormat vfmt = (GL::VERTEX3, GL::NORMAL3, GL::TANGENT3, GL::BINORMAL3, GL::TEXCOORD2, GL::ATTRIB1,7);
+       GL::VertexFormat vfmt = (GL::VERTEX3, GL::NORMAL3, GL::TANGENT3, GL::BINORMAL3, GL::TEXCOORD2, GL::GENERIC1);
        ground_data.mesh = new GL::Mesh(vfmt);
 
        // Create a base grid
@@ -611,7 +626,7 @@ void DesertPillars::create_ground()
        unsigned tan = vfmt.offset(GL::TANGENT3);
        unsigned bin = vfmt.offset(GL::BINORMAL3);
        unsigned tex = vfmt.offset(GL::TEXCOORD2);
-       unsigned gt = vfmt.offset(GL::make_indexed_component(GL::ATTRIB1, 7));
+       unsigned gt = vfmt.offset(GL::GENERIC1);
        for(unsigned i=0; i<n_vertices; ++i)
        {
                float *v = ground_data.mesh->modify_vertex(i);
@@ -661,19 +676,11 @@ float DesertPillars::ground_height(float x, float y)
 void DesertPillars::create_pillars()
 {
        // The pillars are a matt off-white
-       pillar_material.set_diffuse(GL::Color(0.9, 0.88, 0.8));
-       pillar_material.set_ambient(GL::Color(0.9, 0.88, 0.8));
-
-       GL::ProgramBuilder::StandardFeatures features;
-       features.lighting = true;
-       features.material = true;
-       features.shadow = true;
-       GL::ProgramBuilder(features).add_shaders(pillar_shprog);
-       pillar_shprog.link();
+       pillar_material.set_diffuse(GL::Color(0.9, 0.89, 0.85).to_linear());
+       pillar_material.set_receive_shadows(true);
 
        GL::RenderPass *pass = &pillar_tech.add_pass(0);
-       pass->set_material(&pillar_material);
-       pass->set_shader_program(&pillar_shprog, 0);
+       pass->set_material(&pillar_material, &resources);
 
        pass = &pillar_tech.add_pass("shadow");
        pass->set_shader_program(&shadow_shprog, 0);
@@ -719,9 +726,9 @@ void DesertPillars::create_pillars()
                        }
 
                        // Create a square plinth and capitel
-                       bld.matrix() = GL::Matrix::translation(0, 0, 0.3);
+                       bld.set_matrix(GL::Matrix::translation(0, 0, 0.3));
                        GL::BoxBuilder(1.0, 1.0, 0.6).build(bld);
-                       bld.matrix() = GL::Matrix::translation(0, 0, height+0.8);
+                       bld.set_matrix(GL::Matrix::translation(0, 0, height+0.8));
                        GL::BoxBuilder(1.0, 1.0, 0.4).build(bld);
 
                        pd.object = new GL::Object(pd.mesh, &pillar_tech);
@@ -743,37 +750,19 @@ void DesertPillars::create_cube()
 {
        /* The cube is bluish-gray, with a hard specular reflection to produce a
        sun-like spot */
-       cube_material.set_diffuse(GL::Color(0.5, 0.5, 0.55));
-       cube_material.set_ambient(GL::Color(0.5, 0.5, 0.55));
+       cube_material.set_diffuse(GL::Color(0.5, 0.5, 0.55).to_linear());
        cube_material.set_specular(GL::Color(1.0));
        cube_material.set_shininess(120);
        cube_material.set_reflectivity(0.5);
 
-       // First create a simplified shader for rendering the shadow map
-       GL::ProgramBuilder::StandardFeatures features;
-       features.custom = cube_variables;
-       GL::ProgramBuilder(features).add_shaders(cube_shadow_shprog);
-       cube_shadow_shprog.bind_attribute(7, "sphere_coord");
-       cube_shadow_shprog.link();
-
-       // Then add the rest of the features for normal rendering
-       features.lighting = true;
-       features.specular = true;
-       features.material = true;
-       features.shadow = true;
-       features.reflection = true;
-       GL::ProgramBuilder(features).add_shaders(cube_shprog);
-       cube_shprog.bind_attribute(7, "sphere_coord");
-       cube_shprog.link();
-
        GL::RenderPass *pass = &cube_tech.add_pass(0);
-       pass->set_material(&cube_material);
+       pass->set_material(&cube_material, &resources);
        pass->set_shader_program(&cube_shprog, 0);
 
        pass = &cube_tech.add_pass("shadow");
        pass->set_shader_program(&cube_shadow_shprog, 0);
 
-       cube_data.mesh = new GL::Mesh((GL::VERTEX3, GL::NORMAL3, GL::ATTRIB3,7));
+       cube_data.mesh = new GL::Mesh((GL::VERTEX3, GL::NORMAL3, GL::GENERIC3));
        GL::MeshBuilder bld(*cube_data.mesh);
        create_cube_face(bld, GL::Vector3(-1, -1, -1), GL::Vector3(2, 0, 0), GL::Vector3(0, 2, 0), 16);
        bld.offset(cube_data.mesh->get_n_vertices());
@@ -789,7 +778,7 @@ void DesertPillars::create_cube()
        cube_data.object = new GL::Object(cube_data.mesh, &cube_tech);
 
        cube = new Cube(*cube_data.object);
-       env_cube = new GL::EnvironmentMap(512, *cube, env_pipeline);
+       env_cube = new GL::EnvironmentMap(resources, 512, *cube, env_sequence);
        scene.add(*env_cube);
 }
 
@@ -815,7 +804,7 @@ void DesertPillars::create_cube_face(GL::MeshBuilder &bld, const GL::Vector3 &ba
 
                        l = sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
                        l /= 1.732;
-                       bld.attrib(7, v.x/l, v.y/l, v.z/l);
+                       bld.generic(0, v.x/l, v.y/l, v.z/l);
 
                        bld.vertex(v);
                }
@@ -888,9 +877,7 @@ void DesertPillars::tick()
        }
 
        display.tick();
-       GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
-       pipeline.render();
-       gl_context.swap_buffers();
+       view.render();
 }
 
 void DesertPillars::key_press(unsigned key)