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 .
20 #include <sal/config.h>
21 #include <vcl/opengl/OpenGLContext.hxx>
22 #include <vcl/opengl/OpenGLHelper.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
) :
36 mnFilter( GL_NEAREST
),
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
);
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" );
54 // texture with content retrieved from FBO
55 ImplOpenGLTexture::ImplOpenGLTexture( int nX
, int nY
, int nWidth
, int nHeight
) :
60 mnFilter( GL_NEAREST
),
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 );
74 glBindTexture( GL_TEXTURE_2D
, 0 );
76 VCL_GL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture
<< " " << nWidth
<< "x" << nHeight
<< " from x" << nX
<< ", y" << nY
);
81 // texture from buffer data
82 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth
, int nHeight
, int nFormat
, int nType
, void const * pData
) :
87 mnFilter( GL_NEAREST
),
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" );
106 ImplOpenGLTexture::~ImplOpenGLTexture()
108 VCL_GL_INFO( "vcl.opengl", "~OpenGLTexture " << mnTexture
);
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
;
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)
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" );
139 bool ImplOpenGLTexture::InitializeSlots(int nSlotSize
)
141 if (mpSlotReferences
)
144 mpSlotReferences
.reset(new std::vector
<int>(nSlotSize
, 0));
145 mnFreeSlots
= nSlotSize
;
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)
165 OpenGLTexture::OpenGLTexture() :
166 maRect( 0, 0, 0, 0 ),
172 OpenGLTexture::OpenGLTexture(ImplOpenGLTexture
* pImpl
, Rectangle aRectangle
, int nSlotNumber
)
175 , mnSlotNumber(nSlotNumber
)
178 mpImpl
->IncreaseRefCount(nSlotNumber
);
181 OpenGLTexture::OpenGLTexture( int nWidth
, int nHeight
, bool bAllocate
)
182 : maRect( Point( 0, 0 ), Size( nWidth
, nHeight
) )
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
) )
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
) )
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
;
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
;
220 mpImpl
->IncreaseRefCount(mnSlotNumber
);
221 VCL_GL_INFO( "vcl.opengl", "Copying texture " << Id() << " [" << maRect
.Left() << "," << maRect
.Top() << "] " << GetWidth() << "x" << GetHeight() );
224 OpenGLTexture::~OpenGLTexture()
228 mpImpl
->DecreaseRefCount(mnSlotNumber
);
229 if (!mpImpl
->ExistRefs())
234 bool OpenGLTexture::IsUnique() const
236 return ( mpImpl
== NULL
|| mpImpl
->mnRefCount
== 1 );
239 GLuint
OpenGLTexture::Id() const
242 return mpImpl
->mnTexture
;
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() );
262 pCoord
[0] = pCoord
[1] = pCoord
[2] = pCoord
[3] = 0.0f
;
263 pCoord
[4] = pCoord
[5] = pCoord
[6] = pCoord
[7] = 0.0f
;
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
;
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
;
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
;
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
303 return mpImpl
->mnFilter
;
307 void OpenGLTexture::SetFilter( GLenum nFilter
)
311 mpImpl
->mnFilter
= nFilter
;
312 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, nFilter
);
313 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, nFilter
);
319 void OpenGLTexture::Bind()
322 glBindTexture( GL_TEXTURE_2D
, mpImpl
->mnTexture
);
327 void OpenGLTexture::Unbind()
330 glBindTexture( GL_TEXTURE_2D
, 0 );
335 bool OpenGLTexture::Draw()
337 GLfloat aPosition
[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
338 GLfloat aTexCoord
[8];
342 SAL_WARN( "vcl.opengl", "Can't draw invalid texture" );
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 );
364 void OpenGLTexture::Read( GLenum nFormat
, GLenum nType
, sal_uInt8
* pData
)
368 SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
372 VCL_GL_INFO( "vcl.opengl", "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );
374 if( GetWidth() == mpImpl
->mnWidth
&& GetHeight() == mpImpl
->mnHeight
)
377 glPixelStorei( GL_PACK_ALIGNMENT
, 1 );
378 // XXX: Call not available with GLES 2.0
379 glGetTexImage( GL_TEXTURE_2D
, 0, nFormat
, nType
, pData
);
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
);
401 OpenGLTexture::operator bool() const
403 return ( mpImpl
!= NULL
);
406 OpenGLTexture
& OpenGLTexture::operator=( const OpenGLTexture
& rTexture
)
410 rTexture
.mpImpl
->IncreaseRefCount(rTexture
.mnSlotNumber
);
415 mpImpl
->DecreaseRefCount(mnSlotNumber
);
416 if (!mpImpl
->ExistRefs())
420 maRect
= rTexture
.maRect
;
421 mpImpl
= rTexture
.mpImpl
;
422 mnSlotNumber
= rTexture
.mnSlotNumber
;
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: */