--- /dev/null
+#include <msp/gl/camera.h>
+#include <msp/gl/framebuffer.h>
+#include <msp/gl/mesh.h>
+#include <msp/gl/renderer.h>
+#include <msp/strings/format.h>
+#include "water.h"
+
+using namespace std;
+using namespace Msp;
+
+Water::Water(const GL::Object &o, DataFile::Collection &resources, const Region ®ion):
+ ObjectInstance(o),
+ width((region.right-region.left)*100.0f),
+ height((region.top-region.bottom)*100.0f),
+ current(&state[0]),
+ next(&state[1]),
+ sampler(resources.get<GL::Sampler>("linear_clip.samp")),
+ sim_integrate(resources.get<GL::Program>("fluidsim_integrate.glsl.shader")),
+ sim_velocity(resources.get<GL::Program>("fluidsim_velocity.glsl.shader")),
+ sim_clamp(resources.get<GL::Program>("fluidsim_clamp.glsl.shader")),
+ normals_shader(resources.get<GL::Program>("water_normals.glsl.shader")),
+ variance_x_shader(resources.get<GL::Program>("water_variance_x.glsl.shader")),
+ variance_y_shader(resources.get<GL::Program>("water_variance_y.glsl.shader"))
+{
+ sim_shdata.set_debug_name("Water sim params");
+ sim_shdata.uniform("delta_time", stepsize);
+ sim_shdata.uniform("velocity_damping", 0.99995f);
+ sim_shdata.uniform("gravity", 981.0f);
+ sim_shdata.uniform("max_flow_fraction", 0.9999f);
+ sim_shdata.uniform("residual_depth", 0.01f);
+
+ shdata.uniform("Region.scale", 1.0f/(region.right-region.left), 1.0f/(region.top-region.bottom));
+ shdata.uniform("Region.offset", -region.left/(region.right-region.left), -region.bottom/(region.top-region.bottom));
+ shdata.uniform("Region.amplitude", 0.01f);
+
+ bottom.storage(GL::R32F, width, height, 1);
+ bottom.set_debug_name("Water bottom");
+ for(unsigned i=0; i<2; ++i)
+ {
+ state[i].surface.storage(GL::R32F, width, height, 1);
+ state[i].surface.set_debug_name(format("Water surface[%d]", i));
+ state[i].velocity.storage(GL::RG32F, width, height, 1);
+ state[i].velocity.set_debug_name(format("Water velocity[%d]", i));
+ state[i].clamping.storage(GL::R32F, width, height, 1);
+ state[i].clamping.set_debug_name(format("Water clamping[%d]", i));
+ }
+
+ normals.storage(GL::RG8, width, height, 1);
+ normals.set_debug_name("Water normals");
+
+ variance_x.storage(GL::R16F, width, height, 1);
+ variance_x.set_debug_name("Water variance X");
+ variance_y.storage(GL::R16F, width, height, 1);
+ variance_y.set_debug_name("Water variance Y");
+
+ GL::Framebuffer bottom_fbo((GL::COLOR_ATTACHMENT,GL::R32F));
+ bottom_fbo.attach(GL::COLOR_ATTACHMENT, bottom);
+
+ GL::Camera bottom_camera;
+ bottom_camera.set_orthographic(region.right-region.left, region.top-region.bottom);
+ bottom_camera.set_position(GL::Vector3((region.left+region.right)/2, (region.bottom+region.top)/2, 0.0f));
+ bottom_camera.set_depth_clip(-10.0f, 10.0f);
+
+ const GL::Program &bottom_shprog = resources.get<GL::Program>("fluidsim_bottom.glsl.shader");
+ const GL::Program &fill_shprog = resources.get<GL::Program>("fluidsim_fill.glsl.shader");
+
+ GL::Renderer renderer;
+ renderer.begin();
+ renderer.set_camera(bottom_camera);
+ renderer.set_framebuffer(&bottom_fbo);
+ renderer.set_shader_program(&bottom_shprog);
+ region.terrain.draw(renderer);
+
+ renderer.set_shader_program(&fill_shprog);
+ renderer.set_texture("bottom", &bottom, &sampler);
+ for(unsigned i=0; i<2; ++i)
+ {
+ renderer.set_storage_texture("surface_out", &state[i].surface);
+ renderer.set_storage_texture("velocity_out", &state[i].velocity);
+ renderer.set_storage_texture("clamping_out", &state[i].clamping);
+ renderer.dispatch((width+7)/8, (height+7)/8);
+ }
+ renderer.end();
+}
+
+void Water::setup_frame(GL::Renderer &renderer)
+{
+ if(simulated)
+ return;
+
+ GL::Renderer::Push _push(renderer);
+
+ unsigned groups_x = (width+5)/8;
+ unsigned groups_y = (height+5)/8;
+
+ int drop_x = rng()%width;
+ int drop_y = rng()%height;
+ sim_shdata.uniform("drop_pos", drop_x, drop_y);
+ sim_shdata.uniform("drop_time", time);
+
+ renderer.add_shader_data(sim_shdata);
+ renderer.set_texture("bottom_in", &bottom, &sampler);
+ for(unsigned i=0; i<16; ++i)
+ {
+ sim_shdata.uniform("time", time);
+
+ renderer.set_shader_program(&sim_integrate);
+ renderer.set_storage_texture("surface_out", &next->surface);
+ renderer.set_storage_texture("velocity_out", &next->velocity);
+ renderer.set_storage_texture("clamping_out", &next->clamping);
+ renderer.set_texture("surface_in", ¤t->surface, &sampler);
+ renderer.set_texture("velocity_in", ¤t->velocity, &sampler);
+ renderer.set_texture("clamping_in", ¤t->clamping, &sampler);
+ renderer.dispatch(groups_x, groups_y);
+
+ renderer.set_shader_program(&sim_velocity);
+ renderer.set_texture("surface_in", &next->surface, &sampler);
+ renderer.dispatch(groups_x, groups_y);
+
+ renderer.set_shader_program(&sim_clamp);
+ renderer.set_texture("velocity_in", &next->velocity, &sampler);
+ renderer.dispatch(groups_x, groups_y);
+
+ time += stepsize;
+ swap(current, next);
+ }
+
+ renderer.set_shader_program(&normals_shader);
+ renderer.set_texture("surface_in", ¤t->surface, &sampler);
+ renderer.set_storage_texture("normals_out", &normals);
+ renderer.dispatch(groups_x, groups_y);
+
+ renderer.set_shader_program(&variance_x_shader);
+ renderer.set_texture("normals_in", &normals, &sampler);
+ renderer.set_storage_texture("variance_out", &variance_x);
+ renderer.dispatch((width-1)/8, groups_y);
+
+ renderer.set_shader_program(&variance_y_shader);
+ renderer.set_texture("variance_in", &variance_x, &sampler);
+ renderer.set_storage_texture("variance_out", &variance_y);
+ renderer.dispatch(groups_x, (height-1)/8);
+
+ simulated = true;
+}
+
+void Water::finish_frame()
+{
+ simulated = false;
+}
+
+void Water::setup_render(GL::Renderer &renderer, GL::Tag tag) const
+{
+ ObjectInstance::setup_render(renderer, tag);
+ renderer.add_shader_data(shdata);
+ renderer.set_texture("bottom", &bottom, &sampler);
+ renderer.set_texture("surface", ¤t->surface, &sampler);
+ renderer.set_texture("normals", &normals, &sampler);
+ renderer.set_texture("variance", &variance_y, &sampler);
+}