2 #include <msp/gl/renderer.h>
3 #include <msp/gl/texture2d.h>
12 FilmGrain::FilmGrain(unsigned s, unsigned l):
13 mesh(get_fullscreen_quad()),
14 shprog(Resources::get_builtins().get<GL::Program>("filmgrain.glsl")),
19 grain.set_min_filter(GL::LINEAR);
20 grain.set_mag_filter(GL::LINEAR);
21 grain.set_wrap(GL::REPEAT);
22 grain.storage(GL::R8, size, size, layers, 1);
26 texturing.attach(1, grain);
27 shdata.uniform("grain", 1);
33 void FilmGrain::generate_grain()
35 UInt8 *data = new UInt8[size*size*layers];
37 unsigned noise_size = size/2;
38 UInt8 *noise = new UInt8[noise_size*noise_size];
39 Int16 *dbuf = new Int16[3*noise_size*noise_size];
42 for(unsigned i=0; i<layers; ++i)
44 for(unsigned j=0; j<noise_size*noise_size; ++j)
47 bicubic2x(noise, data+i*size*size, dbuf);
53 grain.image(0, GL::RED, GL::UNSIGNED_BYTE, data);
57 void FilmGrain::bicubic2x(const UInt8 *src, UInt8 *target, Int16 *dbuf)
59 unsigned src_size = size/2;
61 // dx and dy will have an implicit scaling factor of 2
63 Int16 *dy = dbuf+src_size*src_size;
64 for(unsigned y=0; y<src_size; ++y)
65 for(unsigned x=0; x<src_size; ++x)
67 unsigned i = x+y*src_size;
68 dx[i] = src[(x+1)%src_size + y*src_size] - src[(x+src_size-1)%src_size + y*src_size];
69 dy[i] = src[x + (y+1)%src_size*src_size] - src[x + (y+src_size-1)%src_size*src_size];
72 // dxy will have an implicit scaling factor of 4
73 Int16 *dxy = dbuf+2*src_size*src_size;
74 for(unsigned y=0; y<src_size; ++y)
75 for(unsigned x=0; x<src_size; ++x)
76 dxy[x+y*src_size] = dy[(x+1)%src_size + y*src_size] - dy[(x+src_size-1)%src_size + y*src_size];
78 for(unsigned y=0; y<src_size; ++y)
80 unsigned y2 = (y+1)%src_size;
82 for(unsigned x=0; x<src_size; ++x)
84 unsigned x2 = (x+1)%src_size;
86 unsigned i00 = x+y*src_size;
87 unsigned i10 = x2+y*src_size;
88 unsigned i01 = x+y2*src_size;
89 unsigned i11 = x2+y2*src_size;
91 // Cubic hermite at t=0.5: 0.5*p0 + 0.125*m0 + 0.5*p1 - 0.125*m1
92 unsigned i = x*2+y*2*size;
94 target[i+1] = clamp(((src[i00]+src[i10])*8+dx[i00]-dx[i10])/16);
95 target[i+size] = clamp(((src[i00]+src[i01])*8+dy[i00]-dy[i01])/16);
96 // dyh0 and dyh1 will have an implicit scaling factor of 32
97 Int16 dyh0 = (dy[i00]+dy[i10])*8+dxy[i00]-dxy[i10];
98 Int16 dyh1 = (dy[i01]+dy[i11])*8+dxy[i01]-dxy[i11];
99 target[i+1+size] = clamp(((src[i00]+src[i10]+src[i01]+src[i11])*64+dyh0-dyh1)/256);
104 UInt8 FilmGrain::clamp(int v)
106 return min(max(v, 0), 255);
109 void FilmGrain::set_coarseness(float c)
111 shdata.uniform("coarseness", c/2.0f);
114 void FilmGrain::set_strength(float s)
116 shdata.uniform("strength", s);
119 void FilmGrain::render(GL::Renderer &renderer, const GL::Texture2D &color, const GL::Texture2D &)
121 current_layer = (current_layer+1)%layers;
122 shdata.uniform("grain_layer", static_cast<int>(current_layer));
123 texturing.attach(0, color);
124 renderer.set_texturing(&texturing);
125 renderer.set_shader_program(&shprog, &shdata);
130 FilmGrain::Template::Template():
137 FilmGrain *FilmGrain::Template::create(unsigned, unsigned) const
139 FilmGrain *grain = new FilmGrain(size, layers);
140 grain->set_coarseness(coarseness);
141 grain->set_strength(strength);
146 FilmGrain::Template::Loader::Loader(Template &t):
147 DerivedObjectLoader<Template, PostProcessor::Template::Loader>(t)
149 add("coarseness", &Template::coarseness);
150 add("layers", &Template::layers);
151 add("size", &Template::size);
152 add("strength", &Template::strength);
155 } // namespace DemoScene