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