Changeset View
Changeset View
Standalone View
Standalone View
effects/blur/blurshader.cpp
Show All 14 Lines | |||||
15 | * along with this program; see the file COPYING. if not, write to | 15 | * along with this program; see the file COPYING. if not, write to | ||
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | * Boston, MA 02110-1301, USA. | 17 | * Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "blurshader.h" | 20 | #include "blurshader.h" | ||
21 | 21 | | |||
22 | #include <kwineffects.h> | 22 | #include <kwineffects.h> | ||
23 | #include "kwinglutils.h" | ||||
23 | #include <kwinglplatform.h> | 24 | #include <kwinglplatform.h> | ||
24 | 25 | | |||
25 | #include <QByteArray> | 26 | #include <QByteArray> | ||
26 | #include <QMatrix4x4> | 27 | #include <QMatrix4x4> | ||
27 | #include <QTextStream> | 28 | #include <QTextStream> | ||
28 | #include <QVector2D> | 29 | #include <QVector2D> | ||
29 | 30 | | |||
30 | #include <cmath> | 31 | #include <cmath> | ||
31 | 32 | | |||
32 | using namespace KWin; | 33 | using namespace KWin; | ||
33 | 34 | | |||
34 | 35 | | |||
35 | BlurShader::BlurShader() | 36 | BlurShader::BlurShader() | ||
36 | : mRadius(0), mValid(false) | 37 | : mValid(false) | ||
37 | { | 38 | { | ||
38 | } | 39 | } | ||
39 | 40 | | |||
40 | BlurShader::~BlurShader() | 41 | BlurShader::~BlurShader() | ||
41 | { | 42 | { | ||
42 | } | 43 | } | ||
43 | 44 | | |||
44 | BlurShader *BlurShader::create() | 45 | BlurShader *BlurShader::create() | ||
45 | { | 46 | { | ||
46 | return new GLSLBlurShader(); | 47 | return new GLSLBlurShader(); | ||
47 | } | 48 | } | ||
48 | 49 | | |||
49 | void BlurShader::setRadius(int radius) | 50 | // ---------------------------------------------------------------------------- | ||
50 | { | 51 | | ||
zzag: No, it should be in the header file. E.g.
```
...
private:
GLShader *m_shaderDownsample =… | |||||
51 | const int r = qMax(radius, 2); | | |||
52 | 52 | | |||
53 | if (mRadius != r) { | | |||
54 | mRadius = r; | | |||
55 | reset(); | | |||
56 | init(); | | |||
57 | } | | |||
58 | } | | |||
59 | 53 | | |||
60 | void BlurShader::setDirection(Qt::Orientation direction) | 54 | GLSLBlurShader::GLSLBlurShader() | ||
55 | : BlurShader(), m_shaderDownsample(NULL), m_shaderUpsample(NULL), m_shaderCopysample(NULL) | ||||
You can simplify: GLShader *m_shaderDownsample = nullptr; GLShader *m_shaderUpsample = nullptr; GLShader *m_shaderCopysample = nullptr; zzag: You can simplify:
```
GLShader *m_shaderDownsample = nullptr;
GLShader… | |||||
61 | { | 56 | { | ||
62 | mDirection = direction; | 57 | init(); | ||
63 | } | 58 | } | ||
64 | 59 | | |||
65 | float BlurShader::gaussian(float x, float sigma) const | 60 | GLSLBlurShader::~GLSLBlurShader() | ||
66 | { | 61 | { | ||
67 | return (1.0 / std::sqrt(2.0 * M_PI) * sigma) | 62 | reset(); | ||
68 | * std::exp(-((x * x) / (2.0 * sigma * sigma))); | | |||
69 | } | 63 | } | ||
70 | 64 | | |||
71 | QList<KernelValue> BlurShader::gaussianKernel() const | 65 | void GLSLBlurShader::reset() | ||
72 | { | 66 | { | ||
73 | int size = qMin(mRadius | 1, maxKernelSize()); | 67 | delete m_shaderDownsample; | ||
74 | if (!(size & 0x1)) | 68 | m_shaderDownsample = NULL; | ||
zzag: `nullptr` | |||||
75 | size -= 1; | 69 | | ||
70 | delete m_shaderUpsample; | ||||
71 | m_shaderUpsample = NULL; | ||||
zzag: `nullptr` | |||||
76 | 72 | | |||
77 | QList<KernelValue> kernel; | 73 | delete m_shaderCopysample; | ||
78 | const int center = size / 2; | 74 | m_shaderCopysample = NULL; | ||
zzag: `nullptr` | |||||
79 | const qreal sigma = (size - 1) / 2.5; | | |||
80 | 75 | | |||
81 | kernel << KernelValue(0.0, gaussian(0.0, sigma)); | 76 | setIsValid(false); | ||
82 | float total = kernel[0].g; | 77 | } | ||
83 | 78 | | |||
84 | for (int x = 1; x <= center; x++) { | 79 | void GLSLBlurShader::setModelViewProjectionMatrix(const QMatrix4x4 &matrix) | ||
85 | const float fx = (x - 1) * 2 + 1.5; | 80 | { | ||
86 | const float g1 = gaussian(fx - 0.5, sigma); | 81 | if (!isValid()) | ||
87 | const float g2 = gaussian(fx + 0.5, sigma); | 82 | return; | ||
88 | 83 | | |||
89 | // Offset taking the contribution of both pixels into account | 84 | switch (m_activeSampleType) { | ||
90 | const float offset = .5 - g1 / (g1 + g2); | 85 | case copySampleType: | ||
86 | if (matrix == m_matrixCopysample) | ||||
zzag: Please use `{}` | |||||
Most other if statements don't use brackets when there is only a return line and I don't intend to break that tradition, or I might have to correct all of them too. anemeth: Most other if statements don't use brackets when there is only a return line and I don't intend… | |||||
87 | return; | ||||
91 | 88 | | |||
92 | kernel << KernelValue(fx + offset, g1 + g2); | 89 | m_matrixCopysample = matrix; | ||
93 | kernel << KernelValue(-(fx + offset), g1 + g2); | 90 | m_shaderCopysample->setUniform(m_mvpMatrixLocationCopysample, matrix); | ||
91 | break; | ||||
94 | 92 | | |||
95 | total += (g1 + g2) * 2; | 93 | case upSampleType: | ||
96 | } | 94 | if (matrix == m_matrixUpsample) | ||
95 | return; | ||||
97 | 96 | | |||
98 | qSort(kernel); | 97 | m_matrixUpsample = matrix; | ||
98 | m_shaderUpsample->setUniform(m_mvpMatrixLocationUpsample, matrix); | ||||
99 | break; | ||||
99 | 100 | | |||
100 | // Normalize the kernel | 101 | case downSampleType: | ||
101 | for (int i = 0; i < kernel.count(); i++) | 102 | if (matrix == m_matrixDownsample) | ||
102 | kernel[i].g /= total; | 103 | return; | ||
103 | 104 | | |||
104 | return kernel; | 105 | m_matrixDownsample = matrix; | ||
106 | m_shaderDownsample->setUniform(m_mvpMatrixLocationDownsample, matrix); | ||||
107 | break; | ||||
108 | } | ||||
105 | } | 109 | } | ||
106 | 110 | | |||
111 | void GLSLBlurShader::setOffset(float offset) | ||||
112 | { | ||||
113 | if (!isValid()) | ||||
114 | return; | ||||
107 | 115 | | |||
116 | switch (m_activeSampleType) { | ||||
117 | case upSampleType: | ||||
118 | if (offset == m_offsetUpsample) | ||||
119 | return; | ||||
108 | 120 | | |||
109 | // ---------------------------------------------------------------------------- | 121 | m_offsetUpsample = offset; | ||
110 | 122 | m_shaderUpsample->setUniform(m_offsetLocationUpsample, offset); | |||
123 | break; | ||||
111 | 124 | | |||
125 | case downSampleType: | ||||
126 | if (offset == m_offsetDownsample) | ||||
127 | return; | ||||
112 | 128 | | |||
113 | GLSLBlurShader::GLSLBlurShader() | 129 | m_offsetDownsample = offset; | ||
114 | : BlurShader(), shader(NULL) | 130 | m_shaderDownsample->setUniform(m_offsetLocationDownsample, offset); | ||
115 | { | 131 | break; | ||
116 | } | 132 | } | ||
117 | | ||||
118 | GLSLBlurShader::~GLSLBlurShader() | | |||
119 | { | | |||
120 | reset(); | | |||
121 | } | 133 | } | ||
122 | 134 | | |||
123 | void GLSLBlurShader::reset() | 135 | void GLSLBlurShader::setTextureSize(QSize textureSize) | ||
124 | { | 136 | { | ||
125 | delete shader; | 137 | if (!isValid()) | ||
126 | shader = NULL; | 138 | return; | ||
127 | 139 | | |||
128 | setIsValid(false); | 140 | QVector2D texSize = QVector2D(textureSize.width(), textureSize.height()); | ||
129 | } | | |||
130 | 141 | | |||
131 | void GLSLBlurShader::setPixelDistance(float val) | 142 | switch (m_activeSampleType) { | ||
132 | { | 143 | case copySampleType: | ||
133 | if (!isValid()) | 144 | if (textureSize == m_textureSizeCopysample) | ||
134 | return; | 145 | return; | ||
135 | 146 | | |||
136 | QVector2D pixelSize(0.0, 0.0); | 147 | m_textureSizeCopysample = textureSize; | ||
137 | if (direction() == Qt::Horizontal) | 148 | m_shaderCopysample->setUniform(m_textureSizeLocationCopysample, texSize); | ||
138 | pixelSize.setX(val); | 149 | break; | ||
139 | else | | |||
140 | pixelSize.setY(val); | | |||
141 | 150 | | |||
142 | shader->setUniform(pixelSizeLocation, pixelSize); | 151 | case upSampleType: | ||
143 | } | 152 | if (textureSize == m_textureSizeUpsample) | ||
153 | return; | ||||
144 | 154 | | |||
145 | void GLSLBlurShader::setTextureMatrix(const QMatrix4x4 &matrix) | 155 | m_textureSizeUpsample = textureSize; | ||
146 | { | 156 | m_shaderUpsample->setUniform(m_textureSizeLocationUpsample, texSize); | ||
147 | if (!isValid()) | 157 | break; | ||
158 | | ||||
159 | case downSampleType: | ||||
160 | if (textureSize == m_textureSizeDownsample) | ||||
148 | return; | 161 | return; | ||
149 | 162 | | |||
150 | shader->setUniform(textureMatrixLocation, matrix); | 163 | m_textureSizeDownsample = textureSize; | ||
164 | m_shaderDownsample->setUniform(m_textureSizeLocationDownsample, texSize); | ||||
165 | break; | ||||
166 | } | ||||
151 | } | 167 | } | ||
152 | 168 | | |||
153 | void GLSLBlurShader::setModelViewProjectionMatrix(const QMatrix4x4 &matrix) | 169 | void GLSLBlurShader::setBlurRect(QRect blurRect, QSize screenSize) | ||
154 | { | 170 | { | ||
155 | if (!isValid()) | 171 | if (!isValid() || blurRect == m_blurRectCopysample) | ||
156 | return; | 172 | return; | ||
157 | 173 | | |||
158 | shader->setUniform(mvpMatrixLocation, matrix); | 174 | m_blurRectCopysample = blurRect; | ||
175 | | ||||
176 | QVector4D rect = QVector4D( | ||||
177 | blurRect.bottomLeft().x() / float(screenSize.width()), | ||||
178 | 1.0 - blurRect.bottomLeft().y() / float(screenSize.height()), | ||||
179 | blurRect.topRight().x() / float(screenSize.width()), | ||||
180 | 1.0 - blurRect.topRight().y() / float(screenSize.height()) | ||||
181 | ); | ||||
182 | | ||||
183 | m_shaderCopysample->setUniform(m_blurRectLocationCopysample, rect); | ||||
159 | } | 184 | } | ||
160 | 185 | | |||
161 | void GLSLBlurShader::bind() | 186 | void GLSLBlurShader::bind(int sampleType) | ||
162 | { | 187 | { | ||
163 | if (!isValid()) | 188 | if (!isValid()) | ||
164 | return; | 189 | return; | ||
165 | 190 | | |||
166 | ShaderManager::instance()->pushShader(shader); | 191 | switch (sampleType) { | ||
192 | case copySampleType: | ||||
193 | ShaderManager::instance()->pushShader(m_shaderCopysample); | ||||
194 | break; | ||||
195 | | ||||
196 | case upSampleType: | ||||
197 | ShaderManager::instance()->pushShader(m_shaderUpsample); | ||||
198 | break; | ||||
199 | | ||||
200 | case downSampleType: | ||||
201 | ShaderManager::instance()->pushShader(m_shaderDownsample); | ||||
202 | break; | ||||
167 | } | 203 | } | ||
168 | 204 | | |||
169 | void GLSLBlurShader::unbind() | 205 | m_activeSampleType = sampleType; | ||
170 | { | | |||
171 | ShaderManager::instance()->popShader(); | | |||
172 | } | 206 | } | ||
173 | 207 | | |||
174 | int GLSLBlurShader::maxKernelSize() const | 208 | void GLSLBlurShader::unbind() | ||
175 | { | 209 | { | ||
176 | if (GLPlatform::instance()->isGLES()) { | 210 | ShaderManager::instance()->popShader(); | ||
177 | // GL_MAX_VARYING_FLOATS not available in GLES | | |||
178 | // querying for GL_MAX_VARYING_VECTORS crashes on nouveau | | |||
179 | // using the minimum value of 8 | | |||
180 | return 8 * 2; | | |||
181 | } else { | | |||
182 | int value; | | |||
183 | glGetIntegerv(GL_MAX_VARYING_FLOATS, &value); | | |||
184 | // Maximum number of vec4 varyings * 2 | | |||
185 | // The code generator will pack two vec2's into each vec4. | | |||
186 | return value / 2; | | |||
187 | } | | |||
188 | } | 211 | } | ||
189 | 212 | | |||
190 | void GLSLBlurShader::init() | 213 | void GLSLBlurShader::init() | ||
191 | { | 214 | { | ||
192 | QList<KernelValue> kernel = gaussianKernel(); | | |||
193 | const int size = kernel.size(); | | |||
194 | const int center = size / 2; | | |||
195 | | ||||
196 | QList<QVector4D> offsets; | | |||
197 | for (int i = 0; i < kernel.size(); i += 2) { | | |||
198 | QVector4D vec4(0, 0, 0, 0); | | |||
199 | | ||||
200 | vec4.setX(kernel[i].x); | | |||
201 | vec4.setY(kernel[i].x); | | |||
202 | | ||||
203 | if (i < kernel.size() - 1) { | | |||
204 | vec4.setZ(kernel[i + 1].x); | | |||
205 | vec4.setW(kernel[i + 1].x); | | |||
206 | } | | |||
207 | | ||||
208 | offsets << vec4; | | |||
209 | } | | |||
210 | | ||||
211 | const bool gles = GLPlatform::instance()->isGLES(); | 215 | const bool gles = GLPlatform::instance()->isGLES(); | ||
212 | const bool glsl_140 = !gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(1, 40); | 216 | const bool glsl_140 = !gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(1, 40); | ||
213 | const bool core = glsl_140 || (gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0)); | 217 | const bool core = glsl_140 || (gles && GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0)); | ||
214 | 218 | | |||
215 | QByteArray vertexSource; | 219 | QByteArray vertexSource; | ||
216 | QByteArray fragmentSource; | 220 | QByteArray fragmentDownSource; | ||
221 | QByteArray fragmentUpSource; | ||||
222 | QByteArray fragmentCopySource; | ||||
217 | 223 | | |||
218 | const QByteArray attribute = core ? "in" : "attribute"; | 224 | const QByteArray attribute = core ? "in" : "attribute"; | ||
219 | const QByteArray varying_in = core ? (gles ? "in" : "noperspective in") : "varying"; | | |||
220 | const QByteArray varying_out = core ? (gles ? "out" : "noperspective out") : "varying"; | | |||
221 | const QByteArray texture2D = core ? "texture" : "texture2D"; | 225 | const QByteArray texture2D = core ? "texture" : "texture2D"; | ||
222 | const QByteArray fragColor = core ? "fragColor" : "gl_FragColor"; | 226 | const QByteArray fragColor = core ? "fragColor" : "gl_FragColor"; | ||
223 | 227 | | |||
224 | // Vertex shader | 228 | QString glHeaderString; | ||
225 | // =================================================================== | | |||
226 | QTextStream stream(&vertexSource); | | |||
227 | 229 | | |||
228 | if (gles) { | 230 | if (gles) { | ||
229 | if (core) { | 231 | if (core) { | ||
230 | stream << "#version 300 es\n\n"; | 232 | glHeaderString += "#version 300 es\n\n"; | ||
231 | } | 233 | } | ||
232 | stream << "precision highp float;\n"; | 234 | | ||
235 | glHeaderString += "precision highp float;\n"; | ||||
233 | } else if (glsl_140) { | 236 | } else if (glsl_140) { | ||
234 | stream << "#version 140\n\n"; | 237 | glHeaderString += "#version 140\n\n"; | ||
QString glHeaderString; if (gles) { if (core) { glHeaderString += "#version 300 es\n\n"; } glHeaderString += "precision highp float;\n"; } else if (glsl_140) { glHeaderString += "#version 140\n\n"; } streamVert << glHeaderString; anthonyfieroni: ```
QString glHeaderString;
if (gles) {
if (core) {
glHeaderString += "#version 300… | |||||
235 | } | 238 | } | ||
236 | 239 | | |||
237 | stream << "uniform mat4 modelViewProjectionMatrix;\n"; | 240 | QString glUniformString = "uniform sampler2D texUnit;\n" | ||
238 | stream << "uniform mat4 textureMatrix;\n"; | 241 | "uniform float offset;\n" | ||
textureSize is also the name of a built-in function in GLSL, so I suggest changing the name to targetSize, renderTargetSize, framebufferSize or something similar. That also makes it clear that it is not the size of the texture being sampled. fredrik: textureSize is also the name of a built-in function in GLSL, so I suggest changing the name to… | |||||
239 | stream << "uniform vec2 pixelSize;\n\n"; | 242 | "uniform vec2 textureSize;\n"; | ||
240 | stream << attribute << " vec4 vertex;\n\n"; | | |||
241 | stream << varying_out << " vec4 samplePos[" << std::ceil(size / 2.0) << "];\n"; | | |||
242 | stream << "\n"; | | |||
243 | stream << "void main(void)\n"; | | |||
244 | stream << "{\n"; | | |||
245 | stream << " vec4 center = vec4(textureMatrix * vertex).stst;\n"; | | |||
246 | stream << " vec4 ps = pixelSize.stst;\n\n"; | | |||
247 | for (int i = 0; i < offsets.size(); i++) { | | |||
248 | stream << " samplePos[" << i << "] = center + ps * vec4(" | | |||
249 | << offsets[i].x() << ", " << offsets[i].y() << ", " | | |||
250 | << offsets[i].z() << ", " << offsets[i].w() << ");\n"; | | |||
251 | } | | |||
252 | stream << "\n"; | | |||
253 | stream << " gl_Position = modelViewProjectionMatrix * vertex;\n"; | | |||
254 | stream << "}\n"; | | |||
255 | stream.flush(); | | |||
256 | 243 | | |||
257 | // Fragment shader | | |||
258 | // =================================================================== | | |||
259 | QTextStream stream2(&fragmentSource); | | |||
260 | | ||||
261 | if (gles) { | | |||
262 | if (core) { | 244 | if (core) { | ||
263 | stream2 << "#version 300 es\n\n"; | 245 | glUniformString += "out vec4 fragColor;\n\n"; | ||
264 | } | | |||
265 | stream2 << "precision highp float;\n"; | | |||
266 | } else if (glsl_140) { | | |||
267 | stream2 << "#version 140\n\n"; | | |||
268 | } | 246 | } | ||
269 | 247 | | |||
270 | stream2 << "uniform sampler2D texUnit;\n"; | | |||
271 | stream2 << varying_in << " vec4 samplePos[" << std::ceil(size / 2.0) << "];\n\n"; | | |||
272 | 248 | | |||
273 | for (int i = 0; i <= center; i++) | 249 | // Vertex shader | ||
274 | stream2 << "const float kernel" << i << " = " << kernel[i].g << ";\n"; | 250 | // =================================================================== | ||
QString glUniformString = "uniform sampler2D texUnit;\n" "uniform float offset;\n" "uniform vec2 textureSize;\n"; if (core) { glUniformString += "out vec4 fragColor;\n\n"; } streamFragDown << glUniformString; anthonyfieroni: ```
QString glUniformString = "uniform sampler2D texUnit;\n"
"uniform… | |||||
275 | stream2 << "\n"; | 251 | QTextStream streamVert(&vertexSource); | ||
252 | | ||||
253 | streamVert << glHeaderString; | ||||
254 | | ||||
255 | streamVert << "uniform mat4 modelViewProjectionMatrix;\n"; | ||||
256 | streamVert << attribute << " vec4 vertex;\n\n"; | ||||
257 | streamVert << "\n"; | ||||
258 | streamVert << "void main(void)\n"; | ||||
259 | streamVert << "{\n"; | ||||
260 | streamVert << " gl_Position = modelViewProjectionMatrix * vertex;\n"; | ||||
261 | streamVert << "}\n"; | ||||
anthonyfieroni: ```
streamFragDown << glHeaderString;
``` | |||||
262 | | ||||
263 | streamVert.flush(); | ||||
264 | | ||||
265 | // Fragment shader (Dual Kawase Blur) - Downsample | ||||
266 | // =================================================================== | ||||
267 | QTextStream streamFragDown(&fragmentDownSource); | ||||
268 | | ||||
269 | streamFragDown << glHeaderString << glUniformString; | ||||
270 | | ||||
271 | streamFragDown << "void main(void)\n"; | ||||
272 | streamFragDown << "{\n"; | ||||
273 | streamFragDown << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
274 | streamFragDown << " vec2 halfpixel = vec2(0.5 / textureSize);\n"; | ||||
275 | streamFragDown << " \n"; | ||||
276 | streamFragDown << " vec4 sum = " << texture2D << "(texUnit, uv) * 4.0;\n"; | ||||
277 | streamFragDown << " sum += " << texture2D << "(texUnit, uv - halfpixel.xy * offset);\n"; | ||||
278 | streamFragDown << " sum += " << texture2D << "(texUnit, uv + halfpixel.xy * offset);\n"; | ||||
279 | streamFragDown << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, -halfpixel.y) * offset);\n"; | ||||
280 | streamFragDown << " sum += " << texture2D << "(texUnit, uv - vec2(halfpixel.x, -halfpixel.y) * offset);\n"; | ||||
281 | streamFragDown << " \n"; | ||||
282 | streamFragDown << " " << fragColor << " = sum / 8.0;\n"; | ||||
283 | streamFragDown << "}\n"; | ||||
284 | | ||||
285 | streamFragDown.flush(); | ||||
286 | | ||||
287 | // Fragment shader (Dual Kawase Blur) - Upsample | ||||
288 | // =================================================================== | ||||
289 | QTextStream streamFragUp(&fragmentUpSource); | ||||
290 | | ||||
291 | streamFragUp << glHeaderString << glUniformString; | ||||
292 | | ||||
293 | streamFragUp << "void main(void)\n"; | ||||
294 | streamFragUp << "{\n"; | ||||
295 | streamFragUp << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
296 | streamFragUp << " vec2 halfpixel = vec2(0.5 / textureSize);\n"; | ||||
297 | streamFragUp << " \n"; | ||||
298 | streamFragUp << " vec4 sum = " << texture2D << "(texUnit, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset);\n"; | ||||
299 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; | ||||
300 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, halfpixel.y * 2.0) * offset);\n"; | ||||
301 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, halfpixel.y) * offset) * 2.0;\n"; | ||||
302 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x * 2.0, 0.0) * offset);\n"; | ||||
303 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; | ||||
304 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(0.0, -halfpixel.y * 2.0) * offset);\n"; | ||||
305 | streamFragUp << " sum += " << texture2D << "(texUnit, uv + vec2(-halfpixel.x, -halfpixel.y) * offset) * 2.0;\n"; | ||||
306 | streamFragUp << " \n"; | ||||
307 | streamFragUp << " " << fragColor << " = sum / 12.0;\n"; | ||||
308 | streamFragUp << "}\n"; | ||||
309 | | ||||
310 | streamFragUp.flush(); | ||||
311 | | ||||
312 | // Fragment shader - Copy texture | ||||
313 | // =================================================================== | ||||
314 | QTextStream streamFragCopy(&fragmentCopySource); | ||||
315 | | ||||
316 | streamFragCopy << glHeaderString; | ||||
317 | | ||||
318 | streamFragCopy << "uniform sampler2D texUnit;\n"; | ||||
319 | streamFragCopy << "uniform vec2 textureSize;\n"; | ||||
320 | streamFragCopy << "uniform vec4 blurRect;\n"; | ||||
276 | 321 | | |||
anthonyfieroni: ```
streamFragUp << glHeaderString << glUniformString;
``` | |||||
277 | if (core) | 322 | if (core) | ||
278 | stream2 << "out vec4 fragColor;\n\n"; | 323 | streamFragCopy << "out vec4 fragColor;\n\n"; | ||
324 | | ||||
325 | streamFragCopy << "void main(void)\n"; | ||||
326 | streamFragCopy << "{\n"; | ||||
327 | streamFragCopy << " vec2 uv = vec2(gl_FragCoord.xy / textureSize);\n"; | ||||
328 | streamFragCopy << " " << fragColor << " = " << texture2D << "(texUnit, clamp(uv, blurRect.xy, blurRect.zw));\n"; | ||||
329 | streamFragCopy << "}\n"; | ||||
279 | 330 | | |||
280 | stream2 << "void main(void)\n"; | 331 | streamFragCopy.flush(); | ||
281 | stream2 << "{\n"; | 332 | | ||
282 | stream2 << " vec4 sum = " << texture2D << "(texUnit, samplePos[0].st) * kernel0;\n"; | 333 | | ||
283 | for (int i = 1, j = -center + 1; i < size; i++, j++) | 334 | m_shaderDownsample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentDownSource); | ||
284 | stream2 << " sum = sum + " << texture2D << "(texUnit, samplePos[" << i / 2 | 335 | m_shaderUpsample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentUpSource); | ||
285 | << ((i % 2) ? "].pq)" : "].st)") << " * kernel" << center - qAbs(j) << ";\n"; | 336 | m_shaderCopysample = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentCopySource); | ||
286 | stream2 << " " << fragColor << " = sum;\n"; | 337 | | ||
287 | stream2 << "}\n"; | 338 | bool areShadersValid = m_shaderDownsample->isValid() && m_shaderUpsample->isValid() && m_shaderCopysample->isValid(); | ||
288 | stream2.flush(); | 339 | setIsValid(areShadersValid); | ||
289 | 340 | | |||
290 | shader = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentSource); | 341 | if (areShadersValid) { | ||
291 | if (shader->isValid()) { | 342 | m_mvpMatrixLocationDownsample = m_shaderDownsample->uniformLocation("modelViewProjectionMatrix"); | ||
292 | pixelSizeLocation = shader->uniformLocation("pixelSize"); | 343 | m_offsetLocationDownsample = m_shaderDownsample->uniformLocation("offset"); | ||
293 | textureMatrixLocation = shader->uniformLocation("textureMatrix"); | 344 | m_textureSizeLocationDownsample = m_shaderDownsample->uniformLocation("textureSize"); | ||
294 | mvpMatrixLocation = shader->uniformLocation("modelViewProjectionMatrix"); | 345 | | ||
346 | m_mvpMatrixLocationUpsample = m_shaderUpsample->uniformLocation("modelViewProjectionMatrix"); | ||||
347 | m_offsetLocationUpsample = m_shaderUpsample->uniformLocation("offset"); | ||||
348 | m_textureSizeLocationUpsample = m_shaderUpsample->uniformLocation("textureSize"); | ||||
349 | | ||||
350 | m_mvpMatrixLocationCopysample = m_shaderCopysample->uniformLocation("modelViewProjectionMatrix"); | ||||
351 | m_textureSizeLocationCopysample = m_shaderCopysample->uniformLocation("textureSize"); | ||||
352 | m_blurRectLocationCopysample = m_shaderCopysample->uniformLocation("blurRect"); | ||||
295 | 353 | | |||
296 | QMatrix4x4 modelViewProjection; | 354 | QMatrix4x4 modelViewProjection; | ||
297 | const QSize screenSize = effects->virtualScreenSize(); | 355 | const QSize screenSize = effects->virtualScreenSize(); | ||
298 | modelViewProjection.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535); | 356 | modelViewProjection.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535); | ||
299 | ShaderManager::instance()->pushShader(shader); | 357 | | ||
300 | shader->setUniform(textureMatrixLocation, QMatrix4x4()); | 358 | //Add default values to the uniforms of the shaders | ||
301 | shader->setUniform(mvpMatrixLocation, modelViewProjection); | 359 | ShaderManager::instance()->pushShader(m_shaderDownsample); | ||
anthonyfieroni: ```
streamFragCopy << glHeaderString << glUniformString;
``` | |||||
360 | m_shaderDownsample->setUniform(m_mvpMatrixLocationDownsample, modelViewProjection); | ||||
361 | m_shaderDownsample->setUniform(m_offsetLocationDownsample, float(1.0)); | ||||
362 | m_shaderDownsample->setUniform(m_textureSizeLocationDownsample, QVector2D(1.0, 1.0)); | ||||
363 | ShaderManager::instance()->popShader(); | ||||
364 | | ||||
365 | ShaderManager::instance()->pushShader(m_shaderUpsample); | ||||
366 | m_shaderUpsample->setUniform(m_mvpMatrixLocationUpsample, modelViewProjection); | ||||
367 | m_shaderUpsample->setUniform(m_offsetLocationUpsample, float(1.0)); | ||||
368 | m_shaderUpsample->setUniform(m_textureSizeLocationUpsample, QVector2D(1.0, 1.0)); | ||||
302 | ShaderManager::instance()->popShader(); | 369 | ShaderManager::instance()->popShader(); | ||
303 | } | | |||
304 | 370 | | |||
305 | setIsValid(shader->isValid()); | 371 | ShaderManager::instance()->pushShader(m_shaderCopysample); | ||
372 | m_shaderCopysample->setUniform(m_mvpMatrixLocationCopysample, modelViewProjection); | ||||
373 | m_shaderCopysample->setUniform(m_textureSizeLocationCopysample, QVector2D(1.0, 1.0)); | ||||
374 | m_shaderCopysample->setUniform(m_blurRectLocationCopysample, QVector4D(1.0, 1.0, 1.0, 1.0)); | ||||
375 | ShaderManager::instance()->popShader(); | ||||
376 | | ||||
377 | m_activeSampleType = -1; | ||||
378 | } | ||||
306 | } | 379 | } |
No, it should be in the header file. E.g.