Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / opengl / gdiimpl.cxx
blobb7443ffd6d263db7496ae5a2d9c34eb482b75086
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 <openglgdiimpl.hxx>
21 #include <opengl/framebuffer.hxx>
23 #include <vcl/gradient.hxx>
24 #include <vcl/idle.hxx>
25 #include <salframe.hxx>
26 #include <salvd.hxx>
27 #include <basegfx/matrix/b2dhommatrixtools.hxx>
28 #include <basegfx/polygon/b2dlinegeometry.hxx>
29 #include <basegfx/polygon/b2dpolygontools.hxx>
30 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
31 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
32 #include <basegfx/polygon/b2dtrapezoid.hxx>
33 #include <sal/log.hxx>
35 #include <vcl/opengl/OpenGLHelper.hxx>
36 #include <salgdi.hxx>
37 #include <svdata.hxx>
38 #include <opengl/zone.hxx>
39 #include <opengl/salbmp.hxx>
40 #include <opengl/RenderState.hxx>
41 #include <opengl/VertexUtils.hxx>
42 #include <opengl/BufferObject.hxx>
44 #include <cmath>
45 #include <vector>
47 #include <glm/gtc/type_ptr.hpp>
48 #include <glm/gtx/norm.hpp>
50 #include <stdlib.h>
52 class OpenGLFlushIdle : public Idle
54 OpenGLSalGraphicsImpl *m_pImpl;
55 public:
56 explicit OpenGLFlushIdle( OpenGLSalGraphicsImpl *pImpl )
57 : Idle( "gl idle swap" )
58 , m_pImpl( pImpl )
60 // We don't want to be swapping before we've painted.
61 SetPriority( TaskPriority::POST_PAINT );
64 virtual void Invoke() override
66 m_pImpl->doFlush();
67 Stop();
68 SetPriority(TaskPriority::HIGHEST);
72 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider)
73 : mrParent(rParent)
74 , mpProvider(pProvider)
75 , mpProgram(nullptr)
76 , mpFlush(new OpenGLFlushIdle(this))
77 , mbUseScissor(false)
78 , mbUseStencil(false)
79 , mbXORMode(false)
80 , mbAcquiringOpenGLContext(false)
81 , mnLineColor(SALCOLOR_NONE)
82 , mnFillColor(SALCOLOR_NONE)
83 #ifdef DBG_UTIL
84 , mProgramIsSolidColor(false)
85 #endif
86 , mnDrawCount(0)
87 , mnDrawCountAtFlush(0)
88 , mProgramSolidColor(SALCOLOR_NONE)
89 , mProgramSolidTransparency(0.0)
90 , mpRenderList(new RenderList)
94 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
96 if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount )
97 VCL_GL_INFO( "Destroying un-flushed on-screen graphics" );
99 mpFlush.reset();
101 ReleaseContext();
104 rtl::Reference<OpenGLContext> OpenGLSalGraphicsImpl::GetOpenGLContext()
106 if (mbAcquiringOpenGLContext)
107 return nullptr;
108 mbAcquiringOpenGLContext = true;
109 bool bSuccess = AcquireContext(true);
110 mbAcquiringOpenGLContext = false;
111 if (!bSuccess)
112 return nullptr;
113 return mpContext;
116 bool OpenGLSalGraphicsImpl::AcquireContext( bool bForceCreate )
118 mpContext = OpenGLContext::getVCLContext( false );
120 if( !mpContext.is() && mpWindowContext.is() )
122 mpContext = mpWindowContext;
124 else if( bForceCreate && !IsOffscreen() )
126 mpWindowContext = CreateWinContext();
127 mpContext = mpWindowContext;
130 if( !mpContext.is() )
131 mpContext = OpenGLContext::getVCLContext();
133 return mpContext.is();
136 void OpenGLSalGraphicsImpl::ReleaseContext()
138 mpContext.clear();
141 void OpenGLSalGraphicsImpl::Init()
143 // Our init phase is strange ::Init is called twice for vdevs.
144 // the first time around with a NULL geometry provider.
145 if( !mpProvider )
146 return;
148 // check if we can simply re-use the same context
149 if( mpContext.is() )
151 if( !UseContext( mpContext ) )
152 ReleaseContext();
155 // Always create the offscreen texture
156 if( maOffscreenTex.GetWidth() != GetWidth() ||
157 maOffscreenTex.GetHeight() != GetHeight() )
159 // We don't want to be swapping before we've painted.
160 mpFlush->SetPriority( TaskPriority::POST_PAINT );
162 if( maOffscreenTex && // don't work to release empty textures
163 mpContext.is() ) // valid context
165 mpContext->makeCurrent();
166 mpContext->ReleaseFramebuffer( maOffscreenTex );
168 maOffscreenTex = OpenGLTexture();
169 VCL_GL_INFO("::Init - re-size offscreen texture");
172 if( mpWindowContext.is() )
174 mpWindowContext->reset();
175 mpWindowContext.clear();
179 // Currently only used to get windows ordering right.
180 void OpenGLSalGraphicsImpl::DeInit()
182 VCL_GL_INFO("::DeInit");
184 FlushDeferredDrawing();
186 // tdf#93839:
187 // Our window handles and resources are being free underneath us.
188 // These can be bound into a context, which relies on them. So
189 // let it know. Other eg. VirtualDevice contexts which have
190 // references on and rely on this context continuing to work will
191 // get a shiny new context in AcquireContext:: next PreDraw.
192 if( mpWindowContext.is() )
194 mpWindowContext->reset();
195 mpWindowContext.clear();
197 mpContext.clear();
200 void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt)
202 FlushDeferredDrawing();
204 InitializePreDrawState(eOpt);
207 void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt)
209 OpenGLZone::enter();
211 mnDrawCount++;
213 if( !AcquireContext() )
215 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
216 return;
219 mpContext->makeCurrent();
220 CHECK_GL_ERROR();
222 CheckOffscreenTexture();
223 CHECK_GL_ERROR();
225 mpContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
227 ImplInitClipRegion();
228 CHECK_GL_ERROR();
230 if (eOpt == IMPLEMENT_XOR && mbXORMode)
232 glEnable(GL_COLOR_LOGIC_OP);
233 CHECK_GL_ERROR();
235 glLogicOp(GL_XOR);
236 CHECK_GL_ERROR();
238 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
239 CHECK_GL_ERROR();
243 void OpenGLSalGraphicsImpl::PostDraw()
245 if (mbXORMode)
247 glDisable(GL_COLOR_LOGIC_OP);
248 CHECK_GL_ERROR();
249 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
250 CHECK_GL_ERROR();
253 if( mpProgram )
255 mpProgram->Clean();
256 mpProgram = nullptr;
257 #ifdef DBG_UTIL
258 mProgramIsSolidColor = false;
259 #endif
262 assert (maOffscreenTex);
264 // Always queue the flush.
265 if( !IsOffscreen() )
266 flush();
268 OpenGLZone::leave();
271 void OpenGLSalGraphicsImpl::PostBatchDraw()
273 if (IsOffscreen())
274 return;
276 if (!mpFlush->IsActive())
277 mpFlush->Start();
280 void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset)
282 mpProgram->ApplyMatrix(GetWidth(), GetHeight(), fPixelOffset);
285 void OpenGLSalGraphicsImpl::freeResources()
287 // TODO Delete shaders, programs and textures if not shared
288 if( mpContext.is() && mpContext->isInitialized() )
290 VCL_GL_INFO( "freeResources" );
291 mpContext->makeCurrent();
292 FlushDeferredDrawing();
293 mpContext->ReleaseFramebuffer( maOffscreenTex );
295 ReleaseContext();
298 void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask )
300 mpContext->state().scissor().disable();
301 mpContext->state().stencil().enable();
303 VCL_GL_INFO( "Adding complex clip / stencil" );
304 GLuint nStencil = maOffscreenTex.StencilId();
305 if( nStencil == 0 )
307 nStencil = maOffscreenTex.AddStencil();
308 glFramebufferRenderbuffer(
309 GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
310 GL_RENDERBUFFER, nStencil );
311 CHECK_GL_ERROR();
313 // else - we associated the stencil in
314 // AcquireFrameBuffer / AttachTexture
316 CHECK_GL_ERROR();
317 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
318 CHECK_GL_ERROR();
319 glStencilMask( nMask );
320 CHECK_GL_ERROR();
321 glStencilFunc( GL_NEVER, nMask, 0xFF );
322 CHECK_GL_ERROR();
323 glStencilOp( GL_REPLACE, GL_KEEP, GL_KEEP );
324 CHECK_GL_ERROR();
326 glClear( GL_STENCIL_BUFFER_BIT );
327 CHECK_GL_ERROR();
328 if( UseSolid( Color( 0xFF, 0xFF, 0xFF ) ) )
330 if( rClip.getRegionBand() )
331 DrawRegionBand( *rClip.getRegionBand() );
332 else
333 DrawPolyPolygon( rClip.GetAsB2DPolyPolygon(), true );
336 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
337 CHECK_GL_ERROR();
338 glStencilMask( 0x00 );
339 CHECK_GL_ERROR();
341 mpContext->state().stencil().disable();
344 void OpenGLSalGraphicsImpl::ImplInitClipRegion()
346 // make sure the context has the right clipping set
347 if (maClipRegion != mpContext->maClipRegion)
349 mpContext->maClipRegion = maClipRegion;
350 if (mbUseStencil)
352 ImplSetClipBit(maClipRegion, 0x01);
356 if (mbUseScissor)
358 tools::Rectangle aRect(maClipRegion.GetBoundRect());
359 mpContext->state().scissor().set(aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth(), aRect.GetHeight());
360 mpContext->state().scissor().enable();
362 else
364 mpContext->state().scissor().disable();
367 if (mbUseStencil)
369 glStencilFunc( GL_EQUAL, 1, 0x1 );
370 CHECK_GL_ERROR();
371 mpContext->state().stencil().enable();
373 else
375 mpContext->state().stencil().disable();
379 const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
381 return maClipRegion;
384 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
386 if (maClipRegion == rClip)
388 VCL_GL_INFO("::setClipRegion (no change) " << rClip);
389 return true;
392 FlushDeferredDrawing();
394 VCL_GL_INFO("::setClipRegion " << rClip);
396 maClipRegion = rClip;
398 mbUseStencil = false;
399 mbUseScissor = false;
400 if (maClipRegion.IsRectangle())
401 mbUseScissor = true;
402 else if (!maClipRegion.IsEmpty())
403 mbUseStencil = true;
405 return true;
408 // set the clip region to empty
409 void OpenGLSalGraphicsImpl::ResetClipRegion()
411 if (maClipRegion.IsEmpty())
413 VCL_GL_INFO("::ResetClipRegion (no change) ");
414 return;
417 FlushDeferredDrawing();
419 VCL_GL_INFO("::ResetClipRegion");
421 maClipRegion.SetEmpty();
422 mbUseScissor = false;
423 mbUseStencil = false;
426 // get the depth of the device
427 sal_uInt16 OpenGLSalGraphicsImpl::GetBitCount() const
429 return 32;
432 // get the width of the device
433 long OpenGLSalGraphicsImpl::GetGraphicsWidth() const
435 return GetWidth();
438 // set the line color to transparent (= don't draw lines)
439 void OpenGLSalGraphicsImpl::SetLineColor()
441 if( mnLineColor != SALCOLOR_NONE )
443 mnLineColor = SALCOLOR_NONE;
447 // set the line color to a specific color
448 void OpenGLSalGraphicsImpl::SetLineColor( Color nColor )
450 if( mnLineColor != nColor )
452 mnLineColor = nColor;
456 // set the fill color to transparent (= don't fill)
457 void OpenGLSalGraphicsImpl::SetFillColor()
459 if( mnFillColor != SALCOLOR_NONE )
461 mnFillColor = SALCOLOR_NONE;
465 // set the fill color to a specific color, shapes will be
466 // filled accordingly
467 void OpenGLSalGraphicsImpl::SetFillColor( Color nColor )
469 if( mnFillColor != nColor )
471 mnFillColor = nColor;
475 // enable/disable XOR drawing
476 void OpenGLSalGraphicsImpl::SetXORMode( bool bSet, bool )
478 if (mbXORMode != bSet)
480 FlushDeferredDrawing();
481 mbXORMode = bSet;
485 void OpenGLSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor)
487 switch (nROPColor)
489 case SalROPColor::N0:
490 mnLineColor = Color(0, 0, 0);
491 break;
492 case SalROPColor::N1:
493 mnLineColor = Color(0xff, 0xff, 0xff);
494 break;
495 case SalROPColor::Invert:
496 mnLineColor = Color(0xff, 0xff, 0xff);
497 break;
501 void OpenGLSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor)
503 switch (nROPColor)
505 case SalROPColor::N0:
506 mnFillColor = Color(0, 0, 0);
507 break;
508 case SalROPColor::N1:
509 mnFillColor = Color(0xff, 0xff, 0xff);
510 break;
511 case SalROPColor::Invert:
512 mnFillColor = Color(0xff, 0xff, 0xff);
513 break;
517 void OpenGLSalGraphicsImpl::CheckOffscreenTexture()
519 bool bClearTexture = false;
521 VCL_GL_INFO( "Check Offscreen texture" );
523 // Always create the offscreen texture
524 if( maOffscreenTex )
526 if( maOffscreenTex.GetWidth() != GetWidth() ||
527 maOffscreenTex.GetHeight() != GetHeight() )
529 VCL_GL_INFO( "re-size offscreen texture " << maOffscreenTex.Id() );
530 mpFlush->SetPriority( TaskPriority::POST_PAINT );
531 mpContext->ReleaseFramebuffer( maOffscreenTex );
532 maOffscreenTex = OpenGLTexture();
536 if( !maOffscreenTex )
538 VCL_GL_INFO( "create texture of size "
539 << GetWidth() << " x " << GetHeight() );
540 maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() );
541 bClearTexture = true;
544 if( !maOffscreenTex.IsUnique() )
546 GLfloat fWidth = GetWidth();
547 GLfloat fHeight = GetHeight();
548 SalTwoRect aPosAry(0, 0, fWidth, fHeight, 0,0, fWidth, fHeight);
550 // TODO: lfrb: User GL_ARB_copy_image?
551 OpenGLTexture aNewTex( GetWidth(), GetHeight() );
553 mpContext->state().scissor().disable();
554 mpContext->state().stencil().disable();
556 mpContext->AcquireFramebuffer( aNewTex );
557 DrawTexture( maOffscreenTex, aPosAry );
558 maOffscreenTex = aNewTex;
560 else
562 mpContext->AcquireFramebuffer( maOffscreenTex );
563 CHECK_GL_ERROR();
565 if( bClearTexture )
567 glDrawBuffer( GL_COLOR_ATTACHMENT0 );
568 #if OSL_DEBUG_LEVEL > 0 // lets have some red debugging background.
569 GLfloat const clearColor[4] = { 1.0, 0, 0, 0 };
570 #else
571 GLfloat const clearColor[4] = { 1.0, 1.0, 1.0, 0 };
572 #endif
573 glClearBufferfv( GL_COLOR, 0, clearColor );
574 // FIXME: use glClearTexImage if we have it ?
578 assert( maOffscreenTex );
580 CHECK_GL_ERROR();
583 bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
585 if( mpProgram != nullptr )
586 mpProgram->Clean();
587 mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader, preamble );
588 #ifdef DBG_UTIL
589 mProgramIsSolidColor = false; // UseSolid() will set to true if needed
590 #endif
591 return ( mpProgram != nullptr );
594 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, sal_uInt8 nTransparency )
596 if( nColor == SALCOLOR_NONE )
597 return false;
598 UseSolid();
599 mpProgram->SetColor( "color", nColor, nTransparency );
600 #ifdef DBG_UTIL
601 mProgramIsSolidColor = true;
602 #endif
603 mProgramSolidColor = nColor;
604 mProgramSolidTransparency = nTransparency / 100.0;
606 return true;
609 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, double fTransparency )
611 if( nColor == SALCOLOR_NONE )
612 return false;
613 UseSolid();
614 mpProgram->SetColorf( "color", nColor, fTransparency );
615 #ifdef DBG_UTIL
616 mProgramIsSolidColor = true;
617 #endif
618 mProgramSolidColor = nColor;
619 mProgramSolidTransparency = fTransparency;
620 return true;
623 void OpenGLSalGraphicsImpl::UseSolid()
625 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
626 return;
627 mpProgram->SetShaderType(DrawShaderType::Normal);
630 bool OpenGLSalGraphicsImpl::UseInvert50()
632 return UseProgram( "dumbVertexShader", "invert50FragmentShader" );
635 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor )
637 return UseSolid( nColor, 0.0f );
640 bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags )
642 OpenGLZone aZone;
644 if( ( nFlags & SalInvert::N50 ) ||
645 ( nFlags & SalInvert::TrackFrame ) )
647 // FIXME: Trackframe really should be 2 pix. on/off stipple.
648 if( !UseInvert50() )
649 return false;
650 mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR,
651 GL_ONE_MINUS_SRC_COLOR );
653 else
655 if( !UseSolid( Color( 255, 255, 255 ) ) )
656 return false;
657 mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
659 return true;
662 void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float y2)
664 std::vector<GLfloat> aVertices;
665 std::vector<GLfloat> aExtrusionVectors;
667 OpenGLZone aZone;
669 glm::vec2 aPoint1(x1, y1);
670 glm::vec2 aPoint2(x2, y2);
672 glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1);
673 glm::vec2 aNormal(-aLineVector.y, aLineVector.x);
675 vcl::vertex::addLineSegmentVertices(aVertices, aExtrusionVectors,
676 aPoint1, aNormal, 1.0f,
677 aPoint2, aNormal, 1.0f);
679 ApplyProgramMatrices(0.5f);
680 mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
681 mpProgram->DrawArrays(GL_TRIANGLES, aVertices);
683 CHECK_GL_ERROR();
686 bool OpenGLSalGraphicsImpl::UseLine(Color nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA)
688 if( nColor == SALCOLOR_NONE )
689 return false;
690 UseLine(fLineWidth, bUseAA);
691 mpProgram->SetColorf("color", nColor, fTransparency);
692 #ifdef DBG_UTIL
693 mProgramIsSolidColor = true;
694 #endif
695 mProgramSolidColor = nColor;
696 mProgramSolidTransparency = fTransparency;
697 return true;
700 void OpenGLSalGraphicsImpl::UseLine(GLfloat fLineWidth, bool bUseAA)
702 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
703 return;
704 mpProgram->SetShaderType(DrawShaderType::Line);
705 mpProgram->SetUniform1f("line_width", fLineWidth);
706 // The width of the feather - area we make lineary transparent in VS.
707 // Good AA value is 0.5f, no AA if feather 0.0f
708 mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f);
709 // We need blending or AA won't work correctly
710 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
713 void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA )
715 OpenGLZone aZone;
717 std::vector<GLfloat> aVertices(nPoints * 2);
718 sal_uInt32 i, j;
720 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
722 aVertices[j] = GLfloat(pPtAry[i].mnX);
723 aVertices[j+1] = GLfloat(pPtAry[i].mnY);
726 ApplyProgramMatrices();
727 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
728 mpProgram->SetExtrusionVectors(aExtrusion.data());
729 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
730 CHECK_GL_ERROR();
732 if( !blockAA && mrParent.getAntiAliasB2DDraw())
734 // Make the edges antialiased by drawing the edge lines again with AA.
735 // TODO: If transparent drawing is set up, drawing the lines themselves twice
736 // may be a problem, if that is a real problem, the polygon areas itself needs to be
737 // masked out for this or something.
738 #ifdef DBG_UTIL
739 assert( mProgramIsSolidColor );
740 #endif
741 Color lastSolidColor = mProgramSolidColor;
742 double lastSolidTransparency = mProgramSolidTransparency;
743 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
745 for( i = 0; i < nPoints; ++i )
747 const SalPoint& rPt1 = pPtAry[ i ];
748 const SalPoint& rPt2 = pPtAry[ ( i + 1 ) % nPoints ];
749 DrawLineSegment(rPt1.mnX, rPt1.mnY, rPt2.mnX, rPt2.mnY);
751 UseSolid( lastSolidColor, lastSolidTransparency );
756 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const tools::Polygon& rPolygon, bool blockAA )
758 OpenGLZone aZone;
760 sal_uInt16 nPoints = rPolygon.GetSize() - 1;
761 std::vector<GLfloat> aVertices(nPoints * 2);
762 sal_uInt32 i, j;
764 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
766 const Point& rPt = rPolygon.GetPoint( i );
767 aVertices[j] = GLfloat(rPt.X());
768 aVertices[j+1] = GLfloat(rPt.Y());
771 ApplyProgramMatrices();
772 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
773 mpProgram->SetExtrusionVectors(aExtrusion.data());
774 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
775 CHECK_GL_ERROR();
777 if( !blockAA && mrParent.getAntiAliasB2DDraw())
779 // Make the edges antialiased by drawing the edge lines again with AA.
780 // TODO: If transparent drawing is set up, drawing the lines themselves twice
781 // may be a problem, if that is a real problem, the polygon areas itself needs to be
782 // masked out for this or something.
783 #ifdef DBG_UTIL
784 assert( mProgramIsSolidColor );
785 #endif
786 Color lastSolidColor = mProgramSolidColor;
787 double lastSolidTransparency = mProgramSolidTransparency;
788 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
790 for( i = 0; i < nPoints; ++i )
792 const Point& rPt1 = rPolygon.GetPoint( i );
793 const Point& rPt2 = rPolygon.GetPoint(( i + 1 ) % nPoints );
794 DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
796 UseSolid( lastSolidColor, lastSolidTransparency );
801 void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA )
803 OpenGLZone aZone;
805 const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon();
806 sal_uInt16 nPoints = rPolygon.count();
807 std::vector<GLfloat> aVertices(nPoints * 2);
808 sal_uInt32 i, j;
810 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
812 const basegfx::B2DPoint& rPt = rPolygon.getB2DPoint( i );
813 aVertices[j] = GLfloat(rPt.getX());
814 aVertices[j+1] = GLfloat(rPt.getY());
817 if (!mpProgram)
819 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
820 return;
823 ApplyProgramMatrices();
824 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
825 mpProgram->SetExtrusionVectors(aExtrusion.data());
826 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
827 CHECK_GL_ERROR();
829 if( !blockAA && mrParent.getAntiAliasB2DDraw())
831 // Make the edges antialiased by drawing the edge lines again with AA.
832 // TODO: If transparent drawing is set up, drawing the lines themselves twice
833 // may be a problem, if that is a real problem, the polygon areas itself needs to be
834 // masked out for this or something.
835 #ifdef DBG_UTIL
836 assert( mProgramIsSolidColor );
837 #endif
838 Color lastSolidColor = mProgramSolidColor;
839 double lastSolidTransparency = mProgramSolidTransparency;
840 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
842 for( i = 0; i < nPoints; ++i )
844 const basegfx::B2DPoint& rPt1 = rPolygon.getB2DPoint( i );
845 const basegfx::B2DPoint& rPt2 = rPolygon.getB2DPoint(( i + 1 ) % nPoints );
846 DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
848 UseSolid( lastSolidColor, lastSolidTransparency );
853 void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight )
855 long nX1( nX );
856 long nY1( nY );
857 long nX2( nX + nWidth );
858 long nY2( nY + nHeight );
859 const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 },
860 { nX2, nY1 }, { nX2, nY2 }};
862 DrawConvexPolygon( 4, aPoints, true );
865 void OpenGLSalGraphicsImpl::DrawRect( const tools::Rectangle& rRect )
867 long nX1( rRect.Left() );
868 long nY1( rRect.Top() );
869 long nX2( rRect.Right() );
870 long nY2( rRect.Bottom() );
871 const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 },
872 { nX2, nY1 }, { nX2, nY2 }};
874 DrawConvexPolygon( 4, aPoints, true );
877 void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
879 basegfx::B2DPolygon aPolygon;
881 for( sal_uInt32 i = 0; i < nPoints; i++ )
882 aPolygon.append( basegfx::B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) );
883 aPolygon.setClosed( true );
885 if( basegfx::utils::isConvex( aPolygon ) )
887 if( nPoints > 2 )
888 DrawConvexPolygon( nPoints, pPtAry );
890 else
892 const basegfx::B2DPolyPolygon aPolyPolygon( aPolygon );
893 DrawPolyPolygon( aPolyPolygon );
897 void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA )
899 const basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::utils::solveCrossovers( rPolyPolygon );
900 basegfx::B2DTrapezoidVector aB2DTrapVector;
901 basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aSimplePolyPolygon );
902 // draw tessellation result
903 for(const basegfx::B2DTrapezoid & i : aB2DTrapVector)
904 DrawTrapezoid( i, blockAA );
907 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion )
909 OpenGLZone aZone;
911 RectangleVector aRects;
912 std::vector<GLfloat> aVertices;
913 rRegion.GetRegionRectangles( aRects );
915 if( aRects.empty() )
916 return;
918 #define ADD_VERTICE(pt) \
919 aVertices.push_back(GLfloat(pt.X())); \
920 aVertices.push_back(GLfloat(pt.Y()));
922 for(tools::Rectangle & rRect : aRects)
924 rRect.AdjustBottom(1 );
925 rRect.AdjustRight(1 );
926 ADD_VERTICE( rRect.TopLeft() );
927 ADD_VERTICE( rRect.TopRight() );
928 ADD_VERTICE( rRect.BottomLeft() );
929 ADD_VERTICE( rRect.BottomLeft() );
930 ADD_VERTICE( rRect.TopRight() );
931 ADD_VERTICE( rRect.BottomRight() );
933 #undef ADD_VERTICE
934 std::vector<GLfloat> aExtrusion(aRects.size() * 6 * 3, 0);
935 mpProgram->SetExtrusionVectors(aExtrusion.data());
936 ApplyProgramMatrices();
937 mpProgram->DrawArrays(GL_TRIANGLES, aVertices);
938 CHECK_GL_ERROR();
941 void OpenGLSalGraphicsImpl::DrawTextureRect( const SalTwoRect& rPosAry )
943 OpenGLZone aZone;
945 SAL_INFO("vcl.opengl", "draw texture rect");
947 long nX = rPosAry.mnDestX;
948 long nY = rPosAry.mnDestY;
949 long nWidth = rPosAry.mnDestWidth;
950 long nHeight = rPosAry.mnDestHeight;
952 std::vector<GLfloat> aVertices;
953 aVertices.reserve(8);
954 vcl::vertex::addRectangle<GL_TRIANGLE_FAN>(aVertices, nX, nY, nX + nWidth, nY + nHeight);
956 ApplyProgramMatrices();
957 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
958 CHECK_GL_ERROR();
961 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted )
963 OpenGLZone aZone;
965 SAL_INFO("vcl.opengl", "draw texture");
967 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
968 return;
969 mpProgram->SetShaderType(TextureShaderType::Normal);
970 mpProgram->SetIdentityTransform("transform");
971 mpProgram->SetTexture("texture", rTexture);
973 GLfloat aTexCoord[8];
974 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
975 mpProgram->SetTextureCoord(aTexCoord);
976 mpProgram->SetMaskCoord(aTexCoord);
977 mpProgram->SetAlphaCoord(aTexCoord);
979 DrawTextureRect( rPosAry );
980 mpProgram->Clean();
983 namespace {
985 bool scaleTexture(const rtl::Reference< OpenGLContext > &xContext,
986 OpenGLTexture& rOutTexture, const double& ixscale, const double& iyscale, OpenGLTexture& rTexture)
988 int nWidth = rTexture.GetWidth();
989 int nHeight = rTexture.GetHeight();
990 if (nWidth == 0 || nHeight == 0)
991 return false;
993 int nNewWidth = nWidth / ixscale;
994 int nNewHeight = nHeight / iyscale;
996 OString sUseReducedRegisterVariantDefine;
997 if (xContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters)
998 sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n");
1000 OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", "areaScaleFragmentShader", sUseReducedRegisterVariantDefine);
1001 if (pProgram == nullptr)
1002 return false;
1004 OpenGLTexture aScratchTex(nNewWidth, nNewHeight);
1005 OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aScratchTex);
1007 // From OpenGLSalBitmap::ImplScaleArea().
1008 pProgram->SetUniform1f("xscale", ixscale);
1009 pProgram->SetUniform1f("yscale", iyscale);
1010 pProgram->SetUniform1i("swidth", nWidth);
1011 pProgram->SetUniform1i("sheight", nHeight);
1012 // For converting between <0,nWidth> and <0.0,1.0> coordinate systems.
1013 GLfloat srcCoords[ 8 ];
1014 rTexture.GetWholeCoord( srcCoords );
1015 pProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] );
1016 pProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] );
1017 pProgram->SetUniform1f( "xtopixelratio", nNewWidth / ( srcCoords[ 4 ] - srcCoords[ 0 ] ));
1018 pProgram->SetUniform1f( "ytopixelratio", nNewHeight / ( srcCoords[ 5 ] - srcCoords[ 1 ] ));
1019 pProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1020 pProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1022 pProgram->SetTexture("sampler", rTexture);
1023 pProgram->DrawTexture(rTexture);
1024 pProgram->Clean();
1026 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
1028 CHECK_GL_ERROR();
1030 rOutTexture = aScratchTex;
1031 return true;
1036 void OpenGLSalGraphicsImpl::DrawTransformedTexture(
1037 OpenGLTexture& rTexture,
1038 OpenGLTexture& rMask,
1039 const basegfx::B2DPoint& rNull,
1040 const basegfx::B2DPoint& rX,
1041 const basegfx::B2DPoint& rY )
1043 OpenGLZone aZone;
1045 std::vector<GLfloat> aVertices = {
1046 0, GLfloat(rTexture.GetHeight()),
1047 0, 0,
1048 GLfloat(rTexture.GetWidth()), 0,
1049 GLfloat(rTexture.GetWidth()), GLfloat(rTexture.GetHeight())
1052 GLfloat aTexCoord[8];
1054 const long nDestWidth = basegfx::fround(basegfx::B2DVector(rX - rNull).getLength());
1055 const long nDestHeight = basegfx::fround(basegfx::B2DVector(rY - rNull).getLength());
1057 // Invisibly small images shouldn't divide by zero.
1058 if( nDestHeight == 0 || nDestWidth == 0 )
1059 return;
1061 // inverted scale ratios
1062 double ixscale = rTexture.GetWidth() / double(nDestWidth);
1063 double iyscale = rTexture.GetHeight() / double(nDestHeight);
1065 // If downscaling at a higher scale ratio, use the area scaling algorithm rather
1066 // than plain OpenGL's scaling (texture mapping), for better results.
1067 // See OpenGLSalBitmap::ImplScaleArea().
1068 bool areaScaling = false;
1069 bool fastAreaScaling = false;
1071 OString sUseReducedRegisterVariantDefine;
1072 if (mpContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters)
1073 sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n");
1075 OUString textureFragmentShader;
1076 if( ixscale >= 2 && iyscale >= 2 ) // scale ratio less than 50%
1078 areaScaling = true;
1079 fastAreaScaling = ( ixscale == std::trunc( ixscale ) && iyscale == std::trunc( iyscale ));
1080 // The generic case has arrays only up to 16 ratio downscaling and is performed in 2 passes,
1081 // when the ratio is in the 16-100 range, which is hopefully enough in practice, but protect
1082 // against buffer overflows in case such an extreme case happens (and in such case the precision
1083 // of the generic algorithm probably doesn't matter anyway).
1084 if( ixscale > 100 || iyscale > 100 )
1085 fastAreaScaling = true;
1086 if( fastAreaScaling )
1087 textureFragmentShader = "areaScaleFastFragmentShader";
1088 else
1089 textureFragmentShader = "areaScaleFragmentShader";
1092 OpenGLTexture aInTexture = rTexture;
1093 OpenGLTexture aInMask = rMask;
1095 // When using the area scaling algorithm we need to reduce the texture size in 2 passes
1096 // in order to not use a big array inside the fragment shader.
1097 if (areaScaling && !fastAreaScaling)
1099 // Perform a first texture downscaling by an inverted scale ratio equal to
1100 // the square root of the whole inverted scale ratio.
1101 if (ixscale > 16 || iyscale > 16)
1103 // The scissor area is set to the current window size in PreDraw,
1104 // so if we do not disable the scissor test, the texture produced
1105 // by the first downscaling is clipped to the current window size.
1106 mpContext->state().scissor().disable();
1107 mpContext->state().stencil().disable();
1109 // the square root of the whole inverted scale ratio
1110 double ixscalesqrt = std::floor(std::sqrt(ixscale));
1111 double iyscalesqrt = std::floor(std::sqrt(iyscale));
1112 ixscale /= ixscalesqrt; // second pass inverted x-scale factor
1113 iyscale /= iyscalesqrt; // second pass inverted y-scale factor
1115 scaleTexture(mpContext, aInTexture, ixscalesqrt, iyscalesqrt, rTexture);
1117 if (rMask) // we need to downscale the mask too
1119 scaleTexture(mpContext, aInMask, ixscalesqrt, iyscalesqrt, rMask);
1122 // We need to re-acquire the off-screen texture.
1123 CheckOffscreenTexture();
1124 CHECK_GL_ERROR();
1126 // Re-enable scissor and stencil tests if needed.
1127 if (mbUseScissor)
1128 mpContext->state().scissor().enable();
1130 if (mbUseStencil)
1131 mpContext->state().stencil().enable();
1135 if( aInMask )
1137 if( !UseProgram( "transformedTextureVertexShader",
1138 textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader,
1139 "#define MASKED\n" + sUseReducedRegisterVariantDefine))
1140 return;
1141 mpProgram->SetTexture( "mask", aInMask );
1142 GLfloat aMaskCoord[8];
1143 aInMask.GetWholeCoord(aMaskCoord);
1144 mpProgram->SetMaskCoord(aMaskCoord);
1145 aInMask.SetFilter( GL_LINEAR );
1146 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1148 else
1150 if( !UseProgram( "transformedTextureVertexShader",
1151 textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader,
1152 sUseReducedRegisterVariantDefine))
1153 return;
1156 if(areaScaling)
1158 int nWidth = aInTexture.GetWidth();
1159 int nHeight = aInTexture.GetHeight();
1161 // From OpenGLSalBitmap::ImplScaleArea().
1162 if (fastAreaScaling && nWidth && nHeight)
1164 mpProgram->SetUniform1i( "xscale", ixscale );
1165 mpProgram->SetUniform1i( "yscale", iyscale );
1166 GLfloat srcCoords[ 8 ];
1167 aInTexture.GetWholeCoord( srcCoords );
1168 mpProgram->SetUniform1f( "xstep", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1169 mpProgram->SetUniform1f( "ystep", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1170 mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale ));
1172 else if (nHeight > 1 && nWidth > 1)
1174 mpProgram->SetUniform1f( "xscale", ixscale );
1175 mpProgram->SetUniform1f( "yscale", iyscale );
1176 mpProgram->SetUniform1i( "swidth", nWidth );
1177 mpProgram->SetUniform1i( "sheight", nHeight );
1178 // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
1179 GLfloat srcCoords[ 8 ];
1180 aInTexture.GetWholeCoord( srcCoords );
1181 mpProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] );
1182 mpProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] );
1183 mpProgram->SetUniform1f( "xtopixelratio", ( nWidth / ixscale ) / ( srcCoords[ 4 ] - srcCoords[ 0 ] ));
1184 mpProgram->SetUniform1f( "ytopixelratio", ( nHeight / iyscale ) / ( srcCoords[ 5 ] - srcCoords[ 1 ] ));
1185 mpProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1186 mpProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1190 ApplyProgramMatrices();
1191 mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() );
1192 // Here, in order to get the correct transformation we need to pass the original texture,
1193 // since it has been used for initializing the rectangle vertices.
1194 mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY );
1195 aInTexture.GetWholeCoord(aTexCoord);
1196 mpProgram->SetTexture("sampler", aInTexture);
1197 aInTexture.SetFilter(GL_LINEAR);
1198 mpProgram->SetTextureCoord( aTexCoord );
1199 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
1201 CHECK_GL_ERROR();
1202 mpProgram->Clean();
1205 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool bPremultiplied )
1207 OpenGLZone aZone;
1209 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1210 return;
1211 mpProgram->SetShaderType(TextureShaderType::Normal);
1212 mpProgram->SetIdentityTransform("transform");
1213 mpProgram->SetTexture("texture", rTexture);
1214 mpProgram->SetBlendMode( bPremultiplied ? GL_ONE : GL_SRC_ALPHA,
1215 GL_ONE_MINUS_SRC_ALPHA );
1217 GLfloat aTexCoord[8];
1218 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
1219 mpProgram->SetTextureCoord(aTexCoord);
1220 mpProgram->SetMaskCoord(aTexCoord);
1221 mpProgram->SetAlphaCoord(aTexCoord);
1223 DrawTextureRect( rPosAry );
1224 mpProgram->Clean();
1227 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted )
1229 OpenGLZone aZone;
1231 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1232 return;
1233 mpProgram->SetShaderType(TextureShaderType::Diff);
1234 mpProgram->SetIdentityTransform("transform");
1235 mpProgram->SetTexture( "texture", rTexture );
1236 mpProgram->SetTexture( "mask", rMask );
1237 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1239 GLfloat aTexCoord[8];
1240 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
1241 mpProgram->SetTextureCoord(aTexCoord);
1242 mpProgram->SetAlphaCoord(aTexCoord);
1244 GLfloat aMaskCoord[8];
1245 rMask.GetCoord(aMaskCoord, rPosAry, bInverted);
1246 mpProgram->SetMaskCoord(aMaskCoord);
1248 DrawTextureRect( rPosAry );
1249 mpProgram->Clean();
1252 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry )
1254 OpenGLZone aZone;
1256 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1257 return;
1258 mpProgram->SetShaderType(TextureShaderType::Masked);
1259 mpProgram->SetIdentityTransform("transform");
1260 mpProgram->SetTexture( "texture", rTexture );
1261 mpProgram->SetTexture( "mask", rMask );
1262 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1264 GLfloat aTexCoord[8];
1265 rTexture.GetCoord(aTexCoord, rPosAry);
1266 mpProgram->SetTextureCoord(aTexCoord);
1267 mpProgram->SetAlphaCoord(aTexCoord);
1269 GLfloat aMaskCoord[8];
1270 rMask.GetCoord(aMaskCoord, rPosAry);
1271 mpProgram->SetMaskCoord(aMaskCoord);
1273 DrawTextureRect(rPosAry);
1274 mpProgram->Clean();
1277 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry )
1279 OpenGLZone aZone;
1281 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1282 return;
1283 mpProgram->SetShaderType(TextureShaderType::Blend);
1284 mpProgram->SetTexture( "texture", rTexture );
1285 mpProgram->SetTexture( "mask", rMask );
1286 mpProgram->SetTexture( "alpha", rAlpha );
1288 GLfloat aTexCoord[8];
1289 rTexture.GetCoord(aTexCoord, rPosAry);
1290 mpProgram->SetTextureCoord(aTexCoord);
1292 GLfloat aAlphaCoord[8];
1293 rAlpha.GetCoord(aAlphaCoord, rPosAry);
1294 mpProgram->SetAlphaCoord(aAlphaCoord);
1296 GLfloat aMaskCoord[8];
1297 rMask.GetCoord(aMaskCoord, rPosAry);
1298 mpProgram->SetMaskCoord(aMaskCoord);
1300 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1301 DrawTextureRect( rPosAry );
1302 mpProgram->Clean();
1305 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, Color nMaskColor, const SalTwoRect& rPosAry )
1307 OpenGLZone aZone;
1309 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1310 return;
1311 mpProgram->SetShaderType(TextureShaderType::MaskedColor);
1312 mpProgram->SetIdentityTransform("transform");
1313 mpProgram->SetColor( "color", nMaskColor, 0 );
1314 mpProgram->SetTexture("texture", rMask);
1316 GLfloat aTexCoord[8];
1317 rMask.GetCoord(aTexCoord, rPosAry);
1318 mpProgram->SetTextureCoord(aTexCoord);
1319 mpProgram->SetMaskCoord(aTexCoord);
1320 mpProgram->SetAlphaCoord(aTexCoord);
1322 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1323 DrawTextureRect(rPosAry);
1324 mpProgram->Clean();
1327 void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture const & rTexture, Color aMaskColor, const SalTwoRect& rPosAry)
1329 mpRenderList->addDrawTextureWithMaskColor(rTexture, aMaskColor, rPosAry);
1330 PostBatchDraw();
1333 void OpenGLSalGraphicsImpl::FlushLinesOrTriangles(DrawShaderType eType, RenderParameters const & rParameters)
1335 if (!UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
1336 return;
1338 mpProgram->SetShaderType(eType);
1339 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1340 ApplyProgramMatrices(0.5f);
1342 vcl::VertexBufferObject<Vertex> vbo;
1343 vbo.upload(rParameters.maVertices);
1345 GLuint positionAttrib = SAL_MAX_UINT32;
1346 GLuint colorAttrib = SAL_MAX_UINT32;
1347 GLuint lineDataAttrib = SAL_MAX_UINT32;
1349 mpProgram->SetVertexAttrib(positionAttrib, "position", 2, GL_FLOAT, GL_FALSE,
1350 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
1352 mpProgram->SetVertexAttrib(colorAttrib, "vertex_color_in", 4, GL_FLOAT, GL_FALSE,
1353 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
1355 mpProgram->SetVertexAttrib(lineDataAttrib, "extrusion_vectors", 4, GL_FLOAT, GL_FALSE,
1356 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, lineData)));
1358 vcl::IndexBufferObject ibo;
1359 ibo.upload(rParameters.maIndices);
1360 ibo.bind();
1362 mpProgram->DrawElements(GL_TRIANGLES, rParameters.maIndices.size());
1363 CHECK_GL_ERROR();
1365 mpProgram->Clean();
1368 void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
1370 if (mpRenderList->empty())
1371 return;
1373 VCL_GL_INFO("FlushDeferredDrawing: " << mpRenderList->getEntries().size());
1375 InitializePreDrawState(XOROption::IMPLEMENT_XOR);
1377 OpenGLZone aZone;
1378 for (RenderEntry& rRenderEntry : mpRenderList->getEntries())
1380 if (rRenderEntry.hasTriangles())
1382 RenderParameters& rParameters = rRenderEntry.maTriangleParameters;
1383 VCL_GL_INFO("Flush Triangles: " << rParameters.maVertices.size());
1384 FlushLinesOrTriangles(DrawShaderType::Normal, rParameters);
1386 if (rRenderEntry.hasLines())
1388 RenderParameters& rParameters = rRenderEntry.maLineParameters;
1389 VCL_GL_INFO("Flush Lines: " << rParameters.maVertices.size());
1390 FlushLinesOrTriangles(DrawShaderType::Line, rParameters);
1392 if (rRenderEntry.hasTextures() && UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader", "#define USE_VERTEX_COLORS"))
1394 mpProgram->SetShaderType(TextureShaderType::MaskedColor);
1395 mpProgram->SetIdentityTransform("transform");
1396 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1398 for (auto& rPair : rRenderEntry.maTextureParametersMap)
1400 RenderTextureParameters& rParameters = rPair.second;
1401 mpProgram->SetTexture("texture", rParameters.maTexture);
1402 ApplyProgramMatrices();
1403 mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
1404 mpProgram->SetMaskCoord(rParameters.maTextureCoords.data());
1405 mpProgram->SetAlphaCoord(rParameters.maTextureCoords.data());
1406 mpProgram->SetVertexColors(rParameters.maColors);
1407 mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
1408 CHECK_GL_ERROR();
1410 mpProgram->Clean();
1414 mpRenderList->clear();
1415 PostDraw();
1417 VCL_GL_INFO("End FlushDeferredDrawing");
1420 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1422 OpenGLZone aZone;
1424 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1425 return;
1426 Color aStartCol = rGradient.GetStartColor();
1427 Color aEndCol = rGradient.GetEndColor();
1428 long nFactor = rGradient.GetStartIntensity();
1429 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1430 nFactor = rGradient.GetEndIntensity();
1431 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1433 tools::Rectangle aBoundRect;
1434 Point aCenter;
1435 rGradient.GetBoundRect( rRect, aBoundRect, aCenter );
1436 tools::Polygon aPoly( aBoundRect );
1437 aPoly.Rotate( aCenter, rGradient.GetAngle() % 3600 );
1439 GLfloat aTexCoord[8] = { 0, 1, 1, 1, 1, 0, 0, 0 };
1440 GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
1441 aTexCoord[5] = aTexCoord[7] = fMin;
1442 mpProgram->SetTextureCoord( aTexCoord );
1443 DrawConvexPolygon( aPoly, true );
1446 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1448 OpenGLZone aZone;
1450 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1451 return;
1452 Color aStartCol = rGradient.GetStartColor();
1453 Color aEndCol = rGradient.GetEndColor();
1454 long nFactor = rGradient.GetStartIntensity();
1455 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1456 nFactor = rGradient.GetEndIntensity();
1457 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1460 * Draw two rectangles with linear gradient.
1462 * 1 *---* 2
1463 * | /|
1464 * | / | Points 0 and 3 have start color
1465 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1466 * |\ |
1467 * | \ |
1468 * | \|
1469 * 5 *---* 4
1473 tools::Rectangle aRect;
1474 Point aCenter;
1475 rGradient.GetBoundRect( rRect, aRect, aCenter );
1477 // determine points 0 and 3
1478 Point aPt0( aRect.Left(), (aRect.Top() + aRect.Bottom() + 1) / 2 );
1479 Point aPt3( aRect.Right(), (aRect.Top() + aRect.Bottom() + 1) / 2 );
1481 tools::Polygon aPoly( 7 );
1482 aPoly.SetPoint( aPt0, 0 );
1483 aPoly.SetPoint( aRect.TopLeft(), 1 );
1484 aPoly.SetPoint( aRect.TopRight(), 2 );
1485 aPoly.SetPoint( aPt3, 3 );
1486 aPoly.SetPoint( aRect.BottomRight(), 4 );
1487 aPoly.SetPoint( aRect.BottomLeft(), 5 );
1488 aPoly.SetPoint( aPt0, 6 );
1489 aPoly.Rotate( aCenter, rGradient.GetAngle() % 3600 );
1491 GLfloat aTexCoord[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 };
1492 GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
1493 aTexCoord[3] = aTexCoord[5] = aTexCoord[9] = aTexCoord[11] = fMin;
1494 mpProgram->SetTextureCoord( aTexCoord );
1495 DrawConvexPolygon( aPoly, true );
1498 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1500 OpenGLZone aZone;
1502 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
1503 return;
1504 Color aStartCol = rGradient.GetStartColor();
1505 Color aEndCol = rGradient.GetEndColor();
1506 long nFactor = rGradient.GetStartIntensity();
1507 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1508 nFactor = rGradient.GetEndIntensity();
1509 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1511 tools::Rectangle aRect;
1512 Point aCenter;
1513 rGradient.GetBoundRect( rRect, aRect, aCenter );
1515 // adjust coordinates so that radius has distance equals to 1.0
1516 double fRadius = aRect.GetWidth() / 2.0f;
1517 GLfloat fWidth = rRect.GetWidth() / fRadius;
1518 GLfloat fHeight = rRect.GetHeight() / fRadius;
1519 GLfloat aTexCoord[8] = { 0, 0, 0, fHeight, fWidth, fHeight, fWidth, 0 };
1520 mpProgram->SetTextureCoord( aTexCoord );
1521 mpProgram->SetUniform2f( "center", (aCenter.X() - rRect.Left()) / fRadius,
1522 (aCenter.Y() - rRect.Top()) / fRadius );
1523 DrawRect( rRect );
1526 void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY)
1528 VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
1529 mpRenderList->addDrawPixel(nX, nY, mnLineColor);
1530 PostBatchDraw();
1533 void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor)
1535 VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
1536 mpRenderList->addDrawPixel(nX, nY, nColor);
1537 PostBatchDraw();
1540 void OpenGLSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2)
1542 VCL_GL_INFO("::drawLine (" << nX1 << ", " << nY1 << ") (" << nX2 << ", " << nY2 << ")");
1543 mpRenderList->addDrawLine(nX1, nY1, nX2, nY2, mnLineColor, mrParent.getAntiAliasB2DDraw());
1544 PostBatchDraw();
1547 void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight )
1549 VCL_GL_INFO("::drawRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]");
1550 mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, 0.0, mnLineColor, mnFillColor);
1551 PostBatchDraw();
1554 void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry )
1556 VCL_GL_INFO("::drawPolyLine legacy -> redirecting to drawPolyLine");
1557 basegfx::B2DPolygon aPoly;
1558 aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints);
1559 for (sal_uInt32 i = 1; i < nPoints; ++i)
1560 aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY));
1561 aPoly.setClosed(false);
1563 drawPolyLine(
1564 basegfx::B2DHomMatrix(),
1565 aPoly,
1566 0.0,
1567 basegfx::B2DVector(1.0, 1.0),
1568 basegfx::B2DLineJoin::Miter,
1569 css::drawing::LineCap_BUTT,
1570 basegfx::deg2rad(15.0) /*default*/,
1571 false);
1574 void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
1576 VCL_GL_INFO("::drawPolygon legacy -> redirecting to drawPolyPolygon with transparency");
1577 basegfx::B2DPolygon aPoly;
1578 aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints);
1579 for (sal_uInt32 i = 1; i < nPoints; ++i)
1580 aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY));
1582 drawPolyPolygon(
1583 basegfx::B2DHomMatrix(),
1584 basegfx::B2DPolyPolygon(aPoly),
1585 0.0);
1588 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPointCounts, PCONSTSALPOINT* pPtAry )
1590 VCL_GL_INFO("::drawPolyPolygon legacy -> redirecting to drawPolyPolygon with transparency");
1591 basegfx::B2DPolyPolygon aPolyPoly;
1592 for(sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon)
1594 sal_uInt32 nPoints = pPointCounts[nPolygon];
1595 if (nPoints)
1597 PCONSTSALPOINT pPoints = pPtAry[nPolygon];
1598 basegfx::B2DPolygon aPoly;
1599 aPoly.append( basegfx::B2DPoint(pPoints->mnX, pPoints->mnY), nPoints);
1600 for (sal_uInt32 i = 1; i < nPoints; ++i)
1601 aPoly.setB2DPoint(i, basegfx::B2DPoint( pPoints[i].mnX, pPoints[i].mnY));
1603 aPolyPoly.append(aPoly);
1607 drawPolyPolygon(
1608 basegfx::B2DHomMatrix(),
1609 aPolyPoly,
1610 0.0);
1613 bool OpenGLSalGraphicsImpl::drawPolyPolygon(
1614 const basegfx::B2DHomMatrix& rObjectToDevice,
1615 const basegfx::B2DPolyPolygon& rPolyPolygon,
1616 double fTransparency)
1618 VCL_GL_INFO("::drawPolyPolygon " << rPolyPolygon.getB2DRange());
1620 // Fallback: Transform to DeviceCoordinates
1621 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
1622 aPolyPolygon.transform(rObjectToDevice);
1624 // FlushLinesOrTriangles() works with a 0.5 pixel offset, compensate for that here.
1625 basegfx::B2DHomMatrix aMatrix;
1626 aMatrix.translate(-0.5f, -0.5f);
1627 aPolyPolygon.transform(aMatrix);
1629 mpRenderList->addDrawPolyPolygon(
1630 aPolyPolygon,
1631 fTransparency,
1632 mnLineColor,
1633 mnFillColor,
1634 mrParent.getAntiAliasB2DDraw());
1636 PostBatchDraw();
1637 return true;
1640 bool OpenGLSalGraphicsImpl::drawPolyLine(
1641 const basegfx::B2DHomMatrix& rObjectToDevice,
1642 const basegfx::B2DPolygon& rPolygon,
1643 double fTransparency,
1644 const basegfx::B2DVector& rLineWidth,
1645 basegfx::B2DLineJoin eLineJoin,
1646 css::drawing::LineCap eLineCap,
1647 double fMiterMinimumAngle,
1648 bool bPixelSnapHairline)
1650 VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange());
1652 // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
1653 basegfx::B2DPolygon aPolyLine(rPolygon);
1654 aPolyLine.transform(rObjectToDevice);
1655 if(bPixelSnapHairline) { aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine); }
1656 const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth);
1658 // addDrawPolyLine() assumes that there are no duplicate points in the
1659 // polygon.
1660 // basegfx::B2DPolygon aPolygon(rPolygon);
1661 aPolyLine.removeDoublePoints();
1663 mpRenderList->addDrawPolyLine(
1664 aPolyLine,
1665 fTransparency,
1666 aLineWidth,
1667 eLineJoin,
1668 eLineCap,
1669 fMiterMinimumAngle,
1670 mnLineColor,
1671 mrParent.getAntiAliasB2DDraw());
1673 PostBatchDraw();
1674 return true;
1677 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1678 sal_uInt32 /*nPoints*/,
1679 const SalPoint* /*pPtAry*/,
1680 const PolyFlags* /*pFlgAry*/ )
1682 return false;
1685 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1686 sal_uInt32 /*nPoints*/,
1687 const SalPoint* /*pPtAry*/,
1688 const PolyFlags* /*pFlgAry*/ )
1690 return false;
1693 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1694 sal_uInt32 /*nPoly*/,
1695 const sal_uInt32* /*pPoints*/,
1696 const SalPoint* const* /*pPtAry*/,
1697 const PolyFlags* const* /*pFlgAry*/ )
1699 return false;
1702 // CopyArea --> No RasterOp, but ClipRegion
1703 void OpenGLSalGraphicsImpl::copyArea(
1704 long nDestX, long nDestY,
1705 long nSrcX, long nSrcY,
1706 long nSrcWidth, long nSrcHeight, bool /*bWindowInvalidate*/ )
1708 VCL_GL_INFO( "::copyArea " << nSrcX << "," << nSrcY << " >> " << nDestX << "," << nDestY << " (" << nSrcWidth << "," << nSrcHeight << ")" );
1709 OpenGLTexture aTexture;
1710 SalTwoRect aPosAry(0, 0, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
1712 PreDraw();
1713 // TODO offscreen case
1714 aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight,
1715 nSrcWidth, nSrcHeight );
1716 DrawTexture( aTexture, aPosAry );
1717 PostDraw();
1720 // CopyBits and DrawBitmap --> RasterOp and ClipRegion
1721 // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
1722 void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGraphicsImpl& rImpl )
1724 VCL_GL_INFO( "::copyBits" );
1726 rImpl.FlushDeferredDrawing();
1728 if( !rImpl.maOffscreenTex )
1730 VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size "
1731 << rImpl.GetWidth() << "x" << rImpl.GetHeight() );
1732 return;
1735 if( &rImpl == this &&
1736 (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
1737 (rPosAry.mnSrcHeight == rPosAry.mnDestHeight))
1739 // short circuit if there is nothing to do
1740 if( (rPosAry.mnSrcX == rPosAry.mnDestX) &&
1741 (rPosAry.mnSrcY == rPosAry.mnDestY))
1742 return;
1743 // use copyArea() if source and destination context are identical
1744 copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY,
1745 rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, false/*bWindowInvalidate*/ );
1746 return;
1749 PreDraw();
1750 DrawTexture( rImpl.maOffscreenTex, rPosAry );
1751 PostDraw();
1754 void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
1756 // check that carefully only in the debug mode
1757 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1759 OpenGLZone aZone;
1761 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1762 OpenGLTexture& rTexture = rBitmap.GetTexture();
1764 VCL_GL_INFO( "::drawBitmap" );
1765 PreDraw();
1766 if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth ||
1767 rPosAry.mnSrcHeight != rPosAry.mnDestHeight)
1769 basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY);
1770 basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY);
1771 basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight);
1772 OpenGLTexture mask; // no mask set
1773 DrawTransformedTexture(rTexture, mask, aNull, aX, aY);
1775 else
1777 DrawTexture( rTexture, rPosAry );
1779 PostDraw();
1782 void OpenGLSalGraphicsImpl::drawBitmap(
1783 const SalTwoRect& rPosAry,
1784 const SalBitmap& rSalBitmap,
1785 const SalBitmap& rMaskBitmap )
1787 VCL_GL_INFO("::drawBitmap with MASK -> redirect to ::drawAlphaBitmap");
1788 drawAlphaBitmap(rPosAry, rSalBitmap, rMaskBitmap);
1791 void OpenGLSalGraphicsImpl::drawMask(
1792 const SalTwoRect& rPosAry,
1793 const SalBitmap& rSalBitmap,
1794 Color nMaskColor )
1796 VCL_GL_INFO("::drawMask");
1798 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1799 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1800 mpRenderList->addDrawTextureWithMaskColor(rBitmap.GetTexture(), nMaskColor, rPosAry);
1801 PostBatchDraw();
1804 std::shared_ptr<SalBitmap> OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long nHeight )
1806 FlushDeferredDrawing();
1808 OpenGLZone aZone;
1810 std::shared_ptr<OpenGLSalBitmap> pBitmap(std::make_shared<OpenGLSalBitmap>());
1811 VCL_GL_INFO( "::getBitmap " << nX << "," << nY <<
1812 " " << nWidth << "x" << nHeight );
1813 //TODO really needed?
1814 PreDraw();
1815 pBitmap->Create( maOffscreenTex, nX, nY, nWidth, nHeight );
1816 PostDraw();
1817 return pBitmap;
1820 Color OpenGLSalGraphicsImpl::getPixel( long nX, long nY )
1822 FlushDeferredDrawing();
1824 char pixel[3] = { 0, 0, 0 };
1826 PreDraw( XOROption::IMPLEMENT_XOR );
1827 nY = GetHeight() - nY - 1;
1828 glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
1829 CHECK_GL_ERROR();
1830 PostDraw();
1832 return Color( pixel[0], pixel[1], pixel[2] );
1835 // invert --> ClipRegion (only Windows or VirDevs)
1836 void OpenGLSalGraphicsImpl::invert(
1837 long nX, long nY,
1838 long nWidth, long nHeight,
1839 SalInvert nFlags)
1841 PreDraw();
1843 if( UseInvert( nFlags ) )
1845 if( nFlags & SalInvert::TrackFrame )
1846 { // FIXME: could be more efficient.
1847 DrawRect( nX, nY, nWidth, 1 );
1848 DrawRect( nX, nY + nHeight, nWidth, 1 );
1849 DrawRect( nX, nY, 1, nHeight );
1850 DrawRect( nX + nWidth, nY, 1, nHeight );
1852 else
1853 DrawRect( nX, nY, nWidth, nHeight );
1856 PostDraw();
1859 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags )
1861 PreDraw();
1863 if( UseInvert( nFlags ) )
1865 if (nFlags & SalInvert::TrackFrame)
1867 // Track frame means the invert50FragmentShader must remain active
1868 // (to draw what looks like a dashed line), so DrawLineSegment()
1869 // can't be used. Draw the edge of the polygon as polygons instead.
1870 for (size_t nPoint = 0; nPoint < nPoints; ++nPoint)
1872 const SalPoint& rFrom = pPtAry[nPoint];
1873 const SalPoint& rTo = pPtAry[(nPoint + 1) % nPoints];
1874 if (rFrom.mnX == rTo.mnX)
1876 // Extend to the right, comments assuming "to" is above
1877 // "from":
1878 const SalPoint aPoints[] = { { rFrom.mnX + 1, rFrom.mnY }, // bottom right
1879 { rFrom.mnX, rFrom.mnY }, // bottom left
1880 { rTo.mnX, rTo.mnY }, // top left
1881 { rTo.mnX + 1, rTo.mnY } }; // top right
1882 DrawConvexPolygon(4, aPoints, true);
1884 else
1886 // Otherwise can extend downwards, comments assuming "to"
1887 // is above and on the right of "from":
1888 const SalPoint aPoints[] = { { rFrom.mnX, rFrom.mnY + 1 }, // bottom left
1889 { rFrom.mnX, rFrom.mnY }, // top left
1890 { rTo.mnX, rTo.mnY }, // top right
1891 { rTo.mnX, rTo.mnY + 1 } }; // bottom right
1892 DrawConvexPolygon(4, aPoints, true);
1896 else
1897 DrawPolygon(nPoints, pPtAry);
1900 PostDraw();
1903 bool OpenGLSalGraphicsImpl::drawEPS(
1904 long /*nX*/, long /*nY*/,
1905 long /*nWidth*/, long /*nHeight*/,
1906 void* /*pPtr*/,
1907 sal_uInt32 /*nSize*/ )
1909 return false;
1912 bool OpenGLSalGraphicsImpl::blendBitmap(
1913 const SalTwoRect& rPosAry,
1914 const SalBitmap& rSalBitmap )
1916 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1918 OpenGLZone aZone;
1920 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1921 OpenGLTexture& rTexture( rBitmap.GetTexture() );
1923 VCL_GL_INFO( "::blendBitmap" );
1924 PreDraw();
1926 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1927 return true;
1929 mpProgram->SetShaderType(TextureShaderType::Normal);
1930 mpProgram->SetIdentityTransform("transform");
1931 mpProgram->SetTexture("texture", rTexture);
1933 GLfloat aTexCoord[8];
1934 rTexture.GetCoord(aTexCoord, rPosAry);
1935 mpProgram->SetTextureCoord(aTexCoord);
1936 mpProgram->SetMaskCoord(aTexCoord);
1937 mpProgram->SetAlphaCoord(aTexCoord);
1939 mpProgram->SetBlendMode(GL_ZERO, GL_SRC_COLOR);
1940 DrawTextureRect(rPosAry);
1941 mpProgram->Clean();
1943 PostDraw();
1944 return true;
1947 bool OpenGLSalGraphicsImpl::blendAlphaBitmap(
1948 const SalTwoRect& rPosAry,
1949 const SalBitmap& rSalSrcBitmap,
1950 const SalBitmap& rSalMaskBitmap,
1951 const SalBitmap& rSalAlphaBitmap )
1953 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalSrcBitmap));
1954 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalMaskBitmap));
1955 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalAlphaBitmap));
1957 OpenGLZone aZone;
1959 const OpenGLSalBitmap& rSrcBitmap = static_cast<const OpenGLSalBitmap&>(rSalSrcBitmap);
1960 const OpenGLSalBitmap& rMaskBitmap = static_cast<const OpenGLSalBitmap&>(rSalMaskBitmap);
1961 const OpenGLSalBitmap& rAlphaBitmap = static_cast<const OpenGLSalBitmap&>(rSalAlphaBitmap);
1962 OpenGLTexture& rTexture( rSrcBitmap.GetTexture() );
1963 OpenGLTexture& rMask( rMaskBitmap.GetTexture() );
1964 OpenGLTexture& rAlpha( rAlphaBitmap.GetTexture() );
1966 VCL_GL_INFO( "::blendAlphaBitmap" );
1967 PreDraw();
1968 DrawBlendedTexture( rTexture, rMask, rAlpha, rPosAry );
1969 PostDraw();
1970 return true;
1973 /** Render bitmap with alpha channel
1975 @param rSourceBitmap
1976 Source bitmap to blit
1978 @param rAlphaBitmap
1979 Alpha channel to use for blitting
1981 @return true, if the operation succeeded, and false
1982 otherwise. In this case, clients should try to emulate alpha
1983 compositing themselves
1985 bool OpenGLSalGraphicsImpl::drawAlphaBitmap(
1986 const SalTwoRect& rPosAry,
1987 const SalBitmap& rSalBitmap,
1988 const SalBitmap& rAlphaBitmap )
1990 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1991 assert(dynamic_cast<const OpenGLSalBitmap*>(&rAlphaBitmap));
1993 OpenGLZone aZone;
1995 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1996 const OpenGLSalBitmap& rAlpha = static_cast<const OpenGLSalBitmap&>(rAlphaBitmap);
1997 OpenGLTexture& rTexture(rBitmap.GetTexture());
1998 OpenGLTexture& rAlphaTexture(rAlpha.GetTexture());
2000 VCL_GL_INFO( "::drawAlphaBitmap" );
2001 PreDraw();
2003 if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth ||
2004 rPosAry.mnSrcHeight != rPosAry.mnDestHeight)
2006 basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY);
2007 basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY);
2008 basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight);
2009 DrawTransformedTexture(rTexture, rAlphaTexture, aNull, aX, aY);
2011 else
2013 DrawTextureWithMask( rTexture, rAlphaTexture, rPosAry );
2016 PostDraw();
2017 return true;
2020 /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
2021 bool OpenGLSalGraphicsImpl::drawTransformedBitmap(
2022 const basegfx::B2DPoint& rNull,
2023 const basegfx::B2DPoint& rX,
2024 const basegfx::B2DPoint& rY,
2025 const SalBitmap& rSrcBitmap,
2026 const SalBitmap* pAlphaBitmap)
2028 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSrcBitmap));
2029 assert(!pAlphaBitmap || dynamic_cast<const OpenGLSalBitmap*>(pAlphaBitmap));
2031 OpenGLZone aZone;
2033 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSrcBitmap);
2034 const OpenGLSalBitmap* pMaskBitmap = static_cast<const OpenGLSalBitmap*>(pAlphaBitmap);
2035 OpenGLTexture& rTexture( rBitmap.GetTexture() );
2036 OpenGLTexture aMask; // no texture
2038 if( pMaskBitmap != nullptr )
2039 aMask = pMaskBitmap->GetTexture();
2041 VCL_GL_INFO( "::drawTransformedBitmap" );
2042 PreDraw();
2043 DrawTransformedTexture( rTexture, aMask, rNull, rX, rY );
2044 PostDraw();
2046 return true;
2049 /** Render solid rectangle with given transparency
2051 @param nTransparency
2052 Transparency value (0-255) to use. 0 blits and opaque, 255 a
2053 fully transparent rectangle
2055 bool OpenGLSalGraphicsImpl::drawAlphaRect(
2056 long nX, long nY,
2057 long nWidth, long nHeight,
2058 sal_uInt8 nTransparency )
2060 VCL_GL_INFO("::drawAlphaRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]");
2061 mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, nTransparency / 100.0, mnLineColor, mnFillColor);
2062 PostBatchDraw();
2063 return true;
2066 bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
2067 const Gradient& rGradient)
2069 tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
2071 VCL_GL_INFO("::drawGradient " << rPolyPoly.GetBoundRect());
2073 if (aBoundRect.IsEmpty())
2075 VCL_GL_INFO("::drawGradient nothing to draw");
2076 return true;
2079 if (rGradient.GetStyle() != GradientStyle::Linear &&
2080 rGradient.GetStyle() != GradientStyle::Axial &&
2081 rGradient.GetStyle() != GradientStyle::Radial )
2083 VCL_GL_INFO("::drawGradient unsupported gradient type");
2084 return false;
2087 aBoundRect.AdjustLeft( -1 );
2088 aBoundRect.AdjustTop( -1 );
2089 aBoundRect.AdjustRight( 1 );
2090 aBoundRect.AdjustBottom( 1 );
2092 PreDraw( XOROption::IMPLEMENT_XOR );
2094 #define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0
2095 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2096 ImplSetClipBit( vcl::Region( rPolyPoly ), 0x02 );
2097 if( mbUseStencil )
2099 mpContext->state().stencil().enable();
2100 CHECK_GL_ERROR();
2101 glStencilFunc( GL_EQUAL, 3, 0xFF );
2102 CHECK_GL_ERROR();
2104 else
2106 mpContext->state().stencil().enable();
2107 CHECK_GL_ERROR();
2108 glStencilFunc( GL_EQUAL, 2, 0xFF );
2109 CHECK_GL_ERROR();
2111 #endif
2113 // if border >= 100%, draw solid rectangle with start color
2114 if (rGradient.GetBorder() >= 100.0)
2116 VCL_GL_INFO("::drawGradient -> DrawRect (no gradient)");
2118 Color aColor = rGradient.GetStartColor();
2119 long nIntensity = rGradient.GetStartIntensity();
2120 if (UseSolid(Color(aColor.GetRed() * nIntensity / 100.0,
2121 aColor.GetGreen()* nIntensity / 100.0,
2122 aColor.GetBlue() * nIntensity / 100.0)))
2124 DrawRect(aBoundRect);
2127 else if (rGradient.GetStyle() == GradientStyle::Linear)
2129 VCL_GL_INFO("::drawGradient -> DrawLinearGradient");
2130 DrawLinearGradient(rGradient, aBoundRect);
2132 else if (rGradient.GetStyle() == GradientStyle::Axial)
2134 VCL_GL_INFO("::drawGradient -> DrawAxialGradient");
2135 DrawAxialGradient(rGradient, aBoundRect);
2137 else if (rGradient.GetStyle() == GradientStyle::Radial)
2139 VCL_GL_INFO("::drawGradient -> DrawRadialGradient");
2140 DrawRadialGradient(rGradient, aBoundRect);
2143 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2144 if( !mbUseStencil )
2146 mpContext->state().stencil().disable();
2147 CHECK_GL_ERROR();
2149 #endif
2150 PostDraw();
2152 return true;
2155 void OpenGLSalGraphicsImpl::flush()
2157 FlushDeferredDrawing();
2159 if( IsOffscreen() )
2160 return;
2162 if( !Application::IsInExecute() )
2164 // otherwise nothing would trigger idle rendering
2165 doFlush();
2167 else if( !mpFlush->IsActive() )
2168 mpFlush->Start();
2171 void OpenGLSalGraphicsImpl::doFlush()
2173 FlushDeferredDrawing();
2175 if (OpenGLContext::hasCurrent())
2177 mpContext->state().scissor().disable();
2178 mpContext->state().stencil().disable();
2181 if( IsOffscreen() )
2182 return;
2184 if( !maOffscreenTex )
2186 VCL_GL_INFO( "doFlush - odd no texture !" );
2187 return;
2190 if( mnDrawCountAtFlush == mnDrawCount )
2192 VCL_GL_INFO( "eliding redundant doFlush, no drawing since last!" );
2193 return;
2196 mnDrawCountAtFlush = mnDrawCount;
2198 OpenGLZone aZone;
2200 VCL_GL_INFO( "doFlush" );
2202 if( !mpWindowContext.is() )
2204 // ensure everything is released from the old context.
2205 OpenGLContext::clearCurrent();
2206 mpWindowContext = CreateWinContext();
2207 VCL_GL_INFO( "late creation of window context" );
2210 assert( mpWindowContext.is() );
2212 if( !mpWindowContext.is() )
2214 // failed to create a GL context for this window:
2215 // eg. mis-matching pixel formats, underlying window
2216 // resource lifecycle, etc.
2217 VCL_GL_INFO( "Failed to create window context" );
2218 return;
2221 // Interesting ! -> this destroys a context [ somehow ] ...
2222 mpWindowContext->makeCurrent();
2223 CHECK_GL_ERROR();
2225 VCL_GL_INFO( "doFlush - acquire default framebuffer" );
2227 mpWindowContext->AcquireDefaultFramebuffer();
2229 CHECK_GL_ERROR();
2231 mpWindowContext->state().sync();
2232 mpWindowContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
2233 mpWindowContext->state().scissor().disable();
2234 mpWindowContext->state().stencil().disable();
2236 #if OSL_DEBUG_LEVEL > 0 // random background glClear
2237 glClearColor(static_cast<float>(double(rand())/RAND_MAX),
2238 static_cast<float>(double(rand())/RAND_MAX),
2239 static_cast<float>(double(rand())/RAND_MAX), 1.0);
2240 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
2241 CHECK_GL_ERROR();
2242 #endif
2244 VCL_GL_INFO( "Texture height " << maOffscreenTex.GetHeight() << " vs. window height " << GetHeight() );
2246 OpenGLFramebuffer* pFrameBuffer = mpWindowContext->AcquireFramebuffer(maOffscreenTex);
2247 CHECK_GL_ERROR();
2248 if (pFrameBuffer)
2250 OpenGLFramebuffer::Unbind(GL_DRAW_FRAMEBUFFER);
2251 pFrameBuffer->Bind(GL_READ_FRAMEBUFFER);
2253 glBlitFramebuffer(0, 0, GetWidth(), GetHeight(),
2254 0, 0, GetWidth(), GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
2255 CHECK_GL_ERROR();
2257 pFrameBuffer->Bind();
2260 static bool bNoSwap = getenv("SAL_GL_NO_SWAP");
2261 if (!bNoSwap)
2262 mpWindowContext->swapBuffers();
2264 VCL_GL_INFO( "doFlush - end." );
2267 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */