1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <opengl/gdiimpl.hxx>
21 #include <opengl/framebuffer.hxx>
23 #include <vcl/gradient.hxx>
24 #include <vcl/idle.hxx>
25 #include <salframe.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>
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>
49 #include <glm/gtc/type_ptr.hpp>
50 #include <glm/gtx/norm.hpp>
54 class OpenGLFlushIdle
: public Idle
56 OpenGLSalGraphicsImpl
*m_pImpl
;
58 explicit OpenGLFlushIdle( OpenGLSalGraphicsImpl
*pImpl
)
59 : Idle( "gl idle swap" )
62 // We don't want to be swapping before we've painted.
63 SetPriority( TaskPriority::POST_PAINT
);
66 virtual void Invoke() override
70 SetPriority(TaskPriority::HIGHEST
);
74 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics
& rParent
, SalGeometryProvider
*pProvider
)
76 , mpProvider(pProvider
)
78 , mpFlush(new OpenGLFlushIdle(this))
82 , mbAcquiringOpenGLContext(false)
83 , mnLineColor(SALCOLOR_NONE
)
84 , mnFillColor(SALCOLOR_NONE
)
86 , mProgramIsSolidColor(false)
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" );
106 rtl::Reference
<OpenGLContext
> OpenGLSalGraphicsImpl::GetOpenGLContext()
108 if (mbAcquiringOpenGLContext
)
110 mbAcquiringOpenGLContext
= true;
111 bool bSuccess
= AcquireContext(true);
112 mbAcquiringOpenGLContext
= false;
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()
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.
150 // check if we can simply re-use the same context
153 if( !UseContext( mpContext
) )
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();
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();
202 void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt
)
204 FlushDeferredDrawing();
206 InitializePreDrawState(eOpt
);
209 void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt
)
215 if( !AcquireContext() )
217 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
221 mpContext
->makeCurrent();
224 CheckOffscreenTexture();
227 mpContext
->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
229 ImplInitClipRegion();
232 if (eOpt
== IMPLEMENT_XOR
&& mbXORMode
)
234 glEnable(GL_COLOR_LOGIC_OP
);
240 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_FALSE
);
245 void OpenGLSalGraphicsImpl::PostDraw()
249 glDisable(GL_COLOR_LOGIC_OP
);
251 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
260 mProgramIsSolidColor
= false;
264 assert (maOffscreenTex
);
266 // Always queue the flush.
273 void OpenGLSalGraphicsImpl::PostBatchDraw()
278 if (!mpFlush
->IsActive())
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
);
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();
309 nStencil
= maOffscreenTex
.AddStencil();
310 glFramebufferRenderbuffer(
311 GL_FRAMEBUFFER
, GL_STENCIL_ATTACHMENT
,
312 GL_RENDERBUFFER
, nStencil
);
315 // else - we associated the stencil in
316 // AcquireFrameBuffer / AttachTexture
319 glColorMask( GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
321 glStencilMask( nMask
);
323 glStencilFunc( GL_NEVER
, nMask
, 0xFF );
325 glStencilOp( GL_REPLACE
, GL_KEEP
, GL_KEEP
);
328 glClear( GL_STENCIL_BUFFER_BIT
);
330 if( UseSolid( Color( 0xFF, 0xFF, 0xFF ) ) )
332 if( rClip
.getRegionBand() )
333 DrawRegionBand( *rClip
.getRegionBand() );
335 DrawPolyPolygon( rClip
.GetAsB2DPolyPolygon(), true );
338 glColorMask( GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
340 glStencilMask( 0x00 );
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
;
354 ImplSetClipBit(maClipRegion
, 0x01);
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();
366 mpContext
->state().scissor().disable();
371 glStencilFunc( GL_EQUAL
, 1, 0x1 );
373 mpContext
->state().stencil().enable();
377 mpContext
->state().stencil().disable();
381 const vcl::Region
& OpenGLSalGraphicsImpl::getClipRegion() const
386 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region
& rClip
)
388 if (maClipRegion
== rClip
)
390 VCL_GL_INFO("::setClipRegion (no change) " << rClip
);
394 FlushDeferredDrawing();
396 VCL_GL_INFO("::setClipRegion " << rClip
);
398 maClipRegion
= rClip
;
400 mbUseStencil
= false;
401 mbUseScissor
= false;
402 if (maClipRegion
.IsRectangle())
404 else if (!maClipRegion
.IsEmpty())
410 // set the clip region to empty
411 void OpenGLSalGraphicsImpl::ResetClipRegion()
413 if (maClipRegion
.IsEmpty())
415 VCL_GL_INFO("::ResetClipRegion (no change) ");
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
434 // get the width of the device
435 tools::Long
OpenGLSalGraphicsImpl::GetGraphicsWidth() const
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();
487 void OpenGLSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor
)
491 case SalROPColor::N0
:
492 mnLineColor
= Color(0, 0, 0);
494 case SalROPColor::N1
:
495 mnLineColor
= Color(0xff, 0xff, 0xff);
497 case SalROPColor::Invert
:
498 mnLineColor
= Color(0xff, 0xff, 0xff);
503 void OpenGLSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor
)
507 case SalROPColor::N0
:
508 mnFillColor
= Color(0, 0, 0);
510 case SalROPColor::N1
:
511 mnFillColor
= Color(0xff, 0xff, 0xff);
513 case SalROPColor::Invert
:
514 mnFillColor
= Color(0xff, 0xff, 0xff);
519 void OpenGLSalGraphicsImpl::CheckOffscreenTexture()
521 bool bClearTexture
= false;
523 VCL_GL_INFO( "Check Offscreen texture" );
525 // Always create the offscreen texture
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
;
564 mpContext
->AcquireFramebuffer( maOffscreenTex
);
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 };
573 GLfloat
const clearColor
[4] = { 1.0, 1.0, 1.0, 0 };
575 glClearBufferfv( GL_COLOR
, 0, clearColor
);
576 // FIXME: use glClearTexImage if we have it ?
580 assert( maOffscreenTex
);
585 bool OpenGLSalGraphicsImpl::UseProgram( const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OString
& preamble
)
587 if( mpProgram
!= nullptr )
589 mpProgram
= mpContext
->UseProgram( rVertexShader
, rFragmentShader
, preamble
);
591 mProgramIsSolidColor
= false; // UseSolid() will set to true if needed
593 return ( mpProgram
!= nullptr );
596 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor
, sal_uInt8 nTransparency
)
598 if( nColor
== SALCOLOR_NONE
)
601 mpProgram
->SetColor( "color", nColor
, nTransparency
);
603 mProgramIsSolidColor
= true;
605 mProgramSolidColor
= nColor
;
606 mProgramSolidTransparency
= nTransparency
/ 100.0;
611 bool OpenGLSalGraphicsImpl::UseSolid( Color nColor
, double fTransparency
)
613 if( nColor
== SALCOLOR_NONE
)
616 mpProgram
->SetColorf( "color", nColor
, fTransparency
);
618 mProgramIsSolidColor
= true;
620 mProgramSolidColor
= nColor
;
621 mProgramSolidTransparency
= fTransparency
;
625 void OpenGLSalGraphicsImpl::UseSolid()
627 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
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
)
646 if( ( nFlags
& SalInvert::N50
) ||
647 ( nFlags
& SalInvert::TrackFrame
) )
649 // FIXME: Trackframe really should be 2 pix. on/off stipple.
652 mpProgram
->SetBlendMode( GL_ONE_MINUS_DST_COLOR
,
653 GL_ONE_MINUS_SRC_COLOR
);
657 if( !UseSolid( Color( 255, 255, 255 ) ) )
659 mpProgram
->SetBlendMode( GL_ONE_MINUS_DST_COLOR
, GL_ZERO
);
664 void OpenGLSalGraphicsImpl::DrawLineSegment(float x1
, float y1
, float x2
, float y2
)
666 std::vector
<GLfloat
> aVertices
;
667 std::vector
<GLfloat
> aExtrusionVectors
;
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
);
688 bool OpenGLSalGraphicsImpl::UseLine(Color nColor
, double fTransparency
, GLfloat fLineWidth
, bool bUseAA
)
690 if( nColor
== SALCOLOR_NONE
)
692 UseLine(fLineWidth
, bUseAA
);
693 mpProgram
->SetColorf("color", nColor
, fTransparency
);
695 mProgramIsSolidColor
= true;
697 mProgramSolidColor
= nColor
;
698 mProgramSolidTransparency
= fTransparency
;
702 void OpenGLSalGraphicsImpl::UseLine(GLfloat fLineWidth
, bool bUseAA
)
704 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
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
)
719 std::vector
<GLfloat
> aVertices(nPoints
* 2);
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
);
734 if( blockAA
|| !mrParent
.getAntiAlias())
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.
742 assert( mProgramIsSolidColor
);
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
)
762 sal_uInt16 nPoints
= rPolygon
.GetSize() - 1;
763 std::vector
<GLfloat
> aVertices(nPoints
* 2);
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
);
779 if( blockAA
|| !mrParent
.getAntiAlias())
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.
787 assert( mProgramIsSolidColor
);
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
)
807 const basegfx::B2DPolygon
& rPolygon
= trapezoid
.getB2DPolygon();
808 sal_uInt16 nPoints
= rPolygon
.count();
809 std::vector
<GLfloat
> aVertices(nPoints
* 2);
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());
821 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
825 ApplyProgramMatrices();
826 std::vector
<GLfloat
> aExtrusion(nPoints
* 3, 0);
827 mpProgram
->SetExtrusionVectors(aExtrusion
.data());
828 mpProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
831 if( blockAA
|| !mrParent
.getAntiAlias())
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.
839 assert( mProgramIsSolidColor
);
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
) )
890 DrawConvexPolygon( nPoints
, pPtAry
);
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
)
913 RectangleVector aRects
;
914 std::vector
<GLfloat
> aVertices
;
915 rRegion
.GetRegionRectangles( aRects
);
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() );
936 std::vector
<GLfloat
> aExtrusion(aRects
.size() * 6 * 3, 0);
937 mpProgram
->SetExtrusionVectors(aExtrusion
.data());
938 ApplyProgramMatrices();
939 mpProgram
->DrawArrays(GL_TRIANGLES
, aVertices
);
943 void OpenGLSalGraphicsImpl::DrawTextureRect( const SalTwoRect
& rPosAry
)
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
);
963 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
)
967 SAL_INFO("vcl.opengl", "draw texture");
969 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
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)
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)
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
);
1028 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
1032 rOutTexture
= aScratchTex
;
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
)
1047 std::vector
<GLfloat
> aVertices
= {
1048 0, GLfloat(rTexture
.GetHeight()),
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 )
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%
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";
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();
1128 // Re-enable scissor and stencil tests if needed.
1130 mpContext
->state().scissor().enable();
1133 mpContext
->state().stencil().enable();
1139 if( !UseProgram( "transformedTextureVertexShader",
1140 textureFragmentShader
.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader
,
1141 "#define MASKED\n" + sUseReducedRegisterVariantDefine
))
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
);
1152 if( !UseProgram( "transformedTextureVertexShader",
1153 textureFragmentShader
.isEmpty() ? "textureFragmentShader" : textureFragmentShader
,
1154 sUseReducedRegisterVariantDefine
))
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
);
1207 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
, bool bPremultiplied
)
1211 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
1229 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
, bool bInverted
)
1233 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
1254 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
)
1258 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
1279 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, OpenGLTexture
& rAlpha
, const SalTwoRect
& rPosAry
)
1283 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
1307 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture
& rMask
, Color nMaskColor
, const SalTwoRect
& rPosAry
)
1311 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
1329 void OpenGLSalGraphicsImpl::FlushLinesOrTriangles(DrawShaderType eType
, RenderParameters
const & rParameters
)
1331 if (!UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
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
);
1358 mpProgram
->DrawElements(GL_TRIANGLES
, rParameters
.maIndices
.size());
1364 void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
1366 if (mpRenderList
->empty())
1369 VCL_GL_INFO("FlushDeferredDrawing: " << mpRenderList
->getEntries().size());
1371 InitializePreDrawState(XOROption::IMPLEMENT_XOR
);
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
);
1410 mpRenderList
->clear();
1413 VCL_GL_INFO("End FlushDeferredDrawing");
1416 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient
& rGradient
, const tools::Rectangle
& rRect
)
1420 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
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
;
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
)
1446 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
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.
1460 * | / | Points 0 and 3 have start color
1461 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1469 tools::Rectangle aRect
;
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
)
1498 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
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
;
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
);
1522 void OpenGLSalGraphicsImpl::drawPixel(tools::Long nX
, tools::Long nY
)
1524 VCL_GL_INFO("::drawPixel: (" << nX
<< ", " << nY
<< ")");
1525 mpRenderList
->addDrawPixel(nX
, nY
, mnLineColor
);
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
);
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());
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
);
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);
1560 basegfx::B2DHomMatrix(),
1565 basegfx::B2DLineJoin::Miter
,
1566 css::drawing::LineCap_BUTT
,
1567 basegfx::deg2rad(15.0) /*default*/,
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()));
1580 basegfx::B2DHomMatrix(),
1581 basegfx::B2DPolyPolygon(aPoly
),
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
];
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
);
1605 basegfx::B2DHomMatrix(),
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(
1631 mrParent
.getAntiAlias());
1637 bool OpenGLSalGraphicsImpl::drawPolyLine(
1638 const basegfx::B2DHomMatrix
& rObjectToDevice
,
1639 const basegfx::B2DPolygon
& rPolygon
,
1640 double fTransparency
,
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)
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
;
1665 basegfx::utils::applyLineDashing(
1667 *pStroke
, // pattern
1668 &aPolyPolygonLine
, // target for lines
1669 nullptr, // target for gaps
1670 fDotDashLength
); // full length if available
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
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(
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
1713 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1714 sal_uInt32
/*nPoints*/,
1715 const Point
* /*pPtAry*/,
1716 const PolyFlags
* /*pFlgAry*/ )
1721 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1722 sal_uInt32
/*nPoints*/,
1723 const Point
* /*pPtAry*/,
1724 const PolyFlags
* /*pFlgAry*/ )
1729 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1730 sal_uInt32
/*nPoly*/,
1731 const sal_uInt32
* /*pPoints*/,
1732 const Point
* const* /*pPtAry*/,
1733 const PolyFlags
* const* /*pFlgAry*/ )
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
);
1749 // TODO offscreen case
1750 aTexture
= OpenGLTexture( nSrcX
, GetHeight() - nSrcY
- nSrcHeight
,
1751 nSrcWidth
, nSrcHeight
);
1752 DrawTexture( aTexture
, aPosAry
);
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() );
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
))
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*/ );
1786 DrawTexture( rImpl
.maOffscreenTex
, rPosAry
);
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
));
1797 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1798 OpenGLTexture
& rTexture
= rBitmap
.GetTexture();
1800 VCL_GL_INFO( "::drawBitmap" );
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
);
1813 DrawTexture( rTexture
, rPosAry
);
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
,
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
);
1840 std::shared_ptr
<SalBitmap
> OpenGLSalGraphicsImpl::getBitmap( tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
)
1842 FlushDeferredDrawing();
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?
1851 pBitmap
->Create( maOffscreenTex
, nX
, nY
, nWidth
, nHeight
);
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
);
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
,
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
);
1889 DrawRect( nX
, nY
, nWidth
, nHeight
);
1895 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints
, const Point
* pPtAry
, SalInvert nFlags
)
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
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);
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);
1933 DrawPolygon(nPoints
, pPtAry
);
1939 bool OpenGLSalGraphicsImpl::drawEPS(
1940 tools::Long
/*nX*/, tools::Long
/*nY*/,
1941 tools::Long
/*nWidth*/, tools::Long
/*nHeight*/,
1943 sal_uInt32
/*nSize*/ )
1948 bool OpenGLSalGraphicsImpl::blendBitmap(
1949 const SalTwoRect
& rPosAry
,
1950 const SalBitmap
& rSalBitmap
)
1952 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
1956 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1957 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1959 VCL_GL_INFO( "::blendBitmap" );
1962 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
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
);
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
));
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" );
2004 DrawBlendedTexture( rTexture
, rMask
, rAlpha
, rPosAry
);
2009 /** Render bitmap with alpha channel
2011 @param rSourceBitmap
2012 Source bitmap to blit
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
));
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" );
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
);
2049 DrawTextureWithMask( rTexture
, rAlphaTexture
, rPosAry
);
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
));
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" );
2079 DrawTransformedTexture( rTexture
, aMask
, rNull
, rX
, rY
);
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
);
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");
2115 if (rGradient
.GetStyle() != GradientStyle::Linear
&&
2116 rGradient
.GetStyle() != GradientStyle::Axial
&&
2117 rGradient
.GetStyle() != GradientStyle::Radial
)
2119 VCL_GL_INFO("::drawGradient unsupported gradient type");
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 );
2135 mpContext
->state().stencil().enable();
2137 glStencilFunc( GL_EQUAL
, 3, 0xFF );
2142 mpContext
->state().stencil().enable();
2144 glStencilFunc( GL_EQUAL
, 2, 0xFF );
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
2182 mpContext
->state().stencil().disable();
2191 bool OpenGLSalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon
const & /*rPolyPolygon*/,
2192 SalGradient
const & /*rGradient*/)
2197 void OpenGLSalGraphicsImpl::flush()
2199 FlushDeferredDrawing();
2204 if( !Application::IsInExecute() )
2206 // otherwise nothing would trigger idle rendering
2209 else if( !mpFlush
->IsActive() )
2213 void OpenGLSalGraphicsImpl::doFlush()
2215 FlushDeferredDrawing();
2217 if (OpenGLContext::hasCurrent())
2219 mpContext
->state().scissor().disable();
2220 mpContext
->state().stencil().disable();
2226 if( !maOffscreenTex
)
2228 VCL_GL_INFO( "doFlush - odd no texture !" );
2232 if( mnDrawCountAtFlush
== mnDrawCount
)
2234 VCL_GL_INFO( "eliding redundant doFlush, no drawing since last!" );
2238 mnDrawCountAtFlush
= mnDrawCount
;
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" );
2263 // Interesting ! -> this destroys a context [ somehow ] ...
2264 mpWindowContext
->makeCurrent();
2267 VCL_GL_INFO( "doFlush - acquire default framebuffer" );
2269 mpWindowContext
->AcquireDefaultFramebuffer();
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
);
2286 VCL_GL_INFO( "Texture height " << maOffscreenTex
.GetHeight() << " vs. window height " << GetHeight() );
2288 OpenGLFramebuffer
* pFrameBuffer
= mpWindowContext
->AcquireFramebuffer(maOffscreenTex
);
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
);
2299 pFrameBuffer
->Bind();
2302 static bool bNoSwap
= getenv("SAL_GL_NO_SWAP");
2304 mpWindowContext
->swapBuffers();
2306 VCL_GL_INFO( "doFlush - end." );
2309 bool OpenGLSalGraphicsImpl::supportsOperation(OutDevSupportType eType
) const
2313 case OutDevSupportType::B2DDraw
:
2314 case OutDevSupportType::TransparentRect
:
2321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */