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 #include <gal/opengl/opengl_gal.h>
30 #include <gal/opengl/utils.h>
31 #include <gal/definitions.h>
32 #include <gl_context_mgr.h>
34 #include <text_utils.h>
35 #include <bitmap_base.h>
36 
37 #include <macros.h>
38 
39 #ifdef __WXDEBUG__
40 #include <profile.h>
41 #include <wx/log.h>
42 #endif /* __WXDEBUG__ */
43 
44 #include <limits>
45 #include <functional>
46 using namespace std::placeholders;
47 using namespace KIGFX;
48 
49 // A ugly workaround to avoid serious issues (crashes) when using bitmaps cache
50 // to speedup redraw.
51 // issues arise when using bitmaps in page layout, when the page layout containd bitmaps,
52 // and is common to schematic and board editor,
53 // and the schematic is a hierarchy and when using cross-probing
54 // When the cross probing from pcbnew to eeschema switches to a sheet, the bitmaps cache
55 // becomes broken (in fact the associated texture).
56 // I hope (JPC) it will be fixed later, but a slighty slower refresh is better than a crash
57 #define DISABLE_BITMAP_CACHE
58 
59 // The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0
60 // (see ubuntu-font-licence-1.0.txt for details)
61 #include "gl_resources.h"
62 #include "gl_builtin_shaders.h"
63 using namespace KIGFX::BUILTIN_FONT;
64 
65 static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
66 static const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 8, 0 };
67 
68 wxGLContext* OPENGL_GAL::glMainContext = NULL;
69 int OPENGL_GAL::instanceCounter = 0;
70 GLuint OPENGL_GAL::fontTexture = 0;
71 bool OPENGL_GAL::isBitmapFontLoaded = false;
72 
73 namespace KIGFX {
75 {
76 public:
78  {
79  }
80 
81  ~GL_BITMAP_CACHE();
82 
83  GLuint RequestBitmap( const BITMAP_BASE* aBitmap );
84 
85 private:
86 
88  {
89  GLuint id;
90  int w, h;
91  };
92 
93  GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
94 
95  std::map<const BITMAP_BASE*, CACHED_BITMAP> m_bitmaps;
96 };
97 
98 };
99 
100 
101 GL_BITMAP_CACHE::~GL_BITMAP_CACHE()
102 {
103  for ( auto b = m_bitmaps.begin(); b != m_bitmaps.end(); ++b )
104  glDeleteTextures( 1, &b->second.id );
105 }
106 
107 
108 GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
109 {
110  auto it = m_bitmaps.find( aBitmap) ;
111 
112  if ( it != m_bitmaps.end() )
113  {
114  // A bitmap is found in cache bitmap.
115  // Ensure the associated texture is still valid (can be destroyed somewhere)
116  if( glIsTexture( it->second.id ) )
117  return it->second.id;
118 
119  // else if not valid, it will be recreated.
120  }
121 
122  return cacheBitmap( aBitmap );
123 }
124 
125 
126 GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
127 {
128  CACHED_BITMAP bmp;
129 
130  bmp.w = aBitmap->GetSizePixels().x;
131  bmp.h = aBitmap->GetSizePixels().y;
132 
133  // The bitmap size needs to be a multiple of 4.
134  // This is easiest to achieve by ensuring that each row
135  // has a multiple of 4 pixels
136  int extra_w = bmp.w % 4;
137 
138  if( extra_w )
139  extra_w = 4 - extra_w;
140 
141  GLuint textureID;
142  glGenTextures(1, &textureID);
143 
144  // make_unique initializes this to 0, so extra pixels are transparent
145  auto buf = std::make_unique<uint8_t[]>( ( bmp.w + extra_w ) * bmp.h * 4 );
146  const wxImage& imgData = *aBitmap->GetImageData();
147 
148  for( int y = 0; y < bmp.h; y++ )
149  {
150  for( int x = 0; x < bmp.w; x++ )
151  {
152  uint8_t *p = buf.get() + ( ( bmp.w + extra_w ) * y + x ) * 4;
153 
154  p[0] = imgData.GetRed( x, y );
155  p[1] = imgData.GetGreen( x, y );
156  p[2] = imgData.GetBlue( x, y );
157 
158  if( imgData.HasAlpha() )
159  p[3] = imgData.GetAlpha( x, y );
160  else if( imgData.HasMask() && p[0] == imgData.GetMaskRed() &&
161  p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
162  p[3] = wxALPHA_TRANSPARENT;
163  else
164  p[3] = wxALPHA_OPAQUE;
165  }
166  }
167 
168  glBindTexture( GL_TEXTURE_2D, textureID );
169  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w + extra_w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf.get() );
170 
171  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
172  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
173 
174  bmp.id = textureID;
175 
176 #ifndef DISABLE_BITMAP_CACHE
177  m_bitmaps[ aBitmap ] = bmp;
178 #endif
179 
180  return textureID;
181 }
182 
183 OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
184  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
185  const wxString& aName ) :
186  GAL( aDisplayOptions ),
187  HIDPI_GL_CANVAS( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
188  wxEXPAND, aName ),
189  mouseListener( aMouseListener ),
190  paintListener( aPaintListener ),
191  currentManager( nullptr ),
192  cachedManager( nullptr ),
193  nonCachedManager( nullptr ),
194  overlayManager( nullptr ),
195  mainBuffer( 0 ),
196  overlayBuffer( 0 ),
197  isContextLocked( false ),
198  lockClientCookie( 0 )
199 {
200 // IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4
201 // starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER)
202 #if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 )
203  const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 };
204 
205  if( !IsDisplaySupported( attr ) )
206  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
207 #endif /* wxCHECK_VERSION( 3, 0, 3 ) */
208 
209  if( glMainContext == NULL )
210  {
212 
213  if( !glMainContext )
214  throw std::runtime_error( "Could not create the main OpenGL context" );
215 
217  }
218  else
219  {
221 
222  if( !glPrivContext )
223  throw std::runtime_error( "Could not create a private OpenGL context" );
224  }
225 
226  shader = new SHADER();
227  ++instanceCounter;
228 
229  bitmapCache.reset( new GL_BITMAP_CACHE );
230 
233 
234  // Initialize the flags
235  isFramebufferInitialized = false;
236  isBitmapFontInitialized = false;
237  isInitialized = false;
238  isGrouping = false;
239  groupCounter = 0;
240 
241  // Connecting the event handlers
242  Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) );
243 
244  // Mouse events are skipped to the parent
245  Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
246  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
247  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
248  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
249  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
250  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
251  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
252  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
253  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
254  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
255  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
256 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
257  Connect( wxEVT_MAGNIFY, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
258 #endif
259 #if defined _WIN32 || defined _WIN64
260  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
261 #endif
262 
263  SetSize( aParent->GetClientSize() );
265 
266  // Grid color settings are different in Cairo and OpenGL
267  SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) );
268  SetAxesColor( COLOR4D( BLUE ) );
269 
270  // Tesselator initialization
271  tesselator = gluNewTess();
273 
274  if( tesselator == NULL )
275  throw std::runtime_error( "Could not create the tesselator" );
276 
277  gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
278 
280 }
281 
282 
284 {
286 
287  --instanceCounter;
288  glFlush();
289  gluDeleteTess( tesselator );
290  ClearCache();
291 
292  delete compositor;
293 
294  if( isInitialized )
295  {
296  delete cachedManager;
297  delete nonCachedManager;
298  delete overlayManager;
299  }
300 
302 
303  // If it was the main context, then it will be deleted
304  // when the last OpenGL GAL instance is destroyed (a few lines below)
307 
308  delete shader;
309 
310  // Are we destroying the last GAL instance?
311  if( instanceCounter == 0 )
312  {
314 
315  if( isBitmapFontLoaded )
316  {
317  glDeleteTextures( 1, &fontTexture );
318  isBitmapFontLoaded = false;
319  }
320 
323  glMainContext = NULL;
324  }
325 }
326 
327 
329 {
330  bool refresh = false;
331 
333  {
335  isFramebufferInitialized = false;
336  refresh = true;
337  }
338 
340  {
342  refresh = true;
343  }
344 
345  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
346  {
347  Refresh();
348  refresh = true;
349  }
350 
351  return refresh;
352 }
353 
354 
356 {
357  auto matrix = GetScreenWorldMatrix();
358  return std::min( std::abs( matrix.GetScale().x ), std::abs( matrix.GetScale().y ) );
359 }
360 
361 
363 {
364  auto sf = GetBackingScaleFactor();
365  return VECTOR2D( 2.0 / (double) ( screenSize.x * sf ), 2.0 / (double) ( screenSize.y * sf ) );
366 }
367 
368 
370 {
371 #ifdef __WXDEBUG__
372  PROF_COUNTER totalRealTime( "OPENGL_GAL::beginDrawing()", true );
373 #endif /* __WXDEBUG__ */
374 
375  wxASSERT_MSG( isContextLocked, "GAL_DRAWING_CONTEXT RAII object should have locked context. "
376  "Calling GAL::beginDrawing() directly is not allowed." );
377 
378  wxASSERT_MSG( IsVisible(), "GAL::beginDrawing() must not be entered when GAL is not visible. "
379  "Other drawing routines will expect everything to be initialized "
380  "which will not be the case." );
381 
382  if( !isInitialized )
383  init();
384 
385  // Set up the view port
386  glMatrixMode( GL_PROJECTION );
387  glLoadIdentity();
388 
389  // Create the screen transformation (Do the RH-LH conversion here)
390  glOrtho( 0, (GLint) screenSize.x, (GLsizei) screenSize.y, 0, -depthRange.x, -depthRange.y );
391 
393  {
394  // Prepare rendering target buffers
398 
400  }
401 
402  compositor->Begin();
403 
404  // Disable 2D Textures
405  glDisable( GL_TEXTURE_2D );
406 
407  glShadeModel( GL_FLAT );
408 
409  // Enable the depth buffer
410  glEnable( GL_DEPTH_TEST );
411  glDepthFunc( GL_LESS );
412 
413  // Setup blending, required for transparent objects
414  glEnable( GL_BLEND );
415  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
416 
417  glMatrixMode( GL_MODELVIEW );
418 
419  // Set up the world <-> screen transformation
421  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
422  matrixData[0] = worldScreenMatrix.m_data[0][0];
423  matrixData[1] = worldScreenMatrix.m_data[1][0];
424  matrixData[2] = worldScreenMatrix.m_data[2][0];
425  matrixData[4] = worldScreenMatrix.m_data[0][1];
426  matrixData[5] = worldScreenMatrix.m_data[1][1];
427  matrixData[6] = worldScreenMatrix.m_data[2][1];
428  matrixData[12] = worldScreenMatrix.m_data[0][2];
429  matrixData[13] = worldScreenMatrix.m_data[1][2];
430  matrixData[14] = worldScreenMatrix.m_data[2][2];
431  glLoadMatrixd( matrixData );
432 
433  // Set defaults
436 
437  // Remove all previously stored items
440 
444 
446  {
447  // Keep bitmap font texture always bound to the second texturing unit
448  const GLint FONT_TEXTURE_UNIT = 2;
449 
450  // Either load the font atlas to video memory, or simply bind it to a texture unit
451  if( !isBitmapFontLoaded )
452  {
453  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
454  glGenTextures( 1, &fontTexture );
455  glBindTexture( GL_TEXTURE_2D, fontTexture );
456  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height,
457  0, GL_RGB, GL_UNSIGNED_BYTE, font_image.pixels );
458  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
459  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
460  checkGlError( "loading bitmap font" );
461 
462  glActiveTexture( GL_TEXTURE0 );
463 
464  isBitmapFontLoaded = true;
465  }
466  else
467  {
468  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
469  glBindTexture( GL_TEXTURE_2D, fontTexture );
470  glActiveTexture( GL_TEXTURE0 );
471  }
472 
473  // Set shader parameter
474  GLint ufm_fontTexture = shader->AddParameter( "fontTexture" );
475  GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" );
476  ufm_worldPixelSize = shader->AddParameter( "worldPixelSize" );
477  ufm_screenPixelSize = shader->AddParameter( "screenPixelSize" );
478  ufm_pixelSizeMultiplier = shader->AddParameter( "pixelSizeMultiplier" );
479 
480  shader->Use();
481  shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
482  shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
483  shader->Deactivate();
484  checkGlError( "setting bitmap font sampler as shader parameter" );
485 
487  }
488 
489  shader->Use();
492  double pixelSizeMultiplier = compositor->GetAntialiasSupersamplingFactor();
493  shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
494  shader->Deactivate();
495 
496  // Something betreen BeginDrawing and EndDrawing seems to depend on
497  // this texture unit being active, but it does not assure it itself.
498  glActiveTexture( GL_TEXTURE0 );
499 
500  // Unbind buffers - set compositor for direct drawing
502 
503 #ifdef __WXDEBUG__
504  totalRealTime.Stop();
505  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::beginDrawing(): %.1f ms" ), totalRealTime.msecs() );
506 #endif /* __WXDEBUG__ */
507 }
508 
509 
511 {
512  wxASSERT_MSG( isContextLocked, "What happened to the context lock?" );
513 
514 #ifdef __WXDEBUG__
515  PROF_COUNTER totalRealTime( "OPENGL_GAL::endDrawing()", true );
516 #endif /* __WXDEBUG__ */
517 
518  // Cached & non-cached containers are rendered to the same buffer
522 
523  // Overlay container is rendered to a different buffer
526 
527  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
528  glColor4d( 1.0, 1.0, 1.0, 1.0 );
529 
530  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
533  compositor->Present();
534  blitCursor();
535 
536  SwapBuffers();
537 
538 #ifdef __WXDEBUG__
539  totalRealTime.Stop();
540  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::endDrawing(): %.1f ms" ), totalRealTime.msecs() );
541 #endif /* __WXDEBUG__ */
542 }
543 
544 
545 void OPENGL_GAL::lockContext( int aClientCookie )
546 {
547  wxASSERT_MSG( !isContextLocked, "Context already locked." );
548  isContextLocked = true;
549  lockClientCookie = aClientCookie;
550 
552 }
553 
554 
555 void OPENGL_GAL::unlockContext( int aClientCookie )
556 {
557  wxASSERT_MSG( isContextLocked, "Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
558  "be stacked rather than making separate lock/unlock calls." );
559 
560  wxASSERT_MSG( lockClientCookie == aClientCookie, "Context was locked by a different client. "
561  "Should not be possible with RAII objects." );
562 
563  isContextLocked = false;
564 
566 }
567 
568 
570 {
571  wxASSERT_MSG( isContextLocked, "GAL_UPDATE_CONTEXT RAII object should have locked context. "
572  "Calling this from anywhere else is not allowed." );
573 
574  wxASSERT_MSG( IsVisible(), "GAL::beginUpdate() must not be entered when GAL is not visible. "
575  "Other update routines will expect everything to be initialized "
576  "which will not be the case." );
577 
578  if( !isInitialized )
579  init();
580 
581  cachedManager->Map();
582 }
583 
584 
586 {
587  if( !isInitialized )
588  return;
589 
590  cachedManager->Unmap();
591 }
592 
593 
594 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
595 {
597 
598  drawLineQuad( aStartPoint, aEndPoint );
599 }
600 
601 
602 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
603  double aWidth )
604 {
605  if( aStartPoint == aEndPoint ) // 0 length segments are just a circle.
606  {
607  DrawCircle( aStartPoint, aWidth/2 );
608  return;
609  }
610 
611  if( isFillEnabled || aWidth == 1.0 )
612  {
614 
615  SetLineWidth( aWidth );
616  drawLineQuad( aStartPoint, aEndPoint );
617  }
618  else
619  {
620  auto startEndVector = aEndPoint - aStartPoint;
621  auto lineAngle = startEndVector.Angle();
622  // Outlined tracks
623  double lineLength = startEndVector.EuclideanNorm();
624 
625  SetLineWidth( 1.0 );
627 
628  Save();
629 
630  currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
631  currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
632 
633  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
634  VECTOR2D( lineLength, aWidth / 2.0 ) );
635 
636  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ),
637  VECTOR2D( lineLength, -aWidth / 2.0 ) );
638 
639  // Draw line caps
640  drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
641  drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );
642 
643  Restore();
644  }
645 }
646 
647 
648 void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
649 {
650  if( isFillEnabled )
651  {
652  currentManager->Reserve( 3 );
654 
655  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
656  * Parameters given to Shader() are indices of the triangle's vertices
657  * (if you want to understand more, check the vertex shader source [shader.vert]).
658  * Shader uses this coordinates to determine if fragments are inside the circle or not.
659  * Does the calculations in the vertex shader now (pixel alignment)
660  * v2
661  * /\
662  * //\\
663  * v0 /_\/_\ v1
664  */
665  currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0, aRadius );
666  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
667 
668  currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0, aRadius );
669  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
670 
671  currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0, aRadius );
672  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
673  }
674  if( isStrokeEnabled )
675  {
676  currentManager->Reserve( 3 );
678 
679  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
680  * Parameters given to Shader() are indices of the triangle's vertices
681  * (if you want to understand more, check the vertex shader source [shader.vert]).
682  * and the line width. Shader uses this coordinates to determine if fragments are
683  * inside the circle or not.
684  * v2
685  * /\
686  * //\\
687  * v0 /_\/_\ v1
688  */
690  currentManager->Vertex( aCenterPoint.x, // v0
691  aCenterPoint.y, layerDepth );
692 
694  currentManager->Vertex( aCenterPoint.x, // v1
695  aCenterPoint.y, layerDepth );
696 
698  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, // v2
699  layerDepth );
700  }
701 }
702 
703 
704 void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
705  double aEndAngle )
706 {
707  if( aRadius <= 0 )
708  return;
709 
710  // Swap the angles, if start angle is greater than end angle
711  SWAP( aStartAngle, >, aEndAngle );
712 
713  const double alphaIncrement = calcAngleStep( aRadius );
714 
715  Save();
716  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
717 
718  if( isFillEnabled )
719  {
720  double alpha;
723 
724  // Triangle fan
725  for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
726  {
727  currentManager->Reserve( 3 );
728  currentManager->Vertex( 0.0, 0.0, layerDepth );
729  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
730  alpha += alphaIncrement;
731  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
732  }
733 
734  // The last missing triangle
735  const VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
736 
737  currentManager->Reserve( 3 );
738  currentManager->Vertex( 0.0, 0.0, layerDepth );
739  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
740  currentManager->Vertex( endPoint.x, endPoint.y, layerDepth );
741  }
742 
743  if( isStrokeEnabled )
744  {
746 
747  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
748  double alpha;
749 
750  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
751  {
752  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
753  DrawLine( p, p_next );
754 
755  p = p_next;
756  }
757 
758  // Draw the last missing part
759  if( alpha != aEndAngle )
760  {
761  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
762  DrawLine( p, p_last );
763  }
764  }
765 
766  Restore();
767 }
768 
769 
770 void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
771  double aEndAngle, double aWidth )
772 {
773  if( aRadius <= 0 )
774  {
775  // Arcs of zero radius are a circle of aWidth diameter
776  if( aWidth > 0 )
777  DrawCircle( aCenterPoint, aWidth / 2.0 );
778 
779  return;
780  }
781 
782  // Swap the angles, if start angle is greater than end angle
783  SWAP( aStartAngle, >, aEndAngle );
784 
785  const double alphaIncrement = calcAngleStep( aRadius );
786 
787  Save();
788  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
789 
790  if( isStrokeEnabled )
791  {
793 
794  double width = aWidth / 2.0;
795  VECTOR2D startPoint( cos( aStartAngle ) * aRadius,
796  sin( aStartAngle ) * aRadius );
797  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
798  sin( aEndAngle ) * aRadius );
799 
800  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
801  drawStrokedSemiCircle( endPoint, width, aEndAngle );
802 
803  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
804  sin( aStartAngle ) * ( aRadius + width ) );
805 
806  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
807  sin( aStartAngle ) * ( aRadius - width ) );
808 
809  double alpha;
810 
811  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
812  {
813  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
814  sin( alpha ) * ( aRadius + width ) );
815  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
816  sin( alpha ) * ( aRadius - width ) );
817 
818  DrawLine( pOuter, pNextOuter );
819  DrawLine( pInner, pNextInner );
820 
821  pOuter = pNextOuter;
822  pInner = pNextInner;
823  }
824 
825  // Draw the last missing part
826  if( alpha != aEndAngle )
827  {
828  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
829  sin( aEndAngle ) * ( aRadius + width ) );
830  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
831  sin( aEndAngle ) * ( aRadius - width ) );
832 
833  DrawLine( pOuter, pLastOuter );
834  DrawLine( pInner, pLastInner );
835  }
836  }
837 
838  if( isFillEnabled )
839  {
841  SetLineWidth( aWidth );
842 
843  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
844  double alpha;
845 
846  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
847  {
848  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
849  DrawLine( p, p_next );
850 
851  p = p_next;
852  }
853 
854  // Draw the last missing part
855  if( alpha != aEndAngle )
856  {
857  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
858  DrawLine( p, p_last );
859  }
860  }
861 
862  Restore();
863 }
864 
865 
866 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
867 {
868  // Compute the diagonal points of the rectangle
869  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
870  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
871 
872  // Fill the rectangle
873  if( isFillEnabled )
874  {
875  currentManager->Reserve( 6 );
878 
879  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
880  currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
881  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
882 
883  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
884  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
885  currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
886  }
887 
888  // Stroke the outline
889  if( isStrokeEnabled )
890  {
892 
893  std::deque<VECTOR2D> pointList;
894  pointList.push_back( aStartPoint );
895  pointList.push_back( diagonalPointA );
896  pointList.push_back( aEndPoint );
897  pointList.push_back( diagonalPointB );
898  pointList.push_back( aStartPoint );
899  DrawPolyline( pointList );
900  }
901 }
902 
903 
904 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
905 {
906  drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
907 }
908 
909 
910 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
911 {
912  drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
913 }
914 
915 
917 {
918  auto numPoints = aLineChain.PointCount();
919 
920  if( aLineChain.IsClosed() )
921  numPoints += 1;
922 
923  drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, numPoints );
924 }
925 
926 
927 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
928 {
929  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
930  GLdouble* ptr = points.get();
931 
932  for( const VECTOR2D& p : aPointList )
933  {
934  *ptr++ = p.x;
935  *ptr++ = p.y;
936  *ptr++ = layerDepth;
937  }
938 
939  drawPolygon( points.get(), aPointList.size() );
940 }
941 
942 
943 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
944 {
945  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
946  GLdouble* target = points.get();
947  const VECTOR2D* src = aPointList;
948 
949  for( int i = 0; i < aListSize; ++i )
950  {
951  *target++ = src->x;
952  *target++ = src->y;
953  *target++ = layerDepth;
954  ++src;
955  }
956 
957  drawPolygon( points.get(), aListSize );
958 }
959 
960 
962 {
965 
966  if( isFillEnabled )
967  {
968  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
969  {
970  auto triPoly = aPolySet.TriangulatedPolygon( j );
971 
972  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
973  {
974  VECTOR2I a, b, c;
975  triPoly->GetTriangle( i, a, b, c );
976  currentManager->Vertex( a.x, a.y, layerDepth );
977  currentManager->Vertex( b.x, b.y, layerDepth );
978  currentManager->Vertex( c.x, c.y, layerDepth );
979  }
980  }
981  }
982 
983  if( isStrokeEnabled )
984  {
985  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
986  {
987  const auto& poly = aPolySet.Polygon( j );
988 
989  for( const auto& lc : poly )
990  {
991  DrawPolyline( lc );
992  }
993  }
994  }
995 }
996 
997 
999 {
1000  if ( aPolySet.IsTriangulationUpToDate() )
1001  {
1002  drawTriangulatedPolyset( aPolySet );
1003  return;
1004  }
1005 
1006  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1007  {
1008  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
1009  DrawPolygon( outline );
1010  }
1011 }
1012 
1013 
1014 
1016 {
1017  if( aPolygon.SegmentCount() == 0 )
1018  return;
1019 
1020  const int pointCount = aPolygon.SegmentCount() + 1;
1021  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
1022  GLdouble* ptr = points.get();
1023 
1024  for( int i = 0; i < pointCount; ++i )
1025  {
1026  const VECTOR2I& p = aPolygon.CPoint( i );
1027  *ptr++ = p.x;
1028  *ptr++ = p.y;
1029  *ptr++ = layerDepth;
1030  }
1031 
1032  drawPolygon( points.get(), pointCount );
1033 }
1034 
1035 
1036 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
1037  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
1038 {
1039  // FIXME The drawing quality needs to be improved
1040  // FIXME Perhaps choose a quad/triangle strip instead?
1041  // FIXME Brute force method, use a better (recursive?) algorithm
1042 
1043  std::deque<VECTOR2D> pointList;
1044 
1045  double t = 0.0;
1046  double dt = 1.0 / (double) CURVE_POINTS;
1047 
1048  for( int i = 0; i <= CURVE_POINTS; i++ )
1049  {
1050  double omt = 1.0 - t;
1051  double omt2 = omt * omt;
1052  double omt3 = omt * omt2;
1053  double t2 = t * t;
1054  double t3 = t * t2;
1055 
1056  VECTOR2D vertex = omt3 * aStartPoint + 3.0 * t * omt2 * aControlPointA
1057  + 3.0 * t2 * omt * aControlPointB + t3 * aEndPoint;
1058 
1059  pointList.push_back( vertex );
1060 
1061  t += dt;
1062  }
1063 
1064  DrawPolyline( pointList );
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  auto processedText = ProcessOverbars( aText );
1129  const auto& text = processedText.first;
1130  const auto& overbars = processedText.second;
1131 
1132  // Compute text size, so it can be properly justified
1133  VECTOR2D textSize;
1134  float commonOffset;
1135  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
1136 
1137  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
1138  bool overbar = false;
1139 
1140  int overbarLength = 0;
1141  double overbarHeight = textSize.y;
1142 
1143  Save();
1144 
1146  currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
1147  currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
1148 
1149  double sx = SCALE * ( globalFlipX ? -1.0 : 1.0 );
1150  double sy = SCALE * ( globalFlipY ? -1.0 : 1.0 );
1151 
1152  currentManager->Scale( sx, sy, 0 );
1153  currentManager->Translate( 0, -commonOffset, 0 );
1154 
1155  switch( GetHorizontalJustify() )
1156  {
1158  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
1159  break;
1160 
1162  //if( !IsTextMirrored() )
1163  Translate( VECTOR2D( -textSize.x, 0 ) );
1164  break;
1165 
1166  case GR_TEXT_HJUSTIFY_LEFT:
1167  //if( IsTextMirrored() )
1168  //Translate( VECTOR2D( -textSize.x, 0 ) );
1169  break;
1170  }
1171 
1172  switch( GetVerticalJustify() )
1173  {
1174  case GR_TEXT_VJUSTIFY_TOP:
1175  Translate( VECTOR2D( 0, -textSize.y ) );
1176  overbarHeight = -textSize.y / 2.0;
1177  break;
1178 
1180  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
1181  overbarHeight = 0;
1182  break;
1183 
1185  break;
1186  }
1187 
1188  int i = 0;
1189 
1190  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
1191  {
1192  unsigned int c = *chIt;
1193  wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
1194 
1195  // Handle overbar
1196  if( overbars[i] && !overbar )
1197  {
1198  overbar = true; // beginning of an overbar
1199  }
1200  else if( overbar && !overbars[i] )
1201  {
1202  overbar = false; // end of an overbar
1203  drawBitmapOverbar( overbarLength, overbarHeight );
1204  overbarLength = 0;
1205  }
1206 
1207  if( overbar )
1208  overbarLength += drawBitmapChar( c );
1209  else
1210  drawBitmapChar( c );
1211 
1212  ++i;
1213  }
1214 
1215  // Handle the case when overbar is active till the end of the drawn text
1216  currentManager->Translate( 0, commonOffset, 0 );
1217 
1218  if( overbar && overbarLength > 0 )
1219  drawBitmapOverbar( overbarLength, overbarHeight );
1220 
1221  Restore();
1222 }
1223 
1224 
1226 {
1229 
1231 
1232  // sub-pixel lines all render the same
1233  float minorLineWidth =
1234  std::fmax( 1.0f, gridLineWidth ) * getWorldPixelSize() / GetBackingScaleFactor();
1235  float majorLineWidth = minorLineWidth * 2.0f;
1236 
1237  // Draw the axis and grid
1238  // For the drawing the start points, end points and increments have
1239  // to be calculated in world coordinates
1240  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1241  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
1242 
1243  // Draw axes if desired
1244  if( axesEnabled )
1245  {
1246  SetLineWidth( minorLineWidth );
1248 
1249  DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) );
1250  DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) );
1251  }
1252 
1253  // force flush
1255 
1256  if( !gridVisibility || gridSize.x == 0 || gridSize.y == 0 )
1257  return;
1258 
1259  VECTOR2D gridScreenSize( gridSize );
1260 
1261  double gridThreshold = computeMinGridSpacing() / worldScale;
1262 
1264  gridThreshold *= 2.0;
1265 
1266  // If we cannot display the grid density, scale down by a tick size and
1267  // try again. Eventually, we get some representation of the grid
1268  while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold )
1269  {
1270  gridScreenSize = gridScreenSize * static_cast<double>( gridTick );
1271  }
1272 
1273  // Compute grid starting and ending indexes to draw grid points on the
1274  // visible screen area
1275  // Note: later any point coordinate will be offsetted by gridOrigin
1276  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridScreenSize.x );
1277  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridScreenSize.x );
1278  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridScreenSize.y );
1279  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridScreenSize.y );
1280 
1281  // Ensure start coordinate > end coordinate
1282  SWAP( gridStartX, >, gridEndX );
1283  SWAP( gridStartY, >, gridEndY );
1284 
1285  // Ensure the grid fills the screen
1286  --gridStartX; ++gridEndX;
1287  --gridStartY; ++gridEndY;
1288 
1289  glDisable( GL_DEPTH_TEST );
1290  glDisable( GL_TEXTURE_2D );
1291 
1292  if( gridStyle == GRID_STYLE::DOTS )
1293  {
1294  glEnable( GL_STENCIL_TEST );
1295  glStencilFunc( GL_ALWAYS, 1, 1 );
1296  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1297  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1298  SetStrokeColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
1299  }
1300  else
1301  {
1302  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1304  }
1305 
1307  {
1308 
1309  // Vertical positions
1310  for( int j = gridStartY; j <= gridEndY; j++ )
1311  {
1312  bool tickY = ( j % gridTick == 0 );
1313  const double posY = j * gridScreenSize.y + gridOrigin.y;
1314 
1315  // Horizontal positions
1316  for( int i = gridStartX; i <= gridEndX; i++ )
1317  {
1318  bool tickX = ( i % gridTick == 0 );
1319  SetLineWidth( ( ( tickX && tickY ) ? majorLineWidth : minorLineWidth ) );
1320  auto lineLen = 2.0 * GetLineWidth();
1321  auto posX = i * gridScreenSize.x + gridOrigin.x;
1322 
1323  DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) );
1324  DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) );
1325  }
1326  }
1327 
1329  }
1330  else
1331  {
1332  // Vertical lines
1333  for( int j = gridStartY; j <= gridEndY; j++ )
1334  {
1335  const double y = j * gridScreenSize.y + gridOrigin.y;
1336 
1337  // If axes are drawn, skip the lines that would cover them
1338  if( axesEnabled && y == 0.0 )
1339  continue;
1340 
1341  SetLineWidth( ( j % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1342  VECTOR2D a ( gridStartX * gridScreenSize.x + gridOrigin.x, y );
1343  VECTOR2D b ( gridEndX * gridScreenSize.x + gridOrigin.x, y );
1344 
1345  DrawLine( a, b );
1346  }
1347 
1349 
1350  if( gridStyle == GRID_STYLE::DOTS )
1351  {
1352  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1353  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1355  }
1356 
1357  // Horizontal lines
1358  for( int i = gridStartX; i <= gridEndX; i++ )
1359  {
1360  const double x = i * gridScreenSize.x + gridOrigin.x;
1361 
1362  // If axes are drawn, skip the lines that would cover them
1363  if( axesEnabled && x == 0.0 )
1364  continue;
1365 
1366  SetLineWidth( ( i % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1367  VECTOR2D a ( x, gridStartY * gridScreenSize.y + gridOrigin.y );
1368  VECTOR2D b ( x, gridEndY * gridScreenSize.y + gridOrigin.y );
1369  DrawLine( a, b );
1370  }
1371 
1373 
1374  if( gridStyle == GRID_STYLE::DOTS )
1375  glDisable( GL_STENCIL_TEST );
1376  }
1377 
1378  glEnable( GL_DEPTH_TEST );
1379  glEnable( GL_TEXTURE_2D );
1380 }
1381 
1382 
1383 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1384 {
1385  screenSize = VECTOR2I( aWidth, aHeight );
1386 
1387  // Resize framebuffers
1388  const float scaleFactor = GetBackingScaleFactor();
1389  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1390  isFramebufferInitialized = false;
1391 
1392  wxGLCanvas::SetSize( aWidth, aHeight );
1393 }
1394 
1395 
1396 bool OPENGL_GAL::Show( bool aShow )
1397 {
1398  bool s = wxGLCanvas::Show( aShow );
1399 
1400  if( aShow )
1401  wxGLCanvas::Raise();
1402 
1403  return s;
1404 }
1405 
1406 
1408 {
1409  glFlush();
1410 }
1411 
1412 
1414 {
1415  // Clear screen
1417  // NOTE: Black used here instead of m_clearColor; it will be composited later
1418  glClearColor( 0, 0, 0, 1 );
1419  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1420 }
1421 
1422 
1423 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1424 {
1425  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1426 
1427  matrixData[0] = aTransformation.m_data[0][0];
1428  matrixData[1] = aTransformation.m_data[1][0];
1429  matrixData[2] = aTransformation.m_data[2][0];
1430  matrixData[4] = aTransformation.m_data[0][1];
1431  matrixData[5] = aTransformation.m_data[1][1];
1432  matrixData[6] = aTransformation.m_data[2][1];
1433  matrixData[12] = aTransformation.m_data[0][2];
1434  matrixData[13] = aTransformation.m_data[1][2];
1435  matrixData[14] = aTransformation.m_data[2][2];
1436 
1437  glMultMatrixd( matrixData );
1438 }
1439 
1440 
1441 void OPENGL_GAL::Rotate( double aAngle )
1442 {
1443  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1444 }
1445 
1446 
1447 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1448 {
1449  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1450 }
1451 
1452 
1453 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1454 {
1455  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1456 }
1457 
1458 
1460 {
1462 }
1463 
1464 
1466 {
1468 }
1469 
1470 
1472 {
1473  isGrouping = true;
1474 
1475  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1476  int groupNumber = getNewGroupNumber();
1477  groups.insert( std::make_pair( groupNumber, newItem ) );
1478 
1479  return groupNumber;
1480 }
1481 
1482 
1484 {
1486  isGrouping = false;
1487 }
1488 
1489 
1490 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1491 {
1492  if( groups[aGroupNumber] )
1493  cachedManager->DrawItem( *groups[aGroupNumber] );
1494 }
1495 
1496 
1497 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1498 {
1499  if( groups[aGroupNumber] )
1500  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1501 }
1502 
1503 
1504 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1505 {
1506  if( groups[aGroupNumber] )
1507  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1508 }
1509 
1510 
1511 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1512 {
1513  // Frees memory in the container as well
1514  groups.erase( aGroupNumber );
1515 }
1516 
1517 
1519 {
1520  bitmapCache.reset( new GL_BITMAP_CACHE );
1521 
1522  groups.clear();
1523 
1524  if( isInitialized )
1525  cachedManager->Clear();
1526 }
1527 
1528 
1530 {
1531  switch( aTarget )
1532  {
1533  default:
1534  case TARGET_CACHED:
1536  break;
1537 
1538  case TARGET_NONCACHED:
1540  break;
1541 
1542  case TARGET_OVERLAY:
1544  break;
1545  }
1546 
1547  currentTarget = aTarget;
1548 }
1549 
1550 
1552 {
1553  return currentTarget;
1554 }
1555 
1556 
1558 {
1559  // Save the current state
1560  unsigned int oldTarget = compositor->GetBuffer();
1561 
1562  switch( aTarget )
1563  {
1564  // Cached and noncached items are rendered to the same buffer
1565  default:
1566  case TARGET_CACHED:
1567  case TARGET_NONCACHED:
1569  break;
1570 
1571  case TARGET_OVERLAY:
1573  break;
1574  }
1575 
1576 
1577  if( aTarget != TARGET_OVERLAY )
1579  else
1581 
1582  // Restore the previous state
1583  compositor->SetBuffer( oldTarget );
1584 }
1585 
1586 
1587 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1588 {
1589  // Now we should only store the position of the mouse cursor
1590  // The real drawing routines are in blitCursor()
1591  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1592  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1593  cursorPosition = aCursorPosition;
1594 }
1595 
1596 
1597 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1598 {
1599  /* Helper drawing: ____--- v3 ^
1600  * ____---- ... \ \
1601  * ____---- ... \ end \
1602  * v1 ____---- ... ____---- \ width
1603  * ---- ...___---- \ \
1604  * \ ___...-- \ v
1605  * \ ____----... ____---- v2
1606  * ---- ... ____----
1607  * start \ ... ____----
1608  * \... ____----
1609  * ----
1610  * v0
1611  * dots mark triangles' hypotenuses
1612  */
1613 
1614  auto v1 = currentManager->GetTransformation() * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 );
1615  auto v2 = currentManager->GetTransformation() * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 );
1616 
1617  VECTOR2D vs( v2.x - v1.x, v2.y - v1.y );
1618 
1619  currentManager->Reserve( 6 );
1620 
1621  // Line width is maintained by the vertex shader
1623  currentManager->Vertex( aStartPoint, layerDepth );
1624 
1626  currentManager->Vertex( aStartPoint, layerDepth );
1627 
1629  currentManager->Vertex( aEndPoint, layerDepth );
1630 
1632  currentManager->Vertex( aEndPoint, layerDepth );
1633 
1635  currentManager->Vertex( aEndPoint, layerDepth );
1636 
1638  currentManager->Vertex( aStartPoint, layerDepth );
1639 }
1640 
1641 
1642 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1643 {
1644  if( isFillEnabled )
1645  {
1647  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1648  }
1649 
1650  if( isStrokeEnabled )
1651  {
1653  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1654  }
1655 }
1656 
1657 
1658 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1659  double aAngle )
1660 {
1661  Save();
1662 
1663  currentManager->Reserve( 3 );
1664  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1665  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1666 
1667  /* Draw a triangle that contains the semicircle, then shade it to leave only
1668  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1669  * (if you want to understand more, check the vertex shader source [shader.vert]).
1670  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1671  * v2
1672  * /\
1673  * /__\
1674  * v0 //__\\ v1
1675  */
1677  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1678 
1680  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1681 
1683  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1684 
1685  Restore();
1686 }
1687 
1688 
1689 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1690  double aAngle )
1691 {
1692  double outerRadius = aRadius + ( lineWidth / 2 );
1693 
1694  Save();
1695 
1696  currentManager->Reserve( 3 );
1697  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1698  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1699 
1700  /* Draw a triangle that contains the semicircle, then shade it to leave only
1701  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1702  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1703  * radius and the line width. Shader uses these coordinates to determine if fragments are
1704  * inside the semicircle or not.
1705  * v2
1706  * /\
1707  * /__\
1708  * v0 //__\\ v1
1709  */
1711  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1712 
1714  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1715 
1717  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1718 
1719  Restore();
1720 }
1721 
1722 
1723 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1724 {
1725  if( isFillEnabled )
1726  {
1729 
1730  // Any non convex polygon needs to be tesselated
1731  // for this purpose the GLU standard functions are used
1733  gluTessBeginPolygon( tesselator, &params );
1734  gluTessBeginContour( tesselator );
1735 
1736  GLdouble* point = aPoints;
1737 
1738  for( int i = 0; i < aPointCount; ++i )
1739  {
1740  gluTessVertex( tesselator, point, point );
1741  point += 3; // 3 coordinates
1742  }
1743 
1744  gluTessEndContour( tesselator );
1745  gluTessEndPolygon( tesselator );
1746 
1747  // Free allocated intersecting points
1748  tessIntersects.clear();
1749  }
1750 
1751  if( isStrokeEnabled )
1752  {
1753  drawPolyline( [&](int idx) { return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] ); },
1754  aPointCount );
1755  }
1756 }
1757 
1758 
1759 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D (int)>& aPointGetter, int aPointCount )
1760 {
1761  if( aPointCount < 2 )
1762  return;
1763 
1765  int i;
1766 
1767  for( i = 1; i < aPointCount; ++i )
1768  {
1769  auto start = aPointGetter( i - 1 );
1770  auto end = aPointGetter( i );
1771 
1772  drawLineQuad( start, end );
1773  }
1774 }
1775 
1776 
1777 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1778 {
1779  const float TEX_X = font_image.width;
1780  const float TEX_Y = font_image.height;
1781 
1782  // handle space
1783  if( aChar == ' ' )
1784  {
1785  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1786  wxASSERT( g );
1787  Translate( VECTOR2D( g->advance, 0 ) );
1788  return g->advance;
1789  }
1790 
1791  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1792 
1793  // If the glyph is not found (happens for many esotheric unicode chars)
1794  // shows a '?' instead.
1795  if( !glyph )
1796  glyph = LookupGlyph( '?' );
1797 
1798  if( !glyph ) // Should not happen.
1799  return 0;
1800 
1801  const float X = glyph->atlas_x + font_information.smooth_pixels;
1802  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1803  const float XOFF = glyph->minx;
1804 
1805  // adjust for height rounding
1806  const float round_adjust = ( glyph->maxy - glyph->miny )
1807  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1808  const float top_adjust = font_information.max_y - glyph->maxy;
1809  const float YOFF = round_adjust + top_adjust;
1810  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1811  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1812  const float B = 0;
1813 
1814  currentManager->Reserve( 6 );
1815  Translate( VECTOR2D( XOFF, YOFF ) );
1816  /* Glyph:
1817  * v0 v1
1818  * +--+
1819  * | /|
1820  * |/ |
1821  * +--+
1822  * v2 v3
1823  */
1824  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1825  currentManager->Vertex( -B, -B, 0 ); // v0
1826 
1827  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1828  currentManager->Vertex( W + B, -B, 0 ); // v1
1829 
1830  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1831  currentManager->Vertex( -B, H + B, 0 ); // v2
1832 
1833 
1834  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1835  currentManager->Vertex( W + B, -B, 0 ); // v1
1836 
1837  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1838  currentManager->Vertex( -B, H + B, 0 ); // v2
1839 
1840  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1841  currentManager->Vertex( W + B, H + B, 0 ); // v3
1842 
1843  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1844 
1845  return glyph->advance;
1846 }
1847 
1848 
1849 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1850 {
1851  // To draw an overbar, simply draw an overbar
1852  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1853  wxCHECK( glyph, /* void */ );
1854 
1855  const float H = glyph->maxy - glyph->miny;
1856 
1857  Save();
1858 
1859  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1860 
1861  currentManager->Reserve( 6 );
1863 
1864  currentManager->Shader( 0 );
1865 
1866  currentManager->Vertex( 0, 0, 0 ); // v0
1867  currentManager->Vertex( aLength, 0, 0 ); // v1
1868  currentManager->Vertex( 0, H, 0 ); // v2
1869 
1870  currentManager->Vertex( aLength, 0, 0 ); // v1
1871  currentManager->Vertex( 0, H, 0 ); // v2
1872  currentManager->Vertex( aLength, H, 0 ); // v3
1873 
1874  Restore();
1875 }
1876 
1877 
1878 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
1879 {
1880  VECTOR2D textSize( 0, 0 );
1881  float commonOffset = std::numeric_limits<float>::max();
1882  static const auto defaultGlyph = LookupGlyph( '(' ); // for strange chars
1883 
1884  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
1885  {
1886  unsigned int c = *chIt;
1887 
1888  const FONT_GLYPH_TYPE* glyph = LookupGlyph( c );
1889  // Debug: show not coded char in the atlas
1890  // Be carefull before allowing the assert: it usually crash kicad
1891  // when the assert is made during a paint event.
1892  // wxASSERT_MSG( glyph, wxString::Format( "missing char in font: code 0x%x <%c>", c, c ) );
1893 
1894  if( !glyph || // Not coded in font
1895  c == '-' || c == '_' ) // Strange size of these 2 chars
1896  {
1897  glyph = defaultGlyph;
1898  }
1899 
1900  if( glyph )
1901  {
1902  textSize.x += glyph->advance;
1903  }
1904  }
1905 
1906  textSize.y = std::max<float>( textSize.y, font_information.max_y - defaultGlyph->miny );
1907  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
1908  textSize.y -= commonOffset;
1909 
1910  return std::make_pair( textSize, commonOffset );
1911 }
1912 
1913 
1914 void OPENGL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1915 {
1916  PostPaint();
1917 }
1918 
1919 
1920 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1921 {
1922  // Post the mouse event to the event listener registered in constructor, if any
1923  if( mouseListener )
1924  wxPostEvent( mouseListener, aEvent );
1925 }
1926 
1927 
1929 {
1930  if( !IsCursorEnabled() )
1931  return;
1932 
1934 
1935  const int cursorSize = fullscreenCursor ? 8000 : 80;
1936 
1937  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
1938  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
1939  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
1940 
1941  const COLOR4D cColor = getCursorColor();
1942  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
1943  cColor.b * cColor.a, 1.0 );
1944 
1945  glActiveTexture( GL_TEXTURE0 );
1946  glDisable( GL_TEXTURE_2D );
1947  glLineWidth( 1.0 );
1948  glColor4d( color.r, color.g, color.b, color.a );
1949 
1950  glBegin( GL_LINES );
1951  glVertex2d( cursorCenter.x, cursorBegin.y );
1952  glVertex2d( cursorCenter.x, cursorEnd.y );
1953 
1954  glVertex2d( cursorBegin.x, cursorCenter.y );
1955  glVertex2d( cursorEnd.x, cursorCenter.y );
1956  glEnd();
1957 }
1958 
1959 
1961 {
1962  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
1963  wxT( "There are no free slots to store a group" ) );
1964 
1965  while( groups.find( groupCounter ) != groups.end() )
1966  {
1967  groupCounter++;
1968  }
1969 
1970  return groupCounter++;
1971 }
1972 
1973 
1975 {
1976  wxASSERT( IsShownOnScreen() );
1977 
1978  wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." );
1979 
1980  GLenum err = glewInit();
1981 
1982  if( GLEW_OK != err )
1983  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
1984 
1985  // Check the OpenGL version (minimum 2.1 is required)
1986  if( !GLEW_VERSION_2_1 )
1987  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
1988 
1989 #if defined (__LINUX__) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
1990 #ifdef DEBUG
1991  if( GLEW_ARB_debug_output )
1992  enableGlDebug( true );
1993 #endif
1994 #endif
1995 
1996  // Framebuffers have to be supported
1997  if( !GLEW_EXT_framebuffer_object )
1998  throw std::runtime_error( "Framebuffer objects are not supported!" );
1999 
2000  // Vertex buffer has to be supported
2001  if( !GLEW_ARB_vertex_buffer_object )
2002  throw std::runtime_error( "Vertex buffer objects are not supported!" );
2003 
2004  // Prepare shaders
2006  throw std::runtime_error( "Cannot compile vertex shader!" );
2007 
2009  throw std::runtime_error( "Cannot compile fragment shader!" );
2010 
2011  if( !shader->IsLinked() && !shader->Link() )
2012  throw std::runtime_error( "Cannot link the shaders!" );
2013 
2014  // Check if video card supports textures big enough to fit the font atlas
2015  int maxTextureSize;
2016  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
2017 
2018  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height )
2019  {
2020  // TODO implement software texture scaling
2021  // for bitmap fonts and use a higher resolution texture?
2022  throw std::runtime_error( "Requested texture size is not supported" );
2023  }
2024 
2025  cachedManager = new VERTEX_MANAGER( true );
2026  nonCachedManager = new VERTEX_MANAGER( false );
2027  overlayManager = new VERTEX_MANAGER( false );
2028 
2029  // Make VBOs use shaders
2033 
2034  isInitialized = true;
2035 }
2036 
2037 
2038 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
2039 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
2040 {
2041  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
2042  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2043  VERTEX_MANAGER* vboManager = param->vboManager;
2044 
2045  assert( vboManager );
2046  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
2047 }
2048 
2049 
2050 void CALLBACK CombineCallback( GLdouble coords[3],
2051  GLdouble* vertex_data[4],
2052  GLfloat weight[4], GLdouble** dataOut, void* aData )
2053 {
2054  GLdouble* vertex = new GLdouble[3];
2055  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2056 
2057  // Save the pointer so we can delete it later
2058  param->intersectPoints.push_back( boost::shared_array<GLdouble>( vertex ) );
2059 
2060  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
2061 
2062  *dataOut = vertex;
2063 }
2064 
2065 
2066 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
2067 {
2068  // This callback is needed to force GLU tesselator to use triangles only
2069 }
2070 
2071 
2072 void CALLBACK ErrorCallback( GLenum aErrorCode )
2073 {
2074  //throw std::runtime_error( std::string( "Tessellation error: " ) +
2075  //std::string( (const char*) gluErrorString( aErrorCode ) );
2076 }
2077 
2078 
2079 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
2080 {
2081  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
2082  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
2083  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
2084  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
2085 }
2086 
2087 void OPENGL_GAL::EnableDepthTest( bool aEnabled )
2088 {
2089  cachedManager->EnableDepthTest( aEnabled );
2090  nonCachedManager->EnableDepthTest( aEnabled );
2091  overlayManager->EnableDepthTest( aEnabled );
2092 }
2093 
2094 
2095 static double roundr( double f, double r )
2096 {
2097  return floor(f / r + 0.5) * r;
2098 }
2099 
2100 
2102 {
2103  auto pixelSize = worldScale;
2104 
2105  lookAtPoint.x = roundr( lookAtPoint.x, pixelSize );
2106  lookAtPoint.y = roundr( lookAtPoint.y, pixelSize );
2107 
2109 }
2110 
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.
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
VERTEX_MANAGER * currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
Definition: opengl_gal.h:297
virtual wxSize GetNativePixelSize() const
float GetLineWidth() const
Get the line width.
virtual void beginUpdate() override
Definition: opengl_gal.cpp:569
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:285
std::pair< UTF8, std::vector< bool > > ProcessOverbars(const UTF8 &aText)
Processes a text to extract the raw text and overbar flags.
Definition: text_utils.cpp:27
double layerDepth
The actual layer depth.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:57
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:305
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:275
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 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:306
bool isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:314
void Use()
Use the shader.
Definition: shader.h:132
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draws a filled 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:291
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:300
GAL_DISPLAY_OPTIONS & options
int color
Definition: DXF_plotter.cpp:62
VECTOR2D getScreenPixelSize() const
Definition: opengl_gal.cpp:362
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:138
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:324
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:927
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:318
double g
Green component.
Definition: color4d.h:302
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:309
bool globalFlipX
Flag for X axis flipping.
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
static const unsigned int DIRECT_RENDERING
int PointCount() const
Function PointCount()
bool isGrouping
Was a group started?
Definition: opengl_gal.h:317
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
#define abs(a)
Definition: auxiliary.h:84
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:555
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:299
double b
Blue component.
Definition: color4d.h:303
Auxiliary rendering target (noncached)
Definition: definitions.h:49
static int instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:287
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:272
T m_data[3][3]
Definition: matrix3x3.h:64
double getWorldPixelSize() const
Definition: opengl_gal.cpp:355
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:770
virtual RENDER_TARGET GetTarget() const override
Gets the currently used target for rendering.
static const int CURVE_POINTS
The number of points for curve approximation.
Definition: opengl_gal.h:283
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
virtual void endUpdate() override
Definition: opengl_gal.cpp:585
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:311
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 CPoint()
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:304
void Unmap()
Function Unmap() unmaps vertex buffer.
OPENGL_COMPOSITOR * compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:303
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)
bool isStrokeEnabled
Are the outlines stroked ?
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
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:295
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:304
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).
Class 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:470
wxEvtHandler * mouseListener
Definition: opengl_gal.h:288
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Function updatedGalDisplayOptions.
Definition: opengl_gal.cpp:328
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:66
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: opengl_gal.cpp:594
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:125
GLint ufm_screenPixelSize
Definition: opengl_gal.h:321
virtual void endDrawing() override
Definition: opengl_gal.cpp:510
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:312
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:961
FONT_INFO_TYPE font_information
Definition: gl_resources.cpp:3
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:306
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
string & err
Definition: json11.cpp:598
void lockContext(int aClientCookie) override
Private: use GAL_CONTEXT_LOCKER RAII object.
Definition: opengl_gal.cpp:545
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:347
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:95
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:298
class uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded ...
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:904
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:602
GLint ufm_worldPixelSize
Definition: opengl_gal.h:320
std::deque< boost::shared_array< GLdouble > > tessIntersects
Storage for intersecting points.
Definition: opengl_gal.h:349
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: opengl_gal.cpp:704
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.
bool isInitialized
Basic initialization flag, has to be done when the window is visible.
Definition: opengl_gal.h:315
COLOR4D gridColor
Color of the grid.
const int scale
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.h:247
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.
#define max(a, b)
Definition: auxiliary.h:86
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.
Class SHAPE_LINE_CHAIN.
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: opengl_gal.h:296
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
size_t i
Definition: json11.cpp:597
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.
#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:286
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:866
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:301
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:283
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:369
GLint ufm_pixelSizeMultiplier
Definition: opengl_gal.h:322
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:648
static bool isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:313
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint) override
Draw a cubic bezier spline.
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.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:114
#define min(a, b)
Definition: auxiliary.h:85
Class GAL is the abstract interface for drawing on a 2D-surface.
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
void drawBitmapOverbar(double aLength, double aHeight)
Draws an overbar over the currently drawn text.