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