#[cfg(all(feature="gl", feature="gles"))]
compile_error!("Error: gl and gles features can't be enabled at the same time");
extern crate rin;
#[macro_use] extern crate glin;
extern crate angle;
extern crate color;
#[cfg(feature = "serialize")]
extern crate serde;
#[cfg(feature = "events")]
extern crate seitan as events;
#[cfg(feature = "events")]
#[macro_use] extern crate ringui;
#[cfg(feature = "serialize")]
#[macro_use] extern crate serde_derive;
#[cfg(feature="autoshader")]
use util::AutoLoader;
#[cfg(feature="autoshader")]
use std::path::Path;
use angle::*;
use rin::color::consts::*;
use rin::prelude::*;
use rin::graphics::{self, Vertex2DTex};
use rin::util::{self, Error};
use rin::gl;
#[cfg(feature = "serialize")]
use std::fmt;
use std::cell::{UnsafeCell, Cell};
#[cfg(feature = "serialize")]
use serde::de::{self, Deserialize, Deserializer, Visitor, SeqAccess, MapAccess};
#[cfg(feature = "events")]
use ringui::{RangedParameterMut, RangedParameter};
#[cfg(feature="autoshader")]
pub struct PostProcessing{
fbo_render: gl::Fbo,
fbo_blit: Option<gl::Fbo>,
fbo_fxaa: gl::Fbo,
fbo_blur: [gl::Fbo;2],
fbo_tonemap: gl::Fbo,
fxaa_loader: AutoLoader<gl::Program>,
blur_v_loader: AutoLoader<gl::Program>,
blur_h_loader: AutoLoader<gl::Program>,
tonemap_loader: UnsafeCell<AutoLoader<gl::Program>>,
tonemap_no_blur_loader: UnsafeCell<AutoLoader<gl::Program>>,
bright_loader: AutoLoader<gl::Program>,
fxaa: gl::Program,
blur_v: gl::Program,
blur_h: gl::Program,
tonemap: UnsafeCell<gl::Program>,
tonemap_no_blur: UnsafeCell<gl::Program>,
bright: gl::Program,
fullscreen_quad: gl::SimpleVao<Vertex2DTexture>,
tonemap_type: Cell<Tonemap>,
}
#[cfg(not(feature="autoshader"))]
pub struct PostProcessing{
fbo_fxaa: gl::Fbo,
fbo_blur: [gl::Fbo;2],
fbo_tonemap: gl::Fbo,
fxaa: gl::Program,
blur_v: gl::Program,
blur_h: gl::Program,
tonemap: UnsafeCell<gl::Program>,
tonemap_no_blur: UnsafeCell<gl::Program>,
bright: gl::Program,
fullscreen_quad: gl::SimpleVao<Vertex2DTex>,
tonemap_type: Cell<Tonemap>,
}
fn fbo(gl: &gl::Renderer, w: u32, h: u32, format: gl::fbo::ColorFormat) -> util::Result<gl::Fbo>{
let color = gl.new_fbo_color_attachment().texture(w, h, format)
.map_err(|e| Error::with_cause("Error creating color attachment", e))?;
gl.new_fbo().from_color(color)
.map_err(|e| Error::with_cause("Error creating fbo", e))
}
fn gaussian(x: f32, mu: f32, sigma: f32) -> f32{
let d = x - mu;
let n = 1.0 / (Rad::<f32>::two_pi().value().sqrt() * sigma);
(-d * d/(2.0 * sigma * sigma)).exp() * n
}
#[cfg(feature = "events")]
enum_iter!{
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum Tonemap{
Linear,
Gamma,
Reinhard1,
Reinhard2,
Filmic,
Uncharted2,
ACES,
ACES_REC2020_1k,
Unreal,
}
}
#[cfg(not(feature = "events"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum Tonemap{
Linear,
Gamma,
Reinhard1,
Reinhard2,
Filmic,
Uncharted2,
ACES,
ACES_REC2020_1k,
Unreal,
}
impl Tonemap{
fn to_str(self) -> &'static str{
match self{
Tonemap::Linear => "LINEAR",
Tonemap::Gamma => "GAMMA",
Tonemap::Reinhard1 => "REINHARD",
Tonemap::Reinhard2 => "REINHARD2",
Tonemap::Filmic => "FILMIC",
Tonemap::Uncharted2 => "UNCHARTED2",
Tonemap::ACES => "ACES",
Tonemap::ACES_REC2020_1k => "ACES_REC2020_1k",
Tonemap::Unreal => "UNREAL",
}
}
}
#[cfg(feature = "events")]
#[derive(ParameterGroup, Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
pub struct Parameters{
pub fxaa: events::Property<'static, bool>,
pub bloom: events::Property<'static, bool>,
pub sigma: RangedParameterMut<'static,f32>,
pub bloom_threshold: RangedParameterMut<'static,f32>,
pub bloom_passes: RangedParameterMut<'static, u8>,
pub contrast: RangedParameterMut<'static,f32>,
pub brightness: RangedParameterMut<'static,f32>,
pub tonemap_type: events::Property<'static, Tonemap>,
pub exposure_bias: RangedParameterMut<'static,f32>,
pub a: RangedParameterMut<'static,f32>,
pub b: RangedParameterMut<'static,f32>,
pub c: RangedParameterMut<'static,f32>,
pub d: RangedParameterMut<'static,f32>,
pub e: RangedParameterMut<'static,f32>,
pub f: RangedParameterMut<'static,f32>,
pub w: RangedParameterMut<'static,f32>,
#[cfg_attr(feature = "serialize", serde(skip_serializing))]
pub curve_data: RangedParameter<'static, Vec<f32>, f32>,
}
#[cfg(not(feature = "events"))]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug)]
pub struct Parameters{
pub fxaa: bool,
pub bloom: bool,
pub sigma: f32,
pub bloom_threshold: f32,
pub bloom_passes: u8,
pub contrast: f32,
pub brightness: f32,
pub tonemap_type: Tonemap,
pub exposure_bias: f32,
pub a: f32,
pub b: f32,
pub c: f32,
pub d: f32,
pub e: f32,
pub f: f32,
pub w: f32,
}
#[cfg(feature = "events")]
impl Default for Parameters{
fn default() -> Parameters{
let fxaa = events::Property::new(false);
let bloom = events::Property::new(true);
let sigma = RangedParameterMut::new(0.9, 0.0001 .. 10.0);
let bloom_threshold = RangedParameterMut::new_log_scale(5., 0.5 .. 100.);
let bloom_passes = RangedParameterMut::new(1, 1 .. 10);
let contrast = RangedParameterMut::new(1.0, 0.0 .. 3.0);
let brightness = RangedParameterMut::new(0.0, -3.0 .. 3.0);
let tonemap_type = events::Property::new(Tonemap::Uncharted2);
let exposure_bias = RangedParameterMut::new(1.0, 0.0 .. 5.0);
let a = RangedParameterMut::new(0.22, 0.01 .. 1.);
let b = RangedParameterMut::new(0.30, 0. .. 1.);
let c = RangedParameterMut::new(0.10, 0. .. 1.);
let d = RangedParameterMut::new(0.20, 0. .. 1.);
let e = RangedParameterMut::new_log_scale(0.01, 0. .. 0.1);
let f = RangedParameterMut::new_log_scale(0.30, 0.05 .. 1.);
let w = RangedParameterMut::new(11.2, 1. .. 20.);
let curve_data = curve_data(&a,&b,&c,&d,&e,&f,&w);
Parameters{
fxaa,
bloom,
sigma,
bloom_threshold,
bloom_passes,
contrast,
brightness,
tonemap_type,
a,
b,
c,
d,
e,
f,
w,
exposure_bias,
curve_data
}
}
}
#[cfg(not(feature = "events"))]
impl Default for Parameters{
fn default() -> Parameters{
let fxaa = false;
let bloom = true;
let sigma = 0.9;
let bloom_threshold = 1.2;
let bloom_passes = 1;
let contrast = 1.0;
let brightness = 0.0;
let tonemap_type = Tonemap::Uncharted2;
let exposure_bias = 1.0;
let a = 0.22;
let b = 0.30;
let c = 0.10;
let d = 0.20;
let e = 0.01;
let f = 0.30;
let w = 11.2;
Parameters{
fxaa,
bloom,
sigma,
bloom_threshold,
bloom_passes,
contrast,
brightness,
tonemap_type,
a,
b,
c,
d,
e,
f,
w,
exposure_bias,
}
}
}
impl PostProcessing{
#[cfg(feature="autoshader")]
fn new(gl: &gl::Renderer, w: u32, h: u32, format: gl::fbo::ColorFormat) -> util::Result<PostProcessing>{
let fbo_fxaa = fbo(gl, w, h, format)?;
let fbo_tonemap = fbo(gl, w, h, format)?;
let w = w/2;
let h = h/2;
let fbo_blur = [ fbo(gl, w, h, format)?, fbo(gl, w, h, format)?];
let shaders_path = Path::new(file!()).parent().unwrap().join("shaders");
let shader = |file|{
shaders_path.join(file)
};
#[cfg(feature="gl")]
let version = 420;
#[cfg(feature="gles")]
let version = 300;
#[cfg(feature="webgl")]
let version = 300;
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![],
shaders: vec![
(gl::VERTEX_SHADER, shader("full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("fxaa.fs.glsl")),
]
};
let mut fxaa_loader = gl.new_auto_program(settings);
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![
("PASS_V".to_string(), "".to_string()),
("BLUR9".to_string(), "".to_string()),
],
shaders: vec![
(gl::VERTEX_SHADER, shader("blur.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("blur.fs.glsl")),
]
};
let mut blur_v_loader = gl.new_auto_program(settings);
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![
("PASS_H".to_string(), "".to_string()),
("BLUR9".to_string(), "".to_string()),
],
shaders: vec![
(gl::VERTEX_SHADER, shader("blur.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("blur.fs.glsl")),
]
};
let mut blur_h_loader = gl.new_auto_program(settings);
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![
("HAS_BLUR".to_string(), "1".to_string()),
("TONEMAP_TYPE", "UNCHARTED2"),
],
shaders: vec![
(gl::VERTEX_SHADER, shader("full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("tonemap.fs.glsl")),
]
};
let mut tonemap_loader = gl.new_auto_program(settings);
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![
("HAS_BLUR".to_string(), "0".to_string()),
("TONEMAP_TYPE", "UNCHARTED2"),
],
shaders: vec![
(gl::VERTEX_SHADER, shader("full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("tonemap.fs.glsl")),
]
};
let mut tonemap_no_blur_loader = gl.new_auto_program(settings);
let settings = gl::autoload::ProgramSettings{
version,
precission: gl::autoload::ShaderPrecision::High,
extensions: vec![],
defines: vec![
("PASS_H".to_string(), "".to_string()),
],
shaders: vec![
(gl::VERTEX_SHADER, shader("full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, shader("bright.fs.glsl")),
]
};
let mut bright_loader = gl.new_auto_program(settings);
let fullscreen_quad = gl.new_simple_vao().from_data_bindings(
&graphics::rect_tex(-1., -1., 2., 2., 0., 1., 1., 0.),
&gl::default_attribute_bindings(),
gl::STATIC_DRAW
).unwrap();
Ok(PostProcessing{
fbo_render,
fbo_blit,
fbo_fxaa,
fbo_blur,
fbo_tonemap,
fxaa: fxaa_loader.load()?,
blur_v: blur_v_loader.load()?,
blur_h: blur_h_loader.load()?,
tonemap: UnsafeCell::new(tonemap_loader.load()?),
tonemap_no_blur: UnsafeCell::new(tonemap_no_blur_loader.load()?),
bright: bright_loader.load()?,
fxaa_loader,
blur_v_loader,
blur_h_loader,
tonemap_loader: UnsafeCell::new(tonemap_loader),
tonemap_no_blur_loader: UnsafeCell::new(tonemap_no_blur_loader),
bright_loader,
fullscreen_quad,
tonemap_type: Cell::new(Tonemap::Uncharted2),
})
}
#[cfg(not(feature="autoshader"))]
pub fn new(gl: &gl::Renderer, w: u32, h: u32, format: gl::fbo::ColorFormat) -> util::Result<PostProcessing>{
let fbo_fxaa = fbo(gl, w, h, format)?;
let fbo_tonemap = fbo(gl, w, h, format)?;
let w = w/2;
let h = h/2;
let fbo_blur = [ fbo(gl, w, h, format)?, fbo(gl, w, h, format)?];
#[cfg(feature="gl")]
let version = 420;
#[cfg(feature="gles")]
let version = 300;
#[cfg(feature="webgl")]
let version = 300;
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
defines: vec![("FXAA_GLSL_130", "1")],
bindings: gl::default_attribute_bindings(),
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/fxaa.fs.glsl")),
],
.. Default::default()
};
let fxaa = gl.new_program()
.from_settings(settings)
.unwrap();
fxaa.uniform_1f("width", w as f32).unwrap();
fxaa.uniform_1f("height", h as f32).unwrap();
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("PASS_V", ""),
("BLUR9", ""),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/blur.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/blur.fs.glsl")),
],
.. Default::default()
};
let blur_v = gl.new_program()
.from_settings(settings)
.unwrap();
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("PASS_H", ""),
("BLUR9", ""),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/blur.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/blur.fs.glsl")),
],
.. Default::default()
};
let blur_h = gl.new_program()
.from_settings(settings)
.unwrap();
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("HAS_BLUR", "1"),
("TONEMAP_TYPE", "UNCHARTED2"),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/tonemap.fs.glsl")),
],
.. Default::default()
};
let tonemap = gl.new_program()
.from_settings(settings)
.unwrap();
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("HAS_BLUR", "0"),
("TONEMAP_TYPE", "UNCHARTED2"),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/tonemap.fs.glsl")),
],
.. Default::default()
};
let tonemap_no_blur = gl.new_program()
.from_settings(settings)
.unwrap();
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("PASS_H", ""),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/bright.fs.glsl")),
],
.. Default::default()
};
let bright = gl.new_program()
.from_settings(settings)
.unwrap();
let fullscreen_quad = gl.new_simple_vao().from_data_bindings(
&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 1., 1., 0.),
&gl::default_attribute_bindings(),
gl::STATIC_DRAW
).unwrap();
Ok(PostProcessing{
fbo_fxaa,
fbo_blur,
fbo_tonemap,
fxaa,
blur_v,
blur_h,
tonemap: UnsafeCell::new(tonemap),
tonemap_no_blur: UnsafeCell::new(tonemap_no_blur),
bright,
fullscreen_quad,
tonemap_type: Cell::new(Tonemap::Uncharted2),
})
}
#[cfg(feature="autoshader")]
pub fn update(&mut self){
match self.fxaa_loader.update(){
Ok(Some(fxaa)) => {
self.fxaa = fxaa;
println!("fbo_fxaa shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
match self.blur_v_loader.update(){
Ok(Some(blur_v)) => {
self.blur_v = blur_v;
println!("blur_v shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
match self.blur_h_loader.update(){
Ok(Some(blur_h)) => {
self.blur_h = blur_h;
println!("blur_h shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
match unsafe{ (*self.tonemap_loader.get()).update() }{
Ok(Some(tonemap)) => {
self.tonemap = tonemap;
println!("tonemap shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
match unsafe{ (*self.tonemap_loader_no_blur.get()).update() }{
Ok(Some(tonemap_no_blur)) => {
self.tonemap_no_blur = tonemap_no_blur;
println!("tonemap_no_blur shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
match self.bright_loader.update(){
Ok(Some(bright)) => {
self.bright = bright;
println!("tonemap shader reloaded correctly");
}
Err(err) => {
println!("{}", err);
}
_ => {}
}
}
pub fn process<'a>(&'a self, gl: &gl::Renderer, tex: &'a gl::Texture, parameters: &Parameters) -> util::Result<&'a gl::Texture>{
let tonemap_type: &Tonemap = ¶meters.tonemap_type;
if *tonemap_type != self.tonemap_type.get() {
#[cfg(feature="gl")]
let version = 420;
#[cfg(feature="gles")]
let version = 300;
#[cfg(feature="webgl")]
let version = 300;
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("HAS_BLUR", "1"),
("TONEMAP_TYPE", tonemap_type.to_str()),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/tonemap.fs.glsl")),
],
.. Default::default()
};
unsafe{ *self.tonemap.get() = gl.new_program()
.from_settings(settings)
.unwrap() };
let settings = gl::program::Settings{
version,
precission: gl::program::ShaderPrecision::High,
extensions: vec![],
bindings: gl::default_attribute_bindings(),
defines: vec![
("HAS_BLUR", "0"),
("TONEMAP_TYPE", tonemap_type.to_str()),
],
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/full_quad.vs.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/tonemap.fs.glsl")),
],
.. Default::default()
};
unsafe{ *self.tonemap_no_blur.get() = gl.new_program()
.from_settings(settings)
.unwrap() };
self.tonemap_type.set(*tonemap_type);
}
let fxaa: &bool = ¶meters.fxaa;
let pre_bloomed_tex = if *fxaa{
let fxaa_uniforms = uniforms!{tex0: tex};
{
let gl = gl.with_fbo(&self.fbo_fxaa);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, &self.fxaa, &fxaa_uniforms);
}
self.fbo_fxaa.color_tex(0).unwrap()
}else{
tex
};
let bloom: &bool = ¶meters.bloom;
if *bloom {
#[cfg(feature="events")]
let passes = *parameters.bloom_passes;
#[cfg(not(feature="events"))]
let passes = parameters.bloom_passes;
let bright_uniforms = uniforms!{
tex0: pre_bloomed_tex,
bright_threshold: parameters.bloom_threshold
};
{
let gl = gl.with_fbo(&self.fbo_blur[0]);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, &self.bright, &bright_uniforms);
}
for pass in 0 .. passes {
let texture = self.fbo_blur[0].color_tex(0).unwrap();
let texel_size = [1./texture.width() as f32, 1./texture.height() as f32];
let std_dev = parameters.sigma.powf(pass as f32 + 1.);
let w0 = gaussian(0.0, 0.0, std_dev);
let w1 = gaussian(1.0, 0.0, std_dev);
let w2 = gaussian(2.0, 0.0, std_dev);
let w3 = gaussian(3.0, 0.0, std_dev);
let w4 = gaussian(4.0, 0.0, std_dev);
let w5 = gaussian(5.0, 0.0, std_dev);
let w6 = gaussian(6.0, 0.0, std_dev);
let w7 = gaussian(7.0, 0.0, std_dev);
let w8 = gaussian(8.0, 0.0, std_dev);
let wn = w0 + 2.0 * (w1 + w2 + w3 + w4 + w5 + w6 + w7 + w8);
let blur_v_uniforms = uniforms!{
tex0: texture,
texel_size: texel_size,
w0: w0/wn,
w1: w1/wn,
w2: w2/wn,
w3: w3/wn,
w4: w4/wn,
w5: w5/wn,
w6: w6/wn,
w7: w7/wn,
w8: w8/wn
};
{
let gl = gl.with_fbo(&self.fbo_blur[1]);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, &self.blur_v, &blur_v_uniforms);
}
let blur_h_uniforms = uniforms!{
tex0: (self.fbo_blur[1].color_tex(0).unwrap(), 2),
texel_size: texel_size,
w0: w0/wn,
w1: w1/wn,
w2: w2/wn,
w3: w3/wn,
w4: w4/wn,
w5: w5/wn,
w6: w6/wn,
w7: w7/wn,
w8: w8/wn
};
{
let gl = gl.with_fbo(&self.fbo_blur[0]);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, &self.blur_h, &blur_h_uniforms);
}
}
let tonemap_uniforms = uniforms!{
tex0: (pre_bloomed_tex, 1),
blurred1: (self.fbo_blur[0].color_tex(0).unwrap(), 2),
contrast: parameters.contrast,
brightness: parameters.brightness,
a: parameters.a,
b: parameters.b,
c: parameters.c,
d: parameters.d,
e: parameters.e,
f: parameters.f,
w: parameters.w,
exposureBias: parameters.exposure_bias,
};
{
let gl = gl.with_fbo(&self.fbo_tonemap);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, unsafe{&*self.tonemap.get()}, &tonemap_uniforms);
}
}else{
let tonemap_uniforms = uniforms!{
tex0: (pre_bloomed_tex, 1),
contrast: parameters.contrast,
brightness: parameters.brightness,
a: parameters.a,
b: parameters.b,
c: parameters.c,
d: parameters.d,
e: parameters.e,
f: parameters.f,
w: parameters.w,
exposureBias: parameters.exposure_bias,
};
{
let gl = gl.with_fbo(&self.fbo_tonemap);
gl.clear(&BLACK);
gl.draw_vao(&self.fullscreen_quad, unsafe{&*self.tonemap_no_blur.get()}, &tonemap_uniforms);
}
}
Ok(self.fbo_tonemap.color_tex(0).unwrap())
}
}
#[cfg(feature = "events")]
fn curve_data(
a: &RangedParameterMut<'static,f32>,
b: &RangedParameterMut<'static,f32>,
c: &RangedParameterMut<'static,f32>,
d: &RangedParameterMut<'static,f32>,
e: &RangedParameterMut<'static,f32>,
f: &RangedParameterMut<'static,f32>,
w: &RangedParameterMut<'static,f32>,
) -> RangedParameter<'static, Vec<f32>, f32>{
fn uncharted2(a: f32,b: f32,c: f32,d: f32,e: f32,f: f32,x: f32) -> f32{
(x*(a*x+c*b)+d*e)/(x*(a*x+b)+d*f) - e/f
};
let curve_data = a.clone().into_property()
.zip(b.clone().into_property())
.zip(c.clone().into_property())
.zip(d.clone().into_property())
.zip(e.clone().into_property())
.zip(f.clone().into_property())
.zip(w.clone().into_property())
.map(move |((((((a,b),c),d),e),f),w)|{
(0usize..200).map(|sample| sample as f32 / 10.)
.map(|x| {
uncharted2(a,b,c,d,e,f,x) / uncharted2(a,b,c,d,e,f,w)
})
.collect()
});
RangedParameter::new(curve_data, 0. .. 1.)
}
#[cfg(all(feature = "events", feature = "serialize"))]
impl<'de> Deserialize<'de> for Parameters{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
#[allow(non_camel_case_types)]
enum Field{
Fxaa, Bloom, Sigma, Bloom_Threshold, Bloom_Passes, Contrast, Brightness,
Tonemap_Type, Exposure_Bias,
A,B,C,D,E,F,W,
}
struct ParametersVisitor;
impl<'de> Visitor<'de> for ParametersVisitor {
type Value = Parameters;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Parameters")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Parameters, V::Error>
where V: SeqAccess<'de>
{
let fxaa = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let bloom = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let sigma = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
let bloom_threshold = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(3, &self))?;
let bloom_passes = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(4, &self))?;
let contrast = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(5, &self))?;
let brightness = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(6, &self))?;
let tonemap_type = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(7, &self))?;
let exposure_bias = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(8, &self))?;
let a: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(9, &self))?;
let b: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(10, &self))?;
let c: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(11, &self))?;
let d: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(12, &self))?;
let e: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(13, &self))?;
let f: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(14, &self))?;
let w: RangedParameterMut<'static,f32> = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(15, &self))?;
let curve_data = curve_data(&a,&b,&c,&d,&e,&f,&w);
Ok(Parameters{
fxaa, bloom, sigma, bloom_threshold, bloom_passes, contrast, brightness,
tonemap_type, exposure_bias,
a, b, c, d, e, f, w, curve_data,
})
}
fn visit_map<V>(self, mut map: V) -> Result<Parameters, V::Error>
where V: MapAccess<'de>
{
let mut fxaa = None;
let mut bloom = None;
let mut sigma = None;
let mut bloom_threshold = None;
let mut bloom_passes = None;
let mut contrast = None;
let mut brightness = None;
let mut tonemap_type = None;
let mut exposure_bias = None;
let mut a = None;
let mut b = None;
let mut c = None;
let mut d = None;
let mut e = None;
let mut f = None;
let mut w = None;
while let Some(key) = map.next_key()? {
match key {
Field::Fxaa => {
if fxaa.is_some() {
return Err(de::Error::duplicate_field("fxaa"));
}
fxaa = Some(map.next_value()?);
}
Field::Bloom => {
if bloom.is_some() {
return Err(de::Error::duplicate_field("bloom"));
}
bloom = Some(map.next_value()?);
}
Field::Sigma => {
if sigma.is_some() {
return Err(de::Error::duplicate_field("sigma"));
}
sigma = Some(map.next_value()?);
}
Field::Bloom_Threshold => {
if bloom_threshold.is_some() {
return Err(de::Error::duplicate_field("bloom_threshold"));
}
bloom_threshold = Some(map.next_value()?);
}
Field::Bloom_Passes => {
if bloom_passes.is_some() {
return Err(de::Error::duplicate_field("bloom_passes"));
}
bloom_passes = Some(map.next_value()?);
}
Field::Contrast => {
if contrast.is_some() {
return Err(de::Error::duplicate_field("contrast"));
}
contrast = Some(map.next_value()?);
}
Field::Brightness => {
if brightness.is_some() {
return Err(de::Error::duplicate_field("brightness"));
}
brightness = Some(map.next_value()?);
}
Field::Tonemap_Type => {
if tonemap_type.is_some() {
return Err(de::Error::duplicate_field("tonemap_type"));
}
tonemap_type = Some(map.next_value()?);
}
Field::Exposure_Bias => {
if exposure_bias.is_some() {
return Err(de::Error::duplicate_field("exposure_bias"));
}
exposure_bias = Some(map.next_value()?);
}
Field::A => {
if a.is_some() {
return Err(de::Error::duplicate_field("a"));
}
a = Some(map.next_value()?);
}
Field::B => {
if b.is_some() {
return Err(de::Error::duplicate_field("b"));
}
b = Some(map.next_value()?);
}
Field::C => {
if c.is_some() {
return Err(de::Error::duplicate_field("c"));
}
c = Some(map.next_value()?);
}
Field::D => {
if d.is_some() {
return Err(de::Error::duplicate_field("d"));
}
d = Some(map.next_value()?);
}
Field::E => {
if e.is_some() {
return Err(de::Error::duplicate_field("e"));
}
e = Some(map.next_value()?);
}
Field::F => {
if f.is_some() {
return Err(de::Error::duplicate_field("f"));
}
f = Some(map.next_value()?);
}
Field::W => {
if w.is_some() {
return Err(de::Error::duplicate_field("w"));
}
w = Some(map.next_value()?);
}
}
}
let fxaa = fxaa.ok_or_else(|| de::Error::missing_field("fxaa"))?;
let bloom = bloom.ok_or_else(|| de::Error::missing_field("bloom"))?;
let sigma = sigma.ok_or_else(|| de::Error::missing_field("sigma"))?;
let bloom_threshold = bloom_threshold.ok_or_else(|| de::Error::missing_field("bloom_threshold"))?;
let bloom_passes = bloom_passes.ok_or_else(|| de::Error::missing_field("bloom_passes"))?;
let contrast = contrast.ok_or_else(|| de::Error::missing_field("contrast"))?;
let brightness = brightness.ok_or_else(|| de::Error::missing_field("brightness"))?;
let tonemap_type = tonemap_type.ok_or_else(|| de::Error::missing_field("tonemap_type"))?;
let exposure_bias = exposure_bias.ok_or_else(|| de::Error::missing_field("exposure_bias"))?;
let a = a.ok_or_else(|| de::Error::missing_field("a"))?;
let b = b.ok_or_else(|| de::Error::missing_field("b"))?;
let c = c.ok_or_else(|| de::Error::missing_field("c"))?;
let d = d.ok_or_else(|| de::Error::missing_field("d"))?;
let e = e.ok_or_else(|| de::Error::missing_field("e"))?;
let f = f.ok_or_else(|| de::Error::missing_field("f"))?;
let w = w.ok_or_else(|| de::Error::missing_field("w"))?;
let curve_data = curve_data(&a,&b,&c,&d,&e,&f,&w);
Ok(Parameters{
fxaa, bloom, sigma, bloom_threshold, bloom_passes, contrast, brightness,
tonemap_type, exposure_bias,
a, b, c, d, e, f, w, curve_data,
})
}
}
const FIELDS: &'static [&'static str] = &[
"fxaa", "bloom", "sigma", "bloom_threshold", "bloom_passes", "contrast", "brightness",
"tonemap_type", "exposure_bias",
"a", "b", "c", "d", "e", "f", "w"
];
deserializer.deserialize_struct("Duration", FIELDS, ParametersVisitor)
}
}