1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10#version 130
11
12uniform sampler2D sampler;
13uniform int swidth;
14uniform int sheight;
15uniform float xscale;
16uniform float yscale;
17uniform float xoffset;
18uniform float yoffset;
19uniform float xfrompixelratio;
20uniform float yfrompixelratio;
21uniform float xtopixelratio;
22uniform float ytopixelratio;
23
24varying vec2 tex_coord;
25
26// This mode makes the scaling work like maskedTextureFragmentShader.glsl
27// (instead of like plain textureVertexShader.glsl).
28#ifdef MASKED
29varying vec2 mask_coord;
30uniform sampler2D mask;
31#endif
32
33#ifdef USE_REDUCED_REGISTER_VARIANT
34
35vec4 getTexel(int x, int y)
36{
37    vec2 pos = vec2( x * xfrompixelratio + xoffset, y * yfrompixelratio + yoffset );
38    vec4 texel = texture2D(sampler, pos);
39#ifdef MASKED
40    texel.a = 1.0 - texture2D(mask, pos - tex_coord.st + mask_coord.st).r;
41#endif
42    return texel;
43}
44
45void main(void)
46{
47    // Convert to pixel coordinates again.
48    int dx = int(( tex_coord.s - xoffset ) * xtopixelratio );
49    int dy = int(( tex_coord.t - yoffset ) * ytopixelratio );
50
51    // Compute the range of source pixels which will make up this destination pixel.
52    float fsx1 = min(dx * xscale,   float(swidth - 1));
53    float fsx2 = min(fsx1 + xscale, float(swidth - 1));
54
55    float fsy1 = min(dy * yscale,   float(sheight - 1));
56    float fsy2 = min(fsy1 + yscale, float(sheight - 1));
57
58    // To whole pixel coordinates.
59    int xstart = int(floor(fsx1));
60    int xend   = int(floor(fsx2));
61
62    int ystart = int(floor(fsy1));
63    int yend   = int(floor(fsy2));
64
65    float xlength = fsx2 - fsx1;
66    float ylength = fsy2 - fsy1;
67
68    float xContribution[3];
69    xContribution[0] = (1.0 - max(0.0, fsx1 - xstart))     / xlength;
70    xContribution[1] =  1.0 / xlength;
71    xContribution[2] = (1.0 - max(0.0, (xend + 1) - fsx2)) / xlength;
72
73    float yContribution[3];
74    yContribution[0] = (1.0 - max(0.0, fsy1 - ystart))     / ylength;
75    yContribution[1] =  1.0 / ylength;
76    yContribution[2] = (1.0 - max(0.0, (yend + 1) - fsy2)) / ylength;
77
78    vec4 sumAll = vec4(0.0, 0.0, 0.0, 0.0);
79    vec4 texel;
80    // First Y pass
81    {
82        vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0);
83
84        sumX += getTexel(xstart, ystart) * xContribution[0];
85        for (int x = xstart + 1; x < xend; ++x)
86        {
87           sumX += getTexel(x, ystart) * xContribution[1];
88        }
89        sumX += getTexel(xend, ystart) * xContribution[2];
90
91        sumAll += sumX * yContribution[0];
92    }
93
94    // Middle Y Passes
95    for (int y = ystart + 1; y < yend; ++y)
96    {
97        vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0);
98
99        sumX += getTexel(xstart, y) * xContribution[0];
100        for (int x = xstart + 1; x < xend; ++x)
101        {
102            sumX += getTexel(x, y) * xContribution[1];
103        }
104        sumX += getTexel(xend, y) * xContribution[2];
105
106        sumAll += sumX * yContribution[1];
107    }
108
109    // Last Y pass
110    {
111        vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0);
112
113        sumX += getTexel(xstart, yend) * xContribution[0];
114        for (int x = xstart + 1; x < xend; ++x)
115        {
116            sumX += getTexel(x, yend) * xContribution[1];
117        }
118        sumX += getTexel(xend, yend) * xContribution[2];
119
120        sumAll += sumX * yContribution[2];
121    }
122
123    gl_FragColor = sumAll;
124}
125#else
126void main(void)
127{
128    // Convert to pixel coordinates again.
129    int dx = int(( tex_coord.s - xoffset ) * xtopixelratio );
130    int dy = int(( tex_coord.t - yoffset ) * ytopixelratio );
131
132    // How much each column/row will contribute to the resulting pixel.
133    // Note: These values are always the same for the same X (or Y),
134    // so they could be precalculated in C++ and passed to the shader,
135    // but GLSL has limits on the size of uniforms passed to it,
136    // so it'd need something like texture buffer objects from newer
137    // GLSL versions, and it seems the hassle is not really worth it.
138    float xratio[ 16 + 2 ];
139    float yratio[ 16 + 2 ];
140
141    // For finding the first and last source pixel.
142    int xpixel[ 16 + 2 ];
143    int ypixel[ 16 + 2 ];
144
145    int xpos = 0;
146    int ypos = 0;
147
148    // Compute the range of source pixels which will make up this destination pixel.
149    float fsx1 = dx * xscale;
150    float fsx2 = fsx1 + xscale;
151    // To whole pixel coordinates.
152    int sx1 = int( ceil( fsx1 ) );
153    int sx2 = int( floor( fsx2 ) );
154    // Range checking.
155    sx2 = min( sx2, swidth - 1 );
156    sx1 = min( sx1, sx2 );
157
158    // How much one full column contributes to the resulting pixel.
159    float width = min( xscale, swidth - fsx1 );
160
161    if( sx1 - fsx1 > 0.001 )
162    {   // The first column contributes only partially.
163        xpixel[ xpos ] = sx1 - 1;
164        xratio[ xpos ] = ( sx1 - fsx1 ) / width;
165        ++xpos;
166    }
167    for( int sx = sx1; sx < sx2; ++sx )
168    {   // Columns that fully contribute to the resulting pixel.
169        xpixel[ xpos ] = sx;
170        xratio[ xpos ] = 1.0 / width;
171        ++xpos;
172    }
173    if( fsx2 - sx2 > 0.001 )
174    {   // The last column contributes only partially.
175        xpixel[ xpos ] = sx2;
176        xratio[ xpos ] = min( min( fsx2 - sx2, 1.0 ) / width, 1.0 );
177        ++xpos;
178    }
179
180    // The same for Y.
181    float fsy1 = dy * yscale;
182    float fsy2 = fsy1 + yscale;
183    int sy1 = int( ceil( fsy1 ) );
184    int sy2 = int( floor( fsy2 ) );
185    sy2 = min( sy2, sheight - 1 );
186    sy1 = min( sy1, sy2 );
187
188    float height = min( yscale, sheight - fsy1 );
189
190    if( sy1 - fsy1 > 0.001 )
191    {
192        ypixel[ ypos ] = sy1 - 1;
193        yratio[ ypos ] = ( sy1 - fsy1 ) / height;
194        ++ypos;
195    }
196    for( int sy = sy1; sy < sy2; ++sy )
197    {
198        ypixel[ ypos ] = sy;
199        yratio[ ypos ] = 1.0 / height;
200        ++ypos;
201    }
202    if( fsy2 - sy2 > 0.001 )
203    {
204        ypixel[ ypos ] = sy2;
205        yratio[ ypos ] = min( min( fsy2 - sy2, 1.0 ) / height, 1.0 );
206        ++ypos;
207    }
208
209    int xstart = xpixel[ 0 ];
210    int xend = xpixel[ xpos - 1 ];
211    int ystart = ypixel[ 0 ];
212    int yend = ypixel[ ypos - 1 ];
213
214    vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );
215
216    ypos = 0;
217    for( int y = ystart; y <= yend; ++y, ++ypos )
218    {
219        vec4 tmp = vec4( 0.0, 0.0, 0.0, 0.0 );
220        xpos = 0;
221        for( int x = xstart; x <= xend; ++x, ++xpos )
222        {
223            vec2 pos = vec2( x * xfrompixelratio + xoffset, y * yfrompixelratio + yoffset );
224#ifndef MASKED
225            tmp += texture2D( sampler, pos ) * xratio[ xpos ];
226#else
227            vec4 texel;
228            texel = texture2D( sampler, pos );
229            texel.a = 1.0 - texture2D( mask, pos - tex_coord.st + mask_coord.st ).r;
230            tmp += texel * xratio[ xpos ];
231#endif
232        }
233        sum += tmp * yratio[ ypos ];
234    }
235
236    gl_FragColor = sum;
237}
238#endif
239/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
240