Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / opengl / gdiimpl.cxx
blobb2e047c2943ff0a704af22d787039e18e2d6e297
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "openglgdiimpl.hxx"
22 #include <vcl/gradient.hxx>
23 #include <salframe.hxx>
24 #include "salvd.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>
33 #include "salgdi.hxx"
34 #include "svdata.hxx"
35 #include "opengl/zone.hxx"
36 #include "opengl/salbmp.hxx"
38 #include <vector>
40 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider)
41 : mpContext(0)
42 , mrParent(rParent)
43 , mpProvider(pProvider)
44 , mpFramebuffer(NULL)
45 , mpProgram(NULL)
46 , mbUseScissor(false)
47 , mbUseStencil(false)
48 , mbOffscreen(false)
49 , mnLineColor(SALCOLOR_NONE)
50 , mnFillColor(SALCOLOR_NONE)
51 #ifdef DBG_UTIL
52 , mProgramIsSolidColor(false)
53 #endif
54 , mProgramSolidColor(SALCOLOR_NONE)
55 , mProgramSolidTransparency(0.0)
59 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
61 ReleaseContext();
64 rtl::Reference<OpenGLContext> OpenGLSalGraphicsImpl::GetOpenGLContext()
66 if( !AcquireContext() )
67 return NULL;
68 return mpContext;
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())
85 mpContext.clear();
88 if( mpContext.is() )
90 // Check whether the context was reset underneath us.
91 if( mpContext->isInitialized() )
92 return true;
93 mpContext.clear();
96 OpenGLContext *pContext = pSVData->maGDIData.mpLastContext;
97 while( pContext )
99 // check if this context can be used by this SalGraphicsImpl instance
100 if( UseContext( pContext ) )
101 break;
102 pContext = pContext->mpPrevContext;
105 if( pContext )
106 mpContext = pContext;
107 else
108 mpContext = mbOffscreen ? GetDefaultContext() : CreateWinContext();
110 return mpContext.is();
113 bool OpenGLSalGraphicsImpl::ReleaseContext()
115 mpContext.clear();
117 return true;
120 void OpenGLSalGraphicsImpl::Init()
122 mbOffscreen = IsOffscreen();
124 // check if we can simply re-use the same context
125 if( mpContext.is() )
127 if( !mpContext->isInitialized() ||
128 !UseContext( mpContext ) )
129 ReleaseContext();
132 // reset the offscreen texture
133 if( !mbOffscreen ||
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()
150 // tdf#93839:
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() )
157 mpContext->reset();
160 void OpenGLSalGraphicsImpl::PreDraw()
162 OpenGLZone::enter();
164 if( !AcquireContext() )
166 SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
167 return;
170 mpContext->makeCurrent();
171 CHECK_GL_ERROR();
173 if( !mbOffscreen )
174 mpContext->AcquireDefaultFramebuffer();
175 else
176 CheckOffscreenTexture();
177 CHECK_GL_ERROR();
179 glViewport( 0, 0, GetWidth(), GetHeight() );
180 ImplInitClipRegion();
182 CHECK_GL_ERROR();
185 void OpenGLSalGraphicsImpl::PostDraw()
187 if( !mbOffscreen && mpContext->mnPainting == 0 )
188 glFlush();
189 if( mbUseScissor )
190 glDisable( GL_SCISSOR_TEST );
191 if( mbUseStencil )
192 glDisable( GL_STENCIL_TEST );
193 if( mpProgram )
195 mpProgram->Clean();
196 mpProgram = NULL;
197 #ifdef DBG_UTIL
198 mProgramIsSolidColor = false;
199 #endif
202 CHECK_GL_ERROR();
203 OpenGLZone::leave();
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 );
219 ReleaseContext();
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() );
235 else
236 DrawPolyPolygon( rClip.GetAsB2DPolyPolygon(), true );
239 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
240 glStencilMask( 0x00 );
241 glDisable( GL_STENCIL_TEST );
243 CHECK_GL_ERROR();
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 );
263 if( mbUseScissor )
264 glEnable( GL_SCISSOR_TEST );
265 if( mbUseStencil )
267 glStencilFunc( GL_EQUAL, 1, 0x1 );
268 glEnable( GL_STENCIL_TEST );
271 CHECK_GL_ERROR();
274 const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
276 return maClipRegion;
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() )
287 mbUseScissor = true;
288 else if ( !maClipRegion.IsEmpty() )
289 mbUseStencil = true;
291 return true;
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
306 return 32;
309 // get the width of the device
310 long OpenGLSalGraphicsImpl::GetGraphicsWidth() const
312 return GetWidth();
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;
384 else
386 mpFramebuffer = mpContext->AcquireFramebuffer( maOffscreenTex );
389 CHECK_GL_ERROR();
390 return true;
393 bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
395 if( mpProgram != NULL )
396 mpProgram->Clean();
397 mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader, preamble );
398 #ifdef DBG_UTIL
399 mProgramIsSolidColor = false; // UseSolid() will set to true if needed
400 #endif
401 return ( mpProgram != NULL );
404 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, sal_uInt8 nTransparency )
406 if( nColor == SALCOLOR_NONE )
407 return false;
408 if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
409 return false;
410 mpProgram->SetColor( "color", nColor, nTransparency );
411 #ifdef DBG_UTIL
412 mProgramIsSolidColor = true;
413 #endif
414 mProgramSolidColor = nColor;
415 mProgramSolidTransparency = nTransparency / 100.0;
416 return true;
419 bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, double fTransparency )
421 if( nColor == SALCOLOR_NONE )
422 return false;
423 if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
424 return false;
425 mpProgram->SetColorf( "color", nColor, fTransparency );
426 #ifdef DBG_UTIL
427 mProgramIsSolidColor = true;
428 #endif
429 mProgramSolidColor = nColor;
430 mProgramSolidTransparency = fTransparency;
431 return true;
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 )
443 return false;
444 if( !mrParent.getAntiAliasB2DDraw())
445 return UseSolid( nColor );
446 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
447 return false;
448 mpProgram->SetColorf( "start_color", nColor, fTransparency );
449 mpProgram->SetColorf( "end_color", nColor, 1.0f );
450 return true;
453 bool OpenGLSalGraphicsImpl::UseSolidAA( SalColor nColor )
455 return UseSolidAA( nColor, 0.0 );
458 bool OpenGLSalGraphicsImpl::UseInvert()
460 OpenGLZone aZone;
462 if( !UseSolid( MAKE_SALCOLOR( 255, 255, 255 ) ) )
463 return false;
464 mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
465 return true;
468 void OpenGLSalGraphicsImpl::DrawPoint( long nX, long nY )
470 OpenGLZone aZone;
472 GLfloat pPoint[2];
474 pPoint[0] = GLfloat(nX);
475 pPoint[1] = GLfloat(nY);
477 ApplyProgramMatrices(0.5f);
478 mpProgram->SetVertices( pPoint );
479 glDrawArrays( GL_POINTS, 0, 1 );
481 CHECK_GL_ERROR();
484 void OpenGLSalGraphicsImpl::DrawLine( double nX1, double nY1, double nX2, double nY2 )
486 OpenGLZone aZone;
488 GLfloat pPoints[4];
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 );
499 CHECK_GL_ERROR();
502 void OpenGLSalGraphicsImpl::DrawLineAA( double nX1, double nY1, double nX2, double nY2 )
504 OpenGLZone aZone;
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);
517 return;
519 ImplDrawLineAA( nX1, nY1, nX2, nY2 );
521 CHECK_GL_ERROR();
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.*/
535 double x1 = nX1;
536 double y1 = nY1;
537 double x2 = nX2;
538 double y2 = nY2;
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;
546 double t(0.0);
547 double R(0.0);
548 double f = w - static_cast<int>(w);
549 //determine parameters t,R
550 if ( w>=0.0 && w<1.0 )
552 t=0.05;
553 R=0.48+0.32*f;
555 else if ( w>=1.0 && w<2.0 )
557 t=0.05+f*0.33;
558 R=0.768+0.312*f;
560 else if ( w>=2.0 && w<3.0 )
562 t=0.38+f*0.58;
563 R=1.08;
565 else if ( w>=3.0 && w<4.0 )
567 t=0.96+f*0.48;
568 R=1.08;
570 else if ( w>=4.0 && w<5.0 )
572 t=1.44+f*0.46;
573 R=1.08;
575 else if ( w>=5.0 && w<6.0 )
577 t=1.9+f*0.6;
578 R=1.08;
580 else if ( w>=6.0 )
582 double ff=w-6.0;
583 t=2.5+ff*0.50;
584 R=1.08;
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
590 double dx=x2-x1;
591 double dy=y2-y1;
592 if ( w < 3 )
593 { //approximate to make things even faster
594 double m=dy/dx;
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)
599 tx=t*0.1; ty=t;
600 Rx=R*0.6; Ry=R;
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)
611 tx=t; ty=t*0.1;
612 Rx=R; Ry=R*0.6;
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;
620 else
621 assert( false );
623 else
624 { //calculate to exact
625 dx=y1-y2;
626 dy=x2-x1;
627 double L=sqrt(dx*dx+dy*dy);
628 dx/=L;
629 dy/=L;
630 tx=t*dx; ty=t*dy;
631 Rx=R*dx; Ry=R*dy;
634 if( edge )
635 { // See above.
636 Rx += tx;
637 Ry += ty;
638 tx = ty = 0;
641 GLfloat vertices[]=
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);
659 CHECK_GL_ERROR();
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 );
666 if( bClose )
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 );
674 if( bClose )
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 )
688 OpenGLZone aZone;
690 std::vector<GLfloat> aVertices(nPoints * 2);
691 sal_uInt32 i, j;
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.
709 #ifdef DBG_UTIL
710 assert( mProgramIsSolidColor );
711 #endif
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 );
726 CHECK_GL_ERROR();
729 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon, bool blockAA )
731 OpenGLZone aZone;
733 sal_uInt16 nPoints = rPolygon.GetSize() - 1;
734 std::vector<GLfloat> aVertices(nPoints * 2);
735 sal_uInt32 i, j;
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.
754 #ifdef DBG_UTIL
755 assert( mProgramIsSolidColor );
756 #endif
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 );
771 CHECK_GL_ERROR();
774 void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA )
776 OpenGLZone aZone;
778 const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon();
779 sal_uInt16 nPoints = rPolygon.count();
780 std::vector<GLfloat> aVertices(nPoints * 2);
781 sal_uInt32 i, j;
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());
790 if (!mpProgram)
792 SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
793 return;
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.
806 #ifdef DBG_UTIL
807 assert( mProgramIsSolidColor );
808 #endif
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 );
823 CHECK_GL_ERROR();
826 void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight )
828 long nX1( nX );
829 long nY1( nY );
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 ) )
860 if( nPoints > 2L )
861 DrawConvexPolygon( nPoints, pPtAry );
863 else
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 )
885 OpenGLZone aZone;
887 RectangleVector aRects;
888 std::vector<GLfloat> aVertices;
889 rRegion.GetRegionRectangles( aRects );
891 if( aRects.empty() )
892 return;
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() );
909 #undef ADD_VERTICE
911 ApplyProgramMatrices();
912 mpProgram->SetVertices( &aVertices[0] );
913 glDrawArrays( GL_TRIANGLES, 0, aVertices.size() / 2 );
915 CHECK_GL_ERROR();
918 void OpenGLSalGraphicsImpl::DrawTextureRect( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted )
920 OpenGLZone aZone;
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 )
930 OpenGLZone aZone;
932 if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
933 return;
934 mpProgram->SetTexture( "sampler", rTexture );
935 DrawTextureRect( rTexture, pPosAry, bInverted );
936 mpProgram->Clean();
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 )
946 OpenGLZone aZone;
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)
963 areaScaling = true;
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";
972 else
973 textureFragmentShader = "areaScaleFragmentShader";
976 if( rMask )
978 if( !UseProgram( "transformedTextureVertexShader",
979 textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader,
980 "#define MASKED" ) )
981 return;
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 );
989 else
991 if( !UseProgram( "transformedTextureVertexShader",
992 textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader ) )
993 return;
996 int mnWidth = rTexture.GetWidth();
997 int mnHeight = rTexture.GetHeight();
998 if(areaScaling )
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 );
1032 mpProgram->Clean();
1034 CHECK_GL_ERROR();
1037 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool bPremultiplied )
1039 OpenGLZone aZone;
1041 if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
1042 return;
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 );
1047 mpProgram->Clean();
1050 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted )
1052 OpenGLZone aZone;
1054 if( !UseProgram( "maskedTextureVertexShader", "diffTextureFragmentShader" ) )
1055 return;
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 );
1065 mpProgram->Clean();
1068 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry )
1070 OpenGLZone aZone;
1072 if( !UseProgram( "maskedTextureVertexShader", "maskedTextureFragmentShader" ) )
1073 return;
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);
1087 mpProgram->Clean();
1090 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry )
1092 OpenGLZone aZone;
1094 if( !UseProgram( "blendedTextureVertexShader", "blendedTextureFragmentShader" ) )
1095 return;
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 );
1110 mpProgram->Clean();
1113 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor, const SalTwoRect& pPosAry )
1115 OpenGLZone aZone;
1117 if( !UseProgram( "textureVertexShader", "maskFragmentShader" ) )
1118 return;
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 );
1123 mpProgram->Clean();
1126 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
1128 OpenGLZone aZone;
1130 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1131 return;
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;
1140 Point aCenter;
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 )
1154 OpenGLZone aZone;
1156 if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
1157 return;
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.
1168 * 1 *---* 2
1169 * | /|
1170 * | / | Points 0 and 3 have start color
1171 * 0 |/__| 3 Points 1, 2, 4 and 5 have end color
1172 * |\ |
1173 * | \ |
1174 * | \|
1175 * 5 *---* 4
1179 Rectangle aRect;
1180 Point aCenter;
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 );
1187 Polygon aPoly( 7 );
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 )
1206 OpenGLZone aZone;
1208 if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
1209 return;
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 );
1217 Rectangle aRect;
1218 Point aCenter;
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 );
1229 DrawRect( rRect );
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 )
1239 PreDraw();
1240 if( UseSolid( mnLineColor ) )
1241 DrawPoint( nX, nY );
1242 PostDraw();
1246 void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor )
1248 VCL_GL_INFO( "vcl.opengl", "::drawPixel" );
1249 if( nSalColor != SALCOLOR_NONE )
1251 PreDraw();
1252 if( UseSolid( nSalColor ) )
1253 DrawPoint( nX, nY );
1254 PostDraw();
1258 void OpenGLSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 )
1260 VCL_GL_INFO( "vcl.opengl", "::drawLine" );
1261 if( mnLineColor != SALCOLOR_NONE )
1263 PreDraw();
1264 if( UseSolidAA( mnLineColor ) )
1265 DrawLineAA( nX1, nY1, nX2, nY2 );
1266 PostDraw();
1270 void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight )
1272 VCL_GL_INFO( "vcl.opengl", "::drawRect" );
1273 PreDraw();
1275 if( UseSolid( mnFillColor ) )
1276 DrawRect( nX, nY, nWidth, nHeight );
1278 if( UseSolid( mnLineColor ) )
1280 GLfloat fX1(nX);
1281 GLfloat fY1(nY);
1282 GLfloat fX2(nX + nWidth - 1);
1283 GLfloat fY2(nY + nHeight - 1);
1285 GLfloat pPoints[16];
1287 pPoints[0] = fX1;
1288 pPoints[1] = fY1;
1289 pPoints[2] = fX2;
1290 pPoints[3] = fY1;
1291 pPoints[4] = fX2;
1292 pPoints[5] = fY2;
1293 pPoints[6] = fX1;
1294 pPoints[7] = fY2;
1296 ApplyProgramMatrices(0.5f);
1297 mpProgram->SetVertices(pPoints);
1298 glDrawArrays(GL_LINE_LOOP, 0, 4);
1301 PostDraw();
1304 void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry )
1306 VCL_GL_INFO( "vcl.opengl", "::drawPolyLine" );
1308 if( mnLineColor != SALCOLOR_NONE && nPoints > 1 )
1310 PreDraw();
1311 if( UseSolidAA( mnLineColor ) )
1312 DrawLinesAA( nPoints, pPtAry, false );
1313 PostDraw();
1317 void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
1319 VCL_GL_INFO( "vcl.opengl", "::drawPolygon" );
1320 if( nPoints == 0 )
1321 return;
1322 if( nPoints == 1 )
1324 drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
1325 return;
1327 if( nPoints == 2 )
1329 drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
1330 pPtAry[1].mnX, pPtAry[1].mnY );
1331 return;
1334 PreDraw();
1336 if( UseSolid( mnFillColor ) )
1337 DrawPolygon( nPoints, pPtAry );
1339 if( UseSolidAA( mnLineColor ) )
1340 DrawLinesAA( nPoints, pPtAry, true );
1342 PostDraw();
1345 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry )
1347 VCL_GL_INFO( "vcl.opengl", "::drawPolyPolygon" );
1348 if( nPoly <= 0 )
1349 return;
1351 PreDraw();
1353 if( UseSolid( mnFillColor ) )
1355 if( nPoly == 1 )
1356 DrawPolygon( pPoints[ 0 ], pPtAry[ 0 ] );
1357 else
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 );
1379 PostDraw();
1382 bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency )
1384 VCL_GL_INFO( "vcl.opengl", "::drawPolyPolygon trans " << fTransparency );
1385 if( rPolyPolygon.count() <= 0 )
1386 return true;
1388 PreDraw();
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 ] );
1401 PostDraw();
1403 return true;
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 )
1415 return true;
1417 const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
1419 // #i101491#
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
1427 // the same way.
1428 return false;
1431 // shortcut for hairline drawing to improve performance
1432 if (bIsHairline)
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.
1437 return false;
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()));
1462 PreDraw();
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 );
1471 PostDraw();
1473 return true;
1476 bool OpenGLSalGraphicsImpl::drawPolyLineBezier(
1477 sal_uInt32 /*nPoints*/,
1478 const SalPoint* /*pPtAry*/,
1479 const sal_uInt8* /*pFlgAry*/ )
1481 return false;
1484 bool OpenGLSalGraphicsImpl::drawPolygonBezier(
1485 sal_uInt32 /*nPoints*/,
1486 const SalPoint* /*pPtAry*/,
1487 const sal_uInt8* /*pFlgAry*/ )
1489 return false;
1492 bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier(
1493 sal_uInt32 /*nPoly*/,
1494 const sal_uInt32* /*pPoints*/,
1495 const SalPoint* const* /*pPtAry*/,
1496 const sal_uInt8* const* /*pFlgAry*/ )
1498 return false;
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);
1512 PreDraw();
1513 // TODO offscreen case
1514 aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight,
1515 nSrcWidth, nSrcHeight );
1516 DrawTexture( aTexture, aPosAry );
1517 PostDraw();
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))
1533 return;
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 );
1537 return;
1540 if( rImpl.mbOffscreen )
1542 PreDraw();
1543 DrawTexture( rImpl.maOffscreenTex, rPosAry );
1544 PostDraw();
1545 return;
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" );
1562 PreDraw();
1563 DrawTexture( rTexture, rPosAry );
1564 PostDraw();
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" );
1586 PreDraw();
1587 DrawTextureWithMask( rTexture, rMaskTex, rPosAry );
1588 PostDraw();
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" );
1600 PreDraw();
1601 DrawMask( rTexture, nMaskColor, rPosAry );
1602 PostDraw();
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?
1611 PreDraw();
1612 if( !pBitmap->Create( maOffscreenTex, nX, nY, nWidth, nHeight ) )
1614 delete pBitmap;
1615 pBitmap = NULL;
1617 PostDraw();
1618 return pBitmap;
1621 SalColor OpenGLSalGraphicsImpl::getPixel( long nX, long nY )
1623 char pixel[3] = { 0, 0, 0 };
1625 PreDraw();
1626 nY = GetHeight() - nY - 1;
1627 glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
1628 PostDraw();
1630 CHECK_GL_ERROR();
1631 return MAKE_SALCOLOR( pixel[0], pixel[1], pixel[2] );
1634 // invert --> ClipRegion (only Windows or VirDevs)
1635 void OpenGLSalGraphicsImpl::invert(
1636 long nX, long nY,
1637 long nWidth, long nHeight,
1638 SalInvert nFlags)
1640 // TODO Figure out what are those:
1641 // * SAL_INVERT_50 (50/50 pattern?)
1642 // * SAL_INVERT_TRACKFRAME (dash-line rectangle?)
1644 PreDraw();
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!");
1654 else // just invert
1656 if( UseInvert() )
1657 DrawRect( nX, nY, nWidth, nHeight );
1660 PostDraw();
1663 void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags )
1665 PreDraw();
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!");
1675 else // just invert
1677 if( UseInvert() )
1678 DrawPolygon( nPoints, pPtAry );
1681 PostDraw();
1684 bool OpenGLSalGraphicsImpl::drawEPS(
1685 long /*nX*/, long /*nY*/,
1686 long /*nWidth*/, long /*nHeight*/,
1687 void* /*pPtr*/,
1688 sal_uLong /*nSize*/ )
1690 return false;
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" );
1701 PreDraw();
1702 glEnable( GL_BLEND );
1703 glBlendFunc( GL_ZERO, GL_SRC_COLOR );
1704 DrawTexture( rTexture, rPosAry );
1705 glDisable( GL_BLEND );
1706 PostDraw();
1707 return true;
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" );
1724 PreDraw();
1725 DrawBlendedTexture( rTexture, rMask, rAlpha, rPosAry );
1726 PostDraw();
1727 return true;
1730 /** Render bitmap with alpha channel
1732 @param rSourceBitmap
1733 Source bitmap to blit
1735 @param rAlphaBitmap
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" );
1753 PreDraw();
1754 DrawTextureWithMask( rTexture, rAlphaTex, rPosAry );
1755 PostDraw();
1756 return true;
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" );
1776 PreDraw();
1777 DrawTransformedTexture( rTexture, aMask, rNull, rX, rY );
1778 PostDraw();
1780 return true;
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(
1790 long nX, long nY,
1791 long nWidth, long nHeight,
1792 sal_uInt8 nTransparency )
1794 VCL_GL_INFO( "vcl.opengl", "::drawAlphaRect" );
1795 if( mnFillColor != SALCOLOR_NONE && nTransparency < 100 )
1797 PreDraw();
1798 UseSolid( mnFillColor, nTransparency );
1799 DrawRect( nX, nY, nWidth, nHeight );
1800 PostDraw();
1803 return true;
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() )
1814 return true;
1816 if( rGradient.GetStyle() != GradientStyle_LINEAR &&
1817 rGradient.GetStyle() != GradientStyle_AXIAL &&
1818 rGradient.GetStyle() != GradientStyle_RADIAL )
1819 return false;
1821 aBoundRect.Left()--;
1822 aBoundRect.Top()--;
1823 aBoundRect.Right()++;
1824 aBoundRect.Bottom()++;
1826 PreDraw();
1828 #define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0
1829 #if FIXME_BROKEN_STENCIL_FOR_GRADIENTS
1830 ImplSetClipBit( vcl::Region( rPolyPoly ), 0x02 );
1831 if( mbUseStencil )
1833 glEnable( GL_STENCIL_TEST );
1834 glStencilFunc( GL_EQUAL, 3, 0xFF );
1836 else
1838 glEnable( GL_STENCIL_TEST );
1839 glStencilFunc( GL_EQUAL, 2, 0xFF );
1841 #endif
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
1867 if( !mbUseStencil )
1868 glDisable( GL_STENCIL_TEST );
1869 #endif
1870 PostDraw();
1872 CHECK_GL_ERROR();
1873 return true;
1876 OpenGLContext *OpenGLSalGraphicsImpl::beginPaint()
1878 if( mbOffscreen || !AcquireContext() )
1879 return NULL;
1880 else
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: */