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