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