KiCad PCB EDA Suite
opengl_gal.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2012-2018 Kicad Developers, see AUTHORS.txt for contributors.
6  * Copyright (C) 2013-2017 CERN
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * Graphics Abstraction Layer (GAL) for OpenGL
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 // Apple, in their infinite wisdom, has decided to mark OpenGL as deprecated.
30 // Luckily we can silence warnings about its deprecation.
31 #ifdef __APPLE__
32 #define GL_SILENCE_DEPRECATION 1
33 #endif
34 
35 #include <gal/opengl/opengl_gal.h>
36 #include <gal/opengl/utils.h>
37 #include <gal/definitions.h>
38 #include <gl_context_mgr.h>
40 #include <bitmap_base.h>
41 #include <bezier_curves.h>
42 #include <math/util.h> // for KiROUND
43 
44 #include <macros.h>
45 
46 #ifdef __WXDEBUG__
47 #include <profile.h>
48 #include <wx/log.h>
49 #endif /* __WXDEBUG__ */
50 
51 #include <functional>
52 #include <limits>
53 #include <memory>
54 using namespace std::placeholders;
55 using namespace KIGFX;
56 
57 // A ugly workaround to avoid serious issues (crashes) when using bitmaps cache
58 // to speedup redraw.
59 // issues arise when using bitmaps in page layout, when the page layout containd bitmaps,
60 // and is common to schematic and board editor,
61 // and the schematic is a hierarchy and when using cross-probing
62 // When the cross probing from pcbnew to eeschema switches to a sheet, the bitmaps cache
63 // becomes broken (in fact the associated texture).
64 // I hope (JPC) it will be fixed later, but a slighty slower refresh is better than a crash
65 #define DISABLE_BITMAP_CACHE
66 
67 // The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0
68 // (see ubuntu-font-licence-1.0.txt for details)
69 #include "gl_resources.h"
70 #include "gl_builtin_shaders.h"
71 using namespace KIGFX::BUILTIN_FONT;
72 
73 static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
74 static const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 8, 0 };
75 
76 wxGLContext* OPENGL_GAL::glMainContext = NULL;
77 int OPENGL_GAL::instanceCounter = 0;
78 GLuint OPENGL_GAL::fontTexture = 0;
79 bool OPENGL_GAL::isBitmapFontLoaded = false;
80 
81 namespace KIGFX {
83 {
84 public:
86  {
87  }
88 
89  ~GL_BITMAP_CACHE();
90 
91  GLuint RequestBitmap( const BITMAP_BASE* aBitmap );
92 
93 private:
94 
96  {
97  GLuint id;
98  int w, h;
99  };
100 
101  GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
102 
103  std::map<const BITMAP_BASE*, CACHED_BITMAP> m_bitmaps;
104 };
105 
106 };
107 
108 
109 GL_BITMAP_CACHE::~GL_BITMAP_CACHE()
110 {
111  for ( auto b = m_bitmaps.begin(); b != m_bitmaps.end(); ++b )
112  glDeleteTextures( 1, &b->second.id );
113 }
114 
115 
116 GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
117 {
118  auto it = m_bitmaps.find( aBitmap) ;
119 
120  if ( it != m_bitmaps.end() )
121  {
122  // A bitmap is found in cache bitmap.
123  // Ensure the associated texture is still valid (can be destroyed somewhere)
124  if( glIsTexture( it->second.id ) )
125  return it->second.id;
126 
127  // else if not valid, it will be recreated.
128  }
129 
130  return cacheBitmap( aBitmap );
131 }
132 
133 
134 GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
135 {
136  CACHED_BITMAP bmp;
137 
138  bmp.w = aBitmap->GetSizePixels().x;
139  bmp.h = aBitmap->GetSizePixels().y;
140 
141  // The bitmap size needs to be a multiple of 4.
142  // This is easiest to achieve by ensuring that each row
143  // has a multiple of 4 pixels
144  int extra_w = bmp.w % 4;
145 
146  if( extra_w )
147  extra_w = 4 - extra_w;
148 
149  GLuint textureID;
150  glGenTextures(1, &textureID);
151 
152  // make_unique initializes this to 0, so extra pixels are transparent
153  auto buf = std::make_unique<uint8_t[]>( ( bmp.w + extra_w ) * bmp.h * 4 );
154  const wxImage& imgData = *aBitmap->GetImageData();
155 
156  for( int y = 0; y < bmp.h; y++ )
157  {
158  for( int x = 0; x < bmp.w; x++ )
159  {
160  uint8_t *p = buf.get() + ( ( bmp.w + extra_w ) * y + x ) * 4;
161 
162  p[0] = imgData.GetRed( x, y );
163  p[1] = imgData.GetGreen( x, y );
164  p[2] = imgData.GetBlue( x, y );
165 
166  if( imgData.HasAlpha() )
167  p[3] = imgData.GetAlpha( x, y );
168  else if( imgData.HasMask() && p[0] == imgData.GetMaskRed() &&
169  p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
170  p[3] = wxALPHA_TRANSPARENT;
171  else
172  p[3] = wxALPHA_OPAQUE;
173  }
174  }
175 
176  glBindTexture( GL_TEXTURE_2D, textureID );
177  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w + extra_w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf.get() );
178 
179  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
180  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
181 
182  bmp.id = textureID;
183 
184 #ifndef DISABLE_BITMAP_CACHE
185  m_bitmaps[ aBitmap ] = bmp;
186 #endif
187 
188  return textureID;
189 }
190 
191 OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
192  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
193  const wxString& aName ) :
194  GAL( aDisplayOptions ),
195  HIDPI_GL_CANVAS( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
196  wxEXPAND, aName ),
197  mouseListener( aMouseListener ),
198  paintListener( aPaintListener ),
199  currentManager( nullptr ),
200  cachedManager( nullptr ),
201  nonCachedManager( nullptr ),
202  overlayManager( nullptr ),
203  mainBuffer( 0 ),
204  overlayBuffer( 0 ),
205  isContextLocked( false ),
206  lockClientCookie( 0 )
207 {
208 // IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4
209 // starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER)
210 #if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 )
211  const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 };
212 
213  if( !IsDisplaySupported( attr ) )
214  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
215 #endif /* wxCHECK_VERSION( 3, 0, 3 ) */
216 
217  if( glMainContext == NULL )
218  {
220 
221  if( !glMainContext )
222  throw std::runtime_error( "Could not create the main OpenGL context" );
223 
225  }
226  else
227  {
229 
230  if( !glPrivContext )
231  throw std::runtime_error( "Could not create a private OpenGL context" );
232  }
233 
234  shader = new SHADER();
235  ++instanceCounter;
236 
237  bitmapCache = std::make_unique<GL_BITMAP_CACHE>( );
238 
241 
242  // Initialize the flags
243  isFramebufferInitialized = false;
244  isBitmapFontInitialized = false;
245  isInitialized = false;
246  isGrouping = false;
247  groupCounter = 0;
248 
249  // Connecting the event handlers
250  Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) );
251 
252  // Mouse events are skipped to the parent
253  Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
254  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
255  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
256  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
257  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
258  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
259  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
260  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
261  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
262  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
263  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
264 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
265  Connect( wxEVT_MAGNIFY, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
266 #endif
267 #if defined _WIN32 || defined _WIN64
268  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
269 #endif
270 
271  SetSize( aParent->GetClientSize() );
273 
274  // Grid color settings are different in Cairo and OpenGL
275  SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) );
276  SetAxesColor( COLOR4D( BLUE ) );
277 
278  // Tesselator initialization
279  tesselator = gluNewTess();
281 
282  if( tesselator == NULL )
283  throw std::runtime_error( "Could not create the tesselator" );
284 
285  gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
286 
288 
289  // Avoid unitialized variables:
290  ufm_worldPixelSize = 1;
293 }
294 
295 
297 {
299 
300  --instanceCounter;
301  glFlush();
302  gluDeleteTess( tesselator );
303  ClearCache();
304 
305  delete compositor;
306 
307  if( isInitialized )
308  {
309  delete cachedManager;
310  delete nonCachedManager;
311  delete overlayManager;
312  }
313 
315 
316  // If it was the main context, then it will be deleted
317  // when the last OpenGL GAL instance is destroyed (a few lines below)
320 
321  delete shader;
322 
323  // Are we destroying the last GAL instance?
324  if( instanceCounter == 0 )
325  {
327 
328  if( isBitmapFontLoaded )
329  {
330  glDeleteTextures( 1, &fontTexture );
331  isBitmapFontLoaded = false;
332  }
333 
337  }
338 }
339 
340 
342 {
343  bool refresh = false;
344 
346  {
348  isFramebufferInitialized = false;
349  refresh = true;
350  }
351 
353  {
355  refresh = true;
356  }
357 
358  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
359  {
360  Refresh();
361  refresh = true;
362  }
363 
364  return refresh;
365 }
366 
367 
369 {
370  auto matrix = GetScreenWorldMatrix();
371  return std::min( std::abs( matrix.GetScale().x ), std::abs( matrix.GetScale().y ) );
372 }
373 
374 
376 {
377  auto sf = GetBackingScaleFactor();
378  return VECTOR2D( 2.0 / (double) ( screenSize.x * sf ), 2.0 / (double) ( screenSize.y * sf ) );
379 }
380 
381 
383 {
384 #ifdef __WXDEBUG__
385  PROF_COUNTER totalRealTime( "OPENGL_GAL::beginDrawing()", true );
386 #endif /* __WXDEBUG__ */
387 
388  wxASSERT_MSG( isContextLocked, "GAL_DRAWING_CONTEXT RAII object should have locked context. "
389  "Calling GAL::beginDrawing() directly is not allowed." );
390 
391  wxASSERT_MSG( IsVisible(), "GAL::beginDrawing() must not be entered when GAL is not visible. "
392  "Other drawing routines will expect everything to be initialized "
393  "which will not be the case." );
394 
395  if( !isInitialized )
396  init();
397 
398  // Set up the view port
399  glMatrixMode( GL_PROJECTION );
400  glLoadIdentity();
401 
402  // Create the screen transformation (Do the RH-LH conversion here)
403  glOrtho( 0, (GLint) screenSize.x, (GLsizei) screenSize.y, 0, -depthRange.x, -depthRange.y );
404 
406  {
407  // Prepare rendering target buffers
411 
413  }
414 
415  compositor->Begin();
416 
417  // Disable 2D Textures
418  glDisable( GL_TEXTURE_2D );
419 
420  glShadeModel( GL_FLAT );
421 
422  // Enable the depth buffer
423  glEnable( GL_DEPTH_TEST );
424  glDepthFunc( GL_LESS );
425 
426  // Setup blending, required for transparent objects
427  glEnable( GL_BLEND );
428  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
429 
430  glMatrixMode( GL_MODELVIEW );
431 
432  // Set up the world <-> screen transformation
434  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
435  matrixData[0] = worldScreenMatrix.m_data[0][0];
436  matrixData[1] = worldScreenMatrix.m_data[1][0];
437  matrixData[2] = worldScreenMatrix.m_data[2][0];
438  matrixData[4] = worldScreenMatrix.m_data[0][1];
439  matrixData[5] = worldScreenMatrix.m_data[1][1];
440  matrixData[6] = worldScreenMatrix.m_data[2][1];
441  matrixData[12] = worldScreenMatrix.m_data[0][2];
442  matrixData[13] = worldScreenMatrix.m_data[1][2];
443  matrixData[14] = worldScreenMatrix.m_data[2][2];
444  glLoadMatrixd( matrixData );
445 
446  // Set defaults
449 
450  // Remove all previously stored items
453 
457 
459  {
460  // Keep bitmap font texture always bound to the second texturing unit
461  const GLint FONT_TEXTURE_UNIT = 2;
462 
463  // Either load the font atlas to video memory, or simply bind it to a texture unit
464  if( !isBitmapFontLoaded )
465  {
466  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
467  glGenTextures( 1, &fontTexture );
468  glBindTexture( GL_TEXTURE_2D, fontTexture );
469  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height,
470  0, GL_RGB, GL_UNSIGNED_BYTE, font_image.pixels );
471  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
472  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
473  checkGlError( "loading bitmap font" );
474 
475  glActiveTexture( GL_TEXTURE0 );
476 
477  isBitmapFontLoaded = true;
478  }
479  else
480  {
481  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
482  glBindTexture( GL_TEXTURE_2D, fontTexture );
483  glActiveTexture( GL_TEXTURE0 );
484  }
485 
486  // Set shader parameter
487  GLint ufm_fontTexture = shader->AddParameter( "fontTexture" );
488  GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" );
489  ufm_worldPixelSize = shader->AddParameter( "worldPixelSize" );
490  ufm_screenPixelSize = shader->AddParameter( "screenPixelSize" );
491  ufm_pixelSizeMultiplier = shader->AddParameter( "pixelSizeMultiplier" );
492 
493  shader->Use();
494  shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
495  shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
496  shader->Deactivate();
497  checkGlError( "setting bitmap font sampler as shader parameter" );
498 
500  }
501 
502  shader->Use();
505  double pixelSizeMultiplier = compositor->GetAntialiasSupersamplingFactor();
506  shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
507  shader->Deactivate();
508 
509  // Something betreen BeginDrawing and EndDrawing seems to depend on
510  // this texture unit being active, but it does not assure it itself.
511  glActiveTexture( GL_TEXTURE0 );
512 
513  // Unbind buffers - set compositor for direct drawing
515 
516 #ifdef __WXDEBUG__
517  totalRealTime.Stop();
518  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::beginDrawing(): %.1f ms" ), totalRealTime.msecs() );
519 #endif /* __WXDEBUG__ */
520 }
521 
522 
524 {
525  wxASSERT_MSG( isContextLocked, "What happened to the context lock?" );
526 
527 #ifdef __WXDEBUG__
528  PROF_COUNTER totalRealTime( "OPENGL_GAL::endDrawing()", true );
529 #endif /* __WXDEBUG__ */
530 
531  // Cached & non-cached containers are rendered to the same buffer
535 
536  // Overlay container is rendered to a different buffer
539 
540  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
541  glColor4d( 1.0, 1.0, 1.0, 1.0 );
542 
543  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
546  compositor->Present();
547  blitCursor();
548 
549  SwapBuffers();
550 
551 #ifdef __WXDEBUG__
552  totalRealTime.Stop();
553  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::endDrawing(): %.1f ms" ), totalRealTime.msecs() );
554 #endif /* __WXDEBUG__ */
555 }
556 
557 
558 void OPENGL_GAL::lockContext( int aClientCookie )
559 {
560  wxASSERT_MSG( !isContextLocked, "Context already locked." );
561  isContextLocked = true;
562  lockClientCookie = aClientCookie;
563 
565 }
566 
567 
568 void OPENGL_GAL::unlockContext( int aClientCookie )
569 {
570  wxASSERT_MSG( isContextLocked, "Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
571  "be stacked rather than making separate lock/unlock calls." );
572 
573  wxASSERT_MSG( lockClientCookie == aClientCookie, "Context was locked by a different client. "
574  "Should not be possible with RAII objects." );
575 
576  isContextLocked = false;
577 
579 }
580 
581 
583 {
584  wxASSERT_MSG( isContextLocked, "GAL_UPDATE_CONTEXT RAII object should have locked context. "
585  "Calling this from anywhere else is not allowed." );
586 
587  wxASSERT_MSG( IsVisible(), "GAL::beginUpdate() must not be entered when GAL is not visible. "
588  "Other update routines will expect everything to be initialized "
589  "which will not be the case." );
590 
591  if( !isInitialized )
592  init();
593 
594  cachedManager->Map();
595 }
596 
597 
599 {
600  if( !isInitialized )
601  return;
602 
603  cachedManager->Unmap();
604 }
605 
606 
607 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
608 {
610 
611  drawLineQuad( aStartPoint, aEndPoint );
612 }
613 
614 
615 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
616  double aWidth )
617 {
618  if( aStartPoint == aEndPoint ) // 0 length segments are just a circle.
619  {
620  DrawCircle( aStartPoint, aWidth/2 );
621  return;
622  }
623 
624  if( isFillEnabled || aWidth == 1.0 )
625  {
627 
628  SetLineWidth( aWidth );
629  drawLineQuad( aStartPoint, aEndPoint );
630  }
631  else
632  {
633  auto startEndVector = aEndPoint - aStartPoint;
634  auto lineAngle = startEndVector.Angle();
635  // Outlined tracks
636  double lineLength = startEndVector.EuclideanNorm();
637 
638  SetLineWidth( 1.0 );
640 
641  Save();
642 
643  currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
644  currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
645 
646  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
647  VECTOR2D( lineLength, aWidth / 2.0 ) );
648 
649  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ),
650  VECTOR2D( lineLength, -aWidth / 2.0 ) );
651 
652  // Draw line caps
653  drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
654  drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );
655 
656  Restore();
657  }
658 }
659 
660 
661 void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
662 {
663  if( isFillEnabled )
664  {
665  currentManager->Reserve( 3 );
667 
668  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
669  * Parameters given to Shader() are indices of the triangle's vertices
670  * (if you want to understand more, check the vertex shader source [shader.vert]).
671  * Shader uses this coordinates to determine if fragments are inside the circle or not.
672  * Does the calculations in the vertex shader now (pixel alignment)
673  * v2
674  * /\
675  * //\\
676  * v0 /_\/_\ v1
677  */
678  currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0, aRadius );
679  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
680 
681  currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0, aRadius );
682  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
683 
684  currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0, aRadius );
685  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
686  }
687  if( isStrokeEnabled )
688  {
689  currentManager->Reserve( 3 );
691 
692  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
693  * Parameters given to Shader() are indices of the triangle's vertices
694  * (if you want to understand more, check the vertex shader source [shader.vert]).
695  * and the line width. Shader uses this coordinates to determine if fragments are
696  * inside the circle or not.
697  * v2
698  * /\
699  * //\\
700  * v0 /_\/_\ v1
701  */
703  currentManager->Vertex( aCenterPoint.x, // v0
704  aCenterPoint.y, layerDepth );
705 
707  currentManager->Vertex( aCenterPoint.x, // v1
708  aCenterPoint.y, layerDepth );
709 
711  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, // v2
712  layerDepth );
713  }
714 }
715 
716 
717 void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
718  double aEndAngle )
719 {
720  if( aRadius <= 0 )
721  return;
722 
723  // Swap the angles, if start angle is greater than end angle
724  SWAP( aStartAngle, >, aEndAngle );
725 
726  const double alphaIncrement = calcAngleStep( aRadius );
727 
728  Save();
729  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
730 
731  if( isFillEnabled )
732  {
733  double alpha;
736 
737  // Triangle fan
738  for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
739  {
740  currentManager->Reserve( 3 );
741  currentManager->Vertex( 0.0, 0.0, layerDepth );
742  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
743  alpha += alphaIncrement;
744  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
745  }
746 
747  // The last missing triangle
748  const VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
749 
750  currentManager->Reserve( 3 );
751  currentManager->Vertex( 0.0, 0.0, layerDepth );
752  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
753  currentManager->Vertex( endPoint.x, endPoint.y, layerDepth );
754  }
755 
756  if( isStrokeEnabled )
757  {
759 
760  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
761  double alpha;
762 
763  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
764  {
765  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
766  DrawLine( p, p_next );
767 
768  p = p_next;
769  }
770 
771  // Draw the last missing part
772  if( alpha != aEndAngle )
773  {
774  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
775  DrawLine( p, p_last );
776  }
777  }
778 
779  Restore();
780 }
781 
782 
783 void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
784  double aEndAngle, double aWidth )
785 {
786  if( aRadius <= 0 )
787  {
788  // Arcs of zero radius are a circle of aWidth diameter
789  if( aWidth > 0 )
790  DrawCircle( aCenterPoint, aWidth / 2.0 );
791 
792  return;
793  }
794 
795  // Swap the angles, if start angle is greater than end angle
796  SWAP( aStartAngle, >, aEndAngle );
797 
798  const double alphaIncrement = calcAngleStep( aRadius );
799 
800  Save();
801  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
802 
803  if( isStrokeEnabled )
804  {
806 
807  double width = aWidth / 2.0;
808  VECTOR2D startPoint( cos( aStartAngle ) * aRadius,
809  sin( aStartAngle ) * aRadius );
810  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
811  sin( aEndAngle ) * aRadius );
812 
813  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
814  drawStrokedSemiCircle( endPoint, width, aEndAngle );
815 
816  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
817  sin( aStartAngle ) * ( aRadius + width ) );
818 
819  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
820  sin( aStartAngle ) * ( aRadius - width ) );
821 
822  double alpha;
823 
824  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
825  {
826  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
827  sin( alpha ) * ( aRadius + width ) );
828  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
829  sin( alpha ) * ( aRadius - width ) );
830 
831  DrawLine( pOuter, pNextOuter );
832  DrawLine( pInner, pNextInner );
833 
834  pOuter = pNextOuter;
835  pInner = pNextInner;
836  }
837 
838  // Draw the last missing part
839  if( alpha != aEndAngle )
840  {
841  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
842  sin( aEndAngle ) * ( aRadius + width ) );
843  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
844  sin( aEndAngle ) * ( aRadius - width ) );
845 
846  DrawLine( pOuter, pLastOuter );
847  DrawLine( pInner, pLastInner );
848  }
849  }
850 
851  if( isFillEnabled )
852  {
854  SetLineWidth( aWidth );
855 
856  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
857  double alpha;
858 
859  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
860  {
861  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
862  DrawLine( p, p_next );
863 
864  p = p_next;
865  }
866 
867  // Draw the last missing part
868  if( alpha != aEndAngle )
869  {
870  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
871  DrawLine( p, p_last );
872  }
873  }
874 
875  Restore();
876 }
877 
878 
879 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
880 {
881  // Compute the diagonal points of the rectangle
882  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
883  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
884 
885  // Fill the rectangle
886  if( isFillEnabled )
887  {
888  currentManager->Reserve( 6 );
891 
892  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
893  currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
894  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
895 
896  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
897  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
898  currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
899  }
900 
901  // Stroke the outline
902  if( isStrokeEnabled )
903  {
905 
906  std::deque<VECTOR2D> pointList;
907  pointList.push_back( aStartPoint );
908  pointList.push_back( diagonalPointA );
909  pointList.push_back( aEndPoint );
910  pointList.push_back( diagonalPointB );
911  pointList.push_back( aStartPoint );
912  DrawPolyline( pointList );
913  }
914 }
915 
916 
917 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
918 {
919  drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
920 }
921 
922 
923 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
924 {
925  drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
926 }
927 
928 
930 {
931  auto numPoints = aLineChain.PointCount();
932 
933  if( aLineChain.IsClosed() )
934  numPoints += 1;
935 
936  drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, numPoints );
937 }
938 
939 
940 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
941 {
942  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
943  GLdouble* ptr = points.get();
944 
945  for( const VECTOR2D& p : aPointList )
946  {
947  *ptr++ = p.x;
948  *ptr++ = p.y;
949  *ptr++ = layerDepth;
950  }
951 
952  drawPolygon( points.get(), aPointList.size() );
953 }
954 
955 
956 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
957 {
958  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
959  GLdouble* target = points.get();
960  const VECTOR2D* src = aPointList;
961 
962  for( int i = 0; i < aListSize; ++i )
963  {
964  *target++ = src->x;
965  *target++ = src->y;
966  *target++ = layerDepth;
967  ++src;
968  }
969 
970  drawPolygon( points.get(), aListSize );
971 }
972 
973 
975 {
978 
979  if( isFillEnabled )
980  {
981  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
982  {
983  auto triPoly = aPolySet.TriangulatedPolygon( j );
984 
985  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
986  {
987  VECTOR2I a, b, c;
988  triPoly->GetTriangle( i, a, b, c );
989  currentManager->Vertex( a.x, a.y, layerDepth );
990  currentManager->Vertex( b.x, b.y, layerDepth );
991  currentManager->Vertex( c.x, c.y, layerDepth );
992  }
993  }
994  }
995 
996  if( isStrokeEnabled )
997  {
998  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
999  {
1000  const auto& poly = aPolySet.Polygon( j );
1001 
1002  for( const auto& lc : poly )
1003  {
1004  DrawPolyline( lc );
1005  }
1006  }
1007  }
1008 }
1009 
1010 
1012 {
1013  if ( aPolySet.IsTriangulationUpToDate() )
1014  {
1015  drawTriangulatedPolyset( aPolySet );
1016  return;
1017  }
1018 
1019  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1020  {
1021  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
1022  DrawPolygon( outline );
1023  }
1024 }
1025 
1026 
1027 
1029 {
1030  if( aPolygon.SegmentCount() == 0 )
1031  return;
1032 
1033  const int pointCount = aPolygon.SegmentCount() + 1;
1034  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
1035  GLdouble* ptr = points.get();
1036 
1037  for( int i = 0; i < pointCount; ++i )
1038  {
1039  const VECTOR2I& p = aPolygon.CPoint( i );
1040  *ptr++ = p.x;
1041  *ptr++ = p.y;
1042  *ptr++ = layerDepth;
1043  }
1044 
1045  drawPolygon( points.get(), pointCount );
1046 }
1047 
1048 
1049 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
1050  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint,
1051  double aFilterValue )
1052 {
1053  std::vector<VECTOR2D> output;
1054  std::vector<VECTOR2D> pointCtrl;
1055 
1056  pointCtrl.push_back( aStartPoint );
1057  pointCtrl.push_back( aControlPointA );
1058  pointCtrl.push_back( aControlPointB );
1059  pointCtrl.push_back( aEndPoint );
1060 
1061  BEZIER_POLY converter( pointCtrl );
1062  converter.GetPoly( output, aFilterValue );
1063 
1064  DrawPolyline( &output[0], output.size() );
1065 }
1066 
1067 
1068 void OPENGL_GAL::DrawBitmap( const BITMAP_BASE& aBitmap )
1069 {
1070  // We have to calculate the pixel size in users units to draw the image.
1071  // worldUnitLength is a factor used for converting IU to inches
1072  double scale = 1.0 / ( aBitmap.GetPPI() * worldUnitLength );
1073  double w = (double) aBitmap.GetSizePixels().x * scale;
1074  double h = (double) aBitmap.GetSizePixels().y * scale;
1075 
1076  auto xform = currentManager->GetTransformation();
1077 
1078  glm::vec4 v0 = xform * glm::vec4( -w/2, -h/2, 0.0, 0.0 );
1079  glm::vec4 v1 = xform * glm::vec4( w/2, h/2, 0.0, 0.0 );
1080  glm::vec4 trans = xform[3];
1081 
1082  auto texture_id = bitmapCache->RequestBitmap( &aBitmap );
1083 
1084  if( !glIsTexture( texture_id ) ) // ensure the bitmap texture is still valid
1085  return;
1086 
1087  auto oldTarget = GetTarget();
1088 
1089  glPushMatrix();
1090  glTranslated( trans.x, trans.y, trans.z );
1091 
1093  glEnable(GL_TEXTURE_2D);
1094  glActiveTexture( GL_TEXTURE0 );
1095  glBindTexture( GL_TEXTURE_2D, texture_id );
1096 
1097  glBegin( GL_QUADS );
1098  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1099  glTexCoord2f( 0.0, 0.0 );
1100  glVertex3f( v0.x, v0.y, layerDepth );
1101  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1102  glTexCoord2f( 1.0, 0.0 );
1103  glVertex3f( v1.x, v0.y, layerDepth );
1104  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1105  glTexCoord2f( 1.0, 1.0 );
1106  glVertex3f( v1.x, v1.y, layerDepth );
1107  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1108  glTexCoord2f( 0.0, 1.0 );
1109  glVertex3f( v0.x, v1.y, layerDepth );
1110  glEnd();
1111 
1112  SetTarget( oldTarget );
1113  glBindTexture( GL_TEXTURE_2D, 0 );
1114 
1115 #ifdef DISABLE_BITMAP_CACHE
1116  glDeleteTextures( 1, &texture_id );
1117 #endif
1118 
1119  glPopMatrix();
1120 }
1121 
1122 
1123 void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
1124  double aRotationAngle )
1125 {
1126  wxASSERT_MSG( !IsTextMirrored(), "No support for mirrored text using bitmap fonts." );
1127 
1128  const UTF8 text( aText );
1129  // Compute text size, so it can be properly justified
1130  VECTOR2D textSize;
1131  float commonOffset;
1132  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
1133 
1134  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
1135  bool overbar = false;
1136 
1137  int overbarLength = 0;
1138  double overbarHeight = textSize.y;
1139 
1140  Save();
1141 
1143  currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
1144  currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
1145 
1146  double sx = SCALE * ( globalFlipX ? -1.0 : 1.0 );
1147  double sy = SCALE * ( globalFlipY ? -1.0 : 1.0 );
1148 
1149  currentManager->Scale( sx, sy, 0 );
1150  currentManager->Translate( 0, -commonOffset, 0 );
1151 
1152  switch( GetHorizontalJustify() )
1153  {
1155  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
1156  break;
1157 
1159  //if( !IsTextMirrored() )
1160  Translate( VECTOR2D( -textSize.x, 0 ) );
1161  break;
1162 
1163  case GR_TEXT_HJUSTIFY_LEFT:
1164  //if( IsTextMirrored() )
1165  //Translate( VECTOR2D( -textSize.x, 0 ) );
1166  break;
1167  }
1168 
1169  switch( GetVerticalJustify() )
1170  {
1171  case GR_TEXT_VJUSTIFY_TOP:
1172  Translate( VECTOR2D( 0, -textSize.y ) );
1173  overbarHeight = -textSize.y / 2.0;
1174  break;
1175 
1177  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
1178  overbarHeight = 0;
1179  break;
1180 
1182  break;
1183  }
1184 
1185  int i = 0;
1186 
1187  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
1188  {
1189  unsigned int c = *chIt;
1190  wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
1191 
1192  bool wasOverbar = overbar;
1193 
1194  if( c == '~' )
1195  {
1196  if( ++chIt == end )
1197  break;
1198 
1199  c = *chIt;
1200 
1201  if( c == '~' )
1202  {
1203  // double ~ is really a ~ so go ahead and process the second one
1204 
1205  // so what's a triple ~? It could be a real ~ followed by an overbar, or
1206  // it could be an overbar followed by a real ~. The old algorithm did the
1207  // former so we will too....
1208  }
1209  else
1210  {
1211  overbar = !overbar;
1212  }
1213  }
1214 
1215  if( wasOverbar && !overbar )
1216  {
1217  drawBitmapOverbar( overbarLength, overbarHeight );
1218  overbarLength = 0;
1219  }
1220 
1221  if( overbar )
1222  overbarLength += drawBitmapChar( c );
1223  else
1224  drawBitmapChar( c );
1225 
1226  ++i;
1227  }
1228 
1229  // Handle the case when overbar is active till the end of the drawn text
1230  currentManager->Translate( 0, commonOffset, 0 );
1231 
1232  if( overbar && overbarLength > 0 )
1233  drawBitmapOverbar( overbarLength, overbarHeight );
1234 
1235  Restore();
1236 }
1237 
1238 
1240 {
1243 
1245 
1246  // sub-pixel lines all render the same
1247  float minorLineWidth =
1248  std::fmax( 1.0f, gridLineWidth ) * getWorldPixelSize() / GetBackingScaleFactor();
1249  float majorLineWidth = minorLineWidth * 2.0f;
1250 
1251  // Draw the axis and grid
1252  // For the drawing the start points, end points and increments have
1253  // to be calculated in world coordinates
1254  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1255  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
1256 
1257  // Draw axes if desired
1258  if( axesEnabled )
1259  {
1260  SetLineWidth( minorLineWidth );
1262 
1263  DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) );
1264  DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) );
1265  }
1266 
1267  // force flush
1269 
1270  if( !gridVisibility || gridSize.x == 0 || gridSize.y == 0 )
1271  return;
1272 
1273  VECTOR2D gridScreenSize( gridSize );
1274 
1275  double gridThreshold = computeMinGridSpacing() / worldScale;
1276 
1278  gridThreshold *= 2.0;
1279 
1280  // If we cannot display the grid density, scale down by a tick size and
1281  // try again. Eventually, we get some representation of the grid
1282  while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold )
1283  {
1284  gridScreenSize = gridScreenSize * static_cast<double>( gridTick );
1285  }
1286 
1287  // Compute grid starting and ending indexes to draw grid points on the
1288  // visible screen area
1289  // Note: later any point coordinate will be offsetted by gridOrigin
1290  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridScreenSize.x );
1291  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridScreenSize.x );
1292  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridScreenSize.y );
1293  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridScreenSize.y );
1294 
1295  // Ensure start coordinate > end coordinate
1296  SWAP( gridStartX, >, gridEndX );
1297  SWAP( gridStartY, >, gridEndY );
1298 
1299  // Ensure the grid fills the screen
1300  --gridStartX; ++gridEndX;
1301  --gridStartY; ++gridEndY;
1302 
1303  glDisable( GL_DEPTH_TEST );
1304  glDisable( GL_TEXTURE_2D );
1305 
1306  if( gridStyle == GRID_STYLE::DOTS )
1307  {
1308  glEnable( GL_STENCIL_TEST );
1309  glStencilFunc( GL_ALWAYS, 1, 1 );
1310  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1311  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1312  SetStrokeColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
1313  }
1314  else
1315  {
1316  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1318  }
1319 
1321  {
1322 
1323  // Vertical positions
1324  for( int j = gridStartY; j <= gridEndY; j++ )
1325  {
1326  bool tickY = ( j % gridTick == 0 );
1327  const double posY = j * gridScreenSize.y + gridOrigin.y;
1328 
1329  // Horizontal positions
1330  for( int i = gridStartX; i <= gridEndX; i++ )
1331  {
1332  bool tickX = ( i % gridTick == 0 );
1333  SetLineWidth( ( ( tickX && tickY ) ? majorLineWidth : minorLineWidth ) );
1334  auto lineLen = 2.0 * GetLineWidth();
1335  auto posX = i * gridScreenSize.x + gridOrigin.x;
1336 
1337  DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) );
1338  DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) );
1339  }
1340  }
1341 
1343  }
1344  else
1345  {
1346  // Vertical lines
1347  for( int j = gridStartY; j <= gridEndY; j++ )
1348  {
1349  const double y = j * gridScreenSize.y + gridOrigin.y;
1350 
1351  // If axes are drawn, skip the lines that would cover them
1352  if( axesEnabled && y == 0.0 )
1353  continue;
1354 
1355  SetLineWidth( ( j % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1356  VECTOR2D a ( gridStartX * gridScreenSize.x + gridOrigin.x, y );
1357  VECTOR2D b ( gridEndX * gridScreenSize.x + gridOrigin.x, y );
1358 
1359  DrawLine( a, b );
1360  }
1361 
1363 
1364  if( gridStyle == GRID_STYLE::DOTS )
1365  {
1366  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1367  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1369  }
1370 
1371  // Horizontal lines
1372  for( int i = gridStartX; i <= gridEndX; i++ )
1373  {
1374  const double x = i * gridScreenSize.x + gridOrigin.x;
1375 
1376  // If axes are drawn, skip the lines that would cover them
1377  if( axesEnabled && x == 0.0 )
1378  continue;
1379 
1380  SetLineWidth( ( i % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1381  VECTOR2D a ( x, gridStartY * gridScreenSize.y + gridOrigin.y );
1382  VECTOR2D b ( x, gridEndY * gridScreenSize.y + gridOrigin.y );
1383  DrawLine( a, b );
1384  }
1385 
1387 
1388  if( gridStyle == GRID_STYLE::DOTS )
1389  glDisable( GL_STENCIL_TEST );
1390  }
1391 
1392  glEnable( GL_DEPTH_TEST );
1393  glEnable( GL_TEXTURE_2D );
1394 }
1395 
1396 
1397 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1398 {
1399  screenSize = VECTOR2I( aWidth, aHeight );
1400 
1401  // Resize framebuffers
1402  const float scaleFactor = GetBackingScaleFactor();
1403  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1404  isFramebufferInitialized = false;
1405 
1406  wxGLCanvas::SetSize( aWidth, aHeight );
1407 }
1408 
1409 
1410 bool OPENGL_GAL::Show( bool aShow )
1411 {
1412  bool s = wxGLCanvas::Show( aShow );
1413 
1414  if( aShow )
1415  wxGLCanvas::Raise();
1416 
1417  return s;
1418 }
1419 
1420 
1422 {
1423  glFlush();
1424 }
1425 
1426 
1428 {
1429  // Clear screen
1431  // NOTE: Black used here instead of m_clearColor; it will be composited later
1432  glClearColor( 0, 0, 0, 1 );
1433  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1434 }
1435 
1436 
1437 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1438 {
1439  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1440 
1441  matrixData[0] = aTransformation.m_data[0][0];
1442  matrixData[1] = aTransformation.m_data[1][0];
1443  matrixData[2] = aTransformation.m_data[2][0];
1444  matrixData[4] = aTransformation.m_data[0][1];
1445  matrixData[5] = aTransformation.m_data[1][1];
1446  matrixData[6] = aTransformation.m_data[2][1];
1447  matrixData[12] = aTransformation.m_data[0][2];
1448  matrixData[13] = aTransformation.m_data[1][2];
1449  matrixData[14] = aTransformation.m_data[2][2];
1450 
1451  glMultMatrixd( matrixData );
1452 }
1453 
1454 
1455 void OPENGL_GAL::Rotate( double aAngle )
1456 {
1457  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1458 }
1459 
1460 
1461 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1462 {
1463  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1464 }
1465 
1466 
1467 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1468 {
1469  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1470 }
1471 
1472 
1474 {
1476 }
1477 
1478 
1480 {
1482 }
1483 
1484 
1486 {
1487  isGrouping = true;
1488 
1489  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1490  int groupNumber = getNewGroupNumber();
1491  groups.insert( std::make_pair( groupNumber, newItem ) );
1492 
1493  return groupNumber;
1494 }
1495 
1496 
1498 {
1500  isGrouping = false;
1501 }
1502 
1503 
1504 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1505 {
1506  if( groups[aGroupNumber] )
1507  cachedManager->DrawItem( *groups[aGroupNumber] );
1508 }
1509 
1510 
1511 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1512 {
1513  if( groups[aGroupNumber] )
1514  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1515 }
1516 
1517 
1518 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1519 {
1520  if( groups[aGroupNumber] )
1521  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1522 }
1523 
1524 
1525 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1526 {
1527  // Frees memory in the container as well
1528  groups.erase( aGroupNumber );
1529 }
1530 
1531 
1533 {
1534  bitmapCache = std::make_unique<GL_BITMAP_CACHE>( );
1535 
1536  groups.clear();
1537 
1538  if( isInitialized )
1539  cachedManager->Clear();
1540 }
1541 
1542 
1544 {
1545  switch( aTarget )
1546  {
1547  default:
1548  case TARGET_CACHED:
1550  break;
1551 
1552  case TARGET_NONCACHED:
1554  break;
1555 
1556  case TARGET_OVERLAY:
1558  break;
1559  }
1560 
1561  currentTarget = aTarget;
1562 }
1563 
1564 
1566 {
1567  return currentTarget;
1568 }
1569 
1570 
1572 {
1573  // Save the current state
1574  unsigned int oldTarget = compositor->GetBuffer();
1575 
1576  switch( aTarget )
1577  {
1578  // Cached and noncached items are rendered to the same buffer
1579  default:
1580  case TARGET_CACHED:
1581  case TARGET_NONCACHED:
1583  break;
1584 
1585  case TARGET_OVERLAY:
1587  break;
1588  }
1589 
1590 
1591  if( aTarget != TARGET_OVERLAY )
1593  else
1595 
1596  // Restore the previous state
1597  compositor->SetBuffer( oldTarget );
1598 }
1599 
1600 
1601 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1602 {
1603  // Now we should only store the position of the mouse cursor
1604  // The real drawing routines are in blitCursor()
1605  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1606  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1607  cursorPosition = aCursorPosition;
1608 }
1609 
1610 
1611 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1612 {
1613  /* Helper drawing: ____--- v3 ^
1614  * ____---- ... \ \
1615  * ____---- ... \ end \
1616  * v1 ____---- ... ____---- \ width
1617  * ---- ...___---- \ \
1618  * \ ___...-- \ v
1619  * \ ____----... ____---- v2
1620  * ---- ... ____----
1621  * start \ ... ____----
1622  * \... ____----
1623  * ----
1624  * v0
1625  * dots mark triangles' hypotenuses
1626  */
1627 
1628  auto v1 = currentManager->GetTransformation() * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 );
1629  auto v2 = currentManager->GetTransformation() * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 );
1630 
1631  VECTOR2D vs( v2.x - v1.x, v2.y - v1.y );
1632 
1633  currentManager->Reserve( 6 );
1634 
1635  // Line width is maintained by the vertex shader
1637  currentManager->Vertex( aStartPoint, layerDepth );
1638 
1640  currentManager->Vertex( aStartPoint, layerDepth );
1641 
1643  currentManager->Vertex( aEndPoint, layerDepth );
1644 
1646  currentManager->Vertex( aEndPoint, layerDepth );
1647 
1649  currentManager->Vertex( aEndPoint, layerDepth );
1650 
1652  currentManager->Vertex( aStartPoint, layerDepth );
1653 }
1654 
1655 
1656 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1657 {
1658  if( isFillEnabled )
1659  {
1661  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1662  }
1663 
1664  if( isStrokeEnabled )
1665  {
1667  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1668  }
1669 }
1670 
1671 
1672 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1673  double aAngle )
1674 {
1675  Save();
1676 
1677  currentManager->Reserve( 3 );
1678  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1679  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1680 
1681  /* Draw a triangle that contains the semicircle, then shade it to leave only
1682  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1683  * (if you want to understand more, check the vertex shader source [shader.vert]).
1684  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1685  * v2
1686  * /\
1687  * /__\
1688  * v0 //__\\ v1
1689  */
1691  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1692 
1694  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1695 
1697  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1698 
1699  Restore();
1700 }
1701 
1702 
1703 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1704  double aAngle )
1705 {
1706  double outerRadius = aRadius + ( lineWidth / 2 );
1707 
1708  Save();
1709 
1710  currentManager->Reserve( 3 );
1711  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1712  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1713 
1714  /* Draw a triangle that contains the semicircle, then shade it to leave only
1715  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1716  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1717  * radius and the line width. Shader uses these coordinates to determine if fragments are
1718  * inside the semicircle or not.
1719  * v2
1720  * /\
1721  * /__\
1722  * v0 //__\\ v1
1723  */
1725  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1726 
1728  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1729 
1731  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1732 
1733  Restore();
1734 }
1735 
1736 
1737 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1738 {
1739  if( isFillEnabled )
1740  {
1743 
1744  // Any non convex polygon needs to be tesselated
1745  // for this purpose the GLU standard functions are used
1747  gluTessBeginPolygon( tesselator, &params );
1748  gluTessBeginContour( tesselator );
1749 
1750  GLdouble* point = aPoints;
1751 
1752  for( int i = 0; i < aPointCount; ++i )
1753  {
1754  gluTessVertex( tesselator, point, point );
1755  point += 3; // 3 coordinates
1756  }
1757 
1758  gluTessEndContour( tesselator );
1759  gluTessEndPolygon( tesselator );
1760 
1761  // Free allocated intersecting points
1762  tessIntersects.clear();
1763  }
1764 
1765  if( isStrokeEnabled )
1766  {
1767  drawPolyline( [&](int idx) { return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] ); },
1768  aPointCount );
1769  }
1770 }
1771 
1772 
1773 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D (int)>& aPointGetter, int aPointCount )
1774 {
1775  if( aPointCount < 2 )
1776  return;
1777 
1779  int i;
1780 
1781  for( i = 1; i < aPointCount; ++i )
1782  {
1783  auto start = aPointGetter( i - 1 );
1784  auto end = aPointGetter( i );
1785 
1786  drawLineQuad( start, end );
1787  }
1788 }
1789 
1790 
1791 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1792 {
1793  const float TEX_X = font_image.width;
1794  const float TEX_Y = font_image.height;
1795 
1796  // handle space
1797  if( aChar == ' ' )
1798  {
1799  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1800  wxASSERT( g );
1801 
1802  if( !g ) // Should not happen.
1803  return 0;
1804 
1805  Translate( VECTOR2D( g->advance, 0 ) );
1806  return g->advance;
1807  }
1808 
1809  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1810 
1811  // If the glyph is not found (happens for many esotheric unicode chars)
1812  // shows a '?' instead.
1813  if( !glyph )
1814  glyph = LookupGlyph( '?' );
1815 
1816  if( !glyph ) // Should not happen.
1817  return 0;
1818 
1819  const float X = glyph->atlas_x + font_information.smooth_pixels;
1820  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1821  const float XOFF = glyph->minx;
1822 
1823  // adjust for height rounding
1824  const float round_adjust = ( glyph->maxy - glyph->miny )
1825  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1826  const float top_adjust = font_information.max_y - glyph->maxy;
1827  const float YOFF = round_adjust + top_adjust;
1828  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1829  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1830  const float B = 0;
1831 
1832  currentManager->Reserve( 6 );
1833  Translate( VECTOR2D( XOFF, YOFF ) );
1834  /* Glyph:
1835  * v0 v1
1836  * +--+
1837  * | /|
1838  * |/ |
1839  * +--+
1840  * v2 v3
1841  */
1842  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1843  currentManager->Vertex( -B, -B, 0 ); // v0
1844 
1845  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1846  currentManager->Vertex( W + B, -B, 0 ); // v1
1847 
1848  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1849  currentManager->Vertex( -B, H + B, 0 ); // v2
1850 
1851 
1852  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1853  currentManager->Vertex( W + B, -B, 0 ); // v1
1854 
1855  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1856  currentManager->Vertex( -B, H + B, 0 ); // v2
1857 
1858  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1859  currentManager->Vertex( W + B, H + B, 0 ); // v3
1860 
1861  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1862 
1863  return glyph->advance;
1864 }
1865 
1866 
1867 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1868 {
1869  // To draw an overbar, simply draw an overbar
1870  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1871  wxCHECK( glyph, /* void */ );
1872 
1873  const float H = glyph->maxy - glyph->miny;
1874 
1875  Save();
1876 
1877  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1878 
1879  currentManager->Reserve( 6 );
1881 
1882  currentManager->Shader( 0 );
1883 
1884  currentManager->Vertex( 0, 0, 0 ); // v0
1885  currentManager->Vertex( aLength, 0, 0 ); // v1
1886  currentManager->Vertex( 0, H, 0 ); // v2
1887 
1888  currentManager->Vertex( aLength, 0, 0 ); // v1
1889  currentManager->Vertex( 0, H, 0 ); // v2
1890  currentManager->Vertex( aLength, H, 0 ); // v3
1891 
1892  Restore();
1893 }
1894 
1895 
1896 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
1897 {
1898  VECTOR2D textSize( 0, 0 );
1899  float commonOffset = std::numeric_limits<float>::max();
1900  static const auto defaultGlyph = LookupGlyph( '(' ); // for strange chars
1901 
1902  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
1903  {
1904  unsigned int c = *chIt;
1905 
1906  const FONT_GLYPH_TYPE* glyph = LookupGlyph( c );
1907  // Debug: show not coded char in the atlas
1908  // Be carefull before allowing the assert: it usually crash kicad
1909  // when the assert is made during a paint event.
1910  // wxASSERT_MSG( glyph, wxString::Format( "missing char in font: code 0x%x <%c>", c, c ) );
1911 
1912  if( !glyph || // Not coded in font
1913  c == '-' || c == '_' ) // Strange size of these 2 chars
1914  {
1915  glyph = defaultGlyph;
1916  }
1917 
1918  if( glyph )
1919  {
1920  textSize.x += glyph->advance;
1921  }
1922  }
1923 
1924  textSize.y = std::max<float>( textSize.y, font_information.max_y - defaultGlyph->miny );
1925  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
1926  textSize.y -= commonOffset;
1927 
1928  return std::make_pair( textSize, commonOffset );
1929 }
1930 
1931 
1932 void OPENGL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1933 {
1934  PostPaint();
1935 }
1936 
1937 
1938 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1939 {
1940  // Post the mouse event to the event listener registered in constructor, if any
1941  if( mouseListener )
1942  wxPostEvent( mouseListener, aEvent );
1943 }
1944 
1945 
1947 {
1948  if( !IsCursorEnabled() )
1949  return;
1950 
1952 
1953  const int cursorSize = fullscreenCursor ? 8000 : 80;
1954 
1955  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
1956  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
1957  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
1958 
1959  const COLOR4D cColor = getCursorColor();
1960  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
1961  cColor.b * cColor.a, 1.0 );
1962 
1963  glActiveTexture( GL_TEXTURE0 );
1964  glDisable( GL_TEXTURE_2D );
1965  glLineWidth( 1.0 );
1966  glColor4d( color.r, color.g, color.b, color.a );
1967 
1968  glBegin( GL_LINES );
1969  glVertex2d( cursorCenter.x, cursorBegin.y );
1970  glVertex2d( cursorCenter.x, cursorEnd.y );
1971 
1972  glVertex2d( cursorBegin.x, cursorCenter.y );
1973  glVertex2d( cursorEnd.x, cursorCenter.y );
1974  glEnd();
1975 }
1976 
1977 
1979 {
1980  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
1981  wxT( "There are no free slots to store a group" ) );
1982 
1983  while( groups.find( groupCounter ) != groups.end() )
1984  {
1985  groupCounter++;
1986  }
1987 
1988  return groupCounter++;
1989 }
1990 
1991 
1993 {
1994  wxASSERT( IsShownOnScreen() );
1995 
1996  wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." );
1997 
1998  GLenum err = glewInit();
1999 
2000  if( GLEW_OK != err )
2001  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
2002 
2003  // Check the OpenGL version (minimum 2.1 is required)
2004  if( !GLEW_VERSION_2_1 )
2005  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
2006 
2007 #if defined (__LINUX__) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
2008 #ifdef DEBUG
2009  if( GLEW_ARB_debug_output )
2010  enableGlDebug( true );
2011 #endif
2012 #endif
2013 
2014  // Framebuffers have to be supported
2015  if( !GLEW_EXT_framebuffer_object )
2016  throw std::runtime_error( "Framebuffer objects are not supported!" );
2017 
2018  // Vertex buffer has to be supported
2019  if( !GLEW_ARB_vertex_buffer_object )
2020  throw std::runtime_error( "Vertex buffer objects are not supported!" );
2021 
2022  // Prepare shaders
2024  throw std::runtime_error( "Cannot compile vertex shader!" );
2025 
2027  throw std::runtime_error( "Cannot compile fragment shader!" );
2028 
2029  if( !shader->IsLinked() && !shader->Link() )
2030  throw std::runtime_error( "Cannot link the shaders!" );
2031 
2032  // Check if video card supports textures big enough to fit the font atlas
2033  int maxTextureSize;
2034  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
2035 
2036  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height )
2037  {
2038  // TODO implement software texture scaling
2039  // for bitmap fonts and use a higher resolution texture?
2040  throw std::runtime_error( "Requested texture size is not supported" );
2041  }
2042 
2043  cachedManager = new VERTEX_MANAGER( true );
2044  nonCachedManager = new VERTEX_MANAGER( false );
2045  overlayManager = new VERTEX_MANAGER( false );
2046 
2047  // Make VBOs use shaders
2051 
2052  isInitialized = true;
2053 }
2054 
2055 
2056 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
2057 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
2058 {
2059  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
2060  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2061  VERTEX_MANAGER* vboManager = param->vboManager;
2062 
2063  assert( vboManager );
2064  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
2065 }
2066 
2067 
2068 void CALLBACK CombineCallback( GLdouble coords[3],
2069  GLdouble* vertex_data[4],
2070  GLfloat weight[4], GLdouble** dataOut, void* aData )
2071 {
2072  GLdouble* vertex = new GLdouble[3];
2073  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2074 
2075  // Save the pointer so we can delete it later
2076  param->intersectPoints.emplace_back( vertex );
2077 
2078  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
2079 
2080  *dataOut = vertex;
2081 }
2082 
2083 
2084 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
2085 {
2086  // This callback is needed to force GLU tesselator to use triangles only
2087 }
2088 
2089 
2090 void CALLBACK ErrorCallback( GLenum aErrorCode )
2091 {
2092  //throw std::runtime_error( std::string( "Tessellation error: " ) +
2093  //std::string( (const char*) gluErrorString( aErrorCode ) );
2094 }
2095 
2096 
2097 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
2098 {
2099  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
2100  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
2101  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
2102  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
2103 }
2104 
2105 void OPENGL_GAL::EnableDepthTest( bool aEnabled )
2106 {
2107  cachedManager->EnableDepthTest( aEnabled );
2108  nonCachedManager->EnableDepthTest( aEnabled );
2109  overlayManager->EnableDepthTest( aEnabled );
2110 }
2111 
2112 
2113 static double roundr( double f, double r )
2114 {
2115  return floor(f / r + 0.5) * r;
2116 }
2117 
2118 
2120 {
2121  auto pixelSize = worldScale;
2122 
2123  lookAtPoint.x = roundr( lookAtPoint.x, pixelSize );
2124  lookAtPoint.y = roundr( lookAtPoint.y, pixelSize );
2125 
2127 }
2128 
Definition: colors.h:57
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:82
int gridTick
Every tick line gets the double width.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
VERTEX_MANAGER * currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
Definition: opengl_gal.h:298
virtual wxSize GetNativePixelSize() const
float GetLineWidth() const
Get the line width.
virtual void beginUpdate() override
Definition: opengl_gal.cpp:582
VECTOR2D cursorPosition
Current cursor position (world coordinates)
bool IsLinked() const
Returns true if shaders are linked correctly.
Definition: shader.h:124
const glm::mat4 & GetTransformation() const
bool axesEnabled
Should the axes be drawn.
virtual void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
int OutlineCount() const
Returns the number of outlines in the set
bool LoadShaderFromStrings(SHADER_TYPE aShaderType, Args &&... aArgs)
Add a shader and compile the shader sources.
Definition: shader.h:99
virtual void DrawBuffer(unsigned int aBufferHandle) override
Function DrawBuffer() draws the selected buffer to the output buffer.
static wxGLContext * glMainContext
Parent OpenGL context.
Definition: opengl_gal.h:286
double layerDepth
The actual layer depth.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:131
void PushMatrix()
Function PushMatrix() pushes the current transformation matrix stack.
int GetAntialiasSupersamplingFactor() const
unsigned int overlayBuffer
Auxiliary rendering target (for menus etc.)
Definition: opengl_gal.h:306
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:276
virtual void Scale(const VECTOR2D &aScale) override
Scale the context.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void ClearTarget(RENDER_TARGET aTarget) override
Clears the target for rendering.
bool IsTextMirrored() const
Returns true if text should displayed mirrored.
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0) override
Draw a cubic bezier spline.
virtual void Translate(const VECTOR2D &aTranslation) override
Translate the context.
virtual void Begin() override
Function Begin() Call this at the beginning of each frame.
double msecs(bool aSinceLast=false)
Definition: profile.h:143
bool Reserve(unsigned int aSize)
Function Reserve() allocates space for vertices, so it will be used with subsequent Vertex() calls.
void BeginDrawing() const
Function BeginDrawing() prepares buffers and items to start drawing.
RENDER_TARGET currentTarget
Current rendering target.
Definition: opengl_gal.h:307
bool isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:315
void Use()
Use the shader.
Definition: shader.h:132
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draws a filled polygon.
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Converts Bezier curve to a polygon.
void DrawItem(const VERTEX_ITEM &aItem) const
Function DrawItem() draws an item to the buffer.
static GLuint fontTexture
Bitmap font texture handle (shared)
Definition: opengl_gal.h:292
GRID_STYLE gridStyle
Grid display style.
void drawLineQuad(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a quad for the line.
VERTEX_MANAGER * overlayManager
Container for storing overlaid VERTEX_ITEMs.
Definition: opengl_gal.h:301
GAL_DISPLAY_OPTIONS & options
int color
Definition: DXF_plotter.cpp:61
VECTOR2D getScreenPixelSize() const
Definition: opengl_gal.cpp:375
virtual void ComputeWorldScreenMatrix() override
Compute the world <-> screen transformation matrix.
virtual void Restore() override
Restore the context.
void CALLBACK EdgeCallback(GLboolean aEdgeFlag)
void SetParameter(int aParameterNumber, float aValue) const
Set a parameter of the shader.
Definition: shader.cpp:139
virtual void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Changes the depth (Z-axis position) of the group.
wxImage * GetImageData()
Definition: bitmap_base.h:83
std::unique_ptr< GL_BITMAP_CACHE > bitmapCache
Definition: opengl_gal.h:325
virtual void EnableDepthTest(bool aEnabled=false) override
Parameters passed to the GLU tesselator.
bool Vertex(const VERTEX &aVertex)
Function Vertex() adds a vertex with the given coordinates to the currently set item.
wxGLCanvas wrapper for HiDPI/Retina support.
uni_iter uend() const
Function uend returns a uni_iter initialized to the end of "this" UTF8 byte sequence.
Definition: utf8.h:294
virtual int BeginGroup() override
Begin a group.
static void InitTesselatorCallbacks(GLUtesselator *aTesselator)
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: opengl_gal.cpp:940
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const
double GetScaleFactor() const
Get the current scale factor.
void Rotate(GLfloat aAngle, GLfloat aX, GLfloat aY, GLfloat aZ)
Function Rotate() multiplies the current matrix by a rotation matrix, so the newly vertices will be r...
bool isContextLocked
Used for assertion checking.
Definition: opengl_gal.h:319
double g
Green component.
Definition: color4d.h:303
Fragment shader.
Definition: shader.h:47
bool Link()
Link the shaders.
Definition: shader.cpp:97
COLOR4D fillColor
The fill color.
VECTOR2D depthRange
Range of the depth.
int checkGlError(const std::string &aInfo, bool aThrow)
Checks if one of recent OpenGL operations has failed.
Definition: utils.cpp:30
MATRIX3x3D screenWorldMatrix
Screen transformation.
SHADER * shader
There is only one shader used for different objects.
Definition: opengl_gal.h:310
bool globalFlipX
Flag for X axis flipping.
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
static const unsigned int DIRECT_RENDERING
int PointCount() const
Function PointCount()
bool isGrouping
Was a group started?
Definition: opengl_gal.h:318
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:44
EDA_TEXT_HJUSTIFY_T GetHorizontalJustify() const
Returns current text horizontal justification setting.
OPENGL_ANTIALIASING_MODE gl_antialiasing_mode
void UnlockCtx(wxGLContext *aContext)
Function UnlockCtx allows other canvases to bind an OpenGL context.
void enableGlDebug(bool aEnable)
Enables/disables OpenGL driver messages output.
Definition: utils.cpp:140
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
bool IsTriangulationUpToDate() const
VECTOR2D lookAtPoint
Point to be looked at in world space.
void unlockContext(int aClientCookie) override
Definition: opengl_gal.cpp:568
void CALLBACK VertexCallback(GLvoid *aVertexPtr, void *aData)
virtual void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
VERTEX_MANAGER * nonCachedManager
Container for storing non-cached VERTEX_ITEMs.
Definition: opengl_gal.h:300
double b
Blue component.
Definition: color4d.h:304
Auxiliary rendering target (noncached)
Definition: definitions.h:49
static int instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:288
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:273
T m_data[3][3]
Definition: matrix3x3.h:64
double getWorldPixelSize() const
Definition: opengl_gal.cpp:368
void SetAntialiasingMode(OPENGL_ANTIALIASING_MODE aMode)
virtual void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle, double aWidth) override
Draw an arc segment.
Definition: opengl_gal.cpp:783
virtual RENDER_TARGET GetTarget() const override
Gets the currently used target for rendering.
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
virtual void endUpdate() override
Definition: opengl_gal.cpp:598
const VECTOR2D & GetGlyphSize() const
void FinishItem() const
Function FinishItem() does the cleaning after adding an item.
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
static const COLOR4D BLACK
Definition: color4d.h:312
uni_iter ubegin() const
Function ubegin returns a uni_iter initialized to the start of "this" UTF8 byte sequence.
Definition: utf8.h:285
const VECTOR2I & CPoint(int aIndex) const
Function Point()
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
virtual void Save() override
Save the context.
void init()
Basic OpenGL initialization.
double a
Alpha component.
Definition: color4d.h:305
void Unmap()
Function Unmap() unmaps vertex buffer.
OPENGL_COMPOSITOR * compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:304
void ChangeItemDepth(const VERTEX_ITEM &aItem, GLfloat aDepth) const
Function ChangeItemDepth() changes the depth of all vertices owned by an item.
bool fullscreenCursor
Shape of the cursor (fullscreen or small cross)
#define NULL
bool isStrokeEnabled
Are the outlines stroked ?
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
GROUPS_MAP groups
Stores informations about VBO objects (groups)
Definition: opengl_gal.h:296
virtual void Present() override
Function Present() Call this to present the output buffer to the screen.
unsigned int mainBuffer
Main rendering target.
Definition: opengl_gal.h:305
virtual bool Show(bool aShow) override
Shows/hides the GAL canvas.
virtual void ClearBuffer(const COLOR4D &aColor) override
Function ClearBuffer() clears the selected buffer (set by the SetBuffer() function).
SHAPE_POLY_SET.
virtual void EndGroup() override
End the group.
COLOR4D axesColor
Color of the axes.
virtual void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
double calcAngleStep(double aRadius) const
Compute the angle step when drawing arcs/circles approximated with lines.
Definition: opengl_gal.h:471
wxEvtHandler * mouseListener
Definition: opengl_gal.h:289
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Function updatedGalDisplayOptions.
Definition: opengl_gal.cpp:341
virtual void DrawGrid() override
COLOR4D strokeColor
The color of the outlines.
float gridLineWidth
Line width of the grid.
void SetShader(SHADER &aShader) const
Function SetShader() sets a shader program that is going to be used during rendering.
void Translate(GLfloat aX, GLfloat aY, GLfloat aZ)
Function Translate() multiplies the current matrix by a translation matrix, so newly vertices will be...
static const int glAttributes[]
Definition: opengl_gal.cpp:74
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: opengl_gal.cpp:607
double worldUnitLength
The unit length of the world coordinates [inch].
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
void Map()
Function Map() maps vertex buffer.
void onPaint(wxPaintEvent &aEvent)
This is the OnPaint event handler.
int AddParameter(const std::string &aParameterName)
Add a parameter to the parameter queue.
Definition: shader.cpp:126
GLint ufm_screenPixelSize
Definition: opengl_gal.h:322
virtual void endDrawing() override
Definition: opengl_gal.cpp:523
virtual void DrawGroup(int aGroupNumber) override
Draw the stored group.
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:141
bool isFramebufferInitialized
Are the framebuffers initialized?
Definition: opengl_gal.h:313
virtual void Resize(unsigned int aWidth, unsigned int aHeight) override
Function Resize() clears the state of COMPOSITOR, so it has to be reinitialized again with the new di...
VECTOR2D gridOrigin
The grid origin.
virtual void ClearCache() override
Delete all data created during caching of graphic items.
FONT_IMAGE_TYPE font_image
Definition: gl_resources.cpp:4
unsigned char pixels[1024 *1024 *3]
Definition: gl_resources.h:38
void drawTriangulatedPolyset(const SHAPE_POLY_SET &aPoly)
Draws a set of polygons with a cached triangulation.
Definition: opengl_gal.cpp:974
FONT_INFO_TYPE font_information
Definition: gl_resources.cpp:3
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:313
MATRIX3x3D worldScreenMatrix
World transformation.
Vertex shader.
Definition: shader.h:46
virtual void SetBuffer(unsigned int aBufferHandle) override
Function SetBuffer() sets the selected buffer as the rendering target.
Class SHADER provides the access to the OpenGL shaders.
Definition: shader.h:76
void lockContext(int aClientCookie) override
Private: use GAL_CONTEXT_LOCKER RAII object.
Definition: opengl_gal.cpp:558
int SegmentCount() const
Function SegmentCount()
void Color(const COLOR4D &aColor)
Function Color() changes currently used color that will be applied to newly added vertices.
GLUtesselator * tesselator
The tessellator.
Definition: opengl_gal.h:348
Use dots for the grid.
Use small cross instead of dots for the grid.
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
std::map< const BITMAP_BASE *, CACHED_BITMAP > m_bitmaps
Definition: opengl_gal.cpp:103
virtual void Rotate(double aAngle) override
Rotate the context.
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Function updatedGalDisplayOptions.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Function LockCtx sets a context as current and prevents other canvases from switching it.
void drawStrokedSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a stroked semicircle.
#define H(x, y, z)
Definition: md5_hash.cpp:17
void PopMatrix()
Function PopMatrix() pops the current transformation matrix stack.
float lineWidth
The line width.
bool isFillEnabled
Is filling of graphic objects enabled ?
void blitCursor()
Blits cursor into the current screen.
VERTEX_MANAGER * cachedManager
Container for storing cached VERTEX_ITEMs.
Definition: opengl_gal.h:299
uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded string...
Definition: utf8.h:207
virtual void Initialize() override
Function Reset() performs primary initialiation, necessary to use the object.
void EndDrawing() const
Function EndDrawing() finishes drawing operations.
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
Definition: opengl_gal.cpp:917
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:615
GLint ufm_worldPixelSize
Definition: opengl_gal.h:321
std::deque< boost::shared_array< GLdouble > > tessIntersects
Storage for intersecting points.
Definition: opengl_gal.h:350
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: opengl_gal.cpp:717
void CALLBACK ErrorCallback(GLenum aErrorCode)
virtual void SetTarget(RENDER_TARGET aTarget) override
Sets the target for rendering.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
bool isInitialized
Basic initialization flag, has to be done when the window is visible.
Definition: opengl_gal.h:316
COLOR4D gridColor
Color of the grid.
const int scale
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.h:248
bool gridVisibility
Should the grid be shown.
void drawSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a semicircle.
Main rendering target (cached)
Definition: definitions.h:48
void EnableDepthTest(bool aEnabled)
Function EnableDepthTest() Enables/disables Z buffer depth test.
virtual float GetBackingScaleFactor() const
bool globalFlipY
Flag for Y axis flipping.
double m_scaleFactor
The pixel scale factor (>1 for hi-DPI scaled displays)
EDA_TEXT_VJUSTIFY_T GetVerticalJustify() const
Returns current text vertical justification setting.
SHAPE_LINE_CHAIN.
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: opengl_gal.h:297
double worldScale
The scale factor world->screen.
int drawBitmapChar(unsigned long aChar)
Draws a single character using bitmap font.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
VECTOR2D gridSize
The grid size.
unsigned int TriangulatedPolyCount() const
Returns the number of triangulated polygons
void Scale(GLfloat aX, GLfloat aY, GLfloat aZ)
Function Scale() multiplies the current matrix by a scaling matrix, so the newly vertices will be sca...
wxSize GetSizePixels() const
Function GetSizePixels.
Definition: bitmap_base.h:141
virtual void ClearScreen() override
Clear the screen.
VECTOR2I screenSize
Screen size in screen coordinates.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:61
#define SWAP(varA, condition, varB)
Swap the variables if a condition is met.
Definition: definitions.h:31
unsigned int getNewGroupNumber()
Returns a valid key that can be used as a new group number.
void SetScaleFactor(double aFactor)
Set the canvas scale factor, probably for a hi-DPI display.
wxGLContext * glPrivContext
Canvas-specific OpenGL context.
Definition: opengl_gal.h:287
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:879
virtual void Flush() override
Force all remaining objects to be drawn.
virtual unsigned int GetBuffer() const override
Function GetBuffer() returns currently used buffer handle.
virtual void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
virtual unsigned int CreateBuffer() override
Function CreateBuffer() prepares a new buffer that may be used as a rendering target.
void drawPolyline(const std::function< VECTOR2D(int)> &aPointGetter, int aPointCount)
Generic way of drawing a polyline stored in different containers.
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
void CALLBACK CombineCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut, void *aData)
void Shader(GLfloat aShaderType, GLfloat aParam1=0.0f, GLfloat aParam2=0.0f, GLfloat aParam3=0.0f)
Function Shader() changes currently used shader and its parameters that will be applied to newly adde...
bool IsClosed() const
Function IsClosed()
double r
Red component.
Definition: color4d.h:302
POLYGON & Polygon(int aIndex)
Returns the aIndex-th subpolygon in the set
void ChangeItemColor(const VERTEX_ITEM &aItem, const COLOR4D &aColor) const
Function ChangeItemColor() changes the color of all vertices owned by an item.
std::pair< VECTOR2D, float > computeBitmapTextSize(const UTF8 &aText) const
Computes a size of text drawn using bitmap font with current text setting applied.
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:46
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=NULL)
Function CreateCtx creates a managed OpenGL context.
virtual void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle) override
Draws a text using a bitmap font.
static double roundr(double f, double r)
#define CALLBACK
Definition: opengl_gal.h:48
virtual ~OPENGL_GAL()
Definition: opengl_gal.cpp:296
bool IsVisible() const override
Definition: opengl_gal.h:99
bool IsCursorEnabled() const
Returns information about cursor visibility.
virtual void beginDrawing() override
Definition: opengl_gal.cpp:382
GLint ufm_pixelSizeMultiplier
Definition: opengl_gal.h:323
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
void Clear() const
Function Clear() removes all the stored vertices from the container.
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: opengl_gal.cpp:661
static bool isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:314
void skipMouseEvent(wxMouseEvent &aEvent)
Skip the mouse event to the parent.
void drawFilledSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a filled semicircle.
int GetPPI() const
Definition: bitmap_base.h:153
virtual void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Changes the color used to draw the group.
Class GAL is the abstract interface for drawing on a 2D-surface.
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40
void drawBitmapOverbar(double aLength, double aHeight)
Draws an overbar over the currently drawn text.