+#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