summaryrefslogtreecommitdiff
path: root/vcl/opengl/areaScaleFragmentShader.glsl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2015-01-17 20:00:52 +0100
committerLuboš Luňák <l.lunak@collabora.com>2015-01-19 12:17:51 +0100
commitab65925b40134ff7d8b88c61db5235549599385f (patch)
treef4a4b61ecc8edc25bcea774456157929dd99f649 /vcl/opengl/areaScaleFragmentShader.glsl
parentc22dbb2602c9c24eaa248a5a506dcb13ba435e9a (diff)
"area" scaling for opengl that has good results for downscaling
Change-Id: I0e4ad776cbf31f9a130aedf0f9741927560b5ac1
Diffstat (limited to 'vcl/opengl/areaScaleFragmentShader.glsl')
-rw-r--r--vcl/opengl/areaScaleFragmentShader.glsl131
1 files changed, 131 insertions, 0 deletions
diff --git a/vcl/opengl/areaScaleFragmentShader.glsl b/vcl/opengl/areaScaleFragmentShader.glsl
new file mode 100644
index 000000000000..cae5eb6030b0
--- /dev/null
+++ b/vcl/opengl/areaScaleFragmentShader.glsl
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* TODO Use textureOffset for newest version of GLSL */
+
+uniform sampler2D sampler;
+uniform int swidth;
+uniform int sheight;
+uniform float xscale;
+uniform float yscale;
+uniform float xsrcconvert;
+uniform float ysrcconvert;
+uniform float xdestconvert;
+uniform float ydestconvert;
+
+varying vec2 tex_coord;
+
+void main(void)
+{
+ // Convert to pixel coordinates again.
+ int dx = int( tex_coord.s * xdestconvert );
+ int dy = int( tex_coord.t * ydestconvert );
+
+ // Note: These values are always the same for the same X (or Y),
+ // so they could be precalculated in C++ and passed to the shader,
+ // but GLSL has limits on the size of uniforms passed to it,
+ // so it'd need something like texture buffer objects from newer
+ // GLSL versions, and it seems the hassle is not really worth it.
+
+ // How much each column/row will contribute to the resulting pixel.
+ // assert( xscale <= 100 ); assert( yscale <= 100 );
+ float xratio[ 100 + 2 ];
+ float yratio[ 100 + 2 ];
+ // For finding the first and last source pixel.
+ int xpixel[ 100 + 2 ];
+ int ypixel[ 100 + 2 ];
+
+ int xpos = 0;
+ int ypos = 0;
+
+ // Compute the range of source pixels which will make up this destination pixel.
+ float fsx1 = dx * xscale;
+ float fsx2 = fsx1 + xscale;
+ // To whole pixel coordinates.
+ int sx1 = ceil( fsx1 );
+ int sx2 = floor( fsx2 );
+ // Range checking.
+ sx2 = min( sx2, swidth - 1 );
+ sx1 = min( sx1, sx2 );
+
+ // How much one full column contributes to the resulting pixel.
+ float width = min( xscale, swidth - fsx1 );
+
+ if( sx1 - fsx1 > 0.001 )
+ { // The first column contributes only partially.
+ xpixel[ xpos ] = sx1 - 1;
+ xratio[ xpos ] = ( sx1 - fsx1 ) / width;
+ ++xpos;
+ }
+ for( int sx = sx1; sx < sx2; ++sx )
+ { // Columns that fully contribute to the resulting pixel.
+ xpixel[ xpos ] = sx;
+ xratio[ xpos ] = 1.0 / width;
+ ++xpos;
+ }
+ if( fsx2 - sx2 > 0.001 )
+ { // The last column contributes only partially.
+ xpixel[ xpos ] = sx2;
+ xratio[ xpos ] = min( min( fsx2 - sx2, 1.0 ) / width, 1.0 );
+ ++xpos;
+ }
+
+ // The same for Y.
+ float fsy1 = dy * yscale;
+ float fsy2 = fsy1 + yscale;
+ int sy1 = ceil( fsy1 );
+ int sy2 = floor( fsy2 );
+ sy2 = min( sy2, sheight - 1 );
+ sy1 = min( sy1, sy2 );
+
+ float height = min( yscale, sheight - fsy1 );
+
+ if( sy1 - fsy1 > 0.001 )
+ {
+ ypixel[ ypos ] = sy1 - 1;
+ yratio[ ypos ] = ( sy1 - fsy1 ) / height;
+ ++ypos;
+ }
+ for( int sy = sy1; sy < sy2; ++sy )
+ {
+ ypixel[ ypos ] = sy;
+ yratio[ ypos ] = 1.0 / height;
+ ++ypos;
+ }
+ if( fsy2 - sy2 > 0.001 )
+ {
+ ypixel[ ypos ] = sy2;
+ yratio[ ypos ] = min( min( fsy2 - sy2, 1.0 ) / height, 1.0 );
+ ++ypos;
+ }
+
+ int xstart = xpixel[ 0 ];
+ int xend = xpixel[ xpos - 1 ];
+ int ystart = ypixel[ 0 ];
+ int yend = ypixel[ ypos - 1 ];
+
+ vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );
+
+ ypos = 0;
+ for( int y = ystart; y <= yend; ++y, ++ypos )
+ {
+ vec4 tmp = vec4( 0.0, 0.0, 0.0, 0.0 );
+ xpos = 0;
+ for( int x = xstart; x <= xend; ++x, ++xpos )
+ {
+ vec2 offset = vec2( x * xsrcconvert, y * ysrcconvert );
+ tmp += texture2D( sampler, offset ) * xratio[ xpos ];
+ }
+ sum += tmp * yratio[ ypos ];
+ }
+
+ gl_FragColor = sum;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */