KiCad PCB EDA Suite
opengl_gal.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2012-2020 Kicad Developers, see AUTHORS.txt for contributors.
6  * Copyright (C) 2013-2017 CERN
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * Graphics Abstraction Layer (GAL) for OpenGL
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 // Apple, in their infinite wisdom, has decided to mark OpenGL as deprecated.
30 // Luckily we can silence warnings about its deprecation.
31 #ifdef __APPLE__
32 #define GL_SILENCE_DEPRECATION 1
33 #endif
34 
35 #include <gl_utils.h>
36 
37 #include <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 {
88 {
89 public:
91  {
92  }
93 
94  ~GL_BITMAP_CACHE();
95 
96  GLuint RequestBitmap( const BITMAP_BASE* aBitmap );
97 
98 private:
99 
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 };
112 
113 
114 GL_BITMAP_CACHE::~GL_BITMAP_CACHE()
115 {
116  for ( auto b = m_bitmaps.begin(); b != m_bitmaps.end(); ++b )
117  glDeleteTextures( 1, &b->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, buf.get() );
183 
184  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
185  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
186 
187  bmp.id = textureID;
188 
189 #ifndef DISABLE_BITMAP_CACHE
190  m_bitmaps[ aBitmap ] = bmp;
191 #endif
192 
193  return textureID;
194 }
195 
196 OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
197  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
198  const wxString& aName ) :
199  GAL( aDisplayOptions ),
200  HIDPI_GL_CANVAS( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
201  wxEXPAND, aName ),
202  mouseListener( aMouseListener ),
203  paintListener( aPaintListener ),
204  currentManager( nullptr ),
205  cachedManager( nullptr ),
206  nonCachedManager( nullptr ),
207  overlayManager( nullptr ),
208  mainBuffer( 0 ),
209  overlayBuffer( 0 ),
210  isContextLocked( false ),
211  lockClientCookie( 0 )
212 {
213  if( glMainContext == NULL )
214  {
216 
218  }
219  else
220  {
222  }
223 
224  shader = new SHADER();
225  ++instanceCounter;
226 
227  bitmapCache = std::make_unique<GL_BITMAP_CACHE>( );
228 
231 
232  // Initialize the flags
233  isFramebufferInitialized = false;
234  isBitmapFontInitialized = false;
235  isInitialized = false;
236  isGrouping = false;
237  groupCounter = 0;
238 
239  // Connecting the event handlers
240  Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) );
241 
242  // Mouse events are skipped to the parent
243  Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
244  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
245  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
246  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
247  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
248  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
249  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
250  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
251  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
252  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
253  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
254 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
255  Connect( wxEVT_MAGNIFY, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
256 #endif
257 #if defined _WIN32 || defined _WIN64
258  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
259 #endif
260 
261  SetSize( aParent->GetClientSize() );
263 
264  // Grid color settings are different in Cairo and OpenGL
265  SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) );
266  SetAxesColor( COLOR4D( BLUE ) );
267 
268  // Tesselator initialization
269  tesselator = gluNewTess();
271 
272  gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
273 
275 
276  // Avoid unitialized variables:
277  ufm_worldPixelSize = 1;
280 }
281 
282 
284 {
286 
287  --instanceCounter;
288  glFlush();
289  gluDeleteTess( tesselator );
290  ClearCache();
291 
292  delete compositor;
293 
294  if( isInitialized )
295  {
296  delete cachedManager;
297  delete nonCachedManager;
298  delete overlayManager;
299  }
300 
302 
303  // If it was the main context, then it will be deleted
304  // when the last OpenGL GAL instance is destroyed (a few lines below)
307 
308  delete shader;
309 
310  // Are we destroying the last GAL instance?
311  if( instanceCounter == 0 )
312  {
314 
315  if( isBitmapFontLoaded )
316  {
317  glDeleteTextures( 1, &fontTexture );
318  isBitmapFontLoaded = false;
319  }
320 
324  }
325 }
326 
327 
329 {
330  wxString retVal = wxEmptyString;
331 
332  wxFrame* testFrame = new wxFrame( NULL, wxID_ANY, wxT( "" ), wxDefaultPosition, wxSize( 1, 1 ),
333  wxFRAME_TOOL_WINDOW | wxNO_BORDER );
334 
335  KIGFX::OPENGL_GAL* opengl_gal = new KIGFX::OPENGL_GAL( aOptions, testFrame );
336 
337  testFrame->Raise();
338  testFrame->Show();
339 
340  try
341  {
342  GAL_CONTEXT_LOCKER lock( opengl_gal );
343  opengl_gal->init();
344  }
345  catch( std::runtime_error& err )
346  {
347  //Test failed
348  retVal = wxString( err.what() );
349  }
350 
351  delete opengl_gal;
352  delete testFrame;
353 
354  return retVal;
355 }
356 
357 
358 void OPENGL_GAL::PostPaint( wxPaintEvent& aEvent )
359 {
360  // posts an event to m_paint_listener to ask for redraw the canvas.
361  if( paintListener )
362  {
363  wxPostEvent( paintListener, aEvent );
364  }
365 }
366 
367 
369 {
370  bool refresh = false;
371 
373  {
375  isFramebufferInitialized = false;
376  refresh = true;
377  }
378 
380  {
382  refresh = true;
383  }
384 
385  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
386  {
387  Refresh();
388  refresh = true;
389  }
390 
391  return refresh;
392 }
393 
394 
396 {
397  auto matrix = GetScreenWorldMatrix();
398  return std::min( std::abs( matrix.GetScale().x ), std::abs( matrix.GetScale().y ) );
399 }
400 
401 
403 {
404  auto sf = GetScaleFactor();
405  return VECTOR2D( 2.0 / (double) ( screenSize.x * sf ), 2.0 / (double) ( screenSize.y * sf ) );
406 }
407 
408 
410 {
411 #ifdef __WXDEBUG__
412  PROF_COUNTER totalRealTime( "OPENGL_GAL::beginDrawing()", true );
413 #endif /* __WXDEBUG__ */
414 
415  wxASSERT_MSG( isContextLocked, "GAL_DRAWING_CONTEXT RAII object should have locked context. "
416  "Calling GAL::beginDrawing() directly is not allowed." );
417 
418  wxASSERT_MSG( IsVisible(), "GAL::beginDrawing() must not be entered when GAL is not visible. "
419  "Other drawing routines will expect everything to be initialized "
420  "which will not be the case." );
421 
422  if( !isInitialized )
423  init();
424 
425  // Set up the view port
426  glMatrixMode( GL_PROJECTION );
427  glLoadIdentity();
428 
429  // Create the screen transformation (Do the RH-LH conversion here)
430  glOrtho( 0, (GLint) screenSize.x, (GLsizei) screenSize.y, 0, -depthRange.x, -depthRange.y );
431 
433  {
434  // Prepare rendering target buffers
437  try
438  {
440  }
441  catch( const std::runtime_error& error )
442  {
443  wxLogVerbose( "Could not create a framebuffer for overlays.\n" );
444  overlayBuffer = 0;
445  }
447  }
448 
449  compositor->Begin();
450 
451  // Disable 2D Textures
452  glDisable( GL_TEXTURE_2D );
453 
454  glShadeModel( GL_FLAT );
455 
456  // Enable the depth buffer
457  glEnable( GL_DEPTH_TEST );
458  glDepthFunc( GL_LESS );
459 
460  // Setup blending, required for transparent objects
461  glEnable( GL_BLEND );
462  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
463 
464  glMatrixMode( GL_MODELVIEW );
465 
466  // Set up the world <-> screen transformation
468  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
469  matrixData[0] = worldScreenMatrix.m_data[0][0];
470  matrixData[1] = worldScreenMatrix.m_data[1][0];
471  matrixData[2] = worldScreenMatrix.m_data[2][0];
472  matrixData[4] = worldScreenMatrix.m_data[0][1];
473  matrixData[5] = worldScreenMatrix.m_data[1][1];
474  matrixData[6] = worldScreenMatrix.m_data[2][1];
475  matrixData[12] = worldScreenMatrix.m_data[0][2];
476  matrixData[13] = worldScreenMatrix.m_data[1][2];
477  matrixData[14] = worldScreenMatrix.m_data[2][2];
478  glLoadMatrixd( matrixData );
479 
480  // Set defaults
483 
484  // Remove all previously stored items
487 
491 
493  {
494  // Keep bitmap font texture always bound to the second texturing unit
495  const GLint FONT_TEXTURE_UNIT = 2;
496 
497  // Either load the font atlas to video memory, or simply bind it to a texture unit
498  if( !isBitmapFontLoaded )
499  {
500  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
501  glGenTextures( 1, &fontTexture );
502  glBindTexture( GL_TEXTURE_2D, fontTexture );
503  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height,
504  0, GL_RGB, GL_UNSIGNED_BYTE, font_image.pixels );
505  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
506  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
507  checkGlError( "loading bitmap font" );
508 
509  glActiveTexture( GL_TEXTURE0 );
510 
511  isBitmapFontLoaded = true;
512  }
513  else
514  {
515  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
516  glBindTexture( GL_TEXTURE_2D, fontTexture );
517  glActiveTexture( GL_TEXTURE0 );
518  }
519 
520  // Set shader parameter
521  GLint ufm_fontTexture = shader->AddParameter( "fontTexture" );
522  GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" );
523  ufm_worldPixelSize = shader->AddParameter( "worldPixelSize" );
524  ufm_screenPixelSize = shader->AddParameter( "screenPixelSize" );
525  ufm_pixelSizeMultiplier = shader->AddParameter( "pixelSizeMultiplier" );
526 
527  shader->Use();
528  shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
529  shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
530  shader->Deactivate();
531  checkGlError( "setting bitmap font sampler as shader parameter" );
532 
534  }
535 
536  shader->Use();
539  double pixelSizeMultiplier = compositor->GetAntialiasSupersamplingFactor();
540  shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
541  shader->Deactivate();
542 
543  // Something betreen BeginDrawing and EndDrawing seems to depend on
544  // this texture unit being active, but it does not assure it itself.
545  glActiveTexture( GL_TEXTURE0 );
546 
547  // Unbind buffers - set compositor for direct drawing
549 
550 #ifdef __WXDEBUG__
551  totalRealTime.Stop();
552  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::beginDrawing(): %.1f ms" ), totalRealTime.msecs() );
553 #endif /* __WXDEBUG__ */
554 }
555 
556 
558 {
559  wxASSERT_MSG( isContextLocked, "What happened to the context lock?" );
560 
561 #ifdef __WXDEBUG__
562  PROF_COUNTER totalRealTime( "OPENGL_GAL::endDrawing()", true );
563 #endif /* __WXDEBUG__ */
564 
565  // Cached & non-cached containers are rendered to the same buffer
569 
570  // Overlay container is rendered to a different buffer
571  if( overlayBuffer )
574 
575  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
576  glColor4d( 1.0, 1.0, 1.0, 1.0 );
577 
578  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
580 
581  if( overlayBuffer )
583 
584  compositor->Present();
585  blitCursor();
586 
587  SwapBuffers();
588 
589 #ifdef __WXDEBUG__
590  totalRealTime.Stop();
591  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::endDrawing(): %.1f ms" ), totalRealTime.msecs() );
592 #endif /* __WXDEBUG__ */
593 }
594 
595 
596 void OPENGL_GAL::lockContext( int aClientCookie )
597 {
598  wxASSERT_MSG( !isContextLocked, "Context already locked." );
599  isContextLocked = true;
600  lockClientCookie = aClientCookie;
601 
603 }
604 
605 
606 void OPENGL_GAL::unlockContext( int aClientCookie )
607 {
608  wxASSERT_MSG( isContextLocked, "Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
609  "be stacked rather than making separate lock/unlock calls." );
610 
611  wxASSERT_MSG( lockClientCookie == aClientCookie, "Context was locked by a different client. "
612  "Should not be possible with RAII objects." );
613 
614  isContextLocked = false;
615 
617 }
618 
619 
621 {
622  wxASSERT_MSG( isContextLocked, "GAL_UPDATE_CONTEXT RAII object should have locked context. "
623  "Calling this from anywhere else is not allowed." );
624 
625  wxASSERT_MSG( IsVisible(), "GAL::beginUpdate() must not be entered when GAL is not visible. "
626  "Other update routines will expect everything to be initialized "
627  "which will not be the case." );
628 
629  if( !isInitialized )
630  init();
631 
632  cachedManager->Map();
633 }
634 
635 
637 {
638  if( !isInitialized )
639  return;
640 
641  cachedManager->Unmap();
642 }
643 
644 
645 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
646 {
648 
649  drawLineQuad( aStartPoint, aEndPoint );
650 }
651 
652 
653 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
654  double aWidth )
655 {
656  VECTOR2D startEndVector = aEndPoint - aStartPoint;
657  double lineLength = startEndVector.EuclideanNorm();
658 
659  float startx = aStartPoint.x;
660  float starty = aStartPoint.y;
661  float endx = aStartPoint.x + lineLength;
662  float endy = aStartPoint.y + lineLength;
663 
664  // Be careful about floating point rounding. As we draw segments in larger and larger coordinates,
665  // the shader (which uses floats) will lose precision and stop drawing small segments.
666  // In this case, we need to draw a circle for the minimal segment
667  if( startx == endx || starty == endy )
668  {
669  DrawCircle( aStartPoint, aWidth/2 );
670  return;
671  }
672 
673  if( isFillEnabled || aWidth == 1.0 )
674  {
676 
677  SetLineWidth( aWidth );
678  drawLineQuad( aStartPoint, aEndPoint );
679  }
680  else
681  {
682  auto lineAngle = startEndVector.Angle();
683  // Outlined tracks
684 
685  SetLineWidth( 1.0 );
687 
688  Save();
689 
690  currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
691  currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
692 
693  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
694  VECTOR2D( lineLength, aWidth / 2.0 ) );
695 
696  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ),
697  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,
868  sin( aStartAngle ) * aRadius );
869  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
870  sin( aEndAngle ) * aRadius );
871 
872  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
873  drawStrokedSemiCircle( endPoint, width, aEndAngle );
874 
875  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
876  sin( aStartAngle ) * ( aRadius + width ) );
877 
878  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
879  sin( aStartAngle ) * ( aRadius - width ) );
880 
881  double alpha;
882 
883  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
884  {
885  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
886  sin( alpha ) * ( aRadius + width ) );
887  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
888  sin( alpha ) * ( aRadius - width ) );
889 
890  DrawLine( pOuter, pNextOuter );
891  DrawLine( pInner, pNextInner );
892 
893  pOuter = pNextOuter;
894  pInner = pNextInner;
895  }
896 
897  // Draw the last missing part
898  if( alpha != aEndAngle )
899  {
900  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
901  sin( aEndAngle ) * ( aRadius + width ) );
902  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
903  sin( aEndAngle ) * ( aRadius - width ) );
904 
905  DrawLine( pOuter, pLastOuter );
906  DrawLine( pInner, pLastInner );
907  }
908  }
909 
910  if( isFillEnabled )
911  {
913  SetLineWidth( aWidth );
914 
915  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
916  double alpha;
917 
918  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
919  {
920  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
921  DrawLine( p, p_next );
922 
923  p = p_next;
924  }
925 
926  // Draw the last missing part
927  if( alpha != aEndAngle )
928  {
929  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
930  DrawLine( p, p_last );
931  }
932  }
933 
934  Restore();
935 }
936 
937 
938 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
939 {
940  // Compute the diagonal points of the rectangle
941  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
942  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
943 
944  // Fill the rectangle
945  if( isFillEnabled )
946  {
947  currentManager->Reserve( 6 );
950 
951  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
952  currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
953  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
954 
955  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
956  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
957  currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
958  }
959 
960  // Stroke the outline
961  if( isStrokeEnabled )
962  {
964 
965  std::deque<VECTOR2D> pointList;
966  pointList.push_back( aStartPoint );
967  pointList.push_back( diagonalPointA );
968  pointList.push_back( aEndPoint );
969  pointList.push_back( diagonalPointB );
970  pointList.push_back( aStartPoint );
971  DrawPolyline( pointList );
972  }
973 }
974 
975 
976 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
977 {
978  drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
979 }
980 
981 
982 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
983 {
984  drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
985 }
986 
987 
989 {
990  auto numPoints = aLineChain.PointCount();
991 
992  if( aLineChain.IsClosed() )
993  numPoints += 1;
994 
995  drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, numPoints );
996 }
997 
998 
999 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
1000 {
1001  wxCHECK( aPointList.size() >= 2, /* void */ );
1002  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
1003  GLdouble* ptr = points.get();
1004 
1005  for( const VECTOR2D& p : aPointList )
1006  {
1007  *ptr++ = p.x;
1008  *ptr++ = p.y;
1009  *ptr++ = layerDepth;
1010  }
1011 
1012  drawPolygon( points.get(), aPointList.size() );
1013 }
1014 
1015 
1016 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
1017 {
1018  wxCHECK( aListSize >= 2, /* void */ );
1019  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
1020  GLdouble* target = points.get();
1021  const VECTOR2D* src = aPointList;
1022 
1023  for( int i = 0; i < aListSize; ++i )
1024  {
1025  *target++ = src->x;
1026  *target++ = src->y;
1027  *target++ = layerDepth;
1028  ++src;
1029  }
1030 
1031  drawPolygon( points.get(), aListSize );
1032 }
1033 
1034 
1036 {
1039 
1040  if( isFillEnabled )
1041  {
1042  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
1043  {
1044  auto triPoly = aPolySet.TriangulatedPolygon( j );
1045 
1046  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1047  {
1048  VECTOR2I a, b, c;
1049  triPoly->GetTriangle( i, a, b, c );
1050  currentManager->Vertex( a.x, a.y, layerDepth );
1051  currentManager->Vertex( b.x, b.y, layerDepth );
1052  currentManager->Vertex( c.x, c.y, layerDepth );
1053  }
1054  }
1055  }
1056 
1057  if( isStrokeEnabled )
1058  {
1059  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1060  {
1061  const auto& poly = aPolySet.Polygon( j );
1062 
1063  for( const auto& lc : poly )
1064  {
1065  DrawPolyline( lc );
1066  }
1067  }
1068  }
1069 
1070  if( ADVANCED_CFG::GetCfg().m_DrawTriangulationOutlines )
1071  {
1072  auto oldStrokeColor = strokeColor;
1073  double oldLayerDepth = layerDepth;
1074 
1075  SetLayerDepth( layerDepth - 1 );
1076  SetStrokeColor( COLOR4D( 0.0, 1.0, 0.2, 1.0 ) );
1077 
1078  for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j )
1079  {
1080  auto triPoly = aPolySet.TriangulatedPolygon( j );
1081 
1082  for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1083  {
1084  VECTOR2I a, b, c;
1085  triPoly->GetTriangle( i, a, b, c );
1086  DrawLine( a, b );
1087  DrawLine( b, c );
1088  DrawLine( c, a );
1089  }
1090  }
1091 
1092  SetStrokeColor( oldStrokeColor );
1093  SetLayerDepth( oldLayerDepth );
1094  }
1095 }
1096 
1097 
1099 {
1100  if ( aPolySet.IsTriangulationUpToDate() )
1101  {
1102  drawTriangulatedPolyset( aPolySet );
1103  return;
1104  }
1105 
1106  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
1107  {
1108  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
1109  DrawPolygon( outline );
1110  }
1111 }
1112 
1113 
1114 
1116 {
1117  wxCHECK( aPolygon.PointCount() >= 2, /* void */ );
1118 
1119  const int pointCount = aPolygon.SegmentCount() + 1;
1120  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
1121  GLdouble* ptr = points.get();
1122 
1123  for( int i = 0; i < pointCount; ++i )
1124  {
1125  const VECTOR2I& p = aPolygon.CPoint( i );
1126  *ptr++ = p.x;
1127  *ptr++ = p.y;
1128  *ptr++ = layerDepth;
1129  }
1130 
1131  drawPolygon( points.get(), pointCount );
1132 }
1133 
1134 
1135 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
1136  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint,
1137  double aFilterValue )
1138 {
1139  std::vector<VECTOR2D> output;
1140  std::vector<VECTOR2D> pointCtrl;
1141 
1142  pointCtrl.push_back( aStartPoint );
1143  pointCtrl.push_back( aControlPointA );
1144  pointCtrl.push_back( aControlPointB );
1145  pointCtrl.push_back( aEndPoint );
1146 
1147  BEZIER_POLY converter( pointCtrl );
1148  converter.GetPoly( output, aFilterValue );
1149 
1150  DrawPolyline( &output[0], output.size() );
1151 }
1152 
1153 
1154 void OPENGL_GAL::DrawBitmap( const BITMAP_BASE& aBitmap )
1155 {
1156  // We have to calculate the pixel size in users units to draw the image.
1157  // worldUnitLength is a factor used for converting IU to inches
1158  double scale = 1.0 / ( aBitmap.GetPPI() * worldUnitLength );
1159  double w = (double) aBitmap.GetSizePixels().x * scale;
1160  double h = (double) aBitmap.GetSizePixels().y * scale;
1161 
1162  auto xform = currentManager->GetTransformation();
1163 
1164  glm::vec4 v0 = xform * glm::vec4( -w/2, -h/2, 0.0, 0.0 );
1165  glm::vec4 v1 = xform * glm::vec4( w/2, h/2, 0.0, 0.0 );
1166  glm::vec4 trans = xform[3];
1167 
1168  auto texture_id = bitmapCache->RequestBitmap( &aBitmap );
1169 
1170  if( !glIsTexture( texture_id ) ) // ensure the bitmap texture is still valid
1171  return;
1172 
1173  auto oldTarget = GetTarget();
1174 
1175  glPushMatrix();
1176  glTranslated( trans.x, trans.y, trans.z );
1177 
1179  glEnable(GL_TEXTURE_2D);
1180  glActiveTexture( GL_TEXTURE0 );
1181  glBindTexture( GL_TEXTURE_2D, texture_id );
1182 
1183  glBegin( GL_QUADS );
1184  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1185  glTexCoord2f( 0.0, 0.0 );
1186  glVertex3f( v0.x, v0.y, layerDepth );
1187  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1188  glTexCoord2f( 1.0, 0.0 );
1189  glVertex3f( v1.x, v0.y, layerDepth );
1190  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1191  glTexCoord2f( 1.0, 1.0 );
1192  glVertex3f( v1.x, v1.y, layerDepth );
1193  glColor4f( 1.0, 1.0, 1.0, 1.0 );
1194  glTexCoord2f( 0.0, 1.0 );
1195  glVertex3f( v0.x, v1.y, layerDepth );
1196  glEnd();
1197 
1198  SetTarget( oldTarget );
1199  glBindTexture( GL_TEXTURE_2D, 0 );
1200 
1201 #ifdef DISABLE_BITMAP_CACHE
1202  glDeleteTextures( 1, &texture_id );
1203 #endif
1204 
1205  glPopMatrix();
1206 }
1207 
1208 
1209 void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
1210  double aRotationAngle )
1211 {
1212  wxASSERT_MSG( !IsTextMirrored(), "No support for mirrored text using bitmap fonts." );
1213 
1214  const UTF8 text( aText );
1215  // Compute text size, so it can be properly justified
1216  VECTOR2D textSize;
1217  float commonOffset;
1218  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
1219 
1220  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
1221  bool overbar = false;
1222 
1223  int overbarLength = 0;
1224  double overbarHeight = textSize.y;
1225 
1226  Save();
1227 
1229  currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
1230  currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
1231 
1232  double sx = SCALE * ( globalFlipX ? -1.0 : 1.0 );
1233  double sy = SCALE * ( globalFlipY ? -1.0 : 1.0 );
1234 
1235  currentManager->Scale( sx, sy, 0 );
1236  currentManager->Translate( 0, -commonOffset, 0 );
1237 
1238  switch( GetHorizontalJustify() )
1239  {
1241  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
1242  break;
1243 
1245  //if( !IsTextMirrored() )
1246  Translate( VECTOR2D( -textSize.x, 0 ) );
1247  break;
1248 
1249  case GR_TEXT_HJUSTIFY_LEFT:
1250  //if( IsTextMirrored() )
1251  //Translate( VECTOR2D( -textSize.x, 0 ) );
1252  break;
1253  }
1254 
1255  switch( GetVerticalJustify() )
1256  {
1257  case GR_TEXT_VJUSTIFY_TOP:
1258  Translate( VECTOR2D( 0, -textSize.y ) );
1259  overbarHeight = -textSize.y / 2.0;
1260  break;
1261 
1263  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
1264  overbarHeight = 0;
1265  break;
1266 
1268  break;
1269  }
1270 
1271  int i = 0;
1272 
1273  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
1274  {
1275  unsigned int c = *chIt;
1276  wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
1277 
1278  bool wasOverbar = overbar;
1279 
1280  if( c == '~' )
1281  {
1282  if( ++chIt == end )
1283  break;
1284 
1285  c = *chIt;
1286 
1287  if( c == '~' )
1288  {
1289  // double ~ is really a ~ so go ahead and process the second one
1290 
1291  // so what's a triple ~? It could be a real ~ followed by an overbar, or
1292  // it could be an overbar followed by a real ~. The old algorithm did the
1293  // former so we will too....
1294  }
1295  else
1296  {
1297  overbar = !overbar;
1298  }
1299  }
1300 
1301  if( wasOverbar && !overbar )
1302  {
1303  drawBitmapOverbar( overbarLength, overbarHeight );
1304  overbarLength = 0;
1305  }
1306 
1307  if( overbar )
1308  overbarLength += drawBitmapChar( c );
1309  else
1310  drawBitmapChar( c );
1311 
1312  ++i;
1313  }
1314 
1315  // Handle the case when overbar is active till the end of the drawn text
1316  currentManager->Translate( 0, commonOffset, 0 );
1317 
1318  if( overbar && overbarLength > 0 )
1319  drawBitmapOverbar( overbarLength, overbarHeight );
1320 
1321  Restore();
1322 }
1323 
1324 
1326 {
1329 
1331 
1332  // sub-pixel lines all render the same
1333  float minorLineWidth =
1334  std::fmax( 1.0f, gridLineWidth ) * getWorldPixelSize() / GetScaleFactor();
1335  float majorLineWidth = minorLineWidth * 2.0f;
1336 
1337  // Draw the axis and grid
1338  // For the drawing the start points, end points and increments have
1339  // to be calculated in world coordinates
1340  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1341  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
1342 
1343  // Draw axes if desired
1344  if( axesEnabled )
1345  {
1346  SetLineWidth( minorLineWidth );
1348 
1349  DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) );
1350  DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) );
1351  }
1352 
1353  // force flush
1355 
1356  if( !gridVisibility || gridSize.x == 0 || gridSize.y == 0 )
1357  return;
1358 
1359  VECTOR2D gridScreenSize( gridSize );
1360 
1361  double gridThreshold = computeMinGridSpacing() / worldScale;
1362 
1364  gridThreshold *= 2.0;
1365 
1366  // If we cannot display the grid density, scale down by a tick size and
1367  // try again. Eventually, we get some representation of the grid
1368  while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold )
1369  {
1370  gridScreenSize = gridScreenSize * static_cast<double>( gridTick );
1371  }
1372 
1373  // Compute grid starting and ending indexes to draw grid points on the
1374  // visible screen area
1375  // Note: later any point coordinate will be offsetted by gridOrigin
1376  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridScreenSize.x );
1377  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridScreenSize.x );
1378  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridScreenSize.y );
1379  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridScreenSize.y );
1380 
1381  // Ensure start coordinate > end coordinate
1382  SWAP( gridStartX, >, gridEndX );
1383  SWAP( gridStartY, >, gridEndY );
1384 
1385  // Ensure the grid fills the screen
1386  --gridStartX; ++gridEndX;
1387  --gridStartY; ++gridEndY;
1388 
1389  glDisable( GL_DEPTH_TEST );
1390  glDisable( GL_TEXTURE_2D );
1391 
1392  if( gridStyle == GRID_STYLE::DOTS )
1393  {
1394  glEnable( GL_STENCIL_TEST );
1395  glStencilFunc( GL_ALWAYS, 1, 1 );
1396  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1397  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1398  SetStrokeColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
1399  }
1400  else
1401  {
1402  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1404  }
1405 
1407  {
1408 
1409  // Vertical positions
1410  for( int j = gridStartY; j <= gridEndY; j++ )
1411  {
1412  bool tickY = ( j % gridTick == 0 );
1413  const double posY = j * gridScreenSize.y + gridOrigin.y;
1414 
1415  // Horizontal positions
1416  for( int i = gridStartX; i <= gridEndX; i++ )
1417  {
1418  bool tickX = ( i % gridTick == 0 );
1419  SetLineWidth( ( ( tickX && tickY ) ? majorLineWidth : minorLineWidth ) );
1420  auto lineLen = 2.0 * GetLineWidth();
1421  auto posX = i * gridScreenSize.x + gridOrigin.x;
1422 
1423  DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) );
1424  DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) );
1425  }
1426  }
1427 
1429  }
1430  else
1431  {
1432  // Vertical lines
1433  for( int j = gridStartY; j <= gridEndY; j++ )
1434  {
1435  const double y = j * gridScreenSize.y + gridOrigin.y;
1436 
1437  // If axes are drawn, skip the lines that would cover them
1438  if( axesEnabled && y == 0.0 )
1439  continue;
1440 
1441  SetLineWidth( ( j % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1442  VECTOR2D a ( gridStartX * gridScreenSize.x + gridOrigin.x, y );
1443  VECTOR2D b ( gridEndX * gridScreenSize.x + gridOrigin.x, y );
1444 
1445  DrawLine( a, b );
1446  }
1447 
1449 
1450  if( gridStyle == GRID_STYLE::DOTS )
1451  {
1452  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1453  glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
1455  }
1456 
1457  // Horizontal lines
1458  for( int i = gridStartX; i <= gridEndX; i++ )
1459  {
1460  const double x = i * gridScreenSize.x + gridOrigin.x;
1461 
1462  // If axes are drawn, skip the lines that would cover them
1463  if( axesEnabled && x == 0.0 )
1464  continue;
1465 
1466  SetLineWidth( ( i % gridTick == 0 ) ? majorLineWidth : minorLineWidth );
1467  VECTOR2D a ( x, gridStartY * gridScreenSize.y + gridOrigin.y );
1468  VECTOR2D b ( x, gridEndY * gridScreenSize.y + gridOrigin.y );
1469  DrawLine( a, b );
1470  }
1471 
1473 
1474  if( gridStyle == GRID_STYLE::DOTS )
1475  glDisable( GL_STENCIL_TEST );
1476  }
1477 
1478  glEnable( GL_DEPTH_TEST );
1479  glEnable( GL_TEXTURE_2D );
1480 }
1481 
1482 
1483 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1484 {
1485  screenSize = VECTOR2I( aWidth, aHeight );
1486 
1487  // Resize framebuffers
1488  const float scaleFactor = GetScaleFactor();
1489  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1490  isFramebufferInitialized = false;
1491 
1492  wxGLCanvas::SetSize( aWidth, aHeight );
1493 }
1494 
1495 
1496 bool OPENGL_GAL::Show( bool aShow )
1497 {
1498  bool s = wxGLCanvas::Show( aShow );
1499 
1500  if( aShow )
1501  wxGLCanvas::Raise();
1502 
1503  return s;
1504 }
1505 
1506 
1508 {
1509  glFlush();
1510 }
1511 
1512 
1514 {
1515  // Clear screen
1517  // NOTE: Black used here instead of m_clearColor; it will be composited later
1518  glClearColor( 0, 0, 0, 1 );
1519  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1520 }
1521 
1522 
1523 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1524 {
1525  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1526 
1527  matrixData[0] = aTransformation.m_data[0][0];
1528  matrixData[1] = aTransformation.m_data[1][0];
1529  matrixData[2] = aTransformation.m_data[2][0];
1530  matrixData[4] = aTransformation.m_data[0][1];
1531  matrixData[5] = aTransformation.m_data[1][1];
1532  matrixData[6] = aTransformation.m_data[2][1];
1533  matrixData[12] = aTransformation.m_data[0][2];
1534  matrixData[13] = aTransformation.m_data[1][2];
1535  matrixData[14] = aTransformation.m_data[2][2];
1536 
1537  glMultMatrixd( matrixData );
1538 }
1539 
1540 
1541 void OPENGL_GAL::Rotate( double aAngle )
1542 {
1543  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1544 }
1545 
1546 
1547 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1548 {
1549  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1550 }
1551 
1552 
1553 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1554 {
1555  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1556 }
1557 
1558 
1560 {
1562 }
1563 
1564 
1566 {
1568 }
1569 
1570 
1572 {
1573  isGrouping = true;
1574 
1575  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1576  int groupNumber = getNewGroupNumber();
1577  groups.insert( std::make_pair( groupNumber, newItem ) );
1578 
1579  return groupNumber;
1580 }
1581 
1582 
1584 {
1586  isGrouping = false;
1587 }
1588 
1589 
1590 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1591 {
1592  if( groups[aGroupNumber] )
1593  cachedManager->DrawItem( *groups[aGroupNumber] );
1594 }
1595 
1596 
1597 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1598 {
1599  if( groups[aGroupNumber] )
1600  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1601 }
1602 
1603 
1604 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1605 {
1606  if( groups[aGroupNumber] )
1607  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1608 }
1609 
1610 
1611 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1612 {
1613  // Frees memory in the container as well
1614  groups.erase( aGroupNumber );
1615 }
1616 
1617 
1619 {
1620  bitmapCache = std::make_unique<GL_BITMAP_CACHE>( );
1621 
1622  groups.clear();
1623 
1624  if( isInitialized )
1625  cachedManager->Clear();
1626 }
1627 
1628 
1630 {
1631  switch( aTarget )
1632  {
1633  default:
1634  case TARGET_CACHED:
1636  break;
1637 
1638  case TARGET_NONCACHED:
1640  break;
1641 
1642  case TARGET_OVERLAY:
1644  break;
1645  }
1646 
1647  currentTarget = aTarget;
1648 }
1649 
1650 
1652 {
1653  return currentTarget;
1654 }
1655 
1656 
1658 {
1659  // Save the current state
1660  unsigned int oldTarget = compositor->GetBuffer();
1661 
1662  switch( aTarget )
1663  {
1664  // Cached and noncached items are rendered to the same buffer
1665  default:
1666  case TARGET_CACHED:
1667  case TARGET_NONCACHED:
1669  break;
1670 
1671  case TARGET_OVERLAY:
1672  if( overlayBuffer )
1674  break;
1675  }
1676 
1677 
1678  if( aTarget != TARGET_OVERLAY )
1680  else if( overlayBuffer )
1682 
1683  // Restore the previous state
1684  compositor->SetBuffer( oldTarget );
1685 }
1686 
1687 
1689 {
1690  switch( aTarget )
1691  {
1692  default:
1693  case TARGET_CACHED:
1694  case TARGET_NONCACHED:
1695  return true;
1696 
1697  case TARGET_OVERLAY:
1698  return ( overlayBuffer != 0 );
1699  }
1700 }
1701 
1702 
1703 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1704 {
1705  // Now we should only store the position of the mouse cursor
1706  // The real drawing routines are in blitCursor()
1707  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1708  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1709  cursorPosition = aCursorPosition;
1710 }
1711 
1712 
1713 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1714 {
1715  /* Helper drawing: ____--- v3 ^
1716  * ____---- ... \ \
1717  * ____---- ... \ end \
1718  * v1 ____---- ... ____---- \ width
1719  * ---- ...___---- \ \
1720  * \ ___...-- \ v
1721  * \ ____----... ____---- v2
1722  * ---- ... ____----
1723  * start \ ... ____----
1724  * \... ____----
1725  * ----
1726  * v0
1727  * dots mark triangles' hypotenuses
1728  */
1729 
1730  auto v1 = currentManager->GetTransformation() * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 );
1731  auto v2 = currentManager->GetTransformation() * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 );
1732 
1733  VECTOR2D vs( v2.x - v1.x, v2.y - v1.y );
1734 
1735  currentManager->Reserve( 6 );
1736 
1737  // Line width is maintained by the vertex shader
1739  currentManager->Vertex( aStartPoint, layerDepth );
1740 
1742  currentManager->Vertex( aStartPoint, layerDepth );
1743 
1745  currentManager->Vertex( aEndPoint, layerDepth );
1746 
1748  currentManager->Vertex( aEndPoint, layerDepth );
1749 
1751  currentManager->Vertex( aEndPoint, layerDepth );
1752 
1754  currentManager->Vertex( aStartPoint, layerDepth );
1755 }
1756 
1757 
1758 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1759 {
1760  if( isFillEnabled )
1761  {
1763  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1764  }
1765 
1766  if( isStrokeEnabled )
1767  {
1769  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1770  }
1771 }
1772 
1773 
1774 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1775  double aAngle )
1776 {
1777  Save();
1778 
1779  currentManager->Reserve( 3 );
1780  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1781  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1782 
1783  /* Draw a triangle that contains the semicircle, then shade it to leave only
1784  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1785  * (if you want to understand more, check the vertex shader source [shader.vert]).
1786  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1787  * v2
1788  * /\
1789  * /__\
1790  * v0 //__\\ v1
1791  */
1793  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1794 
1796  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1797 
1799  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1800 
1801  Restore();
1802 }
1803 
1804 
1805 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1806  double aAngle )
1807 {
1808  double outerRadius = aRadius + ( lineWidth / 2 );
1809 
1810  Save();
1811 
1812  currentManager->Reserve( 3 );
1813  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1814  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1815 
1816  /* Draw a triangle that contains the semicircle, then shade it to leave only
1817  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1818  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1819  * radius and the line width. Shader uses these coordinates to determine if fragments are
1820  * inside the semicircle or not.
1821  * v2
1822  * /\
1823  * /__\
1824  * v0 //__\\ v1
1825  */
1827  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1828 
1830  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1831 
1833  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1834 
1835  Restore();
1836 }
1837 
1838 
1839 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1840 {
1841  if( isFillEnabled )
1842  {
1845 
1846  // Any non convex polygon needs to be tesselated
1847  // for this purpose the GLU standard functions are used
1849  gluTessBeginPolygon( tesselator, &params );
1850  gluTessBeginContour( tesselator );
1851 
1852  GLdouble* point = aPoints;
1853 
1854  for( int i = 0; i < aPointCount; ++i )
1855  {
1856  gluTessVertex( tesselator, point, point );
1857  point += 3; // 3 coordinates
1858  }
1859 
1860  gluTessEndContour( tesselator );
1861  gluTessEndPolygon( tesselator );
1862 
1863  // Free allocated intersecting points
1864  tessIntersects.clear();
1865  }
1866 
1867  if( isStrokeEnabled )
1868  {
1869  drawPolyline( [&](int idx) { return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] ); },
1870  aPointCount );
1871  }
1872 }
1873 
1874 
1875 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D (int)>& aPointGetter, int aPointCount )
1876 {
1877  wxCHECK( aPointCount >= 2, /* return */ );
1878 
1880  int i;
1881 
1882  for( i = 1; i < aPointCount; ++i )
1883  {
1884  auto start = aPointGetter( i - 1 );
1885  auto end = aPointGetter( i );
1886 
1887  drawLineQuad( start, end );
1888  }
1889 }
1890 
1891 
1892 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1893 {
1894  const float TEX_X = font_image.width;
1895  const float TEX_Y = font_image.height;
1896 
1897  // handle space
1898  if( aChar == ' ' )
1899  {
1900  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1901  wxASSERT( g );
1902 
1903  if( !g ) // Should not happen.
1904  return 0;
1905 
1906  Translate( VECTOR2D( g->advance, 0 ) );
1907  return g->advance;
1908  }
1909 
1910  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1911 
1912  // If the glyph is not found (happens for many esotheric unicode chars)
1913  // shows a '?' instead.
1914  if( !glyph )
1915  glyph = LookupGlyph( '?' );
1916 
1917  if( !glyph ) // Should not happen.
1918  return 0;
1919 
1920  const float X = glyph->atlas_x + font_information.smooth_pixels;
1921  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1922  const float XOFF = glyph->minx;
1923 
1924  // adjust for height rounding
1925  const float round_adjust = ( glyph->maxy - glyph->miny )
1926  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1927  const float top_adjust = font_information.max_y - glyph->maxy;
1928  const float YOFF = round_adjust + top_adjust;
1929  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1930  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1931  const float B = 0;
1932 
1933  currentManager->Reserve( 6 );
1934  Translate( VECTOR2D( XOFF, YOFF ) );
1935  /* Glyph:
1936  * v0 v1
1937  * +--+
1938  * | /|
1939  * |/ |
1940  * +--+
1941  * v2 v3
1942  */
1943  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1944  currentManager->Vertex( -B, -B, 0 ); // v0
1945 
1946  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1947  currentManager->Vertex( W + B, -B, 0 ); // v1
1948 
1949  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1950  currentManager->Vertex( -B, H + B, 0 ); // v2
1951 
1952 
1953  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1954  currentManager->Vertex( W + B, -B, 0 ); // v1
1955 
1956  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1957  currentManager->Vertex( -B, H + B, 0 ); // v2
1958 
1959  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1960  currentManager->Vertex( W + B, H + B, 0 ); // v3
1961 
1962  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1963 
1964  return glyph->advance;
1965 }
1966 
1967 
1968 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1969 {
1970  // To draw an overbar, simply draw an overbar
1971  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1972  wxCHECK( glyph, /* void */ );
1973 
1974  const float H = glyph->maxy - glyph->miny;
1975 
1976  Save();
1977 
1978  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1979 
1980  currentManager->Reserve( 6 );
1982 
1983  currentManager->Shader( 0 );
1984 
1985  currentManager->Vertex( 0, 0, 0 ); // v0
1986  currentManager->Vertex( aLength, 0, 0 ); // v1
1987  currentManager->Vertex( 0, H, 0 ); // v2
1988 
1989  currentManager->Vertex( aLength, 0, 0 ); // v1
1990  currentManager->Vertex( 0, H, 0 ); // v2
1991  currentManager->Vertex( aLength, H, 0 ); // v3
1992 
1993  Restore();
1994 }
1995 
1996 
1997 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
1998 {
1999  VECTOR2D textSize( 0, 0 );
2000  float commonOffset = std::numeric_limits<float>::max();
2001  static const auto defaultGlyph = LookupGlyph( '(' ); // for strange chars
2002 
2003  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
2004  {
2005  unsigned int c = *chIt;
2006 
2007  const FONT_GLYPH_TYPE* glyph = LookupGlyph( c );
2008  // Debug: show not coded char in the atlas
2009  // Be carefull before allowing the assert: it usually crash kicad
2010  // when the assert is made during a paint event.
2011  // wxASSERT_MSG( glyph, wxString::Format( "missing char in font: code 0x%x <%c>", c, c ) );
2012 
2013  if( !glyph || // Not coded in font
2014  c == '-' || c == '_' ) // Strange size of these 2 chars
2015  {
2016  glyph = defaultGlyph;
2017  }
2018 
2019  if( glyph )
2020  {
2021  textSize.x += glyph->advance;
2022  }
2023  }
2024 
2025  textSize.y = std::max<float>( textSize.y, font_information.max_y - defaultGlyph->miny );
2026  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
2027  textSize.y -= commonOffset;
2028 
2029  return std::make_pair( textSize, commonOffset );
2030 }
2031 
2032 
2033 void OPENGL_GAL::onPaint( wxPaintEvent& aEvent )
2034 {
2035  PostPaint( aEvent );
2036 }
2037 
2038 
2039 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
2040 {
2041  // Post the mouse event to the event listener registered in constructor, if any
2042  if( mouseListener )
2043  wxPostEvent( mouseListener, aEvent );
2044 }
2045 
2046 
2048 {
2049  if( !IsCursorEnabled() )
2050  return;
2051 
2053 
2054  const int cursorSize = fullscreenCursor ? 8000 : 80;
2055 
2056  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
2057  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
2058  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
2059 
2060  const COLOR4D cColor = getCursorColor();
2061  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
2062  cColor.b * cColor.a, 1.0 );
2063 
2064  glActiveTexture( GL_TEXTURE0 );
2065  glDisable( GL_TEXTURE_2D );
2066  glLineWidth( 1.0 );
2067  glColor4d( color.r, color.g, color.b, color.a );
2068 
2069  glBegin( GL_LINES );
2070  glVertex2d( cursorCenter.x, cursorBegin.y );
2071  glVertex2d( cursorCenter.x, cursorEnd.y );
2072 
2073  glVertex2d( cursorBegin.x, cursorCenter.y );
2074  glVertex2d( cursorEnd.x, cursorCenter.y );
2075  glEnd();
2076 }
2077 
2078 
2080 {
2081  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
2082  wxT( "There are no free slots to store a group" ) );
2083 
2084  while( groups.find( groupCounter ) != groups.end() )
2085  {
2086  groupCounter++;
2087  }
2088 
2089  return groupCounter++;
2090 }
2091 
2092 
2094 {
2095 
2096  wxASSERT( IsShownOnScreen() );
2097 
2098  wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." );
2099 
2100 // IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4
2101 // starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER)
2102 #if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 )
2103  const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 };
2104 
2105  if( !IsDisplaySupported( attr ) )
2106  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
2107 #endif /* wxCHECK_VERSION( 3, 0, 3 ) */
2108 
2109  // Check correct initialization from the constructor
2110  if( !glMainContext )
2111  throw std::runtime_error( "Could not create the main OpenGL context" );
2112 
2113  if( !glPrivContext )
2114  throw std::runtime_error( "Could not create a private OpenGL context" );
2115 
2116  if( tesselator == NULL )
2117  throw std::runtime_error( "Could not create the tesselator" );
2118  // End initialzation checks
2119 
2120  GLenum err = glewInit();
2121 
2122  if( GLEW_OK != err )
2123  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
2124 
2125  // Check the OpenGL version (minimum 2.1 is required)
2126  if( !GLEW_VERSION_2_1 )
2127  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
2128 
2129 #if defined (__LINUX__) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
2130 #ifdef DEBUG
2131  if( GLEW_ARB_debug_output )
2132  enableGlDebug( true );
2133 #endif
2134 #endif
2135 
2136  // Framebuffers have to be supported
2137  if( !GLEW_EXT_framebuffer_object )
2138  throw std::runtime_error( "Framebuffer objects are not supported!" );
2139 
2140  // Vertex buffer has to be supported
2141  if( !GLEW_ARB_vertex_buffer_object )
2142  throw std::runtime_error( "Vertex buffer objects are not supported!" );
2143 
2144  // Prepare shaders
2146  throw std::runtime_error( "Cannot compile vertex shader!" );
2147 
2149  throw std::runtime_error( "Cannot compile fragment shader!" );
2150 
2151  if( !shader->IsLinked() && !shader->Link() )
2152  throw std::runtime_error( "Cannot link the shaders!" );
2153 
2154  // Check if video card supports textures big enough to fit the font atlas
2155  int maxTextureSize;
2156  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
2157 
2158  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int) font_image.height )
2159  {
2160  // TODO implement software texture scaling
2161  // for bitmap fonts and use a higher resolution texture?
2162  throw std::runtime_error( "Requested texture size is not supported" );
2163  }
2164 
2166 
2167  cachedManager = new VERTEX_MANAGER( true );
2168  nonCachedManager = new VERTEX_MANAGER( false );
2169  overlayManager = new VERTEX_MANAGER( false );
2170 
2171  // Make VBOs use shaders
2175 
2176  isInitialized = true;
2177 }
2178 
2179 
2180 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
2181 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
2182 {
2183  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
2184  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2185  VERTEX_MANAGER* vboManager = param->vboManager;
2186 
2187  assert( vboManager );
2188  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
2189 }
2190 
2191 
2192 void CALLBACK CombineCallback( GLdouble coords[3],
2193  GLdouble* vertex_data[4],
2194  GLfloat weight[4], GLdouble** dataOut, void* aData )
2195 {
2196  GLdouble* vertex = new GLdouble[3];
2197  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
2198 
2199  // Save the pointer so we can delete it later
2200  param->intersectPoints.emplace_back( vertex );
2201 
2202  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
2203 
2204  *dataOut = vertex;
2205 }
2206 
2207 
2208 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
2209 {
2210  // This callback is needed to force GLU tesselator to use triangles only
2211 }
2212 
2213 
2214 void CALLBACK ErrorCallback( GLenum aErrorCode )
2215 {
2216  //throw std::runtime_error( std::string( "Tessellation error: " ) +
2217  //std::string( (const char*) gluErrorString( aErrorCode ) );
2218 }
2219 
2220 
2221 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
2222 {
2223  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
2224  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
2225  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
2226  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
2227 }
2228 
2229 void OPENGL_GAL::EnableDepthTest( bool aEnabled )
2230 {
2231  cachedManager->EnableDepthTest( aEnabled );
2232  nonCachedManager->EnableDepthTest( aEnabled );
2233  overlayManager->EnableDepthTest( aEnabled );
2234 }
2235 
2236 
2237 static double roundr( double f, double r )
2238 {
2239  return floor(f / r + 0.5) * r;
2240 }
2241 
2242 
2244 {
2245  auto pixelSize = worldScale;
2246 
2247  lookAtPoint.x = roundr( lookAtPoint.x, pixelSize );
2248  lookAtPoint.y = roundr( lookAtPoint.y, pixelSize );
2249 
2251 }
2252 
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:82
int gridTick
Every tick line gets the double width.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
VERTEX_MANAGER * currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
Definition: opengl_gal.h:302
virtual wxSize GetNativePixelSize() const
float GetLineWidth() const
Get the line width.
void beginUpdate() override
Definition: opengl_gal.cpp:620
VECTOR2D cursorPosition
Current cursor position (world coordinates)
bool IsLinked() const
Returns true if shaders are linked correctly.
Definition: shader.h:124
const glm::mat4 & GetTransformation() const
bool axesEnabled
Should the axes be drawn.
void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
int OutlineCount() const
Returns the number of outlines in the set
bool LoadShaderFromStrings(SHADER_TYPE aShaderType, Args &&... aArgs)
Add a shader and compile the shader sources.
Definition: shader.h:99
virtual void DrawBuffer(unsigned int aBufferHandle) override
Function DrawBuffer() draws the selected buffer to the output buffer.
static wxGLContext * glMainContext
Parent OpenGL context.
Definition: opengl_gal.h:290
double layerDepth
The actual layer depth.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:175
void PushMatrix()
Function PushMatrix() pushes the current transformation matrix stack.
int GetAntialiasSupersamplingFactor() const
unsigned int overlayBuffer
Auxiliary rendering target (for menus etc.)
Definition: opengl_gal.h:310
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:280
void Scale(const VECTOR2D &aScale) override
Scale the context.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
void ClearTarget(RENDER_TARGET aTarget) override
Clears the target for rendering.
bool IsTextMirrored() const
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0) override
Draw a cubic bezier spline.
void Translate(const VECTOR2D &aTranslation) override
Translate the context.
virtual void Begin() override
Function Begin() Call this at the beginning of each frame.
double msecs(bool aSinceLast=false)
Definition: profile.h:143
bool Reserve(unsigned int aSize)
Function Reserve() allocates space for vertices, so it will be used with subsequent Vertex() calls.
void BeginDrawing() const
Function BeginDrawing() prepares buffers and items to start drawing.
RENDER_TARGET currentTarget
Current rendering target.
Definition: opengl_gal.h:311
bool isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:319
void Use()
Use the shader.
Definition: shader.h:132
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draws a filled polygon.
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Converts Bezier curve to a polygon.
void DrawItem(const VERTEX_ITEM &aItem) const
Function DrawItem() draws an item to the buffer.
static GLuint fontTexture
Bitmap font texture handle (shared)
Definition: opengl_gal.h:296
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:305
Class OpenGL_GAL is the OpenGL implementation of the Graphics Abstraction Layer.
Definition: opengl_gal.h:65
GAL_DISPLAY_OPTIONS & options
int color
Definition: DXF_plotter.cpp:60
VECTOR2D getScreenPixelSize() const
Definition: opengl_gal.cpp:402
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
Changes the depth (Z-axis position) of the group.
wxImage * GetImageData()
Definition: bitmap_base.h:83
std::unique_ptr< GL_BITMAP_CACHE > bitmapCache
Definition: opengl_gal.h:329
void EnableDepthTest(bool aEnabled=false) override
Parameters passed to the GLU tesselator.
bool Vertex(const VERTEX &aVertex)
Function Vertex() adds a vertex with the given coordinates to the currently set item.
wxGLCanvas wrapper for HiDPI/Retina support.
uni_iter uend() const
Function uend returns a uni_iter initialized to the end of "this" UTF8 byte sequence.
Definition: utf8.h:294
int BeginGroup() override
Begin a group.
static void InitTesselatorCallbacks(GLUtesselator *aTesselator)
void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: opengl_gal.cpp:999
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const
double GetScaleFactor() const
Get the current scale factor.
void Rotate(GLfloat aAngle, GLfloat aX, GLfloat aY, GLfloat aZ)
Function Rotate() multiplies the current matrix by a rotation matrix, so the newly vertices will be r...
bool isContextLocked
Used for assertion checking.
Definition: opengl_gal.h:323
double g
Green component.
Definition: color4d.h:375
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:32
MATRIX3x3D screenWorldMatrix
Screen transformation.
SHADER * shader
There is only one shader used for different objects.
Definition: opengl_gal.h:314
bool globalFlipX
Flag for X axis flipping.
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
static const unsigned int DIRECT_RENDERING
int PointCount() const
Function PointCount()
bool isGrouping
Was a group started?
Definition: opengl_gal.h:322
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:44
EDA_TEXT_HJUSTIFY_T GetHorizontalJustify() const
Returns current text horizontal justification setting.
OPENGL_ANTIALIASING_MODE gl_antialiasing_mode
void UnlockCtx(wxGLContext *aContext)
Function UnlockCtx allows other canvases to bind an OpenGL context.
void enableGlDebug(bool aEnable)
Enables/disables OpenGL driver messages output.
Definition: utils.cpp:142
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:606
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:304
double b
Blue component.
Definition: color4d.h:376
Auxiliary rendering target (noncached)
Definition: definitions.h:49
static int instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:292
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:277
T m_data[3][3]
Definition: matrix3x3.h:64
double getWorldPixelSize() const
Definition: opengl_gal.cpp:395
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
Gets the currently used target for rendering.
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
void endUpdate() override
Definition: opengl_gal.cpp:636
const VECTOR2D & GetGlyphSize() const
void FinishItem() const
Function FinishItem() does the cleaning after adding an item.
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
static const COLOR4D BLACK
Definition: color4d.h:384
uni_iter ubegin() const
Function ubegin returns a uni_iter initialized to the start of "this" UTF8 byte sequence.
Definition: utf8.h:285
const VECTOR2I & CPoint(int aIndex) const
Function Point()
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
void Save() override
Save the context.
void init()
Basic OpenGL initialization and feature checks.
double a
Alpha component.
Definition: color4d.h:377
void Unmap()
Function Unmap() unmaps vertex buffer.
OPENGL_COMPOSITOR * compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:308
void ChangeItemDepth(const VERTEX_ITEM &aItem, GLfloat aDepth) const
Function ChangeItemDepth() changes the depth of all vertices owned by an item.
bool fullscreenCursor
Shape of the cursor (fullscreen or small cross)
#define NULL
bool isStrokeEnabled
Are the outlines stroked ?
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool IsClosed() const override
Function IsClosed()
GROUPS_MAP groups
Stores informations about VBO objects (groups)
Definition: opengl_gal.h:300
virtual void Present() override
Function Present() Call this to present the output buffer to the screen.
unsigned int mainBuffer
Main rendering target.
Definition: opengl_gal.h:309
bool Show(bool aShow) override
Shows/hides the GAL canvas.
virtual void ClearBuffer(const COLOR4D &aColor) override
Function ClearBuffer() clears the selected buffer (set by the SetBuffer() function).
SHAPE_POLY_SET.
void EndGroup() override
End the group.
COLOR4D axesColor
Color of the axes.
void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
double calcAngleStep(double aRadius) const
Compute the angle step when drawing arcs/circles approximated with lines.
Definition: opengl_gal.h:475
wxEvtHandler * mouseListener
Definition: opengl_gal.h:293
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Function updatedGalDisplayOptions.
Definition: opengl_gal.cpp:368
void DrawGrid() override
COLOR4D strokeColor
The color of the outlines.
float gridLineWidth
Line width of the grid.
void SetShader(SHADER &aShader) const
Function SetShader() sets a shader program that is going to be used during rendering.
void Translate(GLfloat aX, GLfloat aY, GLfloat aZ)
Function Translate() multiplies the current matrix by a translation matrix, so newly vertices will be...
void PostPaint(wxPaintEvent &aEvent)
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.cpp:358
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:645
double worldUnitLength
The unit length of the world coordinates [inch].
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
void Map()
Function Map() maps vertex buffer.
void onPaint(wxPaintEvent &aEvent)
This is the OnPaint event handler.
int AddParameter(const std::string &aParameterName)
Add a parameter to the parameter queue.
Definition: shader.cpp:129
GLint ufm_screenPixelSize
Definition: opengl_gal.h:326
void endDrawing() override
Definition: opengl_gal.cpp:557
void DrawGroup(int aGroupNumber) override
Draw the stored group.
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:141
bool isFramebufferInitialized
Are the framebuffers initialized?
Definition: opengl_gal.h:317
virtual void Resize(unsigned int aWidth, unsigned int aHeight) override
Function Resize() clears the state of COMPOSITOR, so it has to be reinitialized again with the new di...
VECTOR2D gridOrigin
The grid origin.
void ClearCache() override
Delete all data created during caching of graphic items.
FONT_IMAGE_TYPE font_image
Definition: gl_resources.cpp:4
unsigned char pixels[1024 *1024 *3]
Definition: gl_resources.h:38
void drawTriangulatedPolyset(const SHAPE_POLY_SET &aPoly)
Draws a set of polygons with a cached triangulation.
FONT_INFO_TYPE font_information
Definition: gl_resources.cpp:3
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:313
MATRIX3x3D worldScreenMatrix
World transformation.
Vertex shader.
Definition: shader.h:46
virtual void SetBuffer(unsigned int aBufferHandle) override
Function SetBuffer() sets the selected buffer as the rendering target.
Class SHADER provides the access to the OpenGL shaders.
Definition: shader.h:76
void lockContext(int aClientCookie) override
Private: use GAL_CONTEXT_LOCKER RAII object.
Definition: opengl_gal.cpp:596
int SegmentCount() const
Function SegmentCount()
void Color(const COLOR4D &aColor)
Function Color() changes currently used color that will be applied to newly added vertices.
GLUtesselator * tesselator
The tessellator.
Definition: opengl_gal.h:352
Use dots for the grid.
Use small cross instead of dots for the grid.
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
std::map< const BITMAP_BASE *, CACHED_BITMAP > m_bitmaps
Definition: opengl_gal.cpp:108
void Rotate(double aAngle) override
Rotate the context.
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Function updatedGalDisplayOptions.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Function LockCtx sets a context as current and prevents other canvases from switching it.
void drawStrokedSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a stroked semicircle.
#define H(x, y, z)
Definition: md5_hash.cpp:17
void PopMatrix()
Function PopMatrix() pops the current transformation matrix stack.
float lineWidth
The line width.
bool isFillEnabled
Is filling of graphic objects enabled ?
void blitCursor()
Blits cursor into the current screen.
VERTEX_MANAGER * cachedManager
Container for storing cached VERTEX_ITEMs.
Definition: opengl_gal.h:303
uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded string...
Definition: utf8.h:207
virtual void Initialize() override
Function Reset() performs primary initialiation, necessary to use the object.
void EndDrawing() const
Function EndDrawing() finishes drawing operations.
void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
Definition: opengl_gal.cpp:976
void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:653
GLint ufm_worldPixelSize
Definition: opengl_gal.h:325
wxEvtHandler * paintListener
Definition: opengl_gal.h:294
std::deque< boost::shared_array< GLdouble > > tessIntersects
Storage for intersecting points.
Definition: opengl_gal.h:354
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
Sets the target for rendering.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
Definition: color4d.h:57
bool isInitialized
Basic initialization flag, has to be done when the window is visible.
Definition: opengl_gal.h:320
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:328
void EnableDepthTest(bool aEnabled)
Function EnableDepthTest() Enables/disables Z buffer depth test.
bool globalFlipY
Flag for Y axis flipping.
double m_scaleFactor
The pixel scale factor (>1 for hi-DPI scaled displays)
EDA_TEXT_VJUSTIFY_T GetVerticalJustify() const
Returns current text vertical justification setting.
SHAPE_LINE_CHAIN.
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: opengl_gal.h:301
virtual bool HasTarget(RENDER_TARGET aTarget) override
Returns true if the target exists.
double worldScale
The scale factor world->screen.
int drawBitmapChar(unsigned long aChar)
Draws a single character using bitmap font.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
VECTOR2D gridSize
The grid size.
unsigned int TriangulatedPolyCount() const
Returns the number of triangulated polygons
void Scale(GLfloat aX, GLfloat aY, GLfloat aZ)
Function Scale() multiplies the current matrix by a scaling matrix, so the newly vertices will be sca...
wxSize GetSizePixels() const
Function GetSizePixels.
Definition: bitmap_base.h:141
void ClearScreen() override
Clear the screen.
VECTOR2I screenSize
Screen size in screen coordinates.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
#define SWAP(varA, condition, varB)
Swap the variables if a condition is met.
Definition: definitions.h:31
unsigned int getNewGroupNumber()
Returns a valid key that can be used as a new group number.
void SetScaleFactor(double aFactor)
Set the canvas scale factor, probably for a hi-DPI display.
wxGLContext * glPrivContext
Canvas-specific OpenGL context.
Definition: opengl_gal.h:291
void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:938
void Flush() override
Force all remaining objects to be drawn.
virtual unsigned int GetBuffer() const override
Function GetBuffer() returns currently used buffer handle.
void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers of advanced config.
virtual unsigned int CreateBuffer() override
Function CreateBuffer() prepares a new buffer that may be used as a rendering target.
void drawPolyline(const std::function< VECTOR2D(int)> &aPointGetter, int aPointCount)
Generic way of drawing a polyline stored in different containers.
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:299
void CALLBACK CombineCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut, void *aData)
void Shader(GLfloat aShaderType, GLfloat aParam1=0.0f, GLfloat aParam2=0.0f, GLfloat aParam3=0.0f)
Function Shader() changes currently used shader and its parameters that will be applied to newly adde...
double r
Red component.
Definition: color4d.h:374
POLYGON & Polygon(int aIndex)
Returns the aIndex-th subpolygon in the set
void ChangeItemColor(const VERTEX_ITEM &aItem, const COLOR4D &aColor) const
Function ChangeItemColor() changes the color of all vertices owned by an item.
std::pair< VECTOR2D, float > computeBitmapTextSize(const UTF8 &aText) const
Computes a size of text drawn using bitmap font with current text setting applied.
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:46
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=NULL)
Function CreateCtx creates a managed OpenGL context.
void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle) override
Draws a text using a bitmap font.
static int SetSwapInterval(int aVal)
Attempts to set the OpenGL swap interval.
Definition: gl_utils.h:41
static double roundr(double f, double r)
#define CALLBACK
Definition: opengl_gal.h:48
bool IsVisible() const override
Definition: opengl_gal.h:106
bool IsCursorEnabled() const
Returns information about cursor visibility.
void beginDrawing() override
Definition: opengl_gal.cpp:409
GLint ufm_pixelSizeMultiplier
Definition: opengl_gal.h:327
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
void Clear() const
Function Clear() removes all the stored vertices from the container.
void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: opengl_gal.cpp:708
static bool isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:318
void skipMouseEvent(wxMouseEvent &aEvent)
Skip the mouse event to the parent.
void drawFilledSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a filled semicircle.
int GetPPI() const
Definition: bitmap_base.h:153
void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Changes the color used to draw the group.
Class GAL is the abstract interface for drawing on a 2D-surface.
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100
void drawBitmapOverbar(double aLength, double aHeight)
Draws an overbar over the currently drawn text.