+#include "light.h"
+#include "mesh.h"
+#include "renderer.h"
+#include "resources.h"
+#include "sky.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Sky::Sky(Resources &resources, Renderable &r, const Light &s):
+ Effect(r),
+ sun(s),
+ transmittance_shprog(resources.get<Program>("_sky_transmittance.glsl.shader")),
+ transmittance_lookup_dirty(true),
+ distant_shprog(resources.get<Program>("_sky_distant.glsl.shader")),
+ fullscreen_mesh(resources.get<Mesh>("_fullscreen_quad.mesh")),
+ backdrop_shprog(resources.get<Program>("_sky_backdrop.glsl.shader")),
+ sampler(resources.get<Sampler>("_linear_clamp.samp")),
+ wrap_sampler(resources.get<Sampler>("_linear_clamp_v.samp")),
+ rendered(false)
+{
+ transmittance_lookup.storage(RGB16F, 128, 64, 1);
+ transmittance_fbo.attach(COLOR_ATTACHMENT0, transmittance_lookup);
+
+ distant.storage(RGB16F, 256, 128, 1);
+ distant_fbo.attach(COLOR_ATTACHMENT0, distant);
+
+ shdata.uniform("n_steps", 50);
+
+ set_planet(Planet::earth());
+ set_view_height(5.0f);
+}
+
+void Sky::set_planet(const Planet &planet)
+{
+ shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b);
+ shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b);
+ shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b);
+ shdata.uniform("events.ozone_absorb", planet.ozone_absorb.r, planet.ozone_absorb.g, planet.ozone_absorb.b);
+ shdata.uniform("rayleigh_density_decay", planet.rayleigh_density_decay);
+ shdata.uniform("mie_density_decay", planet.mie_density_decay);
+ shdata.uniform("ozone_band_center", planet.ozone_band_center);
+ shdata.uniform("ozone_band_extent", planet.ozone_band_extent);
+ shdata.uniform("atmosphere_thickness", planet.atmosphere_thickness);
+ shdata.uniform("planet_radius", planet.planet_radius);
+ shdata.uniform("ground_albedo", planet.ground_albedo.r, planet.ground_albedo.g, planet.ground_albedo.b);
+}
+
+void Sky::set_view_height(float h)
+{
+ shdata.uniform("view_height", h);
+}
+
+void Sky::setup_frame(Renderer &renderer)
+{
+ if(rendered)
+ return;
+
+ rendered = true;
+
+ shdata.uniform("light_color", sun.get_color());
+ shdata.uniform("light_dir", sun.get_position().slice<3>(0));
+
+ Renderer::Push push(renderer);
+
+ if(transmittance_lookup_dirty)
+ {
+ transmittance_lookup_dirty = false;
+ Bind bind_fbo(transmittance_fbo);
+ renderer.set_shader_program(&transmittance_shprog, &shdata);
+ fullscreen_mesh.draw(renderer);
+ }
+
+ Bind bind_fbo(distant_fbo);
+ renderer.set_shader_program(&distant_shprog, &shdata);
+ renderer.set_texture("transmittance_lookup", &transmittance_lookup, &sampler);
+ fullscreen_mesh.draw(renderer);
+
+ renderable.setup_frame(renderer);
+}
+
+void Sky::finish_frame()
+{
+ if(rendered)
+ {
+ rendered = false;
+ renderable.finish_frame();
+ }
+}
+
+void Sky::render(Renderer &renderer, Tag tag) const
+{
+ renderable.render(renderer, tag);
+
+ Renderer::Push push(renderer);
+
+ renderer.set_shader_program(&backdrop_shprog, &shdata);
+ renderer.set_texture("distant", &distant, &wrap_sampler);
+ fullscreen_mesh.draw(renderer);
+}
+
+
+Sky::Planet::Planet():
+ rayleigh_scatter(0.0f),
+ mie_scatter(0.0f),
+ mie_absorb(0.0f),
+ ozone_absorb(0.0f),
+ rayleigh_density_decay(1e3f),
+ mie_density_decay(1e3f),
+ ozone_band_center(1e4f),
+ ozone_band_extent(1e2f),
+ atmosphere_thickness(2e4f),
+ planet_radius(1e6f)
+{ }
+
+Sky::Planet Sky::Planet::earth()
+{
+ Planet planet;
+ planet.rayleigh_scatter = Color(5.802e-6f, 13.558e-6f, 33.1e-6f);
+ planet.mie_scatter = Color(3.996e-6f, 3.996e-6f, 3.996e-6f);
+ planet.mie_absorb = Color(4.4e-6f, 4.4e-6f, 4.4e-6f);
+ planet.ozone_absorb = Color(0.65e-6f, 1.881e-6f, 0.085e-6f);
+ planet.rayleigh_density_decay = -8e3f;
+ planet.mie_density_decay = -1.2e3f;
+ planet.ozone_band_center = 25e3f;
+ planet.ozone_band_extent = 15e3f;
+ planet.atmosphere_thickness = 1e5f;
+ planet.planet_radius = 6.36e6f;
+ return planet;
+}
+
+} // namespace GL
+} // namespace Msp