Line data Source code
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 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <vcl/opengl/OpenGLHelper.hxx>
23 :
24 : #include "vcl/bitmap.hxx"
25 : #include "vcl/outdev.hxx"
26 : #include "vcl/salbtype.hxx"
27 : #include "svdata.hxx"
28 : #include "salgdi.hxx"
29 :
30 : #include "opengl/program.hxx"
31 : #include "opengl/salbmp.hxx"
32 :
33 0 : static bool isValidBitCount( sal_uInt16 nBitCount )
34 : {
35 0 : return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
36 : }
37 :
38 0 : OpenGLSalBitmap::OpenGLSalBitmap()
39 : : mpContext(NULL)
40 : , mbDirtyTexture(true)
41 : , mnBits(0)
42 : , mnBytesPerRow(0)
43 : , mnWidth(0)
44 : , mnHeight(0)
45 : , mnBufWidth(0)
46 0 : , mnBufHeight(0)
47 : {
48 0 : }
49 :
50 0 : OpenGLSalBitmap::~OpenGLSalBitmap()
51 : {
52 0 : Destroy();
53 : SAL_INFO( "vcl.opengl", "~OpenGLSalBitmap" );
54 0 : }
55 :
56 0 : bool OpenGLSalBitmap::Create( const OpenGLTexture& rTex, long nX, long nY, long nWidth, long nHeight )
57 : {
58 0 : static const BitmapPalette aEmptyPalette;
59 :
60 0 : Destroy();
61 : SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from FBO: [" << nX << ", " << nY << "] " << nWidth << "x" << nHeight );
62 :
63 0 : mnWidth = nWidth;
64 0 : mnHeight = nHeight;
65 0 : mnBufWidth = 0;
66 0 : mnBufHeight = 0;
67 :
68 : // TODO Check the framebuffer configuration
69 0 : mnBits = 32;
70 0 : maPalette = aEmptyPalette;
71 :
72 0 : if( rTex )
73 0 : maTexture = OpenGLTexture( rTex, nX, nY, nWidth, nHeight );
74 : else
75 0 : maTexture = OpenGLTexture( nX, nY, nWidth, nHeight );
76 0 : mbDirtyTexture = false;
77 : SAL_INFO( "vcl.opengl", "Created texture " << maTexture.Id() );
78 :
79 0 : return true;
80 : }
81 :
82 0 : bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
83 : {
84 0 : Destroy();
85 : SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create with size: " << rSize );
86 :
87 0 : if( !isValidBitCount( nBits ) )
88 0 : return false;
89 0 : maPalette = rBitmapPalette;
90 0 : mnBits = nBits;
91 0 : mnWidth = mnBufWidth = rSize.Width();
92 0 : mnHeight = mnBufHeight = rSize.Height();
93 0 : return false;
94 : }
95 :
96 0 : bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp )
97 : {
98 0 : return Create( rSalBmp, rSalBmp.GetBitCount() );
99 : }
100 :
101 0 : bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
102 : {
103 0 : return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
104 : }
105 :
106 0 : bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount )
107 : {
108 : // check that carefully only in the debug mode
109 : assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBmp));
110 :
111 0 : const OpenGLSalBitmap& rSourceBitmap = static_cast<const OpenGLSalBitmap&>(rSalBmp);
112 :
113 : SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from BMP: " << rSourceBitmap.mnWidth << "x" << rSourceBitmap.mnHeight );
114 :
115 0 : if( isValidBitCount( nNewBitCount ) )
116 : {
117 : // TODO: lfrb: What about the pending operations?!
118 0 : mnBits = nNewBitCount;
119 0 : mnBytesPerRow = rSourceBitmap.mnBytesPerRow;
120 0 : mnWidth = rSourceBitmap.mnWidth;
121 0 : mnHeight = rSourceBitmap.mnHeight;
122 0 : mnBufWidth = rSourceBitmap.mnBufWidth;
123 0 : mnBufHeight = rSourceBitmap.mnBufHeight;
124 0 : maPalette = rSourceBitmap.maPalette;
125 : // execute any pending operations on the source bitmap
126 0 : maTexture = rSourceBitmap.GetTexture();
127 0 : mbDirtyTexture = false;
128 0 : maUserBuffer = rSourceBitmap.maUserBuffer;
129 :
130 : // TODO Copy buffer data if the bitcount and palette are the same
131 0 : return true;
132 : }
133 0 : return false;
134 : }
135 :
136 0 : bool OpenGLSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
137 : {
138 : // TODO Is this method needed?
139 0 : return false;
140 : }
141 :
142 0 : OpenGLTexture& OpenGLSalBitmap::GetTexture() const
143 : {
144 0 : OpenGLSalBitmap* pThis = const_cast<OpenGLSalBitmap*>(this);
145 0 : if( !maTexture || mbDirtyTexture )
146 0 : pThis->CreateTexture();
147 0 : else if( !maPendingOps.empty() )
148 0 : pThis->ExecuteOperations();
149 : SAL_INFO( "vcl.opengl", "Got texture " << maTexture.Id() );
150 0 : return pThis->maTexture;
151 : }
152 :
153 0 : void OpenGLSalBitmap::Destroy()
154 : {
155 : SAL_INFO( "vcl.opengl", "Destroy OpenGLSalBitmap" );
156 0 : maPendingOps.clear();
157 0 : maTexture = OpenGLTexture();
158 0 : maUserBuffer.reset();
159 0 : }
160 :
161 0 : bool OpenGLSalBitmap::AllocateUserData()
162 : {
163 : SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::AllocateUserData" );
164 :
165 0 : if( mnWidth && mnHeight )
166 : {
167 0 : mnBytesPerRow = 0;
168 :
169 0 : switch( mnBits )
170 : {
171 0 : case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
172 0 : case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
173 0 : case 8: mnBytesPerRow = mnWidth; break;
174 0 : case 16: mnBytesPerRow = mnWidth << 1; break;
175 0 : case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
176 0 : case 32: mnBytesPerRow = mnWidth << 2; break;
177 : default:
178 : OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
179 : }
180 : }
181 :
182 0 : bool alloc = false;
183 0 : if (mnBytesPerRow != 0 && mnHeight &&
184 0 : mnBytesPerRow <= std::numeric_limits<sal_uInt32>::max() / mnHeight)
185 : {
186 : try
187 : {
188 0 : maUserBuffer.reset( new sal_uInt8[static_cast<sal_uInt32>(mnBytesPerRow) * mnHeight] );
189 0 : alloc = true;
190 : }
191 0 : catch (const std::bad_alloc &) {}
192 : }
193 0 : if (!alloc)
194 : {
195 : SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight);
196 0 : maUserBuffer.reset( static_cast<sal_uInt8*>(NULL) );
197 0 : mnBytesPerRow = 0;
198 : }
199 : #ifdef DBG_UTIL
200 : else
201 : {
202 : for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++)
203 : maUserBuffer.get()[i] = (i & 0xFF);
204 : }
205 : #endif
206 :
207 0 : return maUserBuffer.get() != 0;
208 : }
209 :
210 : namespace {
211 :
212 0 : class ImplPixelFormat
213 : {
214 : protected:
215 : sal_uInt8* mpData;
216 : public:
217 : static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
218 :
219 0 : virtual void StartLine( sal_uInt8* pLine ) { mpData = pLine; }
220 : virtual const BitmapColor& ReadPixel() = 0;
221 0 : virtual ~ImplPixelFormat() { }
222 : };
223 :
224 0 : class ImplPixelFormat8 : public ImplPixelFormat
225 : {
226 : private:
227 : const BitmapPalette& mrPalette;
228 :
229 : public:
230 0 : explicit ImplPixelFormat8( const BitmapPalette& rPalette )
231 0 : : mrPalette( rPalette )
232 : {
233 0 : }
234 0 : virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
235 : {
236 : assert( mrPalette.GetEntryCount() > *mpData );
237 0 : return mrPalette[ *mpData++ ];
238 : }
239 : };
240 :
241 0 : class ImplPixelFormat4 : public ImplPixelFormat
242 : {
243 : private:
244 : const BitmapPalette& mrPalette;
245 : sal_uInt32 mnX;
246 : sal_uInt32 mnShift;
247 :
248 : public:
249 0 : explicit ImplPixelFormat4( const BitmapPalette& rPalette )
250 : : mrPalette( rPalette )
251 : , mnX(0)
252 0 : , mnShift(4)
253 : {
254 0 : }
255 0 : virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE
256 : {
257 0 : mpData = pLine;
258 0 : mnX = 0;
259 0 : mnShift = 4;
260 0 : }
261 0 : virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
262 : {
263 0 : sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
264 : assert( mrPalette.GetEntryCount() > nIdx );
265 0 : const BitmapColor& rColor = mrPalette[nIdx];
266 0 : mnX++;
267 0 : mnShift ^= 4;
268 0 : return rColor;
269 : }
270 : };
271 :
272 0 : class ImplPixelFormat1 : public ImplPixelFormat
273 : {
274 : private:
275 : const BitmapPalette& mrPalette;
276 : sal_uInt32 mnX;
277 :
278 : public:
279 0 : explicit ImplPixelFormat1( const BitmapPalette& rPalette )
280 : : mrPalette(rPalette)
281 0 : , mnX(0)
282 : {
283 0 : }
284 0 : virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE
285 : {
286 0 : mpData = pLine;
287 0 : mnX = 0;
288 0 : }
289 0 : virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
290 : {
291 0 : const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
292 0 : mnX++;
293 0 : return rColor;
294 : }
295 : };
296 :
297 0 : ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
298 : {
299 0 : switch( nBits )
300 : {
301 0 : case 1: return new ImplPixelFormat1( rPalette );
302 0 : case 4: return new ImplPixelFormat4( rPalette );
303 0 : case 8: return new ImplPixelFormat8( rPalette );
304 : }
305 :
306 0 : return 0;
307 : }
308 :
309 : }
310 :
311 0 : Size OpenGLSalBitmap::GetSize() const
312 : {
313 0 : std::deque< OpenGLSalBitmapOp* >::const_iterator it = maPendingOps.begin();
314 0 : Size aSize( mnWidth, mnHeight );
315 :
316 0 : while( it != maPendingOps.end() )
317 0 : (*it++)->GetSize( aSize );
318 :
319 0 : return aSize;
320 : }
321 :
322 0 : void OpenGLSalBitmap::ExecuteOperations()
323 : {
324 0 : makeCurrent();
325 0 : while( !maPendingOps.empty() )
326 : {
327 0 : OpenGLSalBitmapOp* pOp = maPendingOps.front();
328 0 : pOp->Execute();
329 0 : maPendingOps.pop_front();
330 : }
331 0 : }
332 :
333 0 : GLuint OpenGLSalBitmap::CreateTexture()
334 : {
335 : SAL_INFO( "vcl.opengl", "::CreateTexture" );
336 0 : GLenum nFormat = GL_RGBA;
337 0 : GLenum nType = GL_UNSIGNED_BYTE;
338 0 : sal_uInt8* pData( NULL );
339 0 : bool bAllocated( false );
340 :
341 0 : if( maUserBuffer.get() != 0 )
342 : {
343 0 : if( mnBits == 16 || mnBits == 24 || mnBits == 32 )
344 : {
345 : // no conversion needed for truecolor
346 0 : pData = maUserBuffer.get();
347 :
348 0 : switch( mnBits )
349 : {
350 0 : case 16: nFormat = GL_RGB;
351 0 : nType = GL_UNSIGNED_SHORT_5_6_5;
352 0 : break;
353 0 : case 24: nFormat = GL_RGB;
354 0 : nType = GL_UNSIGNED_BYTE;
355 0 : break;
356 0 : case 32: nFormat = GL_RGBA;
357 0 : nType = GL_UNSIGNED_BYTE;
358 0 : break;
359 : }
360 : }
361 0 : else if( mnBits == 8 && maPalette.IsGreyPalette() )
362 : {
363 : // no conversion needed for grayscale
364 0 : pData = maUserBuffer.get();
365 0 : nFormat = GL_LUMINANCE;
366 0 : nType = GL_UNSIGNED_BYTE;
367 : }
368 : else
369 : {
370 : // convert to 32 bits RGBA using palette
371 0 : pData = new sal_uInt8[ mnBufHeight * (mnBufWidth << 2) ];
372 0 : bAllocated = true;
373 0 : nFormat = GL_RGBA;
374 0 : nType = GL_UNSIGNED_BYTE;
375 :
376 0 : ImplPixelFormat* pSrcFormat = ImplPixelFormat::GetFormat( mnBits, maPalette );
377 0 : sal_uInt8* pSrcData = maUserBuffer.get();
378 0 : sal_uInt8* pDstData = pData;
379 :
380 0 : sal_uInt32 nY = mnBufHeight;
381 0 : while( nY-- )
382 : {
383 0 : pSrcFormat->StartLine( pSrcData );
384 :
385 0 : sal_uInt32 nX = mnBufWidth;
386 0 : while( nX-- )
387 : {
388 0 : const BitmapColor& c = pSrcFormat->ReadPixel();
389 :
390 0 : *pDstData++ = c.GetRed();
391 0 : *pDstData++ = c.GetGreen();
392 0 : *pDstData++ = c.GetBlue();
393 0 : *pDstData++ = 255;
394 : }
395 :
396 0 : pSrcData += mnBytesPerRow;
397 : }
398 : }
399 : }
400 :
401 0 : makeCurrent();
402 :
403 0 : maTexture = OpenGLTexture (mnBufWidth, mnBufHeight, nFormat, nType, pData );
404 : SAL_INFO( "vcl.opengl", "Created texture " << maTexture.Id() );
405 :
406 0 : if( bAllocated )
407 0 : delete[] pData;
408 :
409 0 : ExecuteOperations();
410 0 : mbDirtyTexture = false;
411 :
412 0 : CHECK_GL_ERROR();
413 0 : return maTexture.Id();
414 : }
415 :
416 0 : bool OpenGLSalBitmap::ReadTexture()
417 : {
418 0 : sal_uInt8* pData = maUserBuffer.get();
419 0 : GLenum nFormat = GL_RGBA;
420 0 : GLenum nType = GL_UNSIGNED_BYTE;
421 :
422 : SAL_INFO( "vcl.opengl", "::ReadTexture " << mnWidth << "x" << mnHeight );
423 :
424 0 : if( pData == NULL )
425 0 : return false;
426 :
427 0 : if( mnBits == 16 || mnBits == 24 || mnBits == 32 )
428 : {
429 : // no conversion needed for truecolor
430 0 : pData = maUserBuffer.get();
431 :
432 0 : switch( mnBits )
433 : {
434 0 : case 16: nFormat = GL_RGB;
435 0 : nType = GL_UNSIGNED_SHORT_5_6_5;
436 0 : break;
437 0 : case 24: nFormat = GL_RGB;
438 0 : nType = GL_UNSIGNED_BYTE;
439 0 : break;
440 0 : case 32: nFormat = GL_RGBA;
441 0 : nType = GL_UNSIGNED_BYTE;
442 0 : break;
443 : }
444 : }
445 : else
446 : {
447 0 : return false;
448 : }
449 :
450 0 : makeCurrent();
451 0 : maTexture.Read( nFormat, nType, pData );
452 0 : mnBufWidth = mnWidth;
453 0 : mnBufHeight = mnHeight;
454 :
455 0 : return true;
456 : }
457 :
458 0 : sal_uInt16 OpenGLSalBitmap::GetBitCount() const
459 : {
460 0 : return mnBits;
461 : }
462 :
463 0 : OpenGLContext* OpenGLSalBitmap::GetBitmapContext()
464 : {
465 0 : return ImplGetDefaultWindow()->GetGraphics()->GetOpenGLContext();
466 : }
467 :
468 0 : void OpenGLSalBitmap::makeCurrent()
469 : {
470 0 : ImplSVData* pSVData = ImplGetSVData();
471 :
472 : // TODO: make sure we can really use the last used context
473 0 : mpContext = pSVData->maGDIData.mpLastContext;
474 0 : while( mpContext && !mpContext->isInitialized() )
475 0 : mpContext = mpContext->mpPrevContext;
476 0 : if( !mpContext )
477 0 : mpContext = GetBitmapContext();
478 : assert(mpContext && "Couldn't get an OpenGL context");
479 0 : mpContext->makeCurrent();
480 0 : }
481 :
482 0 : BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode )
483 : {
484 :
485 0 : if( nMode != BITMAP_INFO_ACCESS )
486 : {
487 0 : if( !maUserBuffer.get() )
488 : {
489 0 : if( !AllocateUserData() )
490 0 : return NULL;
491 0 : if( maTexture && !ReadTexture() )
492 0 : return NULL;
493 : }
494 :
495 0 : if( !maPendingOps.empty() )
496 : {
497 : SAL_INFO( "vcl.opengl", "** Creating texture and reading it back immediately" );
498 0 : if( !CreateTexture() || !AllocateUserData() || !ReadTexture() )
499 0 : return NULL;
500 : }
501 : }
502 :
503 0 : BitmapBuffer* pBuffer = new BitmapBuffer;
504 0 : pBuffer->mnWidth = mnWidth;
505 0 : pBuffer->mnHeight = mnHeight;
506 0 : pBuffer->maPalette = maPalette;
507 0 : pBuffer->mnScanlineSize = mnBytesPerRow;
508 0 : pBuffer->mpBits = maUserBuffer.get();
509 0 : pBuffer->mnBitCount = mnBits;
510 0 : switch( mnBits )
511 : {
512 0 : case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
513 0 : case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
514 0 : case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
515 0 : case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
516 0 : pBuffer->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
517 0 : break;
518 0 : case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_RGB; break;
519 0 : case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_RGBA;
520 0 : pBuffer->maColorMask = ColorMask( 0xff000000, 0x00ff0000, 0x0000ff00 );
521 0 : break;
522 : }
523 :
524 0 : return pBuffer;
525 : }
526 :
527 0 : void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
528 : {
529 0 : if( nMode == BITMAP_WRITE_ACCESS )
530 : {
531 0 : maTexture = OpenGLTexture();
532 0 : mbDirtyTexture = true;
533 : }
534 : // The palette is modified on read during the BitmapWriteAccess,
535 : // but of course, often it is not modified; interesting.
536 0 : maPalette = pBuffer->maPalette;
537 :
538 : // Are there any more ground movements underneath us ?
539 : assert( pBuffer->mnWidth == mnWidth );
540 : assert( pBuffer->mnHeight == mnHeight );
541 : assert( pBuffer->mnBitCount == mnBits );
542 :
543 0 : delete pBuffer;
544 0 : }
545 :
546 0 : bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ )
547 : {
548 : SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
549 : #if 0
550 : // TODO Implement for ANDROID/OSX/IOS/WIN32
551 : X11SalBitmap rBitmap;
552 : BitmapBuffer* pBuffer;
553 :
554 : rBitmap.Create( GetSize(), mnBits, maPalette );
555 : pBuffer = rBitmap.AcquireBuffer( false );
556 : if( pBuffer == NULL )
557 : return false;
558 :
559 : if( !maUserBuffer.get() )
560 : {
561 : if( !AllocateUserData() || !ReadTexture() )
562 : {
563 : rBitmap.ReleaseBuffer( pBuffer, false );
564 : return false;
565 : }
566 : }
567 :
568 : // TODO Might be more efficient to add a static method to SalBitmap
569 : // to get system data from a buffer
570 : memcpy( pBuffer->mpBits, maUserBuffer.get(), mnBytesPerRow * mnHeight );
571 :
572 : rBitmap.ReleaseBuffer( pBuffer, false );
573 : return rBitmap.GetSystemData( rData );
574 : #else
575 0 : return false;
576 : #endif
577 : }
578 :
579 0 : bool OpenGLSalBitmap::Crop( const Rectangle& /*rRectPixel*/ )
580 : {
581 0 : return false;
582 : }
583 :
584 0 : bool OpenGLSalBitmap::Erase( const ::Color& /*rFillColor*/ )
585 : {
586 0 : return false;
587 : }
588 :
589 0 : bool OpenGLSalBitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
590 : {
591 : OpenGLFramebuffer* pFramebuffer;
592 : OpenGLProgram* pProgram;
593 :
594 0 : GetTexture();
595 0 : makeCurrent();
596 : pProgram = mpContext->UseProgram( "textureVertexShader",
597 0 : "replaceColorFragmentShader" );
598 0 : if( !pProgram )
599 0 : return false;
600 :
601 0 : OpenGLTexture aNewTex = OpenGLTexture( mnWidth, mnHeight );
602 0 : pFramebuffer = mpContext->AcquireFramebuffer( aNewTex );
603 :
604 0 : pProgram->SetTexture( "sampler", maTexture );
605 0 : pProgram->SetColor( "search_color", rSearchColor );
606 0 : pProgram->SetColor( "replace_color", rReplaceColor );
607 0 : pProgram->SetUniform1f( "epsilon", nTol / 255.0f );
608 0 : pProgram->DrawTexture( maTexture );
609 0 : pProgram->Clean();
610 :
611 0 : OpenGLContext::ReleaseFramebuffer( pFramebuffer );
612 0 : maTexture = aNewTex;
613 :
614 0 : CHECK_GL_ERROR();
615 0 : return true;
616 801 : }
617 :
618 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|