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 #include <sal/log.hxx>
22 #include <tools/stream.hxx>
23 #include <vcl/opengl/OpenGLContext.hxx>
24 #include <vcl/opengl/OpenGLHelper.hxx>
25
26 #include <svdata.hxx>
27
28 #include <vcl/pngwrite.hxx>
29
30 #include <opengl/framebuffer.hxx>
31 #include <opengl/texture.hxx>
32 #include <opengl/zone.hxx>
33 #include <opengl/RenderState.hxx>
34
35 namespace
36 {
37
38 constexpr GLenum constInternalFormat = GL_RGBA8;
39
40 } // end anonymous namespace
41
42 // texture with allocated size
ImplOpenGLTexture(int nWidth,int nHeight,bool bAllocate)43 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
44 mnTexture( 0 ),
45 mnWidth( nWidth ),
46 mnHeight( nHeight ),
47 mnFilter( GL_NEAREST ),
48 mnOptStencil( 0 )
49 {
50 OpenGLVCLContextZone aContextZone;
51
52 auto& rState = OpenGLContext::getVCLContext()->state();
53 TextureState::generate(mnTexture);
54 rState.texture().active(0);
55 rState.texture().bind(mnTexture);
56
57 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
58 CHECK_GL_ERROR();
59 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
60 CHECK_GL_ERROR();
61 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
62 CHECK_GL_ERROR();
63 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
64 CHECK_GL_ERROR();
65 if( bAllocate )
66 {
67 #ifdef DBG_UTIL
68 std::vector< sal_uInt8 > buffer;
69 buffer.resize( nWidth * nHeight * 4 );
70 for( size_t i = 0; i < size_t( nWidth * nHeight ); ++i )
71 { // pre-fill the texture with deterministic garbage
72 bool odd = (i & 0x01);
73 buffer[ i * 4 ] = odd ? 0x40 : 0xBF;
74 buffer[ i * 4 + 1 ] = 0x80;
75 buffer[ i * 4 + 2 ] = odd ? 0xBF : 0x40;
76 buffer[ i * 4 + 3 ] = 0xFF;
77 }
78 glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
79 #else
80 glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
81 #endif
82 CHECK_GL_ERROR();
83 }
84
85 VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" );
86 }
87
88 // texture with content retrieved from FBO
ImplOpenGLTexture(int nX,int nY,int nWidth,int nHeight)89 ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
90 mnTexture( 0 ),
91 mnWidth( nWidth ),
92 mnHeight( nHeight ),
93 mnFilter( GL_NEAREST ),
94 mnOptStencil( 0 )
95 {
96 OpenGLVCLContextZone aContextZone;
97
98 // FIXME We need the window height here
99 // nY = GetHeight() - nHeight - nY;
100
101 auto& rState = OpenGLContext::getVCLContext()->state();
102 TextureState::generate(mnTexture);
103 rState.texture().active(0);
104 rState.texture().bind(mnTexture);
105
106 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
107 CHECK_GL_ERROR();
108 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
109 CHECK_GL_ERROR();
110 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
111 CHECK_GL_ERROR();
112 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
113 CHECK_GL_ERROR();
114 glCopyTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nX, nY, nWidth, nHeight, 0 );
115 CHECK_GL_ERROR();
116
117 VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY );
118 }
119
120 // texture from buffer data
ImplOpenGLTexture(int nWidth,int nHeight,int nFormat,int nType,void const * pData)121 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ) :
122 mnTexture( 0 ),
123 mnWidth( nWidth ),
124 mnHeight( nHeight ),
125 mnFilter( GL_NEAREST ),
126 mnOptStencil( 0 )
127 {
128 OpenGLVCLContextZone aContextZone;
129
130 auto& rState = OpenGLContext::getVCLContext()->state();
131 TextureState::generate(mnTexture);
132 rState.texture().active(0);
133 rState.texture().bind(mnTexture);
134
135 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
136 CHECK_GL_ERROR();
137 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
138 CHECK_GL_ERROR();
139 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
140 CHECK_GL_ERROR();
141 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
142 CHECK_GL_ERROR();
143 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
144 CHECK_GL_ERROR();
145 glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, mnWidth, mnHeight, 0, nFormat, nType, pData );
146 CHECK_GL_ERROR();
147
148 VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" );
149 }
150
AddStencil()151 GLuint ImplOpenGLTexture::AddStencil()
152 {
153 assert( mnOptStencil == 0 );
154
155 glGenRenderbuffers( 1, &mnOptStencil );
156 CHECK_GL_ERROR();
157 glBindRenderbuffer( GL_RENDERBUFFER, mnOptStencil );
158 CHECK_GL_ERROR();
159 VCL_GL_INFO( "Allocate stencil " << mnWidth << " x " << mnHeight );
160 glRenderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX,
161 mnWidth, mnHeight );
162 CHECK_GL_ERROR();
163 glBindRenderbuffer(GL_RENDERBUFFER, 0);
164 CHECK_GL_ERROR();
165
166 return mnOptStencil;
167 }
168
~ImplOpenGLTexture()169 ImplOpenGLTexture::~ImplOpenGLTexture()
170 {
171 VCL_GL_INFO( "~OpenGLTexture " << mnTexture );
172 if( mnTexture != 0 )
173 {
174 // During shutdown GL is already de-initialized, so we should not try to create a new context.
175 OpenGLZone aZone;
176 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext(false);
177 if( xContext.is() )
178 {
179 // FIXME: this is really not optimal performance-wise.
180
181 // Check we have been correctly un-bound from all framebuffers.
182 ImplSVData* pSVData = ImplGetSVData();
183 rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
184
185 if( pContext.is() )
186 {
187 pContext->makeCurrent();
188 pContext->UnbindTextureFromFramebuffers( mnTexture );
189 }
190
191 if( mnOptStencil != 0 )
192 {
193 glDeleteRenderbuffers( 1, &mnOptStencil );
194 mnOptStencil = 0;
195 }
196 auto& rState = pContext->state();
197 rState.texture().unbindAndDelete(mnTexture);
198 mnTexture = 0;
199 }
200 else
201 {
202 mnOptStencil = 0;
203 mnTexture = 0;
204 }
205 }
206 }
207
InsertBuffer(int nX,int nY,int nWidth,int nHeight,int nFormat,int nType,sal_uInt8 const * pData)208 bool ImplOpenGLTexture::InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData)
209 {
210 if (!pData || mnTexture == 0)
211 return false;
212
213 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
214 xContext->state().texture().active(0);
215 xContext->state().texture().bind(mnTexture);
216
217 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
218 CHECK_GL_ERROR();
219 glTexSubImage2D(GL_TEXTURE_2D, 0, nX, mnHeight - nY - nHeight, nWidth, nHeight, nFormat, nType, pData);
220 CHECK_GL_ERROR();
221
222 VCL_GL_INFO( "OpenGLTexture " << mnTexture << " Insert buff. to " << nX << " " << nY
223 << " size " << nWidth << "x" << nHeight << " from data" );
224
225 return true;
226 }
227
InitializeSlotMechanism(int nInitialSlotSize)228 void ImplOpenGLTexture::InitializeSlotMechanism(int nInitialSlotSize)
229 {
230 if (mpSlotReferences)
231 return;
232
233 mpSlotReferences.reset(new std::vector<int>(nInitialSlotSize, 0));
234 }
235
IncreaseRefCount(int nSlotNumber)236 void ImplOpenGLTexture::IncreaseRefCount(int nSlotNumber)
237 {
238 if (mpSlotReferences && nSlotNumber >= 0)
239 {
240 if (nSlotNumber >= int(mpSlotReferences->size()))
241 mpSlotReferences->resize(nSlotNumber + 1, 0);
242
243 mpSlotReferences->at(nSlotNumber)++;
244 }
245 }
246
DecreaseRefCount(int nSlotNumber)247 void ImplOpenGLTexture::DecreaseRefCount(int nSlotNumber)
248 {
249 if (mpSlotReferences && nSlotNumber >= 0)
250 {
251 if (nSlotNumber >= int(mpSlotReferences->size()))
252 mpSlotReferences->resize(nSlotNumber, 0);
253
254 mpSlotReferences->at(nSlotNumber)--;
255
256 if (mpSlotReferences->at(nSlotNumber) == 0 && mFunctSlotDeallocateCallback)
257 {
258 mFunctSlotDeallocateCallback(nSlotNumber);
259 }
260 }
261 }
262
OpenGLTexture()263 OpenGLTexture::OpenGLTexture() :
264 maRect( 0, 0, 0, 0 ),
265 mpImpl(),
266 mnSlotNumber(-1)
267 {
268 }
269
OpenGLTexture(const std::shared_ptr<ImplOpenGLTexture> & rpImpl,tools::Rectangle aRectangle,int nSlotNumber)270 OpenGLTexture::OpenGLTexture(const std::shared_ptr<ImplOpenGLTexture>& rpImpl, tools::Rectangle aRectangle, int nSlotNumber)
271 : maRect(aRectangle)
272 , mpImpl(rpImpl)
273 , mnSlotNumber(nSlotNumber)
274 {
275 if (mpImpl)
276 mpImpl->IncreaseRefCount(nSlotNumber);
277 }
278
OpenGLTexture(int nWidth,int nHeight,bool bAllocate)279 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate )
280 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
281 , mpImpl(new ImplOpenGLTexture(nWidth, nHeight, bAllocate))
282 , mnSlotNumber(-1)
283 {
284 }
285
OpenGLTexture(int nX,int nY,int nWidth,int nHeight)286 OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight )
287 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
288 , mpImpl(new ImplOpenGLTexture(nX, nY, nWidth, nHeight))
289 , mnSlotNumber(-1)
290 {
291 }
292
OpenGLTexture(int nWidth,int nHeight,int nFormat,int nType,void const * pData)293 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData )
294 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
295 , mpImpl(new ImplOpenGLTexture(nWidth, nHeight, nFormat, nType, pData))
296 , mnSlotNumber(-1)
297 {
298
299 }
300
OpenGLTexture(const OpenGLTexture & rTexture)301 OpenGLTexture::OpenGLTexture(const OpenGLTexture& rTexture)
302 : maRect(rTexture.maRect)
303 , mpImpl(rTexture.mpImpl)
304 , mnSlotNumber(rTexture.mnSlotNumber)
305 {
306 if (mpImpl)
307 mpImpl->IncreaseRefCount(mnSlotNumber);
308 }
309
OpenGLTexture(OpenGLTexture && rTexture)310 OpenGLTexture::OpenGLTexture(OpenGLTexture&& rTexture) noexcept
311 : maRect(rTexture.maRect)
312 , mpImpl(std::move(rTexture.mpImpl))
313 , mnSlotNumber(rTexture.mnSlotNumber)
314 {
315 }
316
OpenGLTexture(const OpenGLTexture & rTexture,int nX,int nY,int nWidth,int nHeight)317 OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
318 int nX, int nY, int nWidth, int nHeight )
319 {
320 maRect = tools::Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ),
321 Size( nWidth, nHeight ) );
322 mpImpl = rTexture.mpImpl;
323 mnSlotNumber = rTexture.mnSlotNumber;
324 if (mpImpl)
325 mpImpl->IncreaseRefCount(mnSlotNumber);
326 VCL_GL_INFO( "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
327 }
328
~OpenGLTexture()329 OpenGLTexture::~OpenGLTexture()
330 {
331 if (mpImpl)
332 mpImpl->DecreaseRefCount(mnSlotNumber);
333 }
334
IsUnique() const335 bool OpenGLTexture::IsUnique() const
336 {
337 return !mpImpl || (mpImpl.use_count() == 1);
338 }
339
Id() const340 GLuint OpenGLTexture::Id() const
341 {
342 if (mpImpl)
343 return mpImpl->mnTexture;
344 return 0;
345 }
346
GetWidth() const347 int OpenGLTexture::GetWidth() const
348 {
349 return maRect.GetWidth();
350 }
351
GetHeight() const352 int OpenGLTexture::GetHeight() const
353 {
354 return maRect.GetHeight();
355 }
356
StencilId() const357 GLuint OpenGLTexture::StencilId() const
358 {
359 return mpImpl ? mpImpl->mnOptStencil : 0;
360 }
361
AddStencil()362 GLuint OpenGLTexture::AddStencil()
363 {
364 if (mpImpl)
365 return mpImpl->AddStencil();
366 else
367 return 0;
368 }
369
GetCoord(GLfloat * pCoord,const SalTwoRect & rPosAry,bool bInverted) const370 void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
371 {
372 VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
373
374 if (!IsValid())
375 {
376 pCoord[0] = pCoord[1] = pCoord[2] = pCoord[3] = 0.0f;
377 pCoord[4] = pCoord[5] = pCoord[6] = pCoord[7] = 0.0f;
378 return;
379 }
380
381 pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / static_cast<double>(mpImpl->mnWidth);
382 pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / static_cast<double>(mpImpl->mnWidth);
383
384 if( !bInverted )
385 {
386 pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast<double>(mpImpl->mnHeight);
387 pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast<double>(mpImpl->mnHeight);
388 }
389 else
390 {
391 pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast<double>(mpImpl->mnHeight);
392 pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast<double>(mpImpl->mnHeight);
393 }
394 }
395
GetTextureRect(const SalTwoRect & rPosAry,GLfloat & x1,GLfloat & x2,GLfloat & y1,GLfloat & y2) const396 void OpenGLTexture::GetTextureRect(const SalTwoRect& rPosAry, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const
397 {
398 if (IsValid())
399 {
400 double fTextureWidth(mpImpl->mnWidth);
401 double fTextureHeight(mpImpl->mnHeight);
402
403 x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth;
404 x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth;
405
406 y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
407 y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
408 }
409 }
410
411 template <>
FillCoords(std::vector<GLfloat> & rCoords,const SalTwoRect & rPosAry) const412 void OpenGLTexture::FillCoords<GL_TRIANGLE_FAN>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry) const
413 {
414 GLfloat x1 = 0.0f;
415 GLfloat x2 = 0.0f;
416 GLfloat y1 = 0.0f;
417 GLfloat y2 = 0.0f;
418
419 GetTextureRect(rPosAry, x1, x2, y1, y2);
420
421 rCoords.insert(rCoords.end(), {
422 x1, y2, x1, y1,
423 x2, y1, x2, y2
424 });
425 }
426
427 template <>
FillCoords(std::vector<GLfloat> & rCoords,const SalTwoRect & rPosAry) const428 void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry) const
429 {
430 GLfloat x1 = 0.0f;
431 GLfloat x2 = 0.0f;
432 GLfloat y1 = 0.0f;
433 GLfloat y2 = 0.0f;
434
435 GetTextureRect(rPosAry, x1, x2, y1, y2);
436
437 rCoords.insert(rCoords.end(), {
438 x1, y1, x2, y1, x1, y2,
439 x1, y2, x2, y1, x2, y2
440 });
441 }
442
GetWholeCoord(GLfloat * pCoord) const443 void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
444 {
445 if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
446 {
447 pCoord[0] = pCoord[2] = maRect.Left() / static_cast<double>(mpImpl->mnWidth);
448 pCoord[4] = pCoord[6] = maRect.Right() / static_cast<double>(mpImpl->mnWidth);
449 pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / static_cast<double>(mpImpl->mnHeight);
450 pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / static_cast<double>(mpImpl->mnHeight);
451 }
452 else
453 {
454 pCoord[0] = pCoord[2] = 0;
455 pCoord[4] = pCoord[6] = 1;
456 pCoord[1] = pCoord[7] = 0;
457 pCoord[3] = pCoord[5] = 1;
458 }
459 }
460
GetFilter() const461 GLenum OpenGLTexture::GetFilter() const
462 {
463 if( mpImpl )
464 return mpImpl->mnFilter;
465 return GL_NEAREST;
466 }
467
CopyData(int nWidth,int nHeight,int nFormat,int nType,sal_uInt8 const * pData)468 bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData)
469 {
470 if (!pData || !IsValid())
471 return false;
472
473 int nX = maRect.Left();
474 int nY = maRect.Top();
475
476 return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData);
477 }
478
SetFilter(GLenum nFilter)479 void OpenGLTexture::SetFilter( GLenum nFilter )
480 {
481 if( mpImpl )
482 {
483 mpImpl->mnFilter = nFilter;
484 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
485 CHECK_GL_ERROR();
486 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
487 CHECK_GL_ERROR();
488 }
489 }
490
Bind()491 void OpenGLTexture::Bind()
492 {
493 if (IsValid())
494 {
495 OpenGLContext::getVCLContext()->state().texture().bind(mpImpl->mnTexture);
496 }
497 else
498 VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" );
499
500 CHECK_GL_ERROR();
501 }
502
Unbind()503 void OpenGLTexture::Unbind()
504 {
505 if (IsValid())
506 {
507 OpenGLContext::getVCLContext()->state().texture().unbind(mpImpl->mnTexture);
508 }
509 }
510
SaveToFile(const OUString & rFileName)511 void OpenGLTexture::SaveToFile(const OUString& rFileName)
512 {
513 std::vector<sal_uInt8> aBuffer(GetWidth() * GetHeight() * 4);
514 Read(OpenGLHelper::OptimalBufferFormat(), GL_UNSIGNED_BYTE, aBuffer.data());
515 BitmapEx aBitmap = OpenGLHelper::ConvertBufferToBitmapEx(aBuffer.data(), GetWidth(), GetHeight());
516 try
517 {
518 vcl::PNGWriter aWriter(aBitmap);
519 SvFileStream sOutput(rFileName, StreamMode::WRITE);
520 aWriter.Write(sOutput);
521 sOutput.Close();
522 }
523 catch (...)
524 {
525 SAL_WARN("vcl.opengl", "Error writing png to " << rFileName);
526 }
527 }
528
Read(GLenum nFormat,GLenum nType,sal_uInt8 * pData)529 void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData )
530 {
531 if (!IsValid())
532 {
533 SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
534 return;
535 }
536
537 OpenGLVCLContextZone aContextZone;
538
539 VCL_GL_INFO( "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );
540
541 if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight )
542 {
543 Bind();
544 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
545 CHECK_GL_ERROR();
546 // XXX: Call not available with GLES 2.0
547 glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData );
548 CHECK_GL_ERROR();
549 Unbind();
550 }
551 else
552 {
553 long nWidth = maRect.GetWidth();
554 long nHeight = maRect.GetHeight();
555 long nX = maRect.Left();
556 long nY = mpImpl->mnHeight - maRect.Top() - nHeight;
557
558 // Retrieve current context
559 ImplSVData* pSVData = ImplGetSVData();
560 rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
561 OpenGLFramebuffer* pFramebuffer = pContext->AcquireFramebuffer(*this);
562 glPixelStorei(GL_PACK_ALIGNMENT, 1);
563 CHECK_GL_ERROR();
564 glReadPixels(nX, nY, nWidth, nHeight, nFormat, nType, pData);
565 CHECK_GL_ERROR();
566 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
567 }
568 }
569
operator bool() const570 OpenGLTexture::operator bool() const
571 {
572 return IsValid();
573 }
574
operator =(const OpenGLTexture & rTexture)575 OpenGLTexture& OpenGLTexture::operator=(const OpenGLTexture& rTexture)
576 {
577 OpenGLTexture aTemp(rTexture);
578 *this = std::move(aTemp);
579 return *this;
580 }
581
operator =(OpenGLTexture && rTexture)582 OpenGLTexture& OpenGLTexture::operator=(OpenGLTexture&& rTexture)
583 {
584 if (mpImpl)
585 mpImpl->DecreaseRefCount(mnSlotNumber);
586
587 maRect = rTexture.maRect;
588 mpImpl = std::move(rTexture.mpImpl);
589 mnSlotNumber = rTexture.mnSlotNumber;
590
591 return *this;
592 }
593
operator ==(const OpenGLTexture & rTexture) const594 bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const
595 {
596 return (mpImpl == rTexture.mpImpl
597 && maRect == rTexture.maRect
598 && mnSlotNumber == rTexture.mnSlotNumber);
599 }
600
operator !=(const OpenGLTexture & rTexture) const601 bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const
602 {
603 return !( *this == rTexture );
604 }
605
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
607