]> git.tdb.fi Git - libs/demoscene.git/blob - source/filmgrain.cpp
Allow stages to define actions
[libs/demoscene.git] / source / filmgrain.cpp
1 #include <random>
2 #include <msp/gl/renderer.h>
3 #include <msp/gl/texture2d.h>
4 #include "filmgrain.h"
5 #include "resources.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace DemoScene {
11
12 FilmGrain::FilmGrain(unsigned s, unsigned l):
13         mesh(get_fullscreen_quad()),
14         shprog(Resources::get_builtins().get<GL::Program>("filmgrain.glsl")),
15         size(s),
16         layers(l),
17         current_layer(0)
18 {
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);
23
24         generate_grain();
25
26         texturing.attach(1, grain);
27         shdata.uniform("grain", 1);
28
29         set_coarseness(2.0f);
30         set_strength(0.1f);
31 }
32
33 void FilmGrain::generate_grain()
34 {
35         UInt8 *data = new UInt8[size*size*layers];
36
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];
40         minstd_rand random;
41
42         for(unsigned i=0; i<layers; ++i)
43         {
44                 for(unsigned j=0; j<noise_size*noise_size; ++j)
45                         noise[j] = random();
46
47                 bicubic2x(noise, data+i*size*size, dbuf);
48         }
49
50         delete[] noise;
51         delete[] dbuf;
52
53         grain.image(0, GL::RED, GL::UNSIGNED_BYTE, data);
54         delete[] data;
55 }
56
57 void FilmGrain::bicubic2x(const UInt8 *src, UInt8 *target, Int16 *dbuf)
58 {
59         unsigned src_size = size/2;
60
61         // dx and dy will have an implicit scaling factor of 2
62         Int16 *dx = dbuf;
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)
66                 {
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];
70                 }
71
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];
77
78         for(unsigned y=0; y<src_size; ++y)
79         {
80                 unsigned y2 = (y+1)%src_size;
81
82                 for(unsigned x=0; x<src_size; ++x)
83                 {
84                         unsigned x2 = (x+1)%src_size;
85
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;
90
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;
93                         target[i] = src[i00];
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);
100                 }
101         }
102 }
103
104 UInt8 FilmGrain::clamp(int v)
105 {
106         return min(max(v, 0), 255);
107 }
108
109 void FilmGrain::set_coarseness(float c)
110 {
111         shdata.uniform("coarseness", c/2.0f);
112 }
113
114 void FilmGrain::set_strength(float s)
115 {
116         shdata.uniform("strength", s);
117 }
118
119 void FilmGrain::render(GL::Renderer &renderer, const GL::Texture2D &color, const GL::Texture2D &)
120 {
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);
126         mesh.draw(renderer);
127 }
128
129
130 FilmGrain::Template::Template():
131         size(256),
132         layers(16),
133         coarseness(2.0f),
134         strength(0.1f)
135 { }
136
137 FilmGrain *FilmGrain::Template::create(unsigned, unsigned) const
138 {
139         FilmGrain *grain = new FilmGrain(size, layers);
140         grain->set_coarseness(coarseness);
141         grain->set_strength(strength);
142         return grain;
143 }
144
145
146 FilmGrain::Template::Loader::Loader(Template &t):
147         DerivedObjectLoader<Template, PostProcessor::Template::Loader>(t)
148 {
149         add("coarseness", &Template::coarseness);
150         add("layers", &Template::layers);
151         add("size", &Template::size);
152         add("strength", &Template::strength);
153 }
154
155 } // namespace DemoScene
156 } // namespace Msp