Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / opengl / texture.cxx
blob24a7c3852707dfd234d2a0b80c91067dd8e2fa52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <sal/config.h>
21 #include <vcl/opengl/OpenGLContext.hxx>
22 #include <vcl/opengl/OpenGLHelper.hxx>
24 #include "svdata.hxx"
26 #include "vcl/salbtype.hxx"
28 #include "opengl/framebuffer.hxx"
29 #include "opengl/texture.hxx"
31 // texture with allocated size
32 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
33 mnRefCount( 1 ),
34 mnWidth( nWidth ),
35 mnHeight( nHeight ),
36 mnFilter( GL_NEAREST ),
37 mnFreeSlots(-1)
39 glGenTextures( 1, &mnTexture );
40 glBindTexture( GL_TEXTURE_2D, mnTexture );
41 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
42 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
43 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
44 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
45 if( bAllocate )
46 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
47 glBindTexture( GL_TEXTURE_2D, 0 );
49 VCL_GL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" );
51 CHECK_GL_ERROR();
54 // texture with content retrieved from FBO
55 ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
56 mnRefCount( 1 ),
57 mnTexture( 0 ),
58 mnWidth( nWidth ),
59 mnHeight( nHeight ),
60 mnFilter( GL_NEAREST ),
61 mnFreeSlots(-1)
63 // FIXME We need the window height here
64 // nY = GetHeight() - nHeight - nY;
66 glGenTextures( 1, &mnTexture );
67 glBindTexture( GL_TEXTURE_2D, mnTexture );
68 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
69 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
70 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
71 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
72 glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
73 CHECK_GL_ERROR();
74 glBindTexture( GL_TEXTURE_2D, 0 );
76 VCL_GL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY );
78 CHECK_GL_ERROR();
81 // texture from buffer data
82 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ) :
83 mnRefCount( 1 ),
84 mnTexture( 0 ),
85 mnWidth( nWidth ),
86 mnHeight( nHeight ),
87 mnFilter( GL_NEAREST ),
88 mnFreeSlots(-1)
90 if( !mnTexture )
91 glGenTextures( 1, &mnTexture );
92 glBindTexture( GL_TEXTURE_2D, mnTexture );
93 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
94 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
95 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
96 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
97 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
98 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mnWidth, mnHeight, 0, nFormat, nType, pData );
99 glBindTexture( GL_TEXTURE_2D, 0 );
101 VCL_GL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" );
103 CHECK_GL_ERROR();
106 ImplOpenGLTexture::~ImplOpenGLTexture()
108 VCL_GL_INFO( "vcl.opengl", "~OpenGLTexture " << mnTexture );
109 if( mnTexture != 0 )
111 // FIXME: this is really not optimal performance-wise.
113 // Check we have been correctly un-bound from all framebuffers.
114 ImplSVData* pSVData = ImplGetSVData();
115 rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
116 if (pContext.is())
117 pContext->UnbindTextureFromFramebuffers( mnTexture );
119 glDeleteTextures( 1, &mnTexture );
123 bool ImplOpenGLTexture::InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
125 if (!pData || mnTexture == 0)
126 return false;
127 glBindTexture(GL_TEXTURE_2D, mnTexture);
128 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
129 glTexSubImage2D(GL_TEXTURE_2D, 0, nX, mnHeight - nY - nHeight, nWidth, nHeight, nFormat, nType, pData);
130 glBindTexture(GL_TEXTURE_2D, 0);
132 VCL_GL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " Insert buff. to " << nX << " " << nY
133 << " size " << nWidth << "x" << nHeight << " from data" );
134 CHECK_GL_ERROR();
136 return true;
139 bool ImplOpenGLTexture::InitializeSlots(int nSlotSize)
141 if (mpSlotReferences)
142 return false;
144 mpSlotReferences.reset(new std::vector<int>(nSlotSize, 0));
145 mnFreeSlots = nSlotSize;
147 return true;
150 int ImplOpenGLTexture::FindFreeSlot()
152 if (mnFreeSlots > 0 && mpSlotReferences)
154 for (size_t i = 0; i < mpSlotReferences->size(); i++)
156 if (mpSlotReferences->at(i) <= 0)
158 return i;
162 return -1;
165 OpenGLTexture::OpenGLTexture() :
166 maRect( 0, 0, 0, 0 ),
167 mpImpl(NULL),
168 mnSlotNumber(-1)
172 OpenGLTexture::OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber)
173 : maRect(aRectangle)
174 , mpImpl(pImpl)
175 , mnSlotNumber(nSlotNumber)
177 if (mpImpl)
178 mpImpl->IncreaseRefCount(nSlotNumber);
181 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate )
182 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
183 , mnSlotNumber(-1)
185 mpImpl = new ImplOpenGLTexture( nWidth, nHeight, bAllocate );
188 OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight )
189 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
190 , mnSlotNumber(-1)
192 mpImpl = new ImplOpenGLTexture( nX, nY, nWidth, nHeight );
195 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData )
196 : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
197 , mnSlotNumber(-1)
199 mpImpl = new ImplOpenGLTexture( nWidth, nHeight, nFormat, nType, pData );
202 OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture )
204 maRect = rTexture.maRect;
205 mpImpl = rTexture.mpImpl;
206 mnSlotNumber = rTexture.mnSlotNumber;
208 if (mpImpl)
209 mpImpl->IncreaseRefCount(mnSlotNumber);
212 OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
213 int nX, int nY, int nWidth, int nHeight )
215 maRect = Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ),
216 Size( nWidth, nHeight ) );
217 mpImpl = rTexture.mpImpl;
218 mnSlotNumber = rTexture.mnSlotNumber;
219 if (mpImpl)
220 mpImpl->IncreaseRefCount(mnSlotNumber);
221 VCL_GL_INFO( "vcl.opengl", "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
224 OpenGLTexture::~OpenGLTexture()
226 if (mpImpl)
228 mpImpl->DecreaseRefCount(mnSlotNumber);
229 if (!mpImpl->ExistRefs())
230 delete mpImpl;
234 bool OpenGLTexture::IsUnique() const
236 return ( mpImpl == NULL || mpImpl->mnRefCount == 1 );
239 GLuint OpenGLTexture::Id() const
241 if( mpImpl )
242 return mpImpl->mnTexture;
243 return 0;
246 int OpenGLTexture::GetWidth() const
248 return maRect.GetWidth();
251 int OpenGLTexture::GetHeight() const
253 return maRect.GetHeight();
256 void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
258 VCL_GL_INFO( "vcl.opengl", "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
260 if( mpImpl == NULL )
262 pCoord[0] = pCoord[1] = pCoord[2] = pCoord[3] = 0.0f;
263 pCoord[4] = pCoord[5] = pCoord[6] = pCoord[7] = 0.0f;
264 return;
267 pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth;
268 pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth;
270 if( !bInverted )
272 pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
273 pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
275 else
277 pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
278 pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
282 void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
284 if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
286 pCoord[0] = pCoord[2] = maRect.Left() / (double) mpImpl->mnWidth;
287 pCoord[4] = pCoord[6] = maRect.Right() / (double) mpImpl->mnWidth;
288 pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / (double) mpImpl->mnHeight;
289 pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / (double) mpImpl->mnHeight;
291 else
293 pCoord[0] = pCoord[2] = 0;
294 pCoord[4] = pCoord[6] = 1;
295 pCoord[1] = pCoord[7] = 0;
296 pCoord[3] = pCoord[5] = 1;
300 GLenum OpenGLTexture::GetFilter() const
302 if( mpImpl )
303 return mpImpl->mnFilter;
304 return GL_NEAREST;
307 void OpenGLTexture::SetFilter( GLenum nFilter )
309 if( mpImpl )
311 mpImpl->mnFilter = nFilter;
312 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
313 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
316 CHECK_GL_ERROR();
319 void OpenGLTexture::Bind()
321 if( mpImpl )
322 glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
324 CHECK_GL_ERROR();
327 void OpenGLTexture::Unbind()
329 if( mpImpl )
330 glBindTexture( GL_TEXTURE_2D, 0 );
332 CHECK_GL_ERROR();
335 bool OpenGLTexture::Draw()
337 GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
338 GLfloat aTexCoord[8];
340 if( mpImpl == NULL )
342 SAL_WARN( "vcl.opengl", "Can't draw invalid texture" );
343 return false;
346 SAL_INFO( "vcl.opengl", "Drawing texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
348 GetWholeCoord( aTexCoord );
349 glActiveTexture( GL_TEXTURE0 );
350 glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
351 glEnableVertexAttribArray( 0 );
352 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, aPosition );
353 glEnableVertexAttribArray( 1 );
354 glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
355 glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
356 glDisableVertexAttribArray( 0 );
357 glDisableVertexAttribArray( 1 );
358 glBindTexture( GL_TEXTURE_2D, 0 );
360 CHECK_GL_ERROR();
361 return true;
364 void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData )
366 if( mpImpl == NULL )
368 SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
369 return;
372 VCL_GL_INFO( "vcl.opengl", "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );
374 if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight )
376 Bind();
377 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
378 // XXX: Call not available with GLES 2.0
379 glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData );
380 Unbind();
382 else
384 long nWidth = maRect.GetWidth();
385 long nHeight = maRect.GetHeight();
386 long nX = maRect.Left();
387 long nY = mpImpl->mnHeight - maRect.Top() - nHeight;
389 // Retrieve current context
390 ImplSVData* pSVData = ImplGetSVData();
391 rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
392 OpenGLFramebuffer* pFramebuffer = pContext->AcquireFramebuffer(*this);
393 glPixelStorei(GL_PACK_ALIGNMENT, 1);
394 glReadPixels(nX, nY, nWidth, nHeight, nFormat, nType, pData);
395 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
398 CHECK_GL_ERROR();
401 OpenGLTexture::operator bool() const
403 return ( mpImpl != NULL );
406 OpenGLTexture& OpenGLTexture::operator=( const OpenGLTexture& rTexture )
408 if (rTexture.mpImpl)
410 rTexture.mpImpl->IncreaseRefCount(rTexture.mnSlotNumber);
413 if (mpImpl)
415 mpImpl->DecreaseRefCount(mnSlotNumber);
416 if (!mpImpl->ExistRefs())
417 delete mpImpl;
420 maRect = rTexture.maRect;
421 mpImpl = rTexture.mpImpl;
422 mnSlotNumber = rTexture.mnSlotNumber;
424 return *this;
427 bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const
429 return (mpImpl == rTexture.mpImpl
430 && maRect == rTexture.maRect
431 && mnSlotNumber == rTexture.mnSlotNumber);
434 bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const
436 return !( *this == rTexture );
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */