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 "openglgdiimpl.hxx"
22 #include <vcl/gradient.hxx>
23 #include <salframe.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <basegfx/polygon/b2dlinegeometry.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
29 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
30 #include <basegfx/polygon/b2dtrapezoid.hxx>
32 #include <vcl/opengl/OpenGLHelper.hxx>
35 #include "opengl/zone.hxx"
36 #include "opengl/salbmp.hxx"
37 #include "opengl/RenderState.hxx"
41 #include <glm/gtc/type_ptr.hpp>
42 #include <glm/gtx/norm.hpp>
46 class OpenGLFlushIdle
: public Idle
48 OpenGLSalGraphicsImpl
*m_pImpl
;
50 explicit OpenGLFlushIdle( OpenGLSalGraphicsImpl
*pImpl
)
51 : Idle( "gl idle swap" )
54 // We don't want to be swapping before we've painted.
55 SetPriority( SchedulerPriority::POST_PAINT
);
57 virtual ~OpenGLFlushIdle()
60 virtual void Invoke() override
63 SetPriority( SchedulerPriority::HIGHEST
);
68 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics
& rParent
, SalGeometryProvider
*pProvider
)
71 , mpProvider(pProvider
)
73 , mpFlush(new OpenGLFlushIdle(this))
77 , mnLineColor(SALCOLOR_NONE
)
78 , mnFillColor(SALCOLOR_NONE
)
80 , mProgramIsSolidColor(false)
83 , mnDrawCountAtFlush(0)
84 , mProgramSolidColor(SALCOLOR_NONE
)
85 , mProgramSolidTransparency(0.0)
86 , mpAccumulatedTextures(new AccumulatedTextures
)
90 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
92 if( !IsOffscreen() && mnDrawCountAtFlush
!= mnDrawCount
)
93 VCL_GL_INFO( "Destroying un-flushed on-screen graphics" );
100 rtl::Reference
<OpenGLContext
> OpenGLSalGraphicsImpl::GetOpenGLContext()
102 if( !AcquireContext(true) )
107 bool OpenGLSalGraphicsImpl::AcquireContext( bool bForceCreate
)
109 mpContext
= OpenGLContext::getVCLContext( false );
111 if( !mpContext
.is() && mpWindowContext
.is() )
113 mpContext
= mpWindowContext
;
115 else if( bForceCreate
&& !IsOffscreen() )
117 mpWindowContext
= CreateWinContext();
118 mpContext
= mpWindowContext
;
121 if( !mpContext
.is() )
122 mpContext
= OpenGLContext::getVCLContext();
124 return mpContext
.is();
127 bool OpenGLSalGraphicsImpl::ReleaseContext()
134 void OpenGLSalGraphicsImpl::Init()
136 // Our init phase is strange ::Init is called twice for vdevs.
137 // the first time around with a NULL geometry provider.
141 // check if we can simply re-use the same context
144 if( !UseContext( mpContext
) )
148 // Always create the offscreen texture
149 if( maOffscreenTex
.GetWidth() != GetWidth() ||
150 maOffscreenTex
.GetHeight() != GetHeight() )
152 // We don't want to be swapping before we've painted.
153 mpFlush
->SetPriority( SchedulerPriority::POST_PAINT
);
155 if( maOffscreenTex
&& // don't work to release empty textures
156 mpContext
.is() ) // valid context
158 mpContext
->makeCurrent();
159 mpContext
->ReleaseFramebuffer( maOffscreenTex
);
161 maOffscreenTex
= OpenGLTexture();
162 VCL_GL_INFO("::Init - re-size offscreen texture");
165 if( mpWindowContext
.is() )
167 mpWindowContext
->reset();
168 mpWindowContext
.clear();
172 // Currently only used to get windows ordering right.
173 void OpenGLSalGraphicsImpl::DeInit()
176 // Our window handles and resources are being free underneath us.
177 // These can be bound into a context, which relies on them. So
178 // let it know. Other eg. VirtualDevice contexts which have
179 // references on and rely on this context continuing to work will
180 // get a shiny new context in AcquireContext:: next PreDraw.
181 if( mpWindowContext
.is() )
183 mpWindowContext
->reset();
184 mpWindowContext
.clear();
189 void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt
)
191 FlushDeferredDrawing();
193 InitializePreDrawState(eOpt
);
196 void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt
)
202 if( !AcquireContext() )
204 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
208 mpContext
->makeCurrent();
211 CheckOffscreenTexture();
214 mpContext
->state()->viewport(Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
216 ImplInitClipRegion();
219 if (eOpt
== IMPLEMENT_XOR
&& mbXORMode
)
221 glEnable(GL_COLOR_LOGIC_OP
);
228 void OpenGLSalGraphicsImpl::PostDraw()
232 glDisable(GL_COLOR_LOGIC_OP
);
241 mProgramIsSolidColor
= false;
245 assert (maOffscreenTex
);
247 // Always queue the flush.
254 void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset
)
256 mpProgram
->ApplyMatrix(GetWidth(), GetHeight(), fPixelOffset
);
259 void OpenGLSalGraphicsImpl::freeResources()
261 // TODO Delete shaders, programs and textures if not shared
262 if( mpContext
.is() && mpContext
->isInitialized() )
264 VCL_GL_INFO( "freeResources" );
265 mpContext
->makeCurrent();
266 FlushDeferredDrawing();
267 mpContext
->ReleaseFramebuffer( maOffscreenTex
);
272 void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region
& rClip
, GLuint nMask
)
274 mpContext
->state()->scissor().disable();
275 mpContext
->state()->stencil().enable();
277 VCL_GL_INFO( "Adding complex clip / stencil" );
278 GLuint nStencil
= maOffscreenTex
.StencilId();
281 nStencil
= maOffscreenTex
.AddStencil();
282 glFramebufferRenderbuffer(
283 GL_FRAMEBUFFER
, GL_STENCIL_ATTACHMENT
,
284 GL_RENDERBUFFER
, nStencil
);
287 // else - we associated the stencil in
288 // AcquireFrameBuffer / AttachTexture
291 glColorMask( GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
293 glStencilMask( nMask
);
295 glStencilFunc( GL_NEVER
, nMask
, 0xFF );
297 glStencilOp( GL_REPLACE
, GL_KEEP
, GL_KEEP
);
300 glClear( GL_STENCIL_BUFFER_BIT
);
302 if( UseSolid( MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) ) )
304 if( rClip
.getRegionBand() )
305 DrawRegionBand( *rClip
.getRegionBand() );
307 DrawPolyPolygon( rClip
.GetAsB2DPolyPolygon(), true );
310 glColorMask( GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
312 glStencilMask( 0x00 );
315 mpContext
->state()->stencil().disable();
318 void OpenGLSalGraphicsImpl::ImplInitClipRegion()
320 // make sure the context has the right clipping set
321 if (maClipRegion
!= mpContext
->maClipRegion
)
323 mpContext
->maClipRegion
= maClipRegion
;
326 ImplSetClipBit(maClipRegion
, 0x01);
332 Rectangle
aRect(maClipRegion
.GetBoundRect());
333 mpContext
->state()->scissor().set(aRect
.Left(), GetHeight() - aRect
.Bottom() - 1, aRect
.GetWidth(), aRect
.GetHeight());
334 mpContext
->state()->scissor().enable();
338 mpContext
->state()->scissor().disable();
343 glStencilFunc( GL_EQUAL
, 1, 0x1 );
345 mpContext
->state()->stencil().enable();
349 mpContext
->state()->stencil().disable();
353 const vcl::Region
& OpenGLSalGraphicsImpl::getClipRegion() const
358 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region
& rClip
)
360 if (maClipRegion
== rClip
)
362 VCL_GL_INFO("::setClipRegion (no change) " << rClip
);
366 FlushDeferredDrawing();
368 VCL_GL_INFO("::setClipRegion " << rClip
);
370 maClipRegion
= rClip
;
372 mbUseStencil
= false;
373 mbUseScissor
= false;
374 if (maClipRegion
.IsRectangle())
376 else if (!maClipRegion
.IsEmpty())
382 // set the clip region to empty
383 void OpenGLSalGraphicsImpl::ResetClipRegion()
385 if (maClipRegion
.IsEmpty())
387 VCL_GL_INFO("::ResetClipRegion (no change) ");
391 FlushDeferredDrawing();
393 VCL_GL_INFO("::ResetClipRegion");
395 maClipRegion
.SetEmpty();
396 mbUseScissor
= false;
397 mbUseStencil
= false;
400 // get the depth of the device
401 sal_uInt16
OpenGLSalGraphicsImpl::GetBitCount() const
406 // get the width of the device
407 long OpenGLSalGraphicsImpl::GetGraphicsWidth() const
412 // set the line color to transparent (= don't draw lines)
413 void OpenGLSalGraphicsImpl::SetLineColor()
415 if( mnLineColor
!= SALCOLOR_NONE
)
417 mnLineColor
= SALCOLOR_NONE
;
421 // set the line color to a specific color
422 void OpenGLSalGraphicsImpl::SetLineColor( SalColor nSalColor
)
424 if( mnLineColor
!= nSalColor
)
426 mnLineColor
= nSalColor
;
430 // set the fill color to transparent (= don't fill)
431 void OpenGLSalGraphicsImpl::SetFillColor()
433 if( mnFillColor
!= SALCOLOR_NONE
)
435 mnFillColor
= SALCOLOR_NONE
;
439 // set the fill color to a specific color, shapes will be
440 // filled accordingly
441 void OpenGLSalGraphicsImpl::SetFillColor( SalColor nSalColor
)
443 if( mnFillColor
!= nSalColor
)
445 mnFillColor
= nSalColor
;
449 // enable/disable XOR drawing
450 void OpenGLSalGraphicsImpl::SetXORMode( bool bSet
, bool )
455 // set line color for raster operations
456 void OpenGLSalGraphicsImpl::SetROPLineColor( SalROPColor
/*nROPColor*/ )
460 // set fill color for raster operations
461 void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor
/*nROPColor*/ )
465 bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
467 bool bClearTexture
= false;
469 VCL_GL_INFO( "Check Offscreen texture" );
471 // Always create the offscreen texture
474 if( maOffscreenTex
.GetWidth() != GetWidth() ||
475 maOffscreenTex
.GetHeight() != GetHeight() )
477 VCL_GL_INFO( "re-size offscreen texture " << maOffscreenTex
.Id() );
478 mpFlush
->SetPriority( SchedulerPriority::POST_PAINT
);
479 mpContext
->ReleaseFramebuffer( maOffscreenTex
);
480 maOffscreenTex
= OpenGLTexture();
484 if( !maOffscreenTex
)
486 VCL_GL_INFO( "create texture of size "
487 << GetWidth() << " x " << GetHeight() );
488 maOffscreenTex
= OpenGLTexture( GetWidth(), GetHeight() );
489 bClearTexture
= true;
492 if( !maOffscreenTex
.IsUnique() )
494 GLfloat fWidth
= GetWidth();
495 GLfloat fHeight
= GetHeight();
496 SalTwoRect
aPosAry(0, 0, fWidth
, fHeight
, 0,0, fWidth
, fHeight
);
498 // TODO: lfrb: User GL_ARB_copy_image?
499 OpenGLTexture aNewTex
= OpenGLTexture( GetWidth(), GetHeight() );
501 mpContext
->state()->scissor().disable();
502 mpContext
->state()->stencil().disable();
504 mpContext
->AcquireFramebuffer( aNewTex
);
505 DrawTexture( maOffscreenTex
, aPosAry
);
506 maOffscreenTex
= aNewTex
;
510 mpContext
->AcquireFramebuffer( maOffscreenTex
);
515 glDrawBuffer( GL_COLOR_ATTACHMENT0
);
516 #if OSL_DEBUG_LEVEL > 0 // lets have some red debugging background.
517 GLfloat clearColor
[4] = { 1.0, 0, 0, 0 };
519 GLfloat clearColor
[4] = { 1.0, 1.0, 1.0, 0 };
521 glClearBufferfv( GL_COLOR
, 0, clearColor
);
522 // FIXME: use glClearTexImage if we have it ?
526 assert( maOffscreenTex
);
532 bool OpenGLSalGraphicsImpl::UseProgram( const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OString
& preamble
)
534 if( mpProgram
!= nullptr )
536 mpProgram
= mpContext
->UseProgram( rVertexShader
, rFragmentShader
, preamble
);
538 mProgramIsSolidColor
= false; // UseSolid() will set to true if needed
540 return ( mpProgram
!= nullptr );
543 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
, sal_uInt8 nTransparency
)
545 if( nColor
== SALCOLOR_NONE
)
547 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
549 mpProgram
->SetShaderType(DrawShaderType::Normal
);
550 mpProgram
->SetColor( "color", nColor
, nTransparency
);
552 mProgramIsSolidColor
= true;
554 mProgramSolidColor
= nColor
;
555 mProgramSolidTransparency
= nTransparency
/ 100.0;
560 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
, double fTransparency
)
562 if( nColor
== SALCOLOR_NONE
)
564 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
566 mpProgram
->SetShaderType(DrawShaderType::Normal
);
567 mpProgram
->SetColorf( "color", nColor
, fTransparency
);
569 mProgramIsSolidColor
= true;
571 mProgramSolidColor
= nColor
;
572 mProgramSolidTransparency
= fTransparency
;
576 bool OpenGLSalGraphicsImpl::UseInvert50()
578 if( !UseProgram( "dumbVertexShader", "invert50FragmentShader" ) )
583 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
)
585 return UseSolid( nColor
, 0.0f
);
588 bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags
)
592 if( ( nFlags
& SalInvert::N50
) ||
593 ( nFlags
& SalInvert::TrackFrame
) )
595 // FIXME: Trackframe really should be 2 pix. on/off stipple.
598 mpProgram
->SetBlendMode( GL_ONE_MINUS_DST_COLOR
,
599 GL_ONE_MINUS_SRC_COLOR
);
603 if( !UseSolid( MAKE_SALCOLOR( 255, 255, 255 ) ) )
605 mpProgram
->SetBlendMode( GL_ONE_MINUS_DST_COLOR
, GL_ZERO
);
610 void OpenGLSalGraphicsImpl::DrawPoint( long nX
, long nY
)
614 std::vector
<GLfloat
> pPoint
{
615 GLfloat(nX
), GLfloat(nY
)
618 ApplyProgramMatrices(0.5f
);
619 mpProgram
->DrawArrays(GL_POINTS
, pPoint
);
623 void OpenGLSalGraphicsImpl::DrawLine( double nX1
, double nY1
, double nX2
, double nY2
)
627 std::vector
<GLfloat
> pPoint
{
628 GLfloat(nX1
), GLfloat(nY1
),
629 GLfloat(nX2
), GLfloat(nY2
)
632 ApplyProgramMatrices(0.5f
);
633 mpProgram
->DrawArrays(GL_LINES
, pPoint
);
640 inline void addVertex(std::vector
<GLfloat
>& rVertices
, std::vector
<GLfloat
>& rExtrusionVectors
, glm::vec2 point
, glm::vec2 extrusionVector
, float length
)
642 rVertices
.push_back(point
.x
);
643 rVertices
.push_back(point
.y
);
645 rExtrusionVectors
.push_back(extrusionVector
.x
);
646 rExtrusionVectors
.push_back(extrusionVector
.y
);
647 rExtrusionVectors
.push_back(length
);
650 inline void addVertexPair(std::vector
<GLfloat
>& rVertices
, std::vector
<GLfloat
>& rExtrusionVectors
, const glm::vec2
& point
, const glm::vec2
& extrusionVector
, float length
)
652 addVertex(rVertices
, rExtrusionVectors
, point
, -extrusionVector
, -length
);
653 addVertex(rVertices
, rExtrusionVectors
, point
, extrusionVector
, length
);
656 inline glm::vec2
normalize(const glm::vec2
& vector
)
658 if (glm::length(vector
) > 0.0)
659 return glm::normalize(vector
);
663 } // end anonymous namespace
665 void OpenGLSalGraphicsImpl::DrawLineCap(float x1
, float y1
, float x2
, float y2
, css::drawing::LineCap eLineCap
, float fLineWidth
)
667 if (eLineCap
!= css::drawing::LineCap_ROUND
&& eLineCap
!= css::drawing::LineCap_SQUARE
)
672 const int nRoundCapIteration
= 12;
674 std::vector
<GLfloat
> aVertices
;
675 std::vector
<GLfloat
> aExtrusionVectors
;
677 glm::vec2
p1(x1
, y1
);
678 glm::vec2
p2(x2
, y2
);
679 glm::vec2 lineVector
= normalize(p2
- p1
);
680 glm::vec2 normal
= glm::vec2(-lineVector
.y
, lineVector
.x
);
682 if (eLineCap
== css::drawing::LineCap_ROUND
)
684 for (int nFactor
= 0; nFactor
<= nRoundCapIteration
; nFactor
++)
686 float angle
= float(nFactor
) * (M_PI
/ float(nRoundCapIteration
));
687 glm::vec2
roundNormal(normal
.x
* glm::cos(angle
) - normal
.y
* glm::sin(angle
),
688 normal
.x
* glm::sin(angle
) + normal
.y
* glm::cos(angle
));
690 addVertexPair(aVertices
, aExtrusionVectors
, p1
, roundNormal
, 1.0f
);
693 else if (eLineCap
== css::drawing::LineCap_SQUARE
)
695 glm::vec2 extrudedPoint
= p1
+ -lineVector
* (fLineWidth
/ 2.0f
);
697 addVertexPair(aVertices
, aExtrusionVectors
, extrudedPoint
, normal
, 1.0f
);
698 addVertexPair(aVertices
, aExtrusionVectors
, p1
, normal
, 1.0f
);
701 ApplyProgramMatrices(0.5f
);
702 mpProgram
->SetExtrusionVectors(aExtrusionVectors
.data());
703 mpProgram
->DrawArrays(GL_TRIANGLE_STRIP
, aVertices
);
708 void OpenGLSalGraphicsImpl::DrawLineSegment(float x1
, float y1
, float x2
, float y2
)
710 glm::vec2
p1(x1
, y1
);
711 glm::vec2
p2(x2
, y2
);
713 std::vector
<GLfloat
> aPoints
;
714 std::vector
<GLfloat
> aExtrusionVectors
;
718 glm::vec2 lineVector
= normalize(p2
- p1
);
719 glm::vec2 normal
= glm::vec2(-lineVector
.y
, lineVector
.x
);
721 addVertexPair(aPoints
, aExtrusionVectors
, p1
, normal
, 1.0f
);
722 addVertexPair(aPoints
, aExtrusionVectors
, p2
, normal
, 1.0f
);
724 ApplyProgramMatrices(0.5f
);
725 mpProgram
->SetExtrusionVectors(aExtrusionVectors
.data());
726 mpProgram
->DrawArrays(GL_TRIANGLE_STRIP
, aPoints
);
731 /** Draw a simple (non bezier) polyline
733 * OpenGL polyline drawing algorithm inspired by:
734 * - http://mattdesl.svbtle.com/drawing-lines-is-hard
735 * - https://www.mapbox.com/blog/drawing-antialiased-lines/
736 * - https://cesiumjs.org/2013/04/22/Robust-Polyline-Rendering-with-WebGL/
737 * - http://artgrammer.blogspot.si/2011/05/drawing-nearly-perfect-2d-line-segments.html
738 * - http://artgrammer.blogspot.si/2011/07/drawing-polylines-by-tessellation.html
741 void OpenGLSalGraphicsImpl::DrawPolyLine(const basegfx::B2DPolygon
& rPolygon
, float fLineWidth
, basegfx::B2DLineJoin eLineJoin
, css::drawing::LineCap eLineCap
, float fMiterMinimumAngle
)
743 sal_uInt32 nPoints
= rPolygon
.count();
744 bool bClosed
= rPolygon
.isClosed();
746 if (!bClosed
&& nPoints
>= 2)
750 glm::vec2
p1(rPolygon
.getB2DPoint(0).getX(), rPolygon
.getB2DPoint(0).getY());
751 glm::vec2
p2(rPolygon
.getB2DPoint(1).getX(), rPolygon
.getB2DPoint(1).getY());
752 DrawLineCap(p1
.x
, p1
.y
, p2
.x
, p2
.y
, eLineCap
, fLineWidth
);
757 glm::vec2
p1(rPolygon
.getB2DPoint(nPoints
- 1).getX(), rPolygon
.getB2DPoint(nPoints
- 1).getY());
758 glm::vec2
p2(rPolygon
.getB2DPoint(nPoints
- 2).getX(), rPolygon
.getB2DPoint(nPoints
- 2).getY());
759 DrawLineCap(p1
.x
, p1
.y
, p2
.x
, p2
.y
, eLineCap
, fLineWidth
);
763 if (nPoints
== 2 || eLineJoin
== basegfx::B2DLineJoin::NONE
)
765 // If line joint is NONE or a simple line with 2 points, draw the polyline
766 // each line segment separatly.
767 for (int i
= 0; i
< int(nPoints
) - 1; ++i
)
769 glm::vec2
p1(rPolygon
.getB2DPoint(i
+0).getX(), rPolygon
.getB2DPoint(i
+0).getY());
770 glm::vec2
p2(rPolygon
.getB2DPoint(i
+1).getX(), rPolygon
.getB2DPoint(i
+1).getY());
771 DrawLineSegment(p1
.x
, p1
.y
, p2
.x
, p2
.y
);
775 glm::vec2
p1(rPolygon
.getB2DPoint(nPoints
- 1).getX(), rPolygon
.getB2DPoint(nPoints
- 1).getY());
776 glm::vec2
p2(rPolygon
.getB2DPoint(0).getX(), rPolygon
.getB2DPoint(0).getY());
777 DrawLineSegment(p1
.x
, p1
.y
, p2
.x
, p2
.y
);
780 else if (nPoints
> 2)
785 int lastPoint
= int(nPoints
);
787 std::vector
<GLfloat
> aVertices
;
788 std::vector
<GLfloat
> aExtrusionVectors
;
790 // First guess on the size, but we could know relatively exactly
791 // how much vertices we need.
792 aVertices
.reserve(nPoints
* 4);
793 aExtrusionVectors
.reserve(nPoints
* 6);
795 // Handle first point
797 glm::vec2 nextLineVector
;
798 glm::vec2 previousLineVector
;
799 glm::vec2 normal
; // perpendicular to the line vector
801 glm::vec2
p0(rPolygon
.getB2DPoint(nPoints
- 1).getX(), rPolygon
.getB2DPoint(nPoints
- 1).getY());
802 glm::vec2
p1(rPolygon
.getB2DPoint(0).getX(), rPolygon
.getB2DPoint(0).getY());
803 glm::vec2
p2(rPolygon
.getB2DPoint(1).getX(), rPolygon
.getB2DPoint(1).getY());
805 nextLineVector
= normalize(p2
- p1
);
809 normal
= glm::vec2(-nextLineVector
.y
, nextLineVector
.x
); // make perpendicular
810 addVertexPair(aVertices
, aExtrusionVectors
, p1
, normal
, 1.0f
);
812 i
++; // first point done already
813 lastPoint
--; // last point will be calculated separatly from the loop
816 previousLineVector
= nextLineVector
;
820 lastPoint
++; // we need to connect last point to first point so one more line segment to calculate
822 previousLineVector
= normalize(p1
- p0
);
825 for (; i
< lastPoint
; ++i
)
827 int index1
= (i
+ 0) % nPoints
; // loop indices - important when polyline is closed
828 int index2
= (i
+ 1) % nPoints
;
830 p1
= glm::vec2(rPolygon
.getB2DPoint(index1
).getX(), rPolygon
.getB2DPoint(index1
).getY());
831 p2
= glm::vec2(rPolygon
.getB2DPoint(index2
).getX(), rPolygon
.getB2DPoint(index2
).getY());
833 if (p1
== p2
) // skip equal points, normals could div-by-0
836 nextLineVector
= normalize(p2
- p1
);
838 if (eLineJoin
== basegfx::B2DLineJoin::Miter
)
840 float angle
= std::atan2(previousLineVector
.x
* nextLineVector
.y
- previousLineVector
.y
* nextLineVector
.x
,
841 previousLineVector
.x
* nextLineVector
.x
+ previousLineVector
.y
* nextLineVector
.y
);
843 angle
= F_PI
- std::fabs(angle
);
845 if (angle
< fMiterMinimumAngle
)
846 eLineJoin
= basegfx::B2DLineJoin::Bevel
;
849 if (eLineJoin
== basegfx::B2DLineJoin::Miter
)
851 // With miter join we calculate the extrusion vector by adding normals of
852 // previous and next line segment. The vector shows the way but we also
853 // need the length (otherwise the line will be deformed). Length factor is
854 // calculated as dot product of extrusion vector and one of the normals.
855 // The value we get is the inverse length (used in the shader):
856 // length = line_width / dot(extrusionVector, normal)
858 normal
= glm::vec2(-previousLineVector
.y
, previousLineVector
.x
);
860 glm::vec2 tangent
= normalize(nextLineVector
+ previousLineVector
);
861 glm::vec2
extrusionVector(-tangent
.y
, tangent
.x
);
862 GLfloat length
= glm::dot(extrusionVector
, normal
);
864 addVertexPair(aVertices
, aExtrusionVectors
, p1
, extrusionVector
, length
);
866 else if (eLineJoin
== basegfx::B2DLineJoin::Bevel
)
868 // For bevel join we just add 2 additional vertices and use previous
869 // line segment normal and next line segment normal as extrusion vector.
870 // All the magic is done by the fact that we draw triangle strips, so we
871 // cover the joins correctly.
873 glm::vec2 previousNormal
= glm::vec2(-previousLineVector
.y
, previousLineVector
.x
);
874 glm::vec2 nextNormal
= glm::vec2(-nextLineVector
.y
, nextLineVector
.x
);
876 addVertexPair(aVertices
, aExtrusionVectors
, p1
, previousNormal
, 1.0f
);
877 addVertexPair(aVertices
, aExtrusionVectors
, p1
, nextNormal
, 1.0f
);
879 else if (eLineJoin
== basegfx::B2DLineJoin::Round
)
881 // For round join we do a similar thing as in bevel, we add more intermediate
882 // vertices and add normals to get extrusion vectors in the between the
885 // 3 additional extrusion vectors + normals are enough to make most
886 // line joins look round. Ideally the number of vectors could be
889 glm::vec2 previousNormal
= glm::vec2(-previousLineVector
.y
, previousLineVector
.x
);
890 glm::vec2 nextNormal
= glm::vec2(-nextLineVector
.y
, nextLineVector
.x
);
892 glm::vec2 middle
= normalize(previousNormal
+ nextNormal
);
893 glm::vec2 middleLeft
= normalize(previousNormal
+ middle
);
894 glm::vec2 middleRight
= normalize(middle
+ nextNormal
);
896 addVertexPair(aVertices
, aExtrusionVectors
, p1
, previousNormal
, 1.0f
);
897 addVertexPair(aVertices
, aExtrusionVectors
, p1
, middleLeft
, 1.0f
);
898 addVertexPair(aVertices
, aExtrusionVectors
, p1
, middle
, 1.0f
);
899 addVertexPair(aVertices
, aExtrusionVectors
, p1
, middleRight
, 1.0f
);
900 addVertexPair(aVertices
, aExtrusionVectors
, p1
, nextNormal
, 1.0f
);
903 previousLineVector
= nextLineVector
;
908 // Create vertices for the last point. There is no line join so just
909 // use the last line segment normal as the extrusion vector.
911 p1
= glm::vec2(rPolygon
.getB2DPoint(nPoints
- 1).getX(), rPolygon
.getB2DPoint(nPoints
- 1).getY());
913 normal
= glm::vec2(-previousLineVector
.y
, previousLineVector
.x
);
915 addVertexPair(aVertices
, aExtrusionVectors
, p1
, normal
, 1.0f
);
918 ApplyProgramMatrices(0.5f
);
919 mpProgram
->SetExtrusionVectors(aExtrusionVectors
.data());
920 mpProgram
->DrawArrays(GL_TRIANGLE_STRIP
, aVertices
);
926 bool OpenGLSalGraphicsImpl::UseLine(SalColor nColor
, double fTransparency
, GLfloat fLineWidth
, bool bUseAA
)
928 if( nColor
== SALCOLOR_NONE
)
930 if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
932 mpProgram
->SetShaderType(DrawShaderType::Line
);
933 mpProgram
->SetColorf("color", nColor
, fTransparency
);
934 mpProgram
->SetUniform1f("line_width", fLineWidth
);
935 // The width of the feather - area we make lineary transparent in VS.
936 // Good AA value is 0.5f, no AA if feather 0.0f
937 mpProgram
->SetUniform1f("feather", bUseAA
? 0.5f
: 0.0f
);
938 // We need blending or AA won't work correctly
939 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
941 mProgramIsSolidColor
= true;
943 mProgramSolidColor
= nColor
;
944 mProgramSolidTransparency
= fTransparency
;
948 void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, bool blockAA
)
952 std::vector
<GLfloat
> aVertices(nPoints
* 2);
955 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
957 aVertices
[j
] = GLfloat(pPtAry
[i
].mnX
);
958 aVertices
[j
+1] = GLfloat(pPtAry
[i
].mnY
);
961 ApplyProgramMatrices();
962 mpProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
965 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
967 // Make the edges antialiased by drawing the edge lines again with AA.
968 // TODO: If transparent drawing is set up, drawing the lines themselves twice
969 // may be a problem, if that is a real problem, the polygon areas itself needs to be
970 // masked out for this or something.
972 assert( mProgramIsSolidColor
);
974 SalColor lastSolidColor
= mProgramSolidColor
;
975 double lastSolidTransparency
= mProgramSolidTransparency
;
976 if (UseLine(lastSolidColor
, lastSolidTransparency
, 1.0f
, true))
978 for( i
= 0; i
< nPoints
; ++i
)
980 const SalPoint
& rPt1
= pPtAry
[ i
];
981 const SalPoint
& rPt2
= pPtAry
[ ( i
+ 1 ) % nPoints
];
982 DrawLineSegment(rPt1
.mnX
, rPt1
.mnY
, rPt2
.mnX
, rPt2
.mnY
);
984 UseSolid( lastSolidColor
, lastSolidTransparency
);
989 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const tools::Polygon
& rPolygon
, bool blockAA
)
993 sal_uInt16 nPoints
= rPolygon
.GetSize() - 1;
994 std::vector
<GLfloat
> aVertices(nPoints
* 2);
997 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
999 const Point
& rPt
= rPolygon
.GetPoint( i
);
1000 aVertices
[j
] = GLfloat(rPt
.X());
1001 aVertices
[j
+1] = GLfloat(rPt
.Y());
1004 ApplyProgramMatrices();
1005 mpProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
1008 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
1010 // Make the edges antialiased by drawing the edge lines again with AA.
1011 // TODO: If transparent drawing is set up, drawing the lines themselves twice
1012 // may be a problem, if that is a real problem, the polygon areas itself needs to be
1013 // masked out for this or something.
1015 assert( mProgramIsSolidColor
);
1017 SalColor lastSolidColor
= mProgramSolidColor
;
1018 double lastSolidTransparency
= mProgramSolidTransparency
;
1019 if (UseLine(lastSolidColor
, lastSolidTransparency
, 1.0f
, true))
1021 for( i
= 0; i
< nPoints
; ++i
)
1023 const Point
& rPt1
= rPolygon
.GetPoint( i
);
1024 const Point
& rPt2
= rPolygon
.GetPoint(( i
+ 1 ) % nPoints
);
1025 DrawLineSegment(rPt1
.getX(), rPt1
.getY(), rPt2
.getX(), rPt2
.getY());
1027 UseSolid( lastSolidColor
, lastSolidTransparency
);
1032 void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid
& trapezoid
, bool blockAA
)
1036 const basegfx::B2DPolygon
& rPolygon
= trapezoid
.getB2DPolygon();
1037 sal_uInt16 nPoints
= rPolygon
.count();
1038 std::vector
<GLfloat
> aVertices(nPoints
* 2);
1041 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
1043 const basegfx::B2DPoint
& rPt
= rPolygon
.getB2DPoint( i
);
1044 aVertices
[j
] = GLfloat(rPt
.getX());
1045 aVertices
[j
+1] = GLfloat(rPt
.getY());
1050 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
1054 ApplyProgramMatrices();
1055 mpProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
1058 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
1060 // Make the edges antialiased by drawing the edge lines again with AA.
1061 // TODO: If transparent drawing is set up, drawing the lines themselves twice
1062 // may be a problem, if that is a real problem, the polygon areas itself needs to be
1063 // masked out for this or something.
1065 assert( mProgramIsSolidColor
);
1067 SalColor lastSolidColor
= mProgramSolidColor
;
1068 double lastSolidTransparency
= mProgramSolidTransparency
;
1069 if (UseLine(lastSolidColor
, lastSolidTransparency
, 1.0f
, true))
1071 for( i
= 0; i
< nPoints
; ++i
)
1073 const basegfx::B2DPoint
& rPt1
= rPolygon
.getB2DPoint( i
);
1074 const basegfx::B2DPoint
& rPt2
= rPolygon
.getB2DPoint(( i
+ 1 ) % nPoints
);
1075 DrawLineSegment(rPt1
.getX(), rPt1
.getY(), rPt2
.getX(), rPt2
.getY());
1077 UseSolid( lastSolidColor
, lastSolidTransparency
);
1082 void OpenGLSalGraphicsImpl::DrawRect( long nX
, long nY
, long nWidth
, long nHeight
)
1086 long nX2( nX
+ nWidth
);
1087 long nY2( nY
+ nHeight
);
1088 const SalPoint aPoints
[] = { { nX1
, nY2
}, { nX1
, nY1
},
1089 { nX2
, nY1
}, { nX2
, nY2
}};
1091 DrawConvexPolygon( 4, aPoints
, true );
1094 void OpenGLSalGraphicsImpl::DrawRect( const Rectangle
& rRect
)
1096 long nX1( rRect
.Left() );
1097 long nY1( rRect
.Top() );
1098 long nX2( rRect
.Right() );
1099 long nY2( rRect
.Bottom() );
1100 const SalPoint aPoints
[] = { { nX1
, nY2
}, { nX1
, nY1
},
1101 { nX2
, nY1
}, { nX2
, nY2
}};
1103 DrawConvexPolygon( 4, aPoints
, true );
1106 void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1108 basegfx::B2DPolygon aPolygon
;
1110 for( sal_uInt32 i
= 0; i
< nPoints
; i
++ )
1111 aPolygon
.append( basegfx::B2DPoint( pPtAry
[i
].mnX
, pPtAry
[i
].mnY
) );
1112 aPolygon
.setClosed( true );
1114 if( basegfx::tools::isConvex( aPolygon
) )
1117 DrawConvexPolygon( nPoints
, pPtAry
);
1121 const basegfx::B2DPolyPolygon
aPolyPolygon( aPolygon
);
1122 DrawPolyPolygon( aPolyPolygon
);
1126 void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon
& rPolyPolygon
, bool blockAA
)
1128 const basegfx::B2DPolyPolygon
& aSimplePolyPolygon
= ::basegfx::tools::solveCrossovers( rPolyPolygon
);
1129 basegfx::B2DTrapezoidVector aB2DTrapVector
;
1130 basegfx::tools::trapezoidSubdivide( aB2DTrapVector
, aSimplePolyPolygon
);
1131 // draw tesselation result
1132 if( aB2DTrapVector
.size())
1134 for(basegfx::B2DTrapezoid
& i
: aB2DTrapVector
)
1135 DrawTrapezoid( i
, blockAA
);
1139 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand
& rRegion
)
1143 RectangleVector aRects
;
1144 std::vector
<GLfloat
> aVertices
;
1145 rRegion
.GetRegionRectangles( aRects
);
1147 if( aRects
.empty() )
1150 #define ADD_VERTICE(pt) \
1151 aVertices.push_back(GLfloat(pt.X())); \
1152 aVertices.push_back(GLfloat(pt.Y()));
1154 for(Rectangle
& rRect
: aRects
)
1156 rRect
.Bottom() += 1;
1158 ADD_VERTICE( rRect
.TopLeft() );
1159 ADD_VERTICE( rRect
.TopRight() );
1160 ADD_VERTICE( rRect
.BottomLeft() );
1161 ADD_VERTICE( rRect
.BottomLeft() );
1162 ADD_VERTICE( rRect
.TopRight() );
1163 ADD_VERTICE( rRect
.BottomRight() );
1167 ApplyProgramMatrices();
1168 mpProgram
->DrawArrays(GL_TRIANGLES
, aVertices
);
1172 void OpenGLSalGraphicsImpl::DrawTextureRect( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
)
1176 SAL_INFO("vcl.opengl", "draw texture rect");
1178 GLfloat aTexCoord
[8];
1179 rTexture
.GetCoord( aTexCoord
, rPosAry
, bInverted
);
1180 mpProgram
->SetTextureCoord( aTexCoord
);
1181 DrawRect( rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
1184 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& pPosAry
, bool bInverted
)
1188 SAL_INFO("vcl.opengl", "draw texture");
1190 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1192 mpProgram
->SetShaderType(TextureShaderType::Normal
);
1193 mpProgram
->SetIdentityTransform("transform");
1194 mpProgram
->SetTexture("texture", rTexture
);
1195 DrawTextureRect( rTexture
, pPosAry
, bInverted
);
1201 bool scaleTexture(const rtl::Reference
< OpenGLContext
> &xContext
,
1202 OpenGLTexture
& rOutTexture
, const double& ixscale
, const double& iyscale
, OpenGLTexture
& rTexture
)
1204 int nWidth
= rTexture
.GetWidth();
1205 int nHeight
= rTexture
.GetHeight();
1206 int nNewWidth
= nWidth
/ ixscale
;
1207 int nNewHeight
= nHeight
/ iyscale
;
1209 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", "areaScaleFragmentShader");
1210 if (pProgram
== nullptr)
1213 OpenGLTexture
aScratchTex(nNewWidth
, nNewHeight
);
1214 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aScratchTex
);
1216 pProgram
->SetUniform1f("xscale", ixscale
);
1217 pProgram
->SetUniform1f("yscale", iyscale
);
1218 pProgram
->SetUniform1i("swidth", nWidth
);
1219 pProgram
->SetUniform1i("sheight", nHeight
);
1220 // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
1221 pProgram
->SetUniform1f("xsrcconvert", 1.0 / (nWidth
- 1));
1222 pProgram
->SetUniform1f("ysrcconvert", 1.0 / (nHeight
- 1));
1223 pProgram
->SetUniform1f("xdestconvert", 1.0 * (nNewWidth
- 1));
1224 pProgram
->SetUniform1f("ydestconvert", 1.0 * (nNewHeight
- 1));
1226 pProgram
->SetTexture("sampler", rTexture
);
1227 pProgram
->DrawTexture(rTexture
);
1230 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
1234 rOutTexture
= aScratchTex
;
1240 void OpenGLSalGraphicsImpl::DrawTransformedTexture(
1241 OpenGLTexture
& rTexture
,
1242 OpenGLTexture
& rMask
,
1243 const basegfx::B2DPoint
& rNull
,
1244 const basegfx::B2DPoint
& rX
,
1245 const basegfx::B2DPoint
& rY
)
1249 std::vector
<GLfloat
> aVertices
= {
1250 0, GLfloat(rTexture
.GetHeight()),
1252 GLfloat(rTexture
.GetWidth()), 0,
1253 GLfloat(rTexture
.GetWidth()), GLfloat(rTexture
.GetHeight())
1256 GLfloat aTexCoord
[8];
1258 const long nDestWidth
= basegfx::fround(basegfx::B2DVector(rX
- rNull
).getLength());
1259 const long nDestHeight
= basegfx::fround(basegfx::B2DVector(rY
- rNull
).getLength());
1261 // Invisibly small images shouldn't divide by zero.
1262 if( nDestHeight
== 0 || nDestWidth
== 0 )
1265 // inverted scale ratios
1266 double ixscale
= rTexture
.GetWidth() / double(nDestWidth
);
1267 double iyscale
= rTexture
.GetHeight() / double(nDestHeight
);
1269 // If downscaling at a higher scale ratio, use the area scaling algorithm rather
1270 // than plain OpenGL's scaling (texture mapping), for better results.
1271 // See OpenGLSalBitmap::ImplScaleArea().
1272 bool areaScaling
= false;
1273 bool fastAreaScaling
= false;
1274 OUString textureFragmentShader
;
1275 if( ixscale
>= 2 && iyscale
>= 2 ) // scale ratio less than 50%
1278 fastAreaScaling
= ( ixscale
== int( ixscale
) && iyscale
== int( iyscale
));
1279 // The generic case has arrays only up to 16 ratio downscaling and is performed in 2 passes,
1280 // when the ratio is in the 16-100 range, which is hopefully enough in practice, but protect
1281 // against buffer overflows in case such an extreme case happens (and in such case the precision
1282 // of the generic algorithm probably doesn't matter anyway).
1283 if( ixscale
> 100 || iyscale
> 100 )
1284 fastAreaScaling
= true;
1285 if( fastAreaScaling
)
1286 textureFragmentShader
= "areaScaleFastFragmentShader";
1288 textureFragmentShader
= "areaScaleFragmentShader";
1291 OpenGLTexture aInTexture
= rTexture
;
1292 OpenGLTexture aInMask
= rMask
;
1294 // When using the area scaling algorithm we need to reduce the texture size in 2 passes
1295 // in order to not use a big array inside the fragment shader.
1296 if (areaScaling
&& !fastAreaScaling
)
1298 // Perform a first texture downscaling by an inverted scale ratio equal to
1299 // the square root of the whole inverted scale ratio.
1300 if (ixscale
> 16 || iyscale
> 16)
1302 // The scissor area is set to the current window size in PreDraw,
1303 // so if we do not disable the scissor test, the texture produced
1304 // by the first downscaling is clipped to the current window size.
1305 mpContext
->state()->scissor().disable();
1306 mpContext
->state()->stencil().disable();
1308 // the square root of the whole inverted scale ratio
1309 double ixscalesqrt
= std::floor(std::sqrt(ixscale
));
1310 double iyscalesqrt
= std::floor(std::sqrt(iyscale
));
1311 ixscale
/= ixscalesqrt
; // second pass inverted x-scale factor
1312 iyscale
/= iyscalesqrt
; // second pass inverted y-scale factor
1314 scaleTexture(mpContext
, aInTexture
, ixscalesqrt
, iyscalesqrt
, rTexture
);
1316 if (rMask
) // we need to downscale the mask too
1318 scaleTexture(mpContext
, aInMask
, ixscalesqrt
, iyscalesqrt
, rMask
);
1321 // We need to re-acquire the off-screen texture.
1322 CheckOffscreenTexture();
1325 // Re-enable scissor and stencil tests if needed.
1327 mpContext
->state()->scissor().enable();
1330 mpContext
->state()->stencil().enable();
1336 if( !UseProgram( "transformedTextureVertexShader",
1337 textureFragmentShader
.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader
,
1338 "#define MASKED" ) )
1340 mpProgram
->SetTexture( "mask", aInMask
);
1341 GLfloat aMaskCoord
[8];
1342 aInMask
.GetWholeCoord(aMaskCoord
);
1343 mpProgram
->SetMaskCoord(aMaskCoord
);
1344 aInMask
.SetFilter( GL_LINEAR
);
1345 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1349 if( !UseProgram( "transformedTextureVertexShader",
1350 textureFragmentShader
.isEmpty() ? "textureFragmentShader" : textureFragmentShader
) )
1356 int nWidth
= aInTexture
.GetWidth();
1357 int nHeight
= aInTexture
.GetHeight();
1359 // From OpenGLSalBitmap::ImplScaleArea().
1360 if (fastAreaScaling
&& nWidth
&& nHeight
)
1362 mpProgram
->SetUniform1i( "xscale", ixscale
);
1363 mpProgram
->SetUniform1i( "yscale", iyscale
);
1364 mpProgram
->SetUniform1f( "xstep", 1.0 / nWidth
);
1365 mpProgram
->SetUniform1f( "ystep", 1.0 / nHeight
);
1366 mpProgram
->SetUniform1f( "ratio", 1.0 / ( ixscale
* iyscale
));
1368 else if (nHeight
> 1 && nWidth
> 1)
1370 mpProgram
->SetUniform1f( "xscale", ixscale
);
1371 mpProgram
->SetUniform1f( "yscale", iyscale
);
1372 mpProgram
->SetUniform1i( "swidth", nWidth
);
1373 mpProgram
->SetUniform1i( "sheight", nHeight
);
1374 // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
1375 mpProgram
->SetUniform1f( "xsrcconvert", 1.0 / ( nWidth
- 1 ));
1376 mpProgram
->SetUniform1f( "ysrcconvert", 1.0 / ( nHeight
- 1 ));
1377 mpProgram
->SetUniform1f( "xdestconvert", 1.0 * (( nWidth
/ ixscale
) - 1 ));
1378 mpProgram
->SetUniform1f( "ydestconvert", 1.0 * (( nHeight
/ iyscale
) - 1 ));
1382 ApplyProgramMatrices();
1383 mpProgram
->SetUniform2f( "viewport", GetWidth(), GetHeight() );
1384 // Here, in order to get the correct transformation we need to pass the original texture,
1385 // since it has been used for initializing the rectangle vertices.
1386 mpProgram
->SetTransform( "transform", rTexture
, rNull
, rX
, rY
);
1387 aInTexture
.GetWholeCoord(aTexCoord
);
1388 mpProgram
->SetTexture("sampler", aInTexture
);
1389 aInTexture
.SetFilter(GL_LINEAR
);
1390 mpProgram
->SetTextureCoord( aTexCoord
);
1391 mpProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
1397 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
, bool bPremultiplied
)
1401 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1403 mpProgram
->SetShaderType(TextureShaderType::Normal
);
1404 mpProgram
->SetIdentityTransform("transform");
1405 mpProgram
->SetTexture("texture", rTexture
);
1406 mpProgram
->SetBlendMode( bPremultiplied
? GL_ONE
: GL_SRC_ALPHA
,
1407 GL_ONE_MINUS_SRC_ALPHA
);
1408 DrawTextureRect( rTexture
, rPosAry
, bInverted
);
1412 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
, bool bInverted
)
1416 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1418 mpProgram
->SetShaderType(TextureShaderType::Diff
);
1419 mpProgram
->SetIdentityTransform("transform");
1420 mpProgram
->SetTexture( "texture", rTexture
);
1421 mpProgram
->SetTexture( "mask", rMask
);
1422 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1424 GLfloat aMaskCoord
[8];
1425 rMask
.GetCoord(aMaskCoord
, rPosAry
, bInverted
);
1426 mpProgram
->SetMaskCoord(aMaskCoord
);
1428 DrawTextureRect( rTexture
, rPosAry
, bInverted
);
1432 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
)
1436 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1438 mpProgram
->SetShaderType(TextureShaderType::Masked
);
1439 mpProgram
->SetIdentityTransform("transform");
1440 mpProgram
->SetTexture( "texture", rTexture
);
1441 mpProgram
->SetTexture( "mask", rMask
);
1442 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1444 GLfloat aTexCoord
[8];
1445 rTexture
.GetCoord(aTexCoord
, rPosAry
);
1446 mpProgram
->SetTextureCoord(aTexCoord
);
1448 GLfloat aMaskCoord
[8];
1449 rMask
.GetCoord(aMaskCoord
, rPosAry
);
1450 mpProgram
->SetMaskCoord(aMaskCoord
);
1452 DrawRect(rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
1456 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, OpenGLTexture
& rAlpha
, const SalTwoRect
& rPosAry
)
1460 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1462 mpProgram
->SetShaderType(TextureShaderType::Blend
);
1463 mpProgram
->SetTexture( "texture", rTexture
);
1464 mpProgram
->SetTexture( "mask", rMask
);
1465 mpProgram
->SetTexture( "alpha", rAlpha
);
1467 GLfloat aAlphaCoord
[8];
1468 rAlpha
.GetCoord(aAlphaCoord
, rPosAry
);
1469 mpProgram
->SetAlphaCoord(aAlphaCoord
);
1471 GLfloat aMaskCoord
[8];
1472 rMask
.GetCoord(aMaskCoord
, rPosAry
);
1473 mpProgram
->SetMaskCoord(aMaskCoord
);
1475 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1476 DrawTextureRect( rTexture
, rPosAry
);
1480 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture
& rMask
, SalColor nMaskColor
, const SalTwoRect
& pPosAry
)
1484 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1486 mpProgram
->SetShaderType(TextureShaderType::MaskedColor
);
1487 mpProgram
->SetIdentityTransform("transform");
1488 mpProgram
->SetColor( "color", nMaskColor
, 0 );
1489 mpProgram
->SetTexture("texture", rMask
);
1490 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1491 DrawTextureRect( rMask
, pPosAry
);
1495 void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture
& rTexture
, SalColor aMaskColor
, const SalTwoRect
& rPosAry
)
1497 mpAccumulatedTextures
->insert(rTexture
, aMaskColor
, rPosAry
);
1500 void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
1502 if (mpAccumulatedTextures
->empty())
1505 InitializePreDrawState();
1507 VCL_GL_INFO("FlushDeferredDrawing");
1511 #if 0 // Draw a background rect under text for debugging - same color shows text from the same texture
1512 static sal_uInt8 r
= 0xBE;
1513 static sal_uInt8 g
= 0xF0;
1514 static sal_uInt8 b
= 0xFF;
1515 static std::unordered_map
<GLuint
, Color
> aColorForTextureMap
;
1518 for (auto& rPair
: mpAccumulatedTextures
->getAccumulatedTexturesMap())
1520 OpenGLTexture
& rTexture
= rPair
.second
->maTexture
;
1522 if (aColorForTextureMap
.find(rTexture
.Id()) == aColorForTextureMap
.end())
1524 Color
aColor(r
, g
, b
);
1526 aColor
.RGBtoHSB(h
, s
, br
);
1527 aColor
= Color::HSBtoRGB((h
+ 40) % 360, s
, br
);
1528 r
= aColor
.GetRed();
1529 g
= aColor
.GetGreen();
1530 b
= aColor
.GetBlue();
1531 aColorForTextureMap
[rTexture
.Id()] = aColor
;
1533 aUseColor
= aColorForTextureMap
[rTexture
.Id()];
1535 if (!UseSolid(MAKE_SALCOLOR(aUseColor
.GetRed(), aUseColor
.GetGreen(), aUseColor
.GetBlue())))
1537 for (auto rColorTwoRectPair
: rPair
.second
->maColorTextureDrawParametersMap
)
1539 TextureDrawParameters
& rParameters
= rColorTwoRectPair
.second
;
1540 ApplyProgramMatrices();
1541 mpProgram
->SetTextureCoord(rParameters
.maTextureCoords
.data());
1542 mpProgram
->DrawArrays(GL_TRIANGLES
, rParameters
.maVertices
);
1547 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
1549 mpProgram
->SetShaderType(TextureShaderType::MaskedColor
);
1550 mpProgram
->SetIdentityTransform("transform");
1551 mpProgram
->SetBlendMode(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1553 for (auto& rPair
: mpAccumulatedTextures
->getAccumulatedTexturesMap())
1555 OpenGLTexture
& rTexture
= rPair
.second
->maTexture
;
1556 mpProgram
->SetTexture("texture", rTexture
);
1557 for (auto& rColorTwoRectPair
: rPair
.second
->maColorTextureDrawParametersMap
)
1559 mpProgram
->SetColor("color", rColorTwoRectPair
.first
, 0);
1560 TextureDrawParameters
& rParameters
= rColorTwoRectPair
.second
;
1561 ApplyProgramMatrices();
1562 mpProgram
->SetTextureCoord(rParameters
.maTextureCoords
.data());
1563 mpProgram
->DrawArrays(GL_TRIANGLES
, rParameters
.maVertices
);
1567 mpAccumulatedTextures
->clear();
1572 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1576 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1578 Color aStartCol
= rGradient
.GetStartColor();
1579 Color aEndCol
= rGradient
.GetEndColor();
1580 long nFactor
= rGradient
.GetStartIntensity();
1581 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1582 nFactor
= rGradient
.GetEndIntensity();
1583 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1585 Rectangle aBoundRect
;
1587 rGradient
.GetBoundRect( rRect
, aBoundRect
, aCenter
);
1588 tools::Polygon
aPoly( aBoundRect
);
1589 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() % 3600 );
1591 GLfloat aTexCoord
[8] = { 0, 1, 1, 1, 1, 0, 0, 0 };
1592 GLfloat fMin
= 1.0 - 100.0 / (100.0 - rGradient
.GetBorder());
1593 aTexCoord
[5] = aTexCoord
[7] = fMin
;
1594 mpProgram
->SetTextureCoord( aTexCoord
);
1595 DrawConvexPolygon( aPoly
, true );
1598 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1602 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1604 Color aStartCol
= rGradient
.GetStartColor();
1605 Color aEndCol
= rGradient
.GetEndColor();
1606 long nFactor
= rGradient
.GetStartIntensity();
1607 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1608 nFactor
= rGradient
.GetEndIntensity();
1609 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1612 * Draw two rectangles with linear gradient.
1616 * | / | Points 0 and 3 have start color
1617 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1627 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
1629 // determine points 0 and 3
1630 Point
aPt0( aRect
.Left(), (aRect
.Top() + aRect
.Bottom() + 1) / 2 );
1631 Point
aPt3( aRect
.Right(), (aRect
.Top() + aRect
.Bottom() + 1) / 2 );
1633 tools::Polygon
aPoly( 7 );
1634 aPoly
.SetPoint( aPt0
, 0 );
1635 aPoly
.SetPoint( aRect
.TopLeft(), 1 );
1636 aPoly
.SetPoint( aRect
.TopRight(), 2 );
1637 aPoly
.SetPoint( aPt3
, 3 );
1638 aPoly
.SetPoint( aRect
.BottomRight(), 4 );
1639 aPoly
.SetPoint( aRect
.BottomLeft(), 5 );
1640 aPoly
.SetPoint( aPt0
, 6 );
1641 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() % 3600 );
1643 GLfloat aTexCoord
[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 };
1644 GLfloat fMin
= 1.0 - 100.0 / (100.0 - rGradient
.GetBorder());
1645 aTexCoord
[3] = aTexCoord
[5] = aTexCoord
[9] = aTexCoord
[11] = fMin
;
1646 mpProgram
->SetTextureCoord( aTexCoord
);
1647 DrawConvexPolygon( aPoly
, true );
1650 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1654 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
1656 Color aStartCol
= rGradient
.GetStartColor();
1657 Color aEndCol
= rGradient
.GetEndColor();
1658 long nFactor
= rGradient
.GetStartIntensity();
1659 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1660 nFactor
= rGradient
.GetEndIntensity();
1661 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1665 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
1667 // adjust coordinates so that radius has distance equals to 1.0
1668 double fRadius
= aRect
.GetWidth() / 2.0f
;
1669 GLfloat fWidth
= rRect
.GetWidth() / fRadius
;
1670 GLfloat fHeight
= rRect
.GetHeight() / fRadius
;
1671 GLfloat aTexCoord
[8] = { 0, 0, 0, fHeight
, fWidth
, fHeight
, fWidth
, 0 };
1672 mpProgram
->SetTextureCoord( aTexCoord
);
1673 mpProgram
->SetUniform2f( "center", (aCenter
.X() - rRect
.Left()) / fRadius
,
1674 (aCenter
.Y() - rRect
.Top()) / fRadius
);
1679 // draw --> LineColor and FillColor and RasterOp and ClipRegion
1680 void OpenGLSalGraphicsImpl::drawPixel( long nX
, long nY
)
1682 VCL_GL_INFO( "::drawPixel" );
1683 if( mnLineColor
!= SALCOLOR_NONE
)
1685 PreDraw( XOROption::IMPLEMENT_XOR
);
1686 if( UseSolid( mnLineColor
) )
1687 DrawPoint( nX
, nY
);
1692 void OpenGLSalGraphicsImpl::drawPixel( long nX
, long nY
, SalColor nSalColor
)
1694 VCL_GL_INFO( "::drawPixel" );
1695 if( nSalColor
!= SALCOLOR_NONE
)
1697 PreDraw( XOROption::IMPLEMENT_XOR
);
1698 if( UseSolid( nSalColor
) )
1699 DrawPoint( nX
, nY
);
1704 void OpenGLSalGraphicsImpl::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
1706 VCL_GL_INFO( "::drawLine" );
1707 if( mnLineColor
!= SALCOLOR_NONE
)
1709 PreDraw( XOROption::IMPLEMENT_XOR
);
1710 if (UseLine(mnLineColor
, 0.0, 1.0f
, mrParent
.getAntiAliasB2DDraw()))
1711 DrawLineSegment(nX1
, nY1
, nX2
, nY2
);
1716 void OpenGLSalGraphicsImpl::drawRect( long nX
, long nY
, long nWidth
, long nHeight
)
1718 VCL_GL_INFO( "::drawRect" );
1719 PreDraw( XOROption::IMPLEMENT_XOR
);
1721 if( UseSolid( mnFillColor
) )
1722 DrawRect( nX
, nY
, nWidth
, nHeight
);
1724 if( UseSolid( mnLineColor
) )
1728 GLfloat
fX2(nX
+ nWidth
- 1);
1729 GLfloat
fY2(nY
+ nHeight
- 1);
1731 std::vector
<GLfloat
> pPoints
{
1738 ApplyProgramMatrices(0.5f
);
1739 mpProgram
->DrawArrays(GL_LINE_LOOP
, pPoints
);
1746 void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1748 basegfx::B2DPolygon aPoly
;
1749 aPoly
.append(basegfx::B2DPoint(pPtAry
->mnX
, pPtAry
->mnY
), nPoints
);
1750 for (sal_uInt32 i
= 1; i
< nPoints
; ++i
)
1751 aPoly
.setB2DPoint(i
, basegfx::B2DPoint(pPtAry
[i
].mnX
, pPtAry
[i
].mnY
));
1752 aPoly
.setClosed(false);
1754 drawPolyLine(aPoly
, 0.0, basegfx::B2DVector(1.0, 1.0), basegfx::B2DLineJoin::Miter
,
1755 css::drawing::LineCap_BUTT
, 15.0 * F_PI180
/*default*/);
1758 void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1760 basegfx::B2DPolygon aPoly
;
1761 aPoly
.append(basegfx::B2DPoint(pPtAry
->mnX
, pPtAry
->mnY
), nPoints
);
1762 for (sal_uInt32 i
= 1; i
< nPoints
; ++i
)
1763 aPoly
.setB2DPoint(i
, basegfx::B2DPoint(pPtAry
[i
].mnX
, pPtAry
[i
].mnY
));
1765 drawPolyPolygon(basegfx::B2DPolyPolygon(aPoly
), 0.0);
1768 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly
, const sal_uInt32
* pPointCounts
, PCONSTSALPOINT
* pPtAry
)
1770 basegfx::B2DPolyPolygon aPolyPoly
;
1771 for(sal_uInt32 nPolygon
= 0; nPolygon
< nPoly
; ++nPolygon
)
1773 sal_uInt32 nPoints
= pPointCounts
[nPolygon
];
1776 PCONSTSALPOINT pPoints
= pPtAry
[nPolygon
];
1777 basegfx::B2DPolygon aPoly
;
1778 aPoly
.append( basegfx::B2DPoint(pPoints
->mnX
, pPoints
->mnY
), nPoints
);
1779 for (sal_uInt32 i
= 1; i
< nPoints
; ++i
)
1780 aPoly
.setB2DPoint(i
, basegfx::B2DPoint( pPoints
[i
].mnX
, pPoints
[i
].mnY
));
1782 aPolyPoly
.append(aPoly
);
1786 drawPolyPolygon(aPolyPoly
, 0.0);
1789 bool OpenGLSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon
& rPolyPolygon
, double fTransparency
)
1791 VCL_GL_INFO( "::drawPolyPolygon trans " << fTransparency
);
1792 if( rPolyPolygon
.count() <= 0 )
1795 PreDraw( XOROption::IMPLEMENT_XOR
);
1797 if( UseSolid( mnFillColor
, fTransparency
) )
1798 DrawPolyPolygon( rPolyPolygon
);
1800 if( mnLineColor
!= mnFillColor
&& UseSolid( mnLineColor
, fTransparency
))
1802 basegfx::B2DTrapezoidVector aB2DTrapVector
;
1803 basegfx::tools::createLineTrapezoidFromB2DPolyPolygon( aB2DTrapVector
, rPolyPolygon
);
1804 for(basegfx::B2DTrapezoid
& i
: aB2DTrapVector
)
1813 bool OpenGLSalGraphicsImpl::drawPolyLine(
1814 const basegfx::B2DPolygon
& rPolygon
,
1815 double fTransparency
,
1816 const basegfx::B2DVector
& rLineWidth
,
1817 basegfx::B2DLineJoin eLineJoin
,
1818 css::drawing::LineCap eLineCap
,
1819 double fMiterMinimumAngle
)
1821 VCL_GL_INFO( "::drawPolyLine trans " << fTransparency
);
1822 if( mnLineColor
== SALCOLOR_NONE
)
1825 const bool bIsHairline
= (rLineWidth
.getX() == rLineWidth
.getY()) && (rLineWidth
.getX() <= 1.2);
1826 const float fLineWidth
= bIsHairline
? 1.0f
: rLineWidth
.getX();
1828 PreDraw(XOROption::IMPLEMENT_XOR
);
1830 if (UseLine(mnLineColor
, 0.0f
, fLineWidth
, mrParent
.getAntiAliasB2DDraw()))
1832 basegfx::B2DPolygon
aPolygon(rPolygon
);
1834 if (aPolygon
.areControlPointsUsed())
1835 aPolygon
= aPolygon
.getDefaultAdaptiveSubdivision();
1837 DrawPolyLine(aPolygon
, fLineWidth
, eLineJoin
, eLineCap
, fMiterMinimumAngle
);
1844 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1845 sal_uInt32
/*nPoints*/,
1846 const SalPoint
* /*pPtAry*/,
1847 const sal_uInt8
* /*pFlgAry*/ )
1852 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1853 sal_uInt32
/*nPoints*/,
1854 const SalPoint
* /*pPtAry*/,
1855 const sal_uInt8
* /*pFlgAry*/ )
1860 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1861 sal_uInt32
/*nPoly*/,
1862 const sal_uInt32
* /*pPoints*/,
1863 const SalPoint
* const* /*pPtAry*/,
1864 const sal_uInt8
* const* /*pFlgAry*/ )
1869 // CopyArea --> No RasterOp, but ClipRegion
1870 void OpenGLSalGraphicsImpl::copyArea(
1871 long nDestX
, long nDestY
,
1872 long nSrcX
, long nSrcY
,
1873 long nSrcWidth
, long nSrcHeight
, bool /*bWindowInvalidate*/ )
1875 VCL_GL_INFO( "::copyArea " << nSrcX
<< "," << nSrcY
<< " >> " << nDestX
<< "," << nDestY
<< " (" << nSrcWidth
<< "," << nSrcHeight
<< ")" );
1876 OpenGLTexture aTexture
;
1877 SalTwoRect
aPosAry(0, 0, nSrcWidth
, nSrcHeight
, nDestX
, nDestY
, nSrcWidth
, nSrcHeight
);
1880 // TODO offscreen case
1881 aTexture
= OpenGLTexture( nSrcX
, GetHeight() - nSrcY
- nSrcHeight
,
1882 nSrcWidth
, nSrcHeight
);
1883 DrawTexture( aTexture
, aPosAry
);
1887 // CopyBits and DrawBitmap --> RasterOp and ClipRegion
1888 // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
1889 void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect
& rPosAry
, OpenGLSalGraphicsImpl
& rImpl
)
1891 VCL_GL_INFO( "::copyBits" );
1893 rImpl
.FlushDeferredDrawing();
1895 if( !rImpl
.maOffscreenTex
)
1897 VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size "
1898 << rImpl
.GetWidth() << "x" << rImpl
.GetHeight() );
1902 if( &rImpl
== this &&
1903 (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
1904 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
))
1906 // short circuit if there is nothing to do
1907 if( (rPosAry
.mnSrcX
== rPosAry
.mnDestX
) &&
1908 (rPosAry
.mnSrcY
== rPosAry
.mnDestY
))
1910 // use copyArea() if source and destination context are identical
1911 copyArea( rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
1912 rPosAry
.mnSrcWidth
, rPosAry
.mnSrcHeight
, false/*bWindowInvalidate*/ );
1917 DrawTexture( rImpl
.maOffscreenTex
, rPosAry
);
1921 void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
)
1923 // check that carefully only in the debug mode
1924 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
1928 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1929 OpenGLTexture
& rTexture
= rBitmap
.GetTexture();
1931 VCL_GL_INFO( "::drawBitmap" );
1933 DrawTexture( rTexture
, rPosAry
);
1937 void OpenGLSalGraphicsImpl::drawBitmap(
1938 const SalTwoRect
& rPosAry
,
1939 const SalBitmap
& rSalBitmap
,
1940 const SalBitmap
& rMaskBitmap
)
1942 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
1943 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rMaskBitmap
));
1947 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1948 const OpenGLSalBitmap
& rMask
= static_cast<const OpenGLSalBitmap
&>(rMaskBitmap
);
1949 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1950 OpenGLTexture
& rMaskTex( rMask
.GetTexture() );
1952 VCL_GL_INFO( "::drawBitmap with MASK" );
1954 DrawTextureWithMask( rTexture
, rMaskTex
, rPosAry
);
1958 void OpenGLSalGraphicsImpl::drawMask(
1959 const SalTwoRect
& rPosAry
,
1960 const SalBitmap
& rSalBitmap
,
1961 SalColor nMaskColor
)
1963 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
1967 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1968 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1970 VCL_GL_INFO( "::drawMask" );
1972 DrawMask( rTexture
, nMaskColor
, rPosAry
);
1976 SalBitmap
* OpenGLSalGraphicsImpl::getBitmap( long nX
, long nY
, long nWidth
, long nHeight
)
1980 OpenGLSalBitmap
* pBitmap
= new OpenGLSalBitmap
;
1981 VCL_GL_INFO( "::getBitmap " << nX
<< "," << nY
<<
1982 " " << nWidth
<< "x" << nHeight
);
1983 //TODO really needed?
1985 if( !pBitmap
->Create( maOffscreenTex
, nX
, nY
, nWidth
, nHeight
) )
1994 SalColor
OpenGLSalGraphicsImpl::getPixel( long nX
, long nY
)
1996 FlushDeferredDrawing();
1998 char pixel
[3] = { 0, 0, 0 };
2000 PreDraw( XOROption::IMPLEMENT_XOR
);
2001 nY
= GetHeight() - nY
- 1;
2002 glReadPixels( nX
, nY
, 1, 1, GL_RGB
, GL_UNSIGNED_BYTE
, pixel
);
2006 return MAKE_SALCOLOR( pixel
[0], pixel
[1], pixel
[2] );
2009 // invert --> ClipRegion (only Windows or VirDevs)
2010 void OpenGLSalGraphicsImpl::invert(
2012 long nWidth
, long nHeight
,
2017 if( UseInvert( nFlags
) )
2019 if( nFlags
& SalInvert::TrackFrame
)
2020 { // FIXME: could be more efficient.
2021 DrawRect( nX
, nY
, nWidth
, 1 );
2022 DrawRect( nX
, nY
+ nHeight
, nWidth
, 1 );
2023 DrawRect( nX
, nY
, 1, nHeight
);
2024 DrawRect( nX
+ nWidth
, nY
, 1, nHeight
);
2027 DrawRect( nX
, nY
, nWidth
, nHeight
);
2033 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, SalInvert nFlags
)
2037 if( UseInvert( nFlags
) )
2038 DrawPolygon( nPoints
, pPtAry
);
2043 bool OpenGLSalGraphicsImpl::drawEPS(
2044 long /*nX*/, long /*nY*/,
2045 long /*nWidth*/, long /*nHeight*/,
2047 sal_uLong
/*nSize*/ )
2052 bool OpenGLSalGraphicsImpl::blendBitmap(
2053 const SalTwoRect
& rPosAry
,
2054 const SalBitmap
& rSalBitmap
)
2056 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
2060 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
2061 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
2063 VCL_GL_INFO( "::blendBitmap" );
2066 if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
2069 mpProgram
->SetShaderType(TextureShaderType::Normal
);
2070 mpProgram
->SetIdentityTransform("transform");
2071 mpProgram
->SetTexture("texture", rTexture
);
2072 mpProgram
->SetBlendMode(GL_ZERO
, GL_SRC_COLOR
);
2073 DrawTextureRect(rTexture
, rPosAry
);
2080 bool OpenGLSalGraphicsImpl::blendAlphaBitmap(
2081 const SalTwoRect
& rPosAry
,
2082 const SalBitmap
& rSalSrcBitmap
,
2083 const SalBitmap
& rSalMaskBitmap
,
2084 const SalBitmap
& rSalAlphaBitmap
)
2086 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalSrcBitmap
));
2087 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalMaskBitmap
));
2088 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalAlphaBitmap
));
2092 const OpenGLSalBitmap
& rSrcBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalSrcBitmap
);
2093 const OpenGLSalBitmap
& rMaskBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalMaskBitmap
);
2094 const OpenGLSalBitmap
& rAlphaBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalAlphaBitmap
);
2095 OpenGLTexture
& rTexture( rSrcBitmap
.GetTexture() );
2096 OpenGLTexture
& rMask( rMaskBitmap
.GetTexture() );
2097 OpenGLTexture
& rAlpha( rAlphaBitmap
.GetTexture() );
2099 VCL_GL_INFO( "::blendAlphaBitmap" );
2101 DrawBlendedTexture( rTexture
, rMask
, rAlpha
, rPosAry
);
2106 /** Render bitmap with alpha channel
2108 @param rSourceBitmap
2109 Source bitmap to blit
2112 Alpha channel to use for blitting
2114 @return true, if the operation succeeded, and false
2115 otherwise. In this case, clients should try to emulate alpha
2116 compositing themselves
2118 bool OpenGLSalGraphicsImpl::drawAlphaBitmap(
2119 const SalTwoRect
& rPosAry
,
2120 const SalBitmap
& rSalBitmap
,
2121 const SalBitmap
& rAlphaBitmap
)
2123 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
2124 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rAlphaBitmap
));
2128 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
2129 const OpenGLSalBitmap
& rAlpha
= static_cast<const OpenGLSalBitmap
&>(rAlphaBitmap
);
2130 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
2131 OpenGLTexture
& rAlphaTex( rAlpha
.GetTexture() );
2133 VCL_GL_INFO( "::drawAlphaBitmap" );
2135 DrawTextureWithMask( rTexture
, rAlphaTex
, rPosAry
);
2140 /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
2141 bool OpenGLSalGraphicsImpl::drawTransformedBitmap(
2142 const basegfx::B2DPoint
& rNull
,
2143 const basegfx::B2DPoint
& rX
,
2144 const basegfx::B2DPoint
& rY
,
2145 const SalBitmap
& rSrcBitmap
,
2146 const SalBitmap
* pAlphaBitmap
)
2148 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSrcBitmap
));
2149 assert(!pAlphaBitmap
|| dynamic_cast<const OpenGLSalBitmap
*>(pAlphaBitmap
));
2153 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSrcBitmap
);
2154 const OpenGLSalBitmap
* pMaskBitmap
= static_cast<const OpenGLSalBitmap
*>(pAlphaBitmap
);
2155 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
2156 OpenGLTexture aMask
; // no texture
2158 if( pMaskBitmap
!= nullptr )
2159 aMask
= pMaskBitmap
->GetTexture();
2161 VCL_GL_INFO( "::drawTransformedBitmap" );
2163 DrawTransformedTexture( rTexture
, aMask
, rNull
, rX
, rY
);
2169 /** Render solid rectangle with given transparency
2171 @param nTransparency
2172 Transparency value (0-255) to use. 0 blits and opaque, 255 a
2173 fully transparent rectangle
2175 bool OpenGLSalGraphicsImpl::drawAlphaRect(
2177 long nWidth
, long nHeight
,
2178 sal_uInt8 nTransparency
)
2180 VCL_GL_INFO( "::drawAlphaRect" );
2181 if( mnFillColor
!= SALCOLOR_NONE
&& nTransparency
< 100 )
2184 UseSolid( mnFillColor
, nTransparency
);
2185 DrawRect( nX
, nY
, nWidth
, nHeight
);
2192 bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon
& rPolyPoly
,
2193 const Gradient
& rGradient
)
2195 Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
2197 VCL_GL_INFO( "::drawGradient" );
2199 if( aBoundRect
.IsEmpty() )
2202 if( rGradient
.GetStyle() != GradientStyle_LINEAR
&&
2203 rGradient
.GetStyle() != GradientStyle_AXIAL
&&
2204 rGradient
.GetStyle() != GradientStyle_RADIAL
)
2207 aBoundRect
.Left()--;
2209 aBoundRect
.Right()++;
2210 aBoundRect
.Bottom()++;
2212 PreDraw( XOROption::IMPLEMENT_XOR
);
2214 #define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0
2215 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2216 ImplSetClipBit( vcl::Region( rPolyPoly
), 0x02 );
2219 glEnable( GL_STENCIL_TEST
);
2221 glStencilFunc( GL_EQUAL
, 3, 0xFF );
2226 glEnable( GL_STENCIL_TEST
);
2228 glStencilFunc( GL_EQUAL
, 2, 0xFF );
2233 // if border >= 100%, draw solid rectangle with start color
2234 if( rGradient
.GetBorder() >= 100.0 )
2236 Color aCol
= rGradient
.GetStartColor();
2237 long nF
= rGradient
.GetStartIntensity();
2238 if( UseSolid( MAKE_SALCOLOR( aCol
.GetRed() * nF
/ 100,
2239 aCol
.GetGreen() * nF
/ 100,
2240 aCol
.GetBlue() * nF
/ 100 ) ) )
2241 DrawRect( aBoundRect
);
2243 else if( rGradient
.GetStyle() == GradientStyle_LINEAR
)
2245 DrawLinearGradient( rGradient
, aBoundRect
);
2247 else if( rGradient
.GetStyle() == GradientStyle_AXIAL
)
2249 DrawAxialGradient( rGradient
, aBoundRect
);
2251 else if( rGradient
.GetStyle() == GradientStyle_RADIAL
)
2253 DrawRadialGradient( rGradient
, aBoundRect
);
2256 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
2259 glDisable( GL_STENCIL_TEST
);
2268 void OpenGLSalGraphicsImpl::flush()
2270 FlushDeferredDrawing();
2275 if( !Application::IsInExecute() )
2277 // otherwise nothing would trigger idle rendering
2280 else if( !mpFlush
->IsActive() )
2284 void OpenGLSalGraphicsImpl::doFlush()
2286 FlushDeferredDrawing();
2288 if (OpenGLContext::hasCurrent())
2290 mpContext
->state()->scissor().disable();
2291 mpContext
->state()->stencil().disable();
2297 if( !maOffscreenTex
)
2299 VCL_GL_INFO( "doFlush - odd no texture !" );
2303 if( mnDrawCountAtFlush
== mnDrawCount
)
2305 VCL_GL_INFO( "eliding redundant doFlush, no drawing since last!" );
2309 mnDrawCountAtFlush
= mnDrawCount
;
2313 VCL_GL_INFO( "doFlush" );
2315 if( !mpWindowContext
.is() )
2317 // ensure everything is released from the old context.
2318 OpenGLContext::clearCurrent();
2319 mpWindowContext
= CreateWinContext();
2320 VCL_GL_INFO( "late creation of window context" );
2323 assert( mpWindowContext
.is() );
2325 // Interesting ! -> this destroys a context [ somehow ] ...
2326 mpWindowContext
->makeCurrent();
2329 VCL_GL_INFO( "doFlush - acquire default framebuffer" );
2331 mpWindowContext
->state()->sync();
2333 mpWindowContext
->AcquireDefaultFramebuffer();
2336 mpWindowContext
->state()->viewport(Rectangle(Point(0, 0), Size(GetWidth(), GetHeight())));
2337 mpWindowContext
->state()->scissor().disable();
2338 mpWindowContext
->state()->stencil().disable();
2340 #if OSL_DEBUG_LEVEL > 0 // random background glClear
2341 glClearColor((float)rand()/RAND_MAX
, (float)rand()/RAND_MAX
,
2342 (float)rand()/RAND_MAX
, 1.0);
2344 glClearColor(1.0, 1.0, 1.0, 1.0);
2346 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
2349 VCL_GL_INFO( "Texture height " << maOffscreenTex
.GetHeight() << " vs. window height " << GetHeight() );
2351 OpenGLProgram
*pProgram
=
2352 mpWindowContext
->UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader", "// flush shader\n" ); // flush helps profiling
2354 VCL_GL_INFO( "Can't compile simple copying shader !" );
2357 pProgram
->SetShaderType(TextureShaderType::Normal
);
2358 pProgram
->SetIdentityTransform("transform");
2359 pProgram
->SetTexture("texture", maOffscreenTex
);
2361 SalTwoRect
aPosAry( 0, 0, maOffscreenTex
.GetWidth(), maOffscreenTex
.GetHeight(),
2362 0, 0, maOffscreenTex
.GetWidth(), maOffscreenTex
.GetHeight() );
2364 GLfloat aTexCoord
[8];
2365 maOffscreenTex
.GetCoord( aTexCoord
, aPosAry
);
2366 pProgram
->SetTextureCoord( aTexCoord
);
2368 GLfloat
fWidth( maOffscreenTex
.GetWidth() );
2369 GLfloat
fHeight( maOffscreenTex
.GetHeight() );
2370 std::vector
<GLfloat
> aVertices
{
2377 pProgram
->ApplyMatrix(GetWidth(), GetHeight(), 0.0);
2378 pProgram
->DrawArrays(GL_TRIANGLE_FAN
, aVertices
);
2382 maOffscreenTex
.Unbind();
2384 static bool bNoSwap
= getenv("SAL_GL_NO_SWAP");
2386 mpWindowContext
->swapBuffers();
2389 VCL_GL_INFO( "doFlush - end." );
2392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */