2014-11-06 14:17:24 -05:00
|
|
|
/* -*- 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/.
|
|
|
|
*
|
|
|
|
* This file incorporates work covered by the following license notice:
|
|
|
|
*
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
|
|
* with this work for additional information regarding copyright
|
|
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sal/config.h>
|
|
|
|
|
|
|
|
#include <vcl/opengl/OpenGLHelper.hxx>
|
|
|
|
|
|
|
|
#include "vcl/bitmap.hxx"
|
|
|
|
|
|
|
|
#include "opengl/bmpop.hxx"
|
|
|
|
#include "opengl/salbmp.hxx"
|
2014-11-28 14:56:08 -05:00
|
|
|
#include "opengl/program.hxx"
|
2014-11-06 14:17:24 -05:00
|
|
|
#include "opengl/texture.hxx"
|
|
|
|
|
|
|
|
class ScaleOp : public OpenGLSalBitmapOp
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
OpenGLSalBitmap* mpBitmap;
|
|
|
|
double mfScaleX;
|
|
|
|
double mfScaleY;
|
|
|
|
sal_uInt32 mnScaleFlag;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ScaleOp( OpenGLSalBitmap* pBitmap, const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag );
|
|
|
|
|
|
|
|
bool Execute() SAL_OVERRIDE;
|
|
|
|
void GetSize( Size& rSize ) const SAL_OVERRIDE;
|
|
|
|
};
|
|
|
|
|
2014-11-12 12:53:09 -05:00
|
|
|
bool OpenGLSalBitmap::ImplScaleFilter(
|
|
|
|
const double& rScaleX,
|
|
|
|
const double& rScaleY,
|
|
|
|
GLenum nFilter )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
2014-11-26 09:22:25 -05:00
|
|
|
OpenGLFramebuffer* pFramebuffer;
|
2014-11-28 14:56:08 -05:00
|
|
|
OpenGLProgram* pProgram;
|
2014-11-06 14:17:24 -05:00
|
|
|
GLenum nOldFilter;
|
2014-11-12 12:53:09 -05:00
|
|
|
int nNewWidth( mnWidth * rScaleX );
|
|
|
|
int nNewHeight( mnHeight * rScaleY );
|
2014-11-06 14:17:24 -05:00
|
|
|
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram = mpContext->UseProgram( "textureVertexShader",
|
|
|
|
"textureFragmentShader" );
|
|
|
|
if( !pProgram )
|
2014-11-06 14:17:24 -05:00
|
|
|
return false;
|
|
|
|
|
2014-11-13 21:37:54 -05:00
|
|
|
OpenGLTexture aNewTex = OpenGLTexture( nNewWidth, nNewHeight );
|
2014-11-26 09:22:25 -05:00
|
|
|
pFramebuffer = mpContext->AcquireFramebuffer( aNewTex );
|
2014-11-06 14:17:24 -05:00
|
|
|
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram->SetTexture( "sampler", maTexture );
|
2014-11-13 21:37:54 -05:00
|
|
|
nOldFilter = maTexture.GetFilter();
|
|
|
|
maTexture.SetFilter( nFilter );
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram->DrawTexture( maTexture );
|
2014-11-13 21:37:54 -05:00
|
|
|
maTexture.SetFilter( nOldFilter );
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram->Clean();
|
2014-11-06 14:17:24 -05:00
|
|
|
|
2014-11-26 09:22:25 -05:00
|
|
|
mpContext->ReleaseFramebuffer( pFramebuffer );
|
2014-11-06 14:17:24 -05:00
|
|
|
|
2014-11-12 12:53:09 -05:00
|
|
|
mnWidth = nNewWidth;
|
|
|
|
mnHeight = nNewHeight;
|
2014-11-13 21:37:54 -05:00
|
|
|
maTexture = aNewTex;
|
2014-11-12 18:21:47 +01:00
|
|
|
|
|
|
|
CHECK_GL_ERROR();
|
2014-11-06 14:17:24 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLSalBitmap::ImplCreateKernel(
|
|
|
|
const double& fScale,
|
|
|
|
const Kernel& rKernel,
|
|
|
|
GLfloat*& pWeights,
|
|
|
|
sal_uInt32& aKernelSize )
|
|
|
|
{
|
|
|
|
const double fSamplingRadius(rKernel.GetWidth());
|
|
|
|
const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
|
|
|
|
const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
|
|
|
|
int aNumberOfContributions;
|
|
|
|
double aSum( 0 );
|
|
|
|
|
|
|
|
aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1 - 6;
|
|
|
|
aKernelSize = aNumberOfContributions / 2 + 1;
|
|
|
|
|
2014-11-11 11:19:04 +00:00
|
|
|
// avoid a crash for now; re-think me.
|
|
|
|
if (aKernelSize > 16)
|
|
|
|
aKernelSize = 16;
|
|
|
|
|
2014-11-06 14:17:24 -05:00
|
|
|
pWeights = new GLfloat[16];
|
|
|
|
memset( pWeights, 0, 16 * sizeof( GLfloat ) );
|
|
|
|
|
|
|
|
for( sal_uInt32 i(0); i < aKernelSize; i++ )
|
|
|
|
{
|
|
|
|
const GLfloat aWeight( rKernel.Calculate( fFilterFactor * i ) );
|
|
|
|
if( fabs( aWeight ) >= 0.0001 )
|
|
|
|
{
|
|
|
|
pWeights[i] = aWeight;
|
|
|
|
aSum += i > 0 ? aWeight * 2 : aWeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( sal_uInt32 i(0); i < aKernelSize; i++ )
|
|
|
|
{
|
|
|
|
pWeights[i] /= aSum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLSalBitmap::ImplScaleConvolution(
|
|
|
|
const double& rScaleX,
|
|
|
|
const double& rScaleY,
|
|
|
|
const Kernel& aKernel )
|
|
|
|
{
|
2014-11-26 09:22:25 -05:00
|
|
|
OpenGLFramebuffer* pFramebuffer;
|
2014-11-28 14:56:08 -05:00
|
|
|
OpenGLProgram* pProgram;
|
2014-11-06 14:17:24 -05:00
|
|
|
GLfloat* pWeights( 0 );
|
|
|
|
sal_uInt32 nKernelSize;
|
|
|
|
GLfloat aOffsets[32];
|
|
|
|
int nNewWidth( mnWidth * rScaleX );
|
|
|
|
int nNewHeight( mnHeight * rScaleY );
|
|
|
|
|
|
|
|
// TODO Make sure the framebuffer is alright
|
|
|
|
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram = mpContext->UseProgram( "textureVertexShader",
|
|
|
|
"convolutionFragmentShader" );
|
|
|
|
if( pProgram == 0 )
|
2014-11-06 14:17:24 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// horizontal scaling in scratch texture
|
2014-11-13 21:37:54 -05:00
|
|
|
if( mnWidth != nNewWidth )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
2014-11-13 21:37:54 -05:00
|
|
|
OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, mnHeight );
|
2014-11-26 09:22:25 -05:00
|
|
|
pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex );
|
2014-11-06 14:17:24 -05:00
|
|
|
|
2014-11-13 21:37:54 -05:00
|
|
|
for( sal_uInt32 i = 0; i < 16; i++ )
|
|
|
|
{
|
|
|
|
aOffsets[i * 2] = i / (double) mnWidth;
|
|
|
|
aOffsets[i * 2 + 1] = 0;
|
|
|
|
}
|
|
|
|
ImplCreateKernel( rScaleX, aKernel, pWeights, nKernelSize );
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram->SetUniform1fv( "kernel", 16, pWeights );
|
|
|
|
pProgram->SetUniform2fv( "offsets", 16, aOffsets );
|
|
|
|
pProgram->SetTexture( "sampler", maTexture );
|
|
|
|
pProgram->DrawTexture( maTexture );
|
|
|
|
pProgram->Clean();
|
2014-11-13 21:37:54 -05:00
|
|
|
|
|
|
|
maTexture = aScratchTex;
|
2014-11-26 09:22:25 -05:00
|
|
|
mpContext->ReleaseFramebuffer( pFramebuffer );
|
2014-11-13 21:37:54 -05:00
|
|
|
}
|
2014-11-06 14:17:24 -05:00
|
|
|
|
|
|
|
// vertical scaling in final texture
|
2014-11-13 21:37:54 -05:00
|
|
|
if( mnHeight != nNewHeight )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
2014-11-13 21:37:54 -05:00
|
|
|
OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, nNewHeight );
|
2014-11-26 09:22:25 -05:00
|
|
|
pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex );
|
2014-11-13 21:37:54 -05:00
|
|
|
|
|
|
|
for( sal_uInt32 i = 0; i < 16; i++ )
|
|
|
|
{
|
|
|
|
aOffsets[i * 2] = 0;
|
|
|
|
aOffsets[i * 2 + 1] = i / (double) mnHeight;
|
|
|
|
}
|
|
|
|
ImplCreateKernel( rScaleY, aKernel, pWeights, nKernelSize );
|
2014-11-28 14:56:08 -05:00
|
|
|
pProgram->SetUniform1fv( "kernel", 16, pWeights );
|
|
|
|
pProgram->SetUniform2fv( "offsets", 16, aOffsets );
|
|
|
|
pProgram->SetTexture( "sampler", maTexture );
|
|
|
|
pProgram->DrawTexture( maTexture );
|
|
|
|
pProgram->Clean();
|
2014-11-13 21:37:54 -05:00
|
|
|
|
|
|
|
maTexture = aScratchTex;
|
2014-11-26 09:22:25 -05:00
|
|
|
mpContext->ReleaseFramebuffer( pFramebuffer );
|
2014-11-13 21:37:54 -05:00
|
|
|
}
|
2014-11-06 14:17:24 -05:00
|
|
|
|
|
|
|
mnWidth = nNewWidth;
|
|
|
|
mnHeight = nNewHeight;
|
|
|
|
|
2014-11-12 18:21:47 +01:00
|
|
|
CHECK_GL_ERROR();
|
2014-11-06 14:17:24 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
|
|
|
|
{
|
|
|
|
SAL_INFO( "vcl.opengl", "::ImplScale" );
|
|
|
|
|
2014-12-03 17:05:01 -05:00
|
|
|
maUserBuffer.reset();
|
2014-11-18 12:43:45 -05:00
|
|
|
makeCurrent();
|
|
|
|
|
2014-11-06 14:17:24 -05:00
|
|
|
if( nScaleFlag == BMP_SCALE_FAST )
|
|
|
|
{
|
2014-11-12 12:53:09 -05:00
|
|
|
return ImplScaleFilter( rScaleX, rScaleY, GL_NEAREST );
|
2014-11-06 14:17:24 -05:00
|
|
|
}
|
|
|
|
if( nScaleFlag == BMP_SCALE_BILINEAR )
|
|
|
|
{
|
2014-11-12 12:53:09 -05:00
|
|
|
return ImplScaleFilter( rScaleX, rScaleY, GL_LINEAR );
|
2014-11-06 14:17:24 -05:00
|
|
|
}
|
2014-12-15 18:36:32 +01:00
|
|
|
else if( nScaleFlag == BMP_SCALE_SUPER || nScaleFlag == BMP_SCALE_DEFAULT )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
|
|
|
const Lanczos3Kernel aKernel;
|
|
|
|
|
|
|
|
return ImplScaleConvolution( rScaleX, rScaleY, aKernel );
|
|
|
|
}
|
2014-12-15 18:36:32 +01:00
|
|
|
else if( nScaleFlag == BMP_SCALE_LANCZOS || nScaleFlag == BMP_SCALE_BESTQUALITY )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
|
|
|
const Lanczos3Kernel aKernel;
|
|
|
|
|
|
|
|
return ImplScaleConvolution( rScaleX, rScaleY, aKernel );
|
|
|
|
}
|
|
|
|
|
|
|
|
SAL_WARN( "vcl.opengl", "Invalid flag for scaling operation" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScaleOp::ScaleOp(
|
|
|
|
OpenGLSalBitmap* pBitmap,
|
|
|
|
const double& rScaleX,
|
|
|
|
const double& rScaleY,
|
|
|
|
sal_uInt32 nScaleFlag )
|
|
|
|
: mpBitmap( pBitmap )
|
|
|
|
, mfScaleX( rScaleX )
|
|
|
|
, mfScaleY( rScaleY )
|
|
|
|
, mnScaleFlag( nScaleFlag )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScaleOp::Execute()
|
|
|
|
{
|
|
|
|
SAL_INFO( "vcl.opengl", "::Execute" );
|
|
|
|
return mpBitmap->ImplScale( mfScaleX, mfScaleY, mnScaleFlag );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScaleOp::GetSize( Size& rSize ) const
|
|
|
|
{
|
|
|
|
SAL_INFO( "vcl.opengl", "::GetSize" );
|
|
|
|
rSize.setWidth( rSize.Width() * mfScaleX );
|
|
|
|
rSize.setHeight( rSize.Height() * mfScaleY );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLSalBitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
|
|
|
|
{
|
|
|
|
SAL_INFO( "vcl.opengl", "::Scale " << nScaleFlag );
|
|
|
|
|
|
|
|
if( nScaleFlag == BMP_SCALE_FAST ||
|
|
|
|
nScaleFlag == BMP_SCALE_BILINEAR ||
|
|
|
|
nScaleFlag == BMP_SCALE_SUPER ||
|
2015-01-12 14:14:18 +01:00
|
|
|
nScaleFlag == BMP_SCALE_LANCZOS ||
|
|
|
|
nScaleFlag == BMP_SCALE_DEFAULT ||
|
|
|
|
nScaleFlag == BMP_SCALE_BESTQUALITY )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
2014-11-26 09:22:25 -05:00
|
|
|
makeCurrent();
|
|
|
|
if( mpContext == NULL )
|
2014-11-06 14:17:24 -05:00
|
|
|
{
|
|
|
|
SAL_INFO( "vcl.opengl", "Add ScaleOp to pending operations" );
|
|
|
|
maPendingOps.push_back( new ScaleOp( this, rScaleX, rScaleY, nScaleFlag ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImplScale( rScaleX, rScaleY, nScaleFlag );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|