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