diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2015-01-17 20:00:52 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2015-01-19 12:17:51 +0100 |
commit | ab65925b40134ff7d8b88c61db5235549599385f (patch) | |
tree | f4a4b61ecc8edc25bcea774456157929dd99f649 /vcl/opengl/areaScaleFragmentShader.glsl | |
parent | c22dbb2602c9c24eaa248a5a506dcb13ba435e9a (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.glsl | 131 |
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: */ |