Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / vcl / opengl / gdiimpl.cxx
blob6329cb92301c07b35734a9480d2db2d98b17b573
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 <opengl/gdiimpl.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/b2dpolypolygontools.hxx>
31 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
32 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
33 #include <basegfx/polygon/b2dtrapezoid.hxx>
34 #include <sal/log.hxx>
36 #include <vcl/opengl/OpenGLHelper.hxx>
37 #include <salgdi.hxx>
38 #include <svdata.hxx>
39 #include <opengl/zone.hxx>
40 #include <opengl/salbmp.hxx>
41 #include <opengl/RenderState.hxx>
42 #include <opengl/VertexUtils.hxx>
43 #include <opengl/BufferObject.hxx>
45 #include <cmath>
46 #include <vector>
47 #include <numeric>
49 #include <glm/gtc/type_ptr.hpp>
50 #include <glm/gtx/norm.hpp>
52 #include <stdlib.h>
54 class OpenGLFlushIdle : public Idle
56 OpenGLSalGraphicsImpl *m_pImpl;
57 public:
58 explicit OpenGLFlushIdle( OpenGLSalGraphicsImpl *pImpl )
59 : Idle( "gl idle swap" )
60 , m_pImpl( pImpl )
62 // We don't want to be swapping before we've painted.
63 SetPriority( TaskPriority::POST_PAINT );
66 virtual void Invoke() override
68 m_pImpl->doFlush();
69 Stop();
70 SetPriority(TaskPriority::HIGHEST);
74 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider)
75 : mrParent(rParent)
76 , mpProvider(pProvider)
77 , mpProgram(nullptr)
78 , mpFlush(new OpenGLFlushIdle(this))
79 , mbUseScissor(false)
80 , mbUseStencil(false)
81 , mbXORMode(false)
82 , mbAcquiringOpenGLContext(false)
83 , mnLineColor(SALCOLOR_NONE)
84 , mnFillColor(SALCOLOR_NONE)
85 #ifdef DBG_UTIL
86 , mProgramIsSolidColor(false)
87 #endif
88 , mnDrawCount(0)
89 , mnDrawCountAtFlush(0)
90 , mProgramSolidColor(SALCOLOR_NONE)
91 , mProgramSolidTransparency(0.0)
92 , mpRenderList(new RenderList)
96 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
98 if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount )
99 VCL_GL_INFO( "Destroying un-flushed on-screen graphics" );
101 mpFlush.reset();
103 ReleaseContext();
106 rtl::Reference<OpenGLContext> OpenGLSalGraphicsImpl::GetOpenGLContext()
108 if (mbAcquiringOpenGLContext)
109 return nullptr;
110 mbAcquiringOpenGLContext = true;
111 bool bSuccess = AcquireContext(true);
112 mbAcquiringOpenGLContext = false;
113 if (!bSuccess)
114 return nullptr;
115 return mpContext;
118 bool OpenGLSalGraphicsImpl::AcquireContext( bool bForceCreate )
120 mpContext = OpenGLContext::getVCLContext( false );
122 if( !mpContext.is() && mpWindowContext.is() )
124 mpContext = mpWindowContext;
126 else if( bForceCreate && !IsOffscreen() )
128 mpWindowContext = CreateWinContext();
129 mpContext = mpWindowContext;
132 if( !mpContext.is() )
133 mpContext = OpenGLContext::getVCLContext();
135 return mpContext.is();
138 void OpenGLSalGraphicsImpl::ReleaseContext()
140 mpContext.clear();
143 void OpenGLSalGraphicsImpl::Init()
145 // Our init phase is strange ::Init is called twice for vdevs.
146 // the first time around with a NULL geometry provider.
147 if( !mpProvider )
148 return;
150 // check if we can simply re-use the same context
151 if( mpContext.is() )
153 if( !UseContext( mpContext ) )
154 ReleaseContext();
157 // Always create the offscreen texture
158 if( maOffscreenTex.GetWidth() != GetWidth() ||
159 maOffscreenTex.GetHeight() != GetHeight() )
161 // We don't want to be swapping before we've painted.
162 mpFlush->SetPriority( TaskPriority::POST_PAINT );
164 if( maOffscreenTex && // don't work to release empty textures
165 mpContext.is() ) // valid context
167 mpContext->makeCurrent();
168 mpContext->ReleaseFramebuffer( maOffscreenTex );
170 maOffscreenTex = OpenGLTexture();
171 VCL_GL_INFO("::Init - re-size offscreen texture");
174 if( mpWindowContext.is() )
176 mpWindowContext->reset();
177 mpWindowContext.clear();
181 // Currently only used to get windows ordering right.
182 void OpenGLSalGraphicsImpl::DeInit()
184 VCL_GL_INFO("::DeInit");
186 FlushDeferredDrawing();
188 // tdf#93839:
189 // Our window handles and resources are being free underneath us.
190 // These can be bound into a context, which relies on them. So
191 // let it know. Other eg. VirtualDevice contexts which have
192 // references on and rely on this context continuing to work will
193 // get a shiny new context in AcquireContext:: next PreDraw.
194 if( mpWindowContext.is() )
196 mpWindowContext->reset();
197 mpWindowContext.clear();
199 mpContext.clear();
202 void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt)
204 FlushDeferredDrawing();
206 InitializePreDrawState(eOpt);
209 void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt)
211 OpenGLZone::enter();
213 mnDrawCount++;
215 if( !AcquireContext() )
217 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
218 return;
221 mpContext->makeCurrent();
222 CHECK_GL_ERROR();
224 CheckOffscreenTexture();
225 CHECK_GL_ERROR();
227 mpContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
229 ImplInitClipRegion();
230 CHECK_GL_ERROR();
232 if (eOpt == IMPLEMENT_XOR && mbXORMode)
234 glEnable(GL_COLOR_LOGIC_OP);
235 CHECK_GL_ERROR();
237 glLogicOp(GL_XOR);
238 CHECK_GL_ERROR();
240 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
241 CHECK_GL_ERROR();
245 void OpenGLSalGraphicsImpl::PostDraw()
247 if (mbXORMode)
249 glDisable(GL_COLOR_LOGIC_OP);
250 CHECK_GL_ERROR();
251 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
252 CHECK_GL_ERROR();
255 if( mpProgram )
257 mpProgram->Clean();
258 mpProgram = nullptr;
259 #ifdef DBG_UTIL
260 mProgramIsSolidColor = false;
261 #endif
264 assert (maOffscreenTex);
266 // Always queue the flush.
267 if( !IsOffscreen() )
268 flush();
270 OpenGLZone::leave();
273 void OpenGLSalGraphicsImpl::PostBatchDraw()
275 if (IsOffscreen())
276 return;
278 if (!mpFlush->IsActive())
279 mpFlush->Start();
282 void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset)
284 mpProgram->ApplyMatrix(GetWidth(), GetHeight(), fPixelOffset);
287 void OpenGLSalGraphicsImpl::freeResources()
289 // TODO Delete shaders, programs and textures if not shared
290 if( mpContext.is() && mpContext->isInitialized() )
292 VCL_GL_INFO( "freeResources" );
293 mpContext->makeCurrent();
294 FlushDeferredDrawing();
295 mpContext->ReleaseFramebuffer( maOffscreenTex );
297 ReleaseContext();
300 void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask )
302 mpContext->state().scissor().disable();
303 mpContext->state().stencil().enable();
305 VCL_GL_INFO( "Adding complex clip / stencil" );
306 GLuint nStencil = maOffscreenTex.StencilId();
307 if( nStencil == 0 )
309 nStencil = maOffscreenTex.AddStencil();
310 glFramebufferRenderbuffer(
311 GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
312 GL_RENDERBUFFER, nStencil );
313 CHECK_GL_ERROR();
315 // else - we associated the stencil in
316 // AcquireFrameBuffer / AttachTexture
318 CHECK_GL_ERROR();
319 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
320 CHECK_GL_ERROR();
321 glStencilMask( nMask );
322 CHECK_GL_ERROR();
323 glStencilFunc( GL_NEVER, nMask, 0xFF );
324 CHECK_GL_ERROR();
325 glStencilOp( GL_REPLACE, GL_KEEP, GL_KEEP );
326 CHECK_GL_ERROR();
328 glClear( GL_STENCIL_BUFFER_BIT );
329 CHECK_GL_ERROR();
330 if( UseSolid( Color( 0xFF, 0xFF, 0xFF ) ) )
332 if( rClip.getRegionBand() )
333 DrawRegionBand( *rClip.getRegionBand() );
334 else
335 DrawPolyPolygon( rClip.GetAsB2DPolyPolygon(), true );
338 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
339 CHECK_GL_ERROR();
340 glStencilMask( 0x00 );
341 CHECK_GL_ERROR();
343 mpContext->state().stencil().disable();
346 void OpenGLSalGraphicsImpl::ImplInitClipRegion()
348 // make sure the context has the right clipping set
349 if (maClipRegion != mpContext->maClipRegion)
351 mpContext->maClipRegion = maClipRegion;
352 if (mbUseStencil)
354 ImplSetClipBit(maClipRegion, 0x01);
358 if (mbUseScissor)
360 tools::Rectangle aRect(maClipRegion.GetBoundRect());
361 mpContext->state().scissor().set(aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth(), aRect.GetHeight());
362 mpContext->state().scissor().enable();
364 else
366 mpContext->state().scissor().disable();
369 if (mbUseStencil)
371 glStencilFunc( GL_EQUAL, 1, 0x1 );
372 CHECK_GL_ERROR();
373 mpContext->state().stencil().enable();
375 else
377 mpContext->state().stencil().disable();
381 const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
383 return maClipRegion;
386 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
388 if (maClipRegion == rClip)
390 VCL_GL_INFO("::setClipRegion (no change) " << rClip);
391 return true;
394 FlushDeferredDrawing();
396 VCL_GL_INFO("::setClipRegion " << rClip);
398 maClipRegion = rClip;
400 mbUseStencil = false;
401 mbUseScissor = false;
402 if (maClipRegion.IsRectangle())
403 mbUseScissor = true;
404 else if (!maClipRegion.IsEmpty())
405 mbUseStencil = true;
407 return true;
410 // set the clip region to empty
411 void OpenGLSalGraphicsImpl::ResetClipRegion()
413 if (maClipRegion.IsEmpty())
415 VCL_GL_INFO("::ResetClipRegion (no change) ");
416 return;
419 FlushDeferredDrawing();
421 VCL_GL_INFO("::ResetClipRegion");
423 maClipRegion.SetEmpty();
424 mbUseScissor = false;
425 mbUseStencil = false;
428 // get the depth of the device
429 sal_uInt16 OpenGLSalGraphicsImpl::GetBitCount() const
431 return 32;
434 // get the width of the device
435 tools::Long OpenGLSalGraphicsImpl::GetGraphicsWidth() const
437 return GetWidth();
440 // set the line color to transparent (= don't draw lines)
441 void OpenGLSalGraphicsImpl::SetLineColor()
443 if( mnLineColor != SALCOLOR_NONE )
445 mnLineColor = SALCOLOR_NONE;
449 // set the line color to a specific color
450 void OpenGLSalGraphicsImpl::SetLineColor( Color nColor )
452 if( mnLineColor != nColor )
454 mnLineColor = nColor;
458 // set the fill color to transparent (= don't fill)
459 void OpenGLSalGraphicsImpl::SetFillColor()
461 if( mnFillColor != SALCOLOR_NONE )
463 mnFillColor = SALCOLOR_NONE;
467 // set the fill color to a specific color, shapes will be
468 // filled accordingly
469 void OpenGLSalGraphicsImpl::SetFillColor( Color nColor )
471 if( mnFillColor != nColor )
473 mnFillColor = nColor;
477 // enable/disable XOR drawing
478 void OpenGLSalGraphicsImpl::SetXORMode( bool bSet, bool )
480 if (mbXORMode != bSet)
482 FlushDeferredDrawing();
483 mbXORMode = bSet;
487 void OpenGLSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor)
489 switch (nROPColor)
491 case SalROPColor::N0:
492 mnLineColor = Color(0, 0, 0);
493 break;
494 case SalROPColor::N1:
495 mnLineColor = Color(0xff, 0xff, 0xff);
496 break;
497 case SalROPColor::Invert:
498 mnLineColor = Color(0xff, 0xff, 0xff);
499 break;
503 void OpenGLSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor)
505 switch (nROPColor)
507 case SalROPColor::N0:
508 mnFillColor = Color(0, 0, 0);
509 break;
510 case SalROPColor::N1:
511 mnFillColor = Color(0xff, 0xff, 0xff);
512 break;
513 case SalROPColor::Invert:
514 mnFillColor = Color(0xff, 0xff, 0xff);
515 break;
519 void OpenGLSalGraphicsImpl::CheckOffscreenTexture()
521 bool bClearTexture = false;
523 VCL_GL_INFO( "Check Offscreen texture" );
525 // Always create the offscreen texture
526 if( maOffscreenTex )
528 if( maOffscreenTex.GetWidth() != GetWidth() ||
529 maOffscreenTex.GetHeight() != GetHeight() )
531 VCL_GL_INFO( "re-size offscreen texture " << maOffscreenTex.Id() );
532 mpFlush->SetPriority( TaskPriority::POST_PAINT );
533 mpContext->ReleaseFramebuffer( maOffscreenTex );
534 maOffscreenTex = OpenGLTexture();
538 if( !maOffscreenTex )
540 VCL_GL_INFO( "create texture of size "
541 << GetWidth() << " x " << GetHeight() );
542 maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() );
543 bClearTexture = true;
546 if( !maOffscreenTex.IsUnique() )
548 GLfloat fWidth = GetWidth();
549 GLfloat fHeight = GetHeight();
550 SalTwoRect aPosAry(0, 0, fWidth, fHeight, 0,0, fWidth, fHeight);
552 // TODO: lfrb: User GL_ARB_copy_image?
553 OpenGLTexture aNewTex( GetWidth(), GetHeight() );
555 mpContext->state().scissor().disable();
556 mpContext->state().stencil().disable();
558 mpContext->AcquireFramebuffer( aNewTex );
559 DrawTexture( maOffscreenTex, aPosAry );
560 maOffscreenTex = aNewTex;
562 else
564 mpContext->AcquireFramebuffer( maOffscreenTex );
565 CHECK_GL_ERROR();
567 if( bClearTexture )
569 glDrawBuffer( GL_COLOR_ATTACHMENT0 );
570 #if OSL_DEBUG_LEVEL > 0 // lets have some red debugging background.
571 GLfloat const clearColor[4] = { 1.0, 0, 0, 0 };
572 #else
573 GLfloat const clearColor[4] = { 1.0, 1.0, 1.0, 0 };
574 #endif
575 glClearBufferfv( GL_COLOR, 0, clearColor );
576 // FIXME: use glClearTexImage if we have it ?
580 assert( maOffscreenTex );
582 CHECK_GL_ERROR();
585 bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
587 if( mpProgram != nullptr )
588 mpProgram->Clean();
589 mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader, preamble );
590 #ifdef DBG_UTIL
591 mProgramIsSolidColor = false; // UseSolid() will set to true if needed
592 #endif
593 return ( mpProgram != nullptr );
596 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, sal_uInt8 nTransparency )
598 if( nColor == SALCOLOR_NONE )
599 return false;
600 UseSolid();
601 mpProgram->SetColor( "color", nColor, nTransparency );
602 #ifdef DBG_UTIL
603 mProgramIsSolidColor = true;
604 #endif
605 mProgramSolidColor = nColor;
606 mProgramSolidTransparency = nTransparency / 100.0;
608 return true;
611 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, double fTransparency )
613 if( nColor == SALCOLOR_NONE )
614 return false;
615 UseSolid();
616 mpProgram->SetColorf( "color", nColor, fTransparency );
617 #ifdef DBG_UTIL
618 mProgramIsSolidColor = true;
619 #endif
620 mProgramSolidColor = nColor;
621 mProgramSolidTransparency = fTransparency;
622 return true;
625 void OpenGLSalGraphicsImpl::UseSolid()
627 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
628 return;
629 mpProgram->SetShaderType(DrawShaderType::Normal);
632 bool OpenGLSalGraphicsImpl::UseInvert50()
634 return UseProgram( "dumbVertexShader", "invert50FragmentShader" );
637 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor )
639 return UseSolid( nColor, 0.0f );
642 bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags )
644 OpenGLZone aZone;
646 if( ( nFlags & SalInvert::N50 ) ||
647 ( nFlags & SalInvert::TrackFrame ) )
649 // FIXME: Trackframe really should be 2 pix. on/off stipple.
650 if( !UseInvert50() )
651 return false;
652 mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR,
653 GL_ONE_MINUS_SRC_COLOR );
655 else
657 if( !UseSolid( Color( 255, 255, 255 ) ) )
658 return false;
659 mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
661 return true;
664 void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float y2)
666 std::vector<GLfloat> aVertices;
667 std::vector<GLfloat> aExtrusionVectors;
669 OpenGLZone aZone;
671 glm::vec2 aPoint1(x1, y1);
672 glm::vec2 aPoint2(x2, y2);
674 glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1);
675 glm::vec2 aNormal(-aLineVector.y, aLineVector.x);
677 vcl::vertex::addLineSegmentVertices(aVertices, aExtrusionVectors,
678 aPoint1, aNormal, 1.0f,
679 aPoint2, aNormal, 1.0f);
681 ApplyProgramMatrices(0.5f);
682 mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
683 mpProgram->DrawArrays(GL_TRIANGLES, aVertices);
685 CHECK_GL_ERROR();
688 bool OpenGLSalGraphicsImpl::UseLine(Color nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA)
690 if( nColor == SALCOLOR_NONE )
691 return false;
692 UseLine(fLineWidth, bUseAA);
693 mpProgram->SetColorf("color", nColor, fTransparency);
694 #ifdef DBG_UTIL
695 mProgramIsSolidColor = true;
696 #endif
697 mProgramSolidColor = nColor;
698 mProgramSolidTransparency = fTransparency;
699 return true;
702 void OpenGLSalGraphicsImpl::UseLine(GLfloat fLineWidth, bool bUseAA)
704 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
705 return;
706 mpProgram->SetShaderType(DrawShaderType::Line);
707 mpProgram->SetUniform1f("line_width", fLineWidth);
708 // The width of the feather - area we make linearly transparent in VS.
709 // Good AA value is 0.5f, no AA if feather 0.0f
710 mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f);
711 // We need blending or AA won't work correctly
712 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
715 void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const Point* pPtAry, bool blockAA )
717 OpenGLZone aZone;
719 std::vector<GLfloat> aVertices(nPoints * 2);
720 sal_uInt32 i, j;
722 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
724 aVertices[j] = GLfloat(pPtAry[i].getX());
725 aVertices[j+1] = GLfloat(pPtAry[i].getY());
728 ApplyProgramMatrices();
729 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
730 mpProgram->SetExtrusionVectors(aExtrusion.data());
731 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
732 CHECK_GL_ERROR();
734 if( blockAA || !mrParent.getAntiAlias())
735 return;
737 // Make the edges antialiased by drawing the edge lines again with AA.
738 // TODO: If transparent drawing is set up, drawing the lines themselves twice
739 // may be a problem, if that is a real problem, the polygon areas itself needs to be
740 // masked out for this or something.
741 #ifdef DBG_UTIL
742 assert( mProgramIsSolidColor );
743 #endif
744 Color lastSolidColor = mProgramSolidColor;
745 double lastSolidTransparency = mProgramSolidTransparency;
746 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
748 for( i = 0; i < nPoints; ++i )
750 const Point& rPt1 = pPtAry[ i ];
751 const Point& rPt2 = pPtAry[ ( i + 1 ) % nPoints ];
752 DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
754 UseSolid( lastSolidColor, lastSolidTransparency );
758 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const tools::Polygon& rPolygon, bool blockAA )
760 OpenGLZone aZone;
762 sal_uInt16 nPoints = rPolygon.GetSize() - 1;
763 std::vector<GLfloat> aVertices(nPoints * 2);
764 sal_uInt32 i, j;
766 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
768 const Point& rPt = rPolygon.GetPoint( i );
769 aVertices[j] = GLfloat(rPt.X());
770 aVertices[j+1] = GLfloat(rPt.Y());
773 ApplyProgramMatrices();
774 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
775 mpProgram->SetExtrusionVectors(aExtrusion.data());
776 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
777 CHECK_GL_ERROR();
779 if( blockAA || !mrParent.getAntiAlias())
780 return;
782 // Make the edges antialiased by drawing the edge lines again with AA.
783 // TODO: If transparent drawing is set up, drawing the lines themselves twice
784 // may be a problem, if that is a real problem, the polygon areas itself needs to be
785 // masked out for this or something.
786 #ifdef DBG_UTIL
787 assert( mProgramIsSolidColor );
788 #endif
789 Color lastSolidColor = mProgramSolidColor;
790 double lastSolidTransparency = mProgramSolidTransparency;
791 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
793 for( i = 0; i < nPoints; ++i )
795 const Point& rPt1 = rPolygon.GetPoint( i );
796 const Point& rPt2 = rPolygon.GetPoint(( i + 1 ) % nPoints );
797 DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
799 UseSolid( lastSolidColor, lastSolidTransparency );
803 void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA )
805 OpenGLZone aZone;
807 const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon();
808 sal_uInt16 nPoints = rPolygon.count();
809 std::vector<GLfloat> aVertices(nPoints * 2);
810 sal_uInt32 i, j;
812 for( i = 0, j = 0; i < nPoints; i++, j += 2 )
814 const basegfx::B2DPoint& rPt = rPolygon.getB2DPoint( i );
815 aVertices[j] = GLfloat(rPt.getX());
816 aVertices[j+1] = GLfloat(rPt.getY());
819 if (!mpProgram)
821 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
822 return;
825 ApplyProgramMatrices();
826 std::vector<GLfloat> aExtrusion(nPoints * 3, 0);
827 mpProgram->SetExtrusionVectors(aExtrusion.data());
828 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
829 CHECK_GL_ERROR();
831 if( blockAA || !mrParent.getAntiAlias())
832 return;
834 // Make the edges antialiased by drawing the edge lines again with AA.
835 // TODO: If transparent drawing is set up, drawing the lines themselves twice
836 // may be a problem, if that is a real problem, the polygon areas itself needs to be
837 // masked out for this or something.
838 #ifdef DBG_UTIL
839 assert( mProgramIsSolidColor );
840 #endif
841 Color lastSolidColor = mProgramSolidColor;
842 double lastSolidTransparency = mProgramSolidTransparency;
843 if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true))
845 for( i = 0; i < nPoints; ++i )
847 const basegfx::B2DPoint& rPt1 = rPolygon.getB2DPoint( i );
848 const basegfx::B2DPoint& rPt2 = rPolygon.getB2DPoint(( i + 1 ) % nPoints );
849 DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
851 UseSolid( lastSolidColor, lastSolidTransparency );
855 void OpenGLSalGraphicsImpl::DrawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
857 tools::Long nX1( nX );
858 tools::Long nY1( nY );
859 tools::Long nX2( nX + nWidth );
860 tools::Long nY2( nY + nHeight );
861 const Point aPoints[] = { { static_cast<sal_Int32>(nX1), static_cast<sal_Int32>(nY2) }, { static_cast<sal_Int32>(nX1), static_cast<sal_Int32>(nY1) },
862 { static_cast<sal_Int32>(nX2), static_cast<sal_Int32>(nY1) }, { static_cast<sal_Int32>(nX2), static_cast<sal_Int32>(nY2) }};
864 DrawConvexPolygon( 4, aPoints, true );
867 void OpenGLSalGraphicsImpl::DrawRect( const tools::Rectangle& rRect )
869 tools::Long nX1( rRect.Left() );
870 tools::Long nY1( rRect.Top() );
871 tools::Long nX2( rRect.Right() );
872 tools::Long nY2( rRect.Bottom() );
873 const Point aPoints[] = { { static_cast<sal_Int32>(nX1), static_cast<sal_Int32>(nY2) }, { static_cast<sal_Int32>(nX1), static_cast<sal_Int32>(nY1) },
874 { static_cast<sal_Int32>(nX2), static_cast<sal_Int32>(nY1) }, { static_cast<sal_Int32>(nX2), static_cast<sal_Int32>(nY2) }};
876 DrawConvexPolygon( 4, aPoints, true );
879 void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
881 basegfx::B2DPolygon aPolygon;
883 for( sal_uInt32 i = 0; i < nPoints; i++ )
884 aPolygon.append( basegfx::B2DPoint( pPtAry[i].getX(), pPtAry[i].getY() ) );
885 aPolygon.setClosed( true );
887 if( basegfx::utils::isConvex( aPolygon ) )
889 if( nPoints > 2 )
890 DrawConvexPolygon( nPoints, pPtAry );
892 else
894 const basegfx::B2DPolyPolygon aPolyPolygon( aPolygon );
895 DrawPolyPolygon( aPolyPolygon );
899 void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA )
901 const basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::utils::solveCrossovers( rPolyPolygon );
902 basegfx::B2DTrapezoidVector aB2DTrapVector;
903 basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aSimplePolyPolygon );
904 // draw tessellation result
905 for(const basegfx::B2DTrapezoid & i : aB2DTrapVector)
906 DrawTrapezoid( i, blockAA );
909 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion )
911 OpenGLZone aZone;
913 RectangleVector aRects;
914 std::vector<GLfloat> aVertices;
915 rRegion.GetRegionRectangles( aRects );
917 if( aRects.empty() )
918 return;
920 #define ADD_VERTICE(pt) \
921 aVertices.push_back(GLfloat(pt.X())); \
922 aVertices.push_back(GLfloat(pt.Y()));
924 for(tools::Rectangle & rRect : aRects)
926 rRect.AdjustBottom(1 );
927 rRect.AdjustRight(1 );
928 ADD_VERTICE( rRect.TopLeft() );
929 ADD_VERTICE( rRect.TopRight() );
930 ADD_VERTICE( rRect.BottomLeft() );
931 ADD_VERTICE( rRect.BottomLeft() );
932 ADD_VERTICE( rRect.TopRight() );
933 ADD_VERTICE( rRect.BottomRight() );
935 #undef ADD_VERTICE
936 std::vector<GLfloat> aExtrusion(aRects.size() * 6 * 3, 0);
937 mpProgram->SetExtrusionVectors(aExtrusion.data());
938 ApplyProgramMatrices();
939 mpProgram->DrawArrays(GL_TRIANGLES, aVertices);
940 CHECK_GL_ERROR();
943 void OpenGLSalGraphicsImpl::DrawTextureRect( const SalTwoRect& rPosAry )
945 OpenGLZone aZone;
947 SAL_INFO("vcl.opengl", "draw texture rect");
949 tools::Long nX = rPosAry.mnDestX;
950 tools::Long nY = rPosAry.mnDestY;
951 tools::Long nWidth = rPosAry.mnDestWidth;
952 tools::Long nHeight = rPosAry.mnDestHeight;
954 std::vector<GLfloat> aVertices;
955 aVertices.reserve(8);
956 vcl::vertex::addRectangle<GL_TRIANGLE_FAN>(aVertices, nX, nY, nX + nWidth, nY + nHeight);
958 ApplyProgramMatrices();
959 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
960 CHECK_GL_ERROR();
963 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted )
965 OpenGLZone aZone;
967 SAL_INFO("vcl.opengl", "draw texture");
969 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
970 return;
971 mpProgram->SetShaderType(TextureShaderType::Normal);
972 mpProgram->SetIdentityTransform("transform");
973 mpProgram->SetTexture("texture", rTexture);
975 GLfloat aTexCoord[8];
976 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
977 mpProgram->SetTextureCoord(aTexCoord);
978 mpProgram->SetMaskCoord(aTexCoord);
979 mpProgram->SetAlphaCoord(aTexCoord);
981 DrawTextureRect( rPosAry );
982 mpProgram->Clean();
985 namespace {
987 bool scaleTexture(const rtl::Reference< OpenGLContext > &xContext,
988 OpenGLTexture& rOutTexture, const double& ixscale, const double& iyscale, OpenGLTexture& rTexture)
990 int nWidth = rTexture.GetWidth();
991 int nHeight = rTexture.GetHeight();
992 if (nWidth == 0 || nHeight == 0)
993 return false;
995 int nNewWidth = nWidth / ixscale;
996 int nNewHeight = nHeight / iyscale;
998 OString sUseReducedRegisterVariantDefine;
999 if (xContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters)
1000 sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n");
1002 OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", "areaScaleFragmentShader", sUseReducedRegisterVariantDefine);
1003 if (pProgram == nullptr)
1004 return false;
1006 OpenGLTexture aScratchTex(nNewWidth, nNewHeight);
1007 OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aScratchTex);
1009 // From OpenGLSalBitmap::ImplScaleArea().
1010 pProgram->SetUniform1f("xscale", ixscale);
1011 pProgram->SetUniform1f("yscale", iyscale);
1012 pProgram->SetUniform1i("swidth", nWidth);
1013 pProgram->SetUniform1i("sheight", nHeight);
1014 // For converting between <0,nWidth> and <0.0,1.0> coordinate systems.
1015 GLfloat srcCoords[ 8 ];
1016 rTexture.GetWholeCoord( srcCoords );
1017 pProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] );
1018 pProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] );
1019 pProgram->SetUniform1f( "xtopixelratio", nNewWidth / ( srcCoords[ 4 ] - srcCoords[ 0 ] ));
1020 pProgram->SetUniform1f( "ytopixelratio", nNewHeight / ( srcCoords[ 5 ] - srcCoords[ 1 ] ));
1021 pProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1022 pProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1024 pProgram->SetTexture("sampler", rTexture);
1025 pProgram->DrawTexture(rTexture);
1026 pProgram->Clean();
1028 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
1030 CHECK_GL_ERROR();
1032 rOutTexture = aScratchTex;
1033 return true;
1038 void OpenGLSalGraphicsImpl::DrawTransformedTexture(
1039 OpenGLTexture& rTexture,
1040 OpenGLTexture& rMask,
1041 const basegfx::B2DPoint& rNull,
1042 const basegfx::B2DPoint& rX,
1043 const basegfx::B2DPoint& rY )
1045 OpenGLZone aZone;
1047 std::vector<GLfloat> aVertices = {
1048 0, GLfloat(rTexture.GetHeight()),
1049 0, 0,
1050 GLfloat(rTexture.GetWidth()), 0,
1051 GLfloat(rTexture.GetWidth()), GLfloat(rTexture.GetHeight())
1054 GLfloat aTexCoord[8];
1056 const tools::Long nDestWidth = basegfx::fround(basegfx::B2DVector(rX - rNull).getLength());
1057 const tools::Long nDestHeight = basegfx::fround(basegfx::B2DVector(rY - rNull).getLength());
1059 // Invisibly small images shouldn't divide by zero.
1060 if( nDestHeight == 0 || nDestWidth == 0 )
1061 return;
1063 // inverted scale ratios
1064 double ixscale = rTexture.GetWidth() / double(nDestWidth);
1065 double iyscale = rTexture.GetHeight() / double(nDestHeight);
1067 // If downscaling at a higher scale ratio, use the area scaling algorithm rather
1068 // than plain OpenGL's scaling (texture mapping), for better results.
1069 // See OpenGLSalBitmap::ImplScaleArea().
1070 bool areaScaling = false;
1071 bool fastAreaScaling = false;
1073 OString sUseReducedRegisterVariantDefine;
1074 if (mpContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters)
1075 sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n");
1077 OUString textureFragmentShader;
1078 if( ixscale >= 2 && iyscale >= 2 ) // scale ratio less than 50%
1080 areaScaling = true;
1081 fastAreaScaling = ( ixscale == std::trunc( ixscale ) && iyscale == std::trunc( iyscale ));
1082 // The generic case has arrays only up to 16 ratio downscaling and is performed in 2 passes,
1083 // when the ratio is in the 16-100 range, which is hopefully enough in practice, but protect
1084 // against buffer overflows in case such an extreme case happens (and in such case the precision
1085 // of the generic algorithm probably doesn't matter anyway).
1086 if( ixscale > 100 || iyscale > 100 )
1087 fastAreaScaling = true;
1088 if( fastAreaScaling )
1089 textureFragmentShader = "areaScaleFastFragmentShader";
1090 else
1091 textureFragmentShader = "areaScaleFragmentShader";
1094 OpenGLTexture aInTexture = rTexture;
1095 OpenGLTexture aInMask = rMask;
1097 // When using the area scaling algorithm we need to reduce the texture size in 2 passes
1098 // in order to not use a big array inside the fragment shader.
1099 if (areaScaling && !fastAreaScaling)
1101 // Perform a first texture downscaling by an inverted scale ratio equal to
1102 // the square root of the whole inverted scale ratio.
1103 if (ixscale > 16 || iyscale > 16)
1105 // The scissor area is set to the current window size in PreDraw,
1106 // so if we do not disable the scissor test, the texture produced
1107 // by the first downscaling is clipped to the current window size.
1108 mpContext->state().scissor().disable();
1109 mpContext->state().stencil().disable();
1111 // the square root of the whole inverted scale ratio
1112 double ixscalesqrt = std::floor(std::sqrt(ixscale));
1113 double iyscalesqrt = std::floor(std::sqrt(iyscale));
1114 ixscale /= ixscalesqrt; // second pass inverted x-scale factor
1115 iyscale /= iyscalesqrt; // second pass inverted y-scale factor
1117 scaleTexture(mpContext, aInTexture, ixscalesqrt, iyscalesqrt, rTexture);
1119 if (rMask) // we need to downscale the mask too
1121 scaleTexture(mpContext, aInMask, ixscalesqrt, iyscalesqrt, rMask);
1124 // We need to re-acquire the off-screen texture.
1125 CheckOffscreenTexture();
1126 CHECK_GL_ERROR();
1128 // Re-enable scissor and stencil tests if needed.
1129 if (mbUseScissor)
1130 mpContext->state().scissor().enable();
1132 if (mbUseStencil)
1133 mpContext->state().stencil().enable();
1137 if( aInMask )
1139 if( !UseProgram( "transformedTextureVertexShader",
1140 textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader,
1141 "#define MASKED\n" + sUseReducedRegisterVariantDefine))
1142 return;
1143 mpProgram->SetTexture( "mask", aInMask );
1144 GLfloat aMaskCoord[8];
1145 aInMask.GetWholeCoord(aMaskCoord);
1146 mpProgram->SetMaskCoord(aMaskCoord);
1147 aInMask.SetFilter( GL_LINEAR );
1148 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1150 else
1152 if( !UseProgram( "transformedTextureVertexShader",
1153 textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader,
1154 sUseReducedRegisterVariantDefine))
1155 return;
1158 if(areaScaling)
1160 int nWidth = aInTexture.GetWidth();
1161 int nHeight = aInTexture.GetHeight();
1163 // From OpenGLSalBitmap::ImplScaleArea().
1164 if (fastAreaScaling && nWidth && nHeight)
1166 mpProgram->SetUniform1i( "xscale", ixscale );
1167 mpProgram->SetUniform1i( "yscale", iyscale );
1168 GLfloat srcCoords[ 8 ];
1169 aInTexture.GetWholeCoord( srcCoords );
1170 mpProgram->SetUniform1f( "xstep", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1171 mpProgram->SetUniform1f( "ystep", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1172 mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale ));
1174 else if (nHeight > 1 && nWidth > 1)
1176 mpProgram->SetUniform1f( "xscale", ixscale );
1177 mpProgram->SetUniform1f( "yscale", iyscale );
1178 mpProgram->SetUniform1i( "swidth", nWidth );
1179 mpProgram->SetUniform1i( "sheight", nHeight );
1180 // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
1181 GLfloat srcCoords[ 8 ];
1182 aInTexture.GetWholeCoord( srcCoords );
1183 mpProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] );
1184 mpProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] );
1185 mpProgram->SetUniform1f( "xtopixelratio", ( nWidth / ixscale ) / ( srcCoords[ 4 ] - srcCoords[ 0 ] ));
1186 mpProgram->SetUniform1f( "ytopixelratio", ( nHeight / iyscale ) / ( srcCoords[ 5 ] - srcCoords[ 1 ] ));
1187 mpProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth );
1188 mpProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight );
1192 ApplyProgramMatrices();
1193 mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() );
1194 // Here, in order to get the correct transformation we need to pass the original texture,
1195 // since it has been used for initializing the rectangle vertices.
1196 mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY );
1197 aInTexture.GetWholeCoord(aTexCoord);
1198 mpProgram->SetTexture("sampler", aInTexture);
1199 aInTexture.SetFilter(GL_LINEAR);
1200 mpProgram->SetTextureCoord( aTexCoord );
1201 mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices);
1203 CHECK_GL_ERROR();
1204 mpProgram->Clean();
1207 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool bPremultiplied )
1209 OpenGLZone aZone;
1211 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1212 return;
1213 mpProgram->SetShaderType(TextureShaderType::Normal);
1214 mpProgram->SetIdentityTransform("transform");
1215 mpProgram->SetTexture("texture", rTexture);
1216 mpProgram->SetBlendMode( bPremultiplied ? GL_ONE : GL_SRC_ALPHA,
1217 GL_ONE_MINUS_SRC_ALPHA );
1219 GLfloat aTexCoord[8];
1220 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
1221 mpProgram->SetTextureCoord(aTexCoord);
1222 mpProgram->SetMaskCoord(aTexCoord);
1223 mpProgram->SetAlphaCoord(aTexCoord);
1225 DrawTextureRect( rPosAry );
1226 mpProgram->Clean();
1229 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted )
1231 OpenGLZone aZone;
1233 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1234 return;
1235 mpProgram->SetShaderType(TextureShaderType::Diff);
1236 mpProgram->SetIdentityTransform("transform");
1237 mpProgram->SetTexture( "texture", rTexture );
1238 mpProgram->SetTexture( "mask", rMask );
1239 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1241 GLfloat aTexCoord[8];
1242 rTexture.GetCoord(aTexCoord, rPosAry, bInverted);
1243 mpProgram->SetTextureCoord(aTexCoord);
1244 mpProgram->SetAlphaCoord(aTexCoord);
1246 GLfloat aMaskCoord[8];
1247 rMask.GetCoord(aMaskCoord, rPosAry, bInverted);
1248 mpProgram->SetMaskCoord(aMaskCoord);
1250 DrawTextureRect( rPosAry );
1251 mpProgram->Clean();
1254 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry )
1256 OpenGLZone aZone;
1258 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1259 return;
1260 mpProgram->SetShaderType(TextureShaderType::Masked);
1261 mpProgram->SetIdentityTransform("transform");
1262 mpProgram->SetTexture( "texture", rTexture );
1263 mpProgram->SetTexture( "mask", rMask );
1264 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1266 GLfloat aTexCoord[8];
1267 rTexture.GetCoord(aTexCoord, rPosAry);
1268 mpProgram->SetTextureCoord(aTexCoord);
1269 mpProgram->SetAlphaCoord(aTexCoord);
1271 GLfloat aMaskCoord[8];
1272 rMask.GetCoord(aMaskCoord, rPosAry);
1273 mpProgram->SetMaskCoord(aMaskCoord);
1275 DrawTextureRect(rPosAry);
1276 mpProgram->Clean();
1279 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry )
1281 OpenGLZone aZone;
1283 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1284 return;
1285 mpProgram->SetShaderType(TextureShaderType::Blend);
1286 mpProgram->SetTexture( "texture", rTexture );
1287 mpProgram->SetTexture( "mask", rMask );
1288 mpProgram->SetTexture( "alpha", rAlpha );
1290 GLfloat aTexCoord[8];
1291 rTexture.GetCoord(aTexCoord, rPosAry);
1292 mpProgram->SetTextureCoord(aTexCoord);
1294 GLfloat aAlphaCoord[8];
1295 rAlpha.GetCoord(aAlphaCoord, rPosAry);
1296 mpProgram->SetAlphaCoord(aAlphaCoord);
1298 GLfloat aMaskCoord[8];
1299 rMask.GetCoord(aMaskCoord, rPosAry);
1300 mpProgram->SetMaskCoord(aMaskCoord);
1302 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1303 DrawTextureRect( rPosAry );
1304 mpProgram->Clean();
1307 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, Color nMaskColor, const SalTwoRect& rPosAry )
1309 OpenGLZone aZone;
1311 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1312 return;
1313 mpProgram->SetShaderType(TextureShaderType::MaskedColor);
1314 mpProgram->SetIdentityTransform("transform");
1315 mpProgram->SetColor( "color", nMaskColor, 0 );
1316 mpProgram->SetTexture("texture", rMask);
1318 GLfloat aTexCoord[8];
1319 rMask.GetCoord(aTexCoord, rPosAry);
1320 mpProgram->SetTextureCoord(aTexCoord);
1321 mpProgram->SetMaskCoord(aTexCoord);
1322 mpProgram->SetAlphaCoord(aTexCoord);
1324 mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1325 DrawTextureRect(rPosAry);
1326 mpProgram->Clean();
1329 void OpenGLSalGraphicsImpl::FlushLinesOrTriangles(DrawShaderType eType, RenderParameters const & rParameters)
1331 if (!UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
1332 return;
1334 mpProgram->SetShaderType(eType);
1335 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1336 ApplyProgramMatrices(0.5f);
1338 vcl::VertexBufferObject<Vertex> vbo;
1339 vbo.upload(rParameters.maVertices);
1341 GLuint positionAttrib = SAL_MAX_UINT32;
1342 GLuint colorAttrib = SAL_MAX_UINT32;
1343 GLuint lineDataAttrib = SAL_MAX_UINT32;
1345 mpProgram->SetVertexAttrib(positionAttrib, "position", 2, GL_FLOAT, GL_FALSE,
1346 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
1348 mpProgram->SetVertexAttrib(colorAttrib, "vertex_color_in", 4, GL_FLOAT, GL_FALSE,
1349 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
1351 mpProgram->SetVertexAttrib(lineDataAttrib, "extrusion_vectors", 4, GL_FLOAT, GL_FALSE,
1352 sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, lineData)));
1354 vcl::IndexBufferObject ibo;
1355 ibo.upload(rParameters.maIndices);
1356 ibo.bind();
1358 mpProgram->DrawElements(GL_TRIANGLES, rParameters.maIndices.size());
1359 CHECK_GL_ERROR();
1361 mpProgram->Clean();
1364 void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
1366 if (mpRenderList->empty())
1367 return;
1369 VCL_GL_INFO("FlushDeferredDrawing: " << mpRenderList->getEntries().size());
1371 InitializePreDrawState(XOROption::IMPLEMENT_XOR);
1373 OpenGLZone aZone;
1374 for (RenderEntry& rRenderEntry : mpRenderList->getEntries())
1376 if (rRenderEntry.hasTriangles())
1378 RenderParameters& rParameters = rRenderEntry.maTriangleParameters;
1379 VCL_GL_INFO("Flush Triangles: " << rParameters.maVertices.size());
1380 FlushLinesOrTriangles(DrawShaderType::Normal, rParameters);
1382 if (rRenderEntry.hasLines())
1384 RenderParameters& rParameters = rRenderEntry.maLineParameters;
1385 VCL_GL_INFO("Flush Lines: " << rParameters.maVertices.size());
1386 FlushLinesOrTriangles(DrawShaderType::Line, rParameters);
1388 if (rRenderEntry.hasTextures() && UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader", "#define USE_VERTEX_COLORS"))
1390 mpProgram->SetShaderType(TextureShaderType::MaskedColor);
1391 mpProgram->SetIdentityTransform("transform");
1392 mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1394 for (auto& rPair : rRenderEntry.maTextureParametersMap)
1396 RenderTextureParameters& rParameters = rPair.second;
1397 mpProgram->SetTexture("texture", rParameters.maTexture);
1398 ApplyProgramMatrices();
1399 mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
1400 mpProgram->SetMaskCoord(rParameters.maTextureCoords.data());
1401 mpProgram->SetAlphaCoord(rParameters.maTextureCoords.data());
1402 mpProgram->SetVertexColors(rParameters.maColors);
1403 mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
1404 CHECK_GL_ERROR();
1406 mpProgram->Clean();
1410 mpRenderList->clear();
1411 PostDraw();
1413 VCL_GL_INFO("End FlushDeferredDrawing");
1416 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1418 OpenGLZone aZone;
1420 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1421 return;
1422 Color aStartCol = rGradient.GetStartColor();
1423 Color aEndCol = rGradient.GetEndColor();
1424 tools::Long nFactor = rGradient.GetStartIntensity();
1425 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1426 nFactor = rGradient.GetEndIntensity();
1427 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1429 tools::Rectangle aBoundRect;
1430 Point aCenter;
1431 rGradient.GetBoundRect( rRect, aBoundRect, aCenter );
1432 tools::Polygon aPoly( aBoundRect );
1433 aPoly.Rotate( aCenter, rGradient.GetAngle() % Degree10(3600) );
1435 GLfloat aTexCoord[8] = { 0, 1, 1, 1, 1, 0, 0, 0 };
1436 GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
1437 aTexCoord[5] = aTexCoord[7] = fMin;
1438 mpProgram->SetTextureCoord( aTexCoord );
1439 DrawConvexPolygon( aPoly, true );
1442 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1444 OpenGLZone aZone;
1446 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1447 return;
1448 Color aStartCol = rGradient.GetStartColor();
1449 Color aEndCol = rGradient.GetEndColor();
1450 tools::Long nFactor = rGradient.GetStartIntensity();
1451 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1452 nFactor = rGradient.GetEndIntensity();
1453 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1456 * Draw two rectangles with linear gradient.
1458 * 1 *---* 2
1459 * | /|
1460 * | / | Points 0 and 3 have start color
1461 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1462 * |\ |
1463 * | \ |
1464 * | \|
1465 * 5 *---* 4
1469 tools::Rectangle aRect;
1470 Point aCenter;
1471 rGradient.GetBoundRect( rRect, aRect, aCenter );
1473 // determine points 0 and 3
1474 Point aPt0( aRect.Left(), (aRect.Top() + aRect.Bottom() + 1) / 2 );
1475 Point aPt3( aRect.Right(), (aRect.Top() + aRect.Bottom() + 1) / 2 );
1477 tools::Polygon aPoly( 7 );
1478 aPoly.SetPoint( aPt0, 0 );
1479 aPoly.SetPoint( aRect.TopLeft(), 1 );
1480 aPoly.SetPoint( aRect.TopRight(), 2 );
1481 aPoly.SetPoint( aPt3, 3 );
1482 aPoly.SetPoint( aRect.BottomRight(), 4 );
1483 aPoly.SetPoint( aRect.BottomLeft(), 5 );
1484 aPoly.SetPoint( aPt0, 6 );
1485 aPoly.Rotate( aCenter, rGradient.GetAngle() % Degree10(3600) );
1487 GLfloat aTexCoord[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 };
1488 GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
1489 aTexCoord[3] = aTexCoord[5] = aTexCoord[9] = aTexCoord[11] = fMin;
1490 mpProgram->SetTextureCoord( aTexCoord );
1491 DrawConvexPolygon( aPoly, true );
1494 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const tools::Rectangle& rRect )
1496 OpenGLZone aZone;
1498 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
1499 return;
1500 Color aStartCol = rGradient.GetStartColor();
1501 Color aEndCol = rGradient.GetEndColor();
1502 tools::Long nFactor = rGradient.GetStartIntensity();
1503 mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
1504 nFactor = rGradient.GetEndIntensity();
1505 mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
1507 tools::Rectangle aRect;
1508 Point aCenter;
1509 rGradient.GetBoundRect( rRect, aRect, aCenter );
1511 // adjust coordinates so that radius has distance equals to 1.0
1512 double fRadius = aRect.GetWidth() / 2.0f;
1513 GLfloat fWidth = rRect.GetWidth() / fRadius;
1514 GLfloat fHeight = rRect.GetHeight() / fRadius;
1515 GLfloat aTexCoord[8] = { 0, 0, 0, fHeight, fWidth, fHeight, fWidth, 0 };
1516 mpProgram->SetTextureCoord( aTexCoord );
1517 mpProgram->SetUniform2f( "center", (aCenter.X() - rRect.Left()) / fRadius,
1518 (aCenter.Y() - rRect.Top()) / fRadius );
1519 DrawRect( rRect );
1522 void OpenGLSalGraphicsImpl::drawPixel(tools::Long nX, tools::Long nY)
1524 VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
1525 mpRenderList->addDrawPixel(nX, nY, mnLineColor);
1526 PostBatchDraw();
1529 void OpenGLSalGraphicsImpl::drawPixel(tools::Long nX, tools::Long nY, Color nColor)
1531 VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
1532 mpRenderList->addDrawPixel(nX, nY, nColor);
1533 PostBatchDraw();
1536 void OpenGLSalGraphicsImpl::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
1538 VCL_GL_INFO("::drawLine (" << nX1 << ", " << nY1 << ") (" << nX2 << ", " << nY2 << ")");
1539 mpRenderList->addDrawLine(nX1, nY1, nX2, nY2, mnLineColor, mrParent.getAntiAlias());
1540 PostBatchDraw();
1543 void OpenGLSalGraphicsImpl::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
1545 VCL_GL_INFO("::drawRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]");
1546 mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, 0.0, mnLineColor, mnFillColor);
1547 PostBatchDraw();
1550 void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry )
1552 VCL_GL_INFO("::drawPolyLine legacy -> redirecting to drawPolyLine");
1553 basegfx::B2DPolygon aPoly;
1554 aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints);
1555 for (sal_uInt32 i = 1; i < nPoints; ++i)
1556 aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY()));
1557 aPoly.setClosed(false);
1559 drawPolyLine(
1560 basegfx::B2DHomMatrix(),
1561 aPoly,
1562 0.0,
1563 1.0,
1564 nullptr, // MM01
1565 basegfx::B2DLineJoin::Miter,
1566 css::drawing::LineCap_BUTT,
1567 basegfx::deg2rad(15.0) /*default*/,
1568 false);
1571 void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
1573 VCL_GL_INFO("::drawPolygon legacy -> redirecting to drawPolyPolygon with transparency");
1574 basegfx::B2DPolygon aPoly;
1575 aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints);
1576 for (sal_uInt32 i = 1; i < nPoints; ++i)
1577 aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY()));
1579 drawPolyPolygon(
1580 basegfx::B2DHomMatrix(),
1581 basegfx::B2DPolyPolygon(aPoly),
1582 0.0);
1585 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPointCounts, const Point** pPtAry )
1587 VCL_GL_INFO("::drawPolyPolygon legacy -> redirecting to drawPolyPolygon with transparency");
1588 basegfx::B2DPolyPolygon aPolyPoly;
1589 for(sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon)
1591 sal_uInt32 nPoints = pPointCounts[nPolygon];
1592 if (nPoints)
1594 const Point* pPoints = pPtAry[nPolygon];
1595 basegfx::B2DPolygon aPoly;
1596 aPoly.append( basegfx::B2DPoint(pPoints->getX(), pPoints->getY()), nPoints);
1597 for (sal_uInt32 i = 1; i < nPoints; ++i)
1598 aPoly.setB2DPoint(i, basegfx::B2DPoint( pPoints[i].getX(), pPoints[i].getY()));
1600 aPolyPoly.append(aPoly);
1604 drawPolyPolygon(
1605 basegfx::B2DHomMatrix(),
1606 aPolyPoly,
1607 0.0);
1610 bool OpenGLSalGraphicsImpl::drawPolyPolygon(
1611 const basegfx::B2DHomMatrix& rObjectToDevice,
1612 const basegfx::B2DPolyPolygon& rPolyPolygon,
1613 double fTransparency)
1615 VCL_GL_INFO("::drawPolyPolygon " << rPolyPolygon.getB2DRange());
1617 // Fallback: Transform to DeviceCoordinates
1618 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
1619 aPolyPolygon.transform(rObjectToDevice);
1621 // FlushLinesOrTriangles() works with a 0.5 pixel offset, compensate for that here.
1622 basegfx::B2DHomMatrix aMatrix;
1623 aMatrix.translate(-0.5f, -0.5f);
1624 aPolyPolygon.transform(aMatrix);
1626 mpRenderList->addDrawPolyPolygon(
1627 aPolyPolygon,
1628 fTransparency,
1629 mnLineColor,
1630 mnFillColor,
1631 mrParent.getAntiAlias());
1633 PostBatchDraw();
1634 return true;
1637 bool OpenGLSalGraphicsImpl::drawPolyLine(
1638 const basegfx::B2DHomMatrix& rObjectToDevice,
1639 const basegfx::B2DPolygon& rPolygon,
1640 double fTransparency,
1641 double fLineWidth,
1642 const std::vector< double >* pStroke, // MM01
1643 basegfx::B2DLineJoin eLineJoin,
1644 css::drawing::LineCap eLineCap,
1645 double fMiterMinimumAngle,
1646 bool bPixelSnapHairline)
1648 VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange());
1650 // MM01 check done for simple reasons
1651 if(!rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0)
1653 return true;
1656 // MM01 need to do line dashing as fallback stuff here now
1657 const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
1658 const bool bStrokeUsed(0.0 != fDotDashLength);
1659 assert(!bStrokeUsed || (bStrokeUsed && pStroke));
1660 basegfx::B2DPolyPolygon aPolyPolygonLine;
1662 if(bStrokeUsed)
1664 // apply LineStyle
1665 basegfx::utils::applyLineDashing(
1666 rPolygon, // source
1667 *pStroke, // pattern
1668 &aPolyPolygonLine, // target for lines
1669 nullptr, // target for gaps
1670 fDotDashLength); // full length if available
1672 else
1674 // no line dashing, just copy
1675 aPolyPolygonLine.append(rPolygon);
1678 // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
1679 aPolyPolygonLine.transform(rObjectToDevice);
1680 if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); }
1682 // tdf#124848 get correct LineWidth in discrete coordinates,
1683 if(fLineWidth == 0) // hairline
1684 fLineWidth = 1.0;
1685 else // Adjust line width for object-to-device scale.
1686 fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
1688 for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
1690 // addDrawPolyLine() assumes that there are no duplicate points in the polygon
1691 basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
1692 basegfx::utils::simplifyCurveSegments(aPolyLine);
1693 aPolyLine.removeDoublePoints();
1695 mpRenderList->addDrawPolyLine(
1696 aPolyLine,
1697 fTransparency,
1698 fLineWidth,
1699 eLineJoin,
1700 eLineCap,
1701 fMiterMinimumAngle,
1702 mnLineColor,
1703 mrParent.getAntiAlias());
1705 // MM01: not sure - maybe this can be moved out of this loop, but to
1706 // keep on the safe side for now, do not really change something for now
1707 PostBatchDraw();
1710 return true;
1713 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1714 sal_uInt32 /*nPoints*/,
1715 const Point* /*pPtAry*/,
1716 const PolyFlags* /*pFlgAry*/ )
1718 return false;
1721 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1722 sal_uInt32 /*nPoints*/,
1723 const Point* /*pPtAry*/,
1724 const PolyFlags* /*pFlgAry*/ )
1726 return false;
1729 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1730 sal_uInt32 /*nPoly*/,
1731 const sal_uInt32* /*pPoints*/,
1732 const Point* const* /*pPtAry*/,
1733 const PolyFlags* const* /*pFlgAry*/ )
1735 return false;
1738 // CopyArea --> No RasterOp, but ClipRegion
1739 void OpenGLSalGraphicsImpl::copyArea(
1740 tools::Long nDestX, tools::Long nDestY,
1741 tools::Long nSrcX, tools::Long nSrcY,
1742 tools::Long nSrcWidth, tools::Long nSrcHeight, bool /*bWindowInvalidate*/ )
1744 VCL_GL_INFO( "::copyArea " << nSrcX << "," << nSrcY << " >> " << nDestX << "," << nDestY << " (" << nSrcWidth << "," << nSrcHeight << ")" );
1745 OpenGLTexture aTexture;
1746 SalTwoRect aPosAry(0, 0, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
1748 PreDraw();
1749 // TODO offscreen case
1750 aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight,
1751 nSrcWidth, nSrcHeight );
1752 DrawTexture( aTexture, aPosAry );
1753 PostDraw();
1756 // CopyBits and DrawBitmap --> RasterOp and ClipRegion
1757 // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
1758 void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGraphicsImpl& rImpl )
1760 VCL_GL_INFO( "::copyBits" );
1762 rImpl.FlushDeferredDrawing();
1764 if( !rImpl.maOffscreenTex )
1766 VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size "
1767 << rImpl.GetWidth() << "x" << rImpl.GetHeight() );
1768 return;
1771 if( &rImpl == this &&
1772 (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
1773 (rPosAry.mnSrcHeight == rPosAry.mnDestHeight))
1775 // short circuit if there is nothing to do
1776 if( (rPosAry.mnSrcX == rPosAry.mnDestX) &&
1777 (rPosAry.mnSrcY == rPosAry.mnDestY))
1778 return;
1779 // use copyArea() if source and destination context are identical
1780 copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY,
1781 rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, false/*bWindowInvalidate*/ );
1782 return;
1785 PreDraw();
1786 DrawTexture( rImpl.maOffscreenTex, rPosAry );
1787 PostDraw();
1790 void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
1792 // check that carefully only in the debug mode
1793 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1795 OpenGLZone aZone;
1797 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1798 OpenGLTexture& rTexture = rBitmap.GetTexture();
1800 VCL_GL_INFO( "::drawBitmap" );
1801 PreDraw();
1802 if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth ||
1803 rPosAry.mnSrcHeight != rPosAry.mnDestHeight)
1805 basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY);
1806 basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY);
1807 basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight);
1808 OpenGLTexture mask; // no mask set
1809 DrawTransformedTexture(rTexture, mask, aNull, aX, aY);
1811 else
1813 DrawTexture( rTexture, rPosAry );
1815 PostDraw();
1818 void OpenGLSalGraphicsImpl::drawBitmap(
1819 const SalTwoRect& rPosAry,
1820 const SalBitmap& rSalBitmap,
1821 const SalBitmap& rMaskBitmap )
1823 VCL_GL_INFO("::drawBitmap with MASK -> redirect to ::drawAlphaBitmap");
1824 drawAlphaBitmap(rPosAry, rSalBitmap, rMaskBitmap);
1827 void OpenGLSalGraphicsImpl::drawMask(
1828 const SalTwoRect& rPosAry,
1829 const SalBitmap& rSalBitmap,
1830 Color nMaskColor )
1832 VCL_GL_INFO("::drawMask");
1834 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1835 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1836 mpRenderList->addDrawTextureWithMaskColor(rBitmap.GetTexture(), nMaskColor, rPosAry);
1837 PostBatchDraw();
1840 std::shared_ptr<SalBitmap> OpenGLSalGraphicsImpl::getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
1842 FlushDeferredDrawing();
1844 OpenGLZone aZone;
1846 std::shared_ptr<OpenGLSalBitmap> pBitmap(std::make_shared<OpenGLSalBitmap>());
1847 VCL_GL_INFO( "::getBitmap " << nX << "," << nY <<
1848 " " << nWidth << "x" << nHeight );
1849 //TODO really needed?
1850 PreDraw();
1851 pBitmap->Create( maOffscreenTex, nX, nY, nWidth, nHeight );
1852 PostDraw();
1853 return pBitmap;
1856 Color OpenGLSalGraphicsImpl::getPixel( tools::Long nX, tools::Long nY )
1858 FlushDeferredDrawing();
1860 char pixel[3] = { 0, 0, 0 };
1862 PreDraw( XOROption::IMPLEMENT_XOR );
1863 nY = GetHeight() - nY - 1;
1864 glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
1865 CHECK_GL_ERROR();
1866 PostDraw();
1868 return Color( pixel[0], pixel[1], pixel[2] );
1871 // invert --> ClipRegion (only Windows or VirDevs)
1872 void OpenGLSalGraphicsImpl::invert(
1873 tools::Long nX, tools::Long nY,
1874 tools::Long nWidth, tools::Long nHeight,
1875 SalInvert nFlags)
1877 PreDraw();
1879 if( UseInvert( nFlags ) )
1881 if( nFlags & SalInvert::TrackFrame )
1882 { // FIXME: could be more efficient.
1883 DrawRect( nX, nY, nWidth, 1 );
1884 DrawRect( nX, nY + nHeight, nWidth, 1 );
1885 DrawRect( nX, nY, 1, nHeight );
1886 DrawRect( nX + nWidth, nY, 1, nHeight );
1888 else
1889 DrawRect( nX, nY, nWidth, nHeight );
1892 PostDraw();
1895 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags )
1897 PreDraw();
1899 if( UseInvert( nFlags ) )
1901 if (nFlags & SalInvert::TrackFrame)
1903 // Track frame means the invert50FragmentShader must remain active
1904 // (to draw what looks like a dashed line), so DrawLineSegment()
1905 // can't be used. Draw the edge of the polygon as polygons instead.
1906 for (size_t nPoint = 0; nPoint < nPoints; ++nPoint)
1908 const Point& rFrom = pPtAry[nPoint];
1909 const Point& rTo = pPtAry[(nPoint + 1) % nPoints];
1910 if (rFrom.getX() == rTo.getX())
1912 // Extend to the right, comments assuming "to" is above
1913 // "from":
1914 const Point aPoints[] = { { rFrom.getX() + 1, rFrom.getY() }, // bottom right
1915 { rFrom.getX(), rFrom.getY() }, // bottom left
1916 { rTo.getX(), rTo.getY() }, // top left
1917 { rTo.getX() + 1, rTo.getY() } }; // top right
1918 DrawConvexPolygon(4, aPoints, true);
1920 else
1922 // Otherwise can extend downwards, comments assuming "to"
1923 // is above and on the right of "from":
1924 const Point aPoints[] = { { rFrom.getX(), rFrom.getY() + 1 }, // bottom left
1925 { rFrom.getX(), rFrom.getY() }, // top left
1926 { rTo.getX(), rTo.getY() }, // top right
1927 { rTo.getX(), rTo.getY() + 1 } }; // bottom right
1928 DrawConvexPolygon(4, aPoints, true);
1932 else
1933 DrawPolygon(nPoints, pPtAry);
1936 PostDraw();
1939 bool OpenGLSalGraphicsImpl::drawEPS(
1940 tools::Long /*nX*/, tools::Long /*nY*/,
1941 tools::Long /*nWidth*/, tools::Long /*nHeight*/,
1942 void* /*pPtr*/,
1943 sal_uInt32 /*nSize*/ )
1945 return false;
1948 bool OpenGLSalGraphicsImpl::blendBitmap(
1949 const SalTwoRect& rPosAry,
1950 const SalBitmap& rSalBitmap )
1952 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
1954 OpenGLZone aZone;
1956 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
1957 OpenGLTexture& rTexture( rBitmap.GetTexture() );
1959 VCL_GL_INFO( "::blendBitmap" );
1960 PreDraw();
1962 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1963 return true;
1965 mpProgram->SetShaderType(TextureShaderType::Normal);
1966 mpProgram->SetIdentityTransform("transform");
1967 mpProgram->SetTexture("texture", rTexture);
1969 GLfloat aTexCoord[8];
1970 rTexture.GetCoord(aTexCoord, rPosAry);
1971 mpProgram->SetTextureCoord(aTexCoord);
1972 mpProgram->SetMaskCoord(aTexCoord);
1973 mpProgram->SetAlphaCoord(aTexCoord);
1975 mpProgram->SetBlendMode(GL_ZERO, GL_SRC_COLOR);
1976 DrawTextureRect(rPosAry);
1977 mpProgram->Clean();
1979 PostDraw();
1980 return true;
1983 bool OpenGLSalGraphicsImpl::blendAlphaBitmap(
1984 const SalTwoRect& rPosAry,
1985 const SalBitmap& rSalSrcBitmap,
1986 const SalBitmap& rSalMaskBitmap,
1987 const SalBitmap& rSalAlphaBitmap )
1989 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalSrcBitmap));
1990 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalMaskBitmap));
1991 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalAlphaBitmap));
1993 OpenGLZone aZone;
1995 const OpenGLSalBitmap& rSrcBitmap = static_cast<const OpenGLSalBitmap&>(rSalSrcBitmap);
1996 const OpenGLSalBitmap& rMaskBitmap = static_cast<const OpenGLSalBitmap&>(rSalMaskBitmap);
1997 const OpenGLSalBitmap& rAlphaBitmap = static_cast<const OpenGLSalBitmap&>(rSalAlphaBitmap);
1998 OpenGLTexture& rTexture( rSrcBitmap.GetTexture() );
1999 OpenGLTexture& rMask( rMaskBitmap.GetTexture() );
2000 OpenGLTexture& rAlpha( rAlphaBitmap.GetTexture() );
2002 VCL_GL_INFO( "::blendAlphaBitmap" );
2003 PreDraw();
2004 DrawBlendedTexture( rTexture, rMask, rAlpha, rPosAry );
2005 PostDraw();
2006 return true;
2009 /** Render bitmap with alpha channel
2011 @param rSourceBitmap
2012 Source bitmap to blit
2014 @param rAlphaBitmap
2015 Alpha channel to use for blitting
2017 @return true, if the operation succeeded, and false
2018 otherwise. In this case, clients should try to emulate alpha
2019 compositing themselves
2021 bool OpenGLSalGraphicsImpl::drawAlphaBitmap(
2022 const SalTwoRect& rPosAry,
2023 const SalBitmap& rSalBitmap,
2024 const SalBitmap& rAlphaBitmap )
2026 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBitmap));
2027 assert(dynamic_cast<const OpenGLSalBitmap*>(&rAlphaBitmap));
2029 OpenGLZone aZone;
2031 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap);
2032 const OpenGLSalBitmap& rAlpha = static_cast<const OpenGLSalBitmap&>(rAlphaBitmap);
2033 OpenGLTexture& rTexture(rBitmap.GetTexture());
2034 OpenGLTexture& rAlphaTexture(rAlpha.GetTexture());
2036 VCL_GL_INFO( "::drawAlphaBitmap" );
2037 PreDraw();
2039 if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth ||
2040 rPosAry.mnSrcHeight != rPosAry.mnDestHeight)
2042 basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY);
2043 basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY);
2044 basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight);
2045 DrawTransformedTexture(rTexture, rAlphaTexture, aNull, aX, aY);
2047 else
2049 DrawTextureWithMask( rTexture, rAlphaTexture, rPosAry );
2052 PostDraw();
2053 return true;
2056 /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
2057 bool OpenGLSalGraphicsImpl::drawTransformedBitmap(
2058 const basegfx::B2DPoint& rNull,
2059 const basegfx::B2DPoint& rX,
2060 const basegfx::B2DPoint& rY,
2061 const SalBitmap& rSrcBitmap,
2062 const SalBitmap* pAlphaBitmap)
2064 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSrcBitmap));
2065 assert(!pAlphaBitmap || dynamic_cast<const OpenGLSalBitmap*>(pAlphaBitmap));
2067 OpenGLZone aZone;
2069 const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSrcBitmap);
2070 const OpenGLSalBitmap* pMaskBitmap = static_cast<const OpenGLSalBitmap*>(pAlphaBitmap);
2071 OpenGLTexture& rTexture( rBitmap.GetTexture() );
2072 OpenGLTexture aMask; // no texture
2074 if( pMaskBitmap != nullptr )
2075 aMask = pMaskBitmap->GetTexture();
2077 VCL_GL_INFO( "::drawTransformedBitmap" );
2078 PreDraw();
2079 DrawTransformedTexture( rTexture, aMask, rNull, rX, rY );
2080 PostDraw();
2082 return true;
2085 /** Render solid rectangle with given transparency
2087 @param nTransparency
2088 Transparency value (0-255) to use. 0 blits and opaque, 255 a
2089 fully transparent rectangle
2091 bool OpenGLSalGraphicsImpl::drawAlphaRect(
2092 tools::Long nX, tools::Long nY,
2093 tools::Long nWidth, tools::Long nHeight,
2094 sal_uInt8 nTransparency )
2096 VCL_GL_INFO("::drawAlphaRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]");
2097 mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, nTransparency / 100.0, mnLineColor, mnFillColor);
2098 PostBatchDraw();
2099 return true;
2102 bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
2103 const Gradient& rGradient)
2105 tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
2107 VCL_GL_INFO("::drawGradient " << rPolyPoly.GetBoundRect());
2109 if (aBoundRect.IsEmpty())
2111 VCL_GL_INFO("::drawGradient nothing to draw");
2112 return true;
2115 if (rGradient.GetStyle() != GradientStyle::Linear &&
2116 rGradient.GetStyle() != GradientStyle::Axial &&
2117 rGradient.GetStyle() != GradientStyle::Radial )
2119 VCL_GL_INFO("::drawGradient unsupported gradient type");
2120 return false;
2123 aBoundRect.AdjustLeft( -1 );
2124 aBoundRect.AdjustTop( -1 );
2125 aBoundRect.AdjustRight( 1 );
2126 aBoundRect.AdjustBottom( 1 );
2128 PreDraw( XOROption::IMPLEMENT_XOR );
2130 #define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0
2131 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2132 ImplSetClipBit( vcl::Region( rPolyPoly ), 0x02 );
2133 if( mbUseStencil )
2135 mpContext->state().stencil().enable();
2136 CHECK_GL_ERROR();
2137 glStencilFunc( GL_EQUAL, 3, 0xFF );
2138 CHECK_GL_ERROR();
2140 else
2142 mpContext->state().stencil().enable();
2143 CHECK_GL_ERROR();
2144 glStencilFunc( GL_EQUAL, 2, 0xFF );
2145 CHECK_GL_ERROR();
2147 #endif
2149 // if border >= 100%, draw solid rectangle with start color
2150 if (rGradient.GetBorder() >= 100.0)
2152 VCL_GL_INFO("::drawGradient -> DrawRect (no gradient)");
2154 Color aColor = rGradient.GetStartColor();
2155 tools::Long nIntensity = rGradient.GetStartIntensity();
2156 if (UseSolid(Color(aColor.GetRed() * nIntensity / 100.0,
2157 aColor.GetGreen()* nIntensity / 100.0,
2158 aColor.GetBlue() * nIntensity / 100.0)))
2160 DrawRect(aBoundRect);
2163 else if (rGradient.GetStyle() == GradientStyle::Linear)
2165 VCL_GL_INFO("::drawGradient -> DrawLinearGradient");
2166 DrawLinearGradient(rGradient, aBoundRect);
2168 else if (rGradient.GetStyle() == GradientStyle::Axial)
2170 VCL_GL_INFO("::drawGradient -> DrawAxialGradient");
2171 DrawAxialGradient(rGradient, aBoundRect);
2173 else if (rGradient.GetStyle() == GradientStyle::Radial)
2175 VCL_GL_INFO("::drawGradient -> DrawRadialGradient");
2176 DrawRadialGradient(rGradient, aBoundRect);
2179 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2180 if( !mbUseStencil )
2182 mpContext->state().stencil().disable();
2183 CHECK_GL_ERROR();
2185 #endif
2186 PostDraw();
2188 return true;
2191 bool OpenGLSalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/,
2192 SalGradient const & /*rGradient*/)
2194 return false;
2197 void OpenGLSalGraphicsImpl::flush()
2199 FlushDeferredDrawing();
2201 if( IsOffscreen() )
2202 return;
2204 if( !Application::IsInExecute() )
2206 // otherwise nothing would trigger idle rendering
2207 doFlush();
2209 else if( !mpFlush->IsActive() )
2210 mpFlush->Start();
2213 void OpenGLSalGraphicsImpl::doFlush()
2215 FlushDeferredDrawing();
2217 if (OpenGLContext::hasCurrent())
2219 mpContext->state().scissor().disable();
2220 mpContext->state().stencil().disable();
2223 if( IsOffscreen() )
2224 return;
2226 if( !maOffscreenTex )
2228 VCL_GL_INFO( "doFlush - odd no texture !" );
2229 return;
2232 if( mnDrawCountAtFlush == mnDrawCount )
2234 VCL_GL_INFO( "eliding redundant doFlush, no drawing since last!" );
2235 return;
2238 mnDrawCountAtFlush = mnDrawCount;
2240 OpenGLZone aZone;
2242 VCL_GL_INFO( "doFlush" );
2244 if( !mpWindowContext.is() )
2246 // ensure everything is released from the old context.
2247 OpenGLContext::clearCurrent();
2248 mpWindowContext = CreateWinContext();
2249 VCL_GL_INFO( "late creation of window context" );
2252 assert( mpWindowContext.is() );
2254 if( !mpWindowContext.is() )
2256 // failed to create a GL context for this window:
2257 // eg. mis-matching pixel formats, underlying window
2258 // resource lifecycle, etc.
2259 VCL_GL_INFO( "Failed to create window context" );
2260 return;
2263 // Interesting ! -> this destroys a context [ somehow ] ...
2264 mpWindowContext->makeCurrent();
2265 CHECK_GL_ERROR();
2267 VCL_GL_INFO( "doFlush - acquire default framebuffer" );
2269 mpWindowContext->AcquireDefaultFramebuffer();
2271 CHECK_GL_ERROR();
2273 mpWindowContext->state().sync();
2274 mpWindowContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
2275 mpWindowContext->state().scissor().disable();
2276 mpWindowContext->state().stencil().disable();
2278 #if OSL_DEBUG_LEVEL > 0 // random background glClear
2279 glClearColor(static_cast<float>(double(rand())/RAND_MAX),
2280 static_cast<float>(double(rand())/RAND_MAX),
2281 static_cast<float>(double(rand())/RAND_MAX), 1.0);
2282 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
2283 CHECK_GL_ERROR();
2284 #endif
2286 VCL_GL_INFO( "Texture height " << maOffscreenTex.GetHeight() << " vs. window height " << GetHeight() );
2288 OpenGLFramebuffer* pFrameBuffer = mpWindowContext->AcquireFramebuffer(maOffscreenTex);
2289 CHECK_GL_ERROR();
2290 if (pFrameBuffer)
2292 OpenGLFramebuffer::Unbind(GL_DRAW_FRAMEBUFFER);
2293 pFrameBuffer->Bind(GL_READ_FRAMEBUFFER);
2295 glBlitFramebuffer(0, 0, GetWidth(), GetHeight(),
2296 0, 0, GetWidth(), GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
2297 CHECK_GL_ERROR();
2299 pFrameBuffer->Bind();
2302 static bool bNoSwap = getenv("SAL_GL_NO_SWAP");
2303 if (!bNoSwap)
2304 mpWindowContext->swapBuffers();
2306 VCL_GL_INFO( "doFlush - end." );
2309 bool OpenGLSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const
2311 switch (eType)
2313 case OutDevSupportType::B2DDraw:
2314 case OutDevSupportType::TransparentRect:
2315 return true;
2316 default:
2317 return false;
2321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */