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-2021 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 <advanced_config.h>
38 #include <gal/opengl/opengl_gal.h>
39 #include <gal/opengl/utils.h>
40 #include <gal/definitions.h>
41 #include <gl_context_mgr.h>
43 #include <bitmap_base.h>
44 #include <bezier_curves.h>
45 #include <math/util.h> // for KiROUND
46 #include <trace_helpers.h>
47 
48 #include <wx/frame.h>
49 
50 #include <macros.h>
51 
52 #ifdef KICAD_GAL_PROFILE
53 #include <profile.h>
54 #include <wx/log.h>
55 #endif /* KICAD_GAL_PROFILE */
56 
57 #include <functional>
58 #include <limits>
59 #include <memory>
60 using namespace std::placeholders;
61 using namespace KIGFX;
62 
63 // A ugly workaround to avoid serious issues (crashes) when using bitmaps cache
64 // to speedup redraw.
65 // issues arise when using bitmaps in page layout, when the page layout containd bitmaps,
66 // and is common to schematic and board editor,
67 // and the schematic is a hierarchy and when using cross-probing
68 // When the cross probing from pcbnew to eeschema switches to a sheet, the bitmaps cache
69 // becomes broken (in fact the associated texture).
70 // I hope (JPC) it will be fixed later, but a slightly slower refresh is better than a crash
71 #define DISABLE_BITMAP_CACHE
72 
73 // The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0
74 // (see ubuntu-font-licence-1.0.txt for details)
75 #include "gl_resources.h"
76 #include "gl_builtin_shaders.h"
77 using namespace KIGFX::BUILTIN_FONT;
78 
79 static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
80 static const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 8, 0 };
81 
82 wxGLContext* OPENGL_GAL::m_glMainContext = NULL;
83 int OPENGL_GAL::m_instanceCounter = 0;
84 GLuint OPENGL_GAL::g_fontTexture = 0;
85 bool OPENGL_GAL::m_isBitmapFontLoaded = false;
86 
87 namespace KIGFX
88 {
90 {
91 public:
93 
94  ~GL_BITMAP_CACHE();
95 
96  GLuint RequestBitmap( const BITMAP_BASE* aBitmap );
97 
98 private:
100  {
101  GLuint id;
102  int w, h;
103  };
104 
105  GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
106 
107  std::map<const BITMAP_BASE*, CACHED_BITMAP> m_bitmaps;
108 };
109 
110 }; // namespace KIGFX
111 
112 
113 GL_BITMAP_CACHE::~GL_BITMAP_CACHE()
114 {
115  for( auto& bitmap : m_bitmaps )
116  glDeleteTextures( 1, &bitmap.second.id );
117 }
118 
119 
120 GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
121 {
122  auto it = m_bitmaps.find( aBitmap );
123 
124  if( it != m_bitmaps.end() )
125  {
126  // A bitmap is found in cache bitmap.
127  // Ensure the associated texture is still valid (can be destroyed somewhere)
128  if( glIsTexture( it->second.id ) )
129  return it->second.id;
130 
131  // else if not valid, it will be recreated.
132  }
133 
134  return cacheBitmap( aBitmap );
135 }
136 
137 
138 GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
139 {
140  CACHED_BITMAP bmp;
141 
142  bmp.w = aBitmap->GetSizePixels().x;
143  bmp.h = aBitmap->GetSizePixels().y;
144 
145  // The bitmap size needs to be a multiple of 4.
146  // This is easiest to achieve by ensuring that each row
147  // has a multiple of 4 pixels
148  int extra_w = bmp.w % 4;
149 
150  if( extra_w )
151  extra_w = 4 - extra_w;
152 
153  GLuint textureID;
154  glGenTextures( 1, &textureID );
155 
156  // make_unique initializes this to 0, so extra pixels are transparent
157  auto buf = std::make_unique<uint8_t[]>( ( bmp.w + extra_w ) * bmp.h * 4 );
158  const wxImage& imgData = *aBitmap->GetImageData();
159 
160  for( int y = 0; y < bmp.h; y++ )
161  {
162  for( int x = 0; x < bmp.w; x++ )
163  {
164  uint8_t* p = buf.get() + ( ( bmp.w + extra_w ) * y + x ) * 4;
165 
166  p[0] = imgData.GetRed( x, y );
167  p[1] = imgData.GetGreen( x, y );
168  p[2] = imgData.GetBlue( x, y );
169 
170  if( imgData.HasAlpha() )
171  p[3] = imgData.GetAlpha( x, y );
172  else if( imgData.HasMask() && p[0] == imgData.GetMaskRed()
173  && p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
174  p[3] = wxALPHA_TRANSPARENT;
175  else
176  p[3] = wxALPHA_OPAQUE;
177  }
178  }
179 
180  glBindTexture( GL_TEXTURE_2D, textureID );
181  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w + extra_w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
182  buf.get() );
183 
184  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
185  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
186 
187  bmp.id = textureID;
188 
189 #ifndef DISABLE_BITMAP_CACHE
190  m_bitmaps[aBitmap] = bmp;
191 #endif
192 
193  return textureID;
194 }
195 
196 OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
197  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
198  const wxString& aName ) :
199  GAL( aDisplayOptions ),
200  HIDPI_GL_CANVAS( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
201  wxEXPAND, aName ),
202  m_mouseListener( aMouseListener ),
203  m_paintListener( aPaintListener ),
204  m_currentManager( nullptr ),
205  m_cachedManager( nullptr ),
206  m_nonCachedManager( nullptr ),
207  m_overlayManager( nullptr ),
208  m_mainBuffer( 0 ),
209  m_overlayBuffer( 0 ),
210  m_isContextLocked( false ),
211  m_lockClientCookie( 0 )
212 {
213  if( m_glMainContext == NULL )
214  {
216 
218  }
219  else
220  {
222  }
223 
224  m_shader = new SHADER();
226 
227  m_bitmapCache = std::make_unique<GL_BITMAP_CACHE>();
228 
231 
232  // Initialize the flags
235  m_isInitialized = false;
236  m_isGrouping = false;
237  m_groupCounter = 0;
238 
239  // Connect the native cursor handler
240  Connect( wxEVT_SET_CURSOR, wxSetCursorEventHandler( OPENGL_GAL::onSetNativeCursor ), NULL,
241  this );
242 
243  // Connecting the event handlers
244  Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) );
245 
246  // Mouse events are skipped to the parent
247  Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
248  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
249  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
250  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
251  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
252  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
253  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
254  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
255  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
256  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
257  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
258 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
259  Connect( wxEVT_MAGNIFY, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
260 #endif
261 #if defined _WIN32 || defined _WIN64
262  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
263 #endif
264 
265  SetSize( aParent->GetClientSize() );
267 
268  // Grid color settings are different in Cairo and OpenGL
269  SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) );
270  SetAxesColor( COLOR4D( BLUE ) );
271 
272  // Tesselator initialization
273  m_tesselator = gluNewTess();
275 
276  gluTessProperty( m_tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
277 
279 
280  // Avoid uninitialized variables:
281  ufm_worldPixelSize = 1;
285 }
286 
287 
289 {
291 
293  glFlush();
294  gluDeleteTess( m_tesselator );
295  ClearCache();
296 
297  delete m_compositor;
298 
299  if( m_isInitialized )
300  {
301  delete m_cachedManager;
302  delete m_nonCachedManager;
303  delete m_overlayManager;
304  }
305 
307 
308  // If it was the main context, then it will be deleted
309  // when the last OpenGL GAL instance is destroyed (a few lines below)
312 
313  delete m_shader;
314 
315  // Are we destroying the last GAL instance?
316  if( m_instanceCounter == 0 )
317  {
319 
321  {
322  glDeleteTextures( 1, &g_fontTexture );
323  m_isBitmapFontLoaded = false;
324  }
325 
329  }
330 }
331 
332 
334 {
335  wxString retVal = wxEmptyString;
336 
337  wxFrame* testFrame = new wxFrame( NULL, wxID_ANY, wxT( "" ), wxDefaultPosition, wxSize( 1, 1 ),
338  wxFRAME_TOOL_WINDOW | wxNO_BORDER );
339 
340  KIGFX::OPENGL_GAL* opengl_gal = nullptr;
341 
342  try
343  {
344  opengl_gal = new KIGFX::OPENGL_GAL( aOptions, testFrame );
345 
346  testFrame->Raise();
347  testFrame->Show();
348 
349  GAL_CONTEXT_LOCKER lock( opengl_gal );
350  opengl_gal->init();
351  }
352  catch( std::runtime_error& err )
353  {
354  //Test failed
355  retVal = wxString( err.what() );
356  }
357 
358  delete opengl_gal;
359  delete testFrame;
360 
361  return retVal;
362 }
363 
364 
365 void OPENGL_GAL::PostPaint( wxPaintEvent& aEvent )
366 {
367  // posts an event to m_paint_listener to ask for redraw the canvas.
368  if( m_paintListener )
369  wxPostEvent( m_paintListener, aEvent );
370 }
371 
372 
374 {
375  bool refresh = false;
376 
378  {
381  refresh = true;
382  }
383 
385  {
387  refresh = true;
388  }
389 
390  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
391  {
392  Refresh();
393  refresh = true;
394  }
395 
396  return refresh;
397 }
398 
399 
401 {
402  MATRIX3x3D matrix = GetScreenWorldMatrix();
403  return std::min( std::abs( matrix.GetScale().x ), std::abs( matrix.GetScale().y ) );
404 }
405 
406 
408 {
409  double sf = GetScaleFactor();
410  return VECTOR2D( 2.0 / (double) ( m_screenSize.x * sf ), 2.0 / (double) ( m_screenSize.y * sf ) );
411 }
412 
413 
415 {
416 #ifdef KICAD_GAL_PROFILE
417  PROF_COUNTER totalRealTime( "OPENGL_GAL::beginDrawing()", true );
418 #endif /* KICAD_GAL_PROFILE */
419 
420  wxASSERT_MSG( m_isContextLocked, "GAL_DRAWING_CONTEXT RAII object should have locked context. "
421  "Calling GAL::beginDrawing() directly is not allowed." );
422 
423  wxASSERT_MSG( IsVisible(), "GAL::beginDrawing() must not be entered when GAL is not visible. "
424  "Other drawing routines will expect everything to be initialized "
425  "which will not be the case." );
426 
427  if( !m_isInitialized )
428  init();
429 
430  // Set up the view port
431  glMatrixMode( GL_PROJECTION );
432  glLoadIdentity();
433 
434  // Create the screen transformation (Do the RH-LH conversion here)
435  glOrtho( 0, (GLint) m_screenSize.x, (GLsizei) m_screenSize.y, 0,
437 
439  {
440  // Prepare rendering target buffers
443  try
444  {
446  }
447  catch( const std::runtime_error& )
448  {
449  wxLogVerbose( "Could not create a framebuffer for overlays.\n" );
450  m_overlayBuffer = 0;
451  }
453  }
454 
455  m_compositor->Begin();
456 
457  // Disable 2D Textures
458  glDisable( GL_TEXTURE_2D );
459 
460  glShadeModel( GL_FLAT );
461 
462  // Enable the depth buffer
463  glEnable( GL_DEPTH_TEST );
464  glDepthFunc( GL_LESS );
465 
466  // Setup blending, required for transparent objects
467  glEnable( GL_BLEND );
468  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
469 
470  glMatrixMode( GL_MODELVIEW );
471 
472  // Set up the world <-> screen transformation
474  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
475  matrixData[0] = m_worldScreenMatrix.m_data[0][0];
476  matrixData[1] = m_worldScreenMatrix.m_data[1][0];
477  matrixData[2] = m_worldScreenMatrix.m_data[2][0];
478  matrixData[4] = m_worldScreenMatrix.m_data[0][1];
479  matrixData[5] = m_worldScreenMatrix.m_data[1][1];
480  matrixData[6] = m_worldScreenMatrix.m_data[2][1];
481  matrixData[12] = m_worldScreenMatrix.m_data[0][2];
482  matrixData[13] = m_worldScreenMatrix.m_data[1][2];
483  matrixData[14] = m_worldScreenMatrix.m_data[2][2];
484  glLoadMatrixd( matrixData );
485 
486  // Set defaults
489 
490  // Remove all previously stored items
493 
497 
499  {
500  // Keep bitmap font texture always bound to the second texturing unit
501  const GLint FONT_TEXTURE_UNIT = 2;
502 
503  // Either load the font atlas to video memory, or simply bind it to a texture unit
504  if( !m_isBitmapFontLoaded )
505  {
506  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
507  glGenTextures( 1, &g_fontTexture );
508  glBindTexture( GL_TEXTURE_2D, g_fontTexture );
509  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height, 0, GL_RGB,
510  GL_UNSIGNED_BYTE, font_image.pixels );
511  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
512  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
513  checkGlError( "loading bitmap font", __FILE__, __LINE__ );
514 
515  glActiveTexture( GL_TEXTURE0 );
516 
517  m_isBitmapFontLoaded = true;
518  }
519  else
520  {
521  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
522  glBindTexture( GL_TEXTURE_2D, g_fontTexture );
523  glActiveTexture( GL_TEXTURE0 );
524  }
525 
526  // Set shader parameter
527  GLint ufm_fontTexture = m_shader->AddParameter( "fontTexture" );
528  GLint ufm_fontTextureWidth = m_shader->AddParameter( "fontTextureWidth" );
529  ufm_worldPixelSize = m_shader->AddParameter( "worldPixelSize" );
530  ufm_screenPixelSize = m_shader->AddParameter( "screenPixelSize" );
531  ufm_pixelSizeMultiplier = m_shader->AddParameter( "pixelSizeMultiplier" );
532  ufm_antialiasingOffset = m_shader->AddParameter( "antialiasingOffset" );
533 
534  m_shader->Use();
535  m_shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
536  m_shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
537  m_shader->Deactivate();
538  checkGlError( "setting bitmap font sampler as shader parameter", __FILE__, __LINE__ );
539 
541  }
542 
543  m_shader->Use();
545  (float) ( getWorldPixelSize() / GetScaleFactor() ) );
546  const VECTOR2D& screenPixelSize = getScreenPixelSize();
547  m_shader->SetParameter( ufm_screenPixelSize, screenPixelSize );
548  double pixelSizeMultiplier = m_compositor->GetAntialiasSupersamplingFactor();
549  m_shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
551  renderingOffset.x *= screenPixelSize.x;
552  renderingOffset.y *= screenPixelSize.y;
553  m_shader->SetParameter( ufm_antialiasingOffset, renderingOffset );
554  m_shader->Deactivate();
555 
556  // Something betreen BeginDrawing and EndDrawing seems to depend on
557  // this texture unit being active, but it does not assure it itself.
558  glActiveTexture( GL_TEXTURE0 );
559 
560  // Unbind buffers - set compositor for direct drawing
562 
563 #ifdef KICAD_GAL_PROFILE
564  totalRealTime.Stop();
565  wxLogTrace( traceGalProfile, wxT( "OPENGL_GAL::beginDrawing(): %.1f ms" ),
566  totalRealTime.msecs() );
567 #endif /* KICAD_GAL_PROFILE */
568 }
569 
570 
572 {
573  wxASSERT_MSG( m_isContextLocked, "What happened to the context lock?" );
574 
575 #ifdef KICAD_GAL_PROFILE
576  PROF_COUNTER totalRealTime( "OPENGL_GAL::endDrawing()", true );
577 #endif /* KICAD_GAL_PROFILE */
578 
579  // Cached & non-cached containers are rendered to the same buffer
583 
584  // Overlay container is rendered to a different buffer
585  if( m_overlayBuffer )
587 
589 
590  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
591  glColor4d( 1.0, 1.0, 1.0, 1.0 );
592 
593  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
595 
596  if( m_overlayBuffer )
598 
600  blitCursor();
601 
602  SwapBuffers();
603 
604 #ifdef KICAD_GAL_PROFILE
605  totalRealTime.Stop();
606  wxLogTrace( traceGalProfile, wxT( "OPENGL_GAL::endDrawing(): %.1f ms" ),
607  totalRealTime.msecs() );
608 #endif /* KICAD_GAL_PROFILE */
609 }
610 
611 
612 void OPENGL_GAL::lockContext( int aClientCookie )
613 {
614  wxASSERT_MSG( !m_isContextLocked, "Context already locked." );
615  m_isContextLocked = true;
616  m_lockClientCookie = aClientCookie;
617 
619 }
620 
621 
622 void OPENGL_GAL::unlockContext( int aClientCookie )
623 {
624  wxASSERT_MSG( m_isContextLocked, "Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
625  "be stacked rather than making separate lock/unlock calls." );
626 
627  wxASSERT_MSG( m_lockClientCookie == aClientCookie, "Context was locked by a different client. "
628  "Should not be possible with RAII objects." );
629 
630  m_isContextLocked = false;
631 
633 }
634 
635 
637 {
638  wxASSERT_MSG( m_isContextLocked, "GAL_UPDATE_CONTEXT RAII object should have locked context. "
639  "Calling this from anywhere else is not allowed." );
640 
641  wxASSERT_MSG( IsVisible(), "GAL::beginUpdate() must not be entered when GAL is not visible. "
642  "Other update routines will expect everything to be initialized "
643  "which will not be the case." );
644 
645  if( !m_isInitialized )
646  init();
647 
648  m_cachedManager->Map();
649 }
650 
651 
653 {
654  if( !m_isInitialized )
655  return;
656 
658 }
659 
660 
661 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
662 {
664 
665  drawLineQuad( aStartPoint, aEndPoint );
666 }
667 
668 
669 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
670  double aWidth )
671 {
672  VECTOR2D startEndVector = aEndPoint - aStartPoint;
673  double lineLength = startEndVector.EuclideanNorm();
674 
675  float startx = aStartPoint.x;
676  float starty = aStartPoint.y;
677  float endx = aStartPoint.x + lineLength;
678  float endy = aStartPoint.y + lineLength;
679 
680  // Be careful about floating point rounding. As we draw segments in larger and larger
681  // coordinates, the shader (which uses floats) will lose precision and stop drawing small
682  // segments. In this case, we need to draw a circle for the minimal segment.
683  if( startx == endx || starty == endy )
684  {
685  DrawCircle( aStartPoint, aWidth / 2 );
686  return;
687  }
688 
689  if( m_isFillEnabled || aWidth == 1.0 )
690  {
692 
693  SetLineWidth( aWidth );
694  drawLineQuad( aStartPoint, aEndPoint );
695  }
696  else
697  {
698  auto lineAngle = startEndVector.Angle();
699  // Outlined tracks
700 
701  SetLineWidth( 1.0 );
703  m_strokeColor.a );
704 
705  Save();
706 
707  m_currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
708  m_currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
709 
710  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), VECTOR2D( lineLength, aWidth / 2.0 ) );
711 
712  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ), VECTOR2D( lineLength, -aWidth / 2.0 ) );
713 
714  // Draw line caps
715  drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
716  drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );
717 
718  Restore();
719  }
720 }
721 
722 
723 void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
724 {
725  if( m_isFillEnabled )
726  {
729 
730  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
731  * Parameters given to Shader() are indices of the triangle's vertices
732  * (if you want to understand more, check the vertex shader source [shader.vert]).
733  * Shader uses this coordinates to determine if fragments are inside the circle or not.
734  * Does the calculations in the vertex shader now (pixel alignment)
735  * v2
736  * /\
737  * //\\
738  * v0 /_\/_\ v1
739  */
740  m_currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0, aRadius );
741  m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
742 
743  m_currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0, aRadius );
744  m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
745 
746  m_currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0, aRadius );
747  m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
748  }
749  if( m_isStrokeEnabled )
750  {
753  m_strokeColor.a );
754 
755  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
756  * Parameters given to Shader() are indices of the triangle's vertices
757  * (if you want to understand more, check the vertex shader source [shader.vert]).
758  * and the line width. Shader uses this coordinates to determine if fragments are
759  * inside the circle or not.
760  * v2
761  * /\
762  * //\\
763  * v0 /_\/_\ v1
764  */
766  m_currentManager->Vertex( aCenterPoint.x, // v0
767  aCenterPoint.y, m_layerDepth );
768 
770  m_currentManager->Vertex( aCenterPoint.x, // v1
771  aCenterPoint.y, m_layerDepth );
772 
774  m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, // v2
775  m_layerDepth );
776  }
777 }
778 
779 
780 void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
781  double aEndAngle )
782 {
783  if( aRadius <= 0 )
784  return;
785 
786  // Swap the angles, if start angle is greater than end angle
787  SWAP( aStartAngle, >, aEndAngle );
788 
789  const double alphaIncrement = calcAngleStep( aRadius );
790 
791  Save();
792  m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
793 
794  if( m_isFillEnabled )
795  {
796  double alpha;
799 
800  // Triangle fan
801  for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
802  {
804  m_currentManager->Vertex( 0.0, 0.0, m_layerDepth );
805  m_currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius,
806  m_layerDepth );
807  alpha += alphaIncrement;
808  m_currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius,
809  m_layerDepth );
810  }
811 
812  // The last missing triangle
813  const VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
814 
816  m_currentManager->Vertex( 0.0, 0.0, m_layerDepth );
817  m_currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, m_layerDepth );
818  m_currentManager->Vertex( endPoint.x, endPoint.y, m_layerDepth );
819  }
820 
821  if( m_isStrokeEnabled )
822  {
824  m_strokeColor.a );
825 
826  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
827  double alpha;
828 
829  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
830  {
831  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
832  DrawLine( p, p_next );
833 
834  p = p_next;
835  }
836 
837  // Draw the last missing part
838  if( alpha != aEndAngle )
839  {
840  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
841  DrawLine( p, p_last );
842  }
843  }
844 
845  Restore();
846 }
847 
848 
849 void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
850  double aEndAngle, double aWidth )
851 {
852  if( aRadius <= 0 )
853  {
854  // Arcs of zero radius are a circle of aWidth diameter
855  if( aWidth > 0 )
856  DrawCircle( aCenterPoint, aWidth / 2.0 );
857 
858  return;
859  }
860 
861  // Swap the angles, if start angle is greater than end angle
862  SWAP( aStartAngle, >, aEndAngle );
863 
864  double alphaIncrement = calcAngleStep( aRadius );
865 
866  // Refinement: Use a segment count multiple of 2, because we have a control point
867  // on the middle of the arc, and the look is better if it is on a segment junction
868  // because there is no approx error
869  int seg_count = KiROUND( ( aEndAngle - aStartAngle ) / alphaIncrement );
870 
871  if( seg_count % 2 != 0 )
872  seg_count += 1;
873 
874  // Recalculate alphaIncrement with a even integer number of segment
875  if( seg_count )
876  alphaIncrement = ( aEndAngle - aStartAngle ) / seg_count;
877 
878  Save();
879  m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
880 
881  if( m_isStrokeEnabled )
882  {
884  m_strokeColor.a );
885 
886  double width = aWidth / 2.0;
887  VECTOR2D startPoint( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
888  VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
889 
890  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
891  drawStrokedSemiCircle( endPoint, width, aEndAngle );
892 
893  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
894  sin( aStartAngle ) * ( aRadius + width ) );
895 
896  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
897  sin( aStartAngle ) * ( aRadius - width ) );
898 
899  double alpha;
900 
901  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
902  {
903  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
904  sin( alpha ) * ( aRadius + width ) );
905  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
906  sin( alpha ) * ( aRadius - width ) );
907 
908  DrawLine( pOuter, pNextOuter );
909  DrawLine( pInner, pNextInner );
910 
911  pOuter = pNextOuter;
912  pInner = pNextInner;
913  }
914 
915  // Draw the last missing part
916  if( alpha != aEndAngle )
917  {
918  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
919  sin( aEndAngle ) * ( aRadius + width ) );
920  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
921  sin( aEndAngle ) * ( aRadius - width ) );
922 
923  DrawLine( pOuter, pLastOuter );
924  DrawLine( pInner, pLastInner );
925  }
926  }
927 
928  if( m_isFillEnabled )
929  {
931  SetLineWidth( aWidth );
932 
933  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
934  double alpha;
935 
936  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
937  {
938  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
939  DrawLine( p, p_next );
940 
941  p = p_next;
942  }
943 
944  // Draw the last missing part
945  if( alpha != aEndAngle )
946  {
947  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
948  DrawLine( p, p_last );
949  }
950  }
951 
952  Restore();
953 }
954 
955 
956 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
957 {
958  // Compute the diagonal points of the rectangle
959  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
960  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
961 
962  // Fill the rectangle
963  if( m_isFillEnabled )
964  {
968 
969  m_currentManager->Vertex( aStartPoint.x, aStartPoint.y, m_layerDepth );
970  m_currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, m_layerDepth );
971  m_currentManager->Vertex( aEndPoint.x, aEndPoint.y, m_layerDepth );
972 
973  m_currentManager->Vertex( aStartPoint.x, aStartPoint.y, m_layerDepth );
974  m_currentManager->Vertex( aEndPoint.x, aEndPoint.y, m_layerDepth );
975  m_currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, m_layerDepth );
976  }
977 
978  // Stroke the outline
979  if( m_isStrokeEnabled )
980  {
982  m_strokeColor.a );
983 
984  std::deque<VECTOR2D> pointList;
985  pointList.push_back( aStartPoint );
986  pointList.push_back( diagonalPointA );
987  pointList.push_back( aEndPoint );
988  pointList.push_back( diagonalPointB );
989  pointList.push_back( aStartPoint );
990  DrawPolyline( pointList );
991  }
992 }
993 
994 
995 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
996 {
997  drawPolyline(
998  [&]( int idx )
999  {
1000  return aPointList[idx];
1001  },
1002  aPointList.size() );
1003 }
1004 
1005 
1006 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
1007 {
1008  drawPolyline(
1009  [&]( int idx )
1010  {
1011  return aPointList[idx];
1012  },
1013  aListSize );
1014 }
1015 
1016 
1018 {
1019  auto numPoints = aLineChain.PointCount();
1020 
1021  if( aLineChain.IsClosed() )
1022  numPoints += 1;
1023 
1024  drawPolyline(
1025  [&]( int idx )
1026  {
1027  return aLineChain.CPoint( idx );
1028  },
1029  numPoints );
1030 }
1031 
1032 
1033 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
1034 {
1035  wxCHECK( aPointList.size() >= 2, /* void */ );
1036  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
1037  GLdouble* ptr = points.get();
1038 
1039  for( const VECTOR2D& p : aPointList )
1040  {
1041  *ptr++ = p.x;
1042  *ptr++ = p.y;
1043  *ptr++ = m_layerDepth;
1044  }
1045 
1046  drawPolygon( points.get(), aPointList.size() );
1047 }
1048 
1049 
1050 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
1051 {
1052  wxCHECK( aListSize >= 2, /* void */ );
1053  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
1054  GLdouble* target = points.get();
1055  const VECTOR2D* src = aPointList;
1056 
1057  for( int i = 0; i < aListSize; ++i )
1058  {
1059  *target++ = src->x;
1060  *target++ = src->y;
1061  *target++ = m_layerDepth;
1062  ++src;
1063  }
1064 
1065  drawPolygon( points.get(), aListSize );
1066 }
1067 
1068 
1070 {
1073 
1074  if( m_isFillEnabled )
1075  {
1076  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
1077  {
1078  auto triPoly = aPolySet.TriangulatedPolygon( j );
1079 
1080  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1081  {
1082  VECTOR2I a, b, c;
1083  triPoly->GetTriangle( i, a, b, c );
1087  }
1088  }
1089  }
1090 
1091  if( m_isStrokeEnabled )
1092  {
1093  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1094  {
1095  const auto& poly = aPolySet.Polygon( j );
1096 
1097  for( const auto& lc : poly )
1098  {
1099  DrawPolyline( lc );
1100  }
1101  }
1102  }
1103 
1104  if( ADVANCED_CFG::GetCfg().m_DrawTriangulationOutlines )
1105  {
1106  COLOR4D oldStrokeColor = m_strokeColor;
1107  double oldLayerDepth = m_layerDepth;
1108 
1109  SetLayerDepth( m_layerDepth - 1 );
1110  SetStrokeColor( COLOR4D( 0.0, 1.0, 0.2, 1.0 ) );
1111 
1112  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
1113  {
1114  auto triPoly = aPolySet.TriangulatedPolygon( j );
1115 
1116  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1117  {
1118  VECTOR2I a, b, c;
1119  triPoly->GetTriangle( i, a, b, c );
1120  DrawLine( a, b );
1121  DrawLine( b, c );
1122  DrawLine( c, a );
1123  }
1124  }
1125 
1126  SetStrokeColor( oldStrokeColor );
1127  SetLayerDepth( oldLayerDepth );
1128  }
1129 }
1130 
1131 
1133 {
1134  if( aPolySet.IsTriangulationUpToDate() )
1135  {
1136  drawTriangulatedPolyset( aPolySet );
1137  return;
1138  }
1139 
1140  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1141  {
1142  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
1143  DrawPolygon( outline );
1144  }
1145 }
1146 
1147 
1149 {
1150  wxCHECK( aPolygon.PointCount() >= 2, /* void */ );
1151 
1152  const int pointCount = aPolygon.SegmentCount() + 1;
1153  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
1154  GLdouble* ptr = points.get();
1155 
1156  for( int i = 0; i < pointCount; ++i )
1157  {
1158  const VECTOR2I& p = aPolygon.CPoint( i );
1159  *ptr++ = p.x;
1160  *ptr++ = p.y;
1161  *ptr++ = m_layerDepth;
1162  }
1163 
1164  drawPolygon( points.get(), pointCount );
1165 }
1166 
1167 
1168 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
1169  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint,
1170  double aFilterValue )
1171 {
1172  std::vector<VECTOR2D> output;
1173  std::vector<VECTOR2D> pointCtrl;
1174 
1175  pointCtrl.push_back( aStartPoint );
1176  pointCtrl.push_back( aControlPointA );
1177  pointCtrl.push_back( aControlPointB );
1178  pointCtrl.push_back( aEndPoint );
1179 
1180  BEZIER_POLY converter( pointCtrl );
1181  converter.GetPoly( output, aFilterValue );
1182 
1183  DrawPolyline( &output[0], output.size() );
1184 }
1185 
1186 
1187 void OPENGL_GAL::DrawBitmap( const BITMAP_BASE& aBitmap )
1188 {
1189  // We have to calculate the pixel size in users units to draw the image.
1190  // m_worldUnitLength is a factor used for converting IU to inches
1191  double scale = 1.0 / ( aBitmap.GetPPI() * m_worldUnitLength );
1192  double w = (double) aBitmap.GetSizePixels().x * scale;
1193  double h = (double) aBitmap.GetSizePixels().y * scale;
1194 
1195  auto xform = m_currentManager->GetTransformation();
1196 
1197  glm::vec4 v0 = xform * glm::vec4( -w / 2, -h / 2, 0.0, 0.0 );
1198  glm::vec4 v1 = xform * glm::vec4( w / 2, h / 2, 0.0, 0.0 );
1199  glm::vec4 trans = xform[3];
1200 
1201  auto texture_id = m_bitmapCache->RequestBitmap( &aBitmap );
1202 
1203  if( !glIsTexture( texture_id ) ) // ensure the bitmap texture is still valid
1204  return;
1205 
1206  auto oldTarget = GetTarget();
1207 
1208  glPushMatrix();
1209  glTranslated( trans.x, trans.y, trans.z );
1210 
1212  glEnable( GL_TEXTURE_2D );
1213  glActiveTexture( GL_TEXTURE0 );
1214  glBindTexture( GL_TEXTURE_2D, texture_id );
1215 
1216  glBegin( GL_QUADS );
1217  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1218  glTexCoord2f( 0.0, 0.0 );
1219  glVertex3f( v0.x, v0.y, m_layerDepth );
1220  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1221  glTexCoord2f( 1.0, 0.0 );
1222  glVertex3f( v1.x, v0.y, m_layerDepth );
1223  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1224  glTexCoord2f( 1.0, 1.0 );
1225  glVertex3f( v1.x, v1.y, m_layerDepth );
1226  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1227  glTexCoord2f( 0.0, 1.0 );
1228  glVertex3f( v0.x, v1.y, m_layerDepth );
1229  glEnd();
1230 
1231  SetTarget( oldTarget );
1232  glBindTexture( GL_TEXTURE_2D, 0 );
1233 
1234 #ifdef DISABLE_BITMAP_CACHE
1235  glDeleteTextures( 1, &texture_id );
1236 #endif
1237 
1238  glPopMatrix();
1239 }
1240 
1241 
1242 void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
1243  double aRotationAngle )
1244 {
1245  // Fallback to generic impl (which uses the stroke font) on cases we don't handle
1246  if( IsTextMirrored() || aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) ) )
1247  return GAL::BitmapText( aText, aPosition, aRotationAngle );
1248 
1249  const UTF8 text( aText );
1250  VECTOR2D textSize;
1251  float commonOffset;
1252  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
1253 
1254  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
1255  int overbarLength = 0;
1256  double overbarHeight = textSize.y;
1257 
1258  Save();
1259 
1261  m_currentManager->Translate( aPosition.x, aPosition.y, m_layerDepth );
1262  m_currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
1263 
1264  double sx = SCALE * ( m_globalFlipX ? -1.0 : 1.0 );
1265  double sy = SCALE * ( m_globalFlipY ? -1.0 : 1.0 );
1266 
1267  m_currentManager->Scale( sx, sy, 0 );
1268  m_currentManager->Translate( 0, -commonOffset, 0 );
1269 
1270  switch( GetHorizontalJustify() )
1271  {
1273  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
1274  break;
1275 
1277  //if( !IsTextMirrored() )
1278  Translate( VECTOR2D( -textSize.x, 0 ) );
1279  break;
1280 
1281  case GR_TEXT_HJUSTIFY_LEFT:
1282  //if( IsTextMirrored() )
1283  //Translate( VECTOR2D( -textSize.x, 0 ) );
1284  break;
1285  }
1286 
1287  switch( GetVerticalJustify() )
1288  {
1289  case GR_TEXT_VJUSTIFY_TOP:
1290  Translate( VECTOR2D( 0, -textSize.y ) );
1291  overbarHeight = -textSize.y / 2.0;
1292  break;
1293 
1295  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
1296  overbarHeight = 0;
1297  break;
1298 
1300  break;
1301  }
1302 
1303  int overbarDepth = -1;
1304  int braceNesting = 0;
1305 
1306  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
1307  {
1308  wxASSERT_MSG( *chIt != '\n' && *chIt != '\r',
1309  wxT( "No support for multiline bitmap text yet" ) );
1310 
1311  if( *chIt == '~' && overbarDepth == -1 )
1312  {
1313  UTF8::uni_iter lookahead = chIt;
1314 
1315  if( ++lookahead != end && *lookahead == '{' )
1316  {
1317  chIt = lookahead;
1318  overbarDepth = braceNesting;
1319  braceNesting++;
1320  continue;
1321  }
1322  }
1323  else if( *chIt == '{' )
1324  {
1325  braceNesting++;
1326  }
1327  else if( *chIt == '}' )
1328  {
1329  if( braceNesting > 0 )
1330  braceNesting--;
1331 
1332  if( braceNesting == overbarDepth )
1333  {
1334  drawBitmapOverbar( overbarLength, overbarHeight );
1335  overbarLength = 0;
1336 
1337  overbarDepth = -1;
1338  continue;
1339  }
1340  }
1341 
1342  if( overbarDepth != -1 )
1343  overbarLength += drawBitmapChar( *chIt );
1344  else
1345  drawBitmapChar( *chIt );
1346  }
1347 
1348  // Handle the case when overbar is active till the end of the drawn text
1349  m_currentManager->Translate( 0, commonOffset, 0 );
1350 
1351  if( overbarDepth != -1 && overbarLength > 0 )
1352  drawBitmapOverbar( overbarLength, overbarHeight );
1353 
1354  Restore();
1355 }
1356 
1357 
1359 {
1362 
1364 
1365  // sub-pixel lines all render the same
1366  float minorLineWidth = std::fmax( 1.0f,
1368  float majorLineWidth = minorLineWidth * 2.0f;
1369 
1370  // Draw the axis and grid
1371  // For the drawing the start points, end points and increments have
1372  // to be calculated in world coordinates
1373  VECTOR2D worldStartPoint = m_screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1374  VECTOR2D worldEndPoint = m_screenWorldMatrix * VECTOR2D( m_screenSize );
1375 
1376  // Draw axes if desired
1377  if( m_axesEnabled )
1378  {
1379  SetLineWidth( minorLineWidth );
1381 
1382  DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) );
1383  DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) );
1384  }
1385 
1386  // force flush
1388 
1389  if( !m_gridVisibility || m_gridSize.x == 0 || m_gridSize.y == 0 )
1390  return;
1391 
1392  VECTOR2D gridScreenSize( m_gridSize );
1393 
1394  double gridThreshold = computeMinGridSpacing() / m_worldScale;
1395 
1397  gridThreshold *= 2.0;
1398 
1399  // If we cannot display the grid density, scale down by a tick size and
1400  // try again. Eventually, we get some representation of the grid
1401  while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold )
1402  {
1403  gridScreenSize = gridScreenSize * static_cast<double>( m_gridTick );
1404  }
1405 
1406  // Compute grid starting and ending indexes to draw grid points on the
1407  // visible screen area
1408  // Note: later any point coordinate will be offsetted by m_gridOrigin
1409  int gridStartX = KiROUND( ( worldStartPoint.x - m_gridOrigin.x ) / gridScreenSize.x );
1410  int gridEndX = KiROUND( ( worldEndPoint.x - m_gridOrigin.x ) / gridScreenSize.x );
1411  int gridStartY = KiROUND( ( worldStartPoint.y - m_gridOrigin.y ) / gridScreenSize.y );
1412  int gridEndY = KiROUND( ( worldEndPoint.y - m_gridOrigin.y ) / gridScreenSize.y );
1413 
1414  // Ensure start coordinate > end coordinate
1415  SWAP( gridStartX, >, gridEndX );
1416  SWAP( gridStartY, >, gridEndY );
1417 
1418  // Ensure the grid fills the screen
1419  --gridStartX;
1420  ++gridEndX;
1421  --gridStartY;
1422  ++gridEndY;
1423 
1424  glDisable( GL_DEPTH_TEST );
1425  glDisable( GL_TEXTURE_2D );
1426 
1427  if( m_gridStyle == GRID_STYLE::DOTS )
1428  {
1429  glEnable( GL_STENCIL_TEST );
1430  glStencilFunc( GL_ALWAYS, 1, 1 );
1431  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1432  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1433  SetStrokeColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
1434  }
1435  else
1436  {
1437  glColor4d( m_gridColor.r, m_gridColor.g, m_gridColor.b, m_gridColor.a );
1439  }
1440 
1442  {
1443  // Vertical positions
1444  for( int j = gridStartY; j <= gridEndY; j++ )
1445  {
1446  bool tickY = ( j % m_gridTick == 0 );
1447  const double posY = j * gridScreenSize.y + m_gridOrigin.y;
1448 
1449  // Horizontal positions
1450  for( int i = gridStartX; i <= gridEndX; i++ )
1451  {
1452  bool tickX = ( i % m_gridTick == 0 );
1453  SetLineWidth( ( ( tickX && tickY ) ? majorLineWidth : minorLineWidth ) );
1454  auto lineLen = 2.0 * GetLineWidth();
1455  auto posX = i * gridScreenSize.x + m_gridOrigin.x;
1456 
1457  DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) );
1458  DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) );
1459  }
1460  }
1461 
1463  }
1464  else
1465  {
1466  // Vertical lines
1467  for( int j = gridStartY; j <= gridEndY; j++ )
1468  {
1469  const double y = j * gridScreenSize.y + m_gridOrigin.y;
1470 
1471  // If axes are drawn, skip the lines that would cover them
1472  if( m_axesEnabled && y == 0.0 )
1473  continue;
1474 
1475  SetLineWidth( ( j % m_gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1476  VECTOR2D a( gridStartX * gridScreenSize.x + m_gridOrigin.x, y );
1477  VECTOR2D b( gridEndX * gridScreenSize.x + m_gridOrigin.x, y );
1478 
1479  DrawLine( a, b );
1480  }
1481 
1483 
1484  if( m_gridStyle == GRID_STYLE::DOTS )
1485  {
1486  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1487  glColor4d( m_gridColor.r, m_gridColor.g, m_gridColor.b, m_gridColor.a );
1489  }
1490 
1491  // Horizontal lines
1492  for( int i = gridStartX; i <= gridEndX; i++ )
1493  {
1494  const double x = i * gridScreenSize.x + m_gridOrigin.x;
1495 
1496  // If axes are drawn, skip the lines that would cover them
1497  if( m_axesEnabled && x == 0.0 )
1498  continue;
1499 
1500  SetLineWidth( ( i % m_gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1501  VECTOR2D a( x, gridStartY * gridScreenSize.y + m_gridOrigin.y );
1502  VECTOR2D b( x, gridEndY * gridScreenSize.y + m_gridOrigin.y );
1503  DrawLine( a, b );
1504  }
1505 
1507 
1508  if( m_gridStyle == GRID_STYLE::DOTS )
1509  glDisable( GL_STENCIL_TEST );
1510  }
1511 
1512  glEnable( GL_DEPTH_TEST );
1513  glEnable( GL_TEXTURE_2D );
1514 }
1515 
1516 
1517 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1518 {
1519  m_screenSize = VECTOR2I( aWidth, aHeight );
1520 
1521  // Resize framebuffers
1522  const float scaleFactor = GetScaleFactor();
1523  m_compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1525 
1526  wxGLCanvas::SetSize( aWidth, aHeight );
1527 }
1528 
1529 
1530 bool OPENGL_GAL::Show( bool aShow )
1531 {
1532  bool s = wxGLCanvas::Show( aShow );
1533 
1534  if( aShow )
1535  wxGLCanvas::Raise();
1536 
1537  return s;
1538 }
1539 
1540 
1542 {
1543  glFlush();
1544 }
1545 
1546 
1548 {
1549  // Clear screen
1551 
1552  // NOTE: Black used here instead of m_clearColor; it will be composited later
1553  glClearColor( 0, 0, 0, 1 );
1554  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1555 }
1556 
1557 
1558 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1559 {
1560  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1561 
1562  matrixData[0] = aTransformation.m_data[0][0];
1563  matrixData[1] = aTransformation.m_data[1][0];
1564  matrixData[2] = aTransformation.m_data[2][0];
1565  matrixData[4] = aTransformation.m_data[0][1];
1566  matrixData[5] = aTransformation.m_data[1][1];
1567  matrixData[6] = aTransformation.m_data[2][1];
1568  matrixData[12] = aTransformation.m_data[0][2];
1569  matrixData[13] = aTransformation.m_data[1][2];
1570  matrixData[14] = aTransformation.m_data[2][2];
1571 
1572  glMultMatrixd( matrixData );
1573 }
1574 
1575 
1576 void OPENGL_GAL::Rotate( double aAngle )
1577 {
1578  m_currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1579 }
1580 
1581 
1582 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1583 {
1584  m_currentManager->Translate( aVector.x, aVector.y, 0.0f );
1585 }
1586 
1587 
1588 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1589 {
1590  m_currentManager->Scale( aScale.x, aScale.y, 0.0f );
1591 }
1592 
1593 
1595 {
1597 }
1598 
1599 
1601 {
1603 }
1604 
1605 
1607 {
1608  m_isGrouping = true;
1609 
1610  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *m_cachedManager );
1611  int groupNumber = getNewGroupNumber();
1612  m_groups.insert( std::make_pair( groupNumber, newItem ) );
1613 
1614  return groupNumber;
1615 }
1616 
1617 
1619 {
1621  m_isGrouping = false;
1622 }
1623 
1624 
1625 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1626 {
1627  auto group = m_groups.find( aGroupNumber );
1628 
1629  if( group != m_groups.end() )
1630  m_cachedManager->DrawItem( *group->second );
1631 }
1632 
1633 
1634 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1635 {
1636  auto group = m_groups.find( aGroupNumber );
1637 
1638  if( group != m_groups.end() )
1639  m_cachedManager->ChangeItemColor( *group->second, aNewColor );
1640 }
1641 
1642 
1643 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1644 {
1645  auto group = m_groups.find( aGroupNumber );
1646 
1647  if( group != m_groups.end() )
1648  m_cachedManager->ChangeItemDepth( *group->second, aDepth );
1649 }
1650 
1651 
1652 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1653 {
1654  // Frees memory in the container as well
1655  m_groups.erase( aGroupNumber );
1656 }
1657 
1658 
1660 {
1661  m_bitmapCache = std::make_unique<GL_BITMAP_CACHE>();
1662 
1663  m_groups.clear();
1664 
1665  if( m_isInitialized )
1667 }
1668 
1669 
1671 {
1672  switch( aTarget )
1673  {
1674  default:
1678  }
1679 
1680  m_currentTarget = aTarget;
1681 }
1682 
1683 
1685 {
1686  return m_currentTarget;
1687 }
1688 
1689 
1691 {
1692  // Save the current state
1693  unsigned int oldTarget = m_compositor->GetBuffer();
1694 
1695  switch( aTarget )
1696  {
1697  // Cached and noncached items are rendered to the same buffer
1698  default:
1699  case TARGET_CACHED:
1700  case TARGET_NONCACHED:
1702  break;
1703 
1704  case TARGET_OVERLAY:
1705  if( m_overlayBuffer )
1707  break;
1708  }
1709 
1710  if( aTarget != TARGET_OVERLAY )
1712  else if( m_overlayBuffer )
1714 
1715  // Restore the previous state
1716  m_compositor->SetBuffer( oldTarget );
1717 }
1718 
1719 
1721 {
1722  switch( aTarget )
1723  {
1724  default:
1725  case TARGET_CACHED:
1726  case TARGET_NONCACHED: return true;
1727  case TARGET_OVERLAY: return ( m_overlayBuffer != 0 );
1728  }
1729 }
1730 
1731 
1733 {
1734  // Store the current cursor type and get the wxCursor for it
1735  if( !GAL::SetNativeCursorStyle( aCursor ) )
1736  return false;
1737 
1739 
1740  // Update the cursor in the wx control
1741  HIDPI_GL_CANVAS::SetCursor( m_currentwxCursor );
1742 
1743  return true;
1744 }
1745 
1746 
1747 void OPENGL_GAL::onSetNativeCursor( wxSetCursorEvent& aEvent )
1748 {
1749  aEvent.SetCursor( m_currentwxCursor );
1750 }
1751 
1752 
1753 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1754 {
1755  // Now we should only store the position of the mouse cursor
1756  // The real drawing routines are in blitCursor()
1757  //VECTOR2D screenCursor = m_worldScreenMatrix * aCursorPosition;
1758  //m_cursorPosition = m_screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1759  m_cursorPosition = aCursorPosition;
1760 }
1761 
1762 
1763 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1764 {
1765  /* Helper drawing: ____--- v3 ^
1766  * ____---- ... \ \
1767  * ____---- ... \ end \
1768  * v1 ____---- ... ____---- \ width
1769  * ---- ...___---- \ \
1770  * \ ___...-- \ v
1771  * \ ____----... ____---- v2
1772  * ---- ... ____----
1773  * start \ ... ____----
1774  * \... ____----
1775  * ----
1776  * v0
1777  * dots mark triangles' hypotenuses
1778  */
1779 
1780  auto v1 = m_currentManager->GetTransformation()
1781  * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 );
1783  * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 );
1784 
1785  VECTOR2D vs( v2.x - v1.x, v2.y - v1.y );
1786 
1787  m_currentManager->Reserve( 6 );
1788 
1789  // Line width is maintained by the vertex shader
1791  m_currentManager->Vertex( aStartPoint, m_layerDepth );
1792 
1794  m_currentManager->Vertex( aStartPoint, m_layerDepth );
1795 
1797  m_currentManager->Vertex( aEndPoint, m_layerDepth );
1798 
1800  m_currentManager->Vertex( aEndPoint, m_layerDepth );
1801 
1803  m_currentManager->Vertex( aEndPoint, m_layerDepth );
1804 
1806  m_currentManager->Vertex( aStartPoint, m_layerDepth );
1807 }
1808 
1809 
1810 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1811 {
1812  if( m_isFillEnabled )
1813  {
1815  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1816  }
1817 
1818  if( m_isStrokeEnabled )
1819  {
1821  m_strokeColor.a );
1822  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1823  }
1824 }
1825 
1826 
1827 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1828 {
1829  Save();
1830 
1831  m_currentManager->Reserve( 3 );
1832  m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1833  m_currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1834 
1835  /* Draw a triangle that contains the semicircle, then shade it to leave only
1836  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1837  * (if you want to understand more, check the vertex shader source [shader.vert]).
1838  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1839  * v2
1840  * /\
1841  * /__\
1842  * v0 //__\\ v1
1843  */
1845  m_currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, m_layerDepth ); // v0
1846 
1848  m_currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, m_layerDepth ); // v1
1849 
1851  m_currentManager->Vertex( 0.0f, aRadius * 2.0f, m_layerDepth ); // v2
1852 
1853  Restore();
1854 }
1855 
1856 
1857 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1858  double aAngle )
1859 {
1860  double outerRadius = aRadius + ( m_lineWidth / 2 );
1861 
1862  Save();
1863 
1864  m_currentManager->Reserve( 3 );
1865  m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1866  m_currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1867 
1868  /* Draw a triangle that contains the semicircle, then shade it to leave only
1869  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1870  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1871  * radius and the line width. Shader uses these coordinates to determine if fragments are
1872  * inside the semicircle or not.
1873  * v2
1874  * /\
1875  * /__\
1876  * v0 //__\\ v1
1877  */
1879  m_currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, m_layerDepth ); // v0
1880 
1882  m_currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, m_layerDepth ); // v1
1883 
1885  m_currentManager->Vertex( 0.0f, outerRadius * 2.0f, m_layerDepth ); // v2
1886 
1887  Restore();
1888 }
1889 
1890 
1891 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1892 {
1893  if( m_isFillEnabled )
1894  {
1897 
1898  // Any non convex polygon needs to be tesselated
1899  // for this purpose the GLU standard functions are used
1901  gluTessBeginPolygon( m_tesselator, &params );
1902  gluTessBeginContour( m_tesselator );
1903 
1904  GLdouble* point = aPoints;
1905 
1906  for( int i = 0; i < aPointCount; ++i )
1907  {
1908  gluTessVertex( m_tesselator, point, point );
1909  point += 3; // 3 coordinates
1910  }
1911 
1912  gluTessEndContour( m_tesselator );
1913  gluTessEndPolygon( m_tesselator );
1914 
1915  // Free allocated intersecting points
1916  m_tessIntersects.clear();
1917  }
1918 
1919  if( m_isStrokeEnabled )
1920  {
1921  drawPolyline(
1922  [&]( int idx )
1923  {
1924  return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] );
1925  },
1926  aPointCount );
1927  }
1928 }
1929 
1930 
1931 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D( int )>& aPointGetter, int aPointCount )
1932 {
1933  wxCHECK( aPointCount >= 2, /* return */ );
1934 
1936  int i;
1937 
1938  for( i = 1; i < aPointCount; ++i )
1939  {
1940  auto start = aPointGetter( i - 1 );
1941  auto end = aPointGetter( i );
1942 
1943  drawLineQuad( start, end );
1944  }
1945 }
1946 
1947 
1948 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1949 {
1950  const float TEX_X = font_image.width;
1951  const float TEX_Y = font_image.height;
1952 
1953  // handle space
1954  if( aChar == ' ' )
1955  {
1956  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1957  wxASSERT( g );
1958 
1959  if( !g ) // Should not happen.
1960  return 0;
1961 
1962  Translate( VECTOR2D( g->advance, 0 ) );
1963  return g->advance;
1964  }
1965 
1966  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1967 
1968  // If the glyph is not found (happens for many esoteric unicode chars)
1969  // shows a '?' instead.
1970  if( !glyph )
1971  glyph = LookupGlyph( '?' );
1972 
1973  if( !glyph ) // Should not happen.
1974  return 0;
1975 
1976  const float X = glyph->atlas_x + font_information.smooth_pixels;
1977  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1978  const float XOFF = glyph->minx;
1979 
1980  // adjust for height rounding
1981  const float round_adjust = ( glyph->maxy - glyph->miny )
1982  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1983  const float top_adjust = font_information.max_y - glyph->maxy;
1984  const float YOFF = round_adjust + top_adjust;
1985  const float W = glyph->atlas_w - font_information.smooth_pixels * 2;
1986  const float H = glyph->atlas_h - font_information.smooth_pixels * 2;
1987  const float B = 0;
1988 
1989  m_currentManager->Reserve( 6 );
1990  Translate( VECTOR2D( XOFF, YOFF ) );
1991 
1992  /* Glyph:
1993  * v0 v1
1994  * +--+
1995  * | /|
1996  * |/ |
1997  * +--+
1998  * v2 v3
1999  */
2000  m_currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
2001  m_currentManager->Vertex( -B, -B, 0 ); // v0
2002 
2003  m_currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
2004  m_currentManager->Vertex( W + B, -B, 0 ); // v1
2005 
2006  m_currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
2007  m_currentManager->Vertex( -B, H + B, 0 ); // v2
2008 
2009 
2010  m_currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
2011  m_currentManager->Vertex( W + B, -B, 0 ); // v1
2012 
2013  m_currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
2014  m_currentManager->Vertex( -B, H + B, 0 ); // v2
2015 
2016  m_currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
2017  m_currentManager->Vertex( W + B, H + B, 0 ); // v3
2018 
2019  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
2020 
2021  return glyph->advance;
2022 }
2023 
2024 
2025 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
2026 {
2027  // To draw an overbar, simply draw an overbar
2028  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
2029  wxCHECK( glyph, /* void */ );
2030 
2031  const float H = glyph->maxy - glyph->miny;
2032 
2033  Save();
2034 
2035  Translate( VECTOR2D( -aLength, -aHeight - 1.5 * H ) );
2036 
2037  m_currentManager->Reserve( 6 );
2039 
2040  m_currentManager->Shader( 0 );
2041 
2042  m_currentManager->Vertex( 0, 0, 0 ); // v0
2043  m_currentManager->Vertex( aLength, 0, 0 ); // v1
2044  m_currentManager->Vertex( 0, H, 0 ); // v2
2045 
2046  m_currentManager->Vertex( aLength, 0, 0 ); // v1
2047  m_currentManager->Vertex( 0, H, 0 ); // v2
2048  m_currentManager->Vertex( aLength, H, 0 ); // v3
2049 
2050  Restore();
2051 }
2052 
2053 
2054 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
2055 {
2056  static const FONT_GLYPH_TYPE* defaultGlyph = LookupGlyph( '(' ); // for strange chars
2057  static const FONT_GLYPH_TYPE* lineGlyph = LookupGlyph( '_' ); // for overbar thickness
2058 
2059  VECTOR2D textSize( 0, 0 );
2060  float commonOffset = std::numeric_limits<float>::max();
2061  float charHeight = font_information.max_y - defaultGlyph->miny;
2062  int overbarDepth = -1;
2063  int braceNesting = 0;
2064 
2065  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
2066  {
2067  if( *chIt == '~' && overbarDepth == -1 )
2068  {
2069  UTF8::uni_iter lookahead = chIt;
2070 
2071  if( ++lookahead != end && *lookahead == '{' )
2072  {
2073  chIt = lookahead;
2074  overbarDepth = braceNesting;
2075  braceNesting++;
2076  continue;
2077  }
2078  }
2079  else if( *chIt == '{' )
2080  {
2081  braceNesting++;
2082  }
2083  else if( *chIt == '}' )
2084  {
2085  if( braceNesting > 0 )
2086  braceNesting--;
2087 
2088  if( braceNesting == overbarDepth )
2089  {
2090  overbarDepth = -1;
2091  continue;
2092  }
2093  }
2094 
2095  const FONT_GLYPH_TYPE* glyph = LookupGlyph( *chIt );
2096 
2097  if( !glyph // Not coded in font
2098  || *chIt == '-' || *chIt == '_' ) // Strange size of these 2 chars
2099  {
2100  glyph = defaultGlyph;
2101  }
2102 
2103  if( glyph )
2104  {
2105  textSize.x += glyph->advance;
2106 
2107  if( overbarDepth != -1 )
2108  {
2109  const float H = lineGlyph->maxy - lineGlyph->miny;
2110  textSize.y = std::max<float>( textSize.y, charHeight + 1.5 * H );
2111  }
2112  }
2113  }
2114 
2115  textSize.y = std::max<float>( textSize.y, charHeight );
2116  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
2117  textSize.y -= commonOffset;
2118 
2119  return std::make_pair( textSize, commonOffset );
2120 }
2121 
2122 
2123 void OPENGL_GAL::onPaint( wxPaintEvent& aEvent )
2124 {
2125  PostPaint( aEvent );
2126 }
2127 
2128 
2129 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
2130 {
2131  // Post the mouse event to the event listener registered in constructor, if any
2132  if( m_mouseListener )
2133  wxPostEvent( m_mouseListener, aEvent );
2134 }
2135 
2136 
2138 {
2139  if( !IsCursorEnabled() )
2140  return;
2141 
2143 
2144  const int cursorSize = m_fullscreenCursor ? 8000 : 80;
2145 
2146  VECTOR2D cursorBegin = m_cursorPosition - cursorSize / ( 2 * m_worldScale );
2147  VECTOR2D cursorEnd = m_cursorPosition + cursorSize / ( 2 * m_worldScale );
2148  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
2149 
2150  const COLOR4D cColor = getCursorColor();
2151  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a, cColor.b * cColor.a, 1.0 );
2152 
2153  glActiveTexture( GL_TEXTURE0 );
2154  glDisable( GL_TEXTURE_2D );
2155  glLineWidth( 1.0 );
2156  glColor4d( color.r, color.g, color.b, color.a );
2157 
2158  glBegin( GL_LINES );
2159  glVertex2d( cursorCenter.x, cursorBegin.y );
2160  glVertex2d( cursorCenter.x, cursorEnd.y );
2161 
2162  glVertex2d( cursorBegin.x, cursorCenter.y );
2163  glVertex2d( cursorEnd.x, cursorCenter.y );
2164  glEnd();
2165 }
2166 
2167 
2169 {
2170  wxASSERT_MSG( m_groups.size() < std::numeric_limits<unsigned int>::max(),
2171  wxT( "There are no free slots to store a group" ) );
2172 
2173  while( m_groups.find( m_groupCounter ) != m_groups.end() )
2174  m_groupCounter++;
2175 
2176  return m_groupCounter++;
2177 }
2178 
2179 
2181 {
2182  wxASSERT( IsShownOnScreen() );
2183 
2184  wxASSERT_MSG( m_isContextLocked, "This should only be called from within a locked context." );
2185 
2186 // IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4
2187 // starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER)
2188 #if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 )
2189  const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 };
2190 
2191  if( !IsDisplaySupported( attr ) )
2192  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
2193 #endif /* wxCHECK_VERSION( 3, 0, 3 ) */
2194 
2195  // Check correct initialization from the constructor
2196  if( !m_glMainContext )
2197  throw std::runtime_error( "Could not create the main OpenGL context" );
2198 
2199  if( !m_glPrivContext )
2200  throw std::runtime_error( "Could not create a private OpenGL context" );
2201 
2202  if( m_tesselator == NULL )
2203  throw std::runtime_error( "Could not create the m_tesselator" );
2204  // End initialization checks
2205 
2206  GLenum err = glewInit();
2207 
2208  if( GLEW_OK != err )
2209  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
2210 
2211  // Check the OpenGL version (minimum 2.1 is required)
2212  if( !GLEW_VERSION_2_1 )
2213  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
2214 
2215 #if defined( __LINUX__ ) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
2216 #ifdef DEBUG
2217  if( GLEW_ARB_debug_output )
2218  enableGlDebug( true );
2219 #endif
2220 #endif
2221 
2222  // Framebuffers have to be supported
2223  if( !GLEW_EXT_framebuffer_object )
2224  throw std::runtime_error( "Framebuffer objects are not supported!" );
2225 
2226  // Vertex buffer has to be supported
2227  if( !GLEW_ARB_vertex_buffer_object )
2228  throw std::runtime_error( "Vertex buffer objects are not supported!" );
2229 
2230  // Prepare shaders
2231  if( !m_shader->IsLinked()
2234  {
2235  throw std::runtime_error( "Cannot compile vertex shader!" );
2236  }
2237 
2238  if( !m_shader->IsLinked()
2241  {
2242  throw std::runtime_error( "Cannot compile fragment shader!" );
2243  }
2244 
2245  if( !m_shader->IsLinked() && !m_shader->Link() )
2246  throw std::runtime_error( "Cannot link the shaders!" );
2247 
2248  // Check if video card supports textures big enough to fit the font atlas
2249  int maxTextureSize;
2250  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
2251 
2252  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int) font_image.height )
2253  {
2254  // TODO implement software texture scaling
2255  // for bitmap fonts and use a higher resolution texture?
2256  throw std::runtime_error( "Requested texture size is not supported" );
2257  }
2258 
2260 
2261  m_cachedManager = new VERTEX_MANAGER( true );
2262  m_nonCachedManager = new VERTEX_MANAGER( false );
2263  m_overlayManager = new VERTEX_MANAGER( false );
2264 
2265  // Make VBOs use shaders
2269 
2270  m_isInitialized = true;
2271 }
2272 
2273 
2274 // Callback functions for the tesselator. Compare Redbook Chapter 11.
2275 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
2276 {
2277  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
2278  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2279  VERTEX_MANAGER* vboManager = param->vboManager;
2280 
2281  assert( vboManager );
2282  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
2283 }
2284 
2285 
2286 void CALLBACK CombineCallback( GLdouble coords[3], GLdouble* vertex_data[4], GLfloat weight[4],
2287  GLdouble** dataOut, void* aData )
2288 {
2289  GLdouble* vertex = new GLdouble[3];
2290  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2291 
2292  // Save the pointer so we can delete it later
2293  param->intersectPoints.emplace_back( vertex );
2294 
2295  memcpy( vertex, coords, 3 * sizeof( GLdouble ) );
2296 
2297  *dataOut = vertex;
2298 }
2299 
2300 
2301 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
2302 {
2303  // This callback is needed to force GLU tesselator to use triangles only
2304 }
2305 
2306 
2307 void CALLBACK ErrorCallback( GLenum aErrorCode )
2308 {
2309  //throw std::runtime_error( std::string( "Tessellation error: " ) +
2310  //std::string( (const char*) gluErrorString( aErrorCode ) );
2311 }
2312 
2313 
2314 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
2315 {
2316  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, (void( CALLBACK* )()) VertexCallback );
2317  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, (void( CALLBACK* )()) CombineCallback );
2318  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, (void( CALLBACK* )()) EdgeCallback );
2319  gluTessCallback( aTesselator, GLU_TESS_ERROR, (void( CALLBACK* )()) ErrorCallback );
2320 }
2321 
2322 void OPENGL_GAL::EnableDepthTest( bool aEnabled )
2323 {
2324  m_cachedManager->EnableDepthTest( aEnabled );
2325  m_nonCachedManager->EnableDepthTest( aEnabled );
2326  m_overlayManager->EnableDepthTest( aEnabled );
2327 }
2328 
2329 
2330 inline double round_to_half_pixel( double f, double r )
2331 {
2332  return ( ceil( f / r ) - 0.5 ) * r;
2333 }
2334 
2336 {
2338  auto pixelSize = m_worldScale;
2339 
2340  // we need -m_lookAtPoint == -k * pixelSize + 0.5 * pixelSize for OpenGL
2341  // meaning m_lookAtPoint = (k-0.5)*pixelSize with integer k
2344 
2346 }
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition: profile.h:85
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:70
virtual wxSize GetNativePixelSize() const
float GetLineWidth() const
Get the line width.
void onSetNativeCursor(wxSetCursorEvent &aEvent)
Give the correct cursor image when the native widget asks for it.
void beginUpdate() override
Definition: opengl_gal.cpp:636
bool IsLinked() const
Return true if shaders are linked correctly.
Definition: shader.h:118
const glm::mat4 & GetTransformation() const
unsigned int m_overlayBuffer
Auxiliary rendering target (for menus etc.)
Definition: opengl_gal.h:320
GROUPS_MAP m_groups
Stores information about VBO objects (groups)
Definition: opengl_gal.h:309
bool m_isFillEnabled
Is filling of graphic objects enabled ?
void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
bool LoadShaderFromStrings(SHADER_TYPE aShaderType, Args &&... aArgs)
Add a shader and compile the shader sources.
Definition: shader.h:93
virtual void DrawBuffer(unsigned int aBufferHandle) override
Draw the selected buffer to the output buffer.
wxEvtHandler * m_paintListener
Definition: opengl_gal.h:302
static bool m_isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:329
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:194
void PushMatrix()
Push the current transformation matrix stack.
bool m_axesEnabled
Should the axes be drawn.
int GetAntialiasSupersamplingFactor() const
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:288
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
Clear the target for rendering.
virtual void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle)
Draw a text using a bitmap font.
bool IsTextMirrored() const
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
static int m_instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:300
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.
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
virtual void Begin() override
Call this at the beginning of each frame.
double msecs(bool aSinceLast=false)
Definition: profile.h:146
bool Reserve(unsigned int aSize)
Allocate space for vertices, so it will be used with subsequent Vertex() calls.
void BeginDrawing() const
Prepare buffers and items to start drawing.
void Use()
Use the shader.
Definition: shader.h:126
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draw a filled polygon.
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Convert a Bezier curve to a polygon.
void DrawItem(const VERTEX_ITEM &aItem) const
Draw an item to the buffer.
VERTEX_MANAGER * m_overlayManager
Container for storing overlaid VERTEX_ITEMs.
Definition: opengl_gal.h:315
void drawLineQuad(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a quad for the line.
std::deque< boost::shared_array< GLdouble > > m_tessIntersects
Definition: opengl_gal.h:347
OpenGL implementation of the Graphics Abstraction Layer.
Definition: opengl_gal.h:66
int color
Definition: DXF_plotter.cpp:60
VECTOR2D getScreenPixelSize() const
Definition: opengl_gal.cpp:407
void ComputeWorldScreenMatrix() override
Compute the world <-> screen transformation matrix.
void Restore() override
Restore the context.
void CALLBACK EdgeCallback(GLboolean aEdgeFlag)
VECTOR2D m_gridSize
The grid size.
void SetParameter(int aParameterNumber, float aValue) const
Set a parameter of the shader.
Definition: shader.cpp:142
void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Change the depth (Z-axis position) of the group.
wxImage * GetImageData()
Definition: bitmap_base.h:70
void EnableDepthTest(bool aEnabled=false) override
bool Vertex(const VERTEX &aVertex)
Add a vertex with the given coordinates to the currently set item.
static const COLOR4D BLACK
Definition: color4d.h:373
wxGLCanvas wrapper for HiDPI/Retina support.
uni_iter uend() const
Return a uni_iter initialized to the end of "this" UTF8 byte sequence.
Definition: utf8.h:287
int BeginGroup() override
Begin a group.
VECTOR2D m_lookAtPoint
Point to be looked at in world space.
static void InitTesselatorCallbacks(GLUtesselator *aTesselator)
void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const
double GetScaleFactor() const
Get the current scale factor.
void Rotate(GLfloat aAngle, GLfloat aX, GLfloat aY, GLfloat aZ)
Multiply the current matrix by a rotation matrix, so the newly vertices will be rotated by the given ...
double g
Green component.
Definition: color4d.h:364
Fragment shader.
Definition: shader.h:47
bool Link()
Link the shaders.
Definition: shader.cpp:100
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
int checkGlError(const std::string &aInfo, const char *aFile, int aLine, bool aThrow)
Check if a recent OpenGL operation has failed.
Definition: utils.cpp:45
KICURSOR
Definition: cursors.h:33
unsigned int m_mainBuffer
Main rendering target.
Definition: opengl_gal.h:319
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
static const unsigned int DIRECT_RENDERING
int PointCount() const
Function PointCount()
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
A small class to help profiling.
Definition: profile.h:45
EDA_TEXT_HJUSTIFY_T GetHorizontalJustify() const
Return current text horizontal justification setting.
OPENGL_ANTIALIASING_MODE gl_antialiasing_mode
VERTEX_MANAGER * m_cachedManager
Container for storing cached VERTEX_ITEMs.
Definition: opengl_gal.h:313
void UnlockCtx(wxGLContext *aContext)
Allow other canvases to bind an OpenGL context.
void enableGlDebug(bool aEnable)
Enable or disable OpenGL driver messages output.
Definition: utils.cpp:179
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:269
bool IsTriangulationUpToDate() const
int m_gridTick
Every tick line gets the double width.
void unlockContext(int aClientCookie) override
Definition: opengl_gal.cpp:622
void CALLBACK VertexCallback(GLvoid *aVertexPtr, void *aData)
void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
float m_gridLineWidth
Line width of the grid.
MATRIX3x3D m_worldScreenMatrix
World transformation.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
double b
Blue component.
Definition: color4d.h:365
double m_layerDepth
The actual layer depth.
Auxiliary rendering target (noncached)
Definition: definitions.h:49
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:285
T m_data[3][3]
Definition: matrix3x3.h:64
double getWorldPixelSize() const
Definition: opengl_gal.cpp:400
COLOR4D m_gridColor
Color of the grid.
RENDER_TARGET m_currentTarget
Current rendering target.
Definition: opengl_gal.h:321
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:849
RENDER_TARGET GetTarget() const override
Get the currently used target for rendering.
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
double m_worldScale
The scale factor world->screen.
wxEvtHandler * m_mouseListener
Definition: opengl_gal.h:301
void endUpdate() override
Definition: opengl_gal.cpp:652
const VECTOR2D & GetGlyphSize() const
void FinishItem() const
Clean after adding an item.
double round_to_half_pixel(double f, double r)
static GL_CONTEXT_MANAGER & Get()
Return the GL_CONTEXT_MANAGER instance (singleton).
bool SetNativeCursorStyle(KICURSOR aCursor) override
Set the cursor in the native panel.
uni_iter ubegin() const
Returns a uni_iter initialized to the start of "this" UTF8 byte sequence.
Definition: utf8.h:279
VECTOR2D m_cursorPosition
Current cursor position (world coordinates)
GAL_DISPLAY_OPTIONS & m_options
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.
bool m_globalFlipX
Flag for X axis flipping.
VERTEX_MANAGER * m_currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs).
Definition: opengl_gal.h:311
double a
Alpha component.
Definition: color4d.h:366
bool m_isStrokeEnabled
Are the outlines stroked ?
static wxGLContext * m_glMainContext
Parent OpenGL context.
Definition: opengl_gal.h:298
COLOR4D m_strokeColor
The color of the outlines.
void Unmap()
Unmap vertex buffer.
void ChangeItemDepth(const VERTEX_ITEM &aItem, GLfloat aDepth) const
Change the depth of all vertices owned by an item.
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool IsClosed() const override
Function IsClosed()
virtual void Present() override
Call this to present the output buffer to the screen.
bool m_gridVisibility
Should the grid be shown.
bool Show(bool aShow) override
Shows/hides the GAL canvas.
virtual void ClearBuffer(const COLOR4D &aColor) override
Clear the selected buffer (set by the SetBuffer() function).
Represent a set of closed polygons.
void EndGroup() override
End the group.
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:500
static const wxCursor GetCursor(KICURSOR aCursorType)
Definition: cursors.cpp:394
SHADER * m_shader
There is only one shader used for different objects.
Definition: opengl_gal.h:324
bool m_isInitialized
Basic initialization flag, has to be done when the window is visible.
Definition: opengl_gal.h:331
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Handle updating display options.
Definition: opengl_gal.cpp:373
OPENGL_COMPOSITOR * m_compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:318
void DrawGrid() override
void SetShader(SHADER &aShader) const
Set a shader program that is going to be used during rendering.
void Translate(GLfloat aX, GLfloat aY, GLfloat aZ)
Multiply the current matrix by a translation matrix, so newly vertices will be translated by the give...
void PostPaint(wxPaintEvent &aEvent)
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.cpp:365
static const int glAttributes[]
Definition: opengl_gal.cpp:80
void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: opengl_gal.cpp:661
GLUtesselator * m_tesselator
Definition: opengl_gal.h:346
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
void Map()
Map vertex buffer.
GLint ufm_antialiasingOffset
Definition: opengl_gal.h:339
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:129
GLint ufm_screenPixelSize
Definition: opengl_gal.h:337
wxLogTrace helper definitions.
void endDrawing() override
Definition: opengl_gal.cpp:571
void DrawGroup(int aGroupNumber) override
Draw the stored group.
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:135
virtual void Resize(unsigned int aWidth, unsigned int aHeight) override
Clear the state of COMPOSITOR, so it has to be reinitialized again with the new dimensions.
void ClearCache() override
Delete all data created during caching of graphic items.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=nullptr)
Create a managed OpenGL context.
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)
Draw a set of polygons with a cached triangulation.
FONT_INFO_TYPE font_information
Definition: gl_resources.cpp:3
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
Vertex shader.
Definition: shader.h:46
virtual void SetBuffer(unsigned int aBufferHandle) override
Set the selected buffer as the rendering target.
Provide the access to the OpenGL shaders.
Definition: shader.h:76
void lockContext(int aClientCookie) override
Use GAL_CONTEXT_LOCKER RAII object.
Definition: opengl_gal.cpp:612
int SegmentCount() const
Function SegmentCount()
void Color(const COLOR4D &aColor)
Changes currently used color that will be applied to newly added vertices.
Use dots for the grid.
Use small cross instead of dots for the grid.
COLOR4D getCursorColor() const
Get the actual cursor color to draw.
std::map< const BITMAP_BASE *, CACHED_BITMAP > m_bitmaps
Definition: opengl_gal.cpp:107
void Rotate(double aAngle) override
Rotate the context.
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Handle updating display options.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Set a context as current and prevents other canvases from switching it.
void drawStrokedSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a stroked semicircle.
bool m_isContextLocked
Used for assertion checking.
Definition: opengl_gal.h:334
#define H(x, y, z)
Definition: md5_hash.cpp:17
void PopMatrix()
Pop the current transformation matrix stack.
virtual bool SetNativeCursorStyle(KICURSOR aCursor)
Set the cursor in the native panel.
void blitCursor()
Blit cursor into the current screen.
uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded string...
Definition: utf8.h:203
virtual void Initialize() override
Perform primary initialization, necessary to use the object.
static GLuint g_fontTexture
Bitmap font texture handle (shared)
Definition: opengl_gal.h:304
void EndDrawing() const
Finish drawing operations.
void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
Definition: opengl_gal.cpp:995
void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:669
void computeWorldScale()
Compute the scaling factor for the world->screen matrix.
GLint ufm_worldPixelSize
Definition: opengl_gal.h:336
GRID_STYLE m_gridStyle
Grid display style.
void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: opengl_gal.cpp:780
void CALLBACK ErrorCallback(GLenum aErrorCode)
void SetTarget(RENDER_TARGET aTarget) override
Set the target for rendering.
wxGLContext * m_glPrivContext
Canvas-specific OpenGL context.
Definition: opengl_gal.h:299
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
Bezier curves to polygon converter.
Definition: bezier_curves.h:36
COLOR4D m_fillColor
The fill color.
Definition: color4d.h:56
VECTOR2D m_depthRange
Range of the depth.
bool m_isFramebufferInitialized
Are the framebuffers initialized?
Definition: opengl_gal.h:328
COLOR4D m_axesColor
Color of the axes.
const int scale
wxCursor m_currentwxCursor
wxCursor showing the current native cursor
Definition: opengl_gal.h:341
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:333
void EnableDepthTest(bool aEnabled)
Enable/disable Z buffer depth test.
bool m_globalFlipY
Flag for Y axis flipping.
EDA_TEXT_VJUSTIFY_T GetVerticalJustify() const
Returns current text vertical justification setting.
SHAPE_LINE_CHAIN.
virtual bool HasTarget(RENDER_TARGET aTarget) override
Return true if the target exists.
int drawBitmapChar(unsigned long aChar)
Draw a single character using bitmap font.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of outlines in the set.
void Scale(GLfloat aX, GLfloat aY, GLfloat aZ)
Multiply the current matrix by a scaling matrix, so the newly vertices will be scaled by the given fa...
wxSize GetSizePixels() const
Definition: bitmap_base.h:124
void ClearScreen() override
Clear the screen.
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:70
#define SWAP(varA, condition, varB)
Swap the variables if a condition is met.
Definition: definitions.h:31
std::unique_ptr< GL_BITMAP_CACHE > m_bitmapCache
Definition: opengl_gal.h:343
unsigned int getNewGroupNumber()
Return 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.
void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:956
void Flush() override
Force all remaining objects to be drawn.
bool m_fullscreenCursor
Shape of the cursor (fullscreen or small cross)
virtual unsigned int GetBuffer() const override
Return currently used buffer handle.
void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual unsigned int CreateBuffer() override
Prepare 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)
Destroy a managed OpenGL context.
Class to control vertex container and GPU with possibility of emulating old-style OpenGL 1....
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
VECTOR2D m_gridOrigin
The grid origin.
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)
Change currently used shader and its parameters that will be applied to newly added vertices.
double m_worldUnitLength
The unit length of the world coordinates [inch].
double r
Red component.
Definition: color4d.h:363
POLYGON & Polygon(int aIndex)
void ChangeItemColor(const VERTEX_ITEM &aItem, const COLOR4D &aColor) const
Change the color of all vertices owned by an item.
unsigned int m_groupCounter
Counter used for generating keys for groups.
Definition: opengl_gal.h:310
std::pair< VECTOR2D, float > computeBitmapTextSize(const UTF8 &aText) const
Compute a size of text drawn using bitmap font with current text setting applied.
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:46
void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle) override
Draw a text using a bitmap font.
bool m_isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:330
static int SetSwapInterval(int aVal)
Attempts to set the OpenGL swap interval.
Definition: gl_utils.h:40
VERTEX_MANAGER * m_nonCachedManager
Container for storing non-cached VERTEX_ITEMs.
Definition: opengl_gal.h:314
#define CALLBACK
Definition: opengl_gal.h:49
bool IsVisible() const override
Return true if the GAL canvas is visible on the screen.
Definition: opengl_gal.h:106
bool IsCursorEnabled() const
Return information about cursor visibility.
void beginDrawing() override
Definition: opengl_gal.cpp:414
VECTOR2I m_screenSize
Screen size in screen coordinates.
GLint ufm_pixelSizeMultiplier
Definition: opengl_gal.h:338
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
void Clear() const
Remove all the stored vertices from the container.
VECTOR2D GetAntialiasRenderingOffset() const
void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: opengl_gal.cpp:723
KICURSOR m_currentNativeCursor
Current cursor.
float m_lineWidth
The line width.
void skipMouseEvent(wxMouseEvent &aEvent)
Skip the mouse event to the parent.
bool m_isGrouping
Was a group started?
Definition: opengl_gal.h:333
void drawFilledSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a filled semicircle.
int GetPPI() const
Definition: bitmap_base.h:135
void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Change the color used to draw the group.
Abstract interface for drawing on a 2D-surface.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
void drawBitmapOverbar(double aLength, double aHeight)
Draw an overbar over the currently drawn text.