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 staring and ending indexes to draw grid points on the
984  // visible screen area
985  // Note: later any point coordinate will be offsetted by gridOrigin
986  int gridStartX = KiROUND( (worldStartPoint.x-gridOrigin.x) / gridSize.x );
987  int gridEndX = KiROUND( (worldEndPoint.x-gridOrigin.x) / gridSize.x );
988  int gridStartY = KiROUND( (worldStartPoint.y-gridOrigin.y) / gridSize.y );
989  int gridEndY = KiROUND( (worldEndPoint.y-gridOrigin.y) / gridSize.y );
990 
991  // Ensure start coordinate > end coordinate
992  if( gridStartX > gridEndX )
993  std::swap( gridStartX, gridEndX );
994 
995  if( gridStartY > gridEndY )
996  std::swap( gridStartY, gridEndY );
997 
998  glDisable( GL_DEPTH_TEST );
999  glDisable( GL_TEXTURE_2D );
1000 
1001  if( gridStyle == GRID_STYLE::DOTS )
1002  {
1003  glEnable( GL_STENCIL_TEST );
1004  glStencilFunc( GL_ALWAYS, 1, 1 );
1005  glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
1006  glColor4d( 0.0, 0.0, 0.0, 0.0 );
1007  }
1008  else
1009  {
1010  glColor4d( gridColor.r, gridColor.g, gridColor.b, 1.0 );
1011  }
1012 
1014  {
1015  glLineWidth( minorLineWidth );
1016 
1017  // calculate a line len = 2 minorLineWidth, in internal unit value
1018  // (in fact the size of cross is lineLen*2)
1019  int lineLen = KiROUND( minorLineWidth / worldScale *2 );
1020 
1021  // Vertical positions
1022  for( int j = gridStartY-1; j <= gridEndY; j++ )
1023  {
1024  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1025  || gridScreenSizeDense > gridThreshold )
1026  {
1027  int posY = j * gridSize.y + gridOrigin.y;
1028 
1029  // Horizontal positions
1030  for( int i = gridStartX-1; i <= gridEndX; i++ )
1031  {
1032  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1033  || gridScreenSizeDense > gridThreshold )
1034  {
1035  int posX = i * gridSize.x + gridOrigin.x;
1036 
1037  glBegin( GL_LINES );
1038  glVertex2d( posX -lineLen, posY );
1039  glVertex2d( posX + lineLen, posY );
1040  glVertex2d( posX, posY - lineLen );
1041  glVertex2d( posX, posY + lineLen );
1042  glEnd();
1043  }
1044  }
1045  }
1046  }
1047  }
1048  else
1049  {
1050  // Vertical lines
1051  for( int j = gridStartY-1; j <= gridEndY; j++ )
1052  {
1053  const double y = j * gridSize.y + gridOrigin.y;
1054 
1055  // If axes are drawn, skip the lines that would cover them
1056  if( axesEnabled && y == 0 )
1057  continue;
1058 
1059  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
1060  glLineWidth( majorLineWidth );
1061  else
1062  glLineWidth( minorLineWidth );
1063 
1064  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1065  || gridScreenSizeDense > gridThreshold )
1066  {
1067  glBegin( GL_LINES );
1068  glVertex2d( gridStartX * gridSize.x + gridOrigin.x, y );
1069  glVertex2d( gridEndX * gridSize.x + gridOrigin.x, y );
1070  glEnd();
1071  }
1072  }
1073 
1074  if( gridStyle == GRID_STYLE::DOTS )
1075  {
1076  glStencilFunc( GL_NOTEQUAL, 0, 1 );
1077  glColor4d( gridColor.r, gridColor.g, gridColor.b, 1.0 );
1078  }
1079 
1080  // Horizontal lines
1081  for( int i = gridStartX-1; i <= gridEndX; i++ )
1082  {
1083  const double x = i * gridSize.x + gridOrigin.x;
1084 
1085  // If axes are drawn, skip the lines that would cover them
1086  if( axesEnabled && x == 0 )
1087  continue;
1088 
1089  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
1090  glLineWidth( majorLineWidth );
1091  else
1092  glLineWidth( minorLineWidth );
1093 
1094  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
1095  || gridScreenSizeDense > gridThreshold )
1096  {
1097  glBegin( GL_LINES );
1098  glVertex2d( x, gridStartY * gridSize.y + gridOrigin.y );
1099  glVertex2d( x, gridEndY * gridSize.y + gridOrigin.y );
1100  glEnd();
1101  }
1102  }
1103 
1104  if( gridStyle == GRID_STYLE::DOTS )
1105  glDisable( GL_STENCIL_TEST );
1106  }
1107 
1108  glEnable( GL_DEPTH_TEST );
1109  glEnable( GL_TEXTURE_2D );
1110 }
1111 
1112 
1113 void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
1114 {
1115  screenSize = VECTOR2I( aWidth, aHeight );
1116 
1117 #ifdef RETINA_OPENGL_PATCH
1118  const float scaleFactor = GetBackingScaleFactor();
1119 #else
1120  const float scaleFactor = 1.0f;
1121 #endif
1122 
1123  // Resize framebuffers
1124  compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
1125  isFramebufferInitialized = false;
1126 
1127  wxGLCanvas::SetSize( aWidth, aHeight );
1128 }
1129 
1130 
1131 bool OPENGL_GAL::Show( bool aShow )
1132 {
1133  bool s = wxGLCanvas::Show( aShow );
1134 
1135  if( aShow )
1136  wxGLCanvas::Raise();
1137 
1138  return s;
1139 }
1140 
1141 
1143 {
1144  glFlush();
1145 }
1146 
1147 
1148 void OPENGL_GAL::ClearScreen( const COLOR4D& aColor )
1149 {
1150  // Clear screen
1152  glClearColor( aColor.r, aColor.g, aColor.b, aColor.a );
1153  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1154 }
1155 
1156 
1157 void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation )
1158 {
1159  GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1160 
1161  matrixData[0] = aTransformation.m_data[0][0];
1162  matrixData[1] = aTransformation.m_data[1][0];
1163  matrixData[2] = aTransformation.m_data[2][0];
1164  matrixData[4] = aTransformation.m_data[0][1];
1165  matrixData[5] = aTransformation.m_data[1][1];
1166  matrixData[6] = aTransformation.m_data[2][1];
1167  matrixData[12] = aTransformation.m_data[0][2];
1168  matrixData[13] = aTransformation.m_data[1][2];
1169  matrixData[14] = aTransformation.m_data[2][2];
1170 
1171  glMultMatrixd( matrixData );
1172 }
1173 
1174 
1175 void OPENGL_GAL::Rotate( double aAngle )
1176 {
1177  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1178 }
1179 
1180 
1181 void OPENGL_GAL::Translate( const VECTOR2D& aVector )
1182 {
1183  currentManager->Translate( aVector.x, aVector.y, 0.0f );
1184 }
1185 
1186 
1187 void OPENGL_GAL::Scale( const VECTOR2D& aScale )
1188 {
1189  currentManager->Scale( aScale.x, aScale.y, 0.0f );
1190 }
1191 
1192 
1194 {
1196 }
1197 
1198 
1200 {
1202 }
1203 
1204 
1206 {
1207  isGrouping = true;
1208 
1209  std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *cachedManager );
1210  int groupNumber = getNewGroupNumber();
1211  groups.insert( std::make_pair( groupNumber, newItem ) );
1212 
1213  return groupNumber;
1214 }
1215 
1216 
1218 {
1220  isGrouping = false;
1221 }
1222 
1223 
1224 void OPENGL_GAL::DrawGroup( int aGroupNumber )
1225 {
1226  cachedManager->DrawItem( *groups[aGroupNumber] );
1227 }
1228 
1229 
1230 void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
1231 {
1232  cachedManager->ChangeItemColor( *groups[aGroupNumber], aNewColor );
1233 }
1234 
1235 
1236 void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
1237 {
1238  cachedManager->ChangeItemDepth( *groups[aGroupNumber], aDepth );
1239 }
1240 
1241 
1242 void OPENGL_GAL::DeleteGroup( int aGroupNumber )
1243 {
1244  // Frees memory in the container as well
1245  groups.erase( aGroupNumber );
1246 }
1247 
1248 
1250 {
1251  groups.clear();
1252  cachedManager->Clear();
1253 }
1254 
1255 
1257 {
1258  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1259 }
1260 
1261 
1263 {
1264  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
1265 }
1266 
1267 
1269 {
1270  switch( aTarget )
1271  {
1272  default:
1273  case TARGET_CACHED:
1275  break;
1276 
1277  case TARGET_NONCACHED:
1279  break;
1280 
1281  case TARGET_OVERLAY:
1283  break;
1284  }
1285 
1286  currentTarget = aTarget;
1287 }
1288 
1289 
1291 {
1292  return currentTarget;
1293 }
1294 
1295 
1297 {
1298  // Save the current state
1299  unsigned int oldTarget = compositor->GetBuffer();
1300 
1301  switch( aTarget )
1302  {
1303  // Cached and noncached items are rendered to the same buffer
1304  default:
1305  case TARGET_CACHED:
1306  case TARGET_NONCACHED:
1308  break;
1309 
1310  case TARGET_OVERLAY:
1312  break;
1313  }
1314 
1316 
1317  // Restore the previous state
1318  compositor->SetBuffer( oldTarget );
1319 }
1320 
1321 
1322 void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
1323 {
1324  // Now we should only store the position of the mouse cursor
1325  // The real drawing routines are in blitCursor()
1326  //VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition;
1327  //cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenCursor.y );
1328  cursorPosition = aCursorPosition;
1329 }
1330 
1331 
1332 void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1333 {
1334  /* Helper drawing: ____--- v3 ^
1335  * ____---- ... \ \
1336  * ____---- ... \ end \
1337  * v1 ____---- ... ____---- \ width
1338  * ---- ...___---- \ \
1339  * \ ___...-- \ v
1340  * \ ____----... ____---- v2
1341  * ---- ... ____----
1342  * start \ ... ____----
1343  * \... ____----
1344  * ----
1345  * v0
1346  * dots mark triangles' hypotenuses
1347  */
1348 
1349  VECTOR2D startEndVector = aEndPoint - aStartPoint;
1350  double lineLength = startEndVector.EuclideanNorm();
1351 
1352  if( lineLength <= 0.0 )
1353  return;
1354 
1355  double scale = 0.5 * lineWidth / lineLength;
1356 
1357  // The perpendicular vector also needs transformations
1358  glm::vec4 vector = currentManager->GetTransformation() *
1359  glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 );
1360 
1361  currentManager->Reserve( 6 );
1362 
1363  // Line width is maintained by the vertex shader
1364  currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
1365  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
1366 
1367  currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
1368  currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
1369 
1370  currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
1371  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
1372 
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( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
1378 
1379  currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
1380  currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
1381 }
1382 
1383 
1384 void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
1385 {
1386  if( isFillEnabled )
1387  {
1389  drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
1390  }
1391 
1392  if( isStrokeEnabled )
1393  {
1395  drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
1396  }
1397 }
1398 
1399 
1400 void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1401  double aAngle )
1402 {
1403  Save();
1404 
1405  currentManager->Reserve( 3 );
1406  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1407  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1408 
1409  /* Draw a triangle that contains the semicircle, then shade it to leave only
1410  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1411  * (if you want to understand more, check the vertex shader source [shader.vert]).
1412  * Shader uses these coordinates to determine if fragments are inside the semicircle or not.
1413  * v2
1414  * /\
1415  * /__\
1416  * v0 //__\\ v1
1417  */
1419  currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1420 
1422  currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1423 
1425  currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
1426 
1427  Restore();
1428 }
1429 
1430 
1431 void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
1432  double aAngle )
1433 {
1434  double outerRadius = aRadius + ( lineWidth / 2 );
1435 
1436  Save();
1437 
1438  currentManager->Reserve( 3 );
1439  currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
1440  currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
1441 
1442  /* Draw a triangle that contains the semicircle, then shade it to leave only
1443  * the semicircle. Parameters given to Shader() are indices of the triangle's vertices
1444  * (if you want to understand more, check the vertex shader source [shader.vert]), the
1445  * radius and the line width. Shader uses these coordinates to determine if fragments are
1446  * inside the semicircle or not.
1447  * v2
1448  * /\
1449  * /__\
1450  * v0 //__\\ v1
1451  */
1453  currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
1454 
1456  currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
1457 
1459  currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
1460 
1461  Restore();
1462 }
1463 
1464 
1465 void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
1466 {
1469 
1470  // Any non convex polygon needs to be tesselated
1471  // for this purpose the GLU standard functions are used
1473  gluTessBeginPolygon( tesselator, &params );
1474  gluTessBeginContour( tesselator );
1475 
1476  GLdouble* point = aPoints;
1477 
1478  for( int i = 0; i < aPointCount; ++i )
1479  {
1480  gluTessVertex( tesselator, point, point );
1481  point += 3; // 3 coordinates
1482  }
1483 
1484  gluTessEndContour( tesselator );
1485  gluTessEndPolygon( tesselator );
1486 
1487  // Free allocated intersecting points
1488  tessIntersects.clear();
1489 }
1490 
1491 
1492 void OPENGL_GAL::drawPolyline( std::function<VECTOR2D (int)> aPointGetter, int aPointCount )
1493 {
1494  if( aPointCount < 2 )
1495  return;
1496 
1498  int i;
1499 
1500  for( i = 1; i < aPointCount; ++i )
1501  {
1502  auto start = aPointGetter( i - 1 );
1503  auto end = aPointGetter( i );
1504  const VECTOR2D startEndVector = ( end - start );
1505  double lineAngle = startEndVector.Angle();
1506 
1507  drawLineQuad( start, end );
1508 
1509  // There is no need to draw line caps on both ends of polyline's segments
1510  drawFilledSemiCircle( start, lineWidth / 2, lineAngle + M_PI / 2 );
1511  }
1512 
1513  // ..and now - draw the ending cap
1514  auto start = aPointGetter( i - 2 );
1515  auto end = aPointGetter( i - 1 );
1516  const VECTOR2D startEndVector = ( end - start );
1517  double lineAngle = startEndVector.Angle();
1518  drawFilledSemiCircle( end, lineWidth / 2, lineAngle - M_PI / 2 );
1519 }
1520 
1521 
1522 int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
1523 {
1524  const float TEX_X = font_image.width;
1525  const float TEX_Y = font_image.height;
1526 
1527  const FONT_GLYPH_TYPE* glyph = LookupGlyph(aChar);
1528  if( !glyph ) return 0;
1529 
1530  const float X = glyph->atlas_x + font_information.smooth_pixels;
1531  const float Y = glyph->atlas_y + font_information.smooth_pixels;
1532  const float XOFF = glyph->minx;
1533 
1534  // adjust for height rounding
1535  const float round_adjust = ( glyph->maxy - glyph->miny )
1536  - float( glyph->atlas_h - font_information.smooth_pixels * 2 );
1537  const float top_adjust = font_information.max_y - glyph->maxy;
1538  const float YOFF = round_adjust + top_adjust;
1539  const float W = glyph->atlas_w - font_information.smooth_pixels *2;
1540  const float H = glyph->atlas_h - font_information.smooth_pixels *2;
1541  const float B = 0;
1542 
1543  currentManager->Reserve( 6 );
1544  Translate( VECTOR2D( XOFF, YOFF ) );
1545  /* Glyph:
1546  * v0 v1
1547  * +--+
1548  * | /|
1549  * |/ |
1550  * +--+
1551  * v2 v3
1552  */
1553  currentManager->Shader( SHADER_FONT, X / TEX_X, ( Y + H ) / TEX_Y );
1554  currentManager->Vertex( -B, -B, 0 ); // v0
1555 
1556  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1557  currentManager->Vertex( W + B, -B, 0 ); // v1
1558 
1559  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1560  currentManager->Vertex( -B, H + B, 0 ); // v2
1561 
1562 
1563  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, ( Y + H ) / TEX_Y );
1564  currentManager->Vertex( W + B, -B, 0 ); // v1
1565 
1566  currentManager->Shader( SHADER_FONT, X / TEX_X, Y / TEX_Y );
1567  currentManager->Vertex( -B, H + B, 0 ); // v2
1568 
1569  currentManager->Shader( SHADER_FONT, ( X + W ) / TEX_X, Y / TEX_Y );
1570  currentManager->Vertex( W + B, H + B, 0 ); // v3
1571 
1572  Translate( VECTOR2D( -XOFF + glyph->advance, -YOFF ) );
1573 
1574  return glyph->advance;
1575 }
1576 
1577 
1578 void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight )
1579 {
1580  // To draw an overbar, simply draw an overbar
1581  const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' );
1582  const float H = glyph->maxy - glyph->miny;
1583 
1584  Save();
1585 
1586  Translate( VECTOR2D( -aLength, -aHeight-1.5*H ) );
1587 
1588  currentManager->Reserve( 6 );
1590 
1591  currentManager->Shader( 0 );
1592 
1593  currentManager->Vertex( 0, 0, 0 ); // v0
1594  currentManager->Vertex( aLength, 0, 0 ); // v1
1595  currentManager->Vertex( 0, H, 0 ); // v2
1596 
1597  currentManager->Vertex( aLength, 0, 0 ); // v1
1598  currentManager->Vertex( 0, H, 0 ); // v2
1599  currentManager->Vertex( aLength, H, 0 ); // v3
1600 
1601  Restore();
1602 }
1603 
1604 std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const wxString& aText ) const
1605 {
1606  VECTOR2D textSize( 0, 0 );
1607  float commonOffset = std::numeric_limits<float>::max();
1608  bool wasTilda = false;
1609 
1610  for( unsigned int i = 0; i < aText.length(); ++i )
1611  {
1612  // Remove overbar control characters
1613  if( aText[i] == '~' )
1614  {
1615  if( !wasTilda )
1616  {
1617  // Only double tildas are counted as characters, so skip it as it might
1618  // be an overbar control character
1619  wasTilda = true;
1620  continue;
1621  }
1622  else
1623  {
1624  // Double tilda detected, reset the state and process as a normal character
1625  wasTilda = false;
1626  }
1627  }
1628 
1629  const FONT_GLYPH_TYPE* glyph = LookupGlyph(aText[i]);
1630  if( glyph ) {
1631  textSize.x += glyph->advance;
1632  textSize.y = std::max<float>( textSize.y, font_information.max_y - glyph->miny );
1633  commonOffset = std::min<float>( font_information.max_y - glyph->maxy, commonOffset );
1634  }
1635  }
1636 
1637  textSize.y -= commonOffset;
1638 
1639  return std::make_pair( textSize, commonOffset );
1640 }
1641 
1642 
1643 void OPENGL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1644 {
1645  PostPaint();
1646 }
1647 
1648 
1649 void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1650 {
1651  // Post the mouse event to the event listener registered in constructor, if any
1652  if( mouseListener )
1653  wxPostEvent( mouseListener, aEvent );
1654 }
1655 
1656 
1658 {
1659  if( !IsCursorEnabled() )
1660  return;
1661 
1663 
1664  const int cursorSize = fullscreenCursor ? 8000 : 80;
1665 
1666  VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale );
1667  VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale );
1668  VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2;
1669 
1670  const COLOR4D cColor = getCursorColor();
1671  const COLOR4D color( cColor.r * cColor.a, cColor.g * cColor.a,
1672  cColor.b * cColor.a, 1.0 );
1673 
1674  glDisable( GL_TEXTURE_2D );
1675  glLineWidth( 1.0 );
1676  glColor4d( color.r, color.g, color.b, color.a );
1677 
1678  glBegin( GL_LINES );
1679  glVertex2d( cursorCenter.x, cursorBegin.y );
1680  glVertex2d( cursorCenter.x, cursorEnd.y );
1681 
1682  glVertex2d( cursorBegin.x, cursorCenter.y );
1683  glVertex2d( cursorEnd.x, cursorCenter.y );
1684  glEnd();
1685 }
1686 
1687 
1689 {
1690  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
1691  wxT( "There are no free slots to store a group" ) );
1692 
1693  while( groups.find( groupCounter ) != groups.end() )
1694  {
1695  groupCounter++;
1696  }
1697 
1698  return groupCounter++;
1699 }
1700 
1701 
1703 {
1704  wxASSERT( IsShownOnScreen() );
1705 
1707 
1708  GLenum err = glewInit();
1709 
1710  try
1711  {
1712  if( GLEW_OK != err )
1713  throw std::runtime_error( (const char*) glewGetErrorString( err ) );
1714 
1715  // Check the OpenGL version (minimum 2.1 is required)
1716  if( !GLEW_VERSION_2_1 )
1717  throw std::runtime_error( "OpenGL 2.1 or higher is required!" );
1718 
1719  // Framebuffers have to be supported
1720  if( !GLEW_EXT_framebuffer_object )
1721  throw std::runtime_error( "Framebuffer objects are not supported!" );
1722 
1723  // Vertex buffer has to be supported
1724  if( !GLEW_ARB_vertex_buffer_object )
1725  throw std::runtime_error( "Vertex buffer objects are not supported!" );
1726 
1727  // Prepare shaders
1729  throw std::runtime_error( "Cannot compile vertex shader!" );
1730 
1732  throw std::runtime_error( "Cannot compile fragment shader!" );
1733 
1734  if( !shader->IsLinked() && !shader->Link() )
1735  throw std::runtime_error( "Cannot link the shaders!" );
1736 
1737  // Check if video card supports textures big enough to fit the font atlas
1738  int maxTextureSize;
1739  glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
1740 
1741  if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height )
1742  {
1743  // TODO implement software texture scaling
1744  // for bitmap fonts and use a higher resolution texture?
1745  throw std::runtime_error( "Requested texture size is not supported" );
1746  }
1747  }
1748  catch( std::runtime_error& )
1749  {
1751  throw;
1752  }
1753 
1754  // Make VBOs use shaders
1758 
1760  isInitialized = true;
1761 }
1762 
1763 
1764 // ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
1765 void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
1766 {
1767  GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
1768  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
1769  VERTEX_MANAGER* vboManager = param->vboManager;
1770 
1771  assert( vboManager );
1772  vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
1773 }
1774 
1775 
1776 void CALLBACK CombineCallback( GLdouble coords[3],
1777  GLdouble* vertex_data[4],
1778  GLfloat weight[4], GLdouble** dataOut, void* aData )
1779 {
1780  GLdouble* vertex = new GLdouble[3];
1781  OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
1782 
1783  // Save the pointer so we can delete it later
1784  param->intersectPoints.push_back( boost::shared_array<GLdouble>( vertex ) );
1785 
1786  memcpy( vertex, coords, 3 * sizeof(GLdouble) );
1787 
1788  *dataOut = vertex;
1789 }
1790 
1791 
1792 void CALLBACK EdgeCallback( GLboolean aEdgeFlag )
1793 {
1794  // This callback is needed to force GLU tesselator to use triangles only
1795 }
1796 
1797 
1798 void CALLBACK ErrorCallback( GLenum aErrorCode )
1799 {
1800  //throw std::runtime_error( std::string( "Tessellation error: " ) +
1801  //std::string( (const char*) gluErrorString( aErrorCode ) );
1802 }
1803 
1804 
1805 static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
1806 {
1807  gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
1808  gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
1809  gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
1810  gluTessCallback( aTesselator, GLU_TESS_ERROR, ( void (CALLBACK*)() )ErrorCallback );
1811 }
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:58
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
void PushMatrix()
Function PushMatrix() pushes the current transformation matrix stack.
unsigned int overlayBuffer
Auxiliary rendering target (for menus etc.)
Definition: opengl_gal.h: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)
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...
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: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: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
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:288
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: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: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: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: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.