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 valide (can be destoyed 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  auto imgData = const_cast<BITMAP_BASE*>( 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 
339  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
340  {
341  Refresh();
342  refresh = true;
343  }
344 
345  return refresh;
346 }
347 
348 
350 {
351  auto matrix = GetScreenWorldMatrix();
352  return std::min( std::abs( matrix.GetScale().x ), std::abs( matrix.GetScale().y ) );
353 }
354 
355 
357 {
358  auto sf = GetBackingScaleFactor();
359  return VECTOR2D( 2.0 / (double) ( screenSize.x * sf ), 2.0 / (double) ( screenSize.y * sf ) );
360 }
361 
362 
364 {
365 #ifdef __WXDEBUG__
366  PROF_COUNTER totalRealTime( "OPENGL_GAL::beginDrawing()", true );
367 #endif /* __WXDEBUG__ */
368 
369  wxASSERT_MSG( isContextLocked, "GAL_DRAWING_CONTEXT RAII object should have locked context. "
370  "Calling GAL::beginDrawing() directly is not allowed." );
371 
372  wxASSERT_MSG( IsVisible(), "GAL::beginDrawing() must not be entered when GAL is not visible. "
373  "Other drawing routines will expect everything to be initialized "
374  "which will not be the case." );
375 
376  if( !isInitialized )
377  init();
378 
379  // Set up the view port
380  glMatrixMode( GL_PROJECTION );
381  glLoadIdentity();
382 
383  // Create the screen transformation (Do the RH-LH conversion here)
384  glOrtho( 0, (GLint) screenSize.x, (GLsizei) screenSize.y, 0, -depthRange.x, -depthRange.y );
385 
387  {
388  // Prepare rendering target buffers
392 
394  }
395 
396  compositor->Begin();
397 
398  // Disable 2D Textures
399  glDisable( GL_TEXTURE_2D );
400 
401  glShadeModel( GL_FLAT );
402 
403  // Enable the depth buffer
404  glEnable( GL_DEPTH_TEST );
405  glDepthFunc( GL_LESS );
406 
407  // Setup blending, required for transparent objects
408  glEnable( GL_BLEND );
409  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
410 
411  glMatrixMode( GL_MODELVIEW );
412 
413  // Set up the world <-> screen transformation
415  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
416  matrixData[0] = worldScreenMatrix.m_data[0][0];
417  matrixData[1] = worldScreenMatrix.m_data[1][0];
418  matrixData[2] = worldScreenMatrix.m_data[2][0];
419  matrixData[4] = worldScreenMatrix.m_data[0][1];
420  matrixData[5] = worldScreenMatrix.m_data[1][1];
421  matrixData[6] = worldScreenMatrix.m_data[2][1];
422  matrixData[12] = worldScreenMatrix.m_data[0][2];
423  matrixData[13] = worldScreenMatrix.m_data[1][2];
424  matrixData[14] = worldScreenMatrix.m_data[2][2];
425  glLoadMatrixd( matrixData );
426 
427  // Set defaults
430 
431  // Remove all previously stored items
434 
438 
440  {
441  // Keep bitmap font texture always bound to the second texturing unit
442  const GLint FONT_TEXTURE_UNIT = 2;
443 
444  // Either load the font atlas to video memory, or simply bind it to a texture unit
445  if( !isBitmapFontLoaded )
446  {
447  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
448  glGenTextures( 1, &fontTexture );
449  glBindTexture( GL_TEXTURE_2D, fontTexture );
450  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height,
451  0, GL_RGB, GL_UNSIGNED_BYTE, font_image.pixels );
452  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
453  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
454  checkGlError( "loading bitmap font" );
455 
456  glActiveTexture( GL_TEXTURE0 );
457 
458  isBitmapFontLoaded = true;
459  }
460  else
461  {
462  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
463  glBindTexture( GL_TEXTURE_2D, fontTexture );
464  glActiveTexture( GL_TEXTURE0 );
465  }
466 
467  // Set shader parameter
468  GLint ufm_fontTexture = shader->AddParameter( "fontTexture" );
469  GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" );
470  ufm_worldPixelSize = shader->AddParameter( "worldPixelSize" );
471  ufm_screenPixelSize = shader->AddParameter( "screenPixelSize" );
472  ufm_pixelSizeMultiplier = shader->AddParameter( "pixelSizeMultiplier" );
473 
474  shader->Use();
475  shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
476  shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
477  shader->Deactivate();
478  checkGlError( "setting bitmap font sampler as shader parameter" );
479 
481  }
482 
483  shader->Use();
486  double pixelSizeMultiplier = compositor->GetAntialiasSupersamplingFactor();
487  shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
488  shader->Deactivate();
489 
490  // Something betreen BeginDrawing and EndDrawing seems to depend on
491  // this texture unit being active, but it does not assure it itself.
492  glActiveTexture( GL_TEXTURE0 );
493 
494  // Unbind buffers - set compositor for direct drawing
496 
497 #ifdef __WXDEBUG__
498  totalRealTime.Stop();
499  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::beginDrawing(): %.1f ms" ), totalRealTime.msecs() );
500 #endif /* __WXDEBUG__ */
501 }
502 
503 
505 {
506  wxASSERT_MSG( isContextLocked, "What happened to the context lock?" );
507 
508 #ifdef __WXDEBUG__
509  PROF_COUNTER totalRealTime( "OPENGL_GAL::endDrawing()", true );
510 #endif /* __WXDEBUG__ */
511 
512  // Cached & non-cached containers are rendered to the same buffer
516 
517  // Overlay container is rendered to a different buffer
520 
521  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
522  glColor4d( 1.0, 1.0, 1.0, 1.0 );
523 
524  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
527  compositor->Present();
528  blitCursor();
529 
530  SwapBuffers();
531 
532 #ifdef __WXDEBUG__
533  totalRealTime.Stop();
534  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::endDrawing(): %.1f ms" ), totalRealTime.msecs() );
535 #endif /* __WXDEBUG__ */
536 }
537 
538 
539 void OPENGL_GAL::lockContext( int aClientCookie )
540 {
541  wxASSERT_MSG( !isContextLocked, "Context already locked." );
542  isContextLocked = true;
543  lockClientCookie = aClientCookie;
544 
546 }
547 
548 
549 void OPENGL_GAL::unlockContext( int aClientCookie )
550 {
551  wxASSERT_MSG( isContextLocked, "Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
552  "be stacked rather than making separate lock/unlock calls." );
553 
554  wxASSERT_MSG( lockClientCookie == aClientCookie, "Context was locked by a different client. "
555  "Should not be possible with RAII objects." );
556 
557  isContextLocked = false;
558 
560 }
561 
562 
564 {
565  wxASSERT_MSG( isContextLocked, "GAL_UPDATE_CONTEXT RAII object should have locked context. "
566  "Calling this from anywhere else is not allowed." );
567 
568  wxASSERT_MSG( IsVisible(), "GAL::beginUpdate() must not be entered when GAL is not visible. "
569  "Other update routines will expect everything to be initialized "
570  "which will not be the case." );
571 
572  if( !isInitialized )
573  init();
574 
575  cachedManager->Map();
576 }
577 
578 
580 {
581  if( !isInitialized )
582  return;
583 
584  cachedManager->Unmap();
585 }
586 
587 
588 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
589 {
591 
592  drawLineQuad( aStartPoint, aEndPoint );
593 }
594 
595 
596 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
597  double aWidth )
598 {
599  if( aStartPoint == aEndPoint ) // 0 length segments are just a circle.
600  {
601  DrawCircle( aStartPoint, aWidth/2 );
602  return;
603  }
604 
605  if( isFillEnabled || aWidth == 1.0 )
606  {
608 
609  SetLineWidth( aWidth );
610  drawLineQuad( aStartPoint, aEndPoint );
611  }
612  else
613  {
614  auto startEndVector = aEndPoint - aStartPoint;
615  auto lineAngle = startEndVector.Angle();
616  // Outlined tracks
617  double lineLength = startEndVector.EuclideanNorm();
618 
619  SetLineWidth( 1.0 );
621 
622  Save();
623 
624  currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
625  currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
626 
627  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
628  VECTOR2D( lineLength, aWidth / 2.0 ) );
629 
630  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ),
631  VECTOR2D( lineLength, -aWidth / 2.0 ) );
632 
633  // Draw line caps
634  drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
635  drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );
636 
637  Restore();
638  }
639 }
640 
641 
642 void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
643 {
644  if( isFillEnabled )
645  {
646  currentManager->Reserve( 3 );
648 
649  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
650  * Parameters given to Shader() are indices of the triangle's vertices
651  * (if you want to understand more, check the vertex shader source [shader.vert]).
652  * Shader uses this coordinates to determine if fragments are inside the circle or not.
653  * Does the calculations in the vertex shader now (pixel alignment)
654  * v2
655  * /\
656  * //\\
657  * v0 /_\/_\ v1
658  */
659  currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0, aRadius );
660  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
661 
662  currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0, aRadius );
663  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
664 
665  currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0, aRadius );
666  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, layerDepth );
667  }
668  if( isStrokeEnabled )
669  {
670  currentManager->Reserve( 3 );
672 
673  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
674  * Parameters given to Shader() are indices of the triangle's vertices
675  * (if you want to understand more, check the vertex shader source [shader.vert]).
676  * and the line width. Shader uses this coordinates to determine if fragments are
677  * inside the circle or not.
678  * v2
679  * /\
680  * //\\
681  * v0 /_\/_\ v1
682  */
684  currentManager->Vertex( aCenterPoint.x, // v0
685  aCenterPoint.y, layerDepth );
686 
688  currentManager->Vertex( aCenterPoint.x, // v1
689  aCenterPoint.y, layerDepth );
690 
692  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, // v2
693  layerDepth );
694  }
695 }
696 
697 
698 void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
699  double aEndAngle )
700 {
701  if( aRadius <= 0 )
702  return;
703 
704  // Swap the angles, if start angle is greater than end angle
705  SWAP( aStartAngle, >, aEndAngle );
706 
707  const double alphaIncrement = calcAngleStep( aRadius );
708 
709  Save();
710  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
711 
712  if( isFillEnabled )
713  {
714  double alpha;
717 
718  // Triangle fan
719  for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
720  {
721  currentManager->Reserve( 3 );
722  currentManager->Vertex( 0.0, 0.0, layerDepth );
723  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
724  alpha += alphaIncrement;
725  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
726  }
727 
728  // The last missing triangle
729  const VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
730 
731  currentManager->Reserve( 3 );
732  currentManager->Vertex( 0.0, 0.0, layerDepth );
733  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, layerDepth );
734  currentManager->Vertex( endPoint.x, endPoint.y, layerDepth );
735  }
736 
737  if( isStrokeEnabled )
738  {
740 
741  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
742  double alpha;
743 
744  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
745  {
746  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
747  DrawLine( p, p_next );
748 
749  p = p_next;
750  }
751 
752  // Draw the last missing part
753  if( alpha != aEndAngle )
754  {
755  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
756  DrawLine( p, p_last );
757  }
758  }
759 
760  Restore();
761 }
762 
763 
764 void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
765  double aEndAngle, double aWidth )
766 {
767  if( aRadius <= 0 )
768  {
769  // Arcs of zero radius are a circle of aWidth diameter
770  if( aWidth > 0 )
771  DrawCircle( aCenterPoint, aWidth / 2.0 );
772 
773  return;
774  }
775 
776  // Swap the angles, if start angle is greater than end angle
777  SWAP( aStartAngle, >, aEndAngle );
778 
779  const double alphaIncrement = calcAngleStep( aRadius );
780 
781  Save();
782  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
783 
784  if( isStrokeEnabled )
785  {
787 
788  double width = aWidth / 2.0;
789  VECTOR2D startPoint( cos( aStartAngle ) * aRadius,
790  sin( aStartAngle ) * aRadius );
791  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
792  sin( aEndAngle ) * aRadius );
793 
794  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
795  drawStrokedSemiCircle( endPoint, width, aEndAngle );
796 
797  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
798  sin( aStartAngle ) * ( aRadius + width ) );
799 
800  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
801  sin( aStartAngle ) * ( aRadius - width ) );
802 
803  double alpha;
804 
805  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
806  {
807  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
808  sin( alpha ) * ( aRadius + width ) );
809  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
810  sin( alpha ) * ( aRadius - width ) );
811 
812  DrawLine( pOuter, pNextOuter );
813  DrawLine( pInner, pNextInner );
814 
815  pOuter = pNextOuter;
816  pInner = pNextInner;
817  }
818 
819  // Draw the last missing part
820  if( alpha != aEndAngle )
821  {
822  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
823  sin( aEndAngle ) * ( aRadius + width ) );
824  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
825  sin( aEndAngle ) * ( aRadius - width ) );
826 
827  DrawLine( pOuter, pLastOuter );
828  DrawLine( pInner, pLastInner );
829  }
830  }
831 
832  if( isFillEnabled )
833  {
835  SetLineWidth( aWidth );
836 
837  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
838  double alpha;
839 
840  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
841  {
842  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
843  DrawLine( p, p_next );
844 
845  p = p_next;
846  }
847 
848  // Draw the last missing part
849  if( alpha != aEndAngle )
850  {
851  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
852  DrawLine( p, p_last );
853  }
854  }
855 
856  Restore();
857 }
858 
859 
860 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
861 {
862  // Compute the diagonal points of the rectangle
863  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
864  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
865 
866  // Fill the rectangle
867  if( isFillEnabled )
868  {
869  currentManager->Reserve( 6 );
872 
873  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
874  currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
875  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
876 
877  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
878  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
879  currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
880  }
881 
882  // Stroke the outline
883  if( isStrokeEnabled )
884  {
886 
887  std::deque<VECTOR2D> pointList;
888  pointList.push_back( aStartPoint );
889  pointList.push_back( diagonalPointA );
890  pointList.push_back( aEndPoint );
891  pointList.push_back( diagonalPointB );
892  pointList.push_back( aStartPoint );
893  DrawPolyline( pointList );
894  }
895 }
896 
897 
898 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
899 {
900  drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
901 }
902 
903 
904 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
905 {
906  drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
907 }
908 
909 
911 {
912  auto numPoints = aLineChain.PointCount();
913 
914  if( aLineChain.IsClosed() )
915  numPoints += 1;
916 
917  drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, numPoints );
918 }
919 
920 
921 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
922 {
923  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
924  GLdouble* ptr = points.get();
925 
926  for( const VECTOR2D& p : aPointList )
927  {
928  *ptr++ = p.x;
929  *ptr++ = p.y;
930  *ptr++ = layerDepth;
931  }
932 
933  drawPolygon( points.get(), aPointList.size() );
934 }
935 
936 
937 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
938 {
939  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
940  GLdouble* target = points.get();
941  const VECTOR2D* src = aPointList;
942 
943  for( int i = 0; i < aListSize; ++i )
944  {
945  *target++ = src->x;
946  *target++ = src->y;
947  *target++ = layerDepth;
948  ++src;
949  }
950 
951  drawPolygon( points.get(), aListSize );
952 }
953 
954 
956 {
959 
960  if( isFillEnabled )
961  {
962  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
963  {
964  auto triPoly = aPolySet.TriangulatedPolygon( j );
965 
966  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
967  {
968  VECTOR2I a, b, c;
969  triPoly->GetTriangle( i, a, b, c );
970  currentManager->Vertex( a.x, a.y, layerDepth );
971  currentManager->Vertex( b.x, b.y, layerDepth );
972  currentManager->Vertex( c.x, c.y, layerDepth );
973  }
974  }
975  }
976 
977  if( isStrokeEnabled )
978  {
979  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
980  {
981  const auto& poly = aPolySet.Polygon( j );
982 
983  for( const auto& lc : poly )
984  {
985  DrawPolyline( lc );
986  }
987  }
988  }
989 }
990 
991 
993 {
994  if ( aPolySet.IsTriangulationUpToDate() )
995  {
996  drawTriangulatedPolyset( aPolySet );
997  return;
998  }
999 
1000  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1001  {
1002  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
1003  DrawPolygon( outline );
1004  }
1005 }
1006 
1007 
1008 
1010 {
1011  if( aPolygon.SegmentCount() == 0 )
1012  return;
1013 
1014  const int pointCount = aPolygon.SegmentCount() + 1;
1015  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
1016  GLdouble* ptr = points.get();
1017 
1018  for( int i = 0; i < pointCount; ++i )
1019  {
1020  const VECTOR2I& p = aPolygon.CPoint( i );
1021  *ptr++ = p.x;
1022  *ptr++ = p.y;
1023  *ptr++ = layerDepth;
1024  }
1025 
1026  drawPolygon( points.get(), pointCount );
1027 }
1028 
1029 
1030 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
1031  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
1032 {
1033  // FIXME The drawing quality needs to be improved
1034  // FIXME Perhaps choose a quad/triangle strip instead?
1035  // FIXME Brute force method, use a better (recursive?) algorithm
1036 
1037  std::deque<VECTOR2D> pointList;
1038 
1039  double t = 0.0;
1040  double dt = 1.0 / (double) CURVE_POINTS;
1041 
1042  for( int i = 0; i <= CURVE_POINTS; i++ )
1043  {
1044  double omt = 1.0 - t;
1045  double omt2 = omt * omt;
1046  double omt3 = omt * omt2;
1047  double t2 = t * t;
1048  double t3 = t * t2;
1049 
1050  VECTOR2D vertex = omt3 * aStartPoint + 3.0 * t * omt2 * aControlPointA
1051  + 3.0 * t2 * omt * aControlPointB + t3 * aEndPoint;
1052 
1053  pointList.push_back( vertex );
1054 
1055  t += dt;
1056  }
1057 
1058  DrawPolyline( pointList );
1059 }
1060 
1061 
1062 void OPENGL_GAL::DrawBitmap( const BITMAP_BASE& aBitmap )
1063 {
1064  // We have to calculate the pixel size in users units to draw the image.
1065  // worldUnitLength is a factor used for converting IU to inches
1066  double scale = 1.0 / ( aBitmap.GetPPI() * worldUnitLength );
1067  double w = (double) aBitmap.GetSizePixels().x * scale;
1068  double h = (double) aBitmap.GetSizePixels().y * scale;
1069 
1070  auto xform = currentManager->GetTransformation();
1071 
1072  glm::vec4 v0 = xform * glm::vec4( -w/2, -h/2, 0.0, 0.0 );
1073  glm::vec4 v1 = xform * glm::vec4( w/2, h/2, 0.0, 0.0 );
1074  glm::vec4 trans = xform[3];
1075 
1076  auto texture_id = bitmapCache->RequestBitmap( &aBitmap );
1077 
1078  if( !glIsTexture( texture_id ) ) // ensure the bitmap texture is still valid
1079  return;
1080 
1081  auto oldTarget = GetTarget();
1082 
1083  glPushMatrix();
1084  glTranslated( trans.x, trans.y, trans.z );
1085 
1087  glEnable(GL_TEXTURE_2D);
1088  glActiveTexture( GL_TEXTURE0 );
1089  glBindTexture( GL_TEXTURE_2D, texture_id );
1090 
1091  glBegin( GL_QUADS );
1092  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1093  glTexCoord2f( 0.0, 0.0 );
1094  glVertex3f( v0.x, v0.y, layerDepth );
1095  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1096  glTexCoord2f( 1.0, 0.0 );
1097  glVertex3f( v1.x, v0.y, layerDepth );
1098  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1099  glTexCoord2f( 1.0, 1.0 );
1100  glVertex3f( v1.x, v1.y, layerDepth );
1101  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1102  glTexCoord2f( 0.0, 1.0 );
1103  glVertex3f( v0.x, v1.y, layerDepth );
1104  glEnd();
1105 
1106  SetTarget( oldTarget );
1107  glBindTexture( GL_TEXTURE_2D, 0 );
1108 
1109 #ifdef DISABLE_BITMAP_CACHE
1110  glDeleteTextures( 1, &texture_id );
1111 #endif
1112 
1113  glPopMatrix();
1114 }
1115 
1116 
1117 void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
1118  double aRotationAngle )
1119 {
1120  wxASSERT_MSG( !IsTextMirrored(), "No support for mirrored text using bitmap fonts." );
1121 
1122  auto processedText = ProcessOverbars( aText );
1123  const auto& text = processedText.first;
1124  const auto& overbars = processedText.second;
1125 
1126  // Compute text size, so it can be properly justified
1127  VECTOR2D textSize;
1128  float commonOffset;
1129  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
1130 
1131  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
1132  bool overbar = false;
1133 
1134  int overbarLength = 0;
1135  double overbarHeight = textSize.y;
1136 
1137  Save();
1138 
1140  currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
1141  currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
1142 
1143  double sx = SCALE * ( globalFlipX ? -1.0 : 1.0 );
1144  double sy = SCALE * ( globalFlipY ? -1.0 : 1.0 );
1145 
1146  currentManager->Scale( sx, sy, 0 );
1147  currentManager->Translate( 0, -commonOffset, 0 );
1148 
1149  switch( GetHorizontalJustify() )
1150  {
1152  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
1153  break;
1154 
1156  //if( !IsTextMirrored() )
1157  Translate( VECTOR2D( -textSize.x, 0 ) );
1158  break;
1159 
1160  case GR_TEXT_HJUSTIFY_LEFT:
1161  //if( IsTextMirrored() )
1162  //Translate( VECTOR2D( -textSize.x, 0 ) );
1163  break;
1164  }
1165 
1166  switch( GetVerticalJustify() )
1167  {
1168  case GR_TEXT_VJUSTIFY_TOP:
1169  Translate( VECTOR2D( 0, -textSize.y ) );
1170  overbarHeight = -textSize.y / 2.0;
1171  break;
1172 
1174  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
1175  overbarHeight = 0;
1176  break;
1177 
1179  break;
1180  }
1181 
1182  int i = 0;
1183 
1184  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
1185  {
1186  unsigned int c = *chIt;
1187  wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
1188 
1189  // Handle overbar
1190  if( overbars[i] && !overbar )
1191  {
1192  overbar = true; // beginning of an overbar
1193  }
1194  else if( overbar && !overbars[i] )
1195  {
1196  overbar = false; // end of an overbar
1197  drawBitmapOverbar( overbarLength, overbarHeight );
1198  overbarLength = 0;
1199  }
1200 
1201  if( overbar )
1202  overbarLength += drawBitmapChar( c );
1203  else
1204  drawBitmapChar( c );
1205 
1206  ++i;
1207  }
1208 
1209  // Handle the case when overbar is active till the end of the drawn text
1210  currentManager->Translate( 0, commonOffset, 0 );
1211 
1212  if( overbar && overbarLength > 0 )
1213  drawBitmapOverbar( overbarLength, overbarHeight );
1214 
1215  Restore();
1216 }
1217 
1218 
1220 {
1223 
1225 
1226  // sub-pixel lines all render the same
1227  float minorLineWidth = std::fmax( 1.0f, gridLineWidth ) * getWorldPixelSize();
1228  float majorLineWidth = minorLineWidth * 2.0f;
1229 
1230  // Draw the axis and grid
1231  // For the drawing the start points, end points and increments have
1232  // to be calculated in world coordinates
1233  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1234  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
1235 
1236  // Draw axes if desired
1237  if( axesEnabled )
1238  {
1239  SetLineWidth( minorLineWidth );
1241 
1242  DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) );
1243  DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) );
1244  }
1245 
1246  // force flush
1248 
1249  if( !gridVisibility )
1250  return;
1251 
1252  int gridScreenSizeDense = gridSize.x;
1253  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) );
1254 
1255  double gridThreshold = KiROUND( computeMinGridSpacing() / worldScale );
1256 
1258  gridThreshold *= 2.0;
1259 
1260  // If we cannot display the grid density, scale down by a tick size and
1261  // try again. Eventually, we get some representation of the grid
1262  while( std::min( gridScreenSizeDense, gridScreenSizeCoarse ) <= gridThreshold )
1263  {
1264  gridScreenSizeCoarse *= gridTick;
1265  gridScreenSizeDense *= gridTick;
1266  }
1267 
1268  // Compute grid staring and ending indexes to draw grid points on the
1269  // visible screen area
1270  // Note: later any point coordinate will be offsetted by gridOrigin
1271  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridScreenSizeDense );
1272  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridScreenSizeDense );
1273  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridScreenSizeDense );
1274  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridScreenSizeDense );
1275 
1276  // Ensure start coordinate > end coordinate
1277  SWAP( gridStartX, >, gridEndX );
1278  SWAP( gridStartY, >, gridEndY );
1279 
1280  // Ensure the grid fills the screen
1281  --gridStartX; ++gridEndX;
1282  --gridStartY; ++gridEndY;
1283 
1284  glDisable( GL_DEPTH_TEST );
1285  glDisable( GL_TEXTURE_2D );
1286 
1287  if( gridStyle == GRID_STYLE::DOTS )
1288  {
1289  glEnable( GL_STENCIL_TEST );
1290  glStencilFunc( GL_ALWAYS, 1, 1 );
1291  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1292  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1293  SetStrokeColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
1294  }
1295  else
1296  {
1297  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1299  }
1300 
1302  {
1303 
1304  // Vertical positions
1305  for( int j = gridStartY; j <= gridEndY; j++ )
1306  {
1307  bool tickY = ( j % gridTick == 0 );
1308  int posY = j * gridScreenSizeDense + gridOrigin.y;
1309 
1310  // Horizontal positions
1311  for( int i = gridStartX; i <= gridEndX; i++ )
1312  {
1313  bool tickX = ( i % gridTick == 0 );
1314  SetLineWidth( ( ( tickX && tickY ) ? majorLineWidth : minorLineWidth ) );
1315  auto lineLen = 2.0 * GetLineWidth();
1316  auto posX = i * gridScreenSizeDense + gridOrigin.x;
1317 
1318  DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) );
1319  DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) );
1320  }
1321  }
1322 
1324  }
1325  else
1326  {
1327  // Vertical lines
1328  for( int j = gridStartY; j <= gridEndY; j++ )
1329  {
1330  const double y = j * gridScreenSizeDense + gridOrigin.y;
1331 
1332  // If axes are drawn, skip the lines that would cover them
1333  if( axesEnabled && y == 0 )
1334  continue;
1335 
1336  SetLineWidth( ( j % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1337  VECTOR2D a ( gridStartX * gridScreenSizeDense + gridOrigin.x, y );
1338  VECTOR2D b ( gridEndX * gridScreenSizeDense + gridOrigin.x, y );
1339 
1340  DrawLine( a, b );
1341  }
1342 
1344 
1345  if( gridStyle == GRID_STYLE::DOTS )
1346  {
1347  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1348  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1350  }
1351 
1352  // Horizontal lines
1353  for( int i = gridStartX; i <= gridEndX; i++ )
1354  {
1355  const double x = i * gridScreenSizeDense + gridOrigin.x;
1356 
1357  // If axes are drawn, skip the lines that would cover them
1358  if( axesEnabled && x == 0 )
1359  continue;
1360 
1361  SetLineWidth( ( i % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1362  VECTOR2D a ( x, gridStartY * gridScreenSizeDense + gridOrigin.y );
1363  VECTOR2D b ( x, gridEndY * gridScreenSizeDense + gridOrigin.y );
1364  DrawLine( a, b );
1365  }
1366 
1368 
1369  if( gridStyle == GRID_STYLE::DOTS )
1370  glDisable( GL_STENCIL_TEST );
1371  }
1372 
1373  glEnable( GL_DEPTH_TEST );
1374  glEnable( GL_TEXTURE_2D );
1375 }
1376 
1377 
1378 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1379 {
1380  screenSize = VECTOR2I( aWidth, aHeight );
1381 
1382  // Resize framebuffers
1383  const float scaleFactor = GetBackingScaleFactor();
1384  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1385  isFramebufferInitialized = false;
1386 
1387  wxGLCanvas::SetSize( aWidth, aHeight );
1388 }
1389 
1390 
1391 bool OPENGL_GAL::Show( bool aShow )
1392 {
1393  bool s = wxGLCanvas::Show( aShow );
1394 
1395  if( aShow )
1396  wxGLCanvas::Raise();
1397 
1398  return s;
1399 }
1400 
1401 
1403 {
1404  glFlush();
1405 }
1406 
1407 
1409 {
1410  // Clear screen
1412  // NOTE: Black used here instead of m_clearColor; it will be composited later
1413  glClearColor( 0, 0, 0, 1 );
1414  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1415 }
1416 
1417 
1418 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1419 {
1420  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1421 
1422  matrixData[0] = aTransformation.m_data[0][0];
1423  matrixData[1] = aTransformation.m_data[1][0];
1424  matrixData[2] = aTransformation.m_data[2][0];
1425  matrixData[4] = aTransformation.m_data[0][1];
1426  matrixData[5] = aTransformation.m_data[1][1];
1427  matrixData[6] = aTransformation.m_data[2][1];
1428  matrixData[12] = aTransformation.m_data[0][2];
1429  matrixData[13] = aTransformation.m_data[1][2];
1430  matrixData[14] = aTransformation.m_data[2][2];
1431 
1432  glMultMatrixd( matrixData );
1433 }
1434 
1435 
1436 void OPENGL_GAL::Rotate( double aAngle )
1437 {
1438  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1439 }
1440 
1441 
1442 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1443 {
1444  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1445 }
1446 
1447 
1448 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1449 {
1450  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1451 }
1452 
1453 
1455 {
1457 }
1458 
1459 
1461 {
1463 }
1464 
1465 
1467 {
1468  isGrouping = true;
1469 
1470  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1471  int groupNumber = getNewGroupNumber();
1472  groups.insert( std::make_pair( groupNumber, newItem ) );
1473 
1474  return groupNumber;
1475 }
1476 
1477 
1479 {
1481  isGrouping = false;
1482 }
1483 
1484 
1485 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1486 {
1487  if( groups[aGroupNumber] )
1488  cachedManager->DrawItem( *groups[aGroupNumber] );
1489 }
1490 
1491 
1492 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1493 {
1494  if( groups[aGroupNumber] )
1495  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1496 }
1497 
1498 
1499 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1500 {
1501  if( groups[aGroupNumber] )
1502  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1503 }
1504 
1505 
1506 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1507 {
1508  // Frees memory in the container as well
1509  groups.erase( aGroupNumber );
1510 }
1511 
1512 
1514 {
1515  bitmapCache.reset( new GL_BITMAP_CACHE );
1516 
1517  groups.clear();
1518 
1519  if( isInitialized )
1520  cachedManager->Clear();
1521 }
1522 
1523 
1525 {
1526  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1527 }
1528 
1529 
1531 {
1532  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1533 }
1534 
1535 
1537 {
1538  switch( aTarget )
1539  {
1540  default:
1541  case TARGET_CACHED:
1543  break;
1544 
1545  case TARGET_NONCACHED:
1547  break;
1548 
1549  case TARGET_OVERLAY:
1551  break;
1552  }
1553 
1554  currentTarget = aTarget;
1555 }
1556 
1557 
1559 {
1560  return currentTarget;
1561 }
1562 
1563 
1565 {
1566  // Save the current state
1567  unsigned int oldTarget = compositor->GetBuffer();
1568 
1569  switch( aTarget )
1570  {
1571  // Cached and noncached items are rendered to the same buffer
1572  default:
1573  case TARGET_CACHED:
1574  case TARGET_NONCACHED:
1576  break;
1577 
1578  case TARGET_OVERLAY:
1580  break;
1581  }
1582 
1583 
1584  if( aTarget != TARGET_OVERLAY )
1586  else
1588 
1589  // Restore the previous state
1590  compositor->SetBuffer( oldTarget );
1591 }
1592 
1593 
1594 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1595 {
1596  // Now we should only store the position of the mouse cursor
1597  // The real drawing routines are in blitCursor()
1598  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1599  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1600  cursorPosition = aCursorPosition;
1601 }
1602 
1603 
1604 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1605 {
1606  /* Helper drawing: ____--- v3 ^
1607  * ____---- ... \ \
1608  * ____---- ... \ end \
1609  * v1 ____---- ... ____---- \ width
1610  * ---- ...___---- \ \
1611  * \ ___...-- \ v
1612  * \ ____----... ____---- v2
1613  * ---- ... ____----
1614  * start \ ... ____----
1615  * \... ____----
1616  * ----
1617  * v0
1618  * dots mark triangles' hypotenuses
1619  */
1620 
1621  auto v1 = currentManager->GetTransformation() * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 );
1622  auto v2 = currentManager->GetTransformation() * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 );
1623 
1624  VECTOR2D vs( v2.x - v1.x, v2.y - v1.y );
1625 
1626  currentManager->Reserve( 6 );
1627 
1628  // Line width is maintained by the vertex shader
1630  currentManager->Vertex( aStartPoint, layerDepth );
1631 
1633  currentManager->Vertex( aStartPoint, layerDepth );
1634 
1636  currentManager->Vertex( aEndPoint, layerDepth );
1637 
1639  currentManager->Vertex( aEndPoint, layerDepth );
1640 
1642  currentManager->Vertex( aEndPoint, layerDepth );
1643 
1645  currentManager->Vertex( aStartPoint, layerDepth );
1646 }
1647 
1648 
1649 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1650 {
1651  if( isFillEnabled )
1652  {
1654  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1655  }
1656 
1657  if( isStrokeEnabled )
1658  {
1660  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1661  }
1662 }
1663 
1664 
1665 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1666  double aAngle )
1667 {
1668  Save();
1669 
1670  currentManager->Reserve( 3 );
1671  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1672  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1673 
1674  /* Draw a triangle that contains the semicircle, then shade it to leave only
1675  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1676  * (if you want to understand more, check the vertex shader source [shader.vert]).
1677  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1678  * v2
1679  * /\
1680  * /__\
1681  * v0 //__\\ v1
1682  */
1684  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1685 
1687  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1688 
1690  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1691 
1692  Restore();
1693 }
1694 
1695 
1696 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1697  double aAngle )
1698 {
1699  double outerRadius = aRadius + ( lineWidth / 2 );
1700 
1701  Save();
1702 
1703  currentManager->Reserve( 3 );
1704  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1705  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1706 
1707  /* Draw a triangle that contains the semicircle, then shade it to leave only
1708  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1709  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1710  * radius and the line width. Shader uses these coordinates to determine if fragments are
1711  * inside the semicircle or not.
1712  * v2
1713  * /\
1714  * /__\
1715  * v0 //__\\ v1
1716  */
1718  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1719 
1721  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1722 
1724  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1725 
1726  Restore();
1727 }
1728 
1729 
1730 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1731 {
1732  if( isFillEnabled )
1733  {
1736 
1737  // Any non convex polygon needs to be tesselated
1738  // for this purpose the GLU standard functions are used
1740  gluTessBeginPolygon( tesselator, &params );
1741  gluTessBeginContour( tesselator );
1742 
1743  GLdouble* point = aPoints;
1744 
1745  for( int i = 0; i < aPointCount; ++i )
1746  {
1747  gluTessVertex( tesselator, point, point );
1748  point += 3; // 3 coordinates
1749  }
1750 
1751  gluTessEndContour( tesselator );
1752  gluTessEndPolygon( tesselator );
1753 
1754  // Free allocated intersecting points
1755  tessIntersects.clear();
1756  }
1757 
1758  if( isStrokeEnabled )
1759  {
1760  drawPolyline( [&](int idx) { return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] ); },
1761  aPointCount );
1762  }
1763 }
1764 
1765 
1766 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D (int)>& aPointGetter, int aPointCount )
1767 {
1768  if( aPointCount < 2 )
1769  return;
1770 
1772  int i;
1773 
1774  for( i = 1; i < aPointCount; ++i )
1775  {
1776  auto start = aPointGetter( i - 1 );
1777  auto end = aPointGetter( i );
1778 
1779  drawLineQuad( start, end );
1780  }
1781 }
1782 
1783 
1784 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1785 {
1786  const float TEX_X = font_image.width;
1787  const float TEX_Y = font_image.height;
1788 
1789  // handle space
1790  if( aChar == ' ' )
1791  {
1792  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1793  wxASSERT( g );
1794  Translate( VECTOR2D( g->advance, 0 ) );
1795  return g->advance;
1796  }
1797 
1798  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1799 
1800  // If the glyph is not found (happens for many esotheric unicode chars)
1801  // shows a '?' instead.
1802  if( !glyph )
1803  glyph = LookupGlyph( '?' );
1804 
1805  if( !glyph ) // Should not happen.
1806  return 0;
1807 
1808  const float X = glyph->atlas_x + font_information.smooth_pixels;
1809  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1810  const float XOFF = glyph->minx;
1811 
1812  // adjust for height rounding
1813  const float round_adjust = ( glyph->maxy - glyph->miny )
1814  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1815  const float top_adjust = font_information.max_y - glyph->maxy;
1816  const float YOFF = round_adjust + top_adjust;
1817  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1818  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1819  const float B = 0;
1820 
1821  currentManager->Reserve( 6 );
1822  Translate( VECTOR2D( XOFF, YOFF ) );
1823  /* Glyph:
1824  * v0 v1
1825  * +--+
1826  * | /|
1827  * |/ |
1828  * +--+
1829  * v2 v3
1830  */
1831  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1832  currentManager->Vertex( -B, -B, 0 ); // v0
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 
1841  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1842  currentManager->Vertex( W + B, -B, 0 ); // v1
1843 
1844  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1845  currentManager->Vertex( -B, H + B, 0 ); // v2
1846 
1847  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1848  currentManager->Vertex( W + B, H + B, 0 ); // v3
1849 
1850  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1851 
1852  return glyph->advance;
1853 }
1854 
1855 
1856 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1857 {
1858  // To draw an overbar, simply draw an overbar
1859  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1860  wxCHECK( glyph, /* void */ );
1861 
1862  const float H = glyph->maxy - glyph->miny;
1863 
1864  Save();
1865 
1866  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1867 
1868  currentManager->Reserve( 6 );
1870 
1871  currentManager->Shader( 0 );
1872 
1873  currentManager->Vertex( 0, 0, 0 ); // v0
1874  currentManager->Vertex( aLength, 0, 0 ); // v1
1875  currentManager->Vertex( 0, H, 0 ); // v2
1876 
1877  currentManager->Vertex( aLength, 0, 0 ); // v1
1878  currentManager->Vertex( 0, H, 0 ); // v2
1879  currentManager->Vertex( aLength, H, 0 ); // v3
1880 
1881  Restore();
1882 }
1883 
1884 
1885 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
1886 {
1887  VECTOR2D textSize( 0, 0 );
1888  float commonOffset = std::numeric_limits<float>::max();
1889  static const auto defaultGlyph = LookupGlyph( '(' ); // for strange chars
1890 
1891  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
1892  {
1893  unsigned int c = *chIt;
1894 
1895  const FONT_GLYPH_TYPE* glyph = LookupGlyph( c );
1896  // Debug: show not coded char in the atlas
1897  // Be carefull before allowing the assert: it usually crash kicad
1898  // when the assert is made during a paint event.
1899  // wxASSERT_MSG( glyph, wxString::Format( "missing char in font: code 0x%x <%c>", c, c ) );
1900 
1901  if( !glyph || // Not coded in font
1902  c == '-' || c == '_' ) // Strange size of these 2 chars
1903  {
1904  glyph = defaultGlyph;
1905  }
1906 
1907  if( glyph )
1908  {
1909  textSize.x += glyph->advance;
1910  }
1911  }
1912 
1913  textSize.y = std::max<float>( textSize.y, font_information.max_y - defaultGlyph->miny );
1914  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
1915  textSize.y -= commonOffset;
1916 
1917  return std::make_pair( textSize, commonOffset );
1918 }
1919 
1920 
1921 void OPENGL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1922 {
1923  PostPaint();
1924 }
1925 
1926 
1927 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1928 {
1929  // Post the mouse event to the event listener registered in constructor, if any
1930  if( mouseListener )
1931  wxPostEvent( mouseListener, aEvent );
1932 }
1933 
1934 
1936 {
1937  if( !IsCursorEnabled() )
1938  return;
1939 
1941 
1942  const int cursorSize = fullscreenCursor ? 8000 : 80;
1943 
1944  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
1945  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
1946  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
1947 
1948  const COLOR4D cColor = getCursorColor();
1949  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
1950  cColor.b * cColor.a, 1.0 );
1951 
1952  glActiveTexture( GL_TEXTURE0 );
1953  glDisable( GL_TEXTURE_2D );
1954  glLineWidth( 1.0 );
1955  glColor4d( color.r, color.g, color.b, color.a );
1956 
1957  glBegin( GL_LINES );
1958  glVertex2d( cursorCenter.x, cursorBegin.y );
1959  glVertex2d( cursorCenter.x, cursorEnd.y );
1960 
1961  glVertex2d( cursorBegin.x, cursorCenter.y );
1962  glVertex2d( cursorEnd.x, cursorCenter.y );
1963  glEnd();
1964 }
1965 
1966 
1968 {
1969  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
1970  wxT( "There are no free slots to store a group" ) );
1971 
1972  while( groups.find( groupCounter ) != groups.end() )
1973  {
1974  groupCounter++;
1975  }
1976 
1977  return groupCounter++;
1978 }
1979 
1980 
1982 {
1983  wxASSERT( IsShownOnScreen() );
1984 
1985  wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." );
1986 
1987  GLenum err = glewInit();
1988 
1989  if( GLEW_OK != err )
1990  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
1991 
1992  // Check the OpenGL version (minimum 2.1 is required)
1993  if( !GLEW_VERSION_2_1 )
1994  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
1995 
1996 #if defined (__LINUX__) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
1997 #ifdef DEBUG
1998  if( GLEW_ARB_debug_output )
1999  enableGlDebug( true );
2000 #endif
2001 #endif
2002 
2003  // Framebuffers have to be supported
2004  if( !GLEW_EXT_framebuffer_object )
2005  throw std::runtime_error( "Framebuffer objects are not supported!" );
2006 
2007  // Vertex buffer has to be supported
2008  if( !GLEW_ARB_vertex_buffer_object )
2009  throw std::runtime_error( "Vertex buffer objects are not supported!" );
2010 
2011  // Prepare shaders
2013  throw std::runtime_error( "Cannot compile vertex shader!" );
2014 
2016  throw std::runtime_error( "Cannot compile fragment shader!" );
2017 
2018  if( !shader->IsLinked() && !shader->Link() )
2019  throw std::runtime_error( "Cannot link the shaders!" );
2020 
2021  // Check if video card supports textures big enough to fit the font atlas
2022  int maxTextureSize;
2023  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
2024 
2025  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height )
2026  {
2027  // TODO implement software texture scaling
2028  // for bitmap fonts and use a higher resolution texture?
2029  throw std::runtime_error( "Requested texture size is not supported" );
2030  }
2031 
2032  cachedManager = new VERTEX_MANAGER( true );
2033  nonCachedManager = new VERTEX_MANAGER( false );
2034  overlayManager = new VERTEX_MANAGER( false );
2035 
2036  // Make VBOs use shaders
2040 
2041  isInitialized = true;
2042 }
2043 
2044 
2045 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
2046 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
2047 {
2048  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
2049  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2050  VERTEX_MANAGER* vboManager = param->vboManager;
2051 
2052  assert( vboManager );
2053  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
2054 }
2055 
2056 
2057 void CALLBACK CombineCallback( GLdouble coords[3],
2058  GLdouble* vertex_data[4],
2059  GLfloat weight[4], GLdouble** dataOut, void* aData )
2060 {
2061  GLdouble* vertex = new GLdouble[3];
2062  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2063 
2064  // Save the pointer so we can delete it later
2065  param->intersectPoints.push_back( boost::shared_array<GLdouble>( vertex ) );
2066 
2067  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
2068 
2069  *dataOut = vertex;
2070 }
2071 
2072 
2073 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
2074 {
2075  // This callback is needed to force GLU tesselator to use triangles only
2076 }
2077 
2078 
2079 void CALLBACK ErrorCallback( GLenum aErrorCode )
2080 {
2081  //throw std::runtime_error( std::string( "Tessellation error: " ) +
2082  //std::string( (const char*) gluErrorString( aErrorCode ) );
2083 }
2084 
2085 
2086 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
2087 {
2088  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
2089  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
2090  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
2091  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
2092 }
2093 
2094 void OPENGL_GAL::EnableDepthTest( bool aEnabled )
2095 {
2096  cachedManager->EnableDepthTest( aEnabled );
2097  nonCachedManager->EnableDepthTest( aEnabled );
2098  overlayManager->EnableDepthTest( aEnabled );
2099 }
2100 
2101 
2102 static double roundr( double f, double r )
2103 {
2104  return floor(f / r + 0.5) * r;
2105 }
2106 
2107 
2109 {
2110  auto pixelSize = worldScale;
2111 
2112  lookAtPoint.x = roundr( lookAtPoint.x, pixelSize );
2113  lookAtPoint.y = roundr( lookAtPoint.y, pixelSize );
2114 
2116 }
2117 
Definition: colors.h:57
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:83
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:303
virtual wxSize GetNativePixelSize() const
float GetLineWidth() const
Get the line width.
virtual void beginUpdate() override
Definition: opengl_gal.cpp:563
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:291
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
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:121
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:311
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:281
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.
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:312
bool isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:320
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:297
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:306
GAL_DISPLAY_OPTIONS & options
int color
Definition: DXF_plotter.cpp:62
VECTOR2D getScreenPixelSize() const
Definition: opengl_gal.cpp:356
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.
std::unique_ptr< GL_BITMAP_CACHE > bitmapCache
Definition: opengl_gal.h:330
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.
static const COLOR4D BLACK
Definition: color4d.h:319
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:921
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const
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:324
double g
Green component.
Definition: color4d.h:310
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:315
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:323
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:45
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:549
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:305
double b
Blue component.
Definition: color4d.h:311
Auxiliary rendering target (noncached)
Definition: definitions.h:49
static int instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:293
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:278
T m_data[3][3]
Definition: matrix3x3.h:64
double getWorldPixelSize() const
Definition: opengl_gal.cpp:349
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:764
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:289
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:46
virtual void endUpdate() override
Definition: opengl_gal.cpp:579
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).
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:312
void Unmap()
Function Unmap() unmaps vertex buffer.
OPENGL_COMPOSITOR * compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:309
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:301
virtual void Present() override
Function Present() Call this to present the output buffer to the screen.
virtual void RestoreScreen() override
Restore the screen contents.
unsigned int mainBuffer
Main rendering target.
Definition: opengl_gal.h:310
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:476
wxEvtHandler * mouseListener
Definition: opengl_gal.h:294
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:588
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:327
virtual void endDrawing() override
Definition: opengl_gal.cpp:504
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:318
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:955
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:539
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:353
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:304
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:898
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:596
GLint ufm_worldPixelSize
Definition: opengl_gal.h:326
std::deque< boost::shared_array< GLdouble > > tessIntersects
Storage for intersecting points.
Definition: opengl_gal.h:355
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: opengl_gal.cpp:698
void CALLBACK ErrorCallback(GLenum aErrorCode)
virtual void SaveScreen() override
Save the screen contents.
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:321
COLOR4D gridColor
Color of the grid.
const int scale
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.h:253
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.
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:302
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:133
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.
wxGLContext * glPrivContext
Canvas-specific OpenGL context.
Definition: opengl_gal.h:292
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:860
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.
double msecs() const
Definition: profile.h:144
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:309
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:363
GLint ufm_pixelSizeMultiplier
Definition: opengl_gal.h:328
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:642
static bool isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:319
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:145
virtual void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Changes the color used to draw the group.
#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.