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