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