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-2016 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 #include <gal/opengl/opengl_gal.h>
30 #include <gal/opengl/utils.h>
31 #include <gal/definitions.h>
32 #include <gl_context_mgr.h>
34 #include <text_utils.h>
35 
36 #include <macros.h>
37 
38 #ifdef __WXDEBUG__
39 #include <profile.h>
40 #include <wx/log.h>
41 #endif /* __WXDEBUG__ */
42 
43 #include <limits>
44 #include <functional>
45 using namespace std::placeholders;
46 
47 
48 using namespace KIGFX;
49 
50 
51 // The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0
52 // (see ubuntu-font-licence-1.0.txt for details)
53 #include "gl_resources.h"
54 #include "gl_builtin_shaders.h"
55 using namespace KIGFX::BUILTIN_FONT;
56 
57 static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
58 static const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 8, 0 };
59 
60 wxGLContext* OPENGL_GAL::glMainContext = NULL;
61 int OPENGL_GAL::instanceCounter = 0;
62 GLuint OPENGL_GAL::fontTexture = 0;
63 bool OPENGL_GAL::isBitmapFontLoaded = false;
64 SHADER* OPENGL_GAL::shader = NULL;
65 
66 
67 OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
68  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
69  const wxString& aName ) :
70  GAL( aDisplayOptions ),
71  HIDPI_GL_CANVAS( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
72  wxEXPAND, aName ),
73  mouseListener( aMouseListener ), paintListener( aPaintListener ), currentManager( nullptr ),
74  cachedManager( nullptr ), nonCachedManager( nullptr ), overlayManager( nullptr ), mainBuffer( 0 ), overlayBuffer( 0 )
75 {
76  if( glMainContext == NULL )
77  {
80  shader = new SHADER();
81  }
82  else
83  {
85  }
86 
88 
91 
92  // Initialize the flags
95  isInitialized = false;
96  isGrouping = false;
97  groupCounter = 0;
98 
99  // Connecting the event handlers
100  Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) );
101 
102  // Mouse events are skipped to the parent
103  Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
104  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
105  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
106  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
107  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
108  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
109  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
110  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
111  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
112  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
113  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
114 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
115  Connect( wxEVT_MAGNIFY, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
116 #endif
117 #if defined _WIN32 || defined _WIN64
118  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
119 #endif
120 
121  SetSize( aParent->GetClientSize() );
122  screenSize = VECTOR2I( aParent->GetClientSize() );
123 
124  // Grid color settings are different in Cairo and OpenGL
125  SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) );
126  SetAxesColor( COLOR4D( BLUE ) );
127 
128  // Tesselator initialization
129  tesselator = gluNewTess();
131 
132  if( tesselator == NULL )
133  throw std::runtime_error( "Could not create the tesselator" );
134 
135  gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
136 
138 }
139 
140 
142 {
144 
145  --instanceCounter;
146  glFlush();
147  gluDeleteTess( tesselator );
148  ClearCache();
149 
150  delete compositor;
151 
152  if( isInitialized )
153  {
154  delete cachedManager;
155  delete nonCachedManager;
156  delete overlayManager;
157  }
158 
160 
161  // If it was the main context, then it will be deleted
162  // when the last OpenGL GAL instance is destroyed (a few lines below)
165 
166  // Are we destroying the last GAL instance?
167  if( instanceCounter == 0 )
168  {
170 
171  if( isBitmapFontLoaded )
172  {
173  glDeleteTextures( 1, &fontTexture );
174  isBitmapFontLoaded = false;
175  }
176 
177  delete shader;
178 
181  glMainContext = NULL;
182  }
183 }
184 
185 
187 {
188  bool refresh = false;
189 
191  {
193  isFramebufferInitialized = false;
194  refresh = true;
195  }
196 
197  if( super::updatedGalDisplayOptions( aOptions ) || refresh )
198  {
199  Refresh();
200  refresh = true;
201  }
202 
203  return refresh;
204 }
205 
206 
208 {
209  if( !IsShownOnScreen() )
210  return;
211 
212 #ifdef __WXDEBUG__
213  PROF_COUNTER totalRealTime( "OPENGL_GAL::BeginDrawing()", true );
214 #endif /* __WXDEBUG__ */
215 
216  if( !isInitialized )
217  init();
218 
220 
221  // Set up the view port
222  glMatrixMode( GL_PROJECTION );
223  glLoadIdentity();
224 
225  // Create the screen transformation (Do the RH-LH conversion here)
226  glOrtho( 0, (GLint) screenSize.x, (GLsizei) screenSize.y, 0, -depthRange.x, -depthRange.y );
227 
229  {
230  try
231  {
232  // Prepare rendering target buffers
236  }
237  catch( std::runtime_error& )
238  {
240  throw; // DRAW_PANEL_GAL will handle it
241  }
242 
244  }
245 
246  compositor->Begin();
247 
248  // Disable 2D Textures
249  glDisable( GL_TEXTURE_2D );
250 
251  glShadeModel( GL_FLAT );
252 
253  // Enable the depth buffer
254  glEnable( GL_DEPTH_TEST );
255  glDepthFunc( GL_LESS );
256 
257  // Setup blending, required for transparent objects
258  glEnable( GL_BLEND );
259  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
260 
261  glMatrixMode( GL_MODELVIEW );
262 
263  // Set up the world <-> screen transformation
265  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
266  matrixData[0] = worldScreenMatrix.m_data[0][0];
267  matrixData[1] = worldScreenMatrix.m_data[1][0];
268  matrixData[2] = worldScreenMatrix.m_data[2][0];
269  matrixData[4] = worldScreenMatrix.m_data[0][1];
270  matrixData[5] = worldScreenMatrix.m_data[1][1];
271  matrixData[6] = worldScreenMatrix.m_data[2][1];
272  matrixData[12] = worldScreenMatrix.m_data[0][2];
273  matrixData[13] = worldScreenMatrix.m_data[1][2];
274  matrixData[14] = worldScreenMatrix.m_data[2][2];
275  glLoadMatrixd( matrixData );
276 
277  // Set defaults
280 
281  // Remove all previously stored items
284 
288 
290  {
291  // Keep bitmap font texture always bound to the second texturing unit
292  const GLint FONT_TEXTURE_UNIT = 2;
293 
294  // Either load the font atlas to video memory, or simply bind it to a texture unit
295  if( !isBitmapFontLoaded )
296  {
297  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
298  glGenTextures( 1, &fontTexture );
299  glBindTexture( GL_TEXTURE_2D, fontTexture );
300  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, font_image.width, font_image.height,
301  0, GL_RGB, GL_UNSIGNED_BYTE, font_image.pixels );
302  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
303  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
304  checkGlError( "loading bitmap font" );
305 
306  glActiveTexture( GL_TEXTURE0 );
307 
308  isBitmapFontLoaded = true;
309  }
310  else
311  {
312  glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
313  glBindTexture( GL_TEXTURE_2D, fontTexture );
314  glActiveTexture( GL_TEXTURE0 );
315  }
316 
317  // Set shader parameter
318  GLint ufm_fontTexture = shader->AddParameter( "fontTexture" );
319  GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" );
320  shader->Use();
321  shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
322  shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
323  shader->Deactivate();
324  checkGlError( "setting bitmap font sampler as shader parameter" );
325 
327  }
328 
329  // Something betreen BeginDrawing and EndDrawing seems to depend on
330  // this texture unit being active, but it does not assure it itself.
331  glActiveTexture( GL_TEXTURE0 );
332 
333  // Unbind buffers - set compositor for direct drawing
335 
336 #ifdef __WXDEBUG__
337  totalRealTime.Stop();
338  wxLogTrace( "GAL_PROFILE",
339  wxT( "OPENGL_GAL::BeginDrawing(): %.1f ms" ), totalRealTime.msecs() );
340 #endif /* __WXDEBUG__ */
341 }
342 
343 
345 {
346 #ifdef __WXDEBUG__
347  PROF_COUNTER totalRealTime( "OPENGL_GAL::EndDrawing()", true );
348 #endif /* __WXDEBUG__ */
349 
350  // Cached & non-cached containers are rendered to the same buffer
354 
355  // Overlay container is rendered to a different buffer
358 
359  // Be sure that the framebuffer is not colorized (happens on specific GPU&drivers combinations)
360  glColor4d( 1.0, 1.0, 1.0, 1.0 );
361 
362  // Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
365  compositor->Present();
366  blitCursor();
367 
368  SwapBuffers();
370 
371 #ifdef __WXDEBUG__
372  totalRealTime.Stop();
373  wxLogTrace( "GAL_PROFILE", wxT( "OPENGL_GAL::EndDrawing(): %.1f ms" ), totalRealTime.msecs() );
374 #endif /* __WXDEBUG__ */
375 }
376 
377 
379 {
380  if( !IsShownOnScreen() )
381  return;
382 
383  if( !isInitialized )
384  init();
385 
387  cachedManager->Map();
388 }
389 
390 
392 {
393  if( !isInitialized )
394  return;
395 
396  cachedManager->Unmap();
398 }
399 
400 
401 void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
402 {
403  const VECTOR2D startEndVector = aEndPoint - aStartPoint;
404  double lineAngle = startEndVector.Angle();
405 
407 
408  drawLineQuad( aStartPoint, aEndPoint );
409 
410  // Line caps
411  if( lineWidth > 1.0 )
412  {
413  drawFilledSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 );
414  drawFilledSemiCircle( aEndPoint, lineWidth / 2, lineAngle - M_PI / 2 );
415  }
416 }
417 
418 
419 void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
420  double aWidth )
421 {
422  VECTOR2D startEndVector = aEndPoint - aStartPoint;
423  double lineAngle = startEndVector.Angle();
424 
425  if( isFillEnabled )
426  {
427  // Filled tracks
429 
430  SetLineWidth( aWidth );
431  drawLineQuad( aStartPoint, aEndPoint );
432 
433  // Draw line caps
434  drawFilledSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2 );
435  drawFilledSemiCircle( aEndPoint, aWidth / 2, lineAngle - M_PI / 2 );
436  }
437  else
438  {
439  // Outlined tracks
440  double lineLength = startEndVector.EuclideanNorm();
441 
443 
444  Save();
445 
446  currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
447  currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
448 
449  drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
450  VECTOR2D( lineLength, aWidth / 2.0 ) );
451 
452  drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ),
453  VECTOR2D( lineLength, -aWidth / 2.0 ) );
454 
455  // Draw line caps
456  drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
457  drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );
458 
459  Restore();
460  }
461 }
462 
463 
464 void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
465 {
466  if( isFillEnabled )
467  {
468  currentManager->Reserve( 3 );
470 
471  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
472  * Parameters given to Shader() are indices of the triangle's vertices
473  * (if you want to understand more, check the vertex shader source [shader.vert]).
474  * Shader uses this coordinates to determine if fragments are inside the circle or not.
475  * v2
476  * /\
477  * //\\
478  * v0 /_\/_\ v1
479  */
481  currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), // v0
482  aCenterPoint.y - aRadius, layerDepth );
483 
485  currentManager->Vertex( aCenterPoint.x + aRadius * sqrt( 3.0f), // v1
486  aCenterPoint.y - aRadius, layerDepth );
487 
489  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, // v2
490  layerDepth );
491  }
492 
493  if( isStrokeEnabled )
494  {
495  currentManager->Reserve( 3 );
497 
498  /* Draw a triangle that contains the circle, then shade it leaving only the circle.
499  * Parameters given to Shader() are indices of the triangle's vertices
500  * (if you want to understand more, check the vertex shader source [shader.vert]).
501  * and the line width. Shader uses this coordinates to determine if fragments are
502  * inside the circle or not.
503  * v2
504  * /\
505  * //\\
506  * v0 /_\/_\ v1
507  */
508  double outerRadius = aRadius + ( lineWidth / 2 );
510  currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), // v0
511  aCenterPoint.y - outerRadius, layerDepth );
512 
514  currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), // v1
515  aCenterPoint.y - outerRadius, layerDepth );
516 
518  currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, // v2
519  layerDepth );
520  }
521 }
522 
523 
524 void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
525  double aEndAngle )
526 {
527  if( aRadius <= 0 )
528  return;
529 
530  // Swap the angles, if start angle is greater than end angle
531  SWAP( aStartAngle, >, aEndAngle );
532 
533  const double alphaIncrement = calcAngleStep( aRadius );
534 
535  Save();
536  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
537 
538  if( isStrokeEnabled )
539  {
541 
542  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
543  double alpha;
544 
545  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
546  {
547  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
548  DrawLine( p, p_next );
549 
550  p = p_next;
551  }
552 
553  // Draw the last missing part
554  if( alpha != aEndAngle )
555  {
556  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
557  DrawLine( p, p_last );
558  }
559  }
560 
561  if( isFillEnabled )
562  {
563  double alpha;
566 
567  // Triangle fan
568  for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
569  {
570  currentManager->Reserve( 3 );
571  currentManager->Vertex( 0.0, 0.0, 0.0 );
572  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, 0.0 );
573  alpha += alphaIncrement;
574  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, 0.0 );
575  }
576 
577  // The last missing triangle
578  const VECTOR2D endPoint( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
579 
580  currentManager->Reserve( 3 );
581  currentManager->Vertex( 0.0, 0.0, 0.0 );
582  currentManager->Vertex( cos( alpha ) * aRadius, sin( alpha ) * aRadius, 0.0 );
583  currentManager->Vertex( endPoint.x, endPoint.y, 0.0 );
584  }
585 
586  Restore();
587 }
588 
589 
590 void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
591  double aEndAngle, double aWidth )
592 {
593  if( aRadius <= 0 )
594  return;
595 
596  // Swap the angles, if start angle is greater than end angle
597  SWAP( aStartAngle, >, aEndAngle );
598 
599  const double alphaIncrement = calcAngleStep( aRadius );
600 
601  Save();
602  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
603 
604  if( isStrokeEnabled )
605  {
607 
608  double width = aWidth / 2.0;
609  VECTOR2D startPoint( cos( aStartAngle ) * aRadius,
610  sin( aStartAngle ) * aRadius );
611  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
612  sin( aEndAngle ) * aRadius );
613 
614  drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI );
615  drawStrokedSemiCircle( endPoint, width, aEndAngle );
616 
617  VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ),
618  sin( aStartAngle ) * ( aRadius + width ) );
619 
620  VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ),
621  sin( aStartAngle ) * ( aRadius - width ) );
622 
623  double alpha;
624 
625  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
626  {
627  VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
628  sin( alpha ) * ( aRadius + width ) );
629  VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
630  sin( alpha ) * ( aRadius - width ) );
631 
632  DrawLine( pOuter, pNextOuter );
633  DrawLine( pInner, pNextInner );
634 
635  pOuter = pNextOuter;
636  pInner = pNextInner;
637  }
638 
639  // Draw the last missing part
640  if( alpha != aEndAngle )
641  {
642  VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ),
643  sin( aEndAngle ) * ( aRadius + width ) );
644  VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ),
645  sin( aEndAngle ) * ( aRadius - width ) );
646 
647  DrawLine( pOuter, pLastOuter );
648  DrawLine( pInner, pLastInner );
649  }
650  }
651 
652  if( isFillEnabled )
653  {
655  SetLineWidth( aWidth );
656 
657  VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
658  double alpha;
659 
660  for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement )
661  {
662  VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
663  DrawLine( p, p_next );
664 
665  p = p_next;
666  }
667 
668  // Draw the last missing part
669  if( alpha != aEndAngle )
670  {
671  VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
672  DrawLine( p, p_last );
673  }
674  }
675 
676  Restore();
677 }
678 
679 
680 void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
681 {
682  // Compute the diagonal points of the rectangle
683  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
684  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
685 
686  // Stroke the outline
687  if( isStrokeEnabled )
688  {
690 
691  std::deque<VECTOR2D> pointList;
692  pointList.push_back( aStartPoint );
693  pointList.push_back( diagonalPointA );
694  pointList.push_back( aEndPoint );
695  pointList.push_back( diagonalPointB );
696  pointList.push_back( aStartPoint );
697  DrawPolyline( pointList );
698  }
699 
700  // Fill the rectangle
701  if( isFillEnabled )
702  {
703  currentManager->Reserve( 6 );
706 
707  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
708  currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
709  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
710 
711  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
712  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
713  currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
714  }
715 }
716 
717 
718 void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
719 {
720  drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
721 }
722 
723 
724 void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
725 {
726  drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
727 }
728 
729 
731 {
732  auto numPoints = aLineChain.PointCount();
733 
734  if( aLineChain.IsClosed() )
735  numPoints += 1;
736 
737  drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, numPoints );
738 }
739 
740 
741 void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
742 {
743  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
744  GLdouble* ptr = points.get();
745 
746  for( const VECTOR2D& p : aPointList )
747  {
748  *ptr++ = p.x;
749  *ptr++ = p.y;
750  *ptr++ = layerDepth;
751  }
752 
753  drawPolygon( points.get(), aPointList.size() );
754 }
755 
756 
757 void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
758 {
759  auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
760  GLdouble* target = points.get();
761  const VECTOR2D* src = aPointList;
762 
763  for( int i = 0; i < aListSize; ++i )
764  {
765  *target++ = src->x;
766  *target++ = src->y;
767  *target++ = layerDepth;
768  ++src;
769  }
770 
771  drawPolygon( points.get(), aListSize );
772 }
773 
775 {
778 
779 
780  if ( isFillEnabled )
781  {
782  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
783  {
784  auto triPoly = aPolySet.TriangulatedPolygon( j );
785 
786  for( int i = 0; i < triPoly->GetTriangleCount(); i++ )
787  {
788  VECTOR2I a, b, c;
789  triPoly->GetTriangle( i ,a,b,c);
790  currentManager->Vertex( a.x, a.y, layerDepth );
791  currentManager->Vertex( b.x, b.y, layerDepth );
792  currentManager->Vertex( c.x, c.y, layerDepth );
793  }
794  }
795  }
796 
797  if( isStrokeEnabled )
798  {
799  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
800  {
801  const auto& poly = aPolySet.Polygon( j );
802 
803  for( const auto& lc : poly )
804  {
805  DrawPolyline( lc );
806  }
807  }
808  }
809 }
810 
811 
813 {
814  if ( aPolySet.IsTriangulationUpToDate() )
815  {
816  drawTriangulatedPolyset( aPolySet );
817  return;
818  }
819 
820  for( int j = 0; j < aPolySet.OutlineCount(); ++j )
821  {
822  const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
823 
824  if( outline.SegmentCount() == 0 )
825  continue;
826 
827  const int pointCount = outline.SegmentCount() + 1;
828  std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
829  GLdouble* ptr = points.get();
830 
831  for( int i = 0; i < pointCount; ++i )
832  {
833  const VECTOR2I& p = outline.CPoint( i );
834  *ptr++ = p.x;
835  *ptr++ = p.y;
836  *ptr++ = layerDepth;
837  }
838 
839  drawPolygon( points.get(), pointCount );
840  }
841 }
842 
843 
844 void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
845  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
846 {
847  // FIXME The drawing quality needs to be improved
848  // FIXME Perhaps choose a quad/triangle strip instead?
849  // FIXME Brute force method, use a better (recursive?) algorithm
850 
851  std::deque<VECTOR2D> pointList;
852 
853  double t = 0.0;
854  double dt = 1.0 / (double) CURVE_POINTS;
855 
856  for( int i = 0; i <= CURVE_POINTS; i++ )
857  {
858  double omt = 1.0 - t;
859  double omt2 = omt * omt;
860  double omt3 = omt * omt2;
861  double t2 = t * t;
862  double t3 = t * t2;
863 
864  VECTOR2D vertex = omt3 * aStartPoint + 3.0 * t * omt2 * aControlPointA
865  + 3.0 * t2 * omt * aControlPointB + t3 * aEndPoint;
866 
867  pointList.push_back( vertex );
868 
869  t += dt;
870  }
871 
872  DrawPolyline( pointList );
873 }
874 
875 
876 void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
877  double aRotationAngle )
878 {
879  wxASSERT_MSG( !IsTextMirrored(), "No support for mirrored text using bitmap fonts." );
880 
881  auto processedText = ProcessOverbars( aText );
882  const auto& text = processedText.first;
883  const auto& overbars = processedText.second;
884 
885  // Compute text size, so it can be properly justified
886  VECTOR2D textSize;
887  float commonOffset;
888  std::tie( textSize, commonOffset ) = computeBitmapTextSize( text );
889 
890  const double SCALE = 1.4 * GetGlyphSize().y / textSize.y;
891  bool overbar = false;
892 
893  int overbarLength = 0;
894  double overbarHeight = textSize.y;
895 
896  Save();
897 
899  currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
900  currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
901 
902  double sx = SCALE * ( globalFlipX ? -1.0 : 1.0 );
903  double sy = SCALE * ( globalFlipY ? -1.0 : 1.0 );
904 
905  currentManager->Scale( sx, sy, 0 );
906  currentManager->Translate( 0, -commonOffset, 0 );
907 
908  switch( GetHorizontalJustify() )
909  {
911  Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
912  break;
913 
915  //if( !IsTextMirrored() )
916  Translate( VECTOR2D( -textSize.x, 0 ) );
917  break;
918 
920  //if( IsTextMirrored() )
921  //Translate( VECTOR2D( -textSize.x, 0 ) );
922  break;
923  }
924 
925  switch( GetVerticalJustify() )
926  {
928  Translate( VECTOR2D( 0, -textSize.y ) );
929  overbarHeight = -textSize.y / 2.0;
930  break;
931 
933  Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
934  overbarHeight = 0;
935  break;
936 
938  break;
939  }
940 
941  int i = 0;
942 
943  for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
944  {
945  unsigned int c = *chIt;
946  wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
947 
948  // Handle overbar
949  if( overbars[i] && !overbar )
950  {
951  overbar = true; // beginning of an overbar
952  }
953  else if( overbar && !overbars[i] )
954  {
955  overbar = false; // end of an overbar
956  drawBitmapOverbar( overbarLength, overbarHeight );
957  overbarLength = 0;
958  }
959 
960  if( overbar )
961  overbarLength += drawBitmapChar( c );
962  else
963  drawBitmapChar( c );
964 
965  ++i;
966  }
967 
968  // Handle the case when overbar is active till the end of the drawn text
969  currentManager->Translate( 0, commonOffset, 0 );
970 
971  if( overbar && overbarLength > 0 )
972  drawBitmapOverbar( overbarLength, overbarHeight );
973 
974  Restore();
975 }
976 
977 
979 {
982 
983  // sub-pixel lines all render the same
984  double minorLineWidth = std::max( 1.0, gridLineWidth );
985  double majorLineWidth = minorLineWidth * 2.0;
986 
987  // Draw the axis and grid
988  // For the drawing the start points, end points and increments have
989  // to be calculated in world coordinates
990  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
991  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
992 
993  // Draw axes if desired
994  if( axesEnabled )
995  {
996  glLineWidth( minorLineWidth );
997  glColor4d( axesColor.r, axesColor.g, axesColor.b, 1.0 );
998 
999  glBegin( GL_LINES );
1000  glVertex2d( worldStartPoint.x, 0 );
1001  glVertex2d( worldEndPoint.x, 0 );
1002  glEnd();
1003 
1004  glBegin( GL_LINES );
1005  glVertex2d( 0, worldStartPoint.y );
1006  glVertex2d( 0, worldEndPoint.y );
1007  glEnd();
1008  }
1009 
1010  if( !gridVisibility )
1011  return;
1012 
1013  int gridScreenSizeDense = KiROUND( gridSize.x * worldScale );
1014  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) * worldScale );
1015 
1016  const double gridThreshold = computeMinGridSpacing();
1017 
1018  // Check if the grid would not be too dense
1019  if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) < gridThreshold )
1020  return;
1021 
1022  // Compute grid staring and ending indexes to draw grid points on the
1023  // visible screen area
1024  // Note: later any point coordinate will be offsetted by gridOrigin
1025  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridSize.x );
1026  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridSize.x );
1027  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridSize.y );
1028  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridSize.y );
1029 
1030  // Ensure start coordinate > end coordinate
1031  if( gridStartX > gridEndX )
1032  std::swap( gridStartX, gridEndX );
1033 
1034  if( gridStartY > gridEndY )
1035  std::swap( gridStartY, gridEndY );
1036 
1037  // Ensure the grid fills the screen
1038  --gridStartX; ++gridEndX;
1039  --gridStartY; ++gridEndY;
1040 
1041  glDisable( GL_DEPTH_TEST );
1042  glDisable( GL_TEXTURE_2D );
1043 
1044  if( gridStyle == GRID_STYLE::DOTS )
1045  {
1046  glEnable( GL_STENCIL_TEST );
1047  glStencilFunc( GL_ALWAYS, 1, 1 );
1048  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1049  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1050  }
1051  else
1052  {
1053  glColor4d( gridColor.r, gridColor.g, gridColor.b, 1.0 );
1054  }
1055 
1057  {
1058  glLineWidth( minorLineWidth );
1059 
1060  // calculate a line len = 2 minorLineWidth, in internal unit value
1061  // (in fact the size of cross is lineLen*2)
1062  int lineLen = KiROUND( minorLineWidth / worldScale * 2 );
1063 
1064  // Vertical positions
1065  for( int j = gridStartY; j <= gridEndY; j++ )
1066  {
1067  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1068  || gridScreenSizeDense > gridThreshold )
1069  {
1070  int posY = j * gridSize.y + gridOrigin.y;
1071 
1072  // Horizontal positions
1073  for( int i = gridStartX; i <= gridEndX; i++ )
1074  {
1075  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1076  || gridScreenSizeDense > gridThreshold )
1077  {
1078  int posX = i * gridSize.x + gridOrigin.x;
1079 
1080  glBegin( GL_LINES );
1081  glVertex2d( posX -lineLen, posY );
1082  glVertex2d( posX + lineLen, posY );
1083  glVertex2d( posX, posY - lineLen );
1084  glVertex2d( posX, posY + lineLen );
1085  glEnd();
1086  }
1087  }
1088  }
1089  }
1090  }
1091  else
1092  {
1093  // Vertical lines
1094  for( int j = gridStartY; j <= gridEndY; j++ )
1095  {
1096  const double y = j * gridSize.y + gridOrigin.y;
1097 
1098  // If axes are drawn, skip the lines that would cover them
1099  if( axesEnabled && y == 0 )
1100  continue;
1101 
1102  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
1103  glLineWidth( majorLineWidth );
1104  else
1105  glLineWidth( minorLineWidth );
1106 
1107  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1108  || gridScreenSizeDense > gridThreshold )
1109  {
1110  glBegin( GL_LINES );
1111  glVertex2d( gridStartX * gridSize.x + gridOrigin.x, y );
1112  glVertex2d( gridEndX * gridSize.x + gridOrigin.x, y );
1113  glEnd();
1114  }
1115  }
1116 
1117  if( gridStyle == GRID_STYLE::DOTS )
1118  {
1119  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1120  glColor4d( gridColor.r, gridColor.g, gridColor.b, 1.0 );
1121  }
1122 
1123  // Horizontal lines
1124  for( int i = gridStartX; i <= gridEndX; i++ )
1125  {
1126  const double x = i * gridSize.x + gridOrigin.x;
1127 
1128  // If axes are drawn, skip the lines that would cover them
1129  if( axesEnabled && x == 0 )
1130  continue;
1131 
1132  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
1133  glLineWidth( majorLineWidth );
1134  else
1135  glLineWidth( minorLineWidth );
1136 
1137  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1138  || gridScreenSizeDense > gridThreshold )
1139  {
1140  glBegin( GL_LINES );
1141  glVertex2d( x, gridStartY * gridSize.y + gridOrigin.y );
1142  glVertex2d( x, gridEndY * gridSize.y + gridOrigin.y );
1143  glEnd();
1144  }
1145  }
1146 
1147  if( gridStyle == GRID_STYLE::DOTS )
1148  glDisable( GL_STENCIL_TEST );
1149  }
1150 
1151  glEnable( GL_DEPTH_TEST );
1152  glEnable( GL_TEXTURE_2D );
1153 }
1154 
1155 
1156 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1157 {
1158  screenSize = VECTOR2I( aWidth, aHeight );
1159 
1160  // Resize framebuffers
1161  const float scaleFactor = GetBackingScaleFactor();
1162  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1163  isFramebufferInitialized = false;
1164 
1165  wxGLCanvas::SetSize( aWidth, aHeight );
1166 }
1167 
1168 
1169 bool OPENGL_GAL::Show( bool aShow )
1170 {
1171  bool s = wxGLCanvas::Show( aShow );
1172 
1173  if( aShow )
1174  wxGLCanvas::Raise();
1175 
1176  return s;
1177 }
1178 
1179 
1181 {
1182  glFlush();
1183 }
1184 
1185 
1187 {
1188  // Clear screen
1190  // NOTE: Black used here instead of m_clearColor; it will be composited later
1191  glClearColor( 0, 0, 0, 1 );
1192  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1193 }
1194 
1195 
1196 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1197 {
1198  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1199 
1200  matrixData[0] = aTransformation.m_data[0][0];
1201  matrixData[1] = aTransformation.m_data[1][0];
1202  matrixData[2] = aTransformation.m_data[2][0];
1203  matrixData[4] = aTransformation.m_data[0][1];
1204  matrixData[5] = aTransformation.m_data[1][1];
1205  matrixData[6] = aTransformation.m_data[2][1];
1206  matrixData[12] = aTransformation.m_data[0][2];
1207  matrixData[13] = aTransformation.m_data[1][2];
1208  matrixData[14] = aTransformation.m_data[2][2];
1209 
1210  glMultMatrixd( matrixData );
1211 }
1212 
1213 
1214 void OPENGL_GAL::Rotate( double aAngle )
1215 {
1216  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1217 }
1218 
1219 
1220 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1221 {
1222  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1223 }
1224 
1225 
1226 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1227 {
1228  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1229 }
1230 
1231 
1233 {
1235 }
1236 
1237 
1239 {
1241 }
1242 
1243 
1245 {
1246  isGrouping = true;
1247 
1248  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1249  int groupNumber = getNewGroupNumber();
1250  groups.insert( std::make_pair( groupNumber, newItem ) );
1251 
1252  return groupNumber;
1253 }
1254 
1255 
1257 {
1259  isGrouping = false;
1260 }
1261 
1262 
1263 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1264 {
1265  cachedManager->DrawItem( *groups[aGroupNumber] );
1266 }
1267 
1268 
1269 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1270 {
1271  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1272 }
1273 
1274 
1275 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1276 {
1277  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1278 }
1279 
1280 
1281 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1282 {
1283  // Frees memory in the container as well
1284  groups.erase( aGroupNumber );
1285 }
1286 
1287 
1289 {
1290  groups.clear();
1291 
1292  if( isInitialized )
1293  cachedManager->Clear();
1294 }
1295 
1296 
1298 {
1299  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1300 }
1301 
1302 
1304 {
1305  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1306 }
1307 
1308 
1310 {
1311  switch( aTarget )
1312  {
1313  default:
1314  case TARGET_CACHED:
1316  break;
1317 
1318  case TARGET_NONCACHED:
1320  break;
1321 
1322  case TARGET_OVERLAY:
1324  break;
1325  }
1326 
1327  currentTarget = aTarget;
1328 }
1329 
1330 
1332 {
1333  return currentTarget;
1334 }
1335 
1336 
1338 {
1339  // Save the current state
1340  unsigned int oldTarget = compositor->GetBuffer();
1341 
1342  switch( aTarget )
1343  {
1344  // Cached and noncached items are rendered to the same buffer
1345  default:
1346  case TARGET_CACHED:
1347  case TARGET_NONCACHED:
1349  break;
1350 
1351  case TARGET_OVERLAY:
1353  break;
1354  }
1355 
1356 
1357  if( aTarget != TARGET_OVERLAY )
1359  else
1361 
1362  // Restore the previous state
1363  compositor->SetBuffer( oldTarget );
1364 }
1365 
1366 
1367 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1368 {
1369  // Now we should only store the position of the mouse cursor
1370  // The real drawing routines are in blitCursor()
1371  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1372  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1373  cursorPosition = aCursorPosition;
1374 }
1375 
1376 
1377 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1378 {
1379  /* Helper drawing: ____--- v3 ^
1380  * ____---- ... \ \
1381  * ____---- ... \ end \
1382  * v1 ____---- ... ____---- \ width
1383  * ---- ...___---- \ \
1384  * \ ___...-- \ v
1385  * \ ____----... ____---- v2
1386  * ---- ... ____----
1387  * start \ ... ____----
1388  * \... ____----
1389  * ----
1390  * v0
1391  * dots mark triangles' hypotenuses
1392  */
1393 
1394  VECTOR2D startEndVector = aEndPoint - aStartPoint;
1395  double lineLength = startEndVector.EuclideanNorm();
1396 
1397  if( lineLength <= 0.0 )
1398  return;
1399 
1400  double scale = 0.5 * lineWidth / lineLength;
1401 
1402  // The perpendicular vector also needs transformations
1403  glm::vec4 vector = currentManager->GetTransformation() *
1404  glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 );
1405 
1406  currentManager->Reserve( 6 );
1407 
1408  // Line width is maintained by the vertex shader
1409  currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
1410  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
1411 
1412  currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
1413  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
1414 
1415  currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
1416  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
1417 
1418  currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
1419  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
1420 
1421  currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
1422  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
1423 
1424  currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
1425  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
1426 }
1427 
1428 
1429 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1430 {
1431  if( isFillEnabled )
1432  {
1434  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1435  }
1436 
1437  if( isStrokeEnabled )
1438  {
1440  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1441  }
1442 }
1443 
1444 
1445 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1446  double aAngle )
1447 {
1448  Save();
1449 
1450  currentManager->Reserve( 3 );
1451  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1452  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1453 
1454  /* Draw a triangle that contains the semicircle, then shade it to leave only
1455  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1456  * (if you want to understand more, check the vertex shader source [shader.vert]).
1457  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1458  * v2
1459  * /\
1460  * /__\
1461  * v0 //__\\ v1
1462  */
1464  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1465 
1467  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1468 
1470  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1471 
1472  Restore();
1473 }
1474 
1475 
1476 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1477  double aAngle )
1478 {
1479  double outerRadius = aRadius + ( lineWidth / 2 );
1480 
1481  Save();
1482 
1483  currentManager->Reserve( 3 );
1484  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1485  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1486 
1487  /* Draw a triangle that contains the semicircle, then shade it to leave only
1488  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1489  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1490  * radius and the line width. Shader uses these coordinates to determine if fragments are
1491  * inside the semicircle or not.
1492  * v2
1493  * /\
1494  * /__\
1495  * v0 //__\\ v1
1496  */
1498  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1499 
1501  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1502 
1504  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1505 
1506  Restore();
1507 }
1508 
1509 
1510 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1511 {
1512  if( isFillEnabled )
1513  {
1516 
1517  // Any non convex polygon needs to be tesselated
1518  // for this purpose the GLU standard functions are used
1520  gluTessBeginPolygon( tesselator, &params );
1521  gluTessBeginContour( tesselator );
1522 
1523  GLdouble* point = aPoints;
1524 
1525  for( int i = 0; i < aPointCount; ++i )
1526  {
1527  gluTessVertex( tesselator, point, point );
1528  point += 3; // 3 coordinates
1529  }
1530 
1531  gluTessEndContour( tesselator );
1532  gluTessEndPolygon( tesselator );
1533 
1534  // Free allocated intersecting points
1535  tessIntersects.clear();
1536  }
1537 
1538  if( isStrokeEnabled )
1539  {
1540  drawPolyline( [&](int idx) { return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] ); },
1541  aPointCount );
1542  }
1543 }
1544 
1545 
1546 void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D (int)>& aPointGetter, int aPointCount )
1547 {
1548  if( aPointCount < 2 )
1549  return;
1550 
1552  int i;
1553 
1554  for( i = 1; i < aPointCount; ++i )
1555  {
1556  auto start = aPointGetter( i - 1 );
1557  auto end = aPointGetter( i );
1558  const VECTOR2D startEndVector = ( end - start );
1559  double lineAngle = startEndVector.Angle();
1560 
1561  drawLineQuad( start, end );
1562 
1563  // There is no need to draw line caps on both ends of polyline's segments
1564  drawFilledSemiCircle( start, lineWidth / 2, lineAngle + M_PI / 2 );
1565  }
1566 
1567  // ..and now - draw the ending cap
1568  auto start = aPointGetter( i - 2 );
1569  auto end = aPointGetter( i - 1 );
1570  const VECTOR2D startEndVector = ( end - start );
1571  double lineAngle = startEndVector.Angle();
1572  drawFilledSemiCircle( end, lineWidth / 2, lineAngle - M_PI / 2 );
1573 }
1574 
1575 
1576 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1577 {
1578  const float TEX_X = font_image.width;
1579  const float TEX_Y = font_image.height;
1580 
1581  // handle space
1582  if( aChar == ' ' )
1583  {
1584  const FONT_GLYPH_TYPE* g = LookupGlyph( 'x' );
1585  wxASSERT( g );
1586  Translate( VECTOR2D( g->advance, 0 ) );
1587  return g->advance;
1588  }
1589 
1590  const FONT_GLYPH_TYPE* glyph = LookupGlyph( aChar );
1591  wxASSERT( glyph );
1592 
1593  if( !glyph )
1594  return 0;
1595 
1596  const float X = glyph->atlas_x + font_information.smooth_pixels;
1597  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1598  const float XOFF = glyph->minx;
1599 
1600  // adjust for height rounding
1601  const float round_adjust = ( glyph->maxy - glyph->miny )
1602  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1603  const float top_adjust = font_information.max_y - glyph->maxy;
1604  const float YOFF = round_adjust + top_adjust;
1605  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1606  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1607  const float B = 0;
1608 
1609  currentManager->Reserve( 6 );
1610  Translate( VECTOR2D( XOFF, YOFF ) );
1611  /* Glyph:
1612  * v0 v1
1613  * +--+
1614  * | /|
1615  * |/ |
1616  * +--+
1617  * v2 v3
1618  */
1619  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1620  currentManager->Vertex( -B, -B, 0 ); // v0
1621 
1622  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1623  currentManager->Vertex( W + B, -B, 0 ); // v1
1624 
1625  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1626  currentManager->Vertex( -B, H + B, 0 ); // v2
1627 
1628 
1629  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1630  currentManager->Vertex( W + B, -B, 0 ); // v1
1631 
1632  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1633  currentManager->Vertex( -B, H + B, 0 ); // v2
1634 
1635  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1636  currentManager->Vertex( W + B, H + B, 0 ); // v3
1637 
1638  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1639 
1640  return glyph->advance;
1641 }
1642 
1643 
1644 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1645 {
1646  // To draw an overbar, simply draw an overbar
1647  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1648  wxCHECK( glyph, /* void */ );
1649 
1650  const float H = glyph->maxy - glyph->miny;
1651 
1652  Save();
1653 
1654  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1655 
1656  currentManager->Reserve( 6 );
1658 
1659  currentManager->Shader( 0 );
1660 
1661  currentManager->Vertex( 0, 0, 0 ); // v0
1662  currentManager->Vertex( aLength, 0, 0 ); // v1
1663  currentManager->Vertex( 0, H, 0 ); // v2
1664 
1665  currentManager->Vertex( aLength, 0, 0 ); // v1
1666  currentManager->Vertex( 0, H, 0 ); // v2
1667  currentManager->Vertex( aLength, H, 0 ); // v3
1668 
1669  Restore();
1670 }
1671 
1672 
1673 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText ) const
1674 {
1675  VECTOR2D textSize( 0, 0 );
1676  float commonOffset = std::numeric_limits<float>::max();
1677  static const auto defaultGlyph = LookupGlyph( '(' ); // for strange chars
1678 
1679  for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
1680  {
1681  unsigned int c = *chIt;
1682 
1683  const FONT_GLYPH_TYPE* glyph = LookupGlyph( c );
1684  wxASSERT( c == ' ' || glyph ); // space is not in the atlas
1685 
1686  // a few chars
1687  if( !glyph || // Not coded in font
1688  c == '-' || c == '_' ) // Strange size of these 2 chars
1689  {
1690  glyph = defaultGlyph;
1691  }
1692 
1693  if( glyph )
1694  {
1695  textSize.x += glyph->advance;
1696  }
1697  }
1698 
1699  textSize.y = std::max<float>( textSize.y, font_information.max_y - defaultGlyph->miny );
1700  commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
1701  textSize.y -= commonOffset;
1702 
1703  return std::make_pair( textSize, commonOffset );
1704 }
1705 
1706 
1707 void OPENGL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1708 {
1709  PostPaint();
1710 }
1711 
1712 
1713 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1714 {
1715  // Post the mouse event to the event listener registered in constructor, if any
1716  if( mouseListener )
1717  wxPostEvent( mouseListener, aEvent );
1718 }
1719 
1720 
1722 {
1723  if( !IsCursorEnabled() )
1724  return;
1725 
1727 
1728  const int cursorSize = fullscreenCursor ? 8000 : 80;
1729 
1730  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
1731  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
1732  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
1733 
1734  const COLOR4D cColor = getCursorColor();
1735  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
1736  cColor.b * cColor.a, 1.0 );
1737 
1738  glActiveTexture( GL_TEXTURE0 );
1739  glDisable( GL_TEXTURE_2D );
1740  glLineWidth( 1.0 );
1741  glColor4d( color.r, color.g, color.b, color.a );
1742 
1743  glBegin( GL_LINES );
1744  glVertex2d( cursorCenter.x, cursorBegin.y );
1745  glVertex2d( cursorCenter.x, cursorEnd.y );
1746 
1747  glVertex2d( cursorBegin.x, cursorCenter.y );
1748  glVertex2d( cursorEnd.x, cursorCenter.y );
1749  glEnd();
1750 }
1751 
1752 
1754 {
1755  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
1756  wxT( "There are no free slots to store a group" ) );
1757 
1758  while( groups.find( groupCounter ) != groups.end() )
1759  {
1760  groupCounter++;
1761  }
1762 
1763  return groupCounter++;
1764 }
1765 
1766 
1768 {
1769  wxASSERT( IsShownOnScreen() );
1770 
1772 
1773  GLenum err = glewInit();
1774 
1775  try
1776  {
1777  if( GLEW_OK != err )
1778  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
1779 
1780  // Check the OpenGL version (minimum 2.1 is required)
1781  if( !GLEW_VERSION_2_1 )
1782  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
1783 
1784 #if defined (__LINUX__) // calling enableGlDebug crashes opengl on some OS (OSX and some Windows)
1785 #ifdef DEBUG
1786  if( GLEW_ARB_debug_output )
1787  enableGlDebug( true );
1788 #endif
1789 #endif
1790 
1791  // Framebuffers have to be supported
1792  if( !GLEW_EXT_framebuffer_object )
1793  throw std::runtime_error( "Framebuffer objects are not supported!" );
1794 
1795  // Vertex buffer has to be supported
1796  if( !GLEW_ARB_vertex_buffer_object )
1797  throw std::runtime_error( "Vertex buffer objects are not supported!" );
1798 
1799  // Prepare shaders
1801  throw std::runtime_error( "Cannot compile vertex shader!" );
1802 
1804  throw std::runtime_error( "Cannot compile fragment shader!" );
1805 
1806  if( !shader->IsLinked() && !shader->Link() )
1807  throw std::runtime_error( "Cannot link the shaders!" );
1808 
1809  // Check if video card supports textures big enough to fit the font atlas
1810  int maxTextureSize;
1811  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
1812 
1813  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height )
1814  {
1815  // TODO implement software texture scaling
1816  // for bitmap fonts and use a higher resolution texture?
1817  throw std::runtime_error( "Requested texture size is not supported" );
1818  }
1819  }
1820  catch( std::runtime_error& )
1821  {
1823  throw;
1824  }
1825 
1826  cachedManager = new VERTEX_MANAGER( true );
1827  nonCachedManager = new VERTEX_MANAGER( false );
1828  overlayManager = new VERTEX_MANAGER( false );
1829 
1830  // Make VBOs use shaders
1834 
1836  isInitialized = true;
1837 }
1838 
1839 
1840 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
1841 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
1842 {
1843  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
1844  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
1845  VERTEX_MANAGER* vboManager = param->vboManager;
1846 
1847  assert( vboManager );
1848  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
1849 }
1850 
1851 
1852 void CALLBACK CombineCallback( GLdouble coords[3],
1853  GLdouble* vertex_data[4],
1854  GLfloat weight[4], GLdouble** dataOut, void* aData )
1855 {
1856  GLdouble* vertex = new GLdouble[3];
1857  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
1858 
1859  // Save the pointer so we can delete it later
1860  param->intersectPoints.push_back( boost::shared_array<GLdouble>( vertex ) );
1861 
1862  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
1863 
1864  *dataOut = vertex;
1865 }
1866 
1867 
1868 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
1869 {
1870  // This callback is needed to force GLU tesselator to use triangles only
1871 }
1872 
1873 
1874 void CALLBACK ErrorCallback( GLenum aErrorCode )
1875 {
1876  //throw std::runtime_error( std::string( "Tessellation error: " ) +
1877  //std::string( (const char*) gluErrorString( aErrorCode ) );
1878 }
1879 
1880 
1881 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
1882 {
1883  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
1884  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
1885  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
1886  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
1887 }
Definition: colors.h:57
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
bool IsCursorEnabled() const
Returns information about cursor visibility.
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.
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
VERTEX_MANAGER * currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
Definition: opengl_gal.h:304
EDA_TEXT_HJUSTIFY_T GetHorizontalJustify() const
Returns current text horizontal justification setting.
VECTOR2D cursorPosition
Current cursor position (world coordinates)
static SHADER * shader
There is only one shader used for different objects.
Definition: opengl_gal.h:316
virtual void BeginUpdate() override
Enables item update mode.
Definition: opengl_gal.cpp:378
bool axesEnabled
Should the axes be drawn.
bool IsLinked() const
Returns true if shaders are linked correctly.
Definition: shader.h:122
EDA_TEXT_VJUSTIFY_T GetVerticalJustify() const
Returns current text vertical justification setting.
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:292
void Clear() const
Function Clear() removes all the stored vertices from the container.
double calcAngleStep(double aRadius) const
Compute the angle step when drawing arcs/circles approximated with lines.
Definition: opengl_gal.h:454
std::pair< UTF8, std::vector< bool > > ProcessOverbars(const UTF8 &aText)
Processes a text to extract the raw text and overbar flags.
Definition: text_utils.cpp:27
double layerDepth
The actual layer depth.
void ChangeItemDepth(const VERTEX_ITEM &aItem, GLfloat aDepth) const
Function ChangeItemDepth() changes the depth of all vertices owned by an item.
virtual void EndUpdate() override
Disables item update mode.
Definition: opengl_gal.cpp:391
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
void PushMatrix()
Function PushMatrix() pushes the current transformation matrix stack.
unsigned int overlayBuffer
Auxiliary rendering target (for menus etc.)
Definition: opengl_gal.h:312
std::deque< boost::shared_array< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Definition: opengl_gal.h:282
virtual void Scale(const VECTOR2D &aScale) override
Scale the context.
virtual void ClearTarget(RENDER_TARGET aTarget) override
Clears the target for rendering.
virtual void Translate(const VECTOR2D &aTranslation) override
Translate the context.
virtual void Begin() override
Function Begin() Call this at the beginning of each frame.
bool Reserve(unsigned int aSize)
Function Reserve() allocates space for vertices, so it will be used with subsequent Vertex() calls...
RENDER_TARGET currentTarget
Current rendering target.
Definition: opengl_gal.h:313
int PointCount() const
Function PointCount()
bool isBitmapFontInitialized
Is the shader set to use bitmap fonts?
Definition: opengl_gal.h:321
void Use()
Use the shader.
Definition: shader.h:130
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draws a filled polygon.
void SetParameter(int aParameterNumber, float aValue) const
Set a parameter of the shader.
Definition: shader.cpp:137
static GLuint fontTexture
Bitmap font texture handle (shared)
Definition: opengl_gal.h:298
GRID_STYLE gridStyle
Grid display style.
bool LoadShaderFromStrings(SHADER_TYPE aShaderType, Args &&...aArgs)
Add a shader and compile the shader sources.
Definition: shader.h:97
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:307
virtual void EndDrawing() override
End the drawing, needs to be called for every new frame.
Definition: opengl_gal.cpp:344
GAL_DISPLAY_OPTIONS & options
int color
Definition: DXF_plotter.cpp:62
virtual void Restore() override
Restore the context.
void CALLBACK EdgeCallback(GLboolean aEdgeFlag)
virtual void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Changes the depth (Z-axis position) of the group.
bool Vertex(const VERTEX &aVertex)
Function Vertex() adds a vertex with the given coordinates to the currently set item.
static const COLOR4D BLACK
Definition: color4d.h:301
wxGLCanvas wrapper for HiDPI/Retina support.
virtual int BeginGroup() override
Begin a group.
static void InitTesselatorCallbacks(GLUtesselator *aTesselator)
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: opengl_gal.cpp:741
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...
double g
Green component.
Definition: color4d.h:292
Fragment shader.
Definition: shader.h:45
bool Link()
Link the shaders.
Definition: shader.cpp:96
COLOR4D fillColor
The fill color.
VECTOR2D depthRange
Range of the depth.
bool IsTriangulationUpToDate() const
int checkGlError(const std::string &aInfo, bool aThrow)
Checks if one of recent OpenGL operations has failed.
Definition: utils.cpp:30
int OutlineCount() const
Returns the number of outlines in the set
MATRIX3x3D screenWorldMatrix
Screen transformation.
bool globalFlipX
Flag for X axis flipping.
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:589
static const unsigned int DIRECT_RENDERING
bool isGrouping
Was a group started?
Definition: opengl_gal.h:324
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:45
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:103
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
void CALLBACK VertexCallback(GLvoid *aVertexPtr, void *aData)
virtual void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
uni_iter ubegin() const
Function ubegin returns a uni_iter initialized to the start of "this" UTF8 byte sequence.
Definition: utf8.h:285
VERTEX_MANAGER * nonCachedManager
Container for storing non-cached VERTEX_ITEMs.
Definition: opengl_gal.h:306
double b
Blue component.
Definition: color4d.h:293
Auxiliary rendering target (noncached)
Definition: definitions.h:42
static int instanceCounter
GL GAL instance counter.
Definition: opengl_gal.h:294
This file contains miscellaneous commonly used macros and functions.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
Definition: opengl_gal.h:279
T m_data[3][3]
Definition: matrix3x3.h:64
void SetAntialiasingMode(OPENGL_ANTIALIASING_MODE aMode)
virtual void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle, double aWidth) override
Draw an arc segment.
Definition: opengl_gal.cpp:590
virtual RENDER_TARGET GetTarget() const override
Gets the currently used target for rendering.
static const int CURVE_POINTS
The number of points for curve approximation.
Definition: opengl_gal.h:290
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
double lineWidth
The line width.
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:308
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
virtual void Save() override
Save the context.
void init()
Basic OpenGL initialization.
double a
Alpha component.
Definition: color4d.h:294
void Unmap()
Function Unmap() unmaps vertex buffer.
virtual void SetLineWidth(double aLineWidth)
Set the line width.
OPENGL_COMPOSITOR * compositor
Handles multiple rendering targets.
Definition: opengl_gal.h:310
bool fullscreenCursor
Shape of the cursor (fullscreen or small cross)
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:294
bool isStrokeEnabled
Are the outlines stroked ?
VECTOR2< double > VECTOR2D
Definition: vector2d.h:588
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
void Refresh()
Update the board display after modifying it bu a python script (note: it is automatically called by a...
GROUPS_MAP groups
Stores informations about VBO objects (groups)
Definition: opengl_gal.h:302
virtual void Present() override
Function Present() Call this to present the output buffer to the screen.
std::pair< VECTOR2D, float > computeBitmapTextSize(const UTF8 &aText) const
Computes a size of text drawn using bitmap font with current text setting applied.
virtual void BeginDrawing() override
Begin the drawing, needs to be called for every new frame.
Definition: opengl_gal.cpp:207
virtual void RestoreScreen() override
Restore the screen contents.
unsigned int mainBuffer
Main rendering target.
Definition: opengl_gal.h:311
virtual 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).
Class SHAPE_POLY_SET.
virtual void EndGroup() override
End the group.
COLOR4D axesColor
Color of the axes.
virtual void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
wxEvtHandler * mouseListener
Definition: opengl_gal.h:295
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
void EndDrawing() const
Function EndDrawing() finishes drawing operations.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Function updatedGalDisplayOptions.
Definition: opengl_gal.cpp:186
virtual void DrawGrid() override
>
Definition: opengl_gal.cpp:978
COLOR4D strokeColor
The color of the outlines.
void Translate(GLfloat aX, GLfloat aY, GLfloat aZ)
Function Translate() multiplies the current matrix by a translation matrix, so newly vertices will be...
static const int glAttributes[]
Definition: opengl_gal.cpp:58
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: opengl_gal.cpp:401
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
Items that may change while the view stays the same (noncached)
Definition: definitions.h:43
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:124
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const VECTOR2D & GetGlyphSize() const
virtual void DrawGroup(int aGroupNumber) override
Draw the stored group.
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:139
bool isFramebufferInitialized
Are the framebuffers initialized?
Definition: opengl_gal.h:319
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.
virtual 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.
Definition: opengl_gal.cpp:774
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const
FONT_INFO_TYPE font_information
Definition: gl_resources.cpp:3
MATRIX3x3D worldScreenMatrix
World transformation.
Vertex shader.
Definition: shader.h:44
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:74
void BeginDrawing() const
Function BeginDrawing() prepares buffers and items to start drawing.
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:331
Use dots for the grid.
Use small cross instead of dots for the grid.
virtual 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.
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:305
class uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded ...
Definition: utf8.h:207
virtual void Initialize() override
Function Reset() performs primary initialiation, necessary to use the object.
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
Definition: opengl_gal.cpp:718
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: opengl_gal.cpp:419
std::deque< boost::shared_array< GLdouble > > tessIntersects
Storage for intersecting points.
Definition: opengl_gal.h:333
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: opengl_gal.cpp:524
void CALLBACK ErrorCallback(GLenum aErrorCode)
virtual void SaveScreen() override
Save the screen contents.
double msecs() const
Definition: profile.h:124
virtual void SetTarget(RENDER_TARGET aTarget) override
Sets the target for rendering.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
uni_iter uend() const
Function uend returns a uni_iter initialized to the end of "this" UTF8 byte sequence.
Definition: utf8.h:294
bool isInitialized
Basic initialization flag, has to be done when the window is visible.
Definition: opengl_gal.h:322
COLOR4D gridColor
Color of the grid.
const int scale
void ChangeItemColor(const VERTEX_ITEM &aItem, const COLOR4D &aColor) const
Function ChangeItemColor() changes the color of all vertices owned by an item.
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: opengl_gal.h:256
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:41
#define max(a, b)
Definition: auxiliary.h:86
bool globalFlipY
Flag for Y axis flipping.
Class SHAPE_LINE_CHAIN.
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: opengl_gal.h:303
double worldScale
The scale factor world->screen.
int drawBitmapChar(unsigned long aChar)
Draws a single character using bitmap font.
void FinishItem() const
Function FinishItem() does the cleaning after adding an item.
VECTOR2D gridSize
The grid size.
virtual float GetBackingScaleFactor() const
const glm::mat4 & GetTransformation() const
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...
virtual void ClearScreen() override
Clear the screen.
VECTOR2I screenSize
Screen size in screen coordinates.
#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.
wxGLContext * glPrivContext
Canvas-specific OpenGL context.
Definition: opengl_gal.h:293
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: opengl_gal.cpp:680
virtual void Flush() override
Force all remaining objects to be drawn.
bool IsClosed() const
Function IsClosed()
virtual unsigned int GetBuffer() const override
Function GetBuffer() returns currently used buffer handle.
virtual void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
virtual unsigned int CreateBuffer() override
Function CreateBuffer() prepares a new buffer that may be used as a rendering target.
void drawPolyline(const std::function< VECTOR2D(int)> &aPointGetter, int aPointCount)
Generic way of drawing a polyline stored in different containers.
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
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:291
POLYGON & Polygon(int aIndex)
Returns the aIndex-th subpolygon in the set
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:39
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=NULL)
Function CreateCtx creates a managed OpenGL context.
virtual void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle) override
Draws a text using a bitmap font.
Definition: opengl_gal.cpp:876
bool IsTextMirrored() const
Returns true if text should displayed mirrored.
#define CALLBACK
Definition: opengl_gal.h:48
virtual ~OPENGL_GAL()
Definition: opengl_gal.cpp:141
void DrawItem(const VERTEX_ITEM &aItem) const
Function DrawItem() draws an item to the buffer.
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: opengl_gal.cpp:464
static bool isBitmapFontLoaded
Is the bitmap font texture loaded?
Definition: opengl_gal.h:320
int SegmentCount() const
Function SegmentCount()
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint) override
Draw a cubic bezier spline.
Definition: opengl_gal.cpp:844
void skipMouseEvent(wxMouseEvent &aEvent)
Skip the mouse event to the parent.
void drawFilledSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a filled semicircle.
virtual 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.
void SetShader(SHADER &aShader) const
Function SetShader() sets a shader program that is going to be used during rendering.
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
double gridLineWidth
Line width of the grid.
void drawBitmapOverbar(double aLength, double aHeight)
Draws an overbar over the currently drawn text.