1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/debug.hxx>
26 #include <vcl/opengl/OpenGLHelper.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/checksum.hxx>
30 #include <vcl/outdev.hxx>
33 #include <vcleventlisteners.hxx>
34 #include <vcl/lazydelete.hxx>
35 #include <scanlinewriter.hxx>
37 #include <o3tl/make_shared.hxx>
39 #include <opengl/zone.hxx>
40 #include <opengl/program.hxx>
41 #include <opengl/salbmp.hxx>
42 #include <opengl/RenderState.hxx>
43 #include <opengl/FixedTextureAtlas.hxx>
45 #if OSL_DEBUG_LEVEL > 0
46 # define CANARY "tex-canary"
52 bool determineTextureFormat(sal_uInt16 nBits
, GLenum
& nFormat
, GLenum
& nType
)
57 nFormat
= GL_LUMINANCE
;
58 nType
= GL_UNSIGNED_BYTE
;
62 nType
= GL_UNSIGNED_BYTE
;
66 nType
= GL_UNSIGNED_BYTE
;
71 SAL_WARN("vcl.opengl", "Could not determine the appropriate texture format for input bits '" << nBits
<< "'");
75 bool isValidBitCount( sal_uInt16 nBitCount
)
77 return (nBitCount
== 1) || (nBitCount
== 4) || (nBitCount
== 8) || (nBitCount
== 24) || (nBitCount
== 32);
80 sal_uInt32
lclBytesPerRow(sal_uInt16 nBits
, int nWidth
)
84 case 1: return (nWidth
+ 7) >> 3;
85 case 4: return (nWidth
+ 1) >> 1;
86 case 8: return nWidth
;
87 case 24: return nWidth
* 3;
88 case 32: return nWidth
* 4;
90 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
96 OpenGLSalBitmap::OpenGLSalBitmap()
97 : mbDirtyTexture(true)
105 OpenGLSalBitmap::~OpenGLSalBitmap()
108 VCL_GL_INFO( "~OpenGLSalBitmap" );
111 void OpenGLSalBitmap::Create( const OpenGLTexture
& rTex
, tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
)
113 DBG_TESTSOLARMUTEX();
114 static const BitmapPalette aEmptyPalette
;
115 OpenGLVCLContextZone aContextZone
;
118 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
119 << nX
<< ", " << nY
<< "] " << nWidth
<< "x" << nHeight
);
121 GLint nMaxTextureSize
;
122 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
123 if ( nWidth
> nMaxTextureSize
)
125 nWidth
= nMaxTextureSize
;
126 VCL_GL_INFO( "Width limited to " << nMaxTextureSize
);
129 if ( nHeight
> nMaxTextureSize
)
131 nHeight
= nMaxTextureSize
;
132 VCL_GL_INFO( "Height limited to " << nMaxTextureSize
);
138 // TODO Check the framebuffer configuration
140 maPalette
= aEmptyPalette
;
143 maTexture
= OpenGLTexture( rTex
, nX
, nY
, nWidth
, nHeight
);
145 maTexture
= OpenGLTexture( nX
, nY
, nWidth
, nHeight
);
146 mbDirtyTexture
= false;
147 VCL_GL_INFO( "Created texture " << maTexture
.Id() );
149 assert(mnWidth
== maTexture
.GetWidth() &&
150 mnHeight
== maTexture
.GetHeight());
153 bool OpenGLSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rBitmapPalette
)
155 DBG_TESTSOLARMUTEX();
156 OpenGLVCLContextZone aContextZone
;
159 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize
);
161 if( !isValidBitCount( nBits
) )
163 maPalette
= rBitmapPalette
;
165 mnWidth
= rSize
.Width();
166 mnHeight
= rSize
.Height();
168 // Limit size to what GL allows, so later glTexImage2D() won't fail.
169 GLint nMaxTextureSize
;
170 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
171 if (mnWidth
> nMaxTextureSize
)
172 mnWidth
= nMaxTextureSize
;
173 if (mnHeight
> nMaxTextureSize
)
174 mnHeight
= nMaxTextureSize
;
179 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
)
181 DBG_TESTSOLARMUTEX();
182 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
185 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
187 DBG_TESTSOLARMUTEX();
188 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
191 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, sal_uInt16 nNewBitCount
)
193 DBG_TESTSOLARMUTEX();
196 // check that carefully only in the debug mode
197 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBmp
));
199 const OpenGLSalBitmap
& rSourceBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBmp
);
201 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
202 << rSourceBitmap
.mnWidth
<< "x" << rSourceBitmap
.mnHeight
203 << " Bits old: " << mnBits
<< " new:" << nNewBitCount
);
205 if( isValidBitCount( nNewBitCount
) )
207 // TODO: lfrb: What about the pending operations?!
208 mnBits
= nNewBitCount
;
209 mnBytesPerRow
= rSourceBitmap
.mnBytesPerRow
;
210 mnWidth
= rSourceBitmap
.mnWidth
;
211 mnHeight
= rSourceBitmap
.mnHeight
;
212 maPalette
= rSourceBitmap
.maPalette
;
213 // execute any pending operations on the source bitmap
214 maTexture
= rSourceBitmap
.GetTexture();
215 mbDirtyTexture
= false;
217 // be careful here, we are share & reference-count the
218 // mpUserBuffer, BUT this Create() is called from
219 // Bitmap::ImplMakeUnique().
220 // Consequently, there might be cases when this needs to be made
221 // unique later (when we don't do that right away here), like when
222 // using the BitmapWriteAccess.
223 mpUserBuffer
= rSourceBitmap
.mpUserBuffer
;
230 bool OpenGLSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
232 DBG_TESTSOLARMUTEX();
233 // TODO Is this method needed?
237 OpenGLTexture
& OpenGLSalBitmap::GetTexture() const
239 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
240 if( !maTexture
|| mbDirtyTexture
)
241 pThis
->CreateTexture();
242 VCL_GL_INFO( "Got texture " << maTexture
.Id() );
243 return pThis
->maTexture
;
246 void OpenGLSalBitmap::Destroy()
250 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture
.Id());
251 maTexture
= OpenGLTexture();
252 DeallocateUserData();
255 bool OpenGLSalBitmap::AllocateUserData()
257 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
259 if( mnWidth
&& mnHeight
)
261 mnBytesPerRow
= lclBytesPerRow(mnBits
, mnWidth
);
265 if (mnBytesPerRow
!= 0 && mnHeight
&&
266 mnBytesPerRow
<= std::numeric_limits
<sal_uInt32
>::max() / mnHeight
)
270 size_t nToAllocate
= mnBytesPerRow
* mnHeight
;
271 #if OSL_DEBUG_LEVEL > 0
272 nToAllocate
+= sizeof(CANARY
);
274 mpUserBuffer
= o3tl::make_shared_array
<sal_uInt8
>(nToAllocate
);
275 #if OSL_DEBUG_LEVEL > 0
276 memcpy(mpUserBuffer
.get() + nToAllocate
- sizeof(CANARY
),
277 CANARY
, sizeof(CANARY
));
281 catch (const std::bad_alloc
&) {}
285 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow
<< "x" << mnHeight
);
286 DeallocateUserData();
291 for (size_t i
= 0; i
< size_t(mnBytesPerRow
* mnHeight
); i
++)
292 mpUserBuffer
.get()[i
] = (i
& 0xFF);
296 return mpUserBuffer
!= nullptr;
299 void OpenGLSalBitmap::DeallocateUserData()
301 mpUserBuffer
.reset();
307 void lclInstantiateTexture(OpenGLTexture
& rTexture
, const int nWidth
, const int nHeight
,
308 const GLenum nFormat
, const GLenum nType
, sal_uInt8
const * pData
)
310 if (nWidth
== nHeight
)
312 typedef std::vector
<std::unique_ptr
<FixedTextureAtlasManager
>> TextureAtlasVector
;
313 static vcl::DeleteOnDeinit
<TextureAtlasVector
> aTextureAtlases([]() {
314 TextureAtlasVector
* p
= new TextureAtlasVector
;
316 p
->push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 16));
317 p
->push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 24));
318 p
->push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 32));
319 p
->push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 48));
320 p
->push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 64));
323 for (std::unique_ptr
<FixedTextureAtlasManager
>& pTextureAtlas
: *aTextureAtlases
.get())
325 if (nWidth
== pTextureAtlas
->GetSubtextureSize())
327 rTexture
= pTextureAtlas
->InsertBuffer(nWidth
, nHeight
, nFormat
, nType
, pData
);
332 rTexture
= OpenGLTexture (nWidth
, nHeight
, nFormat
, nType
, pData
);
335 } // end anonymous namespace
337 Size
OpenGLSalBitmap::GetSize() const
339 return Size(mnWidth
, mnHeight
);
342 GLuint
OpenGLSalBitmap::CreateTexture()
344 VCL_GL_INFO( "::CreateTexture bits: " << mnBits
);
345 GLenum nFormat
= GL_RGBA
;
346 GLenum nType
= GL_UNSIGNED_BYTE
;
347 sal_uInt8
* pData( nullptr );
348 bool bAllocated( false );
350 if (mpUserBuffer
!= nullptr)
352 if( mnBits
== 24 || mnBits
== 32 )
354 // no conversion needed for truecolor
355 pData
= mpUserBuffer
.get();
357 determineTextureFormat(mnBits
, nFormat
, nType
);
359 else if( mnBits
== 8 && maPalette
.IsGreyPalette8Bit() )
361 // no conversion needed for 8bit grayscale
362 pData
= mpUserBuffer
.get();
363 nFormat
= GL_LUMINANCE
;
364 nType
= GL_UNSIGNED_BYTE
;
368 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits
<< " to 24 bits" );
369 // convert to 24 bits RGB using palette
370 determineTextureFormat(24, nFormat
, nType
);
371 pData
= convertDataBitCount( mpUserBuffer
.get(), mnWidth
, mnHeight
,
372 mnBits
, mnBytesPerRow
, maPalette
,
373 nFormat
== GL_BGR
? BitConvert::BGR
: BitConvert::RGB
).release();
378 OpenGLVCLContextZone aContextZone
;
380 lclInstantiateTexture(maTexture
, mnWidth
, mnHeight
, nFormat
, nType
, pData
);
382 VCL_GL_INFO("Created texture " << maTexture
.Id() << " bits: " << mnBits
);
387 mbDirtyTexture
= false;
390 return maTexture
.Id();
393 bool OpenGLSalBitmap::ReadTexture()
395 sal_uInt8
* pData
= mpUserBuffer
.get();
397 GLenum nFormat
= GL_RGBA
;
398 GLenum nType
= GL_UNSIGNED_BYTE
;
400 VCL_GL_INFO( "::ReadTexture " << mnWidth
<< "x" << mnHeight
<< " bits: " << mnBits
);
402 if( pData
== nullptr )
405 OpenGLVCLContextZone aContextZone
;
407 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
408 xContext
->state().scissor().disable();
409 xContext
->state().stencil().disable();
411 if ((mnBits
== 8 && maPalette
.IsGreyPalette8Bit()) || mnBits
== 24 || mnBits
== 32)
413 determineTextureFormat(mnBits
, nFormat
, nType
);
415 #if OSL_DEBUG_LEVEL > 0
416 // help valgrind & drmemory rescue us - touch last and first bits.
418 pData
[mnBits
/8*mnWidth
*mnHeight
-1] = 0;
419 // if this fails we can read too much into pData
420 assert(mnWidth
== maTexture
.GetWidth() &&
421 mnHeight
== maTexture
.GetHeight());
424 maTexture
.Read(nFormat
, nType
, pData
);
426 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
427 // If we read over the end of pData we have a real hidden memory
428 // corruption problem !
429 size_t nCanary
= mnBytesPerRow
* mnHeight
;
430 assert(!memcmp(pData
+ nCanary
, CANARY
, sizeof (CANARY
)));
434 else if (mnBits
== 1 || mnBits
== 4 || mnBits
== 8)
435 { // convert buffers from 24-bit RGB to 1,4 or 8-bit buffer
436 std::vector
<sal_uInt8
> aBuffer(mnWidth
* mnHeight
* 3);
438 sal_uInt8
* pBuffer
= aBuffer
.data();
439 determineTextureFormat(24, nFormat
, nType
);
440 maTexture
.Read(nFormat
, nType
, pBuffer
);
441 sal_uInt32 nSourceBytesPerRow
= lclBytesPerRow(24, mnWidth
);
443 std::unique_ptr
<vcl::ScanlineWriter
> pWriter
= vcl::ScanlineWriter::Create(mnBits
, maPalette
);
444 for (int y
= 0; y
< mnHeight
; ++y
)
446 sal_uInt8
* pSource
= &pBuffer
[y
* nSourceBytesPerRow
];
447 sal_uInt8
* pDestination
= &pData
[y
* mnBytesPerRow
];
449 pWriter
->nextLine(pDestination
);
451 for (int x
= 0; x
< mnWidth
; ++x
)
454 sal_uInt8 nR
= *pSource
++;
455 sal_uInt8 nG
= *pSource
++;
456 sal_uInt8 nB
= *pSource
++;
458 pWriter
->writeRGB(nR
, nG
, nB
);
464 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture
.Id() << " @ "
465 << mnWidth
<< "x" << mnHeight
<< "- unimplemented bit depth: "
470 sal_uInt16
OpenGLSalBitmap::GetBitCount() const
475 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture
& rInputTexture
, BitmapChecksum
& rChecksum
) const
477 OUString
FragShader("areaHashCRC64TFragmentShader");
479 rtl::Reference
< OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
480 xContext
->state().scissor().disable();
481 xContext
->state().stencil().disable();
483 static vcl::DeleteOnDeinit
<OpenGLTexture
> gCRCTableTexture(
484 new OpenGLTexture(512, 1, GL_RGBA
, GL_UNSIGNED_BYTE
,
485 vcl_get_crc64_table()));
486 OpenGLTexture
&rCRCTableTexture
= *gCRCTableTexture
.get();
490 int nWidth
= rInputTexture
.GetWidth();
491 int nHeight
= rInputTexture
.GetHeight();
493 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
494 if (pProgram
== nullptr)
497 int nNewWidth
= ceil( nWidth
/ 4.0 );
498 int nNewHeight
= ceil( nHeight
/ 4.0 );
500 OpenGLTexture
aFirstPassTexture(nNewWidth
, nNewHeight
);
501 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aFirstPassTexture
);
503 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
504 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
506 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
507 pProgram
->SetTexture("sampler", rInputTexture
);
508 pProgram
->DrawTexture(rInputTexture
);
511 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
517 nWidth
= aFirstPassTexture
.GetWidth();
518 nHeight
= aFirstPassTexture
.GetHeight();
520 pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
521 if (pProgram
== nullptr)
524 nNewWidth
= ceil( nWidth
/ 4.0 );
525 nNewHeight
= ceil( nHeight
/ 4.0 );
527 OpenGLTexture
aSecondPassTexture(nNewWidth
, nNewHeight
);
528 pFramebuffer
= xContext
->AcquireFramebuffer(aSecondPassTexture
);
530 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
531 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
533 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
534 pProgram
->SetTexture("sampler", aFirstPassTexture
);
535 pProgram
->DrawTexture(aFirstPassTexture
);
538 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
543 OpenGLTexture
& aFinalTexture
= aSecondPassTexture
;
544 std::vector
<sal_uInt8
> aBuf( aFinalTexture
.GetWidth() * aFinalTexture
.GetHeight() * 4 );
545 aFinalTexture
.Read(GL_RGBA
, GL_UNSIGNED_BYTE
, aBuf
.data());
547 BitmapChecksum nCrc
= vcl_get_checksum(0, aBuf
.data(), aBuf
.size());
553 void OpenGLSalBitmap::updateChecksum() const
558 if( (mnWidth
* mnHeight
) < (1024*768) || mnWidth
< 128 || mnHeight
< 128 )
560 SalBitmap::updateChecksum();
564 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
566 OpenGLVCLContextZone aContextZone
;
567 OpenGLTexture
& rInputTexture
= GetTexture();
568 pThis
->mbChecksumValid
= calcChecksumGL(rInputTexture
, pThis
->mnChecksum
);
569 if (!pThis
->mbChecksumValid
)
570 SalBitmap::updateChecksum();
573 BitmapBuffer
* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode
)
575 OpenGLVCLContextZone aContextZone
;
577 if( nMode
!= BitmapAccessMode::Info
)
581 if( !AllocateUserData() )
583 if( maTexture
&& !ReadTexture() )
585 DeallocateUserData();
591 // mpUserBuffer must be unique when we are doing the write access
592 if (nMode
== BitmapAccessMode::Write
&& mpUserBuffer
&& mpUserBuffer
.use_count() > 1)
594 std::shared_ptr
<sal_uInt8
> aBuffer(mpUserBuffer
);
596 mpUserBuffer
.reset();
598 memcpy(mpUserBuffer
.get(), aBuffer
.get(), mnBytesPerRow
* mnHeight
);
601 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
602 pBuffer
->mnWidth
= mnWidth
;
603 pBuffer
->mnHeight
= mnHeight
;
604 pBuffer
->maPalette
= maPalette
;
605 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
606 pBuffer
->mpBits
= mpUserBuffer
.get();
607 pBuffer
->mnBitCount
= mnBits
;
612 pBuffer
->mnFormat
= ScanlineFormat::N1BitMsbPal
;
615 pBuffer
->mnFormat
= ScanlineFormat::N4BitMsnPal
;
618 pBuffer
->mnFormat
= ScanlineFormat::N8BitPal
;
622 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcRgb
;
627 pBuffer
->mnFormat
= ScanlineFormat::N32BitTcRgba
;
628 ColorMaskElement
aRedMask(0xff000000);
629 aRedMask
.CalcMaskShift();
630 ColorMaskElement
aGreenMask(0x00ff0000);
631 aGreenMask
.CalcMaskShift();
632 ColorMaskElement
aBlueMask(0x0000ff00);
633 aBlueMask
.CalcMaskShift();
634 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
637 default: assert(false);
643 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
645 OpenGLVCLContextZone aContextZone
;
647 if( nMode
== BitmapAccessMode::Write
)
649 maTexture
= OpenGLTexture();
650 mbDirtyTexture
= true;
651 mbChecksumValid
= false;
653 // The palette is modified on read during the BitmapWriteAccess,
654 // but of course, often it is not modified; interesting.
655 maPalette
= pBuffer
->maPalette
;
657 // Are there any more ground movements underneath us ?
658 assert( pBuffer
->mnWidth
== mnWidth
);
659 assert( pBuffer
->mnHeight
== mnHeight
);
660 assert( pBuffer
->mnBitCount
== mnBits
);
665 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData
& /*rData*/ )
667 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
669 // TODO Implement for ANDROID/OSX/IOS/WIN32
670 X11SalBitmap rBitmap
;
671 BitmapBuffer
* pBuffer
;
673 rBitmap
.Create( GetSize(), mnBits
, maPalette
);
674 pBuffer
= rBitmap
.AcquireBuffer( false );
675 if( pBuffer
== NULL
)
678 if (!mpUserBuffer
.get())
680 if( !AllocateUserData() || !ReadTexture() )
682 rBitmap
.ReleaseBuffer( pBuffer
, false );
683 DeallocateUserData();
688 // TODO Might be more efficient to add a static method to SalBitmap
689 // to get system data from a buffer
690 memcpy( pBuffer
->mpBits
, mpUserBuffer
.get(), mnBytesPerRow
* mnHeight
);
692 rBitmap
.ReleaseBuffer( pBuffer
, false );
693 return rBitmap
.GetSystemData( rData
);
699 bool OpenGLSalBitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uInt8 nTol
)
701 VCL_GL_INFO("::Replace");
704 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
705 xContext
->state().scissor().disable();
706 xContext
->state().stencil().disable();
708 OpenGLFramebuffer
* pFramebuffer
;
709 OpenGLProgram
* pProgram
;
712 pProgram
= xContext
->UseProgram( "textureVertexShader",
713 "replaceColorFragmentShader" );
717 OpenGLTexture
aNewTex( mnWidth
, mnHeight
);
718 pFramebuffer
= xContext
->AcquireFramebuffer( aNewTex
);
720 pProgram
->SetTexture( "sampler", maTexture
);
721 pProgram
->SetColor( "search_color", rSearchColor
);
722 pProgram
->SetColor( "replace_color", rReplaceColor
);
723 pProgram
->SetUniform1f( "epsilon", nTol
/ 255.0f
);
724 pProgram
->DrawTexture( maTexture
);
727 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
734 // Convert texture to greyscale and adjust bitmap metadata
735 bool OpenGLSalBitmap::ConvertToGreyscale()
737 VCL_GL_INFO("::ConvertToGreyscale");
739 // avoid re-converting to 8bits.
740 if ( mnBits
== 8 && maPalette
.IsGreyPalette8Bit())
744 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
745 xContext
->state().scissor().disable();
746 xContext
->state().stencil().disable();
748 OpenGLFramebuffer
* pFramebuffer
;
749 OpenGLProgram
* pProgram
;
752 pProgram
= xContext
->UseProgram("textureVertexShader", "greyscaleFragmentShader");
757 OpenGLTexture
aNewTex(mnWidth
, mnHeight
);
758 pFramebuffer
= xContext
->AcquireFramebuffer(aNewTex
);
759 pProgram
->SetTexture("sampler", maTexture
);
760 pProgram
->DrawTexture(maTexture
);
763 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
766 maPalette
= Bitmap::GetGreyPalette(256);
768 // AllocateUserData will handle the rest.
769 DeallocateUserData();
770 mbDirtyTexture
= false;
776 // This is needed to just make the bitmap usable as an alpha channel.
777 // Converting to 8bit grey will do.
778 bool OpenGLSalBitmap::InterpretAs8Bit()
780 return ConvertToGreyscale();
783 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */