]> git.tdb.fi Git - libs/gl.git/blob - source/bloom.cpp
Use the Blend and DepthTest classes
[libs/gl.git] / source / bloom.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cmath>
9 #include <msp/strings/formatter.h>
10 #include "blend.h"
11 #include "bloom.h"
12 #include "meshbuilder.h"
13 #include "misc.h"
14 #include "tests.h"
15 #include "texunit.h"
16
17 using namespace std;
18
19 namespace {
20
21 static const char blur_vs[]=
22         "varying vec2 texcoord;\n"
23         "void main()\n"
24         "{\n"
25         "       gl_Position = vec4(gl_Vertex.xy*2.0-1.0, 0.0, 1.0);\n"
26         "       texcoord = gl_Vertex.xy;\n"
27         "}";
28
29 static const char blur_fs[]=
30         "uniform sampler2D source;\n"
31         "uniform vec2 delta;\n"
32         "uniform float factors[19];\n"
33         "uniform int size;\n"
34         "varying vec2 texcoord;\n"
35         "void main()\n"
36         "{\n"
37         "       gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
38         "       for(int i=-size; i<=size; ++i)\n"
39         "               gl_FragColor += texture2D(source, texcoord+delta*i)*factors[i+size];\n"
40         "}";
41
42 static const char combine_vs[]=
43         "varying vec2 texcoord;\n"
44         "void main()\n"
45         "{\n"
46         "       gl_Position = vec4(gl_Vertex.xy*2.0-1.0, 0.0, 1.0);\n"
47         "       texcoord = gl_Vertex.xy;\n"
48         "}";
49
50 static const char combine_fs[]=
51         "uniform sampler2D source;\n"
52         "uniform sampler2D blurred;\n"
53         "uniform float strength;\n"
54         "varying vec2 texcoord;\n"
55         "void main()\n"
56         "{\n"
57         "       gl_FragColor = mix(texture2D(source, texcoord), texture2D(blurred, texcoord), strength);\n"
58         "}";
59
60 }
61
62 namespace Msp {
63 namespace GL {
64
65 Bloom::Bloom(unsigned w, unsigned h):
66         blur_shader(blur_vs, blur_fs),
67         combine_shader(combine_vs, combine_fs),
68         quad(VERTEX2)
69 {
70         int loc = blur_shader.get_uniform_location("delta");
71         blur_shdata[0].uniform(loc, 1.0f/w, 0.0f);
72         blur_shdata[1].uniform(loc, 0.0f, 1.0f/h);
73
74         loc = blur_shader.get_uniform_location("source");
75         for(unsigned i=0; i<2; ++i)
76         {
77                 blur_shdata[i].uniform(loc, 0);
78                 tex[i].set_min_filter(NEAREST);
79                 tex[i].storage(RGB16F, w, h, 0);
80                 tex[i].image(0, RGB, UNSIGNED_BYTE, 0);
81         }
82
83         combine_shdata.uniform(combine_shader.get_uniform_location("source"), 1);
84         combine_shdata.uniform(combine_shader.get_uniform_location("blurred"), 0);
85
86         set_radius(2.0f);
87         set_strength(0.2f);
88
89         MeshBuilder mbld(quad);
90         mbld.begin(QUADS);
91         mbld.vertex(0, 0);
92         mbld.vertex(1, 0);
93         mbld.vertex(1, 1);
94         mbld.vertex(0, 1);
95         mbld.end();
96 }
97
98 void Bloom::set_radius(float r)
99 {
100         if(r<=0.0f)
101                 throw InvalidParameterValue("Radius must be positive");
102
103         int size = min(static_cast<int>(r*3.0f), 9);
104         int loc = blur_shader.get_uniform_location("size");
105         blur_shdata[0].uniform(loc, size);
106         blur_shdata[1].uniform(loc, size);
107
108         vector<float> factors(size*2+1);
109         float sum = 0.0f;
110         r = 2*r*r;
111         for(int i=-size; i<=size; ++i)
112                 sum += (factors[size+i] = exp(-i*i/r));
113
114         for(int i=0; i<=size*2; ++i)
115         {
116                 loc = blur_shader.get_uniform_location(format("factors[%d]", i));
117                 float f = factors[i]/sum;
118                 blur_shdata[0].uniform(loc, f);
119                 blur_shdata[1].uniform(loc, f);
120         }
121 }
122
123 void Bloom::set_strength(float s)
124 {
125         if(s<0.0f || s>1.0f)
126                 throw InvalidParameterValue("Strength must be in the range [0.0, 1.0]");
127         combine_shdata.uniform(combine_shader.get_uniform_location("strength"), s);
128 }
129
130 void Bloom::render(const Texture2D &src)
131 {
132         const Framebuffer *dest = Framebuffer::current();
133         blur_shader.bind();
134         fbo.bind();
135         src.bind_to(0);
136         Bind unbind_dtest(static_cast<DepthTest *>(0), true);
137         Bind unbind_blend(static_cast<Blend *>(0), true);
138         for(unsigned i=0; i<2; ++i)
139         {
140                 fbo.attach(COLOR_ATTACHMENT0, tex[i], 0);
141                 blur_shdata[i].apply();
142                 quad.draw();
143                 tex[i].bind_to(0);
144         }
145
146         if(dest)
147                 dest->bind();
148         else
149                 Framebuffer::unbind();
150
151         combine_shader.bind();
152         combine_shdata.apply();
153         src.bind_to(1);
154         quad.draw();
155         Program::unbind();
156         Texture::unbind_from(1);
157         Texture::unbind_from(0);
158 }
159
160 } // namespace GL
161 } // namespace Msp