--- /dev/null
+#include <cmath>
+#include "environmentmap.h"
+#include "renderer.h"
+#include "texunit.h"
+
+namespace Msp {
+namespace GL {
+
+EnvironmentMap::EnvironmentMap(unsigned s, Renderable &r, Renderable &e):
+ Effect(r),
+ size(s),
+ environment(e),
+ rendered(false)
+{
+ env_tex.storage(RGB, size);
+ env_tex.set_wrap(CLAMP_TO_EDGE);
+ env_tex.set_min_filter(LINEAR);
+ depth_buf.storage(DEPTH_COMPONENT, size, size);
+ for(unsigned i=0; i<6; ++i)
+ {
+ fbo[i].attach(COLOR_ATTACHMENT0, env_tex, TextureCube::enumerate_faces(i), 0);
+ fbo[i].attach(DEPTH_ATTACHMENT, depth_buf);
+ }
+
+ // XXX Make the depth range configurable
+ camera.set_field_of_view(M_PI/2);
+ camera.set_aspect(1);
+ camera.set_depth_clip(0.1, 100);
+
+ shdata.uniform("environment", 4);
+}
+
+void EnvironmentMap::setup_frame() const
+{
+ if(rendered)
+ return;
+
+ rendered = true;
+ renderable.setup_frame();
+ environment.setup_frame();
+
+ const Matrix *matrix = renderable.get_matrix();
+ Vector3 position = (*matrix)*Vector3();
+ camera.set_position(position);
+ for(unsigned i=0; i<6; ++i)
+ {
+ TextureCubeFace face = TextureCube::enumerate_faces(i);
+ Bind _bind_fbo(fbo[i]);
+ fbo[i].clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
+ camera.set_look_direction(env_tex.get_face_direction(face));
+ camera.set_up_direction(env_tex.get_t_direction(face));
+ Renderer env_renderer(&camera);
+ env_renderer.exclude(renderable);
+ env_renderer.render(environment);
+ }
+}
+
+void EnvironmentMap::finish_frame() const
+{
+ if(rendered)
+ {
+ rendered = false;
+ renderable.finish_frame();
+ environment.finish_frame();
+ }
+}
+
+void EnvironmentMap::render(Renderer &renderer, const Tag &tag) const
+{
+ if(!enabled_passes.count(tag))
+ return renderer.render(renderable, tag);
+
+ const Matrix &view_matrix = renderer.get_camera()->get_matrix();
+ // XXX The camera should maybe have store its own object matrix
+ float env_mdata[9];
+ env_mdata[0] = view_matrix[0];
+ env_mdata[1] = view_matrix[4];
+ env_mdata[2] = view_matrix[8];
+ env_mdata[3] = view_matrix[1];
+ env_mdata[4] = view_matrix[5];
+ env_mdata[5] = view_matrix[9];
+ env_mdata[6] = view_matrix[2];
+ env_mdata[7] = view_matrix[6];
+ env_mdata[8] = view_matrix[10];
+ shdata.uniform_matrix3("env_eye_matrix", env_mdata);
+
+ env_tex.bind_to(4);
+ TexUnit::activate(0);
+
+ Renderer::Push _push_rend(renderer);
+ renderer.add_shader_data(shdata);
+ renderer.render(renderable, tag);
+
+ env_tex.unbind_from(4);
+ TexUnit::activate(0);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_ENVIRONMENTMAP_H_
+#define MSP_GL_ENVIRONMENTMAP_H_
+
+#include "camera.h"
+#include "effect.h"
+#include "framebuffer.h"
+#include "matrix.h"
+#include "programdata.h"
+#include "renderbuffer.h"
+#include "texturecube.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+class Renderable;
+
+/**
+Creates a cube map texture of the surroundings of the renderable. This texture
+can then be used to implement effects such as reflections or refractions.
+
+If the EnvironmentMap is used in a Pipeline, it's worth noting that the cube
+map will be prepared outside of any rendering pass. It's recommended to use
+another Pipeline to define which passes should be used to render the
+environment.
+*/
+class EnvironmentMap: public Effect
+{
+private:
+ unsigned size;
+ Renderable &environment;
+ TextureCube env_tex;
+ Renderbuffer depth_buf;
+ mutable Framebuffer fbo[6];
+ mutable Camera camera;
+ mutable ProgramData shdata;
+ mutable bool rendered;
+
+public:
+ EnvironmentMap(unsigned size, Renderable &rend, Renderable &env);
+
+ virtual void setup_frame() const;
+ virtual void finish_frame() const;
+
+ virtual void render(Renderer &, const Tag &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif