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