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"
40 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics
& rParent
, SalGeometryProvider
*pProvider
)
43 , mpProvider(pProvider
)
49 , mnLineColor(SALCOLOR_NONE
)
50 , mnFillColor(SALCOLOR_NONE
)
52 , mProgramIsSolidColor(false)
54 , mProgramSolidColor(SALCOLOR_NONE
)
55 , mProgramSolidTransparency(0.0)
59 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
64 rtl::Reference
<OpenGLContext
> OpenGLSalGraphicsImpl::GetOpenGLContext()
66 if( !AcquireContext() )
71 rtl::Reference
<OpenGLContext
> OpenGLSalGraphicsImpl::GetDefaultContext()
73 return ImplGetDefaultWindow()->GetGraphics()->GetOpenGLContext();
76 bool OpenGLSalGraphicsImpl::AcquireContext( )
78 ImplSVData
* pSVData
= ImplGetSVData();
80 // We always prefer to bind our VirtualDevice / offscreen graphics
81 // to the current OpenGLContext - to avoid switching contexts.
82 if (mpContext
.is() && mbOffscreen
)
84 if (OpenGLContext::hasCurrent() && !mpContext
->isCurrent())
90 // Check whether the context was reset underneath us.
91 if( mpContext
->isInitialized() )
96 OpenGLContext
*pContext
= pSVData
->maGDIData
.mpLastContext
;
99 // check if this context can be used by this SalGraphicsImpl instance
100 if( UseContext( pContext
) )
102 pContext
= pContext
->mpPrevContext
;
106 mpContext
= pContext
;
108 mpContext
= mbOffscreen
? GetDefaultContext() : CreateWinContext();
110 return mpContext
.is();
113 bool OpenGLSalGraphicsImpl::ReleaseContext()
120 void OpenGLSalGraphicsImpl::Init()
122 mbOffscreen
= IsOffscreen();
124 // check if we can simply re-use the same context
127 if( !mpContext
->isInitialized() ||
128 !UseContext( mpContext
) )
132 // reset the offscreen texture
134 maOffscreenTex
.GetWidth() != GetWidth() ||
135 maOffscreenTex
.GetHeight() != GetHeight() )
137 if( maOffscreenTex
&& // don't work to release empty textures
138 mpContext
.is() ) // valid context
140 mpContext
->makeCurrent();
141 mpContext
->ReleaseFramebuffer( maOffscreenTex
);
143 maOffscreenTex
= OpenGLTexture();
147 // Currently only used to get windows ordering right.
148 void OpenGLSalGraphicsImpl::DeInit()
151 // Our window handles and resources are being free underneath us.
152 // These can be bound into a context, which relies on them. So
153 // let it know. Other eg. VirtualDevice contexts which have
154 // references on and rely on this context continuing to work will
155 // get a shiny new context in AcquireContext:: next PreDraw.
156 if( mpContext
.is() && !IsOffscreen() )
160 void OpenGLSalGraphicsImpl::PreDraw()
164 if( !AcquireContext() )
166 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
170 mpContext
->makeCurrent();
174 mpContext
->AcquireDefaultFramebuffer();
176 CheckOffscreenTexture();
179 glViewport( 0, 0, GetWidth(), GetHeight() );
180 ImplInitClipRegion();
185 void OpenGLSalGraphicsImpl::PostDraw()
187 if( !mbOffscreen
&& mpContext
->mnPainting
== 0 )
190 glDisable( GL_SCISSOR_TEST
);
192 glDisable( GL_STENCIL_TEST
);
198 mProgramIsSolidColor
= false;
206 void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset
)
208 mpProgram
->ApplyMatrix(GetWidth(), GetHeight(), fPixelOffset
);
211 void OpenGLSalGraphicsImpl::freeResources()
213 // TODO Delete shaders, programs and textures if not shared
214 if( mbOffscreen
&& mpContext
.is() && mpContext
->isInitialized() )
216 mpContext
->makeCurrent();
217 mpContext
->ReleaseFramebuffer( maOffscreenTex
);
222 void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region
& rClip
, GLuint nMask
)
224 glEnable( GL_STENCIL_TEST
);
225 glColorMask( GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
226 glStencilMask( nMask
);
227 glStencilFunc( GL_NEVER
, nMask
, 0xFF );
228 glStencilOp( GL_REPLACE
, GL_KEEP
, GL_KEEP
);
230 glClear( GL_STENCIL_BUFFER_BIT
);
231 if( UseSolid( MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) ) )
233 if( rClip
.getRegionBand() )
234 DrawRegionBand( *rClip
.getRegionBand() );
236 DrawPolyPolygon( rClip
.GetAsB2DPolyPolygon(), true );
239 glColorMask( GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
240 glStencilMask( 0x00 );
241 glDisable( GL_STENCIL_TEST
);
246 void OpenGLSalGraphicsImpl::ImplInitClipRegion()
248 // make sure the context has the right clipping set
249 if( maClipRegion
!= mpContext
->maClipRegion
)
251 mpContext
->maClipRegion
= maClipRegion
;
252 if( maClipRegion
.IsRectangle() )
254 Rectangle
aRect( maClipRegion
.GetBoundRect() );
255 glScissor( aRect
.Left(), GetHeight() - aRect
.Bottom() - 1, aRect
.GetWidth() + 1, aRect
.GetHeight() + 1 );
257 else if( !maClipRegion
.IsEmpty() )
259 ImplSetClipBit( maClipRegion
, 0x01 );
264 glEnable( GL_SCISSOR_TEST
);
267 glStencilFunc( GL_EQUAL
, 1, 0x1 );
268 glEnable( GL_STENCIL_TEST
);
274 const vcl::Region
& OpenGLSalGraphicsImpl::getClipRegion() const
279 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region
& rClip
)
281 VCL_GL_INFO( "vcl.opengl", "::setClipRegion " << rClip
);
282 maClipRegion
= rClip
;
284 mbUseStencil
= false;
285 mbUseScissor
= false;
286 if( maClipRegion
.IsRectangle() )
288 else if ( !maClipRegion
.IsEmpty() )
294 // set the clip region to empty
295 void OpenGLSalGraphicsImpl::ResetClipRegion()
297 VCL_GL_INFO( "vcl.opengl", "::ResetClipRegion" );
298 maClipRegion
.SetEmpty();
299 mbUseScissor
= false;
300 mbUseStencil
= false;
303 // get the depth of the device
304 sal_uInt16
OpenGLSalGraphicsImpl::GetBitCount() const
309 // get the width of the device
310 long OpenGLSalGraphicsImpl::GetGraphicsWidth() const
315 // set the line color to transparent (= don't draw lines)
316 void OpenGLSalGraphicsImpl::SetLineColor()
318 if( mnLineColor
!= SALCOLOR_NONE
)
320 mnLineColor
= SALCOLOR_NONE
;
324 // set the line color to a specific color
325 void OpenGLSalGraphicsImpl::SetLineColor( SalColor nSalColor
)
327 if( mnLineColor
!= nSalColor
)
329 mnLineColor
= nSalColor
;
333 // set the fill color to transparent (= don't fill)
334 void OpenGLSalGraphicsImpl::SetFillColor()
336 if( mnFillColor
!= SALCOLOR_NONE
)
338 mnFillColor
= SALCOLOR_NONE
;
342 // set the fill color to a specific color, shapes will be
343 // filled accordingly
344 void OpenGLSalGraphicsImpl::SetFillColor( SalColor nSalColor
)
346 if( mnFillColor
!= nSalColor
)
348 mnFillColor
= nSalColor
;
352 // enable/disable XOR drawing
353 void OpenGLSalGraphicsImpl::SetXORMode( bool /*bSet*/, bool /*bInvertOnly*/ )
357 // set line color for raster operations
358 void OpenGLSalGraphicsImpl::SetROPLineColor( SalROPColor
/*nROPColor*/ )
362 // set fill color for raster operations
363 void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor
/*nROPColor*/ )
367 bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
369 if( !maOffscreenTex
)
370 maOffscreenTex
= OpenGLTexture( GetWidth(), GetHeight() );
372 if( !maOffscreenTex
.IsUnique() )
374 GLfloat fWidth
= GetWidth();
375 GLfloat fHeight
= GetHeight();
376 SalTwoRect
aPosAry(0, 0, fWidth
, fHeight
, 0,0, fWidth
, fHeight
);
378 // TODO: lfrb: User GL_ARB_copy_image?
379 OpenGLTexture aNewTex
= OpenGLTexture( GetWidth(), GetHeight() );
380 mpFramebuffer
= mpContext
->AcquireFramebuffer( aNewTex
);
381 DrawTexture( maOffscreenTex
, aPosAry
);
382 maOffscreenTex
= aNewTex
;
386 mpFramebuffer
= mpContext
->AcquireFramebuffer( maOffscreenTex
);
393 bool OpenGLSalGraphicsImpl::UseProgram( const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OString
& preamble
)
395 if( mpProgram
!= NULL
)
397 mpProgram
= mpContext
->UseProgram( rVertexShader
, rFragmentShader
, preamble
);
399 mProgramIsSolidColor
= false; // UseSolid() will set to true if needed
401 return ( mpProgram
!= NULL
);
404 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
, sal_uInt8 nTransparency
)
406 if( nColor
== SALCOLOR_NONE
)
408 if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
410 mpProgram
->SetColor( "color", nColor
, nTransparency
);
412 mProgramIsSolidColor
= true;
414 mProgramSolidColor
= nColor
;
415 mProgramSolidTransparency
= nTransparency
/ 100.0;
419 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
, double fTransparency
)
421 if( nColor
== SALCOLOR_NONE
)
423 if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
425 mpProgram
->SetColorf( "color", nColor
, fTransparency
);
427 mProgramIsSolidColor
= true;
429 mProgramSolidColor
= nColor
;
430 mProgramSolidTransparency
= fTransparency
;
434 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor
)
436 return UseSolid( nColor
, 0.0f
);
439 // Like UseSolid(), but sets up for AA drawing, which uses gradients to create the AA.
440 bool OpenGLSalGraphicsImpl::UseSolidAA( SalColor nColor
, double fTransparency
)
442 if( nColor
== SALCOLOR_NONE
)
444 if( !mrParent
.getAntiAliasB2DDraw())
445 return UseSolid( nColor
);
446 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
448 mpProgram
->SetColorf( "start_color", nColor
, fTransparency
);
449 mpProgram
->SetColorf( "end_color", nColor
, 1.0f
);
453 bool OpenGLSalGraphicsImpl::UseSolidAA( SalColor nColor
)
455 return UseSolidAA( nColor
, 0.0 );
458 bool OpenGLSalGraphicsImpl::UseInvert()
462 if( !UseSolid( MAKE_SALCOLOR( 255, 255, 255 ) ) )
464 mpProgram
->SetBlendMode( GL_ONE_MINUS_DST_COLOR
, GL_ZERO
);
468 void OpenGLSalGraphicsImpl::DrawPoint( long nX
, long nY
)
474 pPoint
[0] = GLfloat(nX
);
475 pPoint
[1] = GLfloat(nY
);
477 ApplyProgramMatrices(0.5f
);
478 mpProgram
->SetVertices( pPoint
);
479 glDrawArrays( GL_POINTS
, 0, 1 );
484 void OpenGLSalGraphicsImpl::DrawLine( double nX1
, double nY1
, double nX2
, double nY2
)
490 pPoints
[0] = GLfloat(nX1
);
491 pPoints
[1] = GLfloat(nY1
);
492 pPoints
[2] = GLfloat(nX2
);
493 pPoints
[3] = GLfloat(nY2
);
495 ApplyProgramMatrices(0.5f
);
496 mpProgram
->SetVertices( pPoints
);
497 glDrawArrays( GL_LINES
, 0, 2 );
502 void OpenGLSalGraphicsImpl::DrawLineAA( double nX1
, double nY1
, double nX2
, double nY2
)
506 if( !mrParent
.getAntiAliasB2DDraw())
507 return DrawLine( nX1
, nY1
, nX2
, nY2
);
509 if( nX1
== nX2
|| nY1
== nY2
)
510 { // Horizontal/vertical, no need for AA, both points have normal color.
512 // Still set up for the trivial "gradients", because presumably UseSolidAA() has been called.
513 GLfloat aTexCoord
[4] = { 0, 1, 1, 1 };
514 mpProgram
->SetTextureCoord( aTexCoord
);
515 DrawLine(nX1
, nY1
, nX2
, nY2
);
519 ImplDrawLineAA( nX1
, nY1
, nX2
, nY2
);
524 void OpenGLSalGraphicsImpl::ImplDrawLineAA( double nX1
, double nY1
, double nX2
, double nY2
, bool edge
)
526 // Draw the line anti-aliased. Based on code with the following notice:
527 /* Drawing nearly perfect 2D line segments in OpenGL
528 * You can use this code however you want.
529 * I just hope you to cite my name and the page of this technique:
530 * http://artgrammer.blogspot.com/2011/05/drawing-nearly-perfect-2d-line-segments.html
531 * http://www.codeproject.com/KB/openGL/gllinedraw.aspx
533 * Enjoy. Chris Tsang.*/
540 // A special hack for drawing lines that are in fact AA edges of a shape. Make the line somewhat
541 // wider, but (done further below) draw the entire width as a gradient. This would be wrong for a line
542 // (too wide and seemingly less straight), but it makes the edges look smoother and the width difference
543 // is almost unnoticeable.
544 const double w
= edge
? 1.4 : 1.0;
548 double f
= w
- static_cast<int>(w
);
549 //determine parameters t,R
550 if ( w
>=0.0 && w
<1.0 )
555 else if ( w
>=1.0 && w
<2.0 )
560 else if ( w
>=2.0 && w
<3.0 )
565 else if ( w
>=3.0 && w
<4.0 )
570 else if ( w
>=4.0 && w
<5.0 )
575 else if ( w
>=5.0 && w
<6.0 )
587 //determine angle of the line to horizontal
588 double tx
=0,ty
=0; //core thinkness of a line
589 double Rx
=0,Ry
=0; //fading edge of a line
593 { //approximate to make things even faster
595 //and calculate tx,ty,Rx,Ry
596 if ( m
>-0.4142 && m
<=0.4142)
598 // -22.5< angle <= 22.5, approximate to 0 (degree)
602 else if ( m
>0.4142 && m
<=2.4142)
604 // 22.5< angle <= 67.5, approximate to 45 (degree)
605 tx
=t
*-0.7071; ty
=t
*0.7071;
606 Rx
=R
*-0.7071; Ry
=R
*0.7071;
608 else if ( m
>2.4142 || m
<=-2.4142)
610 // 67.5 < angle <=112.5, approximate to 90 (degree)
614 else if ( m
>-2.4142 && m
<-0.4142)
616 // 112.5 < angle < 157.5, approximate to 135 (degree)
617 tx
=t
*0.7071; ty
=t
*0.7071;
618 Rx
=R
*0.7071; Ry
=R
*0.7071;
624 { //calculate to exact
627 double L
=sqrt(dx
*dx
+dy
*dy
);
643 GLfloat(x1
-tx
-Rx
), GLfloat(y1
-ty
-Ry
), //fading edge1
644 GLfloat(x2
-tx
-Rx
), GLfloat(y2
-ty
-Ry
),
645 GLfloat(x1
-tx
), GLfloat(y1
-ty
), //core
646 GLfloat(x2
-tx
), GLfloat(y2
-ty
),
647 GLfloat(x1
+tx
), GLfloat(y1
+ty
),
648 GLfloat(x2
+tx
), GLfloat(y2
+ty
),
649 GLfloat(x1
+tx
+Rx
), GLfloat(y1
+ty
+Ry
), //fading edge2
650 GLfloat(x2
+tx
+Rx
), GLfloat(y2
+ty
+Ry
)
653 ApplyProgramMatrices(0.0f
);
654 GLfloat aTexCoord
[16] = { 0, 0, 1, 0, 2, 1, 3, 1, 4, 1, 5, 1, 6, 0, 7, 0 };
655 mpProgram
->SetTextureCoord( aTexCoord
);
656 mpProgram
->SetVertices( vertices
);
657 glDrawArrays(GL_TRIANGLE_STRIP
, 0, 8);
662 void OpenGLSalGraphicsImpl::DrawLines( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, bool bClose
)
664 for( int i
= 0; i
< int(nPoints
) - 1; ++i
)
665 DrawLine( pPtAry
[ i
].mnX
, pPtAry
[ i
].mnY
, pPtAry
[ i
+ 1 ].mnX
, pPtAry
[ i
+ 1 ].mnY
);
667 DrawLine( pPtAry
[ nPoints
- 1 ].mnX
, pPtAry
[ nPoints
- 1 ].mnY
, pPtAry
[ 0 ].mnX
, pPtAry
[ 0 ].mnY
);
670 void OpenGLSalGraphicsImpl::DrawLinesAA( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, bool bClose
)
672 for( int i
= 0; i
< int(nPoints
) - 1; ++i
)
673 DrawLineAA( pPtAry
[ i
].mnX
, pPtAry
[ i
].mnY
, pPtAry
[ i
+ 1 ].mnX
, pPtAry
[ i
+ 1 ].mnY
);
675 DrawLineAA( pPtAry
[ nPoints
- 1 ].mnX
, pPtAry
[ nPoints
- 1 ].mnY
, pPtAry
[ 0 ].mnX
, pPtAry
[ 0 ].mnY
);
678 void OpenGLSalGraphicsImpl::DrawEdgeAA( double nX1
, double nY1
, double nX2
, double nY2
)
680 assert( mrParent
.getAntiAliasB2DDraw());
681 if( nX1
== nX2
|| nY1
== nY2
)
682 return; //horizontal/vertical, no need for AA
683 ImplDrawLineAA( nX1
, nY1
, nX2
, nY2
, true );
686 void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, bool blockAA
)
690 std::vector
<GLfloat
> aVertices(nPoints
* 2);
693 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
695 aVertices
[j
] = GLfloat(pPtAry
[i
].mnX
);
696 aVertices
[j
+1] = GLfloat(pPtAry
[i
].mnY
);
699 ApplyProgramMatrices();
700 mpProgram
->SetVertices( &aVertices
[0] );
701 glDrawArrays( GL_TRIANGLE_FAN
, 0, nPoints
);
703 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
705 // Make the edges antialiased by drawing the edge lines again with AA.
706 // TODO: If transparent drawing is set up, drawing the lines themselves twice
707 // may be a problem, if that is a real problem, the polygon areas itself needs to be
708 // masked out for this or something.
710 assert( mProgramIsSolidColor
);
712 SalColor lastSolidColor
= mProgramSolidColor
;
713 double lastSolidTransparency
= mProgramSolidTransparency
;
714 if( UseSolidAA( lastSolidColor
, lastSolidTransparency
))
716 for( i
= 0; i
< nPoints
; ++i
)
718 const SalPoint
& rPt1
= pPtAry
[ i
];
719 const SalPoint
& rPt2
= pPtAry
[ ( i
+ 1 ) % nPoints
];
720 DrawEdgeAA( rPt1
.mnX
, rPt1
.mnY
, rPt2
.mnX
, rPt2
.mnY
);
722 UseSolid( lastSolidColor
, lastSolidTransparency
);
729 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon
& rPolygon
, bool blockAA
)
733 sal_uInt16 nPoints
= rPolygon
.GetSize() - 1;
734 std::vector
<GLfloat
> aVertices(nPoints
* 2);
737 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
739 const Point
& rPt
= rPolygon
.GetPoint( i
);
740 aVertices
[j
] = GLfloat(rPt
.X());
741 aVertices
[j
+1] = GLfloat(rPt
.Y());
744 ApplyProgramMatrices();
745 mpProgram
->SetVertices( &aVertices
[0] );
746 glDrawArrays( GL_TRIANGLE_FAN
, 0, nPoints
);
748 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
750 // Make the edges antialiased by drawing the edge lines again with AA.
751 // TODO: If transparent drawing is set up, drawing the lines themselves twice
752 // may be a problem, if that is a real problem, the polygon areas itself needs to be
753 // masked out for this or something.
755 assert( mProgramIsSolidColor
);
757 SalColor lastSolidColor
= mProgramSolidColor
;
758 double lastSolidTransparency
= mProgramSolidTransparency
;
759 if( UseSolidAA( lastSolidColor
, lastSolidTransparency
))
761 for( i
= 0; i
< nPoints
; ++i
)
763 const Point
& rPt1
= rPolygon
.GetPoint( i
);
764 const Point
& rPt2
= rPolygon
.GetPoint(( i
+ 1 ) % nPoints
);
765 DrawEdgeAA( rPt1
.getX(), rPt1
.getY(), rPt2
.getX(), rPt2
.getY());
767 UseSolid( lastSolidColor
, lastSolidTransparency
);
774 void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid
& trapezoid
, bool blockAA
)
778 const basegfx::B2DPolygon
& rPolygon
= trapezoid
.getB2DPolygon();
779 sal_uInt16 nPoints
= rPolygon
.count();
780 std::vector
<GLfloat
> aVertices(nPoints
* 2);
783 for( i
= 0, j
= 0; i
< nPoints
; i
++, j
+= 2 )
785 const basegfx::B2DPoint
& rPt
= rPolygon
.getB2DPoint( i
);
786 aVertices
[j
] = GLfloat(rPt
.getX());
787 aVertices
[j
+1] = GLfloat(rPt
.getY());
792 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
796 ApplyProgramMatrices();
797 mpProgram
->SetVertices( &aVertices
[0] );
798 glDrawArrays( GL_TRIANGLE_FAN
, 0, nPoints
);
800 if( !blockAA
&& mrParent
.getAntiAliasB2DDraw())
802 // Make the edges antialiased by drawing the edge lines again with AA.
803 // TODO: If transparent drawing is set up, drawing the lines themselves twice
804 // may be a problem, if that is a real problem, the polygon areas itself needs to be
805 // masked out for this or something.
807 assert( mProgramIsSolidColor
);
809 SalColor lastSolidColor
= mProgramSolidColor
;
810 double lastSolidTransparency
= mProgramSolidTransparency
;
811 if( UseSolidAA( lastSolidColor
, lastSolidTransparency
))
813 for( i
= 0; i
< nPoints
; ++i
)
815 const basegfx::B2DPoint
& rPt1
= rPolygon
.getB2DPoint( i
);
816 const basegfx::B2DPoint
& rPt2
= rPolygon
.getB2DPoint(( i
+ 1 ) % nPoints
);
817 DrawEdgeAA( rPt1
.getX(), rPt1
.getY(), rPt2
.getX(), rPt2
.getY());
819 UseSolid( lastSolidColor
, lastSolidTransparency
);
826 void OpenGLSalGraphicsImpl::DrawRect( long nX
, long nY
, long nWidth
, long nHeight
)
830 long nX2( nX
+ nWidth
);
831 long nY2( nY
+ nHeight
);
832 const SalPoint aPoints
[] = { { nX1
, nY2
}, { nX1
, nY1
},
833 { nX2
, nY1
}, { nX2
, nY2
}};
835 DrawConvexPolygon( 4, aPoints
, true );
838 void OpenGLSalGraphicsImpl::DrawRect( const Rectangle
& rRect
)
840 long nX1( rRect
.Left() );
841 long nY1( rRect
.Top() );
842 long nX2( rRect
.Right() );
843 long nY2( rRect
.Bottom() );
844 const SalPoint aPoints
[] = { { nX1
, nY2
}, { nX1
, nY1
},
845 { nX2
, nY1
}, { nX2
, nY2
}};
847 DrawConvexPolygon( 4, aPoints
, true );
850 void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
852 ::basegfx::B2DPolygon aPolygon
;
854 for( sal_uInt32 i
= 0; i
< nPoints
; i
++ )
855 aPolygon
.append( ::basegfx::B2DPoint( pPtAry
[i
].mnX
, pPtAry
[i
].mnY
) );
856 aPolygon
.setClosed( true );
858 if( ::basegfx::tools::isConvex( aPolygon
) )
861 DrawConvexPolygon( nPoints
, pPtAry
);
865 const ::basegfx::B2DPolyPolygon
aPolyPolygon( aPolygon
);
866 DrawPolyPolygon( aPolyPolygon
);
870 void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon
& rPolyPolygon
, bool blockAA
)
872 const ::basegfx::B2DPolyPolygon
& aSimplePolyPolygon
= ::basegfx::tools::solveCrossovers( rPolyPolygon
);
873 basegfx::B2DTrapezoidVector aB2DTrapVector
;
874 basegfx::tools::trapezoidSubdivide( aB2DTrapVector
, aSimplePolyPolygon
);
875 // draw tesselation result
876 if( aB2DTrapVector
.size())
878 for( size_t i
= 0; i
< aB2DTrapVector
.size(); ++i
)
879 DrawTrapezoid( aB2DTrapVector
[ i
], blockAA
);
883 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand
& rRegion
)
887 RectangleVector aRects
;
888 std::vector
<GLfloat
> aVertices
;
889 rRegion
.GetRegionRectangles( aRects
);
894 #define ADD_VERTICE(pt) \
895 aVertices.push_back(GLfloat(pt.X())); \
896 aVertices.push_back(GLfloat(pt.Y()));
898 for( size_t i
= 0; i
< aRects
.size(); ++i
)
900 aRects
[i
].Bottom() += 1;
901 aRects
[i
].Right() += 1;
902 ADD_VERTICE( aRects
[i
].TopLeft() );
903 ADD_VERTICE( aRects
[i
].TopRight() );
904 ADD_VERTICE( aRects
[i
].BottomLeft() );
905 ADD_VERTICE( aRects
[i
].BottomLeft() );
906 ADD_VERTICE( aRects
[i
].TopRight() );
907 ADD_VERTICE( aRects
[i
].BottomRight() );
911 ApplyProgramMatrices();
912 mpProgram
->SetVertices( &aVertices
[0] );
913 glDrawArrays( GL_TRIANGLES
, 0, aVertices
.size() / 2 );
918 void OpenGLSalGraphicsImpl::DrawTextureRect( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
)
922 GLfloat aTexCoord
[8];
923 rTexture
.GetCoord( aTexCoord
, rPosAry
, bInverted
);
924 mpProgram
->SetTextureCoord( aTexCoord
);
925 DrawRect( rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
928 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& pPosAry
, bool bInverted
)
932 if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
934 mpProgram
->SetTexture( "sampler", rTexture
);
935 DrawTextureRect( rTexture
, pPosAry
, bInverted
);
939 void OpenGLSalGraphicsImpl::DrawTransformedTexture(
940 OpenGLTexture
& rTexture
,
941 OpenGLTexture
& rMask
,
942 const basegfx::B2DPoint
& rNull
,
943 const basegfx::B2DPoint
& rX
,
944 const basegfx::B2DPoint
& rY
)
948 GLfloat aVertices
[8] = {
949 0, (float) rTexture
.GetHeight(), 0, 0,
950 (float) rTexture
.GetWidth(), 0, (float) rTexture
.GetWidth(), (float) rTexture
.GetHeight() };
951 GLfloat aTexCoord
[8];
953 // If downscaling at a higher scale ratio, use the area scaling algorithm rather
954 // than plain OpenGL's scaling, for better results.
955 // See OpenGLSalBitmap::ImplScaleArea().
956 double ixscale
= rTexture
.GetWidth() / fabs( rX
.getX() - rNull
.getX());
957 double iyscale
= rTexture
.GetHeight() / fabs( rY
.getY() - rNull
.getY());
958 bool areaScaling
= false;
959 bool fastAreaScaling
= false;
960 OUString textureFragmentShader
;
961 if( ixscale
>= 2 && iyscale
>= 2 ) // Downscaling to 50% or less? (inverted scale ratios)
964 fastAreaScaling
= ( ixscale
== int( ixscale
) && iyscale
== int( iyscale
));
965 // The generic case has arrays only up to 100 ratio downscaling, which is hopefully enough
966 // in practice, but protect against buffer overflows in case such an extreme case happens
967 // (and in such case the precision of the generic algorithm probably doesn't matter anyway).
968 if( ixscale
> 100 || iyscale
> 100 )
969 fastAreaScaling
= true;
970 if( fastAreaScaling
)
971 textureFragmentShader
= "areaScaleFastFragmentShader";
973 textureFragmentShader
= "areaScaleFragmentShader";
978 if( !UseProgram( "transformedTextureVertexShader",
979 textureFragmentShader
.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader
,
982 mpProgram
->SetTexture( "mask", rMask
);
983 GLfloat aMaskCoord
[8];
984 rMask
.GetWholeCoord(aMaskCoord
);
985 mpProgram
->SetMaskCoord(aMaskCoord
);
986 rMask
.SetFilter( GL_LINEAR
);
987 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
991 if( !UseProgram( "transformedTextureVertexShader",
992 textureFragmentShader
.isEmpty() ? "textureFragmentShader" : textureFragmentShader
) )
996 int mnWidth
= rTexture
.GetWidth();
997 int mnHeight
= rTexture
.GetHeight();
1000 // From OpenGLSalBitmap::ImplScaleArea().
1001 if (fastAreaScaling
&& mnWidth
&& mnHeight
)
1003 mpProgram
->SetUniform1i( "xscale", ixscale
);
1004 mpProgram
->SetUniform1i( "yscale", iyscale
);
1005 mpProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
1006 mpProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
1007 mpProgram
->SetUniform1f( "ratio", 1.0 / ( ixscale
* iyscale
));
1009 else if (mnHeight
> 1 && mnWidth
> 1)
1011 mpProgram
->SetUniform1f( "xscale", ixscale
);
1012 mpProgram
->SetUniform1f( "yscale", iyscale
);
1013 mpProgram
->SetUniform1i( "swidth", mnWidth
);
1014 mpProgram
->SetUniform1i( "sheight", mnHeight
);
1015 // For converting between <0,mnWidth-1> and <0.0,1.0> coordinate systems.
1016 mpProgram
->SetUniform1f( "xsrcconvert", 1.0 / ( mnWidth
- 1 ));
1017 mpProgram
->SetUniform1f( "ysrcconvert", 1.0 / ( mnHeight
- 1 ));
1018 mpProgram
->SetUniform1f( "xdestconvert", 1.0 * (( mnWidth
/ ixscale
) - 1 ));
1019 mpProgram
->SetUniform1f( "ydestconvert", 1.0 * (( mnHeight
/ iyscale
) - 1 ));
1023 ApplyProgramMatrices();
1024 mpProgram
->SetUniform2f( "viewport", GetWidth(), GetHeight() );
1025 mpProgram
->SetTransform( "transform", rTexture
, rNull
, rX
, rY
);
1026 rTexture
.GetWholeCoord( aTexCoord
);
1027 mpProgram
->SetTexture( "sampler", rTexture
);
1028 rTexture
.SetFilter( GL_LINEAR
);
1029 mpProgram
->SetTextureCoord( aTexCoord
);
1030 mpProgram
->SetVertices( &aVertices
[0] );
1031 glDrawArrays( GL_TRIANGLE_FAN
, 0, 4 );
1037 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture
& rTexture
, const SalTwoRect
& rPosAry
, bool bInverted
, bool bPremultiplied
)
1041 if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
1043 mpProgram
->SetTexture( "sampler", rTexture
);
1044 mpProgram
->SetBlendMode( bPremultiplied
? GL_ONE
: GL_SRC_ALPHA
,
1045 GL_ONE_MINUS_SRC_ALPHA
);
1046 DrawTextureRect( rTexture
, rPosAry
, bInverted
);
1050 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
, bool bInverted
)
1054 if( !UseProgram( "maskedTextureVertexShader", "diffTextureFragmentShader" ) )
1056 mpProgram
->SetTexture( "texture", rTexture
);
1057 mpProgram
->SetTexture( "mask", rMask
);
1058 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1060 GLfloat aMaskCoord
[8];
1061 rMask
.GetCoord(aMaskCoord
, rPosAry
, bInverted
);
1062 mpProgram
->SetMaskCoord(aMaskCoord
);
1064 DrawTextureRect( rTexture
, rPosAry
, bInverted
);
1068 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, const SalTwoRect
& rPosAry
)
1072 if( !UseProgram( "maskedTextureVertexShader", "maskedTextureFragmentShader" ) )
1074 mpProgram
->SetTexture( "sampler", rTexture
);
1075 mpProgram
->SetTexture( "mask", rMask
);
1076 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1078 GLfloat aTexCoord
[8];
1079 rTexture
.GetCoord(aTexCoord
, rPosAry
);
1080 mpProgram
->SetTextureCoord(aTexCoord
);
1082 GLfloat aMaskCoord
[8];
1083 rMask
.GetCoord(aMaskCoord
, rPosAry
);
1084 mpProgram
->SetMaskCoord(aMaskCoord
);
1086 DrawRect(rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
1090 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture
& rTexture
, OpenGLTexture
& rMask
, OpenGLTexture
& rAlpha
, const SalTwoRect
& rPosAry
)
1094 if( !UseProgram( "blendedTextureVertexShader", "blendedTextureFragmentShader" ) )
1096 mpProgram
->SetTexture( "sampler", rTexture
);
1097 mpProgram
->SetTexture( "mask", rMask
);
1098 mpProgram
->SetTexture( "alpha", rAlpha
);
1100 GLfloat aAlphaCoord
[8];
1101 rAlpha
.GetCoord(aAlphaCoord
, rPosAry
);
1102 mpProgram
->SetAlphaCoord(aAlphaCoord
);
1104 GLfloat aMaskCoord
[8];
1105 rMask
.GetCoord(aMaskCoord
, rPosAry
);
1106 mpProgram
->SetMaskCoord(aMaskCoord
);
1108 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1109 DrawTextureRect( rTexture
, rPosAry
);
1113 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture
& rMask
, SalColor nMaskColor
, const SalTwoRect
& pPosAry
)
1117 if( !UseProgram( "textureVertexShader", "maskFragmentShader" ) )
1119 mpProgram
->SetColor( "color", nMaskColor
, 0 );
1120 mpProgram
->SetTexture( "sampler", rMask
);
1121 mpProgram
->SetBlendMode( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1122 DrawTextureRect( rMask
, pPosAry
);
1126 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1130 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1132 Color aStartCol
= rGradient
.GetStartColor();
1133 Color aEndCol
= rGradient
.GetEndColor();
1134 long nFactor
= rGradient
.GetStartIntensity();
1135 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1136 nFactor
= rGradient
.GetEndIntensity();
1137 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1139 Rectangle aBoundRect
;
1141 rGradient
.GetBoundRect( rRect
, aBoundRect
, aCenter
);
1142 Polygon
aPoly( aBoundRect
);
1143 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() % 3600 );
1145 GLfloat aTexCoord
[8] = { 0, 1, 1, 1, 1, 0, 0, 0 };
1146 GLfloat fMin
= 1.0 - 100.0 / (100.0 - rGradient
.GetBorder());
1147 aTexCoord
[5] = aTexCoord
[7] = fMin
;
1148 mpProgram
->SetTextureCoord( aTexCoord
);
1149 DrawConvexPolygon( aPoly
, true );
1152 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1156 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1158 Color aStartCol
= rGradient
.GetStartColor();
1159 Color aEndCol
= rGradient
.GetEndColor();
1160 long nFactor
= rGradient
.GetStartIntensity();
1161 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1162 nFactor
= rGradient
.GetEndIntensity();
1163 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1166 * Draw two rectangles with linear gradient.
1170 * | / | Points 0 and 3 have start color
1171 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1181 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
1183 // determine points 0 and 3
1184 Point
aPt0( aRect
.Left(), (aRect
.Top() + aRect
.Bottom() + 1) / 2 );
1185 Point
aPt3( aRect
.Right(), (aRect
.Top() + aRect
.Bottom() + 1) / 2 );
1188 aPoly
.SetPoint( aPt0
, 0 );
1189 aPoly
.SetPoint( aRect
.TopLeft(), 1 );
1190 aPoly
.SetPoint( aRect
.TopRight(), 2 );
1191 aPoly
.SetPoint( aPt3
, 3 );
1192 aPoly
.SetPoint( aRect
.BottomRight(), 4 );
1193 aPoly
.SetPoint( aRect
.BottomLeft(), 5 );
1194 aPoly
.SetPoint( aPt0
, 6 );
1195 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() % 3600 );
1197 GLfloat aTexCoord
[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 };
1198 GLfloat fMin
= 1.0 - 100.0 / (100.0 - rGradient
.GetBorder());
1199 aTexCoord
[3] = aTexCoord
[5] = aTexCoord
[9] = aTexCoord
[11] = fMin
;
1200 mpProgram
->SetTextureCoord( aTexCoord
);
1201 DrawConvexPolygon( aPoly
, true );
1204 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient
& rGradient
, const Rectangle
& rRect
)
1208 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
1210 Color aStartCol
= rGradient
.GetStartColor();
1211 Color aEndCol
= rGradient
.GetEndColor();
1212 long nFactor
= rGradient
.GetStartIntensity();
1213 mpProgram
->SetColorWithIntensity( "start_color", aStartCol
, nFactor
);
1214 nFactor
= rGradient
.GetEndIntensity();
1215 mpProgram
->SetColorWithIntensity( "end_color", aEndCol
, nFactor
);
1219 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
1221 // adjust coordinates so that radius has distance equals to 1.0
1222 double fRadius
= aRect
.GetWidth() / 2.0f
;
1223 GLfloat fWidth
= rRect
.GetWidth() / fRadius
;
1224 GLfloat fHeight
= rRect
.GetHeight() / fRadius
;
1225 GLfloat aTexCoord
[8] = { 0, 0, 0, fHeight
, fWidth
, fHeight
, fWidth
, 0 };
1226 mpProgram
->SetTextureCoord( aTexCoord
);
1227 mpProgram
->SetUniform2f( "center", (aCenter
.X() - rRect
.Left()) / fRadius
,
1228 (aCenter
.Y() - rRect
.Top()) / fRadius
);
1233 // draw --> LineColor and FillColor and RasterOp and ClipRegion
1234 void OpenGLSalGraphicsImpl::drawPixel( long nX
, long nY
)
1236 VCL_GL_INFO( "vcl.opengl", "::drawPixel" );
1237 if( mnLineColor
!= SALCOLOR_NONE
)
1240 if( UseSolid( mnLineColor
) )
1241 DrawPoint( nX
, nY
);
1246 void OpenGLSalGraphicsImpl::drawPixel( long nX
, long nY
, SalColor nSalColor
)
1248 VCL_GL_INFO( "vcl.opengl", "::drawPixel" );
1249 if( nSalColor
!= SALCOLOR_NONE
)
1252 if( UseSolid( nSalColor
) )
1253 DrawPoint( nX
, nY
);
1258 void OpenGLSalGraphicsImpl::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
1260 VCL_GL_INFO( "vcl.opengl", "::drawLine" );
1261 if( mnLineColor
!= SALCOLOR_NONE
)
1264 if( UseSolidAA( mnLineColor
) )
1265 DrawLineAA( nX1
, nY1
, nX2
, nY2
);
1270 void OpenGLSalGraphicsImpl::drawRect( long nX
, long nY
, long nWidth
, long nHeight
)
1272 VCL_GL_INFO( "vcl.opengl", "::drawRect" );
1275 if( UseSolid( mnFillColor
) )
1276 DrawRect( nX
, nY
, nWidth
, nHeight
);
1278 if( UseSolid( mnLineColor
) )
1282 GLfloat
fX2(nX
+ nWidth
- 1);
1283 GLfloat
fY2(nY
+ nHeight
- 1);
1285 GLfloat pPoints
[16];
1296 ApplyProgramMatrices(0.5f
);
1297 mpProgram
->SetVertices(pPoints
);
1298 glDrawArrays(GL_LINE_LOOP
, 0, 4);
1304 void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1306 VCL_GL_INFO( "vcl.opengl", "::drawPolyLine" );
1308 if( mnLineColor
!= SALCOLOR_NONE
&& nPoints
> 1 )
1311 if( UseSolidAA( mnLineColor
) )
1312 DrawLinesAA( nPoints
, pPtAry
, false );
1317 void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1319 VCL_GL_INFO( "vcl.opengl", "::drawPolygon" );
1324 drawPixel( pPtAry
[0].mnX
, pPtAry
[0].mnY
);
1329 drawLine( pPtAry
[0].mnX
, pPtAry
[0].mnY
,
1330 pPtAry
[1].mnX
, pPtAry
[1].mnY
);
1336 if( UseSolid( mnFillColor
) )
1337 DrawPolygon( nPoints
, pPtAry
);
1339 if( UseSolidAA( mnLineColor
) )
1340 DrawLinesAA( nPoints
, pPtAry
, true );
1345 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly
, const sal_uInt32
* pPoints
, PCONSTSALPOINT
* pPtAry
)
1347 VCL_GL_INFO( "vcl.opengl", "::drawPolyPolygon" );
1353 if( UseSolid( mnFillColor
) )
1356 DrawPolygon( pPoints
[ 0 ], pPtAry
[ 0 ] );
1359 basegfx::B2DPolyPolygon polyPolygon
;
1360 for( sal_uInt32 i
= 0; i
< nPoly
; ++i
)
1362 basegfx::B2DPolygon polygon
;
1363 for( sal_uInt32 j
= 0; j
< pPoints
[ i
]; ++j
)
1364 polygon
.append( basegfx::B2DPoint( pPtAry
[i
][j
].mnX
, pPtAry
[i
][j
].mnY
) );
1365 polygon
.setClosed( true );
1366 polyPolygon
.append( polygon
);
1368 DrawPolyPolygon( polyPolygon
);
1372 if( mnLineColor
!= mnFillColor
&& UseSolidAA( mnLineColor
) )
1374 // TODO Use glMultiDrawElements or primitive restart
1375 for( sal_uInt32 i
= 0; i
< nPoly
; i
++ )
1376 DrawLinesAA( pPoints
[i
], pPtAry
[i
], true );
1382 bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon
& rPolyPolygon
, double fTransparency
)
1384 VCL_GL_INFO( "vcl.opengl", "::drawPolyPolygon trans " << fTransparency
);
1385 if( rPolyPolygon
.count() <= 0 )
1390 if( UseSolid( mnFillColor
, fTransparency
) )
1391 DrawPolyPolygon( rPolyPolygon
);
1393 if( mnLineColor
!= mnFillColor
&& UseSolid( mnLineColor
, fTransparency
))
1395 basegfx::B2DTrapezoidVector aB2DTrapVector
;
1396 basegfx::tools::createLineTrapezoidFromB2DPolyPolygon( aB2DTrapVector
, rPolyPolygon
);
1397 for( size_t i
= 0; i
< aB2DTrapVector
.size(); ++i
)
1398 DrawTrapezoid( aB2DTrapVector
[ i
] );
1406 bool OpenGLSalGraphicsImpl::drawPolyLine(
1407 const ::basegfx::B2DPolygon
& rPolygon
,
1408 double fTransparency
,
1409 const ::basegfx::B2DVector
& rLineWidth
,
1410 basegfx::B2DLineJoin eLineJoin
,
1411 com::sun::star::drawing::LineCap eLineCap
)
1413 VCL_GL_INFO( "vcl.opengl", "::drawPolyLine trans " << fTransparency
);
1414 if( mnLineColor
== SALCOLOR_NONE
)
1417 const bool bIsHairline
= (rLineWidth
.getX() == rLineWidth
.getY()) && (rLineWidth
.getX() <= 1.2);
1420 if( !bIsHairline
&& (rPolygon
.count() > 1000) )
1422 // the used basegfx::tools::createAreaGeometry is simply too
1423 // expensive with very big polygons; fallback to caller (who
1424 // should use ImplLineConverter normally)
1425 // AW: ImplLineConverter had to be removed since it does not even
1426 // know LineJoins, so the fallback will now prepare the line geometry
1431 // shortcut for hairline drawing to improve performance
1434 // Let's just leave it to OutputDevice to do the bezier subdivision,
1435 // drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) will be
1436 // called with the result.
1440 // #i11575#desc5#b adjust B2D tesselation result to raster positions
1441 basegfx::B2DPolygon aPolygon
= rPolygon
;
1442 const double fHalfWidth
= 0.5 * rLineWidth
.getX();
1444 // get the area polygon for the line polygon
1445 if( (rLineWidth
.getX() != rLineWidth
.getY())
1446 && !basegfx::fTools::equalZero( rLineWidth
.getY() ) )
1448 // prepare for createAreaGeometry() with anisotropic linewidth
1449 aPolygon
.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth
.getX() / rLineWidth
.getY()));
1452 // create the area-polygon for the line
1453 const basegfx::B2DPolyPolygon
aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon
, fHalfWidth
, eLineJoin
, eLineCap
) );
1455 if( (rLineWidth
.getX() != rLineWidth
.getY())
1456 && !basegfx::fTools::equalZero( rLineWidth
.getX() ) )
1458 // postprocess createAreaGeometry() for anisotropic linewidth
1459 aPolygon
.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth
.getY() / rLineWidth
.getX()));
1463 if( UseSolid( mnLineColor
, fTransparency
) )
1465 for( sal_uInt32 i
= 0; i
< aAreaPolyPoly
.count(); i
++ )
1467 const ::basegfx::B2DPolyPolygon
aOnePoly( aAreaPolyPoly
.getB2DPolygon( i
) );
1468 DrawPolyPolygon( aOnePoly
);
1476 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1477 sal_uInt32
/*nPoints*/,
1478 const SalPoint
* /*pPtAry*/,
1479 const sal_uInt8
* /*pFlgAry*/ )
1484 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1485 sal_uInt32
/*nPoints*/,
1486 const SalPoint
* /*pPtAry*/,
1487 const sal_uInt8
* /*pFlgAry*/ )
1492 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1493 sal_uInt32
/*nPoly*/,
1494 const sal_uInt32
* /*pPoints*/,
1495 const SalPoint
* const* /*pPtAry*/,
1496 const sal_uInt8
* const* /*pFlgAry*/ )
1501 // CopyArea --> No RasterOp, but ClipRegion
1502 void OpenGLSalGraphicsImpl::copyArea(
1503 long nDestX
, long nDestY
,
1504 long nSrcX
, long nSrcY
,
1505 long nSrcWidth
, long nSrcHeight
,
1506 sal_uInt16
/*nFlags*/ )
1508 VCL_GL_INFO( "vcl.opengl", "::copyArea " << nSrcX
<< "," << nSrcY
<< " >> " << nDestX
<< "," << nDestY
<< " (" << nSrcWidth
<< "," << nSrcHeight
<< ")" );
1509 OpenGLTexture aTexture
;
1510 SalTwoRect
aPosAry(0, 0, nSrcWidth
, nSrcHeight
, nDestX
, nDestY
, nSrcWidth
, nSrcHeight
);
1513 // TODO offscreen case
1514 aTexture
= OpenGLTexture( nSrcX
, GetHeight() - nSrcY
- nSrcHeight
,
1515 nSrcWidth
, nSrcHeight
);
1516 DrawTexture( aTexture
, aPosAry
);
1520 // CopyBits and DrawBitmap --> RasterOp and ClipRegion
1521 // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
1522 void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect
& rPosAry
, OpenGLSalGraphicsImpl
& rImpl
)
1524 VCL_GL_INFO( "vcl.opengl", "::copyBits" );
1526 if( &rImpl
== this &&
1527 (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
1528 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
))
1530 // short circuit if there is nothing to do
1531 if( (rPosAry
.mnSrcX
== rPosAry
.mnDestX
) &&
1532 (rPosAry
.mnSrcY
== rPosAry
.mnDestY
))
1534 // use copyArea() if source and destination context are identical
1535 copyArea( rPosAry
.mnDestX
, rPosAry
.mnDestY
, rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
1536 rPosAry
.mnSrcWidth
, rPosAry
.mnSrcHeight
, 0 );
1540 if( rImpl
.mbOffscreen
)
1543 DrawTexture( rImpl
.maOffscreenTex
, rPosAry
);
1548 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** copyBits" );
1549 // TODO: Copy from one FBO to the other (glBlitFramebuffer)
1550 // ie. copying from one visible window to another visible window
1553 void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
)
1555 // check that carefully only in the debug mode
1556 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBitmap
));
1558 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1559 OpenGLTexture
& rTexture
= rBitmap
.GetTexture();
1561 VCL_GL_INFO( "vcl.opengl", "::drawBitmap" );
1563 DrawTexture( rTexture
, rPosAry
);
1567 void OpenGLSalGraphicsImpl::drawBitmap(
1568 const SalTwoRect
& /*rPosAry*/,
1569 const SalBitmap
& /*rSalBitmap*/,
1570 SalColor
/*nTransparentColor*/ )
1572 OSL_FAIL( "::DrawBitmap with transparent color not supported" );
1575 void OpenGLSalGraphicsImpl::drawBitmap(
1576 const SalTwoRect
& rPosAry
,
1577 const SalBitmap
& rSalBitmap
,
1578 const SalBitmap
& rMaskBitmap
)
1580 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1581 const OpenGLSalBitmap
& rMask
= static_cast<const OpenGLSalBitmap
&>(rMaskBitmap
);
1582 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1583 OpenGLTexture
& rMaskTex( rMask
.GetTexture() );
1585 VCL_GL_INFO( "vcl.opengl", "::drawBitmap with MASK" );
1587 DrawTextureWithMask( rTexture
, rMaskTex
, rPosAry
);
1591 void OpenGLSalGraphicsImpl::drawMask(
1592 const SalTwoRect
& rPosAry
,
1593 const SalBitmap
& rSalBitmap
,
1594 SalColor nMaskColor
)
1596 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1597 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1599 VCL_GL_INFO( "vcl.opengl", "::drawMask" );
1601 DrawMask( rTexture
, nMaskColor
, rPosAry
);
1605 SalBitmap
* OpenGLSalGraphicsImpl::getBitmap( long nX
, long nY
, long nWidth
, long nHeight
)
1607 OpenGLSalBitmap
* pBitmap
= new OpenGLSalBitmap
;
1608 VCL_GL_INFO( "vcl.opengl", "::getBitmap " << nX
<< "," << nY
<<
1609 " " << nWidth
<< "x" << nHeight
);
1610 //TODO really needed?
1612 if( !pBitmap
->Create( maOffscreenTex
, nX
, nY
, nWidth
, nHeight
) )
1621 SalColor
OpenGLSalGraphicsImpl::getPixel( long nX
, long nY
)
1623 char pixel
[3] = { 0, 0, 0 };
1626 nY
= GetHeight() - nY
- 1;
1627 glReadPixels( nX
, nY
, 1, 1, GL_RGB
, GL_UNSIGNED_BYTE
, pixel
);
1631 return MAKE_SALCOLOR( pixel
[0], pixel
[1], pixel
[2] );
1634 // invert --> ClipRegion (only Windows or VirDevs)
1635 void OpenGLSalGraphicsImpl::invert(
1637 long nWidth
, long nHeight
,
1640 // TODO Figure out what are those:
1641 // * SAL_INVERT_50 (50/50 pattern?)
1642 // * SAL_INVERT_TRACKFRAME (dash-line rectangle?)
1646 if( nFlags
& SAL_INVERT_TRACKFRAME
)
1648 SAL_WARN("vcl.opengl", "check where this call is coming from! NOT IMPLEMENTED YET!");
1650 else if( nFlags
& SAL_INVERT_50
)
1652 SAL_WARN("vcl.opengl", "check where this call is coming from! NOT IMPLEMENTED YET!");
1657 DrawRect( nX
, nY
, nWidth
, nHeight
);
1663 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, SalInvert nFlags
)
1667 if( nFlags
& SAL_INVERT_TRACKFRAME
)
1669 SAL_WARN("vcl.opengl", "check where this call is coming from! NOT IMPLEMENTED YET!");
1671 else if( nFlags
& SAL_INVERT_50
)
1673 SAL_WARN("vcl.opengl", "check where this call is coming from! NOT IMPLEMENTED YET!");
1678 DrawPolygon( nPoints
, pPtAry
);
1684 bool OpenGLSalGraphicsImpl::drawEPS(
1685 long /*nX*/, long /*nY*/,
1686 long /*nWidth*/, long /*nHeight*/,
1688 sal_uLong
/*nSize*/ )
1693 bool OpenGLSalGraphicsImpl::blendBitmap(
1694 const SalTwoRect
& rPosAry
,
1695 const SalBitmap
& rSalBitmap
)
1697 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1698 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1700 VCL_GL_INFO( "vcl.opengl", "::blendBitmap" );
1702 glEnable( GL_BLEND
);
1703 glBlendFunc( GL_ZERO
, GL_SRC_COLOR
);
1704 DrawTexture( rTexture
, rPosAry
);
1705 glDisable( GL_BLEND
);
1710 bool OpenGLSalGraphicsImpl::blendAlphaBitmap(
1711 const SalTwoRect
& rPosAry
,
1712 const SalBitmap
& rSalSrcBitmap
,
1713 const SalBitmap
& rSalMaskBitmap
,
1714 const SalBitmap
& rSalAlphaBitmap
)
1716 const OpenGLSalBitmap
& rSrcBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalSrcBitmap
);
1717 const OpenGLSalBitmap
& rMaskBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalMaskBitmap
);
1718 const OpenGLSalBitmap
& rAlphaBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalAlphaBitmap
);
1719 OpenGLTexture
& rTexture( rSrcBitmap
.GetTexture() );
1720 OpenGLTexture
& rMask( rMaskBitmap
.GetTexture() );
1721 OpenGLTexture
& rAlpha( rAlphaBitmap
.GetTexture() );
1723 VCL_GL_INFO( "vcl.opengl", "::blendAlphaBitmap" );
1725 DrawBlendedTexture( rTexture
, rMask
, rAlpha
, rPosAry
);
1730 /** Render bitmap with alpha channel
1732 @param rSourceBitmap
1733 Source bitmap to blit
1736 Alpha channel to use for blitting
1738 @return true, if the operation succeeded, and false
1739 otherwise. In this case, clients should try to emulate alpha
1740 compositing themselves
1742 bool OpenGLSalGraphicsImpl::drawAlphaBitmap(
1743 const SalTwoRect
& rPosAry
,
1744 const SalBitmap
& rSalBitmap
,
1745 const SalBitmap
& rAlphaBitmap
)
1747 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBitmap
);
1748 const OpenGLSalBitmap
& rAlpha
= static_cast<const OpenGLSalBitmap
&>(rAlphaBitmap
);
1749 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1750 OpenGLTexture
& rAlphaTex( rAlpha
.GetTexture() );
1752 VCL_GL_INFO( "vcl.opengl", "::drawAlphaBitmap" );
1754 DrawTextureWithMask( rTexture
, rAlphaTex
, rPosAry
);
1759 /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
1760 bool OpenGLSalGraphicsImpl::drawTransformedBitmap(
1761 const basegfx::B2DPoint
& rNull
,
1762 const basegfx::B2DPoint
& rX
,
1763 const basegfx::B2DPoint
& rY
,
1764 const SalBitmap
& rSrcBitmap
,
1765 const SalBitmap
* pAlphaBitmap
)
1767 const OpenGLSalBitmap
& rBitmap
= static_cast<const OpenGLSalBitmap
&>(rSrcBitmap
);
1768 const OpenGLSalBitmap
* pMaskBitmap
= static_cast<const OpenGLSalBitmap
*>(pAlphaBitmap
);
1769 OpenGLTexture
& rTexture( rBitmap
.GetTexture() );
1770 OpenGLTexture aMask
; // no texture
1772 if( pMaskBitmap
!= NULL
)
1773 aMask
= pMaskBitmap
->GetTexture();
1775 VCL_GL_INFO( "vcl.opengl", "::drawTransformedBitmap" );
1777 DrawTransformedTexture( rTexture
, aMask
, rNull
, rX
, rY
);
1783 /** Render solid rectangle with given transparency
1785 @param nTransparency
1786 Transparency value (0-255) to use. 0 blits and opaque, 255 a
1787 fully transparent rectangle
1789 bool OpenGLSalGraphicsImpl::drawAlphaRect(
1791 long nWidth
, long nHeight
,
1792 sal_uInt8 nTransparency
)
1794 VCL_GL_INFO( "vcl.opengl", "::drawAlphaRect" );
1795 if( mnFillColor
!= SALCOLOR_NONE
&& nTransparency
< 100 )
1798 UseSolid( mnFillColor
, nTransparency
);
1799 DrawRect( nX
, nY
, nWidth
, nHeight
);
1806 bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon
& rPolyPoly
,
1807 const Gradient
& rGradient
)
1809 Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
1811 VCL_GL_INFO( "vcl.opengl", "::drawGradient" );
1813 if( aBoundRect
.IsEmpty() )
1816 if( rGradient
.GetStyle() != GradientStyle_LINEAR
&&
1817 rGradient
.GetStyle() != GradientStyle_AXIAL
&&
1818 rGradient
.GetStyle() != GradientStyle_RADIAL
)
1821 aBoundRect
.Left()--;
1823 aBoundRect
.Right()++;
1824 aBoundRect
.Bottom()++;
1828 #define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0
1829 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
1830 ImplSetClipBit( vcl::Region( rPolyPoly
), 0x02 );
1833 glEnable( GL_STENCIL_TEST
);
1834 glStencilFunc( GL_EQUAL
, 3, 0xFF );
1838 glEnable( GL_STENCIL_TEST
);
1839 glStencilFunc( GL_EQUAL
, 2, 0xFF );
1843 // if border >= 100%, draw solid rectangle with start color
1844 if( rGradient
.GetBorder() >= 100.0 )
1846 Color aCol
= rGradient
.GetStartColor();
1847 long nF
= rGradient
.GetStartIntensity();
1848 if( UseSolid( MAKE_SALCOLOR( aCol
.GetRed() * nF
/ 100,
1849 aCol
.GetGreen() * nF
/ 100,
1850 aCol
.GetBlue() * nF
/ 100 ) ) )
1851 DrawRect( aBoundRect
);
1853 else if( rGradient
.GetStyle() == GradientStyle_LINEAR
)
1855 DrawLinearGradient( rGradient
, aBoundRect
);
1857 else if( rGradient
.GetStyle() == GradientStyle_AXIAL
)
1859 DrawAxialGradient( rGradient
, aBoundRect
);
1861 else if( rGradient
.GetStyle() == GradientStyle_RADIAL
)
1863 DrawRadialGradient( rGradient
, aBoundRect
);
1866 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
1868 glDisable( GL_STENCIL_TEST
);
1876 OpenGLContext
*OpenGLSalGraphicsImpl::beginPaint()
1878 if( mbOffscreen
|| !AcquireContext() )
1881 return mpContext
.get();
1884 bool OpenGLSalGraphicsImpl::IsForeignContext(const rtl::Reference
<OpenGLContext
> &xContext
)
1886 // so far a blunt heuristic: vcl uses shiny new contexts.
1887 return xContext
->requestedLegacy();
1891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */