Kaydet (Commit) c44ee2be authored tarafından Luboš Luňák's avatar Luboš Luňák

when drawing a transformed bitmap in opengl backend, scale it better

The plain scaling is rather rough, and in fact drawing a scaled bitmap
the normal way gives much better results (because OutputDevice pre-scales
the bitmap before it's drawn). This one may be a bit slow perhaps,
but hopefully nobody there's no code that'd extensively use bitmap
drawing with custom transformations (wishful thinking).

Change-Id: I83e05307adfaeac0ed0757f1a0b2603f64caf8f8
üst df290c63
...@@ -18,6 +18,12 @@ uniform float ratio; // = 1.0/(xscale*yscale) ...@@ -18,6 +18,12 @@ uniform float ratio; // = 1.0/(xscale*yscale)
varying vec2 tex_coord; varying vec2 tex_coord;
// This mode makes the scaling work like maskedTextureFragmentShader.glsl
// (instead of like plain textureVertexShader.glsl).
#ifdef MASKED
uniform sampler2D mask;
#endif
/* /*
Just make the resulting color the average of all the source pixels Just make the resulting color the average of all the source pixels
(which is an area (xscale)x(yscale) ). (which is an area (xscale)x(yscale) ).
...@@ -30,7 +36,14 @@ void main(void) ...@@ -30,7 +36,14 @@ void main(void)
{ {
for( int x = 0; x < xscale; ++x ) for( int x = 0; x < xscale; ++x )
{ {
#ifndef MASKED
sum += texture2D( sampler, tex_coord.st + offset ); sum += texture2D( sampler, tex_coord.st + offset );
#else
vec4 texel;
texel = texture2D( sampler, tex_coord.st + offset );
texel.a = 1.0 - texture2D( mask, tex_coord.st + offset ).r;
sum += texel;
#endif
offset.x += xstep; offset.x += xstep;
} }
offset.y += ystep; offset.y += ystep;
......
...@@ -27,6 +27,12 @@ uniform float ydestconvert; ...@@ -27,6 +27,12 @@ uniform float ydestconvert;
varying vec2 tex_coord; varying vec2 tex_coord;
// This mode makes the scaling work like maskedTextureFragmentShader.glsl
// (instead of like plain textureVertexShader.glsl).
#ifdef MASKED
uniform sampler2D mask;
#endif
void main(void) void main(void)
{ {
// Convert to pixel coordinates again. // Convert to pixel coordinates again.
...@@ -126,7 +132,14 @@ void main(void) ...@@ -126,7 +132,14 @@ void main(void)
for( int x = xstart; x <= xend; ++x, ++xpos ) for( int x = xstart; x <= xend; ++x, ++xpos )
{ {
vec2 offset = vec2( x * xsrcconvert, y * ysrcconvert ); vec2 offset = vec2( x * xsrcconvert, y * ysrcconvert );
#ifndef MASKED
tmp += texture2D( sampler, offset ) * xratio[ xpos ]; tmp += texture2D( sampler, offset ) * xratio[ xpos ];
#else
vec4 texel;
texel = texture2D( sampler, offset );
texel.a = 1.0 - texture2D( mask, offset ).r;
tmp += texel * xratio[ xpos ];
#endif
} }
sum += tmp * yratio[ ypos ]; sum += tmp * yratio[ ypos ];
} }
......
...@@ -894,9 +894,34 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture( ...@@ -894,9 +894,34 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
(float) rTexture.GetWidth(), 0, (float) rTexture.GetWidth(), (float) rTexture.GetHeight() }; (float) rTexture.GetWidth(), 0, (float) rTexture.GetWidth(), (float) rTexture.GetHeight() };
GLfloat aTexCoord[8]; GLfloat aTexCoord[8];
// If downscaling at a higher scale ratio, use the area scaling algorithm rather
// than plain OpenGL's scaling, for better results.
// See OpenGLSalBitmap::ImplScaleArea().
double ixscale = rTexture.GetWidth() / fabs( rX.getX() - rNull.getX());
double iyscale = rTexture.GetHeight() / fabs( rY.getY() - rNull.getY());
bool areaScaling = false;
bool fastAreaScaling = false;
OUString textureFragmentShader;
if( ixscale >= 2 && iyscale >= 2 ) // Downscaling to 50% or less? (inverted scale ratios)
{
areaScaling = true;
fastAreaScaling = ( ixscale == int( ixscale ) && iyscale == int( iyscale ));
// The generic case has arrays only up to 100 ratio downscaling, which is hopefully enough
// in practice, but protect against buffer overflows in case such an extreme case happens
// (and in such case the precision of the generic algorithm probably doesn't matter anyway).
if( ixscale > 100 || iyscale > 100 )
fastAreaScaling = true;
if( fastAreaScaling )
textureFragmentShader = "areaScaleFastFragmentShader";
else
textureFragmentShader = "areaScaleFragmentShader";
}
if( rMask ) if( rMask )
{ {
if( !UseProgram( "transformedTextureVertexShader", "maskedTextureFragmentShader" ) ) if( !UseProgram( "transformedTextureVertexShader",
textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader,
"#define MASKED" ) )
return; return;
mpProgram->SetTexture( "mask", rMask ); mpProgram->SetTexture( "mask", rMask );
rMask.SetFilter( GL_LINEAR ); rMask.SetFilter( GL_LINEAR );
...@@ -904,10 +929,40 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture( ...@@ -904,10 +929,40 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
} }
else else
{ {
if( !UseProgram( "transformedTextureVertexShader", "textureFragmentShader" ) ) if( !UseProgram( "transformedTextureVertexShader",
textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader ) )
return; return;
} }
if( areaScaling )
{
// From OpenGLSalBitmap::ImplScaleArea().
if( fastAreaScaling )
{
int mnWidth = rTexture.GetWidth();
int mnHeight = rTexture.GetHeight();
mpProgram->SetUniform1i( "xscale", ixscale );
mpProgram->SetUniform1i( "yscale", iyscale );
mpProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
mpProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale ));
}
else
{
int mnWidth = rTexture.GetWidth();
int mnHeight = rTexture.GetHeight();
mpProgram->SetUniform1f( "xscale", ixscale );
mpProgram->SetUniform1f( "yscale", iyscale );
mpProgram->SetUniform1i( "swidth", mnWidth );
mpProgram->SetUniform1i( "sheight", mnHeight );
// For converting between <0,mnWidth-1> and <0.0,1.0> coordinate systems.
mpProgram->SetUniform1f( "xsrcconvert", 1.0 / ( mnWidth - 1 ));
mpProgram->SetUniform1f( "ysrcconvert", 1.0 / ( mnHeight - 1 ));
mpProgram->SetUniform1f( "xdestconvert", 1.0 * (( mnWidth / ixscale ) - 1 ));
mpProgram->SetUniform1f( "ydestconvert", 1.0 * (( mnHeight / iyscale ) - 1 ));
}
}
mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() ); mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() );
mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY ); mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY );
rTexture.GetWholeCoord( aTexCoord ); rTexture.GetWholeCoord( aTexCoord );
......
...@@ -225,6 +225,7 @@ bool OpenGLSalBitmap::ImplScaleArea( double rScaleX, double rScaleY ) ...@@ -225,6 +225,7 @@ bool OpenGLSalBitmap::ImplScaleArea( double rScaleX, double rScaleY )
OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, nNewHeight ); OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, nNewHeight );
OpenGLFramebuffer* pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex ); OpenGLFramebuffer* pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex );
// NOTE: This setup is also done in OpenGLSalGraphicsImpl::DrawTransformedTexture().
if( fast ) if( fast )
{ {
pProgram->SetUniform1i( "xscale", ixscale ); pProgram->SetUniform1i( "xscale", ixscale );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment